13 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, generated
| 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 | generated |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 6811 | 车队保存(无供应商)自动落停用;仍有在役车辆时以 601112 拒绝保存 | admin | wx(GIT) | 修改接口 | deployed | verified | verified | mmg | 6985f0cf | v2.1 | 2026-08-31 | #6717 只在「本次保存清除供应商」时强制停用,存量无供应商车队原样再保存仍停留启用。本单把守卫改为按保存结果判定,并对齐 disable 的在役车辆不变量新增 601112。TEST 已实测两条分支。前端已消费:submitForm 补 601112 精确提示,保存后以响应/列表刷新状态展示。 | 2026-08-31 | dev-v3 | 2026-08-31T10:45:00+08:00 |
车队编辑保存:无供应商时自动落停用,仍有在役车辆则以 601112 拒绝
服务: hl-fleet-service (端口 8087/8187) PR: #6827 Issue: #6811 日期: 2026-08-31 影响范围: 管理后台车务 → 车队管理 → 编辑车队保存
⚠️ 关键变化
- 保存车队时若结果为无供应商(
supplierId传null或不传),后端不再允许车队停留在「启用」:无在役车辆时自动把状态落为DISABLED,前端保存成功后需按响应/列表刷新后的状态展示,不能沿用提交前的「启用」。 - 上一版(#6717)只在「本次保存把已绑供应商清空」时才强制停用,存量无供应商车队原样再保存不变状态。该行为已收口:现在按保存结果判定,
null → null同样强制停用。 - 新增错误码 601112:无供应商需自动停用但车队仍有在役车辆时,保存整体失败、零写入。
一、背景
fleet_team 的不变量是 ACTIVE ⇒ 已绑供应商。此前新建(无供应商落停用)和启用(无供应商 601108 拒绝)都有守卫,唯独编辑保存漏了「结果无供应商」这一路,导致管理后台车队列表出现「供应商列为 —(无供应商)+ 状态启用」的行,且反复保存也不收敛。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 修改车队 | PUT | /admin/fleet/teams/{fleetTeamId} |
状态副作用 + 新增错误码 | 保存结果无供应商时自动落停用;仍有在役车辆则 601112 拒绝 |
三、接口详情
1. 修改车队 PUT /admin/fleet/teams/{fleetTeamId}
VO: FleetTeamSaveReqVO → Result<FleetTeamRespVO>
使用场景
车务 → 车队管理 → 列表行「编辑」→ 弹窗改车队名称/类型/负责人/电话/付款方式/排序/备注/供应商后点「保存」。本次仅状态副作用与错误码变化,路径、请求字段、字段类型与必填性都不变。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| fleetTeamId | Path | String(雪花 ID) | ✅ | - | 车队 ID,字符串传递,禁止数值化 |
| teamName | Body | String | ✅ | 非空、全局唯一 | 车队名称 |
| teamType | Body | String | ✅ | SELF_OPERATED / COOPERATIVE |
已关联车辆时不可切换 |
| leaderName | Body | String | ✅ | 非空 | 负责人 |
| leaderPhone | Body | String | ✅ | 手机号 | 负责人电话 |
| settleType | Body | String | ✅ | cash / sign / company |
付款方式(资源付款方式字典) |
| sortOrder | Body | Integer | ✅ | ≥ 0 | 排序 |
| remark | Body | String | ❌ | ≤ 256 | 备注,空串按 null 落库 |
| supplierId | Body | String(雪花 ID) | ❌ | 供应商需生效且含 FLEET 类型 | 不传或传 null = 不选供应商,触发本次自动停用规则 |
出参 Result<FleetTeamRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| fleetTeamId | String | 车队 ID |
| teamName | String | 车队名称 |
| teamType | String | SELF_OPERATED / COOPERATIVE |
| status | String | ACTIVE / DISABLED;保存结果无供应商时返回 DISABLED |
| settleType | String | 付款方式 |
| sortOrder | Integer | 排序 |
| supplierId | String / null | 关联供应商 ID,null = 未关联 |
| supplierName | String / null | 供应商全称快照,供应商为 null 时同步清空 |
| vehicleCount | Number | 名下车辆总数 |
| activeVehicleCount | Number | 在役车辆数 |
请求示例
无供应商的车队原样保存(触发自动停用):
{
"teamName": "测试车队P4-1787131721",
"teamType": "COOPERATIVE",
"leaderName": "测试负责人",
"leaderPhone": "13900000001",
"settleType": "cash",
"sortOrder": 99,
"remark": "由 fleet_attribution/历史业务数据迁移,负责人待完善",
"supplierId": null
}
响应示例
无供应商 + 无在役车辆 → 200,且 status 已变 DISABLED:
{
"code": 200,
"message": "成功",
"data": {
"fleetTeamId": "348397854705979392",
"teamName": "测试车队P4-1787131721",
"teamType": "COOPERATIVE",
"status": "DISABLED",
"settleType": "cash",
"sortOrder": 99,
"supplierId": null,
"supplierName": null,
"vehicleCount": 0,
"activeVehicleCount": 0
},
"success": true
}
空数据 / 降级响应
本接口为写接口,不返回空集。供应商资格校验依赖(resource 侧)不可用时失败关闭,不降级放行:
{
"code": 601110,
"message": "暂时无法校验供应商,请稍后重试",
"success": false,
"data": null
}
错误响应
新增(本次)——无供应商需自动停用但仍有在役车辆:
{
"code": 601112,
"message": "车队未关联供应商需自动停用,但仍有在役车辆,请先关联供应商或转移在役车辆",
"success": false,
"data": null
}
本接口其他错误码(本次未变,供自包含联调):
| code | message | 触发条件 |
|---|---|---|
| 601100 | 车队不存在 | fleetTeamId 无对应车队 |
| 601101 | 车队名称已存在 | teamName 与其他车队重名 |
| 601104 | 车队已关联车辆,不能修改自有/合作类型 | 名下有车辆时改 teamType |
| 601106 | 付款方式不是有效的资源付款方式 | settleType 不在 cash/sign/company |
| 601109 | 供应商不存在、未生效或不包含车队类型 | 绑定的 supplierId 不合格 |
| 601110 | 暂时无法校验供应商,请稍后重试 | 供应商资格校验依赖不可用 |
| 601111 | 车队已关联订单,不能更换供应商 | 已绑供应商的车队换绑/清除且名下车辆有非取消派单 |
业务边界
- 鉴权:需登录且具备车务车队管理权限;未登录网关返 401。
- 状态不由前端入参驱动:请求体没有
status字段,启停仍由/disable、/enable切;唯一例外是本次的自动停用副作用。 - 供应商未变时不调供应商资格校验,也不查订单围栏;仅当
supplierId发生变化才校验。 - 已绑供应商的车队换绑或清除时,名下车辆若有非取消派单一律 601111(该守卫先于 601112 判定)。
- 失败零写入:601112、601111、601109、601110 均在写库前抛出,名称、排序、备注等字段都不会部分保存。
- 并发:同一
fleetTeamId的保存互斥(分布式锁),重复提交不会产生中间态。 - 已停用且无供应商的车队保存时保持停用,不报错。
四、契约约束与正确调用方式
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload 与结果 |
|---|---|
| ✅ 绑定合法供应商保存 | {"supplierId": "2094238127517319170", ...} → 200,status 保持原值 |
| ✅ 无供应商 + 无在役车辆 | {"supplierId": null, ...} → 200,status=DISABLED |
| ✅ 已停用 + 无供应商 | {"supplierId": null, ...} → 200,status 保持 DISABLED |
| ❌ 无供应商 + 有在役车辆 | {"supplierId": null, ...} → 601112,零写入 |
❌ 靠不传 supplierId 保留原供应商 |
不传等同传 null,会被当成「清除供应商」 |
切换状态时的必要动作
- 编辑回显后提交必须原样回传详情里的
supplierId;字段缺失就是清除语义,不存在「不传 = 不改」。 - 保存成功后不能沿用提交前的状态展示:用响应体
data.status或重拉列表/详情。 - 收到 601112 时弹后端 message 即可;修复路径是「选一个合法供应商」或「先把在役车辆转走/停用」。
五、数据库行为
| 前端提交 | 保存后外部可观察结果 |
|---|---|
supplierId 合法值 |
车队关联该供应商,supplierName 刷为当前全称快照,状态不变 |
supplierId=null,无在役车辆 |
供应商关联与全称快照同时置空,状态变 DISABLED |
supplierId=null,有在役车辆 |
零写入(名称/排序/备注等也不保存) |
本次无表结构变更、无 Flyway 迁移,存量脏数据不做批量刷状态(下次编辑保存时自然收口)。
六、边界行为
- 未登录 → 401(网关拦截)。
- 车队不存在 → 601100。
- 供应商资格依赖降级 → 601110 失败关闭,不静默放行。
- 存量无供应商且仍启用的车队:不会被后台任务批量改状态,只在下次编辑保存时收口。
- 已绑供应商的车队保存行为与之前一致,无新增拦截。
- 供应商改名后快照陈旧:仍需重新编辑车队刷新(行为未变)。
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| 请求体字段 | 无变化 | 无变化(路径、字段名、类型、必填性全部不变) |
响应 data.status |
仅当本次清除已绑供应商时可能返回 DISABLED |
只要保存结果无供应商且原为启用,就返回 DISABLED |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
存量无供应商车队(null → null)原样保存 |
保持「启用」 | 无在役车辆 → 自动「停用」;有在役车辆 → 601112 |
清除已绑供应商(X → null) |
启用→停用(不查在役车辆) | 有在役车辆时改为 601112 拒绝,不再产出「停用车队挂在役车辆」脏态 |
| 绑定/换绑合法供应商 | 200,状态不变 | 不变 |
六.7、影响评估
- 是否破坏向后兼容:否(请求/响应结构不变,新增一个错误码与一个状态副作用)。
- 前端是否必须同步上线:否。旧前端不报错,但若保存后不刷新列表,页面会短暂显示陈旧的「启用」。
- 前端 workaround 清理点:若前端曾为「无供应商仍显示启用」做过本地推断或提示,可改为直读后端
status。
七、不影响范围
- 仅影响:管理后台车队编辑保存(
PUT /admin/fleet/teams/{fleetTeamId})。 - 零影响:
- 新建车队
POST /admin/fleet/teams(无供应商本来就落停用) - 启用/停用
POST /admin/fleet/teams/{id}/enable、/disable - 车队列表、详情、options 读接口字段
- 车辆、司机、派单、看板、对账等其他车务接口
- 存量数据(不批量刷状态)
- 新建车队
八、测试环境已验证
部署:dev-v3 合入 PR #6827(merge 740fdb834)后部署 hl-fleet-service(8087/8187 滚动,两实例健康)。
PUT /admin/fleet/teams/348397854705979392 (无供应商 + 启用 + activeVehicleCount=0)
→ 200 成功,保存后 GET 详情 status=DISABLED, supplierId=null ✓
PUT /admin/fleet/teams/348398422098841600 (无供应商 + 启用 + activeVehicleCount=1)
→ 601112 「车队未关联供应商需自动停用,但仍有在役车辆…」
保存后 GET 详情 status=ACTIVE(零写入) ✓
PUT /admin/fleet/teams/2026072200010000001 (已绑供应商 + 有订单, 清除供应商)
→ 601111 既有订单围栏优先,行为未变 ✓
验证用车队:348397854705979392(测试车队P4-1787131721)、348398422098841600(测试车队P4-1787131856,验证用临时车辆已删除并回到 0 车)。
单测与构建:mvn -pl hl-fleet-service -am verify → Tests run 3887 / Failures 0 / Errors 0(Skipped 5 为既有 Release-E 跳过项);mvn -pl hl-fleet-service spotless:check → 799 文件 0 违规。
十、相关文档
- 前置契约:
changelogs-v2/2026-08/30_6717_车队关联供应商并展示供应商全名-修改接口-管理后台.md - 本次 PR:#6827
关联 / 联系人
- Issue:#6811
- 后端联系人:@wx