From 1548a68d4b3c3c5ff202479724c828cf7158d6fd Mon Sep 17 00:00:00 2001 From: wx Date: Mon, 7 Sep 2026 04:39:11 +0800 Subject: [PATCH] =?UTF-8?q?docs(7067):=20=E8=A1=A5=E8=BF=94=E5=B7=A5?= =?UTF-8?q?=E4=BA=8C=E8=BD=AE=E4=B8=8E=E7=AB=AF=E5=88=B0=E7=AB=AF=E9=98=BB?= =?UTF-8?q?=E6=96=AD=E4=BF=AE=E5=A4=8D=E7=9A=84=E5=A5=91=E7=BA=A6=E5=A2=9E?= =?UTF-8?q?=E9=87=8F=EF=BC=88=E5=9B=9B=E6=AD=A5=E5=90=91=E5=AF=BC=20step?= =?UTF-8?q?=20=E5=8F=B7=E3=80=81finalPlanPublished=E3=80=81=E9=97=A8?= =?UTF-8?q?=E7=A6=81=E5=8F=AF=E4=B8=BA=20null=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...按行程日配车-接送机独立配置-修改接口-管理后台.md | 132 +++++++++++++++++- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/changelogs-v2/2026-09/06_7067_派单去槽位化按行程日配车-接送机独立配置-修改接口-管理后台.md b/changelogs-v2/2026-09/06_7067_派单去槽位化按行程日配车-接送机独立配置-修改接口-管理后台.md index 752cbdfc..62f6c7c5 100644 --- a/changelogs-v2/2026-09/06_7067_派单去槽位化按行程日配车-接送机独立配置-修改接口-管理后台.md +++ b/changelogs-v2/2026-09/06_7067_派单去槽位化按行程日配车-接送机独立配置-修改接口-管理后台.md @@ -11,16 +11,16 @@ frontend_status: "pending" frontend_owner: "mmg" frontend_ref: "" target_release: "" -verified_at: "2026-09-06" -status_note: "后端已合 dev-v3(PR #7194 squash 9130624)并部署测试服,网关实测通过。前端 U1(API 层+死端点拆除)已交付 ref 1343b86f:board.js 删 4 个已下线槽位端点、auto-recommend 改 /{assignmentId} 路径、新增 PUT pickup-dropoff-config,拆增删槽/取消残留调用链。U2-U7(看板/矩阵字段改名、canonical 快照、batch 提交体 dailyPlan 重构、向导三步→四步、confirm 605914/605915 门禁、清扫)逐单元推进中,本条保持 pending 至全部闭环。" -updated_at: "2026-09-06" +verified_at: "2026-09-07" +status_note: "2026-09-07 返工二轮(PR #7218)+端到端阻断修复(PR #7223)已合 dev-v3 并部署测试服(fleet/order-v3/user 三服务,user-service 补齐了 #7194 漏部署的 hl-common 通知契约)。端到端实测:新模型订单 D1=A车/D2=B车/D3=A车 判完整并发布 finalPlan、订单车控回到 DONE;接送机门禁三段(605914 阻断→配齐→发布)全通;改派 200 且操作日志恢复写入;需求已 DONE 后再次排车不再 605906;FLEET_ITINERARY_READY 真实投递到 user-service 并写入 notification_send_log。前端 U2-U7 仍在推进,本条保持 pending 至全部闭环;新增的四步向导 step 号变化(九之二 B1)、POST /batch 的 finalPlanPublished(B2)、pickupDropoffGate 可为 null(B3) 三条为破坏性,请优先处理。" +updated_at: "2026-09-07" base: "dev-v3" --- # 车务派单:去槽位化按行程日配车与接送机独立配置(管理后台) > **服务**: hl-fleet-service (8087) -> **PR**: #7194 +> **PR**: #7194、#7218(返工二轮)、#7223(端到端实测暴露的三处阻断) > **Issue**: #7067 > **日期**: 2026-09-06 > **影响范围**: 管理后台车务派单模块——派单向导四步流程(订单详情/排车/接送机/确认执行)、派单看板列表与详情、矩阵派单甘特图与未派订单清单 @@ -38,6 +38,9 @@ base: "dev-v3" - **候选查询字段改名**:`retainedSlotIds` → `retainedGroupIds`,`cells[].slotId` → `cells[].groupId`。 - **司机 H5 短链旧 token 直接失效**:token v2 claim 由 `assignmentSlotId` 改为 `assignmentGroupId`,签名输入口径变化使旧 token 报 605306(fail-closed 拒绝,不是容忍旧值),司机侧需重新获取短链。 - **两个错误码作废**:605012、605911(码位保留不复用,不会再出现在任何响应里)。 +- **(2026-09-07 返工补充)`progressSteps` 由 3 步变 4 步**,`CONFIRM_EXECUTE` 的 step 号 3 → 4:按下标或按数组长度取值的前端会直接破,改为按 `code` 取值。详见「九之二」B1。 +- **(2026-09-07 返工补充)`POST /batch` 提交成功不再等于订单车控完成**:大交通声明要接/送机而第③步未配齐时,最终方案不发布、订单停在处理中。前端必须读响应新增的 `finalPlanPublished`。详见「九之二」B2。 +- **(2026-09-07 返工补充)看板详情 `pickupDropoffGate` 为 `null` 表示「门禁未知」(order-v3 降级),不是「无接送机声明」**。详见「九之二」B3。 --- @@ -1484,6 +1487,127 @@ GET /admin/fleet/matrix/day-orders?date=2026-05-04 - [ ] 看板列表出现 `virtualPending=true` 的虚拟条目 —— **本次未观察到,非缺陷**。看板的虚拟候选窗是 `[今天, 今天+lookahead]`,而清理后测试库里零派车行的需求出发日全部早于今天(最晚 2026-09-01,实测当天为 2026-09-06),按设计「行程已结束的零派车行订单不进看板」被正确排除。矩阵侧(按年月取数)已实测到虚拟条目,读侧投影逻辑本身已验证。该分支由单测覆盖。 - [ ] `POST /admin/fleet/assignments/requirements/{requirementId}/confirm` 触发 605914 / 605915 —— 需要「大交通声明需接/送机 + 对应日期未配置车辆」的特定数据组合,测试库当前无此样本,未构造(构造需改动他人测试数据)。该门禁由单测覆盖。 +## 九之二、2026-09-07 第二轮返工的契约增量(前端必读) + +> #7067 于 2026-09-06 被验收打回三项 P1,本节是返工后的**契约增量**,PR #7218 + #7223(均合 dev-v3)。 +> 前三条是**会破坏现有渲染**的变化,请优先处理。 + +### ⚠️ B1(破坏性)`progressSteps` 由 3 步变 4 步,`CONFIRM_EXECUTE` 的 step 号 3 → 4 + +上一版本节把 `progressSteps` 列为「本单未变更字段」,**这是错的**,本次更正。 + +| step | code | name | 说明 | +|------|------|------|------| +| 1 | ORDER_DETAIL | 订单详情 | 不变 | +| 2 | DISPATCH | 排车 | 不变 | +| 3 | **PICKUP_DROPOFF** | **接送机** | **本次新增的一步** | +| 4 | CONFIRM_EXECUTE | 确认执行 | **step 由 3 变 4** | + +**按数组下标或按数组长度取值的前端会直接破**,请改为按 `code` 取值。 + +第③步的状态取自接送机门禁: + +- 门禁已满足(无接送机声明,或已配齐)→ `DONE`,不置 `active`; +- 有声明但未配齐 → `PROCESSING` 且 `active=true`,同时把第④步压回 `WAITING`; +- **门禁未知(见 B3)→ `WAITING` 且不置 `active`**,第④步同样 `WAITING`。 + +### ⚠️ B2(破坏性)`POST /admin/fleet/assignments/batch` 提交成功不再等于订单车控完成 + +第②步排车照常落库并推进 `assigned`,但**大交通声明要接/送机而第③步尚未配齐时,DAILY_V3 最终方案被压住不发**,order-v3 侧 `vehicle_control_status` 停在 `PROCESSING`。 + +响应 `Result` 新增两个字段: + +| 字段 | 类型 | 说明 | +|------|------|------| +| finalPlanPublished | Boolean | 本次是否已发布最终方案。**false = 排车已落库但接送机未配齐**,必须继续走第③步 | +| pickupDropoffGate | Object | 接送机门禁状态,结构见 B4 | + +**前端必须读 `finalPlanPublished`**:为 false 时不能提示「派单完成」,应引导用户去第③步接送机;为 true 时才是完成态。第③步配齐后服务端会**立即补发**最终方案,无需回到第②步重提交。 + +### ⚠️ B3(破坏性)`pickupDropoffGate` 整体为 `null` 表示「门禁未知」,不是「无声明」 + +`GET /admin/fleet/board/orders/{orderId}` 的顶层 `pickupDropoffGate` 在 order-v3 详情上下文降级(拉取失败)时返回 `null`。此时大交通拿不到权威值,服务端**不给出乐观判定**。 + +前端按「未知」渲染:不展示「接送机已完成」,也不展示缺口日期条;第③④步按 B1 停在 `WAITING`。 +**不要把 `null` 当作「该订单没有接送机要求」**——写侧用的是 strict 拉取,真实状态可能是「有声明未配齐、订单仍在处理中」,两侧结论会正好相反。 + +### B4 接送机门禁结构 `PickupDropoffGateVO` + +出现在三处:`POST /batch` 响应、`PUT /pickup-dropoff-config` 响应、`GET /board/orders/{orderId}` 顶层。三处同一份结构、同一套判据。 + +| 字段 | 类型 | 必返 | 说明 | +|------|------|------|------| +| arrivalRequiredDates | Array\ | ✅ | 大交通声明需要**接机**的服务日(升序) | +| departureRequiredDates | Array\ | ✅ | 大交通声明需要**送机**的服务日(升序) | +| missingPickupDates | Array\ | ✅ | 其中尚未配置接机车辆的服务日(升序) | +| missingDropoffDates | Array\ | ✅ | 其中尚未配置送机车辆的服务日(升序) | +| declared | Boolean | ✅ | 该订单大交通是否有任一方向的接送机声明 | +| satisfied | Boolean | ✅ | 门禁是否已满足(无声明或已配齐)。**false 时最终方案不发布、订单车控停在处理中** | + +`declared=false` 时四个数组均为空、`satisfied=true`——门禁对无接送机声明的订单整体让路,允许车务手工勾选但不强制。 +已完结(`completed`)的服务日豁免:行程中换版平移后该日事实已随历史派车固化,不会再要求重配。 + +### B5 `PUT /admin/fleet/assignments/pickup-dropoff-config` 响应类型变更 + +由原来的空响应改为 `Result`: + +| 字段 | 类型 | 必返 | 说明 | +|------|------|------|------| +| finalPlanPublished | Boolean | ✅ | 本次保存是否**补发**了最终方案快照(配齐即发)。只在门禁由「不满足」跨到「满足」的那一次为 true;重复保存同样已满足的状态不会重复发版 | +| requirementReopened | Boolean | ✅ | 本次是否把**已完成**的订单拉回处理中(见 B6) | +| reopenBlockedReason | String | 否 | 本该拉回处理中却没拉回的原因;`null`=不适用或已成功拉回。当前唯一取值 `REQUIREMENT_LIFECYCLE_DISABLED`(服务端需求级生命周期开关未启用),见 B6 | +| pickupDropoffGate | Object | ✅ | 写入后的门禁状态,结构见 B4 | + +保存成功后订单状态到底变没变,前端从这两个布尔值当场就能知道,不需要再拉一次看板详情。 + +### B6 在已完成的订单上清掉要求日的接送机勾选 → 订单被拉回处理中 + +车务改接送机安排是正常业务动作,服务端不拒绝提交;但订单车控已经是完成态时,清掉要求日的勾选会写一条「重开」意图把用车需求拉回 `PROCESSING`,响应里 `requirementReopened=true`。前端应据此把订单状态从「已完成」改回「处理中」,并提示需要重新配齐接送机。 + +**例外**:服务端配置 `fleet.assign.requirement-lifecycle-enabled=false`(application.yml 默认值;测试服 Nacos `hl-fleet-service-test.yml` 已显式置 `true`,故测试环境走的是正常重开路径)时,重开意图不会被投递。此时接口**不拒绝、照常落库**,但返回 `requirementReopened=false` + `reopenBlockedReason="REQUIREMENT_LIFECYCLE_DISABLED"`——含义是「接送机勾选已保存,但订单状态没能拉回处理中」。 + +前端在拿到 `reopenBlockedReason` 时应提示用户「保存成功,但订单仍显示已完成,请联系运维开启需求级生命周期开关后重新保存一次」,不要把它当成失败,也不要把订单画成已回到处理中。 + +(为什么不整笔拒绝:该开关默认关闭,硬拒等于「改接送机安排」这条正常业务动作在默认配置下永远不可用,还会连带丢弃同一次提交里其它合法的勾选修改。) + +### B7 逐日 `dropoffRequired`(读侧新增,与 `pickupRequired` 对称) + +`GET /admin/fleet/board/orders/{orderId}` 的 `dailyVehiclePlan[]` 每一项新增 `dropoffRequired`(Boolean):当天大交通是否要求**送机**。原先只有 `pickupRequired`(要求接机),设计文档声称有 `dropoffRequired` 而代码里没有,本次补齐。 + +注意区分同名的两组字段: + +- `pickupRequired` / `dropoffRequired` = **大交通要求**当天接/送机(只读,来自订单) +- `pickupParticipant` / `dropoffParticipant` = 该派车行**实际被勾为**当天的接/送机车(可写,第③步配置) + +### B8 服务端配置(不影响契约,供排障参考) + +| Nacos 键 | 默认 | 作用 | +|---|---|---| +| `fleet.assign.pickup-dropoff-gate-enabled` | `true` | 接送机门禁总开关。关闭即整体退回返工前行为(无条件发布最终方案、不做 605914/605915 断言),作为线上回滚阀 | +| `fleet.assign.requirement-lifecycle-enabled` | `false` | 需求级生命周期 Outbox 开关,见 B6 的例外 | + +### B9 后端内部修复(无契约变更,但影响可观察行为) + +- **改派后订单不再卡在处理中**:去槽位化后改派生成的替换行带全新派车组 ID 且不继承槽位,旧实现认不出「墓碑↔替换行」是同一身份,导致方案被永久判为不完整、最终方案不发布、订单卡 `PROCESSING` 且无自动恢复路径。已改为改派时在同一事务里作废墓碑的定稿身份。**前端无需改动**,但此前观察到的「改派完订单一直显示处理中」现象随之消失。 +- 同源修复:改派之后不能再通过「撤销取消」把旧车复活成同日第二辆在途车。 +- 「撤销取消」重建最终方案时也会先过接送机门禁,不再绕过。 + +**以下两条是 2026-09-07 测试服端到端实测才暴露的缺陷,均已随本次修复上线;前端无需改动,但此前的异常现象会随之消失:** + +- **改派必现 `400 字段【assignment_slot_id】未填写`**,且派单操作时间线自 #7067 上线起停止记录。 + 操作日志表 `fleet_assignment_operation_log.assignment_slot_id` 仍是 NOT NULL 且无默认值, + 而去槽位化后写入侧是**无条件**落 NULL(与锚点行是不是存量行无关),MySQL 严格模式直接 + 打断整笔事务。实测边界:改派 400(会写日志),确认执行 200(不写日志,不受影响); + `fleet_assignment_operation_log` 最后一条记录停在 2026-08-31、此后零新增。 + 已由 Flyway 把该列放开为可空,改派与操作时间线随之恢复。 +- **手工调价的订单车控可能永久停在「处理中」**。派车行的调价时间列是秒级精度, + MySQL 落库时对亚秒部分四舍五入,可能比同一笔快照的完成时间晚零点几秒, + order-v3 据此判定「调价晚于完成」并整份拒收 DAILY_V3 快照(约一半概率必现, + 自动计价的行不受影响)。已两侧修复:写入侧秒级下取整,校验侧按列精度给 1 秒容差。 + 修复前已被隔离的快照事件需要运维走 `POST /internal/fleet/jobs/vehicle-assignment-snapshot-outbox/{eventId}/requeue` 重排一次。 + +--- + ## 十、相关文档 - 展示口径权威源(HL 仓库路径):`docs/tasks/7067-display-matrix.md`(看板/详情/四步向导/矩阵的数据源、状态范围、空态、守恒规则)