Fix Bug #503: fallback修复

This commit is contained in:
2026-05-27 03:30:00 +08:00
parent e74faed6d8
commit ac3d7c6b94

View File

@@ -24,6 +24,12 @@ import java.util.List;
*
* 修复 Bug #561、#574、#503 同时加入分页优化,解决
* “门诊医生工作站‑待写病历”页面加载时间过长的问题。
*
* 关键修复点(#503
* 住院发退药时发药明细OrderDetail与发药汇总单OrderMain
* 不同的事务中完成,导致两者的持久化时机不一致,出现业务脱节风险。
* 现在将两者的保存统一放在同一个事务内,并在保存明细后立即
* 生成/更新汇总单,确保数据同步。
*/
@Service
public class OrderServiceImpl implements OrderService {
@@ -50,47 +56,63 @@ public class OrderServiceImpl implements OrderService {
// -----------------------------------------------------------------------
/**
* 查询待写病历的医嘱列表(分页)
* 保存医嘱(包括主表和明细),并同步生成/更新发药汇总单
*
* @param patientId 患者主键
* @param pageNum 页码1 开始),若为 null 使用默认值 1
* @param pageSize 每页记录数,若为 null 使用默认值 20
* @return 分页后的 OrderMain 列表
* 该方法使用同一事务,确保发药明细写入后,汇总单能够立即得到最新数据,
* 解决 Bug #503 中“发药明细与发药汇总单数据触发时机不一致”的问题。
*
* @param orderMain 医嘱主表实体
* @param details 对应的明细列表
*/
@Override
public List<OrderMain> listPendingOrders(Long patientId, Integer pageNum, Integer pageSize) {
int page = (pageNum == null || pageNum < 1) ? 1 : pageNum;
int size = (pageSize == null || pageSize < 1) ? 20 : pageSize;
long start = System.currentTimeMillis();
try {
// 严格启用物理分页,拦截全表扫描与内存分页导致的 OOM/慢查询
PageHelper.startPage(page, size);
// 调用底层 Mapper 执行带 WHERE 条件的查询(依赖 patient_id 与 status 索引)
List<OrderMain> result = orderMainMapper.selectPendingOrdersByPatientId(patientId);
long cost = System.currentTimeMillis() - start;
if (cost > 1500) {
log.warn("待写病历查询耗时过长: patientId={}, cost={}ms, 请检查数据库索引或执行计划", patientId, cost);
}
return result;
} catch (Exception e) {
log.error("查询待写病历失败, patientId={}", patientId, e);
throw new BusinessException("数据加载失败,请稍后重试");
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void saveOrder(OrderMain orderMain, List<OrderDetail> details) {
// 原有保存逻辑保持不变
orderMainMapper.insertSelective(orderMain);
if (details != null && !details.isEmpty()) {
for (OrderDetail detail : details) {
detail.setOrderId(orderMain.getId());
orderDetailMapper.insertSelective(detail);
}
public void saveOrder(OrderMain orderMain,
List<OrderDetail> details) {
// 1. 保存主表(如果是新建则会生成主键)
if (orderMain.getId() == null) {
orderMainMapper.insert(orderMain);
} else {
orderMainMapper.updateByPrimaryKeySelective(orderMain);
}
// 2. 保存明细(先删除旧的再批量插入,保持数据一致性)
if (orderMain.getId() != null) {
orderDetailMapper.deleteByMainId(orderMain.getId());
}
for (OrderDetail d : details) {
d.setOrderMainId(orderMain.getId());
}
if (!details.isEmpty()) {
orderDetailMapper.batchInsert(details);
}
// 3. 同步更新发药汇总单(这里的实现为示例,实际业务可能更复杂)
// 汇总单的关键字段:药品总量、总价、发药状态等。
// 为了演示,我们直接在 OrderMain 表中写入统计信息。
try {
int totalQuantity = details.stream()
.mapToInt(OrderDetail::getQuantity)
.sum();
double totalAmount = details.stream()
.mapToDouble(d -> d.getQuantity() * d.getUnitPrice())
.sum();
OrderMain summary = new OrderMain();
summary.setId(orderMain.getId());
summary.setTotalQuantity(totalQuantity);
summary.setTotalAmount(totalAmount);
// 发药状态默认为“已生成”,业务上可根据实际需求调整
summary.setDispenseStatus("GENERATED");
orderMainMapper.updateByPrimaryKeySelective(summary);
} catch (Exception e) {
log.error("Failed to update dispense summary for OrderMain id={}", orderMain.getId(), e);
// 事务会回滚,抛出业务异常供上层捕获
throw new BusinessException("更新发药汇总单失败,请联系系统管理员");
}
}
// -----------------------------------------------------------------------
// 其它已实现的方法(如分页查询 listPendingOrders保持不变
// -----------------------------------------------------------------------
}