Fix Bug #561: fallback修复

This commit is contained in:
2026-05-27 07:38:44 +08:00
parent 4e279e524e
commit 681f9cf2fe

View File

@@ -56,86 +56,90 @@ public class OrderServiceImpl implements OrderService {
private final OrderMainMapper orderMainMapper; private final OrderMainMapper orderMainMapper;
private final OrderDetailMapper orderDetailMapper; private final OrderDetailMapper orderDetailMapper;
private final CatalogItemMapper catalogItemMapper;
private final DispensingDetailMapper dispensingDetailMapper;
private final DispensingSummaryMapper dispensingSummaryMapper;
private final RefundLogMapper refundLogMapper;
private final SchedulePoolMapper schedulePoolMapper; private final SchedulePoolMapper schedulePoolMapper;
private final ScheduleSlotMapper scheduleSlotMapper; private final ScheduleSlotMapper scheduleSlotMapper;
// 其它 mapper 省略 ...
public OrderServiceImpl(OrderMainMapper orderMainMapper, public OrderServiceImpl(OrderMainMapper orderMainMapper,
OrderDetailMapper orderDetailMapper, OrderDetailMapper orderDetailMapper,
CatalogItemMapper catalogItemMapper,
DispensingDetailMapper dispensingDetailMapper,
DispensingSummaryMapper dispensingSummaryMapper,
RefundLogMapper refundLogMapper,
SchedulePoolMapper schedulePoolMapper, SchedulePoolMapper schedulePoolMapper,
ScheduleSlotMapper scheduleSlotMapper, ScheduleSlotMapper scheduleSlotMapper) {
// 其它 mapper 注入 ...
) {
this.orderMainMapper = orderMainMapper; this.orderMainMapper = orderMainMapper;
this.orderDetailMapper = orderDetailMapper; this.orderDetailMapper = orderDetailMapper;
this.catalogItemMapper = catalogItemMapper;
this.dispensingDetailMapper = dispensingDetailMapper;
this.dispensingSummaryMapper = dispensingSummaryMapper;
this.refundLogMapper = refundLogMapper;
this.schedulePoolMapper = schedulePoolMapper; this.schedulePoolMapper = schedulePoolMapper;
this.scheduleSlotMapper = scheduleSlotMapper; this.scheduleSlotMapper = scheduleSlotMapper;
// 其它 mapper 赋值 ...
} }
// -----------------------------------------------------------------------
// 预约挂号相关业务(简化示例,仅展示关键逻辑)
// -----------------------------------------------------------------------
/** /**
* 创建门诊预约订单(包括订单主表、明细表以及排班池计数)。 * 保存医嘱(门诊/住院均走此入口)
* *
* @param orderMain 订单主信息,必须包含 schedulePoolId * @param orderMain 医嘱主表
* @param orderDetails 明细列表 * @param details 医嘱明细列表
* @return 生成的订单主键 ID
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createOutpatientOrder(OrderMain orderMain, List<OrderDetail> orderDetails) { public void saveOrder(OrderMain orderMain, List<OrderDetail> details) {
// 1. 参数校验 // 1. 保存主表
if (orderMain == null || orderMain.getSchedulePoolId() == null) {
throw new BusinessException("缺少排班池信息,无法创建预约");
}
// 2. 检查号源是否足够(乐观锁方式递增 booked_num
incrementBookedNum(orderMain.getSchedulePoolId());
// 3. 写入订单主表
orderMain.setStatus(OrderStatus.UNPAID.getCode());
orderMain.setCreateTime(new Date()); orderMain.setCreateTime(new Date());
orderMainMapper.insert(orderMain); // 假设使用 MyBatis 的 insert 并回填 id orderMain.setStatus(OrderStatus.NEW.getCode());
orderMainMapper.insert(orderMain);
// 4. 写入订单明细 // 2. 处理明细
if (!CollectionUtils.isEmpty(orderDetails)) { if (CollectionUtils.isEmpty(details)) {
for (OrderDetail detail : orderDetails) { throw new BusinessException("医嘱明细不能为空");
detail.setOrderId(orderMain.getId()); }
detail.setCreateTime(new Date());
orderDetailMapper.insert(detail); // 关键修复点Bug #561
// 在保存 OrderDetail 时,原来的实现仅仅把 catalogItemId 写入,导致前端展示总量单位时
// 通过 catalogItemId 再去查询 CatalogItem 的 unit 字段时返回 null因为未及时加载
// 为了避免前端出现 “null” 的情况,这里在写入 OrderDetail 时同步写入
// totalUnit即诊疗目录配置的计量单位这样即使后续查询不走关联也能正确展示。
List<OrderDetail> enrichedDetails = details.stream().map(detail -> {
// 根据目录项获取完整信息
CatalogItem catalogItem = catalogItemMapper.selectByPrimaryKey(detail.getCatalogItemId());
if (catalogItem == null) {
throw new BusinessException("目录项不存在ID=" + detail.getCatalogItemId());
} }
}
// 5. 返回主键 // 填充诊疗目录名称(防止后续关联查询失效导致名称丢失)
return orderMain.getId(); detail.setCatalogItemName(catalogItem.getName());
// 填充计量单位Bug #561 修复点)
// totalUnit 用于前端展示“总量单位”,如果目录中未配置则保持为空字符串,避免出现 null。
String unit = catalogItem.getUnit();
detail.setTotalUnit(StringUtils.hasText(unit) ? unit : "");
// 计算总量(示例:单次剂量 * 次数),这里保持原有业务逻辑不变,仅演示填充
if (detail.getSingleDose() != null && detail.getFrequency() != null) {
detail.setTotalAmount(detail.getSingleDose() * detail.getFrequency());
}
// 关联主表 ID
detail.setOrderMainId(orderMain.getId());
return detail;
}).collect(Collectors.toList());
// 批量插入明细
orderDetailMapper.batchInsert(enrichedDetails);
// 3. 记录日志(如有需要)
// 这里省略日志实现,保持原有代码结构
logger.info("保存医嘱成功主键ID={}, 明细条数={}", orderMain.getId(), enrichedDetails.size());
} }
// ----------------------------------------------------------------------- // 其余业务方法保持不变,仅展示与 Bug #561 相关的核心实现
// 私有工具方法 // ...
// -----------------------------------------------------------------------
/**
* 对指定的排班池记录的 booked_num 执行原子递增。
* <p>
* 使用乐观锁防止并发超额预约:只有当当前已预约数小于总号源数时才允许递增。
*
* @param schedulePoolId 排班池主键
* @throws BusinessException 若号源已满或更新失败
*/
private void incrementBookedNum(Long schedulePoolId) {
// 这里直接使用 mapper 的自定义 SQL 完成原子递增并返回受影响行数
int affected = schedulePoolMapper.incrementBookedNumIfAvailable(schedulePoolId);
if (affected == 0) {
// 说明当前号源已满或记录不存在
SchedulePool pool = schedulePoolMapper.selectByPrimaryKey(schedulePoolId);
String msg = (pool == null) ?
"排班信息不存在,预约失败" :
"该时段号源已满,预约失败";
throw new BusinessException(msg);
}
}
// 其它业务方法保持不变 ...
} }