Răsfoiți Sursa

pms 瑞恒日报 已填报 未填报逻辑优化 瑞都日报添加 简报 施工部门可选择 施工日期

zhangcl 1 zi în urmă
părinte
comite
d0d6143324

+ 3 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrddailyreport/vo/IotRdDailyReportSaveReqVO.java

@@ -179,6 +179,9 @@ public class IotRdDailyReportSaveReqVO {
     @Schema(description = "审批意见", example = "审核通过")
     private String opinion;
 
+    @Schema(description = "创建日期")
+    private LocalDateTime createTime;
+
     /**
      * 扩展字段
      */

+ 3 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrddailyreport/IotRdDailyReportServiceImpl.java

@@ -135,11 +135,13 @@ public class IotRdDailyReportServiceImpl implements IotRdDailyReportService {
                 createReqVO.setDeptId(deptId);
             }
         }
+        LocalDateTime createTime = createReqVO.getCreateTime();
         // 根据部门名称 当前日期 生成日报标题
         if (ObjUtil.isNotEmpty(createReqVO.getDeptId())) {
             DeptDO dept = deptService.getDept(createReqVO.getDeptId());
+            LocalDateTime tempDateTime = ObjUtil.isEmpty(createTime) ? LocalDateTime.now() : createTime;
             if (ObjUtil.isNotEmpty(dept)) {
-                String todayDateStr = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATE_PATTERN);
+                String todayDateStr = LocalDateTimeUtil.format(tempDateTime, DatePattern.NORM_DATE_PATTERN);
                 iotRdDailyReport.setReportName(dept.getName() + "/" + todayDateStr + "日报");
             }
         }

+ 238 - 155
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportServiceImpl.java

@@ -1766,66 +1766,56 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
             throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
         }
         List<IotRhDailyReportStatisticsVO> results = new ArrayList<>();
-        // 查询 瑞恒157l 所有存在设备的队伍
-        // 查询瑞恒下所有部门
-        // List<IotDeviceDO> devices = devices();
+        // 查询 瑞恒 157l 所有存在设备的队伍
         // 所有需要填报日报的 瑞恒 队伍集合
         Set<Long> deptIds = new HashSet<>();
-        /* devices.forEach(device -> {
-            deptIds.add(device.getDeptId());
-        }); */
 
         Set<Long> ids = new HashSet<>();
         ids = deptService.getChildDeptIdListFromCache(157l);
         ids.add(157l);
 
-        // 根据部门id集合查询所有部门信息
-        // 查询所有部门信息
-        // Map<Long, DeptDO> allDepts = deptService.getDeptMap(deptIds);
-        // 过滤后的所有部门信息
-        // Map<Long, DeptDO> filteredDepts = new HashMap<>();
-        // 过滤掉部门中的 ‘项目部’
-        /* if (CollUtil.isNotEmpty(allDepts)) {
-            allDepts.forEach((deptId, dept) -> {
-                // 将不属于 队伍 的组织部门过滤掉
-                if ("3".equals(dept.getType())) {
-                    filteredDepts.put(deptId, dept);
+        DeptListReqVO deptReqVO = new DeptListReqVO();
+        deptReqVO.setDeptIds(ids);
+        List<DeptDO> depts = deptService.getDeptList(deptReqVO);
+        // 项目部类型的部门id集合
+        Set<Long> projectDeptIds = new HashSet<>();
+        // 队伍类型的部门id集合
+        Set<Long> teamDeptIds = new HashSet<>();
+        depts.forEach(dept -> {
+            // 查找需要统计的项目部
+            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
+                projectDeptIds.add(dept.getId());
+            }
+        });
+        depts.forEach(dept -> {
+            // 队伍类型的部门id集合
+            if ("3".equals(dept.getType()) && projectDeptIds.contains(dept.getParentId())) {
+                teamDeptIds.add(dept.getId());
+            }
+        });
+
+        // 筛选有设备的队伍部门
+        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
+        deviceReqVO.setDeptIds(new ArrayList<>(ids));
+        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
+        // 包含设备的部门id集合
+        Set<Long> deviceTeamIds = new HashSet<>();
+        if (CollUtil.isNotEmpty(devices)) {
+            devices.forEach(device -> {
+                if (teamDeptIds.contains(device.getDeptId())) {
+                    deviceTeamIds.add(device.getDeptId());
                 }
             });
-        } */
+        }
 
         // 瑞恒日报总数
