Browse Source

pms 设备分类BOM设置物料数量 保养工单列表根据保养项的最近保养距离升序排列

zhangcl 1 month ago
parent
commit
de54c7d3f5
13 changed files with 328 additions and 1 deletions
  1. 43 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotcommonbommaterial/IotCommonBomMaterialController.java
  2. 7 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotcommonbommaterial/vo/IotCommonBomMaterialRespVO.java
  3. 22 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorder/IotMainWorkOrderController.java
  4. 6 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmaterial/vo/IotMaterialPageReqVO.java
  5. 7 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmaterial/vo/IotMaterialRespVO.java
  6. 11 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorder/IotMainWorkOrderMapper.java
  7. 20 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmaterial/IotMaterialMapper.java
  8. 1 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotbom/IotBomServiceImpl.java
  9. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderService.java
  10. 162 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderServiceImpl.java
  11. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmaterial/IotMaterialService.java
  12. 5 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmaterial/IotMaterialServiceImpl.java
  13. 28 0
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotMainWorkOrderMapper.xml

+ 43 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotcommonbommaterial/IotCommonBomMaterialController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
@@ -9,8 +10,11 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial.vo.IotCommonBomMaterialPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial.vo.IotCommonBomMaterialRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotcommonbommaterial.vo.IotCommonBomMaterialSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmaterial.vo.IotMaterialPageReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotcommonbommaterial.IotCommonBomMaterialDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmaterial.IotMaterialDO;
 import cn.iocoder.yudao.module.pms.service.iotcommonbommaterial.IotCommonBomMaterialService;
+import cn.iocoder.yudao.module.pms.service.iotmaterial.IotMaterialService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -22,10 +26,15 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
 
 @Tag(name = "管理后台 - PMS 设备分类公共BOM挂载物料关联")
 @RestController
@@ -36,6 +45,9 @@ public class IotCommonBomMaterialController {
     @Resource
     private IotCommonBomMaterialService iotCommonBomMaterialService;
 
+    @Resource
+    private IotMaterialService iotMaterialService;
+
     @PostMapping("/create")
     @Operation(summary = "创建PMS 设备分类公共BOM挂载物料关联")
     @PreAuthorize("@ss.hasPermission('pms:iot-common-bom-material:create')")
@@ -91,7 +103,37 @@ public class IotCommonBomMaterialController {
     @PreAuthorize("@ss.hasPermission('pms:iot-common-bom-material:query')")
     public CommonResult<PageResult<IotCommonBomMaterialRespVO>> getIotCommonBomMaterialPage(@Valid IotCommonBomMaterialPageReqVO pageReqVO) {
         PageResult<IotCommonBomMaterialDO> pageResult = iotCommonBomMaterialService.getIotCommonBomMaterialPage(pageReqVO);
-        return success(BeanUtils.toBean(pageResult, IotCommonBomMaterialRespVO.class));
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(new PageResult<>(pageResult.getTotal()));
+        }
+        // return success(BeanUtils.toBean(pageResult, IotCommonBomMaterialRespVO.class));
+        return success(new PageResult<>(buildBomMaterials(pageResult.getList()), pageResult.getTotal()));
+    }
+
+    /**
+     * 组装 物料 单位
+     * @param bomMaterials
+     * @return
+     */
+    private List<IotCommonBomMaterialRespVO> buildBomMaterials(List<IotCommonBomMaterialDO> bomMaterials) {
+        if (CollUtil.isEmpty(bomMaterials)) {
+            return Collections.emptyList();
+        }
+        // 查询所有物料的单位
+        IotMaterialPageReqVO reqVO = new IotMaterialPageReqVO();
+        reqVO.setCodes(convertList(bomMaterials, IotCommonBomMaterialDO::getCode));
+        List<IotMaterialDO> materials = iotMaterialService.getIotMaterials(reqVO);
+        Map<String, String> materialUnitPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(materials)) {
+            materials.forEach(material -> {
+                materialUnitPair.put(material.getCode(), material.getUnit());
+            });
+        }
+        // 2. 拼接数据
+        return BeanUtils.toBean(bomMaterials, IotCommonBomMaterialRespVO.class, (materialVO) -> {
+            // 2.1 拼接部门信息
+            findAndThen(materialUnitPair, materialVO.getCode(), material -> materialVO.setUnit(material));
+        });
     }
 
     @GetMapping("/export-excel")

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

@@ -53,4 +53,11 @@ public class IotCommonBomMaterialRespVO {
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    /**
+     * 扩展 字段
+     */
+    @Schema(description = "单位")
+    @ExcelProperty("单位")
+    private String unit;
+
 }

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

@@ -129,6 +129,14 @@ public class IotMainWorkOrderController {
         return success(new PageResult<>(buildMainWorkOrderList(pageResult.getList()), pageResult.getTotal()));
     }
 
