336 lines
9.8 KiB
JavaScript
336 lines
9.8 KiB
JavaScript
|
|
const dayjs = require("dayjs");
|
|||
|
|
const Sm4Util = require("../../utils/sm4-util");
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 需要加密的字段列表
|
|||
|
|
*/
|
|||
|
|
const ENCRYPTED_FIELDS = ["name", "mobile", "idCard"];
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 加密诊断记录敏感字段
|
|||
|
|
* @param {Object} data - 诊断记录数据
|
|||
|
|
* @returns {Object} 加密后的数据
|
|||
|
|
*/
|
|||
|
|
function encryptDiagnosticRecordFields(data) {
|
|||
|
|
if (!data || typeof data !== "object") {
|
|||
|
|
return data;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const encryptedData = { ...data };
|
|||
|
|
|
|||
|
|
ENCRYPTED_FIELDS.forEach((field) => {
|
|||
|
|
if (
|
|||
|
|
encryptedData[field] &&
|
|||
|
|
typeof encryptedData[field] === "string" &&
|
|||
|
|
encryptedData[field].trim() !== ""
|
|||
|
|
) {
|
|||
|
|
try {
|
|||
|
|
encryptedData[field] = Sm4Util.encryptDataForSm3(encryptedData[field]);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`加密字段 ${field} 失败:`, error.message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return encryptedData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解密诊断记录敏感字段
|
|||
|
|
* @param {Object} data - 诊断记录数据
|
|||
|
|
* @returns {Object} 解密后的数据
|
|||
|
|
*/
|
|||
|
|
function decryptDiagnosticRecordFields(data) {
|
|||
|
|
if (!data || typeof data !== "object") {
|
|||
|
|
return data;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const decryptedData = { ...data };
|
|||
|
|
|
|||
|
|
ENCRYPTED_FIELDS.forEach((field) => {
|
|||
|
|
if (
|
|||
|
|
decryptedData[field] &&
|
|||
|
|
typeof decryptedData[field] === "string" &&
|
|||
|
|
decryptedData[field].trim() !== ""
|
|||
|
|
) {
|
|||
|
|
try {
|
|||
|
|
decryptedData[field] = Sm4Util.decryptDataForSm3(decryptedData[field]) || decryptedData[field];
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error(`解密字段 ${field} 失败:`, error.message);
|
|||
|
|
// 解密失败时保留原值
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return decryptedData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 批量解密诊断记录列表的敏感字段
|
|||
|
|
* @param {Array} list - 诊断记录列表
|
|||
|
|
* @returns {Array} 解密后的诊断记录列表
|
|||
|
|
*/
|
|||
|
|
function decryptDiagnosticRecordList(list) {
|
|||
|
|
if (!Array.isArray(list)) {
|
|||
|
|
return list;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return list.map((item) => decryptDiagnosticRecordFields(item));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
exports.formatUploadRxData = function (data) {
|
|||
|
|
return {
|
|||
|
|
patientid: data.patientId,
|
|||
|
|
orderno: data.medOrgOrderNo,
|
|||
|
|
doctorcode: data.doctorCode,
|
|||
|
|
unitcode: data.unitCode,
|
|||
|
|
hospid: "108",
|
|||
|
|
phar_code: data.pharmacistNo,
|
|||
|
|
phar_name: data.pharmacist,
|
|||
|
|
phar_chk_time: dayjs(data.auditTime).format("YYYY-MM-DD HH:mm:ss"),
|
|||
|
|
ysjd_time: dayjs(data.prescriptionStartTime).format("YYYY-MM-DD HH:mm:ss"),
|
|||
|
|
prsc_time: dayjs(data.prescriptionEndTime).format("YYYY-MM-DD HH:mm:ss"),
|
|||
|
|
details: data.drugs.map((i) => {
|
|||
|
|
const item = {
|
|||
|
|
drug_id: i.insurance_code,
|
|||
|
|
drug_name: i.drugName,
|
|||
|
|
drug_dosform: "",
|
|||
|
|
drug_spec: i.specification || "",
|
|||
|
|
drug_pric: "0",
|
|||
|
|
drug_cnt: i.quantity,
|
|||
|
|
drug_sumamt: "0",
|
|||
|
|
medc_way_codg: i.usageCode,
|
|||
|
|
medc_way_dscr: i.usageName,
|
|||
|
|
medc_days: i.days,
|
|||
|
|
remark: "",
|
|||
|
|
limit_flag: "0",
|
|||
|
|
used_frqu_codg: i.frequencyCode,
|
|||
|
|
used_frqu_name: i.frequencyName,
|
|||
|
|
sin_doscnt: i.dosage,
|
|||
|
|
sin_dosunt: i.dosage_unit,
|
|||
|
|
unit: i.unit,
|
|||
|
|
appr_flag: i.forceSelfPay === 'Y' ? '2' : '1'
|
|||
|
|
}
|
|||
|
|
if (item.appr_flag === '2') {
|
|||
|
|
//[his要求]当appr_flag=2时必填,如果这个药品维护了限制使用范围的,传1,否则就传2
|
|||
|
|
item.self_pay_rea = i.limitUsageScope === 'Y' ? '1' : '2'
|
|||
|
|
}
|
|||
|
|
return item
|
|||
|
|
}),
|
|||
|
|
icds: data.diagnosisList.map((i) => ({
|
|||
|
|
icd_code: i.code,
|
|||
|
|
icd_name: i.name,
|
|||
|
|
})),
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
exports.formatOnlineMedicinePurchaseData = function (data) {
|
|||
|
|
const details = data.drugs.map(i => {
|
|||
|
|
const item = {
|
|||
|
|
drug_type: "xy",
|
|||
|
|
drug_groupno: i.hisChargeInfo.drugGroupNo,
|
|||
|
|
drug_group: "",
|
|||
|
|
drug_id: i.hisChargeInfo.drugId,
|
|||
|
|
drug_serial: i.hisChargeInfo.drugSerial,
|
|||
|
|
drug_name: i.drugName,
|
|||
|
|
drug_spec: i.specification || "",
|
|||
|
|
drug_pric: i.hisChargeInfo.drugPrice,
|
|||
|
|
drug_cnt: i.quantity,
|
|||
|
|
drug_sumamt: i.hisChargeInfo.drugSumamt, //总金额 总金额=数量*单价
|
|||
|
|
supple_code: i.usageCode,
|
|||
|
|
supple_name: i.usageName,
|
|||
|
|
medc_days: i.days,
|
|||
|
|
drug_times: 1,
|
|||
|
|
drug_comm: "",
|
|||
|
|
drug_ma: "",
|
|||
|
|
remark: "",
|
|||
|
|
limit_flag: "0",
|
|||
|
|
usage: i.frequencyCode,
|
|||
|
|
usage_name: i.frequencyName,
|
|||
|
|
sin_doscnt: i.dosage,
|
|||
|
|
sin_dosunt: i.dosage_unit_code,
|
|||
|
|
unit: i.unit,
|
|||
|
|
appr_flag: i.forceSelfPay === 'Y' ? '2':'1'
|
|||
|
|
}
|
|||
|
|
if (item.appr_flag === '2') {
|
|||
|
|
//[his要求]当appr_flag=2时必填,如果这个药品维护了限制使用范围的,传1,否则就传2
|
|||
|
|
item.self_pay_rea = i.limitUsageScope === 'Y' ? '1' : '2'
|
|||
|
|
}
|
|||
|
|
return item
|
|||
|
|
})
|
|||
|
|
return {
|
|||
|
|
patientid: data.patientId,
|
|||
|
|
registerid: "",
|
|||
|
|
orderno: data.medOrgOrderNo,
|
|||
|
|
doctorcode: data.doctorCode,
|
|||
|
|
unitcode: data.unitCode,
|
|||
|
|
visit_time: dayjs(data.prescriptionStartTime).format("YYYY-MM-DD HH:mm:ss"),
|
|||
|
|
area_code: data.areaCode,
|
|||
|
|
hospid: "108",
|
|||
|
|
details,
|
|||
|
|
icds: data.diagnosisList.map((i, idx) => ({
|
|||
|
|
icd_code: i.code,
|
|||
|
|
icd_name: i.name,
|
|||
|
|
sort: idx + 1
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
exports.formatWinePurchaseData = function (data, order) {
|
|||
|
|
const [wine] = data.wines;
|
|||
|
|
return {
|
|||
|
|
patientid: data.patientId,
|
|||
|
|
registerid: order.medorg_order_no,
|
|||
|
|
orderno: data.medOrgOrderNo,
|
|||
|
|
doctorcode: data.doctorCode,
|
|||
|
|
unitcode: data.unitCode,
|
|||
|
|
visit_time: dayjs(data.prescriptionStartTime).format("YYYY-MM-DD HH:mm:ss"),
|
|||
|
|
operator_id: data.drugStoreNo,
|
|||
|
|
tc_code: wine.hisId,
|
|||
|
|
drug_times: wine.quantity,
|
|||
|
|
delivery: data.pickUpType === 'delivery' ? 1 :0,//是否配送 1配送 0自提 order.pickUpType === 'delivery' ? 1 :0
|
|||
|
|
hospid: "108",
|
|||
|
|
icds: data.diagnosisList.map((i) => ({
|
|||
|
|
icd_code: i.code,
|
|||
|
|
icd_name: i.name,
|
|||
|
|
})),
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 构建支持明文+密文混合搜索的查询条件
|
|||
|
|
* 用于数据迁移期间,数据库中同时存在明文和密文数据的情况
|
|||
|
|
*
|
|||
|
|
* @param {string} fieldName - 字段名(如 'name', 'mobile', 'idCard')
|
|||
|
|
* @param {string} searchValue - 搜索值(明文)
|
|||
|
|
* @param {boolean} exactMatch - 是否精确匹配,默认为false(模糊匹配)
|
|||
|
|
* @returns {Object} MongoDB查询条件对象
|
|||
|
|
*/
|
|||
|
|
function buildHybridSearchQuery(fieldName, searchValue, exactMatch = false) {
|
|||
|
|
if (
|
|||
|
|
!searchValue ||
|
|||
|
|
typeof searchValue !== "string" ||
|
|||
|
|
searchValue.trim() === ""
|
|||
|
|
) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const trimmedValue = searchValue.trim();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 尝试加密搜索值
|
|||
|
|
const encryptedValue = Sm4Util.encryptDataForSm3(trimmedValue);
|
|||
|
|
|
|||
|
|
if (exactMatch) {
|
|||
|
|
// 精确匹配:同时匹配明文和密文
|
|||
|
|
return {
|
|||
|
|
$or: [
|
|||
|
|
{ [fieldName]: trimmedValue }, // 明文精确匹配
|
|||
|
|
{ [fieldName]: encryptedValue }, // 密文精确匹配
|
|||
|
|
],
|
|||
|
|
};
|
|||
|
|
} else {
|
|||
|
|
// 模糊匹配:明文用正则,密文用精确匹配(因为密文无法模糊匹配)
|
|||
|
|
return {
|
|||
|
|
$or: [
|
|||
|
|
{ [fieldName]: new RegExp(trimmedValue, "i") }, // 明文模糊匹配(不区分大小写)
|
|||
|
|
{ [fieldName]: encryptedValue }, // 密文精确匹配
|
|||
|
|
],
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
// 如果加密失败(如环境变量未配置),只搜索明文
|
|||
|
|
console.warn(`加密搜索值失败,只搜索明文数据: ${error.message}`);
|
|||
|
|
|
|||
|
|
if (exactMatch) {
|
|||
|
|
return { [fieldName]: trimmedValue };
|
|||
|
|
} else {
|
|||
|
|
return { [fieldName]: new RegExp(trimmedValue, "i") };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 批量构建混合搜索条件
|
|||
|
|
* @param {Object} searchParams - 搜索参数对象,如 { name: '张三', mobile: '138' }
|
|||
|
|
* @param {boolean} exactMatch - 是否精确匹配
|
|||
|
|
* @returns {Array} MongoDB $and 条件数组
|
|||
|
|
*/
|
|||
|
|
function buildMultiFieldHybridSearch(searchParams, exactMatch = false) {
|
|||
|
|
const conditions = [];
|
|||
|
|
|
|||
|
|
Object.keys(searchParams).forEach((fieldName) => {
|
|||
|
|
const searchValue = searchParams[fieldName];
|
|||
|
|
const condition = buildHybridSearchQuery(
|
|||
|
|
fieldName,
|
|||
|
|
searchValue,
|
|||
|
|
exactMatch
|
|||
|
|
);
|
|||
|
|
if (condition) {
|
|||
|
|
conditions.push(condition);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return conditions;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
exports.formatReviewData = function (data) {
|
|||
|
|
const details = data.drugs.map(i => {
|
|||
|
|
const item = {
|
|||
|
|
drug_type: "xy",
|
|||
|
|
drug_groupno: i.hisChargeInfo.drugGroupNo,
|
|||
|
|
drug_group: "",
|
|||
|
|
drug_id: i.hisChargeInfo.drugId,
|
|||
|
|
drug_serial: i.hisChargeInfo.drugSerial,
|
|||
|
|
drug_name: i.drugName,
|
|||
|
|
drug_spec: i.specification || "",
|
|||
|
|
drug_pric: i.hisChargeInfo.drugPrice,
|
|||
|
|
drug_cnt: i.quantity,
|
|||
|
|
drug_sumamt: i.hisChargeInfo.drugSumamt, //总金额 总金额=数量*单价
|
|||
|
|
supple_code: i.usageCode,
|
|||
|
|
supple_name: i.usageName,
|
|||
|
|
medc_days: i.days,
|
|||
|
|
drug_times: 1,
|
|||
|
|
drug_comm: "",
|
|||
|
|
drug_ma: "",
|
|||
|
|
remark: "",
|
|||
|
|
limit_flag: "0",
|
|||
|
|
usage: i.frequencyCode,
|
|||
|
|
usage_name: i.frequencyName,
|
|||
|
|
sin_doscnt: i.dosage,
|
|||
|
|
sin_dosunt: i.dosage_unit_code,
|
|||
|
|
unit: i.unit,
|
|||
|
|
appr_flag: i.forceSelfPay === 'Y' ? '2':'1'
|
|||
|
|
}
|
|||
|
|
if (item.appr_flag === '2') {
|
|||
|
|
//[his要求]当appr_flag=2时必填,如果这个药品维护了限制使用范围的,传1,否则就传2
|
|||
|
|
item.self_pay_rea = i.limitUsageScope === 'Y' ? '1' : '2'
|
|||
|
|
}
|
|||
|
|
return item
|
|||
|
|
})
|
|||
|
|
return {
|
|||
|
|
patientid: data.patientId,
|
|||
|
|
registerid: "",
|
|||
|
|
orderno: data.medOrgOrderNo,
|
|||
|
|
doctorcode: data.doctorCode,
|
|||
|
|
unitcode: data.unitCode,
|
|||
|
|
visit_time: dayjs(data.prescriptionStartTime).format("YYYY-MM-DD HH:mm:ss"),
|
|||
|
|
area_code: data.areaCode,
|
|||
|
|
hospid: "108",
|
|||
|
|
details,
|
|||
|
|
icds: data.diagnosisList.map((i, idx) => ({
|
|||
|
|
icd_code: i.code,
|
|||
|
|
icd_name: i.name,
|
|||
|
|
sort: idx + 1
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
exports.encryptDiagnosticRecordFields = encryptDiagnosticRecordFields;
|
|||
|
|
exports.decryptDiagnosticRecordFields = decryptDiagnosticRecordFields;
|
|||
|
|
exports.decryptDiagnosticRecordList = decryptDiagnosticRecordList;
|
|||
|
|
exports.buildHybridSearchQuery = buildHybridSearchQuery;
|
|||
|
|
exports.buildMultiFieldHybridSearch = buildMultiFieldHybridSearch;
|
|||
|
|
exports.ENCRYPTED_FIELDS = ENCRYPTED_FIELDS;
|