docs: 交接车务派单全链路 E2E 前端缺陷 (#5279) #43
@ -0,0 +1,229 @@
|
|||||||
|
---
|
||||||
|
schema: "hl-changelog/v2"
|
||||||
|
ticket: "5279"
|
||||||
|
title: "车务派单全链路 E2E 前端缺陷交接"
|
||||||
|
consumer: "admin"
|
||||||
|
change_type: "修改接口"
|
||||||
|
backend_status: "deployed"
|
||||||
|
gateway_status: "verified"
|
||||||
|
frontend_status: "pending"
|
||||||
|
frontend_owner: ""
|
||||||
|
frontend_ref: ""
|
||||||
|
target_release: ""
|
||||||
|
verified_at: ""
|
||||||
|
status_note: "本次没有新增或修改后端字段、类型、必填性、路径和错误码;测试环境当前契约已验证。前端需修正动作码、部分日期、HOLD 费用草稿、刷新重置和冲突日期等消费逻辑。"
|
||||||
|
updated_at: "2026-07-27"
|
||||||
|
base: "dev-v3"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 车务:派单全链路 E2E 前端缺陷交接
|
||||||
|
|
||||||
|
> **服务**: `hl-fleet-service`、`hl-order-service-v3`
|
||||||
|
>
|
||||||
|
> **工单**: [wx/HL#5279](https://git.1814.love:8443/wx/HL/issues/5279)
|
||||||
|
>
|
||||||
|
> **前端基线**: `mmg/hl-ui v2.1@5e6718f952ed156c2e71bc38d08c3482e72ba744`
|
||||||
|
>
|
||||||
|
> **影响范围**: 车务管理 → 派单看板、矩阵派单、派车弹窗、派单详情;订单详情 → 用车需求调整
|
||||||
|
|
||||||
|
## 结论
|
||||||
|
|
||||||
|
这是一份**当前契约消费纠错和前端缺陷交接**,不是后端接口变更:
|
||||||
|
|
||||||
|
- 后端 #5275 已保证部分日期派车只消费目标切片,剩余日期和稳定槽位守恒;
|
||||||
|
- 后端 #5277 已恢复完整已派需求 `canAssign=true + CHANGE_ASSIGNMENT`;
|
||||||
|
- 测试环境通过真实后台 UI 完成 HOLD、DIRECT、司机确认、最终确认、司机拒接、改车、改司机、需求驳回/换版/重派、逐日费用、免费服务日、冲突和重复提交;
|
||||||
|
- 当前剩余阻断均可在最新前端稳定复现,后端不应增加旧动作码别名或重复状态来迁就页面。
|
||||||
|
|
||||||
|
## 变更接口
|
||||||
|
|
||||||
|
本次不新增接口、字段或错误码,仅纠正以下现有管理后台接口的前端消费:
|
||||||
|
|
||||||
|
| 方法 | 路径 | 当前契约用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `GET` | `/admin/fleet/board/orders` | 看板代表行、能力字段、稳定槽位和未派切片上下文 |
|
||||||
|
| `GET` | `/admin/fleet/board/orders/<orderId>` | 当前有效派车组、逐日费用和独立生命周期 |
|
||||||
|
| `POST` | `/admin/fleet/assignments/candidates` | 车辆/司机可用窗口与真实冲突明细 |
|
||||||
|
| `POST` | `/admin/fleet/assignments` | HOLD/DIRECT 首次派车 |
|
||||||
|
| `POST` | `/admin/fleet/assignments/<assignmentId>/change` | 按稳定槽位改车、改司机或同时改派 |
|
||||||
|
| `POST` | `/admin/fleet/assignments/<assignmentId>/driver-confirmation` | 登记司机回复 |
|
||||||
|
| `POST` | `/admin/fleet/assignments/<assignmentId>/confirm` | 最终确认执行 |
|
||||||
|
| `POST` | `/admin/fleet/assignments/<assignmentId>/driver-reject` | 司机拒接并退回未派 |
|
||||||
|
| `DELETE` | `/admin/fleet/assignments/<assignmentId>` | 取消派单 |
|
||||||
|
| `POST` | `/admin/fleet/assignments/<assignmentId>/early-complete` | 提前完结 |
|
||||||
|
|
||||||
|
## 一、动作码必须消费后端当前值
|
||||||
|
|
||||||
|
权威字段来自:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /admin/fleet/board/orders
|
||||||
|
GET /admin/fleet/board/orders/<orderId>
|
||||||
|
```
|
||||||
|
|
||||||
|
前端按 `canAssign` 和 `availableActionCodes` 渲染,不按中文状态或本地别名推断。
|
||||||
|
|
||||||
|
| 生命周期 | `currentStep` | 当前动作码 | 正确页面行为 |
|
||||||
|
| --- | ---: | --- | --- |
|
||||||
|
| `unassigned` | 2 | `ASSIGN`, `REJECT_REQUIREMENT` | 派车派人、驳回需求 |
|
||||||
|
| `holding_wait_driver` | 3 | `CHANGE_ASSIGNMENT`, `RECORD_DRIVER_CONFIRMATION`, `DRIVER_REJECT`,出团前/当天另有 `CANCEL_ASSIGNMENT` | 继续派车、司机拒接、改派、取消 |
|
||||||
|
| `driver_confirmed` | 4 | `CHANGE_ASSIGNMENT`, `CONFIRM_EXECUTION`,出团前/当天另有 `CANCEL_ASSIGNMENT` | 恢复第 4 步确认执行;不得只剩改派 |
|
||||||
|
| `assigned` 且未过出团日 | 4 | `CHANGE_ASSIGNMENT`, `CANCEL_ASSIGNMENT` | 改派、取消派单 |
|
||||||
|
| `assigned` 且已过出团日 | 4 | `CHANGE_ASSIGNMENT`, `EARLY_COMPLETE` | 改派、提前完结 |
|
||||||
|
| `completed/canceled` | 终态 | 无可写动作 | 只读 |
|
||||||
|
|
||||||
|
当前前端存在三处精确错位:
|
||||||
|
|
||||||
|
1. 检查 `CANCEL`,而后端下发 `CANCEL_ASSIGNMENT`;
|
||||||
|
2. 检查 `COMPLETE_EARLY`,而后端下发 `EARLY_COMPLETE`;
|
||||||
|
3. `driver_confirmed` 已下发 `CONFIRM_EXECUTION`,但卡片和详情没有恢复确认执行入口。
|
||||||
|
|
||||||
|
`DRIVER_REJECT` 与 `RECORD_DRIVER_CONFIRMATION` 是现行值,继续沿用。不要让后端同时下发新旧两套动作码。
|
||||||
|
|
||||||
|
## 二、部分日期稳定槽必须保留用户点击上下文
|
||||||
|
|
||||||
|
### 复现
|
||||||
|
|
||||||
|
测试单 `26-6263` 的同一 `assignmentSlotId`:
|
||||||
|
|
||||||
|
- 07-30、07-31:已有 HOLD;
|
||||||
|
- 08-01:唯一剩余 `unassigned`;
|
||||||
|
- 看板卡片正确显示“用车 08-01 · 1天”;
|
||||||
|
- 8 月矩阵未派池也只显示 08-01。
|
||||||
|
|
||||||
|
但当前前端:
|
||||||
|
|
||||||
|
- 从看板进入 Step 2 后改成编辑 07-30/07-31 的 active HOLD;
|
||||||
|
- 从矩阵车辆 08-01 空闲格进入时,顶部虽显示“有效服务日期:08-01”,Step 2 却显示 `已选 0/0 天`,继续复用 07-30/07-31 费用并返回 0 个候选。
|
||||||
|
|
||||||
|
### 正确规则
|
||||||
|
|
||||||
|
- 首次派车 `mode=assign` 必须保留用户点击的看板代表行:`assignmentId/assignmentSlotId/fleetItemIndex/startDate/endDate`;详情异步返回后不能被 `currentAssignment` 覆盖;
|
||||||
|
- 矩阵入口以 `entryContext.clickedDate + startDate + endDate` 与订单合法服务段求交集;本例结果固定为 08-01;
|
||||||
|
- `currentAssignment/activeAssignments[]` 只用于改派和确认已有有效派车组,不代表未派切片;
|
||||||
|
- 实际计费服务日为空时,应从已经校验通过的 `assignmentDateRange` 回退生成,不得读取另一 active 组的逐日费用;
|
||||||
|
- 提交仍使用原稳定 `assignmentSlotId`,只消费 08-01,不得重建第二槽位或覆盖 07-30/07-31。
|
||||||
|
|
||||||
|
## 三、HOLD 手工补价不能在司机确认后丢失
|
||||||
|
|
||||||
|
### 复现
|
||||||
|
|
||||||
|
`26-9140` 改派时:
|
||||||
|
|
||||||
|
- 07-30/07-31 使用日历价 860;
|
||||||
|
- 08-01 日历缺价,页面提交覆盖价 860 和调价原因;
|
||||||
|
- `/change` 返回并落库总价 2580;
|
||||||
|
- 派单详情也正确展示 08-01 覆盖价和原因。
|
||||||
|
|
||||||
|
登记司机确认后,Step 4 又从候选价格日历重建费用,08-01 变为“待补价”,总价变为“价格不完整”,`validateVehicleFeeDraft` 阻断最终确认。
|
||||||
|
|
||||||
|
### 正确规则
|
||||||
|
|
||||||
|
- HOLD 已创建后,`activeAssignments[]/currentAssignment` 的 `dailyVehicleFees`、`vehicleFeeTotal`、`vehicleFeeAdjustmentReason`、`chargeableServiceDates` 和 `vehicleFeeWaiverReason` 是当前派车组权威快照;
|
||||||
|
- 候选接口的价格只用于新选车草稿或日历参考,不得覆盖已经保存的 HOLD 费用;
|
||||||
|
- 第 3 步登记司机回复和第 4 步确认执行都不能清空已保存覆盖价;
|
||||||
|
- 详情重拉后应按 `assignmentId/assignmentGroupId` 恢复同一派车组快照。
|
||||||
|
|
||||||
|
## 四、后台刷新不得重置正在编辑的派车草稿
|
||||||
|
|
||||||
|
实测派车弹窗打开后,后台订单刷新会触发整套初始化:
|
||||||
|
|
||||||
|
- 候选接口已返回 19 辆车和 11 名司机,但两个列表被清空,计数/筛选项仍保留;
|
||||||
|
- 用户已切换 DIRECT,提交前又恢复为 HOLD;
|
||||||
|
- 再点一次筛选会重新请求并恢复候选。
|
||||||
|
|
||||||
|
前端应做到:
|
||||||
|
|
||||||
|
- `props.order` 仅因列表/SSE 刷新生成新对象时,不重置当前弹窗;
|
||||||
|
- 只有订单 ID、目标需求 ID、目标稳定槽位、模式或用户主动关闭/重开变化时才重新初始化;
|
||||||
|
- 已编辑车辆、司机、日期、收费日、逐日价、原因、跨常驻确认和 HOLD/DIRECT 模式全部保留;
|
||||||
|
- 若服务端基线真的变化,使用现有 baseline-difference 强提示并让用户决定,不静默改写草稿。
|
||||||
|
|
||||||
|
## 五、多槽 HOLD 必须按槽位推进
|
||||||
|
|
||||||
|
`26-5256` 有两个稳定车辆槽位。槽位 1 登记司机确认后:
|
||||||
|
|
||||||
|
- 详情真值为槽位 1 `driver_confirmed`、槽位 2 `holding_wait_driver`;
|
||||||
|
- 卡片却仍把代表司机显示为“待回复”;
|
||||||
|
- “继续派车”入口消失,槽位 2 无法登记司机回复。
|
||||||
|
|
||||||
|
正确行为:
|
||||||
|
|
||||||
|
- 订单只要任一 active 槽位包含 `RECORD_DRIVER_CONFIRMATION`,卡片和详情保留“继续派车”;
|
||||||
|
- 打开后默认选中最早待回复槽位,也允许切换其它槽位;
|
||||||
|
- 一个槽位确认不得覆盖或隐藏另一个槽位状态;
|
||||||
|
- 订单聚合步骤取最慢槽位,代表卡文案必须明确“代表槽位”,不能冒充全单状态。
|
||||||
|
|
||||||
|
## 六、冲突窗口字段不能混用
|
||||||
|
|
||||||
|
候选响应同时包含:
|
||||||
|
|
||||||
|
| 字段 | 含义 | 页面用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `conflicts[]` | 真正占用冲突;`blocking=true` 的日期禁止选择 | 展示冲突订单与冲突日期 |
|
||||||
|
| `availabilityWindows[]` | 当前查询区间内仍可用的连续窗口 | 仅在资源可用/部分可用提示中展示 |
|
||||||
|
| `availabilityReasonCode` | `AVAILABLE`、`ASSIGNMENT_CONFLICT` 等判定码 | 决定禁用和提示类型 |
|
||||||
|
| `availabilityReasonMessage` | 后端判定文案 | 展示主提示 |
|
||||||
|
|
||||||
|
实测后端冲突是 08-01,`availabilityWindows` 是 08-02..08-04;页面却显示“存在派单冲突 · 08-02 至 08-04”。禁用结果正确,日期解释相反。
|
||||||
|
|
||||||
|
冲突文案应从 `conflicts[].startDate/endDate` 汇总;`availabilityWindows` 不得拼在冲突文案后。
|
||||||
|
|
||||||
|
## 七、提交与刷新反馈
|
||||||
|
|
||||||
|
### 1. 防重复提交
|
||||||
|
|
||||||
|
真实 UI 同一时刻双击 DIRECT 发出两个不同 `requestId`:
|
||||||
|
|
||||||
|
- 第一笔成功并只生成一个有效派车;
|
||||||
|
- 第二笔被后端守恒门禁拒绝,返回 `605033`:`用车需求完成回写处理中,请稍后重试`。
|
||||||
|
|
||||||
|
前端应在第一笔进入提交函数时立即短路后续点击,并在按钮、快捷键和程序触发路径共用同一 `submitting` 门禁。同一草稿的网络重试应复用 requestId,不应每次生成新值。
|
||||||
|
|
||||||
|
### 2. 司机拒接后的详情
|
||||||
|
|
||||||
|
司机拒接成功后,卡片立即变为未派,但当前详情抽屉仍保留旧 HOLD 车辆、费用和动作。关闭重开才正确。成功后需用最新服务端详情整体替换旧对象,不得继续把 mutation 前的行快照合并回来。
|
||||||
|
|
||||||
|
### 3. 车务角色快捷入口
|
||||||
|
|
||||||
|
车务角色下顶部可见“订单列表”,点击却进入未注册 `/housekeeper/orders` 并显示 404。未注册/无权限时不要展示快捷入口;有权限时应确保动态路由已注册再导航。
|
||||||
|
|
||||||
|
## 八、前端验收清单
|
||||||
|
|
||||||
|
- [ ] `CANCEL_ASSIGNMENT` 显示并执行取消;不再检查 `CANCEL`。
|
||||||
|
- [ ] `EARLY_COMPLETE` 显示并执行提前完结;不再检查 `COMPLETE_EARLY`。
|
||||||
|
- [ ] `driver_confirmed + CONFIRM_EXECUTION` 可从卡片和详情恢复第 4 步。
|
||||||
|
- [ ] 多槽 HOLD 任一槽位待回复时保留“继续派车”,逐槽推进且代表状态不串槽。
|
||||||
|
- [ ] `26-6263` 从看板和 8 月矩阵都只编辑/提交 08-01,07-30/07-31 不变。
|
||||||
|
- [ ] 已保存 HOLD 的手工逐日价、调价原因和免费日配置在司机确认、详情刷新、最终确认之间保持不变。
|
||||||
|
- [ ] SSE/列表刷新不清空候选、车辆司机草稿或切换 HOLD/DIRECT 模式。
|
||||||
|
- [ ] 冲突日期取 `conflicts[]`,可用窗口取 `availabilityWindows[]`,两者文案不混用。
|
||||||
|
- [ ] DIRECT/HOLD 第一击后立即禁用所有重复提交路径;同草稿重试复用 requestId。
|
||||||
|
- [ ] 司机拒接后当前卡片和详情同时刷新到 unassigned。
|
||||||
|
- [ ] 车务角色的订单快捷入口不再进入 404。
|
||||||
|
|
||||||
|
## 验证证据
|
||||||
|
|
||||||
|
- 后端 `dev-v3@79297c838b62af2426cc83ad0e78cffbd961096b` 已部署,Fleet 8087/8187 两实例健康;
|
||||||
|
- #5277 Fleet reactor 2,427 项通过,0 失败、0 错误、1 跳过;Spotless 通过;
|
||||||
|
- 网关验证:完整 assigned 单槽和三槽均为 `canAssign=true + CHANGE_ASSIGNMENT`;
|
||||||
|
- 真实 UI 写入通过:HOLD、DIRECT、司机确认、最终确认(不发送短信)、司机拒接、只换车、只换司机、同时换车司机、需求驳回、V2/V3 换版重派、收费/免费日、重复提交;
|
||||||
|
- 后端守恒:重复 DIRECT 只生成一笔有效派车;需求 `DONE_ADJUST` 返回 `assignmentDeletedCount=1`,旧资源随后可重新选择;
|
||||||
|
- 部分日期后端真值:07-30/07-31 为 HOLD,08-01 唯一 unassigned,三天共用稳定槽位,无重复/孤儿;
|
||||||
|
- 关键页面截图:`fleet-partial-continuation-broken.png`、`5277-assigned-reassign-restored.png`;
|
||||||
|
- 完整逐步证据由 #5279 工单评论和测试记录保留。
|
||||||
|
|
||||||
|
## 十、契约审查
|
||||||
|
|
||||||
|
- 本文件不对应新的 Controller、VO、字段、类型、必填性、动作码或错误码变更;
|
||||||
|
- OpenAPI/oasdiff:`not_required`,没有新的 `frontend_api` diff;
|
||||||
|
- Consumer Contract:`not_required`,没有 Feign/shared Java 变化;
|
||||||
|
- 当前动作码由 `AssignmentLifecycleResolver` 和现有服务测试确认;部署网关响应与源码一致;
|
||||||
|
- 前端代码审查确认当前仍检查 `CANCEL`、`COMPLETE_EARLY`,且没有消费 `CONFIRM_EXECUTION`。
|
||||||
|
|
||||||
|
## 不影响范围
|
||||||
|
|
||||||
|
- 不修改 `hl-ui`,不在 `mmg/hl-ui` 建工单;本文件 `frontend_status` 保持 `pending`;
|
||||||
|
- 不要求后端新增兼容动作码、重复字段、特殊前端分支或放松资源/幂等守恒;
|
||||||
|
- 不修改派车状态机、计费公式、库存/占用、保险、通知、Outbox 或数据库结构;
|
||||||
|
- 不把前端实现、发布、页面验收纳入后端工单关闭条件。
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户