# 【修改接口·管理后台】司机档案 6 接口(详情新增 relatedOrders mock 字段 + 全模块快照) > **PR**: #2796(详情加 relatedOrders mock 字段) | **服务**: hl-fleet-service | **更新时间**: 2026-05-21 > > **存放目录**: `changelogs-v2/2026-05/` > **影响范围**: 管理后台「车管 / 司机档案」页(列表 + 详情 + 新增 + 编辑 + 软删 + Excel 批量导入) --- ## ⚠️ 关键变化 | # | 接口 | 状态 | 说明 | |---|---|---|---| | §3.2 | GET `/admin/fleet/drivers/{driverId}` | **🔧 修改** | 响应**新增 `relatedOrders` 字段**(mock 占位,固定 3 条假数据) | | 其余 5 接口 | — | 首推 | 契约自模块首次落地(PR #2724)以来未变化,本次首推完整 changelog | > **`relatedOrders` 字段是 mock**!固定返回 3 条假数据,所有司机返回相同内容。前端可基于字段做 UI 但**不要硬编码业务逻辑**(如"看到张总订单 = 司机已派单")。详见 §3.2 + §9 + §12。 --- ## 1. 接口背景 司机档案是车队所有司机的主数据:基本信息 / 驾照 / 紧急联系人 / 保险 / 历史统计 / 标签 / 多类目附件(身份证/驾驶证/肖像/健康证/培训证/荣誉/从业资格/其他 8 类)。 PR #2796 在司机详情 §3.2 响应里加了 `relatedOrders` 字段,让前端可以提前对接「司机详情 → 关联订单列表」的 UI 区块。但由于派车模块(订单 ↔ 司机关联)尚未对接到 fleet 服务,**当前返回固定 3 条 mock 假数据**,待后续真实化(详见 #2791)。 --- ## 2. 变更清单 | # | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|----------|------| | 1 | GET | `/admin/fleet/drivers/page` | 首推 | 分页列表 | | 2 | GET | `/admin/fleet/drivers/{driverId}` | **修改** | 详情,**新增 `relatedOrders` mock 字段** | | 3 | POST | `/admin/fleet/drivers` | 首推 | 新增(含标签 + 附件批量提交) | | 4 | PUT | `/admin/fleet/drivers/{driverId}` | 首推 | 编辑(attachments diff + tags 全量覆盖) | | 5 | DELETE | `/admin/fleet/drivers/{driverId}` | 首推 | 软删 | | 6 | POST | `/admin/fleet/drivers/import` | 首推 | Excel 批量导入(按身份证去重) | --- ## 3. 接口详情 ### 3.1 分页查询 **GET** `/admin/fleet/drivers/page` - **使用场景**:司机档案列表页,支持「2026 年赛季在册 / 续费待回复 / 往年档案 / 黑名单 / 全部」5 个 tab 切换(前端按 `season` 字段传值) - **认证**:管理后台 JWT - **幂等**:是 **Query 入参**: | 字段 | 类型 | 必填 | 默认 | 校验 | 说明 | |---|---|---|---|---|---| | `page` | int | ❌ | 1 | `>= 1` | 页码 | | `pageSize` | int | ❌ | 20 | `1-100` | 每页条数 | | `keyword` | string | ❌ | — | — | 姓名模糊匹配 | | `driverStatus` | string | ❌ | — | `idle/busy/rest/pending` | 状态精确(见 §6.2) | | `season` | string | ❌ | — | `active/pending/archived/blacklist` | 赛季精确(见 §6.3,对应前端 5 tab) | | `tagName` | string | ❌ | — | — | 标签名精确(拥有该标签的司机) | | `primaryVehiclePlate` | string | ❌ | — | — | 常驻车车牌精确匹配 | | `insuranceType` | string | ❌ | — | `annual/perTrip/none` | 保险类型精确(见 §6.4) | **出参**:`Result>` (phone/idCard 脱敏;列表项含 tags,**不含**附件详情) | 字段 | 类型 | 说明 | |---|---|---| | `records[].id` | string | 司机 ID | | `records[].name` | string | 姓名 | | `records[].phone` | string | 手机号(脱敏,如 `138****1234`) | | `records[].idCard` | string | 身份证号(脱敏,如 `150102******1234`) | | `records[].gender` | string | 性别 | | `records[].years` | int | 驾龄 | | `records[].driverStatus` | string | 状态(见 §6.2) | | `records[].season` | string | 赛季(见 §6.3) | | `records[].primaryVehiclePlate` | string | 常驻车车牌 | | `records[].insuranceType` | string | 保险类型(见 §6.4) | | `records[].tags[]` | array | 标签列表 | | `records[].createTime` | datetime | — | | `total` / `page` / `pageSize` | int | 分页元数据 | **典型示例 请求**(5 tab 之一:在册): ``` GET /admin/fleet/drivers/page?page=1&pageSize=20&season=active Authorization: Bearer (无请求体) ``` **典型示例 响应**: ```json { "code": 200, "data": { "records": [ { "id": "1234567890123456789", "name": "张三", "phone": "138****1234", "idCard": "150102******1234", "gender": "男", "years": 8, "driverStatus": "idle", "season": "active", "primaryVehiclePlate": "蒙A-88888", "insuranceType": "annual", "tags": ["老司机", "蒙语流利"], "createTime": "2025-05-21 14:00:00" } ], "total": 1, "page": 1, "pageSize": 20 }, "msg": "成功" } ``` **前端 tab → season 取值映射**: | 前端 tab | 后端参数 | |---|---| | 全部 | (不传 season) | | 2026 年赛季在册 | `season=active` | | 续费待回复 | `season=pending` | | 往年档案 | `season=archived` | | 黑名单 | `season=blacklist` | > "2026 年"是装饰文案(取自前端业务文案约定),后端 `season` 字段不带年份维度。 **错误码**:400 参数校验 / 401 未登录 --- ### 3.2 详情 🔧 修改(新增 `relatedOrders` mock 字段) **GET** `/admin/fleet/drivers/{driverId}` - **使用场景**:详情页 / 编辑前预填 - **认证**:管理后台 JWT - **幂等**:是 **路径入参**: | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `driverId` | Long | ✅ | 司机 ID | **出参**:`Result` 主体字段(含 §3.1 全部字段)+ 以下扩展: | 字段 | 类型 | 说明 | |---|---|---| | `nation` | string | 民族 | | `preferredTypeKey` | string | 常开车型大类 key | | `preferredModel` | string | 常开车型名 | | `vehicleSource` | string | 车源(own/company) | | `activeYearsJson` | string | 历次在册年份 JSON 数组字符串(如 `"[2023,2024,2025]"`) | | `license` | object | 驾照信息(见下) | | `emergency` | object | 紧急联系人(见下) | | `insurance` | object | 保险信息(见下) | | `stats` | object | 历史统计(见下) | | `tags[]` | array | 标签列表 | | `attachments` | object | 附件按类目分组(key=category,value=该类目附件列表) | | **`relatedOrders[]`** | **array** | **关联订单(mock 占位,固定 3 条,详见警示)** | | `createTime` / `updateTime` | datetime | — | **`license`**(`DriverLicenseVO`,DB 字段平铺,API 嵌套返回): | 字段 | 类型 | 说明 | |---|---|---| | `no` | string | 驾照号 | | `type` | string | 准驾车型(A1/A2/B1/B2 等) | | `expire` | date | 有效期 | | `issuedBy` | string | 发证机关 | **`emergency`**(`DriverEmergencyVO`): | 字段 | 类型 | 说明 | |---|---|---| | `name` | string | 紧急联系人姓名 | | `phone` | string | 手机号 | | `relation` | string | 关系(父亲 / 妻子 等) | **`insurance`**(`DriverInsuranceVO`): | 字段 | 类型 | 说明 | |---|---|---| | `type` | string | 保险类型(见 §6.4) | | `company` | string | 保险公司(annual 必填) | | `policyNo` | string | 年保单号(annual 必填) | | `annualPremium` | string | 年保险费(BigDecimal 序列化) | | `annualStart` | date | 年保险起始日 | | `annualEnd` | date | 年保险结束日 | | `perDayRate` | string | 行程保险日费率(perTrip 必填) | **`stats`**(`DriverStatsVO`,详情专用): | 字段 | 类型 | 说明 | |---|---|---| | `totalOrders` | int | 历史接单总数 | | `avgRating` | string | 平均评分 0-5(BigDecimal 序列化) | | `lastOrderAt` | date | 最近接单日期 | **`attachments`**:`Map>`,key=类目(见 §6.1),value=该类目下的附件列表(按 sortNo 升序): | 字段 | 类型 | 说明 | |---|---|---| | `id` | string | 附件 ID | | `driverId` | string | 所属司机 ID | | `category` | string | 类目(见 §6.1) | | `sortNo` | int | 同类目排序(0-based) | | `url` | string | OSS URL | | `mimeType` | string | 例 `image/jpeg` | **`relatedOrders[]`**(**⚠️ mock 占位**): | 字段 | 类型 | 说明 | |---|---|---| | `orderId` | string | 订单 ID(前端跳转用) | | `orderNo` | string | 订单号(如 `HL2026060100123`) | | `groupNo` | string | 团号(如 `T2026-001`) | | `customerName` | string | 客户姓名 | | `tripStartDate` | date | 行程起始日 | | `tripEndDate` | date | 行程结束日 | | `destination` | string | 目的地概要 | | `orderStatus` | string | 订单状态(`pending` / `in_progress` / `completed`) | | `vehicleType` | string | 车型快照 | | `licensePlate` | string | 车牌快照 | > **mock 真相**(来自代码 `DriverService.buildMockRelatedOrders()`): > - 当前**固定返回 3 条假数据**(李先生 in_progress / 王女士 completed / 张总 pending) > - 所有 driverId 返回的内容**完全相同** > - 真实化时机:派车模块对接 fleet 服务后,由 DriverService 改为 Feign 调 order 服务按 staffId 反查(Issue #2791) **典型示例 响应**(节选): ```json { "code": 200, "data": { "id": "1234567890123456789", "name": "张三", "phone": "138****1234", "idCard": "150102******1234", "gender": "男", "nation": "蒙古族", "years": 8, "driverStatus": "idle", "season": "active", "activeYearsJson": "[2023,2024,2025]", "primaryVehiclePlate": "蒙A-88888", "preferredTypeKey": "suv", "preferredModel": "丰田汉兰达", "vehicleSource": "company", "license": { "no": "15010219800101XXXX", "type": "B2", "expire": "2030-01-01", "issuedBy": "内蒙古公安厅交通管理局" }, "emergency": { "name": "张三丰", "phone": "13800000000", "relation": "妻子" }, "insurance": { "type": "annual", "company": "中国人保财险", "policyNo": "PICC-2024-XXX", "annualPremium": "3000.00", "annualStart": "2024-01-01", "annualEnd": "2025-01-01", "perDayRate": null }, "stats": { "totalOrders": 128, "avgRating": "4.85", "lastOrderAt": "2025-05-18" }, "tags": ["老司机", "蒙语流利"], "attachments": { "id_card": [ { "id": "...", "driverId": "...", "category": "id_card", "sortNo": 0, "url": "https://oss/.../front.jpg", "mimeType": "image/jpeg" }, { "id": "...", "driverId": "...", "category": "id_card", "sortNo": 1, "url": "https://oss/.../back.jpg", "mimeType": "image/jpeg" } ], "driver_license": [...], "portrait": [...] }, "relatedOrders": [ { "orderId": "900000000000000001", "orderNo": "HL2026060100123", "groupNo": "T2026-001", "customerName": "李先生", "tripStartDate": "2026-06-01", "tripEndDate": "2026-06-05", "destination": "呼伦贝尔草原 / 阿尔山 / 海拉尔", "orderStatus": "in_progress", "vehicleType": "丰田汉兰达", "licensePlate": "蒙A-12345" }, { "orderId": "900000000000000002", "orderNo": "HL2026051800456", "groupNo": "T2026-002", "customerName": "王女士", "tripStartDate": "2026-05-18", "tripEndDate": "2026-05-22", "destination": "额尔古纳 / 室韦 / 莫尔道嘎", "orderStatus": "completed", "vehicleType": "丰田考斯特", "licensePlate": "蒙A-66666" }, { "orderId": "900000000000000003", "orderNo": "HL2026070200789", "groupNo": "T2026-003", "customerName": "张总", "tripStartDate": "2026-07-02", "tripEndDate": "2026-07-08", "destination": "满洲里 / 套娃景区 / 国门", "orderStatus": "pending", "vehicleType": "奔驰威霆", "licensePlate": "蒙A-88888" } ], "createTime": "2025-05-21 14:00:00", "updateTime": "2025-05-21 14:00:00" }, "msg": "成功" } ``` **错误码**:**600205** 司机不存在 / 401 未登录 --- ### 3.3 新增 **POST** `/admin/fleet/drivers` - **使用场景**:新增司机(含 tags 批量 + 附件批量提交,**同一事务**) - **认证**:管理后台 JWT - **幂等**:否(身份证 / 手机号重复抛 600200 / 600203) **Body 入参**(`DriverSaveReqVO`): | 字段 | 类型 | 必填 | 校验 | 说明 | |---|---|---|---|---| | `name` | string | ✅ | `@Size(max=32)` | 姓名 | | `phone` | string | ✅ | `@Pattern(^\d{11}$)` | 手机号 11 位(**编辑时忽略**) | | `idCard` | string | ✅ | `@Size(min=18,max=32)` | 身份证号(**编辑时忽略**) | | `gender` | string | ❌ | `@Size(max=4)` | 性别(男 / 女) | | `nation` | string | ❌ | `@Size(max=16)` | 民族 | | `years` | int | ❌ | — | 驾龄(年) | | `driverStatus` | string | ❌ | `@Pattern(idle\|busy\|rest\|pending)` | 状态 | | `season` | string | ❌ | `@Pattern(active\|pending\|archived\|blacklist)` | 赛季 | | `primaryVehiclePlate` | string | ❌ | `@Size(max=16)` | 常驻车车牌 | | `preferredTypeKey` | string | ❌ | `@Size(max=16)` | 常开车型大类 key | | `preferredModel` | string | ❌ | `@Size(max=64)` | 常开车型名 | | `vehicleSource` | string | ❌ | `@Size(max=16)` | 车源(own / company) | | `license` | object | ❌ | — | 驾照嵌套对象(同 §3.2) | | `emergency` | object | ❌ | — | 紧急联系人嵌套对象(同 §3.2) | | `insurance` | object | ❌ | — | 保险嵌套对象(同 §3.2) | | `tags[]` | array | ❌ | `@Size(max=20)` | 标签列表(**全量覆盖**) | | `attachments[]` | array | ❌ | — | 附件数组(见 §3.3 attachment 表) | **`attachments[]` 单项**(`DriverAttachmentReqVO`): | 字段 | 类型 | 必填 | 校验 | 说明 | |---|---|---|---|---| | `id` | Long | ❌ | — | 新增项不传 | | `category` | string | ✅ | `@Size(max=32)` | 类目(见 §6.1) | | `url` | string | ✅ | `@Size(max=512)` | OSS URL | | `mimeType` | string | ✅ | `@Size(max=64)` | 例 `image/jpeg` | | `sortNo` | int | ❌ | — | 不传时按入参顺序自动重写 0..N-1 | **出参**:`Result` | 字段 | 类型 | 说明 | |---|---|---| | `id` | string | 新增司机 ID | | `attachmentIds[]` | array | 附件 ID 列表(按入参顺序) | **典型示例 请求**(节选): ``` POST /admin/fleet/drivers Authorization: Bearer Content-Type: application/json { "name": "张三", "phone": "13812341234", "idCard": "150102198001011234", "gender": "男", "nation": "蒙古族", "years": 8, "driverStatus": "idle", "season": "active", "primaryVehiclePlate": "蒙A-88888", "preferredTypeKey": "suv", "preferredModel": "丰田汉兰达", "vehicleSource": "company", "license": { "no": "15010219800101XXXX", "type": "B2", "expire": "2030-01-01", "issuedBy": "内蒙古公安厅交通管理局" }, "emergency": { "name": "张三丰", "phone": "13800000000", "relation": "妻子" }, "insurance": { "type": "annual", "company": "中国人保财险", "policyNo": "PICC-2024-XXX", "annualPremium": "3000.00", "annualStart": "2024-01-01", "annualEnd": "2025-01-01" }, "tags": ["老司机", "蒙语流利"], "attachments": [ { "category": "id_card", "url": "https://oss/.../id-front.jpg", "mimeType": "image/jpeg" }, { "category": "id_card", "url": "https://oss/.../id-back.jpg", "mimeType": "image/jpeg" }, { "category": "driver_license", "url": "https://oss/.../license.jpg", "mimeType": "image/jpeg" }, { "category": "portrait", "url": "https://oss/.../portrait.jpg", "mimeType": "image/jpeg" } ] } ``` **异常 请求**(身份证重复): ```json { "code": 600200, "msg": "身份证已存在", "data": null } ``` **异常 请求**(驾照过期): ```json { "code": 600201, "msg": "驾照已过期", "data": null } ``` **错误码**:400 参数校验 / **600200** 身份证已存在 / **600201** 驾照已过期 / **600203** 手机号已存在 / **601002** 附件类目非法 / **601003** 类目张数达上限 / 401 未登录 --- ### 3.4 编辑(attachments diff + tags 全量覆盖) **PUT** `/admin/fleet/drivers/{driverId}` - **使用场景**:编辑司机基本信息 + 标签全量覆盖 + 附件增删改一次性提交 - **认证**:管理后台 JWT - **幂等**:是 **路径入参**: | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `driverId` | Long | ✅ | 司机 ID | **Body 入参**:同 §3.3(共用 `DriverSaveReqVO`),但: - **`idCard` / `phone` 后端忽略**(不可改) - **`tags[]` 全量覆盖**:物理删除旧 tags + 批量 INSERT 新 tags(空数组 = 清空所有标签) - **`attachments[]` diff 语义**:有 id 命中 → 保留;无 id → INSERT;DB 有但未传 → 软删 **附件 diff 语义**(与车辆档案 §3.4 一致): | 入参 attachments[] 项 | DB 中的对应行 | 行为 | |---|---|---| | 有 `id` + DB 命中 | 存在 | 保留(可更新 sortNo) | | 无 `id`(新增项) | — | INSERT | | — | 存在但本次未传 | 软删 | > **特别说明(前 3 类目"换证留历史"语义)**:`id_card` / `driver_license` / `portrait` 旧附件不在本次入参里 → 自动软删;新 url 无 id → INSERT。前端"换证"时不需要先调删除接口,直接组装新 attachments 数组即可。 **出参**:`Result` | 字段 | 类型 | 说明 | |---|---|---| | `kept` | int | 保留的附件数 | | `inserted` | int | 新插入的附件数 | | `softDeleted` | int | 软删的附件数 | | `tagsReplaced` | int | 覆盖写入的标签数 | **典型示例 响应**: ```json { "code": 200, "data": { "kept": 3, "inserted": 1, "softDeleted": 2, "tagsReplaced": 3 }, "msg": "成功" } ``` **错误码**:400 参数校验 / **600201** 驾照已过期 / **600205** 司机不存在 / **601002** 类目非法 / **601003** 类目张数达上限 / 401 未登录 --- ### 3.5 软删 **DELETE** `/admin/fleet/drivers/{driverId}` - **使用场景**:下架司机 - **认证**:管理后台 JWT - **幂等**:是 **路径入参**: | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `driverId` | Long | ✅ | 司机 ID | **出参**:`Result` **典型示例 响应**: ```json { "code": 200, "data": null, "msg": "成功" } ``` **异常 请求**(**业务流水 PR 上线后才生效**): ```json { "code": 600204, "msg": "司机有未完成派单,不能删除", "data": null } ``` **错误码**:**600204** 有未完成派单(占位,业务流水 PR 上线后生效) / **600205** 司机不存在 / 401 未登录 --- ### 3.6 Excel 批量导入 **POST** `/admin/fleet/drivers/import` - **使用场景**:运营批量录入司机 - **认证**:管理后台 JWT - **幂等**:是(按身份证去重,已存在则**更新**,不存在则**新增**) **入参**(multipart/form-data): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `file` | file | ✅ | Excel(`.xlsx` / `.xls`)或 CSV | **表头约定(第 1 行 15 列,顺序固定)**: ``` 姓名 | 手机号 | 身份证号 | 性别 | 民族 | 驾龄(年) | 驾照号 | 准驾车型 | 驾照有效期(yyyy-MM-dd) | 发证机关 | 紧急联系人姓名 | 紧急联系人手机 | 与司机关系 | 保险类型(annual/perTrip/none) | 常驻车车牌 ``` **出参**:`Result`(**字段名与车辆导入不同**) | 字段 | 类型 | 说明 | |---|---|---| | `total` | int | 总行数(不含表头) | | `insertedCount` | int | 新增成功数 | | `renewedCount` | int | 更新成功数(按身份证去重,已存在则更新) | | `errorCount` | int | 失败行数 | | `errors[]` | array | 失败行详情 | **典型示例 响应**: ```json { "code": 200, "data": { "total": 10, "insertedCount": 6, "renewedCount": 2, "errorCount": 2, "errors": [ { "row": 3, "name": "张三", "msg": "驾照已过期" }, { "row": 7, "name": "李四", "msg": "手机号格式错误" } ] }, "msg": "成功" } ``` > ⚠️ 与车辆导入的出参字段不同:车辆是 `success/failed/errorRows`,司机是 `insertedCount/renewedCount/errorCount/errors`。前端**不能**复用同一份解析逻辑。 **错误码**:400 文件解析失败 / 401 未登录 --- ## 6. 枚举 / 数据字典 ### 6.1 附件类目(`category`,`DriverAttachmentCategoryEnum`) **所属字段**:`DriverAttachmentReqVO.category` / `DriverAttachmentRespVO.category` | **类型**:`String` | **必填**:✅ **真枚举**(后端硬编码 8 类目,含同类目张数上限): | 值 | 中文 | 张数上限 | 备注 | |---|---|---|---| | `id_card` | 身份证 | 2 | "换证留历史"语义(支持正反 2 张或新旧 2 套) | | `driver_license` | 驾驶证 | 2 | "换证留历史" | | `portrait` | 肖像照 | 2 | "换证留历史" | | `health_cert` | 健康证 | 2 | — | | `training_cert` | 培训证书 | 5 | — | | `award` | 荣誉奖励 | 5 | — | | `qualification` | 从业资格证 | 3 | — | | `other` | 其他附件 | 5 | — | > 超出上限触发 **601003** "该类目张数已达上限"。 ### 6.2 司机状态(`driverStatus`,`DriverStatusEnum`) **所属字段**:`DriverSaveReqVO.driverStatus` / `DriverPageReqVO.driverStatus` / `DriverPageItemRespVO.driverStatus` / `DriverDetailRespVO.driverStatus` | **类型**:`String` | **必填**:❌ **`@Pattern` 强校验枚举**: | 值 | 中文 | 说明 | |---|---|---| | `idle` | 空闲 | 可接单 | | `busy` | 在途 | 正在执行派单 | | `rest` | 休假 | 暂不接单 | | `pending` | 待激活 | 新入职 / 回归尚未完成入驻 | ### 6.3 赛季(`season`,`SeasonEnum`) **所属字段**:同 driverStatus | **类型**:`String` | **必填**:❌ **`@Pattern` 强校验枚举**: | 值 | 中文 | 说明 | |---|---|---| | `active` | 在册 | 当前赛季正常在职 | | `pending` | 待续签 | 赛季到期已发出续签邀请 | | `archived` | 已归档 | 本赛季已退出 | | `blacklist` | 黑名单 | 永久拉黑 | ### 6.4 保险类型(`insuranceType`,`InsuranceTypeEnum`) **所属字段**:`DriverInsuranceVO.type` / `DriverPageReqVO.insuranceType` / `DriverPageItemRespVO.insuranceType` | **类型**:`String` | **必填**:❌ | 值 | 中文 | 必填字段 | |---|---|---| | `annual` | 年保险 | 需填 `company` / `policyNo` / `annualPremium` / `annualStart` / `annualEnd` | | `perTrip` | 行程保险 | 需填 `perDayRate`(按行程计费) | | `none` | 无保险 | — | ### 6.5 订单状态(`orderStatus`,**mock 字段**) **所属字段**:`DriverDetailRespVO.relatedOrders[].orderStatus` | **类型**:`String` | **mock 占位** | 值 | 中文 | |---|---| | `pending` | 待出行 | | `in_progress` | 进行中 | | `completed` | 已完成 | > ⚠️ 这是 **mock 数据**里的取值,真实派车模块对接后值列表可能扩展(如 `canceled` / `refunded` 等)。前端**不要硬编码状态映射**,等真实化后由后端文档明确。 --- ## 7. 错误码(全模块汇总) | code | 含义 | 触发条件 | 涉及接口 | |---|---|---|---| | 400 | 参数校验失败 | 字段缺失/长度/枚举/手机号格式/MIME 非法 | 所有写入接口 | | 401 | 未登录 | JWT 无效或缺失 | 全部 6 接口 | | **600200** | 身份证已存在 | `idCard` 全局唯一约束 | §3.3 | | **600201** | 驾照已过期 | `license.expire < 今日`(新增 / 编辑主动校验) | §3.3 §3.4 | | **600203** | 手机号已存在 | `phone` 全局唯一约束 | §3.3 | | **600204** | 司机有未完成派单 | 业务流水 PR 上线后才触发(目前占位) | §3.5 | | **600205** | 司机不存在 | `driverId` 无效或软删 | §3.2 §3.4 §3.5 | | **601001** | 实体不存在 | 附件关联的主司机不存在 | §3.3 §3.4 | | **601002** | 附件类目非法 | `category` 不在 §6.1 枚举内 | §3.3 §3.4 | | **601003** | 该类目张数已达上限 | 超出 §6.1 张数上限 | §3.3 §3.4 | | **601004** | 文件超出大小限制 | 应用层 + OSS HEAD 校验 | §3.3 §3.4 | | **601005** | 文件类型非法 | MIME 不在白名单 | §3.3 §3.4 | > 错误码段位 600200-600205 归属司机档案(无与车辆 / 车型管理库冲突);601001-601005 归属附件管理子段(车辆 / 司机共用)。 > > **未列错误码 600202**(司机已黑名单):占位常量,业务流水 PR 上线后才会触发。 --- ## 9. 业务边界 - ✅ **PII 脱敏**:`phone` / `idCard` 在 §3.1 列表项 + §3.2 详情**响应**中均脱敏返回(`138****1234` / `150102******1234`);DB 存明文。前端展示时**直接用响应值**即可 - ✅ **编辑不可改 idCard / phone**:§3.4 入参中的 `idCard` / `phone` 后端**忽略**,要改身份证 / 手机号需联系后端管理员(业务上极少发生) - ✅ **驾照过期校验**:§3.3 §3.4 主动校验 `license.expire < 今日`(不影响存量数据,仅写入时校验) - ✅ **tags 全量覆盖语义**:§3.4 `tags=[]` = 清空所有标签;`tags=null` 也视为不修改(不传字段 = 不动),建议前端**显式传空数组**清空 - ✅ **附件 diff 语义**:与车辆档案 §3.4 一致;id_card/driver_license/portrait 三类支持"换证留历史"(旧软删 + 新插入由 diff 天然完成) - ✅ **唯一约束**:`idCard` / `phone` **全局**唯一 - ⚠️ **relatedOrders mock 占位**:见 §3.2 / §12 --- ## 10. 修改前后对比(仅 §3.2 详情) ### 10.1 字段级对比 | 字段 | 改前 | 改后 | |---|---|---| | `DriverDetailRespVO` | 无 `relatedOrders` 字段 | 新增 `relatedOrders[]` 字段(mock 数据) | ### 10.2 行为级对比 | 行为 | 改前 | 改后 | |---|---|---| | 调 §3.2 详情 | 响应里无关联订单信息 | 响应额外含 3 条 mock 订单 | --- ## 11. 影响评估 - **是否破坏向后兼容**:否(仅新增字段,老前端忽略该字段照常工作) - **前端是否必须同步上线**:否(前端可按节奏对接 relatedOrders UI 区块) - **影响已有数据**:无(mock 数据来自代码,不入库) --- ## 12. 注意事项 - **⚠️ `relatedOrders` 是 mock**: - 固定 3 条假数据,**所有司机返回相同内容** - 前端**不要硬编码**业务逻辑(如"看到张总订单 = 司机已派单 / 不能软删"等推断) - 真实化时机:派车模块对接 fleet 服务后,由 `DriverService.buildMockRelatedOrders` 替换为 Feign 实现(Issue #2791) - 真实化后字段名 / 字段类型与本 changelog 一致(已约定的契约),但**取值范围可能扩展**(如 orderStatus 增加 `canceled`) - **分页参数名**:`page` / `pageSize`(**不是** pageNo) - **Long 主键序列化**:`id` / `attachments[].id` / `relatedOrders[].orderId` 等 Long 字段 JSON 返回为 String,前端**不要**当 Number 解析 - **车辆导入 vs 司机导入字段名不同**:见 §3.6 警示 - **5 个 tab 实现**:见 §3.1 表格,纯通过 `season` 参数实现,无新接口 - **错误码段位连续**:600200-600205 全在司机档案段,无避让 --- ## 13. 关联 / 联系人 ### 13.1 链接 - **Issue(relatedOrders mock)**: [#2791](https://git.1814.love:8443/wx/HL/issues/2791) - **PR(relatedOrders mock)**: [#2796](https://git.1814.love:8443/wx/HL/pulls/2796) - **Merge commit**: [`ec0380439`](https://git.1814.love:8443/wx/HL/commit/ec03804390c7bd39f1b4ec3ddc3bd86aeb8ef47c) - **API 文档**: `docs/order-v3/api/API-SPEC-FLEET-V1.5.html` §3 司机档案 - **DB 文档**: `docs/order-v3/database/DATABASE-SCHEMA-FLEET-V1.5.html` §2.4 + §2.7 - **同期相关 changelog**: - 车型管理库 9 接口([`21_2785_车型管理库-新增接口-管理后台.md`](./21_2785_车型管理库-新增接口-管理后台.md)) - 车辆档案 6 接口([`21_车辆档案-修改接口-管理后台.md`](./21_车辆档案-修改接口-管理后台.md)) ### 13.2 联系人 - **后端负责人**: @yst(腰苏图) - **前端对接(管理后台)**: 待指派