Browse Source

Merge branch 'master' of http://47.100.37.243:10191/quyueting/manHourHousekeeper

QuYueTing 2 days ago
parent
commit
b1ddbce1ff
80 changed files with 7102 additions and 179 deletions
  1. 28 10
      fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/controller/TaskController.java
  2. 270 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/AnnualMaintenancePlanController.java
  3. 103 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/EquipmentArchiveController.java
  4. 147 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/InspectionLibraryController.java
  5. 135 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceCycleConfigController.java
  6. 21 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceIssueController.java
  7. 173 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceLibraryController.java
  8. 116 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceOrderController.java
  9. 21 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceOrderDetailController.java
  10. 81 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MobileEquipmentController.java
  11. 124 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/AnnualMaintenancePlan.java
  12. 155 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentArchive.java
  13. 45 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentInspectionDetail.java
  14. 61 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentInspectionRecord.java
  15. 45 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentMaintenanceDetail.java
  16. 64 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentMaintenanceRecord.java
  17. 71 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentSparePart.java
  18. 58 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentTransferRecord.java
  19. 55 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/InspectionLibrary.java
  20. 61 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceCycleConfig.java
  21. 145 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceIssue.java
  22. 61 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceLibrary.java
  23. 140 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceOrder.java
  24. 69 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceOrderDetail.java
  25. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/AnnualMaintenancePlanMapper.java
  26. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentArchiveMapper.java
  27. 7 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentInspectionDetailMapper.java
  28. 7 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentInspectionRecordMapper.java
  29. 7 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentMaintenanceDetailMapper.java
  30. 7 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentMaintenanceRecordMapper.java
  31. 11 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentSparePartMapper.java
  32. 7 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentTransferRecordMapper.java
  33. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/InspectionLibraryMapper.java
  34. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceCycleConfigMapper.java
  35. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceIssueMapper.java
  36. 11 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceLibraryMapper.java
  37. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceOrderDetailMapper.java
  38. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceOrderMapper.java
  39. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/AnnualMaintenancePlanService.java
  40. 58 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/EquipmentArchiveService.java
  41. 18 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/EquipmentSparePartService.java
  42. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/InspectionLibraryService.java
  43. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceCycleConfigService.java
  44. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceIssueService.java
  45. 14 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceLibraryService.java
  46. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceOrderDetailService.java
  47. 16 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceOrderService.java
  48. 30 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MobileEquipmentService.java
  49. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/AnnualMaintenancePlanServiceImpl.java
  50. 519 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/EquipmentArchiveServiceImpl.java
  51. 67 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/EquipmentSparePartServiceImpl.java
  52. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/InspectionLibraryServiceImpl.java
  53. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceCycleConfigServiceImpl.java
  54. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceIssueServiceImpl.java
  55. 32 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceLibraryServiceImpl.java
  56. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceOrderDetailServiceImpl.java
  57. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceOrderServiceImpl.java
  58. 608 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MobileEquipmentServiceImpl.java
  59. 36 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/AnnualMaintenancePlanMapper.xml
  60. 35 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/EquipmentArchiveMapper.xml
  61. 19 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/InspectionLibraryMapper.xml
  62. 20 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceCycleConfigMapper.xml
  63. 34 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceIssueMapper.xml
  64. 21 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceOrderDetailMapper.xml
  65. 33 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceOrderMapper.xml
  66. 30 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/router/index.js
  67. 172 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/detail.vue
  68. 177 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/inspection.vue
  69. 187 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/list.vue
  70. 188 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/maintenance.vue
  71. 62 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/maintenanceRecords.vue
  72. 56 0
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/transferRecords.vue
  73. 8 1
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/index/index.vue
  74. 6 2
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/vue.config.js
  75. 20 0
      fhKeeper/formulahousekeeper/timesheet-workshop/src/routes.js
  76. 1058 0
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/archive.vue
  77. 217 0
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/inspection.vue
  78. 257 0
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/maintenance-library.vue
  79. 336 0
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/plan.vue
  80. 150 166
      fhKeeper/formulahousekeeper/timesheet_mld/src/components/taskComponent.vue

+ 28 - 10
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/controller/TaskController.java

@@ -255,24 +255,35 @@ public class TaskController {
             List<User> allUsers = userMapper.selectList(new QueryWrapper<User>().eq("company_id", user.getCompanyId()));
             List<TaskExecutor> executorList = JSONArray.parseArray(executorListStr, TaskExecutor.class);
             for (TaskExecutor taskExecutor : executorList) {
-                if (org.apache.commons.lang3.StringUtils.isNotEmpty(taskExecutor.getDailyAllocateListStr())){
+                if (StringUtils.isEmpty(taskExecutor.getExecutorId())) {
+                    msg.setError("执行人不能为空");
+                    return msg;
+                }
+                if (org.apache.commons.lang3.StringUtils.isNotEmpty(taskExecutor.getDailyAllocateListStr())) {
                     String dailyAllocateListStr = taskExecutor.getDailyAllocateListStr();
                     List<TaskDailyAllocate> taskDailyAllocates = JSONArray.parseArray(dailyAllocateListStr, TaskDailyAllocate.class);
+                    for (TaskDailyAllocate allocate : taskDailyAllocates) {
+                        if (StringUtils.isEmpty(allocate.getUserId())) {
+                            allocate.setUserId(taskExecutor.getExecutorId());
+                        }
+                    }
                     allocateArrayList.addAll(taskDailyAllocates);
                 }
             }
             task.setExecutorList(executorList);
-            executorList.stream().forEach(ex->{
-                //执行人必填
-                if (StringUtils.isEmpty(ex.getExecutorId())) {
-                    msg.setError("执行人不能为空");
-                    return;
+            for (TaskExecutor ex : executorList) {
+                Optional<User> exeUserOpt = allUsers.stream()
+                        .filter(al -> al.getId().equals(ex.getExecutorId()))
+                        .findFirst();
+                if (!exeUserOpt.isPresent()) {
+                    msg.setError("执行人不存在");
+                    return msg;
                 }
-                User exeUser = allUsers.stream().filter(al->al.getId().equals(ex.getExecutorId())).findFirst().get();
+                User exeUser = exeUserOpt.get();
                 ex.setExecutorName(exeUser.getName());
                 ex.setExecutorColor(exeUser.getColor());
                 //对于需要审核的任务,设置审核人
-                if (taskType.getNeedAudit()){
+                if (taskType.getNeedAudit()) {
                     ex.setFirstAuditorId(inchargerId);
                     //设置第二负责人,员工部门主要负责人
                     if (exeUser.getDepartmentId() != null && exeUser.getDepartmentId() > 0) {
@@ -281,12 +292,19 @@ public class TaskController {
                         if (!StringUtils.isEmpty(managerId)) {
                             ex.setSecondAuditorId(managerId);
                         } else {
-                            msg.setError("请设置["+byId.getDepartmentName()+"]部门主要负责人");
+                            msg.setError("请设置[" + byId.getDepartmentName() + "]部门主要负责人");
+                            return msg;
                         }
                     }
                 }
-            });
+            }
             if (!allocateArrayList.isEmpty()) {
+                for (TaskDailyAllocate allocate : allocateArrayList) {
+                    if (StringUtils.isEmpty(allocate.getUserId())) {
+                        msg.setError("执行人不能为空");
+                        return msg;
+                    }
+                }
                 Map<String, List<TaskDailyAllocate>> map = allocateArrayList.stream().collect(Collectors.groupingBy(TaskDailyAllocate::getUserId));
                 Set<Map.Entry<String, List<TaskDailyAllocate>>> entries = map.entrySet();
                 for (Map.Entry<String, List<TaskDailyAllocate>> entry : entries) {

+ 270 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/AnnualMaintenancePlanController.java

@@ -0,0 +1,270 @@
+package com.management.platform.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.management.platform.entity.AnnualMaintenancePlan;
+import com.management.platform.entity.EquipmentArchive;
+import com.management.platform.entity.MaintenanceCycleConfig;
+import com.management.platform.entity.MaintenanceOrder;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.EquipmentArchiveMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.AnnualMaintenancePlanService;
+import com.management.platform.service.MaintenanceCycleConfigService;
+import com.management.platform.service.MaintenanceOrderService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 年度维保计划表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@RestController
+@RequestMapping("/annual-maintenance-plan")
+public class AnnualMaintenancePlanController {
+
+    @Resource
+    private AnnualMaintenancePlanService annualMaintenancePlanService;
+
+    @Resource
+    private MaintenanceCycleConfigService cycleConfigService;
+
+    @Resource
+    private MaintenanceOrderService maintenanceOrderService;
+
+    @Resource
+    private EquipmentArchiveMapper equipmentArchiveMapper;
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private HttpServletRequest request;
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(Integer planYear, String equipmentCode, Integer equipmentNature,
+                            @RequestParam(defaultValue = "1") Integer pageIndex,
+                            @RequestParam(defaultValue = "20") Integer pageSize) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<AnnualMaintenancePlan> queryWrapper = new QueryWrapper<>();
+
+        if (planYear != null) {
+            queryWrapper.eq("plan_year", planYear);
+        }
+        if (StringUtils.isNotBlank(equipmentCode)) {
+            queryWrapper.like("equipment_code", equipmentCode);
+        }
+        if (equipmentNature != null) {
+            queryWrapper.eq("equipment_nature", equipmentNature);
+        }
+        queryWrapper.orderByAsc("equipment_code");
+
+        IPage<AnnualMaintenancePlan> pageResult = annualMaintenancePlanService.page(
+                new Page<>(pageIndex, pageSize), queryWrapper);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("data", pageResult.getRecords());
+        result.put("total", pageResult.getTotal());
+        msg.data = result;
+        return msg;
+    }
+
+    @RequestMapping("/generate")
+    public HttpRespMsg generate(@RequestParam Integer planYear) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+            return msg;
+        }
+        if (planYear == null) {
+            msg.setError("计划年份不能为空");
+            return msg;
+        }
+
+        List<MaintenanceCycleConfig> configs = cycleConfigService.list(
+                new QueryWrapper<MaintenanceCycleConfig>().orderByAsc("equipment_nature"));
+        if (configs.isEmpty()) {
+            msg.setError("请先配置维保周期");
+            return msg;
+        }
+        Map<Integer, MaintenanceCycleConfig> configMap = new HashMap<>();
+        for (MaintenanceCycleConfig config : configs) {
+            configMap.put(config.getEquipmentNature(), config);
+        }
+
+        List<EquipmentArchive> equipmentList = equipmentArchiveMapper.selectList(
+                new QueryWrapper<EquipmentArchive>()
+                        .eq("is_deleted", 0)
+                        .eq("equipment_status", 1));
+        if (equipmentList.isEmpty()) {
+            msg.setError("暂无正常状态的设备");
+            return msg;
+        }
+
+        // 删除该年度已有的草稿计划
+        annualMaintenancePlanService.remove(new QueryWrapper<AnnualMaintenancePlan>()
+                .eq("plan_year", planYear)
+                .eq("plan_status", 0));
+
+        List<AnnualMaintenancePlan> planList = new ArrayList<>();
+        for (EquipmentArchive equipment : equipmentList) {
+            MaintenanceCycleConfig config = configMap.get(equipment.getEquipmentNature());
+            if (config == null) {
+                continue;
+            }
+
+            AnnualMaintenancePlan plan = new AnnualMaintenancePlan();
+            plan.setPlanYear(planYear);
+            plan.setEquipmentId(equipment.getId());
+            plan.setEquipmentCode(equipment.getEquipmentCode());
+            plan.setEquipmentName(equipment.getEquipmentName());
+            plan.setEquipmentNature(equipment.getEquipmentNature());
+            plan.setWorkPosition(equipment.getWorkPosition());
+            plan.setPlanStatus(0);
+            plan.setCreatedTime(LocalDateTime.now());
+            plan.setUpdatedTime(LocalDateTime.now());
+
+            int l1Cycle = config.getLevel1CycleMonths() != null ? config.getLevel1CycleMonths() : 1;
+            int l2Cycle = config.getLevel2CycleMonths() != null ? config.getLevel2CycleMonths() : 6;
+
+            for (int month = 1; month <= 12; month++) {
+                Integer level = null;
+                if (l2Cycle > 0 && month % l2Cycle == 0) {
+                    level = 2;
+                } else if (l1Cycle > 0 && month % l1Cycle == 0) {
+                    level = 1;
+                }
+                setMonthLevel(plan, month, level);
+            }
+
+            planList.add(plan);
+        }
+
+        annualMaintenancePlanService.saveBatch(planList);
+        msg.data = "已为 " + planList.size() + " 台设备生成 " + planYear + " 年度保养计划";
+        return msg;
+    }
+
+    @RequestMapping("/publish")
+    public HttpRespMsg publish(@RequestParam Integer planYear) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+            return msg;
+        }
+        if (planYear == null) {
+            msg.setError("计划年份不能为空");
+            return msg;
+        }
+
+        List<AnnualMaintenancePlan> draftPlans = annualMaintenancePlanService.list(
+                new QueryWrapper<AnnualMaintenancePlan>()
+                        .eq("plan_year", planYear)
+                        .eq("plan_status", 0));
+        if (draftPlans.isEmpty()) {
+            msg.setError("当前年度没有草稿状态的计划可发布");
+            return msg;
+        }
+
+        List<MaintenanceOrder> orderList = new ArrayList<>();
+        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMM");
+        String yearMonthPrefix = String.valueOf(planYear);
+
+        for (AnnualMaintenancePlan plan : draftPlans) {
+            plan.setPlanStatus(1);
+            plan.setUpdatedTime(LocalDateTime.now());
+
+            for (int month = 1; month <= 12; month++) {
+                Integer level = getMonthLevel(plan, month);
+                if (level == null) {
+                    continue;
+                }
+
+                LocalDate plannedDate = LocalDate.of(planYear, month, 15);
+                String monthStr = month < 10 ? "0" + month : String.valueOf(month);
+                String orderNo = "WB" + planYear + monthStr + plan.getEquipmentCode()
+                        + String.format("%03d", month);
+
+                MaintenanceOrder order = new MaintenanceOrder();
+                order.setOrderNo(orderNo);
+                order.setPlanId(plan.getId());
+                order.setEquipmentId(plan.getEquipmentId());
+                order.setEquipmentCode(plan.getEquipmentCode());
+                order.setEquipmentName(plan.getEquipmentName());
+                order.setWorkPosition(plan.getWorkPosition());
+                order.setMaintenanceLevel(level);
+                order.setPlannedDate(plannedDate);
+                order.setOrderStatus(0);
+                order.setCreatedTime(LocalDateTime.now());
+                order.setUpdatedTime(LocalDateTime.now());
+                orderList.add(order);
+            }
+        }
+
+        annualMaintenancePlanService.updateBatchById(draftPlans);
+        if (!orderList.isEmpty()) {
+            maintenanceOrderService.saveBatch(orderList);
+        }
+
+        msg.data = "已发布 " + draftPlans.size() + " 条保养计划,共生成 " + orderList.size() + " 条维保单";
+        return msg;
+    }
+
+    private void setMonthLevel(AnnualMaintenancePlan plan, int month, Integer level) {
+        switch (month) {
+            case 1: plan.setMonth1Level(level); break;
+            case 2: plan.setMonth2Level(level); break;
+            case 3: plan.setMonth3Level(level); break;
+            case 4: plan.setMonth4Level(level); break;
+            case 5: plan.setMonth5Level(level); break;
+            case 6: plan.setMonth6Level(level); break;
+            case 7: plan.setMonth7Level(level); break;
+            case 8: plan.setMonth8Level(level); break;
+            case 9: plan.setMonth9Level(level); break;
+            case 10: plan.setMonth10Level(level); break;
+            case 11: plan.setMonth11Level(level); break;
+            case 12: plan.setMonth12Level(level); break;
+            default: break;
+        }
+    }
+
+    private Integer getMonthLevel(AnnualMaintenancePlan plan, int month) {
+        switch (month) {
+            case 1: return plan.getMonth1Level();
+            case 2: return plan.getMonth2Level();
+            case 3: return plan.getMonth3Level();
+            case 4: return plan.getMonth4Level();
+            case 5: return plan.getMonth5Level();
+            case 6: return plan.getMonth6Level();
+            case 7: return plan.getMonth7Level();
+            case 8: return plan.getMonth8Level();
+            case 9: return plan.getMonth9Level();
+            case 10: return plan.getMonth10Level();
+            case 11: return plan.getMonth11Level();
+            case 12: return plan.getMonth12Level();
+            default: return null;
+        }
+    }
+}

+ 103 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/EquipmentArchiveController.java

@@ -0,0 +1,103 @@
+package com.management.platform.controller;
+
+import com.google.zxing.WriterException;
+import com.management.platform.entity.EquipmentArchive;
+import com.management.platform.service.EquipmentArchiveService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * <p>
+ * 设备档案表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@RestController
+@RequestMapping("/equipment-archive")
+public class EquipmentArchiveController {
+
+    @Resource
+    private EquipmentArchiveService equipmentArchiveService;
+
+    @Resource
+    private HttpServletRequest request;
+
+    /**
+     * 分页获取设备档案列表
+     * equipmentCode  设备编号
+     * equipmentName  设备名称
+     * responsibleUserId  责任人工号
+     * equipmentStatus  设备状态 1正常 2封存
+     * pageIndex  页码
+     * pageSize  每页数量
+     */
+    @RequestMapping("/getEquipmentList")
+    public HttpRespMsg getEquipmentList(String equipmentCode, String equipmentName,
+                                        Integer responsibleUserId, Integer equipmentStatus,
+                                        @RequestParam(defaultValue = "1") Integer pageIndex,
+                                        @RequestParam(defaultValue = "10") Integer pageSize) {
+        return equipmentArchiveService.getEquipmentList(equipmentCode, equipmentName,
+                responsibleUserId, equipmentStatus, pageIndex, pageSize, request);
+    }
+
+    /**
+     * 新增设备
+     */
+    @RequestMapping("/insertEquipment")
+    public HttpRespMsg insertEquipment(EquipmentArchive equipment, String sparePartListJson) throws IOException, WriterException {
+        return equipmentArchiveService.insertEquipment(equipment, sparePartListJson, request);
+    }
+
+    /**
+     * 编辑设备
+     */
+    @RequestMapping("/updateEquipment")
+    public HttpRespMsg updateEquipment(EquipmentArchive equipment, String sparePartListJson) throws IOException, WriterException {
+        return equipmentArchiveService.updateEquipment(equipment, sparePartListJson, request);
+    }
+
+    /**
+     * 删除设备
+     * id  设备ID
+     */
+    @RequestMapping("/deleteEquipment")
+    public HttpRespMsg deleteEquipment(@RequestParam Integer id) {
+        return equipmentArchiveService.deleteEquipment(id, request);
+    }
+
+    /**
+     * 封存/取消封存设备
+     * id      设备ID
+     * status  1-正常(取消封存)  2-封存
+     */
+    @RequestMapping("/sealEquipment")
+    public HttpRespMsg sealEquipment(@RequestParam Integer id, @RequestParam Integer status) {
+        return equipmentArchiveService.sealEquipment(id, status, request);
+    }
+
+    /**
+     * 获取设备详情
+     * id  设备ID
+     */
+    @RequestMapping("/getEquipmentDetail")
+    public HttpRespMsg getEquipmentDetail(@RequestParam Integer id) {
+        return equipmentArchiveService.getEquipmentDetail(id);
+    }
+
+    /**
+     * 生成设备二维码
+     * id  设备ID
+     */
+    @RequestMapping("/generateQrCode")
+    public HttpRespMsg generateQrCode(@RequestParam Integer id) {
+        return equipmentArchiveService.generateQrCode(id);
+    }
+}

+ 147 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/InspectionLibraryController.java

@@ -0,0 +1,147 @@
+package com.management.platform.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.management.platform.entity.InspectionLibrary;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.InspectionLibraryService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 点检库表 前端控制器
+ */
+@RestController
+@RequestMapping("/inspection-library")
+public class InspectionLibraryController {
+
+    @Resource
+    private InspectionLibraryService inspectionLibraryService;
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private HttpServletRequest request;
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(String keyword,
+                            @RequestParam(defaultValue = "1") Integer pageIndex,
+                            @RequestParam(defaultValue = "20") Integer pageSize) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<InspectionLibrary> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("is_enabled", 1);
+        if (StringUtils.isNotBlank(keyword)) {
+            queryWrapper.and(wrapper -> wrapper
+                    .like("inspection_name", keyword)
+                    .or()
+                    .like("inspection_detail", keyword));
+        }
+        queryWrapper.orderByAsc("sort_order", "id");
+
+        IPage<InspectionLibrary> pageResult = inspectionLibraryService.page(
+                new Page<>(pageIndex, pageSize), queryWrapper);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("data", pageResult.getRecords());
+        result.put("total", pageResult.getTotal());
+        msg.data = result;
+        return msg;
+    }
+
+    @RequestMapping("/insert")
+    public HttpRespMsg insert(InspectionLibrary inspection) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (!checkLogin(msg)) {
+            return msg;
+        }
+        if (!validateInspection(inspection, msg)) {
+            return msg;
+        }
+        if (inspection.getIsEnabled() == null) {
+            inspection.setIsEnabled(1);
+        }
+        if (inspection.getSortOrder() == null) {
+            inspection.setSortOrder(0);
+        }
+        inspection.setCreatedTime(LocalDateTime.now());
+        inspection.setUpdatedTime(LocalDateTime.now());
+        inspectionLibraryService.save(inspection);
+        msg.data = inspection;
+        return msg;
+    }
+
+    @RequestMapping("/update")
+    public HttpRespMsg update(InspectionLibrary inspection) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (!checkLogin(msg)) {
+            return msg;
+        }
+        if (inspection.getId() == null) {
+            msg.setError("点检项ID不能为空");
+            return msg;
+        }
+        InspectionLibrary exist = inspectionLibraryService.getById(inspection.getId());
+        if (exist == null) {
+            msg.setError("点检项不存在");
+            return msg;
+        }
+        if (!validateInspection(inspection, msg)) {
+            return msg;
+        }
+        inspection.setUpdatedTime(LocalDateTime.now());
+        inspectionLibraryService.updateById(inspection);
+        return msg;
+    }
+
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(@RequestParam Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (!checkLogin(msg)) {
+            return msg;
+        }
+        InspectionLibrary inspection = inspectionLibraryService.getById(id);
+        if (inspection == null) {
+            msg.setError("点检项不存在");
+            return msg;
+        }
+        inspectionLibraryService.removeById(id);
+        return msg;
+    }
+
+    private boolean checkLogin(HttpRespMsg msg) {
+        String token = request.getHeader("Token");
+        if (StringUtils.isBlank(token)) {
+            token = request.getHeader("TOKEN");
+        }
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean validateInspection(InspectionLibrary inspection, HttpRespMsg msg) {
+        if (StringUtils.isBlank(inspection.getInspectionName())) {
+            msg.setError("点检项名称不能为空");
+            return false;
+        }
+        if (StringUtils.isBlank(inspection.getInspectionDetail())) {
+            msg.setError("点检明细不能为空");
+            return false;
+        }
+        return true;
+    }
+}

