Browse Source

pms功能优化 保养工单 填报

zhangcl 3 tháng trước cách đây
mục cha
commit
990916b395
24 tập tin đã thay đổi với 712 bổ sung78 xóa
  1. 177 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmaintenancebom/vo/IotTobeMaintenanceBomRespVO.java
  2. 48 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/IotMainWorkOrderBomController.java
  3. 2 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/vo/IotMainWorkOrderBomPageReqVO.java
  4. 12 1
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/vo/IotMainWorkOrderBomRespVO.java
  5. 2 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/vo/IotMainWorkOrderBomSaveReqVO.java
  6. 2 2
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotmainworkorderbom/IotMainWorkOrderBomDO.java
  7. 6 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotdevicerunlog/IotDeviceRunLogMapper.java
  8. 5 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorder/IotMainWorkOrderMapper.java
  9. 46 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorderbom/IotMainWorkOrderBomMapper.java
  10. 6 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/maintenance/IotMaintenancePlanMapper.java
  11. 68 18
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/mainworkorder/CreateMainWorkOrderJob.java
  12. 23 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotDeviceService.java
  13. 12 4
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotDeviceServiceImpl.java
  14. 29 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotdevicerunlog/IotDeviceRunLogService.java
  15. 8 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotdevicerunlog/IotDeviceRunLogServiceImpl.java
  16. 21 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderService.java
  17. 22 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorder/IotMainWorkOrderServiceImpl.java
  18. 16 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorderbom/IotMainWorkOrderBomService.java
  19. 13 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorderbom/IotMainWorkOrderBomServiceImpl.java
  20. 9 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/maintenance/IotMaintenancePlanService.java
  21. 6 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/maintenance/IotMaintenancePlanServiceImpl.java
  22. 48 48
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotDeviceMapper.xml
  23. 30 0
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotDeviceRunLogMapper.xml
  24. 101 0
      yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotMaintenancePlanMapper.xml

+ 177 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmaintenancebom/vo/IotTobeMaintenanceBomRespVO.java

@@ -0,0 +1,177 @@
+package cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - PMS 需要保养的明细BOM Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotTobeMaintenanceBomRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "27423")
+    @ExcelProperty("主键")
+    private Long id;
+
+    @Schema(description = "部门id", example = "11371")
+    @ExcelProperty("部门id")
+    private Long deptId;
+
+    @Schema(description = "保养计划id", example = "11371")
+    @ExcelProperty("保养计划id")
+    private Long planId;
+
+    @Schema(description = "保养计划名称", example = "11371")
+    private String planName;
+
+    @Schema(description = "负责人")
+    private String responsiblePerson;
+
+    @Schema(description = "保养计划编码")
+    @ExcelProperty("保养计划编码")
+    private String serialNumber;
+
+    @Schema(description = "保养计划明细id", example = "17738")
+    @ExcelProperty("保养计划明细id")
+    private Long planDetailId;
+
+    @Schema(description = "所属设备分类", example = "21283")
+    @ExcelProperty("所属设备分类")
+    private Long deviceCategoryId;
+
+    @Schema(description = "设备id", example = "19729")
+    @ExcelProperty("设备id")
+    private Long deviceId;
+
+    @Schema(description = "保养规则(量程 运行时间 自然日期) 可多选")
+    @ExcelProperty("保养规则(量程 运行时间 自然日期) 可多选")
+    private String rule;
+
+    @Schema(description = "保养规则-里程(0启用 1停用)", example = "2")
+    private Integer mileageRule;
+    @Schema(description = "保养规则-自然日期(0启用 1停用)", example = "2")
+    private Integer naturalDateRule;
+    @Schema(description = "保养规则-运行时间(0启用 1停用)", example = "2")
+    private Integer runningTimeRule;
+
+    @Schema(description = "上次保养运行时长(小时)")
+    @ExcelProperty("上次保养运行时长(小时)")
+    private BigDecimal lastRunningTime;
+
+    @Schema(description = "下次保养运行时长(小时)")
+    @ExcelProperty("下次保养运行时长(小时)")
+    private BigDecimal nextRunningTime;
+
+    @Schema(description = "运行时长周期提前量 H")
+    @ExcelProperty("运行时长周期提前量 H")
+    private BigDecimal timePeriodLead;
+
+    @Schema(description = "上次保养运行公里数(千米)")
+    @ExcelProperty("上次保养运行公里数(千米)")
+    private BigDecimal lastRunningKilometers;
+
+    @Schema(description = "下次保养运行公里数(千米)")
+    @ExcelProperty("下次保养运行公里数(千米)")
+    private BigDecimal nextRunningKilometers;
+
+    @Schema(description = "公里数周期-提前量 km")
+    @ExcelProperty("公里数周期-提前量 km")
+    private BigDecimal kiloCycleLead;
+
+    @Schema(description = "上次保养自然日期(天)")
+    @ExcelProperty("上次保养自然日期(天)")
+    private LocalDateTime lastNaturalDate;
+
+    @Schema(description = "下次保养自然日期(天)")
+    @ExcelProperty("下次保养自然日期(天)")
+    private BigDecimal nextNaturalDate;
+
+    @Schema(description = "自然日周期-提前量(天)")
+    @ExcelProperty("自然日周期-提前量(天)")
+    private BigDecimal naturalDatePeriodLead;
+
+    @Schema(description = "BOM节点 id", example = "18063")
+    private Long bomNodeId;
+
+    @Schema(description = "BOM名称", example = "张三")
+    @ExcelProperty("BOM名称")
+    private String nodeName;
+
+    @Schema(description = "BOM编码")
+    @ExcelProperty("BOM编码")
+    private String code;
+
+    @Schema(description = "父BOM id 顶级为0", example = "18063")
+    @ExcelProperty("父BOM id 顶级为0")
+    private Long parentId;
+
+    @Schema(description = "子节点id 逗号分隔")
+    @ExcelProperty("子节点id 逗号分隔")
+    private String childIds;
+
+    @Schema(description = "层级")
+    @ExcelProperty("层级")
+    private Integer level;
+
+    @Schema(description = "是否叶子节点 0是 1否")
+    @ExcelProperty("是否叶子节点 0是 1否")
+    private Integer leafFlag;
+
+    @Schema(description = "显示顺序")
+    @ExcelProperty("显示顺序")
+    private Integer sort;
+
+    @Schema(description = "M维修 S保养 维修+保养", example = "2")
+    @ExcelProperty("M维修 S保养 维修+保养")
+    private String type;
+
+    @Schema(description = "状态 0启用  1停用", example = "2")
+    @ExcelProperty("状态 0启用  1停用")
+    private Integer status;
+
+    @Schema(description = "备注", example = "你说的对")
+    @ExcelProperty("备注")
+    private String remark;
+
+    @Schema(description = "版本")
+    @ExcelProperty("版本")
+    private Integer version;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 设备关联字段
+     */
+    @Schema(description = "设备名称")
+    private String deviceName;
+    @Schema(description = "设备编码")
+    private String deviceCode;
+    @Schema(description = "设备状态")
+    private String deviceStatus;
+    @Schema(description = "资产性质")
+    private String assetProperty;
+
+    /**
+     * 触发的保养类型
+     */
+    @Schema(description = "需要根据自然日周期保养")
+    private Integer needMaintainByDate;
+
+    @Schema(description = "需要根据运行公里数周期保养")
+    private Integer needMaintainByMileage;
+
+    @Schema(description = "需要根据运行时长周期保养")
+    private Integer needMaintainByTime;
+
+    /**
+     * 新生成的保养工单id
+     */
+    @Schema(description = "需要根据自然日周期保养")
+    private Long workOrderId;
+}

