API/src/service/customer.service.ts

152 lines
4.1 KiB
TypeScript

import { Provide } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Order } from '../entity/order.entity';
import { Repository } from 'typeorm';
import { CustomerTag } from '../entity/customer_tag.entity';
@Provide()
export class CustomerService {
@InjectEntityModel(Order)
orderModel: Repository<Order>;
@InjectEntityModel(CustomerTag)
customerTagModel: Repository<CustomerTag>;
async getCustomerList(param: Record<string, any>) {
const {
current = 1,
pageSize = 10,
email,
tags,
sorterKey,
sorterValue,
state,
first_purchase_date,
customerId,
} = param;
const whereConds: string[] = [];
const havingConds: string[] = [];
if (email) {
whereConds.push(`o.customer_email LIKE '%${email}%'`);
}
if (state) {
whereConds.push(
`JSON_UNQUOTE(JSON_EXTRACT(o.billing, '$.state')) = '${state}'`
);
}
if (customerId) {
whereConds.push(`
o.customer_email = (
SELECT email FROM customer WHERE id = ${Number(customerId)}
)
`);
}
if (tags) {
const tagList = tags
.split(',')
.map(tag => `'${tag.trim()}'`)
.join(',');
havingConds.push(`
EXISTS (
SELECT 1 FROM customer_tag ct
WHERE ct.email = o.customer_email
AND ct.tag IN (${tagList})
)
`);
}
if (first_purchase_date) {
havingConds.push(
`DATE_FORMAT(MIN(o.date_paid), '%Y-%m') = '${first_purchase_date}'`
);
}
const baseQuery = `
${whereConds.length ? `WHERE ${whereConds.join(' AND ')}` : ''}
GROUP BY o.customer_email
${havingConds.length ? `HAVING ${havingConds.join(' AND ')}` : ''}
`;
let sql = `
select
o.customer_email as email,
MIN(date_created) as date_created,
MIN(date_paid) as first_purchase_date,
MAX(date_paid) as last_purchase_date,
COUNT(DISTINCT o.id) as orders,
SUM(total) as total,
ANY_VALUE(o.shipping) AS shipping,
ANY_VALUE(o.billing) AS billing,
(
SELECT JSON_ARRAYAGG(tag)
FROM customer_tag ct
WHERE ct.email = o.customer_email
) AS tags,
(
SELECT id FROM customer c WHERE c.email = o.customer_email
) as customerId,
yoone_stats.yoone_orders,
yoone_stats.yoone_total
FROM \`order\` o
LEFT JOIN (
SELECT
oo.customer_email,
COUNT(DISTINCT oi.orderId) AS yoone_orders,
SUM(oi.total) AS yoone_total
FROM order_item oi
JOIN \`order\` oo ON oi.orderId = oo.id
WHERE oi.name LIKE '%yoone%'
GROUP BY oo.customer_email
) yoone_stats ON yoone_stats.customer_email = o.customer_email
${baseQuery}
${
sorterKey
? `ORDER BY ${sorterKey} ${
sorterValue === 'descend' ? 'DESC' : 'ASC'
}`
: ''
}
limit ${pageSize} offset ${(current - 1) * pageSize}
`;
const countSql = `
SELECT COUNT(*) AS total FROM (
SELECT o.customer_email
FROM \`order\` o
${baseQuery}
) AS sub
`;
const [items, countResult] = await Promise.all([
this.orderModel.query(sql),
this.orderModel.query(countSql),
]);
const total = countResult[0]?.total || 0;
return {
items,
total,
current,
pageSize,
};
}
async addTag(email: string, tag: string) {
const isExist = await this.customerTagModel.findOneBy({ email, tag });
if (isExist) throw new Error(`${tag}已存在`);
return await this.customerTagModel.save({ email, tag });
}
async delTag(email: string, tag: string) {
const isExist = await this.customerTagModel.findOneBy({ email, tag });
if (!isExist) throw new Error(`${tag}不存在`);
return await this.customerTagModel.delete({ email, tag });
}
async getTags() {
const tags = await this.customerTagModel
.createQueryBuilder('tag')
.select('DISTINCT tag.tag', 'tag')
.getRawMany();
return tags.map(t => t.tag);
}
}