From bbc7e63b2e6e803f2d6daa9d313fa7c3795085b9 Mon Sep 17 00:00:00 2001 From: Joshi <3040996759@qq.com> Date: Wed, 13 May 2026 16:18:05 +0800 Subject: [PATCH] =?UTF-8?q?refactor(attendance):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=80=83=E5=8B=A4=E6=A3=80=E6=9F=A5=E9=80=BB=E8=BE=91=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=B7=A8=E5=A4=A9=E7=8F=AD=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加跨天班次判断方法 isCrossDayShift - 修改 getRecords 方法支持跨天查询参数 - 重构考勤记录过滤逻辑,添加 filterWindow 方法 - 调整时间段检查逻辑,区分单时段和多时段班次 - 修复早退状态码命名错误(early_1/2 统一为 early_one/two) - 优化打卡时间匹配逻辑,直接使用记录对象而非时间比较 - 更新严重程度比较列表,修正状态码对应关系 --- .../impl/WmsAttendanceCheckServiceImpl.java | 132 +++++++++++------- 1 file changed, 78 insertions(+), 54 deletions(-) diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsAttendanceCheckServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsAttendanceCheckServiceImpl.java index d15e3144..5b0e29e9 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsAttendanceCheckServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsAttendanceCheckServiceImpl.java @@ -103,22 +103,33 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService continue; } - // 获取该员工该日期的所有打卡记录 - List records = getRecords(schedule.getEmployeeName(), schedule.getWorkDate()); + boolean crossDay = isCrossDayShift(schedule); + List records = getRecords(schedule.getEmployeeName(), schedule.getWorkDate(), crossDay); WmsAttendanceCheck check = buildCheck(schedule, rule, records); - // 删除已有的比对结果 baseMapper.delete(Wrappers.lambdaQuery() .eq(WmsAttendanceCheck::getScheduleId, schedule.getScheduleId())); baseMapper.insert(check); } - // 更新连续旷工天数 updateContinuousAbsent(startLocal, endLocal); } + private boolean isCrossDayShift(WmsAttendanceScheduleVo schedule) { + if (schedule.getShiftStartTime() == null || schedule.getShiftEndTime() == null) { + return false; + } + boolean hasPeriod2 = schedule.getShiftStartTime2() != null && schedule.getShiftEndTime2() != null; + if (hasPeriod2) { + return false; + } + LocalTime start = toLocalTime(schedule.getShiftStartTime()); + LocalTime end = toLocalTime(schedule.getShiftEndTime()); + return end.isBefore(start); + } + private WmsAttendanceRule getActiveRule() { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(WmsAttendanceRule::getDelFlag, 0); @@ -137,12 +148,16 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService return rule; } - private List getRecords(String employeeName, Date workDate) { + private List getRecords(String employeeName, Date workDate, boolean crossDay) { AttendanceRecordsBo recordsBo = new AttendanceRecordsBo(); recordsBo.setEname(employeeName); LocalDate ld = toLocalDate(workDate); recordsBo.setChecktimeStart(toDate(ld.atStartOfDay())); - recordsBo.setChecktimeEnd(toDate(ld.atTime(LocalTime.of(23, 59, 59)))); + if (crossDay) { + recordsBo.setChecktimeEnd(toDate(ld.plusDays(1).atTime(LocalTime.of(23, 59, 59)))); + } else { + recordsBo.setChecktimeEnd(toDate(ld.atTime(LocalTime.of(23, 59, 59)))); + } List voList = attendanceRecordsService.queryList(recordsBo); return voList.stream() .map(v -> { @@ -156,7 +171,8 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService .collect(Collectors.toList()); } - private WmsAttendanceCheck buildCheck(WmsAttendanceScheduleVo schedule, WmsAttendanceRule rule, List records) { + private WmsAttendanceCheck buildCheck(WmsAttendanceScheduleVo schedule, WmsAttendanceRule rule, + List records) { WmsAttendanceCheck check = new WmsAttendanceCheck(); check.setScheduleId(schedule.getScheduleId()); check.setUserId(schedule.getUserId()); @@ -167,6 +183,7 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService check.setShiftType(schedule.getShiftType()); boolean hasPeriod2 = schedule.getShiftStartTime2() != null && schedule.getShiftEndTime2() != null; + boolean crossDay = isCrossDayShift(schedule); if (records.isEmpty()) { check.setOverallStatus("absent_full"); @@ -174,51 +191,71 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService return check; } - List checkTimes = records.stream() - .map(r -> toLocalDateTime(r.getChecktime()).toLocalTime()) - .collect(Collectors.toList()); - - if (hasPeriod2) { - // 正常班次:按时间中点划分上下午 + if (!hasPeriod2) { + List filtered = filterWindow(records, schedule.getWorkDate(), + schedule.getShiftStartTime(), schedule.getShiftEndTime(), crossDay); + check.setP1StartTime(schedule.getShiftStartTime()); + check.setP1EndTime(schedule.getShiftEndTime()); + checkPeriod(check, rule, 1, filtered, schedule.getShiftStartTime(), schedule.getShiftEndTime()); + } else { LocalTime p1End = toLocalTime(schedule.getShiftEndTime()); LocalTime p2Start = toLocalTime(schedule.getShiftStartTime2()); LocalTime split = LocalTime.of( (p1End.getHour() + p2Start.getHour()) / 2, (p1End.getMinute() + p2Start.getMinute()) / 2); - List period1Times = new ArrayList<>(); - List period2Times = new ArrayList<>(); - for (LocalTime t : checkTimes) { + List p1Records = new ArrayList<>(); + List p2Records = new ArrayList<>(); + for (AttendanceRecords r : records) { + LocalTime t = toLocalDateTime(r.getChecktime()).toLocalTime(); if (t.isBefore(split)) { - period1Times.add(t); + p1Records.add(r); } else { - period2Times.add(t); + p2Records.add(r); } } check.setP1StartTime(schedule.getShiftStartTime()); check.setP1EndTime(schedule.getShiftEndTime()); - checkPeriod(check, rule, 1, period1Times, schedule.getShiftStartTime(), schedule.getShiftEndTime(), records); + checkPeriod(check, rule, 1, p1Records, schedule.getShiftStartTime(), schedule.getShiftEndTime()); check.setP2StartTime(schedule.getShiftStartTime2()); check.setP2EndTime(schedule.getShiftEndTime2()); - checkPeriod(check, rule, 2, period2Times, schedule.getShiftStartTime2(), schedule.getShiftEndTime2(), records); - } else { - // 倒班:全天一个时段 - check.setP1StartTime(schedule.getShiftStartTime()); - check.setP1EndTime(schedule.getShiftEndTime()); - checkPeriod(check, rule, 1, checkTimes, schedule.getShiftStartTime(), schedule.getShiftEndTime(), records); + checkPeriod(check, rule, 2, p2Records, schedule.getShiftStartTime2(), schedule.getShiftEndTime2()); } - // 总体判定 calculateOverall(check, rule); return check; } + private List filterWindow(List records, Date workDate, + Date expectedStart, Date expectedEnd, boolean crossDay) { + LocalDate ld = toLocalDate(workDate); + LocalTime st = toLocalTime(expectedStart); + LocalTime et = toLocalTime(expectedEnd); + + LocalDateTime windowStart; + LocalDateTime windowEnd; + + if (crossDay) { + windowStart = LocalDateTime.of(ld, st).minusHours(2); + windowEnd = LocalDateTime.of(ld.plusDays(1), et).plusHours(2); + } else { + windowStart = LocalDateTime.of(ld, st).minusHours(2); + windowEnd = LocalDateTime.of(ld, et).plusHours(2); + } + + return records.stream() + .filter(r -> { + LocalDateTime ct = toLocalDateTime(r.getChecktime()); + return !ct.isBefore(windowStart) && !ct.isAfter(windowEnd); + }) + .collect(Collectors.toList()); + } + private void checkPeriod(WmsAttendanceCheck check, WmsAttendanceRule rule, int period, - List periodTimes, Date expectedStart, Date expectedEnd, - List allRecords) { - if (periodTimes.isEmpty()) { + List periodRecords, Date expectedStart, Date expectedEnd) { + if (periodRecords.isEmpty()) { if (period == 1) { check.setP1Status("missed"); } else { @@ -229,21 +266,20 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService LocalTime expStart = toLocalTime(expectedStart); LocalTime expEnd = toLocalTime(expectedEnd); - LocalTime firstCheck = periodTimes.get(0); - LocalTime lastCheck = periodTimes.get(periodTimes.size() - 1); + AttendanceRecords firstRec = periodRecords.get(0); + AttendanceRecords lastRec = periodRecords.get(periodRecords.size() - 1); + LocalTime firstCheck = toLocalDateTime(firstRec.getChecktime()).toLocalTime(); + LocalTime lastCheck = toLocalDateTime(lastRec.getChecktime()).toLocalTime(); int lateMinutes = 0; int earlyMinutes = 0; BigDecimal deduct = BigDecimal.ZERO; String status = "normal"; - // 迟到判定:最早打卡 vs 理论上班时间 if (firstCheck.isAfter(expStart)) { lateMinutes = (int) Duration.between(expStart, firstCheck).toMinutes(); if (lateMinutes > rule.getAbsentHalfDay()) { status = "absent_half"; - } else if (lateMinutes > rule.getLateTwo()) { - status = "absent_half"; } else if (lateMinutes > rule.getLateOne()) { status = "late_two"; deduct = deduct.add(rule.getDeductTwo()); @@ -255,21 +291,17 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService } } - // 早退判定:最晚打卡 vs 理论下班时间 if (lastCheck.isBefore(expEnd)) { int min = (int) Duration.between(lastCheck, expEnd).toMinutes(); if (min > rule.getAbsentHalfDay()) { status = maxSeverity(status, "absent_half"); earlyMinutes = min; - } else if (min > rule.getLateTwo()) { - status = maxSeverity(status, "absent_half"); - earlyMinutes = min; } else if (min > rule.getLateOne()) { - status = maxSeverity(status, "early_2"); + status = maxSeverity(status, "early_two"); deduct = deduct.add(rule.getDeductTwo()); earlyMinutes = min; } else if (min > rule.getLateWarn()) { - status = maxSeverity(status, "early_1"); + status = maxSeverity(status, "early_one"); deduct = deduct.add(rule.getDeductOne()); earlyMinutes = min; } else { @@ -280,25 +312,16 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService } } - // 找到对应的打卡时间 - for (AttendanceRecords r : allRecords) { - LocalTime ct = toLocalDateTime(r.getChecktime()).toLocalTime(); - if (ct.equals(firstCheck)) { - if (period == 1) check.setP1FirstCheck(r.getChecktime()); - else check.setP2FirstCheck(r.getChecktime()); - } - if (ct.equals(lastCheck)) { - if (period == 1) check.setP1LastCheck(r.getChecktime()); - else check.setP2LastCheck(r.getChecktime()); - } - } - if (period == 1) { + check.setP1FirstCheck(firstRec.getChecktime()); + check.setP1LastCheck(lastRec.getChecktime()); check.setP1LateMinutes(lateMinutes); check.setP1EarlyMinutes(earlyMinutes); check.setP1Status(status); check.setP1Deduct(deduct); } else { + check.setP2FirstCheck(firstRec.getChecktime()); + check.setP2LastCheck(lastRec.getChecktime()); check.setP2LateMinutes(lateMinutes); check.setP2EarlyMinutes(earlyMinutes); check.setP2Status(status); @@ -307,7 +330,8 @@ public class WmsAttendanceCheckServiceImpl implements IWmsAttendanceCheckService } private String maxSeverity(String a, String b) { - List severity = java.util.Arrays.asList("normal", "late_warn", "early_warn", "late_one", "early_1", "late_two", "early_2", "absent_half"); + List severity = java.util.Arrays.asList("normal", "late_warn", "early_warn", + "late_one", "early_one", "late_two", "early_two", "absent_half"); int ai = severity.indexOf(a); int bi = severity.indexOf(b); return severity.get(Math.max(ai, bi));