-        Integer rhTotalCount = 0;
+        long rhTotalCount = 0;
+
         // 瑞恒已填报完成日报总数
         AtomicReference<Integer> rhFinishedCount = new AtomicReference<>(0);
         // 瑞恒未填报完成日报总数
         AtomicReference<Integer> rhUnfinishedCount = new AtomicReference<>(0);
 
-        // 以运行记录表中 指定 时间范围内的 名称中包含 ‘生产日报’ 工单的部门为基数
-        // 瑞鹰钻井 rq_iot_opeation_fill rq_iot_opeation_fill_order 关联查询
-        // 瑞鹰修井 需要结合 挂靠队伍 日报
-        IotOpeationFillPageReqVO fillReqVO = new IotOpeationFillPageReqVO();
-        fillReqVO.setCreateTime(reqVO.getCreateTime());
-        fillReqVO.setDeptIds(new ArrayList<>(ids));
-        List<IotOpeationFillDO> fills = iotOpeationFillMapper.countFills(fillReqVO);
-
-        if (CollUtil.isNotEmpty(fills)) {
-            rhTotalCount = fills.size();
-            fills.forEach(fill -> {
-                // 找出所有已经填报完成的队伍
-                if (1 == fill.getIsFill()) {
-                    // 填报完成
-                    rhFinishedCount.set(rhFinishedCount.get() + 1);
-                } else {
-                    // 填报中属于未填报完成
-                    rhUnfinishedCount.set(rhUnfinishedCount.get() + 1);
-                }
-            });
-        }
-
-        // 比如有20个队伍 某个时间区间D内 必须有20*D份日报 时间区间最好是1天
-        // 查询出指定时间区间内 已经填写的日报数量
-        // List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
         // 根据指定的时间区间 计算出天数
         LocalDateTime[] createTimes = reqVO.getCreateTime();
         // 获取开始时间和结束时间
@@ -1836,12 +1826,43 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         LocalDate endDate = endTime.toLocalDate();
         // 计算天数:日期差 + 1(包含首尾两天)
         long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
-        // 计算指定时间区间内所有日报数量总数
-        // long totalRequiredReports = (long) filteredDepts.size() * days;
-        // 获取【实际已报的日报数量】
-        // long totalReportedReports = CollUtil.isNotEmpty(dailyReports) ? dailyReports.size() : 0l;
-        // 计算指定时间区间内未填报的日报数量
-        // long notReportedCount = totalRequiredReports - totalReportedReports;
+        // 队伍总数 = 天数*符合要求的队伍数量
+
+        if (CollUtil.isNotEmpty(deviceTeamIds)) {
+            long teamCount =deviceTeamIds.size();
+            long totalCount = teamCount * days;
+
+            rhTotalCount = totalCount;
+
+            // 查询指定时间区间内 符合条件的队伍的日报
+            reqVO.setDeptIds(deviceTeamIds);
+            List<IotRhDailyReportDO> reports = iotRhDailyReportMapper.dailyReports(reqVO);
+            // 未生成日报的队伍id集合
+            Set<Long> unCreatedDeptIds = new HashSet<>();
+            // 已生成日报的队伍id集合
+            Set<Long> createdDeptIds = new HashSet<>();
+            if (CollUtil.isNotEmpty(reports)) {
+                reports.forEach(report -> {
+                    createdDeptIds.add(report.getDeptId());
+                    // status = 0未填报    status = 1已填报
+                    if (report.getStatus() == 1) {
+                        rhFinishedCount.set(rhFinishedCount.get() + 1);
+                    }
+                    if (report.getStatus() == 0) {
+                        rhUnfinishedCount.set(rhUnfinishedCount.get() + 1);
+                    }
+                });
+            }
+            // rhUnfinishedCount 还要统计没有生成日报的队伍数量
+            unCreatedDeptIds = deviceTeamIds.stream()
+                    .filter(deptId -> !createdDeptIds.contains(deptId))
+                    .collect(Collectors.toSet());
+            long unCreatedCount = unCreatedDeptIds.size() * days;
+            rhUnfinishedCount.set(rhUnfinishedCount.get() + (int) unCreatedCount);
+        }
+        // 先查询未填报 的队伍数量  已填报数量=总数-未填报
+        rhFinishedCount.set((int)rhTotalCount - rhUnfinishedCount.get());
+
         IotRhDailyReportStatisticsVO allReports = new IotRhDailyReportStatisticsVO();
         allReports.setGroupName("总数");
         allReports.setCount(rhTotalCount);
