diff --git a/changelogs/2026-05/08_1500_arrival-mode.md b/changelogs/2026-05/08_1500_arrival-mode.md new file mode 100644 index 0000000..c604146 --- /dev/null +++ b/changelogs/2026-05/08_1500_arrival-mode.md @@ -0,0 +1,528 @@ +# API 变更通知 + +**更新时间**: 2026-05-08 15:00 +**PR**: #1878 feat(order-v2): 到达/返程信息支持区分一起/多批两种模式 + #1887 修正接口描述 + +--- + +## 破坏性变更:POST /mp/order/{orderId}/arrival 语义彻底变更 + +### 变了什么(前端视角) + +**单数接口从「追加一条」变成「该方向全量替换 1 条」。** + +| 行为 | 旧逻辑(PR 前) | 新逻辑(PR 后) | +|------|----------------|----------------| +| 连续调 2 次 | 产生 2 条批次(追加) | 第 2 次会把第 1 次清掉,只保留最新 1 条 | +| 想分批到达 | 多次调单数接口 | 必须改用 /arrival/batch(提交多元素数组) | +| 已有批次被覆盖范围 | 无此逻辑 | 只清同一 direction 的旧批次,不影响另一方向 | + +如果小程序之前通过多次调 POST /arrival 实现「分批到达」,现在必须改为调 POST /arrival/batch。 + +--- + +## Bug 修复:POST /mp/order/{orderId}/arrival/batch 不再误删另一方向 + +| 行为 | 旧行为(有 bug) | 新行为(已修复) | +|------|----------------|----------------| +| 提交返程多批 | 把已填的到达批次也一起删掉 | 只删 direction=DEPARTURE 的旧批次,ARRIVAL 不受影响 | +| 提交到达多批 | 把已填的返程批次也一起删掉 | 只删 direction=ARRIVAL 的旧批次,DEPARTURE 不受影响 | + +如果前端之前因为这个 bug 做了「先查再保」之类的 workaround,可以清理掉。 + +--- + +## 新增:GET 接口返回 mode + modeLabel 字段 + +GET /mp/order/{orderId}/arrival 返回的每个批次对象新增 2 个字段: + +| 字段 | 类型 | 说明 | +|------|------|------| +| mode | String | 模式枚举:TOGETHER 或 SEPARATE | +| modeLabel | String | 按方向拼出的中文标签(见下表) | + +modeLabel 的 4 种值: + +| direction | mode | modeLabel | +|-----------|------|----------| +| ARRIVAL | TOGETHER | 一起到达 | +| ARRIVAL | SEPARATE | 多批到达 | +| DEPARTURE | TOGETHER | 一起返程 | +| DEPARTURE | SEPARATE | 多批返程 | + +前端可以用 arrivals[0]?.mode(或 departures[0]?.mode)来判断该方向当前 tab 模式,决定进入页面时默认选中哪个选项卡。 + +--- + +## 新增错误码:580010 BATCH_DIRECTION_MIXED + +POST /mp/order/{orderId}/arrival/batch 增加新校验:请求数组里所有元素的 direction 必须一致(不能同一次 batch 里混提 ARRIVAL 和 DEPARTURE)。 + +| 错误码 | message | +|--------|--------| +| 580010 | 批量提交的批次必须同一方向(到达或返程) | + + +响应示例(错误): + +```json +{ + "code": 580010, + "message": "批量提交的批次必须同一方向(到达或返程)", + "data": null +} +``` + +--- + +## 涉及的接口汇总 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 查询订单全量批次 | GET | /mp/order/{orderId}/arrival | 字段新增 | 每个批次对象新增 mode + modeLabel | +| 2 | 新增交通批次 | POST | /mp/order/{orderId}/arrival | 语义破坏性变更 | 从追加改为该方向全量替换 1 条 | +| 3 | 全量替换批次(多批) | POST | /mp/order/{orderId}/arrival/batch | Bug 修复 + 新增校验 | 修方向隔离 bug;新增 direction 混用校验 | +| 4 | 修改交通批次 | PUT | /mp/order/{orderId}/arrival/plan/{planId} | 无变化 | - | +| 5 | 删除交通批次 | DELETE | /mp/order/{orderId}/arrival/plan/{planId} | 无变化 | - | + +--- + +## 接口详细定义 + +### 1. GET /mp/order/{orderId}/arrival — 查询订单全量到达/离开批次 + +- **使用场景**:进入订单详情/行程页时查询,用返回的 arrivals[0]?.mode 和 departures[0]?.mode 决定各方向 tab 默认状态 + +- **路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| orderId | Long | 是 | 订单 ID | + +- **响应字段(data 对象)**: + +| 字段 | 类型 | 说明 | +|------|------|------| +| orderId | Long | 订单 ID | +| arrivals | Array | direction=ARRIVAL 的批次列表 | +| departures | Array | direction=DEPARTURE 的批次列表 | + +arrivals/departures 内每个批次对象字段(MpArrivalPlanRespVO): + +| 字段 | 类型 | 说明 | +|------|------|------| +| planId | Long | 批次 ID | +| orderId | Long | 订单 ID | +| direction | String | ARRIVAL/DEPARTURE | +| directionLabel | String | 到达/离开 | +| mode | String | **[本次新增]** TOGETHER/SEPARATE | +| modeLabel | String | **[本次新增]** 一起到达/多批到达/一起返程/多批返程 | +| transportType | String | FLIGHT/TRAIN/SELF_DRIVE | +| transportTypeLabel | String | 飞机/火车/自驾 | +| transportNo | String | 航班号/车次号(自驾为 null) | +| carrier | String | 航司/铁路公司 | +| departStation | String | 出发站/机场 | +| arriveStation | String | 到达站/机场 | +| departTime | String | 出发时间,格式 yyyy-MM-dd HH:mm:ss | +| arriveTime | String | 到达时间,格式 yyyy-MM-dd HH:mm:ss | +| selfDrivePeriod | String | 自驾时段(MORNING/AFTERNOON/EVENING),非自驾为 null | +| selfDrivePeriodLabel | String | 上午/下午/晚上,非自驾为 null | +| selfDriveEta | String | 自驾预计到达精确时间,非自驾为 null | +| remark | String | 用户备注 | +| creatorType | String | USER/ADMIN | +| createTime | String | 创建时间 | +| travelers | Array | 本批次出行人列表 | + +travelers 内每个出行人字段: + +| 字段 | 类型 | 说明 | +|------|------|------| +| travelerId | Long | 出行人 ID | +| name | String | 姓名 | +| travelerType | String | ADULT/CHILD/YOUNG_CHILD/BABY | + +- **响应示例(完整)**: +```json +{ + "code": 200, + "message": "success", + "data": { + "orderId": 700001, + "arrivals": [ + { + "planId": 800001, + "orderId": 700001, + "direction": "ARRIVAL", + "directionLabel": "到达", + "mode": "TOGETHER", + "modeLabel": "一起到达", + "transportType": "FLIGHT", + "transportTypeLabel": "飞机", + "transportNo": "CZ6255", + "carrier": "南方航空", + "departStation": "北京首都T3", + "arriveStation": "海拉尔东山", + "departTime": "2026-07-10 08:30:00", + "arriveTime": "2026-07-10 11:00:00", + "selfDrivePeriod": null, + "selfDrivePeriodLabel": null, + "selfDriveEta": null, + "remark": "带小孩,需婴儿座椅", + "creatorType": "USER", + "createTime": "2026-07-01 10:00:00", + "travelers": [ + { + "travelerId": 10001, + "name": "张三", + "travelerType": "ADULT" + } + ] + } + ], + "departures": [ + { + "planId": 800002, + "orderId": 700001, + "direction": "DEPARTURE", + "directionLabel": "离开", + "mode": "SEPARATE", + "modeLabel": "多批返程", + "transportType": "TRAIN", + "transportTypeLabel": "火车", + "transportNo": "K209", + "carrier": null, + "departStation": "海拉尔", + "arriveStation": "北京", + "departTime": "2026-07-15 10:00:00", + "arriveTime": "2026-07-16 08:00:00", + "selfDrivePeriod": null, + "selfDrivePeriodLabel": null, + "selfDriveEta": null, + "remark": null, + "creatorType": "USER", + "createTime": "2026-07-02 09:00:00", + "travelers": [ + { + "travelerId": 10001, + "name": "张三", + "travelerType": "ADULT" + } + ] + } + ] + } +} +``` + +--- + +### 2. POST /mp/order/{orderId}/arrival — 新增交通批次(单条,该方向全量替换) + +- **使用场景**:用户在「一起到达」或「一起返程」tab 填写单条信息并提交 +- **语义重申**:调用此接口会把同 direction 的所有旧批次软删,再插入 1 条新批次。最终该方向只剩 1 条,mode 固定为 TOGETHER + +- **路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| orderId | Long | 是 | 订单 ID | + +- **请求参数(JSON Body)**: + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| direction | String | 是 | ARRIVAL=到达 / DEPARTURE=离开 | +| transportType | String | 是 | FLIGHT=飞机 / TRAIN=火车 / SELF_DRIVE=自驾 | +| transportNo | String | 条件必填 | 航班号/车次号;FLIGHT/TRAIN 必填,SELF_DRIVE 不填 | +| carrier | String | 否 | 航司/铁路公司,最长 64 字符 | +| departStation | String | 条件必填 | 出发站/机场;DEPARTURE+FLIGHT/TRAIN 必填;ARRIVAL 可选 | +| arriveStation | String | 条件必填 | 到达站/机场;ARRIVAL+FLIGHT/TRAIN 必填;DEPARTURE 可选 | +| departTime | String | 条件必填 | 出发时间;DEPARTURE+FLIGHT/TRAIN 必填;格式 yyyy-MM-dd HH:mm:ss | +| arriveTime | String | 条件必填 | 到达时间;ARRIVAL+FLIGHT/TRAIN 必填;格式 yyyy-MM-dd HH:mm:ss | +| selfDrivePeriod | String | 条件必填 | 自驾时段;SELF_DRIVE 必填;MORNING/AFTERNOON/EVENING | +| selfDriveEta | String | 否 | 自驾预计到达精确时间;SELF_DRIVE 可选;格式 yyyy-MM-dd HH:mm:ss | +| remark | String | 否 | 用户备注,最长 255 字符 | +| travelerIds | Array | 是 | 出行人 ID 列表,至少 1 人,必须属于本订单 | + +- **请求示例(到达+飞机)**: +```json +{ + "direction": "ARRIVAL", + "transportType": "FLIGHT", + "transportNo": "CZ6255", + "carrier": "南方航空", + "departStation": "北京首都T3", + "arriveStation": "海拉尔东山", + "departTime": "2026-07-10 08:30:00", + "arriveTime": "2026-07-10 11:00:00", + "remark": "带小孩,需婴儿座椅", + "travelerIds": [ + 10001, + 10002 + ] +} +``` + +- **响应示例(完整)**: + +```json +{ + "code": 200, + "message": "success", + "data": { + "planId": 800001, + "orderId": 700001, + "direction": "ARRIVAL", + "directionLabel": "到达", + "mode": "TOGETHER", + "modeLabel": "一起到达", + "transportType": "FLIGHT", + "transportTypeLabel": "飞机", + "transportNo": "CZ6255", + "carrier": "南方航空", + "departStation": "北京首都T3", + "arriveStation": "海拉尔东山", + "departTime": "2026-07-10 08:30:00", + "arriveTime": "2026-07-10 11:00:00", + "selfDrivePeriod": null, + "selfDrivePeriodLabel": null, + "selfDriveEta": null, + "remark": "带小孩,需婴儿座椅", + "creatorType": "USER", + "createTime": "2026-07-01 10:00:00", + "travelers": [ + { + "travelerId": 10001, + "name": "张三", + "travelerType": "ADULT" + }, + { + "travelerId": 10002, + "name": "李四", + "travelerType": "CHILD" + } + ] + } +} +``` + +--- + +### 3. POST /mp/order/{orderId}/arrival/batch — 全量替换批次(多批模式) + +- **使用场景**:用户在「多批到达」或「多批返程」tab,一次性提交该方向所有批次 +- **Bug 修复**:旧版本会把订单全部旧批次删掉(含另一方向),新版本只删 body 第一条元素对应的 direction +- **新增校验**:body 数组里所有元素的 direction 必须一致,混提返回 code=580010 + +- **路径参数**: + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| orderId | Long | 是 | 订单 ID | + +- **请求参数(JSON Body,数组)**:字段同上面单条接口,外层包数组 + +- **请求示例(多批返程)**: +```json +[ + { + "direction": "DEPARTURE", + "transportType": "FLIGHT", + "transportNo": "CZ6256", + "carrier": "南方航空", + "departStation": "海拉尔东山", + "arriveStation": "北京首都T3", + "departTime": "2026-07-15 12:00:00", + "arriveTime": "2026-07-15 15:30:00", + "travelerIds": [ + 10001 + ] + }, + { + "direction": "DEPARTURE", + "transportType": "TRAIN", + "transportNo": "K209", + "departStation": "海拉尔", + "arriveStation": "北京", + "departTime": "2026-07-15 10:00:00", + "arriveTime": "2026-07-16 08:00:00", + "travelerIds": [ + 10002 + ] + } +] +``` + +- **响应示例(完整)**: + +```json +{ + "code": 200, + "message": "success", + "data": { + "orderId": 700001, + "arrivals": [], + "departures": [ + { + "planId": 800003, + "orderId": 700001, + "direction": "DEPARTURE", + "directionLabel": "离开", + "mode": "SEPARATE", + "modeLabel": "多批返程", + "transportType": "FLIGHT", + "transportTypeLabel": "飞机", + "transportNo": "CZ6256", + "carrier": "南方航空", + "departStation": "海拉尔东山", + "arriveStation": "北京首都T3", + "departTime": "2026-07-15 12:00:00", + "arriveTime": "2026-07-15 15:30:00", + "selfDrivePeriod": null, + "selfDrivePeriodLabel": null, + "selfDriveEta": null, + "remark": null, + "creatorType": "USER", + "createTime": "2026-07-01 11:00:00", + "travelers": [ + { + "travelerId": 10001, + "name": "张三", + "travelerType": "ADULT" + } + ] + }, + { + "planId": 800004, + "orderId": 700001, + "direction": "DEPARTURE", + "directionLabel": "离开", + "mode": "SEPARATE", + "modeLabel": "多批返程", + "transportType": "TRAIN", + "transportTypeLabel": "火车", + "transportNo": "K209", + "carrier": null, + "departStation": "海拉尔", + "arriveStation": "北京", + "departTime": "2026-07-15 10:00:00", + "arriveTime": "2026-07-16 08:00:00", + "selfDrivePeriod": null, + "selfDrivePeriodLabel": null, + "selfDriveEta": null, + "remark": null, + "creatorType": "USER", + "createTime": "2026-07-01 11:00:00", + "travelers": [ + { + "travelerId": 10002, + "name": "李四", + "travelerType": "CHILD" + } + ] + } + ] + } +} +``` + +--- + +## 枚举 / 字典值(完整) + +### transport_direction(方向) + +| 值 | 中文 | 说明 | +|----|------|------| +| ARRIVAL | 到达 | 游客到达目的地 | +| DEPARTURE | 离开 | 游客离开目的地(返程) | + +### mode(模式,本次新增) + +| 值 | 中文 | 说明 | +|----|------|------| +| TOGETHER | 一起 | 该方向所有出行人同一批次 | +| SEPARATE | 多批 | 该方向出行人分多个批次 | + +### modeLabel(按 direction + mode 拼,本次新增) + +| direction | mode | modeLabel | +|-----------|------|-----------| +| ARRIVAL | TOGETHER | 一起到达 | +| ARRIVAL | SEPARATE | 多批到达 | +| DEPARTURE | TOGETHER | 一起返程 | +| DEPARTURE | SEPARATE | 多批返程 | + +### transport_type(交通方式) + +| 值 | 中文 | +|----|------| +| FLIGHT | 飞机 | +| TRAIN | 火车 | +| SELF_DRIVE | 自驾 | + +### self_drive_period(自驾时段) + +| 值 | 中文 | 时间范围 | +|----|------|---------| +| MORNING | 上午 | 06:00-12:00 | +| AFTERNOON | 下午 | 12:00-18:00 | +| EVENING | 晚上 | 18:00 以后 | + +### creator_type(创建者类型) + +| 值 | 中文 | +|----|------| +| USER | 用户自填 | +| ADMIN | 定制师代录 | + +### traveler_type(出行人类型) + +| 值 | 中文 | +|----|------| +| ADULT | 成人 | +| CHILD | 儿童 | +| YOUNG_CHILD | 幼儿 | +| BABY | 婴儿 | + +--- + +## 错误码(本模块完整) + +| code | message | 触发场景 | +|------|---------|---------| +| 580001 | 订单当前状态不可修改交通信息: {状态} | 订单不在可编辑状态 | +| 580002 | 出行人列表不能为空 | travelerIds 为空 | +| 580003 | 以下出行人不属于本订单: {ids} | travelerIds 包含不属于此订单的 ID | +| 580004 | 航班号/车次号不能为空 | FLIGHT/TRAIN 时 transportNo 未填 | +| 580005 | 到达机场/车站不能为空 | ARRIVAL+FLIGHT/TRAIN 时 arriveStation 未填 | +| 580006 | 到达时间不能为空 | ARRIVAL+FLIGHT/TRAIN 时 arriveTime 未填 | +| 580007 | 出发机场/车站不能为空 | DEPARTURE+FLIGHT/TRAIN 时 departStation 未填 | +| 580008 | 出发时间不能为空 | DEPARTURE+FLIGHT/TRAIN 时 departTime 未填 | +| 580009 | 自驾时段不能为空 | SELF_DRIVE 时 selfDrivePeriod 未填 | +| 580010 | 批量提交的批次必须同一方向(到达或返程) | batch 接口 body 内 direction 混用(本次新增) | + +--- + +## 业务规则 / 校验规则 + +1. POST /arrival(单数):提交即清空同 direction 旧批次,再插入 1 条。最终该方向只有 1 条批次,mode 固定为 TOGETHER。 +2. POST /arrival/batch:提交即清空同 direction 旧批次,再批量插入。有 2 条及以上时 mode 为 SEPARATE;仅 1 条时 mode 也是 SEPARATE(因为用户选择了「多批」入口)。 +3. 两个接口只影响自己提交的 direction,不互相干扰(本次 bug 修复要点)。 +4. PUT /arrival/plan/{planId} 修改单条,不影响其他批次,不改变 mode。 +5. DELETE /arrival/plan/{planId} 只软删单条。 +6. 以上操作均需订单处于可编辑状态,否则返回 580001。 + +--- + +## 前端实现建议 + + + +--- + +## 补充说明 + +- GET 接口新增 mode/modeLabel 字段,向后兼容(纯新增,无删改名),已有代码不受影响 +- POST 单数接口语义变更属于破坏性变更,旧版用多次调单数接口实现分批的需改用 batch +- 服务重启:需重启 hl-order-service-v2 和 hl-mp-service 后生效