feat: 优化需求
This commit is contained in:
parent
a88b0edd77
commit
0c369655b7
2
.env.dev
2
.env.dev
@ -26,3 +26,5 @@ CONFIG_PRESCRIPTION_PDF_BASE_URL=https://patient.youcan365.com/hn
|
|||||||
## 查询药品信息的时候 带上corpId (测试数据 药品信息存在多家机构, 但是线上各自独立部署, 所以测试环境带corpId区分下)
|
## 查询药品信息的时候 带上corpId (测试数据 药品信息存在多家机构, 但是线上各自独立部署, 所以测试环境带corpId区分下)
|
||||||
CONFIG_SEARCH_DRUG_WITH_CORPID=YES
|
CONFIG_SEARCH_DRUG_WITH_CORPID=YES
|
||||||
|
|
||||||
|
## 生成的咨询订单挂号id编号前缀, 也用于后续生成处方的编号 (his正式环境和测试环境同一个 生成序号规则相同, 产生同编号的话有问题, 所以加个前缀区分下)
|
||||||
|
CONFIG_CONSULT_REGISTER_ID_PREFIX=Test
|
||||||
2
.env.hn
2
.env.hn
@ -37,4 +37,6 @@ CONFIG_PRESCRIPTION_PDF_BASE_URL=https://patient.youcan365.com/hn
|
|||||||
## 查询药品信息的时候 带上corpId (测试数据 药品信息存在多家机构, 但是线上各自独立部署, 所以测试环境带corpId区分下)
|
## 查询药品信息的时候 带上corpId (测试数据 药品信息存在多家机构, 但是线上各自独立部署, 所以测试环境带corpId区分下)
|
||||||
CONFIG_SEARCH_DRUG_WITH_CORPID=YES
|
CONFIG_SEARCH_DRUG_WITH_CORPID=YES
|
||||||
|
|
||||||
|
## 生成的咨询订单挂号id编号前缀, 也用于后续生成处方的编号 (his正式环境和测试环境同一个 生成序号规则相同, 产生同编号的话有问题, 所以加个前缀区分下)
|
||||||
|
CONFIG_CONSULT_REGISTER_ID_PREFIX=Test
|
||||||
|
|
||||||
|
|||||||
@ -498,7 +498,7 @@ function getFailureNotificationExt(error) {
|
|||||||
? `HIS上传错误:${cleanHisUploadFailureMessage(rawReason) || "未知错误"}`
|
? `HIS上传错误:${cleanHisUploadFailureMessage(rawReason) || "未知错误"}`
|
||||||
: errorSource === ERROR_SOURCES.RATIONAL_DRUG
|
: errorSource === ERROR_SOURCES.RATIONAL_DRUG
|
||||||
? `合理用药错误:${rawReason || "未知错误"}`
|
? `合理用药错误:${rawReason || "未知错误"}`
|
||||||
: `系统错误:${rawReason || "未知错误"}`;
|
: `系统错误:${rawReason || "未知错误"}`;
|
||||||
return { errorSource, reason };
|
return { errorSource, reason };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,6 +845,7 @@ async function resolvePrescriptionDrugs(db, order) {
|
|||||||
dosage,
|
dosage,
|
||||||
dosage_unit: dosageUnit.name,
|
dosage_unit: dosageUnit.name,
|
||||||
dosage_unit_code: dosageUnit.code,
|
dosage_unit_code: dosageUnit.code,
|
||||||
|
dose_time_name: requested.dose_time_name || "",
|
||||||
drugName: master.name,
|
drugName: master.name,
|
||||||
specification: master.specification || "",
|
specification: master.specification || "",
|
||||||
frequencyCode: frequency.code,
|
frequencyCode: frequency.code,
|
||||||
|
|||||||
@ -1027,6 +1027,7 @@ describe("automatic prescription assembly", () => {
|
|||||||
dosage_form: "片剂",
|
dosage_form: "片剂",
|
||||||
days: 3,
|
days: 3,
|
||||||
dosage_unit: "mg",
|
dosage_unit: "mg",
|
||||||
|
dose_time_name: "餐后",
|
||||||
administration_method: "口服",
|
administration_method: "口服",
|
||||||
freq: "每日两次",
|
freq: "每日两次",
|
||||||
unit: "盒",
|
unit: "盒",
|
||||||
@ -1083,6 +1084,7 @@ describe("automatic prescription assembly", () => {
|
|||||||
_id: drugId.toString(),
|
_id: drugId.toString(),
|
||||||
erpId: "ERP-1",
|
erpId: "ERP-1",
|
||||||
dosage_unit_code: "MG",
|
dosage_unit_code: "MG",
|
||||||
|
dose_time_name: "餐后",
|
||||||
frequencyCode: "BID",
|
frequencyCode: "BID",
|
||||||
usageCode: "PO",
|
usageCode: "PO",
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const { encryptOrderFields, decryptOrderFields, decryptOrderList } = require("./
|
|||||||
const { getRequiredDrugAccessLevels, doctorMeetsDrugAccessLevels } = require("../drug-access-level");
|
const { getRequiredDrugAccessLevels, doctorMeetsDrugAccessLevels } = require("../drug-access-level");
|
||||||
|
|
||||||
const doctorOrPharmacistOfflineMessage = "当前医生或药师不在线,暂无法提交问诊单,请稍后再试";
|
const doctorOrPharmacistOfflineMessage = "当前医生或药师不在线,暂无法提交问诊单,请稍后再试";
|
||||||
|
const registerIdPrefix = process.env.CONFIG_CONSULT_REGISTER_ID_PREFIX || '';
|
||||||
|
|
||||||
const hisPayStatus = {
|
const hisPayStatus = {
|
||||||
0: "已支付",
|
0: "已支付",
|
||||||
@ -158,7 +159,6 @@ async function addConsultOrder(item) {
|
|||||||
|
|
||||||
async function addOnlineConsultOrder(params) {
|
async function addOnlineConsultOrder(params) {
|
||||||
try {
|
try {
|
||||||
params.registerId = await generateRegisterId(db);
|
|
||||||
const requiredDrugAccessLevels = await getRequiredDrugAccessLevels(db, params.drugs);
|
const requiredDrugAccessLevels = await getRequiredDrugAccessLevels(db, params.drugs);
|
||||||
const storeApi = require("../drug-store");
|
const storeApi = require("../drug-store");
|
||||||
const { success, list, message } = await storeApi(
|
const { success, list, message } = await storeApi(
|
||||||
@ -187,6 +187,7 @@ async function addOnlineConsultOrder(params) {
|
|||||||
params.drugStoreName = store.name;
|
params.drugStoreName = store.name;
|
||||||
params.drugStoreNo = store.login_no;
|
params.drugStoreNo = store.login_no;
|
||||||
const doctorCode = params.doctorCode.trim();
|
const doctorCode = params.doctorCode.trim();
|
||||||
|
params.registerId = await generateRegisterId(db);
|
||||||
// 指定医生
|
// 指定医生
|
||||||
if (doctorCode) {
|
if (doctorCode) {
|
||||||
const doctor = await db.collection("hlw-doctor").findOne(
|
const doctor = await db.collection("hlw-doctor").findOne(
|
||||||
@ -261,7 +262,9 @@ async function addOnlineConsultOrder(params) {
|
|||||||
errorInfo: imAccountResult.errorInfo,
|
errorInfo: imAccountResult.errorInfo,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
params.medorg_order_no = common.generateUniqueStr('HLW', 12);
|
const registerId = await generateRegisterId(db);
|
||||||
|
params.registerId = registerId
|
||||||
|
params.medorg_order_no = registerId;
|
||||||
// 加密敏感字段
|
// 加密敏感字段
|
||||||
const encryptedParams = encryptOrderFields(params);
|
const encryptedParams = encryptOrderFields(params);
|
||||||
const { insertedId } = await db
|
const { insertedId } = await db
|
||||||
@ -2378,5 +2381,5 @@ async function generateRegisterId(db, type = 'consult-register-id') {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
const sequence = result.sequence;
|
const sequence = result.sequence;
|
||||||
return `${day}${String(sequence).padStart(4, '0')}`;
|
return `${registerIdPrefix}${day}${String(sequence).padStart(4, '0')}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -130,10 +130,10 @@ exports.formatUploadRxData = function (data, opt) {
|
|||||||
appr_flag: i.forceSelfPay === 'Y' ? '2' : '1',
|
appr_flag: i.forceSelfPay === 'Y' ? '2' : '1',
|
||||||
dose_time_name: i.dose_time_name,
|
dose_time_name: i.dose_time_name,
|
||||||
}
|
}
|
||||||
if (item.appr_flag === '2') {
|
// if (item.appr_flag === '2') {
|
||||||
//[his要求]当appr_flag=2时必填,如果这个药品维护了限制使用范围的,传1,否则就传2
|
// //[his要求]当appr_flag=2时必填,如果这个药品维护了限制使用范围的,传1,否则就传2
|
||||||
item.self_pay_rea = i.limitUsageScope === 'Y' ? '1' : '2'
|
// item.self_pay_rea = i.limitUsageScope === 'Y' ? '1' : '2'
|
||||||
}
|
// }
|
||||||
return item
|
return item
|
||||||
}),
|
}),
|
||||||
icds: data.diagnosisList.map((i) => ({
|
icds: data.diagnosisList.map((i) => ({
|
||||||
|
|||||||
@ -2234,6 +2234,7 @@ async function getYbReviewResult(ctx, db) {
|
|||||||
name: 1,
|
name: 1,
|
||||||
dosage_form: 1,
|
dosage_form: 1,
|
||||||
specification: 1,
|
specification: 1,
|
||||||
|
forceSelfPay: 1
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -2264,6 +2265,7 @@ async function getYbReviewResult(ctx, db) {
|
|||||||
dosage: drug.dosage,
|
dosage: drug.dosage,
|
||||||
dosage_unit: drug.dosage_unit,
|
dosage_unit: drug.dosage_unit,
|
||||||
dose_time_name: drug.dose_time_name,
|
dose_time_name: drug.dose_time_name,
|
||||||
|
forceSelfPay: dbDrug.forceSelfPay
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,18 @@ function validateAccountId(accountId) {
|
|||||||
return { success: true, accountId: accountId.trim() };
|
return { success: true, accountId: accountId.trim() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidBirthday(birthday) {
|
||||||
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(birthday)) return false;
|
||||||
|
const [year, month, day] = birthday.split('-').map(Number);
|
||||||
|
const date = new Date(Date.UTC(year, month - 1, day));
|
||||||
|
return (
|
||||||
|
date.getUTCFullYear() === year
|
||||||
|
&& date.getUTCMonth() + 1 === month
|
||||||
|
&& date.getUTCDate() === day
|
||||||
|
&& date.getTime() <= Date.now()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function validatePatient(item) {
|
function validatePatient(item) {
|
||||||
const accountResult = validateAccountId(item && item.accountId);
|
const accountResult = validateAccountId(item && item.accountId);
|
||||||
if (!accountResult.success) return accountResult;
|
if (!accountResult.success) return accountResult;
|
||||||
@ -38,10 +50,27 @@ function validatePatient(item) {
|
|||||||
const name = typeof item.name === 'string' ? item.name.trim() : '';
|
const name = typeof item.name === 'string' ? item.name.trim() : '';
|
||||||
const certNo = typeof item.certNo === 'string' ? item.certNo.trim() : '';
|
const certNo = typeof item.certNo === 'string' ? item.certNo.trim() : '';
|
||||||
const mobile = typeof item.mobile === 'string' ? item.mobile.trim() : '';
|
const mobile = typeof item.mobile === 'string' ? item.mobile.trim() : '';
|
||||||
|
let birthday = typeof item.birthday === 'string' ? item.birthday.trim() : '';
|
||||||
|
let sex = typeof item.sex === 'string' ? item.sex.trim() : '';
|
||||||
|
|
||||||
if (!name) return { success: false, message: '姓名不能为空' };
|
if (!name) return { success: false, message: '姓名不能为空' };
|
||||||
if (certNo && !validator.isChinaId(certNo)) {
|
let certInfo = null;
|
||||||
return { success: false, message: '证件号格式不正确' };
|
if (certNo) {
|
||||||
|
certInfo = validator.getChinaIdInfo(certNo);
|
||||||
|
if (!certInfo) return { success: false, message: '证件号格式不正确' };
|
||||||
|
birthday = birthday || certInfo.birthday;
|
||||||
|
sex = sex || certInfo.sex;
|
||||||
|
}
|
||||||
|
if (!birthday) return { success: false, message: '出生日期不能为空' };
|
||||||
|
if (!isValidBirthday(birthday)) {
|
||||||
|
return { success: false, message: '出生日期格式不正确' };
|
||||||
|
}
|
||||||
|
if (!sex) return { success: false, message: '性别不能为空' };
|
||||||
|
if (!['男', '女'].includes(sex)) {
|
||||||
|
return { success: false, message: '性别格式不正确' };
|
||||||
|
}
|
||||||
|
if (certInfo && (birthday !== certInfo.birthday || sex !== certInfo.sex)) {
|
||||||
|
return { success: false, message: '出生日期或性别与证件号信息不一致' };
|
||||||
}
|
}
|
||||||
if (!mobile) return { success: false, message: '手机号不能为空' };
|
if (!mobile) return { success: false, message: '手机号不能为空' };
|
||||||
if (!validator.isMobile(mobile)) {
|
if (!validator.isMobile(mobile)) {
|
||||||
@ -62,6 +91,8 @@ function validatePatient(item) {
|
|||||||
name,
|
name,
|
||||||
certNo,
|
certNo,
|
||||||
mobile,
|
mobile,
|
||||||
|
birthday,
|
||||||
|
sex,
|
||||||
address,
|
address,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
@ -69,6 +100,8 @@ function validatePatient(item) {
|
|||||||
anotherIdNo: certNo ? Sm4Util.encryptDataForSm3(certNo) : '',
|
anotherIdNo: certNo ? Sm4Util.encryptDataForSm3(certNo) : '',
|
||||||
anotherName: Sm4Util.encryptDataForSm3(name),
|
anotherName: Sm4Util.encryptDataForSm3(name),
|
||||||
anotherMobile: Sm4Util.encryptDataForSm3(mobile),
|
anotherMobile: Sm4Util.encryptDataForSm3(mobile),
|
||||||
|
birthday,
|
||||||
|
sex,
|
||||||
address,
|
address,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -90,14 +123,16 @@ async function addHlwPatient(item, db) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if (validation.origin.certNo) {
|
// if (validation.origin.certNo) {
|
||||||
const res = await hnHis({
|
// const res = await hnHis({
|
||||||
type: 'addHisCustomer',
|
// type: 'addHisCustomer',
|
||||||
name: validation.origin.name,
|
// name: validation.origin.name,
|
||||||
idCard: validation.origin.certNo,
|
// idCard: validation.origin.certNo,
|
||||||
mobile: validation.origin.mobile,
|
// mobile: validation.origin.mobile,
|
||||||
address: validation.origin.address,
|
// address: validation.origin.address,
|
||||||
})
|
// birthday: validation.origin.birthday,
|
||||||
if (!res.success) return res;
|
// sex: validation.origin.sex,
|
||||||
|
// })
|
||||||
|
// if (!res.success) return res;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const result = await db.collection(COLLECTION_NAME).insertOne({
|
const result = await db.collection(COLLECTION_NAME).insertOne({
|
||||||
@ -150,7 +185,7 @@ async function getHlwPatientList(item, db) {
|
|||||||
.find({ accountId: validation.accountId, disabled: false })
|
.find({ accountId: validation.accountId, disabled: false })
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
const data = patients.map(toPatientData);
|
const data = patients.map((patient) => toPatientData(patient, true));
|
||||||
|
|
||||||
return { success: true, message: '查询就诊人列表成功', data };
|
return { success: true, message: '查询就诊人列表成功', data };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -181,13 +216,39 @@ async function getHlwPatient(item, db) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toPatientData(patient) {
|
function calculateAge(birthday) {
|
||||||
|
if (!isValidBirthday(birthday)) return '';
|
||||||
|
|
||||||
|
const [birthYear, birthMonth, birthDay] = birthday.split('-').map(Number);
|
||||||
|
const today = new Date();
|
||||||
|
let age = today.getFullYear() - birthYear;
|
||||||
|
const hasHadBirthdayThisYear = (
|
||||||
|
today.getMonth() + 1 > birthMonth
|
||||||
|
|| (today.getMonth() + 1 === birthMonth && today.getDate() >= birthDay)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasHadBirthdayThisYear) age -= 1;
|
||||||
|
return age > 0 ? age : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPatientData(patient, normalizeDemographics = false) {
|
||||||
|
const certNo = Sm4Util.decryptDataForSm3(patient.anotherIdNo);
|
||||||
|
const certInfo = normalizeDemographics && certNo
|
||||||
|
? validator.getChinaIdInfo(certNo)
|
||||||
|
: null;
|
||||||
|
// 证件号信息仅用于本次响应,不回写数据库中的历史就诊人数据。
|
||||||
|
const birthday = certInfo ? certInfo.birthday : (patient.birthday || '');
|
||||||
|
const sex = certInfo ? certInfo.sex : (patient.sex || '');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: patient._id.toString(),
|
id: patient._id.toString(),
|
||||||
accountId: patient.accountId,
|
accountId: patient.accountId,
|
||||||
name: Sm4Util.decryptDataForSm3(patient.anotherName),
|
name: Sm4Util.decryptDataForSm3(patient.anotherName),
|
||||||
certNo: Sm4Util.decryptDataForSm3(patient.anotherIdNo),
|
certNo,
|
||||||
mobile: Sm4Util.decryptDataForSm3(patient.anotherMobile),
|
mobile: Sm4Util.decryptDataForSm3(patient.anotherMobile),
|
||||||
|
birthday,
|
||||||
|
sex,
|
||||||
|
...(normalizeDemographics ? { age: calculateAge(birthday) } : {}),
|
||||||
address: patient.address || '',
|
address: patient.address || '',
|
||||||
createTime: patient.createTime,
|
createTime: patient.createTime,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -77,8 +77,11 @@ async function addHisCustomer(item) {
|
|||||||
const mdtrt_cert_no = typeof item.mdtrt_cert_no === 'string' ? item.mdtrt_cert_no.trim() : '';
|
const mdtrt_cert_no = typeof item.mdtrt_cert_no === 'string' ? item.mdtrt_cert_no.trim() : '';
|
||||||
const ecToken = typeof item.ecToken === 'string' ? item.ecToken.trim() : '';
|
const ecToken = typeof item.ecToken === 'string' ? item.ecToken.trim() : '';
|
||||||
const card_sn = typeof item.card_sn === 'string' ? item.card_sn.trim() : '';
|
const card_sn = typeof item.card_sn === 'string' ? item.card_sn.trim() : '';
|
||||||
|
const birthday = typeof item.birthday === 'string' ? item.birthday.trim() : '';
|
||||||
|
const sex = typeof item.sex === 'string' ? item.sex.trim() : '';
|
||||||
|
|
||||||
if (!name || !mobile) {
|
if (!name || !mobile) {
|
||||||
return { success: false, message: '姓名、证件号、手机号不能为空' }
|
return { success: false, message: '姓名、手机号不能为空' }
|
||||||
}
|
}
|
||||||
const payload = {
|
const payload = {
|
||||||
type: 'addHisCustomer',
|
type: 'addHisCustomer',
|
||||||
@ -88,6 +91,10 @@ async function addHisCustomer(item) {
|
|||||||
address,
|
address,
|
||||||
buildType: '1', // 1.自费建档 2.电子凭证建档 3.线下医保
|
buildType: '1', // 1.自费建档 2.电子凭证建档 3.线下医保
|
||||||
};
|
};
|
||||||
|
if (!idCard) {
|
||||||
|
payload.brdy = birthday;
|
||||||
|
payload.gend = sex === '男' ? 1 : 2
|
||||||
|
}
|
||||||
// 电子凭证建档 医保插件授权建档
|
// 电子凭证建档 医保插件授权建档
|
||||||
if (psnToken) {
|
if (psnToken) {
|
||||||
payload.psnToken = psnToken;
|
payload.psnToken = psnToken;
|
||||||
|
|||||||
@ -173,10 +173,32 @@ function isChinaId(s) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChinaIdInfo(s) {
|
||||||
|
if (typeof s !== 'string' || !isChinaId(s)) return null;
|
||||||
|
|
||||||
|
const sId = idTransfer(s);
|
||||||
|
const birthday = `${sId.substring(6, 10)}-${sId.substring(10, 12)}-${sId.substring(12, 14)}`;
|
||||||
|
const [year, month, day] = birthday.split('-').map(Number);
|
||||||
|
const date = new Date(Date.UTC(year, month - 1, day));
|
||||||
|
if (
|
||||||
|
date.getUTCFullYear() !== year
|
||||||
|
|| date.getUTCMonth() + 1 !== month
|
||||||
|
|| date.getUTCDate() !== day
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
birthday,
|
||||||
|
sex: Number(sId.charAt(16)) % 2 === 0 ? '女' : '男',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
verifyString,
|
verifyString,
|
||||||
verifyNumber,
|
verifyNumber,
|
||||||
verifyListItem,
|
verifyListItem,
|
||||||
isMobile,
|
isMobile,
|
||||||
isChinaId
|
isChinaId,
|
||||||
}
|
getChinaIdInfo,
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user