Parcourir la source

使用加权平均解决板块周日报完成率计算错误的问题

zhangjq il y a 3 semaines
Parent
commit
6981089c66

+ 3 - 0
zjugis-module-adm/zjugis-module-adm-biz/src/main/java/com/zjugis/module/adm/controller/admin/report/vo/statistics/DeptReportStatisticRespVO.java

@@ -41,6 +41,9 @@ public class DeptReportStatisticRespVO {
     @Schema(description = "填写率")
     private Double fillRate;
 
+    @Schema(description = "部门人数")
+    private Integer peopleCount = 0;
+
 
 
     public DeptReportStatisticRespVO(String deptId, String deptName, String parentId, Short reportYear, Short reportMonth, Integer shouldFilledCount, Integer filledCount) {

+ 94 - 80
zjugis-module-adm/zjugis-module-adm-biz/src/main/java/com/zjugis/module/adm/service/report/ReportServiceImpl.java

@@ -207,9 +207,9 @@ public class ReportServiceImpl implements ReportService {
         queryWrapper.eq("REPORT.IS_TEMP", 0);
         queryWrapper.eq("RECEIVE.DELETED", 0);
         queryWrapper.eq("RECEIVE.RECEIVE_USER_ID", SecurityFrameworkUtils.getLoginUserId());
-        queryWrapper.eq(StrUtil.isNotBlank(reqVO.getReportType()),"REPORT.REPORT_TYPE", reqVO.getReportType());
+        queryWrapper.eq(StrUtil.isNotBlank(reqVO.getReportType()), "REPORT.REPORT_TYPE", reqVO.getReportType());
         queryWrapper.orderByDesc("REPORT.UPDATE_TIME");
-        if(CollectionUtil.isNotEmpty(reqVO.getUserIds())){
+        if (CollectionUtil.isNotEmpty(reqVO.getUserIds())) {
             queryWrapper.in("REPORT.USER_ID", reqVO.getUserIds());
         }
         if (reqVO.getReportYear() != null) {
@@ -505,7 +505,7 @@ public class ReportServiceImpl implements ReportService {
                     Long leaveCount = weekLeaveMap.get(date).stream().collect(Collectors.counting());
                     List<WorkdayDO> workdayList = workDayCount.get(date) == null ? new ArrayList<>() : workDayCount.get(date);
                     //如果该周请假的次数 >= 该周工作日 * 2 (上下午),则说明该周都请假
-                    if (leaveCount >= workdayList.size() * 2 && workdayList.size()>0) {
+                    if (leaveCount >= workdayList.size() * 2 && workdayList.size() > 0) {
                         allLeaveWeekSet.add(date);
                     }
                 }
@@ -636,7 +636,7 @@ public class ReportServiceImpl implements ReportService {
             // 如果入职时间在本月 ,需要重新计算应填
             LocalDateTime rgssj;
             StaffRecordSDO staffRecords = userMap.get(staff.getId());
-            if(staffRecords != null) {
+            if (staffRecords != null) {
                 rgssj = staffRecords.getRgssj();
 
                 if (rgssj != null && rgssj.getYear() == year && rgssj.getMonthValue() == month) {
@@ -671,7 +671,6 @@ public class ReportServiceImpl implements ReportService {
     }
 
 
-
     /**
      * 过滤掉在指定年月时尚未入职的用户
      *
@@ -702,6 +701,7 @@ public class ReportServiceImpl implements ReportService {
                 })
                 .collect(Collectors.toList());
     }
+
     public String sendFillRemind(Short year, Short month) {
         ReportStatisticReqDTO reportStatisticReqDTO = new ReportStatisticReqDTO();
         reportStatisticReqDTO.setYear(year);
@@ -766,12 +766,14 @@ public class ReportServiceImpl implements ReportService {
         //获取每个用户周报统计结果
         List<ReportStatisticRespVO> userWeekReportStatistics = this.getReportStatisticsList(reportStatisticReqDTO.setReportType("weekly"));
         //获取每个部门周报统计结果
-        Map<String, DeptReportStatisticRespVO> weekReportStatisticsGroup = this.aggregateDeptReportStatistics(userWeekReportStatistics, deptList, year, month, dailyReportDeptIdList);
+        Map<String, DeptReportStatisticRespVO> weekReportStatisticsGroup = this.aggregateDeptReportStatistics(userWeekReportStatistics, deptList, year, month);
 
         //获取每个用户日报统计结果
         List<ReportStatisticRespVO> userDailyReportStatistics = this.getReportStatisticsList(reportStatisticReqDTO.setReportType("daily"));
         //获取每个部门日报统计结果
-        Map<String, DeptReportStatisticRespVO> dailyReportStatisticsGroup = this.aggregateDeptReportStatistics(userDailyReportStatistics, deptList, year, month, dailyReportDeptIdList);
+        Map<String, DeptReportStatisticRespVO> dailyReportStatisticsGroup = this.aggregateDeptReportStatistics(userDailyReportStatistics, deptList, year, month);
+
+        Map<String, Set<String>> deptIdMap = this.collectSubtreeIds(deptList);
 
         //统计每个部门的周日报完成率
         List<DeptReportStatisticRespVO> voList = new ArrayList<>();
@@ -784,23 +786,58 @@ public class ReportServiceImpl implements ReportService {
             vo.setParentId(dept.getParentId());
 
             DeptReportStatisticRespVO reportStatistic = null;
-            if (dailyReportDeptIdList.contains(dept.getId())) {
-                reportStatistic = dailyReportStatisticsGroup.get(dept.getId());
-                vo.setReportType("daily");
+
+            String currentDeptId = dept.getId();
+            Set<String> childDeptIdList = deptIdMap.get(currentDeptId);
+
+            if (childDeptIdList.size() <= 1) {
+                //如果没有子部门或子部门列表中只有自己 直接使用结果
+                if (dailyReportDeptIdList.contains(currentDeptId)) {
+                    reportStatistic = dailyReportStatisticsGroup.get(currentDeptId);
+                    vo.setReportType("daily");
+                } else {
+                    reportStatistic = weekReportStatisticsGroup.get(currentDeptId);
+                    vo.setReportType("weekly");
+                }
+                if (reportStatistic != null) {
+                    vo.setShouldFilledCount(reportStatistic.getShouldFilledCount());
+                    vo.setFilledCount(reportStatistic.getFilledCount());
+                    vo.setNotFilledCount(reportStatistic.getNotFilledCount());
+                    vo.setFillRate(reportStatistic.getFillRate());
+                    vo.setPeopleCount(reportStatistic.getPeopleCount());
+                }
             } else {
-                reportStatistic = weekReportStatisticsGroup.get(dept.getId());
-                vo.setReportType("weekly");
-            }
+                //如果包含子集部门,则使用按人头加权平均法  部门完成率 = (部门1人数*部门1完成率 +  部门2人数*部门2完成率 +…………)/ 各部门人数总和
+                Integer deptPeopleTotal = 0;
+                Double fz = 0.0;
+                for (String childDeptId : childDeptIdList) {
+                    if (currentDeptId.equals(childDeptId)) continue;
+
+                    if (dailyReportDeptIdList.contains(childDeptId)) {
+                        reportStatistic = dailyReportStatisticsGroup.get(childDeptId);
+
+                    } else {
+                        reportStatistic = weekReportStatisticsGroup.get(childDeptId);
+                    }
+                    if (reportStatistic != null) {
+                        Integer childPeopleCount = reportStatistic.getPeopleCount();
+
+                        Double childFz = reportStatistic.getFillRate() * childPeopleCount;
+                        deptPeopleTotal += childPeopleCount;
+                        fz += childFz;
+                    }
+                }
+                if (reportStatistic != null) {
+                    Double fillRate = fz / (deptPeopleTotal * 1.0);
+                    vo.setFillRate(fillRate);
+                    vo.setPeopleCount(deptPeopleTotal);
+                }
 
-            if (reportStatistic != null) {
-                vo.setShouldFilledCount(reportStatistic.getShouldFilledCount());
-                vo.setFilledCount(reportStatistic.getFilledCount());
-                vo.setNotFilledCount(reportStatistic.getNotFilledCount());
-                vo.setFillRate(reportStatistic.getFillRate());
             }
+
+
             voList.add(vo);
         }
-
         return voList;
     }
 
@@ -812,10 +849,9 @@ public class ReportServiceImpl implements ReportService {
      * @param deptList              部门列表
      * @param year                  年份
      * @param month                 月份
-     * @param dailyReportDeptIdList 填写日报的部门列表
      * @return
      */
-    public Map<String, DeptReportStatisticRespVO> aggregateDeptReportStatistics(List<ReportStatisticRespVO> userReportStatistics, List<DeptRespDTO> deptList, Short year, Short month, List<String> dailyReportDeptIdList) {
+    public Map<String, DeptReportStatisticRespVO> aggregateDeptReportStatistics(List<ReportStatisticRespVO> userReportStatistics, List<DeptRespDTO> deptList, Short year, Short month) {
         //第一步:合并用户统计到部门统计(只能统计到直属部门)
         Map<String, DeptReportStatisticRespVO> deptStatisticMap = new HashMap<>();
         for (ReportStatisticRespVO vo : userReportStatistics) {
@@ -830,85 +866,63 @@ public class ReportServiceImpl implements ReportService {
             deptStat.setFilledCount(deptStat.getFilledCount() + vo.getFilledCount());
             deptStat.setFillRate(deptStat.getShouldFilledCount() == 0 ? null
                     : deptStat.getFilledCount() * 1.0 / deptStat.getShouldFilledCount() > 1 ? 1 : deptStat.getFilledCount() * 1.0 / deptStat.getShouldFilledCount());
-        }
-        List<DeptReportStatisticRespVO> deptStatisticValue = deptStatisticMap.values().stream().collect(Collectors.toList());
-
-        //第二步:合并部门统计到部门统计(可以统计到子部门)
-        //获取每个部门的子部门id(包含自己)列表
-        Map<String, List<String>> deptIdMap = this.collectSubtreeIds(deptList);
-        //遍历部门id,找到有子节点的部门,并计算其子节点的统计值
-        for (String deptId : deptIdMap.keySet()) {
-            List<String> childDeptIdList = deptIdMap.get(deptId);
-            if (childDeptIdList.size() <= 1) {
-                //如果没有子部门或子部门列表中只有自己,不再重新计算,直接使用第一步结果
-                continue;
-            }
-            //TODO 需求 板块统计去除市场部门,如“空间信息研究院”完成率中要去掉“空间信息浙江市场部”
-            //子级去除市场部门
-            List<String> removeMarketChildDeptIdList = childDeptIdList.stream().filter(item -> !dailyReportDeptIdList.contains(item)).collect(Collectors.toList());
-
-            List<DeptReportStatisticRespVO> childDeptList = deptStatisticValue.stream().filter(c -> removeMarketChildDeptIdList.contains(c.getDeptId())).collect(Collectors.toList());
-            // 使用Stream进行统计 应填和已填
-            int shouldFilledCount = (int) childDeptList.stream().mapToLong(DeptReportStatisticRespVO::getShouldFilledCount).sum();
-            int filledCount = (int) childDeptList.stream().mapToLong(DeptReportStatisticRespVO::getFilledCount).sum();
-            DeptReportStatisticRespVO vo = new DeptReportStatisticRespVO(deptId, shouldFilledCount, filledCount);
-            deptStatisticMap.put(deptId, vo);
+
+            // 累加部门人数
+            deptStat.setPeopleCount(deptStat.getPeopleCount() + 1); // 每个用户统计结果代表一个人
         }
         return deptStatisticMap;
     }
 
 
-    /**
-     * 获取部门及子部门id
-     *
-     * @param deptList 部门列表
-     * @return key是部门id,value是所有子集节点id(包含自己)列表
-     */
-    public static Map<String, List<String>> collectSubtreeIds(List<DeptRespDTO> deptList) {
+    public static Map<String, Set<String>> collectSubtreeIds(List<DeptRespDTO> deptList) {
         // 创建一个部门id和部门的映射,用于快速查找部门对象
         Map<String, DeptRespDTO> idToDeptMap = new HashMap<>();
         for (DeptRespDTO dept : deptList) {
             idToDeptMap.put(dept.getId(), dept);
         }
 
-        // 结果集,key是部门id,value是所有子集节点id列表
-        Map<String, List<String>> result = new HashMap<>();
-
-        // 遍历每个部门,并递归地收集子集节点
+        // 构建父子关系图
+        Map<String, List<String>> childrenMap = new HashMap<>();
+        String rootId = null;
         for (DeptRespDTO dept : deptList) {
-            collectSubtreeIdsRecursive(dept, idToDeptMap, result);
+            if (dept.getParentId() == null) { // 找到根节点
+                rootId = dept.getId();
+            }
+            childrenMap.computeIfAbsent(dept.getParentId(), k -> new ArrayList<>()).add(dept.getId());
         }
-        return result;
-    }
 
-    /**
-     * 递归地收集子集节点
-     *
-     * @param dept        部门
-     * @param idToDeptMap 部门id和部门映射Map
-     * @param result      结果集
-     */
-    private static void collectSubtreeIdsRecursive(DeptRespDTO dept, Map<String, DeptRespDTO> idToDeptMap, Map<String, List<String>> result) {
-        // 获取当前部门的ID,并添加到结果映射中(如果尚未添加)
-        String deptId = dept.getId();
-        result.computeIfAbsent(deptId, k -> new ArrayList<>()).add(deptId);
+        // 结果集,key是部门id,value是所有子集节点id(包含自己)列表
+        Map<String, Set<String>> result = new HashMap<>();
 
-        // 递归地处理子部门
-        String parentId = dept.getParentId();
-        if (parentId != null) { // 确保parentId不是null,避免无限循环(理论上应该是这样,但最好检查)
-            DeptRespDTO parentDept = idToDeptMap.get(parentId);
-            if (parentDept != null) { // 确保找到了父部门
-                // 如果父部门的子集列表尚未初始化,则初始化它
-                result.computeIfAbsent(parentId, k -> new ArrayList<>());
-                // 将当前部门添加到父部门的子集列表中
-                result.get(parentId).add(deptId);
-                // 递归地处理父部门的所有其他子部门
-                collectSubtreeIdsRecursive(parentDept, idToDeptMap, result);
+        // 如果有根节点,则从根节点开始收集子树
+        if (rootId != null) {
+            dfsCollect(rootId, idToDeptMap, childrenMap, result);
+        } else {
+            // 如果没有明确的根节点,则对每一个节点作为根节点进行处理
+            for (String deptId : idToDeptMap.keySet()) {
+                if (!result.containsKey(deptId)) {
+                    dfsCollect(deptId, idToDeptMap, childrenMap, result);
+                }
             }
         }
+
+        return result;
     }
 
+    private static void dfsCollect(String deptId, Map<String, DeptRespDTO> idToDeptMap,
+                                   Map<String, List<String>> childrenMap, Map<String, Set<String>> result) {
+        // 初始化当前部门的结果集
+        Set<String> currentSet = result.computeIfAbsent(deptId, k -> new HashSet<>());
+        currentSet.add(deptId); // 添加自己
 
+        // 递归地处理子部门
+        List<String> children = childrenMap.getOrDefault(deptId, Collections.emptyList());
+        for (String childId : children) {
+            dfsCollect(childId, idToDeptMap, childrenMap, result);
+            // 将子部门及其所有子部门合并到当前部门的结果集中
+            currentSet.addAll(result.get(childId));
+        }
+    }
     /**
      * 获取报告工作量统计信息
      *