Просмотр исходного кода

pms 瑞恒日报 汇总 月度工作量统计 折线图

zhangcl 2 дней назад
Родитель
Сommit
eff1a5e220

+ 35 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrhdailyreport/IotRhDailyReportController.java

@@ -511,6 +511,41 @@ public class IotRhDailyReportController {
         return success(result);
         return success(result);
     }
     }
 
 
+    @GetMapping("/monthPolylineStatistics")
+    @Operation(summary = "获得瑞恒日报汇总统计 折线图")
+    @PreAuthorize("@ss.hasPermission('pms:iot-rh-daily-report:query')")
+    public CommonResult<List<IotRhDailyReportPolylineVO>> monthPolylineStatistics(@Valid IotRhDailyReportPageReqVO pageReqVO) {
+        List<IotRhDailyReportPolylineVO> result = new ArrayList<>();
+        // 根据查询参数筛选出 符合条件 的记录id 再传入 分页查询
+        Set<Long> projectIds = new HashSet<>();
+        Set<Long> taskIds = new HashSet<>();
+        if (StrUtil.isNotBlank(pageReqVO.getContractName())) {
+            IotProjectInfoPageReqVO reqVO = new IotProjectInfoPageReqVO();
+            reqVO.setContractName(pageReqVO.getContractName());
+            List<IotProjectInfoDO> projects = iotProjectInfoService.getIotProjectInfos(reqVO);
+            if (CollUtil.isNotEmpty(projects)) {
+                projects.forEach(project -> {
+                    projectIds.add(project.getId());
+                });
+                pageReqVO.setProjectIds(projectIds);
+            }
+        }
+        if (StrUtil.isNotBlank(pageReqVO.getTaskName())) {
+            IotProjectTaskPageReqVO reqVO = new IotProjectTaskPageReqVO();
+            reqVO.setSearchKey(pageReqVO.getTaskName());
+            List<IotProjectTaskDO> tasks = iotProjectTaskService.projectTasks(reqVO);
+            if (CollUtil.isNotEmpty(tasks)) {
+                tasks.forEach(task -> {
+                    taskIds.add(task.getId());
+                });
+                pageReqVO.setTaskIds(taskIds);
+            }
+        }
+        List<IotRhDailyReportPolylineVO> statistics = iotRhDailyReportService.monthPolylineStatistics(pageReqVO);
+        result.addAll(statistics);
+        return success(result);
+    }
+
     @GetMapping("/totalWorkload")
     @GetMapping("/totalWorkload")
     @Operation(summary = "累计工作量统计")
     @Operation(summary = "累计工作量统计")
     @PreAuthorize("@ss.hasPermission('pms:iot-rh-daily-report:query')")
     @PreAuthorize("@ss.hasPermission('pms:iot-rh-daily-report:query')")

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportService.java

@@ -198,4 +198,12 @@ public interface IotRhDailyReportService {
      * @return 瑞恒日报 非生产时效分析 列表
      * @return 瑞恒日报 非生产时效分析 列表
      */
      */
     Map<String, BigDecimal> totalWorkload(IotRhDailyReportPageReqVO pageReqVO);
     Map<String, BigDecimal> totalWorkload(IotRhDailyReportPageReqVO pageReqVO);
+
+    /**
+     * 统计月度的工作量折线图
+     *
+     * @param pageReqVO 无分页查询
+     * @return 瑞恒日报 非生产时效分析 列表
+     */
+    List<IotRhDailyReportPolylineVO> monthPolylineStatistics(IotRhDailyReportPageReqVO pageReqVO);
 }
 }

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

@@ -77,6 +77,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
+import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.ChronoUnit;
@@ -2120,6 +2121,93 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         return result;
         return result;
     }
     }
 
 
