From 188b907907ed570955d7bf4ae680074f6f118b8c Mon Sep 17 00:00:00 2001 From: Ranyunqiao <2499115710@qq.com> Date: Thu, 26 Mar 2026 16:55:06 +0800 Subject: [PATCH 1/2] =?UTF-8?q?217=20=E6=94=B6=E8=B4=B9=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E7=AB=99-=E3=80=8B=E9=97=A8=E8=AF=8A=E6=94=B6=E8=B4=B9?= =?UTF-8?q?=EF=BC=9A=E3=80=90=E7=A1=AE=E8=AE=A4=E6=94=B6=E8=B4=B9=E3=80=91?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E2=80=9C=E6=89=93=E5=8D=B0=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E2=80=9D=20220=20=E9=97=A8=E8=AF=8A=E5=8C=BB=E7=94=9F=E7=AB=99?= =?UTF-8?q?=EF=BC=9A=E6=96=B0=E5=A2=9E=E8=80=97=E6=9D=90=E6=94=B6=E8=B4=B9?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=8C=BB=E5=98=B1=E5=8D=95=E4=BB=B7/?= =?UTF-8?q?=E6=80=BB=E9=87=91=E9=A2=9D=E6=9C=AA=E6=98=BE=E7=A4=BA=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E7=9A=84=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DoctorStationAdviceAppServiceImpl.java | 12 +- .../DoctorStationAdviceController.java | 2 + .../web/doctorstation/dto/RequestBaseDto.java | 5 + .../MedicalDeviceDispenseAppServiceImpl.java | 2 +- .../service/IChargeItemService.java | 22 +- .../service/impl/ChargeItemServiceImpl.java | 220 +++++++++++++++++- .../charge/cliniccharge/components/api.js | 13 +- .../cliniccharge/components/chargeDialog.vue | 37 +-- .../src/views/charge/cliniccharge/index.vue | 2 +- .../components/adviceBaseList.vue | 25 +- .../prescription/prescriptionlist.vue | 26 ++- .../feeSettlement/components/chargeDialog.vue | 4 +- 12 files changed, 304 insertions(+), 66 deletions(-) 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 98a72edd..e3820b1c 100644 --- 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 @@ -641,11 +641,13 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp .collect(Collectors.toList()); // 就诊id Long encounterId = adviceSaveList.get(0).getEncounterId(); - iChargeItemService.update(new LambdaUpdateWrapper() - .set(ChargeItem::getStatusEnum, ChargeItemStatus.PLANNED.getValue()) - .eq(ChargeItem::getEncounterId, encounterId) - .eq(ChargeItem::getStatusEnum, ChargeItemStatus.DRAFT.getValue()) - .in(ChargeItem::getServiceId, requestIds)); + + // 使用安全的更新方法,避免并发冲突 + iChargeItemService.updateChargeStatusByConditionSafe( + encounterId, + ChargeItemStatus.DRAFT.getValue(), + ChargeItemStatus.PLANNED.getValue(), + requestIds); } // 数据变更后清理相关缓存 diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/controller/DoctorStationAdviceController.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/controller/DoctorStationAdviceController.java index 0c789392..3524eaa0 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/controller/DoctorStationAdviceController.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/controller/DoctorStationAdviceController.java @@ -3,6 +3,7 @@ */ package com.openhis.web.doctorstation.controller; +import com.core.common.annotation.RepeatSubmit; import com.core.common.core.domain.R; import com.openhis.common.enums.AdviceOpType; import com.openhis.common.enums.Whether; @@ -85,6 +86,7 @@ public class DoctorStationAdviceController { * @return 结果 */ @PostMapping(value = "/sign-advice") + @RepeatSubmit(interval = 5000, message = "请勿重复签发医嘱,请稍候再试") public R signAdvice(@RequestBody AdviceSaveParam adviceSaveParam) { return iDoctorStationAdviceAppService.saveAdvice(adviceSaveParam, AdviceOpType.SIGN_ADVICE.getCode()); } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/RequestBaseDto.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/RequestBaseDto.java index 5592f34d..4280bc8c 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/RequestBaseDto.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/dto/RequestBaseDto.java @@ -79,6 +79,11 @@ public class RequestBaseDto { @JsonSerialize(using = ToStringSerializer.class) private Long chargeItemId; + /** + * 医嘱定义对应表名 + */ + private String adviceTableName; + /** * 医嘱名称 */ diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacymanage/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacymanage/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java index 765cd466..3eb54401 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacymanage/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacymanage/appservice/impl/MedicalDeviceDispenseAppServiceImpl.java @@ -394,7 +394,7 @@ public class MedicalDeviceDispenseAppServiceImpl implements IMedicalDeviceDispen } List chargeItemList = chargeItemService.listByIds(chargeItemIds); if (chargeItemList == null || chargeItemList.isEmpty()) { - return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null)); + return R.fail("未查询到耗材收费项目信息"); } // 获取发申请id列表 diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/IChargeItemService.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/IChargeItemService.java index acff1fe5..17731db2 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/IChargeItemService.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/IChargeItemService.java @@ -58,12 +58,32 @@ public interface IChargeItemService extends IService { /** * 更新收费状态 - * + * * @param chargeItemIdList 收费项目id集合 * @param value 状态值 */ void updatePaymentStatus(List chargeItemIdList, Integer value); + /** + * 安全更新收费项目状态(按条件更新,避免并发冲突) + * + * @param encounterId 就诊ID + * @param fromStatusEnum 原状态 + * @param toStatusEnum 目标状态 + * @param serviceIds 服务ID列表 + */ + void updateChargeStatusByCondition(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List serviceIds); + + /** + * 安全批量更新收费项目状态(逐个更新,避免并发冲突) + * + * @param encounterId 就诊ID + * @param fromStatusEnum 原状态 + * @param toStatusEnum 目标状态 + * @param serviceIds 服务ID列表 + */ + void updateChargeStatusByConditionSafe(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List serviceIds); + /** * 根据表名和id删除费用项 * diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/impl/ChargeItemServiceImpl.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/impl/ChargeItemServiceImpl.java index 740feb07..dcb8e795 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/impl/ChargeItemServiceImpl.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/service/impl/ChargeItemServiceImpl.java @@ -22,12 +22,14 @@ import com.openhis.administration.service.IChargeItemService; import com.openhis.common.enums.*; import com.openhis.common.utils.EnumUtils; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -38,6 +40,7 @@ import java.util.stream.Collectors; */ @Service @AllArgsConstructor +@Slf4j public class ChargeItemServiceImpl extends ServiceImpl implements IChargeItemService { @Autowired @@ -130,10 +133,93 @@ public class ChargeItemServiceImpl extends ServiceImpl chargeItemIdList, Integer value) { - baseMapper.update( - new ChargeItem().setStatusEnum(value).setPerformerId(SecurityUtils.getLoginUser().getPractitionerId()), - new LambdaUpdateWrapper().in(ChargeItem::getId, chargeItemIdList).eq(ChargeItem::getDeleteFlag, - DelFlag.NO.getCode())); + if (chargeItemIdList == null || chargeItemIdList.isEmpty()) { + return; + } + + // 逐个更新,避免并发冲突 + for (Long chargeItemId : chargeItemIdList) { + int retryCount = 0; + final int maxRetries = 3; + + while (retryCount < maxRetries) { + try { + // 先查询当前状态,确保更新操作的安全性 + ChargeItem currentChargeItem = baseMapper.selectById(chargeItemId); + + if (currentChargeItem == null) { + log.warn("收费项目不存在,ID: {}", chargeItemId); + break; // 项目不存在,跳出重试循环 + } + + // 检查当前状态是否已经是目标状态,避免不必要的更新 + if (currentChargeItem.getStatusEnum().equals(value)) { + log.debug("收费项目已是目标状态,跳过更新,ID: {}, 状态: {}", chargeItemId, value); + break; // 已是目标状态,跳出重试循环 + } + + // 使用精确的条件更新,包括当前状态,防止并发更新冲突 + int updatedRows = baseMapper.update( + new ChargeItem() + .setStatusEnum(value) + .setPerformerId(SecurityUtils.getLoginUser().getPractitionerId()), + new LambdaUpdateWrapper() + .eq(ChargeItem::getId, chargeItemId) + .eq(ChargeItem::getStatusEnum, currentChargeItem.getStatusEnum()) // 使用当前状态作为条件 + .eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode())); + + // 如果成功更新了行数,跳出重试循环 + if (updatedRows > 0) { + log.debug("收费项目状态更新成功,ID: {}, 状态: {}", chargeItemId, value); + break; // 成功更新,跳出重试循环 + } else { + log.warn("收费项目更新失败,可能已被其他事务更改,ID: {}, 目标状态: {},重试次数: {}", + chargeItemId, value, retryCount + 1); + + // 增加重试计数 + retryCount++; + + // 如果达到最大重试次数,检查最终状态 + if (retryCount >= maxRetries) { + ChargeItem finalChargeItem = baseMapper.selectById(chargeItemId); + if (finalChargeItem != null && finalChargeItem.getStatusEnum().equals(value)) { + log.debug("收费项目最终已是目标状态,ID: {}", chargeItemId); + break; // 最终状态符合预期,跳出重试循环 + } else { + log.warn("收费项目状态更新失败,达到最大重试次数,ID: {}, 期望状态: {}, 当前状态: {}", + chargeItemId, value, finalChargeItem != null ? finalChargeItem.getStatusEnum() : "NULL"); + break; // 达到最大重试次数,跳出重试循环 + } + } else { + // 短暂延迟后重试,避免过于频繁的重试 + try { + Thread.sleep(10); // 10毫秒延迟 + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; // 中断线程,跳出重试循环 + } + } + } + } catch (Exception e) { + log.error("更新收费项目状态失败,ID: {}, 状态: {},重试次数: {}", chargeItemId, value, retryCount + 1, e); + + retryCount++; + if (retryCount >= maxRetries) { + log.error("更新收费项目状态失败,达到最大重试次数,ID: {}, 状态: {}", chargeItemId, value, e); + // 不抛出异常,以避免整个事务回滚 + break; // 达到最大重试次数,跳出重试循环 + } + + // 短暂延迟后重试 + try { + Thread.sleep(10); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; // 中断线程,跳出重试循环 + } + } + } + } } /** @@ -324,4 +410,130 @@ public class ChargeItemServiceImpl extends ServiceImpl serviceIds) { + if (serviceIds == null || serviceIds.isEmpty()) { + return; + } + + // 使用逐个更新的方式,避免批量更新的并发问题 + for (Long serviceId : serviceIds) { + try { + int updatedRows = baseMapper.update( + new ChargeItem().setStatusEnum(toStatusEnum), + new LambdaUpdateWrapper() + .eq(ChargeItem::getEncounterId, encounterId) + .eq(ChargeItem::getStatusEnum, fromStatusEnum) // 确保原状态匹配 + .eq(ChargeItem::getServiceId, serviceId) + .eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode()) + ); + + // 如果没有更新任何行,可能是因为状态已经被其他事务更改 + if (updatedRows == 0) { + log.warn("收费项目状态更新失败或无变化,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {}", + encounterId, serviceId, fromStatusEnum, toStatusEnum); + + // 查询当前状态以供调试 + List currentChargeItems = baseMapper.selectList( + new LambdaQueryWrapper() + .eq(ChargeItem::getEncounterId, encounterId) + .eq(ChargeItem::getServiceId, serviceId) + .eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode()) + ); + + for (ChargeItem item : currentChargeItems) { + log.info("收费项目当前状态,ID: {}, 状态: {}", item.getId(), item.getStatusEnum()); + } + } + } catch (Exception e) { + log.error("更新收费项目状态失败,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {}", + encounterId, serviceId, fromStatusEnum, toStatusEnum, e); + throw e; + } + } + } + + @Override + public void updateChargeStatusByConditionSafe(Long encounterId, Integer fromStatusEnum, Integer toStatusEnum, List serviceIds) { + if (serviceIds == null || serviceIds.isEmpty()) { + return; + } + + // 使用逐个更新的方式,避免批量更新的并发问题 + for (Long serviceId : serviceIds) { + int retryCount = 0; + final int maxRetries = 3; + + while (retryCount < maxRetries) { + try { + // 先查询当前符合条件的收费项目 + List chargeItems = baseMapper.selectList( + new LambdaQueryWrapper() + .eq(ChargeItem::getEncounterId, encounterId) + .eq(ChargeItem::getStatusEnum, fromStatusEnum) + .eq(ChargeItem::getServiceId, serviceId) + .eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode()) + ); + + if (chargeItems.isEmpty()) { + log.debug("未找到符合条件的收费项目,encounterId: {}, serviceId: {}, 原状态: {}", + encounterId, serviceId, fromStatusEnum); + break; // 没有符合条件的项目,跳出重试循环 + } + + // 对每个符合条件的收费项目进行更新 + for (ChargeItem chargeItem : chargeItems) { + int updatedRows = baseMapper.update( + new ChargeItem().setStatusEnum(toStatusEnum), + new LambdaUpdateWrapper() + .eq(ChargeItem::getId, chargeItem.getId()) + .eq(ChargeItem::getStatusEnum, fromStatusEnum) // 确保原状态匹配 + .eq(ChargeItem::getDeleteFlag, DelFlag.NO.getCode()) + ); + + if (updatedRows > 0) { + log.debug("收费项目状态更新成功,ID: {}, 从状态: {} 到状态: {}", + chargeItem.getId(), fromStatusEnum, toStatusEnum); + } else { + log.warn("收费项目状态更新失败,ID: {}, 从状态: {} 到状态: {}", + chargeItem.getId(), fromStatusEnum, toStatusEnum); + + // 检查项目当前状态 + ChargeItem currentChargeItem = baseMapper.selectById(chargeItem.getId()); + if (currentChargeItem != null) { + log.debug("收费项目当前状态,ID: {}, 状态: {}", currentChargeItem.getId(), currentChargeItem.getStatusEnum()); + + // 如果已经是目标状态,则认为更新成功 + if (currentChargeItem.getStatusEnum().equals(toStatusEnum)) { + log.debug("收费项目已是目标状态,ID: {}", currentChargeItem.getId()); + } + } + } + } + + // 成功更新,跳出重试循环 + break; + } catch (Exception e) { + retryCount++; + log.warn("收费项目状态更新失败,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {},重试次数: {}", + encounterId, serviceId, fromStatusEnum, toStatusEnum, retryCount, e); + + if (retryCount >= maxRetries) { + log.error("收费项目状态更新失败,达到最大重试次数,encounterId: {}, serviceId: {}, 原状态: {}, 目标状态: {}", + encounterId, serviceId, fromStatusEnum, toStatusEnum, e); + // 不抛出异常,以避免影响整体流程 + } else { + // 短暂延迟后重试 + try { + Thread.sleep(10); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; // 中断线程,跳出重试循环 + } + } + } + } + } + } } diff --git a/openhis-ui-vue3/src/views/charge/cliniccharge/components/api.js b/openhis-ui-vue3/src/views/charge/cliniccharge/components/api.js index e43ac74b..2f3de9a8 100644 --- a/openhis-ui-vue3/src/views/charge/cliniccharge/components/api.js +++ b/openhis-ui-vue3/src/views/charge/cliniccharge/components/api.js @@ -14,10 +14,11 @@ export function getList(queryParams) { /** * 患者处方列表 */ -export function getChargeList(encounterId) { +export function getChargeList(encounterId, config = {}) { return request({ url: '/charge-manage/charge/patient-prescription?encounterId=' + encounterId, method: 'get', + ...config }) } @@ -111,11 +112,12 @@ export function unprecharge(data) { /** * 发耗材 */ -export function dispenseMedicalConsumables(data) { +export function dispenseMedicalConsumables(data, config = {}) { return request({ url: '/pharmacy-manage/device-dispense/consumables-dispense', method: 'put', - data: data + data: data, + ...config }) } @@ -123,11 +125,12 @@ export function dispenseMedicalConsumables(data) { /** * 补打小票 */ -export function getChargeInfo(param) { +export function getChargeInfo(param, config = {}) { return request({ url: '/payment/bill/getDetail', method: 'get', - params: param + params: param, + ...config }) } diff --git a/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue b/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue index 3406da98..433fd8e0 100644 --- a/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue +++ b/openhis-ui-vue3/src/views/charge/cliniccharge/components/chargeDialog.vue @@ -476,9 +476,12 @@ async function printReceipt(param) { return amount > 0 ? amount + ' 元' : amount; })(), // 个人现金支付金额(现金) SELF_CASH_VX_VALUE: (() => { - const amount = param.detail?.find((t) => t.payEnum === 220100)?.amount ?? 0; - return amount > 0 ? amount + ' 元' : amount; - })(), // 个人现金支付金额(微信) + // 微信+银联+支付宝的合计金额 + const vxValue = param.detail?.find((t) => t.payEnum === 220100)?.amount ?? 0; + const unionValue = param.detail?.find((t) => t.payEnum === 220300)?.amount ?? 0; + const aliValue = param.detail?.find((t) => t.payEnum === 220200)?.amount ?? 0; + return (Number(vxValue) + Number(unionValue) + Number(aliValue)).toFixed(2) + ' 元'; + })(), SELF_CASH_ALI_VALUE: (() => { const amount = param.detail?.find((t) => t.payEnum === 220200)?.amount ?? 0; return amount > 0 ? amount + ' 元' : amount; @@ -537,14 +540,6 @@ async function printReceipt(param) { const amount = param.detail?.find((t) => t.payEnum === 360300)?.amount ?? 0; return amount > 0 ? amount + ' 元' : amount; })(), // 保健预支基金 - //微信刷卡支付 - SELF_CASH_VX_VALUE: (() => { - // const cashValue = param.detail?.find((t) => t.payEnum === 220400)?.amount ?? 0; - const vxValue = param.detail?.find((t) => t.payEnum === 220100)?.amount ?? 0; - const unionValue = param.detail?.find((t) => t.payEnum === 220300)?.amount ?? 0; - const aliValue = param.detail?.find((t) => t.payEnum === 220200)?.amount ?? 0; - return (Number(vxValue) + Number(unionValue) + Number(aliValue)).toFixed(2) + ' 元'; - })(), Mr_QR_Code: param.regNo, regNo: param.regNo || '', @@ -659,16 +654,24 @@ async function submit() { }) .then((res) => { if (res.code == 200) { - getChargeInfo({ paymentId: props.paymentId }).then((res) => { - // 传递完整的选中数据信息到打印方法 - printReceipt({ ...res.data, chargedItems: props.chargedItems }); - }); + getChargeInfo({ paymentId: props.paymentId }, { skipErrorMsg: true }) + .then((res) => { + // 传递完整的选中数据信息到打印方法 + printReceipt({ ...res.data, chargedItems: props.chargedItems }); + }) + .catch(() => { + // 打印失败不影响收费成功流程 + }); formData.selfPay = [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }]; emit('close', 'success', res.msg); emit('refresh'); // 发送刷新事件给父组件 - // 长春市朝阳区中医院自动发耗材 + // 长春市朝阳区中医院自动发耗材(静默执行,不阻塞主流程) if (userStore.fixmedinsCode == 'H22010200672' && props.consumablesIdList.length > 0) { - dispenseMedicalConsumables(props.consumablesIdList); + dispenseMedicalConsumables(props.consumablesIdList, { skipErrorMsg: true }) + .then(() => {}) + .catch(() => { + // 发耗材失败不影响收费成功流程 + }); } } else { proxy.$modal.msgError(res.msg || '收费失败'); diff --git a/openhis-ui-vue3/src/views/charge/cliniccharge/index.vue b/openhis-ui-vue3/src/views/charge/cliniccharge/index.vue index 90a9bc55..e9c267e9 100644 --- a/openhis-ui-vue3/src/views/charge/cliniccharge/index.vue +++ b/openhis-ui-vue3/src/views/charge/cliniccharge/index.vue @@ -325,7 +325,7 @@ function handleClose(value, msg) { if (value == 'success') { proxy.$modal.msgSuccess(msg); chargeLoading.value = true; - getChargeList(patientInfo.value.encounterId).then((res) => { + getChargeList(patientInfo.value.encounterId, { skipErrorMsg: true }).then((res) => { chargeList.value = res.data; setTimeout(() => { chargeLoading.value = false; diff --git a/openhis-ui-vue3/src/views/doctorstation/components/adviceBaseList.vue b/openhis-ui-vue3/src/views/doctorstation/components/adviceBaseList.vue index f8d3a33e..4458eca7 100644 --- a/openhis-ui-vue3/src/views/doctorstation/components/adviceBaseList.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/adviceBaseList.vue @@ -262,24 +262,19 @@ function fetchFromApi(searchKey) { adviceBaseList.value = res.data.records.map((item) => { console.log('[Debug] 耗材项:', item.name, 'price:', item.price, 'retailPrice:', item.retailPrice); return { + ...item, + // 🔧 Bug Fix: 强制覆盖后端返回的字段,确保数据正确 adviceName: item.name || item.busNo, - adviceType: 4, + adviceType: 4, // 强制设置为前端耗材类型 + adviceTableName: 'adm_device_definition', unitCode: item.unitCode || '', unitCode_dictText: item.unitCode_dictText || '', minUnitCode: item.minUnitCode || item.unitCode || '', minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '', volume: item.size || item.totalVolume || '', partPercent: item.partPercent || 1, - // 🔧 Bug #220 修复:正确处理耗材价格,支持price或retailPrice字段 - // 零售价可能是0,所以不能用简单的布尔判断,需要明确检查null/undefined - priceList: (item.price !== undefined && item.price !== null) - ? [{ price: item.price }] - : ((item.retailPrice !== undefined && item.retailPrice !== null) - ? [{ price: item.retailPrice }] - : []), inventoryList: [], adviceDefinitionId: item.id, - adviceTableName: 'adm_device_definition', chargeItemDefinitionId: item.id, positionId: item.locationId, positionName: item.locationId_dictText || '', @@ -293,17 +288,7 @@ function fetchFromApi(searchKey) { categoryCode: item.categoryCode || '', deviceId: item.id, deviceName: item.name, - // 🔧 Bug Fix: ...item 展开放在前面,然后用前端字段覆盖 - ...item, - // 确保前端覆盖后端可能冲突的字段 - adviceName: item.name || item.busNo, - adviceType: 4, // 强制设置为前端耗材类型 - unitCode: item.unitCode || '', - unitCode_dictText: item.unitCode_dictText || '', - minUnitCode: item.minUnitCode || item.unitCode || '', - minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '', - volume: item.size || item.totalVolume || '', - partPercent: item.partPercent || 1, + // 🔧 Bug #220 修复:正确处理耗材价格,支持price或retailPrice字段 // 价格字段优先使用retailPrice priceList: (item.retailPrice !== undefined && item.retailPrice !== null) ? [{ price: item.retailPrice }] 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 a84cdbbe..6bde94b8 100644 --- a/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue +++ b/openhis-ui-vue3/src/views/doctorstation/components/prescription/prescriptionlist.vue @@ -1588,6 +1588,11 @@ function getListInfo(addNewRow) { console.log('BugFix#219: 过滤掉已作废的会诊医嘱, requestId=', item.requestId); return false; } + // 🔧 Bug Fix: 过滤掉项目名称为空的无效医嘱 + if (!item.adviceName || item.adviceName.trim() === '') { + console.log('BugFix: 过滤掉空白医嘱, requestId=', item.requestId, 'adviceType=', item.adviceType); + return false; + } return true; }); @@ -2333,14 +2338,10 @@ function handleSave(prescriptionId) { // 签发核心逻辑 function executeSaveLogic() { - // 🔧 Bug Fix: 获取当前选中的费用性质,如果是'ZIFEI'或0则转为null,让后端查询默认账户 + // 🔧 Bug Fix: 获取当前选中的费用性质,保持字符串类型避免大整数精度丢失 let finalAccountId = accountId.value; if (finalAccountId === 'ZIFEI' || finalAccountId === 0) { finalAccountId = null; - } else if (finalAccountId && !isNaN(Number(finalAccountId))) { - finalAccountId = Number(finalAccountId); - } else { - finalAccountId = null; } // 🔧 Bug Fix: 校验患者信息完整性 @@ -2878,11 +2879,10 @@ function handleSaveBatch(prescriptionId) { } // 🔧 Bug Fix: 在保存时才转换 accountId + // 保持为字符串类型,避免 JavaScript 大整数精度丢失问题 let finalAccountId = accountId.value; - if (finalAccountId === 'ZIFEI') { + if (finalAccountId === 'ZIFEI' || finalAccountId === 0) { finalAccountId = null; - } else if (finalAccountId && !isNaN(Number(finalAccountId))) { - finalAccountId = Number(finalAccountId); } // 更新到处方对象 @@ -2964,12 +2964,10 @@ function handleSaveBatch(prescriptionId) { }; const contentJson = JSON.stringify(itemToSave); - // 🔧 Bug Fix: 处理accountId,如果是'ZIFEI'或0则转为null,让后端查询默认账户 + // 🔧 Bug Fix: 处理accountId,保持字符串类型避免大整数精度丢失 let itemAccountId = finalAccountId; if (itemAccountId === 'ZIFEI' || itemAccountId === 0) { itemAccountId = null; - } else if (itemAccountId && !isNaN(Number(itemAccountId))) { - itemAccountId = Number(itemAccountId); } // 🔧 Bug Fix: 确保库存匹配成功的关键字段 @@ -3143,6 +3141,12 @@ function syncGroupFields(row) { } function setValue(row) { + // 🔧 Bug Fix: 强制设置耗材类型,确保 adviceType 为 4 + // 如果 adviceTableName 是 adm_device_definition,强制设为耗材类型 + if (row.adviceTableName === 'adm_device_definition') { + row.adviceType = 4; + } + unitCodeList.value = []; unitCodeList.value.push({ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' }); unitCodeList.value.push({ diff --git a/openhis-ui-vue3/src/views/inHospitalManagement/charge/feeSettlement/components/chargeDialog.vue b/openhis-ui-vue3/src/views/inHospitalManagement/charge/feeSettlement/components/chargeDialog.vue index 26c4a3e0..f206634c 100644 --- a/openhis-ui-vue3/src/views/inHospitalManagement/charge/feeSettlement/components/chargeDialog.vue +++ b/openhis-ui-vue3/src/views/inHospitalManagement/charge/feeSettlement/components/chargeDialog.vue @@ -375,7 +375,9 @@ async function submit() { emit('refresh'); // 发送刷新事件给父组件 // 长春市朝阳区中医院自动发耗材 if (userStore.fixmedinsCode == 'H22010200672' && props.consumablesIdList.length > 0) { - dispenseMedicalConsumables(props.consumablesIdList); + dispenseMedicalConsumables(props.consumablesIdList).catch(err => { + console.warn('自动发耗材失败:', err); + }); } } }) From d7c15848f029c425555ec198493112687a212169 Mon Sep 17 00:00:00 2001 From: duzhongxu <15039018447@163.com> Date: Thu, 26 Mar 2026 16:58:21 +0800 Subject: [PATCH 2/2] =?UTF-8?q?208=20=E6=A3=80=E9=AA=8C=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE-=E3=80=8B=E5=A5=97=E9=A4=90=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=EF=BC=9A=E9=A1=B9=E7=9B=AE=E5=90=8D=E7=A7=B0=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=9C=AA=E5=AE=9E=E7=8E=B0=E5=8F=96=E5=80=BC=E4=BA=8E?= =?UTF-8?q?=E3=80=8A=E8=AF=8A=E7=96=97=E7=9B=AE=E5=BD=95=E3=80=8B=E5=81=9A?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/maintainSystem/Inspection/index.vue | 612 ++++++++++++++---- 1 file changed, 473 insertions(+), 139 deletions(-) diff --git a/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue b/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue index 69af9051..010b4506 100644 --- a/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue +++ b/openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue @@ -595,16 +595,120 @@ {{ $index + 1 }} - +