From c8fed6540d9857fb594b2f24ab3c1628a4ed8ccc Mon Sep 17 00:00:00 2001 From: fl <3098731433@qq.com> Date: Thu, 20 Feb 2025 19:43:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E8=A1=A8=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BF=AE=E6=94=B9=EF=BC=8C=E8=80=83=E5=8B=A4=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=8C=E6=AD=A5=E9=97=AE=E9=A2=98=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20=E8=AF=B7=E5=81=87=E5=90=8C=E6=AD=A5=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20=E5=88=A0=E9=99=A4=E5=BA=9F=E5=BC=83?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AttendanceDetailsController.java | 9 - .../system/att/dao/AttSourceDataDao.java | 2 +- .../bonus/system/att/dao/WechatPushDao.java | 7 +- .../system/att/entity/AttSourceDataBean.java | 2 +- .../att/service/AttendanceDetailsService.java | 2 - .../service/AttendanceDetailsServiceImpl.java | 42 +- .../com/bonus/system/att/tasks/AttTasks.java | 2394 ++++++++--------- .../bonus/system/att/tasks/NewAttTask.java | 36 +- .../bonus/system/att/tasks/WechatTasks.java | 32 +- .../mapper/att/AttSourceDataMapper.xml | 17 +- .../resources/mapper/att/WechatPushMapper.xml | 86 +- 11 files changed, 1290 insertions(+), 1339 deletions(-) diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/controller/AttendanceDetailsController.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/controller/AttendanceDetailsController.java index 200dc46..e010206 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/controller/AttendanceDetailsController.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/controller/AttendanceDetailsController.java @@ -392,15 +392,6 @@ public class AttendanceDetailsController extends BaseController { return getDataTableError(new ArrayList<>()); } - /** - * 用户新增 - */ - @PostMapping("/synchronous") - @Log(title = "考勤报表-> 考勤明细->数据同步", businessType = BusinessType.INSERT) - public AjaxResult synchronous(@Validated @RequestBody AttDataDetailsBean bean) { - return attendanceDetailsService.synchronous(bean); - } - /** * 获取日报表-详细记录 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 a8306ad..890ed98 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 @@ -82,7 +82,7 @@ public interface AttSourceDataDao { Integer getPersonLeaveApplyStatus(AttSourceDataBean bean); /** - * 查出最近三天的人员考勤记录 + * 查出人员考勤记录 * @return list bean */ List getSourceAttData(@Param("pushDate")String pushDate, @Param("pushType")int pushType); diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/WechatPushDao.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/WechatPushDao.java index 733814a..1ca9afa 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/WechatPushDao.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/dao/WechatPushDao.java @@ -1,21 +1,16 @@ package com.bonus.system.att.dao; -import com.bonus.system.api.domain.MapVo; import com.bonus.system.api.domain.SysUser; import com.bonus.system.att.entity.AttFaceBean; import com.bonus.system.att.entity.AttSourceDataBean; -import com.bonus.system.att.entity.LeaveBean; -import com.bonus.system.att.entity.OrgChangeBean; import com.bonus.system.basic.domain.SysOrg; import com.bonus.system.evection.entity.EvectionBean; -import com.bonus.system.holiday.entity.HolidayBean; import com.bonus.system.holiday.entity.WorkReportBean; import com.bonus.system.index.entity.MapBean; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; -import java.util.Map; /** * 小程序同步定时器 @@ -42,7 +37,7 @@ public interface WechatPushDao { */ SysOrg getOrgInfoByUserId(Long userId); - void insertWebLeave(EvectionBean bean); + int insertWebLeave(EvectionBean bean); List getWebLeaveList(); diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttSourceDataBean.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttSourceDataBean.java index 65630ee..75ca1da 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttSourceDataBean.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/entity/AttSourceDataBean.java @@ -115,7 +115,7 @@ public class AttSourceDataBean { /** * 0 默认 1 外勤 2 正常 */ - private String isOutsideAtt; + private String isOutsideAtt = "0"; private String remark; diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsService.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsService.java index 2094918..802ba08 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsService.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsService.java @@ -103,8 +103,6 @@ public interface AttendanceDetailsService { List getOutCountList(AttDataDetailsBean bean); - AjaxResult synchronous(AttDataDetailsBean bean); - List getAttDayList(AttDataDetailsBean bean); List getAttCountList(AttDataDetailsBean bean); diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsServiceImpl.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsServiceImpl.java index 10e40d2..8300712 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsServiceImpl.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/service/AttendanceDetailsServiceImpl.java @@ -5,23 +5,17 @@ import com.bonus.common.core.utils.poi.ExcelUtil; import com.bonus.common.core.web.domain.AjaxResult; import com.bonus.common.security.utils.SecurityUtils; import com.bonus.system.api.domain.MapVo; -import com.bonus.system.api.domain.SysUser; import com.bonus.system.att.dao.AttendanceDetailsDao; import com.bonus.system.att.entity.*; -import com.bonus.system.att.tasks.AttTasks; -import com.bonus.system.att.tasks.WechatTasks; +import com.bonus.system.att.tasks.NewAttTask; import com.bonus.system.basic.domain.SysNotice; import com.bonus.system.basic.service.SysNoticeService; -import com.bonus.system.dept.dao.ProDeptRoleDao; import com.bonus.system.file.service.FileUploadService; import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -36,12 +30,8 @@ public class AttendanceDetailsServiceImpl implements AttendanceDetailsService { @Resource(name = "attendanceDetailsDao") private AttendanceDetailsDao attendanceDetailsDao; - - @Resource(name = "ProDeptRoleDao") - private ProDeptRoleDao proDeptRoleDao; - @Resource - private AttTasks attTasks; + private NewAttTask newAttTask; /** * 消息推送库表 @@ -142,7 +132,6 @@ public class AttendanceDetailsServiceImpl implements AttendanceDetailsService { } }); int i = attendanceDetailsDao.updateAttDetailsDataExamine(list); - // todo 更新月报表和日报表 if (i > 0) { Set keys = new HashSet<>(); for (AttDataDetailsBean attDataDetailsBean : list) { @@ -150,8 +139,8 @@ public class AttendanceDetailsServiceImpl implements AttendanceDetailsService { } // 使用增强的 for 循环遍历 Set for (String item : keys) { - List groupList = attTasks.getGroupData(item); - attTasks.createReportData(groupList, item, 2); + newAttTask.insertDayReportData(item); + newAttTask.updateMonthReportData(item); } } return i; @@ -229,29 +218,6 @@ public class AttendanceDetailsServiceImpl implements AttendanceDetailsService { return attendanceDetailsDao.getOutCountList(bean); } - @Override - public AjaxResult synchronous(AttDataDetailsBean bean) { - try { - List dateList = AttTasks.getStrDateListBetween(bean.getStartDate(), bean.getEndDate()); - //只执行今天之前的时间(包含今天) - // 获取今天的日期 - LocalDate today = LocalDate.now(); - // 定义日期格式 - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - dateList = dateList.stream() - .map(date -> LocalDate.parse(date, formatter)) // 将字符串转换为LocalDate - .filter(date -> !date.isAfter(today)) // 筛选出今天及之前的日期 - .sorted() // 按日期排序(可选) - .map(formatter::format) // 将LocalDate转回为字符串 - .collect(Collectors.toList()); - attTasks.hisAttPush(dateList); - return AjaxResult.success("数据同步成功"); - } catch (Exception e) { - log.error(e.toString(), e); - return AjaxResult.error("数据同步失败"); - } - } - @Override public List getAttDayList(AttDataDetailsBean bean) { return attendanceDetailsDao.getAttDayList(bean); 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 be36132..27b77ea 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 @@ -1,1205 +1,1205 @@ -package com.bonus.system.att.tasks; - -import cn.hutool.core.date.DateUnit; -import cn.hutool.core.date.DateUtil; -import com.bonus.common.core.utils.DateTimeHelper; -import com.bonus.common.core.utils.DateUtils; -import com.bonus.common.core.utils.StringUtils; -import com.bonus.system.att.dao.AttGroupDao; -import com.bonus.system.att.dao.AttSourceDataDao; -import com.bonus.system.att.entity.*; -import com.bonus.system.att.utils.AddressCoordinateFormatUtil; -import com.bonus.system.att.utils.WorkdayCalculator; -import com.bonus.system.holiday.dao.HolidayDao; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.beanutils.BeanUtils; -import org.mybatis.spring.SqlSessionTemplate; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.annotation.Scheduled; - -import javax.annotation.Resource; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.*; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -/** - * @author zys - * 考勤定时器 - */ -@Configuration -@EnableScheduling -@Slf4j -@EnableAsync -public class AttTasks { - - @Resource(name = "attSourceDataDao") - private AttSourceDataDao attSourceDataDao; - @Resource(name = "sqlSessionTemplate") - private SqlSessionTemplate sqlSessionTemplate; - - @Resource(name = "attGroupDao") - private AttGroupDao attGroupDao; - - @Resource(name = "HolidayDao") - private HolidayDao holidayDao; - - - private static final int BATCH_SIZE = 10; // 每批次处理的日期数量 - private static final int THREAD_POOL_SIZE = 5; // 线程池大小 - private volatile boolean executed = false; // 标志位,表示任务是否已经执行过 - -// @Scheduled(cron = "0 0/10 * * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) - @Async - public void getAttTasks() { - log.info("--------考勤定时器开启------"); - String today = DateUtil.today(); - pushAttData(today, 1); - log.info("--------考勤定时器完毕------"); - } - - /** - * 历史考勤数据 - */ -// @Scheduled(initialDelay = 6000,fixedDelay = 60000 * 30) -// @Scheduled(cron = "0 50 19 * * ?") - @Async - public void getHisAttTasks() { - log.info("--------考勤定时器开启------"); - if (executed) { - return; // 如果任务已经执行过,直接返回 - } - executed = true; // 设置标志位,表示任务已经执行过 - String startDate = "2025-01-01"; - String endDate = "2025-01-31"; - List dateList = getStrDateListBetween(startDate, endDate); -// List dateList = new ArrayList<>(); -// dateList.add("2024-10-18"); - hisAttPush(dateList); - log.info("--------考勤定时器完毕------"); - } - - /** - * 防止黔送离线数据每月前三天晚上将数据重新执行 - */ -// @Scheduled(cron = "0 30 22 1-3 * *") - @Async - public void getHisMonthAttTask() { - // 获取当前日期 - LocalDate today = LocalDate.now(); - // 获取上个月的YearMonth实例 - YearMonth previousMonth = YearMonth.from(today).minusMonths(1); - // 上个月的第一天 - LocalDate startOfPreviousMonth = previousMonth.atDay(1); - // 上个月的最后一天 - LocalDate endOfPreviousMonth = previousMonth.atEndOfMonth(); - String startDate = startOfPreviousMonth.toString(); - String endDate = endOfPreviousMonth.toString(); - List dateList = getStrDateListBetween(startDate, endDate); - hisAttPush(dateList); - log.info("--------考勤定时器完毕------"); - } - - /** - * 凌晨0-5点得到数据,算作昨天,将昨天的重新执行 - */ -// @Scheduled(cron = "0 5 6 * * ?") - @Async - public void getHisYesterdayAttTask() { - // 获取今天的日期 - LocalDate today = LocalDate.now(); - // 计算昨天的日期 - LocalDate yesterday = today.minusDays(1); - String startDate = yesterday.toString(); - String endDate = yesterday.toString(); - List dateList = getStrDateListBetween(startDate, endDate); - hisAttPush(dateList); - log.info("--------考勤定时器完毕------"); - } - - - public void hisAttPush(List dateList) { - // 创建固定大小的线程池 - ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); - // 分批处理日期列表 - for (int i = 0; i < dateList.size(); i += BATCH_SIZE) { - int end = Math.min(i + BATCH_SIZE, dateList.size()); - List batch = dateList.subList(i, end); - // 提交任务到线程池 - executorService.submit(() -> { - for (String date : batch) { - try { - delHisData(date); - pushAttData(date, 2); - } catch (Exception e) { - // 记录异常并继续处理下一个日期 - System.err.println("Error processing date: " + date + ", error: " + e.getMessage()); - } - } - }); - } - // 关闭线程池 - executorService.shutdown(); - try { - // 等待所有任务完成 - executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - private void delHisData(String date) { - //查询基础数据是否完备 - int i = attSourceDataDao.getFirstAttendanceData(date); - if(i > 0){ - attSourceDataDao.updateHisData(date); - }else{ - attSourceDataDao.delHisData(date); - } - } - - - /** - * 推送考勤数据 - * - * @param pushDate 时间 - * @param pushType 1:自动推送 2:手动 - */ - private void pushAttData(String pushDate, int pushType) { - //获取黔送云的考勤数据 - getQsyAttendanceData(pushDate, pushType); - //获取考勤机中的考勤数据 - getMachineAttendanceData(pushDate, pushType); -// //查出每一个考勤组的应出勤天数以及考勤组的规则 - List groupList = getGroupData(pushDate); -// //新增默认考勤数据到考勤数据和修改表 - insertAttData(groupList, pushDate, pushType); - //更新请假数据 - updateLeaveData(pushDate); - //修改考勤数据 - updateAttData(groupList, pushDate, pushType); -// 根据考勤数据生成报表数据 - createReportData(groupList, pushDate, pushType); - } - - /** - * 获取黔送云的考勤数据 - */ - private void getQsyAttendanceData(String pushDate, int pushType) { - List attSourceList = Optional.ofNullable(attSourceDataDao.getQsyAttendances(pushDate, pushType)). - orElseGet(ArrayList::new); - if (!attSourceList.isEmpty()) { - attSourceList.forEach(c -> { - String address; - try { - address = AddressCoordinateFormatUtil. - coordinateToAddress(c.getAttLon(), c.getAttLat()); - }catch (IllegalArgumentException e){ - address = "地址未转化成功"; - } - c.setAttAddress(address); - if ("0".equals(c.getAttType())) { - int i = checkTime(c.getAttCurrentTime()); - c.setAttType(String.valueOf(i)); - } - //将00:00:00 至 04:59:59 时间变成att_current_day上一天的 - changeAttCurrentDay(c); - } - ); - //新增考勤到考勤来源表(数据过多时分批次插入) - insertAttSourceData(attSourceList); - } - } - - /** - * 将00:00:00 至 04:59:59 时间变成att_current_day上一天的 - * - * @param c - */ - public void changeAttCurrentDay(AttSourceDataBean c) { - // 定义时间格式 - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - // 解析传入的时间字符串 - LocalTime time = LocalTime.parse(c.getAttCurrentTime(), formatter); - // 定义早上5点和中午12点的时间 - LocalTime morningStart = LocalTime.of(0, 0); - LocalTime noonEnd = LocalTime.of(5, 0); - // 判断时间是否在0:00到05:00之间 - if (time.isAfter(morningStart) && !time.isAfter(noonEnd)) { - //获取前一天时间 - String afterDate = DateUtils.getAfterDate(c.getAttCurrentDay()); - c.setAttCurrentDay(afterDate); - } - } - - public void insertAttSourceData(List attSourceList) { - if (attSourceList == null || attSourceList.isEmpty()) { - return; - } - int batchSize = 3000; - int totalBatches = (int) Math.ceil((double) attSourceList.size() / batchSize); - try { - for (int i = 0; i < totalBatches; i++) { - int fromIndex = i * batchSize; - int toIndex = Math.min(fromIndex + batchSize, attSourceList.size()); - List batch = attSourceList.subList(fromIndex, toIndex); - attSourceDataDao.insertAttSourceData(batch); - if ((i + 1) % 100 == 0 || i + 1 == totalBatches) { - sqlSessionTemplate.flushStatements(); // 提交事务 - sqlSessionTemplate.clearCache(); // 清理缓存 - } - } - } catch (Exception e) { - throw new RuntimeException("Error replacing data", e); - } - } - - - /** - * 获取考勤机的考勤数据 - */ - private void getMachineAttendanceData(String pushDate, int pushType) { - List attSourceList = Optional.ofNullable(attSourceDataDao.getMachineAttendances(pushDate, pushType)). - orElseGet(ArrayList::new); - attSourceList.forEach(c -> { - if ("0".equals(c.getAttType())) { - int i = checkTime(c.getAttCurrentTime()); - c.setAttType(String.valueOf(i)); - } - //将00:00:00 至 04:59:59 时间变成att_current_day上一天的 - changeAttCurrentDay(c); - }); - //新增考勤到考勤来源表(数据过多时分批次插入) - insertAttSourceData(attSourceList); - } - - public int checkTime(String currentTime) { - if (currentTime == null || currentTime.isEmpty()) { - // 如果输入为空或为空字符串,则返回默认值(例如2) - return 1; - } - try { - // 定义时间格式 - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - // 解析传入的时间字符串 - LocalTime time = LocalTime.parse(currentTime, formatter); - // 定义早上5点和中午12点的时间 - LocalTime morningStart = LocalTime.of(5, 0); - LocalTime noonEnd = LocalTime.of(12, 0); - // 判断时间是否在5:00到12:00之间 - if (time.isAfter(morningStart) && !time.isAfter(noonEnd)) { - return 1; // 在早上5点到12点之间 - } else { - return 2; // 其他时间 - } - } catch (DateTimeParseException e) { - // 如果时间格式不正确,返回默认值(例如2) - e.printStackTrace(); - return 1; - } - } - - /** - * 更新所有的请假数据 - */ - private void updateLeaveData(String pushDate) { - /** - * 查出在考勤组人员的请假数据 - */ - List leaveList = Optional.ofNullable(attSourceDataDao.getLeaveData(pushDate)). - orElseGet(ArrayList::new); - if (!leaveList.isEmpty()) { - leaveList.forEach(leaveData -> threadLeaveData(leaveData, pushDate)); - } - } - - /** - * 根据请假数据去更新考勤数据 - */ - private void threadLeaveData(LeaveBean c, String pushDate) { - //1.将请假区间变成日期集合 -// if(c.getUserId() == 263){ -// System.out.println("米娜"); +//package com.bonus.system.att.tasks; +// +//import cn.hutool.core.date.DateUnit; +//import cn.hutool.core.date.DateUtil; +//import com.bonus.common.core.utils.DateTimeHelper; +//import com.bonus.common.core.utils.DateUtils; +//import com.bonus.common.core.utils.StringUtils; +//import com.bonus.system.att.dao.AttGroupDao; +//import com.bonus.system.att.dao.AttSourceDataDao; +//import com.bonus.system.att.entity.*; +//import com.bonus.system.att.utils.AddressCoordinateFormatUtil; +//import com.bonus.system.att.utils.WorkdayCalculator; +//import com.bonus.system.holiday.dao.HolidayDao; +//import lombok.extern.slf4j.Slf4j; +//import org.apache.commons.beanutils.BeanUtils; +//import org.mybatis.spring.SqlSessionTemplate; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.scheduling.annotation.Async; +//import org.springframework.scheduling.annotation.EnableAsync; +//import org.springframework.scheduling.annotation.EnableScheduling; +//import org.springframework.scheduling.annotation.Scheduled; +// +//import javax.annotation.Resource; +//import java.text.DateFormat; +//import java.text.ParseException; +//import java.text.SimpleDateFormat; +//import java.time.*; +//import java.time.format.DateTimeFormatter; +//import java.time.format.DateTimeParseException; +//import java.util.*; +//import java.util.concurrent.ExecutorService; +//import java.util.concurrent.Executors; +//import java.util.concurrent.TimeUnit; +//import java.util.concurrent.atomic.AtomicReference; +//import java.util.stream.Collectors; +// +///** +// * @author zys +// * 考勤定时器 +// */ +//@Configuration +//@EnableScheduling +//@Slf4j +//@EnableAsync +//public class AttTasks { +// +// @Resource(name = "attSourceDataDao") +// private AttSourceDataDao attSourceDataDao; +// @Resource(name = "sqlSessionTemplate") +// private SqlSessionTemplate sqlSessionTemplate; +// +// @Resource(name = "attGroupDao") +// private AttGroupDao attGroupDao; +// +// @Resource(name = "HolidayDao") +// private HolidayDao holidayDao; +// +// +// private static final int BATCH_SIZE = 10; // 每批次处理的日期数量 +// private static final int THREAD_POOL_SIZE = 5; // 线程池大小 +// private volatile boolean executed = false; // 标志位,表示任务是否已经执行过 +// +//// @Scheduled(cron = "0 0/10 * * * ?") +//// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) +// @Async +// public void getAttTasks() { +// log.info("--------考勤定时器开启------"); +// String today = DateUtil.today(); +// pushAttData(today, 1); +// log.info("--------考勤定时器完毕------"); +// } +// +// /** +// * 历史考勤数据 +// */ +//// @Scheduled(initialDelay = 6000,fixedDelay = 60000 * 30) +//// @Scheduled(cron = "0 50 19 * * ?") +// @Async +// public void getHisAttTasks() { +// log.info("--------考勤定时器开启------"); +// if (executed) { +// return; // 如果任务已经执行过,直接返回 // } - List dateLists = getStrDateListBetween(c.getLeaveStartDate(), c.getLeaveEndDate()); - if (!dateLists.isEmpty()) { -// //根据开始时间、结束时间获取节假日的日期集合 - // 1 表示固定打卡 - if("1".equals(c.getAttType())){ - //只有固定打卡蒋周六日不算在请假轮休天数中 - List holidayList = holidayDao.getHolidayDataByType(c.getLeaveStartDate(), c.getLeaveEndDate()); - // 使用Stream API去除A中包含在B中的元素 - dateLists = dateLists.stream().filter(element -> !holidayList.contains(element)).collect(Collectors.toList()); - } - dateLists.forEach(v -> { - boolean tf = false; - AttDataBean toWorkBean = new AttDataBean(v, c.getAttStatus(), "1", - c.getOrgId(), c.getUserId()); - AttDataBean offWorkBean = new AttDataBean(v, c.getAttStatus(), "2", - c.getOrgId(), c.getUserId()); - //开始和结束的那天是否只请了半天 - if (c.getLeaveStartDate().equals(v)) { - if (c.getLeaveStartInterval().equals("2")) { - replaceHolidayData(offWorkBean, 0); - } else { - tf = true; - } - } else if (c.getLeaveEndDate().equals(v)) { - if (c.getLeaveEndInterval().equals("1")) { - replaceHolidayData(toWorkBean, 0); - } else { - tf = true; - } - } else { - tf = true; - } - if (tf) { - replaceHolidayData(toWorkBean, 0); - replaceHolidayData(offWorkBean, 0); - } - }); - } - } - - public static List getStrDateListBetween(String startDateString, String endDateString) { - List dateList = new ArrayList<>(); - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - try { - // 解析开始日期和结束日期 - Date startDate = dateFormat.parse(startDateString); - Date endDate = dateFormat.parse(endDateString); - // 创建 Calendar 实例并设置为开始日期 - Calendar calendar = Calendar.getInstance(); - calendar.setTime(startDate); - // 循环直到当前日期超过结束日期 - while (!calendar.getTime().after(endDate)) { - // 将日期格式化为字符串,并添加到列表中 - dateList.add(dateFormat.format(calendar.getTime())); - // 将日期加一天 - calendar.add(Calendar.DAY_OF_MONTH, 1); - } - } catch (ParseException ignored) { - } - return dateList; - } - - /** - * 查出每一个考勤组的应出勤天数以及考勤组的规则 - * - * @return 考勤组集合 - */ - public List getGroupData(String pushDate) { - //查出考勤组的数据 - List groupList = Optional.ofNullable(attGroupDao.selectAttGroupList(new AttGroupBean())). - orElseGet(ArrayList::new); - if (groupList.isEmpty()) { - return new ArrayList<>(); - } - //查询当月否有节假日或补班 - List holidays = attSourceDataDao.selectHolidayByMonth(pushDate); - groupList.forEach(c -> { - //应考勤天 - List attDayList = WorkdayCalculator.getWorkDay(c.getAttDay(), - Integer.parseInt(c.getAttType()), holidays,pushDate); - c.setAttWorkDayBean(new PersonAttWorkDayBean(c.getGroupId(), attDayList.size(), attDayList)); - }); - return groupList; - } - - /** - * 新增默认考勤数据到考勤数据和修改表 - * - * @param groupList 考勤组集合 - */ - private void insertAttData(List groupList, String pushDate, int pushType) { - //获取所有的用户 - // 2025-01-17 添加时间,查出每个人在对应时间存在的考勤组 - List listPerson = attSourceDataDao.getAllPerson(pushDate); - if (!listPerson.isEmpty()) { - listPerson.forEach(v -> { - groupList.stream() - .filter(c -> Objects.equals(v.getGroupId(), c.getGroupId()) && !c.getAttWorkDayBean() - .getAttDayList().contains(pushDate)) - .findFirst() - .ifPresent(c -> v.setAttStatus("11")); - v.setAttCurrentDay(pushDate); - replaceAttData(v, pushDate); - }); - } - } - - /** - * 新增修改考勤数据 - */ - private void replaceAttData(AttDataBean v, String pushDate) { - //查询考勤模版数据是否已经插入 - Boolean isAttExist = attSourceDataDao.selectAttIsExist(v); - if (!isAttExist) { - //查询能修改的考勤模版数据是否已经插入 - // 判断 pushDate 是否在今天之前 - boolean isPastDate = isBeforeToday(pushDate); - if (isPastDate) { - //不存在且在今天之前 - //之前处理过节假日的数据,只有是默认数据才能将旷工状态写入 - if (v.getAttStatus().equals("0")) { - v.setAttStatus("3"); - } - }else{ - //不存在就在今天 - //逻辑跟修改相同,第一次就不去麻烦根据时间判断状态了 - } - attSourceDataDao.insertAttData(v); - } else { - if (!v.getAttStatus().equals("0")) { - attSourceDataDao.updateAttData(v, 0); - } - if (v.getAttStatus().equals("0")) { - //将未打卡的全部置为旷工 - changeAbsenteeAttStatus(v, 0, 0, pushDate); - } - } - //查询能修改的考勤模版数据是否已经插入 - Boolean isAttUpdateExist = attSourceDataDao.selectAttUpdateIsExist(v); - if (!isAttUpdateExist) { - // 判断 pushDate 是否在今天之前 - boolean isPastDate = isBeforeToday(pushDate); - if (isPastDate) { - //之前处理过节假日的数据,只有是默认数据才能将旷工状态写入 - if (v.getAttStatus().equals("0")) { - v.setAttStatus("3"); - } - } - attSourceDataDao.insertAttUpdateData(v); - } else { - if (!v.getAttStatus().equals("0")) { - attSourceDataDao.updateAttUpdateData(v, 0); - } else { - //将未打卡的全部置为旷工 - changeAbsenteeAttStatus(v, 0, 1, pushDate); - } - } - } - - - /** - * 新增修改请假数据(更新考勤表) - */ - private void replaceHolidayData(AttDataBean v, int type) { - //查询考勤模版数据是否已经插入 - Boolean isAttExist = attSourceDataDao.selectAttIsExist(v); - if (!isAttExist) { - //没有基础数据,插入基础数据并改状态为对应请假状态 - attSourceDataDao.insertAttData(v); - } else { - if (!v.getAttStatus().equals("0")) { - //改状态为对应请假状态 - attSourceDataDao.updateAttData(v, type); - } - } - //查询能修改的考勤模版数据是否已经插入 - Boolean isAttUpdateExist = attSourceDataDao.selectAttUpdateIsExist(v); - if (!isAttUpdateExist) { - //没有基础数据,插入基础数据并改状态为对应请假状态 - attSourceDataDao.insertAttUpdateData(v); - } else { - if (!v.getAttStatus().equals("0")) { - //改状态为对应请假状态 - attSourceDataDao.updateAttUpdateData(v, type); - } - } - } - - - /** - * 将未打卡的全部置为旷工 - * - * @param v 考勤数据 - * @param type 0表示考勤数据,1表示考勤修改数据 - * @param update 0表示修改考勤数据,1表示修改考勤修改数据 - * @param pushDate 推送时间 - */ - private void changeAbsenteeAttStatus(AttDataBean v, int type, int update, String pushDate) { - //将未打卡的全部置为旷工 - // 判断 pushDate 是否在今天之前 - boolean isPastDate = isBeforeToday(pushDate); - if (isPastDate) { - // 如果 pushDate 是过去的时间,直接执行原逻辑 - v.setAttStatus("3"); - if (update == 0) { - attSourceDataDao.updateAttData(v, type); - } else if (update == 1) { - attSourceDataDao.updateAttUpdateData(v, type); - } - } else { - LocalTime currentTime; - // 使用当前时间 - currentTime = LocalTime.now(); - // 定义中午 12 点 - LocalTime noon = LocalTime.of(12, 0); - // 定义下午 22 点 - LocalTime eightPM = LocalTime.of(22, 0); - // 当前时间逻辑 - if (currentTime.isAfter(noon)) { - if ("1".equals(v.getAttType())) { - v.setAttStatus("3"); - if (update == 0) { - attSourceDataDao.updateAttData(v, type); - } else if (update == 1) { - attSourceDataDao.updateAttUpdateData(v, type); - } - } - } - if (currentTime.isAfter(eightPM)) { - if ("2".equals(v.getAttType())) { - v.setAttStatus("3"); - if (update == 0) { - attSourceDataDao.updateAttData(v, type); - } else if (update == 1) { - attSourceDataDao.updateAttUpdateData(v, type); - } - } - } - } - } - - /** - * 判断传入的日期是否在今天的日期之前 - * - * @param dateStr 传入的日期字符串,格式为 "yyyy-MM-dd" - * @return 如果传入的日期在今天的日期之前,返回 true;否则返回 false - */ - public boolean isBeforeToday(String dateStr) { - if (dateStr == null || dateStr.isEmpty()) { - return false; - } - try { - LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - LocalDate today = LocalDate.now(); - return date.isBefore(today); - } catch (Exception e) { - // 如果日期格式不正确,返回 false - e.printStackTrace(); - return false; - } - } - - /** - * 修改考勤数据 - * - * @param groupList 考勤组集合 - */ - private void updateAttData(List groupList, String pushDate, int pushType) { - //查出最近三天的人员考勤记录 - AtomicReference> sourceDataList = new AtomicReference<>(attSourceDataDao.getSourceAttData(pushDate, pushType)); - //根据考勤组的规则和请假记录算出人员的考勤状态 - groupList.forEach(c -> { - List list = Collections.emptyList(); - //考勤规则里面的attType 1 固定打卡 2 自由打卡 - if ("1".equals(c.getAttType())) { - list = GroupFixedData(sourceDataList.get().stream() - .filter(a -> "1".equals(a.getGroupType()) && - a.getGroupId() == c.getGroupId()) - .collect(Collectors.toList()), c); - } else if ("2".equals(c.getAttType())) { - list = getDataList(sourceDataList.get().stream() - .filter(a -> "2".equals(a.getGroupType()) && - a.getGroupId() == c.getGroupId()) - .collect(Collectors.toList()), c, true); - } - //修改考勤记录 att_data - if (!list.isEmpty()) { - if ("1".equals(c.getAttType())) { - //固定打卡 - // 定义时间格式 - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - // 移除移除 attType 为 2 且 attCurrentTime 在上午 5 点到 12 点之间的元素 - list.removeIf(record -> { - String attType = record.getAttType(); - String attCurrentTime = record.getAttCurrentTime(); - if (!"".equals(attCurrentTime)) { - if (attCurrentTime.contains(" ")) { - attCurrentTime = attCurrentTime.split(" ")[0]; - } - LocalDateTime time = LocalDateTime.parse(attCurrentTime, formatter); - // 提取时间部分 - LocalTime localTime = time.toLocalTime(); - boolean condition1 = "2".equals(attType) && localTime.isAfter(LocalTime.of(5, 0)) && localTime.isBefore(LocalTime.of(12, 0)); - boolean condition2 = "1".equals(attType) && localTime.isAfter(LocalTime.of(12, 0)) && localTime.isBefore(LocalTime.of(23, 59)); - return condition1 || condition2; - } else { - return false; - } - }); - // 插入剩余的元素 - attSourceDataDao.updateAttStatusData(list); - } else if ("2".equals(c.getAttType())) { - //自由打卡 - attSourceDataDao.updateAttStatusData(list); - } - } - }); - } - - /** - * 固定考勤数据计算 - * - * @param list 考勤来源数据 - * @param attGroupBean 考勤组数据 - * @return 考勤数据 - */ - private List GroupFixedData(List list, - AttGroupBean attGroupBean) { - List newList = getDataList(list, attGroupBean, false); - Iterator iterator = newList.iterator(); - while (iterator.hasNext()) { - if (iterator.next() == null) { - iterator.remove(); - } - } - processAttendanceStatus(newList, attGroupBean.getToWorkTime(), attGroupBean.getOffWorkTime(), attGroupBean.getLateMinute(), - attGroupBean.getAbsenteeismLateMinute(), attGroupBean.getLeaveMinute(), attGroupBean.getAbsenteeismLeaveMinute()); - return newList; - } - - /** - * 上下班考勤计算 - * - * @param list 考勤来源数据 - * @param attGroupBean 考勤组数据 - * @param tf 固定|自由 - * @return 考勤数据 - */ - private List getDataList(List list, - AttGroupBean attGroupBean, - Boolean tf) { - List newList = new ArrayList<>(); - //分组排序(将每个人每天在自己考勤组的数据分组) - Map> groupedItems = list.stream() - .collect(Collectors.groupingBy( - c -> c.getUserId() + "|" + c.getOrgId() + "|" + c.getAttCurrentDay(), - Collectors.collectingAndThen( - Collectors.toList(), - v -> { - v.sort(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)); - return v; - } - ) - )); - if (!tf) { - //固定打卡,以最靠近上班打卡时间前的出闸机的时间为基准,去除掉之前的所有打卡数据 - processGroupedItems(groupedItems, attGroupBean); - } - groupedItems.forEach((c, v) -> { - //第一次上班时间 - AttSourceDataBean frontToWorkBean = v.stream() - .filter(a -> a.getAttType().equals("1")) - .collect(Collectors.toList()) - .stream().min(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null); - //最新一次下班时间 - AttSourceDataBean backOffWorkBean = v.stream() - .filter(a -> a.getAttType().equals("2")) - .collect(Collectors.toList()) - .stream().max(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null); - if (tf) { - if(v!=null&&v.size()>0&&v.get(0).getName().equals("任荣辉")){ - System.out.println("11111111111"); - } - //自由打卡不需要去除数据 - getFreeAttData(newList, frontToWorkBean, backOffWorkBean, attGroupBean); - } else { - if (backOffWorkBean != null) { - //最新一次下班时间插入list - newList.add(backOffWorkBean); - } -// if(v.get(0).getName().equals("肖阳")){ -// System.out.println("c.getAttCurrentTime() = "); +// executed = true; // 设置标志位,表示任务已经执行过 +// String startDate = "2025-01-01"; +// String endDate = "2025-01-31"; +// List dateList = getStrDateListBetween(startDate, endDate); +//// List dateList = new ArrayList<>(); +//// dateList.add("2024-10-18"); +// hisAttPush(dateList); +// log.info("--------考勤定时器完毕------"); +// } +// +// /** +// * 防止黔送离线数据每月前三天晚上将数据重新执行 +// */ +//// @Scheduled(cron = "0 30 22 1-3 * *") +// @Async +// public void getHisMonthAttTask() { +// // 获取当前日期 +// LocalDate today = LocalDate.now(); +// // 获取上个月的YearMonth实例 +// YearMonth previousMonth = YearMonth.from(today).minusMonths(1); +// // 上个月的第一天 +// LocalDate startOfPreviousMonth = previousMonth.atDay(1); +// // 上个月的最后一天 +// LocalDate endOfPreviousMonth = previousMonth.atEndOfMonth(); +// String startDate = startOfPreviousMonth.toString(); +// String endDate = endOfPreviousMonth.toString(); +// List dateList = getStrDateListBetween(startDate, endDate); +// hisAttPush(dateList); +// log.info("--------考勤定时器完毕------"); +// } +// +// /** +// * 凌晨0-5点得到数据,算作昨天,将昨天的重新执行 +// */ +//// @Scheduled(cron = "0 5 6 * * ?") +// @Async +// public void getHisYesterdayAttTask() { +// // 获取今天的日期 +// LocalDate today = LocalDate.now(); +// // 计算昨天的日期 +// LocalDate yesterday = today.minusDays(1); +// String startDate = yesterday.toString(); +// String endDate = yesterday.toString(); +// List dateList = getStrDateListBetween(startDate, endDate); +// hisAttPush(dateList); +// log.info("--------考勤定时器完毕------"); +// } +// +// +// public void hisAttPush(List dateList) { +// // 创建固定大小的线程池 +// ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); +// // 分批处理日期列表 +// for (int i = 0; i < dateList.size(); i += BATCH_SIZE) { +// int end = Math.min(i + BATCH_SIZE, dateList.size()); +// List batch = dateList.subList(i, end); +// // 提交任务到线程池 +// executorService.submit(() -> { +// for (String date : batch) { +// try { +// delHisData(date); +// pushAttData(date, 2); +// } catch (Exception e) { +// // 记录异常并继续处理下一个日期 +// System.err.println("Error processing date: " + date + ", error: " + e.getMessage()); +// } // } - // 处理逻辑 出入异常的逻辑 +// }); +// } +// // 关闭线程池 +// executorService.shutdown(); +// try { +// // 等待所有任务完成 +// executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } +// +// private void delHisData(String date) { +// //查询基础数据是否完备 +// int i = attSourceDataDao.getFirstAttendanceData(date); +// if(i > 0){ +// attSourceDataDao.updateHisData(date); +// }else{ +// attSourceDataDao.delHisData(date); +// } +// } +// +// +// /** +// * 推送考勤数据 +// * +// * @param pushDate 时间 +// * @param pushType 1:自动推送 2:手动 +// */ +// private void pushAttData(String pushDate, int pushType) { +// //获取黔送云的考勤数据 +// getQsyAttendanceData(pushDate, pushType); +// //获取考勤机中的考勤数据 +// getMachineAttendanceData(pushDate, pushType); +//// //查出每一个考勤组的应出勤天数以及考勤组的规则 +// List groupList = getGroupData(pushDate); +//// //新增默认考勤数据到考勤数据和修改表 +// insertAttData(groupList, pushDate, pushType); +// //更新请假数据 +// updateLeaveData(pushDate); +// //修改考勤数据 +// updateAttData(groupList, pushDate, pushType); +//// 根据考勤数据生成报表数据 +// createReportData(groupList, pushDate, pushType); +// } +// +// /** +// * 获取黔送云的考勤数据 +// */ +// private void getQsyAttendanceData(String pushDate, int pushType) { +// List attSourceList = Optional.ofNullable(attSourceDataDao.getQsyAttendances(pushDate, pushType)). +// orElseGet(ArrayList::new); +// if (!attSourceList.isEmpty()) { +// attSourceList.forEach(c -> { +// String address; // try { -// Map> result = checkAdjacentAttType1WithGapAndCheckTypesBefore(v, attGroupBean.getEntryAbnormalMinute()); -// if (result.containsKey(true)) { -// List matchingItems = result.get(true); -// frontToWorkBean = matchingItems.get(0); -// frontToWorkBean.setAbnormalAttTime(matchingItems.get(1).getAttCurrentTime()); -// frontToWorkBean.setAbnormalAttAddress(matchingItems.get(1).getAttAddress()); -// frontToWorkBean.setAttStatus(8); +// address = AddressCoordinateFormatUtil. +// coordinateToAddress(c.getAttLon(), c.getAttLat()); +// }catch (IllegalArgumentException e){ +// address = "地址未转化成功"; +// } +// c.setAttAddress(address); +// if ("0".equals(c.getAttType())) { +// int i = checkTime(c.getAttCurrentTime()); +// c.setAttType(String.valueOf(i)); +// } +// //将00:00:00 至 04:59:59 时间变成att_current_day上一天的 +// changeAttCurrentDay(c); +// } +// ); +// //新增考勤到考勤来源表(数据过多时分批次插入) +// insertAttSourceData(attSourceList); +// } +// } +// +// /** +// * 将00:00:00 至 04:59:59 时间变成att_current_day上一天的 +// * +// * @param c +// */ +// public void changeAttCurrentDay(AttSourceDataBean c) { +// // 定义时间格式 +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// // 解析传入的时间字符串 +// LocalTime time = LocalTime.parse(c.getAttCurrentTime(), formatter); +// // 定义早上5点和中午12点的时间 +// LocalTime morningStart = LocalTime.of(0, 0); +// LocalTime noonEnd = LocalTime.of(5, 0); +// // 判断时间是否在0:00到05:00之间 +// if (time.isAfter(morningStart) && !time.isAfter(noonEnd)) { +// //获取前一天时间 +// String afterDate = DateUtils.getAfterDate(c.getAttCurrentDay()); +// c.setAttCurrentDay(afterDate); +// } +// } +// +// public void insertAttSourceData(List attSourceList) { +// if (attSourceList == null || attSourceList.isEmpty()) { +// return; +// } +// int batchSize = 3000; +// int totalBatches = (int) Math.ceil((double) attSourceList.size() / batchSize); +// try { +// for (int i = 0; i < totalBatches; i++) { +// int fromIndex = i * batchSize; +// int toIndex = Math.min(fromIndex + batchSize, attSourceList.size()); +// List batch = attSourceList.subList(fromIndex, toIndex); +// attSourceDataDao.insertAttSourceData(batch); +// if ((i + 1) % 100 == 0 || i + 1 == totalBatches) { +// sqlSessionTemplate.flushStatements(); // 提交事务 +// sqlSessionTemplate.clearCache(); // 清理缓存 +// } +// } +// } catch (Exception e) { +// throw new RuntimeException("Error replacing data", e); +// } +// } +// +// +// /** +// * 获取考勤机的考勤数据 +// */ +// private void getMachineAttendanceData(String pushDate, int pushType) { +// List attSourceList = Optional.ofNullable(attSourceDataDao.getMachineAttendances(pushDate, pushType)). +// orElseGet(ArrayList::new); +// attSourceList.forEach(c -> { +// if ("0".equals(c.getAttType())) { +// int i = checkTime(c.getAttCurrentTime()); +// c.setAttType(String.valueOf(i)); +// } +// //将00:00:00 至 04:59:59 时间变成att_current_day上一天的 +// changeAttCurrentDay(c); +// }); +// //新增考勤到考勤来源表(数据过多时分批次插入) +// insertAttSourceData(attSourceList); +// } +// +// public int checkTime(String currentTime) { +// if (currentTime == null || currentTime.isEmpty()) { +// // 如果输入为空或为空字符串,则返回默认值(例如2) +// return 1; +// } +// try { +// // 定义时间格式 +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// // 解析传入的时间字符串 +// LocalTime time = LocalTime.parse(currentTime, formatter); +// // 定义早上5点和中午12点的时间 +// LocalTime morningStart = LocalTime.of(5, 0); +// LocalTime noonEnd = LocalTime.of(12, 0); +// // 判断时间是否在5:00到12:00之间 +// if (time.isAfter(morningStart) && !time.isAfter(noonEnd)) { +// return 1; // 在早上5点到12点之间 +// } else { +// return 2; // 其他时间 +// } +// } catch (DateTimeParseException e) { +// // 如果时间格式不正确,返回默认值(例如2) +// e.printStackTrace(); +// return 1; +// } +// } +// +// /** +// * 更新所有的请假数据 +// */ +// private void updateLeaveData(String pushDate) { +// /** +// * 查出在考勤组人员的请假数据 +// */ +// List leaveList = Optional.ofNullable(attSourceDataDao.getLeaveData(pushDate)). +// orElseGet(ArrayList::new); +// if (!leaveList.isEmpty()) { +// leaveList.forEach(leaveData -> threadLeaveData(leaveData, pushDate)); +// } +// } +// +// /** +// * 根据请假数据去更新考勤数据 +// */ +// private void threadLeaveData(LeaveBean c, String pushDate) { +// //1.将请假区间变成日期集合 +//// if(c.getUserId() == 263){ +//// System.out.println("米娜"); +//// } +// List dateLists = getStrDateListBetween(c.getLeaveStartDate(), c.getLeaveEndDate()); +// if (!dateLists.isEmpty()) { +//// //根据开始时间、结束时间获取节假日的日期集合 +// // 1 表示固定打卡 +// if("1".equals(c.getAttType())){ +// //只有固定打卡蒋周六日不算在请假轮休天数中 +// List holidayList = holidayDao.getHolidayDataByType(c.getLeaveStartDate(), c.getLeaveEndDate()); +// // 使用Stream API去除A中包含在B中的元素 +// dateLists = dateLists.stream().filter(element -> !holidayList.contains(element)).collect(Collectors.toList()); +// } +// dateLists.forEach(v -> { +// boolean tf = false; +// AttDataBean toWorkBean = new AttDataBean(v, c.getAttStatus(), "1", +// c.getOrgId(), c.getUserId()); +// AttDataBean offWorkBean = new AttDataBean(v, c.getAttStatus(), "2", +// c.getOrgId(), c.getUserId()); +// //开始和结束的那天是否只请了半天 +// if (c.getLeaveStartDate().equals(v)) { +// if (c.getLeaveStartInterval().equals("2")) { +// replaceHolidayData(offWorkBean, 0); +// } else { +// tf = true; +// } +// } else if (c.getLeaveEndDate().equals(v)) { +// if (c.getLeaveEndInterval().equals("1")) { +// replaceHolidayData(toWorkBean, 0); +// } else { +// tf = true; +// } +// } else { +// tf = true; +// } +// if (tf) { +// replaceHolidayData(toWorkBean, 0); +// replaceHolidayData(offWorkBean, 0); +// } +// }); +// } +// } +// +// public static List getStrDateListBetween(String startDateString, String endDateString) { +// List dateList = new ArrayList<>(); +// DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); +// try { +// // 解析开始日期和结束日期 +// Date startDate = dateFormat.parse(startDateString); +// Date endDate = dateFormat.parse(endDateString); +// // 创建 Calendar 实例并设置为开始日期 +// Calendar calendar = Calendar.getInstance(); +// calendar.setTime(startDate); +// // 循环直到当前日期超过结束日期 +// while (!calendar.getTime().after(endDate)) { +// // 将日期格式化为字符串,并添加到列表中 +// dateList.add(dateFormat.format(calendar.getTime())); +// // 将日期加一天 +// calendar.add(Calendar.DAY_OF_MONTH, 1); +// } +// } catch (ParseException ignored) { +// } +// return dateList; +// } +// +// /** +// * 查出每一个考勤组的应出勤天数以及考勤组的规则 +// * +// * @return 考勤组集合 +// */ +// public List getGroupData(String pushDate) { +// //查出考勤组的数据 +// List groupList = Optional.ofNullable(attGroupDao.selectAttGroupList(new AttGroupBean())). +// orElseGet(ArrayList::new); +// if (groupList.isEmpty()) { +// return new ArrayList<>(); +// } +// //查询当月否有节假日或补班 +// List holidays = attSourceDataDao.selectHolidayByMonth(pushDate); +// groupList.forEach(c -> { +// //应考勤天 +// List attDayList = WorkdayCalculator.getWorkDay(c.getAttDay(), +// Integer.parseInt(c.getAttType()), holidays,pushDate); +// c.setAttWorkDayBean(new PersonAttWorkDayBean(c.getGroupId(), attDayList.size(), attDayList)); +// }); +// return groupList; +// } +// +// /** +// * 新增默认考勤数据到考勤数据和修改表 +// * +// * @param groupList 考勤组集合 +// */ +// private void insertAttData(List groupList, String pushDate, int pushType) { +// //获取所有的用户 +// // 2025-01-17 添加时间,查出每个人在对应时间存在的考勤组 +// List listPerson = attSourceDataDao.getAllPerson(pushDate); +// if (!listPerson.isEmpty()) { +// listPerson.forEach(v -> { +// groupList.stream() +// .filter(c -> Objects.equals(v.getGroupId(), c.getGroupId()) && !c.getAttWorkDayBean() +// .getAttDayList().contains(pushDate)) +// .findFirst() +// .ifPresent(c -> v.setAttStatus("11")); +// v.setAttCurrentDay(pushDate); +// replaceAttData(v, pushDate); +// }); +// } +// } +// +// /** +// * 新增修改考勤数据 +// */ +// private void replaceAttData(AttDataBean v, String pushDate) { +// //查询考勤模版数据是否已经插入 +// Boolean isAttExist = attSourceDataDao.selectAttIsExist(v); +// if (!isAttExist) { +// //查询能修改的考勤模版数据是否已经插入 +// // 判断 pushDate 是否在今天之前 +// boolean isPastDate = isBeforeToday(pushDate); +// if (isPastDate) { +// //不存在且在今天之前 +// //之前处理过节假日的数据,只有是默认数据才能将旷工状态写入 +// if (v.getAttStatus().equals("0")) { +// v.setAttStatus("3"); +// } +// }else{ +// //不存在就在今天 +// //逻辑跟修改相同,第一次就不去麻烦根据时间判断状态了 +// } +// attSourceDataDao.insertAttData(v); +// } else { +// if (!v.getAttStatus().equals("0")) { +// attSourceDataDao.updateAttData(v, 0); +// } +// if (v.getAttStatus().equals("0")) { +// //将未打卡的全部置为旷工 +// changeAbsenteeAttStatus(v, 0, 0, pushDate); +// } +// } +// //查询能修改的考勤模版数据是否已经插入 +// Boolean isAttUpdateExist = attSourceDataDao.selectAttUpdateIsExist(v); +// if (!isAttUpdateExist) { +// // 判断 pushDate 是否在今天之前 +// boolean isPastDate = isBeforeToday(pushDate); +// if (isPastDate) { +// //之前处理过节假日的数据,只有是默认数据才能将旷工状态写入 +// if (v.getAttStatus().equals("0")) { +// v.setAttStatus("3"); +// } +// } +// attSourceDataDao.insertAttUpdateData(v); +// } else { +// if (!v.getAttStatus().equals("0")) { +// attSourceDataDao.updateAttUpdateData(v, 0); +// } else { +// //将未打卡的全部置为旷工 +// changeAbsenteeAttStatus(v, 0, 1, pushDate); +// } +// } +// } +// +// +// /** +// * 新增修改请假数据(更新考勤表) +// */ +// private void replaceHolidayData(AttDataBean v, int type) { +// //查询考勤模版数据是否已经插入 +// Boolean isAttExist = attSourceDataDao.selectAttIsExist(v); +// if (!isAttExist) { +// //没有基础数据,插入基础数据并改状态为对应请假状态 +// attSourceDataDao.insertAttData(v); +// } else { +// if (!v.getAttStatus().equals("0")) { +// //改状态为对应请假状态 +// attSourceDataDao.updateAttData(v, type); +// } +// } +// //查询能修改的考勤模版数据是否已经插入 +// Boolean isAttUpdateExist = attSourceDataDao.selectAttUpdateIsExist(v); +// if (!isAttUpdateExist) { +// //没有基础数据,插入基础数据并改状态为对应请假状态 +// attSourceDataDao.insertAttUpdateData(v); +// } else { +// if (!v.getAttStatus().equals("0")) { +// //改状态为对应请假状态 +// attSourceDataDao.updateAttUpdateData(v, type); +// } +// } +// } +// +// +// /** +// * 将未打卡的全部置为旷工 +// * +// * @param v 考勤数据 +// * @param type 0表示考勤数据,1表示考勤修改数据 +// * @param update 0表示修改考勤数据,1表示修改考勤修改数据 +// * @param pushDate 推送时间 +// */ +// private void changeAbsenteeAttStatus(AttDataBean v, int type, int update, String pushDate) { +// //将未打卡的全部置为旷工 +// // 判断 pushDate 是否在今天之前 +// boolean isPastDate = isBeforeToday(pushDate); +// if (isPastDate) { +// // 如果 pushDate 是过去的时间,直接执行原逻辑 +// v.setAttStatus("3"); +// if (update == 0) { +// attSourceDataDao.updateAttData(v, type); +// } else if (update == 1) { +// attSourceDataDao.updateAttUpdateData(v, type); +// } +// } else { +// LocalTime currentTime; +// // 使用当前时间 +// currentTime = LocalTime.now(); +// // 定义中午 12 点 +// LocalTime noon = LocalTime.of(12, 0); +// // 定义下午 22 点 +// LocalTime eightPM = LocalTime.of(22, 0); +// // 当前时间逻辑 +// if (currentTime.isAfter(noon)) { +// if ("1".equals(v.getAttType())) { +// v.setAttStatus("3"); +// if (update == 0) { +// attSourceDataDao.updateAttData(v, type); +// } else if (update == 1) { +// attSourceDataDao.updateAttUpdateData(v, type); +// } +// } +// } +// if (currentTime.isAfter(eightPM)) { +// if ("2".equals(v.getAttType())) { +// v.setAttStatus("3"); +// if (update == 0) { +// attSourceDataDao.updateAttData(v, type); +// } else if (update == 1) { +// attSourceDataDao.updateAttUpdateData(v, type); +// } +// } +// } +// } +// } +// +// /** +// * 判断传入的日期是否在今天的日期之前 +// * +// * @param dateStr 传入的日期字符串,格式为 "yyyy-MM-dd" +// * @return 如果传入的日期在今天的日期之前,返回 true;否则返回 false +// */ +// public boolean isBeforeToday(String dateStr) { +// if (dateStr == null || dateStr.isEmpty()) { +// return false; +// } +// try { +// LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); +// LocalDate today = LocalDate.now(); +// return date.isBefore(today); +// } catch (Exception e) { +// // 如果日期格式不正确,返回 false +// e.printStackTrace(); +// return false; +// } +// } +// +// /** +// * 修改考勤数据 +// * +// * @param groupList 考勤组集合 +// */ +// private void updateAttData(List groupList, String pushDate, int pushType) { +// //查出最近三天的人员考勤记录 +// AtomicReference> sourceDataList = new AtomicReference<>(attSourceDataDao.getSourceAttData(pushDate, pushType)); +// //根据考勤组的规则和请假记录算出人员的考勤状态 +// groupList.forEach(c -> { +// List list = Collections.emptyList(); +// //考勤规则里面的attType 1 固定打卡 2 自由打卡 +// if ("1".equals(c.getAttType())) { +// list = GroupFixedData(sourceDataList.get().stream() +// .filter(a -> "1".equals(a.getGroupType()) && +// a.getGroupId() == c.getGroupId()) +// .collect(Collectors.toList()), c); +// } else if ("2".equals(c.getAttType())) { +// list = getDataList(sourceDataList.get().stream() +// .filter(a -> "2".equals(a.getGroupType()) && +// a.getGroupId() == c.getGroupId()) +// .collect(Collectors.toList()), c, true); +// } +// //修改考勤记录 att_data +// if (!list.isEmpty()) { +// if ("1".equals(c.getAttType())) { +// //固定打卡 +// // 定义时间格式 +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// // 移除移除 attType 为 2 且 attCurrentTime 在上午 5 点到 12 点之间的元素 +// list.removeIf(record -> { +// String attType = record.getAttType(); +// String attCurrentTime = record.getAttCurrentTime(); +// if (!"".equals(attCurrentTime)) { +// if (attCurrentTime.contains(" ")) { +// attCurrentTime = attCurrentTime.split(" ")[0]; +// } +// LocalDateTime time = LocalDateTime.parse(attCurrentTime, formatter); +// // 提取时间部分 +// LocalTime localTime = time.toLocalTime(); +// boolean condition1 = "2".equals(attType) && localTime.isAfter(LocalTime.of(5, 0)) && localTime.isBefore(LocalTime.of(12, 0)); +// boolean condition2 = "1".equals(attType) && localTime.isAfter(LocalTime.of(12, 0)) && localTime.isBefore(LocalTime.of(23, 59)); +// return condition1 || condition2; +// } else { +// return false; +// } +// }); +// // 插入剩余的元素 +// attSourceDataDao.updateAttStatusData(list); +// } else if ("2".equals(c.getAttType())) { +// //自由打卡 +// attSourceDataDao.updateAttStatusData(list); +// } +// } +// }); +// } +// +// /** +// * 固定考勤数据计算 +// * +// * @param list 考勤来源数据 +// * @param attGroupBean 考勤组数据 +// * @return 考勤数据 +// */ +// private List GroupFixedData(List list, +// AttGroupBean attGroupBean) { +// List newList = getDataList(list, attGroupBean, false); +// Iterator iterator = newList.iterator(); +// while (iterator.hasNext()) { +// if (iterator.next() == null) { +// iterator.remove(); +// } +// } +// processAttendanceStatus(newList, attGroupBean.getToWorkTime(), attGroupBean.getOffWorkTime(), attGroupBean.getLateMinute(), +// attGroupBean.getAbsenteeismLateMinute(), attGroupBean.getLeaveMinute(), attGroupBean.getAbsenteeismLeaveMinute()); +// return newList; +// } +// +// /** +// * 上下班考勤计算 +// * +// * @param list 考勤来源数据 +// * @param attGroupBean 考勤组数据 +// * @param tf 固定|自由 +// * @return 考勤数据 +// */ +// private List getDataList(List list, +// AttGroupBean attGroupBean, +// Boolean tf) { +// List newList = new ArrayList<>(); +// //分组排序(将每个人每天在自己考勤组的数据分组) +// Map> groupedItems = list.stream() +// .collect(Collectors.groupingBy( +// c -> c.getUserId() + "|" + c.getOrgId() + "|" + c.getAttCurrentDay(), +// Collectors.collectingAndThen( +// Collectors.toList(), +// v -> { +// v.sort(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)); +// return v; +// } +// ) +// )); +// if (!tf) { +// //固定打卡,以最靠近上班打卡时间前的出闸机的时间为基准,去除掉之前的所有打卡数据 +// processGroupedItems(groupedItems, attGroupBean); +// } +// groupedItems.forEach((c, v) -> { +// //第一次上班时间 +// AttSourceDataBean frontToWorkBean = v.stream() +// .filter(a -> a.getAttType().equals("1")) +// .collect(Collectors.toList()) +// .stream().min(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null); +// //最新一次下班时间 +// AttSourceDataBean backOffWorkBean = v.stream() +// .filter(a -> a.getAttType().equals("2")) +// .collect(Collectors.toList()) +// .stream().max(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)).orElse(null); +// if (tf) { +// if(v!=null&&v.size()>0&&v.get(0).getName().equals("任荣辉")){ +// System.out.println("11111111111"); +// } +// //自由打卡不需要去除数据 +// getFreeAttData(newList, frontToWorkBean, backOffWorkBean, attGroupBean); +// } else { +// if (backOffWorkBean != null) { +// //最新一次下班时间插入list +// newList.add(backOffWorkBean); +// } +//// if(v.get(0).getName().equals("肖阳")){ +//// System.out.println("c.getAttCurrentTime() = "); +//// } +// // 处理逻辑 出入异常的逻辑 +//// try { +//// Map> result = checkAdjacentAttType1WithGapAndCheckTypesBefore(v, attGroupBean.getEntryAbnormalMinute()); +//// if (result.containsKey(true)) { +//// List matchingItems = result.get(true); +//// frontToWorkBean = matchingItems.get(0); +//// frontToWorkBean.setAbnormalAttTime(matchingItems.get(1).getAttCurrentTime()); +//// frontToWorkBean.setAbnormalAttAddress(matchingItems.get(1).getAttAddress()); +//// frontToWorkBean.setAttStatus(8); +//// } +//// }catch(Exception e){ +//// e.printStackTrace(); +//// log.error("出入异常处理报错"); +//// } +// //没有下班卡则添加第一次打卡数据 +// newList.add(frontToWorkBean); +// //获取工作异常 +// LocalTime lastOutTime = null; +// DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); +// try { +// //存储工作异常的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); +// } // } // }catch(Exception e){ // e.printStackTrace(); -// log.error("出入异常处理报错"); +// log.error("工作异常处理报错"); // } - //没有下班卡则添加第一次打卡数据 - newList.add(frontToWorkBean); - //获取工作异常 - LocalTime lastOutTime = null; - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); - try { - //存储工作异常的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); - } - } - }catch(Exception e){ - e.printStackTrace(); - log.error("工作异常处理报错"); - } - - } - }); - 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 - */ - private Map> checkAdjacentAttType1WithGapAndCheckTypesBefore(List items, Long entryAbnormalMinute) { - DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); - // 步骤1:根据 getAttCurrentTime 排序 - items.sort(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)); - // 步骤2:找到最早相邻且间隔时间大于2分钟的两个 attType = 1 的数据项 - AttSourceDataBean firstAttType1 = null; - AttSourceDataBean secondAttType1 = null; - for (int i = 0; i < items.size() - 1; i++) { - if ("1".equals(items.get(i).getAttType()) && "1".equals(items.get(i + 1).getAttType())) { - // 提取时间部分 - String firstTimeStr = items.get(i).getAttCurrentTime().substring(11); - String secondTimeStr = items.get(i + 1).getAttCurrentTime().substring(11); - LocalTime firstTime = LocalTime.parse(firstTimeStr, timeFormatter); - LocalTime secondTime = LocalTime.parse(secondTimeStr, timeFormatter); - Duration duration = Duration.between(firstTime, secondTime); - if (duration.toMinutes() > entryAbnormalMinute) { - firstAttType1 = items.get(i); - secondAttType1 = items.get(i + 1); - break; - } - } - } - // 如果没有找到符合条件的两个 attType = 1 的数据项,直接返回 false - if (firstAttType1 == null || secondAttType1 == null) { - Map> result = new HashMap<>(); - result.put(false, Collections.emptyList()); - return result; - } - - // 步骤3:检查这两个数据项之前的数据集合是否同时包含 attType = 1 和 attType = 2 的数据 - int indexFirstAttType1 = items.indexOf(firstAttType1); - List dataBeforeFirstAttType1 = items.subList(0, indexFirstAttType1); - - Set attTypesBefore = dataBeforeFirstAttType1.stream() - .map(AttSourceDataBean::getAttType) - .collect(Collectors.toSet()); - - boolean containsBothTypes = attTypesBefore.contains("1") && attTypesBefore.contains("2"); - // 返回结果 - Map> result = new HashMap<>(); - if (containsBothTypes) { - result.put(true, Arrays.asList(firstAttType1, secondAttType1)); - } else { - result.put(false, Collections.emptyList()); - } - return result; - } - - /** - * 固定打卡清除数据 - * - * @param groupedItems - */ - private void processGroupedItems(Map> groupedItems, AttGroupBean attGroupBean) { - DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - for (Map.Entry> entry : groupedItems.entrySet()) { - String key = entry.getKey(); - List items = entry.getValue(); - if (items.isEmpty()) { - continue; // 如果列表为空,跳过 - } - //五点之前的数据属于过来当天的下班打卡,不计入 - LocalTime noonEnd = LocalTime.of(5, 0); - // 获取上班时间并转换为 LocalTime 以便比较 - LocalTime toWorkTime = LocalTime.parse(attGroupBean.getToWorkTime(), timeFormatter); - // 初始化变量来保存最接近上班时间的数据项及其索引 - AttSourceDataBean closestBeforeToWork = null; - int closestIndex = -1; - // 遍历并查找最接近上班时间且 attType=2 的数据项 - //前面已经排过序了,取第一个就可以了 - for (int i = 0; i < items.size(); i++) { - AttSourceDataBean item = items.get(i); -// System.out.println(item.getName()); -// if("王义".equals(item.getName())){ -// System.out.println(111); -// } - if ("2".equals(item.getAttType())) { - // 只提取时间部分进行比较 - LocalTime recordTime = LocalTime.parse(item.getAttCurrentTime().substring(11), timeFormatter); - // 检查是否在上班时间之前并且是目前找到的最接近上班时间的 - if (recordTime.isBefore(toWorkTime) && recordTime.isAfter(noonEnd) && - (closestBeforeToWork == null || - recordTime.isAfter(LocalTime.parse(closestBeforeToWork.getAttCurrentTime().substring(11), timeFormatter)))) { - closestBeforeToWork = item; - closestIndex = i; - } - } - } - - // 如果找到了符合条件的数据项,则移除它之前的所有数据,包括它自己 - if (closestIndex != -1) { - List filteredItems = items.stream() - .skip(closestIndex) // 跳过最接近上班时间的数据项及其之前的所有数据 - .collect(Collectors.toList()); - // 更新原始映射中的列表 - groupedItems.put(key, filteredItems); - } else { - // 如果没有找到符合条件的数据项,可以选择保留所有数据或清空列表 - // groupedItems.put(key, Collections.emptyList()); // 清空列表 - } - } - } - - /** - * 获取自由考勤数据 - * - * @param newList 考勤数据 - * @param frontToWorkBean 第一次上班考勤数据 - * @param backOffWorkBean 最后一次下班考勤数据 - * @param attGroupBean 考勤组数据 - */ - private void getFreeAttData(List newList, - AttSourceDataBean frontToWorkBean, - AttSourceDataBean backOffWorkBean, - AttGroupBean attGroupBean) { - // todayClockNum 自由打卡每天打卡次数 - if (attGroupBean.getTodayClockNum() == 2) { - if (frontToWorkBean != null) { - frontToWorkBean.setAttStatus(1); - newList.add(frontToWorkBean); - } - if (backOffWorkBean != null) { - if (frontToWorkBean != null) { - long minutesDiff = DateUtil.between( - DateUtils.parseDate(frontToWorkBean.getAttCurrentTime()), - DateUtils.parseDate(backOffWorkBean.getAttCurrentTime()), - DateUnit.MINUTE - ); - if (minutesDiff >= attGroupBean.getAttendanceDuration()) { - backOffWorkBean.setAttStatus(1); - } else { - if (minutesDiff > attGroupBean.getAbsenteeismLateMinute()) { - backOffWorkBean.setAttStatus(1); - }else if (minutesDiff > attGroupBean.getAbsenteeismLeaveMinute()) { - backOffWorkBean.setAttStatus(4); - }else{ - backOffWorkBean.setAttStatus(3); - } - } - newList.add(backOffWorkBean); - } else { - backOffWorkBean.setAttStatus(1); - newList.add(backOffWorkBean); - } - } - } else { - if (frontToWorkBean != null) { -// if(frontToWorkBean.getName().equals("位兆虎")){ -// System.out.println(1); -// } - frontToWorkBean.setAttStatus(1); - AttSourceDataBean bean; - try { - bean = (AttSourceDataBean) BeanUtils.cloneBean(frontToWorkBean); - } catch (Exception e) { - throw new RuntimeException(e); - } - bean.setAttCurrentTime(""); - bean.setAttType("2"); - newList.add(bean); - newList.add(frontToWorkBean); - } else if (backOffWorkBean != null) { - backOffWorkBean.setAttStatus(1); - AttSourceDataBean bean; - try { - bean = (AttSourceDataBean) BeanUtils.cloneBean(backOffWorkBean); - } catch (Exception e) { - throw new RuntimeException(e); - } - bean.setAttCurrentTime(""); - bean.setAttType("1"); - newList.add(bean); - newList.add(backOffWorkBean); - } - - } - } - - /** - * 根据时间段处理上下班 - * - * @param bean - * @param startHour - * @param startMinute - * @param endHour - * @param endMinute - * @param oldAttType - * @param newAttType - * @return - */ - private void dealWithDateToAttType(AttSourceDataBean bean, int startHour, int startMinute, int endHour, int endMinute, String oldAttType, String newAttType) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - String attType = bean.getAttType(); - String attCurrentTime = bean.getAttCurrentTime(); - if (!"".equals(attCurrentTime)) { - if (attCurrentTime.contains(" ")) { - attCurrentTime = attCurrentTime.split(" ")[0]; - } - LocalDateTime time = LocalDateTime.parse(attCurrentTime, formatter); - // 提取时间部分 - LocalTime localTime = time.toLocalTime(); - if (oldAttType.equals(attType) && localTime.isAfter(LocalTime.of(startHour, startMinute)) && localTime.isBefore(LocalTime.of(startMinute, endMinute))) { - bean.setAttType(newAttType); - } - } - } - - - /** - * 处理打卡状态 - * - * @param newList 考勤数据 - * @param toWorkTime 上班时间 - * @param offWorkTime 下班时间 - * @param lateMinute 迟到时间 - * @param absenteeismLateMinute 旷工迟到分钟 - * @param leaveMinute 早退分钟 - * @param absenteeismLeaveMinute 旷工早退分钟 - */ - private void processAttendanceStatus(List newList, String toWorkTime, - String offWorkTime, long lateMinute, - long absenteeismLateMinute, long leaveMinute, - long absenteeismLeaveMinute) { - newList.forEach(c -> { -// if(c.getName().equals("肖阳")){ -// System.out.println("c.getAttCurrentTime() = " + c.getAttCurrentTime()); +// // } - System.out.println(c.getName()); - int attStatus = calculateStatus( - c.getAttType(), - c.getAttCurrentTime(), - "1".equals(c.getAttType()) ? toWorkTime : offWorkTime, - "1".equals(c.getAttType()) ? lateMinute : leaveMinute, - "1".equals(c.getAttType()) ? absenteeismLateMinute : absenteeismLeaveMinute - ); - System.out.println(1111); - // 如打卡状态为正常,检查是否有异常出入时间 - if (attStatus == 1 && c.getAttStatus() != null && c.getAttStatus() == 8) { - attStatus = 8; // 异常 - boolean b = DateTimeHelper.compareTime2(c.getAttCurrentTime(), c.getAbnormalAttTime()); - String time = ""; - String address = ""; - if (b) { - time = c.getAttCurrentTime() + " " + c.getAbnormalAttTime(); - address = c.getAttAddress() + " " + c.getAbnormalAttAddress(); - } else { - time = c.getAbnormalAttTime() + " " + c.getAttCurrentTime(); - address = c.getAbnormalAttAddress() + " " + c.getAttAddress(); - } - c.setAttCurrentTime(time); - c.setAttAddress(address); - } - System.out.println(2222); - c.setAttStatus(attStatus); - }); - } - - - /** - * 计算时间差并返回状态 - * - * @param attType 考勤类型 - * @param attTime 考勤时间 - * @param standardTime 上、下班时间 - * @param lateThreshold 迟到、早退时间 - * @param absenteeismThreshold 旷工时间 - * @return 考勤状态 - */ - private int calculateStatus(String attType, String attTime, String standardTime, - long lateThreshold, long absenteeismThreshold) { - int status = 1; - // 创建两个时间点 - Date date1 = DateUtils.parseDate(DateUtils.getYyyyMmDd(attTime) + " " + standardTime); - Date date2 = DateUtils.parseDate(attTime); - if ("2".equals(attType)) { - String startTime = DateUtils.getYyyyMmDd(attTime) + " 00:00:00"; - String endTime = DateUtils.getYyyyMmDd(attTime) + " 04:59:59"; - if (DateUtils.getTimeIsRange(attTime, startTime, endTime)) { - date1 = DateUtils.parseDate(DateUtils.getAfterDate(DateUtils.getYyyyMmDd(attTime)) + " " + standardTime); - } - } - if ("1".equals(attType)) { // 上班打卡 - // 计算时间差 - // 减 1 原因:30上班,30:59不算迟到,类似于默认可以迟到一分钟 - double difference = (date2.getTime() - date1.getTime()) / 60000.0 - 1; - if (difference > 0) { - if (difference > absenteeismThreshold) { - status = 3; // 旷工 - } else if (difference > lateThreshold) { - status = 2; // 迟到 - } - } - } else if ("2".equals(attType)) { // 下班打卡 - // 计算时间差 - double difference = (date2.getTime() - date1.getTime()) / 60000.0; - if (difference < 0) { - if (Math.abs(difference) > lateThreshold) { - status = 4; // 早退 - } - if (Math.abs(difference) > absenteeismThreshold) { - status = 3; // 旷工 - } - } - } - return status; // 正常 - } - - /** - * 根据考勤数据生成报表数据 - * - * @param groupList 考勤组集合 - */ - public void createReportData(List groupList, String pushDate, int pushType) { - //日报表查询 - List dayReportList = attSourceDataDao.selectAttDayReport(pushDate); - //日报表新增 - attSourceDataDao.insertAttDayReport(dayReportList); - List monthReportList = attSourceDataDao.selectAttMonthReport(pushDate); - //人员对应出月出勤天数 - monthReportList.forEach(c -> - groupList.stream() - .filter(v -> c.getGroupId() != null && c.getGroupId().equals(v.getGroupId())) - .findFirst() - .ifPresent(v -> c.setRequiredDays(v.getAttWorkDayBean().getRequiredDays())) - ); - //先将本月数据删除,重新生成 - attSourceDataDao.deleteAttMonthReport(pushDate); - //月报表新增 - attSourceDataDao.insertAttMonthReport(monthReportList); - } - - /** - * 根据当前日期计算目标日期 - * - * @param now 当前日期时间 - * @return 目标日期 - */ - public static LocalDate getTargetDate(LocalDateTime now) { - // 获取当前日期的年份和月份 - YearMonth currentYearMonth = YearMonth.from(now); - - // 获取当前日期的月初日期 - LocalDate firstDayOfMonth = currentYearMonth.atDay(1); - - // 判断是否是当月 - if (now.getMonth().equals(firstDayOfMonth.getMonth())) { - // 如果是当月,返回当前日期的日期部分 - return now.toLocalDate(); - } else { - // 如果是之前月份,返回该月份的最后一天 - return currentYearMonth.atEndOfMonth(); - } - } - -} \ No newline at end of file +// }); +// 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 +// */ +// private Map> checkAdjacentAttType1WithGapAndCheckTypesBefore(List items, Long entryAbnormalMinute) { +// DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); +// // 步骤1:根据 getAttCurrentTime 排序 +// items.sort(Comparator.comparing(AttSourceDataBean::getAttCurrentTime)); +// // 步骤2:找到最早相邻且间隔时间大于2分钟的两个 attType = 1 的数据项 +// AttSourceDataBean firstAttType1 = null; +// AttSourceDataBean secondAttType1 = null; +// for (int i = 0; i < items.size() - 1; i++) { +// if ("1".equals(items.get(i).getAttType()) && "1".equals(items.get(i + 1).getAttType())) { +// // 提取时间部分 +// String firstTimeStr = items.get(i).getAttCurrentTime().substring(11); +// String secondTimeStr = items.get(i + 1).getAttCurrentTime().substring(11); +// LocalTime firstTime = LocalTime.parse(firstTimeStr, timeFormatter); +// LocalTime secondTime = LocalTime.parse(secondTimeStr, timeFormatter); +// Duration duration = Duration.between(firstTime, secondTime); +// if (duration.toMinutes() > entryAbnormalMinute) { +// firstAttType1 = items.get(i); +// secondAttType1 = items.get(i + 1); +// break; +// } +// } +// } +// // 如果没有找到符合条件的两个 attType = 1 的数据项,直接返回 false +// if (firstAttType1 == null || secondAttType1 == null) { +// Map> result = new HashMap<>(); +// result.put(false, Collections.emptyList()); +// return result; +// } +// +// // 步骤3:检查这两个数据项之前的数据集合是否同时包含 attType = 1 和 attType = 2 的数据 +// int indexFirstAttType1 = items.indexOf(firstAttType1); +// List dataBeforeFirstAttType1 = items.subList(0, indexFirstAttType1); +// +// Set attTypesBefore = dataBeforeFirstAttType1.stream() +// .map(AttSourceDataBean::getAttType) +// .collect(Collectors.toSet()); +// +// boolean containsBothTypes = attTypesBefore.contains("1") && attTypesBefore.contains("2"); +// // 返回结果 +// Map> result = new HashMap<>(); +// if (containsBothTypes) { +// result.put(true, Arrays.asList(firstAttType1, secondAttType1)); +// } else { +// result.put(false, Collections.emptyList()); +// } +// return result; +// } +// +// /** +// * 固定打卡清除数据 +// * +// * @param groupedItems +// */ +// private void processGroupedItems(Map> groupedItems, AttGroupBean attGroupBean) { +// DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); +// DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// for (Map.Entry> entry : groupedItems.entrySet()) { +// String key = entry.getKey(); +// List items = entry.getValue(); +// if (items.isEmpty()) { +// continue; // 如果列表为空,跳过 +// } +// //五点之前的数据属于过来当天的下班打卡,不计入 +// LocalTime noonEnd = LocalTime.of(5, 0); +// // 获取上班时间并转换为 LocalTime 以便比较 +// LocalTime toWorkTime = LocalTime.parse(attGroupBean.getToWorkTime(), timeFormatter); +// // 初始化变量来保存最接近上班时间的数据项及其索引 +// AttSourceDataBean closestBeforeToWork = null; +// int closestIndex = -1; +// // 遍历并查找最接近上班时间且 attType=2 的数据项 +// //前面已经排过序了,取第一个就可以了 +// for (int i = 0; i < items.size(); i++) { +// AttSourceDataBean item = items.get(i); +//// System.out.println(item.getName()); +//// if("王义".equals(item.getName())){ +//// System.out.println(111); +//// } +// if ("2".equals(item.getAttType())) { +// // 只提取时间部分进行比较 +// LocalTime recordTime = LocalTime.parse(item.getAttCurrentTime().substring(11), timeFormatter); +// // 检查是否在上班时间之前并且是目前找到的最接近上班时间的 +// if (recordTime.isBefore(toWorkTime) && recordTime.isAfter(noonEnd) && +// (closestBeforeToWork == null || +// recordTime.isAfter(LocalTime.parse(closestBeforeToWork.getAttCurrentTime().substring(11), timeFormatter)))) { +// closestBeforeToWork = item; +// closestIndex = i; +// } +// } +// } +// +// // 如果找到了符合条件的数据项,则移除它之前的所有数据,包括它自己 +// if (closestIndex != -1) { +// List filteredItems = items.stream() +// .skip(closestIndex) // 跳过最接近上班时间的数据项及其之前的所有数据 +// .collect(Collectors.toList()); +// // 更新原始映射中的列表 +// groupedItems.put(key, filteredItems); +// } else { +// // 如果没有找到符合条件的数据项,可以选择保留所有数据或清空列表 +// // groupedItems.put(key, Collections.emptyList()); // 清空列表 +// } +// } +// } +// +// /** +// * 获取自由考勤数据 +// * +// * @param newList 考勤数据 +// * @param frontToWorkBean 第一次上班考勤数据 +// * @param backOffWorkBean 最后一次下班考勤数据 +// * @param attGroupBean 考勤组数据 +// */ +// private void getFreeAttData(List newList, +// AttSourceDataBean frontToWorkBean, +// AttSourceDataBean backOffWorkBean, +// AttGroupBean attGroupBean) { +// // todayClockNum 自由打卡每天打卡次数 +// if (attGroupBean.getTodayClockNum() == 2) { +// if (frontToWorkBean != null) { +// frontToWorkBean.setAttStatus(1); +// newList.add(frontToWorkBean); +// } +// if (backOffWorkBean != null) { +// if (frontToWorkBean != null) { +// long minutesDiff = DateUtil.between( +// DateUtils.parseDate(frontToWorkBean.getAttCurrentTime()), +// DateUtils.parseDate(backOffWorkBean.getAttCurrentTime()), +// DateUnit.MINUTE +// ); +// if (minutesDiff >= attGroupBean.getAttendanceDuration()) { +// backOffWorkBean.setAttStatus(1); +// } else { +// if (minutesDiff > attGroupBean.getAbsenteeismLateMinute()) { +// backOffWorkBean.setAttStatus(1); +// }else if (minutesDiff > attGroupBean.getAbsenteeismLeaveMinute()) { +// backOffWorkBean.setAttStatus(4); +// }else{ +// backOffWorkBean.setAttStatus(3); +// } +// } +// newList.add(backOffWorkBean); +// } else { +// backOffWorkBean.setAttStatus(1); +// newList.add(backOffWorkBean); +// } +// } +// } else { +// if (frontToWorkBean != null) { +//// if(frontToWorkBean.getName().equals("位兆虎")){ +//// System.out.println(1); +//// } +// frontToWorkBean.setAttStatus(1); +// AttSourceDataBean bean; +// try { +// bean = (AttSourceDataBean) BeanUtils.cloneBean(frontToWorkBean); +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// bean.setAttCurrentTime(""); +// bean.setAttType("2"); +// newList.add(bean); +// newList.add(frontToWorkBean); +// } else if (backOffWorkBean != null) { +// backOffWorkBean.setAttStatus(1); +// AttSourceDataBean bean; +// try { +// bean = (AttSourceDataBean) BeanUtils.cloneBean(backOffWorkBean); +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// bean.setAttCurrentTime(""); +// bean.setAttType("1"); +// newList.add(bean); +// newList.add(backOffWorkBean); +// } +// +// } +// } +// +// /** +// * 根据时间段处理上下班 +// * +// * @param bean +// * @param startHour +// * @param startMinute +// * @param endHour +// * @param endMinute +// * @param oldAttType +// * @param newAttType +// * @return +// */ +// private void dealWithDateToAttType(AttSourceDataBean bean, int startHour, int startMinute, int endHour, int endMinute, String oldAttType, String newAttType) { +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// String attType = bean.getAttType(); +// String attCurrentTime = bean.getAttCurrentTime(); +// if (!"".equals(attCurrentTime)) { +// if (attCurrentTime.contains(" ")) { +// attCurrentTime = attCurrentTime.split(" ")[0]; +// } +// LocalDateTime time = LocalDateTime.parse(attCurrentTime, formatter); +// // 提取时间部分 +// LocalTime localTime = time.toLocalTime(); +// if (oldAttType.equals(attType) && localTime.isAfter(LocalTime.of(startHour, startMinute)) && localTime.isBefore(LocalTime.of(startMinute, endMinute))) { +// bean.setAttType(newAttType); +// } +// } +// } +// +// +// /** +// * 处理打卡状态 +// * +// * @param newList 考勤数据 +// * @param toWorkTime 上班时间 +// * @param offWorkTime 下班时间 +// * @param lateMinute 迟到时间 +// * @param absenteeismLateMinute 旷工迟到分钟 +// * @param leaveMinute 早退分钟 +// * @param absenteeismLeaveMinute 旷工早退分钟 +// */ +// private void processAttendanceStatus(List newList, String toWorkTime, +// String offWorkTime, long lateMinute, +// long absenteeismLateMinute, long leaveMinute, +// long absenteeismLeaveMinute) { +// newList.forEach(c -> { +//// if(c.getName().equals("肖阳")){ +//// System.out.println("c.getAttCurrentTime() = " + c.getAttCurrentTime()); +//// } +// System.out.println(c.getName()); +// int attStatus = calculateStatus( +// c.getAttType(), +// c.getAttCurrentTime(), +// "1".equals(c.getAttType()) ? toWorkTime : offWorkTime, +// "1".equals(c.getAttType()) ? lateMinute : leaveMinute, +// "1".equals(c.getAttType()) ? absenteeismLateMinute : absenteeismLeaveMinute +// ); +// System.out.println(1111); +// // 如打卡状态为正常,检查是否有异常出入时间 +// if (attStatus == 1 && c.getAttStatus() != null && c.getAttStatus() == 8) { +// attStatus = 8; // 异常 +// boolean b = DateTimeHelper.compareTime2(c.getAttCurrentTime(), c.getAbnormalAttTime()); +// String time = ""; +// String address = ""; +// if (b) { +// time = c.getAttCurrentTime() + " " + c.getAbnormalAttTime(); +// address = c.getAttAddress() + " " + c.getAbnormalAttAddress(); +// } else { +// time = c.getAbnormalAttTime() + " " + c.getAttCurrentTime(); +// address = c.getAbnormalAttAddress() + " " + c.getAttAddress(); +// } +// c.setAttCurrentTime(time); +// c.setAttAddress(address); +// } +// System.out.println(2222); +// c.setAttStatus(attStatus); +// }); +// } +// +// +// /** +// * 计算时间差并返回状态 +// * +// * @param attType 考勤类型 +// * @param attTime 考勤时间 +// * @param standardTime 上、下班时间 +// * @param lateThreshold 迟到、早退时间 +// * @param absenteeismThreshold 旷工时间 +// * @return 考勤状态 +// */ +// private int calculateStatus(String attType, String attTime, String standardTime, +// long lateThreshold, long absenteeismThreshold) { +// int status = 1; +// // 创建两个时间点 +// Date date1 = DateUtils.parseDate(DateUtils.getYyyyMmDd(attTime) + " " + standardTime); +// Date date2 = DateUtils.parseDate(attTime); +// if ("2".equals(attType)) { +// String startTime = DateUtils.getYyyyMmDd(attTime) + " 00:00:00"; +// String endTime = DateUtils.getYyyyMmDd(attTime) + " 04:59:59"; +// if (DateUtils.getTimeIsRange(attTime, startTime, endTime)) { +// date1 = DateUtils.parseDate(DateUtils.getAfterDate(DateUtils.getYyyyMmDd(attTime)) + " " + standardTime); +// } +// } +// if ("1".equals(attType)) { // 上班打卡 +// // 计算时间差 +// // 减 1 原因:30上班,30:59不算迟到,类似于默认可以迟到一分钟 +// double difference = (date2.getTime() - date1.getTime()) / 60000.0 - 1; +// if (difference > 0) { +// if (difference > absenteeismThreshold) { +// status = 3; // 旷工 +// } else if (difference > lateThreshold) { +// status = 2; // 迟到 +// } +// } +// } else if ("2".equals(attType)) { // 下班打卡 +// // 计算时间差 +// double difference = (date2.getTime() - date1.getTime()) / 60000.0; +// if (difference < 0) { +// if (Math.abs(difference) > lateThreshold) { +// status = 4; // 早退 +// } +// if (Math.abs(difference) > absenteeismThreshold) { +// status = 3; // 旷工 +// } +// } +// } +// return status; // 正常 +// } +// +// /** +// * 根据考勤数据生成报表数据 +// * +// * @param groupList 考勤组集合 +// */ +// public void createReportData(List groupList, String pushDate, int pushType) { +// //日报表查询 +// List dayReportList = attSourceDataDao.selectAttDayReport(pushDate); +// //日报表新增 +// attSourceDataDao.insertAttDayReport(dayReportList); +// List monthReportList = attSourceDataDao.selectAttMonthReport(pushDate); +// //人员对应出月出勤天数 +// monthReportList.forEach(c -> +// groupList.stream() +// .filter(v -> c.getGroupId() != null && c.getGroupId().equals(v.getGroupId())) +// .findFirst() +// .ifPresent(v -> c.setRequiredDays(v.getAttWorkDayBean().getRequiredDays())) +// ); +// //先将本月数据删除,重新生成 +// attSourceDataDao.deleteAttMonthReport(pushDate); +// //月报表新增 +// attSourceDataDao.insertAttMonthReport(monthReportList); +// } +// +// /** +// * 根据当前日期计算目标日期 +// * +// * @param now 当前日期时间 +// * @return 目标日期 +// */ +// public static LocalDate getTargetDate(LocalDateTime now) { +// // 获取当前日期的年份和月份 +// YearMonth currentYearMonth = YearMonth.from(now); +// +// // 获取当前日期的月初日期 +// LocalDate firstDayOfMonth = currentYearMonth.atDay(1); +// +// // 判断是否是当月 +// if (now.getMonth().equals(firstDayOfMonth.getMonth())) { +// // 如果是当月,返回当前日期的日期部分 +// return now.toLocalDate(); +// } else { +// // 如果是之前月份,返回该月份的最后一天 +// return currentYearMonth.atEndOfMonth(); +// } +// } +// +//} \ No newline at end of file diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/NewAttTask.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/NewAttTask.java index 46e13af..d256c4a 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/NewAttTask.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/att/tasks/NewAttTask.java @@ -1,20 +1,8 @@ package com.bonus.system.att.tasks; -import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; -import com.bonus.common.core.utils.DateTimeHelper; -import com.bonus.common.core.utils.DateUtils; -import com.bonus.system.att.dao.AttGroupDao; -import com.bonus.system.att.dao.AttSourceDataDao; -import com.bonus.system.att.entity.*; import com.bonus.system.att.service.AttCalService; -import com.bonus.system.att.utils.AddressCoordinateFormatUtil; -import com.bonus.system.att.utils.AttTimeUtil; -import com.bonus.system.att.utils.WorkdayCalculator; -import com.bonus.system.holiday.dao.HolidayDao; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.beanutils.BeanUtils; -import org.mybatis.spring.SqlSessionTemplate; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; @@ -22,18 +10,8 @@ import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import javax.annotation.Resource; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; /** * @author zys @@ -52,7 +30,6 @@ public class NewAttTask { * 考勤模版数据定时器 凌晨10分启动一次,一天仅仅一次 */ @Scheduled(cron = "0 10 0 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getAttTempDataTask() { log.info("--------考勤模版数据定时器开启------"); @@ -68,7 +45,6 @@ public class NewAttTask { * 2.考勤数据应用(步骤一:考勤数据更新) */ @Scheduled(cron = "0 0 5-23 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getAttDataPullTask() { log.info("--------数据拉取(考勤)定时器开启------"); @@ -85,7 +61,6 @@ public class NewAttTask { * 每天晚上22点,将下班未打卡置为旷工 */ @Scheduled(cron = "0 0 12,22 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getAbsenteeismDataTask() { log.info("--------旷工判断定时器开启------"); @@ -100,7 +75,6 @@ public class NewAttTask { * 每天7点将昨天数据更新一下 */ @Scheduled(cron = "0 0 7 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getYesterdayAttDataTask() { log.info("--------昨日下班卡更新定时器开启------"); @@ -109,16 +83,16 @@ public class NewAttTask { // 格式化输出 String yesterdayStr = yesterday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); updateAttData(yesterdayStr,2); - //日报表更新 TODO + //日报表更新 + insertDayReportData(yesterdayStr); log.info("--------昨日下班卡更新定时器完毕------"); } /** * 请假数据应用--法假 - * 每天更新一次一点更新 + * 每天更新一次,1点更新 */ @Scheduled(cron = "0 0 1 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getLegalHolidayDataTask() { log.info("--------请假数据应用--法假定时器开启------"); @@ -132,7 +106,6 @@ public class NewAttTask { * 每天更新两次上午8点,下午18点(45天前数据) */ @Scheduled(cron = "0 0 8,18 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getLeaveDataTask() { log.info("--------请假数据应用--请假定时器开启------"); @@ -147,7 +120,6 @@ public class NewAttTask { * 6点10分开始,一小时更新一次 */ @Scheduled(cron = "0 10 6-23 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getDayReportDataTask() { log.info("--------报表数据生成--日报表定时器开启------"); @@ -162,7 +134,6 @@ public class NewAttTask { * 月初生成,之后修改 */ @Scheduled(cron = "0 15 1 1 * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getMonthReportDataTempTask() { log.info("--------报表数据生成--月报表定时器开启------"); @@ -176,7 +147,6 @@ public class NewAttTask { * 每日数据变化修改之后修改 */ @Scheduled(cron = "0 0 8,10,17,19,23 * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 10) @Async public void getMonthReportDataTask() { log.info("--------报表数据生成--月报表定时器开启------"); 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 ca56d06..cac22e0 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 @@ -12,6 +12,7 @@ import com.bonus.system.att.dao.WechatPushDao; import com.bonus.system.att.entity.AttFaceBean; import com.bonus.system.att.entity.AttSourceDataBean; import com.bonus.system.att.service.AttCalService; +import com.bonus.system.att.utils.AddressCoordinateFormatUtil; import com.bonus.system.att.utils.AttTimeUtil; import com.bonus.system.att.utils.DistanceCalculator; import com.bonus.system.att.utils.IpAndPathConfig; @@ -55,7 +56,7 @@ public class WechatTasks { * 人员基础数据同步定时器 */ // @Scheduled(cron = "0 0/10 * * * ?") -// @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 30) + @Scheduled(initialDelay = 60000, fixedDelay = 60000 * 30) @Async public void pushPersonTask() { log.info("--------人员基础数据同步定时器开启------"); @@ -83,7 +84,7 @@ public class WechatTasks { /** * 休假出差数据同步定时器 */ -// @Scheduled(initialDelay = 60000 * 2, fixedDelay = 60000 * 30) +// @Scheduled(initialDelay = 600 * 2, fixedDelay = 60000 * 30) @Async public void leaveTask() { log.info("--------休假出差数据定时器开启------"); @@ -107,18 +108,20 @@ public class WechatTasks { bean.setOrgId(orgInfo.getId()); bean.setOrgName(orgInfo.getOrgName()); } - String jsonStr2 = FastJsonHelper.beanToJsonStr(bean); if(bean.getId() != 0L){ //修改的数据 dao.updateWechatLeave(bean); }else{ //首次推送的数据 - dao.insertWebLeave(bean); + int i = dao.insertWebLeave(bean); //根据uuid将小程序id换成考勤端id + //返回了id,不能在前面生成 + String jsonStr2 = FastJsonHelper.beanToJsonStr(bean); String method2 = "updateWechatLeave"; String string2 = httpPost(method2, jsonStr2); } //将所有数据同步限制解除 + String jsonStr2 = FastJsonHelper.beanToJsonStr(bean); String method2 = "updateWechatIsSync"; String string3 = httpPost(method2, jsonStr2); } @@ -166,7 +169,7 @@ public class WechatTasks { /** * 考勤数据同步定时器 */ -// @Scheduled(initialDelay = 6000 * 3, fixedDelay = 60000 * 30) + @Scheduled(initialDelay = 6000 * 3, fixedDelay = 60000 * 30) @Async public void wechatAttTask() { log.info("--------考勤数据定时器开启------"); @@ -202,6 +205,21 @@ public class WechatTasks { //外勤 bean.setIsOutsideAtt("1"); } + //省内省外 + String address; + String province; + try { + JSONObject result = AddressCoordinateFormatUtil. + coordinateToAddress2(bean.getAttLon(), bean.getAttLat()); + address = result.getString("formatted_address"); + province = result.getJSONObject("addressComponent").getString("province"); + } catch (Exception e) { + e.printStackTrace(); + address = "地址未转化成功"; + province = "地址未转化成功"; + } + bean.setAttAddress(address); + bean.setProvince(province); }); //新增数据 //新增考勤到考勤来源表(数据过多时分批次插入) @@ -387,8 +405,8 @@ public class WechatTasks { MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); RequestBody body = null; try { -// body = RequestBody.create(mediaType, "username=15240004260&password=GZkq@123456!"); - body = RequestBody.create(mediaType, "username=" + AESCBCUtil.encrypt("15240004260wechat") + "&password=" + AESCBCUtil.encrypt("GZkq@123456!")); + body = RequestBody.create(mediaType, "username=15240004260wechat&password=GZkq@123456!"); +// body = RequestBody.create(mediaType, "username=" + AESCBCUtil.encrypt("15240004260wechat") + "&password=" + AESCBCUtil.encrypt("GZkq@123456!")); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/bonus-modules/bonus-system/src/main/resources/mapper/att/AttSourceDataMapper.xml b/bonus-modules/bonus-system/src/main/resources/mapper/att/AttSourceDataMapper.xml index 8044270..057c2a5 100644 --- a/bonus-modules/bonus-system/src/main/resources/mapper/att/AttSourceDataMapper.xml +++ b/bonus-modules/bonus-system/src/main/resources/mapper/att/AttSourceDataMapper.xml @@ -7,10 +7,10 @@ replace into att_source_data(name, id_number, org_id, org_name, att_current_day, - att_current_time, att_type, att_address, province, att_lon, att_lat, data_source, remark) + att_current_time, att_type, att_address, province,is_outside_att, att_lon, att_lat, data_source, remark) values (#{params.name}, #{params.idNumber}, #{params.orgId}, #{params.orgName}, #{params.attCurrentDay}, #{params.attCurrentTime}, #{params.attType}, - #{params.attAddress}, #{params.province}, #{params.attLon}, #{params.attLat}, #{params.dataSource}, + #{params.attAddress}, #{params.province},#{params.isOutsideAtt}, #{params.attLon}, #{params.attLat}, #{params.dataSource}, #{params.remark}) @@ -93,8 +93,10 @@ update att_data set att_current_time = #{params.attCurrentTime}, - att_address = #{params.attAddress}, province = #{params.province}, att_lon = #{params.attLon}, att_lat = - #{params.attLat}, + att_address = #{params.attAddress}, province = #{params.province}, + is_outside_att = #{params.isOutsideAtt}, + att_lon = #{params.attLon}, + att_lat = #{params.attLat}, data_source = #{params.dataSource}, error_remake = #{params.remark}, att_status = CASE @@ -107,8 +109,10 @@ AND att_current_day = #{params.attCurrentDay} and att_type = #{params.attType}; update att_data_update set att_current_time = #{params.attCurrentTime}, - att_address = #{params.attAddress}, province = #{params.province}, att_lon = #{params.attLon}, att_lat = - #{params.attLat}, + att_address = #{params.attAddress}, province = #{params.province}, + is_outside_att = #{params.isOutsideAtt}, + att_lon = #{params.attLon}, + att_lat = #{params.attLat}, data_source = #{params.dataSource}, error_remake = #{params.remark}, att_status = CASE @@ -377,7 +381,6 @@ LEFT JOIN att_setting_history ag ON ag.user_id = su.user_id AND ag.current_day = #{pushDate} LEFT JOIN att_group g ON g.id = ag.group_id; - - SELECT distinct - su.user_id, - su.user_name, - su.phone, - su.`password`, - IF(applied_face is null,1,su.is_face) as isFace, - pd.org_id, - IF(pd.org_id IS NOT NULL, 1, 0) isPd, - su.update_time, - su.open_id - FROM sys_user su - LEFT JOIN ( - SELECT gp.user_id,gp.org_id - FROM att_group g - LEFT JOIN att_group_person_relation gp on g.id = gp.group_id - WHERE g.is_active = 1 and g.att_type = 2 - ) pd ON pd.user_id = su.user_id - LEFT JOIN sys_user_face sw ON sw.user_id = su.user_id - WHERE is_active = '1' - GROUP BY user_id + SELECT DISTINCT + su.user_id, + su.user_name, + su.phone, + su.`password`, + IF + ( applied_face IS NULL, 1, su.is_face ) AS isFace, + suo.org_id, + IF + ( pd.user_id IS NOT NULL, 1, 0 ) isPd, + su.update_time, + su.open_id + FROM + sys_user su + LEFT JOIN sys_user_org suo ON suo.user_id = su.user_id + AND suo.is_active = 1 + LEFT JOIN ( + SELECT + gp.user_id + FROM + att_group g + LEFT JOIN att_group_person_relation gp ON g.id = gp.group_id + WHERE + g.is_active = 1 + AND g.att_type = 2 + ) pd ON pd.user_id = su.user_id + LEFT JOIN sys_user_face sw ON sw.user_id = su.user_id + WHERE + su.is_active = '1' + GROUP BY + user_id