package com.ruoyi.staff.task; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.staff.dto.PerformanceShiftAddDto; import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper; import com.ruoyi.staff.mapper.PersonalShiftMapper; import com.ruoyi.staff.mapper.StaffOnJobMapper; import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig; import com.ruoyi.staff.pojo.PersonalAttendanceRecords; import com.ruoyi.staff.pojo.StaffOnJob; import com.ruoyi.staff.service.PersonalAttendanceRecordsService; import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper; import com.ruoyi.staff.service.PersonalShiftService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.time.temporal.TemporalAdjusters; import java.time.temporal.WeekFields; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; /** * 个人考勤记录定时任务 * * @author 芯导软件(江苏)有限公司 * @since 2026-02-09 */ @Slf4j @Component public class PersonalAttendanceRecordsTask { @Autowired private PersonalAttendanceRecordsMapper personalAttendanceRecordsMapper; @Autowired private PersonalAttendanceRecordsService personalAttendanceRecordsService; @Autowired private PersonalAttendanceLocationConfigMapper personalAttendanceLocationConfigMapper; @Autowired private StaffOnJobMapper staffOnJobMapper; @Autowired private PersonalShiftService personalShiftService; /** * 每天凌晨生成昨日的缺勤记录 * 定时任务:每天凌晨1点执行 * 排除今天刚入职的员工 */ @Scheduled(cron = "0 0 1 * * ?") public void generateAbsenceRecords() { try { // 获取昨日日期 LocalDate yesterday = LocalDate.now().minusDays(1); // 直接查询昨天没有考勤记录的在职员工(排除今天刚入职的) LocalDateTime todayStart = LocalDate.now().atStartOfDay(); List staffWithoutAttendance = personalAttendanceRecordsMapper.selectStaffWithoutAttendanceRecordBeforeTime(yesterday, todayStart); // 遍历没有考勤记录的员工,生成缺勤记录 for (StaffOnJob staff : staffWithoutAttendance) { try { boolean exists = personalAttendanceRecordsMapper.existsAttendanceRecord(staff.getId(), yesterday); if (exists) { continue; } PersonalAttendanceRecords absenceRecord = new PersonalAttendanceRecords(); absenceRecord.setStaffOnJobId(staff.getId()); absenceRecord.setDate(yesterday); absenceRecord.setStatus(4); // 设置状态为缺勤 absenceRecord.setRemark("系统自动生成-缺勤"); absenceRecord.setCreateTime(LocalDateTime.now()); absenceRecord.setUpdateTime(LocalDateTime.now()); absenceRecord.setTenantId(staff.getTenantId()); personalAttendanceRecordsService.save(absenceRecord); } catch (Exception e) { log.error("为员工{}生成缺勤记录失败:{}", staff.getStaffName(), e.getMessage(), e); } } log.info("昨日缺勤记录生成完成"); } catch (Exception e) { log.error("生成昨日缺勤记录任务执行失败:{}", e.getMessage(), e); } } /** * 定时任务,每个月1号的00:00:00给下一个月排班 * 给每个人都进行排班(默认早班) */ @Scheduled(cron = "0 10 0 1 * ?") private void timerCreateSchedule() { log.info("开始给每个人进行排班,默认早班======start"); PerformanceShiftAddDto performanceShiftAddDto = new PerformanceShiftAddDto(); //查询所有班次(打卡规则) List personalAttendanceLocationConfigs = personalAttendanceLocationConfigMapper.selectList(null); if (CollectionUtil.isEmpty(personalAttendanceLocationConfigs)){ return; } performanceShiftAddDto.setPersonalAttendanceLocationConfigId(personalAttendanceLocationConfigs.get(0).getId()); //在职人员 List staffOnJobs = staffOnJobMapper.selectList(Wrappers.lambdaQuery().eq(StaffOnJob::getStaffState, 1)); if (CollectionUtil.isEmpty(staffOnJobs)){ return; } String userIds = staffOnJobs.stream().map(user -> user.getId().toString()).distinct().collect(Collectors.joining(",")); performanceShiftAddDto.setStaffOnJobId(userIds); //周次--当月所有 // 获取当前日期 LocalDate today = LocalDate.now(ZoneId.of(ZoneId.SHORT_IDS.get("CTT"))).plusMonths(1); // 获取本月的第一天和最后一天 LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth()); LocalDate lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth()); // 获取周字段信息(根据区域设置) WeekFields weekFields = WeekFields.of(Locale.getDefault()); // 获取本月第一天的周一 LocalDate startOfWeek = firstDayOfMonth.with(TemporalAdjusters.previousOrSame(weekFields.getFirstDayOfWeek())); // 遍历本月所有天数,找出每周的第一天和最后一天 LocalDate endOfWeek; while (startOfWeek.isBefore(firstDayOfMonth.plusMonths(1))) { endOfWeek = startOfWeek.plusDays(6); LocalDateTime startDateTime = LocalDateTime.of(startOfWeek, LocalTime.MIDNIGHT); LocalDateTime endDateTime = LocalDateTime.of(endOfWeek, LocalTime.MIDNIGHT); log.info("Week starts on {} and ends on {}", startDateTime, endDateTime); performanceShiftAddDto.setStartWeek(startDateTime); performanceShiftAddDto.setEndWeek(endDateTime); personalShiftService.performanceShiftAdd(performanceShiftAddDto); startOfWeek = startOfWeek.plusWeeks(1); } log.info("排班结束======end"); } }