+ 48 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/IotMainWorkOrderBomController.java

@@ -1,15 +1,21 @@
 package cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom;
 
+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;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 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.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
 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;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
+import cn.iocoder.yudao.module.pms.service.IotDeviceService;
+import cn.iocoder.yudao.module.pms.service.iotdevicerunlog.IotDeviceRunLogService;
 import cn.iocoder.yudao.module.pms.service.iotmainworkorderbom.IotMainWorkOrderBomService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -22,12 +28,16 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
 
 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.convertListByFlatMap;
 
-@Tag(name = "管理后台 - PMS 保养计划明细BOM")
+@Tag(name = "管理后台 - PMS 保养工单明细BOM")
 @RestController
 @RequestMapping("/pms/iot-main-work-order-bom")
 @Validated
@@ -35,6 +45,10 @@ public class IotMainWorkOrderBomController {
 
     @Resource
     private IotMainWorkOrderBomService iotMainWorkOrderBomService;
+    @Resource
+    private IotDeviceService iotDeviceService;
+    @Resource
+    private IotDeviceRunLogService iotDeviceRunLogService;
 
     @PostMapping("/create")
     @Operation(summary = "创建PMS 保养计划明细BOM")
@@ -77,6 +91,17 @@ public class IotMainWorkOrderBomController {
         return success(BeanUtils.toBean(pageResult, IotMainWorkOrderBomRespVO.class));
     }
 
+    @GetMapping("/getWorkOrderBOMs")
+    @Operation(summary = "获得PMS 保养工单明细BOM列表")
+    @PreAuthorize("@ss.hasPermission('pms:iot-main-work-order-bom:query')")
+    public CommonResult<List<IotMainWorkOrderBomRespVO>> getWorkOrderBOMs(@Valid IotMainWorkOrderBomPageReqVO reqVO) {
+        List<IotMainWorkOrderBomDO> workOrderBOMs = iotMainWorkOrderBomService.getIotMainWorkOrderBomList(reqVO);
+        // 组装bom关联的设备名称 编码
+        // 组装bom关联的设备 累计运行时间、累计运行公里数
+        return success(buildMainWorkOrderBomList(workOrderBOMs));
+        // return success(BeanUtils.toBean(workOrderBOMs, IotMainWorkOrderBomRespVO.class));
+    }
+
     @GetMapping("/export-excel")
     @Operation(summary = "导出PMS 保养计划明细BOM Excel")
     @PreAuthorize("@ss.hasPermission('pms:iot-main-work-order-bom:export')")
@@ -90,4 +115,26 @@ public class IotMainWorkOrderBomController {
                         BeanUtils.toBean(list, IotMainWorkOrderBomRespVO.class));
     }
 
+    private List<IotMainWorkOrderBomRespVO> buildMainWorkOrderBomList(List<IotMainWorkOrderBomDO> BOMs) {
+        if (CollUtil.isEmpty(BOMs)) {
+            return Collections.emptyList();
+        }
+        // 组装bom关联的设备信息
+        Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(convertListByFlatMap(BOMs,
+                bom -> Stream.of(bom.getDeviceId())));
+        Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap = iotDeviceRunLogService.getDeviceRunLogMap(convertListByFlatMap(BOMs,
+                bom -> Stream.of(bom.getDeviceId())));
+        // 2. 转换成 VO
+        return BeanUtils.toBean(BOMs, IotMainWorkOrderBomRespVO.class, bomVO -> {
+            // 设置设备相关信息
+            MapUtils.findAndThen(deviceMap, bomVO.getDeviceId(),
+                    device -> bomVO.setDeviceName(device.getDeviceName()));
+            MapUtils.findAndThen(deviceMap, bomVO.getDeviceId(),
+                    device -> bomVO.setDeviceCode(device.getDeviceCode()));
+            MapUtils.findAndThen(deviceRunLogMap, bomVO.getDeviceId(),
+                    device -> bomVO.setTotalMileage(device.getTotalMileage()));
+            MapUtils.findAndThen(deviceRunLogMap, bomVO.getDeviceId(),
+                    device -> bomVO.setTotalRunTime(device.getTotalRunTime()));
+        });
+    }
 }

