import { Request, Response } from "express"; import { getRepository } from "typeorm"; import dayjs from "dayjs"; import DeceasedRetail from "@/entity/DeceasedRetail"; import SeletedServiceList from "@/entity/SeletedServiceList"; import Deceased from "@/entity/Deceased"; import { handleError } from "@/util/globalMethods"; interface QueryParams { startDate?: string; endDate?: string; serviceName?: string; deceasedName?: string; pageSize?: number; pageNumber?: number; guide?: string; familyName: string; } interface SalesDetailItem { id: string; checkoutDate: string; deceasedName: string; gender: string; age: number; idCard: string; contactPerson: string; contactPhone: string; serviceName: string; price: number; quantity: number; amount: number; remark: string; } export const getSalesDetails = async (req: Request, res: Response) => { try { const params = parseQueryParams( req.method === "GET" ? req.query : req.body ); const pageSize = Number(params.pageSize) || 10; const pageNumber = Number(params.pageNumber) || 1; // 第一步:查询 SeletedServiceList 和 DeceasedRetail const initialQuery = getRepository(SeletedServiceList) .createQueryBuilder("ssl") .innerJoinAndMapOne( "ssl.deceasedRetail", DeceasedRetail, "dr", "FIND_IN_SET(ssl.id, dr.serviceItems) AND dr.retailState = 1 AND dr.cancelState = 0 " ); if (pageSize !== 999999999) { // 如果还没有连接 Deceased 表,需要确保连接 if ( (params.deceasedName || params.familyName) && !initialQuery.expressionMap.joinAttributes.some( (join) => join.alias.name === "d" ) ) { initialQuery.innerJoin(Deceased, "d", "d.id = dr.deceasedId"); } if (params.startDate || params.endDate) { initialQuery.andWhere("dr.checkoutDate BETWEEN :start AND :end", { start: params.startDate || dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss"), end: params.endDate || dayjs().format("YYYY-MM-DD HH:mm:ss"), }); } // 服务名称条件 if (params.serviceName) { initialQuery.andWhere("ssl.name LIKE :serviceName", { serviceName: `%${params.serviceName}%`, }); } if (params.guide) { initialQuery.andWhere("dr.guide LIKE :guide", { guide: `%${params.guide}%`, }); } // 逝者姓名条件 if (params.deceasedName) { initialQuery.andWhere( "( d.name LIKE :deceasedName OR (dr.deceasedId = 0 AND dr.deceasedName LIKE :deceasedName))", { deceasedName: `%${params.deceasedName}%`, } ); } // 逝者家属姓名条件 if (params.familyName) { initialQuery.andWhere( "( d.familyName LIKE :familyName OR (dr.deceasedId = 0 AND dr.familyName LIKE :familyName) )", { familyName: `%${params.familyName}%`, } ); } } // 执行初步查询 const initialResult = await initialQuery .orderBy("dr.checkoutDate", "DESC") .skip((pageNumber - 1) * pageSize) .take(pageSize) .getMany(); // 第二步:根据初步查询结果查询绑定 Deceased const deceasedIds = initialResult //@ts-ignore .map((item) => item.deceasedRetail?.deceasedId) .filter((id) => id !== undefined && id !== 0); const deceasedMap = new Map(); if (deceasedIds.length > 0) { const deceasedList = await getRepository(Deceased) .createQueryBuilder("d") .where("d.id IN (:...ids)", { ids: deceasedIds }) .getMany(); deceasedList.forEach((deceased) => { deceasedMap.set(deceased.id, deceased); }); } // 合并结果 const result = initialResult.map((item) => { //@ts-ignore if (item.deceasedRetail?.deceasedId !== 0) { //@ts-ignore item.deceased = deceasedMap.get(item.deceasedRetail.deceasedId) || {}; } else { //@ts-ignore item.deceased = { ...item.deceasedRetail }; } return item; }); // 获取总记录数 const total = await initialQuery.getCount(); res.json({ code: 200, data: { list: result.map((item) => { return { ...item, // @ts-ignore sum: Number(item.price).toFixed(2) * Number(item.quantity), }; }), pageSize, pageNumber, total, }, }); } catch (error) { handleError(res, error); } }; const parseQueryParams = (query: any): QueryParams => { const { startDate, endDate, serviceName, deceasedName, guide, pageSize, pageNumber, familyName, } = query; const validateDate = (date: string, field: string) => { if (date && !dayjs(date).isValid()) { throw new Error(`${field}格式错误,请使用YYYY-MM-DD格式`); } }; validateDate(startDate, "开始日期"); validateDate(endDate, "结束日期"); return { startDate: startDate?.trim(), endDate: endDate?.trim(), serviceName: serviceName?.trim(), deceasedName: deceasedName?.trim(), guide: guide?.trim(), pageSize: pageSize ? parseInt(pageSize) : undefined, pageNumber: pageNumber ? parseInt(pageNumber) : undefined, familyName: familyName, }; };