diff --git a/src/com/engine/kq/job/SynClockInTimeJob.java b/src/com/engine/kq/job/SynClockInTimeJob.java index ee596ba..c1a1d78 100644 --- a/src/com/engine/kq/job/SynClockInTimeJob.java +++ b/src/com/engine/kq/job/SynClockInTimeJob.java @@ -1,5 +1,6 @@ package com.engine.kq.job; +import org.apache.commons.lang3.StringUtils; import weaver.conn.RecordSet; import weaver.general.TimeUtil; import weaver.general.Util; @@ -51,6 +52,14 @@ public class SynClockInTimeJob extends BaseCronJob { boolean bool = rs1.executeUpdate("update uf_jbtz set zzdksj=?,zwdkrq=? where id=?",earlystarttime,afterendtime,mainid); if(bool){ rs.writeLog(userid+ " ------------ "+ kssj +" ------------ "+ jsrq +" ---------- "+ bool); + // 计算有效时长 + rs.writeLog("计算有效时长开始"); + rs.writeLog("earlystarttime===" + earlystarttime + ",afterendtime===" + afterendtime + ",gzrq===" + gzrq); + // 来源为导入,且最早、最晚打卡时间,归属日期不为空的数据 + if (StringUtils.isNoneBlank(earlystarttime, afterendtime, gzrq)) { + UpdateEffectiveDuration.execute(mainid, userid, gzrq, earlystarttime, afterendtime,starttime,endtime); + } + rs.writeLog("计算有效时长结束"); } } }catch(Exception e){ diff --git a/src/com/engine/kq/job/UpdateEffectiveDuration.java b/src/com/engine/kq/job/UpdateEffectiveDuration.java new file mode 100644 index 0000000..ec07e1d --- /dev/null +++ b/src/com/engine/kq/job/UpdateEffectiveDuration.java @@ -0,0 +1,317 @@ +package com.engine.kq.job; + +import com.alibaba.fastjson.JSON; +import com.engine.kq.biz.KQShiftManagementComInfo; +import com.engine.kq.biz.KQShiftRestTimeSectionComInfo; +import com.engine.kq.biz.KQWorkTime; +import com.engine.kq.entity.WorkTimeEntity; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import weaver.common.DateUtil; +import weaver.conn.RecordSet; +import weaver.general.BaseBean; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.*; + +/** + * @author:dxfeng + * @createTime: 2024/03/29 + * @version: 1.0 + */ +public class UpdateEffectiveDuration { + /** + * 日期时间格式化 + */ + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + + /** + * 更新加班台账表,有效时长字段 + *

+ *

导入的加班数据增加根据班次的最早最晚打卡时间取交集,按照系统的加班单和打卡数据取交集处理

+ * + * @param mainId 当前数据ID + * @param userId 加班人ID + * @param gzrq 归属日志 + * @param earlyStartTime 最早打卡时间 + * @param afterEndTime 最晚打卡时间 + */ + public static void execute(String mainId, String userId, String gzrq, String earlyStartTime, String afterEndTime, String startTime, String endTime) { + RecordSet recordSet = new RecordSet(); + try { + KQWorkTime kqWorkTime = new KQWorkTime(); + WorkTimeEntity workTimeEntity = kqWorkTime.getWorkTime(userId, gzrq); + String serialId = workTimeEntity.getSerialId(); + recordSet.writeLog("serialId===" + serialId); + if (StringUtils.isBlank(serialId) || "-1".equals(serialId)) { + kqWorkTime.setIsFormat(true); + workTimeEntity = kqWorkTime.getWorkTime(userId, gzrq); + serialId = workTimeEntity.getSerialId(); + } + recordSet.writeLog("userId==" + userId + ",serialId===" + JSON.toJSONString(serialId) + ",workTimeEntity===" + JSON.toJSONString(workTimeEntity)); + // 转换所有的工作时间 + List> workTimeList = new ArrayList<>(); + Map workMap = new HashMap<>(); + workMap.put("startTimes", startTime); + workMap.put("endTimes", endTime); + workTimeList.add(workMap); + recordSet.writeLog("userId==" + userId + ",workTimeList===" + JSON.toJSONString(workTimeList)); + + + // 转换所有的休息时间 + List> restTimeList = new ArrayList<>(); + KQShiftManagementComInfo kqShiftManagementComInfo = new KQShiftManagementComInfo(); + String isRestTimeOpen = kqShiftManagementComInfo.getIsresttimeopen(serialId); + // 排除休息时间是否开启 1表示开启 + recordSet.writeLog("isRestTimeOpen===" + isRestTimeOpen); + if ("1".equals(isRestTimeOpen)) { + List restSectionTimes = new KQShiftRestTimeSectionComInfo().getRestSectionTimes(serialId); + recordSet.writeLog("userId==" + userId + ",restSectionTimes===" + JSON.toJSONString(restSectionTimes)); + if (CollectionUtils.isNotEmpty(restSectionTimes)) { + //convertDateTime(gzrq, restSectionTimes, restTimeList); + convertDateTime2(gzrq, restSectionTimes, restTimeList); + recordSet.writeLog("userId==" + userId + ",restTimeList===" + JSON.toJSONString(restTimeList)); + } + } + + // 所有的有效时间区间 + recordSet.writeLog("userId==" + userId + ",earlyStartTime===" + earlyStartTime + ",afterEndTime===" + afterEndTime); + List effectiveTime = getEffectiveTime(earlyStartTime, afterEndTime, startTime, endTime, restTimeList); + recordSet.writeLog("userId==" + userId + ",effectiveTime===" + JSON.toJSONString(effectiveTime)); + + // 有效区间总计分钟数 + long totalMinutes = effectiveTime.stream() + .mapToInt(interval -> { + String[] parts = interval.split(","); + LocalDateTime start = LocalDateTime.parse(parts[0], DATE_TIME_FORMATTER); + LocalDateTime end = LocalDateTime.parse(parts[1], DATE_TIME_FORMATTER); + return (int) (start.until(end, ChronoUnit.MINUTES)); + }) + .sum(); + double totalHours = (double) totalMinutes / 60; + // 将小时数按照0.5小时的单位向下取整 + double roundedHours = (int) Math.floor(totalHours / 0.5) * 0.5; + recordSet.writeLog("userId==" + userId + ",totalMinutes===" + totalMinutes + ",totalHours==" + totalHours + ",roundedHours==" + roundedHours); + // 更新当前数据的有效时长 + recordSet.executeUpdate("update uf_jbtz set yxsc=? where id=? ", roundedHours, mainId); + + + } catch (Exception e) { + recordSet.writeLog(e); + } + } + + /** + * 获取有效时长时间区间 + */ + private static List getEffectiveTime(String earlyStartTime, String afterEndTime, String startTime, String endTime, List> restTimeList) { + // 打卡时间区间,去除所有的休息时间 + List effectiveTimeList = new ArrayList<>(); + LocalDateTime startSignTime = LocalDateTime.parse(earlyStartTime, DATE_TIME_FORMATTER); + LocalDateTime endSignTime = LocalDateTime.parse(afterEndTime, DATE_TIME_FORMATTER); + + LocalDateTime startWorkTime = LocalDateTime.parse(startTime, DATE_TIME_FORMATTER); + LocalDateTime endWorkTime = LocalDateTime.parse(endTime, DATE_TIME_FORMATTER); + + // 计算交集 + LocalDateTime intersectionStart = startSignTime.isAfter(startWorkTime) ? startSignTime : startWorkTime; + LocalDateTime intersectionEnd = endSignTime.isBefore(endWorkTime) ? endSignTime : endWorkTime; + + + List restIntervals = new ArrayList<>(); + for (Map restTimeMap : restTimeList) { + restIntervals.add(new TimeInterval( + LocalDateTime.parse(restTimeMap.get("startTimes"), DATE_TIME_FORMATTER), + LocalDateTime.parse(restTimeMap.get("endTimes"), DATE_TIME_FORMATTER) + )); + } + // 休息时间区间排序 + restIntervals.sort(Comparator.comparing(TimeInterval::getStart)); + // 实际的工作开始时间、结束时间 + List workIntervals = calculateWorkIntervals(intersectionStart, intersectionEnd, restIntervals); + new BaseBean().writeLog("workIntervals===" + JSON.toJSONString(workIntervals)); + for (TimeInterval workInterval : workIntervals) { + effectiveTimeList.add(workInterval.getStart().format(DATE_TIME_FORMATTER) + "," + workInterval.getEnd().format(DATE_TIME_FORMATTER)); + } + long totalMinutes = calculateTotalWorkMinutes(workIntervals); + new BaseBean().writeLog("totalMinutes==="+totalMinutes); + + + //if (intersectionStart.isBefore(intersectionEnd)) { + // // 去除休息时间 + // for (Map restTimeMap : restTimeList) { + // LocalDateTime startRestTime = LocalDateTime.parse(restTimeMap.get("startTimes"), DATE_TIME_FORMATTER); + // LocalDateTime endRestTime = LocalDateTime.parse(restTimeMap.get("endTimes"), DATE_TIME_FORMATTER); + // + // if (!intersectionEnd.isBefore(startRestTime) && !intersectionStart.isAfter(endRestTime)) { + // if (intersectionStart.isBefore(startRestTime)) { + // // 交集在休息时间之前 + // intersectionEnd = intersectionEnd.isBefore(startRestTime) ? intersectionEnd : startRestTime; + // } else if (intersectionEnd.isAfter(endRestTime)) { + // // 交集在休息时间之后 + // intersectionStart = intersectionStart.isAfter(endRestTime) ? intersectionStart : endRestTime; + // } else { + // // 休息时间在交集中间 + // intersectionStart = startRestTime; + // intersectionEnd = endRestTime; + // } + // } + // } + // effectiveTimeList.add(intersectionStart.format(DATE_TIME_FORMATTER) + "," + intersectionEnd.format(DATE_TIME_FORMATTER)); + //} + + return effectiveTimeList; + } + + + /** + * 转换日期时间 + * + * @param gzrq 归属日期 + * @param sectionTimes 转换前时间 + * @param timeList 转换后日期时间 + */ + private static void convertDateTime(String gzrq, List sectionTimes, List> timeList) { + String currentDate = gzrq; + String preTime = ""; + for (Object sectionTime : sectionTimes) { + List> sectionTime1 = (List) sectionTime; + if (sectionTime1.size() != 2) { + break; + } + // 获取当前的打卡时间 + Map startMap = sectionTime1.get(0); + String startTimes = startMap.get("times"); + Map map = new HashMap<>(); + currentDate = getDateStr(currentDate, preTime, startTimes); + map.put("startTimes", currentDate + " " + startTimes + ":00"); + + Map endMap = sectionTime1.get(1); + String endTimes = endMap.get("times"); + currentDate = getDateStr(currentDate, startTimes, endTimes); + map.put("endTimes", currentDate + " " + endTimes + ":00"); + + preTime = endTimes; + timeList.add(map); + } + } + + private static void convertDateTime2(String gzrq, List sectionTimes, List> timeList) { + String currentDate = gzrq; + String preTime = ""; + for (Object sectionTime : sectionTimes) { + List> sectionTime1 = (List) sectionTime; + if (sectionTime1.size() != 2) { + break; + } + // 获取当前的打卡时间 + Map startMap = sectionTime1.get(0); + String startTimes = startMap.get("times"); + String startAcross = startMap.get("across"); + Map map = new HashMap<>(); + //currentDate = getDateStr(currentDate, preTime, startTimes); + if ("1".equals(startAcross)) { + map.put("startTimes", DateUtil.addDate(currentDate, 1) + " " + startTimes + ":00"); + } else { + map.put("startTimes", currentDate + " " + startTimes + ":00"); + } + + Map endMap = sectionTime1.get(1); + String endTimes = endMap.get("times"); + String endAcross = endMap.get("across"); + + //currentDate = getDateStr(currentDate, startTimes, endTimes); + if ("1".equals(endAcross)) { + map.put("endTimes", DateUtil.addDate(currentDate, 1) + " " + endTimes + ":00"); + } else { + map.put("endTimes", currentDate + " " + endTimes + ":00"); + } + + preTime = endTimes; + timeList.add(map); + } + } + + /** + * 组合日期、时间 + * + * @param currentDate 当前日期 + * @param preTime 之前处理的时间 + * @param currentTime 当前需要处理的时间 + * @return + */ + private static String getDateStr(String currentDate, String preTime, String currentTime) { + // 前一个时间为空,返回当前日期+当前时间 + if (StringUtils.isBlank(preTime)) { + return currentDate; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + LocalTime localPreTime = LocalTime.parse(preTime, formatter); + LocalTime localCurrentTime = LocalTime.parse(currentTime, formatter); + if (localPreTime.isAfter(localCurrentTime)) { + return DateUtil.addDate(currentDate, 1); + } else { + return currentDate; + } + } + + public static List calculateWorkIntervals(LocalDateTime startWork, LocalDateTime endWork, + List restIntervals) { + List workIntervals = new ArrayList<>(); + LocalDateTime currentStart = startWork; + + for (TimeInterval restInterval : restIntervals) { + LocalDateTime restStart = restInterval.getStart(); + LocalDateTime restEnd = restInterval.getEnd(); + + // 如果休息时间与工作时间重合,则调整工作时间段 + if (currentStart.isBefore(restEnd) && endWork.isAfter(restStart)) { + if (currentStart.isBefore(restStart)) { + workIntervals.add(new TimeInterval(currentStart, restStart)); + } + currentStart = restEnd; + } + } + + // 添加剩余的工作时间段 + if (currentStart.isBefore(endWork)) { + workIntervals.add(new TimeInterval(currentStart, endWork)); + } + + return workIntervals; + } + + public static long calculateTotalWorkMinutes(List workIntervals) { + long totalMinutes = 0; + + for (TimeInterval interval : workIntervals) { + totalMinutes += Duration.between(interval.getStart(), interval.getEnd()).toMinutes(); + } + + return totalMinutes; + } + + + static class TimeInterval { + private LocalDateTime start; + private LocalDateTime end; + + public TimeInterval(LocalDateTime start, LocalDateTime end) { + this.start = start; + this.end = end; + } + + public LocalDateTime getStart() { + return start; + } + + public LocalDateTime getEnd() { + return end; + } + } +}