+ 135 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceCycleConfigController.java

@@ -0,0 +1,135 @@
+package com.management.platform.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.MaintenanceCycleConfig;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.MaintenanceCycleConfigService;
+import com.management.platform.util.HttpRespMsg;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 维保周期配置表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@RestController
+@RequestMapping("/maintenance-cycle-config")
+public class MaintenanceCycleConfigController {
+
+    @Resource
+    private MaintenanceCycleConfigService cycleConfigService;
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private HttpServletRequest request;
+
+    @RequestMapping("/list")
+    public HttpRespMsg list() {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<MaintenanceCycleConfig> queryWrapper = new QueryWrapper<>();
+        queryWrapper.orderByAsc("equipment_nature");
+        List<MaintenanceCycleConfig> list = cycleConfigService.list(queryWrapper);
+        msg.data = list;
+        return msg;
+    }
+
+    @RequestMapping("/save")
+    public HttpRespMsg save(@RequestBody String jsonBody) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+            return msg;
+        }
+
+        try {
+            Gson gson = new Gson();
+            Map<String, Object> bodyMap = gson.fromJson(jsonBody, new TypeToken<Map<String, Object>>() {}.getType());
+            List<Map<String, Object>> configList = (List<Map<String, Object>>) bodyMap.get("list");
+
+            if (configList == null || configList.isEmpty()) {
+                msg.setError("配置数据不能为空");
+                return msg;
+            }
+
+            for (Map<String, Object> configMap : configList) {
+                Integer equipmentNature = getIntegerValue(configMap.get("equipmentNature"));
+                Integer level1CycleMonths = getIntegerValue(configMap.get("level1CycleMonths"));
+                Integer level2CycleMonths = getIntegerValue(configMap.get("level2CycleMonths"));
+                Object idObj = configMap.get("id");
+
+                if (equipmentNature == null || level1CycleMonths == null || level2CycleMonths == null) {
+                    continue;
+                }
+
+                MaintenanceCycleConfig config;
+                if (idObj != null) {
+                    Integer id = getIntegerValue(idObj);
+                    config = cycleConfigService.getById(id);
+                    if (config == null) {
+                        config = new MaintenanceCycleConfig();
+                        config.setCreatedTime(LocalDateTime.now());
+                    }
+                    config.setId(id);
+                } else {
+                    QueryWrapper<MaintenanceCycleConfig> queryWrapper = new QueryWrapper<>();
+                    queryWrapper.eq("equipment_nature", equipmentNature);
+                    config = cycleConfigService.getOne(queryWrapper);
+                    if (config == null) {
+                        config = new MaintenanceCycleConfig();
+                        config.setCreatedTime(LocalDateTime.now());
+                    }
+                }
+
+                config.setEquipmentNature(equipmentNature);
+                config.setLevel1CycleMonths(level1CycleMonths);
+                config.setLevel2CycleMonths(level2CycleMonths);
+                config.setUpdatedTime(LocalDateTime.now());
+                cycleConfigService.saveOrUpdate(config);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError("保存失败:" + e.getMessage());
+            return msg;
+        }
+
+        return msg;
+    }
+
+    private Integer getIntegerValue(Object obj) {
+        if (obj == null) {
+            return null;
+        }
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        }
+        if (obj instanceof Double) {
+            return ((Double) obj).intValue();
+        }
+        if (obj instanceof String) {
+            try {
+                return Integer.parseInt((String) obj);
+            } catch (NumberFormatException e) {
+                return null;
+            }
+        }
+        return null;
+    }
+}

+ 21 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceIssueController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 维保异常工单表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@RestController
+@RequestMapping("/maintenance-issue")
+public class MaintenanceIssueController {
+
+}
+

+ 173 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceLibraryController.java

@@ -0,0 +1,173 @@
+package com.management.platform.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.management.platform.entity.MaintenanceLibrary;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.MaintenanceLibraryService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 保养库表 前端控制器
+ */
+@RestController
+@RequestMapping("/maintenance-library")
+public class MaintenanceLibraryController {
+
+    @Resource
+    private MaintenanceLibraryService maintenanceLibraryService;
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private HttpServletRequest request;
+
+    /**
+     * 分页列表
+     */
+    @RequestMapping("/list")
+    public HttpRespMsg list(Integer maintenanceLevel, String maintenancePart,
+                            @RequestParam(defaultValue = "1") Integer pageIndex,
+                            @RequestParam(defaultValue = "20") Integer pageSize) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<MaintenanceLibrary> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("is_enabled", 1);
+        if (maintenanceLevel != null) {
+            queryWrapper.eq("maintenance_level", maintenanceLevel);
+        }
+        if (StringUtils.isNotBlank(maintenancePart)) {
+            queryWrapper.eq("maintenance_part", maintenancePart);
+        }
+        queryWrapper.orderByAsc("maintenance_level", "sort_order", "id");
+
+        IPage<MaintenanceLibrary> pageResult = maintenanceLibraryService.page(
+                new Page<>(pageIndex, pageSize), queryWrapper);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("data", pageResult.getRecords());
+        result.put("total", pageResult.getTotal());
+        msg.data = result;
+        return msg;
+    }
+
+    /**
+     * 保养部位下拉选项
+     */
+    @RequestMapping("/listParts")
+    public HttpRespMsg listParts() {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = maintenanceLibraryService.listMaintenanceParts();
+        return msg;
+    }
+
+    /**
+     * 新增
+     */
+    @RequestMapping("/insert")
+    public HttpRespMsg insert(MaintenanceLibrary library) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (!checkLogin(msg)) {
+            return msg;
+        }
+        if (!validateLibrary(library, msg)) {
+            return msg;
+        }
+        if (library.getIsEnabled() == null) {
+            library.setIsEnabled(1);
+        }
+        if (library.getSortOrder() == null) {
+            library.setSortOrder(0);
+        }
+        library.setCreatedTime(LocalDateTime.now());
+        library.setUpdatedTime(LocalDateTime.now());
+        maintenanceLibraryService.save(library);
+        msg.data = library;
+        return msg;
+    }
+
+    /**
+     * 编辑
+     */
+    @RequestMapping("/update")
+    public HttpRespMsg update(MaintenanceLibrary library) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (!checkLogin(msg)) {
+            return msg;
+        }
+        if (library.getId() == null) {
+            msg.setError("保养库ID不能为空");
+            return msg;
+        }
+        MaintenanceLibrary exist = maintenanceLibraryService.getById(library.getId());
+        if (exist == null) {
+            msg.setError("保养数据不存在");
+            return msg;
+        }
+        if (!validateLibrary(library, msg)) {
+            return msg;
+        }
+        library.setUpdatedTime(LocalDateTime.now());
+        maintenanceLibraryService.updateById(library);
+        return msg;
+    }
+
+    /**
+     * 删除
+     */
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(@RequestParam Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (!checkLogin(msg)) {
+            return msg;
+        }
+        MaintenanceLibrary library = maintenanceLibraryService.getById(id);
+        if (library == null) {
+            msg.setError("保养数据不存在");
+            return msg;
+        }
+        maintenanceLibraryService.removeById(id);
+        return msg;
+    }
+
+    private boolean checkLogin(HttpRespMsg msg) {
+        String token = request.getHeader("Token");
+        if (StringUtils.isBlank(token)) {
+            token = request.getHeader("TOKEN");
+        }
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean validateLibrary(MaintenanceLibrary library, HttpRespMsg msg) {
+        if (library.getMaintenanceLevel() == null) {
+            msg.setError("保养级别不能为空");
+            return false;
+        }
+        if (StringUtils.isBlank(library.getMaintenancePart())) {
+            msg.setError("保养部位不能为空");
+            return false;
+        }
+        if (StringUtils.isBlank(library.getMaintenanceContent())) {
+            msg.setError("保养内容不能为空");
+            return false;
+        }
+        return true;
+    }
+}

+ 116 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceOrderController.java

@@ -0,0 +1,116 @@
+package com.management.platform.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.MaintenanceOrder;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.MaintenanceOrderService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * <p>
+ * 维保单表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@RestController
+@RequestMapping("/maintenance-order")
+public class MaintenanceOrderController {
+
+    @Resource
+    private MaintenanceOrderService maintenanceOrderService;
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private HttpServletRequest request;
+
+    @RequestMapping("/listByPlan")
+    public HttpRespMsg listByPlan(@RequestParam Integer planId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<MaintenanceOrder> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("plan_id", planId);
+        queryWrapper.orderByAsc("planned_date");
+        List<MaintenanceOrder> list = maintenanceOrderService.list(queryWrapper);
+        msg.data = list;
+        return msg;
+    }
+
+    /**
+     * 按设备获取维保记录
+     */
+    @RequestMapping("/listByEquipment")
+    public HttpRespMsg listByEquipment(@RequestParam Integer equipmentId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (equipmentId == null) {
+            msg.setError("设备ID不能为空");
+            return msg;
+        }
+        QueryWrapper<MaintenanceOrder> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("equipment_id", equipmentId);
+        queryWrapper.orderByDesc("planned_date").orderByDesc("id");
+        List<MaintenanceOrder> list = maintenanceOrderService.list(queryWrapper);
+        msg.data = list;
+        return msg;
+    }
+
+    @RequestMapping("/adjust")
+    public HttpRespMsg adjust(Integer id, String plannedDate,
+                              String maintenanceUserName, String operatorUserName) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+            return msg;
+        }
+
+        if (id == null) {
+            msg.setError("维保单ID不能为空");
+            return msg;
+        }
+
+        MaintenanceOrder order = maintenanceOrderService.getById(id);
+        if (order == null) {
+            msg.setError("维保单不存在");
+            return msg;
+        }
+
+        if (order.getOrderStatus() != 0) {
+            msg.setError("只能调整待执行状态的维保单");
+            return msg;
+        }
+
+        if (StringUtils.isNotBlank(plannedDate)) {
+            try {
+                order.setPlannedDate(LocalDate.parse(plannedDate));
+            } catch (Exception e) {
+                msg.setError("日期格式错误");
+                return msg;
+            }
+        }
+        if (StringUtils.isNotBlank(maintenanceUserName)) {
+            order.setMaintenanceUserName(maintenanceUserName);
+        }
+        if (StringUtils.isNotBlank(operatorUserName)) {
+            order.setOperatorUserName(operatorUserName);
+        }
+
+        order.setUpdatedTime(LocalDateTime.now());
+        maintenanceOrderService.updateById(order);
+        return msg;
+    }
+}

+ 21 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MaintenanceOrderDetailController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 维保单点检明细表 前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@RestController
+@RequestMapping("/maintenance-order-detail")
+public class MaintenanceOrderDetailController {
+
+}
+

+ 81 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/MobileEquipmentController.java

@@ -0,0 +1,81 @@
+package com.management.platform.controller;
+
+import com.management.platform.service.MobileEquipmentService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+@RequestMapping("/mobile-equipment")
+public class MobileEquipmentController {
+
+    @Resource
+    private MobileEquipmentService mobileEquipmentService;
+
+    @RequestMapping("/recentHistory")
+    public HttpRespMsg recentHistory(@RequestParam(defaultValue = "1") Integer pageIndex,
+                                     @RequestParam(defaultValue = "20") Integer pageSize,
+                                     HttpServletRequest request) {
+        return mobileEquipmentService.getRecentHistory(request, pageIndex, pageSize);
+    }
+
+    @RequestMapping("/getByCode")
+    public HttpRespMsg getByCode(@RequestParam String equipmentCode, HttpServletRequest request) {
+        return mobileEquipmentService.getEquipmentByCode(equipmentCode, request);
+    }
+
+    @RequestMapping("/detail")
+    public HttpRespMsg detail(@RequestParam Integer equipmentId, HttpServletRequest request) {
+        return mobileEquipmentService.getMobileDetail(equipmentId, request);
+    }
+
+    @RequestMapping("/inspectionForm")
+    public HttpRespMsg inspectionForm(@RequestParam Integer equipmentId, HttpServletRequest request) {
+        return mobileEquipmentService.getInspectionForm(equipmentId, request);
+    }
+
+    @RequestMapping("/submitInspection")
+    public HttpRespMsg submitInspection(@RequestParam Integer equipmentId,
+                                        @RequestParam String detailListJson,
+                                        @RequestParam String photoUrl,
+                                        HttpServletRequest request) {
+        return mobileEquipmentService.submitInspection(equipmentId, detailListJson, photoUrl, request);
+    }
+
+    @RequestMapping("/maintenanceForm")
+    public HttpRespMsg maintenanceForm(@RequestParam Integer equipmentId,
+                                       @RequestParam(defaultValue = "1") Integer maintenanceLevel,
+                                       HttpServletRequest request) {
+        return mobileEquipmentService.getMaintenanceForm(equipmentId, maintenanceLevel, request);
+    }
+
+    @RequestMapping("/submitMaintenance")
+    public HttpRespMsg submitMaintenance(@RequestParam Integer equipmentId,
+                                         @RequestParam(defaultValue = "1") Integer maintenanceLevel,
+                                         @RequestParam(defaultValue = "1") Integer inspectionResult,
+                                         @RequestParam(defaultValue = "1") Integer operatorEvaluation,
+                                         @RequestParam String detailListJson,
+                                         HttpServletRequest request) {
+        return mobileEquipmentService.submitMaintenance(equipmentId, maintenanceLevel, inspectionResult,
+                operatorEvaluation, detailListJson, request);
+    }
+
+    @RequestMapping("/maintenanceRecords")
+    public HttpRespMsg maintenanceRecords(@RequestParam Integer equipmentId) {
+        return mobileEquipmentService.listMaintenanceRecords(equipmentId);
+    }
+
+    @RequestMapping("/transferRecords")
+    public HttpRespMsg transferRecords(@RequestParam Integer equipmentId, HttpServletRequest request) {
+        return mobileEquipmentService.listTransferRecords(equipmentId, request);
+    }
+
+    @RequestMapping("/syncTransfer")
+    public HttpRespMsg syncTransfer(@RequestParam Integer equipmentId, HttpServletRequest request) {
+        return mobileEquipmentService.syncTransferRecords(equipmentId, request);
+    }
+}

+ 124 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/AnnualMaintenancePlan.java

@@ -0,0 +1,124 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 年度维保计划表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class AnnualMaintenancePlan extends Model<AnnualMaintenancePlan> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 计划年份
+     */
+    @TableField("plan_year")
+    private Integer planYear;
+
+    /**
+     * 设备ID
+     */
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    /**
+     * 设备编号(冗余)
+     */
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    /**
+     * 设备名称(冗余)
+     */
+    @TableField("equipment_name")
+    private String equipmentName;
+
+    /**
+     * 设备性质(冗余)
+     */
+    @TableField("equipment_nature")
+    private Integer equipmentNature;
+
+    /**
+     * 工位(冗余)
+     */
+    @TableField("work_position")
+    private String workPosition;
+
+    /**
+     * 1月保养等级 1一级 2二级 NULL无
+     */
+    @TableField("month_1_level")
+    private Integer month1Level;
+
+    @TableField("month_2_level")
+    private Integer month2Level;
+
+    @TableField("month_3_level")
+    private Integer month3Level;
+
+    @TableField("month_4_level")
+    private Integer month4Level;
+
+    @TableField("month_5_level")
+    private Integer month5Level;
+
+    @TableField("month_6_level")
+    private Integer month6Level;
+
+    @TableField("month_7_level")
+    private Integer month7Level;
+
+    @TableField("month_8_level")
+    private Integer month8Level;
+
+    @TableField("month_9_level")
+    private Integer month9Level;
+
+    @TableField("month_10_level")
+    private Integer month10Level;
+
+    @TableField("month_11_level")
+    private Integer month11Level;
+
+    @TableField("month_12_level")
+    private Integer month12Level;
+
+    /**
+     * 计划状态 0草稿 1已发布 2已取消
+     */
+    @TableField("plan_status")
+    private Integer planStatus;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 155 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentArchive.java

@@ -0,0 +1,155 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 设备档案表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentArchive extends Model<EquipmentArchive> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 设备编号
+     */
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    /**
+     * 设备名称
+     */
+    @TableField("equipment_name")
+    private String equipmentName;
+
+    /**
+     * 规格型号
+     */
+    @TableField("equipment_model")
+    private String equipmentModel;
+
+    /**
+     * 出厂编号
+     */
+    @TableField("factory_number")
+    private String factoryNumber;
+
+    /**
+     * 设备性质 1关键设备 2主要设备 3其他设备
+     */
+    @TableField("equipment_nature")
+    private Integer equipmentNature;
+
+    /**
+     * 工位
+     */
+    @TableField("work_position")
+    private String workPosition;
+
+    /**
+     * 工位部门ID
+     */
+    @TableField("department_id")
+    private Integer departmentId;
+
+    /**
+     * 责任人姓名
+     */
+    @TableField("responsible_person")
+    private String responsiblePerson;
+
+    /**
+     * 责任人工号
+     */
+    @TableField("responsible_user_id")
+    private Integer responsibleUserId;
+
+    /**
+     * 设备状态 1正常 2封存 3报废
+     */
+    @TableField("equipment_status")
+    private Integer equipmentStatus;
+
+    /**
+     * 首次运行/保养日期
+     */
+    @TableField("first_run_date")
+    private LocalDate firstRunDate;
+
+    /**
+     * 设备照片JSON数组
+     */
+    @TableField("equipment_photos")
+    private String equipmentPhotos;
+
+    /**
+     * 二维码图片地址
+     */
+    @TableField("qr_code_url")
+    private String qrCodeUrl;
+
+    /**
+     * 二维码数据内容
+     */
+    @TableField("qr_code_data")
+    private String qrCodeData;
+
+    /**
+     * 合同文件JSON数组
+     */
+    @TableField("contract_files")
+    private String contractFiles;
+
+    /**
+     * 发票文件JSON数组
+     */
+    @TableField("invoice_files")
+    private String invoiceFiles;
+
+    /**
+     * 备注
+     */
+    @TableField("remark")
+    private String remark;
+
+    @TableField("created_by")
+    private String createdBy;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_by")
+    private String updatedBy;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+    @TableField("is_deleted")
+    private Integer isDeleted;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 45 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentInspectionDetail.java

@@ -0,0 +1,45 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentInspectionDetail extends Model<EquipmentInspectionDetail> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("record_id")
+    private Integer recordId;
+
+    @TableField("library_id")
+    private Integer libraryId;
+
+    @TableField("inspection_name")
+    private String inspectionName;
+
+    @TableField("inspection_detail")
+    private String inspectionDetail;
+
+    @TableField("check_result")
+    private Integer checkResult;
+
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 61 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentInspectionRecord.java

