Procházet zdrojové kódy

Merge remote-tracking branch 'origin/master'

lipenghui před 1 týdnem
rodič
revize
6367390c14
15 změnil soubory, kde provedl 979 přidání a 589 odebrání
  1. 263 407
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotopeationfill/IotOpeationFillController.java
  2. 62 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotopeationfill/vo/IotOpeationFillWithAttrsVO.java
  3. 19 9
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrydailyreport/IotRyDailyReportController.java
  4. 20 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/TDDeviceMapper.java
  5. 44 5
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotopeationfill/IotOpeationFillMapper.java
  6. 25 9
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotrydailyreport/IotRyDailyReportMapper.java
  7. 68 38
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/IotOperationPlanJob.java
  8. 4 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/DeviceServiceImpl.java
  9. 3 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IDeviceService.java
  10. 13 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotopeationfill/IotOpeationFillService.java
  11. 55 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotopeationfill/IotOpeationFillServiceImpl.java
  12. 65 58
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrhdailyreport/IotRhDailyReportServiceImpl.java
  13. 1 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrydailyreport/IotRyDailyReportService.java
  14. 108 46
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrydailyreport/IotRyDailyReportServiceImpl.java
  15. 229 16
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotOpeationFillMapper.xml

+ 263 - 407
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotopeationfill/IotOpeationFillController.java

@@ -1,33 +1,23 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill;
 
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.common.exception.ServiceException;
-import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmodel.vo.IotModelPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmodeltemplateattrs.vo.IotModelTemplateAttrsRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo.*;
 import cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.IotRhDailyReportSaveReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.IotRyDailyReportPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.IotRyDailyReportSaveReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.DeviceVO;
-import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
-import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcountdata.IotCountDataDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcountdata.IotCountListDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicecountdata.IotDeviceCountData;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO;
-import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodel.IotModelDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO1;
-import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotThingsModelDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillOrderDO;
 
 import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.YfDeviceDO;
 
-import cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant;
 import cn.iocoder.yudao.module.pms.service.IDeviceService;
 import cn.iocoder.yudao.module.pms.service.iotopeationfill.IotOpeationFillService;
 
@@ -37,7 +27,7 @@ import cn.iocoder.yudao.module.pms.service.yanfan.YfDeviceService;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
 import com.aliyun.tea.utils.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -49,7 +39,6 @@ import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.Operation;
 
 import javax.annotation.security.PermitAll;
-import javax.validation.constraints.*;
 import javax.validation.*;
 import javax.servlet.http.*;
 import java.math.BigDecimal;
@@ -60,6 +49,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.*;
 import java.io.IOException;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
@@ -80,6 +70,7 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
 @RestController
 @RequestMapping("/rq/iot-opeation-fill")
 @Validated
+@Slf4j
 public class IotOpeationFillController {
 
     @Resource
@@ -361,61 +352,7 @@ public class IotOpeationFillController {
         }
     }
 
-    /**
-     * 处理累计逻辑
-     */
-    /*private void processSummationLogic(List<IotOpeationFillSaveReqVO> allFillData) {
-        // 按modelId分组,便于查找
-        Map<Long, List<IotOpeationFillSaveReqVO>> modelIdMap = allFillData.stream()
-                .filter(fill -> fill.getModelId() != null)
-                .collect(Collectors.groupingBy(IotOpeationFillSaveReqVO::getModelId));
-
-        // 找出需要累计的数据
-        List<IotOpeationFillSaveReqVO> sumDataList = allFillData.stream()
-                .filter(fill -> {
-                    if (fill.getIsSum() != 1) {
-                        return false;
-                    }
-
-                    String defaultValue = fill.getDefaultValue();
-                    // 同时检查null和空字符串
-                    if (defaultValue == null || defaultValue.isEmpty()) {
-                        return false;
-                    }
-
-                    // 如果还需要排除纯空格的情况
-                    if (defaultValue.trim().isEmpty()) {
-                        return false;
-                    }
-
-                    return true;
-                })
-                .collect(Collectors.toList());
-
-
-        for (IotOpeationFillSaveReqVO fill : sumDataList) {
-            try {
-                Long refModelId = Long.parseLong(fill.getDefaultValue());
-                List<IotOpeationFillSaveReqVO> targetFills = modelIdMap.get(refModelId);
 
-                if (CollectionUtils.isEmpty(targetFills)) {
-                    continue;
-                }
-
-                for (IotOpeationFillSaveReqVO targetFill : targetFills) {
-                    if (fill.getSumId() == 1) {
-                        // 需要累加的情况
-                        processAccumulation(fill, targetFill);
-                    } else if (fill.getSumId() == 0) {
-                        // 直接赋值的情况
-                        fill.setTotalRunTime(new BigDecimal(targetFill.getFillContent()));
-                    }
-                }
-            } catch (NumberFormatException e) {
-                //log.warn("DefaultValue转换失败: {}", fill.getDefaultValue());
-            }
-        }
-    }*/
 
     /**
      * 处理累计逻辑(优化后:批量查询历史数据)
@@ -428,9 +365,7 @@ public class IotOpeationFillController {
 
         // 筛选需要累计的数据(不变)
         List<IotOpeationFillSaveReqVO> sumDataList = allFillData.stream()
-                .filter(fill -> 1 == fill.getIsSum()
-                        && StringUtils.isEmpty(fill.getDefaultValue())
-                        && StringUtils.isEmpty(fill.getDefaultValue().trim()))
+                .filter(fill -> 1 == fill.getIsSum())
                 .collect(Collectors.toList());
 
         if (CollectionUtils.isEmpty(sumDataList)) {
@@ -592,23 +527,6 @@ public class IotOpeationFillController {
         }
     }
 
-    /**
-     * 批量保存日志
-     */
-    /*private void batchSaveLogs(List<IotDeviceRunLogDO> logDOList) {
-        for (IotDeviceRunLogDO log : logDOList) {
-            IotDeviceRunLogDO existingData = iotOpeationFillService.reportData(log);
-            if (existingData == null) {
-                iotOpeationFillService.insertLog1(log);
-            } else {
-                if (log.getIsSum() == 0) {
-                    iotOpeationFillService.updateLog(log);
-                } else {
-                    iotOpeationFillService.updateSumLog(log);
-                }
-            }
-        }
-    }*/
 
     /**
      * 批量保存日志(优化后:批量查询+批量插入+批量更新)
@@ -685,38 +603,7 @@ public class IotOpeationFillController {
         return deptMap;
     }
 
-    /**
-     * 生成日报
-     */
-    /*private void generateDailyReports(List<IotDeviceRunLogDO> logDOList,
-                                      Map<String, Set<Long>> deptMap,
-                                      LocalDate createDate,
-                                      Integer userId) {
-        // 按设备分组处理
-        Map<Long, List<IotDeviceRunLogDO>> deviceLogsMap = logDOList.stream()
-                .collect(Collectors.groupingBy(IotDeviceRunLogDO::getDeviceId));
-
-        for (Map.Entry<Long, List<IotDeviceRunLogDO>> entry : deviceLogsMap.entrySet()) {
-            List<IotDeviceRunLogDO> deviceLogs = entry.getValue();
-            if (CollectionUtils.isEmpty(deviceLogs)) {
-                continue;
-            }
-
-            IotDeviceRunLogDO sampleLog = deviceLogs.get(0);
-            IotOpeationFillDO reportQuery = new IotOpeationFillDO();
-            reportQuery.setDeviceId(sampleLog.getDeviceId());
-            reportQuery.setCreateTime(sampleLog.getCreateTime());
-
-            IotOpeationFillDO fillStatus = iotOpeationFillService.isReport(reportQuery);
-            fillStatus.setUserId(userId);
 
-            if (fillStatus != null && fillStatus.getIsReport() != null &&
-                    fillStatus.getIsReport() == 1) {
-
-                processDepartmentReport(deviceLogs, fillStatus, deptMap, createDate);
-            }
-        }
-    }*/
     private void generateDailyReports(List<IotDeviceRunLogDO> logDOList,
                                       Map<String, Set<Long>> deptMap,
                                       LocalDate createDate,
@@ -761,22 +648,7 @@ public class IotOpeationFillController {
         });
     }
 