@@ -1866,25 +1887,49 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
             throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
         }
         List<IotRhDailyReportStatisticsVO> results = new ArrayList<>();
-        // List<IotDeviceDO> devices = devices();
         // 所有需要填报日报的 瑞恒 队伍集合
         Set<Long> deptIds = new HashSet<>();
         List<String> reportDates = new ArrayList<>();
-        /* devices.forEach(device -> {
-            deptIds.add(device.getDeptId());
-        }); */
 
         Set<Long> ids = new HashSet<>();
         ids = deptService.getChildDeptIdListFromCache(157l);
         ids.add(157l);
 
-        // 以运行记录表中 指定 时间范围内的 名称中包含 ‘生产日报’ 工单的部门为基数
-        // 瑞鹰钻井 rq_iot_opeation_fill rq_iot_opeation_fill_order 关联查询
-        // 瑞鹰修井 需要结合 挂靠队伍 日报
-        IotOpeationFillPageReqVO fillReqVO = new IotOpeationFillPageReqVO();
-        fillReqVO.setCreateTime(reqVO.getCreateTime());
-        fillReqVO.setDeptIds(new ArrayList<>(ids));
-        List<IotOpeationFillDO> fills = iotOpeationFillMapper.countFills(fillReqVO);
+        DeptListReqVO deptReqVO = new DeptListReqVO();
+        deptReqVO.setDeptIds(ids);
+        List<DeptDO> depts = deptService.getDeptList(deptReqVO);
+
+        // 项目部类型的部门id集合
+        Set<Long> projectDeptIds = new HashSet<>();
+        // 队伍类型的部门id集合
+        Set<Long> teamDeptIds = new HashSet<>();
+
+        depts.forEach(dept -> {
+            // 查找需要统计的项目部
+            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
+                projectDeptIds.add(dept.getId());
+            }
+        });
+        depts.forEach(dept -> {
+            // 队伍类型的部门id集合
+            if ("3".equals(dept.getType()) && projectDeptIds.contains(dept.getParentId())) {
+                teamDeptIds.add(dept.getId());
+            }
+        });
+
+        // 筛选有设备的队伍部门
+        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
+        deviceReqVO.setDeptIds(new ArrayList<>(ids));
+        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
+        // 包含设备的部门id集合
+        Set<Long> deviceTeamIds = new HashSet<>();
+        if (CollUtil.isNotEmpty(devices)) {
+            devices.forEach(device -> {
+                if (teamDeptIds.contains(device.getDeptId())) {
+                    deviceTeamIds.add(device.getDeptId());
+                }
+            });
+        }
 
         // 根据指定的时间区间 计算出天数
         LocalDateTime[] createTimes = reqVO.getCreateTime();
