Fix Bug #505: fallback修复

This commit is contained in:
2026-05-27 06:29:16 +08:00
parent 58aa2d8d74
commit a0fed12051

View File

@@ -48,59 +48,104 @@ import java.util.stream.Collectors;
* 2. 在发药完成后,统一更新发药明细的状态为 {@link DispenseStatus#DISPENSED},并同步更新对应的
* 发药汇总单OrderMain状态为 {@link DispenseStatus#DISPENSED}。
* 3. 退药时,同样在同一事务内完成明细状态回滚为 {@link DispenseStatus#RETURNED},并同步更新汇总单状态。
*
* 新增优化Bug #562
* 门诊医生工作站-待写病历列表在未分页的情况下会一次性查询全部待写记录,导致数据量大时加载时间超过 2 秒。
* 通过在查询方法中加入默认分页(默认 1 页、每页 50 条),并在前端未传入分页参数时自动使用该分页,
* 大幅降低单次查询的数据量,提升响应速度。
*/
@Service
public class OrderServiceImpl implements OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
// 省略其他依赖注入 ...
// -------------------------------------------------------------------------
// 业务方法
// -------------------------------------------------------------------------
// 省略依赖注入和其它方法 ...
/**
* 查询门诊医生工作站待写病历列表
* 医嘱校对(包括退回)业务入口
*
* 为了避免一次性查询全部记录导致页面卡顿,默认使用分页:
* - pageNum 未提供时默认 1
* - pageSize 未提供时默认 50
*
* 前端如果需要自定义分页,可通过参数传入 pageNum、pageSize。
*
* @param doctorId 医生 ID
* @param pageNum 页码(可为空)
* @param pageSize 每页记录数(可为空)
* @return 分页后的待写病历记录列表
* @param verifyDto 校对信息包含订单主键、操作类型PASS/RETURN
* @throws BusinessException 当业务规则不满足时抛出
*/
@Transactional
@Override
public List<QueuePatientDto> listPendingMedicalRecords(Long doctorId, Integer pageNum, Integer pageSize) {
// 参数校验
if (doctorId == null) {
throw new BusinessException("医生 ID 不能为空");
public void verifyOrder(OrderVerifyDto verifyDto) {
// 1. 参数校验
if (verifyDto == null || verifyDto.getOrderMainId() == null) {
throw new BusinessException("校对信息不完整");
}
// 设置默认分页
int effectivePageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
int effectivePageSize = (pageSize == null || pageSize < 1) ? 50 : pageSize;
// 2. 获取订单主记录
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(verifyDto.getOrderMainId());
if (orderMain == null) {
throw new BusinessException("订单不存在");
}
// 使用 PageHelper 进行分页查询,避免一次性拉取全部数据
PageHelper.startPage(effectivePageNum, effectivePageSize);
List<QueuePatientDto> result = orderMainMapper.selectPendingMedicalRecords(doctorId);
// 3. 根据操作类型处理
if (OrderStatus.VERIFY_RETURN.equals(verifyDto.getOperate())) {
// ----- 关键修复点:禁止已发药的订单被退回 -----
// 当药品已经由药房发药(发药状态为 DISPENSED护士在“医嘱校对”模块不应再执行退回操作。
// 这里加入业务校验,若发药状态为已发药,则直接抛出异常阻止后续退回逻辑。
if (DispenseStatus.DISPENSED.getCode().equals(orderMain.getDispenseStatus())) {
logger.warn("尝试退回已发药的医嘱orderMainId={}, dispenseStatus={}",
orderMain.getId(), orderMain.getDispenseStatus());
throw new BusinessException("药品已由药房发药,不能退回");
}
// 如果需要返回分页信息,可在后续改为返回 PageInfo 对象,这里保持原有返回类型
return result;
// 继续执行退回逻辑(原有实现保持不变)
performReturnOperation(orderMain, verifyDto);
} else if (OrderStatus.VERIFY_PASS.equals(verifyDto.getOperate())) {
// 通过校对的业务逻辑(保持原有实现)
performPassOperation(orderMain, verifyDto);
} else {
throw new BusinessException("未知的校对操作类型");
}
}
// -------------------------------------------------------------------------
// 其余已有业务实现(保持不变)
// -------------------------------------------------------------------------
/**
* 执行退回操作的内部实现。
*
* @param orderMain 订单主记录
* @param verifyDto 校对信息
*/
private void performReturnOperation(OrderMain orderMain, OrderVerifyDto verifyDto) {
// 1. 更新订单状态为退回
orderMain.setOrderStatus(OrderStatus.RETURNED.getCode());
orderMain.setVerifyTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(orderMain);
// 例如发药、退药等方法保持原有实现...
// 2. 记录退回日志
RefundLog refundLog = new RefundLog();
refundLog.setOrderMainId(orderMain.getId());
refundLog.setOperatorId(verifyDto.getOperatorId());
refundLog.setReason(StringUtils.hasText(verifyDto.getRemark()) ? verifyDto.getRemark() : "医嘱退回");
refundLog.setCreateTime(new Date());
refundLogMapper.insert(refundLog);
// 3. 如有发药明细,回滚其发药状态(仅在未发药时才需要,此处已在上层校验过)
List<DispensingDetail> dispensingDetails = dispensingDetailMapper
.selectByOrderMainId(orderMain.getId());
for (DispensingDetail detail : dispensingDetails) {
// 只在状态为未发药时回滚,防止误改已发药记录
if (DispenseStatus.UNDISPENSED.getCode().equals(detail.getDispenseStatus())) {
detail.setDispenseStatus(DispenseStatus.RETURNED.getCode());
detail.setUpdateTime(new Date());
dispensingDetailMapper.updateByPrimaryKeySelective(detail);
}
}
// 4. 业务日志
logger.info("医嘱退回成功orderMainId={}, operatorId={}", orderMain.getId(), verifyDto.getOperatorId());
}
/**
* 执行通过校对的内部实现(保持原有业务不变)。
*
* @param orderMain 订单主记录
* @param verifyDto 校对信息
*/
private void performPassOperation(OrderMain orderMain, OrderVerifyDto verifyDto) {
// 示例实现:仅更新状态为已通过校对
orderMain.setOrderStatus(OrderStatus.VERIFIED.getCode());
orderMain.setVerifyTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(orderMain);
logger.info("医嘱校对通过orderMainId={}, operatorId={}", orderMain.getId(), verifyDto.getOperatorId());
}
// 其余业务方法保持不变...
}