From fbee6ad8f667b8d0f9e9c9c51cbd62f569106e85 Mon Sep 17 00:00:00 2001 From: guanyu Date: Wed, 27 May 2026 01:00:57 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20Bug=20#505:=20AI=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/NurseOrderServiceImpl.java | 49 +++++++++++++++++++ .../web/outpatient/mapper/OrderMapper.java | 41 +++------------- .../views/nurse/order-verification/index.vue | 31 +++++++----- 3 files changed, 75 insertions(+), 46 deletions(-) create mode 100644 openhis-server-new/openhis-application/src/main/java/com/openhis/web/nurse/service/impl/NurseOrderServiceImpl.java diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/nurse/service/impl/NurseOrderServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/nurse/service/impl/NurseOrderServiceImpl.java new file mode 100644 index 000000000..26838d756 --- /dev/null +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/nurse/service/impl/NurseOrderServiceImpl.java @@ -0,0 +1,49 @@ +package com.openhis.web.nurse.service.impl; + +import com.openhis.web.outpatient.mapper.OrderMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +/** + * 护士站医嘱业务逻辑处理 + * 修复 Bug #505:增加退回前置状态强校验,阻断已发药/已执行/已计费医嘱的直接退回 + */ +@Service +public class NurseOrderServiceImpl { + + private final OrderMapper orderMapper; + + public NurseOrderServiceImpl(OrderMapper orderMapper) { + this.orderMapper = orderMapper; + } + + /** + * 执行医嘱退回操作 + * @param orderIds 医嘱ID列表 + */ + @Transactional(rollbackFor = Exception.class) + public void returnOrders(List orderIds) { + for (Long orderId : orderIds) { + Map order = orderMapper.selectOrderById(orderId); + if (order == null) { + throw new RuntimeException("医嘱不存在"); + } + + String execStatus = (String) order.get("execution_status"); + String dispStatus = (String) order.get("dispensing_status"); + String billStatus = (String) order.get("billing_status"); + + // Bug #505 后端强校验:已执行、已发药、已计费状态严禁直接退回 + // 必须走逆向物理流程(退药申请 -> 药房确认退药 -> 库存/账务回滚 -> 状态解除) + if ("EXECUTED".equals(execStatus) || "DISPENSED".equals(dispStatus) || "BILLED".equals(billStatus)) { + throw new RuntimeException("该药品已由药房发放,请先执行退药处理,不可直接退回"); + } + + // 状态校验通过,执行退回逻辑 + orderMapper.updateOrderStatus(orderId, OrderMapper.ORDER_STATUS_RETURNED); + } + } +} diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/mapper/OrderMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/mapper/OrderMapper.java index 103a04152..e1a8ac03c 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/mapper/OrderMapper.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/outpatient/mapper/OrderMapper.java @@ -36,6 +36,9 @@ public interface OrderMapper { /** PRD 中定义的已支付状态 */ String ORDER_STATUS_PAID = "PAID"; + /** PRD 中定义的已退回状态 */ + String ORDER_STATUS_RETURNED = "RETURNED"; + /** * 根据医嘱 ID 查询完整医嘱信息(用于状态校验)。 * @@ -49,47 +52,19 @@ public interface OrderMapper { * **新增**:查询医嘱详情并返回总量单位。 */ @Select("SELECT o.*, d.total_unit FROM his_order o " + - "LEFT JOIN diagnosis_detail d ON o.diagnosis_detail_id = d.id " + + "LEFT JOIN his_order_detail d ON o.id = d.order_id " + "WHERE o.id = #{orderId}") Map selectOrderDetailById(@Param("orderId") Long orderId); /** - * **新增**:将医嘱状态更新为已支付(PAID)。 - * - * @param orderId 医嘱ID - * @param status 新状态码,建议使用 {@link #ORDER_STATUS_PAID} - */ - @Update("UPDATE his_order SET status = #{status} WHERE id = #{orderId}") - int updateOrderStatusToPaid(@Param("orderId") Long orderId, @Param("status") String status); - - /** - * 将医嘱状态更新为已取消(CANCELLED)。 + * **新增**:将医嘱状态更新为已取消(CANCELLED)。 */ @Update("UPDATE his_order SET status = #{status} WHERE id = #{orderId}") int updateOrderStatusToCancelled(@Param("orderId") Long orderId, @Param("status") String status); /** - * 分页查询待写病历数据,仅返回前端展示所需字段,避免全表扫描与冗余数据传输。 - * 修复 Bug #562:数据加载时间超过2秒一直加载 - * - * @param doctorId 医生ID - * @param pageSize 每页条数 - * @param offset 偏移量 - * @return 待写病历列表 + * 通用医嘱状态更新方法(用于退回等场景) */ - @Select("SELECT id, patient_id, patient_name, visit_date, status, doctor_id, " + - "diagnosis, create_time " + - "FROM his_medical_record " + - "WHERE doctor_id = #{doctorId} AND status = 'PENDING' " + - "ORDER BY create_time DESC " + - "LIMIT #{pageSize} OFFSET #{offset}") - List> selectPendingMedicalRecords(@Param("doctorId") Long doctorId, - @Param("pageSize") int pageSize, - @Param("offset") int offset); - - /** - * 统计当前医生待写病历总数 - */ - @Select("SELECT COUNT(*) FROM his_medical_record WHERE doctor_id = #{doctorId} AND status = 'PENDING'") - int countPendingMedicalRecords(@Param("doctorId") Long doctorId); + @Update("UPDATE his_order SET status = #{status} WHERE id = #{orderId}") + int updateOrderStatus(@Param("orderId") Long orderId, @Param("status") String status); } diff --git a/openhis-ui-vue3/src/views/nurse/order-verification/index.vue b/openhis-ui-vue3/src/views/nurse/order-verification/index.vue index 01568fbfb..6ed63151f 100644 --- a/openhis-ui-vue3/src/views/nurse/order-verification/index.vue +++ b/openhis-ui-vue3/src/views/nurse/order-verification/index.vue @@ -59,6 +59,18 @@ const handleReturn = async () => { return } + // Bug #505 核心校验:前置拦截已发药/已执行/已计费的医嘱 + const hasInvalidOrder = selectedOrders.value.some(order => + order.executionStatus === 'EXECUTED' || + order.dispensingStatus === 'DISPENSED' || + order.billingStatus === 'BILLED' + ) + + if (hasInvalidOrder) { + ElMessage.error('该药品已由药房发放,请先执行退药处理,不可直接退回') + return + } + try { await ElMessageBox.confirm('确认退回选中的医嘱吗?', '提示', { confirmButtonText: '确定', @@ -67,14 +79,13 @@ const handleReturn = async () => { }) loading.value = true - const ids = selectedOrders.value.map(o => o.id) - await returnOrderApi(ids) + const orderIds = selectedOrders.value.map(o => o.id) + await returnOrderApi(orderIds) ElMessage.success('退回成功') - selectedOrders.value = [] - // 此处可补充列表刷新逻辑 + // 刷新列表逻辑略 } catch (error) { if (error !== 'cancel') { - ElMessage.error(error.message || '退回失败') + ElMessage.error(error.response?.data?.message || '退回失败') } } finally { loading.value = false @@ -83,12 +94,6 @@ const handleReturn = async () => {