You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
zs_aucma-mes-back/aucma-dms/DmsBillsFaultInstance_重构方案.md

33 KiB

DmsMobileController 故障报修重构方案

文档版本: 3.1 创建日期: 2026-02-05 最后更新: 2026-02-05 作者: Claude AI 项目: AUCMA-MES 设备管理系统 模块: DMS 设备管理 - PDA故障报修

重要说明

  1. 本方案仅关注 DmsMobileController 的重构保持PDA完美兼容内部补全完整业务流程
  2. DmsBillsFaultInstanceController 为Web端接口不在本次重构范围
  3. 设备信息改为使用 BaseDeviceLedgerbase模块但返回类型为 DmsBaseDeviceLedgerdms模块需要进行字段转换

一、重构背景

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 方法改造

改造前

@PostMapping("/startRepair")
public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity activity) {
    // 直接更新操作记录
    // ❌ 缺少维修工单创建
    // ❌ 缺少派工计划创建
    // ❌ 缺少状态同步
}

改造后

@PostMapping("/startRepair")
public AjaxResult startRepair(@RequestBody DmsFaultInstanceActivity activity) {
    // 1. 查询故障报修
    // 2. 检查是否已有维修工单,没有则创建
    // 3. 【断点1】更新故障报修状态为"维修中"
    // 4. 创建派工计划
    // 5. 【断点2】自动接收派工
    // 6. 更新维修工单状态为"维修中"
    // 7. 更新操作记录
}

2.2.2 completeRepair 方法改造

改造前

@PostMapping("/completeRepair")
public AjaxResult completeRepair(...) {
    // 直接更新操作记录
    // ❌ 缺少维修记录创建
    // ❌ 缺少状态同步
}

改造后

@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 依赖注入(新增)

@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 方法完整重构

/**
 * 开始维修
 *
 * 【重构说明】
 * - 保持接口路径和参数格式不变
 * - 内部补全维修工单和派工计划的创建逻辑
 * - 触发断点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 方法完整重构

/**
 * 完成维修
 *
 * 【重构说明】
 * - 保持接口路径和参数格式不变
 * - 内部补全维修记录的创建逻辑
 * - 触发断点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<MultipartFile> 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<DmsFaultCompentsParts> 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<DmsFaultCompentsParts> parsePartsJson(String parts1) {
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(parts1,
            new TypeReference<List<DmsFaultCompentsParts>>() {});
    } catch (Exception e) {
        log.error("解析配件JSON失败", e);
        return new ArrayList<>();
    }
}

4.5 设备信息字段转换(重要)

4.5.1 字段差异说明

需求DmsMobileController 中所有设备信息改为使用 BaseDeviceLedgeraucma-base模块但返回类型为 DmsBaseDeviceLedgeraucma-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 字段转换方法

/**
 * 将 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<DmsBaseDeviceLedger> convertToDmsBaseDeviceLedgerList(List<BaseDeviceLedger> baseLedgerList) {
    if (CollectionUtils.isEmpty(baseLedgerList)) {
        return new ArrayList<>();
    }

    List<DmsBaseDeviceLedger> dmsLedgerList = new ArrayList<>();
    for (BaseDeviceLedger baseLedger : baseLedgerList) {
        dmsLedgerList.add(convertToDmsBaseDeviceLedger(baseLedger));
    }
    return dmsLedgerList;
}

4.5.3 需要修改的方法

方法1getDeviceByDeviceCodeLine 75-79

修改前

@GetMapping("/getDeviceByDeviceCode/{deviceCode}")
public AjaxResult getDeviceByDeviceCode(@PathVariable("deviceCode") String deviceCode) {
    DmsBaseDeviceLedger dmsBaseDeviceLedger = baseDeviceLedgerService.selectDmsBaseDeviceLedgerByDeviceCode(deviceCode);
    return success(dmsBaseDeviceLedger);
}

修改后

@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);
}

方法2likeDeviceNameLine 102-106

修改前

@GetMapping("/likeDeviceName")
public AjaxResult likeDeviceName(String deviceName) {
    List<DmsBaseDeviceLedger> deviceLedgerList = baseDeviceLedgerService.likeDeviceName(deviceName);
    return success(deviceLedgerList);
}

修改后

@GetMapping("/likeDeviceName")
public AjaxResult likeDeviceName(String deviceName) {
    // 1. 使用 BaseDeviceLedger 查询
    List<BaseDeviceLedger> baseLedgerList = baseDeviceLedgerService.likeBaseDeviceName(deviceName);

    // 2. 批量转换为 DmsBaseDeviceLedger 返回
    List<DmsBaseDeviceLedger> 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 单元测试

@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. 新增依赖注入
- IBaseDeviceLedgerServicebase模块
- IDmsRepairWorkOrderService
- IDmsDispatchPlanService
- IDmsRepairRecordService

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

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

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

5. 新增辅助方法
- parsePartsJson() - 解析配件JSON
仅PDA端Web端不受影响

修改详细说明

新增导入

import com.aucma.base.domain.BaseDeviceLedger;
import com.aucma.base.service.IBaseDeviceLedgerService;
import org.springframework.beans.BeanUtils;

字段转换关键点

  • 主键:objIddeviceId
  • 设备类型:deviceTypedeviceTypeId
  • 设备型号:deviceModeldeviceSpec
  • 供应商:manufacturersuplierName

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 依赖注入清单

// 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 核心方法签名

// 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<MultipartFile> 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端接口不在本次重构范围。

重要更新:设备信息查询改为使用 BaseDeviceLedgerbase模块通过字段转换方法转换为 DmsBaseDeviceLedgerdms模块返回给PDA端。