---
schema: "hl-changelog/v2"
ticket: "5693"
title: "矩阵拖拽改派多槽位支持评估 + 候选排除语义回归锁定（改指定槽位不影响其他）"
consumer: "admin"
author: "wx"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "评估结论：多槽位拖拽改派端到端已实现且槽位语义正确，零行为变更；本次仅补回归测试锁定「候选排除只作用当前槽位，同订单其他槽位仍计目标车/司机冲突」。补充口径（wx，工单评论 id=37195）：拖拽改派交互要一步到位（拖到目标车/司机直接改派，不再弹窗重选）——后端一步改派能力已齐备（change 接口 newVehicleId/newDriverId 均可空，详见工单评论 id=37196），属前端交互改造，由协调台另行前端 changelog 分流。"
updated_at: "2026-08-08"
base: "dev-v3"
generated: "2026-08-08T13:40:00+08:00"
---

# 矩阵拖拽改派多槽位评估与候选排除语义锁定（#5693）

## 背景

#5693 要求评估矩阵拖拽改派对"一个订单多车（多槽位）"的支持：目标槽位确定、指定槽位、按槽位校验、按槽位价格/逐日方案。评估结论：**四维均已实现**（#5573 槽位级派车系列建成），唯一缺口是"同订单其他槽位仍计冲突"无回归测试，本单补齐。

## 变更内容

| 项 | 变更 |
|---|---|
| `AssignmentCandidateServiceTest` | 新增 `query_reassignKeepsOtherSlotConflictOnTargetVehicle`：多槽位订单排除 slot0 查询候选时，slot1 占用目标车仍返回冲突（assignmentId/groupId 指向 slot1），available=false |

零行为/契约变更：无 mapping、字段、类型、必填性、枚举、错误码改动。

## 评估结论（四维）

1. **目标槽位确定**：矩阵每槽位独立数据行（assignmentSlotId/fleetItemIndex/assignmentId），拖拽 payload=被拖槽位行；改派提交 "`POST /admin/fleet/assignments/:assignmentId/change`" 以被拖槽位派单为 anchor，后端只切片该槽位。
2. **指定槽位**：弹窗槽位表可改选其他槽位（"选择改派"）；候选归属校验 fail-closed（excludeAssignmentId 必须同属当前 orderId+requirementId+fleetItemIndex，跨槽位直接拒绝），不可能误改别槽。
3. **校验按槽位**：候选 `withoutExcludedSlot` 只排除当前槽位全部切片；precheck 按组排除自身；座位按 fleetItemIndex 槽位需求（#5573）；常驻为车辆↔司机配对（槽位无关，设计如此）；保险按派单行事件，只触达被改槽位。
4. **价格/逐日方案按槽位**：change 按 effectiveDate 逐日切片原子替换该槽位，保留前缀沿用旧快照；同订单其他车辆返回 `warningCode=ORDER_HAS_OTHER_VEHICLES` 强提示，其他槽位数据不动。

## 变更接口或验证证据

### 接口契约

无契约变更。涉及接口 `POST /admin/fleet/assignments/candidates`（入参 orderId/requirementId/fleetItemIndex/excludeAssignmentId 既有语义）与 `POST /admin/fleet/assignments/:assignmentId/change`（既有槽位原子改派）行为不变。

### 验证证据

- 定向测试：`AssignmentCandidateServiceTest` 50/50 通过（含新增用例）；fleet 全量 verify 失败项全部归账（ReleaseEMixedBinaryHarnessTest 1F + ReleaseEOccupancyMysql8033RecoveryTest 10E 为既有基线失败；2 类 ContainerLaunch 系并行会话抢占固定 3306，空闲窗口复跑 7/7 通过）；spotless:check 通过。
- 部署：hl-fleet-service TEST（dev-v3）部署成功。
- 网关探针（实单 2085938395749515266 双槽位 8/22-24，只读）8/8 PASS：
  - A 排除 slot0 后自身车蒙C01E01 available=true 且无冲突（自身槽位被排除）；
  - B slot1 车蒙A-S6666 available=false，冲突指向 slot1 派单 2085938404851130370（其他槽位仍计冲突）；
  - C 跨槽位排除（excludeAssignmentId=slot0 + fleetItemIndex=1）被 fail-closed 拒绝（"参数非法: 排除派单不属于当前订单、当前用车需求或当前车型项"）。

## 前端交接

本单后端变更（回归测试）无需前端配合。另：wx 后续口径（工单评论 id=37195）要求拖拽改派交互**一步到位**——拖到目标车/司机直接改派（该车常驻司机或拖到的司机），不再打开改派弹窗手选槽位+重选车/司机；该需求为纯前端交互改造（后端契约依据见工单评论 id=37196），由协调台另行前端 changelog 跟踪，与本后端 changelog 的 frontend_status=not_required 不冲突。

## 前端实证确认（2026-08-08 mmg，hl-admin）

确认 not_required 属实，零代码改动：前端候选查询 `useVehicleDriverPicker.js:190-191` 仅传单数 `excludeAssignmentId`（当前槽位派单行 ID），不跨槽位排除，与本单锁定的「候选排除只作用当前槽位、同订单其他槽位仍计冲突、跨槽位 fail-closed」语义一致；改派提交以被拖/被选槽位派单为 anchor，前端未做跨槽位切片。前端在 #5676 记录的「整段改派时同槽其他执行段占用可能被误报」关切，本单后端明确为有意语义（其他槽位/段仍计冲突、失败关闭），非缺陷，前端维持现状。
