Jelajahi Sumber

pms 以公司为维度 统计所有超时保养的设备 明细

zhangcl 4 hari lalu
induk
melakukan
786688b5c4

+ 11 - 6
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorder/IotMainWorkOrderController.java

@@ -10,10 +10,7 @@ import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.*;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
@@ -159,11 +156,19 @@ public class IotMainWorkOrderController {
         return success(new PageResult<>(buildDeviceDistanceList(pageResult.getList()), pageResult.getTotal()));
     }
 
+    @GetMapping("/deviceMainTimeoutList")
+    @Operation(summary = "以公司为维度 统计所有超时保养的设备(保养里程 保养时长 保养自然日期) 统计报表明细")
+    @PermitAll
+    public CommonResult<List<IotDeviceRespVO>> deviceMainTimeoutList(@Valid IotMainWorkOrderPageReqVO pageReqVO) {
+        List<IotDeviceRespVO> timeoutDevices = iotMainWorkOrderService.deviceMainTimeoutList(pageReqVO);
+        return success(buildDeviceDistanceList(timeoutDevices));
+    }
+
     @GetMapping("/timeoutDeviceMainDistances")
     @Operation(summary = "以公司为维度 统计所有超时保养的设备(保养里程 保养时长 保养自然日期)")
     @PermitAll
-    public CommonResult<Map<String, Integer>> timeoutDeviceMainDistances(@Valid IotMainWorkOrderPageReqVO pageReqVO) {
-        Map<String, Integer> deviceMainDistances = iotMainWorkOrderService.timeoutDeviceMainDistances(pageReqVO);
+    public CommonResult<List<IotDeviceMainTimeoutVO>> timeoutDeviceMainDistances(@Valid IotMainWorkOrderPageReqVO pageReqVO) {
+        List<IotDeviceMainTimeoutVO> deviceMainDistances = iotMainWorkOrderService.timeoutDeviceMainDistances(pageReqVO);
         return success(deviceMainDistances);
     }
 

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

@@ -288,6 +288,10 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
                                            @Param("alarmDeviceIds") Collection<Long> alarmDeviceIds,
                                            @Param("deptIds") Collection<Long> deptIds);
 
+    List<IotDeviceRespVO> timeoutDeviceMaintenances(@Param("reqVO") IotMainWorkOrderPageReqVO reqVO,
+                                              @Param("alarmDeviceIds") Collection<Long> alarmDeviceIds,
+                                              @Param("deptIds") Collection<Long> deptIds);
+
     List<IotDeviceRespVO> deviceAlarmDistances(@Param("sortedDeviceIds") Collection<Long> sortedDeviceIds,
                                            @Param("deviceIds") Collection<Long> deviceIds,
                                            @Param("mainBomDeviceIds") Collection<Long> mainBomDeviceIds);

+ 10 - 5
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderService.java

@@ -1,10 +1,7 @@
 package cn.iocoder.yudao.module.pms.service.iotmainworkorder;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.*;
 import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
@@ -83,13 +80,21 @@ public interface IotMainWorkOrderService {
      */
     PageResult<IotDeviceRespVO> deviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO);
 
+    /**
+     * 以公司为维度 统计所有超时保养的设备(保养里程 保养时长 保养自然日期) 统计报表明细
+     *
+     * @param pageReqVO 列表查询
+     * @return 超时保养设备列表
+     */
+    List<IotDeviceRespVO> deviceMainTimeoutList(IotMainWorkOrderPageReqVO pageReqVO);
+
     /**
      * 以公司为维度 统计所有超时保养的设备(保养里程 保养时长 保养自然日期)
      *
      * @param pageReqVO 分页查询
      * @return 保养工单分页
      */