+    @GetMapping("/sortedMainWorkOrderPage")
+    @Operation(summary = "获得保养工单分页 按照保养项的最近保养排序")
+    @PreAuthorize("@ss.hasPermission('pms:iot-main-work-order:query')")
+    public CommonResult<PageResult<IotMainWorkOrderRespVO>> sortedMainWorkOrderPage(@Valid IotMainWorkOrderPageReqVO pageReqVO) {
+        PageResult<IotMainWorkOrderRespVO> pageResult = iotMainWorkOrderService.sortedMainWorkOrderPage(pageReqVO);
+        return success(new PageResult<>(buildSortedMainWorkOrders(pageResult.getList()), pageResult.getTotal()));
+    }
+
     @GetMapping("/deviceMainDistances")
     @Operation(summary = "以设备为维度统计所有保养明细中最近的保养数据 里程/时间/自然日期")
     @PreAuthorize("@ss.hasPermission('pms:iot-main-work-order:query')")
@@ -203,6 +211,20 @@ public class IotMainWorkOrderController {
         });
     }
 
+    private List<IotMainWorkOrderRespVO> buildSortedMainWorkOrders(List<IotMainWorkOrderRespVO> orders) {
+        if (CollUtil.isEmpty(orders)) {
+            return Collections.emptyList();
+        }
+        // 查询保养计划 负责人
+        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(orders,
+                order -> Stream.of(NumberUtils.parseLong(order.getResponsiblePerson()))));
+        return BeanUtils.toBean(orders, IotMainWorkOrderRespVO.class, orderVO -> {
+            // 设置创建人、负责人名称
+            MapUtils.findAndThen(userMap, NumberUtils.parseLong(orderVO.getResponsiblePerson()),
+                    user -> orderVO.setResponsiblePersonName(user.getNickname()));
+        });
+    }
+
     @GetMapping("/export-excel")
     @Operation(summary = "导出保养工单 Excel")
     @PreAuthorize("@ss.hasPermission('pms:iot-main-work-order:export')")

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmaterial/vo/IotMaterialPageReqVO.java

@@ -8,6 +8,7 @@ import lombok.ToString;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.time.LocalDateTime;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
@@ -64,4 +65,9 @@ public class IotMaterialPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
 
+    /**
+     * 扩展字段
+     */
+    @Schema(description = "物料编码列表", example = "2298,2938,923")
+    private List<String> codes;
 }

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

@@ -79,4 +79,11 @@ public class IotMaterialRespVO {
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    /**
+     * 扩展字段
+     */
+    @Schema(description = "数量", example = "12345")
+    @ExcelProperty("数量")
+    private String quantity;
+
 }

+ 11 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorder/IotMainWorkOrderMapper.java

@@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -95,4 +96,14 @@ public interface IotMainWorkOrderMapper extends BaseMapperX<IotMainWorkOrderDO>
     List<Map<String, Integer>> allWorkOrderCountByResult();
 
     IPage<IotMainWorkOrderRespVO> deviceOrderPage(IPage<IotMainWorkOrderRespVO> page, @Param("deviceId") Long deviceId);
+
+    /**
+     * 查询 保养工单 分页列表 按照工单保养项 最近保养时间 升序排列
+     * @param page
+     * @param reqVO
+     * @param alarmWorkOrderIds
+     * @return
+     */
+    IPage<IotMainWorkOrderRespVO> sortedMainWorkOrders(IPage<IotMainWorkOrderDO> page, @Param("reqVO") IotMainWorkOrderPageReqVO reqVO,
+                                              @Param("alarmWorkOrderIds") Collection<Long> alarmWorkOrderIds);
 }

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

@@ -44,6 +44,26 @@ public interface IotMaterialMapper extends BaseMapperX<IotMaterialDO> {
                 .orderByDesc(IotMaterialDO::getId));
     }
 
