Selaa lähdekoodia

pms 瑞恒日报 以任务为维度查询 以井为单位分组小计

zhangcl 1 viikko sitten
vanhempi
commit
f0f6b21aca

+ 557 - 1
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 = "管理后台 - 瑞恒日报")
@@ -216,7 +217,40 @@ public class IotRhDailyReportController {
             }
         }
         PageResult<IotRhDailyReportDO> pageResult = iotRhDailyReportService.teamReports(pageReqVO);
-        return success(new PageResult<>(buildRhDailyReports(pageResult.getList(), pageReqVO), pageResult.getTotal()));
+        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")
@@ -735,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";
 }

+ 36 - 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;
@@ -51,6 +52,41 @@ 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> 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

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

@@ -56,13 +56,37 @@ 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);
+
     /**
      * 瑞恒日报汇总统计
      *

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

@@ -740,6 +740,60 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         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<>();

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

@@ -240,6 +240,170 @@
             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">