docs(changelog): 车务派车候选接口显式返回 selectable(#5850 / PR #5861)
所有检测均成功
changelog-filename-gate / validate (push) Successful in 2s
所有检测均成功
changelog-filename-gate / validate (push) Successful in 2s
这个提交包含在:
父节点
231f2e0411
当前提交
05f0f548d2
@ -0,0 +1,111 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "5850"
|
||||
title: "派车候选接口显式返回 selectable:统一选车弹窗空白复发的后端根治(四条组装路径全覆盖)"
|
||||
consumer: "admin"
|
||||
change_type: "修改接口"
|
||||
author: "wx(GIT)"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "not_required"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "PR #5861 已合并 dev-v3 并部署测试服,网关 9443 实测:候选车辆 20 行 / 司机 20 行 selectable 全部非 null(19/20 车 true,1 行因阻断性冲突为 false)。前端 not_required——mmg 已于 313609db 把 normalizeCandidateVehicle 的缺省口径改成「undefined 视为可选、显式 false 才禁用」,与本次后端显式下发兼容;本条属于把前端的兜底假设升级成后端契约保证,前端零改动即受益。"
|
||||
updated_at: "2026-08-11"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 车务:派车候选接口显式返回 `selectable`(#5850)
|
||||
|
||||
> **服务**: hl-fleet-service
|
||||
> **端点**: `POST /admin/fleet/assignments/candidates`
|
||||
> **性质**: 新增响应字段(向后兼容,无破坏性变更)
|
||||
|
||||
---
|
||||
|
||||
## 一、为什么改
|
||||
|
||||
「统一选择车辆/司机」弹窗**反复出现整片空白**(后端返回 200、数据齐全,列表却渲染不出来)。
|
||||
|
||||
根因在前后端口径断层:
|
||||
|
||||
- 前端统一选车入口(`scope=slot` → `availableOnly=true`)用 `isFullyAvailableCandidate()` 过滤候选,该函数**要求 `selectable === true`**;
|
||||
- 但后端从来**没有下发过 `selectable` 字段**(全仓零命中),前端 `normalize` 出来是 `undefined`;
|
||||
- `undefined === true` 为 false → **整列被过滤成空**。单日入口 `availableOnly=false` 不走该过滤,所以只在统一选车弹窗复发。
|
||||
|
||||
前端已在 `313609db` 做了兜底(缺省视为可选)。但「弹窗空白」这个故障此前已复发多次,只靠前端约定"没有字段就当可选"是脆的——本次由后端把这个字段变成**显式契约**,从源头消除断层。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口
|
||||
|
||||
| 方法 | 路径 | 变更 |
|
||||
|------|------|------|
|
||||
| `POST` | `/admin/fleet/assignments/candidates` | 响应新增 `selectable` 字段(车辆候选项 + 司机候选项,共 4 条组装路径) |
|
||||
|
||||
## 三、契约变更
|
||||
|
||||
`AssignmentCandidateRespVO` 的车辆候选项与司机候选项各**新增一个字段**:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `selectable` | `Boolean` | 本次选车场景下该候选是否可被选中。**恒非 null** |
|
||||
|
||||
### 与已有 `available` 的区别(务必分清)
|
||||
|
||||
| 字段 | 口径 |
|
||||
|------|------|
|
||||
| `available` | **纯资源维度**:该车/该司机在所选服务日期窗内是否空闲 |
|
||||
| `selectable` | 在 `available` 为真的基础上,**再排除阻断性冲突** |
|
||||
|
||||
后端判定式:
|
||||
|
||||
```
|
||||
selectable = available && conflicts 中不存在阻断项
|
||||
```
|
||||
|
||||
其中「阻断项」= `conflicts[].blocking` **不是显式 `false`** 的项一律按阻断处理(null/缺省从严)。
|
||||
|
||||
> ⚠️ 「已被本弹窗其他槽位选中」属于**前端选车上下文**,后端不感知,**不纳入** `selectable` 口径。前端如需这层排除,仍按自己的选中态叠加过滤。
|
||||
|
||||
### 覆盖范围
|
||||
|
||||
四条候选组装路径**全部**下发该字段,不存在只有部分路径带字段的情况:
|
||||
|
||||
1. `vehicles.records[]` —— 车辆候选分页列表
|
||||
2. `drivers.records[]` —— 司机候选分页列表
|
||||
3. `selectedDriverResidentVehicles[]` —— 选定司机的常驻车辆
|
||||
4. `selectedVehicleResidentDriver` —— 选定车辆的常驻司机
|
||||
|
||||
---
|
||||
|
||||
## 四、前端影响
|
||||
|
||||
**无破坏性变更,前端可零改动。** 但建议按下面的口径收敛:
|
||||
|
||||
- 渲染禁用态时**直接读 `selectable`**,不要再自己用 `available` + `conflicts` 二次推导——推导口径与后端不一致正是这次故障的来源。
|
||||
- 保留「`undefined` 视为可选」的兜底(`313609db` 已做)作为防御,但正常情况下该字段恒有值。
|
||||
- `selectable === false` 的行建议**置灰并展示 `availabilityReason`**,而不是从列表里过滤掉——车管需要知道"这辆车为什么不能选"。
|
||||
|
||||
---
|
||||
|
||||
## 五、验证证据(测试环境实测,2026-08-11,网关 9443,车务管理员 token)
|
||||
|
||||
```
|
||||
POST /admin/fleet/assignments/candidates
|
||||
```
|
||||
|
||||
| 项 | 实测 |
|
||||
|----|------|
|
||||
| `vehicles.records[]` | 20 行,`selectable` **全部非 null**;19 行 `true`,1 行 `false`(存在阻断性冲突) |
|
||||
| `drivers.records[]` | 20 行,`selectable` 全部非 null |
|
||||
| 兼容性 | `available` / `availabilityReasonCode` / `availabilityReason` / `conflicts` 语义与取值**均未变化** |
|
||||
|
||||
---
|
||||
|
||||
## 六、关联
|
||||
|
||||
- 工单 #5850、PR #5861
|
||||
- 前端条目:`11_frontend_派单Step2需求展示区与统一选车弹窗空白-前端缺陷-管理后台.md`(同一故障的前端侧修复 `313609db`)
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户