gaoluyang
5 天以前 ce5f8a87bb5d411bae67c39b269d879677bb98da
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceSummaryServiceImpl.java
@@ -1,6 +1,7 @@
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;
@@ -20,7 +21,10 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * 考勤统计汇总 Service 实现类
@@ -168,23 +172,77 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageResult<HrmAttendanceSummaryDO> getAttendanceSummaryPage(HrmAttendanceSummaryPageReqVO pageReqVO) {
        return attendanceSummaryMapper.selectPage(pageReqVO, new LambdaQueryWrapperX<HrmAttendanceSummaryDO>()
        PageResult<HrmAttendanceSummaryDO> pageResult = attendanceSummaryMapper.selectPage(pageReqVO,
                new LambdaQueryWrapperX<HrmAttendanceSummaryDO>()
                .eqIfPresent(HrmAttendanceSummaryDO::getUserId, pageReqVO.getUserId())
                .eqIfPresent(HrmAttendanceSummaryDO::getDeptId, pageReqVO.getDeptId())
                .eqIfPresent(HrmAttendanceSummaryDO::getYearMonth, pageReqVO.getYearMonth())
                .orderByDesc(HrmAttendanceSummaryDO::getYearMonth)
                .orderByAsc(HrmAttendanceSummaryDO::getDeptId));
        refreshWorkDays(pageResult.getList());
        return pageResult;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public HrmAttendanceSummaryDO getMonthlySummary(Long userId, String yearMonth) {
        return attendanceSummaryMapper.selectByUserIdAndYearMonth(userId, yearMonth);
        HrmAttendanceSummaryDO summary = attendanceSummaryMapper.selectByUserIdAndYearMonth(userId, yearMonth);
        if (summary != null) {
            refreshWorkDays(List.of(summary));
        }
        return summary;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<HrmAttendanceSummaryDO> getDeptMonthlySummaryList(Long deptId, String yearMonth) {
        return attendanceSummaryMapper.selectListByDeptIdAndYearMonth(deptId, yearMonth);
        List<HrmAttendanceSummaryDO> list = attendanceSummaryMapper.selectListByDeptIdAndYearMonth(deptId, yearMonth);
        refreshWorkDays(list);
        return list;
    }
    /**
     * 查询/导出时按“最新节假日配置”重算应出勤天数,并把变化的记录回写。
     *
     * 节假日配置可能在生成汇总之后被调整(如新增调休/法定假日),若只返回旧值,
     * 页面上的应出勤天数会与节假日配置长期不一致。
     */
    private void refreshWorkDays(List<HrmAttendanceSummaryDO> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        // 同一次请求内同一年月只计算一次
        Map<String, Integer> workDaysCache = new HashMap<>();
        for (HrmAttendanceSummaryDO summary : list) {
            if (StrUtil.isBlank(summary.getYearMonth())) {
                continue;
            }
            Integer expected;
            try {
                expected = workDaysCache.computeIfAbsent(summary.getYearMonth(), yearMonth -> {
                    YearMonth parsed = YearMonth.parse(yearMonth);
                    return calculateWorkDays(parsed.atDay(1), parsed.atEndOfMonth());
                });
            } catch (Exception e) {
                log.warn("[refreshWorkDays][考勤汇总({}) 年月({}) 无法解析,跳过重算]",
                        summary.getId(), summary.getYearMonth(), e);
                continue;
            }
            if (!Objects.equals(summary.getWorkDays(), expected)) {
                log.info("[refreshWorkDays][考勤汇总({}) 年月({}) 应出勤天数 {} -> {},按最新节假日配置回写]",
                        summary.getId(), summary.getYearMonth(), summary.getWorkDays(), expected);
                summary.setWorkDays(expected);
                try {
                    attendanceSummaryMapper.updateById(HrmAttendanceSummaryDO.builder()
                            .id(summary.getId()).workDays(expected).build());
                } catch (Exception e) {
                    // 回写失败不影响本次查询结果,保留内存中重算后的值
                    log.warn("[refreshWorkDays][考勤汇总({}) 应出勤天数回写失败]", summary.getId(), e);
                }
            }
        }
    }
}