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; @InjectEntityModel(CustomerTag) customerTagModel: Repository; async getCustomerList(param: Record) { 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' }` : 'ORDER BY orders ASC, yoone_total DESC' } 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); } }