changelog-filename-gate / validate (push) Failing after 2s
- #8561 派单矩阵三入口补年份区间校验,越界返新错误码 605076 - #8571 未派订单清单月份越界改由 Service 判定,与 matrix 另两个入口同构返 605010 - #8556 派单看板订单详情识别团期配车,排车步与实派车数不再只认逐户派车行 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
263 行
17 KiB
Markdown
263 行
17 KiB
Markdown
---
|
||
schema: "hl-changelog/v2"
|
||
ticket: "8556"
|
||
title: "派单看板订单详情识别团期配车,排车节点与实派车辆数不再只认逐户派车行"
|
||
consumer: "admin"
|
||
author: "wx(GIT)"
|
||
change_type: "修改接口"
|
||
backend_status: "deployed"
|
||
gateway_status: "verified"
|
||
frontend_status: "pending"
|
||
frontend_owner: ""
|
||
frontend_ref: ""
|
||
target_release: ""
|
||
verified_at: ""
|
||
status_note: "PR #8583 合并 dev-v3(9c7ac93829);hl-fleet-service dev-v3 分支部署测试网关 @ 9c7ac9382 并实测:团期订单详情下发 groupBatchId/groupDispatchManaged/groupDispatchReady/groupDispatchPlan,排车节点由 WAITING 改为 SKIPPED,actualVehicleCount 由团期子订单实测的 0 变为与团期配车总览一致的实派车数;同一订单可同时存在团期配车与个人派车两组数据且互不覆盖。"
|
||
updated_at: "2026-09-30"
|
||
base: "dev-v3"
|
||
---
|
||
|
||
# hl-fleet-service: 派单看板订单详情识别团期配车,排车节点与实派车辆数不再只认逐户派车行
|
||
|
||
> **存放目录**: `changelogs-v2/2026-09/`
|
||
> **服务**: hl-fleet-service (端口 8087)
|
||
> **PR**: #8583
|
||
> **Issue**: #8556
|
||
> **日期**: 2026-09-30
|
||
> **影响范围**: 管理后台派单看板订单详情端点 `GET /admin/fleet/board/orders/{orderId}`
|
||
|
||
---
|
||
|
||
## ⚠️ 关键变化
|
||
|
||
- 🔴 **破坏性变更**:`actualVehicleCount` 字段的响应类型声明一直是 `Integer`(可空),但改动前的实现从未真正下发过 `null`——本次改动起,**团期子订单在团期配车事实暂不可用时会真实下发 `null`**(触发条件:`groupDispatchManaged=true` 且 `groupDispatchReady=false`)。前端若曾经把该字段当作恒为数字直接做算术或比较,现在必须先判空。
|
||
- 新增 4 个字段:`groupBatchId`(当前归属运营团期 ID,非团期订单为 `null`)、`groupDispatchManaged`(用车是否由团期统一编排)、`groupDispatchReady`(团期配车事实是否已取到,`false` 含义是"未知"不是"没有车")、`groupDispatchPlan`(本单所在乘车分组的团级配车行只读列表)。
|
||
- 团期子订单(`groupDispatchManaged=true`)且本地没有任何逐户派车行时,第 2 步"排车"(`code=DISPATCH`)的状态由 `WAITING` 改为 **`SKIPPED`**(`SKIPPED` 是该字段既有的合法取值,非新增枚举值);语义是"本步不由本单单独执行",不是"未排车"。
|
||
- `actualVehicleCount` 的计算口径变化:团期子订单现在统计"本单逐户派车 ∪ 本单所在乘车分组的团级配车"去重后的车辆并集,不再只数逐户派车行。
|
||
- 团期配车(团级统一编排)与逐户接送机派车可以**同时存在于同一张订单**,二者互不覆盖:`dailyVehiclePlan`(逐户派车)与 `groupDispatchPlan`(团级配车)各自独立返回,`currentAssignment` 仍然只指向逐户派车行。
|
||
- 本次**只改了** `assignment == null`(本地无任何逐户派车行)这一分支的排车节点状态;订单若同时存在逐户派车行,排车节点继续如实反映那条真实派车行的状态,不受团期标记影响。
|
||
|
||
---
|
||
|
||
## 二、变更接口清单
|
||
|
||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||
|---|------|------|------|----------|------|
|
||
| 1 | 派单看板订单详情 | GET | `/admin/fleet/board/orders/{orderId}` | 🔴 破坏性变更 + 字段新增 | 新增团期配车相关 4 字段,`actualVehicleCount` 可为 `null`,排车节点新增 `SKIPPED` 用法 |
|
||
|
||
---
|
||
|
||
## 三、接口详情
|
||
|
||
### 1. 派单看板订单详情 `GET /admin/fleet/board/orders/{orderId}`
|
||
|
||
**VO**: `(无请求体,仅路径参数)` → `BoardOrderDetailVO`
|
||
|
||
#### 使用场景
|
||
|
||
车务打开派单弹窗 Step1 查看当前订单详情时调用。本次改动解决团期子订单在本端点与团期配车总览端点给出相反结论的问题:团期已排车的订单此前在本端点被画成"未排车 / 0 辆"。
|
||
|
||
#### 入参字段表
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| orderId | Path | Long | ✅ | - | 订单 ID |
|
||
|
||
#### 出参字段表
|
||
|
||
以下是本次新增/变化的字段;其余既有字段(`dailyVehiclePlan`、`currentAssignment`、`progressSteps` 等)结构未变,此处不重复列出。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| groupBatchId | Long→String,可空 | 当前归属运营团期 ID(非团期订单为 `null`);活体优先、order-v3 降级时回退派车行建行快照 |
|
||
| groupDispatchManaged | Boolean,可空 | 用车是否由团期统一编排;`true`=排车节点为 `SKIPPED`,车辆事实见 `groupDispatchPlan` |
|
||
| groupDispatchReady | Boolean,可空 | 团期配车事实是否已取到;`false`=未知(非团期基线不可达或该团尚无活跃用车需求),**不是**"没有车";非团期订单为 `null` |
|
||
| actualVehicleCount | Integer,🔴 可空 | 车务当前实派车辆数(团期子订单含团级配车去重并集);`null`=团期配车事实暂不可用,前端不得按 `0` 渲染 |
|
||
| groupDispatchPlan | `List<GroupDispatchPlanVO>` | 本单所在乘车分组的团级配车(只读展示,按服务日、配车行 ID 升序) |
|
||
| ├─ dispatchId | Long→String | 团级配车行 ID(排障定位用,不作为任何写口入参) |
|
||
| ├─ tripDate | LocalDate | 服务日 |
|
||
| ├─ groupCode | String | 本单当日所在乘车分组键(`order_group_vehicle_group.group_code`) |
|
||
| ├─ vehicleId | Long→String,可空 | 车辆 ID(团级配车允许未落车,此时为 `null`) |
|
||
| ├─ vehiclePlate | String | 车牌 |
|
||
| ├─ vehicleModel | String | 车型名 |
|
||
| ├─ driverId | Long→String,可空 | 司机 ID(团级配车允许未落司机,此时为 `null`) |
|
||
| ├─ driverName | String | 司机姓名 |
|
||
| ├─ driverPhone | String | 司机手机(已脱敏) |
|
||
| └─ status | String | 团级配车行状态(原样透出 `fleet_group_dispatch.status`,如 `ASSIGNED`/`CONFIRMED`) |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
GET /admin/fleet/board/orders/2104840641597030402
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
真实实测(团期订单 A,团号 26-3682,仅团期配车、无个人派车行)关键字段:
|
||
|
||
```json
|
||
{"code":200,"data":{"id":"HL20260929154809598","teamNo":"26-3682","groupBatchId":"2104840641651556353","groupDispatchManaged":true,"groupDispatchReady":true,"actualVehicleCount":1},"success":true}
|
||
```
|
||
|
||
对照:非团期订单(团号 26-0013):
|
||
|
||
```json
|
||
{"code":200,"data":{"id":"HL20260924152729671","teamNo":"26-0013","groupBatchId":null,"groupDispatchManaged":false,"groupDispatchReady":null},"success":true}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
- 非团期订单:`groupBatchId`/`groupDispatchManaged`/`groupDispatchReady` 均为 `null`/`false`,`groupDispatchPlan` 为空列表,`actualVehicleCount` 按逐户派车行正常计数(不受本次改动影响,不会是 `null`)。
|
||
- 团期订单但团期配车事实取不到(`groupDispatchReady=false`,如 order-v3 团期基线不可达、或该团尚无活跃正式用车需求):`groupDispatchPlan=[]`,`actualVehicleCount=null`——前端应渲染为"团期配车信息暂不可用"这一类提示,不得退化显示为"未排车 / 0 辆"。
|
||
- 团期分组已铺开但本单不在任何乘车分组(整团免车 / 本单自理):`groupDispatchReady=true` 且 `groupDispatchPlan=[]`,这是已验证的业务结论(本单不占团期用车),与上一条"未知"态不同,不要混为一谈。
|
||
|
||
#### 错误响应
|
||
|
||
本端点既有错误码未变:
|
||
|
||
```json
|
||
{"code":605311,"message":"当前需求存在多个不透明派车方案代际","data":null,"success":false}
|
||
```
|
||
|
||
#### 业务边界
|
||
|
||
- 🔴 `actualVehicleCount` 从本次起可以真实为 `null`:判定条件是 `groupDispatchManaged=true && groupDispatchReady=false`。非团期订单、以及团期配车已就绪的订单,该字段仍是非空整数。
|
||
- 排车节点 `SKIPPED` 只出现在"本地无任何逐户派车行 + 团期统一编排"这一种情况;订单若同时有逐户派车行,排车节点继续如实反映那条派车行的真实状态(`WAITING`/`PROCESSING`/`DONE`/`CANCELED`),团期标记不覆盖它。
|
||
- `groupDispatchReady=false` 的含义是"未知",不是"没有车";只有 `groupDispatchReady=true` 且 `groupDispatchPlan=[]` 才是"本单确实不占团期用车"这个已验证的业务结论。
|
||
- `groupDispatchPlan` 是只读展示,团期用车的修改入口在团期配车总览页,不在本端点。
|
||
|
||
---
|
||
|
||
## 四、契约约束与正确调用方式
|
||
|
||
> 本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。
|
||
|
||
### ✅ 正确 / ❌ 错误 payload 对照
|
||
|
||
| 场景 | payload / 响应 |
|
||
|------|-----------------|
|
||
| ✅ 渲染 `actualVehicleCount` 前先判空 | `null` 时渲染为"暂不可用",非 `null` 时按数字展示 |
|
||
| ✅ 判断"本单是否不占团期用车" | 必须同时看 `groupDispatchReady===true && groupDispatchPlan.length===0`,不能只看 `groupDispatchPlan` 是否为空数组 |
|
||
| ❌ 继续把 `actualVehicleCount` 当作恒不为空的数字直接参与计算 | 团期未就绪场景会拿到 `null`,直接参与算术会产生运行时异常 |
|
||
| ❌ 把排车节点 `SKIPPED` 当作未知枚举值兜底处理 | `SKIPPED` 是 `AssignmentProgressStatusEnum` 既有取值,前端 `allowableValues` 已包含,无需新增分支兜底逻辑,但需要有对应的展示文案 |
|
||
|
||
### 切换状态时的必要动作
|
||
|
||
前端渲染 `actualVehicleCount` 与排车进度节点前,必须先读 `groupDispatchManaged`/`groupDispatchReady` 两个标记决定展示分支;直接复用非团期订单的展示逻辑会在团期订单上产生误导性的"0 辆 / 未排车"提示。
|
||
|
||
---
|
||
|
||
## 五、数据库行为
|
||
|
||
本端点为只读查询,无数据库写操作。新增的团期配车事实来自跨服务只读查询:`groupDispatchManaged=true` 时才会额外发起一次到 order-v3 的 Feign 调用取团期基线,非团期订单不受影响、不多打这次调用。查询失败或该团无活跃需求时返回"未知"态(`groupDispatchReady=false`),不抛异常、不影响本端点其余字段的正常返回。
|
||
|
||
---
|
||
|
||
## 六、边界行为
|
||
|
||
- 非团期订单 → `groupBatchId`/`groupDispatchReady` 为 `null`,`groupDispatchManaged=false`,`groupDispatchPlan=[]`,`actualVehicleCount` 按逐户派车行正常计数
|
||
- 团期订单、团期配车基线不可达或该团无活跃需求 → `groupDispatchReady=false`,`groupDispatchPlan=[]`,`actualVehicleCount=null`
|
||
- 团期订单、团期分组已铺开但本单不在任何分组 → `groupDispatchReady=true`,`groupDispatchPlan=[]`,`actualVehicleCount` 按逐户派车行计数(可能为 0,这是已验证结论不是未知态)
|
||
- 团期订单、团期配车已就绪且本单在某分组 → `groupDispatchReady=true`,`groupDispatchPlan` 非空,`actualVehicleCount` 为逐户 ∪ 团级去重后的并集大小
|
||
- 本地无逐户派车行 + 团期统一编排 → 排车节点 `SKIPPED`
|
||
- 本地有逐户派车行(不论是否团期订单)→ 排车节点如实反映该派车行状态,不受团期标记影响
|
||
- 存量 `group_id` 为 `NULL` 的团级配车行(`V20260916_002` 迁移前落库、明确不回填)不进入本单的 `groupDispatchPlan`,但不报错、不影响其它行
|
||
|
||
---
|
||
|
||
## 六.5、枚举 / 数据字典
|
||
|
||
### 排车进度节点状态(`AssignmentProgressStatusEnum`,`progressSteps[].status`,`code=DISPATCH` 这一步)
|
||
|
||
**所属字段**: `progressSteps[].status`(当 `progressSteps[].code=DISPATCH`) | **类型**: `String`
|
||
|
||
| 值 | 中文 | 本次是否新增 | 说明 |
|
||
|----|------|------|------|
|
||
| `WAITING` | 等待中 | 既有值 | 非团期订单本地无派车行时的状态,本次未变 |
|
||
| `PROCESSING` | 进行中 | 既有值 | 本次未变 |
|
||
| `DONE` | 已完成 | 既有值 | 本次未变 |
|
||
| `CANCELED` | 已取消 | 既有值 | 本次未变 |
|
||
| `SKIPPED` | 已跳过 | 本次起用于排车节点 | 团期统一编排且本地无逐户派车行时的新用法;该取值本身已在 VO `allowableValues` 中存在(此前用于其它步骤),本次是新增了"排车"这一步会用到它 |
|
||
|
||
## 六.6、修改前后对比
|
||
|
||
### 字段级对比
|
||
|
||
| 字段 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| `groupBatchId` | 不存在 | 新增,`Long→String`,可空 |
|
||
| `groupDispatchManaged` | 不存在 | 新增,`Boolean`,可空 |
|
||
| `groupDispatchReady` | 不存在 | 新增,`Boolean`,可空 |
|
||
| `groupDispatchPlan` | 不存在 | 新增,`List<GroupDispatchPlanVO>`(10 个子字段,见出参字段表) |
|
||
| `actualVehicleCount` | 字段声明类型一直是 `Integer`,但实现从未真正下发过 `null`(内部局部变量此前是不可空计算) | 团期子订单在配车事实未就绪时,Service 层真实计算出 `null` 并下发 |
|
||
|
||
### 行为级对比
|
||
|
||
| 场景 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| 团期子订单、本地无逐户派车行 | 排车节点 `WAITING`,`actualVehicleCount=0` | 排车节点 `SKIPPED`,`actualVehicleCount` 取团期配车去重实派车数(就绪时)或 `null`(未就绪时) |
|
||
| 团期子订单、同时有逐户派车行 | 排车节点按该派车行真实状态 | 不变,仍按该派车行真实状态 |
|
||
| `actualVehicleCount` 统计口径(团期子订单) | 只数本单逐户派车行 | 本单逐户派车 ∪ 本单所在乘车分组的团级配车,去重后的并集 |
|
||
| 非团期订单 | 无本次描述的任何字段/行为 | 无变化(新增字段均为 `null`/`false`,`actualVehicleCount` 计算口径不变) |
|
||
|
||
## 六.7、影响评估
|
||
|
||
- **是否破坏向后兼容**: 是——`actualVehicleCount` 的字面类型虽然一直是 `Integer`,但运行时从未观测到过 `null`;前端若曾经把它当作恒为数字的字段直接做算术/比较,现在会在团期未就绪场景下遇到真实的 `null`。
|
||
- **前端是否必须同步上线**: 是(仅对涉及团期订单展示的场景)——非团期订单的响应字段与行为完全不变,可以不改;但只要页面会展示团期订单,就必须先对 `actualVehicleCount` 判空,并依据 `groupDispatchManaged`/`groupDispatchReady` 决定排车节点与实派车数的展示分支。
|
||
- **前端 workaround 清理点**: 若此前为"团期订单详情显示未排车/0 辆,但团期配车总览显示已排车"这类矛盾现象写过特殊兼容或屏蔽逻辑,现在两端点结论已一致,可以确认不再需要。
|
||
|
||
---
|
||
|
||
## 七、不影响范围
|
||
|
||
- **仅影响**: 派单看板订单详情端点 `GET /admin/fleet/board/orders/{orderId}` 的响应字段与团期子订单的排车节点/实派车数展示逻辑。
|
||
- **零影响**:
|
||
- 派单看板列表端点 `GET /admin/fleet/board/orders`(`BoardOrderRecordVO`)未受本次改动波及
|
||
- 非团期订单的响应字段与行为
|
||
- 接送机步骤(`PICKUP_DROPOFF`)与确认执行步骤(`CONFIRM_EXECUTE`)的判定逻辑
|
||
- `dailyVehiclePlan`(逐户派车方案)的既有字段结构与计算口径
|
||
- 团期配车总览/就绪判定等团期配车域自身的写口与其余读口
|
||
|
||
---
|
||
|
||
## 八、测试环境已验证
|
||
|
||
服务:`hl-fleet-service`,dev-v3 分支部署测试网关 @ `9c7ac9382`(含 #8556 所在提交),测试网关 `https://api.test.1814.love`;样本均为测试服现存真实业务数据:
|
||
|
||
```
|
||
✓ 团期订单 A(orderId=2104840641597030402,团号 26-3682,团期批次 2104840641651556353,仅团期配车无个人派车):
|
||
groupBatchId="2104840641651556353" groupDispatchManaged=true groupDispatchReady=true
|
||
progressSteps[DISPATCH].status=SKIPPED statusLabel=已跳过 active=false
|
||
actualVehicleCount=1;groupDispatchPlan 共 7 条(2026-11-11~2026-11-17)
|
||
与同批次团期配车总览 GET /admin/fleet/group-dispatch/batches/2104840641651556353/overview 对照:
|
||
vehicleReady=true,7 天 dispatched=true,结论一致(改前两端点结论相反)
|
||
✓ 非团期订单 C(orderId=2103023501973848066,团号 26-0013):
|
||
groupBatchId=null groupDispatchManaged=false groupDispatchReady=null
|
||
✓ 团期订单 B(orderId=2104839654652121090,同时有团期配车与个人派车):
|
||
groupDispatchManaged=true groupDispatchReady=true actualVehicleCount=2
|
||
dailyVehiclePlan:1 条,车辆蒙C10E10/司机铁木尔(个人派车)
|
||
groupDispatchPlan:多条,首条车辆蒙A-K1999/司机巴特尔(团期配车)
|
||
两组数据同时非空、互不顶替;currentAssignment 仍指向个人派车行(蒙C10E10/铁木尔)
|
||
```
|
||
|
||
注:`actualVehicleCount=null` 这一具体取值未在本轮实测中被真实触发(测试服 order-v3 全程可达,两个团期样本 `groupDispatchReady` 均为 `true`);该分支的契约(字段类型可空、触发条件 `groupDispatchManaged=true && groupDispatchReady=false`)已在源码逐一核实(`BoardOrderService.java`、`BoardOrderDetailVO.java`),前端应按此契约做防御性判空,不依赖本轮是否观测到该取值。
|
||
|
||
---
|
||
|
||
## 十、相关文档
|
||
|
||
- 关联 Issue: [wx/HL#8556](https://git.1814.love/wx/HL/issues/8556)
|
||
- 关联 PR: [wx/HL#8583](https://git.1814.love/wx/HL/pulls/8583)
|
||
|
||
## 关联 / 联系人
|
||
|
||
### 链接
|
||
|
||
- **Issue**: [#8556](https://git.1814.love/wx/HL/issues/8556)
|
||
- **PR**: [#8583](https://git.1814.love/wx/HL/pulls/8583)
|
||
- **Merge commit**: [9c7ac93829](https://git.1814.love/wx/HL/commit/9c7ac93829)
|
||
|
||
### 联系人
|
||
|
||
- **后端负责人**: @wx
|