# 【修改接口·管理后台】司机详情 attachments 弱类型 Map 改强类型 DriverAttachmentsVO (#2812) > **PR**: #2818 | **服务**: hl-fleet-service | **更新时间**: 2026-05-21 15:30 > > **存放目录**: `changelogs-v2/2026-05/` > **关联前序**: [`21_2791_司机档案-修改接口-管理后台.md`](./21_2791_司机档案-修改接口-管理后台.md)(commit `761ca07`) --- ## ⚠️ 关键变化(30 秒速读) **`GET /admin/fleet/drivers/{driverId}` 的响应字段 `attachments` 类型变了**: | 项 | 改前 | 改后 | |---|---|---| | 类型 | `Map`(动态 key) | `DriverAttachmentsVO`(8 个固定字段) | | 前端用法 | `data.attachments['id_card']` 字符串访问 | `data.attachments.idCard` 字段访问 | | TypeScript 类型 | 没有具体字段名 | 8 个具体字段(含类型提示) | **前序 changelog 废止内容**:[`21_2791_司机档案-修改接口-管理后台.md`](./21_2791_司机档案-修改接口-管理后台.md) **§3.2 详情接口** + **§9 业务边界** 中所有把 attachments 描述为 `Map>` 的部分**已废**,以本文档为准。 **前端必须改动**(不是兼容的):所有 `data.attachments[key]` 形式的访问要改成 `data.attachments.xxx` 字段访问。 --- ## 1. 接口背景 `attachments` 当前用 `Map>` 返回违反 HL 项目规则 [禁止弱类型返回值]: - Swagger / TypeScript 生成的类型是 `{ [key: string]: DriverAttachmentRespVO[] }`,**没有具体字段名** - 前端 IDE 不能自动补全 - 拼错 key 编译期不报错 - 文档无法自包含描述每个类目出参 改为强类型 `DriverAttachmentsVO`,8 个 List 字段对应 8 个固定类目(与 `DriverAttachmentCategoryEnum` 严格对齐)。 --- ## 2. 变更清单 | # | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|----------|------| | 1 | GET | `/admin/fleet/drivers/{driverId}` | **修改** | 响应字段 `attachments` 类型变化(详见 §3.1) | 仅 1 个端点受影响。其余 5 个司机档案接口(page / create / update / delete / import)**不受影响**。 --- ## 3. 接口详情 ### 3.1 司机详情 — `attachments` 字段类型变化 **GET** `/admin/fleet/drivers/{driverId}` #### 改后的 `attachments` 字段结构 字段:`DriverAttachmentsVO` 对象(**不再是 Map**)。 | 字段 | 类型 | 默认 | 张数上限(来自 DriverAttachmentCategoryEnum) | |---|---|---|---| | `idCard` | `DriverAttachmentRespVO[]` | `[]` | 2("换证留历史":支持正反 2 张或新旧 2 套) | | `driverLicense` | `DriverAttachmentRespVO[]` | `[]` | 2(换证留历史) | | `portrait` | `DriverAttachmentRespVO[]` | `[]` | 2(换证留历史) | | `healthCert` | `DriverAttachmentRespVO[]` | `[]` | 2 | | `trainingCert` | `DriverAttachmentRespVO[]` | `[]` | 5 | | `award` | `DriverAttachmentRespVO[]` | `[]` | 5 | | `qualification` | `DriverAttachmentRespVO[]` | `[]` | 3 | | `other` | `DriverAttachmentRespVO[]` | `[]` | 5 | > **每个字段默认空数组**(不为 null),前端**无需判空**,直接 `.map()` 渲染即可。 `DriverAttachmentRespVO[]` 单条项字段(**不变**): | 字段 | 类型 | 说明 | |---|---|---| | `id` | string | 附件 ID(Long 序列化为 String) | | `driverId` | string | 所属司机 ID | | `category` | string | 类目 | | `sortNo` | int | 同类目排序(0-based) | | `url` | string | OSS URL | | `mimeType` | string | 例 `image/jpeg` | #### 改后响应示例(节选) ```json { "code": 200, "data": { "id": "1234567890123456789", "name": "张三", "...其他字段保持不变...": "...", "attachments": { "idCard": [ { "id": "...", "driverId": "...", "category": "id_card", "sortNo": 0, "url": "https://oss/.../id-front.jpg", "mimeType": "image/jpeg" }, { "id": "...", "driverId": "...", "category": "id_card", "sortNo": 1, "url": "https://oss/.../id-back.jpg", "mimeType": "image/jpeg" } ], "driverLicense": [ { "id": "...", "driverId": "...", "category": "driver_license", "sortNo": 0, "url": "https://oss/.../license.jpg", "mimeType": "image/jpeg" } ], "portrait": [], "healthCert": [], "trainingCert": [], "award": [], "qualification": [], "other": [] }, "relatedOrders": [...] }, "msg": "成功" } ``` --- ## 6. 枚举 / 数据字典 无新增枚举。`category` 字段语义和取值与前序 changelog [`21_2791_司机档案-修改接口-管理后台.md`](./21_2791_司机档案-修改接口-管理后台.md) §6.1 一致(8 个值),唯一差异是 **API 响应不再以 category 字符串作为 key**,而是用 VO 字段名(驼峰)。 类目 ↔ VO 字段对应关系: | DB / category 字段值 | VO 字段(驼峰) | |---|---| | `id_card` | `idCard` | | `driver_license` | `driverLicense` | | `portrait` | `portrait` | | `health_cert` | `healthCert` | | `training_cert` | `trainingCert` | | `award` | `award` | | `qualification` | `qualification` | | `other` | `other` | 注意单条 `DriverAttachmentRespVO.category` 仍然是 `id_card` / `driver_license` 等下划线值(不变)。改的是**外层分组的 key 形式**。 --- ## 7. 错误码 无变化。 --- ## 10. 修改前后对比 ### 10.1 字段级对比 | 字段 | 改前 | 改后 | |---|---|---| | `attachments` 类型 | `Map` | `DriverAttachmentsVO`(8 个固定 List 字段) | | `attachments` key 形式 | DB 下划线值(`id_card` / `driver_license` / `portrait` / ...) | VO 驼峰字段(`idCard` / `driverLicense` / `portrait` / ...) | | 类目缺失 | 该 key 不在 Map 里 | 该字段是空数组 `[]` | ### 10.2 前端代码对照 ```typescript // 改前 const idCardAttachments = data.attachments['id_card'] ?? []; const licenseAttachments = data.attachments['driver_license'] ?? []; // 改后 const idCardAttachments = data.attachments.idCard; // 不用判空 const licenseAttachments = data.attachments.driverLicense; ``` --- ## 11. 影响评估 - **是否破坏向后兼容**:⚠️ **是**(字段类型变了,前端必须改) - **前端是否必须同步上线**:**是**(老前端按 Map 解析会拿到 undefined) - **影响其他后端服务**:无(DriverDetailRespVO 仅 admin 接口返回,不走 Feign) - **影响已有数据**:无(仅 API 序列化形式变化,DB 无变) --- ## 12. 注意事项 - **前端 workaround 清理点**: - 改前如果前端有 `const map = data.attachments; const idCard = map['id_card'] ?? [];` 之类 workaround,**改成 `data.attachments.idCard`** 即可 - 改前如果前端硬编码遍历类目(如 `for (const key of ['id_card', 'driver_license'])`),**改成直接读 VO 字段** - 改前如果前端有 `if (map['portrait'])` 判空逻辑,**直接删** —— 强类型 VO 字段必非 null(默认空数组) - **前序 changelog 描述废止**:[`21_2791_司机档案-修改接口-管理后台.md`](./21_2791_司机档案-修改接口-管理后台.md) 已发出的 attachments Map 描述以本文档为准,前序 changelog **不会修改**(changelog 只追加不回写历史) --- ## 13. 关联 / 联系人 ### 13.1 链接 - **Issue**: [#2812](https://git.1814.love:8443/wx/HL/issues/2812) - **PR**: [#2818](https://git.1814.love:8443/wx/HL/pulls/2818) - **Merge commit**: [`8c340550`](https://git.1814.love:8443/wx/HL/commit/8c340550656bdee3ee2243b98d694b818474aeba) - **前序 changelog(attachments Map 描述废)**: [`21_2791_司机档案-修改接口-管理后台.md`](./21_2791_司机档案-修改接口-管理后台.md) - **规则**: HL `MEMORY.md` → `feedback_no-map-return-type.md` (禁止弱类型返回值) ### 13.2 联系人 - **后端负责人**: @yst(腰苏图) - **前端对接(管理后台)**: 待指派