+    @Override
+    public List<IotRhDailyReportPolylineVO> monthPolylineStatistics(IotRhDailyReportPageReqVO pageReqVO) {
+        // 以 月为维度 统计工作量 非整月 上个月26日-本月25日
+        List<IotRhDailyReportPolylineVO> result = new ArrayList<>();
+        // 不分页统计所有数据
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        Set<Long> ids = new HashSet<>();
+        if (Objects.nonNull(pageReqVO.getDeptId())) {
+            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+            // 找到所有子部门对象集合
+            ids.add(pageReqVO.getDeptId());
+            pageReqVO.setDeptIds(ids);
+        }
+        // 检查contractName不为空但projectIds为空的情况
+        if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
+            return new ArrayList<>();
+        }
+        // 检查taskName不为空但taskIds为空的情况
+        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
+            return new ArrayList<>();
+        }
+
+        // 时间查询区间内如果包含 未发生的时间段(今年 本季度) 则设置 结束时间为 当前日期
+        // 调整 查询时间 因为 非整月查询 比如 查询时间是 2026-04-01 到 2026-05-31 则查询统计 2026年4月(3.26-4.25)、5月(4.26-5.25)的数据
+        // createTime[0]: 2026-09-01 00:00:00
+        // createTime[1]: 2026-09-07 23:59:59
+        adjustMonthStatisticsTime(pageReqVO);
+        
+        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhReportStatistics(
+                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
+                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
+        List<IotRhDailyReportDO> dailyReports = page.getRecords();
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            // 默认显示所有项目部的汇总数据(新疆分公司也展示 下属各项目部的数据)
+            // 点击项目部 显示 下属队伍的数据
+            // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认查询所有项目部数据
+            if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
+                result = monthPolylineStatisticsByProjectDept(dailyReports, 157L, pageReqVO.getCreateTime());
+            } else {
+                // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
+                DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
+                if ("1".equals(selectedDept.getType())) {
+                    // 以项目部为维度汇总数据
+                    result = monthPolylineStatisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
+                } else if ("2".equals(selectedDept.getType())) {
+                    // 以队伍为维度汇总数据
+                    result = monthPolylineStatisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
+                } else if ("3".equals(selectedDept.getType())) {
+                    // 显示单个队伍的汇总数据
+                    result = monthPolylineStatisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
+                } else {
+                    // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
+                    // 以项目部为维度汇总数据
+                    result = monthPolylineStatisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
+                }
+            }
+        }
+        return result;
+    }
+
+    private void adjustMonthStatisticsTime(IotRhDailyReportPageReqVO pageReqVO) {
+        LocalDateTime[] times = pageReqVO.getCreateTime();
+        if (times == null || times.length < 2 || times[0] == null || times[1] == null) {
+            return;
+        }
+
+        // 开始时间:开始时间所在月份的上个月26号 00:00:00
+        times[0] = times[0].minusMonths(1).withDayOfMonth(26).toLocalDate().atStartOfDay();
+
+        // 截止时间规则处理
+        LocalDate today = LocalDate.now();
+        LocalDate bDate = times[1].toLocalDate();
+        LocalDate month25Date = bDate.withDayOfMonth(25);
+
+        LocalDate endDate;
+        if (!month25Date.isAfter(today)) {
+            // 该月25号已经过去或就是今天,截止时间取该月25号
+            endDate = month25Date;
+        } else {
+            // 该月25号还没到,截止时间取 min(B, 今天)
+            endDate = bDate.isAfter(today) ? today : bDate;
+        }
+
+        times[1] = endDate.atTime(23, 59, 59);
+        pageReqVO.setCreateTime(times);
+    }
+
     @Override
     @Override
     public void updateIotRhDailyReport(IotRhDailyReportSaveReqVO updateReqVO) {
     public void updateIotRhDailyReport(IotRhDailyReportSaveReqVO updateReqVO) {
         // 校验存在
         // 校验存在
@@ -3364,6 +3452,270 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         return result;
         return result;
     }
     }
 
 
