From b4c44254d391390b45993e0afac9862cd899ef1e Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Wed, 12 Aug 2026 22:49:31 +0800 Subject: [PATCH] =?UTF-8?q?docs(changelog):=20#5937=20=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E6=94=B9=E6=9C=9F=E6=AE=8B=E7=95=99=E6=B4=BE=E8=BD=A6=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E9=80=90=E6=97=A5=E7=B2=BE=E7=A1=AE=E7=AB=AF=E7=82=B9?= =?UTF-8?q?(PR=20#5939/#5941)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...留派车改为按单日精确取消-修改接口-管理后台.md | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 changelogs-v2/2026-08/12_5937_取消改期残留派车改为按单日精确取消-修改接口-管理后台.md diff --git a/changelogs-v2/2026-08/12_5937_取消改期残留派车改为按单日精确取消-修改接口-管理后台.md b/changelogs-v2/2026-08/12_5937_取消改期残留派车改为按单日精确取消-修改接口-管理后台.md new file mode 100644 index 0000000..98a7caa --- /dev/null +++ b/changelogs-v2/2026-08/12_5937_取消改期残留派车改为按单日精确取消-修改接口-管理后台.md @@ -0,0 +1,121 @@ +--- +schema: "hl-changelog/v2" +ticket: "5937" +title: "取消改期残留派车改为按单日精确取消——禁止误删整槽及整单配车" +consumer: "admin" +change_type: "修改接口" +author: "wx(GIT)" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "mmg" +frontend_ref: "" +target_release: "" +verified_at: "2026-08-12" +status_note: "后端已修复并部署测试服:Step2 cell 新增 assignmentId,新端点 POST /admin/fleet/assignments/{assignmentId}/cancel-residue 仅取消指定窗外逐日残留行,不动同槽其他日期或其他槽位。前端必须把『取消残留派车』从槽位删除/老 cancel 切到新端点,使用 cells[].assignmentId;成功后重拉 candidates。禁止继续调用 DELETE /slots/{slotId} 或 DELETE /assignments/{assignmentId},二者均是整槽语义。" +updated_at: "2026-08-12" +base: "dev-v3" +--- + +# 取消改期残留派车改为按单日精确取消(#5937 / PR #5939 + #5941) + +> **服务**: hl-fleet-service +> **日期**: 2026-08-12 +> **前端负责人**: @mmg +> **严重级别**: P0 + +## 问题实证(订单 26-3559 / 2086270159575535618) + +车务在 Step2 栅格点击 08-24/25 行的「取消残留派车」,只想清理两天旧日期残留,实际触发了槽位删除: + +- 18:44:39:旧槽 08-24/25/26 三行全部 canceled; +- 19:03:23:新槽 08-26/27/28 三行又全部 canceled; +- 最终整单两个槽位共 6 行配车被清空(订单主单未取消,仍为 CUSTOMIZING / VEHICLE PROCESSING)。 + +## 根因 + +1. `canonicalSnapshot.cells[]` 原来没有逐日 `assignmentId`,前端无法精确定位一行。 +2. 前端只能退化调用槽位删除。 +3. 老 `DELETE /admin/fleet/assignments/{assignmentId}` 名字看似按 assignmentId,后端实际也是稳定槽位整槽取消(`updateCancelSlotActive`),同样不能用于逐行残留清理。 + +## 新增响应字段 + +`POST /admin/fleet/assignments/candidates`: + +```text +data.canonicalSnapshot.cells[].assignmentId +``` + +| 字段 | 类型 | 说明 | +|---|---|---| +| `assignmentId` | string | 当天逐日派车行 ID。仅逐日 USED 行返回;全程行/无行/UNUSED 为 null。前端按此 ID 调逐日残留取消。 | + +配合既有字段:`serviceDate`、`rescheduleResidue`、`canDelete`、`deleteBlockReason`、`vehiclePlate`、`driverName`、`protocolPrice`。 + +全程行(`service_date=NULL`)展开的 cell: + +```json +{ + "assignmentId": null, + "canDelete": false, + "deleteBlockReason": "全程派车不可按单日取消,请先拆分或改派" +} +``` + +## 新增接口(前端必须切换) + +```http +POST /admin/fleet/assignments/{assignmentId}/cancel-residue +Content-Type: application/json +``` + +请求: + +```json +{ + "requestId": "residue-cancel-{唯一请求ID}", + "cancelReason": "改期残留逐日取消" +} +``` + +行为: + +- 只允许取消当前需求日期窗外的逐日 `holding/assigned` 残留行; +- Mapper 只按 exact `assignmentId + expectedStatus` CAS 一行; +- 不取消同槽其他日期; +- 不影响其他槽位; +- 不写槽位删除意图,不移除 retained slot; +- 只释放目标日期车辆/司机占用、只退目标日期司机保险; +- 新窗内有效行、全程行、completed 行均拒绝; +- 已 canceled 行重复请求幂等 200,DB 零变化。 + +## 前端改法(必须全部完成) + +1. 「取消残留派车」按钮仅在: + - `rescheduleResidue === true` + - `canDelete === true` + - `assignmentId != null` + 时显示/启用。 +2. 点击后调用新接口: + ```http + POST /admin/fleet/assignments/{cell.assignmentId}/cancel-residue + ``` +3. 成功后必须重新调用 `POST /admin/fleet/assignments/candidates`,用最新 `canonicalSnapshot` 重建栅格;被取消的目标旧日期行自然消失。 +4. **禁止**继续调用: + - `DELETE /admin/fleet/assignments/slots/{slotId}`(整槽删除) + - `DELETE /admin/fleet/assignments/{assignmentId}`(老普通取消,实际整槽语义) +5. 不要只在本地数组里做状态修改;以后端重拉结果为唯一权威。 + +## 测试与测试服证据 + +- AssignmentServiceTest:487 / 0 / 0;覆盖 exact-ID、窗内拒绝、全程拒绝、canceled 幂等、completed 拒绝、状态 TOCTOU、资源身份漂移后只锁最新车/司机。 +- Controller + Step2:60 / 0 / 0。 +- ArchTest:13 / 0 / 0;spotless 绿。 +- fleet 全量 3688:本改动相关测试全绿;两项无关环境/flaky 独立复跑 1/1、2/2 均绿。 +- 测试服双实例 8087/8187 健康。 +- 已 canceled 行实测新端点:HTTP 200、`effectiveDate=2026-08-24`,调用前后本单 8 行 DB 快照完全一致(幂等零副作用)。 + +## 联系人 + +- **后端负责人**: @wx +- **前端消费**: @mmg(切换新逐行端点 + 删除成功后重拉 candidates)