@@ -0,0 +1,61 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentInspectionRecord extends Model<EquipmentInspectionRecord> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    @TableField("equipment_name")
+    private String equipmentName;
+
+    @TableField("inspector_user_id")
+    private String inspectorUserId;
+
+    @TableField("inspector_name")
+    private String inspectorName;
+
+    @TableField("inspector_role")
+    private String inspectorRole;
+
+    @TableField("inspection_type")
+    private Integer inspectionType;
+
+    @TableField("overall_result")
+    private Integer overallResult;
+
+    @TableField("photo_url")
+    private String photoUrl;
+
+    @TableField("company_id")
+    private Integer companyId;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 45 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentMaintenanceDetail.java

@@ -0,0 +1,45 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentMaintenanceDetail extends Model<EquipmentMaintenanceDetail> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("record_id")
+    private Integer recordId;
+
+    @TableField("library_id")
+    private Integer libraryId;
+
+    @TableField("maintenance_part")
+    private String maintenancePart;
+
+    @TableField("maintenance_content")
+    private String maintenanceContent;
+
+    @TableField("is_checked")
+    private Integer isChecked;
+
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 64 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentMaintenanceRecord.java

@@ -0,0 +1,64 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentMaintenanceRecord extends Model<EquipmentMaintenanceRecord> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    @TableField("equipment_name")
+    private String equipmentName;
+
+    @TableField("maintenance_level")
+    private Integer maintenanceLevel;
+
+    @TableField("maintenance_user_id")
+    private String maintenanceUserId;
+
+    @TableField("maintenance_user_name")
+    private String maintenanceUserName;
+
+    @TableField("operator_user_id")
+    private String operatorUserId;
+
+    @TableField("operator_user_name")
+    private String operatorUserName;
+
+    @TableField("inspection_result")
+    private Integer inspectionResult;
+
+    @TableField("operator_evaluation")
+    private Integer operatorEvaluation;
+
+    @TableField("company_id")
+    private Integer companyId;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 71 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentSparePart.java

@@ -0,0 +1,71 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 设备备品备件表
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentSparePart extends Model<EquipmentSparePart> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联设备ID
+     */
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    /**
+     * 名称
+     */
+    @TableField("part_name")
+    private String partName;
+
+    /**
+     * 规格
+     */
+    @TableField("part_spec")
+    private String partSpec;
+
+    /**
+     * 数量
+     */
+    @TableField("quantity")
+    private BigDecimal quantity;
+
+    /**
+     * 单价
+     */
+    @TableField("unit_price")
+    private BigDecimal unitPrice;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+    @TableField("is_deleted")
+    private Integer isDeleted;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 58 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/EquipmentTransferRecord.java

@@ -0,0 +1,58 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EquipmentTransferRecord extends Model<EquipmentTransferRecord> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    @TableField("transfer_type")
+    private String transferType;
+
+    @TableField("from_position")
+    private String fromPosition;
+
+    @TableField("to_position")
+    private String toPosition;
+
+    @TableField("transfer_time")
+    private LocalDateTime transferTime;
+
+    @TableField("sync_source")
+    private String syncSource;
+
+    @TableField("external_order_no")
+    private String externalOrderNo;
+
+    @TableField("company_id")
+    private Integer companyId;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 55 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/InspectionLibrary.java

@@ -0,0 +1,55 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 点检库表
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class InspectionLibrary extends Model<InspectionLibrary> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 点检项名称
+     */
+    @TableField("inspection_name")
+    private String inspectionName;
+
+    /**
+     * 点检明细
+     */
+    @TableField("inspection_detail")
+    private String inspectionDetail;
+
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+    @TableField("is_enabled")
+    private Integer isEnabled;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 61 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceCycleConfig.java

@@ -0,0 +1,61 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 维保周期配置表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class MaintenanceCycleConfig extends Model<MaintenanceCycleConfig> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 设备性质 1关键设备 2主要设备 3其他设备
+     */
+    @TableField("equipment_nature")
+    private Integer equipmentNature;
+
+    /**
+     * 一级保养周期(每运行N个月)
+     */
+    @TableField("level1_cycle_months")
+    private Integer level1CycleMonths;
+
+    /**
+     * 二级保养周期(每运行N个月)
+     */
+    @TableField("level2_cycle_months")
+    private Integer level2CycleMonths;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 145 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceIssue.java

@@ -0,0 +1,145 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 维保异常工单表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class MaintenanceIssue extends Model<MaintenanceIssue> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 异常单号
+     */
+    @TableField("issue_no")
+    private String issueNo;
+
+    /**
+     * 关联维保单ID
+     */
+    @TableField("order_id")
+    private Integer orderId;
+
+    /**
+     * 设备ID
+     */
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    /**
+     * 设备编号(冗余)
+     */
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    /**
+     * 问题描述
+     */
+    @TableField("issue_description")
+    private String issueDescription;
+
+    /**
+     * 问题照片JSON数组
+     */
+    @TableField("issue_photos")
+    private String issuePhotos;
+
+    /**
+     * 上报人工号
+     */
+    @TableField("reporter_user_id")
+    private Integer reporterUserId;
+
+    /**
+     * 上报人姓名
+     */
+    @TableField("reporter_name")
+    private String reporterName;
+
+    /**
+     * 上报时间
+     */
+    @TableField("report_time")
+    private LocalDateTime reportTime;
+
+    /**
+     * 派工人员工号
+     */
+    @TableField("assigned_user_id")
+    private Integer assignedUserId;
+
+    /**
+     * 派工人员姓名
+     */
+    @TableField("assigned_user_name")
+    private String assignedUserName;
+
+    /**
+     * 派工时间
+     */
+    @TableField("assign_time")
+    private LocalDateTime assignTime;
+
+    /**
+     * 处理人工号
+     */
+    @TableField("handler_user_id")
+    private Integer handlerUserId;
+
+    /**
+     * 处理人姓名
+     */
+    @TableField("handler_name")
+    private String handlerName;
+
+    /**
+     * 处理时间
+     */
+    @TableField("handle_time")
+    private LocalDateTime handleTime;
+
+    /**
+     * 处理结果
+     */
+    @TableField("handle_result")
+    private String handleResult;
+
+    /**
+     * 状态 0待派工 1处理中 2已完成 3已关闭
+     */
+    @TableField("issue_status")
+    private Integer issueStatus;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 61 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceLibrary.java

@@ -0,0 +1,61 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 保养库表
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class MaintenanceLibrary extends Model<MaintenanceLibrary> {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 保养级别 1一级 2二级
+     */
+    @TableField("maintenance_level")
+    private Integer maintenanceLevel;
+
+    /**
+     * 保养部位
+     */
+    @TableField("maintenance_part")
+    private String maintenancePart;
+
+    /**
+     * 保养内容及要求
+     */
+    @TableField("maintenance_content")
+    private String maintenanceContent;
+
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+    @TableField("is_enabled")
+    private Integer isEnabled;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+}

+ 140 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceOrder.java

@@ -0,0 +1,140 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 维保单表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class MaintenanceOrder extends Model<MaintenanceOrder> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 维保单号 年月设备编号序号
+     */
+    @TableField("order_no")
+    private String orderNo;
+
+    /**
+     * 关联年度计划ID
+     */
+    @TableField("plan_id")
+    private Integer planId;
+
+    /**
+     * 设备ID
+     */
+    @TableField("equipment_id")
+    private Integer equipmentId;
+
+    /**
+     * 设备编号(冗余)
+     */
+    @TableField("equipment_code")
+    private String equipmentCode;
+
+    /**
+     * 设备名称(冗余)
+     */
+    @TableField("equipment_name")
+    private String equipmentName;
+
+    /**
+     * 工位(冗余)
+     */
+    @TableField("work_position")
+    private String workPosition;
+
+    /**
+     * 保养等级 1一级 2二级
+     */
+    @TableField("maintenance_level")
+    private Integer maintenanceLevel;
+
+    /**
+     * 计划保养日期
+     */
+    @TableField("planned_date")
+    private LocalDate plannedDate;
+
+    /**
+     * 实际完成日期
+     */
+    @TableField("actual_date")
+    private LocalDate actualDate;
+
+    /**
+     * 维修员工号
+     */
+    @TableField("maintenance_user_id")
+    private Integer maintenanceUserId;
+
+    /**
+     * 维修员姓名
+     */
+    @TableField("maintenance_user_name")
+    private String maintenanceUserName;
+
+    /**
+     * 操作员工号
+     */
+    @TableField("operator_user_id")
+    private Integer operatorUserId;
+
+    /**
+     * 操作员姓名
+     */
+    @TableField("operator_user_name")
+    private String operatorUserName;
+
+    /**
+     * 状态 0待点检 1点检中 2已逾期 3已完成 4存在异常 5处理中 6已关闭
+     */
+    @TableField("order_status")
+    private Integer orderStatus;
+
+    /**
+     * 保养后设备状态 1良好 2不良
+     */
+    @TableField("inspection_result")
+    private Integer inspectionResult;
+
+    /**
+     * 设备工位评价 1满意 2不满意
+     */
+    @TableField("operator_evaluation")
+    private Integer operatorEvaluation;
+
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @TableField("updated_time")
+    private LocalDateTime updatedTime;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 69 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/MaintenanceOrderDetail.java

