Explorar el Código

pms 瑞都看板 相关接口

zhangcl hace 23 horas
padre
commit
ca70bad9c8

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

@@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.depttype.vo.IotDeptTypePageR
 import cn.iocoder.yudao.module.pms.controller.admin.failure.vo.IotFailureReportPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.inspect.order.vo.IotInspectOrderPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.inspect.plan.vo.IotInspectPlanPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceassociate.vo.IotDeviceAssociatePageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
@@ -42,8 +43,10 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectOrderDetailDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectPlanDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcountdata.IotCountDataDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceassociate.IotDeviceAssociateDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotoutbound.IotOutboundDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotrddailyreport.IotRdDailyReportDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotrhdailyreport.IotRhDailyReportDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotrydailyreport.IotRyDailyReportDO;
@@ -58,6 +61,7 @@ import cn.iocoder.yudao.module.pms.dal.mysql.failure.IotFailureReportMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.inspect.IotInspectOrderDetailMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.inspect.IotInspectOrderMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.inspect.IotInspectPlanMapper;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotdeviceassociate.IotDeviceAssociateMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicerunlog.IotDeviceRunLogMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotmainworkorder.IotMainWorkOrderMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotopeationfill.IotOpeationFillMapper;
@@ -182,6 +186,8 @@ public class IotStaticController {
     private IotMainWorkOrderService iotMainWorkOrderService;
     @Autowired
     private IotRyHiDailyReportService iotRyHiDailyReportService;
+    @Resource
+    private IotDeviceAssociateMapper iotDeviceAssociateMapper;
 
 
     @GetMapping("/main/day")
@@ -1456,6 +1462,120 @@ public class IotStaticController {
 
     }
 
+    @Operation(summary = "瑞都 近1周的设备利用率")
+    @GetMapping("/rd/device/sevenDayUtilization")
+    @PermitAll
+    public CommonResult<Map<String, Object>> rdSevenDayUtilization() {
+
+        List<String> lastSevenDays = getLastSevenDays();
+        String first = lastSevenDays.get(0);
+        String last = lastSevenDays.get(lastSevenDays.size() - 1);
+        LocalDateTime startOfDay = getStartOfDay(last);
+        LocalDateTime endOfDay = getEndOfDay(first);
+        LocalDateTime[] createTime = new LocalDateTime[]{startOfDay, endOfDay};
+
+        IotRdDailyReportPageReqVO iotRdDailyReportPageReqVO = new IotRdDailyReportPageReqVO();
+        iotRdDailyReportPageReqVO.setCreateTime(createTime);
+        iotRdDailyReportPageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        PageResult<IotRdDailyReportDO> pageReports = iotRdDailyReportMapper.selectPage(iotRdDailyReportPageReqVO);
+        if (ObjUtil.isEmpty(pageReports)) {
+            return buildEmptyResult(lastSevenDays);
+        }
+        List<IotRdDailyReportDO> reports = pageReports.getList();
+        if (CollUtil.isEmpty(reports)) {
+            return buildEmptyResult(lastSevenDays);
+        }
+
+        // 计算最近7天公司整体的设备利用率
+        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(163l);
+
+        // 设备利用率逻辑调整 只筛选 压裂 连油 主设备 rq_iot_device_associate
+        // 队伍日报中关联的主设备数量 /(队伍下所有主设备数量-封存设备数量)
+        Set<Long> mainDeviceIds = new HashSet<>();
+        Set<Long> fcMainDeviceIds = new HashSet<>();
+        // key设备id   value设备所属部门id
+        Map<Long, Long> mainDeviceIdPair = new HashMap<>();
+        IotDeviceAssociatePageReqVO deviceAssocReqVO = new IotDeviceAssociatePageReqVO();
+        deviceAssocReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        deviceAssocReqVO.setDeptIds(allRhChildDeptIds);
+        PageResult<IotDeviceAssociateDO> pageResult = iotDeviceAssociateMapper.selectPage(deviceAssocReqVO);
+        if (ObjUtil.isNotEmpty(pageResult)) {
+            List<IotDeviceAssociateDO> deviceAssociates = pageResult.getList();
+            // 查询出所有瑞都压裂 连油主设备
+            deviceAssociates.forEach(assoc -> {
+                mainDeviceIds.add(assoc.getDeviceId());
+                mainDeviceIdPair.put(assoc.getDeviceId(), assoc.getDeptId());
+            });
+        }
+        // 所有压裂连油主设备
+        Set<Long> abDeviceIds = new HashSet<>();
+        // 查询瑞都 压裂 连油 主设备详情信息
+        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
+        deviceReqVO.setDeviceIds(new ArrayList<>(mainDeviceIds));
+        List<IotDeviceDO> mainDevices = iotDeviceMapper.selectListAlone(deviceReqVO);
+        // 筛选出 封存 的主设备
+        if (CollUtil.isNotEmpty(mainDevices)) {
+            mainDevices.forEach(device -> {
+                if ("fc".equals(device.getDeviceStatus())) {
+                    fcMainDeviceIds.add(device.getId());
+                } else {
+                    abDeviceIds.add(device.getId());
+                }
+            });
+        }
+
+        // key日期2026-06-08   value日期对应的日报数量
+        Map<String, Set<Long>> dateReportDeviceIdPair = new HashMap<>();
+        reports.forEach(report -> {
+            // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
+            LocalDateTime reportLocalDate = report.getCreateTime();
+            // 将日期格式转换成 字符串
+            String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
+            // 统计日报关联施工AB类设备的利用率
+            Set<Long> reportDeviceIds = report.getDeviceIds();
+            if (CollUtil.isNotEmpty(reportDeviceIds)) {
+                if (dateReportDeviceIdPair.containsKey(reportDateStr)) {
+                    Set<Long> tempDeviceIds = dateReportDeviceIdPair.get(reportDateStr);
+                    tempDeviceIds.addAll(reportDeviceIds);
+                    dateReportDeviceIdPair.put(reportDateStr, tempDeviceIds);
+                } else {
+                    dateReportDeviceIdPair.put(reportDateStr, reportDeviceIds);
+                }
+            }
+        });
+        // 计算每天的设备利用率
+        Map<String, BigDecimal> dateReportUtilizationPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(dateReportDeviceIdPair)) {
+            dateReportDeviceIdPair.forEach((reportDateStr, deviceIds) -> {
+                // 计算每天的所有日报涉及到的压裂连油主设备
+                // 1. 求交集:实际使用的A B类设备
+                Set<Long> utilizedDeviceIds = deviceIds.stream()
+                        .filter(abDeviceIds::contains)
+                        .collect(Collectors.toSet());
+                if (CollUtil.isNotEmpty(abDeviceIds)) {
+                    BigDecimal deviceUtilization = new BigDecimal((double) utilizedDeviceIds.size() / abDeviceIds.size())
+                            .setScale(4, RoundingMode.HALF_UP);
+                    dateReportUtilizationPair.put(reportDateStr, deviceUtilization);
+                }
+            });
+        }
+        // 5. 按日期升序补全最近7天,缺失填0
+        List<String> sortedDays = lastSevenDays.stream()
+                .sorted()                                      // yyyy-MM-dd 字符串自然升序
+                .collect(Collectors.toList());
+        LinkedHashMap<String, BigDecimal> fillMap = new LinkedHashMap<>();
+        sortedDays.forEach(day ->
+                fillMap.put(day, dateReportUtilizationPair.getOrDefault(day, BigDecimal.ZERO))
+        );
+
+        LinkedList<Object> xAxis = new LinkedList<>(fillMap.keySet());
+        LinkedList<Object> fillData = new LinkedList<>(fillMap.values());
+
+        ImmutableMap<String, Serializable> fillResult = ImmutableMap.of("name", "设备利用率~~en**device utilization", "data", fillData);
+        return success(ImmutableMap.of("xAxis", xAxis, "series", ImmutableList.of(fillResult)));
+
+    }
+
     /**
      * 无日报时直接返回全0序列
      */