+ 2 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/vo/IotMainWorkOrderBomPageReqVO.java

@@ -65,9 +65,9 @@ public class IotMainWorkOrderBomPageReqVO extends PageParam {
     @Schema(description = "推迟运行公里数(千米)")
     private BigDecimal delayKilometers;
 
-    @Schema(description = "上次保养自然日期(天)")
+    @Schema(description = "上次保养自然日期")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private BigDecimal[] lastNaturalDate;
+    private LocalDateTime[] lastNaturalDate;
 
     @Schema(description = "下次保养自然日期(天)")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)

+ 12 - 1
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/vo/IotMainWorkOrderBomRespVO.java

@@ -79,7 +79,7 @@ public class IotMainWorkOrderBomRespVO {
 
     @Schema(description = "上次保养自然日期(天)")
     @ExcelProperty("上次保养自然日期(天)")
-    private BigDecimal lastNaturalDate;
+    private LocalDateTime lastNaturalDate;
 
     @Schema(description = "下次保养自然日期(天)")
     @ExcelProperty("下次保养自然日期(天)")
@@ -177,4 +177,15 @@ public class IotMainWorkOrderBomRespVO {
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;
 
+    /**
+     * 设备扩展字段
+     */
+    @Schema(description = "设备编码", example = "YF602")
+    private String deviceCode;
+    @Schema(description = "设备名称", example = "增压机")
+    private String deviceName;
+    @Schema(description = "累计运行时间", example = "30000H")
+    private BigDecimal totalRunTime;
+    @Schema(description = "累计运行公里数", example = "20238km")
+    private BigDecimal totalMileage;
 }

+ 2 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotmainworkorderbom/vo/IotMainWorkOrderBomSaveReqVO.java

@@ -58,8 +58,8 @@ public class IotMainWorkOrderBomSaveReqVO {
     @Schema(description = "推迟运行公里数(千米)")
     private BigDecimal delayKilometers;
 
-    @Schema(description = "上次保养自然日期(天)")
-    private BigDecimal lastNaturalDate;
+    @Schema(description = "上次保养自然日期")
+    private LocalDateTime lastNaturalDate;
 
     @Schema(description = "下次保养自然日期(天)")
     private BigDecimal nextNaturalDate;

+ 2 - 2
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotmainworkorderbom/IotMainWorkOrderBomDO.java

@@ -90,9 +90,9 @@ public class IotMainWorkOrderBomDO extends BaseDO {
      */
     private BigDecimal delayKilometers;
     /**
-     * 上次保养自然日期(天)
+     * 上次保养自然日期
      */
-    private BigDecimal lastNaturalDate;
+    private LocalDateTime lastNaturalDate;
     /**
      * 下次保养自然日期(天)
      */

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotdevicerunlog/IotDeviceRunLogMapper.java

@@ -4,8 +4,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Collection;
+import java.util.List;
 
 /**
  * 设备运行数据记录 中间表 Mapper
@@ -35,4 +40,5 @@ public interface IotDeviceRunLogMapper extends BaseMapperX<IotDeviceRunLogDO> {
                 .orderByDesc(IotDeviceRunLogDO::getId));
     }
 
+    List<IotDeviceRunLogRespVO> distinctDevices(@Param("deviceIds") Collection<Long> deviceIds);
 }

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

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainW
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 保养工单 Mapper
  *
@@ -40,4 +42,7 @@ public interface IotMainWorkOrderMapper extends BaseMapperX<IotMainWorkOrderDO>
                 .orderByDesc(IotMainWorkOrderDO::getId));
     }
 
+    default List<IotMainWorkOrderDO> theMaxOne(){
+        return selectList(new LambdaQueryWrapperX<IotMainWorkOrderDO>().orderByDesc(IotMainWorkOrderDO::getId));
+    }
 }

+ 46 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/iotmainworkorderbom/IotMainWorkOrderBomMapper.java

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMa
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * PMS 保养计划明细BOM Mapper
  *
@@ -60,4 +62,48 @@ public interface IotMainWorkOrderBomMapper extends BaseMapperX<IotMainWorkOrderB
                 .orderByDesc(IotMainWorkOrderBomDO::getId));
     }
 
+    default List<IotMainWorkOrderBomDO> selectList(IotMainWorkOrderBomPageReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<IotMainWorkOrderBomDO>()
+                .eqIfPresent(IotMainWorkOrderBomDO::getPlanId, reqVO.getPlanId())
+                .eqIfPresent(IotMainWorkOrderBomDO::getPlanDetailId, reqVO.getPlanDetailId())
+                .eqIfPresent(IotMainWorkOrderBomDO::getWorkOrderId, reqVO.getWorkOrderId())
+                .eqIfPresent(IotMainWorkOrderBomDO::getDeviceCategoryId, reqVO.getDeviceCategoryId())
+                .eqIfPresent(IotMainWorkOrderBomDO::getDeviceId, reqVO.getDeviceId())
+                .eqIfPresent(IotMainWorkOrderBomDO::getRule, reqVO.getRule())
+                .eqIfPresent(IotMainWorkOrderBomDO::getMileageRule, reqVO.getMileageRule())
+                .eqIfPresent(IotMainWorkOrderBomDO::getNaturalDateRule, reqVO.getNaturalDateRule())
+                .eqIfPresent(IotMainWorkOrderBomDO::getRunningTimeRule, reqVO.getRunningTimeRule())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getLastRunningTime, reqVO.getLastRunningTime())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getNextRunningTime, reqVO.getNextRunningTime())
+                .eqIfPresent(IotMainWorkOrderBomDO::getDelayDuration, reqVO.getDelayDuration())
+                .eqIfPresent(IotMainWorkOrderBomDO::getLastRunningKilometers, reqVO.getLastRunningKilometers())
+                .eqIfPresent(IotMainWorkOrderBomDO::getNextRunningKilometers, reqVO.getNextRunningKilometers())
+                .eqIfPresent(IotMainWorkOrderBomDO::getDelayKilometers, reqVO.getDelayKilometers())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getLastNaturalDate, reqVO.getLastNaturalDate())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getNextNaturalDate, reqVO.getNextNaturalDate())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getDelayNaturalDate, reqVO.getDelayNaturalDate())
+                .eqIfPresent(IotMainWorkOrderBomDO::getDelayReason, reqVO.getDelayReason())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getLastMainDate, reqVO.getLastMainDate())
+                .eqIfPresent(IotMainWorkOrderBomDO::getTimePeriod, reqVO.getTimePeriod())
+                .eqIfPresent(IotMainWorkOrderBomDO::getTimePeriodLead, reqVO.getTimePeriodLead())
+                .eqIfPresent(IotMainWorkOrderBomDO::getKilometerCycle, reqVO.getKilometerCycle())
+                .eqIfPresent(IotMainWorkOrderBomDO::getKiloCycleLead, reqVO.getKiloCycleLead())
+                .eqIfPresent(IotMainWorkOrderBomDO::getNaturalDatePeriod, reqVO.getNaturalDatePeriod())
+                .eqIfPresent(IotMainWorkOrderBomDO::getNaturalDatePeriodLead, reqVO.getNaturalDatePeriodLead())
+                .eqIfPresent(IotMainWorkOrderBomDO::getBomNodeId, reqVO.getBomNodeId())
+                .likeIfPresent(IotMainWorkOrderBomDO::getName, reqVO.getName())
+                .eqIfPresent(IotMainWorkOrderBomDO::getCode, reqVO.getCode())
+                .eqIfPresent(IotMainWorkOrderBomDO::getParentId, reqVO.getParentId())
+                .eqIfPresent(IotMainWorkOrderBomDO::getChildIds, reqVO.getChildIds())
+                .eqIfPresent(IotMainWorkOrderBomDO::getLevel, reqVO.getLevel())
+                .eqIfPresent(IotMainWorkOrderBomDO::getLeafFlag, reqVO.getLeafFlag())
+                .eqIfPresent(IotMainWorkOrderBomDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotMainWorkOrderBomDO::getType, reqVO.getType())
+                .eqIfPresent(IotMainWorkOrderBomDO::getMainType, reqVO.getMainType())
+                .eqIfPresent(IotMainWorkOrderBomDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(IotMainWorkOrderBomDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(IotMainWorkOrderBomDO::getVersion, reqVO.getVersion())
+                .betweenIfPresent(IotMainWorkOrderBomDO::getCreateTime, reqVO.getCreateTime()));
+    }
+
 }

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/maintenance/IotMaintenancePlanMapper.java

@@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.pms.dal.mysql.maintenance;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotTobeMaintenanceBomRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanPageReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 保养计划 Mapper
  *
@@ -31,4 +34,7 @@ public interface IotMaintenancePlanMapper extends BaseMapperX<IotMaintenancePlan
     default IotMaintenancePlanDO selectByNo(String no) {
         return selectOne(IotMaintenancePlanDO::getSerialNumber, no);
     }
+
+
+    List<IotTobeMaintenanceBomRespVO> toBeMaintenanceDeviceBOMs();
 }

+ 68 - 18
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/mainworkorder/CreateMainWorkOrderJob.java

@@ -1,17 +1,23 @@
 package cn.iocoder.yudao.module.pms.job.mainworkorder;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
 import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotTobeMaintenanceBomRespVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectOrderDetailDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectPlanDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.inspect.IotInspectRouteDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.inspect.IotInspectOrderDetailMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.inspect.IotInspectOrderMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.inspect.IotInspectPlanMapper;
+import cn.iocoder.yudao.module.pms.enums.common.FailureAuditStatusEnum;
 import cn.iocoder.yudao.module.pms.service.iotmainworkorder.IotMainWorkOrderService;
+import cn.iocoder.yudao.module.pms.service.iotmainworkorderbom.IotMainWorkOrderBomService;
 import cn.iocoder.yudao.module.pms.service.maintenance.IotMaintenancePlanService;
 import com.alibaba.fastjson.JSON;
 import lombok.extern.slf4j.Slf4j;
@@ -20,8 +26,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
-import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 @Component
@@ -38,27 +44,71 @@ public class CreateMainWorkOrderJob implements JobHandler {
     private IotMaintenancePlanService iotMaintenancePlanService;
     @Resource
     private IotMainWorkOrderService iotMainWorkOrderService;
+    @Resource
+    private IotMainWorkOrderBomService iotMainWorkOrderBomService;
 
     @Override
     @TenantJob
     public String execute(String param) throws Exception {
-        // 查询所有的 保养计划
-        List<IotInspectPlanDO> plans = iotInspectPlanMapper.selectList();
-        plans.forEach(plan -> {
-            if (plan.getLastCreateTime()==null) {
-                Date date = Date.from(
-                        plan.getCreateTime().atZone(ZoneId.systemDefault()) // 使用系统默认时区
-                                .toInstant()                    // 转为 Instant(时间戳)
-                );
-                deal(plan, date);
-            } else {
-                Date lastdate = Date.from(
-                        plan.getLastCreateTime().atZone(ZoneId.systemDefault()) // 使用系统默认时区
-                                .toInstant()                    // 转为 Instant(时间戳)
-                );
-                deal(plan, lastdate);
-            }
-        });
+        // 查询所有的 在保养规则周期内的 设备-bom 关联信息
+        List<IotTobeMaintenanceBomRespVO> tobeMaintenanceBomRespVOS = iotMaintenancePlanService.toBeMaintenanceDeviceBOMs();
+
+        Map<String, IotTobeMaintenanceBomRespVO> maintenancePair = new HashMap<>();
+        Map<String, Long> workOrderIdPair = new HashMap<>();
+        if (CollUtil.isNotEmpty(tobeMaintenanceBomRespVOS)) {
+            tobeMaintenanceBomRespVOS.forEach(maintenance -> {
+                maintenancePair.put(maintenance.getSerialNumber(), maintenance);
+            });
+            // 暂时使用以保养计划为维度,生成保养工单
+            // 查询最新的保养工单id
+            AtomicReference<Long> theMaxId = new AtomicReference<>(iotMainWorkOrderService.theMaxId());
+            List<IotMainWorkOrderDO> workOrders = new ArrayList<>();
+            List<IotMainWorkOrderBomDO> workOrderBOMs = new ArrayList<>();
+            // 组装工单集合
+            maintenancePair.forEach((k,v) ->{
+                IotMainWorkOrderDO workOrder = new IotMainWorkOrderDO();
+                theMaxId.getAndSet(theMaxId.get() + 1);
+                workOrder.setId(theMaxId.get());
+                workOrder.setDeptId(v.getDeptId());
+                workOrder.setPlanId(v.getId());
+                workOrder.setOrderNumber(iotMainWorkOrderService.createWorkOrderNumber());
+                workOrder.setName(v.getPlanName());
+                workOrder.setType(1);   // 计划生成
+                workOrder.setResponsiblePerson(v.getResponsiblePerson());
+                workOrder.setAuditStatus(FailureAuditStatusEnum.DRAFT.getStatus());
+                workOrder.setCreator(v.getResponsiblePerson());
+                workOrders.add(workOrder);
+                workOrderIdPair.put(k, theMaxId.get());
+            });
+            // 组装 工单明细 集合
+            tobeMaintenanceBomRespVOS.forEach(maintenance -> {
+                IotMainWorkOrderBomDO workOrderBom = new IotMainWorkOrderBomDO();
+                workOrderBom.setWorkOrderId(workOrderIdPair.get(maintenance.getSerialNumber()));
+                workOrderBom.setDeviceCategoryId(maintenance.getDeviceCategoryId());
+                workOrderBom.setDeviceId(maintenance.getDeviceId());
+                workOrderBom.setMileageRule(maintenance.getMileageRule());
+                workOrderBom.setRunningTimeRule(maintenance.getRunningTimeRule());
+                workOrderBom.setNaturalDateRule(maintenance.getNaturalDateRule());
+                workOrderBom.setLastRunningTime(maintenance.getLastRunningTime());
+                workOrderBom.setNextRunningTime(maintenance.getNextRunningTime());
+                workOrderBom.setTimePeriodLead(maintenance.getTimePeriodLead());
+                workOrderBom.setLastRunningKilometers(maintenance.getLastRunningKilometers());
+                workOrderBom.setNextRunningKilometers(maintenance.getNextRunningKilometers());
+                workOrderBom.setKiloCycleLead(maintenance.getKiloCycleLead());
+                workOrderBom.setLastNaturalDate(maintenance.getLastNaturalDate());
+                workOrderBom.setNextNaturalDate(maintenance.getNextNaturalDate());
+                workOrderBom.setNaturalDatePeriodLead(maintenance.getNaturalDatePeriodLead());
+                workOrderBom.setBomNodeId(maintenance.getBomNodeId());
+                workOrderBom.setName(maintenance.getNodeName());
+                workOrderBom.setCode(maintenance.getCode());
+                workOrderBOMs.add(workOrderBom);
+            });
+            // 批量新增 保养工单记录
+            iotMainWorkOrderService.batchAddOrders(workOrders);
+            // 批量新增 保养工单明细
+            iotMainWorkOrderBomService.batchAddOrderBOMs(workOrderBOMs);
+        }
+        // 查询需要保养的node节点是否包含在正在执行的保养工单中
         return "创建成功";
     }
 

+ 23 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotDeviceService.java

@@ -1,13 +1,18 @@
 package cn.iocoder.yudao.module.pms.service;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 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.controller.admin.vo.IotDeviceSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 
 import javax.validation.Valid;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 设备台账 Service 接口
@@ -70,4 +75,22 @@ public interface IotDeviceService {
      */
     List<IotDeviceRespVO> deviceAssociateBomList(List<Long> deviceIds);
 
+    /**
+     * 根据设备id查询设备关联信息
+     *
+     * @param ids 设备id集合
+     * @return 设备bom 关联 列表
+     */
+    default Map<Long, IotDeviceRespVO> getDeviceMap(List<Long> ids){
+        List<IotDeviceRespVO> list = getDeviceList(ids);
+        return CollectionUtils.convertMap(list, IotDeviceRespVO::getId);
+    }
+
+    /**
+     * 获得设备信息数组
+     *
+     * @param ids 设备编号数组
+     * @return 设备信息数组
+     */
+    List<IotDeviceRespVO> getDeviceList(Collection<Long> ids);
 }

+ 12 - 4
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotDeviceServiceImpl.java

@@ -16,6 +16,8 @@ import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.IotInfoClassifyMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.IotTreeMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotmodel.IotModelMapper;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
 import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
@@ -28,10 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DEVICE_NOT_EXISTS;
@@ -186,4 +185,13 @@ public class IotDeviceServiceImpl implements IotDeviceService {
         List<IotDeviceRespVO> devices = iotDeviceMapper.deviceAssociateBomList(deviceIds);
         return devices;
     }
+
+    @Override
+    public List<IotDeviceRespVO> getDeviceList(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return Collections.emptyList();
+        }
+        List<IotDeviceDO> devices = iotDeviceMapper.selectBatchIds(ids);
+        return BeanUtils.toBean(devices, IotDeviceRespVO.class);
+    }
 }

