21 KiB
【新增接口·管理后台】车型管理库 9 接口(含新增的大类/型号分页 2 接口) (#2785)
PR: #2786 | 服务: hl-fleet-service | 更新时间: 2026-05-21 14:25
存放目录:
changelogs-v2/2026-05/(前端 v3 项目仓库读取) 影响范围: 管理后台「车管 / 车型管理库」页(左侧大类导航 + 右侧型号列表 + 全模块 CRUD)
⚠️ 关键变化(30 秒速读)
本次实质变化是 2 个新增分页接口(§3.2 大类分页 / §3.7 型号分页),原 7 个 CRUD/树接口契约零变化。一并把整模块 9 接口契约打包发给前端,方便对接「左侧大类导航 + 右侧型号列表」联动场景。
| # | 接口 | 状态 | 用途 |
|---|---|---|---|
| §3.1 | GET /admin/fleet/vehicle-types |
已存在·未变 | 一次拉全模块树(大类+型号) |
| §3.2 | GET /admin/fleet/vehicle-types/page |
✨ 新增 | 大类分页+过滤(左侧导航专用) |
| §3.3 | POST /admin/fleet/vehicle-types |
已存在·未变 | 新增大类 |
| §3.4 | PUT /admin/fleet/vehicle-types/{typeId} |
已存在·未变 | 编辑大类 |
| §3.5 | DELETE /admin/fleet/vehicle-types/{typeId} |
已存在·未变 | 删除大类(软删) |
| §3.6 | POST /admin/fleet/vehicle-types/{typeId}/models |
已存在·未变 | 新增型号 |
| §3.7 | GET /admin/fleet/vehicle-types/models/page |
✨ 新增 | 型号分页+过滤(vehicleTypeId 可选) |
| §3.8 | PUT /admin/fleet/vehicle-types/models/{modelId} |
已存在·未变 | 编辑型号 |
| §3.9 | DELETE /admin/fleet/vehicle-types/models/{modelId} |
已存在·未变 | 删除型号(软删) |
1. 接口背景
车型管理库是车队基础字典:大类(如 SUV/MPV/BUS/Sedan)→ 型号(如 丰田汉兰达/本田奥德赛)。管理后台需要:
- 左侧大类导航 + 右侧型号列表联动 → 大类分页 + 型号按 typeId 过滤的分页
- 跨大类按车型名搜索 → 型号分页 typeId 可选 + modelName 模糊
- 已有的 listTree 一次拉树仍保留(其他场景如派单弹窗筛选 / 价格日历分组继续用)
2. 变更清单
| # | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|
| 1 | GET | /admin/fleet/vehicle-types |
未变 | 列出大类+型号整树 |
| 2 | GET | /admin/fleet/vehicle-types/page |
新增 | 大类分页 |
| 3 | POST | /admin/fleet/vehicle-types |
未变 | 新增大类 |
| 4 | PUT | /admin/fleet/vehicle-types/{typeId} |
未变 | 编辑大类(typeKey 不可改) |
| 5 | DELETE | /admin/fleet/vehicle-types/{typeId} |
未变 | 删除大类(软删) |
| 6 | POST | /admin/fleet/vehicle-types/{typeId}/models |
未变 | 新增型号 |
| 7 | GET | /admin/fleet/vehicle-types/models/page |
新增 | 型号分页 |
| 8 | PUT | /admin/fleet/vehicle-types/models/{modelId} |
未变 | 编辑型号 |
| 9 | DELETE | /admin/fleet/vehicle-types/models/{modelId} |
未变 | 删除型号(软删) |
3. 接口详情
3.1 列出大类 + 型号树
GET /admin/fleet/vehicle-types
- 使用场景:一次拉取整棵车型树(大类含 models 数组),用于派单弹窗、价格日历分组等需要全量树的场景
- 认证:管理后台 JWT
- 幂等:是(只读)
- 入参:无
出参:Result<List<VehicleTypeTreeRespVO>>
按 sort_order 升序。每个大类含 models 数组(同大类内按 sort_order 升序)。无大类时返回空数组 []。
典型示例 请求:
GET /admin/fleet/vehicle-types
Authorization: Bearer <token>
(无请求体)
典型示例 响应:
{
"code": 200,
"data": [
{
"id": "1234567890123456789",
"typeKey": "suv",
"typeName": "SUV 越野",
"icon": "🚙",
"description": "适合山地越野、多人出行",
"sortOrder": 1,
"models": [
{
"id": "9876543210987654321",
"vehicleTypeId": "1234567890123456789",
"modelName": "丰田汉兰达",
"seats": 7,
"basePrice": "800.00",
"alias": "汉兰达,HIGHLANDER",
"sortOrder": 1
}
]
}
],
"msg": "成功"
}
错误码:仅 401 未登录
3.2 大类分页列表 ✨ 新增
GET /admin/fleet/vehicle-types/page
- 使用场景:管理后台「车型管理库」左侧大类导航的分页查询,支持名称模糊、key 精确过滤
- 认证:管理后台 JWT
- 幂等:是(只读)
Query 入参:
| 字段 | 类型 | 必填 | 默认 | 校验 | 说明 |
|---|---|---|---|---|---|
page |
int | ❌ | 1 | >= 1 |
页码 |
pageSize |
int | ❌ | 20 | 1-100 |
每页条数 |
typeName |
string | ❌ | — | — | 大类中文名模糊匹配 |
typeKey |
string | ❌ | — | — | 大类 key 精确匹配 |
出参:Result<PageResult<VehicleTypeRespVO>>
按 sort_order 升序。不含 models 数组(需要型号请调 §3.7)。
| 字段 | 类型 | 说明 |
|---|---|---|
records[].id |
string | 大类 ID(Long 序列化为 String 防精度丢失) |
records[].typeKey |
string | 大类 key(如 suv/mpv/bus/sedan) |
records[].typeName |
string | 大类中文名 |
records[].icon |
string | emoji 图标(可空) |
records[].description |
string | 描述(可空) |
records[].sortOrder |
int | 排序权重 |
total |
int | 总记录数 |
page |
int | 当前页码 |
pageSize |
int | 每页条数 |
典型示例 请求:
GET /admin/fleet/vehicle-types/page?page=1&pageSize=20&typeName=SUV
Authorization: Bearer <token>
(无请求体)
典型示例 响应:
{
"code": 200,
"data": {
"records": [
{
"id": "1234567890123456789",
"typeKey": "suv",
"typeName": "SUV 越野",
"icon": "🚙",
"description": "适合山地越野、多人出行",
"sortOrder": 1
}
],
"total": 1,
"page": 1,
"pageSize": 20
},
"msg": "成功"
}
边界 请求(无过滤拿全部,pageSize=100 极限):
GET /admin/fleet/vehicle-types/page?page=1&pageSize=100
异常 请求(pageSize=101 超限):
GET /admin/fleet/vehicle-types/page?page=1&pageSize=101
响应:
{ "code": 400, "msg": "每页条数最大为100", "data": null }
错误码:400 参数校验 / 401 未登录
3.3 新增大类
POST /admin/fleet/vehicle-types
- 使用场景:扩展车型大类(初始化已灌 4 条 suv/mpv/bus/sedan,后续如新增小型客车等)
- 认证:管理后台 JWT
- 幂等:否(重复调用会触发 600101 重复)
Body 入参(VehicleTypeSaveReqVO):
| 字段 | 类型 | 必填 | 校验 | 说明 |
|---|---|---|---|---|
typeKey |
string | ✅ | @Size(max=16) |
大类 key(全局唯一) |
typeName |
string | ✅ | @Size(max=64) |
大类中文名 |
icon |
string | ❌ | @Size(max=8) |
emoji 图标(可为空) |
description |
string | ❌ | @Size(max=256) |
描述(可为空) |
sortOrder |
int | ✅ | — | 排序权重(升序) |
出参:Result<VehicleTypeRespVO>(同 §3.2 records 项字段)
典型示例 请求:
POST /admin/fleet/vehicle-types
Authorization: Bearer <token>
Content-Type: application/json
{
"typeKey": "minibus",
"typeName": "小型客车",
"icon": "🚐",
"description": "10-19 座中巴",
"sortOrder": 5
}
典型示例 响应:
{
"code": 200,
"data": {
"id": "1234567890123456789",
"typeKey": "minibus",
"typeName": "小型客车",
"icon": "🚐",
"description": "10-19 座中巴",
"sortOrder": 5
},
"msg": "成功"
}
异常 请求(typeKey 重复):
{ "typeKey": "suv", "typeName": "重复 SUV", "sortOrder": 99 }
响应:
{ "code": 600101, "msg": "车型大类 key 已存在", "data": null }
错误码:400 参数校验 / 600101 typeKey 已存在 / 401 未登录
3.4 编辑大类
PUT /admin/fleet/vehicle-types/{typeId}
- 使用场景:修改大类的 typeName / icon / description / sortOrder。typeKey 不可改(后端忽略入参中的 typeKey 字段)
- 认证:管理后台 JWT
- 幂等:是(相同 body 重复调结果一致)
路径入参:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
typeId |
Long | ✅ | 大类 ID |
Body 入参:同 §3.3(typeKey 字段后端忽略;其他字段同新增)
出参:Result<VehicleTypeRespVO>(更新后的大类)
典型示例 请求:
PUT /admin/fleet/vehicle-types/1234567890123456789
Authorization: Bearer <token>
Content-Type: application/json
{
"typeKey": "suv",
"typeName": "SUV 越野 (改名)",
"icon": "🚙",
"description": "新描述",
"sortOrder": 2
}
典型示例 响应:
{
"code": 200,
"data": {
"id": "1234567890123456789",
"typeKey": "suv",
"typeName": "SUV 越野 (改名)",
"icon": "🚙",
"description": "新描述",
"sortOrder": 2
},
"msg": "成功"
}
异常 请求(typeId 不存在):
{ "code": 600102, "msg": "车型大类不存在", "data": null }
错误码:400 参数校验 / 600102 大类不存在 / 401 未登录
3.5 删除大类(软删)
DELETE /admin/fleet/vehicle-types/{typeId}
- 使用场景:下架某个大类。大类下存在型号时禁止删除(应用层校验)
- 认证:管理后台 JWT
- 幂等:是(重复删返同样结果)
路径入参:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
typeId |
Long | ✅ | 大类 ID |
出参:Result<Void>(成功时 data: null)
典型示例 请求:
DELETE /admin/fleet/vehicle-types/1234567890123456789
Authorization: Bearer <token>
(无请求体)
典型示例 响应:
{ "code": 200, "data": null, "msg": "成功" }
异常 请求(大类下有型号):
{ "code": 600104, "msg": "大类下存在型号,不能删除", "data": null }
错误码:600102 大类不存在 / 600104 大类下存在型号 / 401 未登录
3.6 新增型号(挂在指定大类下)
POST /admin/fleet/vehicle-types/{typeId}/models
- 使用场景:在某大类下新增型号(如 SUV 大类下加"路虎揽胜")
- 认证:管理后台 JWT
- 幂等:否(同名重复抛 600103)
路径入参:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
typeId |
Long | ✅ | 所属大类 ID |
Body 入参(VehicleModelSaveReqVO):
| 字段 | 类型 | 必填 | 校验 | 说明 |
|---|---|---|---|---|
modelName |
string | ✅ | @Size(max=64) |
型号名(同大类内唯一) |
seats |
int | ✅ | @Min(4) @Max(19) |
座位数 4-19 |
basePrice |
BigDecimal | ✅ | @DecimalMin("0") |
基础日单价(¥,≥ 0) |
alias |
string | ❌ | @Size(max=256) |
别名(搜索匹配用) |
sortOrder |
int | ✅ | — | 排序权重 |
出参:Result<VehicleModelRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 型号 ID(Long 序列化为 String) |
vehicleTypeId |
string | 所属大类 ID |
modelName |
string | 型号名 |
seats |
int | 座位数 |
basePrice |
string | 基础日单价(BigDecimal 序列化) |
alias |
string | 别名 |
sortOrder |
int | 排序 |
典型示例 请求:
POST /admin/fleet/vehicle-types/1234567890123456789/models
Authorization: Bearer <token>
Content-Type: application/json
{
"modelName": "丰田汉兰达",
"seats": 7,
"basePrice": "800.00",
"alias": "汉兰达,HIGHLANDER",
"sortOrder": 1
}
典型示例 响应:
{
"code": 200,
"data": {
"id": "9876543210987654321",
"vehicleTypeId": "1234567890123456789",
"modelName": "丰田汉兰达",
"seats": 7,
"basePrice": "800.00",
"alias": "汉兰达,HIGHLANDER",
"sortOrder": 1
},
"msg": "成功"
}
异常 请求(座位数 20 超限):
{ "modelName": "大巴车", "seats": 20, "basePrice": "1500.00", "sortOrder": 1 }
响应:
{ "code": 400, "msg": "座位数最大为 19", "data": null }
错误码:400 参数校验 / 600102 大类不存在 / 600103 型号名已存在 / 401 未登录
3.7 型号分页列表 ✨ 新增
GET /admin/fleet/vehicle-types/models/page
- 使用场景:
- 「左侧点击大类 → 右侧加载该大类型号」 → 传
vehicleTypeId - 「跨大类按车型名/俗称搜索」 → 不传
vehicleTypeId,传modelName或alias
- 「左侧点击大类 → 右侧加载该大类型号」 → 传
- 认证:管理后台 JWT
- 幂等:是(只读)
Query 入参:
| 字段 | 类型 | 必填 | 默认 | 校验 | 说明 |
|---|---|---|---|---|---|
page |
int | ❌ | 1 | >= 1 |
页码 |
pageSize |
int | ❌ | 20 | 1-100 |
每页条数 |
vehicleTypeId |
Long | ❌ | — | — | 可选:传则按大类过滤,不传跨大类全量 |
modelName |
string | ❌ | — | — | 型号名模糊匹配 |
seats |
int | ❌ | — | — | 座位数精确匹配 |
alias |
string | ❌ | — | — | 别名模糊匹配(车型俗称) |
出参:Result<PageResult<VehicleModelRespVO>>
按 sort_order 升序。不返大类名称(前端从左侧大类列表自取)。
records 项字段同 §3.6 出参字段表。
典型示例 请求(按大类查):
GET /admin/fleet/vehicle-types/models/page?page=1&pageSize=20&vehicleTypeId=1234567890123456789
Authorization: Bearer <token>
(无请求体)
典型示例 响应:
{
"code": 200,
"data": {
"records": [
{
"id": "9876543210987654321",
"vehicleTypeId": "1234567890123456789",
"modelName": "丰田汉兰达",
"seats": 7,
"basePrice": "800.00",
"alias": "汉兰达,HIGHLANDER",
"sortOrder": 1
}
],
"total": 1,
"page": 1,
"pageSize": 20
},
"msg": "成功"
}
边界 请求(跨大类按 modelName 搜"丰田"):
GET /admin/fleet/vehicle-types/models/page?modelName=丰田
边界 请求(按 seats=7 精确 + alias 模糊组合):
GET /admin/fleet/vehicle-types/models/page?seats=7&alias=ODYSSEY
异常 请求(page=0 不合法):
GET /admin/fleet/vehicle-types/models/page?page=0&pageSize=20
响应:
{ "code": 400, "msg": "页码最小为1", "data": null }
错误码:400 参数校验 / 401 未登录
3.8 编辑型号
PUT /admin/fleet/vehicle-types/models/{modelId}
- 使用场景:修改型号的 modelName / seats / basePrice / alias / sortOrder
- 认证:管理后台 JWT
- 幂等:是
路径入参:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
modelId |
Long | ✅ | 型号 ID |
Body 入参:同 §3.6(不含 typeId,型号所属大类不可改)
出参:Result<VehicleModelRespVO>
典型示例 请求:
PUT /admin/fleet/vehicle-types/models/9876543210987654321
Authorization: Bearer <token>
Content-Type: application/json
{
"modelName": "丰田汉兰达 (2025 款)",
"seats": 7,
"basePrice": "900.00",
"alias": "汉兰达,HIGHLANDER",
"sortOrder": 1
}
异常 请求(型号名同大类内已被占用):
{ "code": 600103, "msg": "车型型号已存在", "data": null }
错误码:400 参数校验 / 600103 型号名已存在 / 600106 型号不存在 / 401 未登录
3.9 删除型号(软删)
DELETE /admin/fleet/vehicle-types/models/{modelId}
- 使用场景:下架某个型号。被车辆引用时禁止删除(应用层校验)
- 认证:管理后台 JWT
- 幂等:是
路径入参:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
modelId |
Long | ✅ | 型号 ID |
出参:Result<Void>
典型示例 请求:
DELETE /admin/fleet/vehicle-types/models/9876543210987654321
Authorization: Bearer <token>
(无请求体)
典型示例 响应:
{ "code": 200, "data": null, "msg": "成功" }
异常 请求(型号被车辆引用):
{ "code": 600105, "msg": "型号被车辆引用,不能删除", "data": null }
错误码:600105 型号被车辆引用 / 600106 型号不存在 / 401 未登录
6. 枚举 / 数据字典
本模块无静态枚举 / 字典:
typeKey是fleet_vehicle_type表的一个VARCHAR(16)字段(行级数据),不是后端枚举常量,没有字典表。系统初始化灌入了 4 条标准记录(详见 §9 业务边界),但 typeKey 可通过 §3.3 自由扩展seats是数值范围(4-19,@Min/@Max校验),不是枚举- 其他字段(modelName / basePrice / alias 等)均为自由文本/数字
7. 错误码(全模块汇总)
| code | 含义 | 触发条件 | 涉及接口 |
|---|---|---|---|
| 400 | 参数校验失败 | 字段缺失 / 长度 / 范围越界 | 所有写入接口 + 分页接口 |
| 401 | 未登录 | JWT 无效或缺失 | 全部 9 接口 |
| 600101 | 车型大类 key 已存在 | typeKey 全局唯一约束 | §3.3 新增大类 |
| 600102 | 车型大类不存在 | typeId 无效或已软删 | §3.4 §3.5 §3.6 |
| 600103 | 车型型号已存在 | 同大类内型号名唯一约束 | §3.6 §3.8 |
| 600104 | 大类下存在型号,不能删除 | 应用层校验 | §3.5 |
| 600105 | 型号被车辆引用,不能删除 | 应用层校验 | §3.9 |
| 600106 | 车型型号不存在 | modelId 无效或已软删 | §3.8 §3.9 |
错误码段位 600101-600106 归属 hl-fleet-service,本次未新增段位。
9. 业务边界
- ✅ 大类 typeKey 编辑:编辑大类时后端忽略入参的 typeKey 字段(不改),其他字段正常更新
- ✅ 大类软删保护:大类下有未删除型号时禁删(600104);先删型号或迁移型号到其他大类
- ✅ 型号软删保护:型号被任一车辆(fleet_vehicle)引用时禁删(600105)
- ✅ 同名约束:typeKey 全局唯一(违反抛 600101);modelName 同大类内唯一(违反抛 600103)
- ✅ 分页默认值:
page=1、pageSize=20、pageSize上限 100 - ✅ 跨大类搜索:§3.7 不传
vehicleTypeId+ 任意过滤 = 跨大类搜索(不报错) - ⚠️ 新增型号副作用:§3.6 新增型号后会触发价格日历初始化(见 FLEET §9.4),前端无需感知
typeKey 系统初始化数据(不是枚举,可被 §3.3 扩展)
系统初始化时灌入了 4 条标准大类(来自 DB 初始化脚本):
| typeKey | typeName | 用途参考 |
|---|---|---|
suv |
SUV 越野 | 高底盘 / 多人出行 |
mpv |
MPV 商务 | 7 座商务车 |
bus |
中巴 | 10-19 座 |
sedan |
轿车 | 5 座 |
⚠️ 这是表里的现有数据,不是枚举校验。运营可随时通过 §3.3 新增
minibus/coach等任意 typeKey(仅约束:全局不重复)。前端展示时建议从 §3.1 或 §3.2 实时查,不要硬编码上面 4 个值。
11. 影响评估
- 是否破坏向后兼容:否(§3.1-§3.6/§3.8/§3.9 契约零变化,仅新增 §3.2 §3.7 两个分页接口)
- 前端是否必须同步上线:否(不调用新接口的页面不受影响)
- 影响已有数据:无(无 DDL,无数据迁移)
12. 注意事项
- 分页参数名:
page/pageSize(不是 pageNo),所有继承 PageParam 的入参都遵此约定 - 主键 Long 序列化:
id/vehicleTypeId等 Long 字段 JSON 返回为 String,前端不要当 Number 解析(精度会丢失)。表单提交时仍可用 Number/String 双向兼容 - 整树 vs 分页的取舍:低基数字典(< 20 大类 / < 200 型号)继续用 §3.1 整树拉一次缓存到内存;高基数或要服务端搜索时用 §3.2 / §3.7
- basePrice 序列化:
BigDecimal序列化为 String(如"800.00"),前端按字符串接收避免精度问题
13. 关联 / 联系人
13.1 链接
- Issue: #2785
- PR: #2786
- Merge commit:
90109cd58 - API 文档:
docs/order-v3/api/API-SPEC-FLEET-V1.5.html§1(车型管理库 6 接口;实际代码 9 端点 = §1.4 编辑/删除合并算 1 节) - 同期相关 PR:
13.2 联系人
- 后端负责人: @yst(腰苏图)
- 前端对接(管理后台): 待指派