Compare commits

...

2 Commits

Author SHA1 Message Date
huxuejian
0c369655b7 feat: 优化需求 2026-10-22 15:30:30 +08:00
huxuejian
a88b0edd77 feat: 优化需求开发 2026-10-21 10:54:44 +08:00
14 changed files with 256 additions and 118 deletions

View File

@ -23,3 +23,8 @@ PUPPETEER_EXECUTABLE_PATH="C:\Program Files\Google\Chrome\Application\chrome.exe
PRESCRIPTION_PDF_MAX_CONCURRENCY=2
CONFIG_PRESCRIPTION_PDF_BASE_URL=https://patient.youcan365.com/hn
## 查询药品信息的时候 带上corpId (测试数据 药品信息存在多家机构, 但是线上各自独立部署, 所以测试环境带corpId区分下)
CONFIG_SEARCH_DRUG_WITH_CORPID=YES
## 生成的咨询订单挂号id编号前缀, 也用于后续生成处方的编号 (his正式环境和测试环境同一个 生成序号规则相同, 产生同编号的话有问题, 所以加个前缀区分下)
CONFIG_CONSULT_REGISTER_ID_PREFIX=Test

View File

@ -1,52 +0,0 @@
CONFIG_DB_USERNAME=youcan
CONFIG_DB_PASSWORD=youcanTEST&2025
CONFIG_DB_HOST=119.45.106.100
CONFIG_DB_PORT=27017
CONFIG_NODE_ENV=zytDev
CONFIG_CA_BASE_URL=https://newcoss-dev.isignet.cn:10201/coss/service/v1/
CONFIG_CA_APPID=APP_7B3F36A14E99410A80B37AEF332E3247
CONFIG_CA_SECRET=DLwiH46Esb8ccNTkuSSVAadNTWUfW0sc
CONFIG_JWT_SECRET_KEY=ZYTZYY2025
CONFIG_JWT_EXPIRE_TIME=12h
CONFIG_NODE_PORT=8080
CONFIG_ZYB_YB_APPID=7D8D8E29924048539165F5E2E08C4616
CONFIG_ZYB_YB_SECRET=77F9610253B94263BCF8DBB61BF90D92
CONFIG_SMS_GATEWAY_DISABLED=true
## 支付宝回调地址
CONFIG_ALIPAY_PAY_NOTIFY=https://patient.youcan365.com/zyt/alipay-pay-notify
## 支付宝小程序appId
CONFIG_ALIPAY_MINI_APPID = 2021005110656858
## 蜂鸟即时配送请求域名
CONFIG_FENGNIAO_API_DOMAIN=https://exam-anubis.ele.me
## 蜂鸟即时配送分配的 appId 和 appSecret
CONFIG_FENGNIAO_APPID=2711175259951256784
CONFIG_FENGNIAO_SECRET=744c587a-61eb-4dc5-a226-e88b7f7b15d0
## 蜂鸟即时配送 后台管理页面 -> 应用管理 -> 查看沙箱环境 -> 商户信息的商户ID
CONFIG_FENGNIAO_MERCHANT_ID=15649332
## 蜂鸟即时配送 后台管理页面 -> 应用管理 -> 查看沙箱环境 -> 门店信息的门店编码
CONFIG_FENGNIAO_OUT_SHOP_CODE=testorder001
## 邮政快递 测试环境请求域名、分配的orgId、AES加密秘钥以及IV
CONFIG_EMS_API_DOMAIN=https://topup.beta.ule.com
## 邮政快递 测试环境分配的orgId、AES加密秘钥以及IV
CONFIG_EMS_ORGID=900004
CONFIG_EMS_AES_Key=HOKAwvtyPe9Atve4
CONFIG_EMS_AES_IV=HOKAwvtyPe9Atve4
## 邮政快递 邮乐分享用户ID (接口文档 2.1订单数据回传接口的入参uleShareUserId字段值, 由对方技术人员提供)
CONFIG_EMS_SHARE_USER_ID=yzg10000050008
## 邮政 请求地址
CONFIG_EMS_API_URL=https://api.ems.com.cn/amp-prod-api/f/amp/api/test
## 邮政 协议用户编码
CONFIG_EMS_USER_CODE=NNLXIQRYV
## 邮政 测试授权码
CONFIG_EMS_AUTH_CODE=U1pPOYv6VBULDah6
## 邮政 测试签名钥匙
CONFIG_EMS_SIGN_SECRET=ZmVRRjkyeDZnWHFnUGxkRQ==
## 邮政 协议客户号
CONFIG_EMS_SENDER_NO=1100100971796
## 震元his api
CONFIG_ZYT_HIS_BASE_URL=http://115.239.161.48:8089

