gaoluyang
6 小时以前 ef3cbc1c6882786e8218b08be3e52ea44587f03b
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceSummaryServiceImpl.java
@@ -1,15 +1,18 @@
package cn.iocoder.yudao.module.hrm.service.attendance;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceSummaryPageReqVO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceHolidayDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceRecordDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceSummaryDO;
import cn.iocoder.yudao.module.hrm.dal.dataobject.employee.HrmEmployeeDO;
import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceRecordMapper;
import cn.iocoder.yudao.module.hrm.dal.mysql.attendance.HrmAttendanceSummaryMapper;
import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceClockTypeEnum;
import cn.iocoder.yudao.module.hrm.enums.HrmAttendanceHolidayTypeEnum;
import cn.iocoder.yudao.module.hrm.service.employee.HrmEmployeeService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -18,9 +21,12 @@
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * 考勤统计汇总 Service 实现类
@@ -154,12 +160,28 @@
    /**
     * 计算应出勤天数(工作日数量)
     *
     * 一次取出区间内节假日配置,避免逐日查询。
     */
    private int calculateWorkDays(LocalDate startDate, LocalDate endDate) {
        Map<LocalDate, Integer> holidayTypeMap = attendanceHolidayService
                .getAttendanceHolidayListByDateRange(startDate, endDate)
                .stream()
                .collect(Collectors.toMap(HrmAttendanceHolidayDO::getDate, HrmAttendanceHolidayDO::getType,
                        (a, b) -> a));
        int workDays = 0;
        LocalDate current = startDate;
        while (!current.isAfter(endDate)) {
            if (attendanceHolidayService.isWorkDay(current)) {
            Integer holidayType = holidayTypeMap.get(current);
            boolean work;
            if (holidayType != null) {
                // 有节假日配置时按配置判断:休息日不算应出勤,工作日计入(含调休上班的周末)
                work = HrmAttendanceHolidayTypeEnum.WORK_DAY.getType().equals(holidayType);
            } else {
                DayOfWeek dayOfWeek = current.getDayOfWeek();
                work = dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
            }
            if (work) {
                workDays++;
            }
            current = current.plusDays(1);
@@ -167,8 +189,28 @@
        return workDays;
    }
    /**
     * 节假日配置变更后,已有汇总的应出勤天数会与最新配置不一致。
     * 查询汇总时按最新节假日重算一次并回写,保证「应出勤天数」始终关联节假日配置。
     */
    private void refreshWorkDaysOfMonth(String yearMonth) {
        if (StrUtil.isBlank(yearMonth)) {
            return;
        }
        try {
            YearMonth ym = YearMonth.parse(yearMonth);
            attendanceSummaryMapper.updateWorkDaysByYearMonth(yearMonth,
                    calculateWorkDays(ym.atDay(1), ym.atEndOfMonth()));
        } catch (Exception ex) {
            // 刷新失败不影响查询本身,记录日志即可
            log.warn("[refreshWorkDaysOfMonth][yearMonth({}) 刷新应出勤天数失败]", yearMonth, ex);
        }
    }
    @Override
    public PageResult<HrmAttendanceSummaryDO> getAttendanceSummaryPage(HrmAttendanceSummaryPageReqVO pageReqVO) {
        // 查询前按最新节假日重算该月应出勤天数
        refreshWorkDaysOfMonth(pageReqVO.getYearMonth());
        return attendanceSummaryMapper.selectPage(pageReqVO, new LambdaQueryWrapperX<HrmAttendanceSummaryDO>()
                .eqIfPresent(HrmAttendanceSummaryDO::getUserId, pageReqVO.getUserId())
                .eqIfPresent(HrmAttendanceSummaryDO::getDeptId, pageReqVO.getDeptId())
@@ -184,6 +226,8 @@
    @Override
    public List<HrmAttendanceSummaryDO> getDeptMonthlySummaryList(Long deptId, String yearMonth) {
        // 查询前按最新节假日重算该月应出勤天数
        refreshWorkDaysOfMonth(yearMonth);
        return attendanceSummaryMapper.selectListByDeptIdAndYearMonth(deptId, yearMonth);
    }