diff --git a/aucma-dms/DmsBillsFaultInstance_重构方案.md b/aucma-dms/DmsBillsFaultInstance_重构方案.md new file mode 100644 index 0000000..5e2966f --- /dev/null +++ b/aucma-dms/DmsBillsFaultInstance_重构方案.md @@ -0,0 +1,908 @@ +# 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端。 diff --git a/aucma-dms/src/main/java/com/aucma/dms/controller/DmsMobileController.java b/aucma-dms/src/main/java/com/aucma/dms/controller/DmsMobileController.java index f3f2036..967eeca 100644 --- a/aucma-dms/src/main/java/com/aucma/dms/controller/DmsMobileController.java +++ b/aucma-dms/src/main/java/com/aucma/dms/controller/DmsMobileController.java @@ -5,12 +5,14 @@ import com.aucma.common.core.controller.BaseController; import com.aucma.common.core.domain.AjaxResult; import com.aucma.common.core.page.TableDataInfo; import com.aucma.dms.domain.*; +import com.aucma.dms.domain.dto.DmsBaseDeviceLedgerDTO; import com.aucma.dms.domain.vo.DmsBillsFaultInstanceScanVo; import com.aucma.dms.domain.vo.DmsBillsInspectInstanceScanVo; -import com.aucma.dms.service.IDmsBillsFaultInstanceService; -import com.aucma.dms.service.IDmsBillsInspectInstanceService; -import com.aucma.dms.service.IDmsBillsLubeInstanceService; -import com.aucma.dms.service.IDmsBillsMaintInstanceService; +import com.aucma.base.domain.BaseDeviceLedger; +import com.aucma.base.service.IBaseDeviceLedgerService; +import com.aucma.dms.service.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -35,64 +37,178 @@ import java.util.List; @RequestMapping("/dms/mobile") public class DmsMobileController extends BaseController { + private static final Logger log = LoggerFactory.getLogger(DmsMobileController.class); + @Autowired private IDmsBillsFaultInstanceService dmsBillsFaultInstanceService; @Autowired private IDmsBillsInspectInstanceService dmsBillsInspectInstanceService; - @Autowired private IDmsBillsMaintInstanceService dmsBillsMaintInstanceService; @Autowired private IDmsBillsLubeInstanceService dmsBillsLubeInstanceService; -/* @Resource - private RemoteFileService remoteFileService;*//* + // 【重构新增】维修工单服务 - 用于PDA端自动创建维修工单 + @Autowired + private IDmsRepairWorkOrderService dmsRepairWorkOrderService; + // 【重构新增】派工计划服务 - 用于PDA端自动创建派工计划 + @Autowired + private IDmsDispatchPlanService dmsDispatchPlanService; - */ -/** + // 【重构新增】维修记录服务 - 用于PDA端自动创建维修记录 + @Autowired + private IDmsRepairRecordService dmsRepairRecordService; + + // 【重构新增】基础设备台账服务 - 使用aucma-base模块的设备信息 + @Autowired + private IBaseDeviceLedgerService baseDeviceLedgerService; + + /** * 根据设备编号获取设备信息 + * 【重构】使用aucma-base模块的BaseDeviceLedger,返回类型转换为DmsBaseDeviceLedger * - * @return - *//* - - // //@PreAuthorize("@ss.hasPermi('qms:checkrule:list')" ) + * @param deviceCode 设备编号 + * @return 设备信息 + */ @GetMapping("/getDeviceByDeviceCode/{deviceCode}") public AjaxResult getDeviceByDeviceCode(@PathVariable("deviceCode") String deviceCode) { - DmsBaseDeviceLedger dmsBaseDeviceLedger = baseDeviceLedgerService.selectDmsBaseDeviceLedgerByDeviceCode(deviceCode); - return success(dmsBaseDeviceLedger); + BaseDeviceLedger query = new BaseDeviceLedger(); + query.setDeviceCode(deviceCode); + query.setIsFlag(1L); // 只查询有效设备 + List list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query); + if (CollectionUtils.isEmpty(list)) { + return success(null); + } + // 转换为DmsBaseDeviceLedger返回,保持PDA兼容性 + DmsBaseDeviceLedger result = convertToDeviceLedger(list.get(0)); + return success(convertDeviceLedgerToDto(result)); } - */ -/** - * 获取外协单位列表 - * - * @return - *//* - - // //@PreAuthorize("@ss.hasPermi('qms:checkrule:list')" ) - @GetMapping("/getOutsrcInfos") - public AjaxResult getOutsrcInfos() { - DmsBaseOutsrcInfo queryBaseOutsrcInfo = new DmsBaseOutsrcInfo(); - queryBaseOutsrcInfo.setOutsrcStatus(DmsConstants.DMS_BASE_OUTSRC_INFO_STATUS_NROMAL); - List baseOutsrcInfos = dmsBaseOutsrcInfoService.selectDmsBaseOutsrcInfoList(queryBaseOutsrcInfo); - return success(baseOutsrcInfos); - } - */ -/** + /** * 根据传参模糊查询设备名 - *//* - + * 【重构】使用aucma-base模块的BaseDeviceLedger,返回类型转换为DmsBaseDeviceLedger列表 + * + * @param deviceName 设备名称(模糊匹配) + * @return 设备列表 + */ @GetMapping("/likeDeviceName") public AjaxResult likeDeviceName(String deviceName) { - List deviceLedgerList = baseDeviceLedgerService.likeDeviceName(deviceName); - return success(deviceLedgerList); + BaseDeviceLedger query = new BaseDeviceLedger(); + query.setDeviceName(deviceName); + query.setIsFlag(1L); // 只查询有效设备 + List list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query); + // 转换为DmsBaseDeviceLedger列表返回,保持PDA兼容性 + List resultList = new ArrayList<>(); + if (!CollectionUtils.isEmpty(list)) { + for (BaseDeviceLedger base : list) { + resultList.add(convertDeviceLedgerToDto(convertToDeviceLedger(base))); + } + } + return success(resultList); } -*/ + /** + * 将BaseDeviceLedger转换为DmsBaseDeviceLedger + * 【重构辅助方法】保持PDA接口返回类型不变 + * + * @param base aucma-base模块的设备实体 + * @return DMS模块的设备实体 + */ + private DmsBaseDeviceLedger convertToDeviceLedger(BaseDeviceLedger base) { + if (base == null) { + return null; + } + DmsBaseDeviceLedger dms = new DmsBaseDeviceLedger(); + dms.setDeviceId(base.getObjId()); + dms.setDeviceCode(base.getDeviceCode()); + dms.setDeviceName(base.getDeviceName()); + dms.setDeviceTypeId(base.getDeviceType()); + dms.setDeviceStatus(base.getDeviceStatus()); + dms.setAssetNumber(base.getAssetCode()); + dms.setIsFlag(base.getIsFlag()); + dms.setSuplierName(base.getManufacturer()); + dms.setDeviceSpec(base.getDeviceModel()); // 设备型号映射到设备规格 + dms.setDeviceLocation(base.getUsedDepartment()); // 使用部门映射到设备位置 + // 时间字段映射 + dms.setCreateBy(parseLongSafely(base.getCreatedBy())); + dms.setCreateTime(base.getCreatedTime()); + dms.setUpdateBy(parseLongSafely(base.getUpdatedBy())); + dms.setUpdateTime(base.getUpdatedTime()); + return dms; + } + + /** + * 将DmsBaseDeviceLedger转换为DmsBaseDeviceLedgerDTO + * + * @param entity DmsBaseDeviceLedger实体 + * @return DTO对象 + */ + private DmsBaseDeviceLedgerDTO convertDeviceLedgerToDto(DmsBaseDeviceLedger entity) { + if (entity == null) { + return null; + } + DmsBaseDeviceLedgerDTO dto = new DmsBaseDeviceLedgerDTO(); + dto.setDeviceId(entity.getDeviceId()); + dto.setDeviceCode(entity.getDeviceCode()); + dto.setDeviceName(entity.getDeviceName()); + dto.setStationId(entity.getStationId()); + dto.setAssetNumber(entity.getAssetNumber()); + dto.setDeviceLocation(entity.getDeviceLocation()); + dto.setDeviceTypeId(entity.getDeviceTypeId()); + dto.setDeviceSpec(entity.getDeviceSpec()); + dto.setSupplierId(entity.getSupplierId()); + dto.setDeviceStatus(entity.getDeviceStatus()); + dto.setIsFlag(entity.getIsFlag()); + dto.setSuplierName(entity.getSuplierName()); + return dto; + } + + /** + * 安全地将String转换为Long + * @param value 字符串值 + * @return Long值,转换失败返回null + */ + private Long parseLongSafely(String value) { + if (value == null || value.isEmpty()) { + return null; + } + try { + return Long.valueOf(value); + } catch (NumberFormatException e) { + return null; + } + } + + + /** + * 将DmsBaseDeviceLedgerDTO转换为DmsBaseDeviceLedger + * + * @param dto DTO对象 + * @return DmsBaseDeviceLedger实体 + */ + private DmsBaseDeviceLedger convertDtoToDeviceLedger(DmsBaseDeviceLedgerDTO dto) { + if (dto == null) { + return null; + } + DmsBaseDeviceLedger dms = new DmsBaseDeviceLedger(); + dms.setDeviceId(dto.getDeviceId()); + dms.setDeviceCode(dto.getDeviceCode()); + dms.setDeviceName(dto.getDeviceName()); + dms.setStationId(dto.getStationId()); + dms.setAssetNumber(dto.getAssetNumber()); + dms.setDeviceLocation(dto.getDeviceLocation()); + dms.setDeviceTypeId(dto.getDeviceTypeId()); + dms.setDeviceSpec(dto.getDeviceSpec()); + dms.setSupplierId(dto.getSupplierId()); + dms.setDeviceStatus(dto.getDeviceStatus()); + dms.setIsFlag(dto.getIsFlag()); + dms.setSuplierName(dto.getSuplierName()); + return dms; + } /** * PDA-报修 @@ -198,35 +314,194 @@ public class DmsMobileController extends BaseController { /** * 开始维修 + * + * 【重构说明】 + * - 保持接口路径和参数格式不变,PDA无需修改 + * - 内部补全维修工单和派工计划的创建逻辑 + * - 触发断点1和断点2,确保数据完整性 */ -// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" ) - ////@Log(title = "故障报修工单", businessType = BusinessType.START) @PostMapping("/startRepair") public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity dmsFaultInstanceActivity) { - return success(dmsBillsFaultInstanceService.startRepair(dmsFaultInstanceActivity)); + try { + Long repairInstanceId = dmsFaultInstanceActivity.getRepairInstanceId(); + String repairer = dmsFaultInstanceActivity.getRepairer(); + + log.info("PDA开始维修,故障报修ID: {}, 维修人: {}", repairInstanceId, repairer); + + // ========== 步骤1:调用原有的开始维修逻辑 ========== + int result = dmsBillsFaultInstanceService.startRepair(dmsFaultInstanceActivity); + + // ========== 步骤2:查询故障报修详情 ========== + DmsBillsFaultInstance fault = dmsBillsFaultInstanceService + .selectDmsBillsFaultInstanceByRepairInstanceId(repairInstanceId); + if (fault == null) { + log.warn("故障报修[{}]不存在", repairInstanceId); + return success(result); + } + + // ========== 步骤3:检查是否已有维修工单 ========== + DmsRepairWorkOrder existingOrder = dmsRepairWorkOrderService.selectByFaultInstanceId(repairInstanceId); + + if (existingOrder == null) { + // ========== 步骤4:【断点1】自动创建维修工单 ========== + DmsRepairWorkOrder newOrder = new DmsRepairWorkOrder(); + newOrder.setFaultInstanceId(repairInstanceId); + newOrder.setDeviceId(fault.getDeviceId()); + newOrder.setFaultType(fault.getFaultType()); + newOrder.setFaultDescription(fault.getFaultDescription()); + newOrder.setRepairType(fault.getRepairType()); + newOrder.setOrderStatus("2"); // 直接设为维修中(PDA开始维修即进入维修状态) + newOrder.setPriority("3"); // 默认中优先级 + newOrder.setActualStartTime(new Date()); + // 设置执行人信息 + if (dmsFaultInstanceActivity.getHandleUserId() != null) { + newOrder.setExecutorId(dmsFaultInstanceActivity.getHandleUserId()); + } + if (repairer != null && !repairer.isEmpty()) { + newOrder.setExecutorName(repairer); + } + + dmsRepairWorkOrderService.insertDmsRepairWorkOrder(newOrder); + log.info("【断点1】PDA自动创建维修工单,工单ID: {}, 工单编号: {}", + newOrder.getWorkOrderId(), newOrder.getWorkOrderCode()); + + // ========== 步骤5:【断点2】自动创建派工计划并接收 ========== + DmsDispatchPlan plan = new DmsDispatchPlan(); + plan.setWorkOrderId(newOrder.getWorkOrderId()); + plan.setWorkOrderCode(newOrder.getWorkOrderCode()); + plan.setDeviceId(fault.getDeviceId()); + plan.setDispatchType("1"); // 单人派工 + plan.setReceiveStatus("1"); // 直接设为已接收(PDA开始维修即表示已接收) + plan.setExecutionStatus("1"); // 执行中 + if (dmsFaultInstanceActivity.getHandleUserId() != null) { + plan.setExecutorId(dmsFaultInstanceActivity.getHandleUserId()); + } + if (repairer != null && !repairer.isEmpty()) { + plan.setExecutorName(repairer); + } + plan.setDispatchNotes("由PDA端开始维修自动生成"); + + dmsDispatchPlanService.insertDmsDispatchPlan(plan); + log.info("【断点2】PDA自动创建派工计划并接收,计划ID: {}", plan.getPlanId()); + } else { + // 已有维修工单,更新状态为维修中 + if (!"2".equals(existingOrder.getOrderStatus()) && !"3".equals(existingOrder.getOrderStatus())) { + DmsRepairWorkOrder updateOrder = new DmsRepairWorkOrder(); + updateOrder.setWorkOrderId(existingOrder.getWorkOrderId()); + updateOrder.setOrderStatus("2"); // 维修中 + updateOrder.setActualStartTime(new Date()); + if (dmsFaultInstanceActivity.getHandleUserId() != null) { + updateOrder.setExecutorId(dmsFaultInstanceActivity.getHandleUserId()); + } + if (repairer != null && !repairer.isEmpty()) { + updateOrder.setExecutorName(repairer); + } + dmsRepairWorkOrderService.updateDmsRepairWorkOrder(updateOrder); + log.info("PDA更新已有维修工单[{}]状态为维修中", existingOrder.getWorkOrderCode()); + } + } + + return success(result); + } catch (Exception e) { + log.error("PDA开始维修失败", e); + return error("开始维修失败:" + e.getMessage()); + } } /** * 完成维修 + * + * 【重构说明】 + * - 保持接口路径和参数格式不变,PDA无需修改 + * - 内部补全维修记录的创建逻辑 + * - 触发断点3,确保数据完整性 */ -// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" ) - ////@Log(title = "故障报修工单", businessType = BusinessType.COMPLETE) @PostMapping("/completeRepair") - public AjaxResult completeRepair(DmsFaultInstanceActivity dmsFaultInstanceActivity,@RequestParam(value = "files", required = false) List files) throws JsonProcessingException { - dmsFaultInstanceActivity.setRepairConfirm(2); - dmsFaultInstanceActivity.setConfirmTime(new Date()); - String parts1 = dmsFaultInstanceActivity.getParts1(); - ObjectMapper objectMapper = new ObjectMapper(); - List parts2 = objectMapper.readValue(parts1, new TypeReference>() {}); - dmsFaultInstanceActivity.setParts(parts2); - List < String > fileUrls = new ArrayList<>(); -/* for (MultipartFile file : files) { - R sysFileR = remoteFileService.upload(file); - SysFile sysFile = sysFileR.getData(); - fileUrls.add(sysFile.getUrl()); - }*/ - dmsFaultInstanceActivity.setFileUrls(fileUrls); - return success(dmsBillsFaultInstanceService.completeRepair(dmsFaultInstanceActivity)); + public AjaxResult completeRepair(DmsFaultInstanceActivity dmsFaultInstanceActivity, @RequestParam(value = "files", required = false) List files) throws JsonProcessingException { + try { + Long repairInstanceId = dmsFaultInstanceActivity.getRepairInstanceId(); + String repairer = dmsFaultInstanceActivity.getRepairer(); + + log.info("PDA完成维修,故障报修ID: {}, 维修人: {}", repairInstanceId, repairer); + + // ========== 步骤1:原有逻辑 - 设置确认信息和解析配件 ========== + dmsFaultInstanceActivity.setRepairConfirm(2); + dmsFaultInstanceActivity.setConfirmTime(new Date()); + String parts1 = dmsFaultInstanceActivity.getParts1(); + if (parts1 != null && !parts1.isEmpty()) { + ObjectMapper objectMapper = new ObjectMapper(); + List parts2 = objectMapper.readValue(parts1, new TypeReference>() {}); + dmsFaultInstanceActivity.setParts(parts2); + } + List fileUrls = new ArrayList<>(); + dmsFaultInstanceActivity.setFileUrls(fileUrls); + + // ========== 步骤2:调用原有的完成维修逻辑 ========== + int result = dmsBillsFaultInstanceService.completeRepair(dmsFaultInstanceActivity); + + // ========== 步骤3:查询关联的维修工单 ========== + DmsRepairWorkOrder workOrder = dmsRepairWorkOrderService.selectByFaultInstanceId(repairInstanceId); + + if (workOrder != null) { + // ========== 步骤4:更新维修工单状态为已完成 ========== + DmsRepairWorkOrder updateOrder = new DmsRepairWorkOrder(); + updateOrder.setWorkOrderId(workOrder.getWorkOrderId()); + updateOrder.setOrderStatus("3"); // 已完成 + updateOrder.setActualEndTime(new Date()); + updateOrder.setRepairResult(dmsFaultInstanceActivity.getRepairContent()); + dmsRepairWorkOrderService.updateDmsRepairWorkOrder(updateOrder); + log.info("PDA更新维修工单[{}]状态为已完成", workOrder.getWorkOrderCode()); + + // ========== 步骤5:【断点3】自动创建维修记录 ========== + DmsRepairRecord record = new DmsRepairRecord(); + record.setWorkOrderId(workOrder.getWorkOrderId()); + record.setWorkOrderCode(workOrder.getWorkOrderCode()); + record.setDeviceId(workOrder.getDeviceId()); + record.setDeviceCode(workOrder.getDeviceCode()); + record.setDeviceName(workOrder.getDeviceName()); + record.setFaultPhenomenon(workOrder.getFaultDescription()); + // 维修人员信息 + if (dmsFaultInstanceActivity.getHandleUserId() != null) { + record.setRepairerId(dmsFaultInstanceActivity.getHandleUserId()); + } else if (workOrder.getExecutorId() != null) { + record.setRepairerId(workOrder.getExecutorId()); + } + if (repairer != null && !repairer.isEmpty()) { + record.setRepairerName(repairer); + } else if (workOrder.getExecutorName() != null) { + record.setRepairerName(workOrder.getExecutorName()); + } + // 维修时间 + record.setStartTime(workOrder.getActualStartTime()); + record.setEndTime(new Date()); + // 维修内容 + record.setRepairResult(dmsFaultInstanceActivity.getRepairContent()); + // 默认未存档 + record.setIsArchived("0"); + + dmsRepairRecordService.insertDmsRepairRecord(record); + log.info("【断点3】PDA自动创建维修记录,记录ID: {}", record.getRecordId()); + + // ========== 步骤6:更新派工计划状态为已完成 ========== + DmsDispatchPlan queryPlan = new DmsDispatchPlan(); + queryPlan.setWorkOrderId(workOrder.getWorkOrderId()); + List plans = dmsDispatchPlanService.selectDmsDispatchPlanList(queryPlan); + if (!CollectionUtils.isEmpty(plans)) { + DmsDispatchPlan updatePlan = new DmsDispatchPlan(); + updatePlan.setPlanId(plans.get(0).getPlanId()); + updatePlan.setExecutionStatus("2"); // 已完成 + dmsDispatchPlanService.updateDmsDispatchPlan(updatePlan); + log.info("PDA更新派工计划[{}]状态为已完成", plans.get(0).getPlanCode()); + } + } else { + log.warn("故障报修[{}]无关联维修工单,跳过维修记录创建", repairInstanceId); + } + + return success(result); + } catch (Exception e) { + log.error("PDA完成维修失败", e); + return error("完成维修失败:" + e.getMessage()); + } } diff --git a/aucma-dms/src/main/java/com/aucma/dms/domain/dto/DmsBaseDeviceLedgerDTO.java b/aucma-dms/src/main/java/com/aucma/dms/domain/dto/DmsBaseDeviceLedgerDTO.java new file mode 100644 index 0000000..3c40a7d --- /dev/null +++ b/aucma-dms/src/main/java/com/aucma/dms/domain/dto/DmsBaseDeviceLedgerDTO.java @@ -0,0 +1,186 @@ +package com.aucma.dms.domain.dto; + +import com.aucma.common.annotation.Excel; +import com.aucma.dms.domain.DmsBaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.io.Serializable; + + +public class DmsBaseDeviceLedgerDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 主键标识 */ + private Long deviceId; + + /** 设备编号 */ + @Excel(name = "设备编号") + private String deviceCode; + + /** 设备名称 */ + @Excel(name = "设备名称") + private String deviceName; + + /** 所属工位,关联pd_base_station_info的station_id */ + @Excel(name = "所属工位,关联pd_base_station_info的station_id") + private String stationId; + + /** 资产编号 */ + @Excel(name = "资产编号") + private String assetNumber; + + /** 设备位置 */ + @Excel(name = "设备位置") + private String deviceLocation; + + /** 设备类型,关联dm_base_device_type的device_type_id */ + @Excel(name = "设备类型,关联dm_base_device_type的device_type_id") + private String deviceTypeId; + + /** 设备规格 */ + @Excel(name = "设备规格") + private String deviceSpec; + + /** 供应商,关联dm_base_device_supplier的supplier_id */ + @Excel(name = "供应商,关联dm_base_device_supplier的supplier_id") + private String supplierId; + + /** 设备状态 */ + @Excel(name = "设备状态") + private Long deviceStatus; + + /** 是否标识:1-是;2-否 */ + @Excel(name = "是否标识:1-是;2-否") + private Long isFlag; + + private String suplierName; + + public String getSuplierName() { + return suplierName; + } + + public void setSuplierName(String suplierName) { + this.suplierName = suplierName; + } + + public void setDeviceId(Long deviceId) + { + this.deviceId = deviceId; + } + + public Long getDeviceId() + { + return deviceId; + } + public void setDeviceCode(String deviceCode) + { + this.deviceCode = deviceCode; + } + + public String getDeviceCode() + { + return deviceCode; + } + public void setDeviceName(String deviceName) + { + this.deviceName = deviceName; + } + + public String getDeviceName() + { + return deviceName; + } + public void setStationId(String stationId) + { + this.stationId = stationId; + } + + public String getStationId() + { + return stationId; + } + public void setAssetNumber(String assetNumber) + { + this.assetNumber = assetNumber; + } + + public String getAssetNumber() + { + return assetNumber; + } + public void setDeviceLocation(String deviceLocation) + { + this.deviceLocation = deviceLocation; + } + + public String getDeviceLocation() + { + return deviceLocation; + } + public void setDeviceTypeId(String deviceTypeId) + { + this.deviceTypeId = deviceTypeId; + } + + public String getDeviceTypeId() + { + return deviceTypeId; + } + public void setDeviceSpec(String deviceSpec) + { + this.deviceSpec = deviceSpec; + } + + public String getDeviceSpec() + { + return deviceSpec; + } + public void setSupplierId(String supplierId) + { + this.supplierId = supplierId; + } + + public String getSupplierId() + { + return supplierId; + } + public void setDeviceStatus(Long deviceStatus) + { + this.deviceStatus = deviceStatus; + } + + public Long getDeviceStatus() + { + return deviceStatus; + } + public void setIsFlag(Long isFlag) + { + this.isFlag = isFlag; + } + + public Long getIsFlag() + { + return isFlag; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("deviceId", getDeviceId()) + .append("deviceCode", getDeviceCode()) + .append("deviceName", getDeviceName()) + .append("stationId", getStationId()) + .append("assetNumber", getAssetNumber()) + .append("deviceLocation", getDeviceLocation()) + .append("deviceTypeId", getDeviceTypeId()) + .append("deviceSpec", getDeviceSpec()) + .append("supplierId", getSupplierId()) + .append("deviceStatus", getDeviceStatus()) + .append("isFlag", getIsFlag()) + .toString(); + } + } + + diff --git a/aucma-dms/src/main/java/com/aucma/dms/service/IDmsRepairWorkOrderService.java b/aucma-dms/src/main/java/com/aucma/dms/service/IDmsRepairWorkOrderService.java index 0defb08..c142122 100644 --- a/aucma-dms/src/main/java/com/aucma/dms/service/IDmsRepairWorkOrderService.java +++ b/aucma-dms/src/main/java/com/aucma/dms/service/IDmsRepairWorkOrderService.java @@ -91,4 +91,12 @@ public interface IDmsRepairWorkOrderService { * @return 结果 */ int approveWorkOrder(DmsRepairWorkOrder dmsRepairWorkOrder); + + /** + * 根据故障报修ID查询维修工单 + * + * @param faultInstanceId 故障报修ID + * @return 维修工单 + */ + DmsRepairWorkOrder selectByFaultInstanceId(Long faultInstanceId); } diff --git a/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsRepairWorkOrderServiceImpl.java b/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsRepairWorkOrderServiceImpl.java index a9a9f8e..8147b62 100644 --- a/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsRepairWorkOrderServiceImpl.java +++ b/aucma-dms/src/main/java/com/aucma/dms/service/impl/DmsRepairWorkOrderServiceImpl.java @@ -442,4 +442,15 @@ public class DmsRepairWorkOrderServiceImpl implements IDmsRepairWorkOrderService log.error("为维修工单[{}]创建维修记录失败: {}", workOrder.getWorkOrderCode(), e.getMessage()); } } + + /** + * 根据故障报修ID查询维修工单 + * + * @param faultInstanceId 故障报修ID + * @return 维修工单 + */ + @Override + public DmsRepairWorkOrder selectByFaultInstanceId(Long faultInstanceId) { + return dmsRepairWorkOrderMapper.selectByFaultInstanceId(faultInstanceId); + } }