@@ -1907,110 +1952,148 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
                 .map(date -> date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                 .collect(Collectors.toList());
         // 比如有20个队伍 某个时间区间D内 必须有20*D份日报 时间区间最好是1天
-        // 查询出指定时间区间内 已经填写的日报数量
-        // List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
-        // 已经填报的队伍名称集合
-        Map<String, List<String>> reportedDeptNames = new HashMap<>();
-        // 未填报的队伍名称集合
-        Map<String, List<String>> unReportedDeptNames = new HashMap<>();
-        // 查询所有部门信息
-        Map<Long, DeptDO> allDepts = deptService.getDeptMap(ids);
-        // 过滤后的所有部门信息
-        Map<Long, DeptDO> filteredDepts = new HashMap<>();
-        // 过滤掉部门中的 ‘项目部’
-        /* if (CollUtil.isNotEmpty(allDepts)) {
-            allDepts.forEach((deptId, dept) -> {
-                if ("3".equals(dept.getType())) {
-                    filteredDepts.put(deptId, dept);
-                }
-            });
-        } */
-        /* if (CollUtil.isNotEmpty(dailyReports)) {
-            // 组装每天填写的日报集合 从而统计出每天未填写日报的队伍
-            dailyReports.forEach(report -> {
-                Long tempDeptId = report.getDeptId();
-                if (filteredDepts.containsKey(tempDeptId)) {
-                    String deptName = filteredDepts.get(tempDeptId).getName();
+
+        // 生成 deptId-createTime 全集A allDeptIdReportDates
+        List<String> allDeptIdReportDates = new ArrayList<>();
+        if (CollUtil.isNotEmpty(reportDates) && CollUtil.isNotEmpty(deviceTeamIds)) {
+            // 笛卡尔积:每个队伍ID匹配每个日期,生成 "teamId-reportDate" 格式的字符串
+            List<String> finalReportDates = reportDates;
+            allDeptIdReportDates = deviceTeamIds.stream()
+                    // 对每个队伍ID,关联所有日期
+                    .flatMap(teamId -> finalReportDates.stream()
+                            // 拼接成 "teamId-reportDate" 格式
+                            .map(date -> teamId + "~" + date))
+                    // 收集到List中(如需去重可加 .distinct(),根据实际场景决定)
+                    .collect(Collectors.toList());
+        }
+
+        // 根据符合要求的队伍查询相关的日报列表
+        if (CollUtil.isNotEmpty(deviceTeamIds)) {
+            reqVO.setDeptIds(deviceTeamIds);
+            // 查询出指定时间区间内 已经填写的日报数量
+            List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
+            // 未生成日报的队伍id集合
+            Set<Long> unCreatedDeptIds = new HashSet<>();
+            // 已生成日报的队伍id集合
+            Set<Long> createdDeptIds = new HashSet<>();
+            if (CollUtil.isNotEmpty(dailyReports)) {
+                dailyReports.forEach(report -> {
+                    createdDeptIds.add(report.getDeptId());
+                });
+            }
+            // 统计没有生成日报的队伍id集合
+            unCreatedDeptIds = deviceTeamIds.stream()
+                    .filter(deptId -> !createdDeptIds.contains(deptId))
+                    .collect(Collectors.toSet());
+
+            // 已经填报的队伍名称集合
+            Map<String, List<String>> reportedDeptNames = new HashMap<>();
+            // 未填报的队伍名称集合
+            Map<String, List<String>> unReportedDeptNames = new HashMap<>();
+            // 查询所有部门信息
+            Map<Long, DeptDO> allDepts = deptService.getDeptMap(ids);
+            // 过滤后的所有部门信息
+            Map<Long, DeptDO> filteredDepts = new HashMap<>();
+            // 队伍集合
+            if (CollUtil.isNotEmpty(allDepts)) {
+                allDepts.forEach((deptId, dept) -> {
+                    if ("3".equals(dept.getType()) && deviceTeamIds.contains(deptId)) {
+                        filteredDepts.put(deptId, dept);
+                    }
+                });
+            }
+            // 日报相关的 deptId-createTime 集合
+            List<String> reportDeptDates = new ArrayList<>();
+            if (CollUtil.isNotEmpty(dailyReports)) {
+                // 组装每天填写的日报集合 从而统计出每天未填写日报的队伍
+                dailyReports.forEach(report -> {
+                    // status=1 日报已经填报
                     LocalDateTime createTime = report.getCreateTime();
                     LocalDate tempDate = createTime.toLocalDate();
                     String tempReportDate = tempDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                    if (reportedDeptNames.containsKey(tempReportDate)) {
-                        List<String> tempDeptNames = reportedDeptNames.get(tempReportDate);
-                        tempDeptNames.add(deptName);
-                        reportedDeptNames.put(tempReportDate, tempDeptNames);
-                    } else {
-                        List<String> tempDeptNames = new ArrayList<>();
-                        tempDeptNames.add(deptName);
-                        reportedDeptNames.put(tempReportDate, tempDeptNames);
-                    }
-                }
-            });
-        } */
-        // 遍历所有时间区间的日期 组装每个日期中 未填写日报的队伍名称集合
-        /* if (CollUtil.isNotEmpty(reportDates)) {
-            reportDates.forEach(dateStr -> {
-                // 对时间区间内每个日期 都经过已经填报日报的过滤
-                if (reportedDeptNames.containsKey(dateStr)) {
-                    List<String> tempReportedDeptNames = reportedDeptNames.get(dateStr);
-                    filteredDepts.forEach((deptId, dept) -> {
-                        if (!tempReportedDeptNames.contains(dept.getName())) {
-                            if (unReportedDeptNames.containsKey(dateStr)) {
-                                List<String> tempDeptNames = unReportedDeptNames.get(dateStr);
-                                tempDeptNames.add(dept.getName());
-                                unReportedDeptNames.put(dateStr, tempDeptNames);
+                    // 生成每个队伍日报的 deptId-createTime 集合
+                    reportDeptDates.add(StrUtil.join("~", report.getDeptId(), tempReportDate));
+                    // 已经生成了日报 但是没有填报
+                    if (0 == report.getStatus()) {
+                        Long tempDeptId = report.getDeptId();
+                        if (filteredDepts.containsKey(tempDeptId)) {
+                            String deptName = filteredDepts.get(tempDeptId).getName();
+                            if (unReportedDeptNames.containsKey(tempReportDate)) {
+                                List<String> tempDeptNames = unReportedDeptNames.get(tempReportDate);
+                                tempDeptNames.add(deptName);
+                                unReportedDeptNames.put(tempReportDate, tempDeptNames);
                             } else {
                                 List<String> tempDeptNames = new ArrayList<>();
-                                tempDeptNames.add(dept.getName());
-                                unReportedDeptNames.put(dateStr, tempDeptNames);
+                                tempDeptNames.add(deptName);
+                                unReportedDeptNames.put(tempReportDate, tempDeptNames);
                             }
                         }
-                    });
-                } else {
-                    // 当天没有任何队伍填写日报
-                    filteredDepts.forEach((deptId, dept) -> {
-                        List<String> tempDeptNames = new ArrayList<>();
-                        tempDeptNames.add(dept.getName());
-                        unReportedDeptNames.put(dateStr, tempDeptNames);
-                    });
-                }
-            });
-        } */
-
-        if (CollUtil.isNotEmpty(fills)) {
-            fills.forEach(fill -> {
-                if (1 != fill.getIsFill()) {
-                    // 未完成填报
-                    LocalDate tempDate = fill.getCreateTime().toLocalDate();
-                    String tempDateStr = tempDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                    if (allDepts.containsKey(fill.getDeptId())) {
-                        DeptDO dept = allDepts.get(fill.getDeptId());
-                        if (unReportedDeptNames.containsKey(tempDateStr)) {
-                            List<String> tempDeptNames = unReportedDeptNames.get(tempDateStr);
-                            tempDeptNames.add(dept.getName());
-                            unReportedDeptNames.put(tempDateStr, tempDeptNames);
-                        } else {
-                            List<String> tempDeptNames = new ArrayList<>();
-                            tempDeptNames.add(dept.getName());
-                            unReportedDeptNames.put(tempDateStr, tempDeptNames);
+                    }
+                });
+            }
+
+            // 还需要统计未生成日报的队伍id集合
+            // 首先生成 deptId-createTime 全集allDeptIdReportDates 然后根据生成的日报组装日报相关的deptId-createTime集合 reportDeptDates
+            // allDeptIdReportDates-reportDeptDates 就是没有生成日报的队伍
+            List<String> unCreatedDeptDates = new ArrayList<>();
+            if (CollUtil.isNotEmpty(allDeptIdReportDates)) {
+                // 将已填报的 reportDeptDates 转换为 Set,提升查找效率(O(1))
+                Set<String> reportedSet = new HashSet<>(reportDeptDates);
+
+                // 过滤出 allDeptIdReportDates 中不在 reportedSet 中的元素,即是未生成日报的记录
+                unCreatedDeptDates = allDeptIdReportDates.stream()
+                        .filter(item -> !reportedSet.contains(item)) // 核心:排除已填报的记录
+                        .distinct() // 可选:去重(根据业务场景决定是否需要)
+                        .collect(Collectors.toList());
+            }
+
+            if (CollUtil.isNotEmpty(unCreatedDeptDates)) {
+                unCreatedDeptDates.forEach(deptDate -> {
+                    // deptId-createDate
+                    String[] deptDateArr = deptDate.split("~");
+                    if (deptDateArr.length > 0) {
+                        String tempDeptName = StrUtil.EMPTY;
+                        String deptIdStr = deptDateArr[0];
+                        // 根据deptId获得部门名称
+                        if (StrUtil.isNotBlank(deptIdStr) && !"null".equals(deptIdStr)) {
+                            Long deptId = Long.valueOf(deptIdStr);
+                            if (filteredDepts.containsKey(deptId)) {
+                                DeptDO dept = filteredDepts.get(deptId);
+                                tempDeptName = dept.getName();
+                            }
+                        }
+                        String createTimeStr = deptDateArr[1];
+                        if (StrUtil.isNotBlank(createTimeStr) && !"null".equals(createTimeStr)) {
+                            if (StrUtil.isNotBlank(tempDeptName)) {
+                                if (unReportedDeptNames.containsKey(createTimeStr)) {
+                                    List<String> tempDeptNames = unReportedDeptNames.get(createTimeStr);
+                                    tempDeptNames.add(tempDeptName);
+                                    unReportedDeptNames.put(createTimeStr, tempDeptNames);
+                                } else {
+                                    List<String> tempDeptNames = new ArrayList<>();
+                                    tempDeptNames.add(tempDeptName);
+                                    unReportedDeptNames.put(createTimeStr, tempDeptNames);
+                                }
+                            }
                         }
                     }
-                }
-            });
-        }
+                });
+            }
 
