# 批量测试 - 故障车辆手动恢复 前端对接指引 > 适用版本:`feat-virture-order-contine-for-single-car` 分支 > 后端服务:`xp-robotaxi-operation-boot` > 文档版本:2026-06-07 --- ## 一、需求背景 批量测试执行过程中,若某辆车发生故障(GPS 卡死、车端异常等)导致 `ORDER_NEAR_DESTINATION_EVENT` 事件无法上送,链式回调链路会中断,该车辆停留在某一段订单上无法继续。 为此新增「**故障车辆手动恢复**」功能:人工确认车辆已修复且旧订单已无法继续后,前端调用恢复接口,后端将卡住的旧订单标记为已取消并模拟链式回调推进下一段,使该车辆重新进入批量测试流程。 --- ## 二、新增接口 ### POST `/api/v1/xp-test-plan/manualResume` **用途**:手动恢复故障车辆,跳过当前卡死的订单,推进至下一段。 **请求方式**:`application/x-www-form-urlencoded`(Query / Form 参数,**非 JSON Body**) | 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `testPlanId` | Long | 是 | 测试计划 ID | | `vehicleId` | Long | 是 | 故障车辆 ID | | `currentOrderId` | Long | 是 | 该车辆当前进行中的故障订单 ID(必须等于车辆进度表中的 `currentOrderId`) | **响应**: ```json { "code": 200, "msg": "操作成功", "data": true } ``` **业务校验**(任一失败均返回 500 错误,`msg` 中带具体原因): | 校验 | 错误信息 | | --- | --- | | 订单 ID 必须能在进度表中查到 | `未找到订单对应的车辆进度: {orderId}` | | 订单所属计划/车辆必须与传入参数一致 | `订单与测试计划/车辆不匹配,无法恢复` | | 车辆进度状态必须是 RUNNING(0) | `车辆进度非运行中,无法恢复` | **幂等性**:恢复成功后,车辆进度的 `currentOrderId` 会被链式回调清空并替换为下一段订单 ID。前端再传旧 `currentOrderId` 会触发"订单与测试计划/车辆不匹配"。 --- ## 三、前端调用前置条件 调用 `manualResume` 之前,必须确认以下信息(建议从 `vehicleProgress` 接口获取): 1. 当前批次状态为 RUNNING(批次已取消则恢复无意义) 2. 目标车辆 `status` = `RUNNING`(COMPLETED / ERROR / CANCELLED 不能恢复) 3. 当前 `currentOrderId` 真实存在且确实卡死(建议先与现场人员确认) --- ## 四、推荐 UI 交互 ### 入口位置 批量测试详情页 → 车辆进度列表 → 每行操作列。 ### 显示条件 仅当 **`status === RUNNING`** 时显示「故障恢复」按钮。 ### 二次确认弹窗 执行前必须强提示用户: > ⚠️ 故障恢复将跳过订单 `{currentOrderId}`,并立即派发该车辆的下一段订单。 > - 此操作**仅适用于车辆故障已修复、旧订单确认无法继续的场景** > - 旧订单将被标记为「已取消」,**不会**通知车端 > - 操作前请确认车端已不再执行旧订单,否则可能与新订单冲突 > > 是否继续? ### 调用示例(伪代码) ```typescript // services/testPlan.ts export const manualResume = (params: { testPlanId: number | string vehicleId: number | string currentOrderId: number | string }) => request.post('/api/v1/xp-test-plan/manualResume', null, { params }) // 组件调用 const handleManualResume = async (row: VehicleProgressVO) => { await Modal.confirm({ /* 上面的二次确认文案 */ }) const res = await manualResume({ testPlanId, vehicleId: row.vehicleId, currentOrderId: row.currentOrderId, }) if (res.code === 200) { message.success('已触发故障恢复') refreshVehicleProgress() // 刷新车辆进度列表 } else { message.error(res.msg) } } ``` --- ## 五、相关接口(对接时可能用到) 完整批量测试模块可参考下表,**前端根据现有页面已有的对接情况选择性使用**: | 接口 | Method | 路径 | 主要作用 | | --- | --- | --- | --- | | 启动批量 | POST | `/api/v1/xp-test-plan/batchStart` | 启动批量测试,参数:`{testPlanId, lapCount}` | | 批次进度 | GET | `/api/v1/xp-test-plan/batchProgress?testPlanId=` | 总进度(创建/完成/异常数 + 状态) | | 车辆进度 | GET | `/api/v1/xp-test-plan/vehicleProgress?batchId=` | **故障恢复按钮所在列表的数据来源** | | 重试失败 | POST | `/api/v1/xp-test-plan/batchRetry?testPlanId=` | 批次结束后重跑 ERROR 车辆 | | **故障恢复** | **POST** | **`/api/v1/xp-test-plan/manualResume`** | **本次新增** | | 取消批次 | POST | `/api/v1/xp-test-plan/batchCancel?testPlanId=` | 强制中止整个批次 | ### `VehicleProgressVO` 字段(车辆进度列表项) | 字段 | 类型 | 说明 | | --- | --- | --- | | `vehicleId` | Long | 车辆 ID | | `plateNumber` | String | 车牌号 | | `currentLap` | Integer | 当前圈数 | | `currentSegment` | Integer | 当前路线段索引 | | `currentOrderId` | Long | **当前进行中订单 ID**(manualResume 必传) | | `totalLaps` | Integer | 总圈数 | | `totalSegments` | Integer | 每圈路线段数 | | `status` | String | `RUNNING` / `COMPLETED` / `ERROR` / `CANCELLED` | | `errorMsg` | String | 错误信息(仅 ERROR 状态有值) | ### `BatchProgressVO` 字段(批次进度) | 字段 | 类型 | 说明 | | --- | --- | --- | | `batchId` | Long | 批次 ID | | `totalCount` | Integer | 预计总订单数 = 车辆数 × 段数 × 圈数 | | `createdCount` | Integer | 已创建数 | | `completedCount` | Integer | 已完结数(**含手动恢复跳过的订单**) | | `errorCount` | Integer | 异常数 | | `status` | String | `RUNNING` / `SUCCESS` / `PARTIAL_SUCCESS` / `FAILED` / `CANCELLED` | | `startTime` | DateTime | 开始时间 | | `endTime` | DateTime | 结束时间 | --- ## 六、注意事项与对接 FAQ **Q1:故障恢复后,统计数字会怎么变化?** A:`completedCount` 会 +1(与正常订单完成等同处理),`createdCount` 在派发下一段后再 +1。**前端无需特殊展示"恢复"标记**,统计接口本身不区分。如需区分需另开发审计字段,本期未做。 **Q2:手动恢复成功后是否需要前端轮询?** A:建议保持现有的车辆进度轮询节奏即可(一般 2-5s 一次),无需为本接口单独加轮询逻辑。后端动作是同步的,接口返回成功即代表"标记取消 + 链式回调推进"已执行完毕。 **Q3:能否在批次已 CANCELLED 后调用?** A:不能。批次取消后会写入 Redis 取消标记,链式回调内部自动拦截。但前端最好在 UI 层就根据 `status` 隐藏按钮,避免误触发。 **Q4:连续点击多次会不会重复推进?** A:不会。`currentOrderId` 校验天然幂等——第二次调用时旧 orderId 已不在进度表,会返回"订单与测试计划/车辆不匹配"。 **Q5:恢复失败后该怎么办?** A:根据 `msg` 提示分情况: - "未找到订单"/"不匹配" → 数据已变化,先刷新进度列表 - "非运行中" → 该车辆已 ERROR/CANCELLED,使用 `batchRetry` 而非本接口 - 网络/系统异常 → 建议提示用户稍后重试 **Q6:是否需要权限控制?** A:与 `batchStart`/`batchCancel` 一致,已通过后端 `@AdminOperationLog` 记录操作日志。前端按现有运营管理后台的权限策略管控按钮即可。