# FLEET 接口契约审计修复（错误码补全 + 校验收紧 + 拉黑收口）— 修改接口 — 管理后台 / 司机端 H5

> 变更类型：⚠️ 部分行为收紧（含前端需配合的校验/调用方式变更）
> 端类型：管理后台（车务）+ 司机端 H5（OCR/入职）
> 日期：2026-06-16
> 服务：hl-fleet-service
> PR：https://git.1814.love:8443/wx/HL/pulls/3874

---

## 1. 背景

用接口契约语义审计工作流全量扫描车务（fleet）11 个 Controller，逐端点比对「Swagger `@ApiOperation` 声明的契约 ⨯ 实际实现 ⨯ 业务规则」，修复了 14 处「接口能跑但返回值/落库逻辑与契约不符」。其中**与前端对接相关**的列在下方。已部署测试服并实测通过（fleet 双实例健康、Flyway 迁移应用成功）。

绝大多数是**错误码补全**（实现真会抛、但 Swagger 之前漏列，前端按文档做错误处理时会落到「未知错误」兜底）；另有几处**校验收紧 / 调用方式变更**，前端需配合。

---

## 2. 错误码补全（前端按 Swagger 对接错误处理时请补上这些业务码）

平台 HTTP 始终 200，业务码在 `Result.code`。以下错误码实现一直会抛，本次补进 Swagger notes：

| 接口 | 方法 | 路径 | 新增错误码 | 触发场景 |
|---|---|---|---|---|
| 删除车型型号 | DELETE | `/admin/fleet/vehicle-types/models/{modelId}` | **600107** | 型号已配置价格日历，禁删（请先清价格日历） |
| 编辑司机档案 | PUT | `/admin/fleet/drivers/{driverId}` | **600209** | 关联的保游网保单不存在/不属于该司机/状态不可关联 |
| 审核通过 | POST | `/admin/fleet/drivers/pending/{pendingId}/approve` | **605022** / **600404** / **600203** | 自带车常驻司机已被别车占用 / 续签目标司机为黑名单 / 续签改号撞他人手机号 |
| 批量改价格日历状态 | PUT | `/admin/fleet/pricing-calendar/{vehicleModelId}/status` | **600501** / **600502** | 日期范围非法 / 范围超 366 天 |
| 清除价格日历 | DELETE | `/admin/fleet/pricing-calendar/{vehicleModelId}` | **600502** | 范围超 366 天 |
| 司机险退保 | POST | `/admin/fleet/drivers/{driverId}/insurance/policies/{insuranceOrderId}/cancel` | **540224** | 手工录入的司机年保单禁退保，请在司机档案维护 |
| OCR 识别（H5） | POST | `/app/h5/driver-onboard/ocr/{step}` | **600303** / 600305 / 600306 / 600312 / 600313 | step 非法或证件识别失败 / 身份证 / 驾驶证 / 行驶证 识别失败 / 服务未就绪 |

> ⚠️ OCR 端点修正：原 Swagger 写「step 非法返回 **400**」是错的——实际返业务码 **600303**（HTTP 仍 200）。前端请按 `Result.code===600303` 判断，不要按 HTTP 400。

---

## 3. 行为变更（前端需配合）

### 3.1 编辑车型大类：typeKey 可不传（放宽，兼容性变更）

`PUT /admin/fleet/vehicle-types/{typeId}` 过去若不传 `typeKey` 会被必填校验打回 400；现已修正为**编辑时 typeKey 可不传（后端本就忽略不更新）**。前端编辑表单**不必再为过校验塞一个占位 typeKey**。新增（POST）仍必填 typeKey，不变。

### 3.2 车辆占用态 vehicleStatus：仅 maint 可人工设（收紧）

`POST/PUT /admin/fleet/vehicles` 的 `vehicleStatus` 过去前端可任意写 idle/busy/maint。占用态 `busy`/`idle` 是「按派单反算的缓存值」，**不允许前端手动设**。新规则：

| 操作 | 允许 | 拒绝（返 **600112** 占用态非法转移） |
|---|---|---|
| 新增 | 不传 / `idle` / `maint` | `busy` |
| 编辑 | 不传（保持原值）/ `idle↔maint`（送修、修好） | 设 `busy`；在用车(busy)被人工改 |

前端车辆表单：**只保留「送修(maint)/恢复(idle)」操作，去掉手动设 busy**；非法转移会收到 `600112`。

### 3.3 司机拉黑：收口到专用端点（收紧，调用方式变更）

`PUT /admin/fleet/drivers/{driverId}`（通用编辑）**不再支持** `season: active→blacklist`，传了会返 **100001**（赛季转移非法）。**拉黑必须走专用端点** `POST /admin/fleet/drivers/{driverId}/blacklist`（与解封走 `POST /unban` 同口径，二者均有幂等/锁保护）。前端拉黑入口请改调专用端点。

---

## 4. 其它

### 4.1 已发放链接导出 CSV：审核状态列中文化

`GET /admin/fleet/h5/tokens/export` 导出的 CSV「审核状态」列由英文码（pending/approved/rejected）改为中文（待审核/已通过/已驳回），与同表「类型」「状态」列一致。前端基本无感（导出文件给人看）。

### 4.2 生成入职链接：请前端做按钮防抖（无后端拦截）

`POST /admin/fleet/h5/token`（生成 token）**未加后端幂等**（因幂等键无法区分「双击」与「作废后合法重新生成/同司机多次邀请」）。**请前端在提交时做按钮 disable / loading 防抖**，避免车管双击落两条 pending 记录。

---

## 5. 前端 Action 清单

1. 补充第 2 节各端点的错误码文案/分支处理（尤其 OCR 的 `600303` 按业务码而非 HTTP 400 判断）。
2. 编辑车型大类表单：可不传 typeKey（去掉占位逻辑）。
3. 车辆表单：vehicleStatus 只保留「送修/恢复」(idle↔maint)，去掉手动设 busy。
4. 司机拉黑入口：改调专用端点 `POST /drivers/{driverId}/blacklist`，通用编辑不要再传 `season=blacklist`。
5. 生成入职链接按钮：加防抖。

---

## 6. 关联

| 项目 | 信息 |
|---|---|
| PR | https://git.1814.love:8443/wx/HL/pulls/3874（squash 合并 dev-v3，via api-contract-audit workflow） |
| 部署 | 已部署测试服并实测：fleet 4 端点网关 9443 + admin token 返 code:200；CSV 审核状态列实测为中文；Flyway V20260616_004（group_dispatch 软删唯一键加固）真库应用成功 |
| 本地测试 | mvn test 全绿（803 tests，含集成测试 H2 全链路） |
| 后端负责人 | wx |
