From 41bdfb13b80ca44767345746abdbf3ec01baa600 Mon Sep 17 00:00:00 2001 From: wangjian963 <15215920+aprilry@user.noreply.gitee.com> Date: Thu, 14 May 2026 12:00:18 +0800 Subject: [PATCH] =?UTF-8?q?=20Fix=20Bug=20#437:=20=E3=80=90=E9=97=A8?= =?UTF-8?q?=E8=AF=8A=E6=89=8B=E6=9C=AF=E8=AE=A1=E8=B4=B9=E3=80=91=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E7=AD=BE=E7=AB=A0TOCTOU=E7=AB=9E=E6=80=81=E8=87=B4?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=8F=90=E4=BA=A4=EF=BC=8C=E4=B8=94=E8=80=97?= =?UTF-8?q?=E6=9D=90=E8=AE=A1=E8=B4=B9=E9=A1=B9=E7=9B=AE=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?/=E9=87=8D=E5=A4=8D=E3=80=81=E6=89=8B=E6=9C=AF=E5=8D=95?= =?UTF-8?q?=E5=8F=B7=E6=9C=AA=E5=85=B3=E8=81=94=20=20Fix:=20=E9=A2=91?= =?UTF-8?q?=E6=AC=A1=E6=80=BB=E9=87=8F=E8=AE=A1=E7=AE=97=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E5=AD=97=E5=85=B8store=E5=8A=A8=E6=80=81=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=EF=BC=8Cel-input-number=E6=96=B0=E5=A2=9E@input=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/clinicalmanage/dto/OpScheduleDto.java | 4 - .../DoctorStationAdviceAppServiceImpl.java | 6 +- .../DoctorStationAdviceAppMapper.xml | 5 +- openhis-ui-vue3/src/utils/his.js | 33 +++------ .../bargain/component/prescriptionlist.vue | 74 ++++++++++--------- .../prescription/prescriptionlist.vue | 1 + 6 files changed, 55 insertions(+), 68 deletions(-) diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/clinicalmanage/dto/OpScheduleDto.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/clinicalmanage/dto/OpScheduleDto.java index 5e5c22744..4fdb88480 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/clinicalmanage/dto/OpScheduleDto.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/clinicalmanage/dto/OpScheduleDto.java @@ -107,8 +107,4 @@ public class OpScheduleDto extends OpSchedule { */ private String createByName; - /** - * 费用类别 - */ - private String feeType; } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java index f50c30307..1288f57bf 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java @@ -1529,6 +1529,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp deviceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.DEVICE_RES_NO.getPrefix(), 4)); } deviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源 + deviceRequest.setPrescriptionNo(adviceSaveDto.getSourceBillNo()); // 来源业务单据号(手术单号) deviceRequest.setQuantity(adviceSaveDto.getQuantity()); // 请求数量 deviceRequest.setUnitCode(adviceSaveDto.getUnitCode()); // 请求单位编码 deviceRequest.setLotNumber(adviceSaveDto.getLotNumber());// 产品批号 @@ -1835,6 +1836,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp serviceRequest.setBusNo(assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4)); } serviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue()); // 生成来源 + serviceRequest.setPrescriptionNo(adviceSaveDto.getSourceBillNo()); // 来源业务单据号(手术单号) serviceRequest.setQuantity(adviceSaveDto.getQuantity()); // 请求数量 serviceRequest.setUnitCode(adviceSaveDto.getUnitCode()); // 请求单位编码 @@ -2030,10 +2032,10 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp CommonConstants.TableName.MED_MEDICATION_REQUEST, CommonConstants.TableName.WOR_DEVICE_REQUEST, CommonConstants.TableName.WOR_SERVICE_REQUEST, practitionerId, Whether.NO.getCode(), sourceEnum, sourceBillNo); - // 手术计费场景:sourceBillNo 不为空时,只保留诊疗请求(3/6),过滤掉药品(1)和耗材(2) + // 手术计费场景:sourceBillNo 不为空时,过滤掉药品(1),保留耗材(2)和诊疗(3/6) if (sourceBillNo != null && !sourceBillNo.isEmpty()) { requestBaseInfo.removeIf(dto -> dto.getAdviceType() != null - && (dto.getAdviceType() == 1 || dto.getAdviceType() == 2)); + && dto.getAdviceType() == 1); } for (RequestBaseDto requestBaseDto : requestBaseInfo) { // 请求状态 diff --git a/openhis-server-new/openhis-application/src/main/resources/mapper/doctorstation/DoctorStationAdviceAppMapper.xml b/openhis-server-new/openhis-application/src/main/resources/mapper/doctorstation/DoctorStationAdviceAppMapper.xml index e4091d0f0..9d3a7cf29 100755 --- a/openhis-server-new/openhis-application/src/main/resources/mapper/doctorstation/DoctorStationAdviceAppMapper.xml +++ b/openhis-server-new/openhis-application/src/main/resources/mapper/doctorstation/DoctorStationAdviceAppMapper.xml @@ -539,7 +539,8 @@ AND T1.refund_medicine_id IS NULL ORDER BY T1.status_enum,T1.sort_number) UNION ALL - -- 🔧 新增:查询门诊术中计费生成的耗材数据(这些数据存在于 adm_charge_item 和 wor_device_request) + -- 🔧 查询仅存在于 adm_charge_item 的"孤儿"耗材数据(DeviceRequest 缺失或 generate_source_enum 未设置) + -- 正常 DeviceRequest(generate_source_enum 已赋值)由下方 Part 3 统一负责,此处不做重复覆盖避免 UNION ALL 重复行 (SELECT 2 AS advice_type, CI.service_id AS request_id, CI.service_id || '-ci-dev' AS unique_key, @@ -584,7 +585,7 @@ WHERE CI.delete_flag = '0' AND CI.service_table = 'wor_device_request' - AND (DR.generate_source_enum IS NULL OR DR.generate_source_enum = #{generateSourceEnum}) + AND DR.generate_source_enum IS NULL AND CI.encounter_id = #{encounterId} diff --git a/openhis-ui-vue3/src/utils/his.js b/openhis-ui-vue3/src/utils/his.js index afef3ce34..8767839d4 100755 --- a/openhis-ui-vue3/src/utils/his.js +++ b/openhis-ui-vue3/src/utils/his.js @@ -1,3 +1,5 @@ +import useDictStore from '@/store/modules/dict'; + // 日期格式化 export function parseTime(time, pattern) { if (arguments.length === 0 || !time) { @@ -275,30 +277,13 @@ export function blobValidate(data) { // 按照频次天数计算总数量 export function calculateQuantityByDays(frequency, days) { - // const dict = useDict('rate_code').rate_code.value - // const rate = dict.find(item => item.value === frequency).remark - // if(rate){ - // return Math.floor(Number(rate) * days) - // } else { - // return undefined - // } - const frequencyMap = { - ST: 1, - QD: 1, // 每日一次 - BID: 2, // 每日两次 - TID: 3, // 每日三次 - QID: 4, // 每日四次 - QN: 1, // 每晚一次 - QOD: 1 / 2, // 每隔一日一次 - QW: 1 / 7, // 每周一次 - BIW: 2 / 7, // 每周两次 - TIW: 3 / 7, // 每周三次 - QOW: 1 / 14, // 隔周一次 - }; - if (!frequencyMap[frequency]) { - return; - } - const quantity = frequencyMap[frequency] * days; + const dicts = useDictStore().getDict('rate_code'); + if (!dicts) return; + const dict = dicts.find(item => item.value === frequency); + if (!dict?.remark) return; + const rate = Number(dict.remark); + if (isNaN(rate) || !rate) return; + const quantity = rate * days; return quantity < 1 ? 1 : Math.ceil(quantity); } diff --git a/openhis-ui-vue3/src/views/clinicmanagement/bargain/component/prescriptionlist.vue b/openhis-ui-vue3/src/views/clinicmanagement/bargain/component/prescriptionlist.vue index 750671849..c68dd4301 100755 --- a/openhis-ui-vue3/src/views/clinicmanagement/bargain/component/prescriptionlist.vue +++ b/openhis-ui-vue3/src/views/clinicmanagement/bargain/component/prescriptionlist.vue @@ -461,7 +461,7 @@ watch( console.log(prescriptionList.value,"prescriptionList.value") if(newValue&&newValue.length>0){ let saveList = prescriptionList.value.filter((item) => { - return item.statusEnum == 1&&(Number(item.bizRequestFlag)==1||!item.bizRequestFlag) + return item.check && item.statusEnum == 1&&(Number(item.bizRequestFlag)==1||!item.bizRequestFlag) }) console.log(saveList,"prescriptionList.value") if (saveList.length == 0) { @@ -1015,7 +1015,7 @@ function handleSave() { return; } let saveList = prescriptionList.value.filter((item) => { - return item.statusEnum == 1&&(Number(item.bizRequestFlag)==1||!item.bizRequestFlag) + return item.check && item.statusEnum == 1&&(Number(item.bizRequestFlag)==1||!item.bizRequestFlag) }); // let saveList = prescriptionList.value // .filter((item) => { @@ -1080,42 +1080,44 @@ function handleSaveSign(row, index) { proxy.$modal.msgWarning('诊疗项目必须选择执行科室'); return; } + isSaving.value = true; // #437 立即加锁,消除 TOCTOU 竞态 proxy.$refs['formRef' + index].validate((valid) => { - if (valid) { - isSaving.value = true; // #437 加锁 - row.isEdit = false; - isAdding.value = false; - expandOrder.value = []; - row.patientId = props.patientInfo.patientId; - row.encounterId = props.patientInfo.encounterId; - row.accountId = props.patientInfo.accountId; - const cleanRow = JSON.parse(JSON.stringify(row)); - cleanRow.contentJson = JSON.stringify(cleanRow); - cleanRow.dbOpType = cleanRow.requestId ? '2' : '1'; - cleanRow.minUnitQuantity = cleanRow.quantity * cleanRow.partPercent; - cleanRow.categoryEnum = cleanRow.adviceType - // 如果是手术计费,设置生成来源和来源业务单据号 - if (props.patientInfo.sourceBillNo) { - cleanRow.generateSourceEnum = 6; // 手术计费 - cleanRow.sourceBillNo = props.patientInfo.sourceBillNo; - } - console.log('cleanRow', cleanRow) - savePrescription({ adviceSaveList: [cleanRow] }).then((res) => { - if (res.code === 200) { - proxy.$modal.msgSuccess('保存成功'); - getListInfo(false); - nextId.value = 1; - // 🔧 Bug Fix #238: 如果诊疗项目缺少执行科室,标记为需要修复的脏数据 - if (row.adviceType === 3 && !row.orgId) { - console.warn('Bug #238: 检测到诊疗项目保存时缺少执行科室,请手动编辑修正:', cleanRow); - proxy.$modal.msgWarning('诊疗项目执行科室信息不完整,请编辑后重新保存'); - } - } - }).finally(() => { - isSaving.value = false; // #437 释放锁 - }); + if (!valid) { + isSaving.value = false; // 验证失败释放锁 + return; } - }); + row.isEdit = false; + isAdding.value = false; + expandOrder.value = []; + row.patientId = props.patientInfo.patientId; + row.encounterId = props.patientInfo.encounterId; + row.accountId = props.patientInfo.accountId; + const cleanRow = JSON.parse(JSON.stringify(row)); + cleanRow.contentJson = JSON.stringify(cleanRow); + cleanRow.dbOpType = cleanRow.requestId ? '2' : '1'; + cleanRow.minUnitQuantity = cleanRow.quantity * cleanRow.partPercent; + cleanRow.categoryEnum = cleanRow.adviceType + // 如果是手术计费,设置生成来源和来源业务单据号 + if (props.patientInfo.sourceBillNo) { + cleanRow.generateSourceEnum = 6; // 手术计费 + cleanRow.sourceBillNo = props.patientInfo.sourceBillNo; + } + console.log('cleanRow', cleanRow) + savePrescription({ adviceSaveList: [cleanRow] }, '1').then((res) => { + if (res.code === 200) { + proxy.$modal.msgSuccess('保存成功'); + getListInfo(false); + nextId.value = 1; + // 🔧 Bug Fix #238: 如果诊疗项目缺少执行科室,标记为需要修复的脏数据 + if (row.adviceType === 3 && !row.orgId) { + console.warn('Bug #238: 检测到诊疗项目保存时缺少执行科室,请手动编辑修正:', cleanRow); + proxy.$modal.msgWarning('诊疗项目执行科室信息不完整,请编辑后重新保存'); + } + } + }).finally(() => { + isSaving.value = false; // #437 释放锁 + }); + }) } // 签退 diff --git a/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue b/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue index 551487cd7..38476e3d9 100755 --- a/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue @@ -315,6 +315,7 @@ data-prop="dispensePerDuration">