# 【契约核对·司机 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\ | 车外观照片 URL 列表 | | `interiorUrls` | List\ | 车内饰照片 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\ | 常开车型字典(**仅 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\ | 历次在册年份列表,如 `[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)。