docs(changelog): #8301 车务看板带日期筛选时单条 requirement_id 为空的派车行不再清空整个日期窗
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
这个提交包含在:
@@ -0,0 +1,293 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8301"
|
||||
title: "车务看板带日期筛选时,单条 requirement_id 为空的派车行不再清空整个日期窗"
|
||||
consumer: "admin"
|
||||
author: "wx(GIT)"
|
||||
change_type: "修改接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "not_required"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: ""
|
||||
updated_at: "2026-09-24"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# fleet: 看板日期筛选分支的脏行失败关闭收窄为跳过单行
|
||||
|
||||
> **存放目录**: `changelogs-v2/2026-09/`
|
||||
>
|
||||
> **服务**: hl-fleet-service
|
||||
> **PR**: #8310
|
||||
> **Issue**: #8301
|
||||
> **日期**: 2026-09-24
|
||||
> **影响范围**: 管理后台「车务看板」订单列表/网格视图(带日期筛选时)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
**带日期筛选时,单条脏数据不再清空整个日期窗。** 此前只要日期窗里存在任意一条 `requirement_id` 为空的派车行,`GET /admin/fleet/board/orders`(带 `startDate/endDate` 或 `startDayFrom/startDayTo`)就整页返回 `records=[]`、`total=0`、`code=200`,**不报错**——页面上看到的是「这几天没有订单」而不是任何异常。现在这条行被**跳过并记 WARN**(WARN 里带 `orderId`/`assignmentId`/`assignmentGroupId`),同一日期窗内其余订单**照常返回**,与不带日期筛选时的既有口径一致。
|
||||
|
||||
**接口契约零变化**:路径、参数、字段、类型、必填性、枚举、错误码全部不变,只修正日期分支的行为。
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
车务看板带日期筛选时走一条独立的「当前主单日期候选」扫描分支。该分支原本把四类候选行异常合并成一个失败关闭条件,其中一类是「派车行的 `requirement_id` 为空」——这是历史数据迁移、手工修数或未来写路径缺陷可能留下的占位行。这类行本身匹配不上任何用车需求,在不带日期的路径里只是被跳过并记一条汇总 WARN;但在日期分支里,它会让**同页全部订单**的候选一起作废,表现为整窗静默返回空。
|
||||
|
||||
本次把该条件按成因拆开:真正影响槽位聚合正确性的三类结构性畸形(行对象缺失、主单 ID 缺失、派车组 ID 与派车 ID 同时缺失)以及重复槽位键**仍然失败关闭**,只是各自补一条带定位信息的 WARN;`requirement_id` 为空的行改为逐行剔除并记 WARN。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 看板订单列表 | GET | `/admin/fleet/board/orders` | 行为变更(契约不变) | 带日期筛选时,`requirement_id` 为空的派车行由「整窗失败关闭」改为「跳过该行 + WARN」 |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 看板订单列表 `GET /admin/fleet/board/orders`
|
||||
|
||||
**VO**: `BoardOrderPageReqVO → BoardOrderPageRespVO`(`records: BoardOrderRecordVO[]`)
|
||||
|
||||
#### 使用场景
|
||||
|
||||
管理后台「车务看板」订单列表/网格视图(`variant=list|grid`)。车务人员按状态、日期、团号、车型等条件筛出待派/已派订单卡片,逐卡执行改派、派车、查看行程等操作。本次改动只影响**带日期筛选**时该列表返回的记录集合。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| startDate | Query | LocalDate | ❌ | `yyyy-MM-dd` | 行程日期窗起(`startDayFrom` 的兼容别名) |
|
||||
| endDate | Query | LocalDate | ❌ | `yyyy-MM-dd` | 行程日期窗止(`startDayTo` 的兼容别名) |
|
||||
| startDayFrom | Query | LocalDate | ❌ | `yyyy-MM-dd` | 行程日期窗起;为空时回落到 `startDate` |
|
||||
| startDayTo | Query | LocalDate | ❌ | `yyyy-MM-dd` | 行程日期窗止;为空时回落到 `endDate` |
|
||||
| statuses / status | Query | String[] / String | ❌ | 枚举:unassigned/unassigned_urgent/holding/holding_urgent/assigned/canceled/completed | 状态筛选,可多选;`status` 为单值兼容别名 |
|
||||
| vehicleTypeKeys / typeKeys | Query | String[] | ❌ | 车型大类字典值 | 车型多选筛选 |
|
||||
| keyword / driverName / contactName / teamNo / plannerName | Query | String | ❌ | - | 关键字、司机、联系人、团号、定制师等模糊搜索 |
|
||||
| groupBatchId | Query | Long | ❌ | 等值匹配 | 运营团期 ID |
|
||||
| consultantId | Query | Long | ❌ | - | 定制师 ID 精确筛选 |
|
||||
| variant | Query | String | ❌ | `list`/`grid` | 视图口径 |
|
||||
| page(或 pageNo) | Query | Integer | ❌ | ≥1,缺省 1 | 页码 |
|
||||
| pageSize | Query | Integer | ❌ | 1-100 | 每页条数 |
|
||||
|
||||
> 本单不新增、不删除、不改任何参数的类型与必填性;上表只为把「受影响的日期参数」放进完整上下文。
|
||||
|
||||
#### 出参 `Result<BoardOrderPageRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| records | BoardOrderRecordVO[] | 本页看板卡片;本次改动只影响带日期筛选时该数组的内容 |
|
||||
| total | Long | 命中总数;带日期筛选时不再被单条脏行清零 |
|
||||
| page | Integer | 当前页码 |
|
||||
| pageSize | Integer | 每页条数 |
|
||||
| records[].id | Long | 派车行/虚拟条目主键 |
|
||||
| records[].orderId / orderNo / teamNo | Long / String / String | 子订单 ID、订单编号、团号 |
|
||||
| records[].assignmentId / assignmentGroupId / requirementId | Long | 派车行 ID、派车分组 ID、当前用车需求 ID |
|
||||
| records[].assignmentStatus | String | 派单状态码 |
|
||||
| records[].virtualPending | Boolean | 虚拟待派卡标记(真实记录恒为 `false`) |
|
||||
| records[].groupVehicleCovered | Boolean | 团车整段接管标记(详见 #8235 交接件) |
|
||||
| records[].urgentBadge / canAssign / dispatchReadOnly | String / Boolean / Boolean | 加急标签、可派车、只读 |
|
||||
| records[].startDate / endDate | LocalDate | 行程起止日期 |
|
||||
| records[].currentVehiclePlate / currentDriverName | String | 当前车辆车牌 / 司机姓名 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /admin/fleet/board/orders?startDate=2026-11-01&endDate=2026-11-10&variant=list&pageNo=1&pageSize=20
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"id": 7330843067599549,
|
||||
"orderId": 2101014943313670001,
|
||||
"orderNo": "HL20261106000001",
|
||||
"teamNo": null,
|
||||
"assignmentId": 7330843067599549,
|
||||
"assignmentGroupId": 7330843067599549,
|
||||
"requirementId": 2101014943313670100,
|
||||
"assignmentStatus": "holding",
|
||||
"virtualPending": false,
|
||||
"groupVehicleCovered": null,
|
||||
"urgentBadge": null,
|
||||
"canAssign": true,
|
||||
"dispatchReadOnly": false,
|
||||
"startDate": "2026-11-06",
|
||||
"endDate": "2026-11-07",
|
||||
"currentVehiclePlate": null,
|
||||
"currentDriverName": null
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"pageSize": 20
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无匹配记录时返回空数组与 `total=0`,不报错:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": { "records": [], "total": 0, "page": 1, "pageSize": 20 },
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
带日期筛选时的空列表**仍不等同于**「该日期窗确实无单」:日期候选扫描取数失败、结果集缺失、候选行结构畸形(行对象缺失 / 主单 ID 缺失 / 派车组 ID 与派车 ID 同时为空)或槽位键重复时,本页仍按既有 fail-closed 口径整体返回空,但每一种成因现在都会在 `hl-fleet-service` 日志里留下一条可区分的 WARN。不带日期筛选的查询不走这条分支。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 401,
|
||||
"message": "未登录或登录已过期",
|
||||
"success": false,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 只影响**带日期筛选**的分支。不带日期的查询、车辆矩阵接口、看板汇总接口的口径与本次改动前完全一致。
|
||||
- `requirement_id` 为空的派车行会被剔除:该行原本在不带日期的路径里也匹配不上任何用车需求、不可能出现在看板上,因此剔除它不会让**本该展示**的卡片消失。
|
||||
- 若某订单在日期窗内**只有**这一条脏行,该订单在带日期的视图里看不到——这与它不带日期时的既有表现一致;让它可见需要的是数据修复,不是看板放行。
|
||||
- 日期候选结果集本身取到空(无订单上下文)时不查派车行,正常返回空页。
|
||||
- 鉴权:管理后台登录态,未登录 401(网关拦截)。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
### ✅ 正确 / ❌ 错误用法对照
|
||||
|
||||
| 场景 | 说明 |
|
||||
|------|------|
|
||||
| ✅ 直接使用 `total` 与 `records` | 结构与字段均未变,前端无需做任何解析适配 |
|
||||
| ✅ 把带日期筛选返回的空列表理解为「结构性异常或确实无单」 | 本次改动后,单条 `requirement_id` 为空的脏行不再制造这种空结果;剩余会制造空结果的是结构性畸形(行缺失、主单 ID 缺失、槽位键缺失或重复),均会在服务端留 WARN |
|
||||
| ❌ 为「带日期筛选可能返回空」保留前端兜底或本地缓存回填 | 本次改动后不再是必需;保留也不会出错,但会把真实的结构性畸形空结果一并掩盖 |
|
||||
| ❌ 依赖后端 WARN 的具体文案做前端逻辑 | WARN 只面向排障,文案不是契约 |
|
||||
|
||||
### 切换状态时的必要动作
|
||||
|
||||
无。本接口是只读 GET,跳过脏行的判定完全由后端在读取时完成,不接受前端传参覆盖,也不需要前端在请求前做任何字段准备。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 未登录 → 401(网关拦截)
|
||||
- 无匹配记录 → 200 + 空数组、`total=0`,不报错
|
||||
- 日期候选行含 `requirement_id` 为空的行 → 200,该行被跳过并记 WARN,其余订单照常返回(本次改动)
|
||||
- 日期候选行结构畸形(行对象缺失 / 主单 ID 缺失 / 派车组 ID 与派车 ID 同时缺失)或槽位键重复 → 200 + 整页空(既有 fail-closed 口径保留),并新增带定位信息的 WARN
|
||||
- order-v3 日期候选页取数失败、超过单次一致性快照上限或上下文畸形 → 200 + 整页空(既有 fail-closed 口径保留)
|
||||
- 虚拟待派候选层不可用(开关关闭或远端候选不可用)→ 只丢虚拟条目,真实派车行照常返回
|
||||
|
||||
---
|
||||
|
||||
## 六.6、修改前后对比
|
||||
|
||||
### 字段级对比
|
||||
|
||||
| 字段 | 改前 | 改后 | 变化说明 |
|
||||
|------|------|------|----------|
|
||||
| 请求 / 响应字段 | 无变化 | 无变化 | 本次为纯行为修正,不新增、不删除、不改类型 |
|
||||
|
||||
### 行为级对比
|
||||
|
||||
| 行为 | 改前 | 改后 | 影响 |
|
||||
|------|------|------|------|
|
||||
| 日期窗内某订单存在一条 `requirement_id` 为空的派车行 | **整窗**返回 `records=[]`、`total=0`、`code=200`,服务端无日志 | 只**跳过该行**并记 WARN,同窗其余订单正常返回 | 带日期筛选的列表不再被单条脏数据清空 |
|
||||
| 同一数据**不带日期**查询 | 该行被跳过 + 一条汇总 WARN | 不变 | 无 |
|
||||
| 日期候选出现重复槽位键 | 整页失败关闭,无日志 | 整页失败关闭(不变),新增带重复键样本的 WARN | 排障可定位 |
|
||||
| 日期候选行结构畸形(行缺失 / 主单 ID 缺失 / 槽位键全缺) | 整页失败关闭,无日志 | 整页失败关闭(不变),新增带成因与定位字段的 WARN | 排障可定位 |
|
||||
|
||||
---
|
||||
|
||||
## 六.7、影响评估
|
||||
|
||||
- **是否破坏向后兼容**: 否。请求参数、响应结构、字段类型与错误码全部不变,仅带日期筛选时的记录集合与 `total` 不再被单条脏数据清零。
|
||||
- **前端是否必须同步上线**: 否。前端无需修改即可受益。
|
||||
- **前端 workaround 清理点**: 若前端此前针对「带日期筛选偶发返回空」做过兜底或本地回填,可以在确认后移除;保留不影响功能。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- **仅影响**:管理后台「车务看板」订单列表/网格视图(`/admin/fleet/board/orders`)在**带日期筛选**时的记录集合与 `total`。
|
||||
- **零影响**:
|
||||
- 不带日期筛选的看板订单列表口径
|
||||
- 车辆矩阵未派清单、网格与月度统计(`/admin/fleet/matrix/**`,不走日期候选扫描分支)
|
||||
- 看板汇总与统计接口
|
||||
- 派车、改派、确认等写接口
|
||||
- 用车需求与派车行的数据结构、状态机与任何表结构
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
测试服部署(`deploy:test` 单写租约):`hl-fleet-service` 2026-09-24 10:49:54 滚动部署到 `dev-v3 @ cc70c9ba3`(该提交是本次 squash 合并 `48c755fd1` 的后代),实例 8187 / 8087 均 UP 且健康检查通过。
|
||||
|
||||
网关实测(`https://api.test.1814.love`,管理后台登录态切到车务角色):
|
||||
|
||||
| # | 请求 | 修复前 `total` | 修复后 `total` |
|
||||
|---|------|----------------|----------------|
|
||||
| 1 | `GET /admin/fleet/board/orders`(不带日期) | 243 | 243(对照组,未变)✓ |
|
||||
| 2 | `...&startDate=2026-11-01&endDate=2026-11-10`(窗内含脏行) | **0** | **8** ✓ |
|
||||
| 3 | `...&startDayFrom=2026-11-01&startDayTo=2026-11-10`(同窗别名参数) | **0** | **8** ✓ |
|
||||
| 4 | `...&startDate=2026-09-24&endDate=2026-11-04`(窗内不含脏行) | 71 | 71(对照组,未变)✓ |
|
||||
| 5 | `...&startDate=2026-11-06&endDate=2026-11-06`(脏行当天) | **0** | **6** ✓ |
|
||||
| 6 | `...&startDate=2026-11-05&endDate=2026-11-07` | **0** | **6** ✓ |
|
||||
|
||||
服务端逐行 WARN(两个实例各两条,与上表实测同刻,原始行):
|
||||
|
||||
```text
|
||||
2026-09-24 10:50:56.063 [http-nio-8087-exec-1] WARN c.h.f.b.service.BoardCandidateSource - 车务看板列表日期候选剔除无用车需求ID的派单行(本行不参与候选): orderId=2101014943313670146 assignmentId=7330843067599548 assignmentGroupId=7330843067599548
|
||||
2026-09-24 10:50:56.556 [http-nio-8187-exec-2] WARN c.h.f.b.service.BoardCandidateSource - 车务看板列表日期候选剔除无用车需求ID的派单行(本行不参与候选): orderId=2101014943313670146 assignmentId=7330843067599548 assignmentGroupId=7330843067599548
|
||||
```
|
||||
|
||||
那条脏行(`assignment_id=7330843067599548`,`order_id=2101014943313670146`,行程日期 2026-11-06)本身不再出现在任何日期窗结果里——它匹配不上任何用车需求,本就无法在看板渲染;关键变化是它不再让同窗其余订单一起消失。
|
||||
|
||||
本地验证:定向 42/42 绿、看板与矩阵影响面回归 379/379 绿、`spotless:check` 与 `mvn -o -pl hl-fleet-service -am verify` 均 BUILD SUCCESS(该模块 4766 个用例 0 失败 0 错误 6 跳过)。
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- 关联 Issue: [wx/HL#8301](https://git.1814.love/wx/HL/issues/8301)
|
||||
- 关联 PR: [wx/HL#8310](https://git.1814.love/wx/HL/pulls/8310)
|
||||
- 同一接口的上一份交接件(#8235,看板订单记录新增 `groupVehicleCovered`),其中「带日期筛选的既有 fail-closed 口径」一条由本文件取代
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#8301](https://git.1814.love/wx/HL/issues/8301)
|
||||
- **PR**: [#8310](https://git.1814.love/wx/HL/pulls/8310)
|
||||
- **Merge commit**: [48c755fd1](https://git.1814.love/wx/HL/commit/48c755fd1feff715f9ec946b55f77207f23dc942)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @wx
|
||||
- **前端负责人**: @mmg
|
||||
在新工单中引用
屏蔽一个用户