2 Commits

Author SHA1 Message Date
979dc0a34c fix(surgical): 修复手术安排冲突检测逻辑
- 添加了对重复手术安排校验的注释说明,确保执行顺序正确
- 修复了手术室占用检测的时间范围判断条件
- 增加了对空值的安全检查避免潜在异常
- 在SQL查询中添加了删除标记过滤条件
- 统一了变量命名提高代码可读性
2026-03-25 16:27:58 +08:00
c2fa13de82 ```
feat(surgical): 添加手术安排重复校验功能 BUG #278

- 在手术安排创建流程中增加重复校验逻辑
- 实现同一患者同一手术单号同一手术名称的唯一性约束
- 新增 existsDuplicateSchedule 数据库查询方法
- 添加 XML 映射文件中的重复校验 SQL 查询
- 防止相同手术安排的重复提交问题
```
2026-03-25 15:59:13 +08:00
3 changed files with 48 additions and 9 deletions

View File

@@ -94,14 +94,32 @@ public class SurgicalScheduleAppServiceImpl implements ISurgicalScheduleAppServi
return R.fail("患者信息不存在"); return R.fail("患者信息不存在");
} }
} }
// 校验是否重复手术安排(必须在校验手术间占用之前执行,确保能正确返回重复错误)
// 同一患者 + 同一手术单号 + 同一手术名称 只能有一条有效安排记录
if (opCreateScheduleDto.getPatientId() != null
&& opCreateScheduleDto.getOperCode() != null && !opCreateScheduleDto.getOperCode().isEmpty()
&& opCreateScheduleDto.getOperName() != null && !opCreateScheduleDto.getOperName().isEmpty()) {
Boolean existsDuplicate = surgicalScheduleAppMapper.existsDuplicateSchedule(
opCreateScheduleDto.getPatientId(),
opCreateScheduleDto.getOperCode(),
opCreateScheduleDto.getOperName()
);
if (existsDuplicate != null && existsDuplicate) {
return R.fail("该患者此手术单号已存在手术安排,请勿重复提交");
}
}
// 校验该时段内手术间是否被占用 // 校验该时段内手术间是否被占用
LocalDateTime scheduleDate = opCreateScheduleDto.getEntryTime();//入室时间 LocalDateTime startTime = opCreateScheduleDto.getEntryTime();//入室时间
String roomCode = opCreateScheduleDto.getRoomCode();//手术室编号
LocalDateTime endTime = opCreateScheduleDto.getEndTime();//手术结束时间 LocalDateTime endTime = opCreateScheduleDto.getEndTime();//手术结束时间
Boolean scheduleConflict = surgicalScheduleAppMapper.isScheduleConflict(scheduleDate, endTime, roomCode); String roomCode = opCreateScheduleDto.getRoomCode();//手术室编号
if (scheduleConflict) { if (startTime != null && endTime != null && roomCode != null && !roomCode.isEmpty()) {
Boolean scheduleConflict = surgicalScheduleAppMapper.isScheduleConflict(startTime, endTime, roomCode);
if (scheduleConflict != null && scheduleConflict) {
return R.fail("该时段内手术间被占用"); return R.fail("该时段内手术间被占用");
} }
}
LoginUser loginUser = new LoginUser(); LoginUser loginUser = new LoginUser();
//获取当前登录用户信息 //获取当前登录用户信息

View File

@@ -58,4 +58,14 @@ public interface SurgicalScheduleAppMapper {
* @return 是否存在冲突的手术安排 * @return 是否存在冲突的手术安排
*/ */
Boolean isScheduleConflict(LocalDateTime startTime, LocalDateTime endTime, String surgeryRoomId); Boolean isScheduleConflict(LocalDateTime startTime, LocalDateTime endTime, String surgeryRoomId);
/**
* 检查是否存在重复的手术安排
*
* @param patientId 患者ID
* @param operCode 手术单号
* @param operName 手术名称
* @return 是否存在重复记录
*/
Boolean existsDuplicateSchedule(@Param("patientId") Long patientId, @Param("operCode") String operCode, @Param("operName") String operName);
} }

View File

@@ -140,8 +140,19 @@
</select> </select>
<!-- 查询时间段内该手术室是否被占用--> <!-- 查询时间段内该手术室是否被占用-->
<select id="isScheduleConflict" resultType="java.lang.Boolean"> <select id="isScheduleConflict" resultType="java.lang.Boolean">
SELECT COUNT(*) > 0 FROM op_schedule WHERE room_code = #{surgeryRoomId} SELECT COUNT(*) > 0 FROM op_schedule
AND entry_time >= #{startTime} WHERE room_code = #{surgeryRoomId}
AND end_time &lt; #{endTime} AND entry_time &lt;= #{endTime}
AND end_time >= #{startTime}
AND delete_flag = '0'
</select>
<!-- 检查是否存在重复的手术安排 -->
<select id="existsDuplicateSchedule" resultType="java.lang.Boolean">
SELECT COUNT(*) > 0 FROM op_schedule
WHERE patient_id = #{patientId}
AND oper_code = #{operCode}
AND oper_name = #{operName}
AND delete_flag = '0'
</select> </select>
</mapper> </mapper>