# DmsMobileController 故障报修重构方案 > **文档版本**: 3.1 > **创建日期**: 2026-02-05 > **最后更新**: 2026-02-05 > **作者**: Claude AI > **项目**: AUCMA-MES 设备管理系统 > **模块**: DMS 设备管理 - PDA故障报修 > **重要说明**: > 1. 本方案仅关注 DmsMobileController 的重构,保持PDA完美兼容,内部补全完整业务流程 > 2. DmsBillsFaultInstanceController 为Web端接口,不在本次重构范围 > 3. **设备信息改为使用 BaseDeviceLedger(base模块),但返回类型为 DmsBaseDeviceLedger(dms模块),需要进行字段转换** --- ## 一、重构背景 ### 1.1 当前问题分析 #### 1.1.1 DmsMobileController 故障报修方法现状 **现有方法**: | 方法 | 行号范围 | 当前问题 | |------|---------|----------| | insertFaultInstsanceActivity | ~ | 基本正常,创建故障报修 | | startRepair | ~ | **关键问题**:缺少维修工单和派工计划创建逻辑 | | completeRepair | ~ | **关键问题**:缺少维修记录创建逻辑 | | getBillsFaultInstance4Repair | ~ | 方法复杂,包含知识库匹配逻辑 | #### 1.1.2 业务流程不完整 **PDA端当前流程**: ``` PDA创建故障报修 → dms_bills_fault_instance 表 ↓ PDA开始维修 → ❌ 缺少:创建维修工单(dms_repair_work_order) ❌ 缺少:创建派工计划(dms_dispatch_plan) ❌ 缺少:触发断点1(故障报修状态→维修中) ↓ PDA完成维修 → ❌ 缺少:触发断点3(创建维修记录 dms_repair_record) ❌ 缺少:触发断点3(故障报修状态→维修完成) ``` **Web端完整流程**(参考): ``` 故障报修 (dms_bills_fault_instance) ↓ 维修工单 (dms_repair_work_order) ← 【断点1】更新故障报修状态 ↓ 派工计划 (dms_dispatch_plan) ← 【断点2】派工时自动创建 ↓ 维修完成 ↓ 维修记录 (dms_repair_record) ← 【断点3】自动创建,更新故障报修状态 ``` #### 1.1.3 问题影响 - **数据完整性缺失**:PDA操作后,Web端的维修工单和派工计划模块看不到数据 - **状态不一致**:故障报修、维修工单、派工计划、维修记录之间的状态无法同步 - **业务流程断裂**:3个断点修复机制在PDA端无法工作 ### 1.2 重构目标 1. **PDA完美兼容**:PDA端不需要做任何修改,接口路径和参数格式完全不变 2. **业务流程补全**:DmsMobileController 内部补全维修工单和派工计划的创建 3. **数据一致性**:确保4个Service之间的数据完全同步 4. **最小改动**:仅修改 DmsMobileController,不涉及 Web 端的 DmsBillsFaultInstanceController --- ## 二、架构设计 ### 2.1 DmsMobileController 重构架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ PDA 端(Android) │ └────────────────────────┬────────────────────────────────────┘ │ HTTP/Multipart ▼ ┌─────────────────────────────────────────────────────────────┐ │ DmsMobileController(代理模式) │ ├─────────────────────────────────────────────────────────────┤ │ 保持所有 /dms/mobile/* 接口路径不变 │ │ 保持所有参数格式不变 │ │ 内部转换为业务逻辑调用 │ ├─────────────────────────────────────────────────────────────┤ │ 依赖注入的4个Service: │ │ - DmsBillsFaultInstanceService(故障报修服务) │ │ - DmsRepairWorkOrderService(维修工单服务) │ │ - DmsDispatchPlanService(派工计划服务) │ │ - DmsRepairRecordService(维修记录服务) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 业务服务层(现有4个Service) │ ├─────────────────────────────────────────────────────────────┤ │ DmsBillsFaultInstanceServiceImpl │ │ DmsRepairWorkOrderServiceImpl │ │ DmsDispatchPlanServiceImpl │ │ DmsRepairRecordServiceImpl │ └─────────────────────────────────────────────────────────────┘ ``` ### 2.2 核心方法改造方案 #### 2.2.1 startRepair 方法改造 **改造前**: ```java @PostMapping("/startRepair") public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity activity) { // 直接更新操作记录 // ❌ 缺少维修工单创建 // ❌ 缺少派工计划创建 // ❌ 缺少状态同步 } ``` **改造后**: ```java @PostMapping("/startRepair") public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity activity) { // 1. 查询故障报修 // 2. 检查是否已有维修工单,没有则创建 // 3. 【断点1】更新故障报修状态为"维修中" // 4. 创建派工计划 // 5. 【断点2】自动接收派工 // 6. 更新维修工单状态为"维修中" // 7. 更新操作记录 } ``` #### 2.2.2 completeRepair 方法改造 **改造前**: ```java @PostMapping("/completeRepair") public AjaxResult completeRepair(...) { // 直接更新操作记录 // ❌ 缺少维修记录创建 // ❌ 缺少状态同步 } ``` **改造后**: ```java @PostMapping("/completeRepair") public AjaxResult completeRepair(...) { // 1. 查询故障报修和维修工单 // 2. 更新维修工单状态为"已完成" // 3. 【断点3】创建维修记录 // 4. 【断点3】更新故障报修状态为"维修完成" // 5. 处理配件消耗 // 6. 更新操作记录 } ``` --- ## 三、需要新建的DTO类 ### 3.1 DTO清单(可选,用于内部转换) | 序号 | DTO类名 | 文件路径 | 用途 | |------|---------|----------|------| | 1 | DmsFaultRepairContext | aucma-dms/src/main/java/com/aucma/dms/dto/ | 维修上下文信息(内部使用) | **说明**:DTO类主要用于内部参数传递,也可以直接使用现有的实体类。 --- ## 四、DmsMobileController 重构方案 ### 4.1 文件路径 **文件**: `aucma-dms/src/main/java/com/aucma/dms/controller/DmsMobileController.java` ### 4.2 依赖注入(新增) ```java @RestController @RequestMapping("/dms/mobile") public class DmsMobileController extends BaseController { // 现有依赖 @Autowired private IDmsBillsFaultInstanceService dmsBillsFaultInstanceService; // 【新增】维修工单服务 @Autowired private IDmsRepairWorkOrderService dmsRepairWorkOrderService; // 【新增】派工计划服务 @Autowired private IDmsDispatchPlanService dmsDispatchPlanService; // 【新增】维修记录服务 @Autowired private IDmsRepairRecordService dmsRepairRecordService; // 【新增】维修知识库服务(可选,用于 getBillsFaultInstance4Repair) @Autowired private IDmsKnowledgeRepairService dmsKnowledgeRepairService; } ``` ### 4.3 startRepair 方法完整重构 ```java /** * 开始维修 * * 【重构说明】 * - 保持接口路径和参数格式不变 * - 内部补全维修工单和派工计划的创建逻辑 * - 触发断点1和断点2,确保数据完整性 */ @PostMapping("/startRepair") public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity activity) { try { Long faultInstanceId = activity.getRepairInstanceId(); String repairer = activity.getRepairer(); log.info("PDA开始维修,故障报修ID: {}, 维修人: {}", faultInstanceId, repairer); // ========== 步骤1:查询故障报修 ========== DmsBillsFaultInstance fault = dmsBillsFaultInstanceService .selectDmsBillsFaultInstanceByRepairInstanceId(faultInstanceId); if (fault == null) { return AjaxResult.error("故障报修不存在"); } // ========== 步骤2:检查是否已有维修工单 ========== DmsRepairWorkOrder existingOrder = dmsRepairWorkOrderService .selectByFaultInstanceId(faultInstanceId); DmsRepairWorkOrder order; if (existingOrder == null) { // ========== 步骤3:创建维修工单 ========== order = new DmsRepairWorkOrder(); order.setFaultInstanceId(faultInstanceId); order.setOrderStatus("0"); // 待派工 order.setRepairer(repairer); order.setCreateTime(new Date()); dmsRepairWorkOrderService.insertRepairWorkOrder(order); log.info("自动创建维修工单,工单ID: {}", order.getRepairOrderId()); // 【断点1】更新故障报修状态为"维修中" fault.setBillsStatus("1"); fault.setUpdateTime(new Date()); dmsBillsFaultInstanceService.updateDmsBillsFaultInstance(fault); log.info("【断点1】故障报修状态已更新为维修中"); } else { order = existingOrder; } // ========== 步骤4:创建派工计划 ========== DmsDispatchPlan plan = new DmsDispatchPlan(); plan.setRepairOrderId(order.getRepairOrderId()); plan.setRepairer(repairer); plan.setReceiveStatus("0"); // 待接收 plan.setExecutionStatus("0"); // 未开始 plan.setCreateTime(new Date()); dmsDispatchPlanService.insertDispatchPlan(plan); // 【断点2】派工时自动创建派工计划(自动接收) plan.setReceiveStatus("1"); // 已接收 plan.setExecutionStatus("1"); // 维修中 plan.setReceiveTime(new Date()); plan.setUpdateTime(new Date()); dmsDispatchPlanService.updateDispatchPlan(plan); log.info("【断点2】派工计划已创建并自动接收"); // ========== 步骤5:更新维修工单状态为"维修中" ========== order.setOrderStatus("2"); // 维修中 order.setRealBeginTime(new Date()); order.setUpdateTime(new Date()); dmsRepairWorkOrderService.updateRepairWorkOrder(order); log.info("维修工单状态已更新为维修中"); // ========== 步骤6:更新操作记录(原有逻辑) ========== activity.setProcessHandleStatus("1"); // 执行中 activity.setStartTime(new Date()); dmsBillsFaultInstanceService.updateDmsFaultInstanceActivity(activity); return AjaxResult.success("开始维修成功"); } catch (Exception e) { log.error("开始维修失败", e); return AjaxResult.error("开始维修失败:" + e.getMessage()); } } ``` ### 4.4 completeRepair 方法完整重构 ```java /** * 完成维修 * * 【重构说明】 * - 保持接口路径和参数格式不变 * - 内部补全维修记录的创建逻辑 * - 触发断点3,确保数据完整性 */ @PostMapping("/completeRepair") public AjaxResult completeRepair( @RequestParam("repairInstanceId") Long repairInstanceId, @RequestParam("instanceActivityId") Long instanceActivityId, @RequestParam(value = "checkedFault", required = false) String checkedFault, @RequestParam(value = "repairContent", required = false) String repairContent, @RequestParam(value = "protectedMethod", required = false) String protectedMethod, @RequestParam(value = "repairer", required = false) String repairer, @RequestParam(value = "parts1", required = false) String parts1, @RequestParam(value = "files", required = false) List files) { try { log.info("PDA完成维修,故障报修ID: {}, 维修人: {}", repairInstanceId, repairer); // ========== 步骤1:查询故障报修和维修工单 ========== DmsBillsFaultInstance fault = dmsBillsFaultInstanceService .selectDmsBillsFaultInstanceByRepairInstanceId(repairInstanceId); if (fault == null) { return AjaxResult.error("故障报修不存在"); } DmsRepairWorkOrder order = dmsRepairWorkOrderService .selectByFaultInstanceId(repairInstanceId); if (order == null) { return AjaxResult.error("维修工单不存在,请先开始维修"); } // ========== 步骤2:更新维修工单状态为"已完成" ========== order.setOrderStatus("3"); // 已完成 order.setRealEndTime(new Date()); order.setUpdateTime(new Date()); dmsRepairWorkOrderService.updateRepairWorkOrder(order); log.info("维修工单状态已更新为已完成"); // ========== 步骤3:【断点3】创建维修记录 ========== DmsRepairRecord record = new DmsRepairRecord(); record.setRepairOrderId(order.getRepairOrderId()); record.setFaultInstanceId(repairInstanceId); record.setRepairContent(repairContent); record.setRepairer(repairer); record.setCheckedFault(checkedFault); record.setProtectedMethod(protectedMethod); record.setIsArchived("0"); // 未存档 record.setRepairEndTime(new Date()); record.setCreateTime(new Date()); dmsRepairRecordService.insertDmsRepairRecord(record); log.info("【断点3】维修记录已创建,记录ID: {}", record.getRecordId()); // ========== 步骤4:【断点3】更新故障报修状态为"维修完成" ========== fault.setBillsStatus("2"); // 维修完成 fault.setRealEndTime(new Date()); fault.setUpdateTime(new Date()); dmsBillsFaultInstanceService.updateDmsBillsFaultInstance(fault); log.info("【断点3】故障报修状态已更新为维修完成"); // ========== 步骤5:处理配件消耗 ========== if (parts1 != null && !parts1.isEmpty()) { List parts = parsePartsJson(parts1); for (DmsFaultCompentsParts part : parts) { part.setFaultId(repairInstanceId); // 保存配件信息 } log.info("配件信息已保存,共{}个", parts.size()); } // ========== 步骤6:更新操作记录(原有逻辑) ========== DmsFaultInstanceActivity activity = new DmsFaultInstanceActivity(); activity.setInstanceActivityId(instanceActivityId); activity.setCheckedFault(checkedFault); activity.setRepairContent(repairContent); activity.setProtectedMethod(protectedMethod); activity.setRepairer(repairer); activity.setProcessHandleStatus("2"); // 已完成 activity.setEndTime(new Date()); activity.setRepairConfirm(2); // 已确认 activity.setConfirmTime(new Date()); dmsBillsFaultInstanceService.updateDmsFaultInstanceActivity(activity); return AjaxResult.success("完成维修成功"); } catch (Exception e) { log.error("完成维修失败", e); return AjaxResult.error("完成维修失败:" + e.getMessage()); } } /** * 解析配件JSON字符串 */ private List parsePartsJson(String parts1) { try { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(parts1, new TypeReference>() {}); } catch (Exception e) { log.error("解析配件JSON失败", e); return new ArrayList<>(); } } ``` ### 4.5 设备信息字段转换(重要) #### 4.5.1 字段差异说明 **需求**:DmsMobileController 中所有设备信息改为使用 `BaseDeviceLedger`(aucma-base模块),但返回类型为 `DmsBaseDeviceLedger`(aucma-dms模块),需要进行字段转换。 **字段映射表**: | 业务含义 | BaseDeviceLedger | DmsBaseDeviceLedger | 转换规则 | |---------|------------------|---------------------|----------| | 主键ID | `objId` | `deviceId` | `objId → deviceId` | | 设备编号 | `deviceCode` | `deviceCode` | 直接映射 | | 设备名称 | `deviceName` | `deviceName` | 直接映射 | | 设备类型 | `deviceType` | `deviceTypeId` | `deviceType → deviceTypeId` | | 设备型号 | `deviceModel` | `deviceSpec` | `deviceModel → deviceSpec` | | 设备状态 | `deviceStatus` | `deviceStatus` | 直接映射 | | 设备位置 | - | `deviceLocation` | 可为空 | | 资产编号 | - | `assetNumber` | 可为空 | | 供应商 | `manufacturer` | - | 需映射到 `suplierName` | #### 4.5.2 字段转换方法 ```java /** * 将 BaseDeviceLedger 转换为 DmsBaseDeviceLedger * 用于PDA接口返回值转换 */ private DmsBaseDeviceLedger convertToDmsBaseDeviceLedger(BaseDeviceLedger baseLedger) { if (baseLedger == null) { return null; } DmsBaseDeviceLedger dmsLedger = new DmsBaseDeviceLedger(); // 主键映射 dmsLedger.setDeviceId(baseLedger.getObjId()); // 直接映射字段 dmsLedger.setDeviceCode(baseLedger.getDeviceCode()); dmsLedger.setDeviceName(baseLedger.getDeviceName()); dmsLedger.setDeviceStatus(baseLedger.getDeviceStatus()); // 字段名称转换 dmsLedger.setDeviceTypeId(baseLedger.getDeviceType()); // deviceType → deviceTypeId dmsLedger.setDeviceSpec(baseLedger.getDeviceModel()); // deviceModel → deviceSpec dmsLedger.setSuplierName(baseLedger.getManufacturer()); // manufacturer → suplierName // 可为空字段 dmsLedger.setDeviceLocation(baseLedger.getUsedDepartment()); // 使用部门 → 设备位置 // 复制审计字段 dmsLedger.setCreateTime(baseLedger.getCreateTime()); dmsLedger.setCreateBy(baseLedger.getCreateBy()); dmsLedger.setUpdateTime(baseLedger.getUpdateTime()); dmsLedger.setUpdateBy(baseLedger.getUpdateBy()); dmsLedger.setIsFlag(baseLedger.getIsFlag()); return dmsLedger; } /** * 批量转换 BaseDeviceLedger 列表 */ private List convertToDmsBaseDeviceLedgerList(List baseLedgerList) { if (CollectionUtils.isEmpty(baseLedgerList)) { return new ArrayList<>(); } List dmsLedgerList = new ArrayList<>(); for (BaseDeviceLedger baseLedger : baseLedgerList) { dmsLedgerList.add(convertToDmsBaseDeviceLedger(baseLedger)); } return dmsLedgerList; } ``` #### 4.5.3 需要修改的方法 **方法1:getDeviceByDeviceCode(Line 75-79)** **修改前**: ```java @GetMapping("/getDeviceByDeviceCode/{deviceCode}") public AjaxResult getDeviceByDeviceCode(@PathVariable("deviceCode") String deviceCode) { DmsBaseDeviceLedger dmsBaseDeviceLedger = baseDeviceLedgerService.selectDmsBaseDeviceLedgerByDeviceCode(deviceCode); return success(dmsBaseDeviceLedger); } ``` **修改后**: ```java @Autowired private IBaseDeviceLedgerService baseDeviceLedgerService; // 改为使用 base 模块的 Service @GetMapping("/getDeviceByDeviceCode/{deviceCode}") public AjaxResult getDeviceByDeviceCode(@PathVariable("deviceCode") String deviceCode) { // 1. 使用 BaseDeviceLedger 查询 BaseDeviceLedger baseLedger = baseDeviceLedgerService.selectBaseDeviceLedgerByDeviceCode(deviceCode); // 2. 转换为 DmsBaseDeviceLedger 返回 DmsBaseDeviceLedger dmsBaseDeviceLedger = convertToDmsBaseDeviceLedger(baseLedger); return success(dmsBaseDeviceLedger); } ``` **方法2:likeDeviceName(Line 102-106)** **修改前**: ```java @GetMapping("/likeDeviceName") public AjaxResult likeDeviceName(String deviceName) { List deviceLedgerList = baseDeviceLedgerService.likeDeviceName(deviceName); return success(deviceLedgerList); } ``` **修改后**: ```java @GetMapping("/likeDeviceName") public AjaxResult likeDeviceName(String deviceName) { // 1. 使用 BaseDeviceLedger 查询 List baseLedgerList = baseDeviceLedgerService.likeBaseDeviceName(deviceName); // 2. 批量转换为 DmsBaseDeviceLedger 返回 List dmsLedgerList = convertToDmsBaseDeviceLedgerList(baseLedgerList); return success(dmsLedgerList); } ``` ### 4.6 其他方法保持不变 以下方法保持原有逻辑不变: - insertFaultInstsanceActivity - 创建故障报修 - getBillsFaultInstances - 查询故障列表 - getBillsFaultInstanceByRepairInstanceId - 查询故障详情 - updateFaultInstanceActivity - 更新故障信息 - scanDevice4Repair - 扫码设备验证 --- ## 五、数据流图 ### 5.1 startRepair 数据流(重构后) ``` PDA调用 startRepair(faultInstanceId, repairer) ↓ DmsMobileController.startRepair() ↓ 1. 查询故障报修 ↓ 2. 检查是否已有维修工单 ├→ 没有 → 创建维修工单 │ └→ 【断点1】更新故障报修状态为"维修中" └→ 已有 → 使用现有工单 ↓ 3. 创建派工计划 └→ 【断点2】自动接收派工 ↓ 4. 更新维修工单状态为"维修中" ↓ 5. 更新操作记录 ↓ 返回成功 ``` ### 5.2 completeRepair 数据流(重构后) ``` PDA调用 completeRepair(faultInstanceId, repairContent, parts) ↓ DmsMobileController.completeRepair() ↓ 1. 查询故障报修和维修工单 ↓ 2. 更新维修工单状态为"已完成" ↓ 3. 【断点3】创建维修记录 ↓ 4. 【断点3】更新故障报修状态为"维修完成" ↓ 5. 处理配件消耗 ↓ 6. 更新操作记录 ↓ 返回成功 ``` --- ## 六、测试方案 ### 6.1 单元测试 ```java @SpringBootTest class DmsMobileControllerTest { @Autowired private DmsMobileController dmsMobileController; @Test void testStartRepair() { // 准备测试数据 DmsFaultInstanceActivity activity = new DmsFaultInstanceActivity(); activity.setRepairInstanceId(1L); activity.setRepairer("张三"); // 调用接口 AjaxResult result = dmsMobileController.startRepair(activity); // 验证结果 assertEquals("开始维修成功", result.get("msg")); // 验证:维修工单已创建 DmsRepairWorkOrder order = repairWorkOrderService.selectByFaultInstanceId(1L); assertNotNull(order); assertEquals("2", order.getOrderStatus()); // 维修中 // 验证:派工计划已创建 DmsDispatchPlan plan = dispatchPlanService.selectByRepairOrderId(order.getRepairOrderId()); assertNotNull(plan); assertEquals("1", plan.getReceiveStatus()); // 已接收 // 验证:故障报修状态已更新 DmsBillsFaultInstance fault = faultInstanceService.selectByRepairInstanceId(1L); assertEquals("1", fault.getBillsStatus()); // 维修中 } @Test void testCompleteRepair() { // 准备测试数据 // ... // 调用接口 AjaxResult result = dmsMobileController.completeRepair(...); // 验证结果 assertEquals("完成维修成功", result.get("msg")); // 验证:维修记录已创建 DmsRepairRecord record = repairRecordService.selectByRepairOrderId(1L); assertNotNull(record); // 验证:故障报修状态已更新 DmsBillsFaultInstance fault = faultInstanceService.selectByRepairInstanceId(1L); assertEquals("2", fault.getBillsStatus()); // 维修完成 } } ``` ### 6.2 PDA兼容性测试(关键) | 测试场景 | 测试步骤 | 预期结果 | |---------|----------|----------| | PDA开始维修 | 调用 /startRepair | 1. 维修工单自动创建
2. 派工计划自动创建
3. 故障报修状态→维修中
4. 返回格式不变 | | PDA完成维修 | 调用 /completeRepair | 1. 维修记录自动创建
2. 故障报修状态→维修完成
3. 返回格式不变 | | PDA完整流程 | 创建→开始维修→完成维修 | 4个表数据完整,状态同步正确 | ### 6.3 Web端数据验证 | 模块 | 验证内容 | 验证方法 | |------|----------|----------| | 维修工单 | PDA创建的工单可见 | 查询 dms_repair_work_order 表 | | 派工计划 | PDA自动创建的派工可见 | 查询 dms_dispatch_plan 表 | | 维修记录 | PDA自动创建的记录可见 | 查询 dms_repair_record 表 | | 故障报修 | 状态同步正确 | 查询 dms_bills_fault_instance.bills_status | --- ## 七、文件清单 ### 7.1 需要修改的文件(1个) | 序号 | 文件路径 | 修改内容 | 影响范围 | |------|----------|----------|----------| | 1 | aucma-dms/src/main/java/com/aucma/dms/controller/DmsMobileController.java | **1. 新增依赖注入**:
- IBaseDeviceLedgerService(base模块)
- IDmsRepairWorkOrderService
- IDmsDispatchPlanService
- IDmsRepairRecordService

