新增校验,防止删除存在有效患者预约的医生排班。

更新 SurgeryDto,为计划手术时间添加 JSON 格式配置。

改进接诊确认逻辑,使医师确认流程更加健壮。

在 OrderMapper 中新增方法,用于统计患者在指定时间段内的有效预约订单数量。

增强 TicketServiceImpl,防止同一患者在相同科室与时间段内重复预约。
This commit is contained in:
2026-04-07 17:37:53 +08:00
parent 2584c8f076
commit e573d9f68b
7 changed files with 88 additions and 6 deletions

View File

@@ -42,4 +42,20 @@ public interface OrderMapper extends BaseMapper<Order> {
* @return 结果
*/
int updatePayStatus(@Param("orderId") Long orderId, @Param("payStatus") Integer payStatus, @Param("payTime") Date payTime);
/**
* 统计同一患者在同一科室、同一时段(上午/下午)内的有效预约订单数量
*
* @param patientId 患者ID
* @param departmentId 科室ID
* @param startTime 时段起始时间(含)
* @param endTime 时段结束时间(不含)
* @param statuses 订单状态集合(如 1=已预约,2=已取号)
* @return 数量
*/
int countPatientDeptOrdersInPeriod(@Param("patientId") Long patientId,
@Param("departmentId") Long departmentId,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime,
@Param("statuses") List<Integer> statuses);
}

View File

@@ -28,6 +28,7 @@ import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -182,6 +183,28 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
throw new RuntimeException("该排班医生已停诊");
}
// 2.1 同一患者同一天/同一科室/同一时段(上午/下午)不可重复预约
if (dto.getPatientId() != null && slot.getDepartmentId() != null && slot.getScheduleDate() != null && slot.getExpectTime() != null) {
boolean isMorning = slot.getExpectTime().isBefore(LocalTime.NOON);
LocalDate scheduleDateForCheck = slot.getScheduleDate();
LocalDateTime periodStart = isMorning
? LocalDateTime.of(scheduleDateForCheck, LocalTime.MIN)
: LocalDateTime.of(scheduleDateForCheck, LocalTime.NOON);
LocalDateTime periodEnd = isMorning
? LocalDateTime.of(scheduleDateForCheck, LocalTime.NOON)
: LocalDateTime.of(scheduleDateForCheck.plusDays(1), LocalTime.MIN);
Date startTime = Date.from(periodStart.atZone(ZoneId.systemDefault()).toInstant());
Date endTime = Date.from(periodEnd.atZone(ZoneId.systemDefault()).toInstant());
// 预约去重以订单为准order_main因为预约成功会先落订单clinical_ticket 不一定在此链路写入
List<Integer> effectiveOrderStatuses = Arrays.asList(AppointmentOrderStatus.BOOKED, AppointmentOrderStatus.CHECKED_IN);
int exists = orderMapper.countPatientDeptOrdersInPeriod(dto.getPatientId(), slot.getDepartmentId(), startTime, endTime, effectiveOrderStatuses);
if (exists > 0) {
throw new RuntimeException("该患者已在当前科室该时段存在预约记录,不可重复预约");
}
}
// 原子抢占:避免并发下同一槽位被重复预约
int lockRows = scheduleSlotMapper.lockSlotForBooking(slotId);
if (lockRows <= 0) {
@@ -264,9 +287,6 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
throw new RuntimeException("当前号源没有可取消的预约订单");
}
// 获取订单信息
Order latestOrder = orders.get(0);
// 直接执行取消,不再检查取消限制
// 根据需求,取消限制应在预约挂号时检查,而非取消预约时
for (Order order : orders) {

View File

@@ -217,6 +217,23 @@
where id = #{id}
</update>
<select id="countPatientDeptOrdersInPeriod" resultType="int">
select count(*)
from order_main
<where>
and patient_id = #{patientId}
and department_id = #{departmentId}
and appointment_time &gt;= #{startTime}
and appointment_time &lt; #{endTime}
<if test="statuses != null and statuses.size() &gt; 0">
and status in
<foreach item="s" collection="statuses" open="(" separator="," close=")">
#{s}
</foreach>
</if>
</where>
</select>
<update id="updateOrderStatusById">
update order_main set status = #{status} where id = #{id}
</update>