- #2521 list 路径迁移 /transport-plans → /transport-plan/list - #2522 add 路径 + 错误码 581140-581143 + @Idempotent + @Lock4j - #2523 edit Method PUT → POST + 错误码 581144 - #2524 delete Method DELETE → POST + 桥接表级联软删 测试服 9443 真测全 ✅ (commit 15e2c7eeb 含 hotfix #2550) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
235 行
8.3 KiB
Markdown
235 行
8.3 KiB
Markdown
# 大交通批次编辑: Method 破坏性变更 (PUT → POST) + 错误码 581144
|
|
|
|
> **存放目录**: 二期(v3,`order-v3` 标签)→ `changelogs-v2/2026-05/`
|
|
>
|
|
> **服务**: hl-order-v3 (端口 8084)
|
|
> **PR**: #2546 (commit `1106b9d7f`) + hotfix #2550 (commit `15e2c7eeb` 修 conflict markers)
|
|
> **Issue**: #2523
|
|
> **日期**: 2026-05-18
|
|
> **影响范围**: 管理后台「行程安排 - 接送站」区块 - 大交通批次编辑弹窗
|
|
|
|
---
|
|
|
|
## ⚠️ 关键变化(破坏性 - 前端必同步)
|
|
|
|
一行红字说清:
|
|
- **本次变了什么**: 编辑大交通批次接口 **Method 从 `PUT` 改为 `POST`** + 路径子段从 `/transport-plans/{planId}` 改为 `/transport-plan/{planId}/edit`
|
|
- **前端以前以为的是什么**: `PUT /v3/admin/order/{id}/transport-plans/{planId}`
|
|
- **实际现在是什么**: `POST /v3/admin/order/{id}/transport-plan/{planId}/edit`
|
|
|
|
**Method 变化是头号陷阱**: 前端若沿用 `axios.put(...)` 会直接 404 / 405,必须改 `axios.post(...)`。
|
|
|
|
**配套破坏性**: §2.6 大交通批次模块 4 个接口路径风格 + 动词 + Method 全部统一迁移,见 #2521/#2522/#2524。
|
|
|
|
---
|
|
|
|
## 一、背景
|
|
|
|
V5.48 §2.6 统一管理后台所有变更动作走 `POST /{资源}/{动词}` 风格(对齐订单核心模块、出行人模块):
|
|
|
|
| 旧风格 (REST 经典) | 新风格 (V5.48 统一) |
|
|
|--------------------|---------------------|
|
|
| `PUT /transport-plans/{id}` | `POST /transport-plan/{id}/edit` |
|
|
| `DELETE /transport-plans/{id}` | `POST /transport-plan/{id}/delete` |
|
|
|
|
POST + 动词路径的好处: 网关 RBAC 配置统一只看 path 不看 Method、操作审计日志埋点统一、防误触缓存。
|
|
|
|
`#2550 hotfix` 修复合并 dev-v3 时 IDE 残留的 `<<<<<<<` conflict markers(扫描全代码确保零残留)。
|
|
|
|
---
|
|
|
|
## 二、变更接口清单
|
|
|
|
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
|
|---|------|------|------|----------|------|
|
|
| 1 | 大交通批次编辑 | POST | `/v3/admin/order/{id}/transport-plan/{planId}/edit` | Method + 路径双破坏 | 旧 `PUT /transport-plans/{planId}` 下线;新增错误码 `581144` |
|
|
|
|
---
|
|
|
|
## 三、接口详情
|
|
|
|
### 1. 大交通批次编辑 `POST /v3/admin/order/{id}/transport-plan/{planId}/edit`
|
|
|
|
**VO**: `TransportPlanReqVO`(入参,与 add 同 VO) / `TransportPlanVO`(出参)
|
|
|
|
#### 入参
|
|
|
|
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
|
|------|------|------|:----:|------|
|
|
| `id` | Path | Long | ✅ | 订单 ID |
|
|
| `planId` | Path | Long | ✅ | 批次 ID |
|
|
| Body | Body | `TransportPlanReqVO` | ✅ | 字段同 add(见 #2522 入参表) |
|
|
|
|
#### 出参 `Result<TransportPlanVO>`
|
|
|
|
字段同 #2521 列表元素结构。
|
|
|
|
#### 请求示例
|
|
|
|
```json
|
|
POST /v3/admin/order/60123456789012/transport-plan/80012345/edit
|
|
|
|
{
|
|
"direction": "ARRIVAL",
|
|
"transportType": "FLIGHT",
|
|
"transportNo": "CA1234",
|
|
"carrier": "中国国际航空",
|
|
"departStation": "北京首都T3",
|
|
"arriveStation": "长春龙嘉",
|
|
"departTime": "2026-06-01T09:00:00",
|
|
"arriveTime": "2026-06-01T11:00:00",
|
|
"selfDrivePeriod": null,
|
|
"selfDriveEta": null,
|
|
"travelerIds": [70123456789012, 70123456789013, 70123456789014],
|
|
"remark": "改时间,加一人"
|
|
}
|
|
```
|
|
|
|
#### 响应示例
|
|
|
|
```json
|
|
{
|
|
"code": 200,
|
|
"data": {
|
|
"id": "80012345",
|
|
"orderId": "60123456789012",
|
|
"direction": "ARRIVAL",
|
|
"transportType": "FLIGHT",
|
|
"transportNo": "CA1234",
|
|
"carrier": "中国国际航空",
|
|
"departStation": "北京首都T3",
|
|
"arriveStation": "长春龙嘉",
|
|
"departTime": "2026-06-01T09:00:00",
|
|
"arriveTime": "2026-06-01T11:00:00",
|
|
"selfDrivePeriod": null,
|
|
"selfDriveEta": null,
|
|
"travelers": [
|
|
{"id": "70123456789012", "name": "张三"},
|
|
{"id": "70123456789013", "name": "王小明"},
|
|
{"id": "70123456789014", "name": "李四"}
|
|
],
|
|
"remark": "改时间,加一人"
|
|
},
|
|
"msg": "success"
|
|
}
|
|
```
|
|
|
|
#### 错误响应
|
|
|
|
复用 add 接口的 4 个错误码(`581140`-`581143`),并新增:
|
|
|
|
| 错误码 | 含义 | 触发场景 |
|
|
|--------|------|----------|
|
|
| `581144` | plan 不存在 / 不属于该订单 | `planId` 无效 / 已软删 / order_id 与 path 不匹配 |
|
|
|
|
示例 `581144`:
|
|
|
|
```json
|
|
{ "code": 581144, "msg": "大交通批次不存在或不属于该订单: planId=80099999, orderId=60123456789012", "data": null }
|
|
```
|
|
|
|
---
|
|
|
|
## 四、契约约束与正确调用方式
|
|
|
|
### ✅ 正确 / ❌ 错误调用对照
|
|
|
|
| 场景 | 请求 | 结果 |
|
|
|------|------|------|
|
|
| ✅ 新调用 | `POST /transport-plan/80012345/edit` + Body | 200 |
|
|
| ❌ 沿用旧 PUT | `PUT /transport-plans/80012345` + Body | 404 / 405 |
|
|
| ❌ planId 跨单 | edit path `orderId=A`,planId 属于 `orderId=B` | `581144` |
|
|
| ❌ planId 已软删 | edit 已 deleted=1 的 plan | `581144` |
|
|
|
|
### 全量重建语义
|
|
|
|
- **edit 不是"增量改字段"**: Body 提交什么就最终持久化什么(包括 `travelerIds` 全量)
|
|
- 想去掉 1 个 traveler: 在 `travelerIds` 数组中删掉该 ID 再提交,后端会 DELETE+INSERT 重建桥接表
|
|
- 不能用 edit "局部改 1 个字段而保留其他字段不动"的语义,前端必须先 GET list 取完整 plan 再改
|
|
|
|
### 并发与幂等
|
|
|
|
- `@Lock4j(keys = "#id")`: 同订单 30 秒锁,串行化 add/edit/delete
|
|
- 编辑接口不加 `@Idempotent`(每次编辑都应被尊重,允许相同 Body 重复提交以触发 update_time 刷新)
|
|
|
|
---
|
|
|
|
## 五、数据库行为
|
|
|
|
单事务执行,失败整体回滚:
|
|
|
|
| 步骤 | 表 | 动作 |
|
|
|------|-----|------|
|
|
| 1 | `order_transport_plan` | UPDATE 该 plan 行所有业务字段(direction / transportType / transportNo / carrier / 各 station / 各 time / selfDrive* / remark),`update_time` 自动刷新 |
|
|
| 2 | `order_transport_plan_traveler` | DELETE(物理删除桥接行 WHERE `plan_id = ?`)|
|
|
| 3 | `order_transport_plan_traveler` | INSERT N 行(N = 新 `travelerIds.size()`)|
|
|
|
|
> 桥接表用「全量重建」而非 diff 算法,简化业务逻辑;桥接表本身无业务历史价值,物理删除不留痕。`order_transport_plan` 主表的 `update_time` 会随 edit 刷新供前端展示「最后修改时间」。
|
|
|
|
校验顺序(同 add,附加 plan 归属校验):
|
|
|
|
1. plan 存在性 + 归属 → `581144`
|
|
2. 订单存在性 → `581100`
|
|
3. 字段组合 → `581140`
|
|
4. 时间顺序 → `581142`
|
|
5. travelerIds 归属 → `581141`
|
|
6. 同方向同 traveler 占用(**排除自己**)→ `581143`
|
|
|
|
---
|
|
|
|
## 六、边界行为
|
|
|
|
- 未登录 → 401(网关拦截)
|
|
- planId 不存在 / 跨单 / 已软删 → `581144`
|
|
- 同方向同 traveler 占用判定**排除当前 plan 自己**(改自己不算冲突,只跟其他 active plan 比对)
|
|
- Body 与原 plan 完全相同(无字段变化)→ 200 + 桥接表 DELETE+INSERT(等价 no-op 但 `update_time` 仍刷新)
|
|
- 老数据(v2 历史 plan 字段缺失)→ edit 会以 Body 全量值覆盖
|
|
|
|
---
|
|
|
|
## 七、不影响范围
|
|
|
|
- **仅影响**: 管理后台 F21 「接送站」编辑弹窗
|
|
- **零影响**:
|
|
- C 端订单详情 / mp 抵达计划接口
|
|
- 出行人 CRUD(traveler 表本身不动)
|
|
- 订单状态机
|
|
- 操作日志(本接口暂不挂 `@OperationLog`,与 v2 行为一致)
|
|
|
|
---
|
|
|
|
## 八、测试环境已验证
|
|
|
|
测试服 9443 网关 + 真 admin token round-trip 验证:
|
|
|
|
```
|
|
POST https://web.test.1814.love:9443/v3/admin/order/{orderId}/transport-plan/{planId}/edit
|
|
→ 200 + 返回更新后 plan(travelers 重建)✓
|
|
→ planId 不存在 → 581144 ✓
|
|
→ planId 属于别单 → 581144 ✓
|
|
→ 业务校验复用 581140/581141/581142/581143 全覆盖 ✓
|
|
→ 同方向同 traveler 占用判定排除自己 → 200 ✓
|
|
→ 桥接表全量 DELETE+INSERT 重建生效 ✓
|
|
```
|
|
|
|
**hotfix #2550**(commit `15e2c7eeb`)清理了合并 dev-v3 时残留的 `<<<<<<<` / `=======` / `>>>>>>>` conflict markers(本接口实现文件曾受影响,hotfix 后 mvn compile 通过 + 9443 验证通过)。
|
|
|
|
---
|
|
|
|
## 九、相关历史 PR
|
|
|
|
| PR | Issue | 说明 | 是否仍有效 |
|
|
|----|-------|------|------------|
|
|
| **本 PR #2546** | **#2523** | Method PUT→POST + 路径迁移 + 错误码 581144 | ✅ 最新 |
|
|
| #2550 | (hotfix) | 修复 conflict markers,无功能变化 | ✅ 配套 |
|
|
|
|
---
|
|
|
|
## 十、相关文档
|
|
|
|
- 关联 Issue: [wx/HL#2523](https://git.1814.love:8443/wx/HL/issues/2523)
|
|
- 关联 PR: [wx/HL#2546](https://git.1814.love:8443/wx/HL/pulls/2546)
|
|
- Hotfix PR: [wx/HL#2550](https://git.1814.love:8443/wx/HL/pulls/2550)
|
|
- API 文档: `docs/order-v3/api/API-SPEC-V5.48.html` §2.6.3
|
|
- 配套破坏性: 见 `18_#2521_transport-plan-list-path.md` / `18_#2522_transport-plan-add.md` / `18_#2524_transport-plan-delete.md`
|