소스 검색

Merge remote-tracking branch 'origin/master'

lipenghui 1 주 전
부모
커밋
1fe2d793af
12개의 변경된 파일1144개의 추가작업 그리고 7개의 파일을 삭제
  1. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttask/IotProjectTaskController.java
  2. 589 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrhdailyreport/IotRhDailyReportController.java
  3. 20 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrhdailyreport/vo/IotRhDailyReportRespVO.java
  4. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrhdailyreport/vo/IotRhDailyReportStatisticsRespVO.java
  5. 19 3
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/IotStaticController.java
  6. 7 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/vo/ProjectUtilizationRateVo.java
  7. 47 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotrhdailyreport/IotRhDailyReportMapper.java
  8. 7 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttask/IotProjectTaskService.java
  9. 22 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttask/IotProjectTaskServiceImpl.java
  10. 32 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportService.java
  11. 176 4
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportServiceImpl.java
  12. 209 0
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/iotprojecttask/IotRhDailyReportMapper.xml

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotprojecttask/IotProjectTaskController.java

@@ -354,6 +354,14 @@ public class IotProjectTaskController {
         return success(new PageResult<>(buildProjectTaskList(taskList.getList()), taskList.getTotal()));
     }
 
+    @GetMapping("/taskWellNames")
+    @Operation(summary = "查看某个专业公司下去重后的所有任务列表")
+    @PreAuthorize("@ss.hasPermission('rq:iot-project-task:query')")
+    public CommonResult<List<IotProjectTaskRespVO>> taskWellNames( IotProjectTaskPageReqVO pageReqVO) {
+        List<IotProjectTaskDO> wellNames = iotProjectTaskService.taskWellNames(pageReqVO);
+        return success(BeanUtils.toBean(wellNames, IotProjectTaskRespVO.class));
+    }
+
     private List<IotProjectTaskRespVO> buildProjectTaskList(List<IotProjectTaskDO> tasks) {
         if (CollUtil.isEmpty(tasks)) {
             return Collections.emptyList();

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

@@ -57,6 +57,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
 
 @Tag(name = "管理后台 - 瑞恒日报")
@@ -186,6 +187,72 @@ public class IotRhDailyReportController {
         return success(new PageResult<>(buildRhDailyReports(pageResult.getList(), pageReqVO), pageResult.getTotal()));
     }
 
+    @GetMapping("/teamReports")
+    @Operation(summary = "根据井号查询瑞恒日报列表 按照队伍分组统计工作量")
+    @PreAuthorize("@ss.hasPermission('pms:iot-rh-daily-report:query')")
+    public CommonResult<PageResult<IotRhDailyReportRespVO>> teamReports(@Valid IotRhDailyReportPageReqVO pageReqVO) {
+        // 根据查询参数筛选出 符合条件 的记录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);
+            }
+        }
+        PageResult<IotRhDailyReportDO> pageResult = iotRhDailyReportService.teamReports(pageReqVO);
+        return success(new PageResult<>(buildSubtotalRhDailyReports(pageResult.getList(), pageReqVO), pageResult.getTotal()));
+    }
+
+    @GetMapping("/wellReports")
+    @Operation(summary = "以队伍为维度 查询瑞恒日报列表 按照任务井分组统计工作量")
+    @PreAuthorize("@ss.hasPermission('pms:iot-rh-daily-report:query')")
+    public CommonResult<PageResult<IotRhDailyReportRespVO>> wellReports(@Valid IotRhDailyReportPageReqVO pageReqVO) {
+        // 根据查询参数筛选出 符合条件 的记录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);
+            }
+        }
+        PageResult<IotRhDailyReportDO> pageResult = iotRhDailyReportService.wellReports(pageReqVO);
+        return success(new PageResult<>(buildWellRhDailyReports(pageResult.getList(), pageReqVO), pageResult.getTotal()));
+    }
+
     @GetMapping("/completeRate")
     @Operation(summary = "查询各专业公司日报完成率")
     @DataPermission(enable = false)
@@ -702,6 +769,528 @@ public class IotRhDailyReportController {
         });
     }
 
