连续修订留下一段标着 frontend_status 却在讲 gateway_status 语义的残渣, 标签与内容不符会误导下一个填这个字段的人。内容并入括注,标签改回对的。 mmg 的 frontend_status=not_required 原样保留:他们在自己代码库里查实 getOrderOperationLog(api/fleet/board.js:58) 全仓零调用方、src/views/fleet 无 operationType 命中,后端担心的白名单过滤层尚不存在。那是前端负责人 带证据的判定,比后端的推断硬。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
20 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 | 8061 | 解除共用关系只处置本关系的成员——同一服务日上的非成员在途行不再被连带清空(行为修复,接口形状不变) | admin | wx(GIT) | 修改接口 | deployed | verified | not_required | backend_status=deployed:PR #8067 squash 为 00930f5d6,2026-09-20 22:42 已部署到测试服 192.168.100.236,deploy-status.sh 复核落点 = 00930f5d6,Nacos 两实例(8087/8187)healthy=true。gateway_status=verified:2026-09-21 在测试服网关上以全新三户夹具(团期 2101690789438570497、服务日 2026-10-30)取得阳性与阴性两条对照——阳性:releasedSourceIds 恰为两个成员且库内真变 unassigned;阴性:非成员 C 的 assignment_status/vehicle_id/driver_id 解除前后逐一相等。两条缺一不可:只有阳性的话,「C 没变」与「解除没跑起来」观测相同,且阳性在修复前同样成立。详见正文「八、测试环境已验证」。(📌 gateway_status 这个字段记的是「网关验证有没有做过」,不是「网关路由要不要改」——先例见 2026-08 #5405/#5407:『测试环境部署和网关验证尚未执行,因此 backend_status、gateway_status 保持 pending』。本次不新增端点、不改路由形状,但那不构成填 not_required 的理由,填 verified 的理由是上面那次真实调用。)frontend_status:后端起初填 pending,理由是——请求/响应字段确实零增删,但派车操作日志时间线新增了 operation_type 取值 share_release_cleared——前端若按 operation_type 白名单过滤,这条会被静默丢掉,用户就看不到『车和司机是被哪次共用关系解除清掉的』,而那正是本次补留痕要解决的问题。⇒ 前端至少需要确认自己有没有这层过滤、必要时加上,这是动作不是知会,故 pending。另按指南,not_required 会禁止 mmg 回写 frontend_owner 等认领字段,填错反而挡住认领。mmg 前端实证 2026-09-20:fleet 操作日志读口 getOrderOperationLog(api/fleet/board.js:58)在全仓零调用方,src/views/fleet 无 operationType 命中——后端担心的「时间线按 operation_type 白名单过滤会静默丢 share_release_cleared」过滤层在前端不存在(该时间线 UI 尚未建),故前端零改动,翻 not_required。后续接入操作日志时间线时 operation_type 渲染必须包含 share_release_cleared(detail_json 全字段字符串 ID 透传)。share-groups 解除入口前端未接入,属 #7444 挂起域,同 #8051 口径。 | 2026-09-20 | dev-v3 |
fleet: 解除共用关系只处置本关系的成员,同槽非成员行保留(工单 #8061 + #8051 衍生)
存放目录: 二期(order-v3 标签工单)→
changelogs-v2/2026-09/服务: hl-fleet-service PR: #8067(squash
00930f5d6,已合入 dev-v3) | Issue: #8061 日期: 2026-09-20 影响范围: 管理后台「团期配车」页解除车辆或司机共用关系这一个动作,及其对派车账本的影响
⚠️ 关键变化
三个可观测行为都变了,前端必须知道:
① 处置范围收窄
改动前:解除某一个共用关系,会把该车/该司机在整个资源日槽上的全部在途派车行一起软清成「待派车」,同槽的非成员行也被清。 改动后:只处置该关系的成员占用。同一车/同一司机、同一服务日上那些从不属于本关系的在途派车行,一行不动。
⇒ 响应里的 releasedSourceIds / pendingReassignSourceIds 会比以前短。同一个服务日、同一辆车上那些与本关系无关的在途派单,不再被连带清空。
典型场景:接送机的接、送一对。它们本来就该在同一天占同一辆车,但不一定属于同一个共用关系;现在解除一个关系不再误伤另一对。
② 错误码触发条件变了
- 602111(
KEEP_LEGAL下仍有非法组合)与 602112(收口断言)现在只在「至少一侧是本关系成员」的组合上触发。 - ⇒ 以前会因为两条互不相干的第三方派单存量冲突而整单失败的情况,现在不会再失败了。前端若有「解除失败请联系管理员」这类兜底文案,触发频率会下降。
③ 🔴 派单操作日志时间线新增 share_release_cleared 记录
新增操作类型值 share_release_cleared,中文标签「共用关系解除释放占用」。detail_json 包含以下字段(所有 ID 都是字符串,防雪花 ID 过 JS 掉精度):
| 字段 | 类型 | 说明 |
|---|---|---|
| shareGroupId | String | 被解除的共用关系 ID |
| groupBatchId | String | 团 ID |
| serviceDate | String | 服务日期(YYYY-MM-DD) |
| resourceType | String | 资源维度:VEHICLE 或 DRIVER |
| resourceId | String | 车辆或司机 ID |
| releaseReason | String | 解除原因 |
| survivorPolicy | String | 本次采用的处置策略(RELEASE / REASSIGN / KEEP_LEGAL) |
| vehicleIdBefore | String | 派单清之前挂的车辆 ID(解除后被清成 NULL) |
| driverIdBefore | String | 派单清之前挂的司机 ID(解除后被清成 NULL) |
⚠️ 关键警告:如果前端在时间线上按 operation_type 白名单过滤,这条新记录会被静默丢掉。用户就看不到「车和司机是被哪次共用关系解除清掉的」——而这正是本次补留痕要解决的问题。
一、背景
原 #8051 与本单的关系
#8051 修了「解除共用关系会跨服务日、跨团软清在途派车行」这个 bug,已由 PR #8058(ac9efb735)修复并部署。
本单从 #8051 分出,因为在修复过程中又发现了一个同一服务日范围内的残留问题:RELEASE 策略清的是该资源日槽上全部在途 claim,与"是否属于本关系的成员"之间没有任何约束。结果:同槽上的非成员行也被一起清了,且同样静默。
两处文档说了对的话,实现没跟上
ShareSurvivorPolicy.RELEASE的 javadoc:释放本关系的成员的占用GroupDispatchShareController的@ApiOperation.notes:同样说释放本关系的成员
两处独立写成同一个意思——这代表意图,而不是"实现当前的行为"。现状不是「文档没跟上实现」,是实现从来没有对齐过契约。
实测误清 6 行真实数据
2026-09-20 14:04:12 解除共用关系 359915397639704576(服务日 2026-10-03、车辆 2065329519232720897)时,日志记的是 释放=[7 个派单 ID],经库内逐行核对:
| 派单 ID | 服务日 | 团 | 是否成员 | 预期 | 实际 |
|---|---|---|---|---|---|
| 359887954036002816 | 2026-10-18 | 2101496576453275649 | ❌ | 不该动 | 被清 |
| 359887954396712960 | 2026-10-18 | 2101496576453275649 | ❌ | 不该动 | 被清 |
| 359888468400279552 | 2026-10-25 | 2101498606508994561 | ❌ | 不该动 | 被清 |
| 359888468916178944 | 2026-10-25 | 2101498606508994561 | ❌ | 不该动 | 被清 |
| 359888884127109120 | 2026-10-25 | 2101498606508994561 | ❌ | 不该动 | 被清 |
| 359896486663819264 | 2026-11-20 | 2099073597908647938 | ❌ | 不该动 | 被清 |
| 359915650245857280 | 2026-10-03 | 2101524283048263681 | ✅ | 该清 | 被清 |
6 行误清:横跨 3 个其它服务日、3 个其它团;现状全部 assignment_status=unassigned、vehicle_id/driver_id 置 NULL。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 解除团期车辆/司机共用关系 | DELETE | /admin/fleet/group-dispatch/share-groups/{shareGroupId} |
行为修复(字段、错误码、网关路由均不变) | 处置范围从「整个资源日槽」收窄为「本关系的成员」;错误码触发条件同步收窄 |
| 2 | — | — | — | 日志侧新增 | 派单操作日志新增 share_release_cleared 记录类型 |
三、接口详情
1. 解除团期车辆/司机共用关系 DELETE /admin/fleet/group-dispatch/share-groups/{shareGroupId}
VO: ShareGroupReleaseRespVO(字段零增删改)
使用场景
管理后台「团期配车」页,车务点「解除共用」。解除同时要在同一事务内完成幸存占用的实际处置,survivorPolicy 决定怎么处置。
入参(本次无变化)
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| shareGroupId | Path | Long | ✅ | — | 共用关系 ID |
| survivorPolicy | Query | String | 业务必填 | KEEP_LEGAL / REASSIGN / RELEASE |
幸存占用处置策略;不传返业务码 602110 |
出参(本次无变化)
| 字段 | 类型 | 说明 |
|---|---|---|
| shareGroupId | String | 共用关系 ID(雪花 ID,按字符串序列化) |
| status | String | 固定 RELEASED |
| survivorPolicy | String | 本次采用的处置策略 |
| keptSourceIds | List<String> | 保留占用的来源 ID(本关系成员中被保留的) |
| releasedSourceIds | List<String> | 已释放占用的来源 ID(仅本关系成员,不含非成员) |
| pendingReassignSourceIds | List<String> | 需人工改派的来源 ID(仅本关系成员) |
请求示例
DELETE /admin/fleet/group-dispatch/share-groups/{shareGroupId}?survivorPolicy=RELEASE HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer {token}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"shareGroupId": "{shareGroupId}",
"status": "RELEASED",
"survivorPolicy": "RELEASE",
"keptSourceIds": ["2101524548279238658"],
"releasedSourceIds": ["360022177073991680"],
"pendingReassignSourceIds": []
},
"success": true
}
空数据 / 降级响应
该资源日上仅剩 0-1 个存活 claim 时,三个清单都可能是空数组 []——这是正常终态,不是异常。
错误响应
{
"code": 602111,
"message": "保留合法共用失败,幸存成员之间不满足衔接规则: GROUP_DISPATCH#2101524548279238658 ↔ ASSIGNMENT#360022539151478784",
"data": null,
"success": false
}
业务边界
- 鉴权:需管理后台已登录且具备
fleet:group-dispatch:write权限,未登录/无权限按网关与全局鉴权规则处理。 - 幂等性:关系一旦解除即置
RELEASED;重复发起 DELETE 会拿到 602108。 - 失败零写入:602111 / 602112 都在同一事务内回滚——关系不标 RELEASED,占用状态不变。
survivorPolicy必须传值;不传返 602110,不是 400。- 🔴 已知未覆盖边界(不在本次修复范围):同一资源同一服务日上的非成员在途行仍会被
RELEASE一并软清且同样静默——处置逻辑不区分"共用关系的成员"与"路过的其它派车行";最典型场景是接送机的接、送一对。已在工单 #8061 本单纳入。
错误码(本次不新增、语义不改)
| code | 含义 |
|---|---|
| 602108 | 共用关系不存在或已解除 |
| 602110 | 未指定处置策略 |
| 602111 | KEEP_LEGAL 下本关系的幸存成员之间存在非法组合;整请求回滚 |
| 602112 | 收口断言不成立:处置后账本里至少一侧是本关系成员的组合中仍有非法;回滚 |
四、契约约束与正确调用方式
本节只写后端接受/拒绝 payload 的规则。接口契约本身没有变化——本节写的是既有契约,帮消费方确认自己一直调对了。
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload | 结果 |
|---|---|---|
| ✅ 释放本关系全部幸存成员占用 | DELETE .../share-groups/{id}?survivorPolicy=RELEASE |
200,成员占用全释,同槽非成员不动 |
| ✅ 仅在成员间两两合法时整槽保留 | DELETE .../share-groups/{id}?survivorPolicy=KEEP_LEGAL |
成员间有冲突时 602111 拒绝,整请求回滚 |
| ✅ 真释放冲突成员并标记待改派 | DELETE .../share-groups/{id}?survivorPolicy=REASSIGN |
200,释放冲突成员;成员与非成员冲突时成员让位 |
❌ 不传 survivorPolicy |
DELETE .../share-groups/{id}(无查询参数) |
602110,不是 400 |
❌ shareGroupId 指向不存在或已解除的关系 |
任意 survivorPolicy |
602108 |
切换状态时的必要动作
survivorPolicy必须始终传值——不传拿到 602110,前端应按此逻辑引导用户补选。- 若修改派单分配方案,必须显式传递三选一的大写字面量,不要自行拼接或做大小写转换。
五、数据库行为
- 本服务日范围内:解除共用关系后,该关系名下、在这一个服务日上仍存活的成员派车行会被置为「待派车」,车辆与司机清空(
RELEASE/REASSIGN都触发;KEEP_LEGAL冲突时整请求回滚)。 - 修复点(本次变化):同一资源、同一服务日上那些不属于本关系****的派车行不再受影响——即便它们挂在同一辆车/同一名司机上。
- 新增操作日志:软清每一条成员行时,往
fleet_assignment_operation_log追加一行share_release_cleared记录,带shareGroupId/groupBatchId/vehicleIdBefore/driverIdBefore等字段(见下节)。
六、边界行为
- 未登录 → 401(网关拦截)
- 无
fleet:group-dispatch:write权限 → 403 shareGroupId不存在或已解除 → 602108(不是 404)- 未传
survivorPolicy→ 602110(不是 400) survivorPolicy不是三个合法字面量之一 → 不报错,落入隐式默认分支- 本接口不依赖外部服务(不查 Feign、不查 MQ),没有"下游降级"路径
- 🔴 本次修复范围之外的已知缺陷:同一资源同一服务日上的非成员在途行仍会被
RELEASE一并软清且同样静默,本次不改
六.5、枚举 / 数据字典
survivorPolicy(ShareSurvivorPolicy)
所属字段: survivorPolicy(Query 入参)| 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
RELEASE |
全部释放 | 释放本关系的全部幸存成员的占用,置「待派车」;同槽非成员不动 |
KEEP_LEGAL |
仅合法保留 | 本关系幸存成员间两两全合法时整槽保留;有冲突则 602111 拒绝回滚 |
REASSIGN |
释放并待改派 | 真释放冲突成员的占用,派单置「待改派」;成员与非成员冲突时成员让位 |
operation_type(AssignmentOperationTypeEnum)
新增值 share_release_cleared:共用关系解除释放占用
| 值 | 中文 | 说明 |
|---|---|---|
share_release_cleared |
共用关系解除释放占用 | 解除共用关系时,该派单作为成员被释放占用并置「待改派」;详见 detail_json |
detail_json 结构(JSON 字段类型):
{
"shareGroupId": "359915397639704576",
"groupBatchId": "2101524283048263681",
"serviceDate": "2026-10-03",
"resourceType": "VEHICLE",
"resourceId": "2065329519232720897",
"releaseReason": "共用关系解除",
"survivorPolicy": "RELEASE",
"vehicleIdBefore": "G",
"driverIdBefore": "D001"
}
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| (无)请求 / 响应字段 | 不变 | 不变——本次未增删改任何字段 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
RELEASE 处置的派车行范围 |
该车/该司机同一服务日上全部在途行 | 仅本关系的成员 |
releasedSourceIds 里可能出现非成员行 |
会 | 不会 |
| 同槽非成员在途行是否被清成「待派车」 | 会,且无任何信号 | 不会 |
| 错误码 602111 / 602112 的判定范围 | 整槽全部 claim | 仅「至少一侧是本关系成员」的组合 |
| 派单操作日志 | 无 share_release_cleared 记录 |
新增记录,包含 vehicleIdBefore / driverIdBefore |
六.7、影响评估
- 是否破坏向后兼容: 否——请求/响应字段、错误码、网关路由全部不变。
- 前端是否必须同步上线: 否——管理后台无需改任何代码;但操作日志展示侧需要注意新字段。
- 前端 workaround 清理点: 无新增 workaround。但请转告使用方——测试环境中那些跨服务日、跨团、从不属于本关系的派单,如果曾因为解除共用关系而被误清,不再会发生这种事了。
- 给 mmg 的知会重点:
- 「解除共用关系」这个动作的影响范围变了——同一车/司机同一服务日上的非成员行不再被波及。
- 操作日志时间线上会看到新的
share_release_cleared记录——必须把这条记录类型加进白名单,否则用户看不到派单是被哪次共用关系解除清掉的。
- 存量处理:无需任何 SQL 回滚。测试库中的误清行正常通过改派写口恢复。
七、不影响范围
- 仅影响: 管理后台「团期配车」页解除车辆/司机共用关系这一个动作的副作用范围
- 零影响:
- 请求/响应字段结构、错误码(全部不变,前端无需改代码)
- 网关路由配置(既有路由无需改动)
- 确认共用关系
POST .../batches/{groupBatchId}/share-groups、查询共用关系GET .../batches/{groupBatchId}/share-groups两个端点 - 同一资源同一服务日上非成员在途行的处置口径(仍是旧行为,已在本单纳入)
八、测试环境已验证
部署:fleet 于 2026-09-20 22:42 部署到测试服 192.168.100.236,落点 00930f5d6(deploy-status.sh 复核),Nacos 两实例(8087 / 8187)healthy=true。
网关实测(2026-09-21,真实请求 + 库回读)
夹具:全新团期 2101690789438570497,服务日 2026-10-30,共用车 G 2065329515961163778;三户 A / B / C 与团车行均实占该车该日,其中 A、B 是共用关系 360081477972660224 的成员,C 与团车行不是成员。
DELETE /admin/fleet/group-dispatch/share-groups/360081477972660224?survivorPolicy=RELEASE
→ 200
{"data":{"status":"RELEASED","survivorPolicy":"RELEASE",
"keptSourceIds":["2101691129806340098","360081478538891264"],
"releasedSourceIds":["360081478098489344","360081478333370368"]}}
① 阳性对照(证明解除真的执行了):releasedSourceIds 恰为成员 A 360081478098489344 与 B 360081478333370368;库回读两行 assignment_status: assigned → unassigned,vehicle_id / driver_id → NULL。
② 阴性对照(本次修复的核心断言):非成员 C 360081478538891264 三字段解除前后逐一相等,且不在 releasedSourceIds 里:
| assignment_status | vehicle_id | driver_id | |
|---|---|---|---|
| 解除前 | assigned | 2065329515961163778 | 2065272147277758465 |
| 解除后 | assigned | 2065329515961163778 | 2065272147277758465 |
⚠️ 为什么必须两条一起看:只有 ① 的话,「C 没变」与「解除根本没跑起来」在观测上完全相同;而 ① 本身在修复前也成立(旧实现同样会释放成员,只是顺手把 C 也清了)——单看 ① 是一个在「修好了」和「没修」两个世界里都为真的读数。
后端单元测试 / 集成测试
GroupDispatchShareSurvivorServiceTest:15 条(原 11,+4)GroupDispatchShareReleaseDayScopeIntegrationTest:4 条(原 2,+2,H2 真 Flyway DDL + 真 Mapper)- 变异证明:把处置范围回滚成「清整槽」后 5 条红且全部是新增用例,既有 71 条全绿;复原后全绿
十、相关文档
- 关联 Issue: wx/HL#8061
- 关联 Issue(前置修复): wx/HL#8051
- 关联 PR: wx/HL#8067
- 关联 PR(前置修复): wx/HL#8058
关联 / 联系人
链接
联系人
- 后端负责人: @wx