# 【✨新增接口·管理后台】终止行程·退款预览 (#3556) > **PR**: #3557 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-06 ## 1. 接口背景 出行中订单因特殊原因需要提前终止行程时,需要给定制师一个「按已用资源算应退多少」的界面。本接口提供终止退款弹框所需的**全部资源清单 + 行程时间轴信息**,定制师选择「停在第几天」后,由前端本地标记每项资源已用/未用并实时算出退款额,最终在终止提交接口落账。 ## 2. 变更清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 终止退款预览 | POST | `/v3/admin/order/{id}/terminate/refund-preview` | 新增接口 | 返回终止退款弹框所需资源清单 + 行程信息 | ## 3. 接口详情 ### 3.1 终止退款预览 - **使用场景**:出行中订单点击「终止行程」打开退款弹框时调用一次,拿到整趟全部资源清单 - **认证**:需要管理端 JWT(`Authorization` 头) - **幂等性**:是(只读查询,不落库) - **限流**:无 ## 4. 接口入参 ### 4.1 路径参数 | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | id | String | ✅ | 订单 ID | ### 4.2 请求体字段 无请求体。前端**一次性**拿到整趟全部资源,「停在第几天」的选择与已用/未用标记、退款金额计算全部在前端本地完成,**不需要每选一天再调本接口**。 ## 5. 出参(响应) ### 5.1 响应字段(`data`) | 字段 | 类型 | 说明 | |------|------|------| | paidAmount | BigDecimal | 已付金额(公司账上已收,前端算退款基线用) | | tripDays | Integer | 行程总天数(画时间轴用,如 7 天 6 晚 = 7) | | departDate | String(date) | 出发日期(`yyyy-MM-dd`,第 N 天日期 = 出发日 + N−1) | | tripCurrentDay | Integer | 当前已出行到第几天(时间轴默认选中点) | | rooms | Array | 住宿资源清单(每晚每组房一行) | | tickets | Array | 门票资源清单(每景点每天一行) | | vehicles | Array | 用车资源清单(**整车已按天展开,每天一行**) | | insurance | Array | 保险清单(整单一行,锁定不退) | ### 5.2 ResourceItem 字段(rooms / tickets / vehicles / insurance 各行通用) | 字段 | 类型 | 说明 | |------|------|------| | refId | String | 资源记录 ID(提交终止时按此回传已用判定;用车多天共用同一 refId,靠 dayNumber 区分;保险可能为 null) | | name | String | 资源名称(酒店名 / 景点名 / 车型 / 保险产品名) | | dayNumber | Integer | 对应行程第几天(保险为 null) | | dealPrice | BigDecimal | 成交单价(住宿=每间每晚价 / 门票=每张价 / 用车=每天每辆日租 / 保险=保费) | | quantity | Integer | 数量(住宿=房间数 / 门票=张数 / 用车=车辆数 / 保险=1) | | totalAmount | BigDecimal | 本行小计(= dealPrice × quantity) | | locked | Boolean | 是否锁定不退(保险恒 true,其余 false) | | lockedReason | String | 锁定原因(如「保险已生效不退」;未锁定为 null) | > 响应**不含**「是否已用」标记与「退款合计」——这些由前端按所选结束天(`dayNumber ≤ 结束天` 默认已用,之后默认可退)实时计算。 ## 6. 枚举 / 数据字典 本接口无枚举字段。资源分类通过 `rooms` / `tickets` / `vehicles` / `insurance` 四个数组区分,无独立 `resourceType` 字段。 ## 7. 错误码 | code | 含义 | 触发场景 | |------|------|----------| | 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非「出行中」时调用本接口 | ## 8. 示例 ### 8.1 典型成功 **请求**: ``` POST /v3/admin/order/60001234567890/terminate/refund-preview Authorization: Bearer {token} (无请求体) ``` **响应**: ```json { "code": 200, "message": "ok", "success": true, "data": { "paidAmount": 6000.00, "tripDays": 7, "departDate": "2026-05-12", "tripCurrentDay": 3, "rooms": [ {"refId": "96011", "name": "拉萨瑞吉度假酒店·大床房", "dayNumber": 1, "dealPrice": 1280.00, "quantity": 1, "totalAmount": 1280.00, "locked": false, "lockedReason": null}, {"refId": "96014", "name": "拉萨瑞吉度假酒店·大床房", "dayNumber": 4, "dealPrice": 1280.00, "quantity": 1, "totalAmount": 1280.00, "locked": false, "lockedReason": null} ], "tickets": [ {"refId": "97001", "name": "布达拉宫门票", "dayNumber": 2, "dealPrice": 200.00, "quantity": 2, "totalAmount": 400.00, "locked": false, "lockedReason": null} ], "vehicles": [ {"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 1, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null}, {"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 2, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null}, {"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 3, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null} ], "insurance": [ {"refId": null, "name": "安联境内旅行险·尊享版", "dayNumber": null, "dealPrice": 256.00, "quantity": 1, "totalAmount": 256.00, "locked": true, "lockedReason": "保险已生效不退"} ] } } ``` ### 8.2 边界情况 **场景说明**:某天住两个酒店(同一 dayNumber 出现多行)。 **响应(rooms 片段)**: ```json "rooms": [ {"refId": "96021", "name": "林芝希尔顿·双床房", "dayNumber": 2, "dealPrice": 980.00, "quantity": 1, "totalAmount": 980.00, "locked": false, "lockedReason": null}, {"refId": "96022", "name": "林芝工布庄园·大床房", "dayNumber": 2, "dealPrice": 880.00, "quantity": 1, "totalAmount": 880.00, "locked": false, "lockedReason": null} ] ``` ### 8.3 业务失败(异常) **场景说明**:订单非出行中(如已确认待出发)时调用。 **响应**: ```json { "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false } ``` ## 9. 业务边界 - ✅ **适用场景**:订单当前状态 = 出行中(TRAVELLING) - ❌ **不适用场景**:未出发(待支付 / 待完善 / 已确认待出发)→ 返回 581018;这些状态请走「取消订单」流程,不走终止退款 - ⚠️ **特殊边界**: - 保险行恒 `locked=true`,不参与退款 - 同一天可有多行(多酒店 / 多门票 / 多车),按 refId 区分 - 用车一段车按行程天数展开为多行,多行共用同一 refId ## 13. 关联 / 联系人 ### 13.1 链接 - **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556) - **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557) - **Merge commit**: [773dcdacf](https://git.1814.love:8443/wx/HL/commit/773dcdacf) - **关联 PR(预览状态校验加固)**: [#3559](https://git.1814.love:8443/wx/HL/pulls/3559) ### 13.2 联系人 - **后端负责人**: @yst - **前端对接(管理后台)**: 终止行程弹框页面