hl-api-changelog/changelogs-v2/2026-05/19_followup_transport-plan-rigor.md
API Changelog Bot fa843a7ba8 changelog(order-v3): 大交通 edit/delete 严格化 follow-up
破坏性变更前端必同步:
- #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>
2026-05-19 09:17:47 +08:00

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 影响范围: 管理后台「行程安排 - 接送站」区块 - 大交通批次编辑/删除接口


⚠️ 关键变化(前端必同步两点)

  1. #2524 delete 错误码变更(破坏性,小幅):大交通批次软删接口的「plan 不存在/跨单/已删」错误码 581121581144。前端若对 581121 做了特殊 catch,需改为 581144,或合并到通用错误处理。错误消息文案同步改为「大交通批次不存在或不属于该订单」。
  2. #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 错误码变更(破坏性) 581121581144,消息文案同步

三、接口详情

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 时,SQL WHERE 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 的修正基础):
  • API 文档: docs/order-v3/api/API-SPEC-V5.48.html §2.6.3(edit)/ §2.6.4(delete)
  • 同月配套 changelog:
    • 18_#2523_transport-plan-edit.md
    • 18_#2524_transport-plan-delete.md
    • 18_#2526_traveler-smart-parse.md