+ 29 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotdevicerunlog/IotDeviceRunLogService.java

@@ -1,11 +1,16 @@
 package cn.iocoder.yudao.module.pms.service.iotdevicerunlog;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO;
 
 import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 设备运行数据记录 中间表 Service 接口
@@ -52,4 +57,28 @@ public interface IotDeviceRunLogService {
      */
     PageResult<IotDeviceRunLogDO> getIotDeviceRunLogPage(IotDeviceRunLogPageReqVO pageReqVO);
 
+    /**
+     * 设备的运行记录信息
+     *
+     * @return 设备运行数据记录
+     */
+    List<IotDeviceRunLogRespVO> distinctDevices(List<Long> ids);
+
+    /**
+     * 根据设备id查询设备关联信息
+     *
+     * @param ids 设备id集合
+     * @return 设备bom 关联 列表
+     */
+    default Map<Long, IotDeviceRunLogRespVO> getDeviceRunLogMap(List<Long> ids){
+        List<IotDeviceRunLogRespVO> list = distinctDevices(ids);
+        // 删除集合中的NULL元素
+        list.removeIf(deviceLog -> isAllFieldsNull(deviceLog));
+        return CollectionUtils.convertMap(list, IotDeviceRunLogRespVO::getDeviceId);
+    }
+
+    // 检查是否所有字段都为NULL的辅助方法
+    default boolean isAllFieldsNull(IotDeviceRunLogRespVO deviceLog) {
+        return ObjectUtil.isEmpty(deviceLog.getDeviceId());
+    }
 }

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

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pms.service.iotdevicerunlog;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicerunlog.IotDeviceRunLogMapper;
@@ -11,6 +12,8 @@ import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DEVICE_RUN_LOG_NOT_EXISTS;
 
