From 7714717268d0f25028a822d553bf35b1df745507 Mon Sep 17 00:00:00 2001 From: fl <3098731433@qq.com> Date: Wed, 11 Dec 2024 17:28:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=8E=A8=E9=80=81=E8=B7=A8?= =?UTF-8?q?=E6=9C=88=E5=8E=86=E5=8F=B2=E6=95=B0=E6=8D=AE=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9=20=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/att/dao/AttSourceDataDao.java | 13 ++ .../bonus/system/att/entity/AttGroupBean.java | 15 ++ .../com/bonus/system/att/tasks/AttTasks.java | 136 +++++++++++++----- .../bonus/system/att/tasks/WechatTasks.java | 10 +- .../system/att/utils/WorkdayCalculator.java | 72 ++++++---- .../resources/mapper/att/AttGroupMapper.xml | 2 +- .../mapper/att/AttSourceDataMapper.xml | 39 +++-- 7 files changed, 207 insertions(+), 80 deletions(-) diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/AttSourceDataDao.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/AttSourceDataDao.java index 63b29e0..4ee4f0e 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/AttSourceDataDao.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/AttSourceDataDao.java @@ -143,4 +143,17 @@ public interface AttSourceDataDao { List getSourceAttNoInOutData(); void delHisData(String date); + + /** + * 查询人员固定时间请假消息 + * @param attSourceDataBean + * @return + */ + int getLeaveDataByUserId(AttSourceDataBean attSourceDataBean); + + /** + * 插入工作异常 + * @param longBreakRecords + */ + void insertWorkAbnormal(List longBreakRecords); } diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttGroupBean.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttGroupBean.java index 1797f49..e297739 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttGroupBean.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttGroupBean.java @@ -39,6 +39,16 @@ public class AttGroupBean { */ private String offWorkTime; + /** + * 休息开始时间 + */ + private String breakStartTime; + + /** + * 休息结束时间 + */ + private String breakEndTime; + /** * 每天打卡(次) */ @@ -69,6 +79,11 @@ public class AttGroupBean { */ private Long absenteeismLeaveMinute; + /** + * 工作异常时长分钟 + */ + private Long workAbnormalMinute; + /** * 应出勤时长 */ diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/AttTasks.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/AttTasks.java index d8a4683..86d5517 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/AttTasks.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/AttTasks.java @@ -60,7 +60,7 @@ public class AttTasks { private volatile boolean executed = false; // 标志位,表示任务是否已经执行过 // @Scheduled(cron = "0 0/10 * * * ?") - @Scheduled(initialDelay = 60000 * 5,fixedDelay = 60000 * 10) +// @Scheduled(initialDelay = 60000 * 5, fixedDelay = 60000 * 10) @Async public void getAttTasks() { log.info("--------考勤定时器开启------"); @@ -72,7 +72,7 @@ public class AttTasks { /** * 历史考勤数据 */ -// @Scheduled(fixedDelay = 60000 * 30) + @Scheduled(fixedDelay = 60000 * 30) @Async public void getHisAttTasks() { log.info("--------考勤定时器开启------"); @@ -80,8 +80,8 @@ public class AttTasks { return; // 如果任务已经执行过,直接返回 } executed = true; // 设置标志位,表示任务已经执行过 - String startDate = "2024-11-20"; - String endDate = "2024-11-21"; + String startDate = "2024-11-01"; + String endDate = "2024-11-05"; List dateList = getStrDateListBetween(startDate, endDate); // 创建固定大小的线程池 ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); @@ -343,7 +343,7 @@ public class AttTasks { groupList.forEach(c -> { //应考勤天 List attDayList = WorkdayCalculator.getWorkDay(c.getAttDay(), - Integer.parseInt(c.getAttType()), holidays); + Integer.parseInt(c.getAttType()), holidays,pushDate); c.setAttWorkDayBean(new PersonAttWorkDayBean(c.getGroupId(), attDayList.size(), attDayList)); }); return groupList; @@ -603,34 +603,10 @@ public class AttTasks { list.add(backOffWorkBean); } } -// if (nextOffWork != null) { -// if (StringUtils.isNotEmpty(nextOffWork.getAttCurrentTime())) { -// list.add(nextOffWork); -// } -// } }); return list; } - public AttSourceDataBean getNextOffWorkDate(List v) { - AttSourceDataBean nextOffWork = v.stream() - .filter(a -> { - String time = a.getAttCurrentTime(); - String startTime = DateUtils.getYyyyMmDd(a.getAttCurrentTime()) + " 00:00:00"; - String endTime = DateUtils.getYyyyMmDd(a.getAttCurrentTime()) + " 04:59:59"; - return DateUtils.getTimeIsRange(time, startTime, endTime); - }) - .collect(Collectors.toList()) - .stream().max(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null); - if (nextOffWork != null) { - if (StringUtils.isNotEmpty(nextOffWork.getAttCurrentTime())) { - nextOffWork.setAttType("2"); - nextOffWork.setAttCurrentDay(DateUtils.getAfterDate(nextOffWork.getAttCurrentDay())); - return nextOffWork; - } - } - return null; - } /** * 固定考勤数据计算 @@ -703,11 +679,11 @@ public class AttTasks { //最新一次下班时间插入list newList.add(backOffWorkBean); } - if(v.get(0).getName().equals("肖阳")){ - System.out.println("c.getAttCurrentTime() = "); - } +// if(v.get(0).getName().equals("肖阳")){ +// System.out.println("c.getAttCurrentTime() = "); +// } // 处理逻辑 出入异常的逻辑 - Map> result = checkAdjacentAttType1WithGapAndCheckTypesBefore(v,attGroupBean.getEntryAbnormalMinute()); + Map> result = checkAdjacentAttType1WithGapAndCheckTypesBefore(v, attGroupBean.getEntryAbnormalMinute()); if (result.containsKey(true)) { List matchingItems = result.get(true); frontToWorkBean = matchingItems.get(0); @@ -717,15 +693,102 @@ public class AttTasks { } //没有下班卡则添加第一次打卡数据 newList.add(frontToWorkBean); + //获取工作异常 + LocalTime lastOutTime = null; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + //存储工作异常的list + List longBreakRecords = new ArrayList<>(); + for (int i = 0; i < v.size(); i++) { + AttSourceDataBean record = v.get(i); + // 如果是“出”的记录,保存时间 + if ("2".equals(record.getAttType())) { + lastOutTime = LocalDateTime.parse(record.getAttCurrentTime(), dateTimeFormatter).toLocalTime(); + if(lastOutTime.isAfter(LocalTime.parse(attGroupBean.getOffWorkTime(), timeFormatter))){ + //进在下班之后,不考虑 + break; + } + } + // 如果是“进”的记录并且之前有“出”的记录 + else if ("1".equals(record.getAttType()) && lastOutTime != null) { + LocalTime inTime = LocalDateTime.parse(record.getAttCurrentTime(), dateTimeFormatter).toLocalTime(); + // 计算实际工作时间(不包括午休时间) +// if(record.getName().equals("何波")){ +// System.out.println("11111111111"); +// } + // 出-》进 的时间在上班时间前,去除 + if(inTime.isBefore(LocalTime.parse(attGroupBean.getToWorkTime(), timeFormatter))){ + //进在上班之后,不考虑 + break; + } + Duration workDuration = calculateWorkDuration(lastOutTime, inTime, attGroupBean); + // 如果工作时间外出超过了规定时间,记录下这对“出”和“进” + if (workDuration != null && !workDuration.isNegative() && workDuration.toMinutes() > attGroupBean.getWorkAbnormalMinute()) { + AttSourceDataBean longBreakRecord = new AttSourceDataBean(); + longBreakRecord.setUserId(record.getUserId()); + longBreakRecord.setName(record.getName()); + longBreakRecord.setOrgId(attGroupBean.getOrgId()); + longBreakRecord.setAttCurrentDay(record.getAttCurrentDay()); + longBreakRecord.setAttCurrentTime(v.get(i - 1).getAttCurrentTime() + " " + record.getAttCurrentTime()); + longBreakRecord.setAttAddress(v.get(i - 1).getAttAddress() + " " + record.getAttAddress()); + longBreakRecords.add(longBreakRecord); + } + // 更新lastOutTime为null,因为已经处理了这一对 + lastOutTime = null; + } + } + //判断有没有临时外出请假等等 + if(!longBreakRecords.isEmpty()){ + int x = attSourceDataDao.getLeaveDataByUserId(longBreakRecords.get(0)); + if(x==0){ + attSourceDataDao.insertWorkAbnormal(longBreakRecords); + } + } + } }); return newList; } + private static Duration calculateWorkDuration(LocalTime outTime, LocalTime inTime, AttGroupBean group) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + // 解析上班、下班、午休开始、结束时间 + LocalTime offWorkTime = LocalTime.parse(group.getOffWorkTime(), formatter); + LocalTime breakStartTime = LocalTime.parse(group.getBreakStartTime(), formatter); + LocalTime breakEndTime = LocalTime.parse(group.getBreakEndTime(), formatter); + // 如果出勤时间在午休时间内,调整出勤时间为午休结束时间 + if (outTime.isAfter(breakStartTime) && outTime.isBefore(breakEndTime)) { + outTime = breakEndTime; + } + // 如果进入时间在午休时间内,调整进入时间为午休开始时间 + if (inTime.isAfter(breakStartTime) && inTime.isBefore(breakEndTime)) { + inTime = breakStartTime; + } + // 如果进入时间在下班时间内,调整进入时间为下班时间 + if (inTime.isAfter(offWorkTime)) { + inTime = offWorkTime; + } + // 计算总的工作时间 + Duration totalDuration = Duration.between(outTime, inTime); + // 如果时间段跨越了午休时间,减去午休时长 + if (outTime.isBefore(breakEndTime) && inTime.isAfter(breakStartTime)) { + Duration breakDuration = Duration.between(breakStartTime, breakEndTime); + totalDuration = totalDuration.minus(breakDuration); + } + return totalDuration; + } catch (DateTimeParseException e) { + // 处理解析异常,例如记录日志或返回默认值 + System.err.println("时间解析错误: " + e.getMessage()); + return null; // 或者返回一个默认的 LocalDateTime + } + } + /** * 根据getAttCurrentTime对List进行正序排序。 * 遍历排序后的列表,找到最早相邻且间隔时间大于2分钟的两个attType = 1的数据项。 * 检查这两个数据项之前的数据集合是否同时包含attType = 1和attType = 2的数据。 + * * @param items * @param entryAbnormalMinute * @return @@ -861,10 +924,11 @@ public class AttTasks { if (minutesDiff >= attGroupBean.getAttendanceDuration()) { backOffWorkBean.setAttStatus(1); } else { - if (minutesDiff < attGroupBean.getAbsenteeismLateMinute()) { + if (minutesDiff > attGroupBean.getAbsenteeismLateMinute()) { + backOffWorkBean.setAttStatus(1); + }else if (minutesDiff > attGroupBean.getAbsenteeismLeaveMinute()) { backOffWorkBean.setAttStatus(4); - } - if (minutesDiff < attGroupBean.getAbsenteeismLeaveMinute()) { + }else{ backOffWorkBean.setAttStatus(3); } } diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/WechatTasks.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/WechatTasks.java index 27bf120..f04dc09 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/WechatTasks.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/WechatTasks.java @@ -61,9 +61,9 @@ import static com.bonus.system.att.utils.DistanceCalculator.calculateDistance; * 微信小程序数据同步接口 */ @Configuration -@EnableScheduling @Slf4j -@EnableAsync +//@EnableScheduling +//@EnableAsync public class WechatTasks { @Resource(name = "WechatPushDao") @@ -75,7 +75,7 @@ public class WechatTasks { * 人员基础数据同步定时器 */ // @Scheduled(cron = "0 0/10 * * * ?") - @Scheduled(initialDelay = 60000 * 1,fixedDelay = 60000 * 1) +// @Scheduled(initialDelay = 60000 * 1,fixedDelay = 60000 * 1) @Async public void pushPersonTask() { log.info("--------人员基础数据同步定时器开启------"); @@ -103,7 +103,7 @@ public class WechatTasks { /** * 休假出差数据同步定时器 */ - @Scheduled(initialDelay = 60000 * 2,fixedDelay = 60000 * 1) +// @Scheduled(initialDelay = 60000 * 2,fixedDelay = 60000 * 1) @Async public void leaveTask() { log.info("--------休假出差数据定时器开启------"); @@ -182,7 +182,7 @@ public class WechatTasks { /** * 考勤数据同步定时器 */ - @Scheduled(initialDelay = 60000 * 3,fixedDelay = 60000 * 1) +// @Scheduled(initialDelay = 60000 * 3,fixedDelay = 60000 * 1) @Async public void wechatAttTask() { log.info("--------考勤数据定时器开启------"); diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/utils/WorkdayCalculator.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/utils/WorkdayCalculator.java index 3f00f60..1331325 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/utils/WorkdayCalculator.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/utils/WorkdayCalculator.java @@ -2,11 +2,16 @@ package com.bonus.system.att.utils; import com.bonus.common.core.utils.DateUtils; import com.bonus.system.att.entity.Holiday; + import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; import java.util.*; /** * 计算工作日 + * * @author zys */ public class WorkdayCalculator { @@ -16,35 +21,45 @@ public class WorkdayCalculator { Calendar.FRIDAY, Calendar.SATURDAY, Calendar.SUNDAY}; public static void main(String[] args) { - getWorkDay("1,0,1,1,1,0,1", 1, getHolidays()); + getWorkDay("1,0,1,1,1,0,1", 1, getHolidays(), "2024-11-05"); } - public static List getWorkDay(String attDays, int type, List holidays){ + public static List getWorkDay(String attDays, int type, List holidays, String pushDate) { List dueWorkDates = getDueWorkDates(attDays); - String year = DateUtils.getYear(); - String month = DateUtils.getMm(); - // 获取工作日集合(排除周末) - List workDays = getWorkDays(Integer.parseInt(year), Integer.parseInt(month), dueWorkDates); - // 获取工作日字符串集合 - List dateString = getDateString(workDays); - // 获取法定节假日集合 - if(type == 1) { - holidays.forEach(c -> { - if (c.getType().equals("1")) { - dateString.remove(c.getDate()); - } else if (c.getType().equals("2")) { - dateString.add(c.getDate()); - } - }); + // 定义日期格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + try { + // 解析日期字符串为 LocalDate 对象 + LocalDate date = LocalDate.parse(pushDate, formatter); + // 获取年份和月份 + int year = date.getYear(); + int month = date.getMonthValue(); // 获取月份(1-12) + // 获取工作日集合(排除周末) + List workDays = getWorkDays(year, month, dueWorkDates); + // 获取工作日字符串集合 + List dateString = getDateString(workDays); + // 获取法定节假日集合 + if (type == 1) { + holidays.forEach(c -> { + if (c.getType().equals("1")) { + dateString.remove(c.getDate()); + } else if (c.getType().equals("2")) { + dateString.add(c.getDate()); + } + }); + } + return dateString; + } catch (Exception e) { + e.printStackTrace(); } - return dateString; + return new ArrayList<>(); } private static List getDueWorkDates(String s) { List week = new ArrayList<>(); List list = new ArrayList<>(Arrays.asList(s.split(","))); for (int i = 0; i < list.size(); i++) { - if(list.get(i).equals("1")){ + if (list.get(i).equals("1")) { week.add(weekDays[i]); } } @@ -71,7 +86,7 @@ public class WorkdayCalculator { // 返回工作日集合,只排除周末 - public static List getWorkDays(int year, int month, List dueWorkDates){ + public static List getWorkDays(int year, int month, List dueWorkDates) { // 用于储存每月工作日 List dates = new ArrayList(); @@ -82,19 +97,19 @@ public class WorkdayCalculator { cal.set(Calendar.MONTH, month - 1); // 设置为当月第一天 cal.set(Calendar.DATE, 1); - while(cal.get(Calendar.YEAR) == year && cal.get(Calendar.MONTH) < month){ + while (cal.get(Calendar.YEAR) == year && cal.get(Calendar.MONTH) < month) { // 判断当前天为本周的第几天 int day = cal.get(Calendar.DAY_OF_WEEK); // 如果不为周六或者周天,将日期进行储存 List list = new ArrayList<>(); - dueWorkDates.forEach(c->{ - if(day == c){ + dueWorkDates.forEach(c -> { + if (day == c) { list.add(true); } }); - if(!list.isEmpty()){ - if(list.stream().allMatch(Boolean::booleanValue)){ - dates.add((Date)cal.getTime().clone()); + if (!list.isEmpty()) { + if (list.stream().allMatch(Boolean::booleanValue)) { + dates.add((Date) cal.getTime().clone()); } } // if(!(day == Calendar.SUNDAY || day == Calendar.SATURDAY)){ @@ -108,16 +123,15 @@ public class WorkdayCalculator { } /** - * * @param dateList * @return 返回日期字符串集合 */ - public static List getDateString(List dateList){ + public static List getDateString(List dateList) { // 储存日期字符串 List dateString = new ArrayList<>(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); - for (Date date : dateList){ + for (Date date : dateList) { String date2 = simpleDateFormat.format(date); dateString.add(date2); } diff --git a/bonus-modules/bonus-system/src/main/resources/mapper/att/AttGroupMapper.xml b/bonus-modules/bonus-system/src/main/resources/mapper/att/AttGroupMapper.xml index ddb3aca..ed829cc 100644 --- a/bonus-modules/bonus-system/src/main/resources/mapper/att/AttGroupMapper.xml +++ b/bonus-modules/bonus-system/src/main/resources/mapper/att/AttGroupMapper.xml @@ -5,7 +5,7 @@ @@ -116,7 +125,7 @@ from gz_cloud_test.fc_sup_attendance sup where sup.attendance_date - >= #{pushDate} - INTERVAL 3 DAY + >= #{pushDate} = #{pushDate} @@ -156,7 +165,7 @@ from v_att_update_data where att_current_day - >= #{pushDate} - INTERVAL 3 DAY + >= #{pushDate} = #{pushDate} @@ -196,7 +205,7 @@ from sys_holiday where `date` - >= #{pushDate} - INTERVAL 3 DAY + >= #{pushDate} = #{pushDate} @@ -229,7 +238,7 @@ left join att_group g on g.id = ag.group_id where att_current_day - >= #{pushDate} - INTERVAL 3 DAY + >= #{pushDate} = #{pushDate} @@ -247,7 +256,7 @@ left join att_group g on g.id = ag.group_id where att_current_day - >= #{pushDate} - INTERVAL 3 DAY + >= #{pushDate} = #{pushDate} @@ -294,7 +303,7 @@ left join zkeco.userinfo u on u.userid = c.userid where DATE_FORMAT(c.checktime, '%Y-%m-%d') - >= #{pushDate} - INTERVAL 3 DAY + >= #{pushDate} = #{pushDate} @@ -325,9 +334,21 @@ left join sys_user su on su.user_name = asd.name left join att_group_person_relation ag on ag.user_id = su.user_id and ag.is_active = 1 left join att_group g on g.id = ag.group_id - where att_current_day >= CURDATE() - INTERVAL 3 DAY + where att_current_day >= CURDATE() and g.id is not null and asd.data_source = 2 and asd.att_type = 0 + + \ No newline at end of file