@@ -3149,6 +3269,158 @@ public class IotStaticController {
         return success(resultNptCounts);
     }
 
+    /**
+     * 瑞都 生产异常 数量
+     * 无工作量 井场待命 维修设备 物资影响 异常/复杂
+     * @return
+     */
+    @GetMapping("/rd/device/productionAbnormality")
+    @PermitAll
+    public CommonResult<List<NptCountVo>> productionAbnormality(IotRdDailyReportPageReqVO reqVO) {
+        if (ObjUtil.isEmpty(reqVO.getCreateTime())) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        if (reqVO.getCreateTime().length < 2) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        // 查询瑞鹰 158l 所有项目部
+        Set<Long> childDeptIds = deptService.getChildDeptIdListFromCache(158l);
+        Map<Long, DeptDO> allDeptPair = deptService.getDeptMap(childDeptIds);
+        Set<String> projectDeptNames = new HashSet<>();
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id   value项目部名称
+        Map<Long, String> projectPair = new HashMap<>();
+        // 队伍id 集合
+        Set<Long> crewIds = new HashSet<>();
+        if (CollUtil.isNotEmpty(allDeptPair)) {
+            allDeptPair.forEach((deptId, dept) -> {
+                if ("2".equals(dept.getType())) {
+                    projectDeptIds.add(deptId);
+                    projectDeptNames.add(dept.getName());
+                    projectPair.put(deptId, dept.getName());
+                }
+                if ("3".equals(dept.getType())) {
+                    // 队伍
+                    crewIds.add(dept.getId());
+                }
+            });
+        }
+        // 查询出指定时间区间内 已经填写的日报数量
+        List<IotRdDailyReportDO> dailyReports = iotRdDailyReportMapper.dailyReports(reqVO);
+
+        List<NptCountVo> resultNptCounts = new ArrayList<>();
+        // no 无工作量
+        Map<String, Integer> noStatusPair = new HashMap<>();
+        // xcdm 井场待命
+        Map<String, Integer> dmStatusPair = new HashMap<>();
+        // wxz 维修设备
+        Map<String, Integer> wxStatusPair = new HashMap<>();
+        // wz 物资影响
+        Map<String, Integer> wzStatusPair = new HashMap<>();
+        // yc 异常/复杂
+        Map<String, Integer> ycStatusPair = new HashMap<>();
+
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            // 整理出每个项目部下的队伍填报的日报数量
+            dailyReports.forEach(report -> {
+                String rdStatus = report.getRdStatus();
+                if ("no".equals(rdStatus)) {
+                    if (noStatusPair.containsKey("no")) {
+                        Integer tempNum = noStatusPair.get("no");
+                        noStatusPair.put("no", ++tempNum);
+                    } else {
+                        noStatusPair.put("no", 1);
+                    }
+                }
+                if ("xcdm".equals(rdStatus)) {
+                    if (dmStatusPair.containsKey("xcdm")) {
+                        Integer tempNum = dmStatusPair.get("xcdm");
+                        dmStatusPair.put("xcdm", ++tempNum);
+                    } else {
+                        dmStatusPair.put("xcdm", 1);
+                    }
+                }
+                if ("wxz".equals(rdStatus)) {
+                    if (wxStatusPair.containsKey("wxz")) {
+                        Integer tempNum = wxStatusPair.get("wxz");
+                        wxStatusPair.put("wxz", ++tempNum);
+                    } else {
+                        wxStatusPair.put("wxz", 1);
+                    }
+                }
+                if ("wz".equals(rdStatus)) {
+                    if (wzStatusPair.containsKey("wz")) {
+                        Integer tempNum = wzStatusPair.get("wz");
+                        wzStatusPair.put("wz", ++tempNum);
+                    } else {
+                        wzStatusPair.put("wz", 1);
+                    }
+                }
+                if ("yc".equals(rdStatus)) {
+                    if (ycStatusPair.containsKey("yc")) {
+                        Integer tempNum = ycStatusPair.get("yc");
+                        ycStatusPair.put("yc", ++tempNum);
+                    } else {
+                        ycStatusPair.put("yc", 1);
+                    }
+                }
+            });
+        }
+        // 无工作量
+        NptCountVo noVo = new NptCountVo();
+        noVo.setNptName("no");
+        if (CollUtil.isNotEmpty(noStatusPair)) {
+            Integer noStatusNum = noStatusPair.get("no");
+            noVo.setTeamCount(noStatusNum);
+        } else {
+            noVo.setTeamCount(0);
+        }
+        resultNptCounts.add(noVo);
+        // 井场待命
+        NptCountVo dmVo = new NptCountVo();
+        dmVo.setNptName("xcdm");
+        if (CollUtil.isNotEmpty(dmStatusPair)) {
+            Integer dmStatusNum = dmStatusPair.get("xcdm");
+            dmVo.setTeamCount(dmStatusNum);
+        } else {
+            dmVo.setTeamCount(0);
+        }
+        resultNptCounts.add(dmVo);
+        // 维修设备
+        NptCountVo wxVo = new NptCountVo();
+        wxVo.setNptName("wxz");
+        if (CollUtil.isNotEmpty(wxStatusPair)) {
+            Integer wxStatusNum = wxStatusPair.get("wxz");
+            wxVo.setTeamCount(wxStatusNum);
+        } else {
+            wxVo.setTeamCount(0);
+        }
+        resultNptCounts.add(wxVo);
+        // 物资影响
+        NptCountVo wzVo = new NptCountVo();
+        wzVo.setNptName("wz");
+        if (CollUtil.isNotEmpty(wzStatusPair)) {
+            Integer wzStatusNum = wzStatusPair.get("wz");
+            wzVo.setTeamCount(wzStatusNum);
+        } else {
+            wzVo.setTeamCount(0);
+        }
+        resultNptCounts.add(wzVo);
+        // 异常/复杂
+        NptCountVo ycVo = new NptCountVo();
+        ycVo.setNptName("yc");
+        if (CollUtil.isNotEmpty(ycStatusPair)) {
+            Integer ycStatusNum = ycStatusPair.get("yc");
+            ycVo.setTeamCount(ycStatusNum);
+        } else {
+            ycVo.setTeamCount(0);
+        }
+        resultNptCounts.add(ycVo);
+        // 按照每种非生产时间队伍数量 降序排列
+        resultNptCounts.sort(Comparator.comparingInt(NptCountVo::getTeamCount).reversed());
+        return success(resultNptCounts);
+    }
+
     /**
      * 瑞鹰 设备利用率 按 队伍 统计
      * @return
@@ -3326,9 +3598,29 @@ public class IotStaticController {
         Map<Long, Long> deviceIdToDeptIdMap = new HashMap<>();
         // key项目部id     value项目部下包含的队伍的 压裂 连油 设备数量
         Map<Long, Integer> projectDevicePair = new HashMap<>();
+
+        // 设备利用率逻辑调整 只筛选 压裂 连油 主设备 rq_iot_device_associate
+        // 队伍日报中关联的主设备数量 /(队伍下所有主设备数量-封存设备数量)
+        Set<Long> mainDeviceIds = new HashSet<>();
+        Set<Long> fcMainDeviceIds = new HashSet<>();
+        // key设备id   value设备所属部门id
+        Map<Long, Long> mainDeviceIdPair = new HashMap<>();
+        IotDeviceAssociatePageReqVO deviceAssocReqVO = new IotDeviceAssociatePageReqVO();
+        deviceAssocReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        deviceAssocReqVO.setDeptIds(childDeptIds);
+        PageResult<IotDeviceAssociateDO> pageResult = iotDeviceAssociateMapper.selectPage(deviceAssocReqVO);
+        if (ObjUtil.isNotEmpty(pageResult)) {
+            List<IotDeviceAssociateDO> deviceAssociates = pageResult.getList();
+            // 查询出所有瑞都压裂 连油主设备
+            deviceAssociates.forEach(assoc -> {
+                mainDeviceIds.add(assoc.getDeviceId());
+                mainDeviceIdPair.put(assoc.getDeviceId(), assoc.getDeptId());
+            });
+        }
+
         if (CollUtil.isNotEmpty(allDeptPair)) {
             allDeptPair.forEach((deptId, dept) -> {
-                if (dept.getName().contains("项目部") ) {
+                if ("2".equals(dept.getType())) {
                     projectDeptIds.add(deptId);
                     projectDeptNames.add(dept.getName());
                     projectPair.put(deptId, dept.getName());
@@ -3486,67 +3778,242 @@ public class IotStaticController {
             });
         }
         // 日报应用前先模拟数据
-        rates.clear();
-        ProjectUtilizationRateVo ylk = new ProjectUtilizationRateVo();
-        ylk.setProjectDeptId(331l);
-        ylk.setProjectDeptName("伊拉克项目部");
-        ylk.setTeamCount(4);
-        ylk.setCumulativeDays(1216l);
-        ylk.setConstructionDays(646);
-        ylk.setUtilizationRate(0.5313);
-        ProjectUtilizationRateVo xj = new ProjectUtilizationRateVo();
-        xj.setProjectDeptId(329l);
-        xj.setProjectDeptName("新疆项目部");
-        xj.setTeamCount(2);
-        xj.setCumulativeDays(852l);
-        xj.setConstructionDays(387);
-        xj.setUtilizationRate(0.4542);
-        ProjectUtilizationRateVo db = new ProjectUtilizationRateVo();
-        db.setProjectDeptId(326l);
-        db.setProjectDeptName("东部项目部");
-        db.setTeamCount(3);
-        db.setCumulativeDays(912l);
-        db.setConstructionDays(261);
-        db.setUtilizationRate(0.2862);
-        ProjectUtilizationRateVo qh = new ProjectUtilizationRateVo();
-        qh.setProjectDeptId(327l);
-        qh.setProjectDeptName("青海项目部");
-        qh.setTeamCount(1);
-        qh.setCumulativeDays(304l);
-        qh.setConstructionDays(179);
-        qh.setUtilizationRate(0.5888);
-        ProjectUtilizationRateVo xnyl = new ProjectUtilizationRateVo();
-        xnyl.setProjectDeptId(325l);
-        xnyl.setProjectDeptName("西南压裂项目部");
-        xnyl.setTeamCount(1);
-        xnyl.setCumulativeDays(304l);
-        xnyl.setConstructionDays(252);
-        xnyl.setUtilizationRate(0.8289);
-        ProjectUtilizationRateVo xnly = new ProjectUtilizationRateVo();
-        xnly.setProjectDeptId(330l);
-        xnly.setProjectDeptName("西南连续油管项目部");
-        xnly.setTeamCount(3);
-        xnly.setCumulativeDays(912l);
-        xnly.setConstructionDays(443);
-        xnly.setUtilizationRate(0.4857);
-        ProjectUtilizationRateVo lby = new ProjectUtilizationRateVo();
-        lby.setProjectDeptId(349l);
-        lby.setProjectDeptName("利比亚项目部");
-        lby.setTeamCount(1);
-        lby.setCumulativeDays(304l);
-        lby.setConstructionDays(21);
-        lby.setUtilizationRate(0.0691);
-        rates.add(ylk);
-        rates.add(xj);
-        rates.add(db);
-        rates.add(qh);
-        rates.add(xnyl);
-        rates.add(xnly);
-        rates.add(lby);
         rates.sort(Comparator.comparingDouble(ProjectUtilizationRateVo::getUtilizationRate).reversed());
         return success(rates);
     }
 
+    /**
+     * 瑞都 时间区间内整体的 设备利用率
+     * @return
+     */
+    @GetMapping("/rd/device/totalUtilizationRate")
+    @PermitAll
+    public CommonResult<BigDecimal> rdTotalUtilizationRate(IotRdDailyReportPageReqVO reqVO) {
+        if (ObjUtil.isEmpty(reqVO.getCreateTime())) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        if (reqVO.getCreateTime().length < 2) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        // 计算公司整体的设备利用率
+        BigDecimal totalDeviceUtilization = BigDecimal.ZERO;
+
+        // 查询瑞都 163l 所有项目部
+        Set<Long> childDeptIds = deptService.getChildDeptIdListFromCache(163l);
+        Map<Long, DeptDO> allDeptPair = deptService.getDeptMap(childDeptIds);
+        Set<String> projectDeptNames = new HashSet<>();
+        Set<Long> projectDeptIds = new HashSet<>();
+        // key项目部id   value项目部名称
+        Map<Long, String> projectPair = new HashMap<>();
+        // key项目部id   value项目部包含的队伍id集合
+        Map<Long, Set<Long>> projectTeamPair = new HashMap<>();
+        // 设备ID到其所属部门ID的映射
+        Map<Long, Long> deviceIdToDeptIdMap = new HashMap<>();
+
+        // 20260611 设备利用率逻辑调整 只筛选 压裂 连油 主设备 rq_iot_device_associate
+        // 队伍日报中关联的主设备数量 /(队伍下所有主设备数量-封存设备数量)
+        Set<Long> mainDeviceIds = new HashSet<>();
+        Set<Long> fcMainDeviceIds = new HashSet<>();
+        // key设备id   value设备所属部门id
+        Map<Long, Long> mainDeviceIdPair = new HashMap<>();
+        IotDeviceAssociatePageReqVO deviceAssocReqVO = new IotDeviceAssociatePageReqVO();
+        deviceAssocReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        deviceAssocReqVO.setDeptIds(childDeptIds);
+        PageResult<IotDeviceAssociateDO> pageResult = iotDeviceAssociateMapper.selectPage(deviceAssocReqVO);
+        if (ObjUtil.isNotEmpty(pageResult)) {
+            List<IotDeviceAssociateDO> deviceAssociates = pageResult.getList();
+            // 查询出所有瑞都压裂 连油主设备
+            deviceAssociates.forEach(assoc -> {
+                mainDeviceIds.add(assoc.getDeviceId());
+                mainDeviceIdPair.put(assoc.getDeviceId(), assoc.getDeptId());
+            });
+        }
+        // 过滤掉 封存 的 压裂 连油 主设备id集合
+        Set<Long> abDeviceIds = new HashSet<>();
+
+        if (CollUtil.isNotEmpty(allDeptPair)) {
+            allDeptPair.forEach((deptId, dept) -> {
+                if ("2".equals(dept.getType())) {
+                    projectDeptIds.add(deptId);
+                    projectDeptNames.add(dept.getName());
+                    projectPair.put(deptId, dept.getName());
+                }
+            });
+            // 遍历所有部门
+            allDeptPair.forEach((deptId, dept) -> {
+                // 找出每个项目部下的队伍
+                if (projectPair.containsKey(dept.getParentId())) {
+                    // 获得当前部门的上级项目部
+                    projectPair.forEach((projectDeptId, projectDept) -> {
+                        if (projectDeptId.equals(dept.getParentId())) {
+                            if (projectTeamPair.containsKey(projectDeptId)) {
+                                Set<Long> teamIds = projectTeamPair.get(projectDeptId);
+                                teamIds.add(deptId);
+                                projectTeamPair.put(projectDeptId, teamIds);
+                            } else {
+                                Set<Long> teamIds = new HashSet<>();
+                                teamIds.add(deptId);
+                                projectTeamPair.put(projectDeptId, teamIds);
+                            }
+                        }
+                    });
+                }
+            });
+
+            IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
+            deviceReqVO.setDeviceIds(new ArrayList<>(mainDeviceIds));
+            List<IotDeviceDO> utilizeDevices = iotDeviceMapper.selectListAlone(deviceReqVO);
+            // 筛选出项目部下包含的队伍的设备数量
+            // 过滤掉 封存 的 压裂 连油 主设备
+            if (CollUtil.isNotEmpty(utilizeDevices)) {
+                utilizeDevices.forEach(device -> {
+                    if ("fc".equals(device.getDeviceStatus())) {
+                        fcMainDeviceIds.add(device.getId());
+                    } else {
+                        abDeviceIds.add(device.getId());
+                    }
+                });
+            }
+        }
+        // 查询出指定时间区间内 已经填写的日报 再根据设备id 进行筛选 通过设备id 建立项目部 与 日报数量之间的关联
+        // 判断日报中 device_ids 字段中每个设备 是否属于需要统计的 压裂 连油 设备
+        List<IotRdDailyReportDO> dailyReports = iotRdDailyReportMapper.dailyReports(reqVO);
+        // key项目部id     value项目部包含的队伍指定时间区域内日报数量
+        Map<Long, Integer> projectReportPair = new HashMap<>();
+        // 日报涉及到的施工设备id集合
+        Set<Long> reportDeviceIds = new HashSet<>();
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            // 整理出每个项目部下的队伍填报的日报数量
+            dailyReports.forEach(report -> {
+                // 筛选出日报中施工的 设备id集合
+                if (CollUtil.isNotEmpty(report.getDeviceIds())) {
+                    reportDeviceIds.addAll(report.getDeviceIds());
+                }
+                if (CollUtil.isNotEmpty(projectTeamPair)) {
+                    projectTeamPair.forEach((projectDeptId, teamDeptIds) -> {
+                        Set<Long> tempDeviceIds = report.getDeviceIds();
+                        // 判断 集合 tempDeviceIds 中的任意的 ‘设备id’ 是否包含在 集合 teamDeptIds 中
+                        // 判断tempDeviceIds中的任意设备所属部门是否在当前项目部的队伍部门中
+                        boolean hasMatchingDevice = CollUtil.isNotEmpty(tempDeviceIds) && tempDeviceIds.stream()
+                                .map(deviceIdToDeptIdMap::get) // 通过映射表获取设备所属部门ID
+                                .filter(Objects::nonNull) // 过滤掉非统计范围内的设备(避免空指针)
+                                .anyMatch(teamDeptIds::contains); // 任意设备所属部门在队伍部门中则匹配
+                        if (hasMatchingDevice) {
+                            if (projectReportPair.containsKey(projectDeptId)) {
+                                Integer tempCount = projectReportPair.get(projectDeptId);
+                                projectReportPair.put(projectDeptId, ++tempCount);
+                            } else {
+                                projectReportPair.put(projectDeptId, 1);
+                            }
+                        }
+                    });
+                }
+            });
+
+            // 计算公司整体的设备利用率
+            // 指定时间范围内 日报中所有施工的设备数量/总设备数量 (A B类)
+            // abDeviceIds所有AB类设备  reportDeviceIds日报中用到的所有设备 交集求出日报中使用到的AB类设备
+            if (CollUtil.isNotEmpty(abDeviceIds) && CollUtil.isNotEmpty(reportDeviceIds)) {
+                // 1. 求交集:实际使用的A B类设备
+                Set<Long> utilizedDeviceIds = reportDeviceIds.stream()
+                        .filter(abDeviceIds::contains)
+                        .collect(Collectors.toSet());
+                // 2. 计算设备利用率(实际使用设备数 / 总设备数)
+                // 转换为BigDecimal进行计算,保留4位小数
+                totalDeviceUtilization = BigDecimal.valueOf(utilizedDeviceIds.size())
+                        .divide(BigDecimal.valueOf(abDeviceIds.size()), 4, RoundingMode.HALF_UP);
+            }
+        }
+
+        return success(totalDeviceUtilization);
+    }
+
+    /**
+     * 瑞都 时间区间内整体的 工作量统计
+     * 压裂层数 连油井数
+     * @return
+     */
+    @GetMapping("/rd/device/workloadStatistics")
+    @PermitAll
+    public CommonResult<Map<String, Object>> rdWorkloadStatistics(IotRdDailyReportPageReqVO reqVO) {
+        if (ObjUtil.isEmpty(reqVO.getCreateTime())) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+        if (reqVO.getCreateTime().length < 2) {
+            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("layers", 0.0);
+        result.put("wells", 0.0);
+
+        // 查询出指定时间区间内 已经填写的日报 再根据设备id 进行筛选 通过设备id 建立项目部 与 日报数量之间的关联
+        // 判断日报中 device_ids 字段中每个设备 是否属于需要统计的 压裂 连油 设备
+        List<IotRdDailyReportDO> dailyReports = iotRdDailyReportMapper.dailyReports(reqVO);
+        // 日报涉及到的施工设备id集合
+        Set<Long> reportDeviceIds = new HashSet<>();
+        // key工作量标识   value累计 段数 累计施工-层
+        Map<String, BigDecimal> cumulativeWorkingLayersPair = new HashMap<>();
+        // 连油井数
+        Set<Long> cumulativeWells = new HashSet<>();
+        if (CollUtil.isNotEmpty(dailyReports)) {
+            // 整理出每个项目部下的队伍填报的日报数量
+            dailyReports.forEach(report -> {
+                // 筛选出日报中施工的 设备id集合
+                if (CollUtil.isNotEmpty(report.getDeviceIds())) {
+                    reportDeviceIds.addAll(report.getDeviceIds());
+                }
+                // 设置每个任务的工作量数据  单位相同的工作量值作合并处理
+                List<IotTaskAttrModelProperty> taskAttrs = report.getExtProperty();
+                // 段数 累计施工-层
+                BigDecimal tempTotalCumulativeWorkingLayers = BigDecimal.ZERO;
+                if (CollUtil.isNotEmpty(taskAttrs)) {
+                    for (IotTaskAttrModelProperty attr : taskAttrs) {
+                        // 工作量单位
+                        String unit = attr.getUnit();
+                        // 工作量属性的实际值
+                        String actualValueStr = attr.getActualValue();
+                        // 处理实际值:避免null或非数字字符串导致的异常
+                        BigDecimal actualValue = BigDecimal.ZERO;
+                        if (StrUtil.isNotBlank(actualValueStr)) {
+                            try {
+                                actualValue = new BigDecimal(actualValueStr);
+                            } catch (NumberFormatException e) {
+                                // 若字符串格式错误,默认按0处理(可根据业务调整)
+                                actualValue = BigDecimal.ZERO;
+                            }
+                        }
+                        if ("段数".equals(unit)) {
+                            // 累计施工层
+                            tempTotalCumulativeWorkingLayers = tempTotalCumulativeWorkingLayers.add(actualValue);
+                            if (cumulativeWorkingLayersPair.containsKey("cumulativeWorkingLayers")) {
+                                BigDecimal tempWorkingLayer = cumulativeWorkingLayersPair.get("cumulativeWorkingLayers");
+                                cumulativeWorkingLayersPair.put("cumulativeWorkingLayers", tempTotalCumulativeWorkingLayers.add(tempWorkingLayer));
+                            } else {
+                                cumulativeWorkingLayersPair.put("cumulativeWorkingLayers", tempTotalCumulativeWorkingLayers);
+                            }
+                        }
+                    }
+                }
+                if (ObjUtil.isNotEmpty(report.getTaskId()) && "wg".equals(report.getRdStatus())) {
+                    cumulativeWells.add(report.getTaskId());
+                }
+            });
+
+        }
+        // 压裂层数
+        if (CollUtil.isNotEmpty(cumulativeWorkingLayersPair)) {
+            cumulativeWorkingLayersPair.forEach((key, layers) -> {
+                result.put("layers", layers);
+            });
+        }
+        // 连油井数 完工 的任务井
+        if (CollUtil.isNotEmpty(cumulativeWells)) {
+            result.put("wells", cumulativeWells.size());
+        }
+        return success(result);
+    }
+
     /**
      * 瑞都 设备利用率 按 项目部 统计
      * @return

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

@@ -1126,8 +1126,6 @@ public class IotRdDailyReportServiceImpl implements IotRdDailyReportService {
         // key工作量标识   value累计 台次 当日泵车台次
         Map<String, BigDecimal> cumulativePumpTripsPair = new HashMap<>();
 
-
-
         // 查询 瑞都 施工状态 字典数据 筛选出施工设备为 LY 的记录
         Set<String> lyStatuses = new HashSet<>();
         List<DictDataDO> rdStatuses = dictDataService.getDictDataListByDictType("rdStatus");