@@ -68,4 +71,9 @@ public class IotDeviceRunLogServiceImpl implements IotDeviceRunLogService {
         return iotDeviceRunLogMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public List<IotDeviceRunLogRespVO> distinctDevices(List<Long> ids) {
+        return iotDeviceRunLogMapper.distinctDevices(ids);
+    }
+
 }

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

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainW
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 
 import javax.validation.Valid;
+import java.util.List;
 
 /**
  * 保养工单 Service 接口
@@ -52,4 +53,24 @@ public interface IotMainWorkOrderService {
      */
     PageResult<IotMainWorkOrderDO> getIotMainWorkOrderPage(IotMainWorkOrderPageReqVO pageReqVO);
 
+    /**
+     * 查询工单表中最大的id
+     *
+     * @return 最大的工单id
+     */
+    Long theMaxId();
+
+    /**
+     * 生成保养工单号
+     *
+     * @return 生成保养工单号
+     */
+    String createWorkOrderNumber();
+
+    /**
+     * 定时任务 批量新增 工单
+     *
+     * @return
+     */
+    void batchAddOrders(List<IotMainWorkOrderDO> workOrders);
 }

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

@@ -1,16 +1,20 @@
 package cn.iocoder.yudao.module.pms.service.iotmainworkorder;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotmainworkorder.IotMainWorkOrderMapper;