-    /**
-     * 处理部门日报生成
-     */
-    /*private void processDepartmentReport(List<IotDeviceRunLogDO> deviceLogs,
-                                         IotOpeationFillDO fillStatus,
-                                         Map<String, Set<Long>> deptMap,
-                                         LocalDate createDate) {
-        Set<Long> rhIdList = deptMap.get("RH");
-        Set<Long> ryIdList = deptMap.get("RY");
 
-        if (rhIdList.contains(fillStatus.getDeptId())) {
-            generateRhDailyReport(deviceLogs, fillStatus, createDate);
-        } else if (ryIdList.contains(fillStatus.getDeptId())) {
-            generateRyDailyReport(deviceLogs, fillStatus, createDate);
-        }
-    }*/
 
     /**
      * 处理部门日报生成(新增descMap缓存)
@@ -796,33 +668,7 @@ public class IotOpeationFillController {
         }
     }
 
-    /**
-     * 生成RH日报
-     */
-    /*private void generateRhDailyReport(List<IotDeviceRunLogDO> deviceLogs,
-                                       IotOpeationFillDO fillStatus,
-                                       LocalDate createDate) {
-        IotRhDailyReportSaveReqVO saveReqVO = new IotRhDailyReportSaveReqVO();
-        Map<String, Object> reportData = BeanUtil.beanToMap(saveReqVO);
-
-        for (IotDeviceRunLogDO log : deviceLogs) {
-            IotDeviceRunLogDO descDO = iotOpeationFillService.getDesc(log);
-            if (descDO != null && descDO.getPointName() != null) {
-                String pointName = descDO.getPointName();
-                if (reportData.containsKey(pointName)) {
-                    reportData.put(pointName, log.getFillContent());
-                }
-            }
-        }
-
-        IotRhDailyReportSaveReqVO finalReport = BeanUtil.mapToBean(reportData,
-                IotRhDailyReportSaveReqVO.class, false);
-        finalReport.setDeptId(fillStatus.getDeptId());
-        finalReport.setFillOrderCreateTime(createDate.atStartOfDay());
-        finalReport.setCreator(String.valueOf(fillStatus.getUserId()));
 
-        iotRhDailyReportService.createIotRhDailyReport(finalReport);
-    }*/
 
     /**
      * 生成RH日报(使用缓存的descMap)
@@ -849,38 +695,7 @@ public class IotOpeationFillController {
         iotRhDailyReportService.createIotRhDailyReport(finalReport);
     }
 
-    /**
-     * 生成RY日报
-     */
-    /*private void generateRyDailyReport(List<IotDeviceRunLogDO> deviceLogs,
-                                       IotOpeationFillDO fillStatus,
-                                       LocalDate createDate) {
-        IotRyDailyReportSaveReqVO saveReqVO = new IotRyDailyReportSaveReqVO();
-        Map<String, Object> reportData = BeanUtil.beanToMap(saveReqVO);
-
-        for (IotDeviceRunLogDO log : deviceLogs) {
-            IotDeviceRunLogDO descDO = iotOpeationFillService.getDesc(log);
-            if (descDO != null && descDO.getPointName() != null) {
-                String pointName = descDO.getPointName();
-                if (reportData.containsKey(pointName)) {
-                    reportData.put(pointName, log.getFillContent());
-                }
-            }
-        }
-
-        IotRyDailyReportSaveReqVO finalReport = BeanUtil.mapToBean(reportData,
-                IotRyDailyReportSaveReqVO.class, false);
-        finalReport.setDeptId(fillStatus.getDeptId());
-        finalReport.setFillOrderCreateTime(createDate.atStartOfDay());
-        finalReport.setCreator(String.valueOf(fillStatus.getUserId()));
-
-        if (fillStatus.getDeviceCategoryId() != null &&
-                fillStatus.getDeviceCategoryId() == 228) {
-            finalReport.setProjectClassification("2");
-        }
 
-        iotRyDailyReportService.createIotRyDailyReport(finalReport);
-    }*/
     private void generateRyDailyReport(List<IotDeviceRunLogDO> deviceLogs,
                                        IotOpeationFillDO fillStatus,
                                        LocalDate createDate,
@@ -1087,258 +902,299 @@ public class IotOpeationFillController {
 
     //**************
 
-    // 新VO类,用于返回包含属性详情的分页结果
-    @Data
-    public class IotOpeationFillWithAttrsVO extends IotOpeationFillDO {
-        // 保留IotOpeationFillDO的所有属性
-        // 新增属性详情字段
-        private List<IotModelTemplateAttrsDO1> attrsDetail;
-    }
-
     @GetMapping("/orderFillpage1")
     @Operation(summary = "获得运行记录填报分页")
     @PreAuthorize("@ss.hasPermission('rq:iot-opeation-fill:query')")
-    public CommonResult<PageResult<IotOpeationFillWithAttrsVO>> getIotOpeationFillWithAttrsPage1(@Valid IotOpeationFillPageVO pageReqVO) throws SQLException {
-        // 1. 获取分页数据
-        PageResult<IotOpeationFillDO> fillList = iotOpeationFillService.fillListPage(pageReqVO);
-
-        // 2. 转换为新的VO类型(包含属性详情)
-        List<IotOpeationFillWithAttrsVO> resultList = new ArrayList<>();
-
-        for (IotOpeationFillDO fillDO : fillList.getList()) {
-            IotOpeationFillWithAttrsVO vo = BeanUtils.toBean(fillDO, IotOpeationFillWithAttrsVO.class);
+    public CommonResult<PageResult<IotOpeationFillWithAttrsVO>> getIotOpeationFillWithAttrsPage1(
+            @Valid IotOpeationFillPageVO pageReqVO) throws Exception {
 
-            // 3. 为每个分页项获取属性详情
-            IotModelTemplateAttrsRespVO attrsReqVO = new IotModelTemplateAttrsRespVO();
-            attrsReqVO.setDeviceId(fillDO.getDeviceId());
-            attrsReqVO.setDeviceCode(fillDO.getDeviceCode()); // 假设分页接口返回了deviceCode
-            attrsReqVO.setCreateTime(fillDO.getCreateTime().toLocalDate());
-            attrsReqVO.setDeviceCategoryId(fillDO.getDeviceCategoryId());
+        // 1. 分页查询主数据(不变)
+        PageResult<IotOpeationFillDO> fillPage = iotOpeationFillService.fillListPage(pageReqVO);
+        List<IotOpeationFillDO> fillList = fillPage.getList();
+        /*if (CollectionUtils.isEmpty(fillList)) {
+            return success(BeanUtils.toBean(fillList, IotOpeationFillWithAttrsVO.class));
 
+        }*/
 
-            // 4. 调用原属性详情逻辑
-            List<IotModelTemplateAttrsDO1> attrsDetail = getAttrsDetail(attrsReqVO);
-            vo.setAttrsDetail(attrsDetail);
-
-            resultList.add(vo);
-        }
+        // 2. 批量预处理参数,避免循环中重复操作
+        //List<Long> deviceIds = fillList.stream().map(IotOpeationFillDO::getDeviceId).distinct().collect(Collectors.toList());
+        List<String> deviceCodes = fillList.stream().map(IotOpeationFillDO::getDeviceCode).distinct().collect(Collectors.toList());
+        //Set<LocalDate> createDates = fillList.stream().map(doObj -> doObj.getCreateTime().toLocalDate()).collect(Collectors.toSet());
 
-        // 5. 创建新的分页结果
-        PageResult<IotOpeationFillWithAttrsVO> pageResult = new PageResult<>(
-                resultList,
-                fillList.getTotal()
+        // 3. 批量查询公共数据(一次查询,全局复用)
+        // 3.1 批量查询设备状态(判断是否为虚拟设备)
+        List<YfDeviceDO> allDevice = yfDeviceService.getAllDevice(); // 仅查1次,而非循环中查N次
+        Map<String, YfDeviceDO> deviceStatusMap = allDevice.stream()
+                .collect(Collectors.toMap(
+                        YfDeviceDO::getSerialNumber,
+                        Function.identity(),
+                        (oldVal, newVal) -> newVal
+                ));
+        // 3.2 批量查询isReport状态(避免循环查询)
+        Map<Long, Integer> deviceReportMap = iotOpeationFillService.batchGetIsReport(
+                fillList.stream().map(doObj -> {
+                    IotOpeationFillDO query = new IotOpeationFillDO();
+                    query.setDeviceId(doObj.getDeviceId());
+                    query.setCreateTime(doObj.getCreateTime().toLocalDate().atStartOfDay());
+                    return query;
+                }).collect(Collectors.toList())
         );
+        // 3.3 批量查询orderDO数据
+        Map<Long, IotOpeationFillDO> deviceOrderMap = iotOpeationFillService.batchGetOrderDO(
+                fillList.stream().map(doObj -> {
+                    IotOpeationFillDO query = new IotOpeationFillDO();
+                    query.setDeviceId(doObj.getDeviceId());
+                    query.setCreateTime(doObj.getCreateTime().toLocalDate().atStartOfDay());
+                    return query;
+                }).collect(Collectors.toList())
+        );
+
+        // 4. 并行处理分页数据(利用多核CPU,非IO密集型操作适合并行)
+        List<IotOpeationFillWithAttrsVO> resultList = fillList.parallelStream().map(fillDO -> {
+            try {
+                IotOpeationFillWithAttrsVO vo = BeanUtils.toBean(fillDO, IotOpeationFillWithAttrsVO.class);
+                LocalDate createDate = fillDO.getCreateTime().toLocalDate();
+
+                // 构建参数VO
+                IotModelTemplateAttrsRespVO attrsReqVO = new IotModelTemplateAttrsRespVO();
+                attrsReqVO.setDeviceId(fillDO.getDeviceId());
+                attrsReqVO.setDeviceCode(fillDO.getDeviceCode());
+                attrsReqVO.setCreateTime(createDate);
+                attrsReqVO.setDeviceCategoryId(fillDO.getDeviceCategoryId());
+                // 调用优化后的属性详情查询(带缓存和批量查询)
+                List<IotModelTemplateAttrsDO1> attrsDetail = getAttrsDetailOptimized(
+                        attrsReqVO, deviceStatusMap, deviceReportMap, deviceOrderMap);
+
+                vo.setAttrsDetail(attrsDetail);
+                return vo;
+            } catch (Exception e) {
+                log.error("处理设备[{}]属性详情失败", fillDO.getDeviceId(), e);
+                // 降级处理:返回空属性详情,避免整个分页失败
+                IotOpeationFillWithAttrsVO vo = BeanUtils.toBean(fillDO, IotOpeationFillWithAttrsVO.class);
+                vo.setAttrsDetail(Collections.emptyList());
+                return vo;
+            }
+        }).collect(Collectors.toList());
 
+        // 5. 构建返回结果
+        PageResult<IotOpeationFillWithAttrsVO> pageResult = new PageResult<>(resultList, fillPage.getTotal());
         return success(pageResult);
     }
 
-    // 提取属性详情逻辑为私有方法
-    private List<IotModelTemplateAttrsDO1> getAttrsDetail(IotModelTemplateAttrsRespVO vo) throws SQLException {
-        // 以下是您原getAttrs接口的核心逻辑,保持不变
-        //判断是否为虚拟设备
-        //如果是走原来逻辑
-        //不是走虚拟设备逻辑
-        IotOpeationFillDO fillDO = new IotOpeationFillDO();
-        fillDO.setDeviceId(vo.getDeviceId());
-        fillDO.setCreateTime(vo.getCreateTime().atStartOfDay());
-        IotOpeationFillDO fillDO1 = iotOpeationFillService.isReport(fillDO);
-
-        List<IotModelTemplateAttrsDO1> result = new ArrayList<>();
-        List<IotModelTemplateAttrsDO> list = iotOpeationFillService.getAttrsById(vo);
-
-        if (fillDO1.getIsReport() != null && fillDO1.getIsReport() == 1) {
-            IotOpeationFillDO fillDO2 = iotOpeationFillService.orderDO(fillDO);
+    /**
+     * 优化后的属性详情查询:批量查询+缓存复用+减少冗余计算
+     */
+    private List<IotModelTemplateAttrsDO1> getAttrsDetailOptimized(
+            IotModelTemplateAttrsRespVO vo,
+            Map<String, YfDeviceDO> deviceStatusMap,
+            Map<Long, Integer> deviceReportMap,
+            Map<Long, IotOpeationFillDO> deviceOrderMap) throws SQLException {
+
+        Long deviceId = vo.getDeviceId();
+        String deviceCode = vo.getDeviceCode();
+        LocalDate createDate = vo.getCreateTime();
+
+        // 1. 复用批量查询结果(避免重复数据库查询)
+        Integer isReport = deviceReportMap.getOrDefault(deviceId, 0);
+        IotOpeationFillDO fillDO2 = deviceOrderMap.get(deviceId);
+        YfDeviceDO yfDevice = deviceStatusMap.get(deviceCode);
+        boolean isVirtualDevice = yfDevice != null && yfDevice.getStatus() == 3;
+
+        // 2. 批量查询属性模板(一次查询)
+        List<IotModelTemplateAttrsDO> attrsList = iotOpeationFillService.getAttrsByIdBatch(
+                Collections.singletonList(vo)); // 可扩展为多设备批量查询
+
+        if (CollectionUtils.isEmpty(attrsList)) {
+            return Collections.emptyList();
+        }
 
-            List<IotOpeationFillDO> reportList = new ArrayList<>();
-            List<IotOpeationFillDO> reportList1 = new ArrayList<>();
+        // 3. 按isReport分支处理(优化数据查询逻辑)
+        if (isReport != null && isReport == 1) {
+            handleReportDeviceAttrs(attrsList, fillDO2);
+        } else {
+            handleNormalDeviceAttrs(attrsList, vo, isVirtualDevice, createDate);
+        }
 
-            if (fillDO2 != null) {
-                reportList = iotOpeationFillService.reportList(fillDO2);
-                reportList1 = iotOpeationFillService.reportList1(fillDO2);
+        // 4. 分组处理(提前分组,避免重复流处理)
+        List<IotModelTemplateAttrsDO> sumList = new ArrayList<>();
+        List<IotModelTemplateAttrsDO> nonSumList = new ArrayList<>();
+        for (IotModelTemplateAttrsDO attrsDO : attrsList) {
+            if (attrsDO.getIsSum() == 1) {
+                sumList.add(attrsDO);
+            } else {
+                nonSumList.add(attrsDO);
             }
+        }
 
-            for (IotModelTemplateAttrsDO attrsDO : list) {
-                List<IotOpeationFillDO> cxLixt = reportList.stream().filter(e -> e.getOrgName().equals(attrsDO.getName())).collect(Collectors.toList());
-                //虚拟设备取值
-                List<IotOpeationFillDO> cxLixt1 = reportList1.stream().filter(e -> e.getOrgName().equals(attrsDO.getName())).collect(Collectors.toList());
-
-                if (cxLixt.size() > 0) {
-                    // 使用Map按orgName分组存储累加结果
-                    Map<String, String> orgNameToFillContent = new HashMap<>();
-
-                    for (IotOpeationFillDO reportData : cxLixt) {
-                        IotDeviceRunLogDO report = new IotDeviceRunLogDO();
-                        report.setDeviceId(reportData.getDeviceId());
-                        report.setPointName(reportData.getOrgName());
-                        report.setCreateTime(reportData.getCreateTime());
-
-                        IotDeviceRunLogDO reportCx = iotOpeationFillService.reportData(report);
-
-                        String currentContent = "";
-                        if (reportCx == null) {
-                            attrsDO.setFillContent("");
-                        } else {
-                            currentContent = reportCx.getFillContent() != null ? reportCx.getFillContent() : "";
-                        }
-
-                        // 获取当前orgName
-                        String orgName = reportData.getOrgName();
-
-                        // 累加相同orgName的内容
-                        if (orgNameToFillContent.containsKey(orgName)) {
-                            String existingContent = orgNameToFillContent.get(orgName);
-
-                            double existingValue = safeParseInt(existingContent);
-                            double currentValue = safeParseInt(currentContent);
-
-                            if ((existingValue + currentValue) == 0) {
-                                orgNameToFillContent.put(orgName, "");
-                            } else {
-                                orgNameToFillContent.put(orgName, String.valueOf(existingValue + currentValue));
-                            }
-
-                        } else {
-                            orgNameToFillContent.put(orgName, currentContent);
-                        }
-                        attrsDO.setFillContent(orgNameToFillContent.get(reportData.getOrgName()));
-                    }
-                }
-
-                if (cxLixt1.size() > 0) {
-                    for (IotOpeationFillDO reportData : cxLixt1) {
-                        IotDeviceRunLogDO report = new IotDeviceRunLogDO();
-                        report.setDeviceId(reportData.getDeviceId());
-                        report.setPointName(reportData.getOrgName());
-                        report.setCreateTime(reportData.getCreateTime());
-                        IotDeviceRunLogDO reportCx = iotOpeationFillService.reportData(report);
-
-                        String currentContent = "";
-                        if (reportCx != null) {
-                            currentContent = reportCx.getFillContent() != null ? reportCx.getFillContent() : "";
-                            attrsDO.setFillContent(currentContent);
-                        }
-                    }
-                }
+        // 5. 构建结果(减少对象创建)
+        IotModelTemplateAttrsDO1 resultDO = new IotModelTemplateAttrsDO1();
+        resultDO.setSumList(sumList);
+        resultDO.setNonSumList(nonSumList);
+        return Collections.singletonList(resultDO);
+    }
 
+    /**
+     * 处理虚拟设备(isReport=1)的属性详情
+     */
+    private void handleReportDeviceAttrs(List<IotModelTemplateAttrsDO> attrsList, IotOpeationFillDO fillDO2) throws SQLException {
+        if (fillDO2 == null) {
+            attrsList.forEach(attrsDO -> {
+                attrsDO.setFillContent("");
                 attrsDO.setIsCollection(0);
                 attrsDO.setIsSum(0);
-            }
-
-        } else {
-            List<YfDeviceDO> allDevice = yfDeviceService.getAllDevice();
-
-            LocalTime localTime = LocalTime.of(0, 0, 0);
-            LocalTime localTime1 = LocalTime.of(23, 59, 59);
+            });
+            return;
+        }
 
-            LocalDateTime start = LocalDateTime.of(vo.getCreateTime(), localTime);
-            LocalDateTime end = LocalDateTime.of(vo.getCreateTime(), localTime1);
+        // 批量查询reportList和reportList1(一次查询,避免循环)
+        List<IotOpeationFillDO> reportList = iotOpeationFillService.reportList(fillDO2);
+        List<IotOpeationFillDO> reportList1 = iotOpeationFillService.reportList1(fillDO2);
+
+        // 构建属性名到数据的映射(提前分组,避免重复stream过滤)
+        Map<String, List<IotOpeationFillDO>> reportDataMap = reportList.stream()
+                .collect(Collectors.groupingBy(IotOpeationFillDO::getOrgName));
+        Map<String, List<IotOpeationFillDO>> reportDataMap1 = reportList1.stream()
+                .collect(Collectors.groupingBy(IotOpeationFillDO::getOrgName));
+
+        // 批量收集需要查询的runLog参数
+        List<IotDeviceRunLogDO> runLogQueries = new ArrayList<>();
+        reportList.forEach(reportData -> {
+            IotDeviceRunLogDO query = new IotDeviceRunLogDO();
+            query.setDeviceId(reportData.getDeviceId());
+            query.setPointName(reportData.getOrgName());
+            query.setCreateTime(reportData.getCreateTime());
+            //query.setExt1(reportData.getOrgName()); // 存储orgName用于后续映射
+            runLogQueries.add(query);
+        });
 
-            Timestamp startTime = Timestamp.valueOf(start);
-            Timestamp endTime = Timestamp.valueOf(end);
+        // 批量查询runLog数据(一次查询,替代循环查询)
+        Map<Long, String> runLogFillContentMap = new HashMap<>();
+        if (!runLogQueries.isEmpty()) {
+            List<IotDeviceRunLogDO> runLogList = iotOpeationFillService.batchReportData(runLogQueries);
+            runLogFillContentMap = runLogList.stream()
+                    .collect(Collectors.toMap(
+                            logDO -> logDO.getDeviceId(), // orgName
+                            logDO -> logDO.getFillContent() != null ? logDO.getFillContent() : "",
+                            (v1, v2) -> v1 // 冲突时取第一个
+                    ));
+        }
 
-            List<YfDeviceDO> existList = allDevice.stream().filter(e -> e.getStatus() == 3).collect(Collectors.toList());
-            boolean exists1 = existList.stream().anyMatch(yfDeviceDO -> yfDeviceDO.getSerialNumber().equals(vo.getDeviceCode()));
+        // 处理属性数据
+        for (IotModelTemplateAttrsDO attrsDO : attrsList) {
+            String attrName = attrsDO.getName();
+            List<IotOpeationFillDO> cxList = reportDataMap.getOrDefault(attrName, Collections.emptyList());
+            List<IotOpeationFillDO> cxList1 = reportDataMap1.getOrDefault(attrName, Collections.emptyList());
+
+            // 处理reportList数据(累加逻辑)
+            if (!cxList.isEmpty()) {
+                double total = 0;
+                for (IotOpeationFillDO reportData : cxList) {
+                    String content = runLogFillContentMap.getOrDefault(reportData.getOrgName(), "");
+                    total += safeParseInt(content);
+                }
+                attrsDO.setFillContent(total == 0 ? "" : String.valueOf(total));
+            }
 
-            IotDeviceRunLogDO logDO1 = new IotDeviceRunLogDO();
-            logDO1.setDeviceId(vo.getDeviceId());
-            LocalTime local = LocalTime.of(12, 0);
-            logDO1.setCreateTime(LocalDateTime.of(vo.getCreateTime(), local));
+            // 处理reportList1数据(覆盖逻辑)
+            if (!cxList1.isEmpty()) {
+                IotOpeationFillDO reportData = cxList1.get(0); // 取第一条(原逻辑未处理多条,这里保持一致)
+                String content = runLogFillContentMap.getOrDefault(reportData.getOrgName(), "");
+                attrsDO.setFillContent(content);
+            }
 
-            if (exists1) {
-                for (IotModelTemplateAttrsDO attrsDO : list) {
-                    DeviceVO dv = new DeviceVO();
-                    dv.setDeviceName(vo.getDeviceCode().toLowerCase());
-                    dv.setColName(attrsDO.getModelAttr());
-                    dv.setTs(startTime);
-                    dv.setTs1(endTime);
+            attrsDO.setIsCollection(0);
+            attrsDO.setIsSum(0);
+        }
+    }
 
-                    DeviceVO deviceVO = iDeviceService.getYesInfo(dv);
+    /**
+     * 处理普通设备(isReport!=1)的属性详情
+     */
+    private void handleNormalDeviceAttrs(List<IotModelTemplateAttrsDO> attrsList,
+                                         IotModelTemplateAttrsRespVO vo,
+                                         boolean isVirtualDevice,
+                                         LocalDate createDate) throws SQLException {
+
+        Long deviceId = vo.getDeviceId();
+        String deviceCode = vo.getDeviceCode();
+
+        // 构建时间参数(一次计算,全局复用)
+        LocalDateTime start = LocalDateTime.of(createDate, LocalTime.MIN);
+        LocalDateTime end = LocalDateTime.of(createDate, LocalTime.MAX);
+        Timestamp startTime = Timestamp.valueOf(start);
+        Timestamp endTime = Timestamp.valueOf(end);
+        LocalDateTime midDay = LocalDateTime.of(createDate, LocalTime.of(12, 0));
+
+        // 批量收集DeviceVO查询参数
+        List<DeviceVO> deviceVOQueries = new ArrayList<>();
+        List<IotDeviceRunLogDO> logDOQueries = new ArrayList<>();
+        for (IotModelTemplateAttrsDO attrsDO : attrsList) {
+            if (isVirtualDevice) {
+                DeviceVO dv = new DeviceVO();
+                dv.setDeviceName(deviceCode.toLowerCase());
+                dv.setColName(attrsDO.getModelAttr());
+                dv.setTs(startTime);
+                dv.setTs1(endTime);
+                //dv.setExt1(attrsDO.getId().toString()); // 存储属性ID用于映射
+                deviceVOQueries.add(dv);
+            }
 
-                    if (!StringUtils.isEmpty(deviceVO) && !deviceVO.getEarliestData().equals("0.0")) {
-                        attrsDO.setFillContent(
-                                String.valueOf(Double.parseDouble(deviceVO.getLatestData()) - Double.parseDouble(deviceVO.getEarliestData())));
-                        attrsDO.setTotalRunTime(BigDecimal.valueOf(Double.parseDouble(deviceVO.getLatestData())));
-                        /**
-                         * 设置为数采
-                         */
-                        attrsDO.setIsCollection(1);
-                    } else {
-                        logDO1.setPointName(attrsDO.getName());
-                        IotDeviceRunLogDO logInfo = iotOpeationFillService.getLogInfo(logDO1);
-                        IotDeviceRunLogDO maxLog = iotOpeationFillService.getMaxFillInfo(logDO1);
-                        if (!StringUtils.isEmpty(logInfo)) {
+            IotDeviceRunLogDO logDO = new IotDeviceRunLogDO();
+            logDO.setDeviceId(deviceId);
+            logDO.setPointName(attrsDO.getName());
+            logDO.setCreateTime(midDay);
+            //logDO.setExt1(attrsDO.getId().toString()); // 存储属性ID用于映射
+            logDOQueries.add(logDO);
+        }
 
-                            attrsDO.setFillContent(logInfo.getFillContent());
+        // 批量查询(替代循环查询)
+        Map<String, DeviceVO> deviceVOMap = new HashMap<>();
+        if (isVirtualDevice && !deviceVOQueries.isEmpty()) {
+            List<DeviceVO> deviceVOList = iDeviceService.batchGetYesInfo(deviceVOQueries);
+            deviceVOMap = deviceVOList.stream()
+                    .filter(voObj -> !StringUtils.isEmpty(voObj.getEarliestData()) && !"0.0".equals(voObj.getEarliestData()))
+                    .collect(Collectors.toMap(DeviceVO::getDeviceName, Function.identity()));
+        }
 
-                            if (StringUtils.isEmpty(maxLog)) {
-                                attrsDO.setTotalRunTime(BigDecimal.valueOf(0));
-                            } else {
-                                attrsDO.setTotalRunTime(maxLog.getTotalRunTime());
-                            }
-                            /**
-                             * 设置为非数采
-                             */
-                            attrsDO.setIsCollection(0);
+        // 批量查询logInfo和maxLog
+        Map<String, IotDeviceRunLogDO> logInfoMap = new HashMap<>();
+        Map<String, IotDeviceRunLogDO> maxLogMap = new HashMap<>();
+        if (!logDOQueries.isEmpty()) {
+            logInfoMap = iotOpeationFillService.batchGetLogInfo(logDOQueries).stream()
+                    .collect(Collectors.toMap(IotDeviceRunLogDO::getPointName, Function.identity()));
+            maxLogMap = iotOpeationFillService.batchGetMaxFillInfo(logDOQueries).stream()
+                    .collect(Collectors.toMap(IotDeviceRunLogDO::getPointName, Function.identity()));
+        }
 
-                        } else {
-                            attrsDO.setFillContent("");
-                            if (StringUtils.isEmpty(maxLog)) {
-                                attrsDO.setTotalRunTime(BigDecimal.valueOf(0));
-                            } else {
-                                attrsDO.setTotalRunTime(maxLog.getTotalRunTime());
-                            }
-                            /**
-                             * 设置为非数采
-                             */
-                            attrsDO.setIsCollection(0);
-                        }
-                    }
+        // 处理属性数据
+        for (IotModelTemplateAttrsDO attrsDO : attrsList) {
+            String attrId = attrsDO.getId().toString();
+            String attrName = attrsDO.getName();
+            if (isVirtualDevice) {
+                DeviceVO deviceVO = deviceVOMap.get(attrId);
+                if (deviceVO != null) {
+                    // 数采设备逻辑
+                    double diff = Double.parseDouble(deviceVO.getLatestData()) - Double.parseDouble(deviceVO.getEarliestData());
+                    attrsDO.setFillContent(String.valueOf(diff));
+                    attrsDO.setTotalRunTime(BigDecimal.valueOf(Double.parseDouble(deviceVO.getLatestData())));
+                    attrsDO.setIsCollection(1);
+                    continue;
                 }
-            } else {
-                for (IotModelTemplateAttrsDO attrsDO : list) {
-                    logDO1.setPointName(attrsDO.getName());
-                    IotDeviceRunLogDO logInfo = iotOpeationFillService.getLogInfo(logDO1);
-                    IotDeviceRunLogDO maxLog = iotOpeationFillService.getMaxFillInfo(logDO1);
-                    if (!StringUtils.isEmpty(logInfo)) {
-
-                        attrsDO.setFillContent(logInfo.getFillContent());
-                        attrsDO.setTotalRunTime(logInfo.getTotalRunTime());
-
-                        /**
-                         * 设置为非数采
-                         */
-                        attrsDO.setIsCollection(0);
-
-                    } else {
-                        attrsDO.setFillContent("");
-                        if (StringUtils.isEmpty(maxLog)) {
-                            attrsDO.setTotalRunTime(BigDecimal.valueOf(0));
-                        } else {
-                            attrsDO.setTotalRunTime(maxLog.getTotalRunTime());
-                        }
-
-                        /**
-                         * 设置为非数采
-                         */
-                        attrsDO.setIsCollection(0);
-
-                    }
+            }
 
-                }
+            // 非数采设备逻辑
+            IotDeviceRunLogDO logInfo = logInfoMap.get(attrName);
+            IotDeviceRunLogDO maxLog = maxLogMap.get(attrName);
 
+            if (logInfo != null) {
+                attrsDO.setFillContent(logInfo.getFillContent());
+                attrsDO.setTotalRunTime(logInfo.getTotalRunTime() != null ? logInfo.getTotalRunTime() : BigDecimal.ZERO);
+            } else {
+                attrsDO.setFillContent("");
+                attrsDO.setTotalRunTime(maxLog != null ? maxLog.getTotalRunTime() : BigDecimal.ZERO);
             }
-
+            attrsDO.setIsCollection(0);
         }
-        List<IotModelTemplateAttrsDO> sumList = list.stream().filter(e -> e.getIsSum() == 1).collect(Collectors.toList());
-        List<IotModelTemplateAttrsDO> nonSumList = list.stream().filter(e -> e.getIsSum() == 0).collect(Collectors.toList());
-
-        IotModelTemplateAttrsDO1 sum = new IotModelTemplateAttrsDO1();
-        sum.setSumList(sumList);
-        sum.setNonSumList(nonSumList);
-
-        result.add(sum);
-
-        return result;
     }
 
 

+ 62 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotopeationfill/vo/IotOpeationFillWithAttrsVO.java

@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo;
+
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO1;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * @author yc
+ * @version 1.0
+ * @className IotOpeationFillWithAttrsVO
+ * @date 2025/12/15 9:31
+ * @description
+ */
+@Schema(description = "新增实体类")
+@Data
+@ToString(callSuper = true)
+public class IotOpeationFillWithAttrsVO {
+    private Long id;
+    private String deviceId;
+    private String deviceCode;
+    private LocalDate createTime;
+    private Long deviceCategoryId;
+    private String deviceName;
+    private String orgName;
+    // 新增的属性
+    private List<IotModelTemplateAttrsDO1> attrsDetail;
+
+    // 3. 必须有无参构造器(Lombok的@NoArgsConstructor可自动生成,@Data包含@NoArgsConstructor)
+    public IotOpeationFillWithAttrsVO() {}
+
+    // 4. 所有属性必须有getter和setter(Lombok的@Data可自动生成)
+    // 手动生成示例(如果不用Lombok):
+    public Long getId() { return id; }
+    public void setId(Long id) { this.id = id; }
+    public String getDeviceId() { return deviceId; }
+    public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    // ... 其他属性的getter/setter
+    public List<IotModelTemplateAttrsDO1> getAttrsDetail() { return attrsDetail; }
+    public void setAttrsDetail(List<IotModelTemplateAttrsDO1> attrsDetail) { this.attrsDetail = attrsDetail; }
+}

+ 19 - 9
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotrydailyreport/IotRyDailyReportController.java

@@ -186,7 +186,7 @@ public class IotRyDailyReportController {
 
         PageResult<IotRyDailyReportDO> pageResult = iotRyDailyReportService.getIotRyDailyReportPage(pageReqVO);
 
-        return success(new PageResult<>(buildRyDailyReports(pageResult.getList()), pageResult.getTotal()));
+        return success(new PageResult<>(buildRyDailyReports(pageResult.getList(), pageReqVO), pageResult.getTotal()));
     }
 
     @GetMapping("/statistics")
@@ -232,7 +232,7 @@ public class IotRyDailyReportController {
      * @param reports
      * @return
      */
-    private List<IotRyDailyReportRespVO> buildRyDailyReports(List<IotRyDailyReportDO> reports) {
+    private List<IotRyDailyReportRespVO> buildRyDailyReports(List<IotRyDailyReportDO> reports, IotRyDailyReportPageReqVO pageReqVO) {
         if (CollUtil.isEmpty(reports)) {
             return Collections.emptyList();
         }
@@ -322,7 +322,7 @@ public class IotRyDailyReportController {
             // 按施工队伍统计 钻井日报 施工井数 完工井数
             List<IotRyDailyReportTaskCountVO> deptTasks = iotRyDailyReportService.countTasksByDept();
             // 修井日报 不存在既填写钻井日报 又填写修井日报的队伍
-            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportService.countRepairTasksByDept();
+            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportService.countRepairTasksByDept(pageReqVO);
             if (CollUtil.isNotEmpty(deptTasks)) {
                 deptTasks.forEach(task -> {
                     totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
@@ -450,13 +450,23 @@ public class IotRyDailyReportController {
         Map<Long, Integer> totalTasksPair = new HashMap<>();
         // key施工队伍id    value完工井数量
         Map<Long, Integer> completedTasksPair = new HashMap<>();
-        List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportService.countRepairTasksByDept();
-        if (CollUtil.isNotEmpty(repairDeptTasks)) {
-            repairDeptTasks.forEach(task -> {
-                totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
-                completedTasksPair.put(task.getDeptId(), task.getCompletedTaskCount());
-            });
+        // 瑞鹰修井 施工井数 完工井数 统计
+        Set<Long> ids = new HashSet<>();
+        if (Objects.nonNull(pageReqVO.getDeptId())) {
+            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+            ids.add(pageReqVO.getDeptId());
+            pageReqVO.setDeptIds(ids);
         }
+        if (ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
+            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportService.countRepairTasksByDept(pageReqVO);
+            if (CollUtil.isNotEmpty(repairDeptTasks)) {
+                repairDeptTasks.forEach(task -> {
+                    totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
+                    completedTasksPair.put(task.getDeptId(), task.getCompletedTaskCount());
+                });
+            }
+        }
+
         if (CollUtil.isNotEmpty(list)) {
             for (IotRyDailyReportDO report : list) {
                 BigDecimal dailyFootage = report.getDailyFootage();

+ 20 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/TDDeviceMapper.java

@@ -81,6 +81,26 @@ public interface TDDeviceMapper extends BaseMapperX<TDDeviceDO> {
     @TenantIgnore
     DeviceVO getYesInfo(@Param("deviceName") String tableName, @Param("colName") String colName, @Param("ts") Timestamp ts,@Param("ts1")Timestamp ts1);
 
+    // 7. 批量查询DeviceVO
+    @Select("<script>" +
+            "<foreach collection='queries' item='item' index='index' separator='UNION ALL'>" +
+            "SELECT" +
+            "  #{item.tableName} AS table_name," + // 关联入参表名
+            "  #{item.colName} AS col_name," +     // 关联入参列名
+            "  FIRST(log_value) AS earliest_data," +
+            "  LAST(log_value) AS latest_data" +
+            " FROM iot_log.device_${item.tableName}" + // 表名动态拼接(注意SQL注入风险)
+            " WHERE" +
+            "  ts BETWEEN #{item.startTime} AND #{item.endTime}" +
+            "  AND identity = #{item.colName}" +
+            "  AND log_value != 0.0" +
+            "  AND _c0 IS NOT NULL" +
+            "</foreach>" +
+            "</script>")
+    @DS("tdengine")
+    @TenantIgnore
+    List<DeviceVO> batchGetYesInfo(@Param("queries") List<DeviceVO> queries);
+
 
     @Select("SELECT   _WSTART AS ts, AVG(CAST(log_value AS FLOAT)) as log_value   FROM iot_log.device_${deviceName} " +
             "WHERE ts between #{start} and #{end} and identity = #{identifier}  INTERVAL(1m) " )

+ 44 - 5
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotopeationfill/IotOpeationFillMapper.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo.IotOpeati
 import cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo.IotOpeationFillPageVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo.IotOpeationFillRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo.IotOpeationFillSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.DeviceVO;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotZHBD.DeviceZHBDDO;
@@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLo
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillOrderDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Mapper;
@@ -27,6 +29,7 @@ import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -108,7 +111,7 @@ public interface IotOpeationFillMapper extends BaseMapperX<IotOpeationFillDO> {
     @TenantIgnore
     List<IotOpeationFillDO> getFillDevices(@Param("deviceIds")List<Long> deviceIds);
 
-    List<IotModelTemplateAttrsDO> getAttrsById(IotModelTemplateAttrsRespVO vo);
+
 
     @TenantIgnore
     int insertFill(List<IotOpeationFillDO> vo);
@@ -199,10 +202,8 @@ public interface IotOpeationFillMapper extends BaseMapperX<IotOpeationFillDO> {
     List<IotOpeationFillRespVO> getFillList(IotOpeationFillRespVO vo);
     @TenantIgnore
     List<IotDeviceRunLogDO> getDeivceFillInfo(IotDeviceRunLogDO vo);
-    @TenantIgnore
-    IotDeviceRunLogDO getLogInfo(IotDeviceRunLogDO vo);
-    @TenantIgnore
-    IotDeviceRunLogDO getMaxFillInfo(IotDeviceRunLogDO vo);
+
+
 
 
     @TenantIgnore
@@ -258,11 +259,20 @@ public interface IotOpeationFillMapper extends BaseMapperX<IotOpeationFillDO> {
     @TenantIgnore
     IotDeviceDO devStatus(IotDeviceDO deviceDO) ;
 
+    @TenantIgnore
+    List<IotDeviceDO> selectDevStatusBatch(@Param("teams") List<DeptDO> teams) ;
+
     @TenantIgnore
     IotOpeationFillDO isReport(IotOpeationFillDO fillDO);
+    // 1. 批量查询isReport状态
+    @TenantIgnore
+    List<IotOpeationFillDO> batchGetIsReport(List<IotOpeationFillDO> queries);
 
     @TenantIgnore
     IotOpeationFillDO orderDO(IotOpeationFillDO fillDO);
+    // 2. 批量查询orderDO
+    @TenantIgnore
+    List<IotOpeationFillDO> batchGetOrderDO(List<IotOpeationFillDO> queries);
 
     @TenantIgnore
     IotOpeationFillDO orderDO1(IotOpeationFillDO fillDO);
@@ -270,11 +280,36 @@ public interface IotOpeationFillMapper extends BaseMapperX<IotOpeationFillDO> {
     @TenantIgnore
     List<IotOpeationFillDO> reportList(IotOpeationFillDO fillDO);
 
+
+    @TenantIgnore
+    List<IotModelTemplateAttrsDO> getAttrsById(IotModelTemplateAttrsRespVO vo);
+
+    // 3. 批量查询属性模板
+    @TenantIgnore
+    List<IotModelTemplateAttrsDO> getAttrsByIdBatch(@Param("vos") List<IotModelTemplateAttrsRespVO> vos);
+
+
+    @TenantIgnore
+    IotDeviceRunLogDO getLogInfo(IotDeviceRunLogDO vo);
+    // 5. 批量查询logInfo
+    @TenantIgnore
+    List<IotDeviceRunLogDO> batchGetLogInfo(List<IotDeviceRunLogDO> queries);
+
+    @TenantIgnore
+    IotDeviceRunLogDO getMaxFillInfo(IotDeviceRunLogDO vo);
+    // 6. 批量查询maxFillInfo
+    @TenantIgnore
+    List<IotDeviceRunLogDO> batchGetMaxFillInfo(List<IotDeviceRunLogDO> queries);
+
+
     @TenantIgnore
     List<IotOpeationFillDO> reportList1(IotOpeationFillDO fillDO);
 
     @TenantIgnore
     IotDeviceRunLogDO reportData(IotDeviceRunLogDO runLogDO);
+    // 4. 批量查询reportData
+    @TenantIgnore
+    List<IotDeviceRunLogDO> batchReportData(List<IotDeviceRunLogDO> queries);
 
     @TenantIgnore
     IotDeviceRunLogDO maxReportData(IotDeviceRunLogDO runLogDO);
@@ -297,4 +332,8 @@ public interface IotOpeationFillMapper extends BaseMapperX<IotOpeationFillDO> {
     @TenantIgnore
     AdminUserDO getUserInfo(IotDeviceRunLogDO runLogDO);
 
+
+    @TenantIgnore
+    IotDeviceRunLogDO getUserId(IotDeviceRunLogDO runLogDO);
+
 }

+ 25 - 9
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotrydailyreport/IotRyDailyReportMapper.java

@@ -329,15 +329,31 @@ public interface IotRyDailyReportMapper extends BaseMapperX<IotRyDailyReportDO>
      * 按部门统计 修井 任务数量 完工任务数量
      * @return 部门任务统计列表
      */
-    @Select("SELECT " +
-            "dept_id as deptId, " +
-            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL THEN task_id END) as totalTaskCount, " +
-            "COUNT(DISTINCT CASE WHEN repair_status = 'wg' AND task_id IS NOT NULL THEN task_id END) as completedTaskCount " +
-            "FROM rq_iot_ry_daily_report " +
-            "WHERE deleted = 0 " +
-            "AND project_classification = 2 " +
-            "GROUP BY dept_id")
-    List<IotRyDailyReportTaskCountVO> countRepairTasksByDept();
+    @Select({
+            "<script>",
+            "SELECT ",
+            "dept_id as deptId, ",
+            "COUNT(DISTINCT CASE WHEN task_id IS NOT NULL THEN task_id END) as totalTaskCount, ",
+            "COUNT(DISTINCT CASE WHEN repair_status = 'wg' AND task_id IS NOT NULL THEN task_id END) as completedTaskCount ",
+            "FROM rq_iot_ry_daily_report ",
+            "WHERE deleted = 0 ",
+            "AND project_classification = 2 ",
+            "<if test='reqVO.deptIds != null and !reqVO.deptIds.isEmpty()'>",
+            "AND dept_id IN ",
+            "<foreach collection='reqVO.deptIds' item='deptId' open='(' separator=',' close=')'>",
+            "#{deptId}",
+            "</foreach>",
+            "</if>",
+            "<if test='reqVO.createTime != null and reqVO.createTime[0] != null'>",
+            "AND create_time &gt;= #{reqVO.createTime[0]} ",
+            "</if>",
+            "<if test='reqVO.createTime != null and reqVO.createTime[1] != null'>",
+            "AND create_time &lt;= #{reqVO.createTime[1]} ",
+            "</if>",
+            "GROUP BY dept_id",
+            "</script>"
+    })
+    List<IotRyDailyReportTaskCountVO> countRepairTasksByDept(@Param("reqVO") IotRyDailyReportPageReqVO reqVO);
 
     /**
      * 按部门统计 修井 任务数量 完工任务数量 当前日期所属的月 年

+ 68 - 38
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/IotOperationPlanJob.java

@@ -22,11 +22,16 @@ import cn.iocoder.yudao.module.pms.dal.mysql.iotoperationplandev.IotOperationPla
 import cn.iocoder.yudao.module.pms.message.PmsMessage;
 import cn.iocoder.yudao.module.pms.service.iotopeationfill.IotOpeationFillService;
 import cn.iocoder.yudao.module.pms.service.iotrhdailyreport.IotRhDailyReportService;
+import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 
@@ -35,8 +40,12 @@ import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;
@@ -72,6 +81,8 @@ public class IotOperationPlanJob implements JobHandler {
     private IotOpeationFillService opeationFillService;
     @Resource
     private IotRhDailyReportService iotRhDailyReportService;
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;;
     /**
      * 1、查询开启状态运行计划
      * 2、根据计划获取设备
@@ -134,10 +145,6 @@ public class IotOperationPlanJob implements JobHandler {
                 orderList.add(fillDO);
             }
             deal(planDO, date,devIdList,orderList);
-        }else{
-            //判断计划内是否所有队伍都是非施工状态且为瑞恒
-            //满足条件直接插入日报
-            unNormalTeamInPlan(planDO);
         }
     }
 
@@ -165,6 +172,10 @@ public class IotOperationPlanJob implements JobHandler {
 
 
     private void extracted(List<Long> devIdList, List<IotOpeationFillOrderDO> orderList,IotOperationPlanDO plan) {
+
+
+
+
         //瑞鹰日报计划为12小时执行一次
         //判断计划周期是否为小时,如果是,则保存上次执行时间为当前时间最近的整点
         if ("hour".equals(plan.getPlanUnit())) {
@@ -188,7 +199,10 @@ public class IotOperationPlanJob implements JobHandler {
         }
         planMapper.updateById(plan);
 
-
+        //判断是否为瑞恒特殊计划
+        if(plan.getId()==153L){
+            unNormalTeamInPlan(plan);
+        }
 
         //4、根据设备ID生成子表数据
         List<IotOpeationFillDO> deviceList = iotOpeationFillMapper.getFillDevices(devIdList);
@@ -304,46 +318,61 @@ public class IotOperationPlanJob implements JobHandler {
         });
     }
 
+
+
     private void unNormalTeamInPlan(IotOperationPlanDO planDO) {
-        Set<Long> rhIdList = new HashSet<>();
-        rhIdList =  deptService.getChildDeptIdListFromCache(157L);
-        rhIdList.add(157L);
-        boolean a = rhIdList.contains(planDO.getDeptId());
-        if(a){
-            Set<Long> deptIdList = new HashSet<>();
-            deptIdList =  deptService.getChildDeptIdListFromCache(planDO.getDeptId());
-            if(deptIdList.size()>0){
-                for (Long vir:deptIdList) {
-                    IotRhDailyReportSaveReqVO saveReqVO = new IotRhDailyReportSaveReqVO();
-                    //查询队伍增压机状态
-                    IotDeviceDO virDev = new IotDeviceDO();
-                    virDev.setDeptId(vir);
-                    IotDeviceDO devStatus = iotOpeationFillMapper.devStatus(virDev);
-                    //不为空则为日报赋值
-                    if(devStatus!=null){
-                        saveReqVO.setConstructionStatus(devStatus.getDeviceStatus());
-                    }
-                    //当日注气量
-                    saveReqVO.setDailyGasInjection(BigDecimal.valueOf(0.00));
-                    //当日注水量
-                    saveReqVO.setDailyWaterInjection(BigDecimal.valueOf(0.00));
-                    //当日注气时间
-                    saveReqVO.setDailyInjectGasTime(BigDecimal.valueOf(0.00));
-                    //当日注水时间
-                    saveReqVO.setDailyInjectWaterTime(BigDecimal.valueOf(0.00));
-                    //当日用电量
-                    saveReqVO.setDailyPowerUsage(BigDecimal.valueOf(0.00));
-                    //非生产时间
-                    saveReqVO.setNonProductionTime(BigDecimal.valueOf(0.00));
-                    saveReqVO.setDeptId(vir);
-                    saveReqVO.setFillOrderCreateTime(LocalDateTime.now());
-                    iotRhDailyReportService.createIotRhDailyReport(saveReqVO);
+
+
+        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(planDO.getDeptId());
+        DeptListReqVO reqVO = new DeptListReqVO();
+        reqVO.setDeptIds(allRhChildDeptIds);
+
+        List<DeptDO> depts = deptService.getDeptList(reqVO);
+
+        //筛选出所有小队
+        List<DeptDO> teams = depts.stream().filter(e->e.getType().equals("3")).collect(Collectors.toList());
+
+        //查询增压机状态为非施工的小队
+        List<IotDeviceDO> teamStatusL = iotOpeationFillMapper.selectDevStatusBatch(teams);
+
+        if(teamStatusL.size()>0){
+            for (IotDeviceDO vir:teamStatusL) {
+                IotRhDailyReportSaveReqVO saveReqVO = new IotRhDailyReportSaveReqVO();
+                //查询队伍增压机状态
+
+                IotDeviceRunLogDO cx = new IotDeviceRunLogDO();
+                cx.setDeptId(vir.getDeptId());
+                IotDeviceRunLogDO result = iotOpeationFillMapper.getUserId(cx);
+                //不为空则为日报赋值
+                if(vir.getDeviceStatus()!=null){
+                    saveReqVO.setConstructionStatus(vir.getDeviceStatus());
+                }
+                //当日注气量
+                saveReqVO.setDailyGasInjection(BigDecimal.valueOf(0.00));
+                //当日注水量
+                saveReqVO.setDailyWaterInjection(BigDecimal.valueOf(0.00));
+                //当日注气时间
+                saveReqVO.setDailyInjectGasTime(BigDecimal.valueOf(0.00));
+                //当日注水时间
+                saveReqVO.setDailyInjectWaterTime(BigDecimal.valueOf(0.00));
+                //当日用电量
+                saveReqVO.setDailyPowerUsage(BigDecimal.valueOf(0.00));
+                //非生产时间
+                saveReqVO.setNonProductionTime(BigDecimal.valueOf(0.00));
+                saveReqVO.setDeptId(vir.getDeptId());
+                saveReqVO.setFillOrderCreateTime(LocalDateTime.now());
+                if(result!=null){
+                    saveReqVO.setCreator(String.valueOf(result.getDeviceId()));
                 }
+                iotRhDailyReportService.createIotRhDailyReport(saveReqVO);
             }
         }
+
     }
 
 
+
+
     private void ryReportInsert(IotOperationPlanDO plan, List<IotOpeationFillOrderDO> orderList1, boolean ryContain) {
         if(ryContain){
             //创建日报设备
@@ -411,6 +440,7 @@ public class IotOperationPlanJob implements JobHandler {
                     saveReqVO.setNonProductionTime(BigDecimal.valueOf(0.00));
                     saveReqVO.setDeptId(vir.getDeptId());
                     saveReqVO.setFillOrderCreateTime(LocalDateTime.now());
+                    saveReqVO.setCreator(String.valueOf(vir.getUserId()));
                     iotRhDailyReportService.createIotRhDailyReport(saveReqVO);
                 }
             }

+ 4 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/DeviceServiceImpl.java

@@ -51,6 +51,10 @@ public class DeviceServiceImpl implements IDeviceService {
         return deviceMapper.getYesInfo(deviceVO.getDeviceName(), deviceVO.getColName(),deviceVO.getTs(),deviceVO.getTs1());
     }
 
+    @Override
+    public List<DeviceVO> batchGetYesInfo(List<DeviceVO> queries) {
+        return deviceMapper.batchGetYesInfo(queries);
+    }
 
 
 }

+ 3 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IDeviceService.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.pms.service;
 
 import cn.iocoder.yudao.module.pms.controller.admin.vo.DeviceVO;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -33,4 +34,6 @@ public interface IDeviceService {
 
     DeviceVO getYesInfo(DeviceVO deviceVO);
 
+    List<DeviceVO> batchGetYesInfo(List<DeviceVO> queries);
+
 }

+ 13 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotopeationfill/IotOpeationFillService.java

@@ -19,6 +19,7 @@ import org.apache.ibatis.annotations.Param;
 import javax.validation.Valid;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -213,4 +214,16 @@ public interface IotOpeationFillService {
 
     List<IotDeviceRunLogDO> batchGetDescByPointNames(Set<String> pointNameSet);
 
+    Map<Long, Integer> batchGetIsReport(List<IotOpeationFillDO> queries);
+
+    List<IotModelTemplateAttrsDO> getAttrsByIdBatch(List<IotModelTemplateAttrsRespVO> vos);
+
+    List<IotDeviceRunLogDO> batchGetLogInfo(List<IotDeviceRunLogDO> queries);
+
+    List<IotDeviceRunLogDO> batchGetMaxFillInfo(List<IotDeviceRunLogDO> queries);
+
+    List<IotDeviceRunLogDO> batchReportData(List<IotDeviceRunLogDO> queries);
+
+    Map<Long, IotOpeationFillDO> batchGetOrderDO(List<IotOpeationFillDO> queries);
+
 }

+ 55 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotopeationfill/IotOpeationFillServiceImpl.java

@@ -35,6 +35,7 @@ import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -503,4 +504,58 @@ public class IotOpeationFillServiceImpl implements IotOpeationFillService {
         return iotOpeationFillMapper.batchGetDescByPointNames(pointNameSet);
     }
 
+    @Override
+    public Map<Long, Integer> batchGetIsReport(List<IotOpeationFillDO> queries) {
+        List<IotOpeationFillDO> result = iotOpeationFillMapper.batchGetIsReport(queries);
+        Map<Long, Integer> map = result.stream()
+                // 过滤 null 元素(避免空指针,可选但推荐)
+                .filter(doObj -> doObj != null)
+                // 生成 Map:Key 为 DO 的 Long 字段,Value 为 DO 的 Integer 字段
+                .collect(Collectors.toMap(
+                        // Key 映射:替换为你的实际字段 getter(如 getId()、getDeviceId())
+                        IotOpeationFillDO::getDeviceId,
+                        // Value 映射:替换为你的实际字段 getter(如 getIsReport()、getStatus())
+                        IotOpeationFillDO::getIsReport,
+                        // 冲突解决策略(可选):若 Key 重复,取第一个值(或自定义逻辑)
+                        (v1, v2) -> v1
+                ));
+        return map;
+    }
+
+    @Override
+    public List<IotModelTemplateAttrsDO> getAttrsByIdBatch(List<IotModelTemplateAttrsRespVO> vos) {
+        return iotOpeationFillMapper.getAttrsByIdBatch(vos);
+    }
+
+    @Override
+    public List<IotDeviceRunLogDO> batchGetLogInfo(List<IotDeviceRunLogDO> queries) {
+        return iotOpeationFillMapper.batchGetLogInfo(queries);
+    }
+
+    @Override
+    public List<IotDeviceRunLogDO> batchGetMaxFillInfo(List<IotDeviceRunLogDO> queries) {
+        return iotOpeationFillMapper.batchGetMaxFillInfo(queries);
+    }
+
+    @Override
+    public List<IotDeviceRunLogDO> batchReportData(List<IotDeviceRunLogDO> queries) {
+        return iotOpeationFillMapper.batchReportData(queries);
+    }
+
+    @Override
+    public Map<Long, IotOpeationFillDO> batchGetOrderDO(List<IotOpeationFillDO> queries) {
+        List<IotOpeationFillDO> result = iotOpeationFillMapper.batchGetOrderDO(queries);
+        // 核心:替换 -> 后的 getXXX() 为实际的 Long 类型字段 getter 方法
+        Map<Long, IotOpeationFillDO> fillDOMap = result.stream()
+                // 第一个参数:Map 的 Key(取自 DO 的 Long 字段)
+                // 第二个参数:Map 的 Value(DO 本身)
+                .collect(Collectors.toMap(
+                        IotOpeationFillDO::getId,  // 示例:用 id 作为 Key,替换为实际字段(如 getOrderId())
+                        Function.identity(),       // Value:DO本身(简化写法)
+                        (oldValue, newValue) -> oldValue  // 重复Key时保留旧值(核心修复点)
+                        // 可选:如需保留新值,改为 (oldValue, newValue) -> newValue           // Value 直接是 DO 实例(可简化为 Function.identity())
+                ));
+        return fillDOMap;
+    }
+
 }

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

@@ -324,6 +324,7 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
             iotRhDailyReport.setDailyOilUsage(totalOilUsage);
             // 根据日报关联任务车辆油耗 计算总油耗 后保存日报
             iotRhDailyReportMapper.updateById(iotRhDailyReport);
+
         } else {
             // 修改现有记录
             iotRhDailyReport.setId(existReport.getId());
@@ -331,70 +332,76 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
         }
         // 只要保存了记录就要发送审批提醒到 提交人对应的项目经理 角色 项目部日报审批RH
         // 根据日报的 deptId 查询上级项目部经理 角色的审批人 发送站内信 钉钉提醒
-        DeptDO dept = deptService.getDept(deptId);
-        Long parentId = dept.getParentId();
-        if (ObjUtil.isNotEmpty(parentId)) {
-            AtomicReference<DeptDO> projectDept = new AtomicReference<>();
-            DataPermissionUtils.executeIgnore(() -> {
-                projectDept.set(deptService.getDept(parentId));
-
-                if (ObjUtil.isNotEmpty(projectDept) && "2".equals(projectDept.get().getType())) {
-                    // 查询项目部下具有 项目部日报审批RH 角色的人员
-                    Set<Long> projectIds = new HashSet<>();
-                    projectIds.add(projectDept.get().getId());
-                    List<AdminUserDO> receivedMsgUsers = adminUserService.getUserListByDeptIds(projectIds);
-                    if (CollUtil.isNotEmpty(receivedMsgUsers)) {
-                        Set<Long> userIds = new HashSet<>();
-                        receivedMsgUsers.forEach(user -> {
-                            userIds.add(user.getId());
-                        });
-                        RoleDO role = roleService.getRoleByCode("项目部日报审批RH");
-                        if (ObjUtil.isNotEmpty(role)) {
-                            Set<Long> roleIds = new HashSet<>();
-                            roleIds.add(role.getId());
-                            List<UserRoleDO> userRoles = userRoleMapper.selectListByRoleIds(roleIds);
-                            if (CollUtil.isNotEmpty(userRoles)) {
-                                // 提取有审批角色的所有用户ID(去重+空值过滤)
-                                Set<Long> roleUserIds = userRoles.stream()
-                                        .map(UserRoleDO::getUserId)
-                                        .filter(Objects::nonNull) // 过滤空userId
-                                        .collect(Collectors.toSet());
-                                // 计算两个集合的交集,得到最终目标用户ID
-                                Set<Long> targetUserIds = userIds.stream()
-                                        .filter(roleUserIds::contains)
-                                        .collect(Collectors.toSet());
-                                // 异步发送 站内信 钉钉消息
-                                if (CollUtil.isNotEmpty(targetUserIds)) {
-                                    Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(targetUserIds);
-                                    // 给多个用户发送 相同 的 提醒消息
-                                    if (CollUtil.isNotEmpty(users)) {
-                                        // 生成消息提醒标题 部门名称-井号
-                                        String msgTitle = dept.getName();
-                                        if (StrUtil.isNotBlank(wellName)) {
-                                            msgTitle = StrUtil.join("-", msgTitle, wellName);
-                                        }
-                                        CountDownLatch latch = new CountDownLatch(users.size());
-                                        String finalMsgTitle = msgTitle;
-                                        users.forEach((userId, user) -> {
-                                            pmsThreadPoolTaskExecutor.execute(() -> {
-                                                try {
-                                                    String mobile = user.getMobile();
-                                                    if (StrUtil.isNotBlank(mobile) && StrUtil.isNotBlank(finalMsgTitle)) {
-                                                        pmsMessage.sendMessage(iotRhDailyReport.getId(), finalMsgTitle, PmsConstants.RH_DAILY_REPORT_APPROVAL,
-                                                                userId, mobile);
+        // 此时需要判断下当前队伍下有无增压机,如果 ‘当前队伍下无增压机’ 或 ‘增压机的状态不是施工’ 需要新增空白记录 向填报人推送消息。
+        // 暂时添加判断条件 创建人 是 null 的话 不发送 站内信及钉钉消息
+        if (StrUtil.isNotBlank(iotRhDailyReport.getCreator())) {
+
+            DeptDO dept = deptService.getDept(deptId);
+            Long parentId = dept.getParentId();
+            if (ObjUtil.isNotEmpty(parentId)) {
+                AtomicReference<DeptDO> projectDept = new AtomicReference<>();
+                DataPermissionUtils.executeIgnore(() -> {
+                    projectDept.set(deptService.getDept(parentId));
+
+                    if (ObjUtil.isNotEmpty(projectDept) && "2".equals(projectDept.get().getType())) {
+                        // 查询项目部下具有 项目部日报审批RH 角色的人员
+                        Set<Long> projectIds = new HashSet<>();
+                        projectIds.add(projectDept.get().getId());
+                        List<AdminUserDO> receivedMsgUsers = adminUserService.getUserListByDeptIds(projectIds);
+                        if (CollUtil.isNotEmpty(receivedMsgUsers)) {
+                            Set<Long> userIds = new HashSet<>();
+                            receivedMsgUsers.forEach(user -> {
+                                userIds.add(user.getId());
+                            });
+                            RoleDO role = roleService.getRoleByCode("项目部日报审批RH");
+                            if (ObjUtil.isNotEmpty(role)) {
+                                Set<Long> roleIds = new HashSet<>();
+                                roleIds.add(role.getId());
+                                List<UserRoleDO> userRoles = userRoleMapper.selectListByRoleIds(roleIds);
+                                if (CollUtil.isNotEmpty(userRoles)) {
+                                    // 提取有审批角色的所有用户ID(去重+空值过滤)
+                                    Set<Long> roleUserIds = userRoles.stream()
+                                            .map(UserRoleDO::getUserId)
+                                            .filter(Objects::nonNull) // 过滤空userId
+                                            .collect(Collectors.toSet());
+                                    // 计算两个集合的交集,得到最终目标用户ID
+                                    Set<Long> targetUserIds = userIds.stream()
+                                            .filter(roleUserIds::contains)
+                                            .collect(Collectors.toSet());
+                                    // 异步发送 站内信 钉钉消息
+                                    if (CollUtil.isNotEmpty(targetUserIds)) {
+                                        Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(targetUserIds);
+                                        // 给多个用户发送 相同 的 提醒消息
+                                        if (CollUtil.isNotEmpty(users)) {
+                                            // 生成消息提醒标题 部门名称-井号
+                                            String msgTitle = dept.getName();
+                                            if (StrUtil.isNotBlank(wellName)) {
+                                                msgTitle = StrUtil.join("-", msgTitle, wellName);
+                                            }
+                                            CountDownLatch latch = new CountDownLatch(users.size());
+                                            String finalMsgTitle = msgTitle;
+                                            users.forEach((userId, user) -> {
+                                                pmsThreadPoolTaskExecutor.execute(() -> {
+                                                    try {
+                                                        String mobile = user.getMobile();
+                                                        // 没有手机号也发送站内信消息
+                                                        if (StrUtil.isNotBlank(finalMsgTitle)) {
+                                                            pmsMessage.sendMessage(iotRhDailyReport.getId(), finalMsgTitle, PmsConstants.RH_DAILY_REPORT_APPROVAL,
+                                                                    userId, mobile);
+                                                        }
+                                                    } finally {
+                                                        latch.countDown();
                                                     }
-                                                } finally {
-                                                    latch.countDown();
-                                                }
+                                                });
                                             });
-                                        });
+                                        }
                                     }
                                 }
                             }
                         }
                     }
-                }
-            });
+                });
+            }
         }
         return iotRhDailyReport.getId();
     }
@@ -583,7 +590,7 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
                 AdminUserDO user = users.get(0);
                 String mobile = user.getMobile();
                 String finalMsgTitle = msgTitle;
-                if (StrUtil.isNotBlank(mobile) && StrUtil.isNotBlank(finalMsgTitle)) {
+                if (StrUtil.isNotBlank(finalMsgTitle)) {
                     pmsThreadPoolTaskExecutor.execute(() -> {
                         pmsMessage.sendMessage(dailyReport.getId(), finalMsgTitle, PmsConstants.RH_DAILY_REPORT, user.getId(), mobile);
                     });

+ 1 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrydailyreport/IotRyDailyReportService.java

@@ -81,7 +81,7 @@ public interface IotRyDailyReportService {
      *
      * @return 按部门统计任务数量
      */
-    List<IotRyDailyReportTaskCountVO> countRepairTasksByDept();
+    List<IotRyDailyReportTaskCountVO> countRepairTasksByDept(IotRyDailyReportPageReqVO pageReqVO);
 
     /**
      * 按部门统计 修井 月累计 年累计 任务数量

+ 108 - 46
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotrydailyreport/IotRyDailyReportServiceImpl.java

@@ -286,7 +286,8 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
                                             pmsThreadPoolTaskExecutor.execute(() -> {
                                                 try {
                                                     String mobile = user.getMobile();
-                                                    if (StrUtil.isNotBlank(mobile) && StrUtil.isNotBlank(finalMsgTitle)) {
+                                                    // 没有手机号也可以发送站内信消息
+                                                    if (StrUtil.isNotBlank(finalMsgTitle)) {
                                                         pmsMessage.sendMessage(iotRyDailyReport.getId(), finalMsgTitle, constant,
                                                                 userId, mobile);
                                                     }
@@ -404,8 +405,8 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
     }
 
     @Override
-    public List<IotRyDailyReportTaskCountVO> countRepairTasksByDept() {
-        return iotRyDailyReportMapper.countRepairTasksByDept();
+    public List<IotRyDailyReportTaskCountVO> countRepairTasksByDept(IotRyDailyReportPageReqVO pageReqVO) {
+        return iotRyDailyReportMapper.countRepairTasksByDept(pageReqVO);
     }
 
     @Override
@@ -797,7 +798,7 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
             result = polylineStatisticsByProjectDept(pageReqVO, dailyReports, 158L, pageReqVO.getCreateTime());
         } else {
-            // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
+            // 判断点击的组织树中的部门类型 (公司级1 项目部2 队伍3)
             DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
             if ("1".equals(selectedDept.getType())) {
                 // 以项目部为维度汇总数据
@@ -856,7 +857,8 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
                     // 修井
                     constant = PmsConstants.RY_XJ_DAILY_REPORT;
                 }
-                if (StrUtil.isNotBlank(mobile) && StrUtil.isNotBlank(finalMsgTitle) && StrUtil.isNotBlank(creator)) {
+                // 没有手机号也可以发送站内信消息
+                if (StrUtil.isNotBlank(finalMsgTitle) && StrUtil.isNotBlank(creator)) {
                     pmsThreadPoolTaskExecutor.execute(() -> {
                         pmsMessage.sendMessage(dailyReport.getId(), finalMsgTitle, constant, Long.valueOf(creator), mobile);
                     });
@@ -910,9 +912,14 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         Map<Long, BigDecimal> cumulativeProductTimePair = new HashMap<>();
         // key队伍id/项目部id   value额定生产时间(H)
         Map<Long, BigDecimal> cumulativeRatedTimePair = new HashMap<>();
-        // key队伍id/项目部id   value累计运行时效   累计注气量/累计产能
+        // key队伍id/项目部id   value累计运行时效
         Map<Long, BigDecimal> cumulativeTransitTimePair = new HashMap<>();
 
+        // key部门id-任务id
+        Set<String> deptTaskConstrcts = new HashSet<>();
+        // key部门id-任务id
+        Set<String> deptTaskFinishes = new HashSet<>();
+
         // 以项目部为维度统计数据
         // 找到所有项目部与队伍的对应关系
         // 查询指定根部门下的所有子部门
@@ -939,13 +946,14 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
         if ("2".equals(pageReqVO.getProjectClassification())) {
             // 查询修井 累计施工井数 累计完工井数
-            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportMapper.countRepairTasksByDept();
-            if (CollUtil.isNotEmpty(repairDeptTasks)) {
-                repairDeptTasks.forEach(task -> {
-                    totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
-                    completedTasksPair.put(task.getDeptId(), task.getCompletedTaskCount());
-                });
-
+            if (ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
+                List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportMapper.countRepairTasksByDept(pageReqVO);
+                if (CollUtil.isNotEmpty(repairDeptTasks)) {
+                    repairDeptTasks.forEach(task -> {
+                        totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
+                        completedTasksPair.put(task.getDeptId(), task.getCompletedTaskCount());
+                    });
+                }
             }
             // 计算 运行时效 累计生产时间/累计额定生产时间
             // 查询日报关联的任务信息
@@ -1091,6 +1099,11 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         // key日期yyyy-MM-dd   value额定生产时间(H)
         Map<String, BigDecimal> dateRatedTimePair = new HashMap<>();
 
+        // key部门id-任务id    value施工井对应的日期
+        Map<String, String> deptTaskConstructPair = new HashMap<>();
+        // key部门id-任务id    value完工井对应的日期
+        Map<String, String> deptTaskFinishPair = new HashMap<>();
+
         // 以项目部为维度统计数据
         // 找到所有项目部与队伍的对应关系
         // 查询指定根部门下的所有子部门
@@ -1116,30 +1129,47 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         // key任务id   value额定生产时间
         Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
         if ("2".equals(pageReqVO.getProjectClassification())) {
+            // 计算累计施工井数 累计完工井数 时 过滤掉 taskId 为空的数据
+            dailyReports.forEach(report -> {
+                if (ObjUtil.isNotEmpty(report.getTaskId()) && allRhChildDeptIds.contains(report.getDeptId())) {
+                    String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
+                    String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
+                    deptTaskConstructPair.put(uniqueKey, dateStr);
+                    deptTaskFinishPair.put(uniqueKey, dateStr);
+                }
+            });
             // 查询 指定时间范围内的 修井 累计施工井数 累计完工井数
             // 每天的任务数量 taskId 去重后的数量
-            // 每天完工任务数量 taskId 去重后 状态为 wg 的数量
+            // 每天完工任务数量 deptId+taskId 去重后 状态为 wg 的数量
             dailyReports.forEach(report -> {
+                String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
                 String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
-                if (dateConstructTaskPair.containsKey(dateStr)) {
-                    Set<Long> tempUniqueTaskIds = dateConstructTaskPair.get(dateStr);
-                    tempUniqueTaskIds.add(report.getTaskId());
-                    dateConstructTaskPair.put(dateStr, tempUniqueTaskIds);
-                } else {
-                    Set<Long> tempUniqueTaskIds = new HashSet<>();
-                    tempUniqueTaskIds.add(report.getTaskId());
-                    dateConstructTaskPair.put(dateStr, tempUniqueTaskIds);
-                }
-                // 组装完工任务集合
-                if ("wg".equals(report.getRepairStatus())) {
-                    if (dateFinishTaskPair.containsKey(dateStr)) {
-                        Set<Long> tempUniqueTaskIds = dateFinishTaskPair.get(dateStr);
+                if (deptTaskConstructPair.containsKey(uniqueKey)) {
+                    String tempDateStr = deptTaskFinishPair.get(uniqueKey);
+
+                    if (dateConstructTaskPair.containsKey(tempDateStr)) {
+                        Set<Long> tempUniqueTaskIds = dateConstructTaskPair.get(tempDateStr);
                         tempUniqueTaskIds.add(report.getTaskId());
-                        dateFinishTaskPair.put(dateStr, tempUniqueTaskIds);
+                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
                     } else {
                         Set<Long> tempUniqueTaskIds = new HashSet<>();
                         tempUniqueTaskIds.add(report.getTaskId());
-                        dateFinishTaskPair.put(dateStr, tempUniqueTaskIds);
+                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
+                    }
+                }
+                // 组装完工任务集合
+                if ("wg".equals(report.getRepairStatus())) {
+                    if (deptTaskFinishPair.containsKey(uniqueKey)) {
+                        String tempDateStr = deptTaskFinishPair.get(uniqueKey);
+                        if (dateFinishTaskPair.containsKey(tempDateStr)) {
+                            Set<Long> tempUniqueTaskIds = dateFinishTaskPair.get(tempDateStr);
+                            tempUniqueTaskIds.add(report.getTaskId());
+                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
+                        } else {
+                            Set<Long> tempUniqueTaskIds = new HashSet<>();
+                            tempUniqueTaskIds.add(report.getTaskId());
+                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
+                        }
                     }
                 }
             });
@@ -1269,7 +1299,7 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         Map<Long, BigDecimal> cumulativeProductTimePair = new HashMap<>();
         // key队伍id/项目部id   value额定生产时间(H)
         Map<Long, BigDecimal> cumulativeRatedTimePair = new HashMap<>();
-        // key队伍id   value累计运行时效   累计注气量/累计产能
+        // key队伍id   value累计运行时效
         Map<Long, BigDecimal> cumulativeTransitTimePair = new HashMap<>();
 
         // 以 队伍 为维度统计数据
@@ -1298,7 +1328,7 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
         if ("2".equals(pageReqVO.getProjectClassification())) {
             // 查询修井 累计施工井数 累计完工井数
-            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportMapper.countRepairTasksByDept();
+            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportMapper.countRepairTasksByDept(pageReqVO);
             if (CollUtil.isNotEmpty(repairDeptTasks)) {
                 repairDeptTasks.forEach(task -> {
                     totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
@@ -1425,6 +1455,10 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         // key日期yyyy-MM-dd   value额定生产时间(H)
         Map<String, BigDecimal> dateRatedTimePair = new HashMap<>();
 
+        // key部门id-任务id    value施工井对应的日期
+        Map<String, String> deptTaskConstructPair = new HashMap<>();
+        // key部门id-任务id    value完工井对应的日期
+        Map<String, String> deptTaskFinishPair = new HashMap<>();
 
         // 以 队伍 为维度统计数据
         // 找到所有项目部与队伍的对应关系
@@ -1451,30 +1485,58 @@ public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {
         // key任务id   value额定生产时间
         Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
         if ("2".equals(pageReqVO.getProjectClassification())) {
+
+            // 1. 先校验时间区间数组有效性
+            boolean isCreateTimesValid = createTimes != null && createTimes.length >= 2
+                    && createTimes[0] != null && createTimes[1] != null;
+
+            // 计算累计施工井数 累计完工井数 时 过滤掉 taskId 为空的数据
+            dailyReports.forEach(report -> {
+                // 2. 获取日报创建时间并校验非空
+                LocalDateTime reportCreateTime = report.getCreateTime();
+                if (ObjUtil.isNotEmpty(report.getTaskId()) && allRhChildDeptIds.contains(report.getDeptId())
+                        && ObjUtil.isNotEmpty(reportCreateTime) && isCreateTimesValid
+                        && !reportCreateTime.isBefore(createTimes[0]) && !reportCreateTime.isAfter(createTimes[1])) {
+                    String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
+                    String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
+                    deptTaskConstructPair.put(uniqueKey, dateStr);
+                    deptTaskFinishPair.put(uniqueKey, dateStr);
+                }
+            });
+
             // 查询 指定时间范围内的 修井 累计施工井数 累计完工井数
             // 每天的任务数量 taskId 去重后的数量
             // 每天完工任务数量 taskId 去重后 状态为 wg 的数量
             dailyReports.forEach(report -> {
+                String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
                 String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
-                if (dateConstructTaskPair.containsKey(dateStr)) {
-                    Set<Long> tempUniqueTaskIds = dateConstructTaskPair.get(dateStr);
-                    tempUniqueTaskIds.add(report.getTaskId());
-                    dateConstructTaskPair.put(dateStr, tempUniqueTaskIds);
-                } else {
-                    Set<Long> tempUniqueTaskIds = new HashSet<>();
-                    tempUniqueTaskIds.add(report.getTaskId());
-                    dateConstructTaskPair.put(dateStr, tempUniqueTaskIds);
-                }
-                // 组装完工任务集合
-                if ("wg".equals(report.getRepairStatus())) {
-                    if (dateFinishTaskPair.containsKey(dateStr)) {
-                        Set<Long> tempUniqueTaskIds = dateFinishTaskPair.get(dateStr);
+                if (deptTaskConstructPair.containsKey(uniqueKey)) {
+                    String tempDateStr = deptTaskFinishPair.get(uniqueKey);
+
+                    if (dateConstructTaskPair.containsKey(tempDateStr)) {
+                        Set<Long> tempUniqueTaskIds = dateConstructTaskPair.get(tempDateStr);
                         tempUniqueTaskIds.add(report.getTaskId());
-                        dateFinishTaskPair.put(dateStr, tempUniqueTaskIds);
+                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
                     } else {
                         Set<Long> tempUniqueTaskIds = new HashSet<>();
                         tempUniqueTaskIds.add(report.getTaskId());
-                        dateFinishTaskPair.put(dateStr, tempUniqueTaskIds);
+                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
+                    }
+                }
+                // 组装完工任务集合
+                if ("wg".equals(report.getRepairStatus())) {
+                    if (deptTaskFinishPair.containsKey(uniqueKey)) {
+                        String tempDateStr = deptTaskFinishPair.get(uniqueKey);
+
+                        if (dateFinishTaskPair.containsKey(tempDateStr)) {
+                            Set<Long> tempUniqueTaskIds = dateFinishTaskPair.get(tempDateStr);
+                            tempUniqueTaskIds.add(report.getTaskId());
+                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
+                        } else {
+                            Set<Long> tempUniqueTaskIds = new HashSet<>();
+                            tempUniqueTaskIds.add(report.getTaskId());
+                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
+                        }
                     }
                 }
             });

+ 229 - 16
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotOpeationFillMapper.xml

@@ -758,6 +758,40 @@
             device_category_id = #{deviceCategoryId} and deleted = 0
     </select>
 
+
+    <!--
+批量查询属性模板:入参为List<IotDeviceRespVO>(含多个deviceCategoryId)
+出参:List<IotModelTemplateAttrsDO>(所有分类ID对应的属性模板,包含deviceCategoryId便于分组)
+-->
+    <select id="getAttrsByIdBatch" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO">
+        SELECT
+        id,
+        name,
+        type,
+        model_attr,
+        is_sum,
+        threshold,
+        default_value,
+        sum_id,
+        description,
+        device_category_id
+        FROM
+        rq_iot_model_template_attrs
+        WHERE
+        -- 批量匹配多个deviceCategoryId,deleted=0条件不变
+        device_category_id IN (
+        <foreach collection="vos" item="item" separator="," open="" close="">
+            #{item.deviceCategoryId}
+        </foreach>
+        )
+        AND deleted = 0
+        -- 按分类ID和属性名称排序,保持结果一致性
+        ORDER BY
+        device_category_id ASC, name ASC
+    </select>
+
+
     <update id="updateFill"  parameterType="cn.iocoder.yudao.module.pms.controller.admin.vo.IotOpeationModelPageReqVO">
         update  rq_iot_opeation_fill
         set is_fill = '1'
@@ -819,12 +853,6 @@
 
     <select id="getLogInfo" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
-        <!--SELECT * FROM rq_iot_device_run_log
-        WHERE
-            device_id = #{deviceId}
-        and
-            create_time  = (SELECT MAX(create_time) FROM rq_iot_device_run_log WHERE
-                device_id = #{deviceId})-->
         SELECT
         *
         FROM rq_iot_device_run_log
@@ -839,15 +867,32 @@
         limit 1
     </select>
 
-    <select id="getMaxFillInfo" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO"
+    <select id="batchGetLogInfo" parameterType="java.util.List"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
-        <!--SELECT * FROM rq_iot_device_run_log
-        WHERE
-            device_id = #{deviceId}
-        and
-            create_time  = (SELECT MAX(create_time) FROM rq_iot_device_run_log WHERE
-                device_id = #{deviceId})-->
+        SELECT
+            *
+        FROM rq_iot_device_run_log r
+        WHERE-- 批量匹配多个 (device_id, point_name, DATE(create_time)) 三元组
+        (r.device_id, r.point_name, DATE(r.create_time)) IN (
+        <foreach collection="list" item="item" separator=",">
+            (#{item.deviceId}, #{item.pointName}, DATE(#{item.createTime}))
+        </foreach>
+        )
+        -- 确保每个条件只返回最新一条记录(按id降序,取最大id)
+        AND r.id IN (
+        SELECT MAX(id)
+        FROM rq_iot_device_run_log
+        WHERE (device_id, point_name, DATE(create_time)) IN (
+        <foreach collection="list" item="item" separator=",">
+            (#{item.deviceId}, #{item.pointName}, DATE(#{item.createTime}))
+        </foreach>
+        )
+        GROUP BY device_id, point_name, DATE(create_time)
+        )
+    </select>
 
+    <select id="getMaxFillInfo" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
         select max(total_run_time)total_run_time
         from rq_iot_device_run_log
         where
@@ -856,6 +901,57 @@
         point_name=#{pointName}
     </select>
 
+    <!--<select id="batchGetMaxFillInfo" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
+        select
+        device_id,
+        point_name,
+        max(total_run_time)total_run_time
+        from rq_iot_device_run_log
+        where
+        &#45;&#45; 批量匹配多个 (device_id, point_name) 组合
+        (device_id, point_name) IN (
+        <foreach collection="list" item="item" separator=",">
+            (#{item.deviceId}, #{item.pointName})
+        </foreach>
+        )
+        group by
+        device_id
+    </select>-->
+
+    <select id="batchGetMaxFillInfo" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
+        SELECT
+        device_id,
+        point_name,
+        total_run_time  -- 直接取最新记录的 total_run_time,无需 max()(最新数据已通过排序筛选)
+        FROM (
+        SELECT
+        device_id,
+        point_name,
+        total_run_time,
+        create_time,  -- 表中的时间字段,替换为实际字段名(如 log_time/update_time)
+        -- 按 (device_id, point_name) 分组,每组内按时间倒序排名
+        ROW_NUMBER() OVER (
+        PARTITION BY device_id, point_name
+        ORDER BY create_time DESC  -- 时间倒序:最新的排第1
+        -- 可选:若同一时间有重复记录,加次要排序(如 id DESC)确保唯一
+        -- ORDER BY create_time DESC, id DESC
+        ) AS rn
+        FROM rq_iot_device_run_log
+        WHERE
+        -- 批量匹配多个 (device_id, point_name) 组合(保留原 foreach 逻辑)
+        (device_id, point_name) IN (
+        <foreach collection="list" item="item" separator=",">
+            (#{item.deviceId}, #{item.pointName})
+        </foreach>
+        )
+        ) AS temp
+        WHERE rn = 1;  -- 只取每个组合的最新记录(排名第1)
+    </select>
+
+
+
 
     <select id="devList" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO">
@@ -1144,6 +1240,24 @@
             LIMIT 1
     </select>
 
+
+    <select id="selectDevStatusBatch" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO">
+        SELECT
+        dept_id, -- 建议返回部门ID,方便后续关联结果
+        device_status
+        FROM rq_iot_device
+        WHERE dept_id IN
+        <foreach collection="teams" item="item" open="(" separator="," close=")">
+            #{item.id}
+        </foreach>
+        AND asset_class IN (159, 160, 122, 106, 157, 158, 191)
+        AND device_status != 'sg'
+        GROUP BY dept_id -- 确保每个部门只返回1条记录(若多个设备,取任意1条)
+        -- 可选:如需指定返回某条设备(如最新/最早),可加排序:
+        -- ORDER BY create_time DESC -- 按创建时间倒序(取最新)
+    </select>
+
     <select id="isReport" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO">
         select * from
@@ -1155,6 +1269,37 @@
             LIMIT 1
     </select>
 
+
+    <!--
+批量查询isReport状态:入参为List<IotOpeationFillDO>(包含deviceId和createTime)
+出参:List<IotOpeationFillDO>(每条记录对应一个deviceId+createTime组合的查询结果)
+-->
+    <select id="batchGetIsReport" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO">
+        SELECT
+        t.device_id,
+        COALESCE(t.is_report, 0) AS is_report
+        FROM (
+        -- 子查询:先过滤批量匹配的记录,再按设备+日期分组取最新1条
+        SELECT
+        *,
+        -- 分组内排序:按create_time降序(最新的排第1)
+        ROW_NUMBER() OVER (
+        PARTITION BY device_id, DATE(create_time)  -- 分组键:设备+日期
+        ORDER BY create_time DESC  -- 取数规则:最新的1条(可修改)
+        ) AS rn
+        FROM rq_iot_opeation_fill
+        WHERE
+        -- 批量匹配:(设备ID, 日期) 组合(与之前批量查询逻辑兼容)
+        (device_id, DATE(create_time)) IN
+        <foreach collection="list" item="item" separator="," open="(" close=")">
+            (#{item.deviceId}, DATE(#{item.createTime}))
+        </foreach>
+        ) t
+        WHERE t.rn = 1;  -- 只保留每组第1条(即每个设备每天1条)
+    </select>
+
+
     <select id="orderDO" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO">
         select
@@ -1167,6 +1312,37 @@
             DATE(create_time) = #{createTime}
     </select>
 
+    <select id="batchGetOrderDO" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO">
+        select
+            order_id
+        from(
+        -- 内层查询:批量匹配条件 + 去重(同一 deviceId+日期 取最新记录)
+        SELECT
+        order_id
+        FROM
+        rq_iot_opeation_fill
+        WHERE
+        (device_id, DATE(create_time)) IN (
+        <foreach collection="list" item="item" separator=",">
+            -- 匹配入参中的 deviceId 和 日期(DATE(createTime) 与原逻辑一致)
+            (#{item.deviceId}, DATE(#{item.createTime}))
+        </foreach>
+        )
+        -- 去重逻辑:按 id 降序,确保每个分组取最新记录
+        AND id IN (
+        SELECT MAX(id) -- 取最新记录的 id
+        FROM rq_iot_opeation_fill
+        WHERE (device_id, DATE(create_time)) IN (
+        <foreach collection="list" item="item" separator=",">
+            (#{item.deviceId}, DATE(#{item.createTime}))
+        </foreach>
+        )
+        GROUP BY device_id, DATE(create_time) -- 按 deviceId+日期 分组
+        )
+        ) AS iof
+    </select>
+
 
     <select id="orderDO1" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO">
@@ -1253,6 +1429,29 @@
           and DATE(create_time) = DATE(#{createTime})
     </select>
 
+    <!--
+批量查询设备运行日志:入参为List<IotDeviceRunLogDO>(含deviceId、pointName、createTime)
+出参:List<IotDeviceRunLogDO>(所有匹配条件的日志记录,结构与原单查一致)
+-->
+    <select id="batchReportData" parameterType="java.util.List"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
+        SELECT
+        *
+        -- 如需其他字段,按原单查SQL补充(原SQL用select *,此处显式列出避免冗余)
+        FROM
+        rq_iot_device_run_log
+        WHERE
+        -- 批量匹配多个 (device_id, point_name, DATE(create_time)) 三元组条件
+        (device_id, point_name, DATE(create_time)) IN (
+        <foreach collection="list" item="item" separator=",">
+            (#{item.deviceId}, #{item.pointName}, DATE(#{item.createTime}))
+        </foreach>
+        )
+        -- 按创建时间降序,保持结果一致性(可选,与原单查行为对齐)
+        ORDER BY
+        create_time DESC
+    </select>
+
     <select id="batchQueryExistingLogs" parameterType="java.util.List"
             resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
         select * from rq_iot_device_run_log
@@ -1280,12 +1479,11 @@
 
     <select id="batchQueryMaxReportData" resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
         SELECT t.device_id, t.point_name, MAX(t.total_run_time) as total_run_time
-        FROM iot_device_run_log t
+        FROM rq_iot_device_run_log t
         WHERE
         <foreach collection="list" item="item" separator="OR">
             (t.device_id = #{item.deviceId}
-            AND t.point_name = #{item.pointName}
-            AND DATE(t.create_time) = DATE(#{item.createTime}))
+            AND t.point_name = #{item.pointName})
         </foreach>
         GROUP BY t.device_id, t.point_name
     </select>
@@ -1349,6 +1547,21 @@
         select * from system_users where dept_id = #{deptId} and nickname = '技术员'
     </select>
 
+    <select id="getUserId" parameterType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO"
+            resultType="cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO">
+        select distinct a.person_id device_id from
+            rq_iot_device_person a
+                left join
+            rq_iot_device b
+            on a.device_id = b.id
+                left join
+            system_dept c
+            on b.dept_id = c.id
+        where c.id = #{deptId}
+            limit 1
+    </select>
+
+    
 
 
 </mapper>