changelog-filename-gate / validate (push) Failing after 2s
- #8543 团期订单 Tab 用车状态三处读口按需求类别拆分并统一文案(PR #8592) - #8548/#8549 整团免车放行户级接送机需求,换组重开团期补待审户读数(PR #8586) - #8560 矩阵未派订单卡下发 requirementKind,可区分行程用车与接送机(PR #8589) 三份均已在测试网关实测取证,两道门禁(frontmatter 校验 + changelog_workflow lint)全绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
16 KiB
16 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 | 8560 | 矩阵未派订单清单响应新增用车需求类别字段,同订单双需求两张卡可区分 | admin | wx(GIT) | 修改接口 | deployed | verified | pending | PR #8589 合并 dev-v3(8b045a321b);测试网关部署确认:hl-fleet-service 现部署 @ 99fb369ba(deploy-status.sh 实测,状态 ok,该 SHA 经 git merge-base --is-ancestor 确认已包含 8b045a321b)。GET /admin/fleet/matrix/unassigned-orders 已用车务角色测试账号实测:2026-09 月拿到 TRAVEL 示例(订单 HL20260911193207642)、2026-11 月拿到 TRANSFER 示例(订单 HL20260929154809598),均为测试服真实响应;对 2026-06~2027-03 共 10 个月窗口扫描未发现 requirementKind=null 或同订单双卡的活跃实例,这两种边界行为当前仅由单元测试覆盖(BoardRequirementIdentitiesKindTest 5/5、MatrixServiceTest 新增 6 个 #8560 方法),尚未在测试服活数据上复现。 | 2026-09-30 | dev-v3 |
hl-fleet-service:矩阵未派订单清单响应新增用车需求类别字段,同订单双需求两张卡可区分
存放目录:
changelogs-v2/2026-09/服务: hl-fleet-service PR: #8589 Issue: #8560 日期: 2026-09-30 影响范围: 1 个只读端点响应新增 2 字段(矩阵未派订单清单)
⚠️ 关键变化
GET /admin/fleet/matrix/unassigned-orders响应每条记录新增requirementKind(TRAVEL/TRANSFER/null)与requirementKindLabel(行程用车/接送机/null),两者恒成对(一个为 null 另一个必为 null)。- 背景(#7439):同一订单可并存两条活跃用车需求(行程用车 TRAVEL + 接送机 TRANSFER),车务分别对两者派车,未派池会出现同一订单的两张卡。此前两张卡除车型/日期外没有任何字段能分辨谁是哪一类——既有字段
vehicleCategory/categoryLabel是车型(suv/bus)不是需求类别。新增这两个字段就是用来分辨这两张卡的。 - 🔴
null不兜底成TRAVEL,这是本次修复的核心边界。判不出类别(跨服务降级 context=null;或派车行挂着 #5720 换版过渡窗里的上一版requirement_id,命中不了任何当前活跃身份;或命中的身份自身kind为空白)时两个新字段均为null,前端应不显示类别标签,禁止自行按业务猜测补默认值——尤其禁止把null当TRAVEL处理。 - 与看板列表(
BoardOrderRecordVO.requirementKind,#8518 既有)在判不出这一档口径不同:看板列表的解析方法判不出时兜底返TRAVEL(那里类别同时是筛选维度,返空会让卡片从筛选后的视图里彻底消失);矩阵未派卡判不出时返null(那里类别只是展示标签,车务会照标签去排完全不同的活,标错比不标更危险)。同一张实体卡在两个入口可能显示不一致的类别信息,这是刻意保留的差异,不是缺陷。 - 真实未派行与虚拟待派条目(
virtualPending=true,#7067)两类条目都携带这两个新字段,取值口径一致。 - 类别取的是这张卡自身所属需求(真实行用该行自己的
requirement_id,虚拟条目用该候选自己的requirementId)解析出的类别,不是已有字段requirementId(该字段取「订单侧单值」,#5667 口径,同一订单两类需求并存时恒指向身份列表首项、即恒为 TRAVEL 那条)。同一订单两张卡的requirementId字段取值会相同,但requirementKind/requirementKindLabel不同——这正是新增这两个字段的意义所在,不能拿旧字段替代判断。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 矩阵未派订单清单 | GET | /admin/fleet/matrix/unassigned-orders |
字段新增(非破坏性) | 响应新增 requirementKind/requirementKindLabel |
三、接口详情
1. 矩阵未派订单清单 GET /admin/fleet/matrix/unassigned-orders
VO: MatrixUnassignedReqVO → List<MatrixUnassignedOrderVO>
使用场景
派单矩阵页右面板「未派订单窗口」,车务从此列表拖拽卡片到左面板某车某日完成派车;同一订单若同时有行程用车与接送机两条活跃需求,会在此列表出现两张卡,车务需要靠新增的类别字段区分要往哪类需求上派车,不能再靠车型/日期/备注这类间接信息猜。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| year | query | Integer | 是 | 2020-2100,越界返 605076 | 年份 |
| month | query | Integer | 是 | 1-12,越界返 605010 | 月份 |
| typeKeys | query | String[] | 否 | 取值 suv/mpv/bus/sedan,规范小写 | 车型大类多选,空=全部;对虚拟待派条目按当前需求车型明细任一项归一后命中过滤 |
出参字段表(仅列本次新增字段及理解其语义所需的上下文字段,VO 全量共 39 个字段)
| 字段 | 类型 | 说明 |
|---|---|---|
| requirementKind | String | 新增。用车需求类别:TRAVEL=行程用车 / TRANSFER=接送机 / null=判不出(不兜底为 TRAVEL) |
| requirementKindLabel | String | 新增。类别中文名:行程用车/接送机/null,与 requirementKind 恒成对 |
| requirementId | Long(字符串序列化) | 既有字段,当前生效用车需求 ID;取订单侧单值(#5667),两类需求并存时恒指向 TRAVEL 那条,不能用它推导 requirementKind |
| assignmentId | Long(字符串序列化) | 既有字段,本行唯一主键;虚拟待派条目为 null |
| virtualPending | Boolean | 既有字段,true=虚拟待派条目(零派车行订单,按需求上下文补出) |
| vehicleCategory | String | 既有字段,规范小写车型 key(suv/mpv/bus/sedan),与需求类别是两个不同维度 |
| categoryLabel | String | 既有字段,车型中文标签(恒非 null) |
| orderId / orderNo | String | 既有字段,订单号 |
| teamNo | String | 既有字段,团号 |
请求示例
GET /admin/fleet/matrix/unassigned-orders?year=2026&month=11&typeKeys=mpv
响应示例
实测取自测试服真实数据(2026-11 月,TRANSFER 示例):
{
"code": 200,
"message": "success",
"data": [
{
"orderId": "HL20260929154809598",
"orderNumericId": "2104840641597030402",
"orderNo": "HL20260929154809598",
"teamNo": "26-3682",
"virtualPending": true,
"assignmentId": null,
"assignmentGroupId": null,
"requirementId": "2104844928733548545",
"requirementKind": "TRANSFER",
"requirementKindLabel": "接送机",
"vehicleCategory": "mpv",
"categoryLabel": "商务车",
"customerName": "董海涛",
"headcount": 2,
"headcountLabel": "2大",
"startDate": "2026-11-11",
"endDate": "2026-11-17",
"pickupAt": "阿尔山伊尔施机场",
"dropoffAt": "阿尔山伊尔施机场",
"assignmentStatus": "unassigned",
"urgentBadge": null,
"vehicleAdvice": null,
"parallelAssignments": []
}
]
}
对照:2026-09 月同一账号实测取到的 TRAVEL 示例(订单 HL20260911193207642),响应结构完全相同,仅 requirementKind="TRAVEL"、requirementKindLabel="行程用车"、requirementId="2098950695167148034"。两个示例均为测试服真实取数,未做任何字段改写。
空数据 / 降级响应
- 当月无未派条目:
data: [],非错误。 vehicleAdvice恒为null(M2 数据源未建,既有降级行为,与本次改动无关)。- Nacos
fleet.board.virtual-candidates-enabled=false或 order-v3 候选服务不可用时:只丢虚拟待派条目,真实未派行原样返回(fail-open);真实行的requirementKind解析走独立的上下文查询,不受此开关影响。 requirementKind/requirementKindLabel判不出时为null(见「⚠️ 关键变化」),这不是接口异常,是正常的降级取值,前端应按无标签渲染,不得折算为TRAVEL。
错误响应
{
"code": 605010,
"message": "月份超出范围",
"data": null
}
{
"code": 605076,
"message": "年份超出范围(仅支持 2020-2100 年)",
"data": null
}
100001参数非法:year/month 缺失(框架校验)。401未登录。
业务边界
- 同一订单两类需求并存时,两张卡的
requirementId字段值完全相同(均指向 TRAVEL 那条),但requirementKind/requirementKindLabel不同——单元测试MatrixServiceTest#queryUnassignedOrders_orderWithBothKinds_twoCardsCarryDifferentKinds对此有显式反向对照断言,用来证明「拿 requirementId 反推类别」是错的,前端也不能这么做。 requirementKind=null时前端禁止折算成TRAVEL;这既是判不出的真实状态,也是修复前的错误行为,回退等于复发。- 矩阵未派卡与看板列表对同一张孤儿行(#5720 换版过渡窗)的类别展示口径不同(前者 null、后者兜底 TRAVEL),这是刻意保留的差异,不要据此判断某一端有 bug。
- 真实未派行与虚拟待派条目两种类型都下发这两个字段,前端不需要按
virtualPending分支处理类别逻辑。
四、契约约束与正确调用方式
- 判类别只认
requirementKind/requirementKindLabel这两个新字段,不要用requirementId做二次推导。 requirementKind取值集合当前为{TRAVEL, TRANSFER, null},前端不应写死「非 TRANSFER 即 TRAVEL」的二值判断——若未来 order-v3 新增第三类需求,后端会同步扩展该字段取值与中文映射,二值判断会把新类别误标成 TRAVEL。- 类别中文名由后端下发,前端不需要、也不应该自行维护
TRAVEL/TRANSFER到中文的映射表。
五、数据库行为
无数据库结构变更。本次改动只是查询层新增两次内存解析(基于已查出的订单需求上下文按 requirement_id 匹配),不新增表、不新增列、不新增索引,无 Flyway 迁移。
六、边界行为
- 上下文降级(跨服务 Feign 调用失败,
OrderFleetBoardContextDTO为null):类别字段为null。 - 派车行/候选自身的
requirement_id命中不到订单当前任何活跃需求身份(#5720 换版过渡窗孤儿行):类别字段为null,不回退用订单上下文单值猜测。 - 命中的身份自身
kind字段为空白:类别字段为null(防御性分支;order-v3 当前写路径恒写枚举.name(),正常不触发,仅覆盖历史/异常数据)。 - 以上三种
null场景均只有单元测试覆盖(见八节),本次实测扫描未在测试服活数据中观测到对应真实记录。
六.5、枚举 / 数据字典
| 取值 | 中文标签 | 说明 |
|---|---|---|
| TRAVEL | 行程用车 | 行程用车需求 |
| TRANSFER | 接送机 | 接送机需求(#7439 引入) |
| null | (不显示标签) | 判不出类别,前端不得兜底为 TRAVEL |
六.6、修改前后对比
- 字段层面:
MatrixUnassignedOrderVO新增requirementKind(String)、requirementKindLabel(String),VO 字段总数由 37 增至 39。 - 行为层面:改动前,同一订单的两张未派卡在字段层面完全无法区分类别,只能靠车型/日期/备注人工判断,判断错了会把车派到错误的需求线上;改动后两张卡各自携带准确的类别标识,且判不出时明确返回 null 而非静默给出错误猜测。
六.7、影响评估
- 破坏性:无。两个新增字段为可选新增,未删除/未重命名/未改变任何既有字段的类型或取值口径。
- 涉及消费端:仅管理后台派单矩阵页。
- 前端无需为此做兼容降级处理:未取到新字段(
undefined)与取到null应做同等处理——均不显示类别标签。
七、不影响范围
- 矩阵主数据端点
GET /admin/fleet/matrix/grid、年度月度统计GET /admin/fleet/matrix/month-counts、当天订单清单GET /admin/fleet/matrix/day-orders:均未改动。 - 看板列表端点(
BoardOrderRecordVO.requirementKind,#8518):未改动,其判不出类别时仍兜底 TRAVEL 的既有行为不变。 - 写操作(拖拽派车、改派、取消等):本次改动只涉及查询响应字段新增,不涉及任何写路径。
MatrixUnassignedReqVO请求参数:未新增/未修改(year/month/typeKeys 均为既有字段,越界错误码路由此前已分别由 #8561/#8571 调整完成)。
八、测试环境已验证
- 部署确认:
hl-fleet-service现部署 SHA99fb369ba(deploy-status.sh实测,状态ok),经git merge-base --is-ancestor 8b045a321b 99fb369ba8确认已包含本次改动的合并提交8b045a321b(PR #8589)。 - 实测(真实请求,非构造数据):使用车务角色测试账号(切至 VEHICLE_MANAGER 角色)对
GET /admin/fleet/matrix/unassigned-orders发起真实请求:- 2026-09 月:2 条记录,
requirementKind均为TRAVEL,含示例订单HL20260911193207642(见响应示例节)。 - 2026-11 月:1 条记录,
requirementKind为TRANSFER,订单HL20260929154809598(见响应示例节)。 - 对 2026-06 ~ 2027-03 共 10 个月窗口的扫描(合计 14 条记录)未发现
requirementKind=null的记录,也未发现同一订单出现两条不同类别记录的活跃实例——测试服当前业务数据里暂未出现这两种边界场景,实测未覆盖,靠下面的单元测试兜底。
- 2026-09 月:2 条记录,
- 单元测试覆盖(源码单测验证,未在测试服活数据上复现):
BoardRequirementIdentitiesKindTest(5/5 通过):覆盖双身份按需求 ID 各取各类别、上下文降级返 null(对照既有方法仍兜底 TRAVEL)、陈旧需求 ID 不猜返 null、身份自身类别空白返 null、灰度上下文合成 TRAVEL 身份仍可取到。MatrixServiceTest新增 6 个#8560测试方法(均通过):同订单两类需求两张卡类别互不相同(含反向对照:两张卡requirementId字段完全相同)、需求身份类别空白返 null 不兜底 TRAVEL、上下文降级返 null 不兜底 TRAVEL、派车行挂陈旧需求 ID(#5720)返 null 不兜底 TRAVEL、虚拟待派条目携带类别、虚拟待派条目无身份列表时类别为 null。- 聚合结果(
mvn -pl hl-fleet-service -am test):Tests run: 365, Failures: 0, Errors: 0, Skipped: 0,BUILD SUCCESS;含VehicleRequirementKindsTest4、BoardOrderServiceTest233、FleetRedLineArchTest18(架构守护门禁绿)。 - 嵌套用例选择器守卫(
nested_selector_census):通过,内层名比对无缺组。 spotless:check:BUILD SUCCESS,916 文件全部合规。
十、相关文档
- Issue #8560
- PR #8589(合并提交
8b045a321b) - 相关既有机制:#7439(TRAVEL/TRANSFER 双需求引入)、#8518(看板列表既有类别字段)、#7067(虚拟待派条目/去槽位化)、#5667(
requirementId订单侧单值口径)、#5720(换版过渡窗孤儿行)
关联 / 联系人
- 后端:wx(GIT)
- 消费端:管理后台(派单矩阵页)