根据你的需求,需要判断dto中的时间区间是否与列表中任何一条记录的时间区间存在重叠。时间区间重叠的判断逻辑是:两条记录的时间区间有交集。
一、时间区间重叠的判断逻辑
假设两条记录的时间区间分别为:
现有记录:
[existingStart, existingEnd]新记录:
[newStart, newEnd]
存在重叠的条件:
text
newStart < existingEnd AND newEnd > existingStart
二、完整方法实现
java
private CommonResult checkSaveData(VehicleDriverDispatchDTO dto) { // 1. 查询该车在相同组织机构、相同调派人员下的所有记录 List<VehicleDriverDispatch> vehicleDriverDispatches = this.lambdaQuery() .eq(VehicleDriverDispatch::getOrganizationId, dto.getOrganizationId()) .eq(VehicleDriverDispatch::getPlateNumber, dto.getPlateNumber()) .eq(VehicleDriverDispatch::getDispatchPersonId, dto.getDispatchPersonId()) .list(); // 2. 判断是否存在时间重叠 boolean isOverlap = vehicleDriverDispatches.stream() .anyMatch(existing -> isTimeOverlap( dto.getStartTime(), dto.getEndTime(), existing.getStartTime(), existing.getEndTime() )); // 3. 返回结果 return isOverlap ? CommonResult.failed("检测到与列表中调派时间有重合,请修改后重新保存") : CommonResult.success(); } /** * 判断两个时间区间是否有重叠 * * @param newStart 新记录开始时间 * @param newEnd 新记录结束时间 * @param existingStart 已有记录开始时间 * @param existingEnd 已有记录结束时间 * @return true-有重叠,false-无重叠 */ private boolean isTimeOverlap(LocalDateTime newStart, LocalDateTime newEnd, LocalDateTime existingStart, LocalDateTime existingEnd) { // 任一时间为空,视为不重叠 if (newStart == null || newEnd == null || existingStart == null || existingEnd == null) { return false; } // 重叠条件:新开始 < 旧结束 AND 新结束 > 旧开始 return newStart.isBefore(existingEnd) && newEnd.isAfter(existingStart); }三、边界情况说明
| 场景 | 示例 | 是否重叠 |
|---|---|---|
| 新记录完全在已有记录之前 | 已有[10:00, 12:00],新[08:00, 09:00] | ❌ 不重叠 |
| 新记录完全在已有记录之后 | 已有[10:00, 12:00],新[13:00, 14:00] | ❌ 不重叠 |
| 新记录与已有记录有部分重叠 | 已有[10:00, 12:00],新[11:00, 13:00] | ✅ 重叠 |
| 新记录完全包含已有记录 | 已有[10:00, 12:00],新[09:00, 13:00] | ✅ 重叠 |
| 新记录被已有记录包含 | 已有[10:00, 12:00],新[10:30, 11:30] | ✅ 重叠 |
| 新记录开始时间等于已有记录结束时间 | 已有[10:00, 12:00],新[12:00, 13:00] | ❌ 不重叠 |
四、如果考虑id去重(更新场景)
如果是更新操作,需要排除自身:
java
private CommonResult checkSaveData(VehicleDriverDispatchDTO dto) { List<VehicleDriverDispatch> vehicleDriverDispatches = this.lambdaQuery() .eq(VehicleDriverDispatch::getOrganizationId, dto.getOrganizationId()) .eq(VehicleDriverDispatch::getPlateNumber, dto.getPlateNumber()) .eq(VehicleDriverDispatch::getDispatchPersonId, dto.getDispatchPersonId()) // 如果是更新,排除自身 .ne(dto.getId() != null, VehicleDriverDispatch::getId, dto.getId()) .list(); boolean isOverlap = vehicleDriverDispatches.stream() .anyMatch(existing -> isTimeOverlap( dto.getStartTime(), dto.getEndTime(), existing.getStartTime(), existing.getEndTime() )); return isOverlap ? CommonResult.failed("检测到与列表中调派时间有重合,请修改后重新保存") : CommonResult.success(); }五、总结
| 场景 | 代码 |
|---|---|
| 判断两个区间是否重叠 | newStart < existingEnd && newEnd > existingStart |
| 避免 null 导致 NPE | 在isTimeOverlap方法中判空 |
| 更新时排除自身 | .ne(dto.getId() != null, VehicleDriverDispatch::getId, dto.getId()) |