编辑 | blame | 历史 | 原始文档

取消原因同步到DispatchOrd功能说明

功能概述

在转运任务取消时,自动将取消原因同步到旧系统的DispatchOrd表中,记录到DispatchOrdCancelReason(取消原因ID)和DispatchOrdCancelReasonTXT(取消原因文本)字段。

实现方式

1. 核心流程

当任务状态变更为"已取消"时:
1. 监听器(DispatchOrdRunningListener)检测到取消状态
2. 从sys_task_emergency表获取取消原因(cancelReason字段,存储数据字典value)
3. 将取消原因value转换为Integer作为DispatchOrdCancelReason
4. 从数据字典task_cancel_reason查询对应的中文标签作为DispatchOrdCancelReasonTXT
5. 执行UPDATE语句更新DispatchOrd表

2. 数据映射关系

新系统字段 新系统表 旧系统字段 旧系统表 说明
cancel_reason sys_task_emergency DispatchOrdCancelReason DispatchOrd 取消原因ID(数字)
字典label sys_dict_data DispatchOrdCancelReasonTXT DispatchOrd 取消原因文本(中文)

3. 取消原因字典

数据字典类型:task_cancel_reason

包含26个取消原因选项:
1. 价格不接受
2. 时间紧急
3. 出车速度慢
4. 选择其他车
5. 病人没有生命体征
6. 医生护士均不足
7. 病人情况有变
8. 其他
9. 第三方取消
10. 测试订单
11. 传染性疾病
12. 家属挂机/拒接/不接电话
13. 护士不足
14. 医生不足
15. 设备不足(呼吸机)
16. 家属没联系好床位
17. 移交分支机构执行
18. 移交办事处(湛江)
19. 移交办事处(茂名)
20. 家属不肯透露信息
21. 所在医院/目的地医院派车
22. 自驾车接送患者
23. 选择其他机构车辆
24. 外联通知取消
25. 外联无反馈
26. 家属无原因直接告知取消

代码修改清单

1. DispatchOrdMapper.java

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/mapper/DispatchOrdMapper.java

新增方法:
java /** * 更新调度单取消原因 * * @param dispatchOrdID 调度单ID * @param cancelReasonId 取消原因ID * @param cancelReasonText 取消原因文本 * @return 影响行数 */ public int updateDispatchOrdCancelReason(@Param("dispatchOrdID") Long dispatchOrdID, @Param("cancelReasonId") Integer cancelReasonId, @Param("cancelReasonText") String cancelReasonText);

2. DispatchOrdMapper.xml

文件路径: ruoyi-system/src/main/resources/mapper/system/DispatchOrdMapper.xml

新增SQL:
xml <!-- 更新调度单取消原因 --> <update id="updateDispatchOrdCancelReason"> update DispatchOrd set DispatchOrdCancelReason = #{cancelReasonId}, DispatchOrdCancelReasonTXT = #{cancelReasonText} where DispatchOrdID = #{dispatchOrdID} </update>

3. DispatchOrdRunningListener.java

文件路径: ruoyi-system/src/main/java/com/ruoyi/system/listener/DispatchOrdRunningListener.java

新增依赖注入:
```java
@Autowired
private DispatchOrdMapper dispatchOrdMapper;

@Autowired
private SysDictDataMapper sysDictDataMapper;
```

新增import:
java import com.ruoyi.system.mapper.DispatchOrdMapper; import com.ruoyi.system.mapper.SysDictDataMapper;

修改handleTaskStatusChangedEvent方法:
在状态转换后增加取消原因同步逻辑(第122-126行):
java // 如果是取消状态,同步取消原因到DispatchOrd表 if (TaskStatus.CANCELLED.equals(newTaskStatus) && emergency.getCancelReason() != null) { syncCancelReasonToDispatchOrd(emergency.getLegacyDispatchOrdId(), emergency.getCancelReason()); }

