911 lines
25 KiB
JavaScript
Raw Permalink Normal View History

2026-07-27 11:28:33 +08:00
const dayjs = require("dayjs");
const setCountText = require("./order-status");
const { ObjectId } = require("mongodb");
const unionPay = require("../union-pay");
module.exports = async (item, db) => {
const builded = process.env.IS_BUILDED === 'YES';
switch (item.statsType) {
case "order":
return await getOrderCount(item, db);
case "doctorOrder":
return await getDoctorOrderCount(item, db);
case "getStoreMatePadRxStats":
return await getStoreMatePadRxStats(item, db);
case "zyStoreRx":
return await getZyStoreRxCount(item, db);
// case "oldRx":
// return await getZyStoreAgeRxCount(item, db);
case "getPayStatus":
return await getHisPayStatus(item, db);
case "rxDurationStats":
return await getRxDurationStats(item, db);
case "drugStats":
return await getDrugStats(item, db);
case "createAlipayOrder":
return builded ? null : await createAlipayOrder(item, db);
case "queryAlipayOrder":
return await queryAlipayOrder(item, db);
case "refundAlipayOrder":
return builded ? null : await refundAlipayOrder(item, db);
case "fengniaoTest":
return await fengniaoTest(item, db);
case "emsTest":
return await emsTest(item, db);
case "hisTest":
return await hisTest(item, db);
case "lackTest":
return await lackTest(item, db);
case "purchaseTest":
return await purchaseTest(item, db);
case "testMedicineNotify":
return await testMedicineNotify(item, db);
case "tradeTest":
return await tradeTest(item, db);
case "unionTest":
// return await unionPay.main({ type: "refundUnionPayBill", billNo: '3JHR202604091344UN' , billDate: Date.now(), refundAmount: 100 });
// return await unionPay.main({ type: "getUnionPayQrcode", billNo: '3JHR202604091344UN' , billDate: Date.now(), totalAmount: 100 });
case "wineTest":
return await wineTest(item, db);
default:
return { success: false, message: "未知统计类型!!" };
}
};
function getDateRange({ dates }) {
console.log("dates", dates);
const dateArr =
typeof dates === "string"
? dates
.split(",")
.filter((i) => i && dayjs(i).isValid())
.map((i) => dayjs(i))
: [];
console.log("dateArr", dateArr);
const [dateStart = dayjs(), dateEnd = dayjs(dateStart)] = dateArr;
const minDate = dateStart.isBefore(dateEnd) ? dateStart : dateEnd;
const maxDate = dateStart.isBefore(dateEnd) ? dateEnd : dateStart;
if (Math.abs(minDate.diff(maxDate, "day")) > 30) {
return [
minDate.startOf("day").valueOf(),
minDate.add(31, "day").endOf("day").valueOf(),
];
}
console.log("minDate", minDate);
console.log("maxDate", maxDate);
return [minDate.startOf("day").valueOf(), maxDate.endOf("day").valueOf()];
}
async function getOrderCount(params, db) {
try {
const [startTime, endTime] = params;
const startTimeTemp = dayjs(startTime).startOf("day").valueOf();
const endTimeTemp = dayjs(endTime).endOf("day").valueOf();
const data = await db
.collection("consult-order")
.aggregate([
{ $match: { createTime: { $gte: startTimeTemp, $lte: endTimeTemp } } },
{
$group: {
_id: {
orderStatus: "$orderStatus",
payStatus: "$payStatus",
},
count: { $sum: 1 }, // 统计每个组合的数量
},
},
{
$project: {
_id: 0, // 如果不需要显示 _id
orderStatus: "$_id.orderStatus",
payStatus: "$_id.payStatus",
count: 1,
},
},
])
.toArray();
const res = setCountText(data);
const allCount = res.reduce((acc, cur) => acc + cur.count, 0);
return {
success: true,
message: "查询成功",
startDate: dayjs(startTime).format("YYYY-MM-DD HH:mm:ss"),
endDate: dayjs(endTime).format("YYYY-MM-DD HH:mm:ss"),
allCount: allCount,
data: res,
};
} catch (err) {
return { success: false, message: err.message };
}
}
async function getDoctorOrderCount(params, db) {
try {
const [startTime, endTime] = getDateRange(params);
const doctorCount = await db
.collection("hlw-doctor")
.countDocuments({ job: "doctor" });
const doctorList = await db
.collection("hlw-doctor")
.find(
{ job: "doctor" },
{ projection: { doctorName: 1, doctorNo: 1, _id: 0 } }
)
.toArray();
const data = await db
.collection("consult-order")
.aggregate([
{ $match: { createTime: { $gte: startTime, $lte: endTime } } },
{
$group: {
_id: {
orderStatus: "$orderStatus",
payStatus: "$payStatus",
doctorCode: "$doctorCode",
},
count: { $sum: 1 }, // 统计每个组合的数量
},
},
{
$project: {
_id: 0, // 如果不需要显示 _id
doctorCode: "$_id.doctorCode",
orderStatus: "$_id.orderStatus",
payStatus: "$_id.payStatus",
count: 1,
},
},
])
.toArray();
const res = setCountText(data, doctorList);
const allCount = res.reduce((acc, cur) => acc + (cur.allCount || 0), 0);
return {
success: true,
message: "查询成功",
startDate: dayjs(startTime).format("YYYY-MM-DD HH:mm:ss"),
endDate: dayjs(endTime).format("YYYY-MM-DD HH:mm:ss"),
allCount,
doctorCount,
statsCount: res.length,
data: res,
};
} catch (err) {
return { success: false, message: err.message };
}
}
async function getStoreCount(params, db) {
try {
let storeIds = [];
const [startTime, endTime] = getDateRange(params);
if (params.dataType === "storeOrder" || params.dataType === "storeRx") {
if (typeof params.area !== "string" || params.area.trim() === "") {
return { success: false, message: "区域不能为空" };
}
const stores = await db
.collection("store-list")
.find(
{ "region.2": params.area },
{ projection: { store_id: 1, _id: 0 } }
)
.toArray();
storeIds = stores.map((i) => i.store_id);
}
// 统计越城区药店的今日订单数量 start
if (params.dataType === "storeOrder") {
const storeOrderStats = await db
.collection("consult-order")
.aggregate([
{
$match: {
drugStoreNo: { $in: storeIds },
createTime: { $gte: startTime, $lte: endTime },
},
},
{
$group: {
_id: "$drugStoreNo",
drugStoreName: { $first: "$drugStoreName" },
count: { $sum: 1 }, // 统计每个组合的数量
},
},
])
.toArray();
const storeOrderRes = Array.from(storeOrderStats.values());
return storeOrderRes;
}
if (params.dataType === "storeRx") {
// 统计药店的处方数量 start
const orders = await db
.collection("consult-order")
.find(
{
drugStoreNo: { $in: storeIds },
createTime: { $gte: startTime, $lte: endTime },
},
{
projection: {
orderId: 1,
_id: 0,
drugStoreName: 1,
drugStoreNo: 1,
},
}
)
.toArray();
const orderIds = orders.map((i) => i.orderId);
const record = await db
.collection("diagnostic-record")
.aggregate([
{ $match: { orderId: { $in: orderIds }, status: "PASS" } },
{
$group: {
_id: "$orderId",
count: { $sum: 1 }, // 统计每个组合的数量
},
},
])
.toArray();
const om = record.reduce((acc, cur) => {
acc[cur._id] = cur.count;
return acc;
}, {});
const rxOrders = orders.filter((i) => om[i.orderId] > 0);
const storeRx = rxOrders.reduce((acc, cur) => {
const data = acc.get(cur.drugStoreNo) || {
drugStoreNo: cur.drugStoreNo,
drugStoreName: cur.drugStoreName,
count: 0,
};
data.count += 1;
acc.set(cur.drugStoreNo, data);
return acc;
}, new Map());
const storeRxRes = Array.from(storeRx.values());
// 统计不同类型药店的数据
const typeStore = storeRxRes.reduce(
(acc, cur) => {
if (cur.drugStoreName.startsWith("浙江震元")) {
acc.zy += cur.count;
} else {
acc.nzy += cur.count;
}
return acc;
},
{ zy: 0, nzy: 0 }
);
return { ...typeStore, storeRxRes };
}
if (params.dataType === "doctorRx") {
// 统计医生的处方数量 start
const doctorRx = await db
.collection("diagnostic-record")
.aggregate([
{
$match: {
createTime: { $gte: startTime, $lte: endTime },
status: "PASS",
_id: {
$nin: [
new ObjectId("67eca29fecce43c72c51d1e7"),
new ObjectId("67ecfe26ecce43c72c520ec7"),
],
},
},
},
{
$group: {
_id: "$doctorCode",
doctorName: { $first: "$doctorName" },
count: { $sum: 1 }, // 统计每个组合的数量
},
},
])
.toArray();
return doctorRx;
}
} catch (e) {
return { success: false, message: e.message };
}
}
async function getPeriodRxCount(params, db) {
const data =
params.date && dayjs(params.period).isValid()
? dayjs(params.date).format("YYYY-MM-DD")
: dayjs().format("YYYY-MM-DD");
try {
let time = dayjs().startOf("day").format("YYYY-MM-DD HH:mm:ss");
const group = [];
while (dayjs(time).isBefore(dayjs().endOf("day"))) {
group.push([
dayjs(time).valueOf(),
dayjs(time).add(30, "minutes").valueOf(),
]);
// group.push({ $match: { createTime: { $gte: dayjs(time).format('YYYY-MM-DD HH:mm:ss'), $lt: dayjs(time).add(30, 'minutes').format('YYYY-MM-DD HH:mm:ss') }, status: 'PASS' } })
time = dayjs(time).add(30, "minutes").format("YYYY-MM-DD HH:mm:ss");
}
const result = [];
for (let [start, end] of group) {
const total = await db.collection("diagnostic-record").countDocuments({
createTime: { $gte: start, $lt: end },
status: "PASS",
});
result.push({
start: dayjs(start).format("YYYY-MM-DD HH:mm:ss"),
end: dayjs(end).format("YYYY-MM-DD HH:mm:ss"),
total,
});
}
return result;
} catch (e) {
return { success: false, message: e.message };
}
}
async function getStoreMatePadRxStats(params, db) {
const [startTime, endTime] = getDateRange(params);
try {
const res = await db
.collection("diagnostic-record")
.aggregate([
{
$match: {
orderSource: "MATEPAD",
createTime: { $gte: startTime, $lte: endTime },
status: "PASS",
},
},
{
$group: {
_id: "$drugStoreNo",
count: { $sum: 1 },
},
},
])
.toArray();
const stores = await db
.collection("store-list")
.find(
{ store_id: { $in: res.map((i) => i._id) } },
{ projection: { store_id: 1, name: 1, _id: 0 } }
)
.toArray();
return { success: true, data: res, stores };
} catch (e) {
return { success: false, message: e.message };
}
}
async function getZyStoreRxCount(ctx, db) {
const [startTime, endTime, storeType, source] = getDateRange(ctx);
const storeTypes = storeType === "other" ? ["其他"] : ["加盟", "直营"];
try {
const stores = await db
.collection("store-list")
.find(
{ type: { $in: storeTypes } },
{ projection: { store_id: 1, name: 1, _id: 0 } }
)
.toArray();
const storeIds = stores.map((i) => i.store_id);
const m = stores.reduce((acc, cur) => {
// console.log(cur.store_id, cur.name)
acc.set(cur.store_id, cur.name);
return acc;
}, new Map());
const matches = {
drugStoreNo: { $in: storeIds },
createTime: { $gte: startTime, $lte: endTime },
status: "PASS",
};
if (source) {
matches.orderSource = source;
}
const res = await db
.collection("diagnostic-record")
.aggregate([
{ $match: matches },
{
$addFields: {
date: {
$dateToString: {
format: "%Y-%m-%d",
date: { $toDate: "$createTime" },
timezone: "Asia/Shanghai", // 设置为中国标准时间
},
},
},
},
{
$group: {
_id: { date: "$date", id: "$drugStoreNo" },
date: { $first: "$date" },
drugStoreNo: { $first: "$drugStoreNo" },
count: { $sum: 1 },
},
},
{
$project: {
_id: 0,
date: 1,
drugStoreNo: 1,
count: 1,
},
},
])
.toArray();
res.forEach((i) => {
i.name = m.get(i.drugStoreNo) || "";
});
return res;
} catch (e) {
return { success: false, message: e.message };
}
}
async function getZyStoreAgeRxCount(ctx, db) {
const [startTime, endTime] = getDateRange(ctx);
try {
const query = { createTime: { $gte: startTime, $lte: endTime } };
if (ctx.ageType === "old") {
query.age = { $gte: 70 };
} else {
query.age = { $lt: 70 };
}
const orders = await db
.collection("consult-order")
.find(query, { projection: { orderId: 1, _id: 0 } })
.toArray();
const orderIds = orders.map((i) => i.orderId);
const rxCountGroup = await db
.collection("diagnostic-record")
.aggregate([
{
$match: {
createTime: { $gte: startTime, $lte: endTime },
status: "PASS",
orderId: { $in: orderIds },
},
},
{
$group: {
_id: "$drugStoreNo",
drugStoreNo: { $first: "$drugStoreNo" },
count: { $sum: 1 },
},
},
])
.toArray();
const stores = await db
.collection("store-list")
.find(
{ store_id: { $in: rxCountGroup.map((i) => i.drugStoreNo) } },
{ projection: { store_id: 1, name: 1, _id: 0, type: 1, region: 1 } }
)
.toArray();
const m = stores.reduce((acc, cur) => {
acc.set(cur.store_id, cur);
return acc;
}, new Map());
rxCountGroup.forEach((i) => {
const store = m.get(i.drugStoreNo) || null;
if (store) {
i.name = store.name || "";
i.type = store.type || "";
i.area = Array.isArray(store.region) ? store.region[2] : "";
} else {
i.name = "";
i.type = "";
i.area = "";
}
});
return rxCountGroup;
} catch (e) {
return { success: false, message: e.message };
}
}
async function getHisPayStatus(ctx) {
// patientId, registerId, medorgOrderNo
const { patientId, registerId } = ctx;
const hisApi = require("../zyt-his");
const res = await hisApi({
type: "getPayStatus",
patientId,
registerId,
medorgOrderNo: registerId,
});
if (res.success) {
return { success: true, data: res };
} else {
return { success: false, message: res.message || "查询失败" };
}
}
async function refundFee(ctx) {
// patientId, registerId, medorgOrderNo
const { patientId, registerId } = ctx;
const hisApi = require("../zyt-his");
const res = await hisApi({
type: "hlwRefund",
patientId,
registerId,
medorgOrderNo: registerId,
});
if (res.success) {
return { success: true, data: res };
} else {
return { success: false, message: res.message || "查询失败" };
}
}
async function getRxDurationStats(params, db) {
const { startTime, endTime } = params;
const startTimeTemp = dayjs(startTime).startOf("day").valueOf();
const endTimeTemp = dayjs(endTime).endOf("day").valueOf();
const pipeline = [
{
$match: {
// age: { $gte: 60 },
createTime: { $gte: startTimeTemp, $lte: endTimeTemp },
},
},
{
$project: {
orderId: 1,
_id: 0,
},
},
{
$lookup: {
from: "hlw-doctor-times",
localField: "orderId",
foreignField: "orderId",
as: "doctorTimes",
},
},
{
$unwind: {
path: "$doctorTimes",
preserveNullAndEmptyArrays: false,
},
},
{
$match: {
"doctorTimes.rxDuration": { $gt: 0 },
},
},
// 6. 计算统计信息
{
$group: {
_id: null,
totalCount: { $sum: 1 },
avgDuration: { $avg: "$doctorTimes.rxDuration" },
minDuration: { $min: "$doctorTimes.rxDuration" },
maxDuration: { $max: "$doctorTimes.rxDuration" },
durations: { $push: "$doctorTimes.rxDuration" },
},
},
];
const result = await db
.collection("consult-order")
.aggregate(pipeline)
.toArray();
if (result.length === 0) {
return {
success: true,
message: "查询成功",
startDate: dayjs(startTime).format("YYYY-MM-DD HH:mm:ss"),
endDate: dayjs(endTime).format("YYYY-MM-DD HH:mm:ss"),
totalOrders: 0,
stats: {
totalCount: 0,
avgDuration: 0,
minDuration: 0,
maxDuration: 0,
durationRanges: [],
},
};
}
const stats = result[0];
const durations = stats.durations;
// 按时长范围分组统计
const durationRanges = [
{ range: "0-30s", min: 0, max: 30000, count: 0 },
{ range: "30s-1分钟", min: 30000, max: 60000, count: 0 },
{ range: "1分钟-2分钟", min: 60000, max: 120000, count: 0 },
{ range: "2-3分钟", min: 120000, max: 180000, count: 0 },
{ range: "3分钟以上", min: 180000, max: Infinity, count: 0 },
];
durations.forEach((duration) => {
const range = durationRanges.find(
(r) => duration >= r.min && duration < r.max
);
if (range) {
range.count++;
}
});
return {
success: true,
message: "查询成功",
startDate: dayjs(startTime).format("YYYY-MM-DD HH:mm:ss"),
endDate: dayjs(endTime).format("YYYY-MM-DD HH:mm:ss"),
totalOrders: stats.totalCount,
stats: {
totalCount: stats.totalCount,
avgDuration: Math.round(stats.avgDuration),
minDuration: stats.minDuration,
maxDuration: stats.maxDuration,
durationRanges: durationRanges.filter((range) => range.count > 0),
},
};
}
async function getDrugStats(params, db) {
const { startTime, endTime } = params;
const startTimeTemp = dayjs(startTime).startOf("day").valueOf();
const endTimeTemp = dayjs(endTime).endOf("day").valueOf();
// 先检查基础数据
const baseCount = await db.collection("consult-order").countDocuments({
age: { $gte: 60 },
createTime: { $gte: startTimeTemp, $lte: endTimeTemp },
});
console.log("基础订单数量 (age >= 60):", baseCount);
const pipeline = [
{
$match: {
age: { $gte: 60 },
createTime: { $gte: startTimeTemp, $lte: endTimeTemp },
},
},
{
$project: {
orderId: 1,
},
},
{
$lookup: {
from: "diagnostic-record",
localField: "orderId",
foreignField: "orderId",
as: "diagnosticRecords",
},
},
{
$unwind: {
path: "$diagnosticRecords",
preserveNullAndEmptyArrays: false,
},
},
{
$match: {
"diagnosticRecords.status": "PASS",
},
},
// 调试:检查诊断记录数量
{
$addFields: {
debug_drugs_count: {
$size: { $ifNull: ["$diagnosticRecords.drugs", []] },
},
},
},
{
$unwind: {
path: "$diagnosticRecords.drugs",
preserveNullAndEmptyArrays: false,
},
},
{
$group: {
_id: {
drugName: "$diagnosticRecords.drugs.drugName",
insuranceCode: "$diagnosticRecords.drugs.insurance_code",
productId: "$diagnosticRecords.drugs.product_id",
specification: "$diagnosticRecords.drugs.specification",
unit: "$diagnosticRecords.drugs.unit",
},
totalQuantity: { $sum: "$diagnosticRecords.drugs.quantity" },
prescriptionCount: { $sum: 1 },
drugInfo: { $first: "$diagnosticRecords.drugs" },
},
},
// 8. 格式化输出
{
$project: {
_id: 0,
drugName: "$_id.drugName",
insuranceCode: "$_id.insuranceCode",
productId: "$_id.productId",
specification: "$_id.specification",
unit: "$_id.unit",
totalQuantity: 1,
prescriptionCount: 1,
drugInfo: 1,
},
},
// 9. 按总数量降序排序
{
$sort: {
totalQuantity: -1,
},
},
// 10. 限制返回前30条记录
{
$limit: 30,
},
];
const result = await db
.collection("consult-order")
.aggregate(pipeline)
.toArray();
console.log("聚合结果数量:", result.length);
console.log("前3条结果:", result.slice(0, 3));
// 计算总统计信息
const totalPrescriptions = result.reduce(
(sum, item) => sum + item.prescriptionCount,
0
);
const totalQuantity = result.reduce(
(sum, item) => sum + item.totalQuantity,
0
);
return {
success: true,
message: "查询成功",
startDate: dayjs(startTime).format("YYYY-MM-DD HH:mm:ss"),
endDate: dayjs(endTime).format("YYYY-MM-DD HH:mm:ss"),
summary: {
totalPrescriptions, // 总处方次数
totalDrugTypes: result.length, // 药品种类数前30
totalQuantity, // 总药品数量(盒数)
},
data: result, // Top30 药品统计,按数量降序排列
};
}
async function createAlipayOrder() {
try {
const tradeApi = require("../trade");
const payload = {
totalAmount: 0.02,
businessNo: dayjs().valueOf().toString(),
businessType: 'onlineMedicinePurchase',
desc: `[${dayjs().format('YYYY-MM-DD HH:mm:ss')}] 线上购药订单测试`,
openId: '2088612594454930'
}
const { success, message, tradeNo } = await tradeApi.getAlipayTradeNo(payload);
if (success) {
return { success: true, message: '创建交易订单成功', tradeNo: tradeNo };
} else {
return { success: false, message: message };
}
} catch (e) {
return { success: false, message: e.message };
}
}
async function queryAlipayOrder(data) {
try {
const tradeApi = require("../trade");
const { success, message, data: tradeInfo } = await tradeApi.queryAlipayTradeNo(data);
if (success) {
return { success: true, message: '查询交易订单成功', data: tradeInfo };
} else {
return { success: false, message: message };
}
} catch (e) {
return { success: false, message: e.message };
}
}
async function refundAlipayOrder(data) {
try {
const tradeApi = require("../trade");
console.log(`申请退费: ${data.tradeNo}`)
const res = await tradeApi.refundTrade({ tradeNo: data.tradeNo, reason: `${dayjs().format('YYYY-MM-DD HH:mm:ss')} 用户申请退款` });
return res
} catch (e) {
return { success: false, message: e.message };
}
}
async function fengniaoTest(ctx) {
try {
const fengniaoApi = require("../fengniao");
const res = await fengniaoApi.fengniaoTest(ctx);
return { success: true, data: res }
} catch (e) {
return { success: false, message: e.message }
}
}
async function emsTest() {
try {
const emsApi = require("../ems-express");
const res = await emsApi.emsTest();
return { success: true, data: res }
} catch (e) {
return { success: false, message: e.message }
}
}
async function hisTest() {
const hisApi = require("../zyt-his");
const res = await hisApi({
type: "hisTest"
});
return { success: true, data: res }
}
async function lackTest(item, db) {
try {
const lackApi = require("../lack-medicine-reg");
const res = await lackApi({
type: "lackTest"
}, db);
return { success: true, data: res }
} catch (e) {
return { success: false, message: e.message }
}
}
async function wineTest(item, db) {
try {
const api = require("../chinese-medicine-order");
return await api.main({
type: "wineTest"
}, db);
} catch (e) {
return { success: false, message: e.message }
}
}
async function purchaseTest(item, db) {
try {
const purchaseApi = require("../medicine-purchase-order");
const res = await purchaseApi({
type: "purchaseTest"
}, db);
return { success: true, data: res }
} catch (e) {
return { success: false, message: e.message }
}
}
async function testMedicineNotify(item, db) {
try {
const purchaseApi = require("../medicine-purchase-order");
return await purchaseApi({
type: "testMedicineNotify"
}, db);
} catch (e) {
return { success: false, message: e.message }
}
}
async function tradeTest(item, db) {
try {
const tradeApi = require("../trade");
const res = await tradeApi.tradeTest();
return { success: true, data: res }
} catch (e) {
return { success: false, message: e.message }
}
}