+    /**
+     * 以井为维度 统计 瑞恒日报 分页数据 以队伍分组小计工作量
+     * @param reports
+     * @return
+     */
+    private List<IotRhDailyReportRespVO> buildSubtotalRhDailyReports(List<IotRhDailyReportDO> reports, IotRhDailyReportPageReqVO pageReqVO) {
+        if (CollUtil.isEmpty(reports)) {
+            return Collections.emptyList();
+        }
+        // 设备部门信息
+        Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(reports, IotRhDailyReportDO::getDeptId));
+        // key项目id   value项目合同号
+        Map<Long, String> projectPair = new HashMap<>();
+        //  key任务id     value任务井号-施工区域
+        Map<Long, String> taskPair = new HashMap<>();
+        // key任务id   value设计注气量
+        Map<Long, String> taskExtPropertyPair = new HashMap<>();
+        // key施工状态数据字典value   value施工状态数据字典label
+        Map<String, String> constructStatusPair = new HashMap<>();
+        // key非生产时间原因数据字典value   value非生产时间原因数据字典label
+        Map<String, String> nptReasonPair = new HashMap<>();
+        // 搬迁安装天数
+        Map<Long, BigDecimal> relocationDaysPair = new HashMap<>();
+
+        // key部门id-队伍id   value 队伍当年累计注气量
+        Map<String, BigDecimal> groupGasInjectionPair = new HashMap<>();
+        // key部门id-队伍id   value 队伍当年累计注水量
+        Map<String, BigDecimal> groupWaterInjectionPair = new HashMap<>();
+        // key部门id-队伍id   value 队伍当年累计用电量
+        Map<String, BigDecimal> groupPowerPair = new HashMap<>();
+        // key部门id-队伍id   value 队伍当年累计油耗
+        Map<String, BigDecimal> groupFuelPair = new HashMap<>();
+        // key部门id-队伍id    value 注气时间小计
+        Map<String, BigDecimal> groupGasTimePair = new HashMap<>();
+        // key部门id-队伍id    value 非生产时间小计
+        Map<String, BigDecimal> groupNoProductTimePair = new HashMap<>();
+        // key部门id-队伍id    value 小计平均运行时效
+        Map<String, BigDecimal> groupTransTimePair = new HashMap<>();
+
+        // key小组最后1条记录id   value 队伍当年累计注气量
+        Map<Long, BigDecimal> groupIdGasInjectionPair = new HashMap<>();
+        // key小组最后1条记录id   value 队伍当年累计注水量
+        Map<Long, BigDecimal> groupIdWaterInjectionPair = new HashMap<>();
+        // key小组最后1条记录id   value 队伍当年累计用电量
+        Map<Long, BigDecimal> groupIdPowerPair = new HashMap<>();
+        // key小组最后1条记录id   value 队伍当年累计油耗
+        Map<Long, BigDecimal> groupIdFuelPair = new HashMap<>();
+        // key小组最后1条记录id    value 注气时间小计
+        Map<Long, BigDecimal> groupIdGasTimePair = new HashMap<>();
+        // key小组最后1条记录id    value 非生产时间小计
+        Map<Long, BigDecimal> groupIdNoProductTimePair = new HashMap<>();
+        // key小组最后1条记录id    value 小计平均运行时效
+        Map<Long, BigDecimal> groupIdTransTimePair = new HashMap<>();
+
+
+        // 查询 当前分页 所有部门 任务井 日报数据 小计工作量
+        IotRhDailyReportPageReqVO currentTaskReqVO = new IotRhDailyReportPageReqVO();
+        currentTaskReqVO.setTaskIds(convertSet(reports, IotRhDailyReportDO::getTaskId));
+        currentTaskReqVO.setDeptIds(convertSet(reports, IotRhDailyReportDO::getDeptId));
+        currentTaskReqVO.setCreateTime(pageReqVO.getCreateTime());
+        currentTaskReqVO.setProjectIds(pageReqVO.getProjectIds());
+        currentTaskReqVO.setTaskIds(pageReqVO.getTaskIds());
+        List<IotRhDailyReportDO> deptTaskDailyReports = iotRhDailyReportMapper.dailyReports(currentTaskReqVO);
+
+        // 以 deptId-taskId 为唯一键 小计日报工作量
+        if (CollUtil.isNotEmpty(deptTaskDailyReports)) {
+            deptTaskDailyReports.forEach(report -> {
+                String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
+                // 注气量
+                if (groupGasInjectionPair.containsKey(uniqueKey)) {
+                    BigDecimal tempGasInjection = groupGasInjectionPair.get(uniqueKey);
+                    BigDecimal tempResult = tempGasInjection.add(report.getDailyGasInjection());
+                    groupGasInjectionPair.put(uniqueKey, tempResult);
+                } else {
+                    groupGasInjectionPair.put(uniqueKey, report.getDailyGasInjection());
+                }
+                // 注水量
+                if (groupWaterInjectionPair.containsKey(uniqueKey)) {
+                    BigDecimal tempWaterInjection = groupWaterInjectionPair.get(uniqueKey);
+                    BigDecimal tempResult = tempWaterInjection.add(report.getDailyWaterInjection());
+                    groupWaterInjectionPair.put(uniqueKey, tempResult);
+                } else {
+                    groupWaterInjectionPair.put(uniqueKey, report.getDailyWaterInjection());
+                }
+                // 电量
+                if (groupPowerPair.containsKey(uniqueKey)) {
+                    BigDecimal tempPower = groupPowerPair.get(uniqueKey);
+                    BigDecimal tempResult = tempPower.add(report.getDailyPowerUsage());
+                    groupPowerPair.put(uniqueKey, tempResult);
+                } else {
+                    groupPowerPair.put(uniqueKey, report.getDailyPowerUsage());
+                }
+                // 油耗
+                if (groupFuelPair.containsKey(uniqueKey)) {
+                    BigDecimal tempFuel = groupFuelPair.get(uniqueKey);
+                    BigDecimal tempResult = tempFuel.add(report.getDailyOilUsage());
+                    groupFuelPair.put(uniqueKey, tempResult);
+                } else {
+                    groupFuelPair.put(uniqueKey, report.getDailyOilUsage());
+                }
+                // 注气时间
+                if (groupGasTimePair.containsKey(uniqueKey)) {
+                    BigDecimal tempGasTime = groupGasTimePair.get(uniqueKey);
+                    BigDecimal tempResult = tempGasTime.add(report.getDailyInjectGasTime());
+                    groupGasTimePair.put(uniqueKey, tempResult);
+                } else {
+                    groupGasTimePair.put(uniqueKey, report.getDailyInjectGasTime());
+                }
+                // 非生产时间
+                if (groupNoProductTimePair.containsKey(uniqueKey)) {
+                    BigDecimal tempNoProductTime = groupNoProductTimePair.get(uniqueKey);
+                    BigDecimal tempResult = tempNoProductTime.add(report.getNonProductionTime());
+                    groupNoProductTimePair.put(uniqueKey, tempResult);
+                } else {
+                    groupNoProductTimePair.put(uniqueKey, report.getNonProductionTime());
+                }
+            });
+        }
+
+        // 查询 deptId-taskId 分组内最后1条记录id 设置展开列标识
+        List<IotRhDailyReportDO> currentGroupIds = iotRhDailyReportService.rhWellNameDailyReportsGroupIds(currentTaskReqVO);
+        // key部门id-任务id   value小组内最后1条记录id
+        Map<String, Long> groupIdPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(currentGroupIds)) {
+            currentGroupIds.forEach(groupId -> {
+                String uniqueKey = StrUtil.join("-", groupId.getDeptId(), groupId.getTaskId());
+                groupIdPair.put(uniqueKey, groupId.getId());
+            });
+        }
+
+        // 设置 分组内最后1条记录id 与 deptId-taskId 唯一键的对应关系
+        if (CollUtil.isNotEmpty(groupIdPair)) {
+            groupIdPair.forEach((uniqueKey, groupId) -> {
+                if (groupGasInjectionPair.containsKey(uniqueKey)) {
+                    groupIdGasInjectionPair.put(groupId, groupGasInjectionPair.get(uniqueKey));
+                }
+                if (groupWaterInjectionPair.containsKey(uniqueKey)) {
+                    groupIdWaterInjectionPair.put(groupId, groupWaterInjectionPair.get(uniqueKey));
+                }
+                if (groupPowerPair.containsKey(uniqueKey)) {
+                    groupIdPowerPair.put(groupId, groupPowerPair.get(uniqueKey));
+                }
+                if (groupFuelPair.containsKey(uniqueKey)) {
+                    groupIdFuelPair.put(groupId, groupFuelPair.get(uniqueKey));
+                }
+                if (groupGasTimePair.containsKey(uniqueKey)) {
+                    groupIdGasTimePair.put(groupId, groupGasTimePair.get(uniqueKey));
+                }
+                if (groupNoProductTimePair.containsKey(uniqueKey)) {
+                    groupIdNoProductTimePair.put(groupId, groupNoProductTimePair.get(uniqueKey));
+                }
+
+            });
+        }
+
+        // key部门id  value产能
+        AtomicReference<Map<Long, BigDecimal>> capacityPair = new AtomicReference<>(new HashMap<>());
+        // 施工状态 字典数据
+        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("constructionStatus");
+        // 非生产时间原因 字典数据
+        List<DictDataDO> nptReasonDictData = dictDataService.getDictDataListByDictType("nptReason");
+        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
+            constructionStatusDictData.forEach(data -> {
+                constructStatusPair.put(data.getValue(), data.getLabel());
+            });
+        }
+        if (CollUtil.isNotEmpty(nptReasonDictData)) {
+            nptReasonDictData.forEach(data -> {
+                nptReasonPair.put(data.getValue(), data.getLabel());
+            });
+        }
+        DataPermissionUtils.executeIgnore(() -> {
+            // 查询日报关联的项目信息
+            IotProjectInfoPageReqVO reqVO = new IotProjectInfoPageReqVO();
+            reqVO.setProjectIds(convertList(reports, IotRhDailyReportDO::getProjectId));
+            List<IotProjectInfoDO> projects = iotProjectInfoService.getIotProjectInfos(reqVO);
+            if (CollUtil.isNotEmpty(projects)) {
+                projects.forEach(project -> {
+                    projectPair.put(project.getId(), project.getContractName());
+                });
+            }
+            // 查询日报关联的任务信息
+            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
+            taskReqVO.setTaskIds(convertList(reports, IotRhDailyReportDO::getTaskId));
+            List<IotProjectTaskDO> tasks = iotProjectTaskService.projectTasks(taskReqVO);
+            if (CollUtil.isNotEmpty(tasks)) {
+                tasks.forEach(task -> {
+                    taskPair.put(task.getId(), task.getWellName());
+                    if (CollUtil.isNotEmpty(task.getExtProperty())) {
+                        List<IotTaskAttrModelProperty> taskAttrs = task.getExtProperty();
+                        if (CollUtil.isNotEmpty(taskAttrs)) {
+                            // 找到 设计注气量 属性 对应的值
+                            taskAttrs.forEach(attr -> {
+                                if ("设计注气量".equals(attr.getName()) && StrUtil.isNotBlank(attr.getActualValue())) {
+                                    taskExtPropertyPair.put(task.getId(), attr.getActualValue());
+                                }
+                            });
+                        }
+                    }
+                });
+            }
+            // 查询当前日报所属施工队伍中包含 增压机 的产能
+            capacityPair.set(iotRhDailyReportService.queryCapacities(convertList(reports, IotRhDailyReportDO::getDeptId)));
+            // 查询每个任务的搬迁安装天数
+            List<IotRhDailyReportDO> relocationDays = iotRhDailyReportService.relocationDays(null);
+            if (CollUtil.isNotEmpty(relocationDays)) {
+                relocationDays.forEach(day -> {
+                    relocationDaysPair.put(day.getDeptId(), day.getRelocationDays());
+                });
+            }
+        });
+        // 2. 拼接数据
+        return BeanUtils.toBean(reports, IotRhDailyReportRespVO.class, (reportVO) -> {
+            if (ObjUtil.isNotEmpty(reportVO.getTransitTime())) {
+                // 获取原始小数
+                BigDecimal transitTime = reportVO.getTransitTime();
+                // 乘以100转换为百分比数值
+                BigDecimal percentage = transitTime.multiply(BigDecimal.valueOf(100));
+                // 格式化保留2位小数
+                DecimalFormat df = new DecimalFormat("0.00");
+                String transitTimeRate = df.format(percentage) + "%";
+                // 赋值
+                reportVO.setTransitTimeRate(transitTimeRate);
+            }
+            // 2.1 拼接部门信息
+            findAndThen(deptMap, reportVO.getDeptId(), dept -> reportVO.setDeptName(dept.getName()));
+
+            // 小组内最后1条记录标识
+            findAndThen(groupIdGasInjectionPair, reportVO.getId(), gasInjection -> reportVO.setLastGroupIdFlag("Y"));
+            // 小组内累计注气量
+            findAndThen(groupIdGasInjectionPair, reportVO.getId(), gasInjection -> reportVO.setGroupIdGasInjection(gasInjection));
+            // 小组内累计注水量
+            findAndThen(groupIdWaterInjectionPair, reportVO.getId(), waterInjection -> reportVO.setGroupIdWaterInjection(waterInjection));
+            // 小组内累计用电量
+            findAndThen(groupIdPowerPair, reportVO.getId(), power -> reportVO.setGroupIdPower(power));
+            // 小组内累计油耗
+            findAndThen(groupIdFuelPair, reportVO.getId(), fuel -> reportVO.setGroupIdFuel(fuel));
+            // 小组内累计注气时间
+            findAndThen(groupIdGasTimePair, reportVO.getId(), gasTime -> reportVO.setGroupIdGasTime(gasTime));
+            // 小组内累计非生产时间
+            findAndThen(groupIdNoProductTimePair, reportVO.getId(), noProductTime -> reportVO.setGroupIdNoProductTime(noProductTime));
+            // 小组内累计运行时效
+            // findAndThen(groupIdTransTimePair, reportVO.getId(), transitTime -> reportVO.setGroupIdTransitTime(transitTime));
+
+            // 2.2 日报关联的项目信息
+            findAndThen(projectPair, reportVO.getProjectId(), contractName -> reportVO.setContractName(contractName));
+            // 2.3 日报关联的任务信息
+            findAndThen(taskPair, reportVO.getTaskId(), taskName -> reportVO.setTaskName(taskName));
+            // 2.4 设计注气量
+            findAndThen(taskExtPropertyPair, reportVO.getTaskId(), designInjection -> reportVO.setDesignInjection(designInjection));
+            // 2.5 搬迁安装天数
+            findAndThen(relocationDaysPair, reportVO.getDeptId(), relocationDays -> reportVO.setRelocationDays(relocationDays));
+            // 2.6 产能
+            findAndThen(capacityPair.get(), reportVO.getDeptId(), capacity -> reportVO.setCapacity(capacity));
+            // 施工状态 数据字典
+            findAndThen(constructStatusPair, reportVO.getConstructionStatus(), statusLabel -> reportVO.setConstructionStatusName(statusLabel));
+            // 非生产时间原因 数据字典
+            findAndThen(nptReasonPair, reportVO.getNptReason(), statusLabel -> reportVO.setNptReasonName(statusLabel));
+        });
+    }
+
+    /**
+     * 以队伍为维度 统计 瑞恒日报 分页数据 以任务井分组小计工作量
+     * @param reports
+     * @return
+     */
+    private List<IotRhDailyReportRespVO> buildWellRhDailyReports(List<IotRhDailyReportDO> reports, IotRhDailyReportPageReqVO pageReqVO) {
+        if (CollUtil.isEmpty(reports)) {
+            return Collections.emptyList();
+        }
+        // 设备部门信息
+        Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(reports, IotRhDailyReportDO::getDeptId));
+        // key项目id   value项目合同号
+        Map<Long, String> projectPair = new HashMap<>();
+        //  key任务id     value任务井号-施工区域
+        Map<Long, String> taskPair = new HashMap<>();
+        // key任务id   value设计注气量
+        Map<Long, String> taskExtPropertyPair = new HashMap<>();
+        // key施工状态数据字典value   value施工状态数据字典label
+        Map<String, String> constructStatusPair = new HashMap<>();
+        // key非生产时间原因数据字典value   value非生产时间原因数据字典label
+        Map<String, String> nptReasonPair = new HashMap<>();
+        // 搬迁安装天数
+        Map<Long, BigDecimal> relocationDaysPair = new HashMap<>();
+
+        // key部门id-队伍id   value 任务井当年累计注气量
+        Map<String, BigDecimal> groupGasInjectionPair = new HashMap<>();
+        // key部门id-队伍id   value 任务井当年累计注水量
+        Map<String, BigDecimal> groupWaterInjectionPair = new HashMap<>();
+        // key部门id-队伍id   value 任务井当年累计用电量
+        Map<String, BigDecimal> groupPowerPair = new HashMap<>();
+        // key部门id-队伍id   value 任务井当年累计油耗
+        Map<String, BigDecimal> groupFuelPair = new HashMap<>();
+        // key部门id-队伍id    value 任务井注气时间小计
+        Map<String, BigDecimal> groupGasTimePair = new HashMap<>();
+        // key部门id-队伍id    value 任务井非生产时间小计
+        Map<String, BigDecimal> groupNoProductTimePair = new HashMap<>();
+        // key部门id-队伍id    value 任务井小计平均运行时效
+        Map<String, BigDecimal> groupTransTimePair = new HashMap<>();
+
+        // key小组最后1条记录id   value 任务井当年累计注气量
+        Map<Long, BigDecimal> groupIdGasInjectionPair = new HashMap<>();
+        // key小组最后1条记录id   value 任务井当年累计注水量
+        Map<Long, BigDecimal> groupIdWaterInjectionPair = new HashMap<>();
+        // key小组最后1条记录id   value 任务井当年累计用电量
+        Map<Long, BigDecimal> groupIdPowerPair = new HashMap<>();
+        // key小组最后1条记录id   value 任务井当年累计油耗
+        Map<Long, BigDecimal> groupIdFuelPair = new HashMap<>();
+        // key小组最后1条记录id    value 任务井注气时间小计
+        Map<Long, BigDecimal> groupIdGasTimePair = new HashMap<>();
+        // key小组最后1条记录id    value 任务井非生产时间小计
+        Map<Long, BigDecimal> groupIdNoProductTimePair = new HashMap<>();
+        // key小组最后1条记录id    value 任务井小计平均运行时效
+        Map<Long, BigDecimal> groupIdTransTimePair = new HashMap<>();
+
+
+        // 查询 当前分页 所有部门 任务井 日报数据 小计工作量
+        IotRhDailyReportPageReqVO currentTaskReqVO = new IotRhDailyReportPageReqVO();
+        currentTaskReqVO.setTaskIds(convertSet(reports, IotRhDailyReportDO::getTaskId));
+        currentTaskReqVO.setDeptIds(convertSet(reports, IotRhDailyReportDO::getDeptId));
+        currentTaskReqVO.setCreateTime(pageReqVO.getCreateTime());
+        currentTaskReqVO.setProjectIds(pageReqVO.getProjectIds());
+        currentTaskReqVO.setTaskIds(pageReqVO.getTaskIds());
+        List<IotRhDailyReportDO> deptTaskDailyReports = iotRhDailyReportMapper.dailyReports(currentTaskReqVO);
+
+        // 以 deptId-taskId 为唯一键 小计日报工作量
+        if (CollUtil.isNotEmpty(deptTaskDailyReports)) {
+            deptTaskDailyReports.forEach(report -> {
+                String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
+                // 注气量
+                if (groupGasInjectionPair.containsKey(uniqueKey)) {
+                    BigDecimal tempGasInjection = groupGasInjectionPair.get(uniqueKey);
+                    BigDecimal tempResult = tempGasInjection.add(report.getDailyGasInjection());
+                    groupGasInjectionPair.put(uniqueKey, tempResult);
+                } else {
+                    groupGasInjectionPair.put(uniqueKey, report.getDailyGasInjection());
+                }
+                // 注水量
+                if (groupWaterInjectionPair.containsKey(uniqueKey)) {
+                    BigDecimal tempWaterInjection = groupWaterInjectionPair.get(uniqueKey);
+                    BigDecimal tempResult = tempWaterInjection.add(report.getDailyWaterInjection());
+                    groupWaterInjectionPair.put(uniqueKey, tempResult);
+                } else {
+                    groupWaterInjectionPair.put(uniqueKey, report.getDailyWaterInjection());
+                }
+                // 电量
+                if (groupPowerPair.containsKey(uniqueKey)) {
+                    BigDecimal tempPower = groupPowerPair.get(uniqueKey);
+                    BigDecimal tempResult = tempPower.add(report.getDailyPowerUsage());
+                    groupPowerPair.put(uniqueKey, tempResult);
+                } else {
+                    groupPowerPair.put(uniqueKey, report.getDailyPowerUsage());
+                }
+                // 油耗
+                if (groupFuelPair.containsKey(uniqueKey)) {
+                    BigDecimal tempFuel = groupFuelPair.get(uniqueKey);
+                    BigDecimal tempResult = tempFuel.add(report.getDailyOilUsage());
+                    groupFuelPair.put(uniqueKey, tempResult);
+                } else {
+                    groupFuelPair.put(uniqueKey, report.getDailyOilUsage());
+                }
+                // 注气时间
+                if (groupGasTimePair.containsKey(uniqueKey)) {
+                    BigDecimal tempGasTime = groupGasTimePair.get(uniqueKey);
+                    BigDecimal tempResult = tempGasTime.add(report.getDailyInjectGasTime());
+                    groupGasTimePair.put(uniqueKey, tempResult);
+                } else {
+                    groupGasTimePair.put(uniqueKey, report.getDailyInjectGasTime());
+                }
+                // 非生产时间
+                if (groupNoProductTimePair.containsKey(uniqueKey)) {
+                    BigDecimal tempNoProductTime = groupNoProductTimePair.get(uniqueKey);
+                    BigDecimal tempResult = tempNoProductTime.add(report.getNonProductionTime());
+                    groupNoProductTimePair.put(uniqueKey, tempResult);
+                } else {
+                    groupNoProductTimePair.put(uniqueKey, report.getNonProductionTime());
+                }
+            });
+        }
+
+        // 查询 deptId-taskId 分组内最后1条记录id 设置展开列标识
+        List<IotRhDailyReportDO> currentGroupIds = iotRhDailyReportService.rhDeptDailyReportsGroupIds(currentTaskReqVO);
+        // key部门id-任务id   value小组内最后1条记录id
+        Map<String, Long> groupIdPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(currentGroupIds)) {
+            currentGroupIds.forEach(groupId -> {
+                String uniqueKey = StrUtil.join("-", groupId.getDeptId(), groupId.getTaskId());
+                groupIdPair.put(uniqueKey, groupId.getId());
+            });
+        }
+
+        // 设置 分组内最后1条记录id 与 deptId-taskId 唯一键的对应关系
+        if (CollUtil.isNotEmpty(groupIdPair)) {
+            groupIdPair.forEach((uniqueKey, groupId) -> {
+                if (groupGasInjectionPair.containsKey(uniqueKey)) {
+                    groupIdGasInjectionPair.put(groupId, groupGasInjectionPair.get(uniqueKey));
+                }
+                if (groupWaterInjectionPair.containsKey(uniqueKey)) {
+                    groupIdWaterInjectionPair.put(groupId, groupWaterInjectionPair.get(uniqueKey));
+                }
+                if (groupPowerPair.containsKey(uniqueKey)) {
+                    groupIdPowerPair.put(groupId, groupPowerPair.get(uniqueKey));
+                }
+                if (groupFuelPair.containsKey(uniqueKey)) {
+                    groupIdFuelPair.put(groupId, groupFuelPair.get(uniqueKey));
+                }
+                if (groupGasTimePair.containsKey(uniqueKey)) {
+                    groupIdGasTimePair.put(groupId, groupGasTimePair.get(uniqueKey));
+                }
+                if (groupNoProductTimePair.containsKey(uniqueKey)) {
+                    groupIdNoProductTimePair.put(groupId, groupNoProductTimePair.get(uniqueKey));
+                }
+
+            });
+        }
+
+        // key部门id  value产能
+        AtomicReference<Map<Long, BigDecimal>> capacityPair = new AtomicReference<>(new HashMap<>());
+        // 施工状态 字典数据
+        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("constructionStatus");
+        // 非生产时间原因 字典数据
+        List<DictDataDO> nptReasonDictData = dictDataService.getDictDataListByDictType("nptReason");
+        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
+            constructionStatusDictData.forEach(data -> {
+                constructStatusPair.put(data.getValue(), data.getLabel());
+            });
+        }
+        if (CollUtil.isNotEmpty(nptReasonDictData)) {
+            nptReasonDictData.forEach(data -> {
+                nptReasonPair.put(data.getValue(), data.getLabel());
+            });
+        }
+        DataPermissionUtils.executeIgnore(() -> {
+            // 查询日报关联的项目信息
+            IotProjectInfoPageReqVO reqVO = new IotProjectInfoPageReqVO();
+            reqVO.setProjectIds(convertList(reports, IotRhDailyReportDO::getProjectId));
+            List<IotProjectInfoDO> projects = iotProjectInfoService.getIotProjectInfos(reqVO);
+            if (CollUtil.isNotEmpty(projects)) {
+                projects.forEach(project -> {
+                    projectPair.put(project.getId(), project.getContractName());
+                });
+            }
+            // 查询日报关联的任务信息
+            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
+            taskReqVO.setTaskIds(convertList(reports, IotRhDailyReportDO::getTaskId));
+            List<IotProjectTaskDO> tasks = iotProjectTaskService.projectTasks(taskReqVO);
+            if (CollUtil.isNotEmpty(tasks)) {
+                tasks.forEach(task -> {
+                    taskPair.put(task.getId(), task.getWellName());
+                    if (CollUtil.isNotEmpty(task.getExtProperty())) {
+                        List<IotTaskAttrModelProperty> taskAttrs = task.getExtProperty();
+                        if (CollUtil.isNotEmpty(taskAttrs)) {
+                            // 找到 设计注气量 属性 对应的值
+                            taskAttrs.forEach(attr -> {
+                                if ("设计注气量".equals(attr.getName()) && StrUtil.isNotBlank(attr.getActualValue())) {
+                                    taskExtPropertyPair.put(task.getId(), attr.getActualValue());
+                                }
+                            });
+                        }
+                    }
+                });
+            }
+            // 查询当前日报所属施工队伍中包含 增压机 的产能
+            capacityPair.set(iotRhDailyReportService.queryCapacities(convertList(reports, IotRhDailyReportDO::getDeptId)));
+            // 查询每个任务的搬迁安装天数
+            List<IotRhDailyReportDO> relocationDays = iotRhDailyReportService.relocationDays(null);
+            if (CollUtil.isNotEmpty(relocationDays)) {
+                relocationDays.forEach(day -> {
+                    relocationDaysPair.put(day.getDeptId(), day.getRelocationDays());
+                });
+            }
+        });
+        // 2. 拼接数据
+        return BeanUtils.toBean(reports, IotRhDailyReportRespVO.class, (reportVO) -> {
+            if (ObjUtil.isNotEmpty(reportVO.getTransitTime())) {
+                // 获取原始小数
+                BigDecimal transitTime = reportVO.getTransitTime();
+                // 乘以100转换为百分比数值
+                BigDecimal percentage = transitTime.multiply(BigDecimal.valueOf(100));
+                // 格式化保留2位小数
+                DecimalFormat df = new DecimalFormat("0.00");
+                String transitTimeRate = df.format(percentage) + "%";
+                // 赋值
+                reportVO.setTransitTimeRate(transitTimeRate);
+            }
+            // 2.1 拼接部门信息
+            findAndThen(deptMap, reportVO.getDeptId(), dept -> reportVO.setDeptName(dept.getName()));
+
+            // 小组内最后1条记录标识
+            findAndThen(groupIdGasInjectionPair, reportVO.getId(), gasInjection -> reportVO.setLastGroupIdFlag("Y"));
+            // 小组内累计注气量
+            findAndThen(groupIdGasInjectionPair, reportVO.getId(), gasInjection -> reportVO.setGroupIdGasInjection(gasInjection));
+            // 小组内累计注水量
+            findAndThen(groupIdWaterInjectionPair, reportVO.getId(), waterInjection -> reportVO.setGroupIdWaterInjection(waterInjection));
+            // 小组内累计用电量
+            findAndThen(groupIdPowerPair, reportVO.getId(), power -> reportVO.setGroupIdPower(power));
+            // 小组内累计油耗
+            findAndThen(groupIdFuelPair, reportVO.getId(), fuel -> reportVO.setGroupIdFuel(fuel));
+            // 小组内累计注气时间
+            findAndThen(groupIdGasTimePair, reportVO.getId(), gasTime -> reportVO.setGroupIdGasTime(gasTime));
+            // 小组内累计非生产时间
+            findAndThen(groupIdNoProductTimePair, reportVO.getId(), noProductTime -> reportVO.setGroupIdNoProductTime(noProductTime));
+            // 小组内累计运行时效
+            // findAndThen(groupIdTransTimePair, reportVO.getId(), transitTime -> reportVO.setGroupIdTransitTime(transitTime));
+
+            // 2.2 日报关联的项目信息
+            findAndThen(projectPair, reportVO.getProjectId(), contractName -> reportVO.setContractName(contractName));
+            // 2.3 日报关联的任务信息
+            findAndThen(taskPair, reportVO.getTaskId(), taskName -> reportVO.setTaskName(taskName));
+            // 2.4 设计注气量
+            findAndThen(taskExtPropertyPair, reportVO.getTaskId(), designInjection -> reportVO.setDesignInjection(designInjection));
+            // 2.5 搬迁安装天数
+            findAndThen(relocationDaysPair, reportVO.getDeptId(), relocationDays -> reportVO.setRelocationDays(relocationDays));
+            // 2.6 产能
+            findAndThen(capacityPair.get(), reportVO.getDeptId(), capacity -> reportVO.setCapacity(capacity));
+            // 施工状态 数据字典
+            findAndThen(constructStatusPair, reportVO.getConstructionStatus(), statusLabel -> reportVO.setConstructionStatusName(statusLabel));
+            // 非生产时间原因 数据字典
+            findAndThen(nptReasonPair, reportVO.getNptReason(), statusLabel -> reportVO.setNptReasonName(statusLabel));
+        });
+    }
+
     @GetMapping("/export-excel")
     @Operation(summary = "导出瑞恒日报 Excel")
     @PreAuthorize("@ss.hasPermission('pms:iot-rh-daily-report:export')")