16
.env.hn
View File

@ -24,3 +24,19 @@ CONFIG_ALIPAY_MINI_PRIVATE_KEY=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBA
CONFIG_HN_HIS_BASE_URL=http://122.225.16.74:8026
## im图片存储服务端的位置
CONFIG_IM_IMAGE_ROOT=/root/service/hn/private-files/im-chat
## 处方 PDF(Linux Chrome)
PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome
PRESCRIPTION_PDF_MAX_CONCURRENCY=2
CONFIG_PRESCRIPTION_PDF_ROOT=/root/service/hn/private-files/prescriptions
CONFIG_PRESCRIPTION_PDF_BASE_URL=https://patient.youcan365.com/hn
## 查询药品信息的时候 带上corpId (测试数据 药品信息存在多家机构, 但是线上各自独立部署, 所以测试环境带corpId区分下)
CONFIG_SEARCH_DRUG_WITH_CORPID=YES
## 生成的咨询订单挂号id编号前缀, 也用于后续生成处方的编号 (his正式环境和测试环境同一个 生成序号规则相同, 产生同编号的话有问题, 所以加个前缀区分下)
CONFIG_CONSULT_REGISTER_ID_PREFIX=Test

View File

@ -20,6 +20,7 @@ const TASK_STATUS = {
const ERROR_SOURCES = {
SYSTEM: "SYSTEM",
HIS: "HIS",
RATIONAL_DRUG: "RATIONAL_DRUG",
};
const TASK_CANCEL_REASONS = {
HIGH_RISK_DRUG: "HIGH_RISK_DRUG",
@ -44,7 +45,9 @@ class AutomationError extends Error {
super(message);
this.name = "AutomationError";
this.retryable = retryable;
this.source = source === ERROR_SOURCES.HIS ? ERROR_SOURCES.HIS : ERROR_SOURCES.SYSTEM;
this.source = Object.values(ERROR_SOURCES).includes(source)
? source
: ERROR_SOURCES.SYSTEM;
}
}
@ -485,15 +488,17 @@ function cleanHisUploadFailureMessage(message) {
function getFailureNotificationExt(error) {
const errorSource =
error && error.source === ERROR_SOURCES.HIS
? ERROR_SOURCES.HIS
error && Object.values(ERROR_SOURCES).includes(error.source)
? error.source
: ERROR_SOURCES.SYSTEM;
const rawReason =
error && typeof error.message === "string" ? error.message.trim() : "";
const reason =
errorSource === ERROR_SOURCES.HIS
? `HIS上传错误:${cleanHisUploadFailureMessage(rawReason) || "未知错误"}`
: `系统错误:${rawReason || "未知错误"}`;
: errorSource === ERROR_SOURCES.RATIONAL_DRUG
? `合理用药错误:${rawReason || "未知错误"}`
: `系统错误:${rawReason || "未知错误"}`;
return { errorSource, reason };
}
@ -840,6 +845,7 @@ async function resolvePrescriptionDrugs(db, order) {
dosage,
dosage_unit: dosageUnit.name,
dosage_unit_code: dosageUnit.code,
dose_time_name: requested.dose_time_name || "",
drugName: master.name,
specification: master.specification || "",
frequencyCode: frequency.code,
@ -969,9 +975,9 @@ async function handleAutoOpenRx(db, task) {
db
);
if (!reviewResult || !reviewResult.success) {
throw new AutomationError(
reviewResult?.message || "合理用药审核未通过"
);
throw new AutomationError(reviewResult?.message || "合理用药审核未通过", {
source: ERROR_SOURCES.RATIONAL_DRUG,
});
}
const result = await diagnosticRecord(

View File

@ -726,6 +726,21 @@ describe("automation task scheduling", () => {
}),
})
);
expect(tencentIM).toHaveBeenCalledWith(
expect.objectContaining({
msgBody: [
expect.objectContaining({
MsgContent: expect.objectContaining({
Ext: JSON.stringify({
errorSource: ERROR_SOURCES.RATIONAL_DRUG,
reason: "合理用药错误:该处方存在不合理用药",
}),
}),
}),
],
}),
db
);
});
test("fails automatic audit immediately and sends the failure reason", async () => {
@ -1012,6 +1027,7 @@ describe("automatic prescription assembly", () => {
dosage_form: "片剂",
days: 3,
dosage_unit: "mg",
dose_time_name: "餐后",
administration_method: "口服",
freq: "每日两次",
unit: "盒",
@ -1068,6 +1084,7 @@ describe("automatic prescription assembly", () => {
_id: drugId.toString(),
erpId: "ERP-1",
dosage_unit_code: "MG",
dose_time_name: "餐后",
frequencyCode: "BID",
usageCode: "PO",
quantity: 1,

View File

@ -10,6 +10,7 @@ const { encryptOrderFields, decryptOrderFields, decryptOrderList } = require("./
const { getRequiredDrugAccessLevels, doctorMeetsDrugAccessLevels } = require("../drug-access-level");
const doctorOrPharmacistOfflineMessage = "当前医生或药师不在线,暂无法提交问诊单,请稍后再试";
const registerIdPrefix = process.env.CONFIG_CONSULT_REGISTER_ID_PREFIX || '';
const hisPayStatus = {
0: "已支付",
@ -158,7 +159,6 @@ async function addConsultOrder(item) {
async function addOnlineConsultOrder(params) {
try {
params.registerId = await generateRegisterId(db);
const requiredDrugAccessLevels = await getRequiredDrugAccessLevels(db, params.drugs);
const storeApi = require("../drug-store");
const { success, list, message } = await storeApi(
@ -187,6 +187,7 @@ async function addOnlineConsultOrder(params) {
params.drugStoreName = store.name;
params.drugStoreNo = store.login_no;
const doctorCode = params.doctorCode.trim();
params.registerId = await generateRegisterId(db);
// 指定医生
if (doctorCode) {
const doctor = await db.collection("hlw-doctor").findOne(
@ -261,7 +262,9 @@ async function addOnlineConsultOrder(params) {
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 { insertedId } = await db
@ -2378,5 +2381,5 @@ async function generateRegisterId(db, type = 'consult-register-id') {
}
);
const sequence = result.sequence;
return `${day}${String(sequence).padStart(4, '0')}`;
return `${registerIdPrefix}${day}${String(sequence).padStart(4, '0')}`;
}

View File

@ -130,10 +130,10 @@ exports.formatUploadRxData = function (data, opt) {
appr_flag: i.forceSelfPay === 'Y' ? '2' : '1',
dose_time_name: i.dose_time_name,
}
if (item.appr_flag === '2') {
//[his要求]当appr_flag=2时必填,如果这个药品维护了限制使用范围的,传1,否则就传2
item.self_pay_rea = i.limitUsageScope === 'Y' ? '1' : '2'
}
// 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) => ({

View File

@ -2234,6 +2234,7 @@ async function getYbReviewResult(ctx, db) {
name: 1,
dosage_form: 1,
specification: 1,
forceSelfPay: 1
},
}
)
@ -2264,6 +2265,7 @@ async function getYbReviewResult(ctx, db) {
dosage: drug.dosage,
dosage_unit: drug.dosage_unit,
dose_time_name: drug.dose_time_name,
forceSelfPay: dbDrug.forceSelfPay
};
});

View File

@ -6,6 +6,8 @@ const { validateApplicableDiagnosisCodes } = require('./applicable-diagnosis');
const hnHis = require("../hn-his");
let db = "";
const WithCorpId = process.env.CONFIG_SEARCH_DRUG_WITH_CORPID === 'YES';
function getConfigOptionNames(list) {
return [...new Set((Array.isArray(list) ? list : [])
.map(item => typeof item === "string" ? item : item && item.name)
@ -67,6 +69,9 @@ async function getDrugInfo(item) {
let { name, _id, ids, pinyin_code, keyword, insuranceCodes, barcode } = item;
let fuzzyQuery = null;
let query = { onSale: true };
if (WithCorpId) {
query.corpId = item.corpId
}
if (typeof name === "string") query.name = new RegExp(name.trim(), "i");
if (_id) query._id = new ObjectId(_id);
if (Array.isArray(ids) && ids.length > 0) {
@ -211,6 +216,9 @@ async function getHlwDrugInfo(ctx) {
const page = Number.isSafeInteger(requestedPage) && requestedPage > 0 ? requestedPage : 1;
const pageSize = Number.isSafeInteger(requestedPageSize) && requestedPageSize > 0 ? requestedPageSize : 10;
const query = {};
if (WithCorpId) {
query.corpId = ctx.corpId
}
// if (typeof ctx.corpId === "string" && ctx.corpId.trim()) {
// query.corpId = ctx.corpId.trim();
// }
@ -285,6 +293,9 @@ async function addHlwDrugInfo(ctx) {
newDrug.tumor_use = 0;
}
newDrug.createTime = Date.now();
if (WithCorpId) {
newDrug.corpId = ctx.corpId
}
const res = await db.collection("drug-info").insertOne(newDrug);
if (res && res.insertedId) {
updateHisDrugInfo({ id: res.insertedId.toString() })

View File

@ -23,6 +23,7 @@ const drugFieldDict = [
{ name: '抗生素级别', field: 'antibiotic_level', verify: (val, label) => validator.verifyListItem(val, [0, 1, 2, 3], false, label, 0) },
{ name: '肿瘤使用', field: 'tumor_use', verify: (val, label) => validator.verifyListItem(val, [0, 1, 2, 3], false, label, 0) },
{ name: '风险等级', field: 'riskLevel', verify: (val, label) => validator.verifyListItem(val, ['低风险', '高风险'], false, label) },
{ name: '默认医保自费', field: 'forceSelfPay', verify: (val, label) => validator.verifyListItem(val, ['Y', 'N'], false, label) },
// 仅在线药品库使用:管理分类(处方药 / OTC)与剂型
{ name: '管理分类', field: 'manage_category', verify: (val, label) => validator.verifyString(val, label) },
{ name: '剂型', field: 'dosage_form', verify: (val, label) => validator.verifyString(val, label) },

View File

@ -53,22 +53,55 @@ async function getDiagnosisList(item) {
if (category && typeof category === "string") {
query.category = new RegExp(category.trim(), "i");
}
if (typeof keyword == "string" && keyword.trim()) {
const normalizedKeyword = typeof keyword === "string" ? keyword.trim() : "";
if (normalizedKeyword) {
query.$or = [
{ name: new RegExp(keyword.trim(), "i") },
{ code: new RegExp(keyword.trim(), "i") },
{ category: new RegExp(keyword.trim(), "i") },
{ pinyin: new RegExp(keyword.trim(), "i") },
{ name: new RegExp(normalizedKeyword, "i") },
{ code: new RegExp(normalizedKeyword, "i") },
{ category: new RegExp(normalizedKeyword, "i") },
{ pinyin: new RegExp(normalizedKeyword, "i") },
];
}
const res = await db
.collection("hlw-diagnosis")
.find(query)
.sort({ _id: -1 })
.skip((page - 1) * pageSize)
.limit(pageSize)
.toArray();
const total = await db.collection("hlw-diagnosis").countDocuments(query);
const collection = db.collection("hlw-diagnosis");
let res;
if (normalizedKeyword) {
// Keep fuzzy search behavior, but bring an exact match for any searchable
// field to the front before applying pagination.
const exactKeyword = `^${normalizedKeyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`;
res = await collection.aggregate([
{ $match: query },
{
$addFields: {
exactKeywordMatch: {
$cond: [
{
$or: [
{ $regexMatch: { input: { $ifNull: ["$name", ""] }, regex: exactKeyword, options: "i" } },
{ $regexMatch: { input: { $ifNull: ["$code", ""] }, regex: exactKeyword, options: "i" } },
{ $regexMatch: { input: { $ifNull: ["$category", ""] }, regex: exactKeyword, options: "i" } },
{ $regexMatch: { input: { $ifNull: ["$pinyin", ""] }, regex: exactKeyword, options: "i" } },
],
},
1,
0,
],
},
},
},
{ $sort: { exactKeywordMatch: -1, _id: -1 } },
{ $skip: (page - 1) * pageSize },
{ $limit: pageSize },
{ $project: { exactKeywordMatch: 0 } },
]).toArray();
} else {
res = await collection
.find(query)
.sort({ _id: -1 })
.skip((page - 1) * pageSize)
.limit(pageSize)
.toArray();
}
const total = await collection.countDocuments(query);
return {
success: true,
message: "查询成功",

View File

@ -31,6 +31,18 @@ function validateAccountId(accountId) {
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) {
const accountResult = validateAccountId(item && item.accountId);
if (!accountResult.success) return accountResult;
@ -38,9 +50,28 @@ function validatePatient(item) {
const name = typeof item.name === 'string' ? item.name.trim() : '';
const certNo = typeof item.certNo === 'string' ? item.certNo.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 (!certNo) return { success: false, message: '证件号不能为空' };
let certInfo = null;
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 (!validator.isMobile(mobile)) {
return { success: false, message: '手机号格式不正确' };
@ -60,13 +91,17 @@ function validatePatient(item) {
name,
certNo,
mobile,
birthday,
sex,
address,
},
data: {
accountId: accountResult.accountId,
anotherIdNo: Sm4Util.encryptDataForSm3(certNo),
anotherIdNo: certNo ? Sm4Util.encryptDataForSm3(certNo) : '',
anotherName: Sm4Util.encryptDataForSm3(name),
anotherMobile: Sm4Util.encryptDataForSm3(mobile),
birthday,
sex,
address,
},
};
@ -77,24 +112,28 @@ async function addHlwPatient(item, db) {
const validation = validatePatient(item);
if (!validation.success) return validation;
const exists = await db.collection(COLLECTION_NAME).countDocuments({
accountId: validation.data.accountId,
anotherIdNo: validation.data.anotherIdNo,
disabled: false,
});
if (exists > 0) {
return { success: false, message: '当前账户下已存在相同证件号的就诊人' };
if (validation.origin.certNo) {
const exists = await db.collection(COLLECTION_NAME).countDocuments({
accountId: validation.data.accountId,
anotherIdNo: validation.data.anotherIdNo,
disabled: false,
});
if (exists > 0) {
return { success: false, message: '当前账户下已存在相同证件号的就诊人' };
}
}
console.log(validation.data)
const res = await hnHis({
type: 'addHisCustomer',
name: validation.origin.name,
idCard: validation.origin.certNo,
mobile: validation.origin.mobile,
address: validation.origin.address,
})
if (!res.success) return res;
// if (validation.origin.certNo) {
// const res = await hnHis({
// type: 'addHisCustomer',
// name: validation.origin.name,
// idCard: validation.origin.certNo,
// mobile: validation.origin.mobile,
// address: validation.origin.address,
// birthday: validation.origin.birthday,
// sex: validation.origin.sex,
// })
// if (!res.success) return res;
// }
const result = await db.collection(COLLECTION_NAME).insertOne({
...validation.data,
@ -117,14 +156,16 @@ async function autoAddHlwPatient(item, db) {
const validation = validatePatient(item);
if (!validation.success) return validation;
const exists = await db.collection(COLLECTION_NAME).countDocuments({
accountId: validation.data.accountId,
anotherIdNo: validation.data.anotherIdNo,
disabled: false,
});
if (validation.origin.certNo) {
const exists = await db.collection(COLLECTION_NAME).countDocuments({
accountId: validation.data.accountId,
anotherIdNo: validation.data.anotherIdNo,
disabled: false,
});
if (exists > 0) {
return { success: true, data: true, message: '就诊人已存在' };
if (exists > 0) {
return { success: true, data: true, message: '就诊人已存在' };
}
}
const result = await addHlwPatient(item, db);
@ -144,7 +185,7 @@ async function getHlwPatientList(item, db) {
.find({ accountId: validation.accountId, disabled: false })
.toArray();
const data = patients.map(toPatientData);
const data = patients.map((patient) => toPatientData(patient, true));
return { success: true, message: '查询就诊人列表成功', data };
} catch (error) {
@ -175,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 {
id: patient._id.toString(),
accountId: patient.accountId,
name: Sm4Util.decryptDataForSm3(patient.anotherName),
certNo: Sm4Util.decryptDataForSm3(patient.anotherIdNo),
certNo,
mobile: Sm4Util.decryptDataForSm3(patient.anotherMobile),
birthday,
sex,
...(normalizeDemographics ? { age: calculateAge(birthday) } : {}),
address: patient.address || '',
createTime: patient.createTime,
};

View File

@ -75,9 +75,13 @@ async function addHisCustomer(item) {
const address = typeof item.address === 'string' ? item.address.trim() : '';
const psnToken = typeof item.psnToken === 'string' ? item.psnToken.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 card_sn = typeof item.card_sn === 'string' ? item.card_sn.trim() : '';
if (!name || !idCard || !mobile) {
return { success: false, message: '姓名、证件号、手机号不能为空' }
const birthday = typeof item.birthday === 'string' ? item.birthday.trim() : '';
const sex = typeof item.sex === 'string' ? item.sex.trim() : '';
if (!name || !mobile) {
return { success: false, message: '姓名、手机号不能为空' }
}
const payload = {
type: 'addHisCustomer',
@ -87,21 +91,24 @@ async function addHisCustomer(item) {
address,
buildType: '1', // 1.自费建档 2.电子凭证建档 3.线下医保
};
if (!idCard) {
payload.brdy = birthday;
payload.gend = sex === '男' ? 1 : 2
}
// 电子凭证建档 医保插件授权建档
if (psnToken) {
payload.psnToken = psnToken;
payload.buildType = "2";
// payload.mdtrt_cert_type = '01'
}
// 线下医保建档
// mdtrt_cert_type 就诊凭证类型 01 | 03
// mdtrt_cert_no 就诊凭证号码 mdtrt_cert_type为01 填写电子凭证令牌 | mdtrt_cert_type为03 填写社会保障卡卡号
if (mdtrt_cert_no) {
} else if (mdtrt_cert_no) {
payload.mdtrt_cert_type = '03';
payload.mdtrt_cert_no = mdtrt_cert_no;
payload.card_sn = card_sn; //就诊凭证类型为“03”时填写社会保障卡内码
} else if (ecToken) {
payload.buildType = '2';
payload.mdtrt_cert_type = '01';
payload.mdtrt_cert_no = ecToken;
}
const { data, status_code, message } = await request.main(
url,
payload,

View File

@ -173,10 +173,32 @@ function isChinaId(s) {
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 = {
verifyString,
verifyNumber,
verifyListItem,
isMobile,
isChinaId
}
isChinaId,
getChinaIdInfo,
}