# 搬运任务操作重构 + PC 端操作功能设计 - 日期:2026-07-15 - 分支:feature/20260713/task-module - 状态:已评审通过(方案 A:单类路由表) ## 1. 背景与目标 任务状态操作目前存在两个入口: - **ACS 入口**:`AcsFeedbackController` → `TransportTaskFeedbackServiceImpl.receiveAcsFeedback()`,用字符串 if-else 按 `status` 分发到 `handleExecuting/handlePicked/handleFinished/handleCancelled`,代码凌乱。 - **PC 入口**:尚不存在。前端 `views/task/transporttask/index.vue` 已有"完成任务/取消任务/强制完成任务"三个按钮,但都错绑在 `handleEdit` 上,未传操作类型。 目标: 1. 消灭 if-else 分发,改为表驱动策略(路由表)。 2. 操作业务代码统一集中到 `TransportTaskServiceImpl`;`handleExecuting/handlePicked/handleFinished/handleCancelled/publishEvent` 方法体**原样迁移**,不改业务逻辑。 3. 新增 PC 端统一操作接口 `POST /task/transport-task/operate`(taskId + operationType),支持 FINISHED / CANCELLED / FORCE-FINISH。 4. `APPLY-AGAIN`(二次请求)、`FORCE-FINISH`(强制完成)业务未开发,路由表中注册 todo 占位(仅打日志)。 5. 前端按钮补齐操作类型标识与调用逻辑。 ## 2. 操作类型与入口矩阵 | 操作类型 | code | ACS 触发 | PC 触发 | 业务 | |---|---|---|---|---| | EXECUTING | EXECUTING | ✅ | ❌ | handleExecuting(已有) | | PICKED | PICKED | ✅ | ❌ | handlePicked(已有) | | FINISHED | FINISHED | ✅ | ✅ | handleFinished(已有) | | CANCELLED | CANCELLED | ✅ | ✅ | handleCancelled(已有) | | APPLY_AGAIN | APPLY-AGAIN | ✅ | ❌ | todo,未开发 | | FORCE_FINISH | FORCE-FINISH | ❌ | ✅ | todo,未开发 | ## 3. 后端设计 ### 3.1 枚举增强 `TaskOperationTypeEnum`(task-api 模块) - 增加两个布尔属性:`acsAllowed`(允许 ACS 触发)、`pcAllowed`(允许 PC 触发),取值见上表。 - 增加静态解析方法 `getByCode(String code)`:忽略大小写匹配 `code`,找不到返回 `null`。 ### 3.2 `TransportTaskServiceImpl`:路由表 + PC 入口 - 从 `TransportTaskFeedbackServiceImpl` **原样迁入**:`handleExecuting`、`handlePicked`、`handleFinished`、`handleCancelled`、`publishEvent`、`buildCallbackReq`(当前无调用方,随迁保留);依赖 `TaskEventProducer`、`TaskCommonApiFactory`、`OBJECT_MAPPER` 相关部分随迁。 - 路由表:`EnumMap>`,在 `@PostConstruct` 中注册六种类型;`APPLY_AGAIN`、`FORCE_FINISH` 注册为 todo 占位(打 log.info,不做业务)。 - 新增接口方法 `dispatchOperation(TransportTaskDO task, TaskOperationTypeEnum type, AcsFeedbackReqDTO reqDTO)`:查路由表分发,查不到打 warn 日志。 - 新增 PC 入口 `operateTransportTask(TransportTaskOperateReqVO reqVO)`,`@Transactional(rollbackFor = Exception.class)`: 1. 查任务,不存在 → 抛 `TRANSPORT_TASK_NOT_EXISTS`。 2. `getByCode` 解析 operationType,为 `null` 或 `pcAllowed=false` → 抛新错误码 `TRANSPORT_TASK_OPERATION_NOT_SUPPORTED`。 3. 任务已终态(79 完成 / 89 取消)→ 抛新错误码 `TRANSPORT_TASK_ALREADY_FINAL`(PC 端需给用户明确反馈,区别于 ACS 入口的静默幂等返回)。 4. **PC 与 ACS 的差异点——记录完成类型/来源**:`FINISHED` → `task.setFinishedType("MANUAL")`(人工完成);`FORCE_FINISH` → `task.setFinishedType("FORCE")`(强制完成);`CANCELLED` 不设置。注意:`FORCE_FINISH` 的业务 handler 当前为 todo 占位、不执行 `updateById`,因此该 finishedType 设置在业务开发完成前不会实际落库,属预期行为。 5. 构造仅含 `taskId`、`status` 的 `AcsFeedbackReqDTO`,调用 `dispatchOperation` 走同一路由表(保持 handler 签名不变)。 - 新错误码追加到 `ErrorCodeConstants`,编号顺延现有 task 模块段。 ### 3.3 `TransportTaskFeedbackServiceImpl` 瘦身 只保留 ACS 前置处理,注入 `TransportTaskService` 后委托分发: 1. 查任务(不存在打 warn 返回,保持现状)。 2. 终态幂等判断(保持现状)。 3. 保存 `resultParam`(保持现状)。 4. 分发段替换为: ```java TaskOperationTypeEnum type = TaskOperationTypeEnum.getByCode(reqDTO.getStatus()); if (type == null || !type.isAcsAllowed()) { log.warn("未知或不允许的 ACS 反馈状态, taskId={}, status={}", reqDTO.getTaskId(), reqDTO.getStatus()); return; } transportTaskService.dispatchOperation(task, type, reqDTO); ``` `handle*`、`publishEvent`、`buildCallbackReq` 从此类删除。依赖方向为 Feedback → TransportTaskService 单向,无循环依赖;`receiveAcsFeedback` 的 `@Transactional` 保持,跨 Bean 调用按 REQUIRED 传播沿用同一事务。 ### 3.4 Controller / VO - `TransportTaskController` 新增: ```java @PostMapping("/operate") @Operation(summary = "PC 端操作搬运任务(完成/取消/强制完成)") @PreAuthorize("@ss.hasPermission('task:transport-task:operate')") public CommonResult operateTransportTask(@Valid @RequestBody TransportTaskOperateReqVO reqVO) ``` - 新 VO `TransportTaskOperateReqVO`(controller vo 包):`@NotNull Long taskId`;`@NotEmpty String operationType`(取值 FINISHED/CANCELLED/FORCE-FINISH)。 ## 4. 前端设计(web-antdv-next) ### 4.1 API(`api/task/transporttask/index.ts`) ```ts /** PC 端操作搬运任务(完成/取消/强制完成) */ export function operateTransportTask(data: { operationType: string; taskId: number; }) { return requestClient.post('/task/transport-task/operate', data); } ``` ### 4.2 页面(`views/task/transporttask/index.vue`) - 新增操作函数: ```ts async function handleOperate( row: TaskTransportTaskApi.TransportTask, operationType: string, label: string, ) { await confirm(`确认要${label}【${row.taskCode}】吗?`); await operateTransportTask({ taskId: row.taskId!, operationType }); message.success(`${label}成功`); handleRefresh(); } ``` - 三个按钮 `onClick` 替换错绑的 `handleEdit`: - 完成任务 → `handleOperate(row, 'FINISHED', '完成任务')` - 取消任务 → `handleOperate(row, 'CANCELLED', '取消任务')` - 强制完成任务 → `handleOperate(row, 'FORCE-FINISH', '强制完成任务')` - 备注:强制完成按钮当前 `auth` 复用 `task:transport-task:cancel`、icon 用 `CANCEL`,本次不调整权限(需菜单配套),仅修正绑定。 ## 5. 错误处理 - PC 入口:任务不存在 / 操作类型不支持 / 任务已终态,均抛 ServiceException,由全局异常处理返回给前端提示。 - ACS 入口:保持现状(不存在/终态/未知状态均打日志静默返回成功,避免 ACS 重试)。 - MQ 发布失败:沿用 `publishEvent` 现有逻辑(callbackStatus=FAILED + 记录错误信息)。 ## 6. 测试与验证 - 按项目约定本次不编写测试(CLAUDE.md:除非用户允许测试)。 - 验证方式:后端 `mvn compile`(task 模块)通过;前端 lint/类型检查通过。 ## 7. 范围外(明确不做) - APPLY-AGAIN、FORCE-FINISH 的具体业务实现(todo 占位)。 - 强制完成按钮的独立权限与菜单配置。 - PC 操作联动 ACS(如向 ACS 下发取消指令)。 - `finishedType` 的字典配置与前端字典展示。