docs(changelog-v2): 团期配车重排资源态硬校验与四读口 600015 收敛前端交接(#8528 #8529 #8536 #8537)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
- 29_8528:POST reconfigure 新增 605037/605038 资源态错误码(全批次一票否决), 响应新增 ignoredDemandDays(clearAll=true 时回填被忽略的行程日)。 - 29_8536:overview/readiness/share-groups/share-member-candidates 四个读口 对「团期不存在」统一收敛为 600015;其中 share-groups 是破坏性变更 (此前 200+[],与「有效团期零关系」同形,前端需新增分支); readiness 零配车行 blocker 文案改为「本团尚未创建任何配车行」。 均已合并 dev-v3 并在测试网关实测;校验器 --files 两个对象 PASS。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -0,0 +1,245 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8528"
|
||||
title: "团期配车重排新增资源态硬校验,响应回填被 clearAll 忽略的行程日"
|
||||
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 #8553 合并 dev-v3(7b702f5c3f);hl-fleet-service dev-v3 分支部署测试网关 @ e2982739e8(含 7b702f5c3f)并实测:排入 rest 司机返 605038、排入 DISABLED 车辆返 605037(均一行未落库);正常 ACTIVE 车辆 7 天全排返 addedCount=7;clearAll=true 场景返 ignoredDemandDays 回填生效。"
|
||||
updated_at: "2026-09-29"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期配车重排:新增资源态硬校验,响应回填被 clearAll 忽略的行程日
|
||||
|
||||
> **存放目录**: `changelogs-v2/2026-09/`
|
||||
> **服务**: hl-fleet-service (端口 8087)
|
||||
> **PR**: #8553
|
||||
> **Issue**: #8528 #8529
|
||||
> **日期**: 2026-09-29
|
||||
> **影响范围**: 管理后台团期配车页「整团逐日配车提交」
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
- 团期配车重排提交时,本次新增或就地改动的配车行,其车辆与司机的当前状态(是否维保/停用/休假/待激活/黑名单/非在册赛季)现在会被硬校验,不可派即整批提交回滚(工单 #8528)。
|
||||
- 响应新增字段 `ignoredDemandDays`:`clearAll=true` 时把未被写入的行程日回填给前端(工单 #8529)。此前 `clearAll=true` 提交后无法区分「清完并按新计划重排」与「只清空」,两者响应里 `addedCount` 都是 0。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 整团逐日配车提交 | POST | `/admin/fleet/group-dispatch/batches/{groupBatchId}/reconfigure` | 新增错误码 + 新增响应字段 | 605037/605038 新增;605006/605013 文案带占位符;响应新增 `ignoredDemandDays` |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 整团逐日配车提交 `POST /admin/fleet/group-dispatch/batches/{groupBatchId}/reconfigure`
|
||||
|
||||
**VO**: `GroupDispatchReconfigureReqVO` → `GroupDispatchReconfigureRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
车务在团期配车页提交/重排整团逐日配车计划:服务端按乘车分组与现状差量比对,多删少补,旧记录软删留痕。本次改动新增两类内容:①提交时对新增/就地改的配车行做车辆与司机的当前可派性硬校验;②`clearAll=true` 时把未写入的行程日回填进响应。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | - | 团期主订单 ID |
|
||||
| requirementId | Body | Long | ✅ | - | 正式团级用车需求 ID;与基线不一致抛 602005 |
|
||||
| requirementVersion | Body | Integer | ✅ | - | 需求版本;落后于基线当前版本抛 602005 |
|
||||
| clearAll | Body | Boolean | 否 | 默认 false | true=整团清零,`demands` 仅当待清日用,不写入任何配车行 |
|
||||
| survivorPolicy | Body | String | 条件必填 | `KEEP_LEGAL`/`REASSIGN`/`RELEASE` | 仅 `clearAll=true` 且该团存在 active 共用关系时必填,缺失抛 602110 |
|
||||
| demands | Body | List<GroupDispatchDayDemandReqVO> | 条件必填 | - | `clearAll=false` 时必填且非空;每项含 `tripDate` + `assignments`(车辆/司机/分组),本次不变 |
|
||||
| reconfigureWindowToken | Body | String | 条件必填 | - | 团期过资源准备阶段后必填,本次不变 |
|
||||
|
||||
#### 出参 `Result<GroupDispatchReconfigureRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| ignoredDemandDays | List<LocalDate> | **新增(#8529)**:因 `clearAll=true` 未被写入的行程日清单,格式 `yyyy-MM-dd`;`clearAll=false` 时恒为空列表,不会是 null |
|
||||
| addedCount / removedCount / keptCount / updatedCount / aliveCount | Integer | 结构不变 |
|
||||
| coverage | GroupDispatchCoverageRespVO | 结构不变,含 `wholeBatchSatisfied`(全团行程日整体覆盖是否成立)等字段 |
|
||||
| 其余字段 | - | 结构不变,与既有契约一致(本次不变) |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
正常提交(7 天全排 ACTIVE 车辆场景,节选一天):
|
||||
|
||||
```json
|
||||
{
|
||||
"requirementId": "5501",
|
||||
"requirementVersion": 3,
|
||||
"clearAll": false,
|
||||
"demands": [
|
||||
{ "tripDate": "2026-09-12", "assignments": [ { "groupId": "BUS", "vehicleId": "1001", "driverId": "2001" } ] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
clearAll 场景:
|
||||
|
||||
```json
|
||||
{
|
||||
"requirementId": "5501",
|
||||
"requirementVersion": 3,
|
||||
"clearAll": true,
|
||||
"survivorPolicy": "RELEASE",
|
||||
"demands": [
|
||||
{ "tripDate": "2026-11-10", "assignments": [] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
7 天全排成功:
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": { "addedCount": 7, "coverage": { "wholeBatchSatisfied": true } }, "success": true }
|
||||
```
|
||||
|
||||
clearAll 场景(行程日被回填进 `ignoredDemandDays`):
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": { "addedCount": 0, "ignoredDemandDays": ["2026-11-10"] }, "success": true }
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空数据形态;命中资源态硬校验或既有校验失败时 `data=null`,见错误响应。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 605038, "message": "司机处于休假或待激活状态,不能派车:苏和巴特尔", "data": null, "success": false }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 605037, "message": "车辆处于维保或停用状态,不能派车:蒙C02E02", "data": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 605037/605038/605006/605013 四个码新增的占位符文案同样出现在逐户派单写路径(`POST /admin/fleet/assignments` 及改派端点),二者共用同一个资源态校验组件;前端若对这 4 个码有硬编码文案匹配,两条路径都要一起改。
|
||||
- 资源态校验是整批拒绝:任意一天新增/就地改的车辆或司机不可派,会回滚本次整团提交,不是部分成功。
|
||||
- 本次未改动的存量配车行不重判——车辆/司机事后状态变化不会把整团重配卡死,只挡本次新增/就地改的行。
|
||||
- 车辆/司机已被删除时,占位符退回请求里携带的主键(`ID=车辆ID` / `ID=司机ID`),不是报 500。
|
||||
- `ignoredDemandDays` 在 `clearAll=false` 时恒为空列表(不是 null),前端可无条件取其长度判断有无回填项。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式(接口类必写)
|
||||
|
||||
> 本节只写**后端接受/拒绝 payload 的规则**,不写 UI 渲染建议。
|
||||
|
||||
### ✅ 正确 / ❌ 错误 payload 对照
|
||||
|
||||
| 场景 | payload |
|
||||
|------|---------|
|
||||
| ✅ 排入正常 ACTIVE 车辆/司机 | 正常提交,返回 `code=200` |
|
||||
| ❌ 排入 DISABLED/维保车辆 | 任意排车项使用该车辆 → `605037` |
|
||||
| ❌ 排入休假/待激活司机 | 任意排车项使用该司机 → `605038` |
|
||||
|
||||
### 切换状态时的必要动作
|
||||
|
||||
收到 605037/605038/605006/605013 直接把 `message` 展示给车务,引导其在该排车项上更换车辆或司机后重新提交;本端点无独立幂等键字段,防重仅靠既有 10 秒窗口,修正后正常重提即可。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为(涉及写操作时必写)
|
||||
|
||||
本次未新增表、未新增列。资源态硬校验发生在写入前(校验车辆/司机当前状态),校验不通过时整批回滚、不产生任何 `fleet_group_dispatch` 写入;`ignoredDemandDays` 是内存计算结果、不落库。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 未登录 → 401(网关拦截)
|
||||
- 车辆/司机已被删除 → 错误码占位符退回请求里携带的主键(`ID=车辆ID`/`ID=司机ID`),不是 500
|
||||
- 本次未改动的存量配车行不参与资源态重判
|
||||
- `clearAll=false` 时 `ignoredDemandDays` 恒为空列表,不是 null
|
||||
|
||||
---
|
||||
|
||||
## 六.5、枚举 / 数据字典(接口出现枚举时必写)
|
||||
|
||||
本次未新增或变更任何枚举取值;`survivorPolicy`(`KEEP_LEGAL`/`REASSIGN`/`RELEASE`)沿用既有契约,未变化。
|
||||
|
||||
## 六.6、修改前后对比(修改/删除类接口必写,新增跳过)
|
||||
|
||||
### 字段级对比
|
||||
|
||||
| 字段 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| `data.ignoredDemandDays` | 不存在 | 新增,`clearAll=true` 时回填未被写入的行程日 |
|
||||
| 605006 `message` | `司机已黑名单,不能派车` | `司机已黑名单,不能派车:{司机姓名}`(缺姓名退回 `ID=司机ID`) |
|
||||
| 605013 `message` | `司机非在册赛季不可派单` | `司机非在册赛季不可派单:{司机姓名}`(缺姓名退回 `ID=司机ID`) |
|
||||
|
||||
### 行为级对比
|
||||
|
||||
| 行为 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| 排入维保/停用车辆 | 无该项硬校验,可能带着不可派车辆落库 | 605037 拒绝,整批回滚 |
|
||||
| 排入休假/待激活司机 | 无该项硬校验,可能带着不可派司机落库 | 605038 拒绝,整批回滚 |
|
||||
| `clearAll=true` 提交 | 响应无法区分「清完重排」与「只清空」 | `ignoredDemandDays` 回填未写入日期 |
|
||||
|
||||
## 六.7、影响评估(修改/删除类必写)
|
||||
|
||||
- **是否破坏向后兼容**: 否——605037/605038 是新增错误码,605006/605013 只在文案末尾追加占位符文本(前端如做精确字符串匹配需要更新);`ignoredDemandDays` 是新增字段,旧前端忽略它不受影响。
|
||||
- **前端是否必须同步上线**: 否——新增字段/错误码是可选适配,未处理时行为退化为"看不到具体车牌/司机名,只看到通用错误码提示",不影响提交本身的成败判定。
|
||||
- **前端 workaround 清理点**: 若此前靠 `addedCount===0` 猜测「clearAll 是否清空后又重排」,可以换成直接读 `ignoredDemandDays`。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
|
||||
|
||||
- **仅影响**: 管理后台团期配车页「整团逐日配车提交」(`POST reconfigure`)
|
||||
- **零影响**:
|
||||
- 确认整团配车端点(`POST confirm`)本次未改动响应结构(其资源态硬校验为工单 #8528 同批改动,但不在本 changelog 覆盖范围内)
|
||||
- 团期配车四个读口(总览/就绪/共用关系/共用候选,见另一份 changelog)
|
||||
- 既有错误码(600003-600011、602005-602012 等)语义与格式不变
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
服务:`hl-fleet-service`,dev-v3 分支部署测试网关 @ `e2982739e8`(含 #8528/#8529 所在提交 `7b702f5c3f`),测试网关 `https://api.test.1814.love`:
|
||||
|
||||
```
|
||||
✓ 排入 driverStatus=rest 的司机 → code=605038, message="司机处于休假或待激活状态,不能派车:苏和巴特尔",一行未落库
|
||||
✓ 排入 DISABLED 车辆(车牌 蒙C02E02)→ code=605037, message="车辆处于维保或停用状态,不能派车:蒙C02E02",一行未落库
|
||||
✓ 正常 ACTIVE 车辆 7 天全排 → code=200, addedCount=7, coverage.wholeBatchSatisfied=true(回归未破坏)
|
||||
✓ clearAll=true 场景 → code=200, data.addedCount=0, data.ignoredDemandDays=["2026-11-10"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- 关联 Issue: [wx/HL#8528](https://git.1814.love/wx/HL/issues/8528)、[wx/HL#8529](https://git.1814.love/wx/HL/issues/8529)
|
||||
- 关联 PR: [wx/HL#8553](https://git.1814.love/wx/HL/pulls/8553)
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#8528](https://git.1814.love/wx/HL/issues/8528)、[#8529](https://git.1814.love/wx/HL/issues/8529)
|
||||
- **PR**: [#8553](https://git.1814.love/wx/HL/pulls/8553)
|
||||
- **Merge commit**: [7b702f5c3f](https://git.1814.love/wx/HL/commit/7b702f5c3f)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @wx
|
||||
@@ -0,0 +1,418 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8536"
|
||||
title: "团期配车四个读口团期不存在统一收敛为 600015;就绪判定零配车行文案调整"
|
||||
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 #8554 合并 dev-v3(e2982739e8);hl-fleet-service dev-v3 分支部署测试网关 @ e2982739e8 并实测:四个读口对不存在团期均返回 600015;有效团期零共用关系仍返回 200+data=[];就绪判定零配车行场景文案已改为「本团尚未创建任何配车行」。"
|
||||
updated_at: "2026-09-29"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期配车四个读口:团期不存在统一收敛为 600015;就绪判定零配车行文案调整
|
||||
|
||||
> **存放目录**: `changelogs-v2/2026-09/`
|
||||
> **服务**: hl-fleet-service (端口 8087)
|
||||
> **PR**: #8554
|
||||
> **Issue**: #8536 #8537
|
||||
> **日期**: 2026-09-29
|
||||
> **影响范围**: 管理后台团期配车页四个只读端点(总览/就绪判定/共用关系查询/共用成员候选)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键变化
|
||||
|
||||
- 🔴 **破坏性变更(共用关系查询)**:此前对**不存在的团期**调用 `GET share-groups` 会返回 `HTTP 200 + code=200 + data=[]`,与"团期确有效存在但零共用关系"完全同形,前端无法区分。**现在改为返回 `code=600015`**(团期不存在)。有效团期确实零关系时仍然是 `code=200 + data=[]`,未变化。
|
||||
- 四个读口(总览/就绪判定/共用关系查询/共用成员候选)对"团期不存在"场景**统一改用 600015** 作为失败关闭码,与各自原先分散的、语义偏"可重试"的码区分开:600015 是永久性否定,前端不应引导重试。
|
||||
- 就绪判定端点在"该团尚无任何配车行"这一具体场景下,`blockers[].message` 文案从 `本团有 0 条配车行尚未确认` 改为 `本团尚未创建任何配车行`;`code` 仍是 `BLOCK_NOT_CONFIRMED`,未拆分新码。
|
||||
|
||||
---
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 团期配车总览 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/overview` | 错误码语义收敛 | 团期不存在统一改返 600015 |
|
||||
| 2 | 团期配车就绪判定 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/readiness` | 错误码语义收敛 + 文案调整 | 团期不存在统一改返 600015;零配车行 blocker 文案调整 |
|
||||
| 3 | 查询团期车辆共用关系 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/share-groups` | 🔴 破坏性变更 | 团期不存在从 `200+data=[]` 改为 `600015` |
|
||||
| 4 | 查询共用成员候选清单 | GET | `/admin/fleet/group-dispatch/batches/{groupBatchId}/share-member-candidates` | 错误码语义收敛 | 团期不存在统一改返 600015 |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 团期配车总览 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/overview`
|
||||
|
||||
**VO**: `(无请求体,仅路径参数)` → `GroupDispatchOverviewRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
车务打开团期配车页时调用,取按权威服务日逐日铺开的已排车、空洞日与逐户接送机缺口。本次改动只影响"团期不存在"时的响应,成功路径字段结构未变。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | - | 团期主订单 ID |
|
||||
|
||||
#### 出参 `Result<GroupDispatchOverviewRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId | Long→String | 团期主订单 ID |
|
||||
| batchNo | String | 团号 |
|
||||
| departDate / endDate | LocalDate | 出团日 / 返团日 |
|
||||
| serviceDates | List<LocalDate> | 权威服务日集合 |
|
||||
| requirementConfirmed | Boolean | 整团需求是否已确认 |
|
||||
| vehicleReady | Boolean | 配车是否已就绪 |
|
||||
| days | List | 逐日行,按 serviceDates 铺满 |
|
||||
| missingDates | List<LocalDate> | 空洞日 |
|
||||
| orders | List | 逐户行 |
|
||||
| transferPendingTotal | Integer | 全团接送机未配计数 |
|
||||
| conversationKey | String | 团期车务会话键 |
|
||||
|
||||
以上字段结构本次均未改动。
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /admin/fleet/group-dispatch/batches/1934567890123456789/overview
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": { "groupBatchId": "1934567890123456789", "batchNo": "T26-8867", "departDate": "2026-09-12", "endDate": "2026-09-16", "requirementConfirmed": true, "vehicleReady": false, "transferPendingTotal": 3, "conversationKey": "GROUP_FLEET:1934567890123456789" }, "success": true }
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空对象/空 200 形态:团期不存在时不再返回任何形式的空数据,而是抛 600015,见错误响应;上游确实不可达(非团期不存在)时仍返回原有的可重试码 600012。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 600015, "message": "团期不存在: 9107777777777777777", "data": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 团期不存在时统一改抛 600015(永久性否定),前端不应引导用户重试;此前该场景返回的是可重试语义的 600012,含义已变化。
|
||||
- 上游确实不可达(超时/熔断/降级,而非团期不存在)时仍返回原有的 600012,含义不变。
|
||||
- 600015 的判定统一由服务端集中完成,不因具体是哪个下游 Feign 端点而有条件遗漏。
|
||||
|
||||
### 2. 团期配车就绪判定 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/readiness`
|
||||
|
||||
**VO**: `(无请求体,仅路径参数)` → `GroupDispatchReadinessRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
车务打开团期配车页时调用,判定"硬拦三项"是否全过(`ready`)与"只提醒两项"是否有黄牌(`warned`)。本次改动:①团期不存在统一改返 600015;②该团尚无任何配车行时的 blocker 文案调整。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | - | 团期主订单 ID |
|
||||
|
||||
#### 出参 `Result<GroupDispatchReadinessRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| groupBatchId / requirementId | Long→String | 团期主订单 ID / 判定所依据的正式需求 ID |
|
||||
| requirementVersion | Integer | 判定所依据的需求版本 |
|
||||
| planVersion | Long | fleet 侧当前计划版本 |
|
||||
| ready | Boolean | `= blockers.isEmpty()`,硬拦三项是否全过 |
|
||||
| warned | Boolean | `= !warnings.isEmpty()`,是否有只提醒项,与 ready 互相独立 |
|
||||
| blockers / warnings | List | 硬拦未过项 / 只提醒项,每项含 `code` + `message` |
|
||||
| groups | List | 逐组覆盖明细,与配车写口 `coverage` 同源 |
|
||||
| shareGroupCount | Integer | 本团 active 共用关系数 |
|
||||
|
||||
以上字段结构本次均未改动,仅 `blockers[].message` 在特定场景下文案调整(见下)。
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /admin/fleet/group-dispatch/batches/2104838272570245121/readiness
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
该团级需求已确认、但尚无任何物理配车行(真实实测取值):
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": { "groupBatchId": "2104838272570245121", "ready": false, "blockers": [ { "code": "BLOCK_NOT_CONFIRMED", "message": "本团尚未创建任何配车行" } ] }, "success": true }
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无空对象/空 200 形态:团期不存在时不再返回默认就绪对象,而是抛 600015,见错误响应;`blockers`/`warnings` 均可以是空数组(表示该维度全部通过/无提醒),空数组不是错误也不是降级。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 600015, "message": "团期不存在: 9107777777777777777", "data": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- `BLOCK_NOT_CONFIRMED` 这一个 `code` 现在对应两种不同的 `message` 文案(该团尚无任何配车行 / 该团有 N 条配车行尚未确认);两种场景下前端的处置动作相同(引导去配车页排车/确认),如果此前是按 `message` 文本内容做分支判断,请改成按 `code` 判断,不要再解析 `message` 里的具体文案或数字。
|
||||
- 团期不存在时统一改抛 600015(永久性否定),不应引导重试;`602113`(基线不可用或该团未声明任何乘车分组)含义不变,仍是可重试语义。
|
||||
- `ready` 与 `warned` 互相独立,`ready=true && warned=true` 是合法组合,本次改动未影响这一既有语义。
|
||||
|
||||
### 3. 查询团期车辆共用关系 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/share-groups`
|
||||
|
||||
**VO**: `ShareGroupQueryReqVO` → `List<ShareGroupRespVO>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
车务在团期配车页查看本团当前(及可选的历史)车辆共用关系。🔴 本次改动是**破坏性变更**:团期不存在时的响应形状发生变化。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | - | 团期主订单 ID |
|
||||
| serviceDate | Query | LocalDate | 否 | `yyyy-MM-dd` | 不传=全部服务日 |
|
||||
| resourceType | Query | String | 否 | `VEHICLE`/`DRIVER` | 不传=两者;非法枚举按入参非法拒绝 |
|
||||
| includeReleased | Query | Boolean | 否 | 默认 `false` | 是否一并返回已解除的关系与变更历史 |
|
||||
|
||||
#### 出参 `Result<List<ShareGroupRespVO>>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| shareGroupId / groupBatchId | Long→String | 共用关系 ID / 运营团期 ID |
|
||||
| serviceDate | LocalDate | 共用发生的服务日 |
|
||||
| resourceType | String | `VEHICLE` / `DRIVER` |
|
||||
| resourceId | Long→String | 车辆或司机 ID |
|
||||
| status | String | `ACTIVE` / `RELEASED` |
|
||||
| costBearer | String | `GROUP` / `ORDER` |
|
||||
| costBearerOrderId | Long→String | `costBearer=ORDER` 时的承担订单 ID |
|
||||
| costBearerTeamNo | String | 承担订单的团号 |
|
||||
| costSourceRefNo | String | 车费来源引用,格式 `SHARE-{shareGroupId}` |
|
||||
| members | List | 成员全集 |
|
||||
| confirmedBy / confirmedAt | Long→String / LocalDateTime | 确认人 / 确认时间 |
|
||||
| version | Integer | 乐观锁版本号 |
|
||||
| history | List | 变更历史;仅 `includeReleased=true` 时返回 |
|
||||
|
||||
以上字段结构本次未改动,仅"团期不存在"场景的响应形状变化,见下方请求/响应示例。
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /admin/fleet/group-dispatch/batches/2104840641651556353/share-groups
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
真实实测:团期 `2104840641651556353` 存在且零共用关系:
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": [], "success": true }
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
团期确有效存在但零共用关系时,返回 `HTTP 200 + code=200 + data=[]`(上方响应示例即为此场景的真实实测结果)——这与"团期不存在"的 `600015` 是两个不同的信号,前端必须能区分两者,不能再把"拿到 600015 错误"当成"data 是空数组"来处理。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 600015, "message": "团期不存在: 9107777777777777777", "data": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 🔴 **此前**对不存在的团期调用本接口返回 `code=200 + data=[]`,与"团期确有效存在但零共用关系"完全同形,无法区分;**现在**不存在的团期改为返回 `code=600015`。
|
||||
- 有效团期确实零共用关系时的响应**未变化**,仍是 `code=200 + data=[]`(见响应示例,真实实测)。
|
||||
- 如果此前把 `data.length===0` 当作"该团无共用关系"的唯一判据,现在必须新增对 `600015` 的分支处理,否则遇到不存在的团期会因为拿到错误响应、取不到 `data` 数组而报错或白屏,而不是正确显示"查无此团"。
|
||||
- `includeReleased=true` 时才返回非空的 `history` 字段,默认 `false` 时行为不变。
|
||||
|
||||
### 4. 查询共用成员候选清单 `GET /admin/fleet/group-dispatch/batches/{groupBatchId}/share-member-candidates`
|
||||
|
||||
**VO**: `ShareMemberCandidateQueryReqVO` → `List<ShareMemberCandidateRespVO>`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
车务在团期配车页勾选共用关系成员时调用,返回的 `sourceType` + `sourceId` 直接喂给确认写口 `POST share-groups` 的 `members[]`。本次改动只影响"团期不存在"时的响应,候选行结构未变。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|------|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | ✅ | - | 团期主订单 ID |
|
||||
| serviceDate | Query | LocalDate | ✅ | `yyyy-MM-dd` | 必须落在该团基线 serviceDates 内,窗外抛 602104 |
|
||||
| resourceType | Query | String | ✅ | `VEHICLE`/`DRIVER` | 非法字面量抛 `INVALID_PARAM` |
|
||||
| resourceId | Query | Long | 否 | - | 不传=浏览态,此时 `occupying`/`selectable` 恒为 `null`(未判定) |
|
||||
|
||||
#### 出参 `Result<List<ShareMemberCandidateRespVO>>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| sourceType | String | `ASSIGNMENT`(逐户接送派单)/ `GROUP_DISPATCH`(团级配车行) |
|
||||
| sourceId | Long→String | 成员来源 ID,确认写口 `members[].sourceId` 直接用它 |
|
||||
| requirementId / orderId | Long→String | 用车需求 ID / 订单 ID(团级配车行为空) |
|
||||
| orderNo / teamNo / customerName | String | 订单号 / 团号(GROUP_DISPATCH 行与无团号为 null)/ 客户名 |
|
||||
| headcount | Integer | 人数 |
|
||||
| pickupAt / dropoffAt | String | 接客地 / 送客地 |
|
||||
| pickupParticipant / dropoffParticipant | Integer | 当日是否参与接机/送机,1=是 |
|
||||
| groupCode | String | 车务分组编码(非团号) |
|
||||
| vehicleModel | String | 车型,仅 ASSIGNMENT 行有值 |
|
||||
| occupiedVehicleId / occupiedVehiclePlate | Long→String / String | 当前占用车辆 ID / 车牌 |
|
||||
| occupiedDriverId / occupiedDriverName | Long→String / String | 当前占用司机 ID / 姓名 |
|
||||
| occupying | Boolean | 三态:`null`=未判定(`resourceId` 未传时) |
|
||||
| shareGroupId | Long→String | 本行已属的 ACTIVE 共用关系 ID,不属任何关系为 null |
|
||||
| selectable | Boolean | 三态:`true`=可选 / `false`=不可选 / `null`=未判定 |
|
||||
| unselectableReason / unselectableDetail | String | 不可选原因(机器可读)/ 人读补充 |
|
||||
|
||||
以上字段结构本次未改动,仅"团期不存在"场景的响应形状变化。
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```http
|
||||
GET /admin/fleet/group-dispatch/batches/8801/share-member-candidates?serviceDate=2026-09-12&resourceType=VEHICLE
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
以下取值取自该 VO 源码 `@ApiModelProperty` 声明的示例值(非本轮实测输出,实测仅覆盖下方"错误响应"的团期不存在场景),用于说明字段形状:
|
||||
|
||||
```json
|
||||
{ "code": 200, "message": "成功", "data": [ { "sourceType": "ASSIGNMENT", "sourceId": "88001", "requirementId": "5501", "orderId": "70123", "orderNo": "26-0503", "teamNo": "26-0480", "customerName": "赵先生", "headcount": 3, "pickupAt": "海拉尔机场", "dropoffAt": "满洲里口岸", "pickupParticipant": 1, "dropoffParticipant": 0, "groupCode": "G1", "vehicleModel": "别克GL8", "occupiedVehicleId": "2001", "occupiedVehiclePlate": "京A·····", "occupiedDriverId": "3001", "occupiedDriverName": "王师傅", "occupying": true, "shareGroupId": "360462416850587648", "selectable": true } ], "success": true }
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
无匹配候选时返回 `data=[]`,这是正常结果,不是错误;与"团期不存在"的 `600015` 不同。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{ "code": 600015, "message": "团期不存在: 9107777777777777777", "data": null, "success": false }
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 团期不存在时统一改抛 600015,与另外三个读口一致。
|
||||
- `occupying` / `selectable` 三态字段语义本次不变:不传 `resourceId` 时恒为 `null`(未判定),不会误报 `false`。
|
||||
- `shareGroupId` 非空表示该行已属某个共用关系;本读口不知道调用方正在编辑哪一个关系——若在追加同一关系的成员,前端仍需把该关系已有成员一并带上(成员是全集不是增量),这一点本次未变化。
|
||||
- `selectable=true` 不是提交必成功的承诺,候选清单是时点快照、不加锁,提交时仍可能撞 602106,本次未变化。
|
||||
|
||||
---
|
||||
|
||||
## 四、契约约束与正确调用方式(接口类必写)
|
||||
|
||||
> 本节只写**后端接受/拒绝 payload 的规则**,不写 UI 渲染建议。
|
||||
|
||||
### ✅ 正确 / ❌ 错误 payload 对照
|
||||
|
||||
| 场景 | payload / 响应 |
|
||||
|------|-----------------|
|
||||
| ✅ 查询存在的团期 | 四个读口均正常返回 `code=200` |
|
||||
| ✅ 查询存在但零共用关系的团期(share-groups) | `code=200 + data=[]` |
|
||||
| ❌ 查询不存在的团期(四个读口) | `code=600015` |
|
||||
| ❌ 继续把 `data.length===0` 当作"团期不存在"的判据 | 遇到 600015 时拿不到 `data` 数组,需新增 600015 分支 |
|
||||
|
||||
### 切换状态时的必要动作
|
||||
|
||||
前端拦到 `code=600015` 时应提示"团期不存在"类文案并阻断当前页面的后续操作(如返回列表页重新选择团期),不要自动重试;600012/602113/600009 等其余错误码仍按原"可重试"逻辑处理,含义未变。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库行为(涉及写操作时必写)
|
||||
|
||||
本次涉及的四个接口均为只读查询,无任何数据库写操作。改动只影响 Feign 出向调用失败时的错误码分流逻辑与部分错误/提示文案,不涉及任何表结构或存量数据变化。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 未登录 → 401(网关拦截)
|
||||
- 团期不存在 → 600015(四个读口统一,本次新行为)
|
||||
- 上游确实不可达(非团期不存在,如超时/熔断降级)→ 仍返回各读口原有的可重试码(overview=600012,readiness=602113,share-groups 查询=600009,share-member-candidates=600009),含义未变
|
||||
- share-groups / share-member-candidates 无匹配数据 → `data=[]`,不是错误
|
||||
- readiness 的 `blockers`/`warnings` 为空数组 → 表示该维度全部通过/无提醒,不是错误
|
||||
|
||||
---
|
||||
|
||||
## 六.5、枚举 / 数据字典(接口出现枚举时必写)
|
||||
|
||||
### 团期不存在错误码(`GroupDispatchErrorCode`)
|
||||
|
||||
**所属字段**: 无(HTTP 响应顶层 `code`) | **类型**: `Integer`
|
||||
|
||||
| 值 | 中文 | 说明 |
|
||||
|----|------|------|
|
||||
| `600015` | 团期不存在 | 上游 order-v3 明确回"团期不存在"(含已软删)时的失败关闭码;本 changelog 覆盖的四个读口统一适用;永久性否定,不应自动重试 |
|
||||
|
||||
`BLOCK_NOT_CONFIRMED` 不是新增枚举值,本次只是其 `message` 文案按"零配车行/有配车行未确认"两种子场景分化,见六.6。
|
||||
|
||||
## 六.6、修改前后对比(修改/删除类接口必写,新增跳过)
|
||||
|
||||
### 字段级对比
|
||||
|
||||
本次无响应字段新增或删除,四个接口的成功路径字段结构均未改动。
|
||||
|
||||
### 行为级对比
|
||||
|
||||
| 场景 | 改前 | 改后 |
|
||||
|------|------|------|
|
||||
| 四个读口对不存在团期的响应 | overview / readiness / share-member-candidates 返回各自原有的可重试码;share-groups 返回 `code=200 + data=[]` | 统一返回 `code=600015`(永久性否定) |
|
||||
| readiness 该团尚无任何配车行 | `blockers[].message` = "本团有 0 条配车行尚未确认" | `blockers[].message` = "本团尚未创建任何配车行"(`code` 仍是 `BLOCK_NOT_CONFIRMED`) |
|
||||
| readiness 该团有配车行但部分未确认 | `blockers[].message` = "本团有 N 条配车行尚未确认" | 不变,仍是 "本团有 N 条配车行尚未确认" |
|
||||
|
||||
## 六.7、影响评估(修改/删除类必写)
|
||||
|
||||
- **是否破坏向后兼容**: 是——`share-groups` 对不存在团期的响应形状变化(`200+data=[]` → `600015`)是唯一的结构性破坏点;`overview`/`readiness`/`share-member-candidates` 原本就是错误响应分支,只是错误码数值变了(code 判断逻辑需同步更新,但不是从"成功"变"失败")。
|
||||
- **前端是否必须同步上线**: 是——针对 `share-groups`,若继续沿用旧的 `data.length===0` 判断"无共用关系",遇到不存在的团期会因为拿到 `600015` 错误响应、取不到 `data` 数组而报错,而不是正确显示"查无此团";针对 readiness 若有按 `message` 文本内容做分支判断的逻辑需要改成按 `code` 判断。
|
||||
- **前端 workaround 清理点**: 若此前为"team not found 但 share-groups 返回空数组"这类情况写过特殊兼容逻辑,可以确认改造后不再需要,因为现在有独立的 600015 信号可用。
|
||||
|
||||
---
|
||||
|
||||
## 七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
|
||||
|
||||
- **仅影响**: 管理后台团期配车页四个只读端点在"团期不存在"场景下的响应;就绪判定端点"该团尚无任何配车行"这一特定场景的提示文案。
|
||||
- **零影响**:
|
||||
- 四个读口成功路径的响应字段结构(除本 changelog 描述的错误码分流与 readiness 文案外,无字段增删)
|
||||
- 其余可重试错误码(600009 / 600012 / 602113 等)的含义与返回条件
|
||||
- readiness 端点"该团有配车行但部分未确认"场景的提示文案
|
||||
- 团期配车写口(`reconfigure`/`confirm`)与共用关系写口(`confirm`/`release`),本次改动仅涉及只读端点
|
||||
|
||||
---
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
服务:`hl-fleet-service`,dev-v3 分支部署测试网关 @ `e2982739e8`(含 #8536/#8537 所在提交),测试网关 `https://api.test.1814.love`:
|
||||
|
||||
```
|
||||
✓ 不存在团期 groupBatchId=9107777777777777777 → 总览/就绪判定/共用关系查询/共用成员候选 四个读口均返回 code=600015, message="团期不存在: 9107777777777777777"
|
||||
✓ 团期 groupBatchId=2104840641651556353(存在且零共用关系)→ GET share-groups 返回 code=200, data=[](与不存在团期的 600015 可区分)
|
||||
✓ 团期 groupBatchId=2104838272570245121(团级需求已确认、零物理配车行)→ GET readiness 返回 blockers=[{"code":"BLOCK_NOT_CONFIRMED","message":"本团尚未创建任何配车行"}]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- 关联 Issue: [wx/HL#8536](https://git.1814.love/wx/HL/issues/8536)、[wx/HL#8537](https://git.1814.love/wx/HL/issues/8537)
|
||||
- 关联 PR: [wx/HL#8554](https://git.1814.love/wx/HL/pulls/8554)
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#8536](https://git.1814.love/wx/HL/issues/8536)、[#8537](https://git.1814.love/wx/HL/issues/8537)
|
||||
- **PR**: [#8554](https://git.1814.love/wx/HL/pulls/8554)
|
||||
- **Merge commit**: [e2982739e8](https://git.1814.love/wx/HL/commit/e2982739e8)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @wx
|
||||
在新工单中引用
屏蔽一个用户