@@ -0,0 +1,69 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 维保单点检明细表
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class MaintenanceOrderDetail extends Model<MaintenanceOrderDetail> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 维保单ID
+     */
+    @TableField("order_id")
+    private Integer orderId;
+
+    /**
+     * 点检库ID
+     */
+    @TableField("library_id")
+    private Integer libraryId;
+
+    /**
+     * 保养部位
+     */
+    @TableField("maintenance_part")
+    private String maintenancePart;
+
+    /**
+     * 保养内容
+     */
+    @TableField("maintenance_content")
+    private String maintenanceContent;
+
+    /**
+     * 是否已勾选 0否 1是
+     */
+    @TableField("is_checked")
+    private Integer isChecked;
+
+    @TableField("sort_order")
+    private Integer sortOrder;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/AnnualMaintenancePlanMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.AnnualMaintenancePlan;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 年度维保计划表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface AnnualMaintenancePlanMapper extends BaseMapper<AnnualMaintenancePlan> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentArchiveMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.EquipmentArchive;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 设备档案表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface EquipmentArchiveMapper extends BaseMapper<EquipmentArchive> {
+
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentInspectionDetailMapper.java

@@ -0,0 +1,7 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.EquipmentInspectionDetail;
+
+public interface EquipmentInspectionDetailMapper extends BaseMapper<EquipmentInspectionDetail> {
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentInspectionRecordMapper.java

@@ -0,0 +1,7 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.EquipmentInspectionRecord;
+
+public interface EquipmentInspectionRecordMapper extends BaseMapper<EquipmentInspectionRecord> {
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentMaintenanceDetailMapper.java

@@ -0,0 +1,7 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.EquipmentMaintenanceDetail;
+
+public interface EquipmentMaintenanceDetailMapper extends BaseMapper<EquipmentMaintenanceDetail> {
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentMaintenanceRecordMapper.java

@@ -0,0 +1,7 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.EquipmentMaintenanceRecord;
+
+public interface EquipmentMaintenanceRecordMapper extends BaseMapper<EquipmentMaintenanceRecord> {
+}

+ 11 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentSparePartMapper.java

@@ -0,0 +1,11 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.EquipmentSparePart;
+
+/**
+ * 设备备品备件表 Mapper 接口
+ */
+public interface EquipmentSparePartMapper extends BaseMapper<EquipmentSparePart> {
+
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/EquipmentTransferRecordMapper.java

@@ -0,0 +1,7 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.EquipmentTransferRecord;
+
+public interface EquipmentTransferRecordMapper extends BaseMapper<EquipmentTransferRecord> {
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/InspectionLibraryMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.InspectionLibrary;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 点检库表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface InspectionLibraryMapper extends BaseMapper<InspectionLibrary> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceCycleConfigMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.MaintenanceCycleConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 维保周期配置表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceCycleConfigMapper extends BaseMapper<MaintenanceCycleConfig> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceIssueMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.MaintenanceIssue;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 维保异常工单表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceIssueMapper extends BaseMapper<MaintenanceIssue> {
+
+}

+ 11 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceLibraryMapper.java

@@ -0,0 +1,11 @@
+package com.management.platform.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.MaintenanceLibrary;
+
+/**
+ * 保养库表 Mapper
+ */
+public interface MaintenanceLibraryMapper extends BaseMapper<MaintenanceLibrary> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceOrderDetailMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.MaintenanceOrderDetail;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 维保单点检明细表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceOrderDetailMapper extends BaseMapper<MaintenanceOrderDetail> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/MaintenanceOrderMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.MaintenanceOrder;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 维保单表 Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceOrderMapper extends BaseMapper<MaintenanceOrder> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/AnnualMaintenancePlanService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.AnnualMaintenancePlan;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 年度维保计划表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface AnnualMaintenancePlanService extends IService<AnnualMaintenancePlan> {
+
+}

+ 58 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/EquipmentArchiveService.java

@@ -0,0 +1,58 @@
+package com.management.platform.service;
+
+import com.google.zxing.WriterException;
+import com.management.platform.entity.EquipmentArchive;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.util.HttpRespMsg;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * <p>
+ * 设备档案表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface EquipmentArchiveService extends IService<EquipmentArchive> {
+
+    /**
+     * 分页获取设备档案列表
+     */
+    HttpRespMsg getEquipmentList(String equipmentCode, String equipmentName, 
+                                 Integer responsibleUserId, Integer equipmentStatus,
+                                 Integer pageIndex, Integer pageSize, HttpServletRequest request);
+
+    /**
+     * 新增设备
+     */
+    HttpRespMsg insertEquipment(EquipmentArchive equipment, String sparePartListJson, HttpServletRequest request) throws IOException, WriterException;
+
+    /**
+     * 编辑设备
+     */
+    HttpRespMsg updateEquipment(EquipmentArchive equipment, String sparePartListJson, HttpServletRequest request) throws IOException, WriterException;
+
+    /**
+     * 删除设备
+     */
+    HttpRespMsg deleteEquipment(Integer id, HttpServletRequest request);
+
+    /**
+     * 封存/取消封存设备
+     */
+    HttpRespMsg sealEquipment(Integer id, Integer status, HttpServletRequest request);
+
+    /**
+     * 获取设备详情
+     */
+    HttpRespMsg getEquipmentDetail(Integer id);
+
+    /**
+     * 生成设备二维码
+     */
+    HttpRespMsg generateQrCode(Integer id);
+
+}

+ 18 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/EquipmentSparePartService.java

@@ -0,0 +1,18 @@
+package com.management.platform.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.entity.EquipmentSparePart;
+
+import java.util.List;
+
+/**
+ * 设备备品备件表 服务类
+ */
+public interface EquipmentSparePartService extends IService<EquipmentSparePart> {
+
+    List<EquipmentSparePart> listByEquipmentId(Integer equipmentId);
+
+    void saveSpareParts(Integer equipmentId, List<EquipmentSparePart> spareParts);
+
+    void deleteByEquipmentId(Integer equipmentId);
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/InspectionLibraryService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.InspectionLibrary;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 点检库表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface InspectionLibraryService extends IService<InspectionLibrary> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceCycleConfigService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.MaintenanceCycleConfig;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 维保周期配置表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceCycleConfigService extends IService<MaintenanceCycleConfig> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceIssueService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.MaintenanceIssue;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 维保异常工单表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceIssueService extends IService<MaintenanceIssue> {
+
+}

+ 14 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceLibraryService.java

@@ -0,0 +1,14 @@
+package com.management.platform.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.entity.MaintenanceLibrary;
+
+import java.util.List;
+
+/**
+ * 保养库表 服务类
+ */
+public interface MaintenanceLibraryService extends IService<MaintenanceLibrary> {
+
+    List<String> listMaintenanceParts();
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceOrderDetailService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.MaintenanceOrderDetail;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 维保单点检明细表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceOrderDetailService extends IService<MaintenanceOrderDetail> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MaintenanceOrderService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.MaintenanceOrder;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 维保单表 服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+public interface MaintenanceOrderService extends IService<MaintenanceOrder> {
+
+}

+ 30 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/MobileEquipmentService.java

@@ -0,0 +1,30 @@
+package com.management.platform.service;
+
+import com.management.platform.util.HttpRespMsg;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface MobileEquipmentService {
+
+    HttpRespMsg getRecentHistory(HttpServletRequest request, Integer pageIndex, Integer pageSize);
+
+    HttpRespMsg getEquipmentByCode(String equipmentCode, HttpServletRequest request);
+
+    HttpRespMsg getMobileDetail(Integer equipmentId, HttpServletRequest request);
+
+    HttpRespMsg getInspectionForm(Integer equipmentId, HttpServletRequest request);
+
+    HttpRespMsg submitInspection(Integer equipmentId, String detailListJson, String photoUrl,
+                                 HttpServletRequest request);
+
+    HttpRespMsg getMaintenanceForm(Integer equipmentId, Integer maintenanceLevel, HttpServletRequest request);
+
+    HttpRespMsg submitMaintenance(Integer equipmentId, Integer maintenanceLevel, Integer inspectionResult,
+                                  Integer operatorEvaluation, String detailListJson, HttpServletRequest request);
+
+    HttpRespMsg listMaintenanceRecords(Integer equipmentId);
+
+    HttpRespMsg listTransferRecords(Integer equipmentId, HttpServletRequest request);
+
+    HttpRespMsg syncTransferRecords(Integer equipmentId, HttpServletRequest request);
+}

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/AnnualMaintenancePlanServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.AnnualMaintenancePlan;
+import com.management.platform.mapper.AnnualMaintenancePlanMapper;
+import com.management.platform.service.AnnualMaintenancePlanService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 年度维保计划表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Service
+public class AnnualMaintenancePlanServiceImpl extends ServiceImpl<AnnualMaintenancePlanMapper, AnnualMaintenancePlan> implements AnnualMaintenancePlanService {
+
+}

+ 519 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/EquipmentArchiveServiceImpl.java

@@ -0,0 +1,519 @@
+package com.management.platform.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.management.platform.entity.Department;
+import com.management.platform.entity.EquipmentArchive;
+import com.management.platform.entity.EquipmentSparePart;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.DepartmentMapper;
+import com.management.platform.mapper.EquipmentArchiveMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.EquipmentArchiveService;
+import com.management.platform.service.EquipmentSparePartService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 设备档案表 服务实现类
+ */
+@Service
+public class EquipmentArchiveServiceImpl extends ServiceImpl<EquipmentArchiveMapper, EquipmentArchive> implements EquipmentArchiveService {
+
+    private static final int MAX_FILE_COUNT = 5;
+
+    @Value("${upload.path}")
+    private String uploadPath;
+
+    @Resource
+    private UserMapper userMapper;
+
+    @Resource
+    private EquipmentSparePartService equipmentSparePartService;
+
+    @Resource
+    private DepartmentMapper departmentMapper;
+
+    @Override
+    public HttpRespMsg getEquipmentList(String equipmentCode, String equipmentName,
+                                        Integer responsibleUserId, Integer equipmentStatus,
+                                        Integer pageIndex, Integer pageSize, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<EquipmentArchive> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("is_deleted", 0);
+        if (StringUtils.isNotBlank(equipmentCode)) {
+            queryWrapper.like("equipment_code", equipmentCode);
+        }
+        if (StringUtils.isNotBlank(equipmentName)) {
+            queryWrapper.like("equipment_name", equipmentName);
+        }
+        if (responsibleUserId != null) {
+            queryWrapper.eq("responsible_user_id", responsibleUserId);
+        }
+        if (equipmentStatus != null) {
+            queryWrapper.eq("equipment_status", equipmentStatus);
+        }
+        queryWrapper.orderByDesc("created_time");
+
+        IPage<EquipmentArchive> pageResult = page(new Page<>(pageIndex, pageSize), queryWrapper);
+        Map<String, Object> result = new HashMap<>();
+        result.put("data", pageResult.getRecords());
+        result.put("total", pageResult.getTotal());
+        msg.data = result;
+        return msg;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public HttpRespMsg insertEquipment(EquipmentArchive equipment, String sparePartListJson, HttpServletRequest request) throws IOException, WriterException {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        if (StringUtils.isBlank(equipment.getEquipmentCode())) {
+            msg.setError("设备编号不能为空");
+            return msg;
+        }
+        if (StringUtils.isBlank(equipment.getEquipmentName())) {
+            msg.setError("设备名称不能为空");
+            return msg;
+        }
+        if (!validateFileJson(equipment.getEquipmentPhotos(), msg, "设备图片")) {
+            return msg;
+        }
+        if (!validateFileJson(equipment.getContractFiles(), msg, "合同图片")) {
+            return msg;
+        }
+        if (!validateFileJson(equipment.getInvoiceFiles(), msg, "发票图片")) {
+            return msg;
+        }
+        List<EquipmentSparePart> spareParts = parseSpareParts(sparePartListJson, msg);
+        if (msg.getCode().equals("error")) {
+            return msg;
+        }
+
+        long count = count(new QueryWrapper<EquipmentArchive>()
+                .eq("equipment_code", equipment.getEquipmentCode())
+                .eq("is_deleted", 0));
+        if (count > 0) {
+            msg.setError("设备编号已存在");
+            return msg;
+        }
+
+        if (equipment.getDepartmentId() != null && equipment.getDepartmentId() == 0) {
+            equipment.setDepartmentId(null);
+            equipment.setWorkPosition(null);
+        }
+        equipment.setEquipmentStatus(1);
+        equipment.setIsDeleted(0);
+        equipment.setCreatedBy(user.getId());
+        equipment.setCreatedTime(LocalDateTime.now());
+        equipment.setUpdatedBy(user.getId());
+        equipment.setUpdatedTime(LocalDateTime.now());
+        if (!fillDepartmentInfo(equipment, msg)) {
+            return msg;
+        }
+        save(equipment);
+
+        equipmentSparePartService.saveSpareParts(equipment.getId(), spareParts);
+        generateAndSaveQrCode(equipment);
+
+        Map<String, Object> result = buildDetailResult(equipment);
+        msg.data = result;
+        return msg;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public HttpRespMsg updateEquipment(EquipmentArchive equipment, String sparePartListJson, HttpServletRequest request) throws IOException, WriterException {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        if (equipment.getId() == null) {
+            msg.setError("设备ID不能为空");
+            return msg;
+        }
+        EquipmentArchive exist = getById(equipment.getId());
+        if (exist == null || exist.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        if (StringUtils.isNotBlank(equipment.getEquipmentCode()) &&
+                !equipment.getEquipmentCode().equals(exist.getEquipmentCode())) {
+            long count = count(new QueryWrapper<EquipmentArchive>()
+                    .eq("equipment_code", equipment.getEquipmentCode())
+                    .eq("is_deleted", 0)
+                    .ne("id", equipment.getId()));
+            if (count > 0) {
+                msg.setError("设备编号已存在");
+                return msg;
+            }
+        }
+        if (!validateFileJson(equipment.getEquipmentPhotos(), msg, "设备图片")) {
+            return msg;
+        }
+        if (!validateFileJson(equipment.getContractFiles(), msg, "合同图片")) {
+            return msg;
+        }
+        if (!validateFileJson(equipment.getInvoiceFiles(), msg, "发票图片")) {
+            return msg;
+        }
+
+        boolean sparePartProvided = StringUtils.isNotBlank(sparePartListJson);
+        List<EquipmentSparePart> spareParts = sparePartProvided ? parseSpareParts(sparePartListJson, msg) : null;
+        if (msg.getCode().equals("error")) {
+            return msg;
+        }
+
+        boolean clearDepartment = equipment.getDepartmentId() != null && equipment.getDepartmentId() == 0;
+        boolean codeChanged = StringUtils.isNotBlank(equipment.getEquipmentCode())
+                && !equipment.getEquipmentCode().equals(exist.getEquipmentCode());
+
+        mergeEquipmentFields(equipment, exist);
+        if (clearDepartment) {
+            equipment.setDepartmentId(null);
+            equipment.setWorkPosition(null);
+        }
+        if (!fillDepartmentInfo(equipment, msg)) {
+            return msg;
+        }
+        equipment.setUpdatedBy(user.getId());
+        equipment.setUpdatedTime(LocalDateTime.now());
+        updateById(equipment);
+
+        if (sparePartProvided) {
+            equipmentSparePartService.saveSpareParts(equipment.getId(), spareParts);
+        }
+
+        EquipmentArchive latest = getById(equipment.getId());
+        if (codeChanged || StringUtils.isBlank(latest.getQrCodeUrl())) {
+            generateAndSaveQrCode(latest);
+        }
+
+        msg.data = buildDetailResult(getById(equipment.getId()));
+        return msg;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public HttpRespMsg deleteEquipment(Integer id, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        EquipmentArchive equipment = getById(id);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        equipment.setIsDeleted(1);
+        equipment.setUpdatedBy(user.getId());
+        equipment.setUpdatedTime(LocalDateTime.now());
+        updateById(equipment);
+        equipmentSparePartService.deleteByEquipmentId(id);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg sealEquipment(Integer id, Integer status, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        EquipmentArchive equipment = getById(id);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        if (status != 1 && status != 2) {
+            msg.setError("状态参数错误");
+            return msg;
+        }
+        equipment.setEquipmentStatus(status);
+        equipment.setUpdatedBy(user.getId());
+        equipment.setUpdatedTime(LocalDateTime.now());
+        updateById(equipment);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg getEquipmentDetail(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        EquipmentArchive equipment = getById(id);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        msg.data = buildDetailResult(equipment);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg generateQrCode(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        EquipmentArchive equipment = getById(id);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        try {
+            generateAndSaveQrCode(equipment);
+            Map<String, Object> data = new HashMap<>();
+            data.put("qrCodeUrl", equipment.getQrCodeUrl());
+            data.put("qrCodeData", equipment.getQrCodeData());
+            msg.data = data;
+        } catch (Exception e) {
+            e.printStackTrace();
+            msg.setError("二维码生成失败:" + e.getMessage());
+        }
+        return msg;
+    }
+
+    private User getLoginUser(HttpServletRequest request, HttpRespMsg msg) {
+        String token = request.getHeader("Token");
+        if (StringUtils.isBlank(token)) {
+            token = request.getHeader("TOKEN");
+        }
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+        }
+        return user;
+    }
+
+    private boolean validateFileJson(String json, HttpRespMsg msg, String label) {
+        if (StringUtils.isBlank(json)) {
+            return true;
+        }
+        try {
+            JSONArray array = JSON.parseArray(json);
+            if (array.size() > MAX_FILE_COUNT) {
+                msg.setError(label + "最多上传" + MAX_FILE_COUNT + "张");
+                return false;
+            }
+            return true;
+        } catch (Exception e) {
+            msg.setError(label + "格式错误");
+            return false;
+        }
+    }
+
+    private List<EquipmentSparePart> parseSpareParts(String sparePartListJson, HttpRespMsg msg) {
+        List<EquipmentSparePart> result = new ArrayList<>();
+        if (StringUtils.isBlank(sparePartListJson)) {
+            return result;
+        }
+        try {
+            JSONArray array = JSON.parseArray(sparePartListJson);
+            for (int i = 0; i < array.size(); i++) {
+                com.alibaba.fastjson.JSONObject item = array.getJSONObject(i);
+                String partName = item.getString("partName");
+                String partSpec = item.getString("partSpec");
+                if (StringUtils.isBlank(partName) && StringUtils.isBlank(partSpec)) {
+                    continue;
+                }
+                if (StringUtils.isBlank(partName)) {
+                    msg.setError("备品备件第" + (i + 1) + "行名称不能为空");
+                    return result;
+                }
+                if (StringUtils.isBlank(partSpec)) {
+                    msg.setError("备品备件第" + (i + 1) + "行规格不能为空");
+                    return result;
+                }
+                EquipmentSparePart part = new EquipmentSparePart();
+                part.setPartName(partName.trim());
+                part.setPartSpec(partSpec.trim());
+                BigDecimal quantity = item.getBigDecimal("quantity");
+                BigDecimal unitPrice = item.getBigDecimal("unitPrice");
+                part.setQuantity(quantity == null ? BigDecimal.ZERO : quantity);
+                part.setUnitPrice(unitPrice == null ? BigDecimal.ZERO : unitPrice);
+                result.add(part);
+            }
+        } catch (Exception e) {
+            msg.setError("备品备件数据格式错误");
+        }
+        return result;
+    }
+
+    private Map<String, Object> buildDetailResult(EquipmentArchive equipment) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("id", equipment.getId());
+        result.put("equipmentCode", equipment.getEquipmentCode());
+        result.put("equipmentName", equipment.getEquipmentName());
+        result.put("equipmentModel", equipment.getEquipmentModel());
+        result.put("factoryNumber", equipment.getFactoryNumber());
+        result.put("equipmentNature", equipment.getEquipmentNature());
+        result.put("workPosition", equipment.getWorkPosition());
+        result.put("departmentId", equipment.getDepartmentId());
+        result.put("responsiblePerson", equipment.getResponsiblePerson());
+        result.put("responsibleUserId", equipment.getResponsibleUserId());
+        result.put("equipmentStatus", equipment.getEquipmentStatus());
+        result.put("firstRunDate", equipment.getFirstRunDate());
+        result.put("equipmentPhotos", equipment.getEquipmentPhotos());
+        result.put("qrCodeUrl", equipment.getQrCodeUrl());
+        result.put("qrCodeData", equipment.getQrCodeData());
+        result.put("contractFiles", equipment.getContractFiles());
+        result.put("invoiceFiles", equipment.getInvoiceFiles());
+        result.put("remark", equipment.getRemark());
+        result.put("createdBy", equipment.getCreatedBy());
+        result.put("createdTime", equipment.getCreatedTime());
+        result.put("updatedBy", equipment.getUpdatedBy());
+        result.put("updatedTime", equipment.getUpdatedTime());
+        result.put("equipmentPhotoList", parseFileList(equipment.getEquipmentPhotos()));
+        result.put("contractFileList", parseFileList(equipment.getContractFiles()));
+        result.put("invoiceFileList", parseFileList(equipment.getInvoiceFiles()));
+        result.put("sparePartList", equipmentSparePartService.listByEquipmentId(equipment.getId()));
+        return result;
+    }
+
+    private List<String> parseFileList(String json) {
+        if (StringUtils.isBlank(json)) {
+            return new ArrayList<>();
+        }
+        try {
+            return JSON.parseArray(json, String.class);
+        } catch (Exception e) {
+            return new ArrayList<>();
+        }
+    }
+
+    private void generateAndSaveQrCode(EquipmentArchive equipment) throws WriterException, IOException {
+        String qrContent = buildQrCodeData(equipment);
+        String fileName = "qrcode_" + equipment.getEquipmentCode() + "_" +
+                UUID.randomUUID().toString().replaceAll("-", "") + ".png";
+
+        File dir = new File(uploadPath);
+        if (!dir.exists()) {
+            dir.mkdirs();
+        }
+
+        Map<EncodeHintType, Object> hints = new HashMap<>();
+        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
+        hints.put(EncodeHintType.MARGIN, 1);
+
+        BitMatrix bitMatrix = new MultiFormatWriter().encode(
+                qrContent, BarcodeFormat.QR_CODE, 300, 300, hints);
+        Path outputPath = Paths.get(uploadPath, fileName);
+        MatrixToImageWriter.writeToPath(bitMatrix, "PNG", outputPath);
+
+        equipment.setQrCodeData(qrContent);
+        equipment.setQrCodeUrl(fileName);
+        updateById(equipment);
+    }
+
+    private String buildQrCodeData(EquipmentArchive equipment) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("id", equipment.getId());
+        data.put("equipmentCode", equipment.getEquipmentCode());
+        data.put("equipmentName", equipment.getEquipmentName());
+        data.put("equipmentModel", equipment.getEquipmentModel());
+        data.put("equipmentNature", equipment.getEquipmentNature());
+        data.put("workPosition", equipment.getWorkPosition());
+        data.put("departmentId", equipment.getDepartmentId());
+        data.put("responsiblePerson", equipment.getResponsiblePerson());
+        data.put("firstRunDate", equipment.getFirstRunDate());
+        return JSON.toJSONString(data);
+    }
+
+    private void mergeEquipmentFields(EquipmentArchive target, EquipmentArchive exist) {
+        if (StringUtils.isBlank(target.getEquipmentCode())) {
+            target.setEquipmentCode(exist.getEquipmentCode());
+        }
+        if (StringUtils.isBlank(target.getEquipmentName())) {
+            target.setEquipmentName(exist.getEquipmentName());
+        }
+        if (target.getEquipmentModel() == null) {
+            target.setEquipmentModel(exist.getEquipmentModel());
+        }
+        if (target.getFactoryNumber() == null) {
+            target.setFactoryNumber(exist.getFactoryNumber());
+        }
+        if (target.getEquipmentNature() == null) {
+            target.setEquipmentNature(exist.getEquipmentNature());
+        }
+        if (target.getWorkPosition() == null) {
+            target.setWorkPosition(exist.getWorkPosition());
+        }
+        if (target.getDepartmentId() == null) {
+            target.setDepartmentId(exist.getDepartmentId());
+        }
+        if (target.getResponsiblePerson() == null) {
+            target.setResponsiblePerson(exist.getResponsiblePerson());
+        }
+        if (target.getResponsibleUserId() == null) {
+            target.setResponsibleUserId(exist.getResponsibleUserId());
+        }
+        if (target.getEquipmentStatus() == null) {
+            target.setEquipmentStatus(exist.getEquipmentStatus());
+        }
+        if (target.getFirstRunDate() == null) {
+            target.setFirstRunDate(exist.getFirstRunDate());
+        }
+        if (target.getEquipmentPhotos() == null) {
+            target.setEquipmentPhotos(exist.getEquipmentPhotos());
+        }
+        if (target.getContractFiles() == null) {
+            target.setContractFiles(exist.getContractFiles());
+        }
+        if (target.getInvoiceFiles() == null) {
+            target.setInvoiceFiles(exist.getInvoiceFiles());
+        }
+        if (target.getRemark() == null) {
+            target.setRemark(exist.getRemark());
+        }
+        if (target.getQrCodeUrl() == null) {
+            target.setQrCodeUrl(exist.getQrCodeUrl());
+        }
+        if (target.getQrCodeData() == null) {
+            target.setQrCodeData(exist.getQrCodeData());
+        }
+        target.setIsDeleted(exist.getIsDeleted());
+        target.setCreatedBy(exist.getCreatedBy());
+        target.setCreatedTime(exist.getCreatedTime());
+    }
+
+    private boolean fillDepartmentInfo(EquipmentArchive equipment, HttpRespMsg msg) {
+        if (equipment.getDepartmentId() == null) {
+            return true;
+        }
+        Department department = departmentMapper.selectById(equipment.getDepartmentId());
+        if (department == null) {
+            msg.setError("工位部门不存在");
+            return false;
+        }
+        equipment.setWorkPosition(department.getDepartmentName());
+        return true;
+    }
+}

+ 67 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/EquipmentSparePartServiceImpl.java

@@ -0,0 +1,67 @@
+package com.management.platform.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.entity.EquipmentSparePart;
+import com.management.platform.mapper.EquipmentSparePartMapper;
+import com.management.platform.service.EquipmentSparePartService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 设备备品备件表 服务实现类
+ */
+@Service
+public class EquipmentSparePartServiceImpl extends ServiceImpl<EquipmentSparePartMapper, EquipmentSparePart>
+        implements EquipmentSparePartService {
+
+    @Override
+    public List<EquipmentSparePart> listByEquipmentId(Integer equipmentId) {
+        if (equipmentId == null) {
+            return new ArrayList<>();
+        }
+        return list(new QueryWrapper<EquipmentSparePart>()
+                .eq("equipment_id", equipmentId)
+                .eq("is_deleted", 0)
+                .orderByAsc("id"));
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void saveSpareParts(Integer equipmentId, List<EquipmentSparePart> spareParts) {
+        deleteByEquipmentId(equipmentId);
+        if (spareParts == null || spareParts.isEmpty()) {
+            return;
+        }
+        LocalDateTime now = LocalDateTime.now();
+        for (EquipmentSparePart part : spareParts) {
+            if (StringUtils.isBlank(part.getPartName()) && StringUtils.isBlank(part.getPartSpec())) {
+                continue;
+            }
+            part.setId(null);
+            part.setEquipmentId(equipmentId);
+            part.setIsDeleted(0);
+            part.setCreatedTime(now);
+            part.setUpdatedTime(now);
+            save(part);
+        }
+    }
+
+    @Override
+    public void deleteByEquipmentId(Integer equipmentId) {
+        if (equipmentId == null) {
+            return;
+        }
+        update(new UpdateWrapper<EquipmentSparePart>()
+                .eq("equipment_id", equipmentId)
+                .eq("is_deleted", 0)
+                .set("is_deleted", 1)
+                .set("updated_time", LocalDateTime.now()));
+    }
+}

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/InspectionLibraryServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.InspectionLibrary;
+import com.management.platform.mapper.InspectionLibraryMapper;
+import com.management.platform.service.InspectionLibraryService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 点检库表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Service
+public class InspectionLibraryServiceImpl extends ServiceImpl<InspectionLibraryMapper, InspectionLibrary> implements InspectionLibraryService {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceCycleConfigServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.MaintenanceCycleConfig;
+import com.management.platform.mapper.MaintenanceCycleConfigMapper;
+import com.management.platform.service.MaintenanceCycleConfigService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 维保周期配置表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Service
+public class MaintenanceCycleConfigServiceImpl extends ServiceImpl<MaintenanceCycleConfigMapper, MaintenanceCycleConfig> implements MaintenanceCycleConfigService {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceIssueServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.MaintenanceIssue;
+import com.management.platform.mapper.MaintenanceIssueMapper;
+import com.management.platform.service.MaintenanceIssueService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 维保异常工单表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Service
+public class MaintenanceIssueServiceImpl extends ServiceImpl<MaintenanceIssueMapper, MaintenanceIssue> implements MaintenanceIssueService {
+
+}

+ 32 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceLibraryServiceImpl.java

@@ -0,0 +1,32 @@
+package com.management.platform.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.entity.MaintenanceLibrary;
+import com.management.platform.mapper.MaintenanceLibraryMapper;
+import com.management.platform.service.MaintenanceLibraryService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 保养库表 服务实现类
+ */
+@Service
+public class MaintenanceLibraryServiceImpl extends ServiceImpl<MaintenanceLibraryMapper, MaintenanceLibrary>
+        implements MaintenanceLibraryService {
+
+    @Override
+    public List<String> listMaintenanceParts() {
+        QueryWrapper<MaintenanceLibrary> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("is_enabled", 1);
+        queryWrapper.orderByAsc("maintenance_part");
+        return list(queryWrapper).stream()
+                .map(MaintenanceLibrary::getMaintenancePart)
+                .filter(StringUtils::isNotBlank)
+                .distinct()
+                .collect(Collectors.toList());
+    }
+}

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceOrderDetailServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.MaintenanceOrderDetail;
+import com.management.platform.mapper.MaintenanceOrderDetailMapper;
+import com.management.platform.service.MaintenanceOrderDetailService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 维保单点检明细表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Service
+public class MaintenanceOrderDetailServiceImpl extends ServiceImpl<MaintenanceOrderDetailMapper, MaintenanceOrderDetail> implements MaintenanceOrderDetailService {
+
+}

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MaintenanceOrderServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.MaintenanceOrder;
+import com.management.platform.mapper.MaintenanceOrderMapper;
+import com.management.platform.service.MaintenanceOrderService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 维保单表 服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2026-06-05
+ */
+@Service
+public class MaintenanceOrderServiceImpl extends ServiceImpl<MaintenanceOrderMapper, MaintenanceOrder> implements MaintenanceOrderService {
+
+}

+ 608 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/MobileEquipmentServiceImpl.java

@@ -0,0 +1,608 @@
+package com.management.platform.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.management.platform.entity.*;
+import com.management.platform.mapper.*;
+import com.management.platform.service.MobileEquipmentService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.TemporalAdjusters;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class MobileEquipmentServiceImpl implements MobileEquipmentService {
+
+    @Resource
+    private EquipmentArchiveMapper equipmentArchiveMapper;
+    @Resource
+    private EquipmentInspectionRecordMapper inspectionRecordMapper;
+    @Resource
+    private EquipmentInspectionDetailMapper inspectionDetailMapper;
+    @Resource
+    private EquipmentMaintenanceRecordMapper maintenanceRecordMapper;
+    @Resource
+    private EquipmentMaintenanceDetailMapper maintenanceDetailMapper;
+    @Resource
+    private EquipmentTransferRecordMapper transferRecordMapper;
+    @Resource
+    private InspectionLibraryMapper inspectionLibraryMapper;
+    @Resource
+    private MaintenanceLibraryMapper maintenanceLibraryMapper;
+    @Resource
+    private MaintenanceOrderMapper maintenanceOrderMapper;
+    @Resource
+    private DepartmentMapper departmentMapper;
+    @Resource
+    private UserMapper userMapper;
+
+    @Override
+    public HttpRespMsg getRecentHistory(HttpServletRequest request, Integer pageIndex, Integer pageSize) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        int page = pageIndex == null ? 1 : pageIndex;
+        int size = pageSize == null ? 20 : pageSize;
+
+        List<Map<String, Object>> all = new ArrayList<>();
+
+        QueryWrapper<EquipmentInspectionRecord> iq = new QueryWrapper<>();
+        iq.eq("company_id", user.getCompanyId());
+        iq.orderByDesc("created_time");
+        iq.last("LIMIT 100");
+        for (EquipmentInspectionRecord r : inspectionRecordMapper.selectList(iq)) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("recordType", "inspection");
+            item.put("recordTime", r.getCreatedTime());
+            item.put("equipmentCode", r.getEquipmentCode());
+            item.put("equipmentId", r.getEquipmentId());
+            item.put("resultText", r.getOverallResult() != null && r.getOverallResult() == 1 ? "通过检查" : "存在隐患");
+            item.put("resultStatus", r.getOverallResult());
+            item.put("maintenanceLevel", null);
+            item.put("maintenanceLevelText", "-");
+            all.add(item);
+        }
+
+        QueryWrapper<EquipmentMaintenanceRecord> mq = new QueryWrapper<>();
+        mq.eq("company_id", user.getCompanyId());
+        mq.orderByDesc("created_time");
+        mq.last("LIMIT 100");
+        for (EquipmentMaintenanceRecord r : maintenanceRecordMapper.selectList(mq)) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("recordType", "maintenance");
+            item.put("recordTime", r.getCreatedTime());
+            item.put("equipmentCode", r.getEquipmentCode());
+            item.put("equipmentId", r.getEquipmentId());
+            item.put("resultText", r.getInspectionResult() != null && r.getInspectionResult() == 1 ? "通过检查" : "存在隐患");
+            item.put("resultStatus", r.getInspectionResult());
+            item.put("maintenanceLevel", r.getMaintenanceLevel());
+            item.put("maintenanceLevelText", r.getMaintenanceLevel() != null && r.getMaintenanceLevel() == 2 ? "二级保养" : "一级保养");
+            all.add(item);
+        }
+
+        all.sort((a, b) -> {
+            LocalDateTime ta = (LocalDateTime) a.get("recordTime");
+            LocalDateTime tb = (LocalDateTime) b.get("recordTime");
+            if (ta == null && tb == null) return 0;
+            if (ta == null) return 1;
+            if (tb == null) return -1;
+            return tb.compareTo(ta);
+        });
+
+        int from = (page - 1) * size;
+        int to = Math.min(from + size, all.size());
+        List<Map<String, Object>> pageData = from >= all.size() ? new ArrayList<>() : all.subList(from, to);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("data", pageData);
+        result.put("total", all.size());
+        msg.data = result;
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg getEquipmentByCode(String equipmentCode, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        String code = resolveEquipmentCode(equipmentCode);
+        if (StringUtils.isBlank(code)) {
+            msg.setError("设备编号不能为空");
+            return msg;
+        }
+        EquipmentArchive equipment = findEquipmentByCode(code);
+        if (equipment == null) {
+            msg.setError("未找到该设备");
+            return msg;
+        }
+        msg.data = buildMobileDetail(equipment, user);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg getMobileDetail(Integer equipmentId, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        EquipmentArchive equipment = equipmentArchiveMapper.selectById(equipmentId);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        msg.data = buildMobileDetail(equipment, user);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg getInspectionForm(Integer equipmentId, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        EquipmentArchive equipment = equipmentArchiveMapper.selectById(equipmentId);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+
+        InspectionRoleInfo roleInfo = resolveInspectionRole(equipment, user);
+        if (roleInfo == null) {
+            msg.setError("当前设备无需您执行点检,或您暂无点检权限");
+            return msg;
+        }
+
+        QueryWrapper<InspectionLibrary> qw = new QueryWrapper<>();
+        qw.eq("is_enabled", 1).orderByAsc("sort_order").orderByAsc("id");
+        List<InspectionLibrary> items = inspectionLibraryMapper.selectList(qw);
+
+        Map<String, Object> data = new HashMap<>();
+        data.put("equipmentId", equipment.getId());
+        data.put("equipmentCode", equipment.getEquipmentCode());
+        data.put("equipmentName", equipment.getEquipmentName());
+        data.put("inspectorRole", roleInfo.roleName);
+        data.put("inspectionType", roleInfo.inspectionType);
+        data.put("inspectorName", user.getName());
+        data.put("stationLeaderName", findStationLeaderName(equipment.getDepartmentId()));
+        data.put("items", items);
+        msg.data = data;
+        return msg;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public HttpRespMsg submitInspection(Integer equipmentId, String detailListJson, String photoUrl,
+                                        HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        if (StringUtils.isBlank(photoUrl)) {
+            msg.setError("请上传点检照片");
+            return msg;
+        }
+        EquipmentArchive equipment = equipmentArchiveMapper.selectById(equipmentId);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        InspectionRoleInfo roleInfo = resolveInspectionRole(equipment, user);
+        if (roleInfo == null) {
+            msg.setError("当前设备无需您执行点检");
+            return msg;
+        }
+
+        JSONArray details;
+        try {
+            details = JSON.parseArray(detailListJson);
+        } catch (Exception e) {
+            msg.setError("点检明细格式错误");
+            return msg;
+        }
+        if (details == null || details.isEmpty()) {
+            msg.setError("请完成点检项");
+            return msg;
+        }
+
+        boolean hasAbnormal = false;
+        for (int i = 0; i < details.size(); i++) {
+            JSONObject item = details.getJSONObject(i);
+            Integer checkResult = item.getInteger("checkResult");
+            if (checkResult != null && checkResult == 2) {
+                hasAbnormal = true;
+            }
+        }
+
+        EquipmentInspectionRecord record = new EquipmentInspectionRecord();
+        record.setEquipmentId(equipment.getId());
+        record.setEquipmentCode(equipment.getEquipmentCode());
+        record.setEquipmentName(equipment.getEquipmentName());
+        record.setInspectorUserId(user.getId());
+        record.setInspectorName(user.getName());
+        record.setInspectorRole(roleInfo.roleName);
+        record.setInspectionType(roleInfo.inspectionType);
+        record.setOverallResult(hasAbnormal ? 2 : 1);
+        record.setPhotoUrl(photoUrl);
+        record.setCompanyId(user.getCompanyId());
+        record.setCreatedTime(LocalDateTime.now());
+        inspectionRecordMapper.insert(record);
+
+        for (int i = 0; i < details.size(); i++) {
+            JSONObject item = details.getJSONObject(i);
+            EquipmentInspectionDetail detail = new EquipmentInspectionDetail();
+            detail.setRecordId(record.getId());
+            detail.setLibraryId(item.getInteger("libraryId"));
+            detail.setInspectionName(item.getString("inspectionName"));
+            detail.setInspectionDetail(item.getString("inspectionDetail"));
+            detail.setCheckResult(item.getInteger("checkResult"));
+            detail.setSortOrder(i + 1);
+            inspectionDetailMapper.insert(detail);
+        }
+
+        msg.data = record.getId();
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg getMaintenanceForm(Integer equipmentId, Integer maintenanceLevel, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        EquipmentArchive equipment = equipmentArchiveMapper.selectById(equipmentId);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+        int level = maintenanceLevel == null ? 1 : maintenanceLevel;
+
+        QueryWrapper<MaintenanceLibrary> qw = new QueryWrapper<>();
+        qw.eq("is_enabled", 1);
+        qw.eq("maintenance_level", level);
+        qw.orderByAsc("maintenance_part").orderByAsc("sort_order").orderByAsc("id");
+        List<MaintenanceLibrary> allItems = maintenanceLibraryMapper.selectList(qw);
+
+        Map<String, List<MaintenanceLibrary>> grouped = allItems.stream()
+                .collect(Collectors.groupingBy(
+                        item -> StringUtils.defaultIfBlank(item.getMaintenancePart(), "其他"),
+                        LinkedHashMap::new,
+                        Collectors.toList()));
+
+        Map<String, Object> data = new HashMap<>();
+        data.put("equipmentId", equipment.getId());
+        data.put("equipmentCode", equipment.getEquipmentCode());
+        data.put("equipmentName", equipment.getEquipmentName());
+        data.put("maintenanceLevel", level);
+        data.put("maintenanceUserName", user.getName());
+        data.put("operatorUserName", equipment.getResponsiblePerson());
+        data.put("partGroups", grouped);
+        msg.data = data;
+        return msg;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public HttpRespMsg submitMaintenance(Integer equipmentId, Integer maintenanceLevel, Integer inspectionResult,
+                                         Integer operatorEvaluation, String detailListJson,
+                                         HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        EquipmentArchive equipment = equipmentArchiveMapper.selectById(equipmentId);
+        if (equipment == null || equipment.getIsDeleted() == 1) {
+            msg.setError("设备不存在");
+            return msg;
+        }
+
+        JSONArray details;
+        try {
+            details = JSON.parseArray(detailListJson);
+        } catch (Exception e) {
+            msg.setError("保养明细格式错误");
+            return msg;
+        }
+
+        EquipmentMaintenanceRecord record = new EquipmentMaintenanceRecord();
+        record.setEquipmentId(equipment.getId());
+        record.setEquipmentCode(equipment.getEquipmentCode());
+        record.setEquipmentName(equipment.getEquipmentName());
+        record.setMaintenanceLevel(maintenanceLevel == null ? 1 : maintenanceLevel);
+        record.setMaintenanceUserId(user.getId());
+        record.setMaintenanceUserName(user.getName());
+        record.setOperatorUserId(null);
+        record.setOperatorUserName(equipment.getResponsiblePerson());
+        record.setInspectionResult(inspectionResult == null ? 1 : inspectionResult);
+        record.setOperatorEvaluation(operatorEvaluation == null ? 1 : operatorEvaluation);
+        record.setCompanyId(user.getCompanyId());
+        record.setCreatedTime(LocalDateTime.now());
+        maintenanceRecordMapper.insert(record);
+
+        if (details != null) {
+            for (int i = 0; i < details.size(); i++) {
+                JSONObject item = details.getJSONObject(i);
+                EquipmentMaintenanceDetail detail = new EquipmentMaintenanceDetail();
+                detail.setRecordId(record.getId());
+                detail.setLibraryId(item.getInteger("libraryId"));
+                detail.setMaintenancePart(item.getString("maintenancePart"));
+                detail.setMaintenanceContent(item.getString("maintenanceContent"));
+                detail.setIsChecked(item.getInteger("isChecked") != null && item.getInteger("isChecked") == 1 ? 1 : 0);
+                detail.setSortOrder(i + 1);
+                maintenanceDetailMapper.insert(detail);
+            }
+        }
+
+        msg.data = record.getId();
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg listMaintenanceRecords(Integer equipmentId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<EquipmentMaintenanceRecord> mq = new QueryWrapper<>();
+        mq.eq("equipment_id", equipmentId).orderByDesc("created_time");
+        List<EquipmentMaintenanceRecord> mobileRecords = maintenanceRecordMapper.selectList(mq);
+
+        QueryWrapper<MaintenanceOrder> oq = new QueryWrapper<>();
+        oq.eq("equipment_id", equipmentId).orderByDesc("planned_date");
+        List<MaintenanceOrder> planRecords = maintenanceOrderMapper.selectList(oq);
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("mobileRecords", mobileRecords);
+        result.put("planRecords", planRecords);
+        msg.data = result;
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg listTransferRecords(Integer equipmentId, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        syncTransferRecordsInternal(equipmentId, user.getCompanyId());
+
+        QueryWrapper<EquipmentTransferRecord> qw = new QueryWrapper<>();
+        qw.eq("equipment_id", equipmentId).orderByDesc("transfer_time");
+        msg.data = transferRecordMapper.selectList(qw);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg syncTransferRecords(Integer equipmentId, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = getLoginUser(request, msg);
+        if (user == null) {
+            return msg;
+        }
+        syncTransferRecordsInternal(equipmentId, user.getCompanyId());
+        return msg;
+    }
+
+    private void syncTransferRecordsInternal(Integer equipmentId, Integer companyId) {
+        EquipmentArchive equipment = equipmentArchiveMapper.selectById(equipmentId);
+        if (equipment == null) {
+            return;
+        }
+        // 预留企业微信调拨工单同步接口,当前无外部数据源时不写入模拟数据
+    }
+
+    private Map<String, Object> buildMobileDetail(EquipmentArchive equipment, User user) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("id", equipment.getId());
+        data.put("equipmentCode", equipment.getEquipmentCode());
+        data.put("equipmentName", equipment.getEquipmentName());
+        data.put("equipmentModel", equipment.getEquipmentModel());
+        data.put("workPosition", equipment.getWorkPosition());
+        data.put("responsiblePerson", equipment.getResponsiblePerson());
+        data.put("equipmentNature", equipment.getEquipmentNature());
+        data.put("equipmentPhotos", equipment.getEquipmentPhotos());
+        data.put("firstRunDate", equipment.getFirstRunDate());
+
+        boolean inspectionDone = isInspectionDoneInCurrentCycle(equipment, user);
+        boolean maintenanceDone = isMaintenanceDoneRecently(equipment);
+
+        data.put("inspectionStatus", inspectionDone ? 1 : 0);
+        data.put("inspectionStatusText", inspectionDone ? "已完成" : "未完成");
+        data.put("maintenanceStatus", maintenanceDone ? 1 : 0);
+        data.put("maintenanceStatusText", maintenanceDone ? "已完成" : "未完成");
+        data.put("nextMaintenanceDate", calcNextMaintenanceDate(equipment));
+        data.put("canInspect", resolveInspectionRole(equipment, user) != null);
+        data.put("photoList", parsePhotoList(equipment.getEquipmentPhotos()));
+        return data;
+    }
+
+    private boolean isInspectionDoneInCurrentCycle(EquipmentArchive equipment, User user) {
+        InspectionRoleInfo roleInfo = resolveInspectionRole(equipment, user);
+        if (roleInfo == null) {
+            return true;
+        }
+        LocalDateTime cycleStart = getCycleStart(roleInfo.inspectionType);
+        QueryWrapper<EquipmentInspectionRecord> qw = new QueryWrapper<>();
+        qw.eq("equipment_id", equipment.getId());
+        qw.eq("inspection_type", roleInfo.inspectionType);
+        qw.ge("created_time", cycleStart);
+        return inspectionRecordMapper.selectCount(qw) > 0;
+    }
+
+    private boolean isMaintenanceDoneRecently(EquipmentArchive equipment) {
+        LocalDateTime monthStart = LocalDate.now().withDayOfMonth(1).atStartOfDay();
+        QueryWrapper<EquipmentMaintenanceRecord> mq = new QueryWrapper<>();
+        mq.eq("equipment_id", equipment.getId());
+        mq.ge("created_time", monthStart);
+        if (maintenanceRecordMapper.selectCount(mq) > 0) {
+            return true;
+        }
+        QueryWrapper<MaintenanceOrder> oq = new QueryWrapper<>();
+        oq.eq("equipment_id", equipment.getId());
+        oq.in("order_status", 3, 6);
+        oq.ge("actual_date", LocalDate.now().withDayOfMonth(1));
+        return maintenanceOrderMapper.selectCount(oq) > 0;
+    }
+
+    private LocalDate calcNextMaintenanceDate(EquipmentArchive equipment) {
+        QueryWrapper<MaintenanceOrder> qw = new QueryWrapper<>();
+        qw.eq("equipment_id", equipment.getId());
+        qw.in("order_status", 0, 1, 2);
+        qw.ge("planned_date", LocalDate.now());
+        qw.orderByAsc("planned_date");
+        qw.last("LIMIT 1");
+        MaintenanceOrder next = maintenanceOrderMapper.selectOne(qw);
+        if (next != null && next.getPlannedDate() != null) {
+            return next.getPlannedDate();
+        }
+        if (equipment.getFirstRunDate() != null) {
+            return equipment.getFirstRunDate().plusMonths(1);
+        }
+        return null;
+    }
+
+    private InspectionRoleInfo resolveInspectionRole(EquipmentArchive equipment, User user) {
+        if (equipment.getEquipmentNature() != null && equipment.getEquipmentNature() != 1) {
+            if (!isResponsiblePerson(equipment, user) && !isStationLeader(equipment, user)) {
+                return null;
+            }
+        }
+
+        if (isDirector(user) && equipment.getEquipmentNature() != null && equipment.getEquipmentNature() == 1) {
+            return new InspectionRoleInfo("车间主任", 3);
+        }
+        if (isStationLeader(equipment, user)) {
+            return new InspectionRoleInfo("工位长", 2);
+        }
+        if (isResponsiblePerson(equipment, user)) {
+            return new InspectionRoleInfo("责任人", 1);
+        }
+        return null;
+    }
+
+    private boolean isResponsiblePerson(EquipmentArchive equipment, User user) {
+        if (StringUtils.isNotBlank(equipment.getResponsiblePerson())
+                && equipment.getResponsiblePerson().equals(user.getName())) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isStationLeader(EquipmentArchive equipment, User user) {
+        if (equipment.getDepartmentId() == null) {
+            return false;
+        }
+        Department dept = departmentMapper.selectById(equipment.getDepartmentId());
+        return dept != null && user.getId().equals(dept.getManagerId());
+    }
+
+    private boolean isDirector(User user) {
+        return user.getRoleName() != null && user.getRoleName().contains("主任");
+    }
+
+    private String findStationLeaderName(Integer departmentId) {
+        if (departmentId == null) {
+            return "";
+        }
+        Department dept = departmentMapper.selectById(departmentId);
+        if (dept == null || StringUtils.isBlank(dept.getManagerId())) {
+            return "";
+        }
+        User manager = userMapper.selectById(dept.getManagerId());
+        return manager != null ? manager.getName() : "";
+    }
+
+    private LocalDateTime getCycleStart(int inspectionType) {
+        LocalDate today = LocalDate.now();
+        if (inspectionType == 1) {
+            return today.atStartOfDay();
+        }
+        if (inspectionType == 2) {
+            LocalDate monday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+            return monday.atStartOfDay();
+        }
+        LocalDate monthStart = today.withDayOfMonth(1);
+        if (today.getDayOfMonth() < 15) {
+            monthStart = today.minusMonths(1).withDayOfMonth(15);
+        } else {
+            monthStart = today.withDayOfMonth(15);
+        }
+        return monthStart.atStartOfDay();
+    }
+
+    private EquipmentArchive findEquipmentByCode(String code) {
+        QueryWrapper<EquipmentArchive> qw = new QueryWrapper<>();
+        qw.eq("equipment_code", code);
+        qw.eq("is_deleted", 0);
+        return equipmentArchiveMapper.selectOne(qw);
+    }
+
+    private String resolveEquipmentCode(String raw) {
+        if (StringUtils.isBlank(raw)) {
+            return null;
+        }
+        String trimmed = raw.trim();
+        if (trimmed.startsWith("{")) {
+            try {
+                JSONObject json = JSON.parseObject(trimmed);
+                if (json.containsKey("equipmentCode")) {
+                    return json.getString("equipmentCode");
+                }
+            } catch (Exception ignored) {
+            }
+        }
+        return trimmed;
+    }
+
+    private List<String> parsePhotoList(String json) {
+        if (StringUtils.isBlank(json)) {
+            return new ArrayList<>();
+        }
+        try {
+            return JSON.parseArray(json, String.class);
+        } catch (Exception e) {
+            return new ArrayList<>();
+        }
+    }
+
+    private User getLoginUser(HttpServletRequest request, HttpRespMsg msg) {
+        String token = request.getHeader("Token");
+        if (StringUtils.isBlank(token)) {
+            token = request.getHeader("TOKEN");
+        }
+        User user = userMapper.selectById(token);
+        if (user == null) {
+            msg.setError("用户未登录");
+        }
+        return user;
+    }
+
+    private static class InspectionRoleInfo {
+        final String roleName;
+        final int inspectionType;
+
+        InspectionRoleInfo(String roleName, int inspectionType) {
+            this.roleName = roleName;
+            this.inspectionType = inspectionType;
+        }
+    }
+}

+ 36 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/AnnualMaintenancePlanMapper.xml

@@ -0,0 +1,36 @@
+<?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="com.management.platform.mapper.AnnualMaintenancePlanMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.AnnualMaintenancePlan">
+        <id column="id" property="id" />
+        <result column="plan_year" property="planYear" />
+        <result column="equipment_id" property="equipmentId" />
+        <result column="equipment_code" property="equipmentCode" />
+        <result column="equipment_name" property="equipmentName" />
+        <result column="equipment_nature" property="equipmentNature" />
+        <result column="work_position" property="workPosition" />
+        <result column="month_1_level" property="month1Level" />
+        <result column="month_2_level" property="month2Level" />
+        <result column="month_3_level" property="month3Level" />
+        <result column="month_4_level" property="month4Level" />
+        <result column="month_5_level" property="month5Level" />
+        <result column="month_6_level" property="month6Level" />
+        <result column="month_7_level" property="month7Level" />
+        <result column="month_8_level" property="month8Level" />
+        <result column="month_9_level" property="month9Level" />
+        <result column="month_10_level" property="month10Level" />
+        <result column="month_11_level" property="month11Level" />
+        <result column="month_12_level" property="month12Level" />
+        <result column="plan_status" property="planStatus" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_time" property="updatedTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, plan_year, equipment_id, equipment_code, equipment_name, equipment_nature, work_position, month_1_level, month_2_level, month_3_level, month_4_level, month_5_level, month_6_level, month_7_level, month_8_level, month_9_level, month_10_level, month_11_level, month_12_level, plan_status, created_time, updated_time
+    </sql>
+
+</mapper>

+ 35 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/EquipmentArchiveMapper.xml

@@ -0,0 +1,35 @@
+<?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="com.management.platform.mapper.EquipmentArchiveMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.EquipmentArchive">
+        <id column="id" property="id" />
+        <result column="equipment_code" property="equipmentCode" />
+        <result column="equipment_name" property="equipmentName" />
+        <result column="equipment_model" property="equipmentModel" />
+        <result column="factory_number" property="factoryNumber" />
+        <result column="equipment_nature" property="equipmentNature" />
+        <result column="work_position" property="workPosition" />
+        <result column="responsible_person" property="responsiblePerson" />
+        <result column="responsible_user_id" property="responsibleUserId" />
+        <result column="equipment_status" property="equipmentStatus" />
+        <result column="first_run_date" property="firstRunDate" />
+        <result column="equipment_photos" property="equipmentPhotos" />
+        <result column="qr_code_url" property="qrCodeUrl" />
+        <result column="contract_files" property="contractFiles" />
+        <result column="invoice_files" property="invoiceFiles" />
+        <result column="remark" property="remark" />
+        <result column="created_by" property="createdBy" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_by" property="updatedBy" />
+        <result column="updated_time" property="updatedTime" />
+        <result column="is_deleted" property="isDeleted" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, equipment_code, equipment_name, equipment_model, factory_number, equipment_nature, work_position, responsible_person, responsible_user_id, equipment_status, first_run_date, equipment_photos, qr_code_url, contract_files, invoice_files, remark, created_by, created_time, updated_by, updated_time, is_deleted
+    </sql>
+
+</mapper>

+ 19 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/InspectionLibraryMapper.xml

@@ -0,0 +1,19 @@
+<?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="com.management.platform.mapper.InspectionLibraryMapper">
+
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.InspectionLibrary">
+        <id column="id" property="id" />
+        <result column="inspection_name" property="inspectionName" />
+        <result column="inspection_detail" property="inspectionDetail" />
+        <result column="sort_order" property="sortOrder" />
+        <result column="is_enabled" property="isEnabled" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_time" property="updatedTime" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id, inspection_name, inspection_detail, sort_order, is_enabled, created_time, updated_time
+    </sql>
+
+</mapper>

+ 20 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceCycleConfigMapper.xml

@@ -0,0 +1,20 @@
+<?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="com.management.platform.mapper.MaintenanceCycleConfigMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.MaintenanceCycleConfig">
+        <id column="id" property="id" />
+        <result column="equipment_nature" property="equipmentNature" />
+        <result column="level1_cycle_months" property="level1CycleMonths" />
+        <result column="level2_cycle_months" property="level2CycleMonths" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_time" property="updatedTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, equipment_nature, level1_cycle_months, level2_cycle_months, created_time, updated_time
+    </sql>
+
+</mapper>

+ 34 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceIssueMapper.xml

@@ -0,0 +1,34 @@
+<?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="com.management.platform.mapper.MaintenanceIssueMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.MaintenanceIssue">
+        <id column="id" property="id" />
+        <result column="issue_no" property="issueNo" />
+        <result column="order_id" property="orderId" />
+        <result column="equipment_id" property="equipmentId" />
+        <result column="equipment_code" property="equipmentCode" />
+        <result column="issue_description" property="issueDescription" />
+        <result column="issue_photos" property="issuePhotos" />
+        <result column="reporter_user_id" property="reporterUserId" />
+        <result column="reporter_name" property="reporterName" />
+        <result column="report_time" property="reportTime" />
+        <result column="assigned_user_id" property="assignedUserId" />
+        <result column="assigned_user_name" property="assignedUserName" />
+        <result column="assign_time" property="assignTime" />
+        <result column="handler_user_id" property="handlerUserId" />
+        <result column="handler_name" property="handlerName" />
+        <result column="handle_time" property="handleTime" />
+        <result column="handle_result" property="handleResult" />
+        <result column="issue_status" property="issueStatus" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_time" property="updatedTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, issue_no, order_id, equipment_id, equipment_code, issue_description, issue_photos, reporter_user_id, reporter_name, report_time, assigned_user_id, assigned_user_name, assign_time, handler_user_id, handler_name, handle_time, handle_result, issue_status, created_time, updated_time
+    </sql>
+
+</mapper>

+ 21 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceOrderDetailMapper.xml

@@ -0,0 +1,21 @@
+<?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="com.management.platform.mapper.MaintenanceOrderDetailMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.MaintenanceOrderDetail">
+        <id column="id" property="id" />
+        <result column="order_id" property="orderId" />
+        <result column="library_id" property="libraryId" />
+        <result column="maintenance_part" property="maintenancePart" />
+        <result column="maintenance_content" property="maintenanceContent" />
+        <result column="is_checked" property="isChecked" />
+        <result column="sort_order" property="sortOrder" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, order_id, library_id, maintenance_part, maintenance_content, is_checked, sort_order
+    </sql>
+
+</mapper>

+ 33 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/MaintenanceOrderMapper.xml

@@ -0,0 +1,33 @@
+<?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="com.management.platform.mapper.MaintenanceOrderMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.MaintenanceOrder">
+        <id column="id" property="id" />
+        <result column="order_no" property="orderNo" />
+        <result column="plan_id" property="planId" />
+        <result column="equipment_id" property="equipmentId" />
+        <result column="equipment_code" property="equipmentCode" />
+        <result column="equipment_name" property="equipmentName" />
+        <result column="work_position" property="workPosition" />
+        <result column="maintenance_level" property="maintenanceLevel" />
+        <result column="planned_date" property="plannedDate" />
+        <result column="actual_date" property="actualDate" />
+        <result column="maintenance_user_id" property="maintenanceUserId" />
+        <result column="maintenance_user_name" property="maintenanceUserName" />
+        <result column="operator_user_id" property="operatorUserId" />
+        <result column="operator_user_name" property="operatorUserName" />
+        <result column="order_status" property="orderStatus" />
+        <result column="inspection_result" property="inspectionResult" />
+        <result column="operator_evaluation" property="operatorEvaluation" />
+        <result column="created_time" property="createdTime" />
+        <result column="updated_time" property="updatedTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, order_no, plan_id, equipment_id, equipment_code, equipment_name, work_position, maintenance_level, planned_date, actual_date, maintenance_user_id, maintenance_user_name, operator_user_id, operator_user_name, order_status, inspection_result, operator_evaluation, created_time, updated_time
+    </sql>
+
+</mapper>

+ 30 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/router/index.js

@@ -119,6 +119,36 @@ const router = new Router({
             title: "加班申请",
             keepAlive: false
         }
+    },
+    {
+        path: "/equipment/list",
+        component: () => import("@/views/equipment/list"),
+        meta: { title: "设备点检" }
+    },
+    {
+        path: "/equipment/detail",
+        component: () => import("@/views/equipment/detail"),
+        meta: { title: "设备详情" }
+    },
+    {
+        path: "/equipment/inspection",
+        component: () => import("@/views/equipment/inspection"),
+        meta: { title: "点检单" }
+    },
+    {
+        path: "/equipment/maintenance",
+        component: () => import("@/views/equipment/maintenance"),
+        meta: { title: "保养单" }
+    },
+    {
+        path: "/equipment/maintenance-records",
+        component: () => import("@/views/equipment/maintenanceRecords"),
+        meta: { title: "保养记录" }
+    },
+    {
+        path: "/equipment/transfer-records",
+        component: () => import("@/views/equipment/transferRecords"),
+        meta: { title: "转移记录" }
     },
      {
         path: "/MemberInfo",

+ 172 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/detail.vue

@@ -0,0 +1,172 @@
+<template>
+  <div class="equipment-detail">
+    <van-nav-bar title="设备详情" left-arrow fixed @click-left="$router.go(-1)" />
+
+    <div class="search-bar">
+      <van-field v-model="keyword" placeholder="设备编号" clearable @keyup.enter="searchEquipment" />
+      <div class="scan-btn" @click="scanCode">
+        <van-icon name="photograph" size="24" />
+      </div>
+    </div>
+
+    <van-cell-group v-if="detail">
+      <van-cell title="点检状态">
+        <template #default>
+          <span :class="detail.inspectionStatus === 1 ? 'status-ok' : 'status-warn'">
+            <van-icon :name="detail.inspectionStatus === 1 ? 'passed' : 'warning-o'" />
+            {{ detail.inspectionStatusText }}
+          </span>
+        </template>
+      </van-cell>
+      <van-cell title="保养状态">
+        <template #default>
+          <span :class="detail.maintenanceStatus === 1 ? 'status-ok' : 'status-warn'">
+            <van-icon :name="detail.maintenanceStatus === 1 ? 'passed' : 'warning-o'" />
+            {{ detail.maintenanceStatusText }}
+          </span>
+        </template>
+      </van-cell>
+      <van-cell title="设备编号" :value="detail.equipmentCode" />
+      <van-cell title="设备名称" :value="detail.equipmentName" />
+      <van-cell title="设备型号" :value="detail.equipmentModel || '-'" />
+      <van-cell title="工位" :value="detail.workPosition || '-'" />
+      <van-cell title="责任人" :value="detail.responsiblePerson || '-'" />
+      <van-cell title="下次保养时间" :value="detail.nextMaintenanceDate || '-'" />
+      <van-cell title="保养记录" is-link @click="goRecords('maintenance')" />
+      <van-cell title="转移记录" is-link @click="goRecords('transfer')" />
+    </van-cell-group>
+
+    <div class="photo-wrap" v-if="photoUrl">
+      <van-image width="200" height="200" fit="contain" :src="photoUrl" />
+    </div>
+
+    <div class="action-bar">
+      <van-button round block type="info" @click="goInspection">设备点检</van-button>
+      <van-button round block type="primary" @click="goMaintenance">设备保养</van-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import wx from "weixin-js-sdk";
+
+export default {
+  name: "EquipmentDetail",
+  data() {
+    return {
+      keyword: "",
+      detail: null,
+      equipmentId: null,
+      isCorpWX: false,
+      isWX: false
+    };
+  },
+  computed: {
+    photoUrl() {
+      if (!this.detail || !this.detail.photoList || !this.detail.photoList.length) return "";
+      return "/upload/" + this.detail.photoList[0];
+    }
+  },
+  created() {
+    const ua = navigator.userAgent.toLowerCase();
+    this.isCorpWX = ua.indexOf("wxwork") > 0;
+    this.isWX = ua.indexOf("micromessenger") > 0;
+    this.equipmentId = this.$route.query.id;
+    if (this.equipmentId) {
+      this.loadDetail();
+    }
+  },
+  methods: {
+    loadDetail() {
+      this.$axios.post("/mobile-equipment/detail", { equipmentId: this.equipmentId })
+        .then(res => {
+          if (res.code === "ok") {
+            this.detail = res.data;
+            this.keyword = res.data.equipmentCode || "";
+          } else {
+            this.$toast.fail(res.msg || "加载失败");
+          }
+        });
+    },
+    searchEquipment() {
+      if (!this.keyword.trim()) return;
+      this.$axios.post("/mobile-equipment/getByCode", { equipmentCode: this.keyword.trim() })
+        .then(res => {
+          if (res.code === "ok" && res.data) {
+            this.equipmentId = res.data.id;
+            this.detail = res.data;
+          } else {
+            this.$toast.fail(res.msg || "未找到设备");
+          }
+        });
+    },
+    scanCode() {
+      const that = this;
+      if ((this.isCorpWX || this.isWX) && wx) {
+        wx.scanQRCode({
+          needResult: 1,
+          scanType: ["qrCode", "barCode"],
+          success(res) {
+            that.keyword = res.resultStr;
+            that.searchEquipment();
+          }
+        });
+      } else {
+        this.$toast("请手动输入设备编号");
+      }
+    },
+    goInspection() {
+      this.$router.push({ path: "/equipment/inspection", query: { id: this.equipmentId } });
+    },
+    goMaintenance() {
+      this.$router.push({ path: "/equipment/maintenance", query: { id: this.equipmentId } });
+    },
+    goRecords(type) {
+      const path = type === "transfer" ? "/equipment/transfer-records" : "/equipment/maintenance-records";
+      this.$router.push({ path, query: { id: this.equipmentId } });
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.equipment-detail {
+  padding-top: 46px;
+  padding-bottom: 80px;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+.search-bar {
+  display: flex;
+  align-items: center;
+  padding: 12px 16px;
+  background: #fff;
+  margin-bottom: 10px;
+  .van-field { flex: 1; background: #f7f8fa; border-radius: 4px; padding: 4px 12px; }
+  .scan-btn {
+    margin-left: 12px;
+    width: 44px; height: 44px;
+    border: 1px solid #ddd; border-radius: 4px;
+    display: flex; align-items: center; justify-content: center;
+  }
+}
+.status-ok { color: #07c160; }
+.status-warn { color: #ee0a24; }
+.photo-wrap {
+  margin: 16px;
+  text-align: center;
+  background: #fff;
+  padding: 16px;
+  border-radius: 8px;
+}
+.action-bar {
+  position: fixed;
+  bottom: 0; left: 0; right: 0;
+  display: flex;
+  gap: 12px;
+  padding: 12px 16px;
+  background: #fff;
+  box-shadow: 0 -2px 8px rgba(0,0,0,0.06);
+  .van-button { flex: 1; }
+}
+</style>

+ 177 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/inspection.vue

@@ -0,0 +1,177 @@
+<template>
+  <div class="inspection-form">
+    <van-nav-bar title="点检单" left-arrow fixed @click-left="$router.go(-1)" />
+
+    <div class="header-info" v-if="formData">
+      <span>{{ formData.equipmentCode }}</span>
+      <span>{{ formData.equipmentName }}</span>
+    </div>
+
+    <div class="form-body" v-if="formData">
+      <div class="item-block" v-for="(item, index) in items" :key="item.id">
+        <div class="item-title">{{ index + 1 }}. {{ item.inspectionName }}</div>
+        <div class="item-detail">{{ item.inspectionDetail }}</div>
+        <div class="item-label">检查结果</div>
+        <van-radio-group v-model="item.checkResult" direction="horizontal">
+          <van-radio :name="1">良好</van-radio>
+          <van-radio :name="2">异常</van-radio>
+          <van-radio :name="3">休息</van-radio>
+        </van-radio-group>
+      </div>
+
+      <div class="photo-section">
+        <div class="section-title">点检照片</div>
+        <van-uploader v-model="photoList" :max-count="1" :after-read="afterRead" />
+      </div>
+
+      <van-cell-group>
+        <van-cell title="日期" :value="currentTime" />
+        <van-cell title="点检人" :value="formData.inspectorName" />
+        <van-cell title="工位长" :value="formData.stationLeaderName || '-'" />
+      </van-cell-group>
+    </div>
+
+    <div class="submit-bar">
+      <van-button round block type="info" :loading="submitting" @click="submit">完成点检</van-button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "EquipmentInspection",
+  data() {
+    return {
+      equipmentId: null,
+      formData: null,
+      items: [],
+      photoList: [],
+      photoUrl: "",
+      submitting: false,
+      currentTime: ""
+    };
+  },
+  created() {
+    this.equipmentId = this.$route.query.id;
+    this.currentTime = this.formatNow();
+    this.loadForm();
+  },
+  methods: {
+    loadForm() {
+      this.$axios.post("/mobile-equipment/inspectionForm", { equipmentId: this.equipmentId })
+        .then(res => {
+          if (res.code === "ok") {
+            this.formData = res.data;
+            this.items = (res.data.items || []).map(item => ({
+              ...item,
+              checkResult: 1
+            }));
+          } else {
+            this.$toast.fail(res.msg || "无法加载点检单");
+            setTimeout(() => this.$router.go(-1), 1500);
+          }
+        });
+    },
+    afterRead(file) {
+      const formData = new FormData();
+      formData.append("multipartFile", file.file);
+      this.$axios.post("/common/uploadFile", formData)
+        .then(res => {
+          if (res.code === "ok") {
+            this.photoUrl = res.data;
+          } else {
+            this.$toast.fail(res.msg || "上传失败");
+            this.photoList = [];
+          }
+        })
+        .catch(() => {
+          this.$toast.fail("上传失败");
+          this.photoList = [];
+        });
+    },
+    submit() {
+      if (!this.photoUrl) {
+        this.$toast.fail("请上传点检照片");
+        return;
+      }
+      const unfinished = this.items.find(i => !i.checkResult);
+      if (unfinished) {
+        this.$toast.fail("请完成所有点检项");
+        return;
+      }
+      const detailList = this.items.map(item => ({
+        libraryId: item.id,
+        inspectionName: item.inspectionName,
+        inspectionDetail: item.inspectionDetail,
+        checkResult: item.checkResult
+      }));
+
+      this.submitting = true;
+      this.$axios.post("/mobile-equipment/submitInspection", {
+        equipmentId: this.equipmentId,
+        detailListJson: JSON.stringify(detailList),
+        photoUrl: this.photoUrl
+      }).then(res => {
+        this.submitting = false;
+        if (res.code === "ok") {
+          this.$toast.success("点检完成");
+          this.$router.replace({ path: "/equipment/detail", query: { id: this.equipmentId } });
+        } else {
+          this.$toast.fail(res.msg || "提交失败");
+        }
+      }).catch(() => {
+        this.submitting = false;
+        this.$toast.fail("提交失败");
+      });
+    },
+    formatNow() {
+      const d = new Date();
+      const y = d.getFullYear();
+      const m = String(d.getMonth() + 1).padStart(2, "0");
+      const day = String(d.getDate()).padStart(2, "0");
+      const h = String(d.getHours()).padStart(2, "0");
+      const mi = String(d.getMinutes()).padStart(2, "0");
+      return `${y}-${m}-${day} ${h}:${mi}`;
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.inspection-form {
+  padding-top: 46px;
+  padding-bottom: 80px;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+.header-info {
+  display: flex;
+  justify-content: space-between;
+  padding: 12px 16px;
+  background: #fff;
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 10px;
+}
+.form-body { padding: 0 0 16px; }
+.item-block {
+  background: #fff;
+  padding: 16px;
+  margin-bottom: 10px;
+  .item-title { font-size: 15px; font-weight: 500; margin-bottom: 8px; }
+  .item-detail { font-size: 13px; color: #666; margin-bottom: 12px; line-height: 1.5; }
+  .item-label { font-size: 13px; color: #999; margin-bottom: 8px; }
+}
+.photo-section {
+  background: #fff;
+  padding: 16px;
+  margin-bottom: 10px;
+  .section-title { font-size: 14px; margin-bottom: 12px; }
+}
+.submit-bar {
+  position: fixed;
+  bottom: 0; left: 0; right: 0;
+  padding: 12px 16px;
+  background: #fff;
+}
+</style>

+ 187 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/list.vue

@@ -0,0 +1,187 @@
+<template>
+  <div class="equipment-list">
+    <van-nav-bar title="设备点检" left-arrow fixed @click-left="$router.push('/index')" />
+
+    <div class="search-bar">
+      <van-field
+        v-model="keyword"
+        placeholder="设备编号"
+        clearable
+        @keyup.enter="searchEquipment"
+      />
+      <div class="scan-btn" @click="scanCode">
+        <van-icon name="photograph" size="24" />
+      </div>
+    </div>
+
+    <div class="history-title" v-if="historyList.length">近期维保记录</div>
+
+    <van-empty v-if="!loading && historyList.length === 0" description="暂无维保记录,请先完成设备点检或保养" />
+
+    <div class="history-list" v-else>
+      <div
+        class="history-item"
+        v-for="(item, index) in historyList"
+        :key="index"
+        @click="goDetail(item.equipmentId)"
+      >
+        <div class="row-top">
+          <span class="time">{{ formatTime(item.recordTime) }}</span>
+          <span :class="['result', item.resultStatus === 1 ? 'pass' : 'fail']">
+            {{ item.resultText }}
+          </span>
+        </div>
+        <div class="row-bottom">
+          <span class="code">{{ item.equipmentCode }}</span>
+          <span class="level">{{ item.maintenanceLevelText }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import wx from "weixin-js-sdk";
+
+export default {
+  name: "EquipmentList",
+  data() {
+    return {
+      keyword: "",
+      historyList: [],
+      loading: false,
+      isCorpWX: false,
+      isWX: false
+    };
+  },
+  created() {
+    const ua = navigator.userAgent.toLowerCase();
+    this.isCorpWX = ua.indexOf("wxwork") > 0;
+    this.isWX = ua.indexOf("micromessenger") > 0;
+    this.loadHistory();
+  },
+  methods: {
+    loadHistory() {
+      this.loading = true;
+      this.$axios.post("/mobile-equipment/recentHistory", { pageIndex: 1, pageSize: 50 })
+        .then(res => {
+          if (res.code === "ok") {
+            this.historyList = (res.data && res.data.data) || [];
+          }
+        })
+        .finally(() => { this.loading = false; });
+    },
+    searchEquipment() {
+      if (!this.keyword.trim()) {
+        this.$toast.fail("请输入设备编号");
+        return;
+      }
+      this.lookupEquipment(this.keyword.trim());
+    },
+    lookupEquipment(code) {
+      const toast = this.$toast.loading({ forbidClick: true, duration: 0 });
+      this.$axios.post("/mobile-equipment/getByCode", { equipmentCode: code })
+        .then(res => {
+          this.$toast.clear();
+          if (res.code === "ok" && res.data) {
+            this.$router.push({ path: "/equipment/detail", query: { id: res.data.id } });
+          } else {
+            this.$toast.fail(res.msg || "未找到设备");
+          }
+        })
+        .catch(() => { this.$toast.clear(); this.$toast.fail("查询失败"); });
+    },
+    scanCode() {
+      const that = this;
+      if ((this.isCorpWX || this.isWX) && wx) {
+        wx.scanQRCode({
+          needResult: 1,
+          scanType: ["qrCode", "barCode"],
+          success(res) {
+            that.lookupEquipment(res.resultStr);
+          },
+          fail() {
+            that.$toast.fail("扫码失败,请手动输入设备编号");
+          }
+        });
+      } else {
+        this.$toast("当前环境不支持扫码,请手动输入设备编号");
+      }
+    },
+    goDetail(equipmentId) {
+      if (equipmentId) {
+        this.$router.push({ path: "/equipment/detail", query: { id: equipmentId } });
+      }
+    },
+    formatTime(time) {
+      if (!time) return "";
+      const d = new Date(time);
+      const mm = String(d.getMonth() + 1).padStart(2, "0");
+      const dd = String(d.getDate()).padStart(2, "0");
+      const hh = String(d.getHours()).padStart(2, "0");
+      const mi = String(d.getMinutes()).padStart(2, "0");
+      return `${mm}-${dd} ${hh}:${mi}`;
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.equipment-list {
+  padding-top: 46px;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+.search-bar {
+  display: flex;
+  align-items: center;
+  padding: 12px 16px;
+  background: #fff;
+  .van-field {
+    flex: 1;
+    background: #f7f8fa;
+    border-radius: 4px;
+    padding: 4px 12px;
+  }
+  .scan-btn {
+    margin-left: 12px;
+    width: 44px;
+    height: 44px;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: #fff;
+  }
+}
+.history-title {
+  padding: 16px 16px 8px;
+  font-size: 14px;
+  color: #666;
+}
+.history-list {
+  padding: 0 16px 16px;
+}
+.history-item {
+  background: #fff;
+  border-radius: 8px;
+  padding: 12px 16px;
+  margin-bottom: 10px;
+  .row-top, .row-bottom {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  .row-bottom {
+    margin-top: 8px;
+    color: #666;
+    font-size: 13px;
+  }
+  .time { font-size: 14px; color: #333; }
+  .result.pass { color: #07c160; }
+  .result.fail { color: #ee0a24; }
+  .code { font-weight: 500; }
+  .level { color: #999; }
+}
+</style>

+ 188 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/maintenance.vue

@@ -0,0 +1,188 @@
+<template>
+  <div class="maintenance-form">
+    <van-nav-bar title="保养单" left-arrow fixed @click-left="$router.go(-1)" />
+
+    <div class="header-info" v-if="formData">
+      <span>{{ formData.equipmentCode }}</span>
+      <span>{{ formData.equipmentName }}</span>
+    </div>
+
+    <div class="form-body" v-if="formData">
+      <van-cell title="保养级别" is-link :value="levelText" @click="showLevelPicker = true" />
+
+      <div class="part-group" v-for="(items, partName) in partGroups" :key="partName">
+        <div class="part-title">{{ partName }}</div>
+        <van-checkbox-group v-model="checkedIds">
+          <div class="check-item" v-for="item in items" :key="item.id">
+            <van-checkbox :name="item.id" shape="square">
+              {{ item.sortOrder }}. {{ item.maintenanceContent }}
+            </van-checkbox>
+          </div>
+        </van-checkbox-group>
+      </div>
+
+      <div class="option-section">
+        <div class="option-title">保养后设备状态</div>
+        <van-radio-group v-model="inspectionResult" direction="horizontal">
+          <van-radio :name="1">良好</van-radio>
+          <van-radio :name="2">不良</van-radio>
+        </van-radio-group>
+      </div>
+
+      <div class="option-section">
+        <div class="option-title">设备工位检查评语</div>
+        <van-radio-group v-model="operatorEvaluation" direction="horizontal">
+          <van-radio :name="1">满意</van-radio>
+          <van-radio :name="2">不满意</van-radio>
+        </van-radio-group>
+      </div>
+
+      <van-cell-group>
+        <van-cell title="维修员" :value="formData.maintenanceUserName" />
+        <van-cell title="操作员" :value="formData.operatorUserName || '-'" />
+      </van-cell-group>
+    </div>
+
+    <van-popup v-model="showLevelPicker" position="bottom">
+      <van-picker
+        show-toolbar
+        :columns="levelColumns"
+        @confirm="onLevelConfirm"
+        @cancel="showLevelPicker = false"
+      />
+    </van-popup>
+
+    <div class="submit-bar">
+      <van-button round block type="info" :loading="submitting" @click="submit">完成保养</van-button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "EquipmentMaintenance",
+  data() {
+    return {
+      equipmentId: null,
+      formData: null,
+      partGroups: {},
+      checkedIds: [],
+      maintenanceLevel: 1,
+      inspectionResult: 1,
+      operatorEvaluation: 1,
+      showLevelPicker: false,
+      levelColumns: ["一级保养", "二级保养"],
+      submitting: false
+    };
+  },
+  computed: {
+    levelText() {
+      return this.maintenanceLevel === 2 ? "二级保养" : "一级保养";
+    }
+  },
+  created() {
+    this.equipmentId = this.$route.query.id;
+    this.loadForm();
+  },
+  methods: {
+    loadForm() {
+      this.$axios.post("/mobile-equipment/maintenanceForm", {
+        equipmentId: this.equipmentId,
+        maintenanceLevel: this.maintenanceLevel
+      }).then(res => {
+        if (res.code === "ok") {
+          this.formData = res.data;
+          this.partGroups = res.data.partGroups || {};
+          this.checkedIds = [];
+        } else {
+          this.$toast.fail(res.msg || "加载失败");
+        }
+      });
+    },
+    onLevelConfirm(value, index) {
+      this.maintenanceLevel = index + 1;
+      this.showLevelPicker = false;
+      this.loadForm();
+    },
+    submit() {
+      const detailList = [];
+      Object.keys(this.partGroups).forEach(partName => {
+        this.partGroups[partName].forEach(item => {
+          detailList.push({
+            libraryId: item.id,
+            maintenancePart: partName,
+            maintenanceContent: item.maintenanceContent,
+            isChecked: this.checkedIds.includes(item.id) ? 1 : 0
+          });
+        });
+      });
+
+      this.submitting = true;
+      this.$axios.post("/mobile-equipment/submitMaintenance", {
+        equipmentId: this.equipmentId,
+        maintenanceLevel: this.maintenanceLevel,
+        inspectionResult: this.inspectionResult,
+        operatorEvaluation: this.operatorEvaluation,
+        detailListJson: JSON.stringify(detailList)
+      }).then(res => {
+        this.submitting = false;
+        if (res.code === "ok") {
+          this.$toast.success("保养完成");
+          this.$router.replace({ path: "/equipment/detail", query: { id: this.equipmentId } });
+        } else {
+          this.$toast.fail(res.msg || "提交失败");
+        }
+      }).catch(() => {
+        this.submitting = false;
+        this.$toast.fail("提交失败");
+      });
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.maintenance-form {
+  padding-top: 46px;
+  padding-bottom: 80px;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+.header-info {
+  display: flex;
+  justify-content: space-between;
+  padding: 12px 16px;
+  background: #fff;
+  font-weight: 500;
+  margin-bottom: 10px;
+}
+.part-group {
+  background: #fff;
+  padding: 16px;
+  margin-bottom: 10px;
+  .part-title {
+    font-size: 15px;
+    font-weight: 500;
+    margin-bottom: 12px;
+    padding-bottom: 8px;
+    border-bottom: 1px solid #eee;
+  }
+  .check-item {
+    margin-bottom: 12px;
+    font-size: 13px;
+    line-height: 1.5;
+  }
+}
+.option-section {
+  background: #fff;
+  padding: 16px;
+  margin-bottom: 10px;
+  .option-title { font-size: 14px; margin-bottom: 12px; }
+}
+.submit-bar {
+  position: fixed;
+  bottom: 0; left: 0; right: 0;
+  padding: 12px 16px;
+  background: #fff;
+}
+</style>

+ 62 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/maintenanceRecords.vue

@@ -0,0 +1,62 @@
+<template>
+  <div class="record-page">
+    <van-nav-bar title="保养记录" left-arrow fixed @click-left="$router.go(-1)" />
+    <van-empty v-if="!loading && records.length === 0" description="暂无保养记录" />
+    <van-cell-group v-else>
+      <van-cell
+        v-for="(item, index) in records"
+        :key="index"
+        :title="formatTime(item.createdTime || item.plannedDate)"
+        :label="item.maintenanceUserName || item.maintenanceUserName"
+        :value="levelText(item)"
+      />
+    </van-cell-group>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "MaintenanceRecords",
+  data() {
+    return {
+      equipmentId: null,
+      records: [],
+      loading: false
+    };
+  },
+  created() {
+    this.equipmentId = this.$route.query.id;
+    this.loadRecords();
+  },
+  methods: {
+    loadRecords() {
+      this.loading = true;
+      this.$axios.post("/mobile-equipment/maintenanceRecords", { equipmentId: this.equipmentId })
+        .then(res => {
+          if (res.code === "ok") {
+            const mobile = res.data.mobileRecords || [];
+            const plan = res.data.planRecords || [];
+            this.records = [...mobile, ...plan];
+          }
+        })
+        .finally(() => { this.loading = false; });
+    },
+    formatTime(time) {
+      if (!time) return "";
+      return String(time).replace("T", " ").substring(0, 16);
+    },
+    levelText(item) {
+      const level = item.maintenanceLevel;
+      return level === 2 ? "二级保养" : "一级保养";
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.record-page {
+  padding-top: 46px;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+</style>

+ 56 - 0
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/equipment/transferRecords.vue

@@ -0,0 +1,56 @@
+<template>
+  <div class="record-page">
+    <van-nav-bar title="转移记录" left-arrow fixed @click-left="$router.go(-1)" />
+    <van-empty v-if="!loading && records.length === 0" description="暂无转移记录" />
+    <van-cell-group v-else>
+      <van-cell
+        v-for="(item, index) in records"
+        :key="index"
+        :title="formatTime(item.transferTime)"
+        :label="`${item.fromPosition || '-'} → ${item.toPosition || '-'}`"
+        :value="item.transferType || '调拨'"
+      />
+    </van-cell-group>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "TransferRecords",
+  data() {
+    return {
+      equipmentId: null,
+      records: [],
+      loading: false
+    };
+  },
+  created() {
+    this.equipmentId = this.$route.query.id;
+    this.loadRecords();
+  },
+  methods: {
+    loadRecords() {
+      this.loading = true;
+      this.$axios.post("/mobile-equipment/transferRecords", { equipmentId: this.equipmentId })
+        .then(res => {
+          if (res.code === "ok") {
+            this.records = res.data || [];
+          }
+        })
+        .finally(() => { this.loading = false; });
+    },
+    formatTime(time) {
+      if (!time) return "";
+      return String(time).replace("T", " ").substring(0, 16);
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.record-page {
+  padding-top: 46px;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+</style>

+ 8 - 1
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/index/index.vue

@@ -250,6 +250,13 @@ export default {
                 url: '/overtimeApplication',
                 icon: 'balance-list-o'
               },
+              {
+                name: '设备点检',
+                moudelName: '设备点检',
+                url: '/equipment/list',
+                icon: 'setting-o',
+                fixed: true
+              },
 
             ]
             console.log(routersList, modelNameList)
@@ -277,7 +284,7 @@ export default {
                         timestamp: res.data.timestamp, // 必填,生成签名的时间戳 
                         nonceStr: res.data.noncestr, // 必填,生成签名的随机串 
                         signature: res.data.sign, // 必填,签名,见附录1 
-                        jsApiList: ['chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'previewFile', 'getLocation', 'agentConfig']
+                        jsApiList: ['chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'previewFile', 'getLocation', 'agentConfig', 'scanQRCode']
                     })
                     let that = this
                     wx.ready(function () {

+ 6 - 2
fhKeeper/formulahousekeeper/timesheet-workshop-h5/vue.config.js

@@ -8,7 +8,7 @@ const Timestamp = new Date().getTime();
 // var ip = '47.100.37.243'
 //var ip = '192.168.2.12'
 //var ip = '192.168.2.12'
-//  var ip = '127.0.0.1'
+ var ip = '127.0.0.1'
 
 
 var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
@@ -62,13 +62,17 @@ module.exports = {
         proxy: {
             // 只要请求地址有'api'都会匹配上
             "/api": {
-                target: "http://"+ip+":10010",
+                target: "http://"+ip+":10090",
                 ws: true,
                 // 允许跨域
                 changeOrigin: true,
                 pathRewrite: {
                     "^/api": "" //通过pathRewrite重写地址,将前缀/api转为/
                 }
+            },
+            "/upload": {
+                target: "http://"+ip+":10090",
+                changeOrigin: true
             }
         }
     },

+ 20 - 0
fhKeeper/formulahousekeeper/timesheet-workshop/src/routes.js

@@ -51,6 +51,12 @@ import attendanceCalendar from './views/attendanceCalendar/index.vue'
 import applyOvertime from './views/workOvertime/apply.vue'
 import applyOvertimeList from './views/workOvertime/applyList.vue'
 
+// 设备维保管理
+import equipmentArchive from './views/equipment/archive.vue'
+import equipmentMaintenanceLibrary from './views/equipment/maintenance-library.vue'
+import equipmentPlan from './views/equipment/plan.vue'
+import equipmentInspection from './views/equipment/inspection.vue'
+
 Vue.use(Router)
 
 export const fixedRouter = [
@@ -149,6 +155,20 @@ export const allRouters = [
         ],
     },
 
+    {
+        path: '/equipment',
+        component: Home,
+        name: '设备维保管理',
+        iconCls: 'iconfont firerock-iconjianzhugongchenglei',
+        leaf: false,
+        children: [
+            { path: '/equipment/archive', component: equipmentArchive, name: '设备档案管理' },
+            { path: '/equipment/maintenance-library', component: equipmentMaintenanceLibrary, name: '保养库管理' },
+            { path: '/equipment/inspection', component: equipmentInspection, name: '点检库管理' },
+            { path: '/equipment/plan', component: equipmentPlan, name: '保养计划管理' },
+        ],
+    },
+
     {
         path: '/',
         component: Home,

File diff suppressed because it is too large
+ 1058 - 0
fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/archive.vue


+ 217 - 0
fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/inspection.vue

@@ -0,0 +1,217 @@
+<template>
+  <div class="inspection-library">
+    <el-card class="filter-card">
+      <el-form :inline="true">
+        <el-form-item label="点检库列表"></el-form-item>
+        <el-form-item>
+          <el-input v-model="filters.keyword" placeholder="点检项名称/明细" style="width:180px" clearable></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="searchList">搜索</el-button>
+        </el-form-item>
+        <el-form-item style="float:right">
+          <el-button type="primary" size="small" @click="handleAdd">新增</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="table-card">
+      <el-table ref="inspectionTable" :data="list" v-loading="listLoading" :height="tableHeight" border class="inspection-table">
+        <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
+        <el-table-column prop="inspectionName" label="点检项名称" width="200" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="inspectionDetail" label="点检明细" min-width="320" show-overflow-tooltip></el-table-column>
+        <el-table-column label="操作" width="150" fixed="right" align="center" class-name="action-column">
+          <template slot-scope="scope">
+            <div class="table-action-cell">
+              <el-button type="text" size="small" @click="handleEdit(scope.row)">编辑</el-button>
+              <el-button type="text" size="small" style="color:#f56c6c" @click="handleDelete(scope.row)">删除</el-button>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="pageIndex"
+          :page-sizes="[20,50,80,100]"
+          :page-size="pageSize"
+          layout="total,sizes,prev,pager,next"
+          :total="total">
+        </el-pagination>
+      </div>
+    </el-card>
+
+    <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="560px">
+      <el-form ref="inspectionForm" :model="form" :rules="formRules" label-width="100px">
+        <el-form-item label="点检项名称" prop="inspectionName">
+          <el-input v-model="form.inspectionName" placeholder="例如:机器润滑"></el-input>
+        </el-form-item>
+        <el-form-item label="点检明细" prop="inspectionDetail">
+          <el-input v-model="form.inspectionDetail" type="textarea" :rows="4" placeholder="请输入点检明细"></el-input>
+        </el-form-item>
+        <el-form-item label="排序号">
+          <el-input-number v-model="form.sortOrder" :min="0" :max="9999" controls-position="right" style="width:100%"></el-input-number>
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="dialogVisible=false">取消</el-button>
+        <el-button type="primary" @click="submitForm" :loading="submitLoading">保存</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'InspectionLibrary',
+  data() {
+    return {
+      filters: { keyword: '' },
+      list: [],
+      total: 0,
+      pageIndex: 1,
+      pageSize: 20,
+      listLoading: false,
+      tableHeight: 500,
+      dialogVisible: false,
+      dialogTitle: '新增点检项',
+      form: {},
+      formRules: {
+        inspectionName: [{ required: true, message: '请输入点检项名称', trigger: 'blur' }],
+        inspectionDetail: [{ required: true, message: '请输入点检明细', trigger: 'blur' }],
+      },
+      submitLoading: false,
+    };
+  },
+  mounted() {
+    this.calcTableHeight();
+    this.getList();
+    window.addEventListener('resize', this.calcTableHeight);
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.calcTableHeight);
+  },
+  methods: {
+    calcTableHeight() {
+      this.tableHeight = window.innerHeight - 270;
+      this.$nextTick(() => {
+        this.$refs.inspectionTable && this.$refs.inspectionTable.doLayout();
+      });
+    },
+
+    getList() {
+      this.listLoading = true;
+      this.http.post('/inspection-library/list', {
+        pageIndex: this.pageIndex,
+        pageSize: this.pageSize,
+        keyword: this.filters.keyword || null,
+      }, res => {
+        this.listLoading = false;
+        if (res.code === 'ok') {
+          this.list = res.data.data || [];
+          this.total = res.data.total || 0;
+          this.$nextTick(() => {
+            this.$refs.inspectionTable && this.$refs.inspectionTable.doLayout();
+          });
+        } else {
+          this.$message.error(res.msg || '获取列表失败');
+        }
+      });
+    },
+
+    searchList() {
+      this.pageIndex = 1;
+      this.getList();
+    },
+
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.getList();
+    },
+
+    handleCurrentChange(val) {
+      this.pageIndex = val;
+      this.getList();
+    },
+
+    handleAdd() {
+      this.dialogTitle = '新增点检项';
+      this.form = { sortOrder: 0, isEnabled: 1 };
+      this.dialogVisible = true;
+      this.$nextTick(() => this.$refs.inspectionForm && this.$refs.inspectionForm.clearValidate());
+    },
+
+    handleEdit(row) {
+      this.dialogTitle = '编辑点检项';
+      this.form = { ...row };
+      this.dialogVisible = true;
+      this.$nextTick(() => this.$refs.inspectionForm && this.$refs.inspectionForm.clearValidate());
+    },
+
+    submitForm() {
+      this.$refs.inspectionForm.validate(valid => {
+        if (!valid) return;
+        this.submitLoading = true;
+        const url = this.form.id ? '/inspection-library/update' : '/inspection-library/insert';
+        this.http.post(url, this.form, res => {
+          this.submitLoading = false;
+          if (res.code === 'ok') {
+            this.$message.success('保存成功');
+            this.dialogVisible = false;
+            this.getList();
+          } else {
+            this.$message.error(res.msg || '保存失败');
+          }
+        });
+      });
+    },
+
+    handleDelete(row) {
+      this.$confirm('确定删除该点检项吗?删除后不可恢复', '警告', { type: 'warning' }).then(() => {
+        this.http.post('/inspection-library/delete', { id: row.id }, res => {
+          if (res.code === 'ok') {
+            this.$message.success('删除成功');
+            this.getList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        });
+      }).catch(() => {});
+    },
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.inspection-library {
+  padding: 20px;
+
+  .filter-card {
+    margin-bottom: 16px;
+  }
+
+  .table-card {
+    .inspection-table {
+      width: 100%;
+    }
+
+    .table-action-cell {
+      white-space: nowrap;
+      display: inline-block;
+      line-height: 1;
+    }
+
+    ::v-deep .action-column .cell {
+      white-space: nowrap;
+      overflow: visible;
+    }
+
+    .pagination-container {
+      margin-top: 16px;
+      text-align: right;
+    }
+  }
+}
+</style>

+ 257 - 0
fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/maintenance-library.vue

@@ -0,0 +1,257 @@
+<template>
+  <div class="maintenance-library">
+    <el-card class="filter-card">
+      <el-form :inline="true">
+        <el-form-item label="保养库列表"></el-form-item>
+        <el-form-item label="保养部位">
+          <el-select v-model="filters.maintenancePart" placeholder="全部" style="width:160px" clearable @change="searchList">
+            <el-option label="全部" value=""></el-option>
+            <el-option
+              v-for="item in partOptions"
+              :key="item"
+              :label="item"
+              :value="item">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="searchList">搜索</el-button>
+        </el-form-item>
+        <el-form-item style="float:right">
+          <el-button type="primary" size="small" @click="handleAdd">新增</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="table-card">
+      <el-table ref="maintenanceTable" :data="list" v-loading="listLoading" :height="tableHeight" border class="maintenance-table">
+        <el-table-column label="保养级别" width="100" align="center">
+          <template slot-scope="scope">
+            {{ getLevelText(scope.row.maintenanceLevel) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="maintenancePart" label="保养部位" width="160" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="maintenanceContent" label="保养内容" min-width="320" show-overflow-tooltip></el-table-column>
+        <el-table-column label="操作" width="150" fixed="right" align="center" class-name="action-column">
+          <template slot-scope="scope">
+            <div class="table-action-cell">
+              <el-button type="text" size="small" @click="handleEdit(scope.row)">编辑</el-button>
+              <el-button type="text" size="small" style="color:#f56c6c" @click="handleDelete(scope.row)">删除</el-button>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="pageIndex"
+          :page-sizes="[20,50,80,100]"
+          :page-size="pageSize"
+          layout="total,sizes,prev,pager,next"
+          :total="total">
+        </el-pagination>
+      </div>
+    </el-card>
+
+    <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="680px">
+      <el-form ref="libraryForm" :model="form" :rules="formRules" label-width="110px">
+        <el-form-item label="保养级别" prop="maintenanceLevel">
+          <el-select v-model="form.maintenanceLevel" placeholder="请选择" style="width:100%">
+            <el-option label="一级" :value="1"></el-option>
+            <el-option label="二级" :value="2"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="保养部位" prop="maintenancePart">
+          <el-input v-model="form.maintenancePart" placeholder="例如:本体保养、车头箱、润滑系统等"></el-input>
+        </el-form-item>
+        <el-form-item label="保养内容" prop="maintenanceContent">
+          <el-input
+            v-model="form.maintenanceContent"
+            type="textarea"
+            :rows="5"
+            placeholder="请输入保养内容及要求">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="排序号">
+          <el-input-number v-model="form.sortOrder" :min="0" :max="9999" controls-position="right" style="width:100%"></el-input-number>
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="dialogVisible=false">取消</el-button>
+        <el-button type="primary" @click="submitForm" :loading="submitLoading">保存</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'MaintenanceLibrary',
+  data() {
+    return {
+      filters: { maintenancePart: '' },
+      partOptions: [],
+      list: [],
+      total: 0,
+      pageIndex: 1,
+      pageSize: 20,
+      listLoading: false,
+      tableHeight: 500,
+      dialogVisible: false,
+      dialogTitle: '新增保养数据',
+      form: {},
+      formRules: {
+        maintenanceLevel: [{ required: true, message: '请选择保养级别', trigger: 'change' }],
+        maintenancePart: [{ required: true, message: '请输入保养部位', trigger: 'blur' }],
+        maintenanceContent: [{ required: true, message: '请输入保养内容', trigger: 'blur' }],
+      },
+      submitLoading: false,
+    };
+  },
+  mounted() {
+    this.calcTableHeight();
+    this.loadPartOptions();
+    this.getList();
+    window.addEventListener('resize', this.calcTableHeight);
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.calcTableHeight);
+  },
+  methods: {
+    calcTableHeight() {
+      this.tableHeight = window.innerHeight - 270;
+      this.$nextTick(() => {
+        this.$refs.maintenanceTable && this.$refs.maintenanceTable.doLayout();
+      });
+    },
+
+    getLevelText(level) {
+      return { 1: '一级', 2: '二级' }[level] || '-';
+    },
+
+    loadPartOptions() {
+      this.http.post('/maintenance-library/listParts', {}, res => {
+        if (res.code === 'ok') {
+          this.partOptions = res.data || [];
+        }
+      });
+    },
+
+    getList() {
+      this.listLoading = true;
+      this.http.post('/maintenance-library/list', {
+        pageIndex: this.pageIndex,
+        pageSize: this.pageSize,
+        maintenancePart: this.filters.maintenancePart || null,
+      }, res => {
+        this.listLoading = false;
+        if (res.code === 'ok') {
+          this.list = res.data.data || [];
+          this.total = res.data.total || 0;
+          this.$nextTick(() => {
+            this.$refs.maintenanceTable && this.$refs.maintenanceTable.doLayout();
+          });
+        } else {
+          this.$message.error(res.msg || '获取列表失败');
+        }
+      });
+    },
+
+    searchList() {
+      this.pageIndex = 1;
+      this.getList();
+    },
+
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.getList();
+    },
+
+    handleCurrentChange(val) {
+      this.pageIndex = val;
+      this.getList();
+    },
+
+    handleAdd() {
+      this.dialogTitle = '新增保养数据';
+      this.form = { maintenanceLevel: 1, sortOrder: 0, isEnabled: 1 };
+      this.dialogVisible = true;
+      this.$nextTick(() => this.$refs.libraryForm && this.$refs.libraryForm.clearValidate());
+    },
+
+    handleEdit(row) {
+      this.dialogTitle = '编辑保养数据';
+      this.form = { ...row };
+      this.dialogVisible = true;
+      this.$nextTick(() => this.$refs.libraryForm && this.$refs.libraryForm.clearValidate());
+    },
+
+    submitForm() {
+      this.$refs.libraryForm.validate(valid => {
+        if (!valid) return;
+        this.submitLoading = true;
+        const url = this.form.id ? '/maintenance-library/update' : '/maintenance-library/insert';
+        this.http.post(url, this.form, res => {
+          this.submitLoading = false;
+          if (res.code === 'ok') {
+            this.$message.success('保存成功');
+            this.dialogVisible = false;
+            this.loadPartOptions();
+            this.getList();
+          } else {
+            this.$message.error(res.msg || '保存失败');
+          }
+        });
+      });
+    },
+
+    handleDelete(row) {
+      this.$confirm('确定删除该保养数据吗?删除后不可恢复', '警告', { type: 'warning' }).then(() => {
+        this.http.post('/maintenance-library/delete', { id: row.id }, res => {
+          if (res.code === 'ok') {
+            this.$message.success('删除成功');
+            this.loadPartOptions();
+            this.getList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        });
+      }).catch(() => {});
+    },
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.maintenance-library {
+  padding: 20px;
+
+  .filter-card {
+    margin-bottom: 16px;
+  }
+
+  .table-card {
+    .maintenance-table {
+      width: 100%;
+    }
+
+    .table-action-cell {
+      white-space: nowrap;
+      display: inline-block;
+      line-height: 1;
+    }
+
+    ::v-deep .action-column .cell {
+      white-space: nowrap;
+      overflow: visible;
+    }
+
+    .pagination-container {
+      margin-top: 16px;
+      text-align: right;
+    }
+  }
+}
+</style>

+ 336 - 0
fhKeeper/formulahousekeeper/timesheet-workshop/src/views/equipment/plan.vue

@@ -0,0 +1,336 @@
+<template>
+  <div class="maintenance-plan">
+    <el-card class="filter-card">
+      <el-form :inline="true">
+        <el-form-item label="保养计划管理"></el-form-item>
+        <el-form-item>
+          <el-input-number v-model="filters.planYear" :min="2020" :max="2099" controls-position="right" style="width:100px"></el-input-number>
+          <span style="margin:0 4px">年</span>
+        </el-form-item>
+        <el-form-item>
+          <el-input v-model="filters.equipmentCode" placeholder="设备编号" style="width:140px" clearable></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-select v-model="filters.equipmentNature" placeholder="设备分类" style="width:120px" clearable>
+            <el-option label="关键设备" :value="1"></el-option>
+            <el-option label="主要设备" :value="2"></el-option>
+            <el-option label="其他设备" :value="3"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="searchList">搜索</el-button>
+        </el-form-item>
+        <el-form-item style="float:right">
+          <el-button type="primary" size="small" @click="handleGenerate">生成年度计划</el-button>
+          <el-button type="success" size="small" @click="handlePublish">发布计划</el-button>
+          <el-button size="small" @click="openCycleConfig">周期配置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="table-card">
+      <el-table :data="list" v-loading="listLoading" :height="tableHeight" border style="width:100%">
+        <el-table-column prop="equipmentCode" label="设备编号" width="130" fixed></el-table-column>
+        <el-table-column prop="equipmentName" label="设备名称" width="130" fixed></el-table-column>
+        <el-table-column label="分类" width="80" fixed>
+          <template slot-scope="scope">{{ getNatureText(scope.row.equipmentNature) }}</template>
+        </el-table-column>
+        <el-table-column label="状态" width="80" fixed>
+          <template slot-scope="scope">
+            <el-tag :type="getPlanStatusType(scope.row.planStatus)" size="small">
+              {{ getPlanStatusText(scope.row.planStatus) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column v-for="m in 12" :key="m" :label="m+'月'" width="65" align="center">
+          <template slot-scope="scope">
+            <el-tag v-if="scope.row['month'+m+'Level']" size="mini" :type="scope.row['month'+m+'Level']===1?'':'warning'">
+              {{ scope.row['month'+m+'Level']===1?'一级':'二级' }}
+            </el-tag>
+            <span v-else style="color:#c0c4cc">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="100" fixed="right">
+          <template slot-scope="scope">
+            <el-button size="mini" @click="viewOrders(scope.row)">维保单</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="pageIndex"
+          :page-sizes="[20,50,80,100]"
+          :page-size="pageSize"
+          layout="total,sizes,prev,pager,next"
+          :total="total">
+        </el-pagination>
+      </div>
+    </el-card>
+
+    <el-dialog title="生成年度保养计划" :visible.sync="generateVisible" width="420px">
+      <el-form label-width="90px">
+        <el-form-item label="计划年份">
+          <el-input-number v-model="generateForm.planYear" :min="2020" :max="2099" style="width:120px"></el-input-number>
+        </el-form-item>
+        <el-alert type="info" :closable="false">根据各设备类型的维保周期配置,自动计算全年每月保养等级。草稿状态数据将被覆盖。</el-alert>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="generateVisible=false">取消</el-button>
+        <el-button type="primary" @click="submitGenerate" :loading="generateLoading">生成</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="orderDialogTitle" :visible.sync="ordersVisible" width="900px">
+      <el-table :data="orderList" v-loading="orderLoading" border size="small">
+        <el-table-column prop="orderNo" label="维保单号" width="155"></el-table-column>
+        <el-table-column label="保养等级" width="90">
+          <template slot-scope="scope">{{ scope.row.maintenanceLevel===1?'一级':'二级' }}</template>
+        </el-table-column>
+        <el-table-column prop="plannedDate" label="计划日期" width="110"></el-table-column>
+        <el-table-column prop="maintenanceUserName" label="维修员" width="90"></el-table-column>
+        <el-table-column prop="operatorUserName" label="操作员" width="90"></el-table-column>
+        <el-table-column label="状态" width="90">
+          <template slot-scope="scope">
+            <el-tag :type="getOrderStatusType(scope.row.orderStatus)" size="small">
+              {{ getOrderStatusText(scope.row.orderStatus) }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="90">
+          <template slot-scope="scope">
+            <el-button v-if="scope.row.orderStatus===0" size="mini" @click="handleAdjustOrder(scope.row)">调整</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-dialog>
+
+    <el-dialog title="调整维保单" :visible.sync="adjustVisible" width="460px">
+      <el-form label-width="110px">
+        <el-form-item label="计划保养日期">
+          <el-date-picker v-model="adjustForm.plannedDate" type="date" value-format="yyyy-MM-dd" style="width:100%"></el-date-picker>
+        </el-form-item>
+        <el-form-item label="维修员">
+          <el-input v-model="adjustForm.maintenanceUserName" placeholder="维修员姓名"></el-input>
+        </el-form-item>
+        <el-form-item label="操作员">
+          <el-input v-model="adjustForm.operatorUserName" placeholder="操作员姓名"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="adjustVisible=false">取消</el-button>
+        <el-button type="primary" @click="submitAdjust" :loading="adjustLoading">保存</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="维保周期配置" :visible.sync="cycleConfigVisible" width="560px">
+      <el-table :data="cycleConfigList" v-loading="cycleLoading" border size="small">
+        <el-table-column label="设备分类" width="110">
+          <template slot-scope="scope">{{ getNatureText(scope.row.equipmentNature) }}</template>
+        </el-table-column>
+        <el-table-column label="一级保养周期(月)">
+          <template slot-scope="scope">
+            <el-input-number v-model="scope.row.level1CycleMonths" :min="1" :max="12" size="small" style="width:110px"></el-input-number>
+          </template>
+        </el-table-column>
+        <el-table-column label="二级保养周期(月)">
+          <template slot-scope="scope">
+            <el-input-number v-model="scope.row.level2CycleMonths" :min="1" :max="60" size="small" style="width:110px"></el-input-number>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div slot="footer">
+        <el-button @click="cycleConfigVisible=false">取消</el-button>
+        <el-button type="primary" @click="saveCycleConfig" :loading="cycleSaveLoading">保存</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  name: 'MaintenancePlan',
+  data() {
+    return {
+      filters: { planYear: new Date().getFullYear(), equipmentCode: '', equipmentNature: null },
+      list: [],
+      total: 0,
+      pageIndex: 1,
+      pageSize: 20,
+      listLoading: false,
+      tableHeight: 500,
+      generateVisible: false,
+      generateForm: { planYear: new Date().getFullYear() },
+      generateLoading: false,
+      ordersVisible: false,
+      orderDialogTitle: '',
+      orderList: [],
+      orderLoading: false,
+      currentPlan: null,
+      adjustVisible: false,
+      adjustForm: {},
+      adjustLoading: false,
+      cycleConfigVisible: false,
+      cycleConfigList: [],
+      cycleLoading: false,
+      cycleSaveLoading: false,
+    };
+  },
+  mounted() {
+    this.calcTableHeight();
+    this.getList();
+    window.addEventListener('resize', this.calcTableHeight);
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.calcTableHeight);
+  },
+  methods: {
+    calcTableHeight() {
+      this.tableHeight = window.innerHeight - 270;
+    },
+    getList() {
+      this.listLoading = true;
+      this.http.post('/annual-maintenance-plan/list', {
+        pageIndex: this.pageIndex,
+        pageSize: this.pageSize,
+        planYear: this.filters.planYear || null,
+        equipmentCode: this.filters.equipmentCode || null,
+        equipmentNature: this.filters.equipmentNature || null,
+      }, res => {
+        this.listLoading = false;
+        if (res.code === 'ok') {
+          this.list = res.data.data || [];
+          this.total = res.data.total || 0;
+        } else {
+          this.$message.error(res.msg || '获取列表失败');
+        }
+      });
+    },
+    searchList() { this.pageIndex = 1; this.getList(); },
+    handleSizeChange(val) { this.pageSize = val; this.getList(); },
+    handleCurrentChange(val) { this.pageIndex = val; this.getList(); },
+    handleGenerate() {
+      this.generateForm.planYear = this.filters.planYear || new Date().getFullYear();
+      this.generateVisible = true;
+    },
+    submitGenerate() {
+      this.$confirm('确定生成年度保养计划吗?已有草稿状态的数据将被覆盖', '提示', { type: 'warning' }).then(() => {
+        this.generateLoading = true;
+        this.http.post('/annual-maintenance-plan/generate', { planYear: this.generateForm.planYear }, res => {
+          this.generateLoading = false;
+          if (res.code === 'ok') {
+            this.$message.success('生成成功');
+            this.generateVisible = false;
+            this.getList();
+          } else {
+            this.$message.error(res.msg || '生成失败');
+          }
+        });
+      }).catch(() => {});
+    },
+    handlePublish() {
+      const draftPlans = this.list.filter(item => item.planStatus === 0);
+      if (draftPlans.length === 0) {
+        this.$message.warning('当前年度没有草稿状态的计划可发布');
+        return;
+      }
+      this.$confirm('确定发布当前年度的保养计划吗?发布后将自动生成维保单', '提示', { type: 'warning' }).then(() => {
+        this.http.post('/annual-maintenance-plan/publish', { planYear: this.filters.planYear }, res => {
+          if (res.code === 'ok') {
+            this.$message.success('发布成功');
+            this.getList();
+          } else {
+            this.$message.error(res.msg || '发布失败');
+          }
+        });
+      }).catch(() => {});
+    },
+    viewOrders(row) {
+      this.currentPlan = row;
+      this.orderDialogTitle = row.equipmentName + ' - 维保单列表';
+      this.ordersVisible = true;
+      this.orderLoading = true;
+      this.http.post('/maintenance-order/listByPlan', { planId: row.id }, res => {
+        this.orderLoading = false;
+        if (res.code === 'ok') {
+          this.orderList = res.data || [];
+        } else {
+          this.$message.error(res.msg || '获取维保单失败');
+        }
+      });
+    },
+    handleAdjustOrder(row) {
+      this.adjustForm = {
+        id: row.id,
+        plannedDate: row.plannedDate,
+        maintenanceUserName: row.maintenanceUserName,
+        operatorUserName: row.operatorUserName,
+      };
+      this.adjustVisible = true;
+    },
+    submitAdjust() {
+      this.adjustLoading = true;
+      this.http.post('/maintenance-order/adjust', this.adjustForm, res => {
+        this.adjustLoading = false;
+        if (res.code === 'ok') {
+          this.$message.success('调整成功');
+          this.adjustVisible = false;
+          this.viewOrders(this.currentPlan);
+        } else {
+          this.$message.error(res.msg || '调整失败');
+        }
+      });
+    },
+    openCycleConfig() {
+      this.cycleConfigVisible = true;
+      this.cycleLoading = true;
+      this.http.post('/maintenance-cycle-config/list', {}, res => {
+        this.cycleLoading = false;
+        if (res.code === 'ok') {
+          this.cycleConfigList = res.data || [];
+          if (this.cycleConfigList.length === 0) {
+            this.cycleConfigList = [
+              { equipmentNature: 1, level1CycleMonths: 1, level2CycleMonths: 6 },
+              { equipmentNature: 2, level1CycleMonths: 2, level2CycleMonths: 12 },
+              { equipmentNature: 3, level1CycleMonths: 3, level2CycleMonths: 12 },
+            ];
+          }
+        } else {
+          this.$message.error(res.msg || '获取配置失败');
+        }
+      });
+    },
+    saveCycleConfig() {
+      this.cycleSaveLoading = true;
+      this.http.post('/maintenance-cycle-config/save', { list: this.cycleConfigList }, res => {
+        this.cycleSaveLoading = false;
+        if (res.code === 'ok') {
+          this.$message.success('保存成功');
+          this.cycleConfigVisible = false;
+        } else {
+          this.$message.error(res.msg || '保存失败');
+        }
+      });
+    },
+    getNatureText(val) { return { 1: '关键设备', 2: '主要设备', 3: '其他设备' }[val] || '-'; },
+    getPlanStatusText(val) { return { 0: '草稿', 1: '已发布' }[val] || '-'; },
+    getPlanStatusType(val) { return { 0: 'info', 1: 'success' }[val] || 'info'; },
+    getOrderStatusText(val) { return { 0: '待执行', 1: '执行中', 2: '已完成' }[val] || '-'; },
+    getOrderStatusType(val) { return { 0: 'info', 1: 'warning', 2: 'success' }[val] || 'info'; },
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.maintenance-plan {
+  padding: 20px;
+  .filter-card { margin-bottom: 16px; }
+  .table-card {
+    .pagination-container {
+      margin-top: 16px;
+      text-align: right;
+    }
+  }
+}
+</style>

File diff suppressed because it is too large
+ 150 - 166
fhKeeper/formulahousekeeper/timesheet_mld/src/components/taskComponent.vue