+import cn.iocoder.yudao.module.pms.dal.redis.BizNoRedisDAO;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_MAIN_WORK_ORDER_NOT_EXISTS;
 
@@ -25,6 +29,8 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
 
     @Resource
     private IotMainWorkOrderMapper iotMainWorkOrderMapper;
+    @Resource
+    private BizNoRedisDAO bizNoRedisDAO;
 
     @Override
     public Long createIotMainWorkOrder(IotMainWorkOrderSaveReqVO createReqVO) {
@@ -68,4 +74,20 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
         return iotMainWorkOrderMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public Long theMaxId() {
+        List<IotMainWorkOrderDO> workOrderDOS = iotMainWorkOrderMapper.theMaxOne();
+        return CollUtil.isNotEmpty(workOrderDOS) ? workOrderDOS.get(0).getId() : 0l;
+    }
+
+    @Override
+    public String createWorkOrderNumber() {
+        return bizNoRedisDAO.generate(BizNoRedisDAO.MAIN_WORK_ORDER_NO_PREFIX);
+    }
+
+    @Override
+    public void batchAddOrders(List<IotMainWorkOrderDO> workOrders) {
+        iotMainWorkOrderMapper.insertBatch(workOrders);
+    }
+
 }

+ 16 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/iotmainworkorderbom/IotMainWorkOrderBomService.java