+    default List<IotMaterialDO> selectList(IotMaterialPageReqVO reqVO, Collection<Long> ids) {
+        return selectList(new LambdaQueryWrapperX<IotMaterialDO>()
+                .inIfPresent(IotMaterialDO::getMaterialGroupId, ids)
+                .eqIfPresent(IotMaterialDO::getBomId, reqVO.getBomId())
+                .eqIfPresent(IotMaterialDO::getType, reqVO.getType())
+                .likeIfPresent(IotMaterialDO::getCode, reqVO.getCode())
+                .inIfPresent(IotMaterialDO::getCode, reqVO.getCodes())
+                .likeIfPresent(IotMaterialDO::getName, reqVO.getName())
+                .eqIfPresent(IotMaterialDO::getModel, reqVO.getModel())
+                .eqIfPresent(IotMaterialDO::getUnit, reqVO.getUnit())
+                .eqIfPresent(IotMaterialDO::getSapCode, reqVO.getSapCode())
+                .eqIfPresent(IotMaterialDO::getSyncStatus, reqVO.getSyncStatus())
+                .betweenIfPresent(IotMaterialDO::getSyncTime, reqVO.getSyncTime())
+                .eqIfPresent(IotMaterialDO::getSyncError, reqVO.getSyncError())
+                .eqIfPresent(IotMaterialDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotMaterialDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(IotMaterialDO::getRemark, reqVO.getRemark())
+                .betweenIfPresent(IotMaterialDO::getCreateTime, reqVO.getCreateTime()));
+    }
+
     /**
      * 查询 未同步的物料 列表
      * @return

+ 1 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotbom/IotBomServiceImpl.java

@@ -279,6 +279,7 @@ public class IotBomServiceImpl implements IotBomService {
                 deviceMaterial.setBomNodeId(deviceBomNodeId);
                 deviceMaterial.setName(bomMaterial.getName());
                 deviceMaterial.setCode(bomMaterial.getCode());
+                deviceMaterial.setQuantity(bomMaterial.getQuantity());
                 deviceMaterial.setMaterialId(bomMaterial.getMaterialId());
                 deviceMaterial.setCreator(bomMaterial.getCreator());
                 deviceMaterial.setCreateTime(LocalDateTime.now());

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

@@ -59,6 +59,14 @@ public interface IotMainWorkOrderService {
      */
     PageResult<IotMainWorkOrderDO> getIotMainWorkOrderPage(IotMainWorkOrderPageReqVO pageReqVO);
 
+    /**
+     * 保养工单分页 按照 每个保养工单中 最近保养项的保养距离 由小到大 排序
+     *
+     * @param pageReqVO 分页查询
+     * @return 保养工单分页
+     */
+    PageResult<IotMainWorkOrderRespVO> sortedMainWorkOrderPage(IotMainWorkOrderPageReqVO pageReqVO);
+
     /**
      * 以设备为维度统计所有保养明细中最近的保养数据 里程/时间/自然日期
      *

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

@@ -137,6 +137,168 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
         return iotMainWorkOrderMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public PageResult<IotMainWorkOrderRespVO> sortedMainWorkOrderPage(IotMainWorkOrderPageReqVO pageReqVO) {
+        // 查询 未执行 计划生成 的工单
+        IotMainWorkOrderPageReqVO reqVO = new IotMainWorkOrderPageReqVO();
+        reqVO.setResult(1);
+        reqVO.setType(1);
+        List<Long> workOrderIds = new ArrayList<>();
+        List<IotMainWorkOrderDO> workOrders = iotMainWorkOrderMapper.selectList(reqVO);
+        if (CollUtil.isNotEmpty(workOrders)) {
+            workOrders.forEach(order -> {
+                workOrderIds.add(order.getId());
+            });
+        }
+        List<IotMainWorkOrderBomDO> workOrderBomS = new ArrayList<>();
+        IotMainWorkOrderBomPageReqVO bomReqVO = new IotMainWorkOrderBomPageReqVO();
+        if (CollUtil.isNotEmpty(workOrderIds)) {
+            bomReqVO.setWorkOrderIds(workOrderIds);
+            // 查询 未执行的计划生成的工单 的保养项明细
+            workOrderBomS= iotMainWorkOrderBomMapper.selectList(bomReqVO);
+        }
+        // 保养工单保养项明细中已经绑定的 多累计属性 名称
+        Set<String> boundedMultiAttrNames = new HashSet<>();
+        // 工单保养项中包含的设备id集合
+        Set<Long> deviceIds = new HashSet<>();
+        if (CollUtil.isNotEmpty(workOrderBomS)) {
+            // 查询所有保养计划 保养项 中已经绑定的 多个累计时长 公里数 属性名称值
+            workOrderBomS.forEach(bom -> {
+                if (StrUtil.isNotBlank(bom.getType())) {
+                    // 累计公里数属性
+                    boundedMultiAttrNames.add(bom.getType());
+                }
+                if (StrUtil.isNotBlank(bom.getCode())) {
+                    // 累计时长属性
+                    boundedMultiAttrNames.add(bom.getCode());
+                }
+                if (ObjUtil.isNotEmpty(bom.getDeviceId())) {
+                    deviceIds.add(bom.getDeviceId());
+                }
+            });
+        }
+        // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
+        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));
+        // 以保养工单为维度 统计每个工单相关的保养项的最近保养距离 key保养工单id    value保养工单下每个保养项的的最小保养距离集合
+        Map<Long, List<Map<String, Object>>> orderDistancePair = new HashMap<>();
+        // key保养工单id  value设备保养工单明细下所有保养规则数据最小值
+        Map<Long, String> resultMap = new HashMap<>();
+
+        // 计算出每个保养工单明细的不同保养规则的保养距离最小值
+        if (CollUtil.isNotEmpty(workOrderBomS)) {
+            workOrderBomS.forEach(bom -> {
+                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();    // 运行时间周期
+                    runningTimeDistance = runningTimePeriod.subtract(totalRunTime.subtract(lastRunningTime));
+                }
+                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();    // 运行里程周期
+                    runningKiloDistance = runningKiloPeriod.subtract(totalMileage.subtract(lastRunningKilo));
+                }
+                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));
+                    }
+                }
+                // 找出距离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.getWorkOrderId())) {
+                    List<Map<String, Object>> tempDistances = orderDistancePair.get(bom.getWorkOrderId());
+                    tempDistances.add(tempDistance);
+                    orderDistancePair.put(bom.getWorkOrderId(), tempDistances);
+                } else {
+                    List<Map<String, Object>> tempDistances = new ArrayList<>();
+                    tempDistances.add(tempDistance);
+                    orderDistancePair.put(bom.getWorkOrderId(), tempDistances);
+                }
+            });
+        }
+        try {
+            // 以 保养工单id 为维度 统计每个保养工单明细中 距离最近的保养数据
+            resultMap = findClosestToZero(orderDistancePair);
+            // 对集合 resultMap 中所有数据进行排序 按照 map 的value值 去除后面的 字符后 升序排列
+            // 排序后输出一个 List<Long> 类型的集合,排序对应上面的排序规则 集合中的元素是 保养工单id
+            List<Long> sortedWorkOrderIds = sortByNumericValue(resultMap);
+            // 查询所有设备列表 通过SQL形式 使用 FIELD 字段
+            IPage<IotMainWorkOrderRespVO> page = iotMainWorkOrderMapper.sortedMainWorkOrders(
+                    new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO, sortedWorkOrderIds);
+            if (CollUtil.isNotEmpty(page.getRecords())) {
+                Map<Long, String> finalResultMap = resultMap;
+                page.getRecords().forEach(order -> {
+                    if (finalResultMap.containsKey(order.getId())) {
+                        order.setMainDistance(finalResultMap.get(order.getId()));
+                    }
+                });
+            }
+            return new PageResult<>(page.getRecords(), page.getTotal());
+        } catch (Exception exception) {
+            if (exception.getMessage().contains("Table does not exist")) {
+                return PageResult.empty();
+            }
+            throw exception;
+        }
+    }
+
     @Override
     public PageResult<IotDeviceRespVO> deviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO) {
         // 20250624 只查询保养计划中的设备 不查询保养工单表

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmaterial/IotMaterialService.java

@@ -61,6 +61,14 @@ public interface IotMaterialService {
      */
     PageResult<IotMaterialDO> getIotMaterialPage(IotMaterialPageReqVO pageReqVO);
 
+    /**
+     * 获得PMS 功能优化 物料 列表
+     *
+     * @param pageReqVO 分页查询
+     * @return PMS 功能优化 物料 列表
+     */
+    List<IotMaterialDO> getIotMaterials(IotMaterialPageReqVO pageReqVO);
+
     /**
      * 获得指定状态的 物料
      *

+ 5 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmaterial/IotMaterialServiceImpl.java

@@ -94,6 +94,11 @@ public class IotMaterialServiceImpl implements IotMaterialService {
         return iotMaterialMapper.selectPage(pageReqVO, ids);
     }
 
+    @Override
+    public List<IotMaterialDO> getIotMaterials(IotMaterialPageReqVO reqVO) {
+        return iotMaterialMapper.selectList(reqVO, null);
+    }
+
     @Override
     public List<IotMaterialDO> getMaterialListByStatus(Integer status) {
         return iotMaterialMapper.selectListByStatus(status);

+ 28 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotMainWorkOrderMapper.xml

@@ -24,4 +24,32 @@
         ORDER BY rimwo.id DESC
     </select>
 
+    <!-- 按照最近保养时间排序的保养工单 列表 -->
+    <select id="sortedMainWorkOrders"
+            resultType="cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO">
+        SELECT
+            *
+        FROM rq_iot_main_work_order mwo
+        WHERE mwo.deleted = 0
+        <if test="reqVO.name != null and reqVO.name != ''">
+            AND mwo.name LIKE concat(concat("%",#{reqVO.name}),"%")
+        </if>
+        <if test="reqVO.result != null">
+            AND mwo.result = #{reqVO.result}
+        </if>
+        ORDER BY
+        <if test="alarmWorkOrderIds != null and alarmWorkOrderIds.size &gt; 0">
+            CASE WHEN mwo.id IN
+            <foreach collection="alarmWorkOrderIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+            THEN 0 ELSE 1 END,
+            FIELD(mwo.id,
+            <foreach collection="alarmWorkOrderIds" index="index" item="key" separator=",">
+                #{key}
+            </foreach>),
+        </if>
+        mwo.id DESC;
+    </select>
+
 </mapper>