回应前端 mmg 在 #2 issue 提的 2 处契约空白: §3.2 §1.2 OrderListItemRespVO - 字段表 17 → 18 字段,新增 teamNo(订金支付成功时生成;列表"团号"展示用) - 响应 JSON 示例同步加 teamNo 字段 - 前端不再从 displayOrderNo substr 解析团号 §6.17 transition eventCode - 9 行平铺表 → 16 条规则三元组(事件 → 前置态 → 目标态) - 显式标注 CONFIRM 复用 2 种语义: · CUSTOMIZING → PENDING_DEPARTURE = 确认锁单 · REVIEWING → SETTLED = 核单通过 / 确认结算 - FINISH 仅用于 TRAVELLING → REVIEWING(结团,不是结算) - 新增 §6.17.2「非 transition 业务路径」段落: · 核单结算走独立 6 步接口 /settlement/step{1-6}/*,Step 6 submit 内部自动推 REVIEWING → SETTLED,前端不 fire eventCode · 退款走独立退款接口 · 「申请解锁」v3 已砍,前端隐藏对应按钮 §13 关联链接 v5.49 → v5.50(同步 PR #2614 升的设计文档版本号) 关联: - HL PR: wx/HL#2614 (merged 087c4331) - 前端 issue: #2
64 KiB
【新增接口·管理后台】v3 订单核心模块 §1 core
更新时间: 2026-05-18 端类型: 管理后台 设计文档版本: v5.49(API-SPEC / SRS / DETAIL-DESIGN / DATABASE-SCHEMA 4 份 HTML 同步)
0. 模块全貌
| 子模块 | 含接口 | 接口数 | 状态 |
|---|---|---|---|
| §1A 订单 CRUD + 详情 | §1.1 创建 / §1.2 列表 / §1.3.1 详情主聚合 / §1.3.2~§1.3.7 6 Tab 子接口 / §1.4 修改 | 10 | ✅ |
| §1B 取消订单 | §1.5.0 预览 / §1.5.1 出行前 / §1.5.2 出行中 | 3 | ✅ |
| §1C 状态机 + 锁单 | §1.7 transition / §1.8 confirm-checklist | 2 | ✅ |
| §1 合计 | — | 15 | ✅ 本次推送 |
1. 接口背景
订单服务 v3(hl-order-service-v3 全新二期)的订单核心模块 §1 core 提供订单管理基础能力,覆盖定制师 B 端代下单 / 多维度筛选列表 / 订单详情(首屏主聚合 + 6 个 Tab 独立懒加载)/ 非关键字段修改。
本次推送 §1 模块全 15 个接口,对应管理后台原型 F8-F20(订单列表+创建+详情主体)、F22-F26(详情各 Tab 单刷新)、F37(修改订单字段)、F30-F32(取消订单弹框+出行前/出行中)、F33-F34(确认锁单 checklist + 状态机操作)。
2. 变更清单
| # | § | 接口名 | 方法 | 路径 |
|---|---|---|---|---|
| 1 | 1.1 | 创建订单 | POST | /v3/admin/order |
| 2 | 1.2 | 订单列表 | GET | /v3/admin/order |
| 3 | 1.3.1 | 订单详情主聚合 | GET | /v3/admin/order/{id} |
| 4 | 1.3.2 | 财务 Tab | GET | /v3/admin/order/{id}/finance |
| 5 | 1.3.3 | 合同保险 Tab | GET | /v3/admin/order/{id}/contract-insurance |
| 6 | 1.3.4 | 行程安排 Tab ⚠️Mock | GET | /v3/admin/order/{id}/itinerary |
| 7 | 1.3.5 | 状态记录 Tab | GET | /v3/admin/order/{id}/status-log |
| 8 | 1.3.6 | 退款明细 Tab | GET | /v3/admin/order/{id}/refund |
| 9 | 1.3.7 | 服务标准 Tab | GET | /v3/admin/order/{id}/service-standard |
| 10 | 1.4 | 修改订单字段 | PUT | /v3/admin/order/{id} |
| 11 | 1.5.0 | 取消订单预览 | GET | /v3/admin/order/{id}/cancel-preview |
| 12 | 1.5.1 | 取消订单(出行前) | POST | /v3/admin/order/{id}/cancel/pre-trip |
| 13 | 1.5.2 | 取消订单(出行中) | POST | /v3/admin/order/{id}/cancel/on-trip |
| 14 | 1.7 | 状态变更操作(状态机) | POST | /v3/admin/order/{id}/transition |
| 15 | 1.8 | 确认锁单前置 Checklist | GET | /v3/admin/order/{id}/confirm-checklist |
3. 接口详情
每个接口自包含:使用场景 / 入参 / 出参 / 错误码 / 业务边界 / 示例(请求 + 响应)。 跨接口共享枚举集中在 §6;模块整体影响评估在 §11。
3.1 §1.1 创建订单
路径:POST /v3/admin/order
使用场景:定制师 B 端代下单(电话 / 微信 / 线下渠道)。客户自助下单走 mp 端不在本模块。
认证:JWT(admin 角色) | 幂等性:否 | 限流:无
入参(OrderCreateReqVO,13 字段)
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|---|---|---|---|---|
productId |
Long | ✅ | 产品 ID | @NotNull |
tierSeq |
Integer | ✅ | 档位序号 | @NotNull |
departureDate |
LocalDate | ✅ | 出发日期 | @NotNull |
adultCount |
Integer | ✅ | 成人数 | @NotNull @Min(1) |
childCount |
Integer | ❌ | 儿童数 | @Min(0),默认 0 |
youngChildCount |
Integer | ❌ | 幼儿数 | @Min(0),默认 0 |
babyCount |
Integer | ❌ | 婴儿数 | @Min(0),默认 0 |
customerName |
String | ✅ | 客户姓名 | @NotBlank |
customerPhone |
String | ✅ | 客户手机(明文传,11 位数字) | @NotBlank |
customerRemark |
String | ❌ | 客户备注 | @Size(max=500) |
createSource |
String | ❌ | 创建来源(不传默认 CONSULTANT) |
枚举见 §6.1 |
groupBatchId |
Long | ❌ | 拼团批次 ID(自由出团传空) | — |
roomCount |
Integer | ❌ | 房间数 | @Min(1) |
tags |
List<String> | ❌ | 订单标签名列表 | — |
出参(Result<OrderCreateRespVO>,20 字段)
| 字段 | 类型 | 说明 |
|---|---|---|
id |
String | 订单主键 |
orderNo |
String | 订单号,格式 HL{yyyyMMddHHmmss}{3 位序号} |
displayOrderNo |
String | 展示订单号 = orderNo + teamNo;teamNo 为空时等同 orderNo |
orderStatus |
String | 创单后固定 PENDING_PAY(枚举见 §6.2) |
flowStatus |
String | 创单后固定 AWAITING_PROFILE(枚举见 §6.3) |
consultantId |
String | 实际绑定的定制师 ID |
consultantSource |
String | 定制师来源(枚举见 §6.4) |
tags |
List<String> | 标签列表(含入参 tags + 系统自动标签) |
createdAt |
LocalDateTime | 创单时间 |
productName |
String | 产品名称 |
tierName |
String | 档位名 |
groupBatchName |
String? | 拼团批次名(自由出团时 null) |
departureDate |
LocalDate | 出发日 |
returnDate |
LocalDate | 返团日 |
totalAmount |
BigDecimal | 订单总价(元,2 位小数) |
depositAmount |
BigDecimal | 建议定金金额 |
depositRatio |
Integer | 定金比例百分比(DEPOSIT 模式有值;FULL 模式恒为 100) |
paymentMode |
String | 支付模式(枚举见 §6.5) |
expiryMinutes |
Integer | 支付时限分钟数,默认 1440 |
payUrl |
String | 支付页绝对 URL |
customerName |
String | 客户姓名(回显) |
错误码
| code | 含义 |
|---|---|
510101 |
产品不存在 / 已下架 |
510102 |
档位不存在 |
510103 |
出发日期早于今天 |
510104 |
出发日期超过报名截止 |
510105 |
拼团批次不存在 / 已满员 |
510106 |
总人数 = 0 |
510107 |
createSource 枚举非法 |
510108 |
客户手机格式非法 |
510109 |
系统未配置默认定制师 |
581013 |
定制师 ID 缺失(admin 端 JWT adminId 缺失) |
581014 |
产品域 Feign 调用失败 |
581015 |
产品域返回产品不存在 |
581020 |
MQ 事件发布失败(非主路径,记审计) |
581021 |
跨公司访问被拒(公司隔离) |
业务边界
- ✅ 适用:产品上架;档位有效;出发日期 ≥ 今天;总人数 ≥ 1;客户手机合法
- ❌ 拒绝:产品下架 / 出发日期过期 / 总人数 0 / 拼团满员 / 客户手机非 11 位
- ⚠️ 可选字段省略:不传
createSource用默认CONSULTANT/ 不传roomCount返 null / 不传tags仅含系统自动标签
示例
典型成功 - 请求:
POST /v3/admin/order
Authorization: Bearer {admin_jwt}
Content-Type: application/json
{
"productId": 30001234567,
"tierSeq": 1,
"departureDate": "2026-06-01",
"adultCount": 2,
"childCount": 1,
"customerName": "张三",
"customerPhone": "13800002046",
"customerRemark": "希望住朝阳房",
"createSource": "CONSULTANT",
"groupBatchId": 80001234567890,
"roomCount": 2,
"tags": ["VIP 客户"]
}
典型成功 - 响应:
{
"code": 200,
"data": {
"id": "60123456789012",
"orderNo": "HL20260518220000001",
"displayOrderNo": "HL20260518220000001",
"orderStatus": "PENDING_PAY",
"flowStatus": "AWAITING_PROFILE",
"consultantId": "50001234567890",
"consultantSource": "DEFAULT_ASSIGNED",
"tags": ["VIP 客户", "含儿童"],
"createdAt": "2026-05-18T22:00:00",
"productName": "长白山天池3日深度游",
"tierName": "经典档",
"groupBatchName": "第 2 期",
"departureDate": "2026-06-01",
"returnDate": "2026-06-03",
"totalAmount": 8580.00,
"depositAmount": 2574.00,
"depositRatio": 30,
"paymentMode": "DEPOSIT",
"expiryMinutes": 1440,
"payUrl": "https://pay.hulalv.com/pay/HL20260518220000001",
"customerName": "张三"
},
"msg": "success"
}
异常(拼团满员 510105) - 请求:(同上,但 groupBatchId 指向已满批次)
异常 - 响应:
{ "code": 510105, "data": null, "msg": "拼团批次不存在或已满员" }
3.2 §1.2 订单列表
路径:GET /v3/admin/order
使用场景:定制师 / 主管 / 客服多维度筛选订单
认证:JWT(admin 角色) | 分页:继承 PageParam
入参(OrderListReqVO extends PageParam)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
page |
Integer | ❌ | 页码,默认 1 |
pageSize |
Integer | ❌ | 每页条数,默认 10 |
orderStatus |
String | ❌ | 粗状态过滤(传英文枚举值,多值用逗号,见 §6.2) |
flowStatus |
String | ❌ | 细状态过滤(传英文枚举值,见 §6.3) |
tagNames |
List<String> | ❌ | 按标签过滤(多标签为 AND) |
keyword |
String | ❌ | 关键字(LIKE 团号 / 客户姓名 / 产品名 / 订单号 任一) |
departureDateFrom |
LocalDate | ❌ | 出发日期范围起始 |
departureDateTo |
LocalDate | ❌ | 出发日期范围结束 |
createSource |
String | ❌ | 来源过滤(枚举见 §6.1) |
cancelled |
Boolean | ❌ | 是否含已取消(默认 false) |
出参(Result<PageResult<OrderListItemRespVO>>)
PageResult 字段:list: List<OrderListItemRespVO> / total: Long / page / pageSize
OrderListItemRespVO(18 字段):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
String | 订单 ID |
orderNo |
String | 订单号 |
teamNo |
String? | 团号(订金支付成功时生成,创单时为 null) |
displayOrderNo |
String | 完整展示订单号 |
productName |
String | 产品名(快照) |
productCoverImg |
String | 产品封面 URL |
tierName |
String | 档位名(快照) |
customerName |
String | 客户姓名 |
customerPhoneMasked |
String | 客户手机(脱敏 138****2046) |
peopleSummary |
String | 人数摘要("2 大 1 小") |
departureDate |
LocalDate? | 出发日(未定时 null) |
tripDays |
Integer | 行程天数 |
orderStatus |
String | 粗状态(枚举见 §6.2) |
flowStatus |
String | 细状态(枚举见 §6.3) |
totalAmount |
BigDecimal | 订单金额 |
paidAmount |
BigDecimal | 实付金额 |
balanceAmount |
BigDecimal | 待付金额 |
consultantName |
String | 定制师姓名 |
tags |
List<String> | 标签列表 |
createdAt |
LocalDateTime | 创单时间 |
错误码
参数格式错误走全局 400,无业务错误码。
业务边界
- ✅ 默认行为:
cancelled不传 = 不含已取消订单 - ⚠️ 关键字:
keyword同时 LIKE 4 字段(团号 / 客户姓名 / 产品名 / 订单号)任一命中 - ⚠️ 标签过滤:
tagNames多值是 AND(订单必须含全部标签才命中),不是 OR
示例
典型 - 请求:
GET /v3/admin/order?page=1&pageSize=10&orderStatus=PENDING_DEPARTURE&tagNames=VIP%20%E5%AE%A2%E6%88%B7
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": {
"list": [
{
"id": "60123456789012",
"orderNo": "HL20260510143025001",
"teamNo": "20260601A",
"displayOrderNo": "HL20260510143025001-T20260601A",
"productName": "长白山天池3日深度游",
"productCoverImg": "https://oss.hulalv.com/p/changbai-cover.jpg",
"tierName": "经典档",
"customerName": "张三",
"customerPhoneMasked": "138****2046",
"peopleSummary": "2 大 1 小",
"departureDate": "2026-06-01",
"tripDays": 3,
"orderStatus": "PENDING_DEPARTURE",
"flowStatus": "PENDING_DEPARTURE",
"totalAmount": 8580.00,
"paidAmount": 8580.00,
"balanceAmount": 0.00,
"consultantName": "李定制",
"tags": ["VIP 客户", "二次复购"],
"createdAt": "2026-05-10T14:30:25"
}
],
"total": 1,
"page": 1,
"pageSize": 10
},
"msg": "success"
}
3.3 §1.3.1 订单详情主聚合
路径:GET /v3/admin/order/{id}
使用场景:详情页首屏加载——一次请求拿到主单 + 标签 + 概览(出行人 / 备注 / 紧急联系人);Tab 详情按需懒加载(§1.3.2 ~ §1.3.7)
认证:JWT + 公司隔离 | 响应规模:精简,不含 6 Tab 子接口数据
📌 本接口只返回 main / tags / overview 3 个顶层字段。原 v5.48 设计的"一次返 9 Tab 全部数据"已拆分:finance / itinerary / contractInsurance / serviceStandard / statusLog / refund 移到 §1.3.2 ~ §1.3.7 独立懒加载接口。
入参
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | ✅ | 订单 ID(path) |
出参(Result<OrderDetailRespVO>,3 顶层字段)
| 字段 | 类型 | 说明 |
|---|---|---|
main |
OrderMainVO | 订单主单 + 异常态横条 + progressStepper 步骤进度条 |
tags |
List<TagVO> | 标签列表 |
overview |
OverviewVO | Tab 1 概览(出行人 + 备注 + 紧急联系人) |
OrderMainVO 关键字段:
| 字段 | 类型 | 说明 |
|---|---|---|
id |
String | 订单 ID |
displayOrderNo |
String | 完整展示订单号 |
productName / tierName |
String | 产品名 / 档位名(快照) |
orderStatus |
String | 粗状态(枚举见 §6.2) |
flowStatus |
String | 细状态(枚举见 §6.3) |
totalAmount / paidAmount / balanceAmount |
BigDecimal | 金额三件套 |
departureDate / returnDate |
LocalDate | 出发日 / 返团日 |
tripDays / tripNights |
Integer | 行程天数 / 晚数 |
adultCount / childCount / youngChildCount / babyCount |
Integer | 4 类人数 |
customerName |
String | 客户姓名 |
customerPhoneMasked |
String | 客户手机(admin 也脱敏,如 138****2046) |
consultantName |
String | 定制师姓名 |
confirmedAt |
LocalDateTime? | 确认锁单时间 |
exceptionBadges |
Map<String, Boolean> | 异常态横条 9 类标识(见下方)⚠️ 运行时暂返 null,OrderInfoConverter 派生逻辑待 Issue 接通子表后实现 |
progressStepper |
Object | 步骤进度条(见下方)⚠️ 运行时暂返 null,OrderInfoConverter 派生逻辑待 Issue 接通子表后实现 |
contractStatus |
String? | [Tab 状态] 合同状态枚举:NONE/GENERATING/GENERATED/SIGNED/VOIDED/RESIGNING,直接读主表 contract_status |
insuranceStatus |
String? | [Tab 状态] 保险状态枚举:NONE/ISSUING/ISSUED/CANCELLED/FAILED,直接读主表 insurance_status |
refundStatus |
String | [Tab 状态] 退款汇总状态枚举:NONE/PROCESSING/COMPLETED(派生,见 OrderMainRefundStatus) |
hasRefund |
Boolean | [Tab 状态] 是否存在退款记录(refundedAmount > 0) |
hasServiceStandard |
Boolean | [Tab 状态] 是否存在服务标准快照(EXISTS order_product_snapshot) |
hasFinanceDetail |
Boolean | [Tab 状态] 是否有财务明细(discountAmount > 0 OR surchargeAmount > 0,派生无 SQL) |
exceptionBadges 9 类布尔字段(全 false 表示无异常):contractFail / insuranceFail / refundAbnormal / grabTimeout / hotelPending / vehiclePending / travelerIncomplete / longUnpaid / awaitingCustomerConfirm
progressStepper:currentStage (String) + nodes 数组,每节点 {key, label, status, subItems?}
- 节点 key 枚举:
INFO_COMPLETE/ASSIGN_PARALLEL/CONFIRM/DEPARTED/RETURNED/REVIEW/SETTLED - 节点 status:
DONE/ACTIVE/PENDING/NOT_APPLICABLE ASSIGN_PARALLEL含subItems:HOTEL/VEHICLE/LEADER/PHOTOGRAPHER子项,每子项 {key, label, subStatus, applicable};subStatus 枚举同节点 status:DONE / ACTIVE / PENDING / NOT_APPLICABLE
TagVO:name / type(枚举见 §6.15) / color
OverviewVO 关键字段:
| 字段 | 类型 | 说明 |
|---|---|---|
travelers |
List<TravelerVO> | 出行人完整集合(复用 traveler 模块 TravelerVO,含证件 / 性别 / 生日 / 民族 / 手机 / 紧急联系人 / 同住分组等,admin 明文) |
customerRemark |
String? | 客户备注 |
consultantRemark |
String? | 定制师备注 |
emergencyContactName |
String? | 紧急联系人姓名 |
emergencyContactPhone |
String? | 紧急联系人手机 |
TravelerVO 字段口径详见 traveler 模块 §2.1 出行人列表 changelog。
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单(公司隔离) |
业务边界
- ✅ 首屏一次请求拿全 main + tags + overview
- ⚠️ 6 Tab 数据不在本响应,按需调 §1.3.2 ~ §1.3.7 子接口
- ⚠️ 跨公司访问 →
581021
示例
典型 - 请求:
GET /v3/admin/order/60123456789012
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": {
"main": {
"id": "60123456789012",
"displayOrderNo": "HL20260510143025001-T20260601A",
"productName": "长白山天池3日深度游",
"tierName": "经典档",
"orderStatus": "PENDING_DEPARTURE",
"flowStatus": "PENDING_DEPARTURE",
"totalAmount": 8580.00,
"paidAmount": 8580.00,
"balanceAmount": 0.00,
"departureDate": "2026-06-01",
"returnDate": "2026-06-03",
"tripDays": 3,
"tripNights": 2,
"adultCount": 2,
"childCount": 1,
"youngChildCount": 0,
"babyCount": 0,
"customerName": "张三",
"customerPhoneMasked": "138****2046",
"consultantName": "李定制",
"confirmedAt": "2026-05-12T10:25:00",
"exceptionBadges": {
"contractFail": false, "insuranceFail": false, "refundAbnormal": false,
"grabTimeout": false, "hotelPending": false, "vehiclePending": false,
"travelerIncomplete": false, "longUnpaid": false, "awaitingCustomerConfirm": false
},
"progressStepper": {
"currentStage": "RETURNED",
"nodes": [
{"key": "INFO_COMPLETE", "label": "补全信息", "status": "DONE"},
{"key": "ASSIGN_PARALLEL", "label": null, "status": "DONE", "subItems": [
{"key": "HOTEL", "label": "配房", "subStatus": "DONE", "applicable": true},
{"key": "VEHICLE", "label": "配车", "subStatus": "DONE", "applicable": true},
{"key": "LEADER", "label": "配领队", "subStatus": "DONE", "applicable": true},
{"key": "PHOTOGRAPHER", "label": "配摄影", "subStatus": "DONE", "applicable": true}
]},
{"key": "CONFIRM", "label": "确认", "status": "DONE"},
{"key": "DEPARTED", "label": "出行", "status": "DONE"},
{"key": "RETURNED", "label": "返团", "status": "ACTIVE"},
{"key": "REVIEW", "label": "核单", "status": "PENDING"},
{"key": "SETTLED", "label": "结算", "status": "PENDING"}
]
}
},
"tags": [
{"name": "二次复购", "type": "SYSTEM", "color": "#52C41A"},
{"name": "VIP 客户", "type": "PERSONAL", "color": "#FAAD14"}
],
"overview": {
"travelers": [
{
"id": "70123456789012",
"orderId": "60123456789012",
"travelerType": "ADULT",
"name": "张三",
"gender": "MALE",
"birthday": "1985-08-12",
"idType": "ID_CARD",
"idNo": "220103198508121234",
"nationality": "中国",
"race": "汉族",
"phone": "13800002046",
"emergencyContact": "李四",
"emergencyPhone": "13900008888",
"roomGroupNo": 1,
"profileStatus": "COMPLETED",
"transportPlanIds": ["80012345678901234"]
}
],
"customerRemark": "希望住朝阳房",
"consultantRemark": "VIP 客户,已沟通到达接机",
"emergencyContactName": "李四",
"emergencyContactPhone": "13900008888"
}
},
"msg": "success"
}
异常(跨公司访问 581021) - 请求:(admin JWT 不属于订单所属公司)
GET /v3/admin/order/60999999999999
Authorization: Bearer {admin_jwt}
异常 - 响应:
{ "code": 581021, "data": null, "msg": "无权访问该订单" }
3.4 §1.3.2 财务 Tab(懒加载)
路径:GET /v3/admin/order/{id}/finance
使用场景:详情页财务 Tab 单独刷新(如优惠 / 退款操作完后刷新)
认证:JWT + 公司隔离
入参
id (path, Long) — 订单 ID
出参(Result<FinanceVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
totalAmount |
BigDecimal | 订单总额 |
paidAmount |
BigDecimal | 实付金额 |
balanceAmount |
BigDecimal | 待付金额 |
discountAmount |
BigDecimal | 优惠金额汇总 |
surchargeAmount |
BigDecimal | 附加费用汇总 |
refundAmount |
BigDecimal | 退款金额汇总 |
payments |
List<PaymentVO> | 支付明细 |
discounts |
List<DiscountVO> | 优惠明细 |
surcharges |
List<SurchargeVO> | 附加费用 |
PaymentVO:id / payType(枚举见 §6.6) / amount / paidAt / status(枚举见 §6.7)
DiscountVO:id / name / amount / type(枚举见 §6.8) / source(枚举见 §6.9) / createdAt
SurchargeVO:id / name / amount / type / source / createdAt
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
示例
典型 - 请求:
GET /v3/admin/order/60123456789012/finance
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": {
"totalAmount": 8580.00,
"paidAmount": 8580.00,
"balanceAmount": 0.00,
"discountAmount": 200.00,
"surchargeAmount": 0.00,
"refundAmount": 0.00,
"payments": [
{"id": 90011, "payType": "DEPOSIT", "amount": 2000.00, "paidAt": "2026-05-10T15:00:00", "status": "SUCCESS"},
{"id": 90012, "payType": "BALANCE", "amount": 6580.00, "paidAt": "2026-05-15T09:30:00", "status": "SUCCESS"}
],
"discounts": [
{"id": 95001, "name": "早鸟优惠", "amount": 200.00, "type": "EARLY_BIRD", "source": "MANUAL", "createdAt": "2026-05-10T14:30:00"}
],
"surcharges": []
},
"msg": "success"
}
3.5 §1.3.3 合同保险 Tab(懒加载)
路径:GET /v3/admin/order/{id}/contract-insurance
使用场景:合同重签 / 保险重投后单独刷新该 Tab
响应结构:contract / insurance 两个并列子对象(前端 Tab 内上下两栏布局)
入参
id (path, Long) — 订单 ID
出参(Result<ContractInsuranceVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
contract.contractStatus |
String | 合同状态(枚举见 §6.10) |
contract.contractSignedAt |
LocalDateTime? | 签约时间 |
contract.contractFileUrl |
String? | 合同文件 URL |
contract.events[].eventType |
String | 合同事件类型(枚举见 §6.11) |
contract.events[].occurredAt |
LocalDateTime | 事件发生时间 |
insurance.insuranceStatus |
String | 保险状态(枚举见 §6.12) |
insurance.insurancePolicyNo |
String? | 保单号 |
insurance.insurancePremium |
BigDecimal? | 保费 |
insurance.events[].eventType |
String | 保险事件类型(枚举见 §6.11) |
insurance.events[].occurredAt |
LocalDateTime | 事件发生时间 |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
示例
典型 - 请求:
GET /v3/admin/order/60123456789012/contract-insurance
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": {
"contract": {
"contractStatus": "SIGNED",
"contractSignedAt": "2026-05-12T11:00:00",
"contractFileUrl": "https://oss.hulalv.com/contract/HL20260510143025001.pdf",
"events": [
{"eventType": "GENERATE", "occurredAt": "2026-05-12T10:55:00"},
{"eventType": "SIGN", "occurredAt": "2026-05-12T11:00:00"}
]
},
"insurance": {
"insuranceStatus": "ACTIVE",
"insurancePolicyNo": "PICC2026060100123",
"insurancePremium": 88.00,
"events": [
{"eventType": "ISSUE", "occurredAt": "2026-05-12T11:05:00"}
]
}
},
"msg": "success"
}
3.6 §1.3.4 行程安排 Tab(懒加载)⚠️ Mock
路径:GET /v3/admin/order/{id}/itinerary
使用场景:调整行程节点 / 房车配置后单独刷新
⚠️ 当前数据 Mock:行程节点 + 房车需求&实配为 Mock 数据,真实化进度见 follow-up Issue。前端可先按字段结构对接,真实化后无需改字段口径。
入参
id (path, Long) — 订单 ID
出参(Result<ItineraryVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
days[].dayIndex |
Integer | 天序 |
days[].dayDate |
String | 日期(yyyy-MM-dd) |
days[].title |
String | 标题 |
days[].nodes |
List<Object> | 节点列表(结构见 itinerary 模块 §5) |
hotelGroup.requirement |
Object | 配房需求(requirementId / status / roomTypeSummary / claimedBy 等) |
hotelGroup.assignments |
List<Object> | 实际配房(hotelName / stayDate / roomType / roomCount / unitPrice / subtotal) |
vehicleGroup.requirement |
Object | 配车需求(requirementId / status / vehicleTypeSummary / claimedBy) |
vehicleGroup.assignments |
List<Object> | 实际配车(vehicleType / plate / driverName / dailyFee / totalFee) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
示例
典型 - 请求:
GET /v3/admin/order/60123456789012/itinerary
Authorization: Bearer {admin_jwt}
典型 - 响应(Mock 数据示意):
{
"code": 200,
"data": {
"days": [
{
"dayIndex": 1,
"dayDate": "2026-06-01",
"title": "抵达长春-接机",
"nodes": [
{"nodeType": "TRANSPORT", "title": "接机", "startTime": "10:30"},
{"nodeType": "HOTEL", "title": "入住凯悦酒店", "actualResourceName": "长春凯悦酒店"}
]
}
],
"hotelGroup": {
"requirement": {
"requirementId": "70011", "status": "DONE", "version": 2,
"roomTypeSummary": "1 大床房×2 + 1 标间×1",
"remark": "希望朝阳房,带浴缸优先",
"budgetRange": "500-800/晚",
"claimedBy": "房控-王芳", "claimedAt": "2026-05-11T14:20:00"
},
"assignments": [
{"id": "80011", "hotelName": "长春凯悦酒店", "stayDate": "2026-06-01", "roomType": "大床房", "roomCount": 2, "roomGroupNo": 1, "unitPrice": 680, "subtotal": 1360}
]
},
"vehicleGroup": {
"requirement": {
"requirementId": "70021", "status": "DONE", "version": 1,
"vehicleTypeSummary": "9 座商务车×1",
"claimedBy": "车控-李强", "claimedAt": "2026-05-11T15:00:00"
},
"assignments": [
{"id": "80021", "vehicleType": "MPV", "plate": "吉A·888XX", "driverName": "王师傅", "driverPhone": "138****1234", "dailyFee": 1100, "totalDays": 3, "totalFee": 3300}
]
}
},
"msg": "success"
}
3.7 §1.3.5 状态记录 Tab(懒加载)
路径:GET /v3/admin/order/{id}/status-log
使用场景:执行状态变更后刷新时间线
数据来源:5 张审计表联合(status_log / payment / refund / contract_event / insurance_event)按 occurredAt desc 倒序
入参
id (path, Long) — 订单 ID
出参(Result<List<LogTimelineVO>>)
| 字段 | 类型 | 说明 |
|---|---|---|
occurredAt |
LocalDateTime | 发生时间 |
operator |
String | 操作人 |
action |
String | 操作描述 |
fromStatus |
String? | 变更前状态(有状态变更时有值) |
toStatus |
String? | 变更后状态 |
amount |
BigDecimal? | 涉及金额(支付/退款时有值) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
示例
典型 - 请求:
GET /v3/admin/order/60123456789012/status-log
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": [
{"occurredAt": "2026-05-12T10:25:00", "operator": "李定制", "action": "确认锁单", "fromStatus": "定制中", "toStatus": "待出行"},
{"occurredAt": "2026-05-10T15:00:00", "operator": "张三", "action": "支付订金", "amount": 2000.00},
{"occurredAt": "2026-05-10T14:30:25", "operator": "李定制", "action": "创建订单"}
],
"msg": "success"
}
3.8 §1.3.6 退款明细 Tab(懒加载,条件显示)
路径:GET /v3/admin/order/{id}/refund
使用场景:退款流程节点变更后刷新;前端轮询等待退款到账
空值约定:无退款时 data=null(前端据此判断是否渲染该 Tab)
入参
id (path, Long) — 订单 ID
出参(Result<RefundDetailVO> 或 Result<null>)
| 字段 | 类型 | 说明 |
|---|---|---|
totalRefundAmount |
BigDecimal | 合计退款金额(= finance.refundAmount) |
applications[].applicationId |
Long | 申请 ID |
applications[].status |
String | 进度状态(枚举见 §6.13) |
applications[].statusText |
String | 状态描述文案 |
applications[].refundAmount |
BigDecimal | 退款金额 |
applications[].refundChannel |
String | 退款渠道("原路退回(支付宝)") |
applications[].approverName |
String? | 审批人 |
applications[].approvedAt |
LocalDateTime? | 审批时间 |
applications[].estimatedArriveDate |
LocalDate? | 预计到账日期 |
applications[].actualArriveDate |
LocalDate? | 实际到账日期 |
applications[].progress[].step |
String | 步骤(枚举见 §6.14) |
applications[].progress[].label |
String | 步骤展示标签 |
applications[].progress[].status |
String | 步骤状态(DONE / ACTIVE / PENDING) |
applications[].progress[].occurredAt |
LocalDateTime? | 步骤发生时间 |
applications[].items[].itemName |
String | 项目名称 |
applications[].items[].reason |
String | 退款原因 |
applications[].items[].appliedAt |
LocalDateTime | 申请时间 |
applications[].items[].amount |
BigDecimal | 退款金额(负数) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
示例
典型(有退款) - 请求:
GET /v3/admin/order/60123456789012/refund
Authorization: Bearer {admin_jwt}
典型(有退款) - 响应:
{
"code": 200,
"data": {
"totalRefundAmount": 4800.00,
"applications": [
{
"applicationId": 60101,
"status": "PENDING_PAYOUT",
"statusText": "财务已审批,等待打款",
"refundAmount": 4800.00,
"refundChannel": "原路退回(支付宝)",
"approverName": "财务 · 周经理",
"approvedAt": "2026-04-25T14:20:00",
"estimatedArriveDate": "2026-04-30",
"actualArriveDate": null,
"progress": [
{"step": "APPLY", "label": "退款申请", "status": "DONE", "occurredAt": "2026-04-25T11:30:00"},
{"step": "APPROVE", "label": "财务审批", "status": "DONE", "occurredAt": "2026-04-25T14:20:00"},
{"step": "PAYOUT", "label": "退款打款", "status": "ACTIVE", "occurredAt": null},
{"step": "ARRIVED", "label": "到账确认", "status": "PENDING", "occurredAt": null}
],
"items": [
{"itemName": "主行程退款(同行小孩临时不能出行)", "reason": "同行儿童突发感冒,不参与本次出行", "appliedAt": "2026-04-25T11:30:00", "amount": -4800.00}
]
}
]
},
"msg": "success"
}
边界(无退款) - 请求:(同上路径)
边界 - 响应:
{ "code": 200, "data": null, "msg": "success" }
3.9 §1.3.7 服务标准 Tab(懒加载,条件显示)
路径:GET /v3/admin/order/{id}/service-standard
使用场景:服务标准 Tab 单独刷新
数据来源:产品快照冻结(永不变)
空值约定:快照缺失时 data=null
入参
id (path, Long) — 订单 ID
出参(Result<ServiceStandardVO> 或 Result<null>)
| 字段 | 类型 | 说明 |
|---|---|---|
itinerary |
List<String> | 行程天纲(产品快照) |
notice.title |
String | 出团注意事项标题 |
notice.content |
String | 出团注意事项内容(Markdown) |
refundPolicy.policyId |
Long | 退改政策 ID |
refundPolicy.policyName |
String | 退改政策名称 |
refundPolicy.tiers[].minDays |
Integer | 出发前最小天数 |
refundPolicy.tiers[].refundRatio |
Integer | 退款比例(百分比 0-100) |
refundPolicy.tiers[].label |
String | 展示文案 |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
示例
典型 - 请求:
GET /v3/admin/order/60123456789012/service-standard
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": {
"itinerary": ["Day1 抵达长春-接机入住", "Day2 长白山天池1日游", "Day3 返程"],
"notice": {
"title": "长白山天池 3 日深度游 - 出团注意事项",
"content": "# 出团必读\n\n1. 高原反应:海拔 2691m,请提前服用红景天\n2. 天气:山顶常年低于 0℃,请备厚外套\n..."
},
"refundPolicy": {
"policyId": 50001,
"policyName": "标准退改政策",
"tiers": [
{"minDays": 15, "refundRatio": 100, "label": "出发前 15 天 100%退"},
{"minDays": 7, "refundRatio": 80, "label": "出发前 7-14 天 80%退"},
{"minDays": 3, "refundRatio": 50, "label": "出发前 3-6 天 50%退"},
{"minDays": 0, "refundRatio": 0, "label": "出发前 2 天内不退"}
]
}
},
"msg": "success"
}
3.10 §1.4 修改订单字段
路径:PUT /v3/admin/order/{id}
使用场景:修改订单非关键字段(备注 / 紧急联系人 / 客户信息 / 转单),不触发状态机
关键字段约定:订单金额 / 状态等不允许在此接口改,需走专用接口
语义:PATCH(传哪个改哪个)
审计:每次修改写 1 行 order_status_log(即使状态未变也记录"字段被改")
入参(OrderUpdateReqVO,PATCH 语义)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
customerName |
String | ❌ | 客户姓名 |
customerPhone |
String | ❌ | 客户手机 |
emergencyContactName |
String | ❌ | 紧急联系人姓名 |
emergencyContactPhone |
String | ❌ | 紧急联系人电话 |
customerRemark |
String | ❌ | 客户备注 |
consultantRemark |
String | ❌ | 定制师备注 |
targetConsultantId |
Long | ❌ | 转单目标定制师 ID(仅主管 / 客服角色可传) |
transferReason |
String | ❌ | 转单原因(传 targetConsultantId 时必填) |
出参(Result<Boolean>)
返回 true 表示成功,false 表示无字段实际变化。
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
581030 |
转单目标定制师不存在 |
581031 |
转单原因为空(传 targetConsultantId 时) |
581032 |
当前角色无转单权限(仅主管 / 客服可转单) |
业务边界
- ✅ 可改字段:备注 / 紧急联系人 / 客户信息 / 转单(仅主管 / 客服角色)
- ❌ 不可改字段:订单金额 / 订单状态 / 出发日期 / 出行人数 / 拼团批次 → 需走专用接口
- ⚠️ 转单约束:传
targetConsultantId必须同时传transferReason - ⚠️ PATCH 语义:不传 = 不改;传空字符串 = 改成空(区分两者)
示例
典型(转单) - 请求:
PUT /v3/admin/order/60123456789012
Authorization: Bearer {admin_jwt}
Content-Type: application/json
{
"targetConsultantId": 50009876543210,
"transferReason": "客户主动申请更换定制师",
"consultantRemark": "已联系新定制师"
}
典型 - 响应:
{ "code": 200, "data": true, "msg": "success" }
异常(转单缺原因 581031) - 请求:
PUT /v3/admin/order/60123456789012
Authorization: Bearer {admin_jwt}
Content-Type: application/json
{
"targetConsultantId": 50009876543210
}
异常 - 响应:
{ "code": 581031, "data": null, "msg": "转单原因为空" }
3.11 §1.5.0 取消订单预览(只读)
路径:GET /v3/admin/order/{id}/cancel-preview
使用场景:定制师点击「取消订单」按钮,弹框打开瞬间调用,展示退款金额 + 扣费 + 退款政策
认证:JWT(admin 角色) | 幂等性:是(只读不入库) | 限流:无
金额规则:严格按订单创建时冻结的 RefundPolicy 快照计算,不接受人工覆盖
入参
id (path, Long) — 订单 ID
出参(Result<OrderCancelPreviewRespVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
refundAmount |
BigDecimal | 退款金额(按 RefundPolicy 计算) |
paidAmount |
BigDecimal | 客户已付金额 |
deductAmount |
BigDecimal | 扣费金额 = paidAmount - refundAmount |
daysToDeparture |
Integer | 距出发天数(今天 - 出发日;负数表已过出发日) |
refundPolicy |
RefundPolicyVO | 退款政策快照(结构同 §3.9 refundPolicy) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
581050 |
订单状态不允许取消(已取消 / 已完成 / 退款中等) |
业务边界
- ✅ 适用:订单粗状态 ∈ {PENDING_PAY, PENDING_COMPLETE, CUSTOMIZING, PENDING_DEPARTURE, PENDING_BALANCE}(v3 状态机:CONFIRM event 直接迁到 PENDING_DEPARTURE;尾款重开切到 PENDING_BALANCE)
- ❌ 拒绝:已取消 / 已完成 / 退款中 →
581050 - ⚠️
daysToDeparture负数:已过出发日,前端应引导走 §3.13 出行中取消(on-trip)而非本接口预览
示例
典型(出行前 12 天) - 请求:
GET /v3/admin/order/60123456789012/cancel-preview
Authorization: Bearer {admin_jwt}
典型 - 响应:
{
"code": 200,
"data": {
"refundAmount": 6864.00,
"paidAmount": 8580.00,
"deductAmount": 1716.00,
"daysToDeparture": 12,
"refundPolicy": {
"policyId": 50001,
"policyName": "标准退改政策",
"tiers": [
{"minDays": 15, "refundRatio": 100, "label": "出发前 15 天 100%退"},
{"minDays": 7, "refundRatio": 80, "label": "出发前 7-14 天 80%退"},
{"minDays": 3, "refundRatio": 50, "label": "出发前 3-6 天 50%退"},
{"minDays": 0, "refundRatio": 0, "label": "出发前 2 天内不退"}
]
}
},
"msg": "success"
}
3.12 §1.5.1 取消订单 - 出行前(pre-trip)
路径:POST /v3/admin/order/{id}/cancel/pre-trip
使用场景:定制师代客取消出行前订单。走企微 OA 审批 + 通道退款
认证:JWT(admin 角色) | 幂等性:否(提交企微 OA + 创建退款申请) | 限流:无
金额规则:严格按 RefundPolicy 计算,不接受人工覆盖(金额由 §3.11 预览给定)
入参(OrderCancelPreTripReqVO)
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|---|---|---|---|---|
cancelReason |
String | ✅ | 取消原因(前端可选下拉 + 自由填写) | @NotBlank |
cancelDetail |
String | ❌ | 详细说明 | — |
出参(Result<OrderCancelPreTripRespVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
refundApplicationId |
Long | 退款申请 ID(已提企微 OA) |
refundAmount |
BigDecimal | 退款金额(按 RefundPolicy 政策计算) |
pendingApprovalMsg |
String | 审批中提示文案 |
newStatus |
String | 取消后订单状态(如 退款中) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
581050 |
订单状态不允许取消(已取消 / 已完成 / 退款中) |
581051 |
订单已过出发日,需走 §3.13 on-trip 取消 |
581052 |
企微 OA 提交失败 |
业务边界
- ✅ 适用:订单状态可取消 +
daysToDeparture≥ 0 - ❌ 拒绝:出发日过 / 状态不可取消
- ⚠️ 不可重复提交:同一订单存在 PENDING 退款申请时第二次调用返
581050
示例
典型 - 请求:
POST /v3/admin/order/60123456789012/cancel/pre-trip
Authorization: Bearer {admin_jwt}
Content-Type: application/json
{
"cancelReason": "客户临时有事无法出行",
"cancelDetail": "客户家属突发疾病需照顾"
}
典型 - 响应:
{
"code": 200,
"data": {
"refundApplicationId": 95001234567890,
"refundAmount": 6864.00,
"pendingApprovalMsg": "已提交企微审批,预计 2 小时内完成",
"newStatus": "退款中"
},
"msg": "success"
}
3.13 §1.5.2 取消订单 - 出行中(on-trip)
路径:POST /v3/admin/order/{id}/cancel/on-trip
使用场景:定制师代客取消出行中订单。仅登记返还金额,不走支付通道(返还金额在核单 Step 5 自动拉取结算)
认证:JWT(admin 角色)
入参(OrderCancelOnTripReqVO)
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|---|---|---|---|---|
cancelReason |
String | ✅ | 取消原因 | @NotBlank |
returnAmount |
BigDecimal | ✅ | 定制师手填的返还金额(不走政策算) | @NotNull @DecimalMin(0, exclusive) |
returnRemark |
String | ✅ | 返还金额备注(说明已用成本扣除项) | @NotBlank |
出参(Result<OrderCancelOnTripRespVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
settlementRefundId |
Long | 返还登记 ID |
returnAmount |
BigDecimal | 已登记的返还金额(= 入参回显) |
newStatus |
String | 取消后状态(已取消) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
581053 |
订单未出发,不能走 on-trip 取消 |
581054 |
订单已完成,不能取消 |
581055 |
returnAmount 大于 paidAmount |
业务边界
- ✅ 适用:订单粗状态 =
出行中或已确认但已过出发日 - ❌ 拒绝:未出发 →
581053;已完成 →581054;返还金额超额 →581055 - ⚠️ 不走支付通道:本接口只登记返还金额,不发起实退;实退在核单 Step 5 走
示例
典型 - 请求:
POST /v3/admin/order/60123456789012/cancel/on-trip
Authorization: Bearer {admin_jwt}
Content-Type: application/json
{
"cancelReason": "客户中途突发疾病",
"returnAmount": 2500.00,
"returnRemark": "已用 2 天住宿+用车+导游,扣除 5880 元"
}
典型 - 响应:
{
"code": 200,
"data": {
"settlementRefundId": 96001234567890,
"returnAmount": 2500.00,
"newStatus": "已取消"
},
"msg": "success"
}
3.14 §1.7 状态变更操作(通用状态机)
路径:POST /v3/admin/order/{id}/transition
使用场景:所有由状态机驱动的操作统一走此接口。例如「确认锁单」「关闭订单」「触发尾款支付」等
认证:JWT(admin 角色) | 幂等性:否(写 order_status_log)
副作用:根据 eventCode 触发不同副作用(生成合同 / 投保 / 通知司机等),副作用列表在响应 triggeredEvents 中返回
入参(OrderTransitionReqVO)
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|---|---|---|---|---|
eventCode |
String | ✅ | 状态机事件代码,9 个:PAY_DEPOSIT / PAY_FULL / CANCEL / CONFIRM / INITIATE_REFUND / SET_PENDING_BALANCE / SET_PENDING_DEPARTURE / DEPART / FINISH(含义见 §6.17) | @NotBlank |
reason |
String | ❌ | 操作原因(按 event 强制要求时必填) | — |
payload |
Map<String, Object> | ❌ | 事件相关额外数据(不同 event 含义不同) | — |
出参(Result<OrderTransitionRespVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
success |
Boolean | 是否成功 |
oldStatus |
String | 变更前粗状态 |
newStatus |
String | 变更后粗状态 |
oldFlowStatus |
String | 变更前细状态 |
newFlowStatus |
String | 变更后细状态 |
triggeredEvents |
List<String> | 副作用事件列表(枚举见 §6.18) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
581060 |
eventCode 枚举非法 |
581061 |
当前状态不允许该 event(状态机迁移非法) |
581062 |
reason 必填但未传(如 CANCEL event) |
581063 |
前置 checklist 未全通过(如 CONFIRM event 时需 §3.15 全 ✅) |
业务边界
- ✅ 状态机驱动:触发条件由后端状态机定义,前端只传
eventCode,不需要懂迁移规则 - ⚠️
CONFIRMevent 强约束:调用前必须先调 §3.15 confirm-checklist 且allPassed=true,否则返581063 - ⚠️ 副作用异步:
triggeredEvents中ASYNC_*前缀的事件是异步执行的,本接口返回时副作用可能未完成(用 status-log Tab §3.7 跟踪)
示例
典型(确认锁单) - 请求:
POST /v3/admin/order/60123456789012/transition
Authorization: Bearer {admin_jwt}
Content-Type: application/json
{
"eventCode": "CONFIRM",
"reason": "定制师确认所有前置条件已完成",
"payload": {}
}
典型 - 响应:
{
"code": 200,
"data": {
"success": true,
"oldStatus": "CUSTOMIZING",
"newStatus": "PENDING_DEPARTURE",
"oldFlowStatus": "PENDING_CONFIRM",
"newFlowStatus": "PENDING_DEPARTURE",
"triggeredEvents": ["ASYNC_CONTRACT_GENERATE", "ASYNC_INSURANCE_ISSUE"]
},
"msg": "success"
}
异常(checklist 未通过 581063) - 请求:(同上 eventCode=CONFIRM,但订单存在未完善出行人)
异常 - 响应:
{ "code": 581063, "data": null, "msg": "前置 checklist 未全通过:出行人信息未完善 1/3" }
3.15 §1.8 确认锁单前置 Checklist
路径:GET /v3/admin/order/{id}/confirm-checklist
使用场景:定制师点击「确认订单」按钮时调用。
- 返回 5 项前置校验明细(决定按钮是否可点)
- 通过时返回"确认行程"弹框预览数据(行程概览 + 自动副作用 + 通知项)
- 不通过时
preview=null,前端展示 5 项failReason列表 +actionPath跳转引导
认证:JWT(admin 角色) | 幂等性:是(只读不入库)
入参
id (path, Long) — 订单 ID
出参(Result<ConfirmChecklistRespVO>)
| 字段 | 类型 | 说明 |
|---|---|---|
allPassed |
Boolean | 是否全部通过(任一项不通过则 false) |
items |
List<ChecklistItemVO> | 5 项详细结果 |
preview |
PreviewVO? | 确认行程弹框预览(仅 allPassed=true 时返回) |
ChecklistItemVO:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
String | 检查项代码(枚举见 §6.19) |
passed |
Boolean | 是否通过 |
failReason |
String? | 未通过原因(通过时 null) |
actionPath |
String? | 引导操作路径(如配房页跳转;通过时 null) |
PreviewVO(仅 allPassed=true 时存在):
| 字段 | 类型 | 说明 |
|---|---|---|
departureDate |
LocalDate | 出发日期 |
totalPeopleCount |
Integer | 总出行人数(4 类相加) |
driverName |
String | 司机姓名 |
driverPhoneMasked |
String | 司机手机(脱敏) |
hotels |
List<{cityName, hotelName}> | 酒店列表(按行程城市分组) |
contractAutoAction.planName |
String | 合同方案名(产品快照) |
contractAutoAction.autoSign |
Boolean | 是否自动发送给客户线上签署 |
insuranceAutoAction.planName |
String | 保险产品名 |
insuranceAutoAction.peopleCount |
Integer | 投保人数(= totalPeopleCount) |
insuranceAutoAction.effectiveDescription |
String | 生效时间描述 |
notifications.notifyDriver |
Boolean | 是否通知司机 |
notifications.notifyHotel |
Boolean | 是否通知酒店确认房态 |
notifications.notifyCustomer |
Boolean | 是否向客户发送出行提醒 |
notifications.customerChannel |
String | 客户通知渠道(WX / SMS / MIXED) |
错误码
| code | 含义 |
|---|---|
581020 |
订单不存在 |
581021 |
无权访问该订单 |
业务边界
- ✅ 前置校验:5 项 checklist 用于阻止用户点【确认订单】按钮在前置条件未满足时
- ⚠️
actionPath引导:前端建议按字面值跳转(如/admin/order/orders/{id}?tab=overview),不是后端约定渲染 - ⚠️
preview条件返回:allPassed=false时preview为 null,前端不渲染预览区 - ⚠️
preview数据是预演:本接口返回的合同方案 / 保险方案是「点击确认后会执行什么」的预演,不意味着已经执行(实际执行由 §3.14eventCode=CONFIRM触发)
示例
典型(未通过) - 请求:
GET /v3/admin/order/60123456789012/confirm-checklist
Authorization: Bearer {admin_jwt}
典型(未通过) - 响应:
{
"code": 200,
"data": {
"allPassed": false,
"items": [
{"code": "TRAVELER_COMPLETE", "passed": false, "failReason": "出行人信息未完善 1/3 (小明缺证件号)", "actionPath": "/admin/order/orders/60123456789012?tab=overview"},
{"code": "PAYMENT_OK", "passed": true, "failReason": null, "actionPath": null},
{"code": "HOTEL_DONE", "passed": true, "failReason": null, "actionPath": null},
{"code": "VEHICLE_DONE", "passed": true, "failReason": null, "actionPath": null},
{"code": "CONTRACT_TEMPLATE_OK", "passed": true, "failReason": null, "actionPath": null}
],
"preview": null
},
"msg": "success"
}
典型(全通过) - 请求:(同上)
典型(全通过) - 响应:
{
"code": 200,
"data": {
"allPassed": true,
"items": [
{"code": "TRAVELER_COMPLETE", "passed": true, "failReason": null, "actionPath": null},
{"code": "PAYMENT_OK", "passed": true, "failReason": null, "actionPath": null},
{"code": "HOTEL_DONE", "passed": true, "failReason": null, "actionPath": null},
{"code": "VEHICLE_DONE", "passed": true, "failReason": null, "actionPath": null},
{"code": "CONTRACT_TEMPLATE_OK", "passed": true, "failReason": null, "actionPath": null}
],
"preview": {
"departureDate": "2026-05-30",
"totalPeopleCount": 14,
"driverName": "扎西师傅",
"driverPhoneMasked": "1398761****",
"hotels": [
{"cityName": "拉萨", "hotelName": "瑞吉度假酒店"},
{"cityName": "林芝", "hotelName": "悦榕庄"}
],
"contractAutoAction": {
"planName": "标准跟团方案 v3.2",
"autoSign": true
},
"insuranceAutoAction": {
"planName": "安联境内旅行险 · 尊享版",
"peopleCount": 14,
"effectiveDescription": "出发前 24h 内生效"
},
"notifications": {
"notifyDriver": true,
"notifyHotel": true,
"notifyCustomer": true,
"customerChannel": "WX"
}
}
},
"msg": "success"
}
6. 枚举 / 数据字典
跨接口共享枚举集中列出,按字段分组,标注「使用字段在哪里」。
6.1 createSource(订单创建来源)
使用字段:§3.1 入参 createSource / §3.2 入参 createSource 过滤
| 值 | 中文 | 说明 |
|---|---|---|
CUSTOMER |
客户自助 | 客户在小程序自助下单 |
CONSULTANT |
定制师代下单 | 默认值 |
OTA |
OTA 渠道 | 携程 / 美团等 OTA 引流 |
WALK_IN |
门店步入 | 线下门店现场下单 |
B2B |
B2B 渠道 | 旅行社代下单 |
VIP_REPURCHASE |
VIP 复购 | — |
REFERRAL |
老客户转介绍 | — |
PROMOTION |
营销活动 | — |
INTERNAL |
内部测试 | 不计入业绩 |
6.2 orderStatus(订单粗状态)
使用字段:§3.1 出参 / §3.2 出参 / §3.3 main / §3.2 入参过滤
后端 enum:
com.hulalv.order.core.enums.OrderStatus,共 9 项(v5.49 对齐 SRS:退款粗态已移除,退款发起瞬间订单 order_status 直接变为CANCELLED,退款进度由 refund_status 子字段记录)。API 传/返均为英文枚举值,中文标签前端自己映射。
| 值 | 中文标签 | 说明 |
|---|---|---|
PENDING_PAY |
待支付 | 创单后默认 |
PENDING_COMPLETE |
待完善 | 订金到账后进入 |
CUSTOMIZING |
定制中 | 出行人 + 房车齐前 |
PENDING_DEPARTURE |
待出行 | 确认锁单后 |
PENDING_BALANCE |
待付尾款 | 重开尾款场景(SET_PENDING_BALANCE 事件迁入) |
TRAVELLING |
出行中 | 已发车 |
REVIEWING |
核单中 | 出行结束待财务核算 |
SETTLED |
已结算 | 财务核算完成 |
CANCELLED |
已取消 | 含退款流程中的订单(refund_status 区分进度) |
6.3 flowStatus(订单细状态)
使用字段:§3.1 出参 / §3.2 出参 / §3.3 main / §3.2 入参过滤
后端 enum:
com.hulalv.order.core.enums.OrderFlowStatus,共 15 项(v5.49 全量重写:原 13 项支付节奏视角已废,现采 SRS v5.48 §0.4 行 636 业务环节视角,与 SRS 中文 1:1 对齐)。flow_status 列只承载流程细节,不喂状态机;粗态见 §6.2。
| 值 | 中文标签 | 说明 |
|---|---|---|
AWAITING_PROFILE |
待补全信息 | 订金到账后默认细态 |
AWAITING_HOTEL_SUBMIT |
待提交房型 | 出行人齐全后等定制师提交房型需求 |
AWAITING_HOTEL_CLAIM |
待抢房 | 房型需求提交后进入抢单池 |
HOTEL_IN_PROGRESS |
房控处理中 | 房控已接单配置中 |
HOTEL_NEED_ADJUST |
房控需调整 | 房控需求调整中 |
AWAITING_VEHICLE_SUBMIT |
待提交用车 | 出行人齐全后等定制师提交用车需求 |
VEHICLE_IN_PROGRESS |
车控处理中 | 车控已接单配置中 |
VEHICLE_NEED_ADJUST |
车控需调整 | 车控需求调整中 |
PENDING_CONFIRM |
待确认 | 房车齐后等定制师确认锁单 |
PENDING_DEPARTURE |
待出行 | 确认锁单后默认细态 |
TRAVELLING |
出行中 | 已发车 |
PENDING_REVIEW |
待核单 | 出行结束等核单 |
REVIEWING |
核单中 | 财务核单中 |
SETTLED |
已结算 | 核单通过 |
CANCELLED |
已取消 | 终态 |
6.4 consultantSource(定制师分配来源)
使用字段:§3.1 出参 / §3.3 main
该字段为字符串而非强枚举类:admin 端硬编码
MANUAL;C 端分享下单硬编码SHARED;C 端兜底默认定制师时透传 hl-user-service 派生值(如DEFAULT_ASSIGNED/ROUND_ROBIN,由 user-service 决定)。
| 值 | 说明 |
|---|---|
MANUAL |
admin 端代下单(JWT adminId 即定制师) |
SHARED |
C 端客户扫定制师专属分享码下单 |
DEFAULT_ASSIGNED |
C 端兜底:hl-user-service 派发默认定制师 |
ROUND_ROBIN |
C 端兜底:hl-user-service 轮询派发(未来扩展) |
LINK_BOUND |
(DB comment 保留,当前代码路径未实际写入) |
⚠️ 因 user-service 可能新增 source 值,前端严禁对该字段穷举判断;展示时未知值兜底为
MANUAL的中文标签即可。
6.5 paymentMode(支付模式)
使用字段:§3.1 出参
| 值 | 说明 |
|---|---|
DEPOSIT |
定金模式(30% 定金 + 余款) |
FULL |
全款模式(100% 一次付清) |
6.6 payType(支付类型)
使用字段:§3.4 出参 payments[].payType
| 值 | 说明 |
|---|---|
DEPOSIT |
定金 |
BALANCE |
尾款 |
6.7 payment status(支付记录状态)
使用字段:§3.4 出参 payments[].status
| 值 | 说明 |
|---|---|
SUCCESS |
成功 |
PENDING |
处理中 |
FAIL |
失败 |
6.8 discount type(优惠类型)
使用字段:§3.4 出参 discounts[].type
| 值 | 说明 |
|---|---|
EARLY_BIRD |
早鸟优惠 |
VIP |
VIP 优惠 |
COUPON |
优惠券 |
PROMOTION |
营销活动优惠 |
6.9 discount source(优惠 / 附加费来源)
使用字段:§3.4 出参 discounts[].source / surcharges[].source
| 值 | 说明 |
|---|---|
MANUAL |
手动添加(定制师人工) |
AUTO |
系统自动 |
HOTEL_ASSIGN |
配房环节产生(仅 surcharge) |
VEHICLE_ASSIGN |
配车环节产生(仅 surcharge) |
6.10 contractStatus(合同状态)
使用字段:§3.5 出参 contract.contractStatus
| 值 | 说明 |
|---|---|
PENDING |
待生成 |
GENERATED |
已生成待签 |
SIGNED |
已签约 |
VOIDED |
已作废 |
6.11 event type(合同 / 保险事件类型)
使用字段:§3.5 出参 contract.events[].eventType / insurance.events[].eventType
| 值 | 说明 |
|---|---|
GENERATE |
合同生成 |
SIGN |
合同签约 |
VOID |
合同作废 |
REOPEN |
合同重开 |
ISSUE |
保险出单 |
CANCEL |
保险退保 |
6.12 insuranceStatus(保险状态)
使用字段:§3.5 出参 insurance.insuranceStatus
| 值 | 说明 |
|---|---|
PENDING |
待出单 |
ACTIVE |
已生效 |
FAILED |
出单失败 |
CANCELLED |
已退保 |
6.13 refund application status(退款申请状态)
使用字段:§3.8 出参 applications[].status
| 值 | 说明 |
|---|---|
PENDING_APPROVE |
待审批 |
PENDING_PAYOUT |
财务已审批,待打款 |
PENDING_ARRIVAL |
已打款,待到账 |
COMPLETED |
退款完成(已到账) |
REJECTED |
已拒绝 |
6.14 refund progress step(退款进度步骤)
使用字段:§3.8 出参 applications[].progress[].step
| 值 | 说明 |
|---|---|
APPLY |
退款申请 |
APPROVE |
财务审批 |
PAYOUT |
退款打款 |
ARRIVED |
到账确认 |
6.15 tag type(标签类型)
使用字段:§3.3 出参 tags[].type
| 值 | 说明 |
|---|---|
SYSTEM |
系统自动打的标签 |
PERSONAL |
定制师手动打的标签 |
MANUAL |
主管手动打的标签 |
6.16 traveler & exception badge(出行人 / 异常态字段)
OverviewVO.travelers[] 的 travelerType / idType / profileStatus 等枚举详见 traveler 模块 §2.1 出行人列表 changelog。
OrderMainVO.exceptionBadges 9 类布尔标识 / progressStepper.nodes[].key / progressStepper.nodes[].status 字段含义已在 §3.3 出参说明中列出。
6.17 transition eventCode(状态机事件代码)
使用字段:§3.14 入参 eventCode
后端 enum:
com.hulalv.order.core.enums.OrderEvent,共 9 个值。 状态机由OrderStateMachineConfig16 条规则驱动。
6.17.1 完整规则表(事件 → 前置态 → 目标态)
| 事件 | 前置态(orderStatus) | 目标态(orderStatus) | 业务语义 |
|---|---|---|---|
PAY_DEPOSIT |
PENDING_PAY |
CUSTOMIZING |
客户支付订金 |
PAY_FULL |
PENDING_PAY |
CUSTOMIZING |
客户支付全款 |
CANCEL |
PENDING_PAY |
CANCELLED |
未付款取消 |
CONFIRM ⚠️ |
CUSTOMIZING |
PENDING_DEPARTURE |
确认锁单(语义 ①,需先通过 §3.15 checklist) |
SET_PENDING_BALANCE |
PENDING_DEPARTURE |
PENDING_BALANCE |
重新开放尾款 / 调整价格 |
DEPART |
PENDING_DEPARTURE |
TRAVELLING |
开始出行 |
SET_PENDING_DEPARTURE |
PENDING_BALANCE |
PENDING_DEPARTURE |
尾款补齐 |
FINISH |
TRAVELLING |
REVIEWING |
结团(进入核单) |
CONFIRM ⚠️ |
REVIEWING |
SETTLED |
核单通过 / 确认结算(语义 ②) |
CANCEL |
CUSTOMIZING |
CANCELLED |
定制中取消 |
CANCEL |
TRAVELLING |
CANCELLED |
出行中取消 |
INITIATE_REFUND |
CUSTOMIZING |
CANCELLED |
定制中发起退款 |
INITIATE_REFUND |
PENDING_DEPARTURE |
CANCELLED |
待出行发起退款 |
INITIATE_REFUND |
PENDING_BALANCE |
CANCELLED |
待付尾款发起退款 |
INITIATE_REFUND |
REVIEWING |
CANCELLED |
核单中发起退款 |
INITIATE_REFUND |
SETTLED |
CANCELLED |
已结算售后退款 |
⚠️ CONFIRM 事件复用 2 种语义:状态机以「当前粗态 + 事件」找规则,不会冲突,但前端按钮文案要按当前状态判断(CUSTOMIZING 下叫"确认锁单",REVIEWING 下叫"确认结算")。
6.17.2 非 transition 业务路径(不走本接口)
下列业务不走 POST /v3/admin/order/{id}/transition,前端按对应独立接口调用:
| 业务 | 独立接口 | 备注 |
|---|---|---|
| 核单结算(6 步) | PUT /v3/admin/order/{id}/settlement/step1 ~ step4GET / POST / DELETE /v3/admin/order/{id}/settlement/step5/*POST /v3/admin/order/{id}/settlement/step6/submitGET /v3/admin/order/{id}/settlement/summary |
Step 6 submit 内部事务自动推 REVIEWING → SETTLED,前端不要自己 fire eventCode |
| 退款发起 | 退款专用接口(详见 refund 模块 changelog) | INITIATE_REFUND 是 transition 事件,但前端入口走独立退款按钮 |
| 申请解锁 | v3 已砍 | 原型 UnlockModal 按钮 v3 不实现;前端隐藏对应按钮 |
6.18 transition triggeredEvents(状态机副作用事件)
使用字段:§3.14 出参 triggeredEvents[]
| 值 | 说明 |
|---|---|
ASYNC_CONTRACT_GENERATE |
异步生成电子合同 |
ASYNC_INSURANCE_ISSUE |
异步出保单 |
NOTIFY_DRIVER |
通知司机 |
NOTIFY_HOTEL |
通知酒店确认房态 |
NOTIFY_CUSTOMER |
向客户发出行提醒 |
ASYNC_REFUND_APPLY |
异步发起退款申请 |
副作用异步执行,本接口返回时可能未完成;用 §3.7 status-log Tab 跟踪进度。
6.19 checklist item code(确认锁单前置 5 项)
使用字段:§3.15 出参 items[].code
| 值 | 说明 |
|---|---|
TRAVELER_COMPLETE |
出行人信息完整(姓名 + 证件 + 手机 + 证件类型齐) |
PAYMENT_OK |
支付状态满足(订金或全款到账) |
HOTEL_DONE |
配房完成(hotel_stage = DONE) |
VEHICLE_DONE |
配车完成(vehicle_stage = DONE) |
CONTRACT_TEMPLATE_OK |
合同模板就绪(产品快照含合同方案) |
6.20 customerChannel(客户通知渠道)
使用字段:§3.15 出参 preview.notifications.customerChannel
| 值 | 说明 |
|---|---|
WX |
仅企微 / 微信 |
SMS |
仅短信 |
MIXED |
双通道(企微 + 短信) |
11. 影响评估
- 是否破坏向后兼容:否(v3 全新二期,前端 v3 项目仓库首次消费)
- 前端是否必须同步上线:是
- 本次推送范围:§1 模块全 15 接口(§1A 10 接口 + §1B 取消 3 接口 + §1C 状态机+锁单 2 接口),覆盖订单核心全生命周期入口
12. 注意事项
- §3.6 itinerary 子接口数据 Mock:当前返回占位数据,前端按字段结构对接即可,真实化后无需改字段口径
- §3.8 / §3.9 条件显示:
data=null时前端不渲染对应 Tab - 首屏 vs 单 Tab 刷新:详情页打开用 §3.3 主聚合(一次拿 main + tags + overview);Tab 切换 / 单 Tab 操作完按需调 §3.4 ~ §3.9
- 公司隔离 581021:所有 §1 接口均带跨公司隔离校验,前端无需自行过滤
- 取消订单分支:出行前走 §3.12 走政策算金额 + 企微 OA 审批;出行中走 §3.13 仅登记返还金额(核单 Step 5 自动拉取实退);前端按 §3.11 预览的
daysToDeparture决定走哪个入口 - CONFIRM 锁单:前端点【确认订单】按钮必须先调 §3.15 checklist 拿
allPassed=true再调 §3.14eventCode=CONFIRM,否则后端拒绝(581063)
13. 关联
- API 设计文档:
docs/order-v3/api/API-SPEC-V5.50.html§1.1 ~ §1.4 - SRS 业务规格:
docs/order-v3/srs/order-cloud-v3-srs-v5.50.html§F1 创单 / §1.0i 模型 / §1.3 创单流程 - 数据库 Schema:
docs/order-v3/database/DATABASE-SCHEMA-V5.50.html§1.1 order_main / §1.2 order_tag - 后端负责人: @yaosutu
📝 后续追加计划
§1 模块 15 接口全部首推完毕。后续若有接口字段调整 / 错误码新增 / 业务边界变化,通过追加 commit 扩充本文件。