@@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.pms.service.iotmainworkorderbom;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
 
 import javax.validation.Valid;
+import java.util.List;
 
 /**
  * PMS 保养计划明细BOM Service 接口
@@ -52,4 +54,18 @@ public interface IotMainWorkOrderBomService {
      */
     PageResult<IotMainWorkOrderBomDO> getIotMainWorkOrderBomPage(IotMainWorkOrderBomPageReqVO pageReqVO);
 
+    /**
+     * 保养计划明细BOM列表
+     *
+     * @param pageReqVO 分页查询
+     * @return PMS 保养计划明细BOM分页
+     */
+    List<IotMainWorkOrderBomDO> getIotMainWorkOrderBomList(IotMainWorkOrderBomPageReqVO pageReqVO);
+
+    /**
+     * 批量 新增保养工单 明细BOM
+     *
+     * @param
+     */
+    void batchAddOrderBOMs(List<IotMainWorkOrderBomDO> workOrderBOMs);
 }

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

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomSaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotmainworkorderbom.IotMainWorkOrderBomMapper;
 import cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant;
@@ -12,6 +13,8 @@ import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
 
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 
 /**
@@ -68,4 +71,14 @@ public class IotMainWorkOrderBomServiceImpl implements IotMainWorkOrderBomServic
         return iotMainWorkOrderBomMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public List<IotMainWorkOrderBomDO> getIotMainWorkOrderBomList(IotMainWorkOrderBomPageReqVO pageReqVO) {
+        return iotMainWorkOrderBomMapper.selectList(pageReqVO);
+    }
+
+    @Override
+    public void batchAddOrderBOMs(List<IotMainWorkOrderBomDO> workOrderBOMs) {
+        iotMainWorkOrderBomMapper.insertBatch(workOrderBOMs);
+    }
+
 }

+ 9 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/maintenance/IotMaintenancePlanService.java

@@ -1,12 +1,14 @@
 package cn.iocoder.yudao.module.pms.service.maintenance;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotTobeMaintenanceBomRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanSaveReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenanceSaveVO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
 
 import javax.validation.Valid;
+import java.util.List;
 
 /**
  * 保养计划 Service 接口
@@ -53,4 +55,11 @@ public interface IotMaintenancePlanService {
      */
     PageResult<IotMaintenancePlanDO> getIotMaintenancePlanPage(IotMaintenancePlanPageReqVO pageReqVO);
 
+    /**
+     * 获取待保养的设备-bom关联信息
+     *
+     * @return 设备bom-保养计划列表
+     */
+    List<IotTobeMaintenanceBomRespVO> toBeMaintenanceDeviceBOMs();
+
 }

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/maintenance/IotMaintenancePlanServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomSaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotTobeMaintenanceBomRespVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanPageReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenancePlanSaveReqVO;
 import cn.iocoder.yudao.module.pms.controller.admin.maintenance.vo.IotMaintenanceSaveVO;
@@ -106,4 +107,9 @@ public class IotMaintenancePlanServiceImpl implements IotMaintenancePlanService
         return iotMaintenancePlanMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public List<IotTobeMaintenanceBomRespVO> toBeMaintenanceDeviceBOMs() {
+        return iotMaintenancePlanMapper.toBeMaintenanceDeviceBOMs();
+    }
+
 }

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

@@ -51,55 +51,55 @@
             resultType="cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO">
         SELECT *
         FROM (
-        SELECT
-        t.id ,
-        t.device_code,
-        t.device_name,
-        t.asset_class,
-        t.brand,
-        t.model,
-        t.dept_id,
-        t.device_status,
-        t.asset_property,
-        t.pic_url,
-        t.remark,
-        t.create_time,
-        t1.id bomNodeId,
-        t1.`name`,
-        t1.`code`
-        FROM
-        rq_iot_device t
-        INNER JOIN rq_iot_bom t1 ON ( t1.device_category_id = t.asset_class AND t1.deleted = 0 )
-        WHERE
-        t.deleted = 0
-        AND t1.deleted = 0
-        AND t1.leaf_flag = 1
-        AND t1.type LIKE '%2%'
-        <if test="deviceIds != null and deviceIds.size &gt; 0">
-            AND t.id IN
-            <foreach collection="deviceIds" index="index" item="key" open="(" separator="," close=")">
-                #{key}
-            </foreach>
-        </if>
-        )t2
+            SELECT
+                t.id ,
+                t.device_code,
+                t.device_name,
+                t.asset_class,
+                t.brand,
+                t.model,
+                t.dept_id,
+                t.device_status,
+                t.asset_property,
+                t.pic_url,
+                t.remark,
+                t.create_time,
+                t1.id bomNodeId,
+                t1.`name`,
+                t1.`code`
+            FROM
+                rq_iot_device t
+            INNER JOIN rq_iot_bom t1 ON ( t1.device_category_id = t.asset_class AND t1.deleted = 0 )
+            WHERE
+                t.deleted = 0
+            AND t1.deleted = 0
+            AND t1.leaf_flag = 1
+            AND t1.type LIKE '%2%'
+            <if test="deviceIds != null and deviceIds.size &gt; 0">
+                AND t.id IN
+                <foreach collection="deviceIds" index="index" item="key" open="(" separator="," close=")">
+                    #{key}
+                </foreach>
+            </if>
+        ) t2
         LEFT JOIN (
-        SELECT
-        l.device_id,
-        l.total_run_time,
-        l.total_mileage,
-        l.time
-        FROM rq_iot_device_run_log l
-        RIGHT JOIN (
-        SELECT
-        device_id,
-        MAX(time) AS latest_time,
-        MAX(id)	AS max_id
-        FROM rq_iot_device_run_log
-        GROUP BY device_id
-        ) AS latest
-        ON l.device_id = latest.device_id
-        AND l.time = latest.latest_time
-        AND l.id = latest.max_id
+            SELECT
+            l.device_id,
+            l.total_run_time,
+            l.total_mileage,
+            l.time
+            FROM rq_iot_device_run_log l
+            RIGHT JOIN (
+                SELECT
+                    device_id,
+                    MAX(time) AS latest_time,
+                    MAX(id)	AS max_id
+                FROM rq_iot_device_run_log
+                GROUP BY device_id
+            ) AS latest
+            ON l.device_id = latest.device_id
+            AND l.time = latest.latest_time
+            AND l.id = latest.max_id
         ) tmp ON tmp.device_id = t2.id
     </select>
 </mapper>

