From ce5f8a87bb5d411bae67c39b269d879677bb98da Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期日, 08 十一月 2026 19:29:25 +0800
Subject: [PATCH] feat(hrm): 请假导入、加班代申请、批量排班与考勤应出勤重算

---
 yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceSummaryServiceImpl.java |   74 +++++++++++++++++++++++++++++++++----
 1 files changed, 66 insertions(+), 8 deletions(-)

diff --git a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceSummaryServiceImpl.java b/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceSummaryServiceImpl.java
index 67eb1ef..dfe2a24 100644
--- a/yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/attendance/HrmAttendanceSummaryServiceImpl.java
+++ b/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>()
-                .eqIfPresent(HrmAttendanceSummaryDO::getUserId, pageReqVO.getUserId())
-                .eqIfPresent(HrmAttendanceSummaryDO::getDeptId, pageReqVO.getDeptId())
-                .eqIfPresent(HrmAttendanceSummaryDO::getYearMonth, pageReqVO.getYearMonth())
-                .orderByDesc(HrmAttendanceSummaryDO::getYearMonth)
-                .orderByAsc(HrmAttendanceSummaryDO::getDeptId));
+        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][鑰冨嫟姹囨��({}) 骞存湀({}) 鏃犳硶瑙f瀽锛岃烦杩囬噸绠梋",
+                        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);
+                }
+            }
+        }
     }
 
 }
\ No newline at end of file

--
Gitblit v1.9.3