# 转运任务取消原因功能实现说明
## 一、功能概述
为转运任务增加取消原因记录功能,当用户取消任务时,需要选择取消原因并记录取消人和取消时间。
## 二、数据库变更
### 2.1 sys_task_emergency表增加三个字段
执行SQL脚本:`sql/add_cancel_reason_fields.sql`
```sql
ALTER TABLE sys_task_emergency
ADD COLUMN cancel_reason VARCHAR(50) COMMENT '取消原因(关联数据字典task_cancel_reason)';
ALTER TABLE sys_task_emergency
ADD COLUMN cancel_by VARCHAR(64) COMMENT '取消人';
ALTER TABLE sys_task_emergency
ADD COLUMN cancel_time DATETIME COMMENT '取消时间';
```
### 2.2 数据字典配置
执行SQL脚本:`sql/insert_dict_task_cancel_reason.sql`
添加数据字典类型 `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. 家属无原因直接告知取消
## 三、后端修改
### 3.1 实体类修改
**文件**: `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java`
添加三个字段属性:
- `private String cancelReason;` - 取消原因
- `private String cancelBy;` - 取消人
- `private java.util.Date cancelTime;` - 取消时间
### 3.2 Mapper XML修改
**文件**: `ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml`
在`resultMap`、`selectSysTaskEmergencyVo`、`insertSysTaskEmergency`、`updateSysTaskEmergency`中添加三个字段的映射和处理。
### 3.3 控制器修改
**文件**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java`
#### 3.3.1 ChangeStatusRequest增加字段
```java
private String cancelReason; // 取消原因(关联数据字典task_cancel_reason)
```
#### 3.3.2 修改appChangeTaskStatus方法
在状态变更方法中添加取消原因处理逻辑:
```java
// 如果是取消状态,保存取消原因
if (newStatus == TaskStatus.CANCELLED && StringUtils.isNotEmpty(request.getCancelReason())) {
sysTaskService.saveCancelInfo(taskId, request.getCancelReason());
}
```
### 3.4 服务层修改
**文件**: `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java`
添加接口方法:
```java
/**
* 保存任务取消信息(仅限转运任务)
*
* @param taskId 任务ID
* @param cancelReason 取消原因(数据字典task_cancel_reason的value)
* @return 结果
*/
public int saveCancelInfo(Long taskId, String cancelReason);
```
**文件**: `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java`
实现saveCancelInfo方法,保存取消原因、取消人和取消时间:
```java
@Override
@Transactional
public int saveCancelInfo(Long taskId, String cancelReason) {
// 获取任务信息
SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
if (task == null) {
throw new RuntimeException("任务不存在");
}
// 只有转运任务才保存取消信息
if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
return 0;
}
// 获取转运任务扩展信息
SysTaskEmergency emergency = sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
if (emergency == null) {
return 0;
}
// 设置取消信息
emergency.setCancelReason(cancelReason);
emergency.setCancelBy(SecurityUtils.getUsername());
emergency.setCancelTime(DateUtils.getNowDate());
emergency.setUpdateBy(SecurityUtils.getUsername());
emergency.setUpdateTime(DateUtils.getNowDate());
// 更新数据库
return sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
}
```
## 四、前端修改
### 4.1 任务详情页修改
**文件**: `app/pagesTask/detail.vue`
#### 4.1.1 data中添加字段
```javascript
data() {
return {
taskDetail: null,
taskId: null,
paymentInfo: null,
cancelReasonList: [], // 取消原因列表
showCancelDialog: false, // 显示取消原因对话框
selectedCancelReason: '' // 选中的取消原因
}
}
```
#### 4.1.2 onLoad中加载字典
```javascript
onLoad(options) {
this.taskId = options.id
this.loadTaskDetail()
this.loadCancelReasonDict() // 加载取消原因字典
}
```
#### 4.1.3 修改取消按钮处理逻辑
```javascript
case 'cancel':
// 取消 -> 显示取消原因选择对话框
this.showCancelReasonDialog();
break;
```
#### 4.1.4 添加方法
- `loadCancelReasonDict()` - 从后端加载取消原因字典
- `showCancelReasonDialog()` - 显示取消原因选择弹窗
- `confirmCancelTask()` - 确认取消任务
- `closeCancelDialog()` - 关闭取消弹窗
- `selectCancelReason(e)` - 选择取消原因
- `updateTaskStatusWithCancelReason()` - 带取消原因的状态更新
- `getCancelReasonLabel()` - 根据value获取label显示
#### 4.1.5 修改getLocationAndUpdateStatus方法
添加cancelReason参数,在状态更新请求中传递取消原因:
```javascript
// 如果有取消原因,添加到请求数据中
if (cancelReason) {
statusData.cancelReason = cancelReason
}
```
#### 4.1.6 添加UI组件
**取消原因选择弹窗**:
```vue
请选择取消原因
取消原因
{{ selectedCancelReason ? cancelReasonList.find(r => r.value === selectedCancelReason)?.label : '请选择' }}
```
**取消信息显示区域**(仅在任务已取消且有取消原因时显示):
```vue
取消信息
取消原因
{{ getCancelReasonLabel(taskDetail.emergencyInfo.cancelReason) }}
取消人
{{ taskDetail.emergencyInfo.cancelBy }}
取消时间
{{ formatTime(taskDetail.emergencyInfo.cancelTime) }}
```
#### 4.1.7 添加样式
为取消原因弹窗添加样式,包括对话框、选择器和按钮样式。
## 五、使用流程
### 5.1 取消任务流程
1. 用户在任务详情页点击"取消"按钮
2. 系统弹出取消原因选择对话框
3. 用户从26个预设选项中选择取消原因
4. 用户点击"确定"按钮
5. 系统调用状态更新接口,传递取消原因
6. 后端保存取消原因、取消人(当前用户)和取消时间(当前时间)
7. 任务状态变更为"已取消"
### 5.2 查看取消信息
在任务详情页,如果任务状态为"已取消"且记录了取消原因,会在费用信息下方显示"取消信息"区块,包括:
- 取消原因(显示中文标签)
- 取消人
- 取消时间
## 六、注意事项
1. **仅限转运任务**:取消原因功能仅对转运任务(EMERGENCY_TRANSFER)生效
2. **强制选择**:取消任务时必须选择取消原因,否则无法提交
3. **自动记录**:取消人和取消时间由系统自动记录,无需用户输入
4. **不可修改**:取消信息一旦保存不可修改
5. **数据字典依赖**:需要先执行数据字典SQL脚本,否则前端无法加载取消原因列表
## 七、文件清单
### SQL文件
- `sql/add_cancel_reason_fields.sql` - 添加数据库字段
- `sql/insert_dict_task_cancel_reason.sql` - 插入数据字典
### 后端文件
- `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java`
- `ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml`
- `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java`
- `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java`
- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java`
### 前端文件
- `app/pagesTask/detail.vue`
## 八、测试建议
1. 测试取消原因弹窗是否正常显示
2. 测试选择不同取消原因后是否正确保存
3. 测试未选择取消原因时是否阻止提交
4. 测试取消信息是否正确显示
5. 测试非转运任务点击取消是否正常(不应显示取消原因弹窗)
6. 测试已取消的任务是否正确显示取消信息