-        // 将集合中的未填报日报的队伍集合转换成 逗号 分隔的字符串
-        if (CollUtil.isNotEmpty(unReportedDeptNames)) {
-            unReportedDeptNames.forEach((reportDate, deptList) -> {
-                IotRhDailyReportStatisticsVO dailyReportVO = new IotRhDailyReportStatisticsVO();
-                dailyReportVO.setReportDate(reportDate);
-                dailyReportVO.setDeptNames(deptList.stream().collect(Collectors.joining(",")));
-                dailyReportVO.setCount(deptList.size());
-                results.add(dailyReportVO);
-            });
-            // 使用Comparator进行排序
-            results.sort(Comparator
-                    .comparing(IotRhDailyReportStatisticsVO::getReportDate,
-                            Comparator.nullsLast(Comparator.reverseOrder())));
+            // 将集合中的未填报日报的队伍集合转换成 逗号 分隔的字符串
+            if (CollUtil.isNotEmpty(unReportedDeptNames)) {
+                unReportedDeptNames.forEach((reportDate, deptList) -> {
+                    IotRhDailyReportStatisticsVO dailyReportVO = new IotRhDailyReportStatisticsVO();
+                    dailyReportVO.setReportDate(reportDate);
+                    dailyReportVO.setDeptNames(deptList.stream().collect(Collectors.joining(",")));
+                    dailyReportVO.setCount(deptList.size());
+                    results.add(dailyReportVO);
+                });
+                // 使用Comparator进行排序
+                results.sort(Comparator
+                        .comparing(IotRhDailyReportStatisticsVO::getReportDate,
+                                Comparator.nullsLast(Comparator.reverseOrder())));
+            }
         }
         return results;
     }