破坏性变更前端必同步: - #2524 delete 错误码 581121 → 581144(跨订单/不存在 plan 都统一) - #2523 edit 补 4 项业务校验(581140/581141/581142/581143)+ @Idempotent(3s) + @Lock4j(30s) - #2526 错误码注释笔误修正(无 API 影响) 测试服 9443 真测 9/9 PASS 来源:/@arch + /@cr 双重审查 → follow-up PR #2560(commit 08deec4d1) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
大交通批次 edit/delete 严格化 follow-up: 错误码 581121 → 581144 + edit 4 项业务校验补齐
存放目录: 二期(v3,
order-v3标签)→changelogs-v2/2026-05/服务: hl-order-v3 (端口 8084) PR: #2560 (commit
08deec4d1) Issue: 无新增工单(审查 follow-up,语义对齐 #2523 / #2524 / #2526,原工单已 closed) 日期: 2026-05-19 影响范围: 管理后台「行程安排 - 接送站」区块 - 大交通批次编辑/删除接口
⚠️ 关键变化(前端必同步两点)
- #2524 delete 错误码变更(破坏性,小幅):大交通批次软删接口的「plan 不存在/跨单/已删」错误码
581121→581144。前端若对581121做了特殊 catch,需改为581144,或合并到通用错误处理。错误消息文案同步改为「大交通批次不存在或不属于该订单」。 - #2523 edit 严格化(行为收紧):之前 edit 接口只校验
direction/transportType两个枚举,本次补齐 add 同款 4 项业务校验(581140 字段组合 / 581141 出行人归属 / 581142 时间顺序 / 581143 同方向同一出行人占用),且 edit 加@Idempotent(3s),3 秒内重复提交直接返100502 处理中。前端 add 已有的错误处理代码可直接复用到 edit。
这是 #2546(#2523) / #2547(#2524) / #2554(#2526) 三个原 PR 合并后,/@arch + /@cr 审查发现的尾巴一次性收完,不开新工单。
一、背景
V5.48 §2.6 大交通模块四接口在 #2521/#2522/#2523/#2524 完成路径风格 + Method 迁移后,审查发现两处实质语义偏差和一处注释笔误:
| 维度 | 原 PR 状态 | 本 follow-up 修正后 |
|---|---|---|
editTransportPlan 业务校验 |
仅枚举 direction/transportType,不校验字段组合/出行人归属/时间顺序/同方向占用 | 全 4 项校验,完全对齐 add |
editTransportPlan 防并发 |
仅 @Lock4j(30s),无幂等 |
@Lock4j(30s) + @Idempotent(3s) |
deleteTransportPlan 错误码 |
581121(沿用 §2 baseline) |
581144(对齐 §2.6.4 文档 + #2523 命名) |
TravelerErrorCode 错误码区间注释 |
"581131-581135" 整体看作启用 | "581131-581134 启用 + 581135 预留" |
错误码 581121 是 §2 出行人模块的"归属校验"基线值,但 §2.6 大交通批次模块已在 add/edit 中使用 581140-581144 段位,delete 也应统一使用 581144,前端可用同一段位错误处理覆盖全部 §2.6 接口。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 大交通批次编辑 | POST | /v3/admin/order/{id}/transport-plan/{planId}/edit |
行为收紧 + 注解新增 | 补 4 项业务校验 + @Idempotent(3s) |
| 2 | 大交通批次软删 | POST | /v3/admin/order/{id}/transport-plan/{planId}/delete |
错误码变更(破坏性) | 581121 → 581144,消息文案同步 |
三、接口详情
1. 大交通批次编辑 POST /v3/admin/order/{id}/transport-plan/{planId}/edit
入参 / 出参 / 路径 / Method 均与 PR #2546 一致,仅以下行为变化:
新增/补齐校验(对齐 add POST .../transport-plan/add)
校验顺序(从上到下,任一不通过立刻返错):
| 步骤 | 校验项 | 错误码 | 说明 |
|---|---|---|---|
| 1 | plan 存在 + 归属订单 + 未软删 | 581144 |
(本 follow-up 改造点,见接口 2) |
| 2 | 订单存在性 | 581100 |
|
| 3 | 字段组合合法性 | 581140 |
FLIGHT/TRAIN/COACH 缺 transportNo,SELF_DRIVE 错带 transportNo/站点 等 |
| 4 | 时间顺序 | 581142 |
departTime > arriveTime 拒绝(SELF_DRIVE 用 selfDriveEta 单点时间不触发此校验) |
| 5 | travelerIds 归属订单 | 581141 |
任一 ID 不在 order.travelerIds → 整体拒绝 |
| 6 | 同方向同一出行人已被占用(排除自己) | 581143 |
同 direction + 同 travelerId 在其他 active plan 中存在 → 拒绝;自己的旧关联不算冲突 |
新增注解
@Idempotent(timeout = 3) // 新增:3 秒内重复 POST 同 path+Body 返首次结果
@Lock4j(keys = "#id", expire = 30000) // 已有
错误响应示例
// 字段组合非法(FLIGHT 缺 transportNo)
{ "code": 581140, "msg": "transportNo 必填(运输方式=FLIGHT)", "data": null }
// travelerIds 含订单外的出行人
{ "code": 581141, "msg": "出行人不属于该订单: travelerIds=[70123456789099]", "data": null }
// 时间顺序错误
{ "code": 581142, "msg": "departTime 不能晚于 arriveTime", "data": null }
// 同方向同 traveler 占用(其他 plan)
{ "code": 581143, "msg": "出行人在同方向已有另一批次: direction=ARRIVAL, travelerId=70123456789012, conflictPlanId=80012999", "data": null }
// 幂等命中(3 秒内重复 POST)
{ "code": 100502, "msg": "请求处理中,请稍后重试", "data": null }
edit 排除自身规则:校验
581143时,SQLWHERE plan_id != #{currentPlanId},改自己不算冲突。该排除是 edit 接口独有,add 接口不存在 currentPlanId 概念。
2. 大交通批次软删 POST /v3/admin/order/{id}/transport-plan/{planId}/delete
入参 / 出参 / 路径 / Method / 数据库行为 均与 PR #2547 一致,仅错误码变化:
错误响应变更
| 场景 | 变更前(PR #2547) | 变更后(PR #2560,当前) |
|---|---|---|
| plan 不存在 | 581121 "大交通批次不属于该订单" |
581144 "大交通批次不存在或不属于该订单" |
| plan 跨单(orderId 不匹配) | 581121 同上 |
581144 同上 |
| plan 已软删(deleted=1)再 delete | 581121 同上 |
581144 同上 |
| 订单不存在 | 581100 |
581100(不变) |
示例响应:
{ "code": 581144, "msg": "大交通批次不存在或不属于该订单: planId=80099999, orderId=60123456789012", "data": null }
581121在 §2.6 模块不再返回(仍保留在 §2 出行人模块的其他接口中)。
四、契约约束与正确调用方式
edit 接口(前端 actionable)
| 场景 | payload | 结果 |
|---|---|---|
| ✅ 合法 edit | FLIGHT + transportNo + 站点 + travelerIds 都属本单 + 时间顺序对 | 200 |
| ✅ 改自己旧关联的 traveler | edit Body travelerIds=[A,B],A 在原 plan 已有 → 不触发 581143 |
200 |
| ❌ 缺 transportNo(FLIGHT) | {"transportType":"FLIGHT","transportNo":null} |
581140 |
| ❌ 时间倒挂 | departTime=11:00, arriveTime=09:00 |
581142 |
| ❌ traveler 跨单 | travelerIds=[订单外的 ID] |
581141 |
| ❌ 同方向 A 已在别 plan | direction=ARRIVAL + travelerA 在 plan #B 占用 | 581143 |
| ❌ 3 秒内双击 | 第二次同 path+Body POST | 100502 处理中 |
delete 接口(前端 actionable)
| 错误码 | 前端建议 |
|---|---|
旧 581121 |
移除或合并到通用错误处理 |
新 581144 |
提示「该批次不存在或已被删除」,刷新列表 |
前端代码迁移建议
// 旧
if (resp.code === 581121) showToast('批次不属于该订单');
// 新(推荐合并 581121 + 581144,兼容过渡期)
if (resp.code === 581144 || resp.code === 581121) showToast('批次不存在或已被删除');
五、数据库行为
无变化。本 follow-up 仅修改 Service 层校验顺序 + Controller 注解 + 错误码常量值,DB schema / 表行为完全沿用 PR #2546 / #2547。
六、边界行为
edit 接口
- 新校验全部在事务开始前完成,失败不写库
@Idempotent(3s)缓存键 = path + 用户 ID + Body hash,3 秒内重复同 Body 直接拿首次结果- 同方向同 traveler 占用判定 SQL:
WHERE direction = ? AND traveler_id IN (?) AND plan_id != #{currentPlanId} AND deleted = 0 - 已软删的 plan 不参与
581143占用判定
delete 接口
@Idempotent(3s)+@Lock4j(30s)沿用,不变- 错误码常量从
TRANSPORT_PLAN_NOT_BELONG_TO_ORDER(581121)改为TRANSPORT_PLAN_NOT_FOUND_OR_NOT_BELONG(581144)
通用
- 未登录 → 401(网关拦截,不变)
- 历史 plan(v2 迁移数据)edit/delete 行为完全一致
七、不影响范围
- 仅影响: 管理后台 F21 「接送站」编辑弹窗 + 删除按钮
- 零影响:
- C 端订单详情 / mp 抵达计划接口
- §2.6.1 list 接口 / §2.6.2 add 接口(本 follow-up 不动)
- 出行人 CRUD(traveler 表本身不动)
- 订单状态机
581121在 §2 出行人模块其他接口仍正常返回,语义未变581131-581134出行人模块错误码无功能变化,仅注释笔误修正
八、测试环境已验证
测试服 9443 网关 + 真 admin token round-trip 9/9 PASS(/@qa 报告):
edit 接口严格化:
✓ FLIGHT 缺 transportNo → 581140
✓ travelerIds 含订单外 ID → 581141
✓ departTime > arriveTime → 581142
✓ 同方向 traveler 在别 plan 占用 → 581143
✓ 同方向 traveler 在自己 plan(改自己)→ 200(排除自身生效)
✓ 3 秒内重复 POST 同 Body → 100502 幂等命中
delete 接口错误码:
✓ planId 不存在 → 581144(原 581121)
✓ planId 跨单 → 581144(原 581121)
✓ 重复 delete 已软删 plan → 581144(原 581121)
本地单测 109/109 全绿(5 单测 + 7 IT,注解反射断言验证 @Idempotent.timeout=3 / @Lock4j.keys="#id")。
九、相关历史 PR
| PR | Issue | 说明 | 是否仍有效 |
|---|---|---|---|
| #2546 | #2523 | edit 接口 Method+路径迁移(原版只校验 2 枚举) | ✅ 仍有效,本 follow-up 在其上补 4 校验 + 幂等 |
| #2547 | #2524 | delete 接口 Method+路径迁移(原版用 581121) |
✅ 仍有效,本 follow-up 改错误码 → 581144 |
| #2554 | #2526 | 出行人 smart-parse 新增接口(原版注释笔误) | ✅ 仍有效,本 follow-up 仅修注释,无 API 变化 |
| 本 PR #2560 | (审查 follow-up,无新工单) | edit 严格化 + delete 错误码 + 注释笔误 | ✅ 最新 |
十、相关文档
- 关联 PR: wx/HL#2560
- 原 PR(本 follow-up 的修正基础):
- wx/HL#2546(关联 #2523)
- wx/HL#2547(关联 #2524)
- wx/HL#2554(关联 #2526)
- API 文档:
docs/order-v3/api/API-SPEC-V5.48.html§2.6.3(edit)/ §2.6.4(delete) - 同月配套 changelog:
18_#2523_transport-plan-edit.md18_#2524_transport-plan-delete.md18_#2526_traveler-smart-parse.md