18 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8294 | 团期配车就绪检查「座位不足」黄牌改为扣司机座,新增 passengerSeatTotal | admin | wx(GIT) | 修改接口 | deployed | verified | verified | mmg | e5a34cd13e641ac10394a9a245f0548461894a02 | v2.1 | 2026-09-24 | PR #8305 已合并 dev-v3(2a3b9df59)。部署:hl-fleet-service dev-v3 @ 2a3b9df59,2026-09-24 09:48:52 起滚,09:50:13 完成,8087/8187 两实例均 UP;实测 09:52 晚于部署完成时刻。测试服网关真实 GET /admin/fleet/group-dispatch/batches/{groupBatchId}/readiness:团期 2101514348969226242 返回 WARN_SEAT_SHORTAGE,seatTotal=7、passengerSeatTotal=6、headcount=40、gap=34(7-1=6 证明扣座、40-6=34 证明 gap 按新口径);团期 2102066067272826881 座位合计 0 时 passengerSeatTotal=0 不为负;团期 2101997326354862082(座位合计 5/可载客 4/人数 4)与 2101690789438570497(7/6/6)warned=false,证明取等号时不误报。fleet 定向单测 778/0/0(含 GroupDispatchReadinessServiceTest 26、VehicleSeatCapacityTest 4、FleetRedLineArchTest 18)+ spotless:check 绿;回退判据后 3 个用例转红(含「20 座车 20 人应报缺 1 座」),恢复后转绿。gateway_status: verified —— 路径本就在既有 admin-fleet-service 路由 Path=/admin/fleet/** 下,本次零路由改动,并已通过真实网关实测。frontend_status: pending —— 前端需读新字段 passengerSeatTotal,且 gap 的语义已变(改为 用车人数 − 已扣司机座的可载客数),若仍按「用车人数 − seatTotal」渲染会差 1×车数。 前端已交付并验证:实证黄牌 b.message 直显、seatTotal/gap/headcount 零数值消费,新文案自动生效;group-dispatch.js JSDoc 订正新口径(透 message 禁文本匹配/自算 gap,seatTotal+gap≠headcount 正常须 passengerSeatTotal+gap 闭合),drawer spec fixture/断言改新文案回归锁 7 例全绿。hl-admin@e5a34cd1。 | 2026-09-24 | dev-v3 |
fleet 团期配车就绪检查: 座位不足黄牌改为扣司机座
存放目录: 二期(v3) →
changelogs-v2/2026-09/服务: hl-fleet-service(团期配车读口) PR: #8305 Issue: #8294 日期: 2026-09-24 影响范围: 管理后台「团期详情 → 配车」页的就绪检查提示(黄牌文案与字段)
⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)
- 本次变化:
GET /admin/fleet/group-dispatch/batches/{groupBatchId}/readiness响应里warnings[]中code=WARN_SEAT_SHORTAGE的条目,判据由「座位合计(含司机座)< 该日用车人数」改为「可载客数合计 < 该日用车人数」。每车可载乘客数 = 座位数 − 1(扣 1 个司机座)。口径与团级用车需求 809116(#8278,PR #8296)、fleet 单车派车完全一致。 - 前端以前以为的:
seatTotal就是「能坐多少人」,gap = headcount − seatTotal。现在gap不再按seatTotal算——同一响应里seatTotal + gap ≠ headcount是正常的,必须叠加新字段passengerSeatTotal才闭合(passengerSeatTotal + gap = headcount)。 - 实际现在的行为:判据字段是
passengerSeatTotal;seatTotal原义与数值都未变(仍是含司机座的座位合计,可以直接继续展示「N 座车」)。 - 会新增黄牌:
座位合计 ≥ 用车人数 > 可载客数合计这个区间以前不报、现在报。最小例子:1 辆 20 座车、该日 20 人——改前不报,改后报「缺 1 座」(司机没座)。存量数据不重算,下一次读取即按新口径。 message文案改写(前端如果做文本匹配会失效):旧「2027-06-10 分组 MAIN 座位合计 7,该日用车人数 40,缺 33 座」→ 新「2027-06-10 分组 MAIN 座位合计 7 座(含司机座),已扣司机座后可载客 6 人,该日用车人数 40,缺 34 座」。- 黄牌语义不变:仍然只提醒、不阻断,
ready与warned仍互相独立,ready=true && warned=true依然合法。
一、背景(选填)
#8278 已定案:团级用车需求的容量一律按「每车扣 1 个司机座」算(VehicleSeatCalculator),订单子级与 fleet 单车派车(预检告警、候选容量)本来就是这个口径。唯一没对齐的是 fleet 的团级就绪检查——它直接累加 vehicle.getSeats(),把「20 座车塞 20 人」判成够。同一份排法在团级需求侧已被 809116 拦下,在配车就绪页却显示「够」,运营无法判断该信哪一个。本单让第三处(也是最后一处)向已有口径看齐,而不是放松另外两处。
最强反例(评审已确认,留档):「刚好坐满、司机另开一辆车」这类排法在新口径下会多出一条黄牌。它只是提醒不是硬拦,且这类配置在业务上本就不成立(司机座不能卖给乘客);被提醒是纠正而不是误伤。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 团期配车就绪检查 | GET | /admin/fleet/group-dispatch/batches/{groupBatchId}/readiness |
响应新增字段 + 字段语义变更 + 文案变更 | warnings[] 中 WARN_SEAT_SHORTAGE 条目新增 passengerSeatTotal,gap 改按它计算,message 改写 |
本次只动这一个端点(同一控制器的其余端点未改)。
三、接口详情
1. 团期配车就绪检查 GET /admin/fleet/group-dispatch/batches/{groupBatchId}/readiness
VO: GroupDispatchReadinessRespVO → GroupDispatchReadinessItemVO[]
使用场景
团期详情「配车」页进入时拉取,用于展示硬拦(不能置 vehicle_ready)与黄牌(能发车但有缺口)。请求参数与响应整体结构均不变,本条只改「只提醒」数组里座位不足那一档的字段与文案。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
groupBatchId |
Path | Long | 是 | 团期主订单 ID | 路径参数 |
出参 Result<GroupDispatchReadinessRespVO>
顶层字段(本次未变):
| 字段 | 类型 | 说明 |
|---|---|---|
groupBatchId |
String(Long) | 团期主订单 ID |
requirementId |
String(Long) | 判定所依据的正式需求 ID |
requirementVersion |
Integer | 判定所依据的需求版本 |
planVersion |
Long | fleet 侧当前计划版本(该团尚无任何计划行时为 null) |
ready |
Boolean | 硬拦三项是否全过(= blockers.isEmpty()) |
warned |
Boolean | 是否有只提醒项(= !warnings.isEmpty()) |
blockers |
Array | 硬拦未过项 |
warnings |
Array | 只提醒项 |
groups |
Array | 逐组覆盖明细(与配车写口 coverage 同源,逐字段可比对) |
shareGroupCount |
Integer | 本团 active 同团车辆共用关系数(只供展示,不参与判定) |
warnings[] 元素(GroupDispatchReadinessItemVO):
| 字段 | 类型 | 说明 |
|---|---|---|
code |
String | 判定项代码:WARN_SEAT_SHORTAGE / WARN_DRIVER_MISSING |
message |
String | 中文描述(本次改写,见下表) |
tripDate |
LocalDate | 相关行程日 |
groupCode |
String | 相关乘车分组码 |
seatTotal |
Integer | 该日该组的座位合计(含司机座);仅座位不足档有值 |
passengerSeatTotal |
Integer | 新增:该日该组的可载客数合计(Σ max(0, seats − 1));仅座位不足档有值 |
headcount |
Integer | 该日该组的用车人数;仅座位不足档有值 |
gap |
Integer | 座位缺口(本次改按 passengerSeatTotal 计算);仅座位不足档有值 |
dispatchId |
String(Long) | 相关配车行 ID;仅司机缺失档有值 |
本次逐字段变化(仅 WARN_SEAT_SHORTAGE 档):
| 字段 | 类型 | 本次变化 | 说明 |
|---|---|---|---|
code |
String | 不变 | WARN_SEAT_SHORTAGE / WARN_DRIVER_MISSING |
message |
String | 改写 | 座位不足档现在写明「含司机座」与「已扣司机座后可载客 N 人」 |
tripDate |
LocalDate | 不变 | 相关行程日 |
groupCode |
String | 不变 | 相关乘车分组码 |
seatTotal |
Integer | 语义不变 | 该日该组活跃配车行的座位合计(含司机座),数值与改前逐字相同 |
passengerSeatTotal |
Integer | 新增 | 该日该组的可载客数合计 = Σ max(0, seats − 1),座位数取不到的车按 0 计,恒 ≥ 0 |
headcount |
Integer | 不变 | 该日该组用车人数 |
gap |
Integer | 语义变更 | 由 headcount − seatTotal 改为 headcount − passengerSeatTotal(恒 ≥ 1) |
dispatchId |
String(Long) | 不变 | 仅 WARN_DRIVER_MISSING 有值 |
以上与座位相关的五项仅 WARN_SEAT_SHORTAGE 档有值;WARN_DRIVER_MISSING 档这五项均为 null(含新增的 passengerSeatTotal)。
请求示例
GET /admin/fleet/group-dispatch/batches/2101514348969226242/readiness
Authorization: Bearer <admin token>
响应示例
测试服真实响应(2026-09-24 09:52,hl-fleet-service dev-v3 @ 2a3b9df59,节选该接口 warnings 内容):
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"groupBatchId": "2101514348969226242",
"ready": true,
"warned": true,
"planVersion": 4,
"warnings": [
{
"code": "WARN_SEAT_SHORTAGE",
"message": "2027-06-10 分组 MAIN 座位合计 7 座(含司机座),已扣司机座后可载客 6 人,该日用车人数 40,缺 34 座",
"tripDate": "2027-06-10",
"groupCode": "MAIN",
"seatTotal": 7,
"passengerSeatTotal": 6,
"headcount": 40,
"gap": 34,
"dispatchId": null
}
]
}
}
对照:seatTotal(7) + gap(34) = 41 ≠ headcount(40);passengerSeatTotal(6) + gap(34) = 40 = headcount —— 前端做守恒校验请用后者。
空数据 / 降级响应
- 无缺口时
warnings: []、warned: false,其余字段照常返回。 - 该团未声明任何乘车分组或基线不可用:
code=602113,失败关闭,绝不返回ready=true。 - 入参非法:
code=602114。
错误响应
{ "code": 602113, "message": "...", "success": false, "data": null }
业务边界
- 座位不足只提醒:
ready只看blockers,不受本档影响;两条写路径(配车方向判定、就绪意图发射)只调hardGatesPass,该入口完全不看座位。 - 扣座是逐车的:N 辆车扣 N 个司机座(两辆 20 座车 / 39 人 ⇒ 可载客 38、缺 1 座),不是全团只扣 1 个。
- 座位数取不到(车已软删 / 车型未录座位数)的车按 0 计,可载客数不出现负数。
- 按「组 + 行程日」逐格比:同一组不同日期分别判定,不同组分别判定。
四、契约约束与正确调用方式(接口类必写)
✅ 正确 / ❌ 错误用法对照
| 场景 | ✅ 正确 | ❌ 错误 |
|---|---|---|
| 判断「够不够」 | 后端已给结论:warned / warnings 是否为空 |
前端自己用 seatTotal >= headcount 重算 |
| 展示缺口 | 直接展示 gap,或展示 headcount − passengerSeatTotal |
用 headcount − seatTotal 现算(会少 1×车数) |
| 展示运力 | passengerSeatTotal(可载客)与 seatTotal(车辆座位规格)分开显示 |
把 seatTotal 当成可载客数展示 |
| 文案 | 直接展示后端 message |
按旧文案做字符串匹配/替换 |
切换状态时的必要动作
无。本接口是只读 GET,不改变任何状态,也不触发重算。
五、数据库行为(涉及写操作时必写)
无写入。判据全部基于既有列在读取时现算(活跃配车行 × 车辆座位数 × 需求逐日人数),不落库、不新增列、无迁移。
六、边界行为
| 边界 | 行为 |
|---|---|
headcount = 0 |
不报(0 >= 0) |
| 座位数取不到(车软删 / 未录) | 该车按 0 计,缺口如实报出 |
| 座位数为 0 或 1 | 可载客数 0,不出现负数 |
| 恰好坐满(可载客数 == 人数) | 不报(取等号判「够」) |
| 该日没有排车 | 该日可载客数 0;整组没排车由硬拦 BLOCK_GROUP_MISSING 承接 |
| 需求已 DONE | 仍返回 ready=true(DONE 比 CONFIRMED/DISPATCHED 更靠后) |
六.5、枚举 / 数据字典(接口出现枚举时必写)
warnings[].code 取值不变,仍为两档:
| 取值 | 含义 | 相关字段 |
|---|---|---|
WARN_SEAT_SHORTAGE |
该日该组可载客数不足 | tripDate / groupCode / seatTotal / passengerSeatTotal / headcount / gap |
WARN_DRIVER_MISSING |
配车行未排司机(消息带车牌) | tripDate / groupCode / dispatchId,其余为 null |
无新增错误码。
六.6、修改前后对比(修改/删除类接口必写,新增跳过)
字段级对比(warnings[] 中 WARN_SEAT_SHORTAGE 条目)
| 字段 | 修改前 | 修改后 |
|---|---|---|
seatTotal |
座位合计(含司机座) | 不变(同值同义) |
passengerSeatTotal |
不存在 | 新增,Σ max(0, seats − 1) |
gap |
headcount − seatTotal |
headcount − passengerSeatTotal |
message |
{日期} 分组 {组} 座位合计 {N},该日用车人数 {M},缺 {K} 座 |
{日期} 分组 {组} 座位合计 {N} 座(含司机座),已扣司机座后可载客 {P} 人,该日用车人数 {M},缺 {G} 座 |
行为级对比
| 行为 | 修改前 | 修改后 |
|---|---|---|
| 1 辆 20 座车 / 该日 20 人 | 不报(20 ≥ 20) | 报,缺 1 座 |
| 1 辆 20 座车 / 该日 19 人 | 不报 | 不报(可载客 19 ≥ 19) |
| 2 辆 20 座车 / 该日 39 人 | 不报(40 ≥ 39) | 报,缺 1 座(可载客 38) |
| 1 辆 7 座车 / 该日 40 人 | 报,seatTotal=7、gap=33 |
报,seatTotal=7、passengerSeatTotal=6、gap=34 |
| 座位数为 0 / 取不到 | 报,seatTotal=0、gap=人数 |
报,passengerSeatTotal=0、gap=人数(不为负) |
ready |
不受本档影响 | 不变(仍只提醒) |
六.7、影响评估(修改/删除类必写)
- 变宽:
座位合计 ≥ 用车人数 > 可载客数合计这个区间由「不报」变「报」。区间宽度恰是「该日排的车数」(每车多算 1 个司机座),所以车越多、越容易落进来。 - 不变:
gap的值在「座位取不到」和「原本就严重不足」的场景里可能不变;但在「刚好卡边界」的场景会 +1×车数。任何拿gap做阈值判断的前端逻辑都要复核。 - 后端消费方:
getSeatTotal()/getGap()在 HL 全仓(Java)生产代码中消费方为 0(只有测试引用),本接口的消费方是管理后台前端。 - 存量数据不重算:不落库,下一次读取即按新口径;测试服现有 116 条活跃配车行、34 个团期中,没有落在新增黄牌区间(
用车人数 == 座位合计)的活跃分组,本次口径变更对既有数据的可见影响为 0。 - 前置依赖:本单与 #8278 是同一口径的第三处收口,不改变 809116、子订单级校验、候选容量的任何行为。
七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
blockers[]三档与ready的判定逻辑:零改动。groups[]、shareGroupCount、planVersion、requirementVersion等字段:零改动。- 同一控制器的其余端点(
/pending-batches、/batches/{id}/overview、/resource-schedule):零改动。 - 配车写口(提交 / 确认 / 改派 / 删除)与
coverage:零改动。 - 单车派车的预检告警、候选容量、候选页
passengerCapacity字段:行为零改动(只把内部重复实现收口到一份工具方法)。 - 团级用车需求 809116(#8278 已交付)与 order-v3:行为零改动(仅同步了两处已失效的注释)。
- 数据库:无迁移、无新列。
八、测试环境已验证
- 定向测试:
mvn -o -pl hl-fleet-service -am test -Dtest='GroupDispatchReadinessServiceTest*,VehicleSeatCapacityTest*,AssignmentCandidateServiceTest*,AssignmentServiceTest*,AssignmentServiceNoVehicleDeclarationTest*,AssignmentServicePickupDropoffTest*,AssignmentServiceClearCancelledOccupancyTest*,AssignmentServiceResolveExceptionTest*,FleetRedLineArchTest' -DfailIfNoTests=false -Dhl.surefire.failIfNoTests=false→ 778 / 0 / 0,BUILD SUCCESS(逐类核对Tests run,报告文件时间均晚于本轮起跑)。 - 分辨力:把判据临时还原为旧口径后 3 个用例转红(含「20 座车 20 人应报缺 1 座」),恢复后 30/0/0 转绿。
- 网关验证:
GET https://api.test.1814.love/admin/fleet/group-dispatch/batches/{groupBatchId}/readiness(fleet dev-v3 @2a3b9df59,09:52 实测)——团期2101514348969226242返回WARN_SEAT_SHORTAGE(seatTotal=7、passengerSeatTotal=6、headcount=40、gap=34);团期2102066067272826881座位合计 0 时passengerSeatTotal=0;团期2101997326354862082(5/4/4)与2101690789438570497(7/6/6)warned=false。全程只读 GET。 - 兼容性结论:
seatTotal语义与数值不变,新增字段为增量、老前端不会因缺字段崩溃;但任何用seatTotal反算缺口的旧逻辑会差 1×车数,必须改读passengerSeatTotal(或直接用gap)。
十、相关文档
- 接口契约:
hl-fleet-service/src/main/java/com/hulalv/fleet/dispatch/controller/GroupDispatchQueryController.java - 响应结构:
hl-fleet-service/src/main/java/com/hulalv/fleet/dispatch/vo/GroupDispatchReadinessItemVO.java - 口径工具:
hl-fleet-service/src/main/java/com/hulalv/fleet/common/util/VehicleSeatCapacity.java - 同口径前置单:#8278 / PR #8296(团级 809116 扣司机座),本单是其
changelogs-v2/2026-09/23_8278_团级用车分组座位校验扣司机座-修改接口-管理后台.md里声明的「fleet 团级就绪检查仍不扣座、由 #8294 跟踪」的收口。
关联 / 联系人
链接
联系人
- 后端负责人: @wx