diff --git a/changelogs-v2/2026-06/15_司机自助录入H5契约逐字核对-字段名权威清单-司机H5.md b/changelogs-v2/2026-06/15_司机自助录入H5契约逐字核对-字段名权威清单-司机H5.md new file mode 100644 index 0000000..8f7d9bd --- /dev/null +++ b/changelogs-v2/2026-06/15_司机自助录入H5契约逐字核对-字段名权威清单-司机H5.md @@ -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\ | 车外观照片 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)。