+ 20 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrhdailyreport/vo/IotRhDailyReportRespVO.java

@@ -183,4 +183,24 @@ public class IotRhDailyReportRespVO {
     private BigDecimal wellTotalPower;
     @Schema(description = "井累计油耗")
     private BigDecimal wellTotalFuel;
+
+
+    @Schema(description = "小组内累计注气量")
+    private BigDecimal groupIdGasInjection;
+    @Schema(description = "小组内累计注水量")
+    private BigDecimal groupIdWaterInjection;
+    @Schema(description = "小组内累计用电量")
+    private BigDecimal groupIdPower;
+    @Schema(description = "小组内累计油耗")
+    private BigDecimal groupIdFuel;
+
+    @Schema(description = "小组内累计注气时间")
+    private BigDecimal groupIdGasTime;
+    @Schema(description = "小组内累计非生产时间")
+    private BigDecimal groupIdNoProductTime;
+    @Schema(description = "小组内平均运行时效")
+    private BigDecimal groupIdTransitTime;
+
+    @Schema(description = "小组内最后1条记录标识 Y N")
+    private String lastGroupIdFlag = "N";
 }

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrhdailyreport/vo/IotRhDailyReportStatisticsRespVO.java

@@ -61,4 +61,12 @@ public class IotRhDailyReportStatisticsRespVO {
     @ExcelProperty("运行时效")
     private String transitTimePercent;
 
+    @Schema(description = "队伍数量")
+    private Integer teamCount = 0;
+    @Schema(description = "施工 队伍数量")
+    private Integer sgTeamCount = 0;
+    @Schema(description = "施工准备 队伍数量")
+    private Integer zbTeamCount = 0;
+    @Schema(description = "驻地待命 队伍数量")
+    private Integer zddmTeamCount = 0;
 }

