docs(changelog): #8371 改期残留行单行取消 + #8372 团期总览 groupCode;20_5935 加订正指针
changelog-filename-gate / validate (push) Failing after 2s

- 26_8371:DELETE /admin/fleet/assignments/{assignmentId} 命中改期残留行只取消该行、豁免 605027/605047/605028;
  CancelRespVO.evidenceFileIds 改为按组累计(本次未传凭证时为空);取窗失败 605710 失败关闭。
- 26_8372:GET 团期派车总览 days[].vehicles[] 新增 groupCode,可原样回提 reconfigure 的 assignments[].groupId。
- 20_5935:旧件各【需确认】/错误说法处加 #8371 订正指针,指向新件。

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
这个提交包含在:
API Changelog Bot
2026-09-26 15:13:41 +08:00
共同撰写人 Claude Opus 5.5
父节点 9521237265
当前提交 69f82a17a2
共修改 3 个文件,包含 645 行新增和 3 行删除
@@ -10,10 +10,10 @@ gateway_status: "not_required"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "28d4482c636dbfeba1803c64ef263f09c3656934"
target_release: ""
target_release: "hl-ui@28d4482c"
verified_at: "2026-09-21"
status_note: "前端 2026-09-20 反馈清单第4项引用了一个不存在的写口 POST .../slots/{slotId}/clear-residue-dates(该端点已随 #7067 去槽位化整体删除,origin/dev-v3 全仓零命中),并要求后端在读侧新增 residueServiceDates 字段。核实:读侧 cells[].rescheduleResidue 已能推导出该日期子集,写侧 DELETE /{assignmentId} 与 POST /batch 两条既有端点已覆盖单日/整批清理,本次零后端代码改动。POST /batch 对已过去的残留日期有硬门禁会拦截,DELETE 是否放行未取证,本文档已如实标注【需确认】。前端 2026-09-21 已交付:Step2 逐日栅格恢复残留格「取消残留」入口(canDelete!==false 且 assignmentId 时渲染,只读行禁用,deleteBlockReason 透传),逐日清理走 DELETE /admin/fleet/assignments/{assignmentId}(cancelReason/driverNotified/requestId 按契约显式传,requestId=createRequestId('residue-clear'));整批 POST /batch 100001「已过去或已完结」识别后提示改走逐日清理。DELETE 对过去日期是否放行(605028)仍未实证,由拦截器统一透后端 message 兜底。"
updated_at: "2026-09-20"
status_note: "前端 2026-09-20 反馈清单第4项引用了一个不存在的写口 POST .../slots/{slotId}/clear-residue-dates(该端点已随 #7067 去槽位化整体删除,origin/dev-v3 全仓零命中),并要求后端在读侧新增 residueServiceDates 字段。核实:读侧 cells[].rescheduleResidue 已能推导出该日期子集,写侧 DELETE /{assignmentId} 与 POST /batch 两条既有端点已覆盖单日/整批清理,本次零后端代码改动。POST /batch 对已过去的残留日期有硬门禁会拦截,DELETE 是否放行未取证,本文档已如实标注【需确认】。前端 2026-09-21 已交付:Step2 逐日栅格恢复残留格「取消残留」入口(canDelete!==false 且 assignmentId 时渲染,只读行禁用,deleteBlockReason 透传),逐日清理走 DELETE /admin/fleet/assignments/{assignmentId}(cancelReason/driverNotified/requestId 按契约显式传,requestId=createRequestId('residue-clear'));整批 POST /batch 100001「已过去或已完结」识别后提示改走逐日清理。DELETE 对过去日期是否放行(605028)仍未实证,由拦截器统一透后端 message 兜底。2026-09-26 订正(#8371):DELETE 命中改期残留行已改为单行取消,并豁免 605027/605047/605028 三道日期门,见 26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md。"
updated_at: "2026-09-26"
base: "dev-v3"
---
@@ -41,6 +41,10 @@ base: "dev-v3"
- 前端要求新增的读侧字段 `residueServiceDates`**不需要新增**:`AssignmentCandidateRespVO.CanonicalSnapshotVO.cells[]`(`AssignmentCandidateRespVO.java:108-150`)里每个 cell 已经逐日携带 `rescheduleResidue`(布尔)+ `serviceDate` + `assignmentId`,前端自己过滤即可得到这个数组。
- ⚠️ **`POST /batch` 整批清理对"已过去的残留日期"有硬门禁会拦截**(详见「四、契约约束」),前端做整批清理时必须预期这种场景下的 400。逐日清理 `DELETE /{assignmentId}` 是否放行过去日期,本轮**未取证**,标记为【需确认】。
> **2026-09-26 订正(#8371)**:
> - `DELETE /{assignmentId}` 逐日清理残留行现已**单行取消**(不再整组取消),并豁免 605027/605047/605028 三道日期门。
> - 改期残留行判定、单行处理、错误码豁免的细节,见 26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md。
---
## 一、背景
@@ -72,6 +76,8 @@ base: "dev-v3"
| 2 | 取消派单(逐日清理残留) | DELETE | `/admin/fleet/assignments/{assignmentId}` | 复用不改 | 按 cell 的 `assignmentId` 单日取消,条件释放占用 |
| 3 | 批量创建派单(整批清理残留) | POST | `/admin/fleet/assignments/batch` | 复用不改 | 提交时不带残留日期项,后端按 diff 精确取消 |
> **2026-09-26 订正(#8371)**:上表第 2 行「按 cell 的 `assignmentId` 单日取消」在写作当时并不成立——彼时 `DELETE` 命中改期残留行仍按**整组**取消(还会连带取消同组窗内的其它日期行,这正是 #8371 要修的缺陷)。#8371 已实测确认:`DELETE` 现在对「改期残留行」做真正的单行取消,窗内其它行不受影响;非残留行仍按原整组逻辑处理。细节与实测证据见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
---
## 三、接口详情
@@ -197,6 +203,8 @@ base: "dev-v3"
**VO**: `CancelReqVO → CancelRespVO`
> **2026-09-26 订正(#8371)**:本小节标题「逐日清理残留」写作时是前端诉求的期望描述,当时源码并不支持——`DELETE` 命中改期残留行时仍按整组取消。#8371 已实测确认标题所述行为现已成立:目标行若判定为「改期残留行」,走单行取消分支,操作日志 `operationLog[].detailJson` 会带 `scope="RESIDUE_ROW"` 可供核验;非残留行不受影响,仍是整组取消。细节见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
#### 使用场景
车务在 Step2 栅格里勾选一个或多个 `rescheduleResidue=true` 的日期后,对每个勾选日期取其 cell 的 `assignmentId`,逐日调用本端点单独取消,条件释放该行占用的车辆/司机。适合「只清理某几天」「部分勾选」场景。
@@ -287,9 +295,13 @@ base: "dev-v3"
其它错误码(`AssignmentController.java:469-471`):400(`cancelReason`/`driverNotified`/`requestId` 请求校验)/ 605009(派单不存在)/ 605020(当前状态不允许取消)/ 605026(无凭证未二次确认)/ 605027(已出发禁止整组取消)。
> **2026-09-26 订正(#8371)**:目标行判定为「改期残留行」时,605027(连同 605047/605028)**不再触发**,改走单行取消;新增 605710「订单服务不可用:{0}」——残留行判定依赖 order-v3 查询窗口数据,查询失败时整笔 fail-closed,不取消任何行。非残留行的错误码集合不变。见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
#### 业务边界
- 【需确认】**本端点对"服务日期已过去的改期残留行"是否放行取消,本轮未取证**:`CancelReqVO.cutoffDate` 注释写明「服务端仅接受当天,空值按当天处理,不支持预约未来取消」,而 605028 的语义是「取消生效日不在派单服务日期范围内」——若某残留行 `serviceDate` 是 3 天前、`cutoffDate` 按当天处理,"当天"是否落在该行的服务日期范围内、会不会触发 605028,未经实测确认。读侧 `canDelete` 字段的设计意图是「改期残留旧行恒 `true`,受只读窗口约束时 `false`」(`AssignmentCandidateRespVO.java:149-150`),但这是响应快照上的展示态,不等于运行时 DELETE 调用本身在过去日期上必然放行。**若实测发现本端点对已过去日期同样拦截,那才是真正需要后端开一张单的地方**(放开残留行对过去日期的取消)。
> **2026-09-26 订正(#8371)**:已实测坐实——修复前,改期残留行(服务日期已过去)确实被拦截,实测复现 605027;#8371 修复后,同一残留行 `DELETE` 直接取消成功,不再命中 605027/605047/605028。取消后该行状态落 `exception`(不是 `canceled`,因取消前处于 `assigned`/`holding`,与通用取消 #6152 同口径)。判定逻辑与全链路证据见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
- `assignmentId` 必须取自对应 cell(残留清理场景下即 `rescheduleResidue=true` 的那一项),传错会命中另一天的派车行。
- `driverNotified` 传 `false` 也允许取消,只是前端需要在未告知司机时给出强提示(后端只做存证,不代为通知)。
@@ -416,6 +428,8 @@ base: "dev-v3"
前端在实现"整批清理"按钮时,遇到 `code=100001` 且消息含"已过去或已完结",应识别为"残留日期已过去,本接口无法清理",引导车务改走逐日 `DELETE` 路径(而不是当成普通校验失败重试原样提交)。
> **2026-09-26 订正(#8371)**:上表「✅ 逐日清理(含过去日期,未取证是否放行)」与本段「引导车务改走逐日 `DELETE`」在写作时均未经实测;实测结果是**当时同样会被拦截**(改期残留行过去日期 `DELETE` 命中 605027),引导车务改走逐日 `DELETE` 在当时并不能真正解决问题。#8371 已修复:残留行现在 `DELETE` 直接取消成功,完全跳过整组门禁,上表与本段的方向自此才成立。见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
---
## 五、数据库行为
@@ -429,6 +443,8 @@ base: "dev-v3"
两条路径都不会物理删除行,只做状态流转;`assignmentId` 一旦取消不可复用为新方案的匹配键。
> **2026-09-26 订正(#8371)**:上表「状态置 `canceled`」是简化写法。测试服实测:取消前处于 `assigned`/`holding` 的行,落库状态是 `exception`(与通用取消 #6152 同口径),仅 `unassigned` 行取消才直接落 `canceled`。改期残留行走单行取消分支时同样遵循这条状态机,不因残留身份而特殊化。见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
---
## 六、边界行为
@@ -437,6 +453,8 @@ base: "dev-v3"
- `assignmentId` 不存在 → `DELETE` 返 605009
- `requirementId` 缺失或需求上下文不可用 → `candidates` 的 `canonicalSnapshot` 为 `null`,不报错
- 已出发/已完结的派单 → 605027(整组取消禁止)/「该日已完结不可改派」400(`AssignmentService.java:2714`)
> **2026-09-26 订正(#8371)**:上条仅对**非改期残留行**成立。目标行判定为改期残留行时,605027/605047/605028 三道日期门全部豁免,按单行取消处理;order-v3 查询窗口失败时新增 605710 fail-closed(不取消任何行)。见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
- 老数据兼容:历史行无 `assignmentGroupId` 时,`cells[].groupId` 回退返回 `assignmentId`,对任何真实行恒非空
---
@@ -498,6 +516,8 @@ grep clear-residue-dates / clearResidueDates / cancel-residue → 全仓零命
**【需确认】未取证项**:`DELETE /{assignmentId}` 对服务日期已过去的改期残留行是否放行取消(涉及 605028 与只读窗口判定),需要一次真实测试服调用才能确认,本文档不代为下结论。
> **2026-09-26 订正(#8371)**:已取证,不再是【需确认】。改前基线:确实拦截,命中 605027。改后(#8371 测试服全链路 6 步实测):改期残留行判定为真时,`DELETE` 直接放行取消,不命中 605027/605047/605028;判定失败(order-v3 不可达)时新码 605710 fail-closed。见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
---
## 十、相关文档
@@ -506,6 +526,8 @@ grep clear-residue-dates / clearResidueDates / cancel-residue → 全仓零命
- 退役背景:#7067 去槽位化重构(`06_7067_派单去槽位化按行程日配车-接送机独立配置-修改接口-管理后台.md`)
- 后续计划:若【需确认】项实测发现 `DELETE` 对过去日期同样拦截,需另开工单放开残留行的过去日期取消
> **2026-09-26 订正(#8371)**:该「另开工单」已完成,即 #8371——已实测坐实过去拦截、已修复并验证放行。见 `26_8371_改期残留行单行取消与累计凭证回显-修改接口-管理后台.md`。
## 关联 / 联系人
### 链接