32 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 6717 | 车队关联供应商并展示供应商全名 | admin | wx(GIT) | 修改接口 | deployed | verified | verified | mmg | 4faf23bb | v2.1 | 2026-08-30 | PR #6753 已合并 dev-v3(merge commit 447b92f5);Deploy Panel 任务 2fe21f84(hl-fleet-service,2026-08-30 17:20)与 f29a293f(hl-resource-service,2026-08-30 17:22)均已部署测试服成功。真实 TEST 身份已验证 5 条负向链路全绿 + 列表字段结构正确,测试数据已清理。车队列表操作列的「供应商」按钮需下线,改为在车队新增/编辑弹窗选择供应商。前端已消费(frontend_status: verified):车队列表下线操作列「供应商」入口并新增供应商列透传 supplierName 快照;新增/编辑弹窗内嵌供应商 NSelect(远程搜索 FLEET+ACTIVE、可清空、编辑回填并补快照选项防显原始 ID),提交体携带 supplierId 字符串;601108/601109/601110/601111 按 bizCode 精确提示,新建不选供应商落 DISABLED 并提示。前端 commit 4faf23bb 已推 v2.1。 | 2026-08-30 | dev-v3 |
车队管理:车队关联供应商并展示供应商全名
存放目录:
- 二期(v3,
order-v3标签的工单)→changelogs-v2/2026-08/服务: hl-fleet-service(端口 8094)/ hl-resource-service(内部依赖) PR: #6753 Issue: #6717 日期: 2026-08-30 影响范围: 管理后台「车辆管理 - 车队管理」列表/新增/编辑/启用
车队管理新增供应商归属字段(可空),供应商只能随车队新增/编辑一起提交,不再提供单独配置入口。
⚠️ 关键变化
- 车队列表操作列的「供应商」按钮(
views/fleet/teams/index.vue弹窗SupplierResourceRelModal)需要下线;供应商关联改为在车队新增/编辑弹窗里选择。 - 「不选供应商不能启动,只能停用」:未关联供应商的车队调用启用接口会被 601108 拦截;新建时不选供应商则车队落停用态。
- 已有订单(名下车辆存在非取消派单)的车队,不允许更换或清除供应商;允许首次绑定。
一、背景
车队此前没有供应商归属字段;供应商域(supplier_main,类型字典 supplier_type)已支持车队类型供应商(FLEET),但车队主数据与供应商档案之间未建立关联。工单 #6717 要求车队管理列表展示供应商全名,并在车队新增/编辑时明确供应商归属。
最终口径(2026-08-30 用户确认,覆盖工单原文「必选」语义):
- 供应商字段不必填(可选);不选 → 不能启用,只能停用。
- 车队已有订单时,不允许更换或清除供应商(含已有订单的历史车队豁免存量,不动存量数据)。
- 去掉单独配置供应商接口入口:前端车队列表的「供应商」按钮下线;供应商关联只随车队新增/编辑一起提交。
- 供应商全名以写时快照存于
fleet_team.supplier_name;列表/详情零 Feign 读,供应商改名后陈旧、重新编辑可刷新。 - 供应商资格校验走跨服务 Feign(fleet → resource
GET /internal/supplier/{supplierId}/fleet-eligibility):主体存在 + 状态 ACTIVE + 类型关联含 FLEET。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 分页查询车队 | GET | /admin/fleet/teams/page |
响应新增字段 | records[] 增加 supplierId(String/null) + supplierName(String/null) |
| 2 | 查询车队详情 | GET | /admin/fleet/teams/{fleetTeamId} |
响应新增字段 | 同 #1 |
| 3 | 新增车队 | POST | /admin/fleet/teams |
请求体新增可选字段 + 响应新增字段 | 请求体加 supplierId(Long 字符串/可空);响应同 #2 |
| 4 | 编辑车队 | PUT | /admin/fleet/teams/{fleetTeamId} |
请求体新增可选字段 + 响应新增字段 + 失败语义 | 请求体加 supplierId;更换/清除时已有订单被 601111 拦截;清除且当前 ACTIVE 会强制落 DISABLED |
| 5 | 启用车队 | POST | /admin/fleet/teams/{fleetTeamId}/enable |
失败语义新增 | supplierId==null 时抛 601108「车队未关联供应商,不能启用」 |
三、接口详情
1. 分页查询车队 GET /admin/fleet/teams/page
VO: FleetTeamPageReqVO / Result<PageResult<FleetTeamRespVO>>
使用场景
管理后台「车辆管理 - 车队管理」列表页加载时调用。供应商列新增展示。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
page |
Query | Integer | 否 | ≥1,默认 1 | 页码 |
pageSize |
Query | Integer | 否 | 1..100,默认 10 | 每页大小 |
keyword |
Query | String | 否 | ≤64 | 车队名称/负责人姓名模糊搜索 |
teamType |
Query | String | 否 | SELF_OPERATED/COOPERATIVE |
车队类型筛选 |
status |
Query | String | 否 | ACTIVE/DISABLED |
状态筛选 |
settleType |
Query | String | 否 | cash/sign/company |
付款方式筛选 |
出参 Result<PageResult<FleetTeamRespVO>>
records[] 每一项 FleetTeamRespVO 字段(与改前相比只多两列,其余字段语义不变):
| 字段 | 类型 | 说明 |
|---|---|---|
fleetTeamId |
String | 车队 ID(雪花序列化为字符串,禁止转 Number) |
teamCode |
String | 内部稳定编码(ft_xxx) |
teamName |
String | 车队名称 |
teamType |
String | SELF_OPERATED/COOPERATIVE |
leaderName |
String | 负责人姓名 |
leaderPhone |
String | 负责人电话(分页脱敏:138****8000) |
settleType |
String | cash/sign/company |
status |
String | ACTIVE/DISABLED |
sortOrder |
Integer | 排序值 |
remark |
String | 备注 |
vehicleCount |
Integer | 名下车辆总数(含停用) |
activeVehicleCount |
Integer | 名下在役车辆数 |
supplierId |
String/null | 关联供应商 ID(雪花字符串;未关联为 null) |
supplierName |
String/null | 关联供应商全称快照(写时同步,未关联为 null) |
createTime |
String | 创建时间 yyyy-MM-dd HH:mm:ss |
updateTime |
String | 最后更新时间 yyyy-MM-dd HH:mm:ss |
请求示例
GET /admin/fleet/teams/page?page=1&pageSize=10&status=ACTIVE
Authorization: Bearer <admin-token>
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"total": 2,
"page": 1,
"pageSize": 10,
"records": [
{
"fleetTeamId": "2102345678901234567",
"teamCode": "ft_2x9k3m",
"teamName": "合作车队A",
"teamType": "COOPERATIVE",
"leaderName": "测试负责人甲",
"leaderPhone": "138****0001",
"settleType": "cash",
"status": "ACTIVE",
"sortOrder": 10,
"remark": "由 fleet_attribution/历史业务数据迁移",
"vehicleCount": 12,
"activeVehicleCount": 9,
"supplierId": "2091381911266967553",
"supplierName": "内蒙古呼籁旅游服务有限公司",
"createTime": "2026-06-01 10:00:00",
"updateTime": "2026-08-30 15:30:00"
},
{
"fleetTeamId": "2102345678901234568",
"teamCode": "ft_2x9k3n",
"teamName": "自有车队",
"teamType": "SELF_OPERATED",
"leaderName": "自有负责人",
"leaderPhone": "139****0002",
"settleType": "company",
"status": "DISABLED",
"sortOrder": 20,
"remark": "",
"vehicleCount": 0,
"activeVehicleCount": 0,
"supplierId": null,
"supplierName": null,
"createTime": "2026-08-01 09:00:00",
"updateTime": "2026-08-30 15:30:00"
}
]
}
}
空数据 / 降级响应
无车队时 records=[] total=0,code=200。供应商字段未关联时为 null(不是空串),前端按未关联渲染。
错误响应
分页查询无业务错误分支。网关/框架错误:
{ "code": 401, "message": "未登录", "success": false, "data": null }
业务边界
- 只读查询;返回的
supplierId/supplierName来自fleet_team.supplier_id/supplier_name列快照,不做实时跨服务取数。 - 供应商改名后列表展示旧名(快照口径);如需最新名称,让用户重新编辑车队保存触发刷新。
- 车队停用车队(
status=DISABLED)也可被列表查到(不带状态筛选时默认返回全部状态)。
2. 查询车队详情 GET /admin/fleet/teams/{fleetTeamId}
VO: Result<FleetTeamRespVO>
使用场景
管理后台编辑车队弹窗初始化时调用,回填 supplierId/supplierName 到供应商选择器。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
fleetTeamId |
Path | String(Long) | 是 | 正整数 ID 字符串 | 目标车队 ID(雪花,不得转 Number) |
出参 Result<FleetTeamRespVO>
字段与 #1 records[] 项结构一致(含新增 supplierId/supplierName):
| 字段 | 类型 | 说明 |
|---|---|---|
fleetTeamId |
String | 车队 ID(雪花序列化为字符串,禁止转 Number) |
teamCode |
String | 内部稳定编码(ft_xxx) |
teamName |
String | 车队名称 |
teamType |
String | SELF_OPERATED/COOPERATIVE |
leaderName |
String | 负责人姓名 |
leaderPhone |
String | 负责人电话(详情返回原值,编辑场景回填用) |
settleType |
String | cash/sign/company |
status |
String | ACTIVE/DISABLED |
sortOrder |
Integer | 排序值 |
remark |
String | 备注 |
vehicleCount |
Integer | 名下车辆总数(含停用) |
activeVehicleCount |
Integer | 名下在役车辆数 |
supplierId |
String/null | 关联供应商 ID(雪花字符串;未关联为 null) |
supplierName |
String/null | 关联供应商全称快照(写时同步) |
createTime |
String | 创建时间 yyyy-MM-dd HH:mm:ss |
updateTime |
String | 最后更新时间 yyyy-MM-dd HH:mm:ss |
请求示例
GET /admin/fleet/teams/2102345678901234567
Authorization: Bearer <admin-token>
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"fleetTeamId": "2102345678901234567",
"teamCode": "ft_2x9k3m",
"teamName": "合作车队A",
"teamType": "COOPERATIVE",
"leaderName": "测试负责人甲",
"leaderPhone": "13800000001",
"settleType": "cash",
"status": "ACTIVE",
"sortOrder": 10,
"remark": "由 fleet_attribution/历史业务数据迁移",
"vehicleCount": 12,
"activeVehicleCount": 9,
"supplierId": "2091381911266967553",
"supplierName": "内蒙古呼籁旅游服务有限公司",
"createTime": "2026-06-01 10:00:00",
"updateTime": "2026-08-30 15:30:00"
}
}
空数据 / 降级响应
车队不存在或已软删除(业务错误,见下方错误响应);无空数据分支。
错误响应
车队不存在或已软删除:
{ "code": 601100, "message": "车队不存在", "success": false, "data": null }
未登录(网关拦截):
{ "code": 401, "message": "未登录", "success": false, "data": null }
业务边界
- 详情接口返回
leaderPhone为原值(编辑场景需要回填),分页接口脱敏。 supplierId必须按字符串处理,禁止转 JavaScript Number。
3. 新增车队 POST /admin/fleet/teams
VO: FleetTeamSaveReqVO / Result<FleetTeamRespVO>
使用场景
管理后台「车辆管理 - 车队管理」点击「新增车队」,在表单里可选填供应商。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
teamName |
Body | String | 是 | ≤64,唯一 | 车队名称 |
teamType |
Body | String | 是 | SELF_OPERATED/COOPERATIVE |
车队类型 |
leaderName |
Body | String | 是 | ≤64 | 负责人姓名 |
leaderPhone |
Body | String | 是 | 电话格式正则 | 负责人电话 |
settleType |
Body | String | 是 | cash/sign/company |
付款方式 |
sortOrder |
Body | Integer | 是 | ≥0 | 排序 |
remark |
Body | String | 否 | ≤256 | 备注 |
supplierId |
Body | String(Long)/null | 否 | @Positive |
关联供应商 ID(雪花字符串;不填=不选供应商,新建车队落 DISABLED) |
出参 Result<FleetTeamRespVO>
响应结构同 #2;supplierId/supplierName 按请求回填(选了供应商且校验通过则写入快照,否则为 null)。
| 字段 | 类型 | 说明 |
|---|---|---|
fleetTeamId |
String | 新车队 ID(雪花序列化为字符串) |
supplierId |
String/null | 按请求回填(选了且校验通过) |
supplierName |
String/null | 写时同步的供应商全称快照;未选为 null |
status |
String | 选供应商=ACTIVE;不选=DISABLED |
createTime |
String | 创建时间 yyyy-MM-dd HH:mm:ss |
updateTime |
String | 创建时间(与 createTime 相同) |
| (其余字段) | - | 与详情 #2 同构 |
请求示例
POST /admin/fleet/teams
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"teamName": "新合作车队B",
"teamType": "COOPERATIVE",
"leaderName": "王队长",
"leaderPhone": "13800138000",
"settleType": "sign",
"sortOrder": 20,
"remark": "新签约车队",
"supplierId": "2091381911266967553"
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"fleetTeamId": "2103456789012345678",
"teamCode": "ft_3a1b2c",
"teamName": "新合作车队B",
"teamType": "COOPERATIVE",
"leaderName": "王队长",
"leaderPhone": "13800138000",
"settleType": "sign",
"status": "ACTIVE",
"sortOrder": 20,
"remark": "新签约车队",
"vehicleCount": 0,
"activeVehicleCount": 0,
"supplierId": "2091381911266967553",
"supplierName": "内蒙古呼籁旅游服务有限公司",
"createTime": "2026-08-30 16:00:00",
"updateTime": "2026-08-30 16:00:00"
}
}
空数据 / 降级响应
未选供应商创建(落 DISABLED,供应商字段为 null):
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"fleetTeamId": "2103456789012345679",
"teamCode": "ft_3a1b2d",
"teamName": "临时车队",
"teamType": "COOPERATIVE",
"leaderName": "临时负责人",
"leaderPhone": "13900139000",
"settleType": "cash",
"status": "DISABLED",
"sortOrder": 30,
"remark": "",
"vehicleCount": 0,
"activeVehicleCount": 0,
"supplierId": null,
"supplierName": null,
"createTime": "2026-08-30 16:00:00",
"updateTime": "2026-08-30 16:00:00"
}
}
错误响应
供应商不存在/未生效/不含车队类型(不写库):
{ "code": 601109, "message": "供应商不存在、未生效或不包含车队类型", "success": false, "data": null }
供应商校验依赖故障(Feign 不可用,不写库):
{ "code": 601110, "message": "暂时无法校验供应商,请稍后重试", "success": false, "data": null }
车队名称重复(uk_fleet_team_name 唯一索引兜底):
{ "code": 601101, "message": "车队名称已存在", "success": false, "data": null }
Bean Validation 校验失败:
{ "code": 400, "message": "供应商ID必须为正数", "success": false, "data": null }
业务边界
- 幂等:同一 teamName + 请求摘要 10 秒窗口内重复提交只生效一次(@Idempotent key=
fleet:team:create:{teamName})。 - 分布式锁:同 teamName 创建串行化(@Lock4j)。
- 选供应商时先 Feign 校验(事务外),通过后写库(事务内),Feign 失败/不合格一律不写库(失败关闭)。
- 不写供应商时新建车队 status=DISABLED,需后续编辑绑定供应商后才能启用。
4. 编辑车队 PUT /admin/fleet/teams/{fleetTeamId}
VO: FleetTeamSaveReqVO / Result<FleetTeamRespVO>
使用场景
管理后台编辑车队弹窗提交。可修改基础字段 + 供应商;不允许修改 status(启停用走独立接口)。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
fleetTeamId |
Path | String(Long) | 是 | 正整数 ID 字符串 | 目标车队 ID(不得转 Number) |
| (其余字段) | Body | String | 同新增 | 同新增 | 全字段提交(SaveReqVO 整体语义) |
supplierId |
Body | String(Long)/null | 否 | @Positive |
供应商 ID;更换/清除受订单围栏 |
出参 Result<FleetTeamRespVO>
同 #2;supplierId/supplierName 反映最新写入值。
| 字段 | 类型 | 说明 |
|---|---|---|
fleetTeamId |
String | 车队 ID(路径回显) |
supplierId |
String/null | 最新写入值(更换/清除后刷新) |
supplierName |
String/null | 最新写入快照(更换时取新供应商 full_name;清除时为 null) |
status |
String | 清除供应商且当前 ACTIVE 时强制落 DISABLED;其余场景不变 |
updateTime |
String | 本次写入时间(秒级严格递增) |
| (其余字段) | - | 与详情 #2 同构 |
请求示例
PUT /admin/fleet/teams/2102345678901234567
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"teamName": "合作车队A",
"teamType": "COOPERATIVE",
"leaderName": "测试负责人甲",
"leaderPhone": "13800000001",
"settleType": "cash",
"sortOrder": 10,
"remark": "",
"supplierId": "2091381911266967553"
}
响应示例
成功(更换供应商且无订单):
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"fleetTeamId": "2102345678901234567",
"teamCode": "ft_2x9k3m",
"teamName": "合作车队A",
"teamType": "COOPERATIVE",
"leaderName": "测试负责人甲",
"leaderPhone": "13800000001",
"settleType": "cash",
"status": "ACTIVE",
"sortOrder": 10,
"remark": "",
"vehicleCount": 12,
"activeVehicleCount": 9,
"supplierId": "2091381911266967553",
"supplierName": "内蒙古呼籁旅游服务有限公司",
"createTime": "2026-06-01 10:00:00",
"updateTime": "2026-08-30 16:30:00"
}
}
空数据 / 降级响应
清除供应商(原值 → null)且车队无订单:快照清空,若当前 ACTIVE 强制落 DISABLED(保持不变量:ACTIVE ⇒ 已绑供应商)。
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"fleetTeamId": "2102345678901234567",
"teamCode": "ft_2x9k3m",
"teamName": "合作车队A",
"teamType": "COOPERATIVE",
"status": "DISABLED",
"supplierId": null,
"supplierName": null,
"updateTime": "2026-08-30 16:30:00"
}
}
错误响应
车队已有订单时更换/清除供应商(含从原供应商换到新供应商、从原供应商清为空):
{ "code": 601111, "message": "车队已关联订单,不能更换供应商", "success": false, "data": null }
供应商校验失败(同新增 #3 的 601109/601110);车队不存在:
{ "code": 601100, "message": "车队不存在", "success": false, "data": null }
业务边界
- 幂等:同 fleetTeamId + 请求摘要(含 supplierId 参与摘要)10 秒窗口内重复提交只生效一次(@Idempotent key=
fleet:team:update:{fleetTeamId}:{sha256})。 - 分布式锁:同 fleetTeamId 编辑串行化(@Lock4j)。
- 更换供应商校验顺序:订单围栏(601111)→ Feign 资格校验(601109/601110)→ 写库。
- 供应商不变时(含 null→null)不触发订单围栏,也不调 Feign。
- 首次绑定(null → 新值)即使已有订单也允许。
status不在 SaveReqVO,本接口不修改启停状态;清除供应商且当前 ACTIVE 时强制落 DISABLED 是唯一例外。
5. 启用车队 POST /admin/fleet/teams/{fleetTeamId}/enable
VO: Result<Void>
使用场景
管理后台对已停用车队点击「启用」。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
fleetTeamId |
Path | String(Long) | 是 | 正整数 ID 字符串 | 目标车队 ID |
出参 Result<Void>
成功时 data=null:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
Integer | 恒为 200 表示成功 |
data |
null | 启用接口无返回体 |
空数据 / 降级响应
启用成功恒返回 {"code":200,"success":true,"data":null};无空数据分支。已是启用态时幂等放行不重复写(返回同样结构)。
请求示例
POST /admin/fleet/teams/2102345678901234567/enable
Authorization: Bearer <admin-token>
响应示例
{ "code": 200, "message": "成功", "success": true, "data": null }
错误响应
未关联供应商(新增语义):
{ "code": 601108, "message": "车队未关联供应商,不能启用", "success": false, "data": null }
已是启用态(幂等放行,不重复写):
{ "code": 200, "message": "成功", "success": true, "data": null }
车队不存在:601100。
业务边界
- 幂等:同 fleetTeamId 重复调用只生效一次(@Idempotent key=
fleet:team:enable:{fleetTeamId})。 - 分布式锁:同 fleetTeamId 启停用串行化(@Lock4j key=
fleet:team:status:{fleetTeamId})。 - 存量迁移车队(own/coopA/coopB)当前 ACTIVE 且无供应商:enable 若已被置 DISABLED 后会被 601108 拦截,需先编辑绑定供应商再启用。
四、契约约束与正确调用方式
✅ 正确 / ❌ 错误 payload 对照
| 场景 | 调用 / 结果 |
|---|---|
| ✅ 新增时不选供应商 | { "supplierId": null }(或不传)→ 车队落 DISABLED,待绑定后启用 |
| ✅ 新增时选供应商 | { "supplierId": "2091381911266967553" } → Feign 校验通过后落 ACTIVE |
| ✅ 编辑时供应商不变 | 原 supplierId 原样传回(或省略由后端按原值处理?——必须原样传,SaveReqVO 整份语义) |
| ✅ 首次绑定 | 原 supplierId=null,新 supplierId=有效 FLEET 供应商 → 允许(不受订单围栏) |
| ✅ 供应商改名后刷新快照 | 重新编辑车队并保存(supplierId 原样),快照重新取最新 full_name |
| ❌ 供应商 ID 转 Number | 雪花精度丢失;必须按字符串传输 |
| ❌ 已有订单车队换供应商 | 601111,不写库 |
| ❌ 已有订单车队清供应商 | 601111,不写库 |
| ❌ 清除供应商后期望仍 ACTIVE | 无订单时快照清空+强制 DISABLED;前端收到 200 但 status=DISABLED 属于预期行为 |
关键提示(当前 TEST 构建)
supplierId/supplierName在所有响应中均按字符串序列化(@JsonSerialize(ToStringSerializer));禁止前端用Number()/parseInt()/一元+转换。- 供应商全名快照为写时取数:
supplier_main.full_name改名后列表展示旧值,重新编辑车队保存触发刷新。 - 供应商选择器数据源:可复用
GET /admin/supplier/items/list?typeCode=FLEET&status=ACTIVE(mmg 自查前端是否已有该接口封装;无则后端再补)。
五、数据库行为
- 写操作只影响
fleet_team一行(新增 insert / 编辑 update / 启停用 update),不跨服务写supplier_resource_rel或supplier_main。 - 快照列:
supplier_id(关联 ID)+supplier_name(全称快照)同列写入;清除时同列置 NULL。 - 幂等窗口内重复请求只写一次;锁键串行化同车队写。
- 迁移:
V20260830_001__add_supplier_to_fleet_team.sql对fleet_team加supplier_id BIGINT NULL+supplier_name VARCHAR(500) NULL+ 索引idx_fleet_team_supplier(supplier_id);存量车队两列均为 NULL。 - 不动
supplier_resource_rel(车队供应商不走资源关系表;关系表仅用于九大资源模块)。
六、边界行为
- 未登录/登录失效:业务码
401(网关拦截)。 - 车队不存在:
601100。 - 车队名称重复:
601101(含 DuplicateKeyException 翻译)。 - 车队已停用仍选该车:
601102(既有口径,本工单不改)。 - 车队下有在役车辆时禁止停用:
601103(既有口径)。 - 车队已关联车辆时禁止改自有/合作类型:
601104(既有口径)。 - 车队名下仍有车辆/司机时禁止删除:
601107(既有口径)。 - 车队未关联供应商禁止启用:
601108(新增)。 - 供应商不存在/未生效/不含车队类型:
601109(新增)。 - 供应商校验依赖故障:
601110(新增,失败关闭不写库)。 - 车队已有订单禁止更换/清除供应商:
601111(新增)。 - Bean Validation 校验失败:
400。 - 跨服务 Feign 不可用:写接口一律失败关闭(601110);读接口(列表/详情)读快照列,不受影响。
六.5、枚举 / 数据字典
status(车队启停状态)
所属字段: FleetTeamRespVO.status | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
ACTIVE |
启用 | 可被车辆选择;前提:已关联供应商 |
DISABLED |
停用 | 不可被车辆选择;新建未选供应商时默认落此态 |
teamType(车队类型)
所属字段: FleetTeamSaveReqVO.teamType / FleetTeamRespVO.teamType | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
SELF_OPERATED |
自有 | 自有车队 |
COOPERATIVE |
合作 | 合作车队 |
settleType(付款方式,字典 resource_settle_type)
所属字段: FleetTeamSaveReqVO.settleType / FleetTeamRespVO.settleType | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
cash |
现付 | - |
sign |
挂账签单 | - |
company |
公司月结 | - |
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
FleetTeamSaveReqVO.supplierId |
无 | 新增可选字段,@Positive,参与幂等摘要 |
FleetTeamRespVO.supplierId |
无 | 新增,String/null(ToStringSerializer) |
FleetTeamRespVO.supplierName |
无 | 新增,String/null(快照) |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 新建车队默认状态 | ACTIVE | 选供应商=ACTIVE;不选=DISABLED |
| 启用校验 | 只查当前状态 | 增加 supplierId==null → 601108 |
| 编辑车队供应商 | 无此字段 | 有订单禁换/禁清(601111);清除+ACTIVE→强制 DISABLED |
| 供应商配置入口 | 前端有独立「供应商」按钮(调通用资源关系接口) | 下线;改为车队新增/编辑内嵌选择 |
六.7、影响评估
- 是否破坏向后兼容: 否(新增可选字段;响应只多两列,前端旧版忽略即兼容)
- 前端是否必须同步上线: 是(车队列表「供应商」按钮需下线,否则用户仍能从旧入口调通用接口——但通用接口对车队模块本工单起后端侧保留不拦,是前端入口下线)
- 前端 workaround 清理点: 车队列表的「供应商」操作入口(
views/fleet/teams/index.vue中supplierRelaShow/supplierRelaRow/openSupplierRelation相关代码)整体删除
七、不影响范围
- 仅影响: 管理后台「车辆管理 - 车队管理」列表/新增/编辑/启用 4 个端点 + 详情 1 个端点。
- 零影响:
- 车辆档案(
fleet_vehicle)/ 司机档案(fleet_driver)/ 派单(fleet_assignment)等车队下游域——它们继续经FleetTeamService.resolveForVehicle解析车队,供应商字段不影响车辆选车队。 - 供应商域九大资源模块(景区/餐厅/备品/组合/游玩项目/酒店/服务/额外成本/服务人员/车辆)的独立供应商关系维护(
/admin/supplier/resource-relations/{module}/{id}/update等通用接口保留不动)。 - 订单/对账/看板读路径(只读 fleet_team 既有字段,新增两列不影响)。
- Gateway 路由(
/admin/fleet/**通配已覆盖;/internal/**不走网关)。 - Redis/MQ(无新增 key/消息)。
- 车辆档案(
八、测试环境已验证
真实 TEST 环境实测(2026-08-30,网关 https://api.test.1814.love:9443,admin token 走 /admin/auth/login):
POST /admin/fleet/teams 无供应商新建 → 200, status=DISABLED, supplierId=null, supplierName=null ✓
POST /admin/fleet/teams/{id}/enable 无供应商启用 → 601108「车队未关联供应商,不能启用」 ✓
PUT /admin/fleet/teams/{id} 绑定 DRAFT 供应商 → 601109 ✓
PUT /admin/fleet/teams/{id} 绑定不存在供应商 → 601109 ✓
PUT /admin/fleet/teams/{id} 绑定非 FLEET 类型 ACTIVE 供应商(RESTAURANT) → 601109 ✓
GET /admin/fleet/teams/page → records[] 含 supplierId/supplierName 键(未关联为 null) ✓
- 部署:Deploy Panel 任务
2fe21f84(hl-fleet-service,2026-08-30 17:20 success)+f29a293f(hl-resource-service,2026-08-30 17:22 success),预期/实际提交均为447b92f5143e9ca4381d590d4f868d518cf66e0a(dev-v3 HEAD)。 - 正向链路(绑定合格 FLEET ACTIVE 供应商 → ACTIVE + 快照写 supplierName):测试服当前无 ACTIVE 状态的 FLEET 类型供应商(供应商审批链要求必备资质,
supplier_type_qualification_rule规则表为空,无法造出合格供应商);该路径本地单测已覆盖(FleetTeamServiceTest#create_withEligibleSupplier_activeAndSnapshot等 24 用例全绿),建议 mmg 联调时在真实数据上补验。 - 有订单换供应商(601111)链路:测试服车队均无订单派单可安全构造验证数据,本地单测覆盖(
FleetTeamServiceTest#update_changeSupplierWithOrders_rejected/update_clearSupplierWithOrders_rejected)。 - 本地自动化:fleet 全量 3883 项 0 失败 0 错误(含 FleetRedLineArchTest 13 项门禁);resource 全量 0 失败 0 错误;spotless:check 绿。
- 数据清理:测试车队(352385968453586944)与测试供应商(2093993745543299074)均已删除;未触碰同事真实订单;admin token 已登出。
九、相关历史 PR
| PR | Issue | 说明 | 是否仍有效 |
|---|---|---|---|
| #6753 | #6717 | 车队关联供应商并展示供应商全名(本次) | ✅ 最新 |
十、相关文档
- 关联 Issue: wx/HL#6717
- 关联 PR: wx/HL#6753
- 任务设计文档:
docs/tasks/6717-fleet-team-supplier.md(worktreeD:\work2\HL-v3-0830-fleetsup)
撤回
- 管理端先恢复车队列表「供应商」操作入口(参照改前版本),保持线上可用。
- 从最新
dev-v3建独立回退分支,回退 PR #6753 的合并 commit(72c9018ab及其后续如有),验证后经独立 PR 合入。 - 仅需下线新供应商字段时可先保留两列(快照保留无副作用),只回退 Controller/Service 逻辑与 Feign 校验。
- 使用 Deploy Panel 滚动部署
hl-fleet-service与hl-resource-service;数据库列保留不删(supplier_id/supplier_name允许 NULL,回退后不影响)。 - 撤回后经 Gateway 验证新增/编辑/启用接口按改前口径通过;车队列表的供应商列展示空白或下线列头。
关联 / 联系人
链接
联系人
- 后端负责人: @wx
- 前端联动: @mmg(下线车队列表「供应商」按钮 + 车队新增/编辑弹窗加供应商选择器)