+ 19 - 3
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/IotStaticController.java

@@ -1552,23 +1552,34 @@ public class IotStaticController {
                 }
             });
         }
-        // 查询出指定时间区间内 已经填写的日报数量
-        reqVO.setStatisticFlag("Y");
+        // 查询出指定时间区间内 已经填写的日报数量 存在注气时间是0 但是 注气量 不为0的情况
+        // reqVO.setStatisticFlag("Y");
         List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
         // key项目部id     value项目部包含的队伍指定时间区域内日报数量
         Map<Long, Integer> projectReportPair = new HashMap<>();
+        // key项目部id     value项目部注气量
+        Map<Long, BigDecimal> projectGasInjectionPair = new HashMap<>();
         if (CollUtil.isNotEmpty(dailyReports)) {
             // 整理出每个项目部下的队伍填报的日报数量
             dailyReports.forEach(report -> {
                 if (CollUtil.isNotEmpty(projectTeamPair)) {
                     projectTeamPair.forEach((projectDeptId, teamDeptIds) -> {
                         if (teamDeptIds.contains(report.getDeptId())) {
+                            // 项目部日报数量
                             if (projectReportPair.containsKey(projectDeptId)) {
                                 Integer tempCount = projectReportPair.get(projectDeptId);
                                 projectReportPair.put(projectDeptId, ++tempCount);
                             } else {
                                 projectReportPair.put(projectDeptId, 1);
                             }
+                            // 项目部 注气量
+                            if (projectGasInjectionPair.containsKey(projectDeptId)) {
+                                BigDecimal tempGasInjection = projectGasInjectionPair.get(projectDeptId);
+                                BigDecimal subtotal = tempGasInjection.add(report.getDailyGasInjection());
+                                projectGasInjectionPair.put(projectDeptId, subtotal);
+                            } else {
+                                projectGasInjectionPair.put(projectDeptId, report.getDailyGasInjection());
+                            }
                         }
                     });
                 }
@@ -1606,6 +1617,11 @@ public class IotStaticController {
                             DeptDO dept = allDeptPair.get(projectDeptId);
                             rateVo.setSort(dept.getSort());
                         }
+                        // 设置每个项目部的注气量
+                        if (projectGasInjectionPair.containsKey(projectDeptId)) {
+                            BigDecimal gasInjection = projectGasInjectionPair.get(projectDeptId);
+                            rateVo.setGasInjection(gasInjection);
+                        }
                         // 遍历每个项目部 获取每个项目部下队伍数量
                         Integer currentTeamNum = teamIds.size();
                         rateVo.setTeamCount(currentTeamNum);
@@ -1741,7 +1757,7 @@ public class IotStaticController {
         if (CollUtil.isNotEmpty(projectTeamIds)) {
             // 查询出指定时间区间内 指定队伍id集合 已经填写的日报数量
             reqVO.setDeptIds(projectTeamIds);
-            reqVO.setStatisticFlag("Y");
+            // reqVO.setStatisticFlag("Y");
             List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
             // 筛选出每个队伍的日报
             if (CollUtil.isNotEmpty(dailyReports)) {

+ 7 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/stat/vo/ProjectUtilizationRateVo.java

@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pms.controller.admin.stat.vo;
 import lombok.Data;
 import lombok.ToString;
 
+import java.math.BigDecimal;
+
 /**
  * 项目部维度 设备利用率
  */
@@ -35,6 +37,11 @@ public class ProjectUtilizationRateVo {
      */
     private Double utilizationRate;
 
+    /**
+     * 注气量
+     */
+    private BigDecimal gasInjection;
+
     /**
      * 排序规则
      */

+ 47 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotrhdailyreport/IotRhDailyReportMapper.java

@@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
 import cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.stat.vo.YearTotalGas;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotrhdailyreport.IotRhDailyReportDO;
@@ -40,6 +41,52 @@ public interface IotRhDailyReportMapper extends BaseMapperX<IotRhDailyReportDO>
                                              @Param("taskIds") Collection<Long> taskIds,
                                              @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);
 
+    /**
+     * 根据 井号 查询 瑞恒日报 按照队伍分组 小计
+     * @param page
+     * @param reqVO
+     * @param projectIds
+     * @return
+     */
+    IPage<IotRhDailyReportDO> rhWellNameDailyReports(IPage<IotRhDailyReportDO> page, @Param("reqVO") IotRhDailyReportPageReqVO reqVO,
+                                             @Param("taskIds") Collection<Long> taskIds,
+                                             @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);
+
+    /**
+     * 根据 井号 查询 瑞恒日报 按照队伍分组 小计
+     * @param page
+     * @param reqVO
+     * @param projectIds
+     * @return
+     */
+    IPage<IotRhDailyReportDO> rhDeptDailyReports(IPage<IotRhDailyReportDO> page, @Param("reqVO") IotRhDailyReportPageReqVO reqVO,
+                                                     @Param("taskIds") Collection<Long> taskIds,
+                                                     @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);
+
+    /**
+     * 根据 井号 查询 瑞恒日报 按照队伍分组 小计 查询小组内最后1条记录id
+     * @param page
+     * @param reqVO
+     * @param projectIds
+     * @return
+     */
+    @TenantIgnore
+    List<IotRhDailyReportDO> rhWellNameDailyReportsGroupIds(IPage<IotRhDailyReportDO> page, @Param("reqVO") IotRhDailyReportPageReqVO reqVO,
+                                                     @Param("taskIds") Collection<Long> taskIds,
+                                                     @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);
+
+    /**
+     * 以队伍为维度 查询 井号 分组后的 瑞恒日报 按照任务井分组 小计 查询小组内最后1条记录id
+     * @param page
+     * @param reqVO
+     * @param projectIds
+     * @return
+     */
+    @TenantIgnore
+    List<IotRhDailyReportDO> rhDeptDailyReportsGroupIds(IPage<IotRhDailyReportDO> page, @Param("reqVO") IotRhDailyReportPageReqVO reqVO,
+                                                            @Param("taskIds") Collection<Long> taskIds,
+                                                            @Param("projectIds") Collection<Long> projectIds, @Param("deptIds") Collection<Long> deptIds);
+
     /**
      * 瑞恒日报汇总统计
      * @param page

+ 7 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttask/IotProjectTaskService.java

@@ -72,4 +72,11 @@ public interface IotProjectTaskService {
 
     PageResult<IotProjectTaskDO> taskList(IotProjectTaskPageReqVO taskDO,Collection<Long> deptIds);
 
+    /**
+     * 查询所有任务井号信息 过滤数据权限
+     *
+     * @param pageReqVO 列表查询
+     * @return 项目信息任务列表
+     */
+    List<IotProjectTaskDO> taskWellNames(IotProjectTaskPageReqVO pageReqVO);
 }

+ 22 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotprojecttask/IotProjectTaskServiceImpl.java

@@ -25,6 +25,7 @@ import javax.annotation.Resource;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_PROJECT_TASK_NOT_EXISTS;
@@ -265,4 +266,25 @@ public class IotProjectTaskServiceImpl implements IotProjectTaskService {
         return new PageResult<>(taskDOIPage.getRecords(), taskDOIPage.getTotal());
     }
 
+    @Override
+    public List<IotProjectTaskDO> taskWellNames(IotProjectTaskPageReqVO pageReqVO) {
+        List<IotProjectTaskDO> tasks = iotProjectTaskMapper.selectList(pageReqVO);
+        // 井号有重名的情况 需要去重
+        if (CollUtil.isNotEmpty(tasks)) {
+            // 1. 以wellName为key去重,保留第一个出现的元素(推荐,符合“只显示1条”的默认需求)
+            Map<String, IotProjectTaskDO> wellNameTaskMap = tasks.stream()
+                    // 可选:过滤wellName为null/空字符串的元素,避免null作为key导致的异常
+                    .filter(task -> task.getWellName() != null && !task.getWellName().trim().isEmpty())
+                    .collect(Collectors.toMap(
+                            IotProjectTaskDO::getWellName,  // Map的key:井号wellName(去重依据)
+                            task -> task,                   // Map的value:任务对象本身
+                            (existingTask, newTask) -> existingTask  // 重复key时:保留已存在的元素(即第一个出现的元素)
+                    ));
+
+            // 2. 将Map的value转为List,得到去重后的集合
+            tasks = wellNameTaskMap.values().stream().collect(Collectors.toList());
+        }
+        return tasks;
+    }
+
 }

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

@@ -55,6 +55,38 @@ public interface IotRhDailyReportService {
      */
     PageResult<IotRhDailyReportDO> getIotRhDailyReportPage(IotRhDailyReportPageReqVO pageReqVO);
 
+    /**
+     * 获得瑞恒日报分页 以井为维度统计工作量
+     *
+     * @param pageReqVO 分页查询
+     * @return 瑞恒日报分页
+     */
+    PageResult<IotRhDailyReportDO> teamReports(IotRhDailyReportPageReqVO pageReqVO);
+
+    /**
+     * 获得瑞恒日报分页 以队伍为维度统计工作量
+     *
+     * @param pageReqVO 分页查询
+     * @return 瑞恒日报分页
+     */
+    PageResult<IotRhDailyReportDO> wellReports(IotRhDailyReportPageReqVO pageReqVO);
+
+    /**
+     * 根据 井号 查询 瑞恒日报 按照队伍分组 小计 查询小组内最后1条记录id
+     *
+     * @param pageReqVO 列表查询
+     * @return 瑞恒日报 列表 小组内最后 的记录
+     */
+    List<IotRhDailyReportDO> rhWellNameDailyReportsGroupIds(IotRhDailyReportPageReqVO pageReqVO);
+
+    /**
+     * 根据 队伍 查询 瑞恒日报 按照任务井分组 小计 查询小组内最后1条记录id
+     *
+     * @param pageReqVO 列表查询
+     * @return 瑞恒日报 列表 小组内最后 的记录
+     */
+    List<IotRhDailyReportDO> rhDeptDailyReportsGroupIds(IotRhDailyReportPageReqVO pageReqVO);
+
     /**
      * 瑞恒日报汇总统计
      *

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

@@ -716,6 +716,84 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         return new PageResult<>(page.getRecords(), page.getTotal());
     }
 
+    @Override
+    public PageResult<IotRhDailyReportDO> teamReports(IotRhDailyReportPageReqVO pageReqVO) {
+        // 查询选择部门下面所有子部门
+        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 PageResult<>(Collections.emptyList(), 0L);
+        }
+        // 检查taskName不为空但taskIds为空的情况
+        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
+            return new PageResult<>(Collections.emptyList(), 0L);
+        }
+        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhWellNameDailyReports(
+                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
+                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
+
+        return new PageResult<>(page.getRecords(), page.getTotal());
+    }
+
+    @Override
+    public PageResult<IotRhDailyReportDO> wellReports(IotRhDailyReportPageReqVO pageReqVO) {
+        // 查询选择部门下面所有子部门
+        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 PageResult<>(Collections.emptyList(), 0L);
+        }
+        // 检查taskName不为空但taskIds为空的情况
+        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
+            return new PageResult<>(Collections.emptyList(), 0L);
+        }
+        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhDeptDailyReports(
+                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
+                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
+
+        return new PageResult<>(page.getRecords(), page.getTotal());
+    }
+
+    @Override
+    public List<IotRhDailyReportDO> rhWellNameDailyReportsGroupIds(IotRhDailyReportPageReqVO pageReqVO) {
+        // 查询选择部门下面所有子部门
+        Set<Long> ids = new HashSet<>();
+        if (Objects.nonNull(pageReqVO.getDeptId())) {
+            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+            ids.add(pageReqVO.getDeptId());
+            pageReqVO.setDeptIds(ids);
+        }
+        List<IotRhDailyReportDO> groupIds = iotRhDailyReportMapper.rhWellNameDailyReportsGroupIds(
+                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
+                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
+        return groupIds;
+    }
+
+    @Override
+    public List<IotRhDailyReportDO> rhDeptDailyReportsGroupIds(IotRhDailyReportPageReqVO pageReqVO) {
+        // 查询选择部门下面所有子部门
+        Set<Long> ids = new HashSet<>();
+        if (Objects.nonNull(pageReqVO.getDeptId())) {
+            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+            ids.add(pageReqVO.getDeptId());
+            pageReqVO.setDeptIds(ids);
+        }
+        List<IotRhDailyReportDO> groupIds = iotRhDailyReportMapper.rhDeptDailyReportsGroupIds(
+                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
+                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
+        return groupIds;
+    }
+
     @Override
     public List<IotRhDailyReportStatisticsRespVO> statistics(IotRhDailyReportPageReqVO pageReqVO) {
         List<IotRhDailyReportStatisticsRespVO> result = new ArrayList<>();
@@ -745,13 +823,13 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         // 点击项目部 显示 下属队伍的数据
         // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认查询所有项目部数据
         if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
-            result = statisticsByProjectDept(dailyReports, 157L);
+            result = statisticsByProjectDept(dailyReports, 157L, pageReqVO);
         } else {
             // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
             DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
             if ("1".equals(selectedDept.getType())) {
                 // 以项目部为维度汇总数据
-                result = statisticsByProjectDept(dailyReports, pageReqVO.getDeptId());
+                result = statisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO);
             } else if ("2".equals(selectedDept.getType())) {
                 // 以队伍为维度汇总数据
                 result = statisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId());
@@ -761,7 +839,7 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
             } else {
                 // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
                 // 以项目部为维度汇总数据
-                result = statisticsByProjectDept(dailyReports, pageReqVO.getDeptId());
+                result = statisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO);
             }
         }
         // 根据result集合内对象的 sort 属性正序排列 sort 类型为 integer 类型
@@ -780,7 +858,8 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
      * @param rootDeptId 根部门ID(如157L为瑞恒根部门,或其他公司级部门ID)
      * @return 项目部维度统计结果列表
      */
-    private List<IotRhDailyReportStatisticsRespVO> statisticsByProjectDept(List<IotRhDailyReportDO> dailyReports, Long rootDeptId) {
+    private List<IotRhDailyReportStatisticsRespVO> statisticsByProjectDept(List<IotRhDailyReportDO> dailyReports,
+                                                                           Long rootDeptId, IotRhDailyReportPageReqVO pageReqVO) {
         List<IotRhDailyReportStatisticsRespVO> result = new ArrayList<>();
 
         Set<Long> projectDeptIds = new HashSet<>();
@@ -801,6 +880,16 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         Map<Long, BigDecimal> cumulativeCapacityPair = new HashMap<>();
         // key队伍id/项目部id   value累计运行时效   累计注气量/累计产能
         Map<Long, BigDecimal> cumulativeTransitTimePair = new HashMap<>();
+        // key项目部id   value项目部下包含的队伍总数
+        Map<Long, Integer> teamCountPair = new HashMap<>();
+        // key项目部id   value项目部下包含的 施工 队伍数量
+        Map<Long, Integer> sgTeamCountPair = new HashMap<>();
+        // key项目部id   value项目部下包含的 施工准备 队伍数量
+        Map<Long, Integer> zbTeamCountPair = new HashMap<>();
+        // key项目部id   value项目部下包含的 驻地待命 队伍数量
+        Map<Long, Integer> zddmTeamCountPair = new HashMap<>();
+        // 队伍id 集合
+        Set<Long> teamIds = new HashSet<>();
 
         // 以项目部为维度统计数据
         // 找到所有项目部与队伍的对应关系
@@ -813,12 +902,79 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         // 构建项目部映射和父子部门关系
         depts.forEach(dept -> {
             if ("2".equals(dept.getType())) {
+                // 项目部
                 projectDeptIds.add(dept.getId());
                 projectDeptPair.put(dept.getId(), dept);
             }
+            if ("3".equals(dept.getType())) {
+                // 队伍
+                teamIds.add(dept.getId());
+            }
             teamProjectIdPair.put(dept.getId(), dept.getParentId());
         });
 
+        LocalDateTime[] createTime = pageReqVO.getCreateTime();
+        // 如果 createTime 包含的时间是 1天则查询 这1天时间内的 队伍总数 施工队伍数量 施工准备队伍数量 驻地待命队伍数量
+        if (ObjUtil.isNotEmpty(createTime)) {
+            LocalDateTime startTime = createTime[0];
+            LocalDateTime endTime = createTime[1];
+            if (ObjUtil.isNotEmpty(startTime) && ObjUtil.isNotEmpty(endTime)) {
+                LocalDate startLocalDate = startTime.toLocalDate();
+                LocalDate endLocalDate = endTime.toLocalDate();
+                if (startLocalDate.isEqual(endLocalDate)) {
+                    // 查询日期区间是 同一天
+                    // 设置每个项目部下的队伍数量
+                    projectDeptPair.forEach((projectDeptId, projectDept) -> {
+                        // 找到每个项目部下的队伍
+                        teamProjectIdPair.forEach((deptId, parentDeptId) -> {
+                            if (parentDeptId.equals(projectDeptId)) {
+                                if (teamCountPair.containsKey(projectDeptId)) {
+                                    Integer tempCount = teamCountPair.get(projectDeptId);
+                                    teamCountPair.put(projectDeptId, ++tempCount);
+                                } else {
+                                    teamCountPair.put(projectDeptId, 1);
+                                }
+                            }
+                        });
+                    });
+                    // 找出日报列表中 状态为 施工 施工准备 驻地待命的 记录
+                    if (CollUtil.isNotEmpty(dailyReports)) {
+                        dailyReports.forEach(report -> {
+                            if (teamProjectIdPair.containsKey(report.getDeptId())) {
+                                // 找到队伍所属的上级项目部
+                                Long projectDeptId = teamProjectIdPair.get(report.getDeptId());
+                                // 施工状态
+                                if ("sg".equals(report.getConstructionStatus())) {
+                                    if (sgTeamCountPair.containsKey(projectDeptId)) {
+                                        Integer tempCount = sgTeamCountPair.get(projectDeptId);
+                                        sgTeamCountPair.put(projectDeptId, ++tempCount);
+                                    } else {
+                                        sgTeamCountPair.put(projectDeptId, 1);
+                                    }
+                                }
+                                if ("zb".equals(report.getConstructionStatus())) {
+                                    if (zbTeamCountPair.containsKey(projectDeptId)) {
+                                        Integer tempCount = zbTeamCountPair.get(projectDeptId);
+                                        zbTeamCountPair.put(projectDeptId, ++tempCount);
+                                    } else {
+                                        zbTeamCountPair.put(projectDeptId, 1);
+                                    }
+                                }
+                                if ("zddm".equals(report.getConstructionStatus())) {
+                                    if (zddmTeamCountPair.containsKey(projectDeptId)) {
+                                        Integer tempCount = zddmTeamCountPair.get(projectDeptId);
+                                        zddmTeamCountPair.put(projectDeptId, ++tempCount);
+                                    } else {
+                                        zddmTeamCountPair.put(projectDeptId, 1);
+                                    }
+                                }
+                            }
+                        });
+                    }
+                }
+            }
+        }
+
         // 查询指定部门下相关设备的产能
         // key队伍id   value队伍下相关设备产能
         Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));
@@ -873,6 +1029,22 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
             statistics.setCumulativePowerConsumption(cumulativePowerConsumptionPair.get(deptId));
             statistics.setCumulativeFuelConsumption(cumulativeOilConsumptionPair.get(deptId));
             statistics.setTransitTime(cumulativeTransitTimePair.get(deptId));
+            // 队伍数量
+            if (CollUtil.isNotEmpty(teamCountPair)) {
+                statistics.setTeamCount(teamCountPair.get(deptId));
+            }
+            // 施工队伍 数量
+            if (CollUtil.isNotEmpty(sgTeamCountPair)) {
+                statistics.setSgTeamCount(sgTeamCountPair.get(deptId));
+            }
+            // 施工准备队伍数量
+            if (CollUtil.isNotEmpty(zbTeamCountPair)) {
+                statistics.setZbTeamCount(zbTeamCountPair.get(deptId));
+            }
+            // 驻地待命 队伍数量
+            if (CollUtil.isNotEmpty(zddmTeamCountPair)) {
+                statistics.setZddmTeamCount(zddmTeamCountPair.get(deptId));
+            }
             result.add(statistics);
         });
 

+ 209 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/iotprojecttask/IotRhDailyReportMapper.xml

@@ -195,6 +195,215 @@
             d.sort ASC;
     </select>
 
+    <select id="rhWellNameDailyReports" resultMap="BaseResultMap"
+            parameterType="cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportPageReqVO">
+        SELECT
+        rdr.*
+        FROM
+        rq_iot_rh_daily_report rdr
+        INNER JOIN system_dept d ON d.id = rdr.dept_id
+        LEFT JOIN system_dept pd ON pd.id = d.parent_id
+        WHERE
+        rdr.deleted = 0
+        AND rdr.dept_id IS NOT NULL
+        <if test="deptIds != null and deptIds.size &gt; 0">
+            AND rdr.dept_id IN
+            <foreach collection="deptIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="projectIds != null and projectIds.size &gt; 0">
+            AND rdr.project_id IN
+            <foreach collection="projectIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="taskIds != null and taskIds.size &gt; 0">
+            AND rdr.task_id IN
+            <foreach collection="taskIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="reqVO.createTime != null and reqVO.createTime.length > 0">
+            <!-- 处理“开始时间”(数组第1位,如 createTime[0] = 2024-01-01 00:00:00) -->
+            <if test="reqVO.createTime[0] != null">
+                AND rdr.create_time &gt;= #{reqVO.createTime[0]}
+            </if>
+            <!-- 处理“结束时间”(数组第2位,如 createTime[1] = 2024-01-31 23:59:59) -->
+            <if test="reqVO.createTime.length > 1 and reqVO.createTime[1] != null">
+                AND rdr.create_time &lt;= #{reqVO.createTime[1]}
+            </if>
+        </if>
+        ORDER BY
+            COALESCE(pd.sort, 999999) ASC,
+            d.sort ASC,
+            DATE(rdr.create_time) DESC;
+    </select>
+
+    <select id="rhWellNameDailyReportsGroupIds" resultMap="BaseResultMap"
+            parameterType="cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportPageReqVO">
+        WITH sorted_data AS (
+        SELECT
+            rdr.id,
+            rdr.dept_id,
+            rdr.task_id,
+        ROW_NUMBER() OVER (
+        PARTITION BY rdr.dept_id, rdr.task_id
+        ORDER BY
+            COALESCE(pd.sort, 999999) DESC,  -- 反转:ASC -> DESC
+            d.sort DESC,                     -- 反转:ASC -> DESC
+            rdr.task_id ASC,                 -- 反转:DESC -> ASC
+            DATE(rdr.create_time) ASC        -- 反转:DESC -> ASC
+        ) AS rn
+        FROM
+        rq_iot_rh_daily_report rdr
+        INNER JOIN system_dept d ON d.id = rdr.dept_id
+        LEFT JOIN system_dept pd ON pd.id = d.parent_id
+        WHERE
+        rdr.deleted = 0
+        AND rdr.dept_id IS NOT NULL
+        <if test="deptIds != null and deptIds.size &gt; 0">
+            AND rdr.dept_id IN
+            <foreach collection="deptIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="projectIds != null and projectIds.size &gt; 0">
+            AND rdr.project_id IN
+            <foreach collection="projectIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="taskIds != null and taskIds.size &gt; 0">
+            AND rdr.task_id IN
+            <foreach collection="taskIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="reqVO.createTime != null and reqVO.createTime.length > 0">
+            <!-- 处理“开始时间”(数组第1位,如 createTime[0] = 2024-01-01 00:00:00) -->
+            <if test="reqVO.createTime[0] != null">
+                AND rdr.create_time &gt;= #{reqVO.createTime[0]}
+            </if>
+            <!-- 处理“结束时间”(数组第2位,如 createTime[1] = 2024-01-31 23:59:59) -->
+            <if test="reqVO.createTime.length > 1 and reqVO.createTime[1] != null">
+                AND rdr.create_time &lt;= #{reqVO.createTime[1]}
+            </if>
+        </if>
+        )
+        SELECT
+            id,
+            dept_id,
+            task_id
+        FROM sorted_data
+        WHERE rn = 1
+    </select>
+
+    <select id="rhDeptDailyReports" resultMap="BaseResultMap"
+            parameterType="cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportPageReqVO">
+        SELECT
+            rdr.*
+        FROM
+            rq_iot_rh_daily_report rdr
+        INNER JOIN system_dept d ON d.id = rdr.dept_id
+        LEFT JOIN system_dept pd ON pd.id = d.parent_id
+        WHERE
+            rdr.deleted = 0
+        AND rdr.dept_id IS NOT NULL
+        <if test="deptIds != null and deptIds.size &gt; 0">
+            AND rdr.dept_id IN
+            <foreach collection="deptIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="projectIds != null and projectIds.size &gt; 0">
+            AND rdr.project_id IN
+            <foreach collection="projectIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="taskIds != null and taskIds.size &gt; 0">
+            AND rdr.task_id IN
+            <foreach collection="taskIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="reqVO.createTime != null and reqVO.createTime.length > 0">
+            <!-- 处理“开始时间”(数组第1位,如 createTime[0] = 2024-01-01 00:00:00) -->
+            <if test="reqVO.createTime[0] != null">
+                AND rdr.create_time &gt;= #{reqVO.createTime[0]}
+            </if>
+            <!-- 处理“结束时间”(数组第2位,如 createTime[1] = 2024-01-31 23:59:59) -->
+            <if test="reqVO.createTime.length > 1 and reqVO.createTime[1] != null">
+                AND rdr.create_time &lt;= #{reqVO.createTime[1]}
+            </if>
+        </if>
+        ORDER BY
+            rdr.task_id DESC,
+            COALESCE(pd.sort, 999999) ASC,
+            d.sort ASC,
+            DATE(rdr.create_time) DESC;
+    </select>
+
+    <select id="rhDeptDailyReportsGroupIds" resultMap="BaseResultMap"
+            parameterType="cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportPageReqVO">
+        WITH sorted_data AS (
+        SELECT
+            rdr.id,
+            rdr.dept_id,
+            rdr.task_id,
+            ROW_NUMBER() OVER (
+            PARTITION BY rdr.dept_id, rdr.task_id
+            ORDER BY
+                rdr.task_id ASC,                 -- 反转:DESC -> ASC
+                COALESCE(pd.sort, 999999) DESC,  -- 反转:ASC -> DESC
+                d.sort DESC,                     -- 反转:ASC -> DESC
+                DATE(rdr.create_time) ASC        -- 反转:DESC -> ASC
+            ) AS rn
+        FROM
+        rq_iot_rh_daily_report rdr
+        INNER JOIN system_dept d ON d.id = rdr.dept_id
+        LEFT JOIN system_dept pd ON pd.id = d.parent_id
+        WHERE
+        rdr.deleted = 0
+        AND rdr.dept_id IS NOT NULL
+        <if test="deptIds != null and deptIds.size &gt; 0">
+            AND rdr.dept_id IN
+            <foreach collection="deptIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="projectIds != null and projectIds.size &gt; 0">
+            AND rdr.project_id IN
+            <foreach collection="projectIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="taskIds != null and taskIds.size &gt; 0">
+            AND rdr.task_id IN
+            <foreach collection="taskIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="reqVO.createTime != null and reqVO.createTime.length > 0">
+            <!-- 处理“开始时间”(数组第1位,如 createTime[0] = 2024-01-01 00:00:00) -->
+            <if test="reqVO.createTime[0] != null">
+                AND rdr.create_time &gt;= #{reqVO.createTime[0]}
+            </if>
+            <!-- 处理“结束时间”(数组第2位,如 createTime[1] = 2024-01-31 23:59:59) -->
+            <if test="reqVO.createTime.length > 1 and reqVO.createTime[1] != null">
+                AND rdr.create_time &lt;= #{reqVO.createTime[1]}
+            </if>
+        </if>
+        )
+        SELECT
+            id,
+            dept_id,
+            task_id
+        FROM sorted_data
+        WHERE rn = 1
+    </select>
+
     <!-- 瑞恒日报汇总统计 -->
     <select id="rhReportStatistics" resultMap="BaseResultMap"
             parameterType="cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportPageReqVO">