feat: 接口调整

This commit is contained in:
huxuejian 2026-09-21 17:04:40 +08:00
parent c8f4c72205
commit 0165c2c064
5 changed files with 209 additions and 8 deletions

View File

@ -261,6 +261,8 @@ async function addHlwDrugInfo(ctx) {
}
const diagnosisCodes = await validateApplicableDiagnosisCodes(params, db);
const { onSale, applicableDiagnosisCodes, ...data } = params;
// ERP ID is allocated by the service so clients cannot supply or predict it.
data.erpId = await generateDrugErpId(db);
let newDrug = {};
if (Object.keys(data).length) {
const [item] = getDrugList([data], true, peopleInfo, 'hlw', optionLists);
@ -299,6 +301,9 @@ async function editHlwDrugInfo(ctx) {
const optionLists = await getHlwDrugOptionLists(ctx.corpId);
const diagnosisCodes = await validateApplicableDiagnosisCodes(params, db);
const { onSale, applicableDiagnosisCodes, ...data } = params;
// ERP ID is immutable after creation. Ignore it even when sent by an older
// client or a manually constructed request.
delete data.erpId;
const currentDrug = await db.collection("drug-info").findOne(
{ _id: new ObjectId(id) },
{ projection: { erpId: 1, product_id: 1, product_id_str: 1 } }
@ -306,13 +311,6 @@ async function editHlwDrugInfo(ctx) {
if (!currentDrug) {
return { success: false, message: "未找到对应药品" }
}
const legacyErpId = currentDrug.product_id_str || currentDrug.product_id;
const erpId = Object.prototype.hasOwnProperty.call(data, "erpId")
? data.erpId
: (currentDrug.erpId || (legacyErpId || legacyErpId === 0 ? String(legacyErpId) : ""));
if (typeof erpId !== "string" || !erpId.trim()) {
return { success: false, message: "ERP ID不能为空" }
}
let updateData = {};
if (Object.keys(data).length) {
const peopleInfo = {
@ -349,6 +347,23 @@ async function editHlwDrugInfo(ctx) {
}
async function generateDrugErpId(db) {
const key = 'drug-erp-id';
const type = 'drug-erp-id';
const result = await db.collection('sequence-counter').findOneAndUpdate(
{ key, type },
{
$inc: { sequence: 1 },
$setOnInsert: { key, type }
},
{
upsert: true,
returnDocument: 'after'
}
);
return String(result.sequence).padStart(6, '0');
}
async function setHlwDrugOnSale(ctx) {
const { ids, onSale, updaterId, updater } = ctx;
const _ids = Array.isArray(ids) ? ids.filter(i => typeof i === 'string' && i.trim()).map(i => new ObjectId(i.trim())) : [ids];

View File

@ -558,6 +558,9 @@ async function getAllDoctorNos(ctx) {
try {
const jobs = Array.isArray(ctx.jobs) ? ctx.jobs : ['doctor'];
const query = ctx.showAll === true ? {} : { job: { $in: jobs } };
if (typeof ctx.corpId === 'string' && ctx.corpId.trim()) {
query.corpId = ctx.corpId.trim();
}
const res = await db
.collection("hlw-doctor")
.find(query, { projection: { doctorNo: 1, doctorName: 1, job: 1 } })

163
hlw/hlw-schedule/index.js Normal file
View File

@ -0,0 +1,163 @@
const dayjs = require('dayjs');
module.exports = async (item, db) => {
switch (item.type) {
case 'getHlwSchedule':
return getHlwSchedule(item, db);
case 'saveHlwSchedule':
return saveHlwSchedule(item, db);
case 'setTodayScheduledPeopleOnline':
return setTodayScheduledPeopleOnline(db);
}
};
function getDate(value) {
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return '';
const parsed = dayjs(value);
return parsed.isValid() && parsed.format('YYYY-MM-DD') === value ? value : '';
}
function getMonth(value) {
if (typeof value !== 'string' || !/^\d{4}-\d{2}$/.test(value)) return '';
const parsed = dayjs(`${value}-01`);
return parsed.isValid() && parsed.format('YYYY-MM') === value ? value : '';
}
async function getHlwSchedule({ corpId, month }, db) {
const normalizedCorpId = typeof corpId === 'string' ? corpId.trim() : '';
const normalizedMonth = getMonth(month);
if (!normalizedCorpId || !normalizedMonth) return { success: false, message: '机构或月份参数错误' };
try {
const startDate = `${normalizedMonth}-01`;
const endDate = dayjs(startDate).add(1, 'month').format('YYYY-MM-DD');
const data = await db.collection('hlw-schedule')
.find({ corpId: normalizedCorpId, date: { $gte: startDate, $lt: endDate } }, { projection: { _id: 0 } })
.sort({ date: 1 })
.toArray();
return { success: true, message: '查询成功', data };
} catch (error) {
return { success: false, message: error.message || '查询排班失败' };
}
}
async function saveHlwSchedule({ corpId, date, doctorNos = [], pharmacistNos = [], operator, operatorId }, db) {
const normalizedCorpId = typeof corpId === 'string' ? corpId.trim() : '';
const normalizedDate = getDate(date);
if (!normalizedCorpId || !normalizedDate) return { success: false, message: '机构或日期参数错误' };
if (dayjs(normalizedDate).isBefore(dayjs(), 'day')) return { success: false, message: '过去日期的排班不可编辑' };
const normalizeNos = values => [...new Set((Array.isArray(values) ? values : [])
.filter(value => typeof value === 'string' && value.trim())
.map(value => value.trim()))];
const normalizedDoctorNos = normalizeNos(doctorNos);
const normalizedPharmacistNos = normalizeNos(pharmacistNos);
try {
const personnel = await db.collection('hlw-doctor').find(
{
corpId: normalizedCorpId,
doctorNo: { $in: [...normalizedDoctorNos, ...normalizedPharmacistNos] },
job: { $in: ['doctor', 'pharmacist'] }
},
{ projection: { doctorNo: 1, doctorName: 1, job: 1 } }
).toArray();
const peopleByNo = new Map(personnel.map(person => [person.doctorNo, person]));
const toPeople = (nos, job) => {
const people = nos.map(no => peopleByNo.get(no));
return people.length === nos.length && people.every(person => person && person.job === job)
? people.map(({ doctorNo, doctorName }) => ({ doctorNo, doctorName }))
: null;
};
const doctors = toPeople(normalizedDoctorNos, 'doctor');
const pharmacists = toPeople(normalizedPharmacistNos, 'pharmacist');
if (!doctors || !pharmacists) return { success: false, message: '排班人员不存在或岗位不匹配' };
await db.collection('hlw-schedule').updateOne(
{ corpId: normalizedCorpId, date: normalizedDate },
{
$set: {
doctors,
pharmacists,
updater: typeof operator === 'string' ? operator : '',
updaterId: typeof operatorId === 'string' ? operatorId : '',
updateTime: Date.now()
},
$setOnInsert: { corpId: normalizedCorpId, date: normalizedDate, createTime: Date.now() }
},
{ upsert: true }
);
if (normalizedDate === dayjs().format('YYYY-MM-DD')) {
const onlineResult = await setTodayScheduledPeopleOnline(db);
if (!onlineResult.success) {
return { success: false, message: `排班已保存,但设置当天排班人员在线失败:${onlineResult.message}` };
}
}
return { success: true, message: '排班保存成功' };
} catch (error) {
return { success: false, message: error.message || '保存排班失败' };
}
}
async function setTodayScheduledPeopleOnline(db) {
const date = dayjs().format('YYYY-MM-DD');
try {
const schedules = await db.collection('hlw-schedule')
.find({ date }, { projection: { corpId: 1, doctors: 1, pharmacists: 1 } })
.toArray();
const peopleByCorp = new Map();
const addPeople = (corpId, people, job) => {
if (typeof corpId !== 'string' || !corpId.trim()) return;
if (!peopleByCorp.has(corpId)) {
peopleByCorp.set(corpId, { doctors: new Set(), pharmacists: new Set() });
}
const target = job === 'doctor'
? peopleByCorp.get(corpId).doctors
: peopleByCorp.get(corpId).pharmacists;
(Array.isArray(people) ? people : []).forEach((person) => {
if (typeof person?.doctorNo === 'string' && person.doctorNo.trim()) {
target.add(person.doctorNo.trim());
}
});
};
schedules.forEach(({ corpId, doctors, pharmacists }) => {
addPeople(corpId, doctors, 'doctor');
addPeople(corpId, pharmacists, 'pharmacist');
});
const updateTime = Date.now();
const operations = [];
for (const [corpId, { doctors, pharmacists }] of peopleByCorp) {
if (doctors.size > 0) {
operations.push({
updateMany: {
filter: { corpId, doctorNo: { $in: [...doctors] }, job: 'doctor' },
update: { $set: { onlineStatus: 'online', offlineTime: null, updateTime } }
}
});
}
if (pharmacists.size > 0) {
operations.push({
updateMany: {
filter: { corpId, doctorNo: { $in: [...pharmacists] }, job: 'pharmacist' },
update: { $set: { onlineStatus: 'online', offlineTime: null, updateTime } }
}
});
}
}
if (operations.length === 0) {
return { success: true, message: '当天无排班人员', data: { date, matchedCount: 0, modifiedCount: 0 } };
}
const result = await db.collection('hlw-doctor').bulkWrite(operations);
return {
success: true,
message: '当天排班人员已上线',
data: { date, matchedCount: result.matchedCount, modifiedCount: result.modifiedCount }
};
} catch (error) {
return { success: false, message: error.message || '设置当天排班人员在线失败' };
}
}

View File

@ -29,6 +29,7 @@ const chineseMedicineOrder = require("./chinese-medicine-order");
const hlwPatient = require("./hlw-patient");
const scannedCardArchive = require("./scanned-card-archive");
const selfAuth = require("./self-auth");
const hlwSchedule = require("./hlw-schedule");
module.exports = async (item, db, context) => {
switch (item.type) {
@ -88,6 +89,10 @@ module.exports = async (item, db, context) => {
case "autoSetPeopleOffline":
case "getDoctorByNo":
return await hlwDoctor(item, db);
case "getHlwSchedule":
case "saveHlwSchedule":
case "setTodayScheduledPeopleOnline":
return await hlwSchedule(item, db);
case "getDiagnosisList":
case "deleteHlwDiagnosis":
case "updateHlwDiagnosis":

View File

@ -4,9 +4,24 @@ const dayjs = require("dayjs");
exports.initSchedule = () => {
// triggerEveryMinute()
triggerAtNight()
triggerAtNight();
triggerDailySchedulePeopleOnline();
};
function triggerDailySchedulePeopleOnline() {
// node-schedule 格式:秒 分 时 日 月 周;每天 00:30 将当天排班的医生、药师上线。
schedule.scheduleJob("0 30 0 * * *", async () => {
try {
const result = await api.getInternetHospitalApi({ type: "setTodayScheduledPeopleOnline" });
if (!result?.success) {
console.log(`[${dayjs().format('YYYY-MM-DD HH:mm:ss:SSS')}] 排班人员自动上线失败: ${result?.message || '未知错误'}`);
}
} catch (error) {
console.log(`[${dayjs().format('YYYY-MM-DD HH:mm:ss:SSS')}] 排班人员自动上线失败: ${error.message}`);
}
});
}
async function triggerEveryMinute() {
schedule.scheduleJob("0 * * * * *", async () => {
runHighFrequencyTask()