-    Map<String, Integer> timeoutDeviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO);
+    List<IotDeviceMainTimeoutVO> timeoutDeviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO);
 
     /**
      * 以设备为维度统计所有保养计划明细中最近的保养数据 里程/时间/自然日期 可能以设备BOM分组

+ 254 - 8
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderServiceImpl.java

@@ -14,10 +14,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDevice
 import cn.iocoder.yudao.module.pms.controller.admin.iotlockstock.vo.IotLockStockPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomRespVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.*;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomSaveReqVO;
@@ -665,11 +662,255 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
         }
     }
 
+    @Override
+    public List<IotDeviceRespVO> deviceMainTimeoutList(IotMainWorkOrderPageReqVO pageReqVO) {
+        // 所有保养计划 + 保养工单 明细中待保养的最近距离 里程/时间/自然日
+        List<IotMainWorkOrderBomDO> workOrderBomS = new ArrayList<>();
+        Set<Long> deviceIds = CollUtil.isEmpty(workOrderBomS)
+                ? new HashSet<>()
+                : workOrderBomS.stream()
+                .map(IotMainWorkOrderBomDO::getDeviceId) // 获取 deviceId
+                .filter(Objects::nonNull)      // 过滤非空值
+                .collect(Collectors.toSet());  // 收集到 Set 中
+        Set<Long> orderDeviceIds = new HashSet<>();
+        orderDeviceIds.addAll(deviceIds);
+        // 查询保养计划明细中不包含 deviceIds 的设备id集合
+        List<IotMaintenanceBomDO> mainBomS = new ArrayList<>();
+        Set<Long> mainBomDeviceIds = new HashSet<>();
+        IotMaintenanceBomPageReqVO mainBomReqVO = new IotMaintenanceBomPageReqVO();
+        if (CollUtil.isNotEmpty(deviceIds)) {
+            mainBomReqVO.setDeviceIds(new ArrayList<>(deviceIds));
+            mainBomS = iotMaintenanceBomMapper.selectAlarmList(mainBomReqVO);
+        } else {
+            mainBomS = iotMaintenanceBomMapper.selectList(mainBomReqVO);
+        }
+        Set<String> boundedMultiAttrNames = new HashSet<>();
+        Set<Long> deviceCategoryIds = new HashSet<>();
+        Map<Long, Long> deviceCategoryPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(mainBomS)) {
+            mainBomDeviceIds = CollUtil.isEmpty(mainBomS)
+                    ? Collections.emptySet()
+                    : mainBomS.stream()
+                    .map(IotMaintenanceBomDO::getDeviceId) // 获取 deviceId
+                    .filter(Objects::nonNull)      // 过滤非空值
+                    .collect(Collectors.toSet());  // 收集到 Set 中
+            // 查询所有保养计划 保养项 中已经绑定的 多个累计时长 公里数 属性名称值
+            mainBomS.forEach(bom -> {
+                if (StrUtil.isNotBlank(bom.getType())) {
+                    // 累计公里数属性
+                    boundedMultiAttrNames.add(bom.getType());
+                }
+                if (StrUtil.isNotBlank(bom.getCode())) {
+                    // 累计时长属性
+                    boundedMultiAttrNames.add(bom.getCode());
+                }
+            });
+            // 查询所有设备类别id
+            // 组装bom关联的设备信息
+            Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(convertListByFlatMap(mainBomS,
+                    bom -> Stream.of(bom.getDeviceId())));
+            if (CollUtil.isNotEmpty(deviceMap)) {
+                deviceMap.forEach((k,v) -> {
+                    deviceCategoryIds.add(v.getAssetClass());
+                    deviceCategoryPair.put(k, v.getAssetClass());
+                });
+            }
+        }
+        deviceIds.addAll(mainBomDeviceIds);
+        if (CollUtil.isEmpty(deviceIds)){
+            // 没有设备信息,返回空列表
+            return new ArrayList<>();
+        }
+        // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
+        List<IotDeviceRunLogRespVO> multipleAccumulatedData = new ArrayList<>();
+        if (CollUtil.isNotEmpty(deviceIds) && CollUtil.isNotEmpty(boundedMultiAttrNames)) {
+            multipleAccumulatedData = iotDeviceRunLogService.multipleAccumulatedData(deviceIds, boundedMultiAttrNames);
+        }
+        // key(设备id-累计时长属性名称)    value时长属性累计时长数值
+        Map<String, BigDecimal> tempTotalRunDataPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(multipleAccumulatedData)) {
+            multipleAccumulatedData.forEach(data -> {
+                String uniqueKey = StrUtil.join("-", data.getDeviceId(), data.getPointName());
+                tempTotalRunDataPair.put(uniqueKey, data.getTotalRunTime());
+            });
+        }
+
+        // 查询 运行记录模板中 正常的累计时长 公里数集合
+        // Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap = iotDeviceRunLogService.getDeviceRunLogMap(new ArrayList<>(deviceIds));
+        Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap =
+                iotDeviceRunLogService.getDeviceRunLogMapAlone(new ArrayList<>(deviceIds), new ArrayList<>(deviceCategoryIds), deviceCategoryPair);
+        // 以设备为维度统计每个设备相关的保养项的最近保养距离 key设备id    value设备下每个保养项的的最小保养距离集合
+        Map<Long, List<Map<String, Object>>> orderDistancePair = new HashMap<>();
+        // 设备保养明细 key设备id  value设备保养工单明细下所有保养规则数据最小值
+        Map<Long, String> resultMap = new HashMap<>();
+        // 记录保养项的 提前量 key设备id-保养项id-距离保养值   value提前量
+        Map<String, BigDecimal> bomLeadPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(mainBomS)) {
+            // 遍历保养计划明细 计算 保养计划中的设备 的最近的保养时间
+            for (IotMaintenanceBomDO bom : mainBomS) {
+                BigDecimal runningTimeDistance = null;
+                BigDecimal runningKiloDistance = null;
+                BigDecimal naturalDateDistance = null;
+                // 计算每个保养项 每个保养规则下的 距离保养时间 单位 小时
+                if (ObjUtil.isNotEmpty(bom.getRunningTimeRule()) && 0 == bom.getRunningTimeRule()) {
+                    // 运行时间保养规则
+                    BigDecimal totalRunTime = BigDecimal.ZERO;
+                    if (deviceRunLogMap.containsKey(bom.getDeviceId())) {
+                        totalRunTime = deviceRunLogMap.get(bom.getDeviceId()).getTotalRunTime();
+                    } else {
+                        // 运行记录模板中包含多个累计时长 公里数类型的属性
+                        String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getCode());
+                        if (tempTotalRunDataPair.containsKey(uniqueKey)) {
+                            totalRunTime = tempTotalRunDataPair.get(uniqueKey);
+                        }
+                    }
+                    BigDecimal lastRunningTime = bom.getLastRunningTime();      // 上次保养运行时间
+                    BigDecimal runningTimePeriod = bom.getNextRunningTime();    // 运行时间周期
+                    BigDecimal timePeriodLead = bom.getTimePeriodLead();    // 运行时间周期提前量
+                    runningTimeDistance = runningTimePeriod.subtract(totalRunTime.subtract(lastRunningTime));
+                    String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), runningTimeDistance);
+                    bomLeadPair.put(uniqueKey, timePeriodLead);
+                }
+                if (ObjUtil.isNotEmpty(bom.getMileageRule()) && 0 == bom.getMileageRule()) {
+                    // 运行里程保养规则 累计运行里程规则 累计运行里程 >= (上次保养运行里程+运行里程周期-提前量)
+                    BigDecimal totalMileage = BigDecimal.ZERO;
+                    if (deviceRunLogMap.containsKey(bom.getDeviceId())) {
+                        totalMileage = deviceRunLogMap.get(bom.getDeviceId()).getTotalMileage();
+                    } else {
+                        // 运行记录模板中包含多个累计时长 公里数类型的属性
+                        String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getType());
+                        if (tempTotalRunDataPair.containsKey(uniqueKey)) {
+                            totalMileage = tempTotalRunDataPair.get(uniqueKey);
+                        }
+                    }
+                    BigDecimal lastRunningKilo = bom.getLastRunningKilometers();      // 上次保养运行里程
+                    BigDecimal runningKiloPeriod = bom.getNextRunningKilometers();    // 运行里程周期
+                    BigDecimal kiloCycleLead = bom.getKiloCycleLead();    // 运行里程周期提前量
+                    runningKiloDistance = runningKiloPeriod.subtract(totalMileage.subtract(lastRunningKilo));
+                    String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), runningKiloDistance);
+                    bomLeadPair.put(uniqueKey, kiloCycleLead);
+                }
+                if (ObjUtil.isNotEmpty(bom.getNaturalDateRule()) && 0 == bom.getNaturalDateRule()) {
+                    // 自然日期保养规则
+                    LocalDateTime lastNaturalDate = bom.getLastNaturalDate();      // 上次保养自然日期
+                    BigDecimal naturalDatePeriod = bom.getNextNaturalDate();        // 自然日周期
+                    BigDecimal natualDateLead = bom.getNaturalDatePeriodLead();    // 自然日周期提前量
+                    if (ObjUtil.isNotEmpty(lastNaturalDate) && ObjUtil.isNotEmpty(naturalDatePeriod) && ObjUtil.isNotEmpty(natualDateLead)) {
+                        // 计算有效天数 = 自然日周期 - 提前量
+                        long days = naturalDatePeriod.longValue(); // 转为长整型天数
+                        // 计算目标日期:上次保养日期 + 有效天数(注意:LocalDateTime加天数会自动处理日期进位)
+                        LocalDateTime targetDate = lastNaturalDate.plusDays(days);
+                        // 获取当前日期时间
+                        LocalDateTime now = LocalDateTime.now();
+                        // 计算日期差值(以天为单位)
+                        naturalDateDistance = new BigDecimal(ChronoUnit.DAYS.between(now, targetDate));
+                        String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), naturalDateDistance);
+                        bomLeadPair.put(uniqueKey, natualDateLead);
+                    }
+                }
+                // 找出距离0最近的数,作为工单的最近保养距离数据
+                Object closet = chooseNearestDistance(runningTimeDistance, runningKiloDistance, naturalDateDistance);
+                Map<String, Object> tempDistance = new HashMap<>();
+                if (closet == runningTimeDistance) {
+                    tempDistance.put("H", closet);
+                } else if (closet == runningKiloDistance) {
+                    tempDistance.put("KM", closet);
+                } else if (closet == naturalDateDistance) {
+                    tempDistance.put("D", closet);
+                }
+                if (orderDistancePair.containsKey(bom.getDeviceId())) {
+                    List<Map<String, Object>> tempDistances = orderDistancePair.get(bom.getDeviceId());
+                    tempDistances.add(tempDistance);
+                    orderDistancePair.put(bom.getDeviceId(), tempDistances);
+                } else {
+                    List<Map<String, Object>> tempDistances = new ArrayList<>();
+                    tempDistances.add(tempDistance);
+                    orderDistancePair.put(bom.getDeviceId(), tempDistances);
+                }
+            }
+        }
+        // 以设备id 为维度 统计每个保养工单明细中 距离最近的保养数据
+        resultMap = findClosestToZero(orderDistancePair);
+        // 根据保养项规则应该生成保养工单的设备id集合
+        Set<Long> shouldWorkOrderFlags = new HashSet<>();
+        // 找出设备保养项距离保养最小值对应的 提前量
+        if (CollUtil.isNotEmpty(resultMap)) {
+            resultMap.forEach((k,v) -> {
+                // k设备id    v距离保养最小值(带单位)
+                // 去掉v中带的单位 310 D   -61.00 H
+                String[] distanceStrs = v.split(" ");
+                BigDecimal tempDistance = new BigDecimal(distanceStrs[0]);
+                if (tempDistance.compareTo(BigDecimal.ZERO) < 0) {
+                    shouldWorkOrderFlags.add(k);
+                }
+                if (CollUtil.isNotEmpty(bomLeadPair)) {
+                    bomLeadPair.forEach((key,value) -> {
+                        // key设备id-保养项id-距离保养值   value提前量
+                        String[] uniqueKeyStrs = key.split("-");
+                        if (uniqueKeyStrs.length == 3) {
+                            if (String.valueOf(k).equals(uniqueKeyStrs[0]) && distanceStrs[0].equals(uniqueKeyStrs[2])
+                                    && tempDistance.compareTo(BigDecimal.ZERO)>=0 && tempDistance.compareTo(value)<=0 )  {
+                                shouldWorkOrderFlags.add(k);
+                            }
+                        }
+                    });
+                }
+            });
+        }
+        // 对集合 resultMap 中所有数据进行排序 按照 map 的value值 去除后面的 字符后 升序排列
+        // 排序后输出一个 List<Long> 类型的集合,排序对应上面的排序规则
+        List<Long> sortedDeviceIds = sortByNumericTimeoutValue(resultMap);
+        try {
+            // 左侧组织树 组织层级查询
+            Set<Long> ids = new HashSet<>();
+            if (Objects.nonNull(pageReqVO.getDeptId())) {
+                ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
+                ids.add(pageReqVO.getDeptId());
+            }
+            // 不查询保养订单表 暂时传一个不会出现的设备id
+            orderDeviceIds.add(Long.MIN_VALUE);
+            List<IotDeviceRespVO> alarmDevices = iotDeviceMapper.deviceAlarmDistances(sortedDeviceIds, orderDeviceIds, sortedDeviceIds);
+            // 处理当前分页数据 拼接上已经排序的 筛选出的设备保养项 最小保养距离
+            List<Long> alarmDeviceIds = new ArrayList<>();
+            Map<Long, IotDeviceRespVO> alarmDevicePair = new HashMap<>();
+            if (CollUtil.isNotEmpty(alarmDevices)) {
+                for (IotDeviceRespVO device : alarmDevices) {
+                    if (resultMap.containsKey(device.getId())) {
+                        device.setMainDistance(resultMap.get(device.getId()));
+                        alarmDeviceIds.add(device.getId());
+                    }
+                    alarmDevicePair.put(device.getId(), device);
+                }
+            }
+            // 查询所有设备列表 通过SQL形式 使用 FIELD 字段
+            List<IotDeviceRespVO> page = iotDeviceMapper.timeoutDeviceMaintenances(pageReqVO, alarmDeviceIds, ids);
+            if (CollUtil.isNotEmpty(page)) {
+                page.forEach(device -> {
+                    if (alarmDevicePair.containsKey(device.getId())) {
+                        device.setMainDistance(alarmDevicePair.get(device.getId()).getMainDistance());
+                        device.setPlanId(alarmDevicePair.get(device.getId()).getPlanId());
+                        device.setWorkOrderId(alarmDevicePair.get(device.getId()).getWorkOrderId());
+                    }
+                    if (shouldWorkOrderFlags.contains(device.getId())) {
+                        device.setShouldWorkOrder(true);
+                    }
+                });
+            }
+            return page;
+        } catch (Exception exception) {
+            if (exception.getMessage().contains("Table does not exist")) {
+                return new ArrayList<>();
+            }
+            throw exception;
+        }
+    }
+
 
     @Override
-    public Map<String, Integer> timeoutDeviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO) {
+    public List<IotDeviceMainTimeoutVO> timeoutDeviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO) {
         // key公司级部门名称     value公司下所有保养超时的设备数量
         Map<String, Integer> companyNameTimeoutDevices = new HashMap<>();
+        List<IotDeviceMainTimeoutVO> companyMainTimeoutDevices = new ArrayList<>();
         // 所有保养计划 明细中待保养的最近距离 里程/时间/自然日
         DataPermissionUtils.executeIgnore(() -> {
             List<IotMainWorkOrderBomDO> workOrderBomS = new ArrayList<>();
@@ -726,7 +967,7 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
             deviceIds.addAll(mainBomDeviceIds);
             if (CollUtil.isEmpty(deviceIds)){
                 // 没有设备信息,返回空列表
-                return companyNameTimeoutDevices;
+                return companyMainTimeoutDevices;
             }
             // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
             List<IotDeviceRunLogRespVO> multipleAccumulatedData = new ArrayList<>();
@@ -927,17 +1168,22 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
                                 if (firstLevelDeptNamePair.containsKey(k)) {
                                     String companyName = firstLevelDeptNamePair.get(k);
                                     companyNameTimeoutDevices.put(companyName, v);
+                                    IotDeviceMainTimeoutVO timeoutDevice = new IotDeviceMainTimeoutVO();
+                                    timeoutDevice.setDeptName(companyName);
+                                    timeoutDevice.setDeptId(k);
+                                    timeoutDevice.setCount(v);
+                                    companyMainTimeoutDevices.add(timeoutDevice);
                                 }
                             });
                         }
                     }
                 }
-                return companyNameTimeoutDevices;
+                return companyMainTimeoutDevices;
             } catch (Exception exception) {
                 return new HashMap<>();
             }
         });
-        return companyNameTimeoutDevices;
+        return companyMainTimeoutDevices;
     }
 
     @Override

+ 45 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotDeviceMapper.xml

@@ -86,6 +86,51 @@
         rid.id DESC;
     </select>
 
+    <select id="timeoutDeviceMaintenances"
+            resultType="cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO">
+        SELECT
+        rid.id,
+        rid.dept_id AS deptId,
+        rid.device_code AS deviceCode,
+        rid.device_name AS deviceName,
+        rid.device_status AS deviceStatus,
+        rid.model AS model,
+        rid.asset_property AS assetProperty
+        FROM rq_iot_device rid
+        WHERE rid.deleted = 0
+        <if test="deptIds != null and deptIds.size &gt; 0">
+            AND rid.dept_id IN
+            <foreach collection="deptIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        <if test="reqVO.deviceName!=null and reqVO.deviceName!=''">
+            AND rid.device_name LIKE concat(concat("%",#{reqVO.deviceName}),"%")
+        </if>
+        <if test="reqVO.deviceCode!=null and reqVO.deviceCode!=''">
+            AND rid.device_code LIKE concat(concat("%",#{reqVO.deviceCode}),"%")
+        </if>
+        <if test="alarmDeviceIds != null and alarmDeviceIds.size &gt; 0">
+            AND rid.id IN
+            <foreach collection="alarmDeviceIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+        ORDER BY
+        <if test="alarmDeviceIds != null and alarmDeviceIds.size &gt; 0">
+            CASE WHEN rid.id IN
+            <foreach collection="alarmDeviceIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+            THEN 0 ELSE 1 END,
+            FIELD(rid.id,
+            <foreach collection="alarmDeviceIds" index="index" item="key" separator=",">
+                #{key}
+            </foreach>),
+        </if>
+        rid.id DESC;
+    </select>
+
     <select id="deviceDistances"
             resultType="cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO">
         SELECT *