**2. 新增字段转换方法**:
- convertToDmsBaseDeviceLedger() - 单个对象转换
- convertToDmsBaseDeviceLedgerList() - 批量转换

**3. 修改设备查询方法**:
- getDeviceByDeviceCode() - 改用 BaseDeviceLedger
- likeDeviceName() - 改用 BaseDeviceLedger

**4. 重构核心方法**:
- startRepair() - 补全工单和派工创建
- completeRepair() - 补全维修记录创建

**5. 新增辅助方法**:
- parsePartsJson() - 解析配件JSON | 仅PDA端,Web端不受影响 | **修改详细说明**: **新增导入**: ```java import com.aucma.base.domain.BaseDeviceLedger; import com.aucma.base.service.IBaseDeviceLedgerService; import org.springframework.beans.BeanUtils; ``` **字段转换关键点**: - 主键:`objId` → `deviceId` - 设备类型:`deviceType` → `deviceTypeId` - 设备型号:`deviceModel` → `deviceSpec` - 供应商:`manufacturer` → `suplierName` ### 7.2 需要新建的文件(0个) **说明**:本次重构不需要新建DTO类,直接使用现有实体类 + 字段转换方法即可。 ### 7.3 不需要修改的文件 | 文件 | 说明 | |------|------| | DmsBillsFaultInstanceController.java | Web端接口,不在本次重构范围 | | DmsBillsFaultInstanceServiceImpl.java | 现有服务,直接调用 | | DmsRepairWorkOrderServiceImpl.java | 现有服务,直接调用 | | DmsDispatchPlanServiceImpl.java | 现有服务,直接调用 | | DmsRepairRecordServiceImpl.java | 现有服务,直接调用 | --- ## 八、实施步骤 ### 阶段1:准备工作(半天) - [ ] 备份 DmsMobileController.java - [ ] 创建开发分支 - [ ] 确认4个Service的可用性 - [ ] 准备测试数据 ### 阶段2:代码重构(1天) - [ ] 新增4个Service依赖注入 - [ ] 重构 startRepair 方法 - [ ] 重构 completeRepair 方法 - [ ] 新增 parsePartsJson 辅助方法 - [ ] 添加日志记录 ### 阶段3:单元测试(半天) - [ ] 编写 startRepair 测试用例 - [ ] 编写 completeRepair 测试用例 - [ ] 验证数据一致性 ### 阶段4:集成测试(1天) - [ ] PDA端联调测试 - [ ] Web端数据验证 - [ ] 完整流程测试 ### 阶段5:部署和验证(半天) - [ ] 部署到测试环境 - [ ] PDA端功能验证 - [ ] Web端数据验证 - [ ] 性能测试 **总计:3-4天** --- ## 九、风险控制 ### 9.1 风险识别 | 风险 | 影响 | 概率 | 应对措施 | |------|------|------|----------| | PDA接口变更导致PDA无法使用 | 高 | 低 | 严格保持接口路径和参数不变 | | 业务流程补全导致数据错误 | 高 | 中 | 充分的单元测试和集成测试 | | 性能下降 | 中 | 低 | 优化查询,添加必要的日志 | | 事务回滚导致数据不一致 | 中 | 低 | 添加事务注解,确保原子性 | ### 9.2 回滚方案 1. **代码备份**:重构前备份 DmsMobileController.java 2. **快速回滚**:如出现问题,立即恢复备份文件 3. **灰度发布**:先在部分PDA设备上测试 4. **监控观察**:部署后密切关注日志和数据 --- ## 十、成功标准 ### 10.1 功能标准 - [ ] PDA端功能完全正常,无需修改 - [ ] startRepair 后自动创建维修工单和派工计划 - [ ] completeRepair 后自动创建维修记录 - [ ] Web端4个模块能看到完整的PDA操作数据 - [ ] 3个断点修复机制正常工作 ### 10.2 质量标准 - [ ] 单元测试覆盖率 > 80% - [ ] 集成测试全部通过 - [ ] 数据一致性检查无错误 - [ ] PDA兼容性测试全部通过 ### 10.3 性能标准 - [ ] startRepair 接口响应时间 < 500ms - [ ] completeRepair 接口响应时间 < 500ms - [ ] 系统吞吐量无明显下降 --- ## 十一、附录 ### 11.1 状态流转图 ``` 故障报修状态 (bills_status) 0 (待维修) ──────────────→ 1 (维修中) ──────────────→ 2 (维修完成) ↑ ↓ ↓ └──── 创建报修 └─ startRepair └─ completeRepair 维修工单状态 (order_status) 0 (待派工) ──→ 1 (已派工) ──→ 2 (维修中) ──→ 3 (已完成) ↑ ↓ ↓ ↓ └─ startRepair创建 └─ 派工 └─ 接收派工 └─ completeRepair 计划 派工计划状态 (receive_status / execution_status) 0 (待接收) ──→ 1 (已接收) ↓ ↓ └─ startRepair创建 └─ 自动接收 维修记录状态 (is_archived) 0 (未存档) ↑ └─ completeRepair 自动创建 ``` ### 11.2 依赖注入清单 ```java // DmsMobileController 需要注入的Service // 【原有】故障报修服务 @Autowired private IDmsBillsFaultInstanceService dmsBillsFaultInstanceService; // 【重构新增】设备台账服务(base模块)- 用于设备信息查询和转换 @Autowired private IBaseDeviceLedgerService baseDeviceLedgerService; // 【重构新增】维修工单服务 - 用于PDA端自动创建维修工单 @Autowired private IDmsRepairWorkOrderService dmsRepairWorkOrderService; // 【重构新增】派工计划服务 - 用于PDA端自动创建派工计划 @Autowired private IDmsDispatchPlanService dmsDispatchPlanService; // 【重构新增】维修记录服务 - 用于PDA端自动创建维修记录 @Autowired private IDmsRepairRecordService dmsRepairRecordService; ``` **说明**: - `IBaseDeviceLedgerService` 来自 `com.aucma.base.service` 包 - 其他Service来自 `com.aucma.dms.service` 包 ### 11.3 核心方法签名 ```java // startRepair @PostMapping("/startRepair") public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity activity) // completeRepair @PostMapping("/completeRepair") public AjaxResult completeRepair( @RequestParam("repairInstanceId") Long repairInstanceId, @RequestParam("instanceActivityId") Long instanceActivityId, @RequestParam(value = "checkedFault", required = false) String checkedFault, @RequestParam(value = "repairContent", required = false) String repairContent, @RequestParam(value = "protectedMethod", required = false) String protectedMethod, @RequestParam(value = "repairer", required = false) String repairer, @RequestParam(value = "parts1", required = false) String parts1, @RequestParam(value = "files", required = false) List files) ``` --- ## 文档变更记录 | 版本 | 日期 | 变更内容 | 作者 | |------|------|----------|------| | 1.0 | 2025-02-05 | 初始版本 | Claude AI | | 2.0 | 2026-02-05 | 基于4个Service分析,完全重写 | Claude AI | | 3.0 | 2026-02-05 | **聚焦 DmsMobileController 重构,不涉及 Web 端** | Claude AI | | 3.1 | 2026-02-05 | **新增设备信息字段转换方案(BaseDeviceLedger → DmsBaseDeviceLedger)** | Claude AI | --- **文档结束** > 本方案仅关注 DmsMobileController 的重构,保持PDA完美兼容,内部补全完整业务流程。DmsBillsFaultInstanceController 为Web端接口,不在本次重构范围。 > > **重要更新**:设备信息查询改为使用 BaseDeviceLedger(base模块),通过字段转换方法转换为 DmsBaseDeviceLedger(dms模块)返回给PDA端。