新增方法:
```java
/**
* 同步取消原因到DispatchOrd表
*
* @param dispatchOrdId 调度单ID
* @param cancelReason 取消原因(字典value)
*/
private void syncCancelReasonToDispatchOrd(Long dispatchOrdId, String cancelReason) {
try {
if (cancelReason == null || cancelReason.isEmpty()) {
log.debug("取消原因为空,跳过同步,DispatchOrdID: {}", dispatchOrdId);
return;
}

    // 将cancelReason(字典value)转换为Integer
    Integer cancelReasonId = null;
    try {
        cancelReasonId = Integer.valueOf(cancelReason);
    } catch (NumberFormatException e) {
        log.error("取消原因格式错误,无法转换为数字,cancelReason: {}, DispatchOrdID: {}", cancelReason, dispatchOrdId);
        return;
    }

    // 从数据字典中查询取消原因文本
    String cancelReasonText = sysDictDataMapper.selectDictLabel("task_cancel_reason", cancelReason);
    if (cancelReasonText == null || cancelReasonText.isEmpty()) {
        log.warn("未找到取消原因对应的文本,cancelReason: {}, DispatchOrdID: {}", cancelReason, dispatchOrdId);
        cancelReasonText = cancelReason; // 使用原值作为预备
    }

    log.info("开始同步取消原因到DispatchOrd,DispatchOrdID: {}, 取消原因ID: {}, 取消原因文本: {}", 
        dispatchOrdId, cancelReasonId, cancelReasonText);

    // 调用Mapper更新DispatchOrd表
    int rows = dispatchOrdMapper.updateDispatchOrdCancelReason(dispatchOrdId, cancelReasonId, cancelReasonText);

    if (rows > 0) {
        log.info("成功同步取消原因到DispatchOrd,DispatchOrdID: {}, 取消原因: {} ({})", 
            dispatchOrdId, cancelReasonText, cancelReasonId);
    } else {
        log.warn("同步取消原因失败,未找到对应的调度单,DispatchOrdID: {}", dispatchOrdId);
    }

} catch (Exception e) {
    log.error("同步取消原因到DispatchOrd异常,DispatchOrdID: {}, 取消原因: {}", 
        dispatchOrdId, cancelReason, e);
    // 不抛出异常,避免影响主流程
}

}
```

执行SQL示例

当取消原因为"价格不接受"(value=1)时,实际执行的SQL:

UPDATE DispatchOrd 
SET DispatchOrdCancelReason = 1,
    DispatchOrdCancelReasonTXT = '价格不接受'
WHERE DispatchOrdID = 12345

同步条件

取消原因同步需要满足以下条件:
1. ✅ 旧系统同步已启用
2. ✅ 任务类型为急救转运任务(EMERGENCY_TRANSFER)
3. ✅ 任务已同步到旧系统(有legacyDispatchOrdId)
4. ✅ 任务状态变更为"已取消"(CANCELLED)
5. ✅ 任务记录了取消原因(cancelReason不为空)

执行时机

异步执行:任务状态变更为"已取消"时,通过事件监听器异步处理,不影响主业务流程。

日志说明

正常日志

INFO - 收到任务状态变更事件,准备同步到DispatchOrd_Running,任务ID:1001,旧状态:PENDING,新状态:CANCELLED
INFO - 开始同步取消原因到DispatchOrd,DispatchOrdID: 12345, 取消原因ID: 1, 取消原因文本: 价格不接受
INFO - 成功同步取消原因到DispatchOrd,DispatchOrdID: 12345, 取消原因: 价格不接受 (1)

跳过日志

DEBUG - 取消原因为空,跳过同步,DispatchOrdID: 12345

异常日志

WARN - 未找到取消原因对应的文本,cancelReason: 99, DispatchOrdID: 12345
ERROR - 取消原因格式错误,无法转换为数字,cancelReason: abc, DispatchOrdID: 12345
WARN - 同步取消原因失败,未找到对应的调度单,DispatchOrdID: 12345
ERROR - 同步取消原因到DispatchOrd异常,DispatchOrdID: 12345, 取消原因: 1

验证方法

1. 数据库验证

查询DispatchOrd表的取消原因字段:
sql SELECT DispatchOrdID, DispatchOrdState, DispatchOrdCancelReason, DispatchOrdCancelReasonTXT FROM DispatchOrd WHERE DispatchOrdID = 12345

2. 测试步骤

  1. 在新系统创建转运任务并同步到旧系统
  2. 在任务详情页点击"取消"按钮
  3. 选择取消原因(如"价格不接受")
  4. 确认取消
  5. 检查应用日志,确认同步成功
  6. 查询DispatchOrd表,验证取消原因字段已更新

3. 预期结果

  • DispatchOrdCancelReason = 1
  • DispatchOrdCancelReasonTXT = "价格不接受"

特性说明

  1. 异步处理:不阻塞主业务流程,提高系统响应速度
  2. 容错机制:同步失败不影响任务取消操作
  3. 完整日志:记录详细的同步过程和结果
  4. 数据转换:自动将字典value转换为ID和文本
  5. 事件驱动:利用Spring事件机制实现解耦
  6. 自动同步:无需手动触发,状态变更时自动执行

注意事项

  1. 仅限取消状态:只有任务状态变更为CANCELLED时才会同步取消原因
  2. 依赖调度单同步:必须先同步到旧系统才能更新取消原因
  3. 异常不中断:同步异常只记录日志,不抛出异常,不影响主流程
  4. 数据库字段:确保DispatchOrd表有DispatchOrdCancelReason和DispatchOrdCancelReasonTXT字段
  5. 字典依赖:依赖数据字典task_cancel_reason正确配置

相关文档

更新日志

  • 2025-12-26: 实现取消原因同步到DispatchOrd功能