docs(前端通知): 司机自助录入H5契约逐字核对——字段名权威清单(submit/new+renew+OCR+init)

前端反馈选填字段名是推断的,请后端拿真实VO逐字核对。本文以dev-v3代码实物为准:
- 纠正VO类名: OcrRespVO实为OcrResultVO, InitRespVO实为H5InitRespVO
- 驾龄字段是drivingYears(非years)
- 标出准驾车型写读不一致: submit/OCR用licenseClass, init预填用licenseType
- 逐字列出 submit/new(含vehicle/emergency嵌套块)/submit/renew/ocr-{step}/init(含renew预填)全字段
后端零改动,纯契约核对回执。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
这个提交包含在:
API Changelog Bot 2026-06-15 15:59:04 +08:00
父节点 489ef6f535
当前提交 cf3c1bc722

查看文件

@ -0,0 +1,192 @@
# 【契约核对·司机 H5】司机自助录入新招/续签/OCR/init字段名权威清单 — 逐字核对回执
> 端:司机 H5自助录入| 服务hl-fleet-service `com.hulalv.fleet.h5` | 后端**零改动**(仅核对回执)| 2026-06-15
>
> 起因:前端反馈「硬必填字段已确定不会 400,但选填字段名是推断的」,请后端拿真实 VO 逐字核对。本文以**当前 dev-v3 代码实物**为准(非文档推断),逐项确认/纠正下列 5 个待核项。
## ⚠️ 关键说明(先看这 3 条,最容易踩)
1. **VO 类名两处纠正**:前端用的 `OcrRespVO` 实际叫 **`OcrResultVO`**;`InitRespVO` 实际叫 **`H5InitRespVO`**。`SubmitNewReqVO` / `SubmitRenewReqVO` 名字正确。
2. **驾龄字段是 `drivingYears`Integer,不是 `years`**
3. **🔴 准驾车型字段名「写读不一致」(后端真实如此,前端必须分别对待)**
- **提交**submit/new**OCR 返回**OcrResultVO里叫 **`licenseClass`**;
- **续签预填**init 的 prefill里叫 **`licenseType`**。
- 即:续签场景前端读 `prefill.licenseType` 回显,但若进 submit 入参得用 `licenseClass` 字段名。这是两个不同 VO、历史命名差异,后端本次不动动它要前后端联调,且你们已在按它编码。续签提交本身**不收准驾车型**(见 §3,所以实际只影响「续签页准驾车型回显读 `licenseType`」一处。
---
## 1. submit/new 新招提交 — `POST /app/h5/driver-onboard/submit/new`
入参 `SubmitNewReqVO``@RequestBody`,application/json。**硬必填只有 2 个**`token``licenseNo`;**其余全选填**(不传不会 400
### 1.1 顶层字段(逐字)
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token` | String | ✅ @NotBlank | H5 邀请凭证URL 透传) |
| `name` | String | 选填 | 姓名 |
| `phone` | String | 选填 | 手机号 11 位 |
| `gender` | String | 选填 | **性别编码字符串**`1`=男 / `2`=女 / `0`=未知(取值来自字典 gender,提交时字典校验,非法报 **100001** |
| `nation` | String | 选填 | 民族 |
| `drivingYears` | Integer | 选填 | **驾龄(年)— 注意不是 `years`** |
| `idCard` | String | 选填 | 身份证号 18 位 |
| `idCardFrontUrl` | String | 选填 | 身份证正面 OSS URL |
| `idCardBackUrl` | String | 选填 | 身份证背面 OSS URL ← **前端推断的名字正确** |
| `licenseNo` | String | ✅ @NotBlank | 驾照号(#3781 与表单创建口径对齐,缺失返 400 |
| `licenseClass` | String | 选填 | 准驾车型 A1/A2/B1/B2 等 |
| `licenseExpire` | String(date) | 选填 | 驾照有效期 `yyyy-MM-dd`LocalDate |
| `licenseFrontUrl` | String | 选填 | 驾照正页 OSS URL |
| `licenseBackUrl` | String | 选填 | 驾照副页 OSS URL ← **前端推断的名字正确** |
| `hasOwnVehicle` | Boolean | 选填 | 是否自带车 |
| `vehicle` | object | 选填 | 自带车信息hasOwnVehicle=true 时填,见 §1.2 |
| `preferredCategory` | String | 选填 | 常开大类 key如 suv/mpv/bus,取自 init 的 `vehicleTypeOptions[].typeKey` |
| `preferredModel` | String | 选填 | 常开型号(取自 `vehicleTypeOptions[].models[].modelName` |
| `vehicleSource` | String | 选填 | 车源:仅 `own` / `company`@Pattern,其它值 400 |
| `vehicleNotes` | String | 选填 | 备注 |
| `emergency` | object | 选填 | 紧急联系人嵌套块(见 §1.3 |
| `portraitUrl` | String | 选填 | 本人正脸照 OSS URL头像 |
### 1.2 `vehicle` 嵌套块(`SubmitVehicleVO`
| 字段名 | 类型 | 说明 |
|---|---|---|
| `plate` | String | 车牌号 |
| `model` | String | 车型名称 |
| `seats` | Integer | 核定座位数(含驾驶员) |
| `annualInspectDate` | String(date) | 下次年检日期 `yyyy-MM-dd` |
| `regFrontUrl` | String | **行驶证**正面 OSS URL注意是 `reg` 不是 license |
| `regBackUrl` | String | **行驶证**副页 OSS URL |
| `exteriorUrls` | List\<String\> | 车外观照片 URL 列表 |
| `interiorUrls` | List\<String\> | 车内饰照片 URL 列表 |
### 1.3 `emergency` 嵌套块(`SubmitEmergencyVO`
| 字段名 | 类型 | 说明 |
|---|---|---|
| `name` | String | 紧急联系人姓名 |
| `phone` | String | 紧急联系人手机号 11 位 |
| `relation` | String | 与司机的关系(如「父亲」,自由文本) |
### 1.4 返回 `SubmitRespVO`
```json
{ "pendingId": "1234567890123456789", "estimatedReviewHours": 24, "season": null }
```
- `pendingId`:雪花 ID,**字符串格式**(已 ToStringSerializer,按字符串收`estimatedReviewHours`:新招=24;`season`:新招恒为 null。
- 错误码400 参数校验 / **600300** token 无效 / **600301** token 已过期 / **600302** token 已使用 / **600200** 身份证已存在。
---
## 2. OCR 识别 — `POST /app/h5/driver-onboard/ocr/{step}`
### 2.1 step 步骤标识(路径参数,仅这 3 个合法值,其它返 400
| step 值 | 用途 | 驾照即 §前端问的「ocr/license」 |
|---|---|---|
| `id-card` | 身份证 | |
| `license` | **驾照 ← 前端用的 `ocr/license` 路径正确** | ✅ |
| `reg-cert` | 行驶证 | |
### 2.2 入参multipart/form-data,不是 JSON
| 参数 | 必填 | 说明 |
|---|---|---|
| `token` | ✅ | form 参数 |
| `file` | ✅ | 图片文件,仅图片类型 ≤10MB违反报 **100001** |
| `side` | 选填 | `front` / `back`,默认 `front` |
### 2.3 返回 `OcrResultVO`(统一 VO,按 step 填对应字段,其余为 null
| step | 该步会填的字段 |
|---|---|
| `id-card` | `name` / `idCard` / `gender`(1=男/2=女) / `nation` / `issuedBy`(签发机关) |
| `license` | `licenseNo` / `licenseClass` / `licenseExpire`(`yyyy-MM-dd`) |
| `reg-cert` | `plate` / `model` / `seats`(Integer) / `annualInspectDate`(`yyyy-MM-dd`) |
> 注意①OCR 驾照返回的是 **`licenseClass`**(与 submit 一致,非 prefill 的 licenseType
> 注意②:**当前 OCR 是 stub**`OcrStubService` 返回固定假数据,工单 #2797 真实 OCR 未接);字段名/契约已稳定,可照此编码,但识别值现在是假的。
> 错误码400 step 非法 / **100001** 文件空/非图片/超 10MB / **600300** token 无效 / **600301** token 已过期。
---
## 3. submit/renew 续签提交 — `POST /app/h5/driver-onboard/submit/renew`
入参 `SubmitRenewReqVO`。**只填变更项**。
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token` | String | ✅ @NotBlank | H5 邀请凭证 |
| `continueSeason` | **Boolean** | ✅ @NotNull | **是否继续合作:`true`=继续 / `false`=今年休息 ← 前端按 boolean 传,正确** |
| `phoneChanged` | Boolean | 选填 | 手机号是否已变更 |
| `phone` | String | 选填 | 新手机号phoneChanged=true 时填) |
| `primaryVehiclePlateChanged` | Boolean | 选填 | 常驻车是否已变更 |
| `primaryVehiclePlate` | String | 选填 | 新常驻车牌…Changed=true 时填) |
| `licenseRenewed` | Boolean | 选填 | 驾照是否已续期 |
| `licenseExpire` | String(date) | 选填 | 新驾照有效期 `yyyy-MM-dd`licenseRenewed=true 时填) |
| `licenseFrontUrl` | String | 选填 | 新驾照正页 URL |
| `licenseBackUrl` | String | 选填 | 新驾照副页 URL |
- 续签**不收准驾车型**字段(无 licenseClass/licenseType 入参),所以 §0 那条不一致只影响「预填回显」不影响续签提交。
- 返回 `SubmitRespVO``{ pendingId, estimatedReviewHours: 12, season: "pending" }`
- 错误码400 / **600300** / **600301** / **600302**
---
## 4. init 初始化(含续签预填档案结构)— `GET /app/h5/driver-onboard/init?token={token}`
返回 `H5InitRespVO`(前端用名 `InitRespVO`,真实类名 `H5InitRespVO`)。
### 4.1 顶层字段
| 字段名 | 类型 | 说明 |
|---|---|---|
| `mode` | String | `new`=新招 / `renew`=续签(决定走 8 步还是 4 步) |
| `tokenValid` | Boolean | =`tokenState∈{fresh,editable,rejected_editable}`;false 时按 tokenState 渲染失效文案 |
| `tokenState` | String | 7 态:`fresh` / `editable` / `rejected_editable` / `expired` / `voided` / `consumed` / `invalid` |
| `reviewStatus` | String | `pending` / `approved` / `rejected`token 不存在时 null |
| `rejectReason` | String | 驳回原因(仅 rejected 相关态有值) |
| `lastSubmittedAt` | String(datetime) | 上次提交时间(未提交过 null |
| `expireAt` | String(datetime) | token 过期时间 |
| `stepConfig` | object | `{ totalSteps: new=8/renew=4, stepNames: [...] }` |
| `prefill` | object | **续签预填档案(仅 mode=renew 有值,新招 null见 §4.2** |
| `vehicleTypeOptions` | List\<object\> | 常开车型字典(**仅 mode=new 且 token 可编辑**,renew 为 null;第 5 步「常开车型」唯一合法数据源 |
### 4.2 `prefill` 续签预填结构(`RenewPrefillVO`)← 前端待核项「续签 init 预填档案结构」
| 字段名 | 类型 | 说明 |
|---|---|---|
| `name` | String | 司机姓名 |
| `phone` | String | 手机号**脱敏展示**`138****1234`,仅展示,提交变更走 §3 的 phone |
| `primaryVehiclePlate` | String | 常驻车车牌 |
| `licenseNo` | String | 驾照号**脱敏展示**`150102******1234` |
| `licenseType` | String | **准驾车型 ← 注意此处字段名是 `licenseType`,不是 licenseClass见 §0 关键说明 3** |
| `licenseExpire` | String(date) | 驾照有效期 `yyyy-MM-dd` |
| `licenseDaysLeft` | Long | 驾照距到期天数(前端展示续期提醒用) |
| `activeYears` | List\<Integer\> | 历次在册年份列表,如 `[2023,2024,2025]` |
### 4.3 `vehicleTypeOptions` 结构(仅新招用,`VehicleTypeOptionVO`
```
[{ typeKey, typeName, icon, models: [{ modelName, seats }] }]
```
- 严禁带价格basePrice 物理上不在该 VO,司机端不透出基准价;前端禁写死内置 typeKey运营动态字典
---
## 5. 图片上传补充(前端可能也要)— `POST /app/h5/driver-onboard/upload`
multipart`token`(必填) / `file`(图片≤10MB) / `groupKey`(可选,默认 fleet-driver);返回 `UploadRespVO` = `{ "url": "OSS公开URL" }`。所有 *Url 字段idCardFrontUrl/licenseFrontUrl/portraitUrl/vehicle.regFrontUrl…都回填这个 url。
---
## 核对结论汇总(对应前端 5 个待核项)
| 前端待核项 | 结论 |
|---|---|
| ① submit/new 选填字段名drivingYears vs years、紧急联系人块 | 是 **`drivingYears`**;紧急联系人块字段名 `emergency.{name,phone,relation}`,全部按 §1.1/§1.3 |
| ② 照片 idCardBackUrl/licenseBackUrl | **推断正确**;另注意自带车行驶证是 `vehicle.regFrontUrl/regBackUrl`reg 非 license |
| ③ submit/renew continueSeason 类型 | **Boolean,正确**@NotNull 必填) |
| ④ OCR ocr/license 步骤标识及返回字段名 | step=**`license`** 正确;返回字段见 §2.3(驾照填 licenseNo/licenseClass/licenseExpire;类名是 **OcrResultVO** |
| ⑤ 续签 init 预填档案结构 | 见 §4.2;**唯一坑:准驾车型在 prefill 里叫 `licenseType`** |
> 后端本次零代码改动;以上为 dev-v3 当前代码实物核对。若真机测试某选填项「没落库」,优先核对字段名是否与本清单一致(尤其 drivingYears、vehicle 内 reg* 命名、prefill.licenseType