diff --git a/changelogs-v2/2026-09/23_8142_行程用车与接送机并存时接送机需求整行从派单看板消失-修复-管理后台.md b/changelogs-v2/2026-09/23_8142_行程用车与接送机并存时接送机需求整行从派单看板消失-修复-管理后台.md new file mode 100644 index 00000000..41864a59 --- /dev/null +++ b/changelogs-v2/2026-09/23_8142_行程用车与接送机并存时接送机需求整行从派单看板消失-修复-管理后台.md @@ -0,0 +1,94 @@ +--- +schema: "hl-changelog/v2" +ticket: "8142" +title: "车务派单看板: 行程用车与接送机需求并存时,接送机需求整行从列表消失——已修复,同一订单现按需求维度出多条记录" +consumer: "admin" +author: "wx(GIT)" +change_type: "修复" +backend_status: "deployed" +gateway_status: "not_required" +frontend_status: "not_required" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "本条不改变 GET /admin/fleet/board/orders 的任何响应字段名、类型或嵌套结构,变的是记录的产出规则:修复前该端点在「一单同时有活跃 TRAVEL 需求与活跃 TRANSFER 需求」时只产出其中一条需求的记录,另一条整行不出现(且出现的那条还可能挂着另一类的 requirementRemark 与派车行);修复后每条活跃用车需求各出一条记录。gateway_status=not_required:零新增路由,端点既有。frontend_status=not_required:hl-ui(origin/v2.1)的看板列表与卡片视图早已用 requirementId 作 row-key(src/views/fleet/board/utils/boardSummary.js:9-14,resolveBoardRecordKey,注释原文「看板已按当前有效用车需求聚合;列表身份必须锚定 requirementId,历史响应缺失时才回退原记录/订单 ID」),同一订单多条记录不会撞 key,无需前端改动——这是查证结论不是推断,若后续发现有按 orderId 去重的调用点,以那处为准另发订正。backend_status=deployed:hl-fleet-service 与 hl-order-service-v3 均已滚动到测试服 78d0aad3d(分别 2026-09-23 07:38:54 / 07:40:25),并在测试服活体上完成改前/改后对跑取证,读数见正文第四节。" +updated_at: "2026-09-23" +base: "dev-v3" +--- + +# 车务派单看板: 行程用车与接送机需求并存时,接送机需求整行从列表消失 + +> **存放目录**: 二期(order-v3)→ `changelogs-v2/2026-09/` +> +> **服务**: hl-fleet-service(看板候选与聚合)+ hl-order-service-v3(需求身份供给)+ hl-common +> **PR**: [#8211](https://git.1814.love:8443/wx/HL/pulls/8211) +> **Issue**: [#8142](https://git.1814.love:8443/wx/HL/issues/8142) +> **日期**: 2026-09-23 +> **影响范围**: `GET /admin/fleet/board/orders`(车务派单看板列表 / 待派分面) + +--- + +## ⚠️ 关键变化 + +1. **同一订单现在可能出现多条记录,每条活跃用车需求各一条。** 字段名、类型、嵌套结构**零变化**,变的是**记录的产出规则**。 + 如果你的代码里有「一个 orderId 对应一条记录」这个隐含假设(按 orderId 去重、按 orderId 建 Map、用 orderId 当列表 key),**它现在不成立了**。 + `hl-ui` 当前实现不受影响——看板列表与卡片视图已用 `requirementId` 作 row-key(`src/views/fleet/board/utils/boardSummary.js:9-14`)。 + +2. **`requirementId` 现在是列表记录的身份键,`orderId` 不是。** 唯一性口径是 `(orderId, requirementId)` 组合,`requirementId` 恒非 null。 + +3. **`requirementRemark` / `dailyAssignments` / `requiredVehicles` 现在保证属于本记录自己的那条需求。** 修复前存在反向错配:TRANSFER 需求的记录上挂着 TRAVEL 需求的 `requirementRemark`,派车行也只显示了其中一部分。 + +4. **「接送机还没派车」的虚拟待派卡现在会出现在待派分面里**(`virtualPending: true`、`dailyAssignments: []`、`assignmentStatus: "unassigned"`、`assignmentGroupId: null`)。修复前这类需求在列表侧完全不可见,车务无从发现「这单的接送机还没派车」。 + +--- + +## 一、变更接口清单 + +| 方法 | 路径 | 变更性质 | +|---|---|---| +| GET | `/admin/fleet/board/orders` | 响应**字段结构不变**,记录产出规则变更(一单一条 → 一需求一条) | + +> 本条不属「新增接口 / 修改接口」:无新增或删除的请求参数,无新增、删除或改名的响应字段,无新增错误码。 + +--- + +## 二、失败形态(供你判断历史数据与截图) + +修复前有两种形态,都**静默**——接口返 200、`code=200`、无任何错误码或警告字段: + +**形态甲 · 整批不出现**:两类需求并存时只产出一条记录,另一条整行没有。 +实测:某广口径查询 `.data.total` 修复前 **22**、修复后 **25**,多出的 3 条恰好一单一条落在三个订单上。 + +**形态乙 · 反向错配**:产出的那条记录 `requirementId` 是 A 需求的,而 `requirementRemark` 是 B 需求的,`dailyAssignments` 只含 A 的一部分派车行。 +实测订单 `HL20260919104049371`:修复前该条记录 `requirementId=7330964160969957`(TRANSFER)却带着 TRAVEL 的备注、只有 1 条日行;修复后备注是自己的、日行 2 条(与库中该需求的活派车行集合逐条相等)。 + +⇒ **修复前的看板截图与导出数据不可作为历史对账依据**,涉及两类需求并存的订单需重新拉取。 + +--- + +## 三、边界:有一类记录按设计仍然不出现 + +用车需求处于 `DONE`/`CANCELED` 等**非待派状态**、且**零条活派车行**时,看板**不为它造虚拟待派卡**,只打一条 warn 日志。 +这属于数据不一致的兜底分支(`BoardCandidateSource.java:383-397`,判据 `isAwaitingDispatch = PENDING || PROCESSING`),**不是本次修复的残留**。 +⇒ 若你看到某单「库里有这条需求、看板上没有」,先看该需求的 `status`:非 `PENDING`/`PROCESSING` 且零派车行时,这是预期行为。 + +--- + +## 四、后端已验证的读数(测试服活体,部署 commit `78d0aad3d`) + +| 验证项 | 读数 | +|---|---| +| 虚拟待派卡可见 | 某 TRANSFER 需求记录数 `0 → 1`,该单 `.data.total` `1 → 2`;`virtualPending=true`、`dailyAssignments=[]` 与库一致 | +| 两类派车行各自完整 | TRAVEL 与 TRANSFER 两条需求的日行 `assignmentGroupId` 集合,与库中各自的活派车行集合**逐条相等** | +| 单类订单零回归 | TRAVEL-only 与 TRANSFER-only 两单,响应递归展平后各 243 / 205 个叶路径,**各只有 1 个键变化**且都是随日期自然漂移的 `daysUntilDeparture`(恰好 −1);剔除该键后改前/改后 sha256 **完全相等** | +| 待派分面未被打穿 | 广口径 `?statuses=unassigned` 返 `total=133`;fleet 日志中 fail-open 分支关键词 **0 命中**(同窗口任意 board 日志行 21 条,证明日志在写) | +| 记录唯一性 | 8 份响应逐份核 `(orderId, requirementId)` 对唯一、`requirementId` 非 null 全绿 | + +--- + +## 五、你需要做的 + +- **无需改动**即可继续工作;若你的代码按 orderId 去重或建 Map,改为按 `requirementId`(或 `(orderId, requirementId)`)。 +- 渲染时优先用 `requirementId` 作列表 key。 +- 展示「这单还有没有没派的车」时,把 `virtualPending: true` 的记录算进去——它就是「有需求、还没派车」这一状态的载体。