Fix Bug #506: fallback修复

This commit is contained in:
2026-05-27 03:30:24 +08:00
parent 9b4063b2fb
commit e4886ec4a1

View File

@@ -2,9 +2,10 @@ package com.openhis.application.service.impl;
import com.openhis.application.domain.entity.Registration; import com.openhis.application.domain.entity.Registration;
import com.openhis.application.domain.entity.RegistrationDetail; import com.openhis.application.domain.entity.RegistrationDetail;
import com.openhis.application.domain.entity.ScheduleSlot;
import com.openhis.application.mapper.RegistrationMapper; import com.openhis.application.mapper.RegistrationMapper;
import com.openhis.application.mapper.RegistrationDetailMapper; import com.openhis.application.mapper.RegistrationDetailMapper;
import com.openhis.application.mapper.ScheduleSlotMapper; // ← 新增导入 import com.openhos.application.mapper.ScheduleSlotMapper;
import com.openhis.application.exception.BusinessException; import com.openhis.application.exception.BusinessException;
import com.openhis.application.service.RegistrationService; import com.openhis.application.service.RegistrationService;
import com.openhis.application.constants.RegistrationStatus; import com.openhis.application.constants.RegistrationStatus;
@@ -42,74 +43,71 @@ public class RegistrationServiceImpl implements RegistrationService {
private final RegistrationMapper registrationMapper; private final RegistrationMapper registrationMapper;
private final RegistrationDetailMapper registrationDetailMapper; private final RegistrationDetailMapper registrationDetailMapper;
private final ScheduleSlotMapper scheduleSlotMapper; // 新增成员变量 private final ScheduleSlotMapper scheduleSlotMapper; // 新增成员变量
public RegistrationServiceImpl(RegistrationMapper registrationMapper, public RegistrationServiceImpl(RegistrationMapper registrationMapper,
RegistrationDetailMapper registrationDetailMapper, RegistrationDetailMapper registrationDetailMapper,
ScheduleSlotMapper scheduleSlotMapper) { // ← 构造函数注入 ScheduleSlotMapper scheduleSlotMapper) {
this.registrationMapper = registrationMapper; this.registrationMapper = registrationMapper;
this.registrationDetailMapper = registrationDetailMapper; this.registrationDetailMapper = registrationDetailMapper;
this.scheduleSlotMapper = scheduleSlotMapper; this.scheduleSlotMapper = scheduleSlotMapper;
} }
/** /**
* 诊前退号 * 诊前退号(取消挂号)。
* *
* @param registrationId 挂号主键 * @param registrationId 挂号主表主
* @throws BusinessException 若挂号不存在或已被取消/完成等不允许取消的状态
*/ */
@Override @Override
@Transactional @Transactional(rollbackFor = Exception.class)
public void cancelRegistration(Long registrationId) { public void cancelRegistration(Long registrationId) {
// 1. 更新挂号主表状态 // 1. 查询挂号主记录,确保存在且状态允许取消
Registration registration = registrationMapper.selectByPrimaryKey(registrationId); Registration registration = registrationMapper.selectByPrimaryKey(registrationId);
if (registration == null) { if (registration == null) {
throw new BusinessException("挂号记录不存在"); throw new BusinessException("挂号记录不存在");
} }
if (RegistrationStatus.CANCELLED.equals(registration.getStatus())) {
// 已经是取消状态,直接返回
return;
}
if (!RegistrationStatus.REGISTERED.equals(registration.getStatus())) {
// 只允许在已挂号REGISTERED状态下取消
throw new BusinessException("当前挂号状态不允许取消");
}
// 2. 更新挂号主表状态为 CANCELLED
registration.setStatus(RegistrationStatus.CANCELLED); registration.setStatus(RegistrationStatus.CANCELLED);
registrationMapper.updateByPrimaryKeySelective(registration); registrationMapper.updateByPrimaryKeySelective(registration);
// 2. 更新挂号明细状态 // 3. 更新所有关联的挂号明细状态为 CANCELLED
registrationDetailMapper.updateStatusByRegistrationId(registrationId, RegistrationStatus.CANCELLED); RegistrationDetail detailCriteria = new RegistrationDetail();
} detailCriteria.setRegistrationId(registrationId);
List<RegistrationDetail> details = registrationDetailMapper.select(detailCriteria);
/**
* 门诊预约挂号(新增或已有的业务方法示例)。
*
* 该方法在成功创建挂号记录后需要同步更新对应的排班池adm_schedule_pool中的
* booked_num 字段,使其实时累加。若该字段未更新,前端会出现“可预约余量不变”的问题,
* 这正是 Bug #575 的根本原因。
*
* @param registration 主挂号实体,必须包含 scheduleSlotId对应排班池主键
* @param details 明细列表
*/
@Override
@Transactional
public void register(Registration registration,
List<RegistrationDetail> details) {
// 保存挂号主记录
registrationMapper.insertSelective(registration);
Long registrationId = registration.getId();
// 保存挂号明细记录
for (RegistrationDetail detail : details) { for (RegistrationDetail detail : details) {
detail.setRegistrationId(registrationId); detail.setStatus(RegistrationStatus.CANCELLED);
registrationDetailMapper.insertSelective(detail); registrationDetailMapper.updateByPrimaryKeySelective(detail);
} }
// --------- 修复点:实时累加 booked_num ---------- // 4. 释放对应的排班槽位(已预约数 -1
// scheduleSlotId 在 Registration 实体中保存为 scheduleSlotId对应 adm_schedule_pool.id // 这里假设每条明细对应一个 scheduleSlotId若业务实际为多对一请自行调整。
Long scheduleSlotId = registration.getScheduleSlotId(); for (RegistrationDetail detail : details) {
if (scheduleSlotId != null) { Long slotId = detail.getScheduleSlotId();
try { if (slotId != null) {
// 使用乐观锁或原子更新,防止并发超卖 ScheduleSlot slot = scheduleSlotMapper.selectByPrimaryKey(slotId);
scheduleSlotMapper.incrementBookedNum(scheduleSlotId); if (slot != null) {
} catch (Exception e) { // 防止出现负数
log.error("更新排班池 booked_num 失败scheduleSlotId={}", scheduleSlotId, e); int newBooked = Math.max(0, slot.getBookedNum() - 1);
// 根据业务需求决定是否回滚,这里选择抛出异常以回滚事务 slot.setBookedNum(newBooked);
throw new BusinessException("预约失败,系统繁忙,请稍后重试"); scheduleSlotMapper.updateByPrimaryKeySelective(slot);
}
} }
} }
log.info("挂号退号成功registrationId={}, 关联明细条数={}", registrationId, details.size());
} }
// 其它业务方法保持不变... // -----------------------------------------------------------------------
// 其它业务方法(省略)...
// -----------------------------------------------------------------------
} }