|
|
|
@ -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");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 更新加班台账表,有效时长字段
|
|
|
|
|
* <p/>
|
|
|
|
|
* <p>导入的加班数据增加根据班次的最早最晚打卡时间取交集,按照系统的加班单和打卡数据取交集处理</p>
|
|
|
|
|
*
|
|
|
|
|
* @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<Map<String, String>> workTimeList = new ArrayList<>();
|
|
|
|
|
Map<String, String> workMap = new HashMap<>();
|
|
|
|
|
workMap.put("startTimes", startTime);
|
|
|
|
|
workMap.put("endTimes", endTime);
|
|
|
|
|
workTimeList.add(workMap);
|
|
|
|
|
recordSet.writeLog("userId==" + userId + ",workTimeList===" + JSON.toJSONString(workTimeList));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 转换所有的休息时间
|
|
|
|
|
List<Map<String, String>> restTimeList = new ArrayList<>();
|
|
|
|
|
KQShiftManagementComInfo kqShiftManagementComInfo = new KQShiftManagementComInfo();
|
|
|
|
|
String isRestTimeOpen = kqShiftManagementComInfo.getIsresttimeopen(serialId);
|
|
|
|
|
// 排除休息时间是否开启 1表示开启
|
|
|
|
|
recordSet.writeLog("isRestTimeOpen===" + isRestTimeOpen);
|
|
|
|
|
if ("1".equals(isRestTimeOpen)) {
|
|
|
|
|
List<Object> 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<String> 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<String> getEffectiveTime(String earlyStartTime, String afterEndTime, String startTime, String endTime, List<Map<String, String>> restTimeList) {
|
|
|
|
|
// 打卡时间区间,去除所有的休息时间
|
|
|
|
|
List<String> 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<TimeInterval> restIntervals = new ArrayList<>();
|
|
|
|
|
for (Map<String, String> 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<TimeInterval> 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<String, String> 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<Object> sectionTimes, List<Map<String, String>> timeList) {
|
|
|
|
|
String currentDate = gzrq;
|
|
|
|
|
String preTime = "";
|
|
|
|
|
for (Object sectionTime : sectionTimes) {
|
|
|
|
|
List<Map<String, String>> sectionTime1 = (List) sectionTime;
|
|
|
|
|
if (sectionTime1.size() != 2) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// 获取当前的打卡时间
|
|
|
|
|
Map<String, String> startMap = sectionTime1.get(0);
|
|
|
|
|
String startTimes = startMap.get("times");
|
|
|
|
|
Map<String, String> map = new HashMap<>();
|
|
|
|
|
currentDate = getDateStr(currentDate, preTime, startTimes);
|
|
|
|
|
map.put("startTimes", currentDate + " " + startTimes + ":00");
|
|
|
|
|
|
|
|
|
|
Map<String, String> 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<Object> sectionTimes, List<Map<String, String>> timeList) {
|
|
|
|
|
String currentDate = gzrq;
|
|
|
|
|
String preTime = "";
|
|
|
|
|
for (Object sectionTime : sectionTimes) {
|
|
|
|
|
List<Map<String, String>> sectionTime1 = (List) sectionTime;
|
|
|
|
|
if (sectionTime1.size() != 2) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// 获取当前的打卡时间
|
|
|
|
|
Map<String, String> startMap = sectionTime1.get(0);
|
|
|
|
|
String startTimes = startMap.get("times");
|
|
|
|
|
String startAcross = startMap.get("across");
|
|
|
|
|
Map<String, String> 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<String, String> 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<TimeInterval> calculateWorkIntervals(LocalDateTime startWork, LocalDateTime endWork,
|
|
|
|
|
List<TimeInterval> restIntervals) {
|
|
|
|
|
List<TimeInterval> 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<TimeInterval> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|