+ 30 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotDeviceRunLogMapper.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.pms.dal.mysql.iotdevicerunlog.IotDeviceRunLogMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+    <select id="distinctDevices"
+            resultType="cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO">
+        SELECT
+            l.device_id,
+            l.total_run_time,
+            l.total_mileage,
+            l.time
+        FROM
+            rq_iot_device_run_log l
+            RIGHT JOIN ( SELECT device_id, MAX( time ) AS latest_time, MAX( id ) AS max_id FROM rq_iot_device_run_log GROUP BY device_id ) AS latest ON l.device_id = latest.device_id
+            AND l.id = latest.max_id
+        <if test="deviceIds != null and deviceIds.size &gt; 0">
+            AND latest.device_id IN
+            <foreach collection="deviceIds" index="index" item="key" open="(" separator="," close=")">
+                #{key}
+            </foreach>
+        </if>
+    </select>
+
+</mapper>

+ 101 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/resources/mapper/static/IotMaintenancePlanMapper.xml

@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.pms.dal.mysql.maintenance.IotMaintenancePlanMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+    <select id="toBeMaintenanceDeviceBOMs"
+            resultType="cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotTobeMaintenanceBomRespVO">
+        SELECT
+            plan.*,
+            b.total_mileage,
+            b.total_run_time,
+            CASE
+                WHEN plan.natural_date_rule = 0
+                    AND DATE_ADD(plan.last_natural_date, INTERVAL plan.next_natural_date DAY)
+                         > DATE_SUB(CURDATE(), INTERVAL plan.natural_date_period_lead DAY)
+                    THEN 1 ELSE 0
+                END AS need_maintain_by_date,
+            CASE
+                WHEN plan.mileage_rule = 0
+                    AND (b.total_mileage - plan.last_running_kilometers)
+                         >= (plan.next_running_kilometers - plan.kilo_cycle_lead)
+                    THEN 1 ELSE 0
+                END AS need_maintain_by_mileage,
+            CASE
+                WHEN plan.running_time_rule = 0
+                    AND (b.total_run_time - plan.last_running_time)
+                         >= (plan.next_running_time - plan.time_period_lead)
+                    THEN 1 ELSE 0
+                END AS need_maintain_by_time
+        FROM (
+                 -- 原始联合查询
+                 SELECT
+                     t.id,
+                     t.dept_id,
+                     t.serial_number,
+                     t.`name` planName,
+                     t.responsible_person,
+                     t1.device_category_id,
+                     t1.device_id,
+                     t1.mileage_rule,
+                     t1.natural_date_rule,
+                     t1.running_time_rule,
+                     t1.last_running_time,
+                     t1.next_running_time,
+                     t1.time_period_lead,
+                     t1.last_running_kilometers,
+                     t1.next_running_kilometers,
+                     t1.kilo_cycle_lead,
+                     t1.last_natural_date,
+                     t1.next_natural_date,
+                     t1.natural_date_period_lead,
+                     t1.bom_node_id,
+                     t1.`name` nodeName,
+                     t1.`code`
+                 FROM
+                     rq_iot_maintenance_plan t
+                         INNER JOIN rq_iot_maintenance_bom t1
+                                    ON t1.plan_id = t.id
+                                        AND t1.deleted = 0
+                 WHERE
+                     t.deleted = 0
+             ) AS plan
+-- 关联设备实时数据表
+                 LEFT JOIN (
+            SELECT
+                l.device_id,
+                l.total_run_time,
+                l.total_mileage,
+                l.time
+            FROM
+                rq_iot_device_run_log l
+                    RIGHT JOIN ( SELECT device_id, MAX( time ) AS latest_time, MAX( id ) AS max_id FROM rq_iot_device_run_log GROUP BY device_id ) AS latest ON l.device_id = latest.device_id
+                    AND l.id = latest.max_id
+        ) b ON plan.device_id = b.device_id
+        WHERE
+            (
+                -- 自然日期规则判断
+                (plan.natural_date_rule = 0
+                    AND DATE_ADD(plan.last_natural_date, INTERVAL plan.next_natural_date DAY)
+                     > DATE_SUB(CURDATE(), INTERVAL plan.natural_date_period_lead DAY))
+                    OR
+                    -- 里程规则判断
+                (plan.mileage_rule = 0
+                    AND (b.total_mileage - plan.last_running_kilometers)
+                     >= (plan.next_running_kilometers - plan.kilo_cycle_lead))
+                    OR
+                    -- 运行时间规则判断
+                (plan.running_time_rule = 0
+                    AND (b.total_run_time - plan.last_running_time)
+                     >= (plan.next_running_time - plan.time_period_lead))
+                )
+          -- 确保有实时数据
+          AND b.device_id IS NOT NULL;
+    </select>
+
+</mapper>