package com.ruoyi.staff.task;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.ruoyi.approve.mapper.HolidaySettingsMapper;
|
import com.ruoyi.approve.pojo.HolidaySettings;
|
import com.ruoyi.staff.dto.PerformanceShiftAddDto;
|
import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
|
import com.ruoyi.staff.mapper.PersonalAttendanceRecordsMapper;
|
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.service.PersonalShiftService;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Component;
|
|
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.stream.Collectors;
|
|
/**
|
* 个人考勤记录定时任务
|
*
|
* @author 芯导软件(江苏)有限公司
|
* @since 2026-02-09
|
*/
|
@Slf4j
|
@Component
|
@RequiredArgsConstructor
|
public class PersonalAttendanceRecordsTask {
|
|
private final PersonalAttendanceRecordsMapper personalAttendanceRecordsMapper;
|
private final PersonalAttendanceRecordsService personalAttendanceRecordsService;
|
private final PersonalAttendanceLocationConfigMapper personalAttendanceLocationConfigMapper;
|
private final StaffOnJobMapper staffOnJobMapper;
|
private final PersonalShiftService personalShiftService;
|
private final HolidaySettingsMapper holidaySettingsMapper;
|
|
/**
|
* 每天凌晨生成昨日的缺勤记录
|
* 定时任务:每天凌晨1点执行
|
* 排除今天刚入职的员工
|
*/
|
@Scheduled(cron = "0 0 1 * * ?")
|
public void generateAbsenceRecords() {
|
try {
|
// 获取昨日日期
|
LocalDate yesterday = LocalDate.now().minusDays(1);
|
|
// 周末、法定节假日是休息日,不生成缺勤记录
|
if (!isWorkingDay(yesterday)) {
|
log.info("昨日{}为周末或法定节假日,跳过缺勤记录生成", yesterday);
|
return;
|
}
|
|
// 直接查询昨天没有考勤记录的在职员工(排除今天刚入职的)
|
LocalDateTime todayStart = LocalDate.now().atStartOfDay();
|
List<StaffOnJob> 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);
|
}
|
}
|
|
/**
|
* 判断某天是否为工作日。
|
* 假期设置里“调休上班”(adjustment) 算工作日;其他假期(法定节假日等)算休息日;
|
* 没有配置假期的日期按自然周判断,周六、周日休息。
|
*/
|
private boolean isWorkingDay(LocalDate date) {
|
List<HolidaySettings> holidays = holidaySettingsMapper.selectList(
|
Wrappers.<HolidaySettings>lambdaQuery()
|
.eq(HolidaySettings::getStatus, "active")
|
.le(HolidaySettings::getStartDate, date)
|
.ge(HolidaySettings::getEndDate, date));
|
if (CollectionUtil.isNotEmpty(holidays)) {
|
return holidays.stream().anyMatch(h -> "adjustment".equals(h.getType()));
|
}
|
return date.getDayOfWeek().getValue() < 6;
|
}
|
|
/**
|
* 定时任务,每个月1号的00:00:00给下一个月排班
|
* 给每个人都进行排班(默认早班)
|
*/
|
@Scheduled(cron = "0 10 0 1 * ?")
|
private void timerCreateSchedule() {
|
log.info("开始给每个人进行排班,默认早班======start");
|
PerformanceShiftAddDto performanceShiftAddDto = new PerformanceShiftAddDto();
|
//查询所有班次(打卡规则)
|
List<PersonalAttendanceLocationConfig> personalAttendanceLocationConfigs = personalAttendanceLocationConfigMapper.selectList(null);
|
if (CollectionUtil.isEmpty(personalAttendanceLocationConfigs)){
|
return;
|
}
|
performanceShiftAddDto.setPersonalAttendanceLocationConfigId(personalAttendanceLocationConfigs.get(0).getId());
|
//在职人员
|
List<StaffOnJob> staffOnJobs = staffOnJobMapper.selectList(Wrappers.<StaffOnJob>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");
|
}
|
}
|