---
schema: "hl-changelog/v2"
ticket: "5301"
title: "配车矩阵统一手动加急状态与统计"
consumer: "admin"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "hl-ui-pi"
frontend_ref: "e1d0a44a734fefc4f12ff1b71d218df0b265dc62"
target_release: ""
verified_at: "2026-07-28T14:38:26+08:00"
status_note: "hl-admin 已消费人工加急徽章、精确 statuses 筛选与 grid/month 五键统计；业务提交 e1d0a44a 已在 origin/v2.1 可达，checkpoint 通过"
updated_at: "2026-07-28"
base: "dev-v3"
---

# Fleet：配车矩阵统一手动加急状态与统计

> **服务**：`hl-fleet-service`
> **Issue**：#5301
> **影响页面**：管理后台车务管理 → 配车矩阵
> **兼容性**：只新增可选请求参数与响应字段；路径、方法、既有字段、持久化状态不变

## 问题与目标

派车看板已经使用当前有效用车需求的 `manualUrgent` 派生人工加急，配车矩阵此前只计算临近出团与 HOLD 超时自动紧急态。同一需求因此可能在看板显示加急、矩阵仍显示普通待派/待确认，矩阵筛选和月份统计也无法精确区分人工加急。

本次后端统一矩阵全部读视图的有效状态来源，并提供稳定的人工加急字段、中文标签、精确状态筛选和五键计数。人工加急不修改落库派单状态。

## 变更接口

### `GET /admin/fleet/matrix/grid`

#### 1. 新增请求参数 `statuses`

| 参数 | 类型 | 必填 | 说明 |
|---|---|---:|---|
| `statuses` | `String[]` | 否 | 按有效状态精确筛选，多值取并集；非空且至少含一个合法值时优先于旧 `status` |

合法值：

- `unassigned`
- `unassigned_urgent`
- `holding`
- `holding_urgent`
- `assigned`
- `completed`

兼容规则：

- 旧 `status=unassigned` 继续同时包含 `unassigned` 与 `unassigned_urgent`；
- 旧 `status=assigned` 继续包含 `holding`、`holding_urgent` 与 `assigned`；
- `statuses` 全空或全非法时回退旧 `status`；
- 未传二者时保持全部展示。

请求示例：

```http
GET /admin/fleet/matrix/grid?year=2026&month=8&season=active&statuses=unassigned_urgent&statuses=holding_urgent
```

#### 2. `data.vehicles[].assignments[]` 新增字段

| 字段 | 类型 | 空值规则 | 说明 |
|---|---|---|---|
| `manualUrgent` | `Boolean` | 固定 `true/false` | 当前有效用车需求是否人工加急；order-v3 上下文整体不可用时为 `false`，不得前端猜测 |
| `assignmentStatusLabel` | `String` | 正常非空 | 后端统一有效状态中文标签，例如“待派车”“待确认”“已派车” |
| `urgentBadge` | `String` | 非紧急为空 | 人工加急固定“手动加急”；自动紧急继续返回既有 T-N/HOLD 超时文案 |

有效状态规则：

- 基础态 `unassigned` 且 `manualUrgent=true` → `assignmentStatus=unassigned_urgent`；
- 基础态 `holding` 且 `manualUrgent=true` → `assignmentStatus=holding_urgent`；
- 人工加急优先于临近出团/HOLD 超时自动派生；
- `assigned`、`completed` 不因人工加急改变；`canceled` 继续排除；
- 只消费当前有效需求上下文，旧需求派单不会继承当前需求的人工加急。

#### 3. `data.statusCounts.effectiveStatusCounts` 新增固定五键

```json
{
  "unassigned": 2,
  "unassigned_urgent": 1,
  "holding": 3,
  "holding_urgent": 1,
  "assigned": 4
}
```

- 五个键始终存在，缺类为 `0`；
- 每个活跃派车组只进入一个精确状态；
- 五键之和恒等于既有 `statusCounts.totalAssignments`；
- 既有 `unassignedAssignments`、`assignedAssignments` 和订单级统计保持兼容聚合口径，不删除、不改名。

### `GET /admin/fleet/matrix/month-counts`

每月 `statusCounts` 同样新增 `effectiveStatusCounts`：

- 固定返回 1–12 月，零值月份不省略；
- 同样固定五键；
- 与相同 `year/month/season/fleetTeamIds/typeKeys` 的 grid 顶部统计守恒；
- 年度读取仍为一次批量上下文，不循环产生 N+1。

## 前端必须调整

1. 派车条直接展示后端 `assignmentStatusLabel`；不要在前端维护第二套中文状态映射。
2. `manualUrgent=true` 且状态为 `unassigned_urgent/holding_urgent` 时，展示 `urgentBadge=手动加急`，颜色与派车看板人工加急保持一致。
3. 需要精确状态 Tab/筛选时改传 `statuses[]`；不要用旧 `status=unassigned` 期待只命中普通待派。
4. 精确分类数字使用 `statusCounts.effectiveStatusCounts`；既有全部/未派/已派聚合卡片可继续使用旧统计字段。
5. 月份切换统计直接使用 `month-counts[].statusCounts.effectiveStatusCounts`，不要前端遍历当前月卡片重算。
6. 继续保持 #5299 的实际车辆/司机/常驻标记和 Long ID 字符串处理；禁止转为 JS `Number`。

## 不影响范围

- 不修改人工加急写接口或 order-v3 需求状态。
- 不修改派单落库状态、车辆/司机占用、费用、保险、对账或常驻关系。
- 不新增 Feign、数据库查询或逐订单 N+1。
- 不修改 `hl-ui` 仓库；前端消费状态独立流转。

## 验证证据

- 后端 PR [wx/HL#5304](https://git.1814.love:8443/wx/HL/pulls/5304) 已 squash 合并至 `dev-v3`，合并提交 `ed56bec1f`。
- `hl-fleet-service` 已滚动部署测试环境，8087/8187 双实例健康。
- 定向 `MatrixServiceTest,MatrixControllerTest,BoardCandidateSourceTest`：51 tests，0 failures，0 errors，0 skipped；覆盖人工加急、自动回退、精确筛选、五键守恒、当前需求门禁与全局降级。
- Fleet reactor verify：2474 tests，0 failures，0 errors，1 skipped；Spotless 628 Java files clean。
- 真实测试网关：grid 新字段完整且 `manualUrgent` 全为非空 Boolean；五键固定且和等于 `totalAssignments`；`statuses=assigned` 在旧 `status=unassigned` 同时传入时仍只返回 assigned，证明精确筛选优先；month-counts 固定 12 月且同月五键与 grid 相等；Long ID 为字符串、手机号脱敏、全程无业务写入。
- 当前测试矩阵数据没有 `manualUrgent=true` 的活跃派车组，因此真实网关未伪报人工加急正例；正例由 Service/Controller 定向测试覆盖。
- 网关证据：`D:/work2/HL-v3/.tmp/5301-gateway.json`，SHA-256 `6ae185282e2194a63168298168888f4c03086916b7ad91268b24ac133b2b363d`。
- OpenAPI/oasdiff：项目未配置可复现 Swagger2→OAS3 与 oasdiff，状态为 `not_configured`；使用源码字段对比、Controller/Service 测试及真实网关响应作为人工回退证据。Spring Cloud Contract 为 `not_required`。

当前状态：后端已部署、网关已验证，前端消费保持 `pending`。

关联：#5301、#5299。
