2026-07-27 11:28:33 +08:00

2143 lines
65 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const common = require("../../common");
const zytHis = require("../zyt-his");
const dayjs = require("dayjs");
const { getConfig } = require("../utils/config");
const tencentIM = require("../tencent-im");
const trigger = require("./trigger");
const { ObjectId } = require("mongodb");
const timeApi = require("../hlw-time-duration");
const { encryptOrderFields, decryptOrderFields, decryptOrderList } = require("./format");
const hisPayStatus = {
0: "已支付",
1: "已退费",
5: "未支付",
x: "已作废",
};
const refundStatus = {
INIT: "未处理",
PASS: "已通过",
REJECT: "已拒绝",
};
const RefundOrderScene = {
DOCTORAGREEREFUND: "患者已退费",
OFFLINEREFUND: "患者线下已退费",
}; // 咨询订单退费场景
const ConsultTypeByFeeType = {
YB: "onlineConsult",
ZF: "onlineConsult",
};
let db = "";
module.exports = async (item, mongodb) => {
db = mongodb;
switch (item.type) {
case "addConsultOrder":
return await addConsultOrder(item);
case "addDrugStoreConsultOrder":
return await addDrugStoreConsultOrder(item);
case "getPatientOrder":
return await getPatientOrder(item);
case "getPatientOrderList":
return await getPatientOrderList(item);
case "getDrugStoreOrderList":
return await getDrugStoreOrderList(item);
case "deleteConsultOrder":
return await deleteConsultOrder(item);
case "updateConsultOrder":
return await updateConsultOrder(item);
case "getConsultOrder":
return await getConsultOrder(item);
case "updateConsultOrderStatus":
return await updateConsultOrderStatus(item);
case "refundConsultOrder":
return await refundConsultOrder(item);
case "acceptConsultOrder":
return await acceptConsultOrder(item);
case "completeConsultOrder":
return await completeConsultOrder(item);
case "finishConsultOrder":
return await finishConsultOrder(item);
case "startConsultOrder":
return await startConsultOrder(item);
case "refreshOrderPayStatus":
return await refreshOrderPayStatus(item);
case "cancelConsultOrder":
return await cancelConsultOrder(item);
case "doctorHasPendingOrder":
return await doctorHasPendingOrder(item);
case "refundFeeAndOrder":
return await refundFeeAndOrder(item);
case "serviceFinishConsultOrder":
return await serviceFinishConsultOrder(item);
case "getHisStoreRegList":
return await getHisStoreRegList(item);
case "validHlwOrderConfig":
return await validHlwOrderConfig(item);
case "customerRefundOrder":
return await customerRefundOrder(item);
case "getOrderPatientList":
return await getOrderPatientList(item);
case "getHlwOrderList":
return await getHlwOrderList(item);
case "applyRefundOrder":
return await applyRefundOrder(item);
case "getRefundOrderList":
return await getRefundOrderList(item);
case "handleRefundOrder":
return await handleRefundOrder(item);
case "autoHandleExpireOrder":
return await autoHandleExpireOrder(item);
default:
return {
success: false,
message: "请求失败!",
};
}
};
let scheduleTaskIsRunning = false;
// 咨询订单库 数据库是 consult-order
async function addConsultOrder(item) {
let { params, corpId } = item;
if (!['YB', 'ZF'].includes(params.feeType)) {
return { success: false, message: "费用类型不支持" };
}
params.feeType = params.feeType;
params.orderId = common.generateUniqueStr('WZ');
params.createTime = Date.now();
params.orderStatus = "pending";
params.payStatus = "success";
params.corpId = corpId;
params.orderSource = "ALIPAY_MINI"; // 支付宝小程序
params.doctorCode = params.doctorCode.trim();
return await addOnlineConsultOrder(params);
}
async function addOnlineConsultOrder(params) {
try {
params.registerId = common.generateUniqueStr('GH');
const res1 = await getConfig(params.corpId);
if (!res1) {
return { success: false, message: "未查询到配置信息" };
}
const { autoAcceptOrder, consultationDuration } = res1 || {};
if (typeof autoAcceptOrder !== 'boolean' || !(Number.isInteger(consultationDuration) && consultationDuration > 0)) {
return { success: false, message: "咨询配置错误" };
}
if (autoAcceptOrder) {
params.orderStatus = "processing";
params.expireTime = dayjs().add(consultationDuration, "minute").valueOf();
}
params.drugStoreId = 'HN000001';
if (!params.drugStoreId) {
return { success: false, message: "药房信息缺失" };
}
const storeApi = require("../drug-store");
const { success, list, message } = await storeApi(
{
type: "getDrugStoreList",
storeId:
typeof params.drugStoreId === "string" ? params.drugStoreId : "",
pageSize: 1,
},
db
);
if (!success) {
return { success, message };
}
const store = Array.isArray(list) ? list[0] : null;
const chargeItem =
store && Array.isArray(store.chargeItems) ? store.chargeItems[0] : null;
if (!store) {
return { success: false, message: "为查询到药房信息" };
}
if (!chargeItem || !chargeItem.code) {
return { success: false, message: "当前药房未配置互联网诊查费" };
}
params.chargeCode = chargeItem.code;
params.chargeFee = chargeItem.fee;
params.drugStoreName = store.name;
params.drugStoreNo = store.login_no;
const doctorCode = params.doctorCode.trim();
// 指定医生
if (doctorCode) {
const doctor = await db.collection("hlw-doctor").findOne(
{ doctorNo: doctorCode, job: "doctor" },
{
projection: {
doctorNo: 1,
doctorName: 1,
title: 1,
deptName: 1,
deptCode: 1,
onlineStatus: 1,
},
}
);
if (!doctor) {
return { success: false, message: "未查询到医生" };
}
if (doctor.onlineStatus !== "online") {
return { success: false, message: "医生未在线, 请重新选择医生" };
}
params.doctorName = doctor.doctorName || "";
params.doctorTitle = doctor.title || "";
params.deptName = doctor.deptName || "";
params.unitCode = doctor.deptCode || "";
params.doctorCode = doctor.doctorNo;
} else {
// 随机选取一位医生 (单量少的权重大)
const doctorApi = require("../hlw-doctor");
const data = await doctorApi({ type: "getOptimalRecommendDoctor", doctorType: 'west' }, db);
if (data.success && data.data) {
params.doctorName = data.data.doctorName || "";
params.doctorCode = data.data.doctorNo;
params.doctorTitle = data.data.title || "";
params.deptName = data.data.deptName || "";
params.unitCode = data.data.deptCode || "";
} else {
return { success: false, message: data.message };
}
}
params.medorg_order_no = common.generateUniqueStr('HLW', 12);
// 加密敏感字段
const encryptedParams = encryptOrderFields(params);
const { insertedId } = await db
.collection("consult-order")
.insertOne(encryptedParams);
if (insertedId) {
return {
success: true,
message: "新增成功",
data: {
orderId: params.orderId,
registerId: params.registerId,
medorg_order_no: params.medorg_order_no,
doctorCode: params.doctorCode,
doctorName: params.doctorName,
doctorTitle: params.doctorTitle,
deptName: params.deptName,
deptCode: params.unitCode,
},
}
}
return {
success: false,
message: "新增失败",
};
} catch (e) {
return { success: false, message: `新增在线复诊订单失败: ${e.message}` }
}
}
async function addOnlineMedicinePurchaseOrder(params) {
try {
// 线上购药订单 先咨询 后连同药费一起收取
params.drugStoreId = undefined;
params.payStatus = "success";
params.medorg_order_no = common.generateUniqueStr('HLW', 12);
if (typeof params.doctorCode === "string" && params.doctorCode.trim() !== "") {
const doctor = await db.collection("hlw-doctor").findOne(
{ doctorNo: params.doctorCode.trim(), job: "doctor" },
{
projection: {
doctorNo: 1,
doctorName: 1,
title: 1,
deptName: 1,
deptCode: 1,
onlineStatus: 1,
},
}
);
if (!doctor) {
return { success: false, message: "未查询到医生" };
}
if (doctor.onlineStatus !== "online") {
return { success: false, message: "医生未在线, 请重新选择医生" };
}
params.doctorName = doctor.doctorName || "";
params.doctorTitle = doctor.title || "";
params.deptName = doctor.deptName || "";
params.unitCode = doctor.deptCode || "";
params.doctorCode = doctor.doctorNo;
} else {
// 随机选取一位医生 (单量少的权重大)
const doctorApi = require("../hlw-doctor");
const data = await doctorApi({ type: "getOptimalRecommendDoctor", doctorType: 'west' }, db);
if (data.success && data.data) {
params.doctorName = data.data.doctorName || "";
params.doctorCode = data.data.doctorNo;
params.doctorTitle = data.data.title || "";
params.deptName = data.data.deptName || "";
params.unitCode = data.data.deptCode || "";
} else {
return { success: false, message: data.message };
}
}
const encryptedParams = encryptOrderFields(params);
const { insertedId } = await db
.collection("consult-order")
.insertOne(encryptedParams);
return {
success: true,
message: "新增线上购药订单成功",
data: {
orderId: params.orderId,
doctorCode: params.doctorCode,
doctorName: params.doctorName,
doctorTitle: params.doctorTitle,
deptName: params.deptName,
deptCode: params.unitCode,
},
};
} catch (e) {
return { success: false, message: `新增线上购药订单失败: ${e.message}` }
}
}
async function addDrugStoreConsultOrder(ctx) {
const { params } = ctx;
const { registerId, consultType = 'onlineConsult' } = params || {};
if (!registerId) {
return {
success: false,
message: "参数错误",
};
}
if (!['onlineConsult', 'wineConsult'].includes(consultType)) {
return { success: false, message: '咨询类型错误' }
}
try {
const total = await db.collection("consult-order").countDocuments({
registerId,
});
if (total > 0) {
return {
success: false,
message: "当前挂号已存在订单",
};
}
const { status, settlement } = await zytHis({
type: "getPayStatus",
patientId: params.patientId,
registerId,
medorgOrderNo: registerId,
});
if (status !== "0") {
return {
success: false,
message: hisPayStatus[status]
? `当前挂号${hisPayStatus[status]}`
: "查询当前挂号支付状态失败",
};
}
const orderId = common.generateUniqueStr('WZ');
params.settlement = settlement;
params.createTime = Date.now();
params.orderId = orderId;
params.orderStatus = "pending";
params.payStatus = "success";
params.medorg_order_no = registerId;
params.orderSource = "MATEPAD"; // 门店pad
params.consultType = consultType;
if (ctx.corpId) {
params.corpId = ctx.corpId;
}
const doctor = await db.collection("hlw-doctor").findOne(
{
doctorNo: typeof params.doctorCode === "string" ? params.doctorCode : "",
job: "doctor",
},
{ projection: { _id: 0, onlineStatus: 1, offlineTime: 1, doctorName: 1, title: 1, deptName: 1, deptCode: 1 } }
);
if (!doctor) {
return { success: false, message: "未查询到挂号医生" };
}
if (doctor.onlineStatus !== "online") {
const offlineTime = typeof doctor.offlineTime === 'number' ? doctor.offlineTime : 0;
const tenMinutesLater = offlineTime + 10 * 60 * 1000;
if (!offlineTime || Date.now() > tenMinutesLater) {
return { success: false, message: "医生已下线。请联系门店工作人员退号,如需继续就诊请重新挂号。" };
}
}
if (params.consultType === 'wineConsult') {
const wineUtil = require('./wine-consult');
params.wines = await wineUtil.getConsultWines(params.wines, db);
}
// 加密敏感字段
const encryptedParams = encryptOrderFields(params);
const { insertedId } = await db
.collection("consult-order")
.insertOne(encryptedParams);
return {
success: true,
message: "新增成功",
data: {
orderId,
registerId: params.registerId,
insertedId,
medorg_order_no: params.registerId,
},
};
} catch (e) {
return {
success: false,
message: e.message || "新增失败",
};
}
}
async function cancelConsultOrder(item) {
const { orderId, corpId } = item;
if (
typeof orderId !== "string" ||
orderId.trim() === "" ||
typeof corpId !== "string" ||
corpId.trim() === ""
) {
return { success: false, message: "参数错误" };
}
try {
const order = await db
.collection("consult-order")
.findOne(
{ orderId, corpId },
{ projection: { patientId: 1, payStatus: 1, registerId: 1 } }
);
if (!order) {
return { success: false, message: "订单不存在" };
}
if (order.payStatus !== "pending") {
return { success: false, message: "当前订单不可取消" };
}
const { patientId, registerId } = order;
const res1 = await zytHis({
type: "getPayStatus",
patientId,
registerId,
});
if (!res1 || !res1.success) {
return {
success: false,
message: res1.message || "查询订单支付状态失败",
};
}
if (res1.status === "0") {
const res2 = await zytHis({
type: "hlwRefund",
patientId,
registerId,
});
if (!res2 || !res2.success) {
return { success: false, message: res2.message || "取消订单失败" };
}
}
// 获取订单
const res = await db.collection("consult-order").updateOne(
{ orderId, corpId },
{
$set: {
orderStatus: "cancelled",
payStatus: "cancelled",
payResult: "用户取消订单",
updateTime: Date.now(),
},
}
);
return {
success: true,
message: "取消成功",
data: res,
};
} catch (error) {
return {
success: false,
message: error.message || "取消失败",
};
}
}
async function getPatientOrder(item) {
const { orderId } = item;
if (!orderId) {
return {
success: false,
message: "参数错误",
};
}
try {
const [data] = await db
.collection("consult-order")
.aggregate([
{ $match: { orderId: orderId } },
{
$lookup: {
from: "diagnostic-record", // 连接到 diagnostic-record 集合
localField: "orderId", // consult-order 集合中的 orderId 字段
foreignField: "orderId", // diagnostic-record 集合中的 orderId 字段
as: "diagnostic", // 返回的联接结果存储在 diagnostic 字段中
},
},
{
$addFields: {
diagnostic: {
$filter: {
input: "$diagnostic",
as: "diagnosticRecord",
cond: { $eq: ["$$diagnosticRecord.status", "PASS"] },
},
},
},
},
{
$addFields: {
hasPassDiagnostic: { $gt: [{ $size: "$diagnostic" }, 0] },
},
},
{
$project: {
diagnostic: 0, // 排除 diagnostic 字段
},
},
{
$limit: 1,
},
])
.toArray();
if (
data &&
data.payExpireTime < Date.now() &&
data.payStatus === "pending"
) {
data.payStatus = "expired";
data.payResult = "超时未支付";
}
if (
data &&
["processing", "pending", "completed"].includes(data.orderStatus) &&
data.expireTime < Date.now()
) {
data.orderStatus = "cancelled";
}
// 解密敏感字段
const decryptedData = data ? decryptOrderFields(data) : data;
return {
success: true,
data: decryptedData,
message: "查询成功",
};
} catch (err) {
return {
success: false,
message: err.message || "查询失败",
};
}
}
async function getDrugStoreOrderList(ctx) {
const { storeId, name } = ctx;
if (typeof storeId !== "string" || storeId.trim() === "") {
return { success: false, message: "店铺id不能为空" };
}
const page = parseInt(ctx.page) > 0 ? parseInt(ctx.page) : 1;
const pageSize = parseInt(ctx.pageSize) > 0 ? parseInt(ctx.pageSize) : 20;
const date =
ctx.date && dayjs(ctx.date).isValid() ? dayjs(ctx.date) : dayjs();
const createTime = {
$gte: date.startOf("day").valueOf(),
$lte: date.endOf("day").valueOf(),
};
try {
const query = {
drugStoreNo: storeId.trim(),
createTime,
orderSource: "MATEPAD",
};
if (typeof name == "string" && name.trim() !== "") {
query.$or = [
{ name: { $regex: name.trim(), $options: "i" } },
{ doctorName: { $regex: name.trim(), $options: "i" } },
];
}
const list = await db
.collection("consult-order")
.aggregate([
{ $match: query },
{ $sort: { createTime: -1 } },
{ $skip: (page - 1) * pageSize },
{ $limit: pageSize },
{
$lookup: {
from: "diagnostic-record", // 连接到 diagnostic-record 集合
localField: "orderId", // consult-order 集合中的 orderId 字段
foreignField: "orderId", // diagnostic-record 集合中的 orderId 字段
as: "diagnostic", // 返回的联接结果存储在 diagnostic 字段中
},
},
{
$addFields: {
diagnostic: {
$filter: {
input: "$diagnostic",
as: "diagnosticRecord",
cond: { $eq: ["$$diagnosticRecord.status", "PASS"] },
},
},
},
},
{
$addFields: {
hasPassDiagnostic: { $gt: [{ $size: "$diagnostic" }, 0] },
},
},
])
.toArray();
const total = await db.collection("consult-order").countDocuments(query);
const todayCount = await db.collection("consult-order").countDocuments({
drugStoreNo: storeId.trim(),
createTime: {
$gte: dayjs().startOf("day").valueOf(),
$lte: dayjs().endOf("day").valueOf(),
},
orderSource: "MATEPAD",
});
// 解密列表中的敏感字段
const decryptedList = decryptOrderList(list);
return {
success: true,
list: decryptedList,
total,
page,
pageSize,
todayCount,
pages: Math.ceil(total / pageSize),
message: "查询成功",
};
} catch (e) {
return {
success: false,
message: e.message || "查询失败",
};
}
}
async function acceptConsultOrder(item) {
const { orderId, corpId, doctorCode } = item;
try {
const item = await db.collection("consult-order").findOne(
{ orderId },
{
projection: {
expireTime: 1,
createTime: 1,
doctorCode: 1,
orderStatus: 1,
doctorName: 1,
},
}
);
if (!item) {
return { success: false, message: "订单不存在" };
}
if (
dayjs().startOf("day").valueOf() > item.expireTime ||
dayjs().startOf("day").valueOf() > item.createTime
) {
return { success: false, message: "订单已过期,请刷新" };
}
if (item.orderStatus !== "pending") {
return { success: false, message: "订单已失效,请刷新" };
}
const { consultationDuration } = await getConfig(corpId);
const expireTime = dayjs().add(consultationDuration, "minute").valueOf();
await updateConsultOrderStatus({
orderId,
orderStatus: "processing",
expireTime,
doctorCode: item.doctorCode,
corpId,
});
timeApi(
{
type: "addDoctorOrderDuration",
doctorCode: item.doctorCode,
doctorName: item.doctorName,
orderId,
createTime: item.createTime,
},
db
);
// 后端自动生成并保存处方开始时间(毫秒),由服务器记录接单时间点
let serverPrescriptionStartTime = null;
try {
serverPrescriptionStartTime = Date.now();
await db.collection("consult-order").updateOne(
{ orderId },
{
$set: {
prescriptionStartTime: serverPrescriptionStartTime,
updateTime: Date.now(),
},
}
);
} catch (e) {
console.error(
"保存 prescriptionStartTime 到 consult-order 失败",
e && e.message
);
// 保持 serverPrescriptionStartTime 的值(可能为 null 如果 Date.now() 未赋值),以便返回给调用者以作判断
}
// 接受问诊 发送系统消息
await tencentIM({
type: "sendSystemNotification",
formAccount: orderId,
toAccount: doctorCode,
SyncOtherMachine: 1,
corpId,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "ACCEPTCONSULT",
Ext: "您已接诊了患者发起的图文问诊服务,请及时回复处理。感谢您的辛勤付出!",
},
},
],
});
// 删除定时任务
await trigger({
type: "deleteDelayedTask",
triggerTaskId: orderId,
corpId,
});
// 从新建一个定时任务
await trigger({
type: "createDelayedTask",
triggerTaskId: orderId,
endTime: expireTime,
corpId,
});
return {
success: true,
message: "接诊成功",
expireTime,
serverPrescriptionStartTime,
};
} catch (err) {
return {
success: false,
message: "接诊失败",
};
}
}
// 结束问诊
async function finishConsultOrder(item) {
// 判断是否有正在审核的单子
const count = await db.collection("diagnostic-record").countDocuments({
orderId: item.orderId,
status: "INIT",
});
if (count > 0) {
return {
success: false,
message: "存在正在审核的诊断单,不能结束咨询",
};
}
return await serviceFinishConsultOrder(item);
}
async function serviceFinishConsultOrder(item) {
let { orderId, doctorCode, corpId } = item;
try {
// 获取订单
if (!doctorCode || !corpId) {
const order = await db.collection("consult-order").findOne({ orderId });
doctorCode = order.doctorCode;
corpId = order.corpId;
if (
order.orderStatus === "finished" ||
order.orderStatus === "cancelled"
) {
return {
success: false,
message: "订单已结束",
};
}
}
// 更新订单状态
await closeConsultOrder({ orderId, corpId, doctorCode });
await setDiagnosticExpired({ orderId });
return {
success: true,
message: "完成成功",
};
} catch (error) {
return {
success: false,
message: "完成失败",
};
}
}
async function closeConsultOrder({ orderId, doctorCode, corpId }) {
// 删除定时任务
await trigger({
type: "deleteDelayedTask",
triggerTaskId: orderId,
});
await tencentIM({
type: "sendSystemNotification",
formAccount: doctorCode,
toAccount: orderId,
SyncOtherMachine: 1,
corpId,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "FINISHED",
Ext: "本次问诊已结束,不能继续发消息。",
},
},
],
});
await updateConsultOrderStatus({
orderId,
orderStatus: "finished",
doctorCode,
corpId,
});
}
// 完成订单
async function completeConsultOrder(item) {
let { orderId, doctorCode, sendText, corpId } = item;
try {
// 获取订单
if (doctorCode) {
const order = await db.collection("consult-order").findOne({ orderId });
doctorCode = order.doctorCode;
}
// 更新订单状态
await updateConsultOrderStatus({
orderId,
orderStatus: "completed",
});
// 删除定时任务
await trigger({
type: "deleteDelayedTask",
triggerTaskId: orderId,
});
// 发送系统消息
tencentIM({
type: "sendSystemNotification",
formAccount: doctorCode,
toAccount: orderId,
corpId,
SyncOtherMachine: 1,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "COMPLETED",
Desc: sendText,
},
},
],
});
return {
success: true,
message: "完成成功",
};
} catch (error) {
return {
success: false,
message: "完成失败",
};
}
}
// 删除咨询订单
async function deleteConsultOrder(item) {
const { orderId } = item;
try {
// 调用mongo 数据库删除
const res = await db.collection("consult-order").deleteOne({
orderId,
});
return {
success: true,
message: "删除成功",
data: res,
};
} catch (err) {
return {
success: false,
message: "删除失败",
};
}
}
// 更新咨询订单
async function updateConsultOrder(item) {
const { orderId, params } = item;
try {
// 加密敏感字段
const encryptedParams = encryptOrderFields(params);
// 调用mongo 数据库更新
const res = await db.collection("consult-order").updateOne(
{ orderId },
{
$set: {
...encryptedParams,
updateTime: Date.now(),
},
}
);
return {
success: true,
message: "更新成功",
data: res,
};
} catch (err) {
return {
success: false,
message: "更新失败",
};
}
}
// 获取咨询订单 分页查询 page 页码 pageSize 每页数量 数据库分页
async function getConsultOrder(item) {
const {
page,
pageSize,
orderId,
hospitalId,
patientId,
idCard,
orderStatus,
mergeStatus,
doctorCode,
corpId,
showPassdiagnostic = false,
hasPassDiagnostic,
drugStoreId,
orderSource,
accountId,
} = item;
const query = {};
if (orderId) query.orderId = orderId;
if (hospitalId) query.hospitalId = hospitalId;
if (patientId) query.patientId = patientId;
if (idCard) query.idCard = idCard;
// if (corpId) query.corpId = corpId;
if (doctorCode) query.doctorCode = doctorCode;
if (orderStatus) query.orderStatus = orderStatus;
if (drugStoreId) query.drugStoreId = drugStoreId;
if (orderSource) query.orderSource = orderSource;
if (typeof accountId === 'string' && accountId.trim()) query.accountId = accountId.trim();
if (mergeStatus === "需处理") {
query.orderStatus = {
$in: ["pending", "processing", "completed"],
};
}
// 已完成 包括已完成和已取消 两种状态 或者 过期时间小于当前时间 注意 是或的关系 使用 or
if (mergeStatus === "已处理") {
query.orderStatus = {
$in: ["cancelled", "finished"],
};
}
try {
let res, total;
// 优化:分离查询,避免使用 $lookup 聚合操作
if (showPassdiagnostic) {
// 方案1如果需要根据 hasPassDiagnostic 过滤,先查询诊断记录获取相关的 orderId
if (typeof hasPassDiagnostic === "boolean") {
// 先查询所有通过审核的诊断记录的 orderId
const passedDiagnosticOrderIds = await db
.collection("diagnostic-record")
.distinct("orderId", { status: "PASS" });
// 根据 hasPassDiagnostic 条件调整查询
if (hasPassDiagnostic) {
// 只查询有通过诊断的订单
if (query.orderId) {
// 如果已经指定了orderId检查它是否在通过的列表中
if (!passedDiagnosticOrderIds.includes(query.orderId)) {
query.orderId = null; // 不在列表中设为null表示无结果
}
} else {
// 没有指定orderId查询所有通过的订单
if (passedDiagnosticOrderIds.length > 0) {
query.orderId = { $in: passedDiagnosticOrderIds };
} else {
// 如果没有通过的诊断记录,返回空结果
query.orderId = null;
}
}
} else {
// 只查询没有通过诊断的订单
if (query.orderId) {
// 如果已经指定了orderId检查它是否不在通过的列表中
if (passedDiagnosticOrderIds.includes(query.orderId)) {
query.orderId = null; // 在列表中设为null表示无结果
}
} else {
// 没有指定orderId排除所有通过的订单
if (passedDiagnosticOrderIds.length > 0) {
query.orderId = { $nin: passedDiagnosticOrderIds };
}
// 如果没有通过的诊断记录,则查询所有订单(不需要额外条件)
}
}
// 如果查询条件导致没有结果,直接返回
if (
query.orderId === null ||
(Array.isArray(query.orderId?.$in) && query.orderId.$in.length === 0)
) {
return {
success: true,
message: "查询成功",
data: [],
total: 0,
pages: 0,
};
}
}
// const { patientId: _patientId, ...restQuery } = query;
// const allQuery =
// typeof accountId == "string"
// ? { $or: [{ ...restQuery, accountId }, query] }
// : query;
// console.log("allQuery case!!!!: ", allQuery);
const allQuery = query;
// 先查询订单列表
res = await db
.collection("consult-order")
.find(allQuery)
.sort({ createTime: -1 })
.skip((page - 1) * pageSize)
.limit(pageSize)
.toArray();
// 获取总数
total = await db.collection("consult-order").countDocuments(allQuery);
// 如果有订单结果,批量查询诊断记录
if (res.length > 0) {
const orderIds = res.map((order) => order.orderId);
// 批量查询这些订单的通过审核的诊断记录
const diagnosticRecords = await db
.collection("diagnostic-record")
.find(
{
orderId: { $in: orderIds },
status: "PASS",
},
{ projection: { orderId: 1, _id: 0 } }
)
.toArray();
// 创建 orderId 到 hasPassDiagnostic 的映射
const diagnosticMap = new Set(
diagnosticRecords.map((record) => record.orderId)
);
// 为每个订单添加 hasPassDiagnostic 字段
res = res.map((order) => ({
...order,
hasPassDiagnostic: diagnosticMap.has(order.orderId),
}));
}
} else {
// 如果不需要诊断信息,直接查询订单
if (typeof hasPassDiagnostic === "boolean") {
// 仍然需要根据诊断状态过滤
const passedDiagnosticOrderIds = await db
.collection("diagnostic-record")
.distinct("orderId", { status: "PASS" });
if (hasPassDiagnostic) {
// 只查询有通过诊断的订单
if (query.orderId) {
// 如果已经指定了orderId检查它是否在通过的列表中
if (!passedDiagnosticOrderIds.includes(query.orderId)) {
query.orderId = null; // 不在列表中设为null表示无结果
}
} else {
// 没有指定orderId查询所有通过的订单
if (passedDiagnosticOrderIds.length > 0) {
query.orderId = { $in: passedDiagnosticOrderIds };
} else {
// 如果没有通过的诊断记录,返回空结果
query.orderId = null;
}
}
} else {
// 只查询没有通过诊断的订单
if (query.orderId) {
// 如果已经指定了orderId检查它是否不在通过的列表中
if (passedDiagnosticOrderIds.includes(query.orderId)) {
query.orderId = null; // 在列表中设为null表示无结果
}
} else {
// 没有指定orderId排除所有通过的订单
if (passedDiagnosticOrderIds.length > 0) {
query.orderId = { $nin: passedDiagnosticOrderIds };
}
// 如果没有通过的诊断记录,则查询所有订单(不需要额外条件)
}
}
if (
query.orderId === null ||
(Array.isArray(query.orderId?.$in) && query.orderId.$in.length === 0)
) {
return {
success: true,
message: "查询成功",
data: [],
total: 0,
pages: 0,
};
}
}
// const { patientId: _patientId, ...restQuery } = query;
// const allQuery =
// typeof accountId == "string"
// ? { $or: [{ ...restQuery, accountId }, query] }
// : query;
// console.log("allQuery case2: ", allQuery);
const allQuery = query;
res = await db
.collection("consult-order")
.find(allQuery)
.sort({ createTime: -1 })
.skip((page - 1) * pageSize)
.limit(pageSize)
.toArray();
total = await db.collection("consult-order").countDocuments(allQuery);
}
// 处理订单状态
const array = res.map((item) => {
if (item.payExpireTime < Date.now() && item.payStatus === "pending") {
item.payStatus = "expired";
item.payResult = "超时未支付";
}
if (
["processing", "pending", "completed"].includes(item.orderStatus) &&
item.expireTime < Date.now()
) {
item.orderStatus = "cancelled";
}
return item;
});
// 解密列表中的敏感字段
const decryptedArray = decryptOrderList(array);
return {
success: true,
message: "查询成功",
data: decryptedArray,
total,
pages: Math.ceil(total / pageSize),
};
} catch (err) {
return {
success: false,
message: err.message || "查询失败",
};
}
}
// 修改问诊状态
async function updateConsultOrderStatus(item) {
const {
orderId,
orderStatus,
payStatus,
expireTime,
doctorCode,
corpId,
reason,
} = item;
try {
let query = {};
if (orderStatus) query.orderStatus = orderStatus;
if (payStatus) query.payStatus = payStatus;
if (expireTime) query.expireTime = expireTime;
if (typeof reason === "string") query.reason = reason;
// 当医生开始处理, 开始加过期时间, 过期时间为30分钟
const res = await db.collection("consult-order").updateOne(
{ orderId },
{
$set: {
...query,
updateTime: Date.now(),
},
}
);
// 删除会话
if (orderStatus === "cancelled" || orderStatus === "finished") {
const res = await tencentIM({
type: "deleteSession",
fromAccount: doctorCode,
toAccount: orderId,
corpId: corpId,
});
}
return {
success: true,
message: "更新成功",
data: res,
};
} catch (err) {
return {
success: false,
message: "更新失败",
};
}
}
// 退费并退款接口
async function refundConsultOrder(item) {
// 判断是否有正在审核的单子
const count = await db.collection("diagnostic-record").countDocuments({
orderId: item.orderId,
status: "INIT",
});
if (count > 0) {
return {
success: false,
message: "存在正在审核的诊断单,不能退单",
};
}
// 退费并退诊
return await refundFeeAndOrder(item);
}
// 退费并退诊 换一个方法名
async function refundFeeAndOrder(item) {
let { orderId, reason, order } = item;
try {
// 1. 更新订单状态
if (!order) {
order = await db.collection("consult-order").findOne({ orderId });
if (!order) {
return {
success: false,
message: "订单不存在",
};
}
}
if (["cancelled", "finished"].includes(order.orderStatus)) {
return {
success: false,
message: "订单已取消或已完成,不能退单",
};
}
const { doctorCode, corpId, orderSource } = order;
// 如果订单已完成,且 审核通过
if (order.orderStatus === "completed") {
const count = await db.collection("diagnostic-record").countDocuments({
orderId,
status: "PASS",
});
if (count > 0) {
return await serviceFinishConsultOrder({ orderId, doctorCode, corpId });
}
}
// 调用退费接口
// 2. 退费
let payStatus = "",
payResult = "";
// 在线购药的咨询订单无需支付所以无需退款; pad端的咨询订单线下收费线下退
if (orderSource !== "MATEPAD" && order.consultType !== 'onlineMedicinePurchase') {
const { success, message } = await zytHis({
type: "hlwRefund",
patientId: order.patientId,
registerId: order.registerId,
medorgOrderNo: order.medorgOrderNo,
});
payStatus = success ? "refunded" : "refundFailed";
payResult = success ? "退费成功" : message;
}
// 更新诊断单状态
await setDiagnosticExpired({ orderId });
await tencentIM({
type: "sendSystemNotification",
formAccount: doctorCode,
toAccount: orderId,
SyncOtherMachine: 1,
corpId,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "CANCELLED",
Desc: "notification",
Ext: reason,
},
},
],
});
// 3. 更新订单状态
await updateConsultOrderStatus({
orderId,
orderStatus: "cancelled",
payStatus,
payResult,
doctorCode,
corpId,
reason: typeof reason == "string" ? reason : "",
});
return {
success: true,
message: "退费成功",
};
} catch (err) {
return {
success: false,
message: "退费失败",
};
}
}
// // 问诊开始
async function startConsultOrder(item) {
const { orderId, corpId, doctorCode } = item;
const { consultationDuration, acceptDuration } = await getConfig(corpId);
const expireTime = dayjs().add(acceptDuration, "minute").valueOf();
try {
const item = await db
.collection("consult-order")
.findOne({ orderId }, { projection: { expireTime: 1, orderStatus: 1 } });
if (!item) {
return { success: false, message: "订单不存在" };
}
if (item.orderStatus !== "pending") {
return { success: false, message: "当前订单已失效,请刷新" };
}
if (item.expireTime) {
return { success: true, message: "订单已开始" };
}
// 更新订单过期时间
await db
.collection("consult-order")
.updateOne({ orderId }, { $set: { expireTime } });
// 从新建一个定时任务
await trigger({
type: "createDelayedTask",
triggerTaskId: orderId,
endTime: expireTime,
corpId,
});
await tencentIM({
type: "sendSystemNotification",
formAccount: orderId,
toAccount: doctorCode,
SyncOtherMachine: 2,
corpId,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "STARTCONSULT",
Ext: `问诊已开始,本次问诊可持续${consultationDuration}分钟`,
},
},
],
});
// 患者向医生发送一个系统消息,告诉医生问诊已经开始
setTimeout(() => {
tencentIM({
type: "sendSystemNotification",
formAccount: doctorCode,
toAccount: orderId,
SyncOtherMachine: 2,
corpId,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "START",
Ext: "医生会尽快接诊,请在当前页面等待,避免错过医生的消息或视频问诊提示",
},
},
],
});
}, 1000);
return {
success: true,
message: "开始成功",
expireTime,
};
} catch (err) {
return {
success: false,
message: "开始失败",
};
}
}
async function refreshOrderPayStatus(params) {
const { orderId, patientId, registerId, medorgOrderNo } = params;
if (!orderId || !patientId || !registerId || !medorgOrderNo) {
return {
success: false,
message: "参数错误",
};
}
try {
const res = await zytHis({
type: "getPayStatus",
patientId,
registerId,
medorgOrderNo,
});
if (res && res.settlement) {
await db.collection("consult-order").updateOne(
{
orderId,
patientId,
registerId,
medorg_order_no: medorgOrderNo,
},
{
$set: {
settlement: res.settlement,
},
}
);
}
return { ...res };
} catch (e) {
return { success: false, message: e.message || "刷新失败" };
}
}
/**
* 查询医生是否存在进行中的订单
* @param {*} params
* @returns
*/
async function doctorHasPendingOrder(params) {
try {
const count = await db.collection("consult-order").countDocuments({
doctorCode: params.doctorCode,
orderStatus: { $in: ["pending", "processing", "completed"] },
});
return { success: true, data: count > 0, message: "查询成功" };
} catch (e) {
return { success: false, message: e.message || "查询失败" };
}
}
// 设置处方诊断过期
async function setDiagnosticExpired(item) {
const { orderId } = item;
try {
const res = await db
.collection("diagnostic-record")
.updateMany({ orderId, status: "INIT" }, { $set: { status: "EXPIRED" } });
return { success: true, message: "操作成功" };
} catch (e) {
return { success: false, message: e.message || "操作失败" };
}
}
async function getHisStoreRegList(ctx) {
const { storeId, regType } = ctx;
if (typeof storeId !== "string" || storeId.trim() === "") {
return { success: false, message: "药店id不能为空" };
}
try {
const { success, list, message } = await zytHis({
type: "getHisStoreRegList",
storeId,
});
if (success && list.length) {
// channel为1表示浸酒号源
const regList = list.filter(i => regType === 'wine' ? i.channel == '1' : i.channel != '1');
const registerids = regList.map((i) => i.registerid);
const existRegisteridData = await db
.collection("consult-order")
.find(
{ registerId: { $in: registerids } },
{ projection: { _id: 0, registerId: 1 } }
)
.toArray();
const existRegisterids = existRegisteridData.map((i) => i.registerId);
const data = regList.filter((i) => !existRegisterids.includes(i.registerid));
return { success, list: data, message };
}
if (success) {
return { success, list, message };
}
return { success, message };
} catch (e) {
return { success: false, message: e.message };
}
}
async function validHlwOrderConfig(ctx) {
try {
const { key, corpId } = ctx;
if (typeof key !== "string" || key.trim() === "") {
return { success: false, message: "获取失败" };
}
const res = await getConfig(corpId);
const data = res[key];
if (data) {
return { success: true, message: "获取成功", data };
}
return { success: false, message: "获取失败" };
} catch (e) {
return { success: false, message: e.message };
}
}
/**
* 用户退费导致 取消订单
* @param {*} item
* @returns
*/
async function customerRefundOrder(item) {
const { registerId, patientId, refundType = "OFFLINEREFUND" } = item;
if (
typeof registerId !== "string" ||
registerId.trim() === "" ||
typeof patientId !== "string" ||
patientId.trim() === ""
) {
return {
success: false,
message: "参数错误",
};
}
const msg = RefundOrderScene[refundType] || RefundOrderScene.OFFLINEREFUND;
try {
// 获取订单
const record = await db.collection("consult-order").findOne(
{ registerId, patientId },
{
projection: {
_id: 1,
doctorCode: 1,
orderId: 1,
corpId: 1,
orderStatus: 1,
},
}
);
if (!record) return { success: false, message: "订单不存在" };
if (["finished"].includes(record.orderStatus)) {
return {
success: true,
message: "订单已结束,无法取消",
orderId: typeof record.orderId === "string" ? record.orderId : "",
};
}
if (record.orderStatus === "cancelled") {
return {
success: true,
message: "订单已取消",
orderId: typeof record.orderId === "string" ? record.orderId : "",
};
}
const res = await db.collection("consult-order").updateOne(
{ _id: record._id },
{
$set: {
orderStatus: "cancelled",
payStatus: "cancelled",
payResult: "患者已退费",
reason: "患者已退费",
updateTime: Date.now(),
},
}
);
if (["processing", "pending", "completed"].includes(record.orderStatus)) {
await tencentIM({
type: "sendSystemNotification",
formAccount: record.orderId,
toAccount: record.doctorCode,
SyncOtherMachine: 1,
corpId: record.corpId,
msgBody: [
{
MsgType: "TIMCustomElem",
MsgContent: {
Data: "CANCELLED",
Desc: "notification",
Ext: `本次问诊已取消,取消原因:${msg}`,
},
},
],
});
}
return {
success: true,
message: "取消成功",
orderId: typeof record.orderId === "string" ? record.orderId : "",
};
} catch (error) {
return {
success: false,
message: "取消失败",
};
}
}
async function getPatientOrderList(ctx) {
const { patientId, startDate, endDate, isPres, orderStatus } = ctx;
if (typeof patientId !== "string" || patientId.trim() === "") {
return { success: false, message: "患者id不能为空" };
}
const startTime =
startDate && dayjs(startDate).isValid()
? dayjs(startDate).startOf("day").valueOf()
: "";
const endTime =
endDate && dayjs(endDate).isValid()
? dayjs(endDate).endOf("day").valueOf()
: "";
try {
const query = { patientId, payStatus: "success" };
if (typeof orderStatus === "string" && orderStatus.trim() !== "") {
query.orderStatus = orderStatus.trim();
}
if (typeof isPres === "boolean") {
query.preOrderId = { $exists: isPres };
}
if (startTime && endTime) {
query.createTime = { $gte: startTime, $lte: endTime };
}
const list = await db
.collection("consult-order")
.find(query)
.sort({ createTime: -1 })
.toArray();
// 解密列表中的敏感字段
const decryptedList = decryptOrderList(list);
return { success: true, message: "查询成功", list: decryptedList };
} catch (e) {
return { success: false, message: e.message || "查询失败" };
}
}
async function getOrderPatientList(ctx) {
const { doctorCode, name, mobile, patientId, corpId } = ctx;
const query = {};
// 机构隔离:如果传了 corpId则只查当前机构
if (typeof corpId === "string" && corpId.trim()) {
query.corpId = corpId.trim();
}
// 优先使用 patientId 精确查询基础信息
if (typeof patientId === "string" && patientId.trim()) {
query.patientId = patientId.trim();
} else {
// 兼容旧逻辑:按医生/姓名/手机号聚合患者列表
if (typeof doctorCode === "string" && doctorCode.trim()) {
query.doctorCode = doctorCode.trim();
}
if (typeof name === "string" && name.trim()) {
query.name = { $regex: name.trim(), $options: "i" };
}
if (typeof mobile === "string" && mobile.trim()) {
query.mobile = { $regex: mobile.trim(), $options: "i" };
}
}
const page =
parseInt(ctx.page, 10) > 0 ? parseInt(ctx.page, 10) : 1;
const pageSize =
parseInt(ctx.pageSize, 10) > 0 ? parseInt(ctx.pageSize, 10) : 10;
try {
const list = await db
.collection("consult-order")
.aggregate([
{ $match: query },
{
$group: {
_id: "$patientId",
blhno: { $first: "$blhno" },
name: { $first: "$name" },
sex: { $first: "$sex" },
age: { $first: "$age" },
mobile: { $first: "$mobile" },
idCard: { $first: "$idCard" },
address: { $first: "$address" },
createTime: { $first: "$createTime" },
patientId: { $first: "$patientId" },
},
},
{ $sort: { createTime: -1 } },
{ $skip: (page - 1) * pageSize },
{ $limit: pageSize },
])
.toArray();
const [stats] = await db
.collection("consult-order")
.aggregate([
{ $match: query },
{
$group: {
_id: "$patientId",
},
},
{ $count: "total" },
])
.toArray();
const total = stats ? stats.total : 0;
// 解密列表中的敏感字段
const decryptedList = decryptOrderList(list);
// 兼容旧用法(直接返回 list/total同时为 PC 端提供 data 包装
const pages = Math.ceil(total / pageSize);
return {
success: true,
message: "查询成功",
list: decryptedList,
total,
page,
pageSize,
pages,
data: {
list: decryptedList,
total,
page,
pageSize,
pages,
},
};
} catch (e) {
return { success: false, message: e.message || "查询失败" };
}
}
async function getHlwOrderList(ctx) {
try {
const andConditions = [];
const page = parseInt(ctx.page) > 0 ? parseInt(ctx.page) : 1;
const pageSize = parseInt(ctx.pageSize) > 0 ? parseInt(ctx.pageSize) : 10;
const escapeRegExp = (str) =>
String(str).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// 姓名筛选:兼容加密存储(精确匹配密文)+ 旧数据明文模糊匹配
if (typeof ctx.name === "string" && ctx.name.trim() !== "") {
const keyword = ctx.name.trim();
let encryptedKeyword = "";
try {
encryptedKeyword = encryptOrderFields({ name: keyword }).name;
} catch (e) {
// ignore: fallback to plaintext match
}
const orList = [];
if (encryptedKeyword) {
orList.push({ name: encryptedKeyword });
}
orList.push({ name: { $regex: `.*${escapeRegExp(keyword)}.*`, $options: "i" } });
andConditions.push({ $or: orList });
}
if (typeof ctx.consultType === "string" && ctx.consultType.trim() !== "") {
andConditions.push({ consultType: ctx.consultType.trim() });
}
if (typeof ctx.orderSource === "string" && ctx.orderSource.trim() !== "") {
andConditions.push({ orderSource: ctx.orderSource });
}
const orderStatus =
typeof ctx.orderStatus === "string" ? ctx.orderStatus.trim() : "";
if (orderStatus) {
// 修复:待处理(pending)不应包含“支付超时(前端展示为已取消)”订单
if (orderStatus === "pending") {
const now = Date.now();
andConditions.push({ orderStatus: "pending" });
andConditions.push({
$or: [
{ payStatus: { $ne: "pending" } },
{ payExpireTime: { $gte: now } },
{ payExpireTime: { $exists: false } },
],
});
} else {
andConditions.push({ orderStatus });
}
}
if (Array.isArray(ctx.doctorCodes) && ctx.doctorCodes.length) {
andConditions.push({ doctorCode: { $in: ctx.doctorCodes } });
}
if (typeof ctx.isPres === "boolean") {
andConditions.push({ preOrderId: { $exists: ctx.isPres } });
}
if (Array.isArray(ctx.storeIds) && ctx.storeIds.length) {
andConditions.push({ drugStoreId: { $in: ctx.storeIds } });
}
const { startDate, endDate } = ctx;
const createTime = {};
if (startDate && dayjs(startDate).isValid()) {
createTime.$gte = dayjs(startDate).startOf("day").valueOf();
}
if (endDate && dayjs(endDate).isValid()) {
createTime.$lte = dayjs(endDate).endOf("day").valueOf();
}
if (Object.keys(createTime).length) {
andConditions.push({ createTime });
}
if (ctx.isDoctorView === true) {
andConditions.push({
orderStatus: { $ne: "pending" },
payStatus: { $ne: "pending" },
});
}
const allQuery =
andConditions.length === 0
? {}
: andConditions.length === 1
? andConditions[0]
: { $and: andConditions };
const list = await db
.collection("consult-order")
.find(allQuery)
.sort({ createTime: -1 })
.skip((page - 1) * pageSize)
.limit(pageSize)
.toArray();
const total = await db.collection("consult-order").countDocuments(allQuery);
// 解密列表中的敏感字段
const decryptedList = decryptOrderList(list);
// 聚合已成功的服务端录制数量,用于 PC 订单列表视频图标展示
let videoCountMap = {};
try {
const orderIds = decryptedList.map((i) => i.orderId).filter(Boolean);
if (orderIds.length) {
const agg = await db
.collection("mrtc-video-record")
.aggregate([
{
$match: {
orderId: { $in: orderIds },
status: 2, // 2: 录制成功(且至少两路流,见 recordTotalStream 配置)
filePath: { $exists: true, $ne: "" },
},
},
{ $group: { _id: "$orderId", count: { $sum: 1 } } },
])
.toArray();
agg.forEach((i) => {
if (i && i._id) videoCountMap[i._id] = i.count || 0;
});
}
} catch (e) {
console.warn("[MRTC] aggregate videoRecordCount failed:", e.message);
}
const listWithVideoCount = decryptedList.map((i) => ({
...i,
videoRecordCount: videoCountMap[i.orderId] || 0,
}));
return { success: true, list: listWithVideoCount, message: "查询成功", total };
} catch (e) {
return { success: false, message: e.message };
}
}
async function applyRefundOrder(ctx) {
const { id: _id, orderId, reason } = ctx;
if (
typeof _id !== "string" ||
_id.trim() === "" ||
typeof orderId !== "string" ||
orderId.trim() === ""
) {
return { success: false, message: "参数错误" };
}
if (typeof reason !== "string" || reason.trim() === "") {
return { success: false, message: "退款原因不能为空" };
}
if (reason.trim().length > 200) {
return { success: false, message: "退款原因最多输入200字" };
}
try {
const refundInfo = {
status: "INIT",
createTime: Date.now(),
reason: reason.trim(),
};
const res = await db
.collection("consult-order")
.updateOne(
{ _id: new ObjectId(_id), orderId, refundInfo: { $exists: false } },
{ $set: { refundInfo } }
);
if (res.matchedCount === 0) {
return { success: false, message: "订单不存在或者已经存在申请信息" };
}
if (res.modifiedCount === 1) {
return { success: true, message: "申请成功", data: refundInfo };
}
return { success: false, message: "申请失败" };
} catch (e) {
return { success: false, message: e.message || "申请退款失败" };
}
}
async function getRefundOrderList(ctx) {
try {
const query = {
refundInfo: { $exists: true },
doctorCode:
typeof ctx.doctorCode === "string" ? ctx.doctorCode.trim() : "",
};
if (typeof ctx.name === "string" && ctx.name.trim() != "") {
query.name = { $regex: ".*" + ctx.name.trim() + ".*", $options: "i" };
}
if (typeof ctx.mobile === "string" && ctx.mobile.trim() != "") {
query.mobile = { $regex: ".*" + ctx.mobile.trim() + ".*", $options: "i" };
}
if (typeof ctx.status === "string" && ctx.status.trim() != "") {
query["refundInfo.status"] = ctx.status;
}
const page = parseInt(ctx.page) > 0 ? parseInt(ctx.page) : 1;
const pageSize = parseInt(ctx.pageSize) > 0 ? parseInt(ctx.pageSize) : 10;
const projection = {
_id: 1,
name: 1,
doctorName: 1,
mobile: 1,
refundInfo: 1,
orderId: 1,
};
// const list = await db.collection('consult-order').find(query, { projection }).sort({ 'refundInfo.createTime': -1 }).skip((page - 1) * pageSize).limit(pageSize).toArray();
const list = await db
.collection("consult-order")
.aggregate([
{ $match: query },
{ $project: projection },
{
$addFields: {
initFirst: {
$cond: [{ $eq: ["$refundInfo.status", "INIT"] }, 0, 1],
},
},
},
{ $sort: { initFirst: 1, "refundInfo.createTime": -1, _id: -1 } },
{ $skip: (page - 1) * pageSize },
{ $limit: pageSize },
])
.toArray();
const total = await db.collection("consult-order").countDocuments(query);
const count = await db
.collection("consult-order")
.countDocuments({ ...query, "refundInfo.status": "INIT" });
// 解密列表中的敏感字段
const decryptedList = decryptOrderList(list);
return { success: true, list: decryptedList, message: "查询成功", total, count };
} catch (e) {
return { success: false, message: e.message || "查询失败" };
}
}
async function handleRefundOrder(ctx) {
const { id: _id, orderId, status, reason, operatorId, operator } = ctx;
if (
typeof _id !== "string" ||
_id.trim() === "" ||
typeof orderId !== "string" ||
orderId.trim() === ""
) {
return { success: false, message: "参数错误" };
}
if (typeof status !== "string" || !["PASS", "REJECT"].includes(status)) {
return { success: false, message: "无效的退费状态" };
}
if (
status === "REJECT" &&
(typeof reason !== "string" || reason.trim() === "")
) {
return { success: false, message: "拒绝退费原因不能为空" };
}
try {
const doctorCode = typeof ctx.doctorCode === "string" ? ctx.doctorCode : "";
const refundInfo = {
"refundInfo.status": status,
"refundInfo.rejectReason": status === "REJECT" ? reason.trim() : "",
"refundInfo.updateTime": Date.now(),
"refundInfo.operatorId":
typeof operatorId === "string" ? operatorId.trim() : "",
"refundInfo.operator":
typeof operator === "string" ? operator.trim() : "",
};
const record = await db.collection("consult-order").findOne(
{
_id: new ObjectId(_id),
orderId,
"refundInfo.status": "INIT",
doctorCode,
},
{ _id: 1 }
);
const rxApi = require("../diagnostic-record");
if (!record) {
return { success: false, message: "订单不存在或者退费申请已经处理" };
}
if (status === "PASS") {
const order = await db
.collection("consult-order")
.findOne(
{ orderId },
{ projection: { registerId: 1, patientId: 1, medorgOrderNo: 1 } }
);
if (order && order.registerId && order.patientId) {
const { success, message } = await zytHis({
type: "hlwRefund",
patientId: order.patientId,
registerId: order.registerId,
medorgOrderNo: order.medorgOrderNo,
});
if (!success) {
return {
success: false,
message: message || "退费失败",
errType: "HIS_REFUND_FAIL",
};
}
await customerRefundOrder({
registerId: order.registerId,
patientId: order.patientId,
refundType: "DOCTORAGREEREFUND",
});
await rxApi({ type: "discardDiagnosticRecord", orderId }, db);
}
}
await db
.collection("consult-order")
.updateOne({ _id: record._id }, { $set: refundInfo });
return { success: true, message: "操作成功", data: refundInfo };
} catch (e) {
return { success: false, message: e.message || "操作失败" };
}
}
async function autoHandleExpireOrder() {
const hour = dayjs().hour();
if (hour < 22 || hour > 23) {
return { success: false, message: '每天无效订单自动退费时间在22:00-24:00之间' }
}
if (scheduleTaskIsRunning) return;
scheduleTaskIsRunning = true;
try {
// 订单过期判断 有expireTime,则根据expireTime字段判断 否则根据 payExpireTime
const conditions = {
$or: [
{
orderStatus: "pending",
createTime: { $gt: dayjs().startOf("day").valueOf() },
payExpireTime: { $lt: Date.now() },
expireTime: { $exists: false }
},
{
orderStatus: "pending",
createTime: { $gt: dayjs().startOf("day").valueOf() },
expireTime: { $lt: Date.now() }
}
]
}
const orderList = await db.collection("consult-order").find(conditions, { projection: { _id: 1, orderId: 1, patientId: 1, registerId: 1, medorgOrderNo: 1, consultType: 1 } }).toArray();
const now = dayjs().format('YYYY-MM-DD HH:mm:ss')
const updateTime = Date.now();
let processedCount = 0;
let refundedCount = 0;
let cancelledCount = 0;
let errorCount = 0;
for (let order of orderList) {
try {
const rx = await db.collection("diagnostic-record").findOne({ orderId: order.orderId }, { projection: { _id: 1, status: 1 } });
const hasValidRx = rx && rx.status === 'PASS';
// 配药订单咨询 实际无需支付, 问诊费和药费事后一起收取
if (order.consultType === 'onlineMedicinePurchase') {
const target = hasValidRx ? { orderStatus: "finished", updateTime } : { updateTime, orderStatus: "cancelled", payStatus: "cancelled", reason: `取消原因: 订单超时未处理,定时任务自动取消(${now})` };
await db.collection("consult-order").updateOne({ _id: order._id }, { $set: target });
processedCount++;
if (!hasValidRx) cancelledCount++;
continue;
}
// 在线问诊 自动结束
if (hasValidRx) {
await db.collection("consult-order").updateOne({ _id: order._id }, { $set: { orderStatus: "finished", updateTime } });
processedCount++;
continue;
}
// 检查必要字段
if (!order.patientId || !order.registerId || !order.medorgOrderNo) {
// 缺少必要字段,直接取消订单
await db.collection("consult-order").updateOne({ _id: order._id }, { $set: { updateTime, orderStatus: "cancelled", payStatus: "cancelled", reason: `取消原因: 订单信息不完整,定时任务自动取消(${now})` } });
processedCount++;
cancelledCount++;
continue;
}
const payStatusResult = await zytHis({ type: 'getPayStatus', patientId: order.patientId, registerId: order.registerId, medorgOrderNo: order.medorgOrderNo });
// 如果查询失败,记录错误但继续处理下一个订单
if (!payStatusResult || !payStatusResult.success) {
errorCount++;
continue;
}
const status = payStatusResult.status;
// (1 已退费 5 未收费 x 已作废) his状态不需要退费的情况 直接修改为取消状态
if (['5', '1', 'x'].includes(status)) {
await db.collection("consult-order").updateOne({ _id: order._id }, { $set: { updateTime, orderStatus: "cancelled", payStatus: "cancelled", reason: `取消原因: 订单超时未处理,定时任务自动取消(${now})` } });
processedCount++;
cancelledCount++;
continue;
}
// his状态不是已收费 直接跳过
if (status !== '0') {
continue;
}
const refundResult = await zytHis({ type: 'hlwRefund', patientId: order.patientId, registerId: order.registerId, medorgOrderNo: order.medorgOrderNo });
if (refundResult && refundResult.success) {
await db.collection("consult-order").updateOne({ _id: order._id }, { $set: { updateTime, orderStatus: "cancelled", payStatus: "refunded", reason: `取消原因: 订单超时未处理,定时任务自动退费(${now})` } });
processedCount++;
refundedCount++;
} else {
// 退费失败,记录错误但继续处理
errorCount++;
}
} catch (orderError) {
// 单个订单处理失败,记录错误但继续处理下一个
errorCount++;
console.error(`处理订单 ${order.orderId} 时出错:`, orderError);
}
}
console.log(`处理完成: 共处理${orderList.length}个订单, 成功${processedCount}个, 退费${refundedCount}个, 取消${cancelledCount}个, 错误${errorCount}`)
scheduleTaskIsRunning = false;
return { success: true, message: "处理完成" };
} catch (e) {
scheduleTaskIsRunning = false;
console.error("处理订单失败:", e.message);
return { success: false, message: e.message || "操作失败" };
}
}