---
schema: "hl-changelog/v2"
ticket: "6107"
title: "终止行程后已取消派单「释放车辆/司机占用」入口（一键清除占用端点告知）"
consumer: "admin"
author: "wx"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "2ebfddc7"
target_release: ""
verified_at: "2026-08-20"
status_note: "端点 POST /admin/fleet/assignments/clear-cancelled-occupancy 由 #5921（关联 #5913/#5828）交付并部署 TEST，但当初未单独发 changelog，前端不知其存在，导致「终止行程后已取消派单仍占着车/司机、无释放按钮」。本文补告知取值与 UI 挂载点。后端本次无代码变更。"
updated_at: "2026-08-20"
base: "dev-v3"
generated: "2026-08-20T00:00:00+08:00"
---

# 终止行程后已取消派单「释放车辆/司机占用」入口（#6107）

## 背景

订单**中止行程**后，订单侧已把对应车务派单截断为 `canceled`，看板正确显示「已取消」。

但「已取消」只是把派单行冻结，**该行原本锁住的车辆/司机资源占用（脏 busy）不会自动全部归还**——需要车务同事手动触发一次「释放占用」。此前前端不知道后端已有这个释放端点，导致看板详情里看不到任何释放按钮，资源一直被冻结，影响后续派车。

**本文一次性告知：释放占用的后端能力早已上线，前端只需补挂一个按钮。**

## 变更接口

| 接口 | 变更 |
| --- | --- |
| `POST /admin/fleet/assignments/clear-cancelled-occupancy` | **已上线，本次补告知**。一键圈定某订单/需求下全部已取消(canceled)派单的车辆/司机，清掉它们的脏占用（合法 busy 不动）。**只清占用，不修改派单任何字段** |
| `POST /admin/fleet/assignments/{assignmentId}/soft-clear-assignment` | 已上线（#5936）。单条软清备用；本单默认用上面的整单一键清 |

## 一、调用方式（clear-cancelled-occupancy）

**入参**（body）：

```json
{
  "orderId": "1934567890123456789",
  "requestId": "clear-cancel-20260820-001"
}
```

- `orderId` 与 `requirementId` **二选一**（都填/都不填返 100001）。车务看板详情页天然有 `orderId`，用它即可。
- `requestId` **必填**，幂等标识，≤64 字符，前端生成（如 `clear-cancel-` + 时间戳）。

**返回**（data）：

```json
{
  "vehicleDriverPairs": 2,
  "intentsWritten": 2,
  "assignmentIds": ["1934567890123456701"]
}
```

- `assignmentIds` 为本次实际圈到的已取消派单 ID 列表（雪花按字符串返回）。
- `intentsWritten=0` 表示没有可清的脏占用（幂等安全，可视为成功）。

**错误码**：`100001`（orderId 与 requirementId 二选一）/ `605047`（行程已结束）/ `605054`（终止冻结中，稍后重试）/ `605600`（已关账）。

## 二、前端动作（本次唯一要改的地方）

在**车务看板 → 订单详情抽屉 → 「车辆执行段」列表**补一个入口：

1. **可见条件**：`GET /admin/fleet/board/orders/{orderId}` 返回的 `activeAssignments[]` / `vehicleSlots[]` 里存在 `assignmentStatus === "canceled"` 的行，且该行 `assignmentId` 非空时，显示「释放车辆/司机占用」按钮（或文字链）。
2. **点击**：弹确认框（文案建议「将释放该订单下已取消派单占用的车辆/司机，是否继续？」），确认后调 `clear-cancelled-occupancy`，`orderId` 取当前订单、`requestId` 前端生成。
3. **成功后**：提示成功并**重新拉取详情**（占用释放是异步 outbox 反算，稍候在矩阵/资源日历可见车、司机恢复 idle）。
4. **非 canceled 行不展示该入口**；`holding`/`assigned` 仍走既有「清空司机/车辆」(#5936)，语义不同，别混用。

## 三、取值字段（详情接口已返回，无需后端改）

`GET /admin/fleet/board/orders/{orderId}`（BoardOrderDetailVO）已含：
- `vehicleSlots[].assignmentStatus` / `assignmentStatusLabel`（canceled = 已取消）
- `vehicleSlots[].assignmentId`、`assignmentSlotId`、`vehicleId`、`driverId`
- `activeAssignments[].assignmentStatus` / `assignmentId`

## 验证证据

- 后端 `ClearCancelledOccupancy` 单测 7 例随 #5921 交付即绿；端点已在 TEST 部署。
- 全量 API 测试（2026-08-20，232 用例）复核：终止行程后 fleet assignment 正确置 `canceled`，仅缺前端释放按钮——纯前端缺口。
- 网关（TEST 9443，真 SUPER_ADMIN token）实测本端点：不存在 orderId 幂等返回 `200 {vehicleDriverPairs:0, intentsWritten:0, assignmentIds:[]}`，路由可达、结构符合 RespVO 契约。
