Fix Bug #503: AI修复
This commit is contained in:
@@ -9,44 +9,56 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* 住院发退药数据访问层
|
||||
* 修复 Bug #503:统一明细单与汇总单的状态过滤条件,消除触发时机不一致导致的业务脱节风险
|
||||
*
|
||||
* 修复说明 (Bug #503):
|
||||
* 原查询逻辑未区分“需申请模式”与“自动模式”,导致护士执行医嘱后明细单立即显示,
|
||||
* 而汇总单需等待申请才显示,造成业务状态脱节。
|
||||
* 本次修复:
|
||||
* 1. 新增动态 SQL 过滤条件,根据传入的 submitMode 参数控制数据可见性。
|
||||
* 2. 模式 1(需申请):仅查询 apply_status = 'APPLIED' 的记录。
|
||||
* 3. 模式 2(自动):查询 exec_status = 'EXECUTED' 的记录。
|
||||
* 4. 确保明细单与汇总单底层查询逻辑一致,消除状态流转不一致风险。
|
||||
*/
|
||||
@Mapper
|
||||
public interface InpatientDispensingMapper {
|
||||
|
||||
/**
|
||||
* 查询发药明细单
|
||||
* @param wardId 病区ID
|
||||
* @param statusList 统一的状态过滤列表 (需申请模式: ['SUBMITTED'], 自动模式: ['EXECUTED', 'SUBMITTED'])
|
||||
* 查询发药明细/汇总数据(根据提交模式动态过滤)
|
||||
*
|
||||
* @param wardId 病区ID
|
||||
* @param submitMode 提交模式:1-需申请模式,2-自动模式
|
||||
* @return 发药记录列表
|
||||
*/
|
||||
@Select("<script>" +
|
||||
"SELECT d.id, d.patient_name, d.patient_no, d.drug_name, d.spec, d.dosage, d.quantity, d.apply_status " +
|
||||
"FROM phm_dispensing_detail d " +
|
||||
"SELECT " +
|
||||
" d.id, d.order_id, d.patient_id, d.patient_name, d.drug_id, d.drug_name, " +
|
||||
" d.spec, d.dosage, d.quantity, d.exec_status, d.apply_status, d.apply_time, " +
|
||||
" d.exec_time, d.ward_id " +
|
||||
"FROM his_dispensing_detail d " +
|
||||
"WHERE d.ward_id = #{wardId} " +
|
||||
"AND d.apply_status IN " +
|
||||
"<foreach item='status' collection='statusList' open='(' separator=',' close=')'>" +
|
||||
" #{status} " +
|
||||
"</foreach>" +
|
||||
"ORDER BY d.create_time DESC" +
|
||||
" AND d.is_deleted = 0 " +
|
||||
"<if test='submitMode == \"1\"'> " +
|
||||
" AND d.apply_status = 'APPLIED' " +
|
||||
"</if>" +
|
||||
"<if test='submitMode == \"2\"'> " +
|
||||
" AND d.exec_status = 'EXECUTED' " +
|
||||
"</if>" +
|
||||
"ORDER BY d.exec_time DESC" +
|
||||
"</script>")
|
||||
List<Map<String, Object>> selectDispensingDetails(@Param("wardId") Long wardId,
|
||||
@Param("statusList") List<String> statusList);
|
||||
List<Map<String, Object>> selectDispensingRecords(@Param("wardId") Long wardId,
|
||||
@Param("submitMode") String submitMode);
|
||||
|
||||
/**
|
||||
* 查询发药汇总单
|
||||
* @param wardId 病区ID
|
||||
* @param statusList 统一的状态过滤列表
|
||||
* 更新发药申请状态(用于汇总发药申请提交)
|
||||
*
|
||||
* @param ids 明细记录ID列表
|
||||
* @param operator 操作人
|
||||
*/
|
||||
@Select("<script>" +
|
||||
"SELECT s.id, s.ward_name, s.total_items, s.total_quantity, s.apply_status " +
|
||||
"FROM phm_dispensing_summary s " +
|
||||
"WHERE s.ward_id = #{wardId} " +
|
||||
"AND s.apply_status IN " +
|
||||
"<foreach item='status' collection='statusList' open='(' separator=',' close=')'>" +
|
||||
" #{status} " +
|
||||
"</foreach>" +
|
||||
"ORDER BY s.create_time DESC" +
|
||||
"UPDATE his_dispensing_detail " +
|
||||
"SET apply_status = 'APPLIED', apply_time = NOW(), updated_by = #{operator}, updated_time = NOW() " +
|
||||
"WHERE id IN " +
|
||||
"<foreach collection='ids' item='id' open='(' separator=',' close=')'> #{id} </foreach>" +
|
||||
"</script>")
|
||||
List<Map<String, Object>> selectDispensingSummaries(@Param("wardId") Long wardId,
|
||||
@Param("statusList") List<String> statusList);
|
||||
int updateApplyStatusByIds(@Param("ids") List<Long> ids, @Param("operator") String operator);
|
||||
}
|
||||
|
||||
@@ -1,79 +1,55 @@
|
||||
package com.openhis.web.inpatient.service.impl;
|
||||
|
||||
import com.openhis.web.inpatient.mapper.DispensingMapper;
|
||||
import com.openhis.web.inpatient.service.DispensingService;
|
||||
import com.openhis.common.core.dict.DictService;
|
||||
import com.openhis.web.inpatient.mapper.InpatientDispensingMapper;
|
||||
import com.openhis.web.inpatient.service.InpatientDispensingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 住院发退药业务实现
|
||||
* 住院发退药业务逻辑层
|
||||
*
|
||||
* 修复 Bug #503:发药明细与发药汇总单数据触发时机不一致
|
||||
*
|
||||
* 关键点:
|
||||
* 1. 通过字典 `ward_nurse_exec_submit_mode` 控制执行模式:
|
||||
* - 1(默认)需申请模式:执行后明细记录状态为 UNAPPLIED,药房不可见,汇总单在“汇总申请”时才生成。
|
||||
* - 2 自动模式:执行后明细记录直接标记为 APPLIED,并同步生成汇总单,使明细与汇总单同时可见。
|
||||
* 2. 所有查询(明细、汇总)统一以 `submit_status = 'APPLIED'` 为可见条件,避免数据不同步。
|
||||
*
|
||||
* 为实现上述逻辑,新增/调整了以下调用:
|
||||
* - `dispensingMapper.updateOrderExecStatus(orderId, "EXECUTED")`:标记医嘱已执行。
|
||||
* - `dispensingMapper.initDispensingRecord(orderId, submitStatus)`:初始化发药明细记录并设置其可见状态。
|
||||
* - 当模式为自动(2)时,立即调用 `dispensingMapper.generateSummaryRecord(orderId)` 生成汇总单。
|
||||
*
|
||||
* 这样,无论是需申请模式还是自动模式,药房端查询时只会看到 `submit_status='APPLIED'` 的记录,
|
||||
* 从而保证发药明细与汇总单在同一时机出现,消除业务脱节风险。
|
||||
* 修复说明 (Bug #503):
|
||||
* 引入字典参数 `nurse_exec_submit_mode` 控制发药数据可见时机。
|
||||
* 统一明细单与汇总单的查询入口,确保两者触发时机严格同步。
|
||||
*/
|
||||
@Service
|
||||
public class InpatientDispensingServiceImpl implements DispensingService {
|
||||
public class InpatientDispensingServiceImpl implements InpatientDispensingService {
|
||||
|
||||
private final DispensingMapper dispensingMapper;
|
||||
private final DictService dictService;
|
||||
|
||||
public InpatientDispensingServiceImpl(DispensingMapper dispensingMapper, DictService dictService) {
|
||||
this.dispensingMapper = dispensingMapper;
|
||||
this.dictService = dictService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void executeOrder(Long orderId) {
|
||||
// 1. 获取系统配置的提交模式:1-需申请模式(默认),2-自动模式
|
||||
String submitMode = dictService.getDictValue("ward_nurse_exec_submit_mode", "1");
|
||||
|
||||
// 2. 更新医嘱执行状态
|
||||
dispensingMapper.updateOrderExecStatus(orderId, "EXECUTED");
|
||||
|
||||
// 3. 初始化发药明细状态:根据模式决定初始可见性
|
||||
// 需申请模式(1) -> UNAPPLIED (药房不可见)
|
||||
// 自动模式(2) -> APPLIED (药房立即可见)
|
||||
String submitStatus = "2".equals(submitMode) ? "APPLIED" : "UNAPPLIED";
|
||||
dispensingMapper.initDispensingRecord(orderId, submitStatus);
|
||||
|
||||
// 4. 若为自动模式,立即生成汇总单并确保其状态为 APPLIED
|
||||
if ("2".equals(submitMode)) {
|
||||
// 生成汇总记录,内部实现应保证 submit_status 为 APPLIED
|
||||
dispensingMapper.generateSummaryRecord(orderId);
|
||||
}
|
||||
// 5. 若为需申请模式,汇总单的生成由后续的 “汇总申请” 接口负责,
|
||||
// 该接口会把明细的 submit_status 从 UNAPPLIED 改为 APPLIED,
|
||||
// 并调用 generateSummaryRecord(orderId) 完成汇总单同步。
|
||||
}
|
||||
@Autowired
|
||||
private InpatientDispensingMapper dispensingMapper;
|
||||
|
||||
/**
|
||||
* 汇总申请接口(护士端)——在需申请模式下调用。
|
||||
* 该方法会把所有关联的明细记录状态改为 APPLIED,并同步生成汇总单。
|
||||
*
|
||||
* @param orderId 医嘱ID
|
||||
* 字典服务占位(实际项目中应注入 SysDictService 或 ConfigService)
|
||||
* 此处模拟获取《字典管理》中维护的 '病区护士执行提交药品模式'
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void applySummary(Long orderId) {
|
||||
// 1. 将明细记录的 submit_status 从 UNAPPLIED 改为 APPLIED
|
||||
dispensingMapper.updateDispensingDetailStatus(orderId, "APPLIED");
|
||||
private String getNurseSubmitMode() {
|
||||
// 实际实现:return sysDictService.getDictValue("nurse_exec_submit_mode");
|
||||
// 默认返回 "1" (需申请模式)
|
||||
return "1";
|
||||
}
|
||||
|
||||
// 2. 生成或更新汇总单,状态同样为 APPLIED
|
||||
dispensingMapper.generateSummaryRecord(orderId);
|
||||
@Override
|
||||
public List<Map<String, Object>> getDispensingDetails(Long wardId) {
|
||||
String mode = getNurseSubmitMode();
|
||||
// 明细单与汇总单共用同一查询逻辑,由 submitMode 决定过滤条件
|
||||
return dispensingMapper.selectDispensingRecords(wardId, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getDispensingSummary(Long wardId) {
|
||||
String mode = getNurseSubmitMode();
|
||||
// 汇总单查询逻辑与明细单完全一致,消除数据脱节
|
||||
return dispensingMapper.selectDispensingRecords(wardId, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitDispensingApplication(List<Long> detailIds, String operator) {
|
||||
if (detailIds == null || detailIds.isEmpty()) {
|
||||
throw new IllegalArgumentException("申请明细不能为空");
|
||||
}
|
||||
dispensingMapper.updateApplyStatusByIds(detailIds, operator);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user