+    /**
+     * 按项目部 日期 维度统计 月度 折线 数据
+     * @param dailyReports 日报数据列表
+     * @param rootDeptId 根部门ID(如157L为瑞恒根部门,或其他公司级部门ID)
+     * @return 项目部 月度 维度统计结果列表
+     */
+    private List<IotRhDailyReportPolylineVO> monthPolylineStatisticsByProjectDept(List<IotRhDailyReportDO> dailyReports, Long rootDeptId, LocalDateTime[] createTimes) {
+        List<IotRhDailyReportPolylineVO> result = new ArrayList<>();
+        // 按照日期维度统计数据
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id    value项目部名称
+        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
+        // key部门id   value部门parentId
+        Map<Long, Long> teamProjectIdPair = new HashMap<>();
+
+        // 按照日期维度统计各工作量数据
+        // key日期yyyy-MM-dd   value累计注气量
+        Map<String, BigDecimal> dateGasInjectionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计注水量
+        Map<String, BigDecimal> dateWaterInjectionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计用电量
+        Map<String, BigDecimal> datePowerConsumptionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计油耗
+        Map<String, BigDecimal> dateFuelConsumptionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计运行时效   累计注气量/累计产能
+        Map<String, BigDecimal> dateTransitTimePair = new HashMap<>();
+        // key日期yyyy-MM-dd   value对应日报部门的总产能
+        Map<String, BigDecimal> dateCapacityPair = new HashMap<>();
+
+        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
+        Set<Long> mainDeviceCategoryIds = new HashSet<>();
+        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
+        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
+            constructionStatusDictData.forEach(data -> {
+                String value = data.getValue();
+                if (NumberUtil.isNumber(value)) {
+                    Long longValue = Long.valueOf(value);
+                    mainDeviceCategoryIds.add(longValue);
+                }
+            });
+        }
+
+        // 以项目部为维度统计数据
+        // 找到所有项目部与队伍的对应关系
+        // 查询指定根部门下的所有子部门
+        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(rootDeptId);
+        DeptListReqVO reqVO = new DeptListReqVO();
+        reqVO.setDeptIds(allRhChildDeptIds);
+        List<DeptDO> depts = deptService.getDeptList(reqVO);
+
+        // 包含瑞恒主设备的 部门id 集合
+        Set<Long> haveDeviceDeptIds = new HashSet<>();
+        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
+        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
+        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
+        if (CollUtil.isNotEmpty(devices)) {
+            // 筛选出包含设备的队伍部门集合
+            devices.forEach(device -> {
+                // 20260605 筛选包含主设备的队伍
+                if (mainDeviceCategoryIds.contains(device.getAssetClass())) {
+                    haveDeviceDeptIds.add(device.getDeptId());
+                }
+            });
+        }
+
+        // 当前已经选择的部门下 包含瑞恒主设备的 队伍id 集合
+        Set<Long> currentDeviceDeptIds = new HashSet<>();
+
+        // 20260915 修改设备利用率计算逻辑 修改分母为 日报总数
+
+        // 构建项目部映射和父子部门关系
+        depts.forEach(dept -> {
+            if ("2".equals(dept.getType())) {
+                projectDeptIds.add(dept.getId());
+                projectDeptPair.put(dept.getId(), dept);
+            }
+            teamProjectIdPair.put(dept.getId(), dept.getParentId());
+            // 筛选出当前选择的组织部门下包含瑞恒主设备的 队伍id 列表
+            if ("3".equals(dept.getType()) && haveDeviceDeptIds.contains(dept.getId())) {
+                currentDeviceDeptIds.add(dept.getId());
+            }
+        });
+
+        // 查询指定部门下相关设备的产能
+        // key队伍id   value队伍下相关设备产能
+        Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));
+
+        // key日期yyyy-MM-dd   value日报id集合
+        Map<String, Set<Long>> dateUtilizationDeptPair = new HashMap<>();
+
+        // key日期yyyy-MM-dd   value日期对应的日报总数量
+        Map<String, Integer> dateTotalReportPair = new HashMap<>();
+
+        // 累计计算各项指标
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            dailyReports.forEach(report -> {
+                Long reportId = report.getId();
+                Long deptId = report.getDeptId();
+                // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
+                LocalDateTime reportLocalDate = report.getCreateTime();
+                String reportMonth = getReportMonthGroup(reportLocalDate);
+                // 将日期格式转换成 字符串
+                String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
+                // 累计注气量
+                dateGasInjectionPair.merge(reportMonth, report.getDailyGasInjection(), BigDecimal::add);
+                // 累计注水量
+                dateWaterInjectionPair.merge(reportMonth, report.getDailyWaterInjection(), BigDecimal::add);
+                // 累计用电量
+                datePowerConsumptionPair.merge(reportMonth, report.getDailyPowerUsage(), BigDecimal::add);
+                // 累计油耗
+                dateFuelConsumptionPair.merge(reportMonth, report.getDailyOilUsage(), BigDecimal::add);
+                // 累计产能
+                if (teamCapacityPair.containsKey(deptId)) {
+                    BigDecimal tempCapacity = teamCapacityPair.get(deptId);
+                    dateCapacityPair.merge(reportMonth, tempCapacity, BigDecimal::add);
+                }
+                // 统计各日期的设备利用率 注气量 或 注水量 >0 的日报数量
+                BigDecimal dailyGasInjection = report.getDailyGasInjection();
+                BigDecimal dailyWaterInjection = report.getDailyWaterInjection();
+                if (haveDeviceDeptIds.contains(deptId) && (dailyGasInjection.compareTo(BigDecimal.ZERO)>0 || dailyWaterInjection.compareTo(BigDecimal.ZERO)>0)) {
+                    if (dateUtilizationDeptPair.containsKey(reportMonth)) {
+                        Set<Long> tempDeptIds = dateUtilizationDeptPair.get(reportMonth);
+                        tempDeptIds.add(reportId);
+                        dateUtilizationDeptPair.put(reportMonth, tempDeptIds);
+                    } else {
+                        Set<Long> tempDeptIds = new HashSet<>();
+                        tempDeptIds.add(reportId);
+                        dateUtilizationDeptPair.put(reportMonth, tempDeptIds);
+                    }
+                }
+                // 统计当前日期下所有日报总数量
+                if (dateTotalReportPair.containsKey(reportMonth)) {
+                    Integer tempCount = dateTotalReportPair.get(reportMonth);
+                    dateTotalReportPair.put(reportMonth, ++tempCount);
+                } else {
+                    dateTotalReportPair.put(reportMonth, 1);
+                }
+            });
+            // 根据 累计注气量 累计产能 计算指定日期范围的平均产能
+            if (CollUtil.isNotEmpty(dateGasInjectionPair) && CollUtil.isNotEmpty(dateCapacityPair)) {
+                dateGasInjectionPair.forEach((reportDateStr, dateGasInjection) -> {
+                    if (dateCapacityPair.containsKey(reportDateStr)) {
+                        BigDecimal tempCapacity = dateCapacityPair.get(reportDateStr);
+                        if (tempCapacity.compareTo(BigDecimal.ZERO) > 0) {
+                            // 指日期范围的累计运行时效
+                            BigDecimal tempTransitTime = dateGasInjection.divide(tempCapacity, 4, RoundingMode.HALF_UP);
+                            dateTransitTimePair.put(reportDateStr, tempTransitTime);
+                        } else {
+                            dateTransitTimePair.put(reportDateStr, BigDecimal.ZERO);
+                        }
+                    }
+                });
+            }
+        }
+
+        // 新增:日期字符串集合
+        List<String> dateRangeList = getMonthRangeList(createTimes);
+
+        /* if (ObjUtil.isNotEmpty(createTimes) && createTimes.length >= 2) {
+            LocalDate startDate = createTimes[0].toLocalDate();
+            LocalDate endDate = createTimes[1].toLocalDate();
+            // 生成从起始日期到结束日期的所有日期
+            for (LocalDate date = startDate;
+                 !date.isAfter(endDate);  // 使用 isAfter 而不是 <= 判断
+                 date = date.plusDays(1)) {
+                dateRangeList.add(date.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
+            }
+        } */
+
+        if (CollUtil.isNotEmpty(dateRangeList)) {
+            dateRangeList.forEach(date -> {
+                IotRhDailyReportPolylineVO statistics = new IotRhDailyReportPolylineVO();
+                statistics.setReportDate(date);
+                statistics.setCumulativeGasInjection(dateGasInjectionPair.get(date));
+                statistics.setCumulativeWaterInjection(dateWaterInjectionPair.get(date));
+                statistics.setCumulativePowerConsumption(datePowerConsumptionPair.get(date));
+                statistics.setCumulativeFuelConsumption(dateFuelConsumptionPair.get(date));
+                statistics.setTransitTime(dateTransitTimePair.get(date));
+                // 设置每个日期的设备利用率
+                if (dateUtilizationDeptPair.containsKey(date)) {
+                    Set<Long> dateDeptIds = dateUtilizationDeptPair.get(date);
+                    Integer dateDeptIdCount = dateDeptIds.size();
+                    Integer mainDeviceIdCount = currentDeviceDeptIds.size();
+                    // 20260915 修改设备利用率 计算逻辑 分母修改为日报总数量
+                    BigDecimal rate = BigDecimal.ZERO;
+                    if (dateTotalReportPair.containsKey(date)) {
+                        Integer totalReportNum = dateTotalReportPair.get(date);
+                        BigDecimal total = new BigDecimal(totalReportNum);
+                        BigDecimal current = new BigDecimal(dateDeptIdCount);
+                        rate = current.divide(total, 4, RoundingMode.HALF_UP);
+                    }
+                    statistics.setUtilizationRate(rate);
+                }
+                result.add(statistics);
+            });
+        }
+        return result;
+    }
+
+    /**
+     * 根据日报日期获取统计月份分组,格式:yyyy-MM
+     * 规则:上月26日 ~ 本月25日 算作本月
+     *
+     * 例如:
+     * 2026-04-26 ~ 2026-05-25 -> 2026-05
+     * 2026-05-26 ~ 2026-06-25 -> 2026-06
+     * 2026-09-20 -> 2026-09
+     *
+     * @param reportTime 日报创建时间
+     * @return 统计月份,格式 yyyy-MM
+     */
+    private String getReportMonthGroup(LocalDateTime reportTime) {
+        if (reportTime == null) {
+            return null;
+        }
+
+        LocalDate reportDate = reportTime.toLocalDate();
+        YearMonth yearMonth = YearMonth.from(reportDate);
+
+        // 26号及以后,归属下个月
+        if (reportDate.getDayOfMonth() >= 26) {
+            yearMonth = yearMonth.plusMonths(1);
+        }
+
+        // YearMonth.toString() 默认就是 yyyy-MM
+        return yearMonth.toString();
+    }
+
+    /**
+     * 根据时间筛选区间获取所包含的统计月份列表(升序)
+     * 统计月规则:上月26日 ~ 本月25日 算作本月
+     * 例如:2026-04-26 ~ 2026-05-25 -> 2026-05
+     *
+     * @param createTimes 时间筛选区间,[开始时间, 结束时间]
+     * @return 月份字符串列表,格式:yyyy-MM,例如 ["2026-05", "2026-06"]
+     */
+    public List<String> getMonthRangeList(LocalDateTime[] createTimes) {
+        List<String> monthRangeList = new ArrayList<>();
+        if (createTimes == null || createTimes.length < 2
+                || createTimes[0] == null || createTimes[1] == null) {
+            return monthRangeList;
+        }
+
+        // 计算起始和结束的统计月
+        YearMonth startMonth = getStatisticsMonth(createTimes[0].toLocalDate());
+        YearMonth endMonth = getStatisticsMonth(createTimes[1].toLocalDate());
+
+        // 按月份升序生成
+        for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
+            monthRangeList.add(month.toString()); // YearMonth.toString() 返回 yyyy-MM
+        }
+        return monthRangeList;
+    }
+
+    /**
+     * 获取日期所属的统计月
+     * 规则:day >= 26 归属下个月,day <= 25 归属当前月
+     */
+    private YearMonth getStatisticsMonth(LocalDate date) {
+        return date.getDayOfMonth() >= 26
+                ? YearMonth.from(date).plusMonths(1)
+                : YearMonth.from(date);
+    }
+
     /**
     /**
      * 按 队伍 维度统计数据
      * 按 队伍 维度统计数据
      * @param dailyReports 日报数据列表
      * @param dailyReports 日报数据列表
@@ -4201,6 +4553,189 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         return result;
         return result;
     }
     }
 
 
+    /**
+     * 按 队伍 月度 维度统计数据
+     * @param dailyReports 日报数据列表
+     * @param deptId 项目部ID 或 队伍id(塔河项目部 HY-A1)
+     * @return 队伍 月份 维度统计结果列表
+     */
+    private List<IotRhDailyReportPolylineVO> monthPolylineStatisticsByProjectDepartment(List<IotRhDailyReportDO> dailyReports, Long deptId, LocalDateTime[] createTimes) {
+        List<IotRhDailyReportPolylineVO> result = new ArrayList<>();
+
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id    value项目部名称
+        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
+        // key队伍id    value队伍名称
+        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
+        // key部门id   value部门parentId
+        Map<Long, Long> teamProjectIdPair = new HashMap<>();
+
+        // 按照日期维度统计各工作量数据
+        // key日期yyyy-MM-dd   value累计注气量
+        Map<String, BigDecimal> dateGasInjectionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计注水量
+        Map<String, BigDecimal> dateWaterInjectionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计用电量
+        Map<String, BigDecimal> datePowerConsumptionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计油耗
+        Map<String, BigDecimal> dateFuelConsumptionPair = new HashMap<>();
+        // key日期yyyy-MM-dd   value累计运行时效   累计注气量/累计产能
+        Map<String, BigDecimal> dateTransitTimePair = new HashMap<>();
+        // key日期yyyy-MM-dd   value对应日报部门的总产能
+        Map<String, BigDecimal> dateCapacityPair = new HashMap<>();
+
+        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
+        Set<Long> mainDeviceCategoryIds = new HashSet<>();
+        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
+        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
+            constructionStatusDictData.forEach(data -> {
+                String value = data.getValue();
+                if (NumberUtil.isNumber(value)) {
+                    Long longValue = Long.valueOf(value);
+                    mainDeviceCategoryIds.add(longValue);
+                }
+            });
+        }
+
+        // 以 队伍 为维度统计数据
+        // 找到所有项目部与队伍的对应关系
+        // 查询指定根部门下的所有子部门
+        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(deptId);
+        DeptListReqVO reqVO = new DeptListReqVO();
+        allRhChildDeptIds.add(deptId);  // 查询某支队伍
+        reqVO.setDeptIds(allRhChildDeptIds);
+        List<DeptDO> depts = deptService.getDeptList(reqVO);
+
+        // 包含瑞恒主设备的 部门id 集合
+        Set<Long> haveDeviceDeptIds = new HashSet<>();
+        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
+        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
+        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
+        if (CollUtil.isNotEmpty(devices)) {
+            // 筛选出包含设备的队伍部门集合
+            devices.forEach(device -> {
+                // 20260605 筛选包含主设备的队伍
+                if (mainDeviceCategoryIds.contains(device.getAssetClass())) {
+                    haveDeviceDeptIds.add(device.getDeptId());
+                }
+            });
+        }
+
+        // 构建项目部映射和父子部门关系
+        // 当前已经选择的部门下 包含瑞恒主设备的 队伍id 集合
+        Set<Long> currentDeviceDeptIds = new HashSet<>();
+        depts.forEach(dept -> {
+            if ("3".equals(dept.getType())) {
+                projectDeptIds.add(dept.getId());
+                teamDeptPair.put(dept.getId(), dept);
+                // 筛选出当前选择的组织部门下包含瑞恒主设备的 队伍id 列表
+                if (haveDeviceDeptIds.contains(dept.getId())) {
+                    currentDeviceDeptIds.add(dept.getId());
+                }
+            }
+            teamProjectIdPair.put(dept.getId(), dept.getParentId());
+        });
+
+        // 查询指定部门下相关设备的产能
+        // key队伍id   value队伍下相关设备产能
+        Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));
+
+        // key日期yyyy-MM-dd   value指定日期内包含主设备队伍id集合
+        Map<String, Set<Long>> dateUtilizationDeptPair = new HashMap<>();
+
+        // 累计计算各项指标
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            dailyReports.forEach(report -> {
+                Long currentDeptId = report.getDeptId();
+                // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
+                LocalDateTime reportLocalDate = report.getCreateTime();
+                // 将日期格式转换成 字符串
+                String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
+                // 累计注气量
+                dateGasInjectionPair.merge(reportDateStr, report.getDailyGasInjection(), BigDecimal::add);
+                // 累计注水量
+                dateWaterInjectionPair.merge(reportDateStr, report.getDailyWaterInjection(), BigDecimal::add);
+                // 累计用电量
+                datePowerConsumptionPair.merge(reportDateStr, report.getDailyPowerUsage(), BigDecimal::add);
+                // 累计油耗
+                dateFuelConsumptionPair.merge(reportDateStr, report.getDailyOilUsage(), BigDecimal::add);
+                // 累计产能
+                if (teamCapacityPair.containsKey(currentDeptId)) {
+                    BigDecimal tempCapacity = teamCapacityPair.get(currentDeptId);
+                    dateCapacityPair.merge(reportDateStr, tempCapacity, BigDecimal::add);
+                }
+                // 统计各日期的设备利用率 注气量 或 注水量 >0 的日报数量
+                BigDecimal dailyGasInjection = report.getDailyGasInjection();
+                BigDecimal dailyWaterInjection = report.getDailyWaterInjection();
+                if (haveDeviceDeptIds.contains(currentDeptId) && (dailyGasInjection.compareTo(BigDecimal.ZERO)>0 || dailyWaterInjection.compareTo(BigDecimal.ZERO)>0)) {
+                    if (dateUtilizationDeptPair.containsKey(reportDateStr)) {
+                        Set<Long> tempDeptIds = dateUtilizationDeptPair.get(reportDateStr);
+                        tempDeptIds.add(currentDeptId);
+                        dateUtilizationDeptPair.put(reportDateStr, tempDeptIds);
+                    } else {
+                        Set<Long> tempDeptIds = new HashSet<>();
+                        tempDeptIds.add(currentDeptId);
+                        dateUtilizationDeptPair.put(reportDateStr, tempDeptIds);
+                    }
+                }
+            });
+            // 根据 累计注气量 累计产能 计算指定队伍下的平均产能
+            if (CollUtil.isNotEmpty(dateGasInjectionPair) && CollUtil.isNotEmpty(dateCapacityPair)) {
+                dateGasInjectionPair.forEach((teamDeptId, dateGasInjection) -> {
+                    if (dateCapacityPair.containsKey(teamDeptId)) {
+                        BigDecimal tempCapacity = dateCapacityPair.get(teamDeptId);
+                        if (tempCapacity.compareTo(BigDecimal.ZERO) > 0) {
+                            // 指定队伍的累计运行时效
+                            BigDecimal tempTransitTime = dateGasInjection.divide(tempCapacity, 4, RoundingMode.HALF_UP);
+                            dateTransitTimePair.put(teamDeptId, tempTransitTime);
+                        }
+                    }
+                });
+            }
+        }
+
+        // 新增:日期字符串集合
+        List<String> dateRangeList = new ArrayList<>();
+        if (createTimes.length >= 2) {
+            LocalDate startDate = createTimes[0].toLocalDate();
+            LocalDate endDate = createTimes[1].toLocalDate();
+            // 生成从起始日期到结束日期的所有日期
+            for (LocalDate date = startDate;
+                 !date.isAfter(endDate);  // 使用 isAfter 而不是 <= 判断
+                 date = date.plusDays(1)) {
+                dateRangeList.add(date.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
+            }
+        }
+
+        if (CollUtil.isNotEmpty(dateRangeList)) {
+            dateRangeList.forEach(date -> {
+                IotRhDailyReportPolylineVO statistics = new IotRhDailyReportPolylineVO();
+                statistics.setReportDate(date);
+                statistics.setCumulativeGasInjection(dateGasInjectionPair.get(date));
+                statistics.setCumulativeWaterInjection(dateWaterInjectionPair.get(date));
+                statistics.setCumulativePowerConsumption(datePowerConsumptionPair.get(date));
+                statistics.setCumulativeFuelConsumption(dateFuelConsumptionPair.get(date));
+                statistics.setTransitTime(dateTransitTimePair.get(date));
+                // 设置每个日期的设备利用率
+                if (dateUtilizationDeptPair.containsKey(date)) {
+                    Set<Long> dateDeptIds = dateUtilizationDeptPair.get(date);
+                    Integer dateDeptIdCount = dateDeptIds.size();
+                    Integer mainDeviceIdCount = currentDeviceDeptIds.size();
+                    BigDecimal rate = BigDecimal.ZERO;
+                    if (mainDeviceIdCount > 0) {
+                        BigDecimal total = new BigDecimal(mainDeviceIdCount);
+                        BigDecimal current = new BigDecimal(dateDeptIdCount);
+                        rate = current.divide(total, 4, RoundingMode.HALF_UP);
+                    }
+                    statistics.setUtilizationRate(rate);
+                }
+                result.add(statistics);
+            });
+        }
+
+        return result;
+    }
+
     @Override
     @Override
     public List<IotRhDailyReportStatisticsVO> rhDailyReportStatistics(IotRhDailyReportPageReqVO reqVO) {
     public List<IotRhDailyReportStatisticsVO> rhDailyReportStatistics(IotRhDailyReportPageReqVO reqVO) {
         if (reqVO.getCreateTime().length == 0) {
         if (reqVO.getCreateTime().length == 0) {