---
schema: "hl-changelog/v2"
ticket: "5255"
title: "已派车恢复改派与行程单入口更正"
consumer: "admin"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "hl-ui-codex"
frontend_ref: "mmg/hl-ui@f9251d0ffabf13641630588733d103e00f35e85d"
target_release: ""
verified_at: ""
status_note: "后端已部署并完成网关验证；前端需恢复已派车改派按钮，并将看板行程单入口直接复用订单详情现有打印实现。本文件覆盖 #5186 的已派车禁用改派及复制司机 H5 链接口径。"
updated_at: "2026-07-26T03:32:07.805Z"
base: "dev-v3"
---

# 车务：已派车恢复改派与行程单入口更正

> **服务**: `hl-fleet-service`
>
> **工单**: [wx/HL#5255](https://git.1814.love:8443/wx/HL/issues/5255)
>
> **后端 PR**: [wx/HL#5258](https://git.1814.love:8443/wx/HL/pulls/5258)
>
> **影响范围**: 车务管理 → 派单看板操作区、既有派车/改派弹窗、行程单打印入口

## 关键变化

- 当前有效派单状态为 `assigned` 时，派单看板列表现在返回 `canAssign=true`，并继续下发
  `CHANGE_ASSIGNMENT`。车辆已经配好后，只要派单尚未进入 `completed/canceled` 终态，车务仍可
  随时进入既有改派流程，再次更换当前车辆槽位的车辆、司机或两者。
- `holding/holding_urgent` 的改派能力不变；`completed/canceled` 继续不可改派。
- 看板操作区的行程单入口统一为“打印行程单”，直接复用订单详情已有的
  `PrintItineraryModal.vue` 和 `getPrintItinerary(orderId)`，不新写打印组件、打印接口或打印数据模型。

## ⚠️ 对 #5186 的口径更正

本文件取代
`23_5186_排车中订单恢复派车派人入口-修改接口-管理后台.md`
中的以下两项旧交接：

1. #5186 响应矩阵把 `assigned` 与终态一起写成 `canAssign=false`。该口径已失效：
   `assigned` 现在允许改派，只有 `completed/canceled` 禁止改派。
2. #5186 要求看板复制 `currentAssignment.itineraryUrl`，并明确“不复用
   `PrintItineraryModal.vue`”。该口径已撤销：看板不再把“复制司机 H5 链接”作为本入口的实现，
   而是直接复用订单详情现有打印代码。

#5186 中与本次两项更正无关的候选上下文、稳定槽位和待确认流程说明继续有效。本次也不删除后端
司机 H5 短链能力；只是看板这个用户入口不再消费它。

## 变更接口

| 方法 | 路径 | 本次口径 |
| --- | --- | --- |
| `GET` | `/admin/fleet/board/orders` | 既有字段语义更正：有效 `assigned` 记录返回 `canAssign=true`，且 `availableActionCodes` 包含 `CHANGE_ASSIGNMENT` |
| `POST` | `/admin/fleet/assignments/<assignmentId>/change` | 既有改派接口，路径和请求/响应契约不变；继续按稳定车辆槽位与生效日原子替换 |
| `GET` | `/v3/admin/order/<orderId>/print-itinerary` | 订单详情已有打印接口，本次无后端变更；看板直接复用现有前端调用 |

## 1. 派单看板动作语义

`GET /admin/fleet/board/orders` 的字段名、类型和必填性均未变化。前端按后端动作字段渲染：

| `assignmentStatus` | `canAssign` | `availableActionCodes` | 看板主操作 |
| --- | ---: | --- | --- |
| `unassigned/unassigned_urgent` | `true` | 包含 `ASSIGN` | “派车派人”，进入既有首次派车流程 |
| `holding/holding_urgent` | `true` | 包含 `CHANGE_ASSIGNMENT` | “改派”，进入既有改派流程 |
| `assigned` | `true` | 包含 `CHANGE_ASSIGNMENT` | “改派”，已配车后仍可再次调整 |
| `completed/canceled` | `false` | 不包含 `CHANGE_ASSIGNMENT` | 不显示改派入口 |

前端不得再把“已有车辆/司机”或 `assignmentStatus === 'assigned'` 当作隐藏改派按钮的条件。
入口首先以 `canAssign === true` 判断是否可进入，再以 `availableActionCodes` 区分首次派车或改派。

## 2. 继续复用既有按槽位改派

点击“改派”后继续使用当前派车弹窗和现有
`POST /admin/fleet/assignments/<assignmentId>/change`：

- `assignmentId` 取用户选中的 `activeAssignments[]` 派车组/槽位，不得固定取代表项后误改其它车；
- 生效日及之后只替换该稳定 `assignmentSlotId` 的逐日切片；
- 同一订单其它车辆槽位保持不变；
- 可只换车辆、只换司机或同时替换；
- 成功后重新拉取看板列表与详情，不缓存旧的 `canAssign`、动作码或派车组数据；
- 后端返回 `ORDER_HAS_OTHER_VEHICLES` 等既有警告时继续沿用当前强提示。

本次没有新增写接口，也没有修改改派请求字段、错误码或事务规则。

## 3. 行程单入口直接复用订单详情打印代码

管理后台现有可复用实现位于：

- `src/views/order-v2/detail/modals/PrintItineraryModal.vue`
- `src/api/orderV2.js` 的 `getPrintItinerary(orderId)`
- 既有接口 `GET /v3/admin/order/<orderId>/print-itinerary`

看板按以下方式接入：

- 操作文案统一为“打印行程单”，点击后把当前订单的字符串 `orderId` 传给现有
  `PrintItineraryModal`；
- 打印预览、加载、错误提示、页面排版和打印动作全部沿用订单详情现有组件；
- 可抽取共享挂载点或直接复用组件，但不得复制组件源码形成第二套打印实现；
- 不新增 fleet 打印 API，不在前端重新组装行程节点、费用、住宿、大交通或每日行程；
- 不调用看板详情去读取 `currentAssignment.itineraryUrl`，不执行剪贴板复制，也不继续使用
  `ItinerarySendSheet.vue` 承载这个入口；
- 无 `orderId` 时不打开弹窗、不提示成功，沿用现有缺少订单上下文的错误态。

## 前端展示矩阵

| 页面区域 | 展示内容 | 数据来源 | 包含/排除状态 | 空数据表现 | 标签与颜色 | 守恒规则 |
| --- | --- | --- | --- | --- | --- | --- |
| 派车看板操作区 | 派车派人 | `availableActionCodes` 含 `ASSIGN` | 包含待派车；排除终态 | 无候选沿用现有提示 | 沿用现有待派状态色 | 只创建目标槽位 |
| 派车看板操作区 | 改派 | `availableActionCodes` 含 `CHANGE_ASSIGNMENT` | 包含待确认；排除终态 | 无有效派单不显示 | 沿用现有待确认状态色 | 只替换选中槽位 |
| 派车看板操作区 | 改派 | `canAssign=true` 且含 `CHANGE_ASSIGNMENT` | 包含已派车且未完结；排除已完结/已取消 | 无剩余可改服务日时展示既有后端错误 | 沿用现有已派状态色 | 配完仍可再次改派，其他槽位不变 |
| 派车看板操作区 | 不显示改派 | 无 `CHANGE_ASSIGNMENT` | 仅已完结/已取消 | 不展示按钮 | 沿用终态灰 | 不恢复终态 |
| 派车看板操作区 | 打印行程单 | 订单 `orderId` 与既有打印接口 | 包含可查看订单；排除无订单 ID | 沿用现有打印弹窗加载/错误态 | 沿用现有打印按钮样式 | 只复用一套 `PrintItineraryModal.vue` |

## 前端处理清单

- [ ] `assigned + canAssign=true + CHANGE_ASSIGNMENT` 显示“改派”，点击进入既有改派流程。
- [ ] `holding/holding_urgent` 继续显示“改派”，首次待派仍显示“派车派人”。
- [ ] `completed/canceled` 不显示改派入口。
- [ ] 用户选择哪个 `activeAssignments[]` 槽位，就把该槽位的 `assignmentId` 传给既有 change 接口。
- [ ] 改派成功后刷新列表与详情，当前槽位更新，其他槽位数量和身份保持不变。
- [ ] 将看板行程单操作统一为“打印行程单”，直接复用订单详情
      `PrintItineraryModal.vue + getPrintItinerary(orderId)`。
- [ ] 不新增打印组件/API，不读取或复制 `currentAssignment.itineraryUrl`，不继续使用
      `ItinerarySendSheet.vue` 实现该入口。
- [ ] 覆盖无订单 ID、打印接口失败和打印数据空态，全部沿用既有打印弹窗行为。

## 验证证据

- 后端提交：`9ea7d555a078101cbf57d1571d106cd0ec2863af`；PR #5258。
- `BoardControllerTest + BoardOrderServiceTest` 共 54 项通过。
- `AssignmentServiceTest#change_directFromEffectiveDate_replacesDailySlicesAndWarnsOtherVehicle`
  通过，验证只替换目标稳定槽位，其它车辆槽位不取消。
- `mvn -pl hl-fleet-service spotless:check` 通过。
- `mvn -pl hl-fleet-service -am verify` 通过；fleet 207 套件、2,373 项测试，
  0 失败、0 错误、1 个既有跳过。
- 测试环境已滚动部署 `hl-fleet-service`；Nacos `test` 命名空间的 8087、8187 两实例健康。
- 测试网关查询 `assigned` 返回 4 条真实记录，全部为
  `canAssign=true + CHANGE_ASSIGNMENT`，HTTP/code 均为 200。
- 测试环境当时没有 `holding/holding_urgent/completed/canceled` 样本；这些状态不冒充网关实测，
  由已通过的服务状态矩阵与 Controller JSON 测试覆盖。
- 网关证据 SHA-256：
  `1409d22ce9fc2c86101d9f811fef867e0493f177191fb8ac5ee30eb4427185e2`。
- OpenAPI/oasdiff：`not_configured`。字段名、类型和 requiredness 未变；仓库没有可复现的
  Swagger2 → OAS3 导出链且未安装 `oasdiff`，已用 Controller JSON、服务状态矩阵和当前
  `hl-ui` 消费源码做人工回退核对。
- 消费者契约/Spring Cloud Contract：`not_required`。本次没有内部 Feign 或共享 Java DTO 变化。

## 不影响范围

- 不修改或部署 `D:/work2/hl-ui`；`frontend_status` 保持 `pending`，页面实现和发布独立流转。
- 不删除司机 H5 行程短链、签名 token 或公开行程接口；仅更正看板入口的前端消费方式。
- 不新增/删除 API 字段，不改变字段类型、必填性、错误码或雪花 ID 的字符串消费要求。
- 不修改首次派车、待确认推进、取消派单、司机确认、资源占用或通知冻结规则。
- 不新增 DDL，不迁移、清理或回填数据。
