新增 车辆档案 6 接口 + 司机档案 6 接口 全模块快照 changelog(fleet 模块批量补发)
两份 changelog 都按 SKILL.md 多接口模板(按接口分小节)+ 严格代码契约(不照搬文档)写: 文件 1: changelogs-v2/2026-05/21_车辆档案-修改接口-管理后台.md - 6 接口(page/detail/create/update/delete/import)全契约 - 真枚举 VehicleAttachmentCategoryEnum(6 类目 + 张数上限)+ fleet/vehicleStatus @Pattern 强校验 - 错误码:600100 + 600107-600110(与文档 v1.4 差异已显式注解)+ 共用 601001-601005 - 标注:本模块无单独 PR 改动,本次为全模块快照首推 文件 2: changelogs-v2/2026-05/21_2791_司机档案-修改接口-管理后台.md - 6 接口全契约 + 详情接口新增 relatedOrders mock 字段(PR #2796) - 真枚举 DriverAttachmentCategoryEnum(8 类目 + 张数上限,前 3 类换证留历史语义) + DriverStatusEnum / SeasonEnum / InsuranceTypeEnum @Pattern 强校验 - 4 嵌套 VO 完整字段表(DriverLicenseVO/DriverEmergencyVO/DriverInsuranceVO/DriverStatsVO) - attachments 是 Map<category, List> 按类目分组 - 错误码:600200-600205 + 601001-601005 - 5 tab 后端实现说明(season=active/pending/archived/blacklist + 全部不传) - 关联 Issue #2791 + PR #2796 - mock 警示(固定 3 条假数据,所有司机返回相同,待真实化) 校准(代码 vs 文档): - 车辆错误码段位实际避让到 600107-600110(与车型管理库 600101-600106 冲突) - 司机详情 attachments 是 Map<String, List<Item>> 按类目分组返回(不是扁平 array) - DriverImportRespVO 字段名与 VehicleImportRespVO 不同(前者 insertedCount/renewedCount/errorCount,后者 success/failed/errorRows)
这个提交包含在:
父节点
1a796e52b1
当前提交
761ca0742d
@ -0,0 +1,748 @@
|
||||
# 【修改接口·管理后台】司机档案 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<PageResult<DriverPageItemRespVO>>` (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 <token>
|
||||
(无请求体)
|
||||
```
|
||||
|
||||
**典型示例 响应**:
|
||||
```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<DriverDetailRespVO>`
|
||||
|
||||
主体字段(含 §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<string, array> | 附件按类目分组(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<String, List<DriverAttachmentRespVO>>`,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<DriverCreateRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | string | 新增司机 ID |
|
||||
| `attachmentIds[]` | array<Long> | 附件 ID 列表(按入参顺序) |
|
||||
|
||||
**典型示例 请求**(节选):
|
||||
```
|
||||
POST /admin/fleet/drivers
|
||||
Authorization: Bearer <token>
|
||||
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<DriverUpdateRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `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<Void>`
|
||||
|
||||
**典型示例 响应**:
|
||||
```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<DriverImportRespVO>`(**字段名与车辆导入不同**)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `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(腰苏图)
|
||||
- **前端对接(管理后台)**: 待指派
|
||||
@ -0,0 +1,553 @@
|
||||
# 【修改接口·管理后台】车辆档案 6 接口(全模块首次推送 changelog)
|
||||
|
||||
> **PR**: 无(本次为首次推送,实质接口契约未变更,配合 §1 §3 模块 changelog 一并补齐 fleet 全档案契约)
|
||||
> **服务**: hl-fleet-service | **更新时间**: 2026-05-21
|
||||
>
|
||||
> **存放目录**: `changelogs-v2/2026-05/`
|
||||
> **影响范围**: 管理后台「车管 / 车辆档案」页(列表 + 详情 + 新增 + 编辑 + 软删 + Excel 批量导入)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键说明
|
||||
|
||||
车辆档案模块 6 接口自 fleet 服务首次落地(PR #2724)以来契约**未变化**,本次仅作**首次完整 changelog 推送**,让前端 v3 项目仓库一次拿全 6 接口契约。
|
||||
|
||||
**与车型管理库(§1 changelog)配套**:车辆档案的 `vehicleModelId` 引用车型管理库的型号 ID,前端可在新增车辆页用 §1.5 / §1.7 拉型号下拉。
|
||||
|
||||
---
|
||||
|
||||
## 1. 接口背景
|
||||
|
||||
车辆档案是车队所有车辆的主数据:车牌 / 车型 / VIN / 行驶证 / 保险 / 年检 / 多类目附件(外观/内饰/保险/年检/营运证/其他 6 类)。
|
||||
|
||||
前端"车管 / 车辆档案"页面提供:
|
||||
- 列表筛选(按车牌、车队、车型大类、状态、保险/年检到期日)
|
||||
- 详情查看(含附件按类目分组)
|
||||
- 新增 / 编辑(含附件 diff 语义批量提交)
|
||||
- 软删(业务流水模块上线后会按"未完成派单"拒删)
|
||||
- Excel 批量导入
|
||||
|
||||
---
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| # | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|----------|------|
|
||||
| 1 | GET | `/admin/fleet/vehicles/page` | 首推 | 分页列表(多条件过滤) |
|
||||
| 2 | GET | `/admin/fleet/vehicles/{vehicleId}` | 首推 | 详情(含附件) |
|
||||
| 3 | POST | `/admin/fleet/vehicles` | 首推 | 新增(含附件批量 INSERT) |
|
||||
| 4 | PUT | `/admin/fleet/vehicles/{vehicleId}` | 首推 | 编辑(附件 diff 语义) |
|
||||
| 5 | DELETE | `/admin/fleet/vehicles/{vehicleId}` | 首推 | 软删 |
|
||||
| 6 | POST | `/admin/fleet/vehicles/import` | 首推 | Excel 批量导入 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口详情
|
||||
|
||||
### 3.1 分页查询
|
||||
|
||||
**GET** `/admin/fleet/vehicles/page`
|
||||
|
||||
- **使用场景**:车管车辆档案列表页
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:是(只读)
|
||||
|
||||
**Query 入参**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 默认 | 校验 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| `page` | int | ❌ | 1 | `>= 1` | 页码 |
|
||||
| `pageSize` | int | ❌ | 20 | `1-100` | 每页条数 |
|
||||
| `keyword` | string | ❌ | — | — | 车牌模糊匹配 |
|
||||
| `fleet` | string | ❌ | — | `own/coopA/coopB` | 车队精确过滤 |
|
||||
| `typeKey` | string | ❌ | — | — | 车型大类 key 精确(如 suv) |
|
||||
| `vehicleStatus` | string | ❌ | — | `idle/busy/maint` | 状态精确 |
|
||||
| `insureDueBefore` | date | ❌ | — | yyyy-MM-dd | 保险到期日早于此日(含) |
|
||||
| `inspectDueBefore` | date | ❌ | — | yyyy-MM-dd | 年检到期日早于此日(含) |
|
||||
|
||||
**出参**:`Result<PageResult<VehiclePageItemRespVO>>` (按 create_time DESC)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `records[].id` | string | 车辆 ID(Long 序列化为 String) |
|
||||
| `records[].plate` | string | 车牌 |
|
||||
| `records[].vehicleModelId` | string | 型号 ID |
|
||||
| `records[].vehicleTypeId` | string | 大类 ID |
|
||||
| `records[].modelName` | string | 型号名(如丰田汉兰达) |
|
||||
| `records[].seats` | int | 座位数 |
|
||||
| `records[].fleet` | string | 车队(own/coopA/coopB) |
|
||||
| `records[].vehicleStatus` | string | 状态(idle/busy/maint) |
|
||||
| `records[].insurer` | string | 保险公司 |
|
||||
| `records[].insureDue` | date | 保险到期日 |
|
||||
| `records[].inspectDue` | date | 年检到期日 |
|
||||
| `records[].createTime` | datetime | 创建时间 |
|
||||
| `total` / `page` / `pageSize` | int | 分页元数据 |
|
||||
|
||||
**典型示例 请求**:
|
||||
```
|
||||
GET /admin/fleet/vehicles/page?page=1&pageSize=20&fleet=own&insureDueBefore=2025-12-31
|
||||
Authorization: Bearer <token>
|
||||
(无请求体)
|
||||
```
|
||||
|
||||
**典型示例 响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"id": "1234567890123456789",
|
||||
"plate": "蒙A-88888",
|
||||
"vehicleModelId": "1234567890123456001",
|
||||
"vehicleTypeId": "1234567890123456002",
|
||||
"modelName": "丰田汉兰达",
|
||||
"seats": 7,
|
||||
"fleet": "own",
|
||||
"vehicleStatus": "idle",
|
||||
"insurer": "中国人保财险",
|
||||
"insureDue": "2025-12-31",
|
||||
"inspectDue": "2025-12-31",
|
||||
"createTime": "2025-05-21 14:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"pageSize": 20
|
||||
},
|
||||
"msg": "成功"
|
||||
}
|
||||
```
|
||||
|
||||
**错误码**:400 参数校验 / 401 未登录
|
||||
|
||||
---
|
||||
|
||||
### 3.2 详情
|
||||
|
||||
**GET** `/admin/fleet/vehicles/{vehicleId}`
|
||||
|
||||
- **使用场景**:详情页 / 编辑前预填
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:是
|
||||
|
||||
**路径入参**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `vehicleId` | Long | ✅ | 车辆 ID |
|
||||
|
||||
**出参**:`Result<VehicleDetailRespVO>`
|
||||
|
||||
包含 §3.1 全部字段 + 以下扩展:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `vin` | string | 车架号(VIN) |
|
||||
| `regDate` | date | 注册日期 |
|
||||
| `policyNo` | string | 保单号 |
|
||||
| `regCertNo` | string | 行驶证号 |
|
||||
| `regCertOwner` | string | 行驶证所有人 |
|
||||
| `regCertUsage` | string | 使用性质 |
|
||||
| `regCertFrontUrl` | string | 行驶证正面 OSS URL |
|
||||
| `regCertBackUrl` | string | 行驶证副页 OSS URL |
|
||||
| `attachments[]` | array | 附件列表(按 category + sortNo 升序) |
|
||||
| `attachments[].id` | string | 附件 ID |
|
||||
| `attachments[].category` | string | 类目(见 §6.1) |
|
||||
| `attachments[].sortNo` | int | 同类目排序(0-based) |
|
||||
| `attachments[].url` | string | OSS URL |
|
||||
| `attachments[].mimeType` | string | 例 `image/jpeg` |
|
||||
| `primaryDriverName` | string\|null | **目前恒为 null**(待业务流水 PR 注入司机姓名) |
|
||||
| `updateTime` | datetime | — |
|
||||
|
||||
**典型示例 响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"id": "1234567890123456789",
|
||||
"plate": "蒙A-88888",
|
||||
"vehicleModelId": "1234567890123456001",
|
||||
"vehicleTypeId": "1234567890123456002",
|
||||
"modelName": "丰田汉兰达",
|
||||
"seats": 7,
|
||||
"fleet": "own",
|
||||
"vehicleStatus": "idle",
|
||||
"vin": "LSVNV2182E2100001",
|
||||
"regDate": "2020-01-01",
|
||||
"inspectDue": "2025-12-31",
|
||||
"insurer": "中国人保财险",
|
||||
"policyNo": "PICC-2024-XXX",
|
||||
"insureDue": "2025-12-31",
|
||||
"regCertNo": "12345678",
|
||||
"regCertOwner": "呼籁旅游服务有限公司",
|
||||
"regCertUsage": "营运租赁",
|
||||
"regCertFrontUrl": "https://oss.example.com/fleet/cert-front.jpg",
|
||||
"regCertBackUrl": "https://oss.example.com/fleet/cert-back.jpg",
|
||||
"attachments": [
|
||||
{
|
||||
"id": "1234567890123456900",
|
||||
"vehicleId": "1234567890123456789",
|
||||
"category": "exterior",
|
||||
"sortNo": 0,
|
||||
"url": "https://oss.example.com/fleet/ext-1.jpg",
|
||||
"mimeType": "image/jpeg"
|
||||
}
|
||||
],
|
||||
"primaryDriverName": null,
|
||||
"createTime": "2025-05-21 14:00:00",
|
||||
"updateTime": "2025-05-21 14:00:00"
|
||||
},
|
||||
"msg": "成功"
|
||||
}
|
||||
```
|
||||
|
||||
**错误码**:**600110** 车辆不存在 / 401 未登录
|
||||
|
||||
---
|
||||
|
||||
### 3.3 新增
|
||||
|
||||
**POST** `/admin/fleet/vehicles`
|
||||
|
||||
- **使用场景**:新增车辆 + 附件批量提交(前端 STS 直传 OSS 后把 URL 数组放主表单一并提交)
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:否(重复抛 600100/600107)
|
||||
|
||||
**Body 入参**(`VehicleSaveReqVO`):
|
||||
|
||||
| 字段 | 类型 | 必填 | 校验 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `plate` | string | ✅ | `@Size(max=16)` | 车牌(全局唯一) |
|
||||
| `vehicleModelId` | Long | ✅ | — | 车型型号 ID(引用 §1 模块) |
|
||||
| `fleet` | string | ✅ | `@Pattern(own\|coopA\|coopB)` | 车队 |
|
||||
| `vehicleStatus` | string | ❌ | `@Pattern(idle\|busy\|maint)` | 状态,默认 idle |
|
||||
| `vin` | string | ❌ | `@Size(max=32)` | 车架号(传则全局唯一) |
|
||||
| `regDate` | date | ❌ | — | 注册日期 |
|
||||
| `inspectDue` | date | ❌ | — | 年检到期日 |
|
||||
| `insurer` | string | ❌ | `@Size(max=64)` | 保险公司 |
|
||||
| `policyNo` | string | ❌ | `@Size(max=64)` | 保单号 |
|
||||
| `insureDue` | date | ❌ | — | 保险到期日 |
|
||||
| `regCertNo` | string | ❌ | `@Size(max=64)` | 行驶证号 |
|
||||
| `regCertOwner` | string | ❌ | `@Size(max=128)` | 行驶证所有人 |
|
||||
| `regCertUsage` | string | ❌ | `@Size(max=32)` | 使用性质 |
|
||||
| `regCertFrontUrl` | string | ❌ | `@Size(max=512)` | 行驶证正面 OSS URL |
|
||||
| `regCertBackUrl` | string | ❌ | `@Size(max=512)` | 行驶证副页 OSS URL |
|
||||
| `attachments[]` | array | ❌ | — | 附件数组(见下) |
|
||||
|
||||
**`attachments[]` 单项**(`VehicleAttachmentReqVO`):
|
||||
|
||||
| 字段 | 类型 | 必填 | 校验 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `id` | Long | ❌ | — | 附件 ID(新增项不传) |
|
||||
| `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<VehicleCreateRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | string | 新增车辆 ID |
|
||||
| `attachmentIds[]` | array<Long> | 附件 ID 列表(按入参顺序) |
|
||||
|
||||
**典型示例 请求**:
|
||||
```
|
||||
POST /admin/fleet/vehicles
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"plate": "蒙A-88888",
|
||||
"vehicleModelId": "1234567890123456001",
|
||||
"fleet": "own",
|
||||
"vehicleStatus": "idle",
|
||||
"vin": "LSVNV2182E2100001",
|
||||
"regDate": "2020-01-01",
|
||||
"inspectDue": "2025-12-31",
|
||||
"insurer": "中国人保财险",
|
||||
"policyNo": "PICC-2024-XXX",
|
||||
"insureDue": "2025-12-31",
|
||||
"regCertNo": "12345678",
|
||||
"regCertOwner": "呼籁旅游服务有限公司",
|
||||
"regCertUsage": "营运租赁",
|
||||
"regCertFrontUrl": "https://oss.example.com/fleet/cert-front.jpg",
|
||||
"regCertBackUrl": "https://oss.example.com/fleet/cert-back.jpg",
|
||||
"attachments": [
|
||||
{ "category": "exterior", "url": "https://oss.example.com/fleet/ext-1.jpg", "mimeType": "image/jpeg" },
|
||||
{ "category": "exterior", "url": "https://oss.example.com/fleet/ext-2.jpg", "mimeType": "image/jpeg" },
|
||||
{ "category": "insurance", "url": "https://oss.example.com/fleet/ins.jpg", "mimeType": "image/jpeg" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**典型示例 响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"id": "1234567890123456789",
|
||||
"attachmentIds": ["1234567890123456900", "1234567890123456901", "1234567890123456902"]
|
||||
},
|
||||
"msg": "成功"
|
||||
}
|
||||
```
|
||||
|
||||
**异常 请求**(车牌重复):
|
||||
```json
|
||||
{ "code": 600100, "msg": "车牌已存在", "data": null }
|
||||
```
|
||||
|
||||
**异常 请求**(附件类目张数超上限 `exterior` > 6):
|
||||
```json
|
||||
{ "code": 601003, "msg": "该类目张数已达上限", "data": null }
|
||||
```
|
||||
|
||||
**错误码**:400 参数校验 / **600100** 车牌已存在 / **600107** VIN 已存在 / **600108** 车型不存在 / **601002** 附件类目非法 / **601003** 类目张数达上限 / 401 未登录
|
||||
|
||||
---
|
||||
|
||||
### 3.4 编辑(附件 diff 语义)
|
||||
|
||||
**PUT** `/admin/fleet/vehicles/{vehicleId}`
|
||||
|
||||
- **使用场景**:编辑车辆基本信息 + 附件增删改一次性提交
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:是
|
||||
|
||||
**路径入参**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `vehicleId` | Long | ✅ | 车辆 ID |
|
||||
|
||||
**Body 入参**:同 §3.3(共用 `VehicleSaveReqVO`)
|
||||
|
||||
**附件 diff 语义**:
|
||||
|
||||
| 入参 attachments[] 项 | DB 中的对应行 | 行为 |
|
||||
|---|---|---|
|
||||
| 有 `id` + DB 命中 | 存在 | **保留**(可更新 sortNo) |
|
||||
| 无 `id`(新增项) | — | **INSERT** |
|
||||
| — | 存在但本次未传 | **软删** |
|
||||
|
||||
**出参**:`Result<VehicleUpdateRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `kept` | int | 保留的附件数 |
|
||||
| `inserted` | int | 新插入的附件数 |
|
||||
| `softDeleted` | int | 软删的附件数 |
|
||||
|
||||
**典型示例 响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": { "kept": 2, "inserted": 1, "softDeleted": 1 },
|
||||
"msg": "成功"
|
||||
}
|
||||
```
|
||||
|
||||
**错误码**:400 参数校验 / **600100** 车牌已存在 / **600107** VIN 已存在 / **600108** 车型不存在 / **600110** 车辆不存在 / **601002** 类目非法 / **601003** 类目张数达上限 / 401 未登录
|
||||
|
||||
---
|
||||
|
||||
### 3.5 软删
|
||||
|
||||
**DELETE** `/admin/fleet/vehicles/{vehicleId}`
|
||||
|
||||
- **使用场景**:下架车辆
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:是
|
||||
|
||||
**路径入参**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `vehicleId` | Long | ✅ | 车辆 ID |
|
||||
|
||||
**出参**:`Result<Void>`(`data: null`)
|
||||
|
||||
**典型示例 响应**:
|
||||
```json
|
||||
{ "code": 200, "data": null, "msg": "成功" }
|
||||
```
|
||||
|
||||
**异常 请求**(车辆有未完成派单 —— **业务流水 PR 落地后才生效**):
|
||||
```json
|
||||
{ "code": 600109, "msg": "车辆有未完成派单,不能删除", "data": null }
|
||||
```
|
||||
|
||||
**错误码**:**600109** 有未完成派单(占位,业务流水 PR 上线后生效)/ **600110** 车辆不存在 / 401 未登录
|
||||
|
||||
---
|
||||
|
||||
### 3.6 Excel 批量导入
|
||||
|
||||
**POST** `/admin/fleet/vehicles/import`
|
||||
|
||||
- **使用场景**:运营批量录入车辆
|
||||
- **认证**:管理后台 JWT
|
||||
- **幂等**:否(重复行按车牌冲突拒绝单行)
|
||||
|
||||
**入参**(multipart/form-data):
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `file` | file | ✅ | Excel(`.xlsx` / `.xls`)或 CSV |
|
||||
|
||||
**表头约定(第 1 行 12 列,顺序固定)**:
|
||||
|
||||
```
|
||||
车牌 | 车型型号ID | 车队(own/coopA/coopB) | 车架号(VIN) |
|
||||
注册日期(yyyy-MM-dd) | 年检到期日(yyyy-MM-dd) |
|
||||
保险公司 | 保单号 | 保险到期日(yyyy-MM-dd) |
|
||||
行驶证号 | 行驶证所有人 | 使用性质
|
||||
```
|
||||
|
||||
**出参**:`Result<VehicleImportRespVO>`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `total` | int | 总行数(不含表头) |
|
||||
| `success` | int | 成功导入数 |
|
||||
| `failed` | int | 失败行数 |
|
||||
| `errorRows[]` | array | 失败行详情 |
|
||||
| `errorRows[].row` | int | Excel 行号(从 2 开始,1 为表头) |
|
||||
| `errorRows[].plate` | string | 车牌(用于定位) |
|
||||
| `errorRows[].msg` | string | 错误信息(如"车牌已存在") |
|
||||
|
||||
**典型示例 响应**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"total": 10,
|
||||
"success": 8,
|
||||
"failed": 2,
|
||||
"errorRows": [
|
||||
{ "row": 3, "plate": "蒙A-88888", "msg": "车牌已存在" },
|
||||
{ "row": 7, "plate": "蒙A-99999", "msg": "车型型号 ID 不存在" }
|
||||
]
|
||||
},
|
||||
"msg": "成功"
|
||||
}
|
||||
```
|
||||
|
||||
**错误码**:400 文件解析失败 / 401 未登录
|
||||
|
||||
---
|
||||
|
||||
## 6. 枚举 / 数据字典
|
||||
|
||||
### 6.1 附件类目(`category`,`VehicleAttachmentCategoryEnum`)
|
||||
|
||||
**所属字段**:`VehicleAttachmentReqVO.category` / `VehicleAttachmentRespVO.category` | **类型**:`String` | **必填**:✅
|
||||
|
||||
**真枚举**(后端硬编码,含同类目张数上限):
|
||||
|
||||
| 值 | 中文 | 张数上限 |
|
||||
|---|---|---|
|
||||
| `exterior` | 车辆外观 | 6 |
|
||||
| `interior` | 车辆内饰 | 3 |
|
||||
| `insurance` | 保险单据 | 2 |
|
||||
| `inspection` | 年检单据 | 2 |
|
||||
| `operation_license` | 营运证 | 2 |
|
||||
| `other` | 其他附件 | 5 |
|
||||
|
||||
> 超出上限触发 **601003** "该类目张数已达上限"。
|
||||
|
||||
### 6.2 车队(`fleet`)
|
||||
|
||||
**所属字段**:`VehicleSaveReqVO.fleet` / `VehiclePageReqVO.fleet` / `VehiclePageItemRespVO.fleet` | **类型**:`String` | **必填**:✅(新增时)
|
||||
|
||||
**`@Pattern` 强校验枚举**:
|
||||
|
||||
| 值 | 含义 |
|
||||
|---|---|
|
||||
| `own` | 自营车辆 |
|
||||
| `coopA` | 合作车队 A |
|
||||
| `coopB` | 合作车队 B |
|
||||
|
||||
### 6.3 车辆状态(`vehicleStatus`)
|
||||
|
||||
**所属字段**:同 `fleet` | **类型**:`String` | **必填**:❌(默认 idle)
|
||||
|
||||
**`@Pattern` 强校验枚举**:
|
||||
|
||||
| 值 | 含义 |
|
||||
|---|---|
|
||||
| `idle` | 空闲 |
|
||||
| `busy` | 在途 |
|
||||
| `maint` | 维修中 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 错误码(全模块汇总)
|
||||
|
||||
| code | 含义 | 触发条件 | 涉及接口 |
|
||||
|---|---|---|---|
|
||||
| 400 | 参数校验失败 | 字段缺失/长度/枚举值不合法/MIME 非法 | 所有写入接口 |
|
||||
| 401 | 未登录 | JWT 无效或缺失 | 全部 6 接口 |
|
||||
| **600100** | 车牌已存在 | `plate` 全局唯一约束 | §3.3 §3.4 |
|
||||
| **600107** | VIN 已存在 | `vin` 全局唯一约束 | §3.3 §3.4 |
|
||||
| **600108** | 车型不存在 | `vehicleModelId` 无效或软删 | §3.3 §3.4 |
|
||||
| **600109** | 有未完成派单,不能删除 | 业务流水 PR 上线后才触发(目前占位) | §3.5 |
|
||||
| **600110** | 车辆不存在 | `vehicleId` 无效或软删 | §3.2 §3.4 §3.5 |
|
||||
| **601001** | 实体不存在 | 附件关联的主车辆不存在 | §3.3 §3.4 |
|
||||
| **601002** | 附件类目非法 | `category` 不在枚举内 | §3.3 §3.4 |
|
||||
| **601003** | 该类目张数已达上限 | 超出 §6.1 张数上限 | §3.3 §3.4 |
|
||||
| **601004** | 文件超出大小限制 | 应用层 + OSS HEAD 校验 | §3.6(导入),§3.3/§3.4 主体不直接校验 |
|
||||
| **601005** | 文件类型非法 | MIME 不在白名单 | §3.3 §3.4 |
|
||||
|
||||
> 错误码段位 600100-600110 归属车辆档案;601001-601005 归属附件管理(车辆/司机共用)。
|
||||
>
|
||||
> **注意:与文档 v1.4 的差异** —— 文档原计划 VIN 用 600101 / 车型不存在 600102 / 派单冲突 600103,但因这 3 个段位被车型管理库占用(见 §1 changelog),实际代码避让到 **600107/600108/600109**。本 changelog 反映**代码实际值**。
|
||||
|
||||
---
|
||||
|
||||
## 9. 业务边界
|
||||
|
||||
- ✅ **附件 diff 语义统一**:§3.3 新增时所有项无 id;§3.4 编辑时按 `id` 命中度决定保留/插入/软删
|
||||
- ✅ **sortNo 自动重写**:附件 `sortNo` 不传时按入参顺序自动写 0..N-1(同 category 内 0-based)
|
||||
- ✅ **行驶证 OSS URL 留主表**:`regCertFrontUrl` / `regCertBackUrl` 是主表字段(不走附件表),与附件分离
|
||||
- ✅ **唯一约束**:`plate` / `vin` **全局**唯一(违反抛 600100 / 600107)
|
||||
- ✅ **车队 / 状态强枚举**:`fleet` `vehicleStatus` 走 `@Pattern` 校验,违反返 400
|
||||
- ⚠️ **primaryDriverName 占位**:§3.2 详情返 `primaryDriverName: null`,待业务流水 PR 上线后注入司机姓名
|
||||
- ⚠️ **派单删除保护占位**:§3.5 错误码 600109 在业务流水 PR 上线后才会真触发
|
||||
|
||||
---
|
||||
|
||||
## 11. 影响评估
|
||||
|
||||
- **是否破坏向后兼容**:否(接口契约自首次落地以来未变更)
|
||||
- **前端是否必须同步上线**:否(本次仅补发 changelog,无代码改动)
|
||||
- **影响已有数据**:无
|
||||
|
||||
---
|
||||
|
||||
## 12. 注意事项
|
||||
|
||||
- **分页参数名**:`page` / `pageSize`(**不是** pageNo)
|
||||
- **Long 主键序列化**:`id` / `vehicleModelId` / `vehicleTypeId` / `attachments[].id` 等 Long 字段 JSON 返回为 String,前端**不要**当 Number 解析
|
||||
- **错误码不连续**:600100 / 600107-600110(中间 600101-600106 是车型管理库的段位),见 §7 注解
|
||||
- **附件 URL 不可改**:§3.4 编辑时 `attachments[].url` 不可改(后端忽略),只能保留 / 新增 / 软删
|
||||
- **`primaryDriverName` 当前恒为 null**:业务流水 PR 上线前前端**不要**展示该字段或处理为"未指派"
|
||||
|
||||
---
|
||||
|
||||
## 13. 关联 / 联系人
|
||||
|
||||
### 13.1 链接
|
||||
|
||||
- **API 文档**: `docs/order-v3/api/API-SPEC-FLEET-V1.5.html` §2 车辆档案
|
||||
- **DB 文档**: `docs/order-v3/database/DATABASE-SCHEMA-FLEET-V1.5.html` §2.3 / §2.6
|
||||
- **同期相关 changelog**:
|
||||
- 车型管理库 9 接口([`21_2785_车型管理库-新增接口-管理后台.md`](./21_2785_车型管理库-新增接口-管理后台.md))
|
||||
- 司机档案 6 接口([`21_2791_司机档案-修改接口-管理后台.md`](./21_2791_司机档案-修改接口-管理后台.md))
|
||||
|
||||
### 13.2 联系人
|
||||
|
||||
- **后端负责人**: @yst(腰苏图)
|
||||
- **前端对接(管理后台)**: 待指派
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户