# 【新增接口·管理后台】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\ | ❌ | 订单标签名列表 | — | #### 出参(`Result`,20 字段) | 字段 | 类型 | 说明 | |------|------|------| | `id` | String | 订单主键 | | `orderNo` | String | 订单号,格式 `HL{yyyyMMddHHmmss}{3 位序号}` | | `displayOrderNo` | String | 展示订单号 = `orderNo + teamNo`;`teamNo` 为空时等同 `orderNo` | | `orderStatus` | String | 创单后固定 `待支付`(枚举见 §6.2) | | `flowStatus` | String | 创单后固定 `待支付订金`(枚举见 §6.3) | | `consultantId` | String | 实际绑定的定制师 ID | | `consultantSource` | String | 定制师来源(枚举见 §6.4) | | `tags` | List\ | 标签列表(含入参 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` 仅含系统自动标签 #### 示例 **典型成功 - 请求**: ```http 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 客户"] } ``` **典型成功 - 响应**: ```json { "code": 200, "data": { "id": "60123456789012", "orderNo": "HL20260518220000001", "displayOrderNo": "HL20260518220000001", "orderStatus": "待支付", "flowStatus": "待支付订金", "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` 指向已满批次) **异常 - 响应**: ```json { "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 | ❌ | 粗状态过滤(多值用逗号) | | `flowStatus` | String | ❌ | 细状态过滤 | | `tagNames` | List\ | ❌ | 按标签过滤(多标签为 AND) | | `keyword` | String | ❌ | 关键字(LIKE 团号 / 客户姓名 / 产品名 / 订单号 任一) | | `departureDateFrom` | LocalDate | ❌ | 出发日期范围起始 | | `departureDateTo` | LocalDate | ❌ | 出发日期范围结束 | | `createSource` | String | ❌ | 来源过滤(枚举见 §6.1) | | `cancelled` | Boolean | ❌ | 是否含已取消(默认 false) | #### 出参(`Result>`) `PageResult` 字段:`list: List` / `total: Long` / `page` / `pageSize` `OrderListItemRespVO`(17 字段): | 字段 | 类型 | 说明 | |------|------|------| | `id` | String | 订单 ID | | `orderNo` | String | 订单号 | | `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\ | 标签列表 | | `createdAt` | LocalDateTime | 创单时间 | #### 错误码 参数格式错误走全局 400,无业务错误码。 #### 业务边界 - ✅ **默认行为**:`cancelled` 不传 = 不含已取消订单 - ⚠️ **关键字**:`keyword` 同时 LIKE 4 字段(团号 / 客户姓名 / 产品名 / 订单号)任一命中 - ⚠️ **标签过滤**:`tagNames` 多值是 **AND**(订单必须含全部标签才命中),不是 OR #### 示例 **典型 - 请求**: ```http GET /v3/admin/order?page=1&pageSize=10&orderStatus=待出行&tagNames=VIP%20%E5%AE%A2%E6%88%B7 Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "code": 200, "data": { "list": [ { "id": "60123456789012", "orderNo": "HL20260510143025001", "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": "待出行", "flowStatus": "待出行", "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`,3 顶层字段) | 字段 | 类型 | 说明 | |------|------|------| | `main` | OrderMainVO | 订单主单 + 异常态横条 + progressStepper 步骤进度条 | | `tags` | List\ | 标签列表 | | `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` / `customerPhone` | String | 客户姓名 / 手机(admin 明文) | | `consultantName` | String | 定制师姓名 | | `confirmedAt` | LocalDateTime? | 确认锁单时间 | | `exceptionBadges` | Object | 异常态横条 9 类标识(见下方) | | `progressStepper` | Object | 步骤进度条(见下方) | **`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` - `ASSIGN_PARALLEL` 含 `subItems`:`HOTEL` / `VEHICLE` / `LEADER` / `PHOTOGRAPHER` 子项 `TagVO`:`name` / `type`(枚举见 §6.15) / `color` `OverviewVO` 关键字段: | 字段 | 类型 | 说明 | |------|------|------| | `travelers` | List\ | 出行人完整集合(复用 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` #### 示例 **典型 - 请求**: ```http GET /v3/admin/order/60123456789012 Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "code": 200, "data": { "main": { "id": "60123456789012", "displayOrderNo": "HL20260510143025001-T20260601A", "productName": "长白山天池3日深度游", "tierName": "经典档", "orderStatus": "待出行", "flowStatus": "待出行", "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": "张三", "customerPhone": "13800002046", "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": ["80012345"] } ], "customerRemark": "希望住朝阳房", "consultantRemark": "VIP 客户,已沟通到达接机", "emergencyContactName": "李四", "emergencyContactPhone": "13900008888" } }, "msg": "success" } ``` **异常(跨公司访问 581021) - 请求**:(admin JWT 不属于订单所属公司) ```http GET /v3/admin/order/60999999999999 Authorization: Bearer {admin_jwt} ``` **异常 - 响应**: ```json { "code": 581021, "data": null, "msg": "无权访问该订单" } ``` --- ### 3.4 §1.3.2 财务 Tab(懒加载) **路径**:`GET /v3/admin/order/{id}/finance` **使用场景**:详情页财务 Tab 单独刷新(如优惠 / 退款操作完后刷新) **认证**:JWT + 公司隔离 #### 入参 `id` (path, Long) — 订单 ID #### 出参(`Result`) | 字段 | 类型 | 说明 | |------|------|------| | `totalAmount` | BigDecimal | 订单总额 | | `paidAmount` | BigDecimal | 实付金额 | | `balanceAmount` | BigDecimal | 待付金额 | | `discountAmount` | BigDecimal | 优惠金额汇总 | | `surchargeAmount` | BigDecimal | 附加费用汇总 | | `refundAmount` | BigDecimal | 退款金额汇总 | | `payments` | List\ | 支付明细 | | `discounts` | List\ | 优惠明细 | | `surcharges` | List\ | 附加费用 | `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` | 无权访问该订单 | #### 示例 **典型 - 请求**: ```http GET /v3/admin/order/60123456789012/finance Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "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`) | 字段 | 类型 | 说明 | |------|------|------| | `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` | 无权访问该订单 | #### 示例 **典型 - 请求**: ```http GET /v3/admin/order/60123456789012/contract-insurance Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "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`) | 字段 | 类型 | 说明 | |------|------|------| | `days[].dayIndex` | Integer | 天序 | | `days[].dayDate` | String | 日期(`yyyy-MM-dd`) | | `days[].title` | String | 标题 | | `days[].nodes` | List\ | 节点列表(结构见 itinerary 模块 §5) | | `hotelGroup.requirement` | Object | 配房需求(`requirementId / status / roomTypeSummary / claimedBy` 等) | | `hotelGroup.assignments` | List\ | 实际配房(`hotelName / stayDate / roomType / roomCount / unitPrice / subtotal`) | | `vehicleGroup.requirement` | Object | 配车需求(`requirementId / status / vehicleTypeSummary / claimedBy`) | | `vehicleGroup.assignments` | List\ | 实际配车(`vehicleType / plate / driverName / dailyFee / totalFee`) | #### 错误码 | code | 含义 | |------|------| | `581020` | 订单不存在 | | `581021` | 无权访问该订单 | #### 示例 **典型 - 请求**: ```http GET /v3/admin/order/60123456789012/itinerary Authorization: Bearer {admin_jwt} ``` **典型 - 响应**(Mock 数据示意): ```json { "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>`) | 字段 | 类型 | 说明 | |------|------|------| | `occurredAt` | LocalDateTime | 发生时间 | | `operator` | String | 操作人 | | `action` | String | 操作描述 | | `fromStatus` | String? | 变更前状态(有状态变更时有值) | | `toStatus` | String? | 变更后状态 | | `amount` | BigDecimal? | 涉及金额(支付/退款时有值) | #### 错误码 | code | 含义 | |------|------| | `581020` | 订单不存在 | | `581021` | 无权访问该订单 | #### 示例 **典型 - 请求**: ```http GET /v3/admin/order/60123456789012/status-log Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "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` 或 `Result`) | 字段 | 类型 | 说明 | |------|------|------| | `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` | 无权访问该订单 | #### 示例 **典型(有退款) - 请求**: ```http GET /v3/admin/order/60123456789012/refund Authorization: Bearer {admin_jwt} ``` **典型(有退款) - 响应**: ```json { "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" } ``` **边界(无退款) - 请求**:(同上路径) **边界 - 响应**: ```json { "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` 或 `Result`) | 字段 | 类型 | 说明 | |------|------|------| | `itinerary` | List\ | 行程天纲(产品快照) | | `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` | 无权访问该订单 | #### 示例 **典型 - 请求**: ```http GET /v3/admin/order/60123456789012/service-standard Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "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`) 返回 `true` 表示成功,`false` 表示无字段实际变化。 #### 错误码 | code | 含义 | |------|------| | `581020` | 订单不存在 | | `581021` | 无权访问该订单 | | `581030` | 转单目标定制师不存在 | | `581031` | 转单原因为空(传 `targetConsultantId` 时) | | `581032` | 当前角色无转单权限(仅主管 / 客服可转单) | #### 业务边界 - ✅ **可改字段**:备注 / 紧急联系人 / 客户信息 / 转单(仅主管 / 客服角色) - ❌ **不可改字段**:订单金额 / 订单状态 / 出发日期 / 出行人数 / 拼团批次 → 需走专用接口 - ⚠️ **转单约束**:传 `targetConsultantId` 必须同时传 `transferReason` - ⚠️ **PATCH 语义**:不传 = 不改;传空字符串 = 改成空(区分两者) #### 示例 **典型(转单) - 请求**: ```http PUT /v3/admin/order/60123456789012 Authorization: Bearer {admin_jwt} Content-Type: application/json { "targetConsultantId": 50009876543210, "transferReason": "客户主动申请更换定制师", "consultantRemark": "已联系新定制师" } ``` **典型 - 响应**: ```json { "code": 200, "data": true, "msg": "success" } ``` **异常(转单缺原因 581031) - 请求**: ```http PUT /v3/admin/order/60123456789012 Authorization: Bearer {admin_jwt} Content-Type: application/json { "targetConsultantId": 50009876543210 } ``` **异常 - 响应**: ```json { "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`) | 字段 | 类型 | 说明 | |------|------|------| | `refundAmount` | BigDecimal | 退款金额(按 RefundPolicy 计算) | | `paidAmount` | BigDecimal | 客户已付金额 | | `deductAmount` | BigDecimal | 扣费金额 = `paidAmount - refundAmount` | | `daysToDeparture` | Integer | 距出发天数(今天 - 出发日;负数表已过出发日) | | `refundPolicy` | RefundPolicyVO | 退款政策快照(结构同 §3.9 `refundPolicy`) | #### 错误码 | code | 含义 | |------|------| | `581020` | 订单不存在 | | `581021` | 无权访问该订单 | | `581050` | 订单状态不允许取消(已取消 / 已完成 / 退款中等) | #### 业务边界 - ✅ **适用**:订单粗状态 ∈ {待支付, 待完善, 定制中, 已确认, 待出行} - ❌ **拒绝**:已取消 / 已完成 / 退款中 → `581050` - ⚠️ **`daysToDeparture` 负数**:已过出发日,前端应引导走 §3.13 出行中取消(on-trip)而非本接口预览 #### 示例 **典型(出行前 12 天) - 请求**: ```http GET /v3/admin/order/60123456789012/cancel-preview Authorization: Bearer {admin_jwt} ``` **典型 - 响应**: ```json { "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`) | 字段 | 类型 | 说明 | |------|------|------| | `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` #### 示例 **典型 - 请求**: ```http POST /v3/admin/order/60123456789012/cancel/pre-trip Authorization: Bearer {admin_jwt} Content-Type: application/json { "cancelReason": "客户临时有事无法出行", "cancelDetail": "客户家属突发疾病需照顾" } ``` **典型 - 响应**: ```json { "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`) | 字段 | 类型 | 说明 | |------|------|------| | `settlementRefundId` | Long | 返还登记 ID | | `returnAmount` | BigDecimal | 已登记的返还金额(= 入参回显) | | `newStatus` | String | 取消后状态(`已取消`) | #### 错误码 | code | 含义 | |------|------| | `581020` | 订单不存在 | | `581021` | 无权访问该订单 | | `581053` | 订单未出发,不能走 on-trip 取消 | | `581054` | 订单已完成,不能取消 | | `581055` | `returnAmount` 大于 `paidAmount` | #### 业务边界 - ✅ **适用**:订单粗状态 = `出行中` 或 `已确认` 但已过出发日 - ❌ **拒绝**:未出发 → `581053`;已完成 → `581054`;返还金额超额 → `581055` - ⚠️ **不走支付通道**:本接口**只登记**返还金额,不发起实退;实退在核单 Step 5 走 #### 示例 **典型 - 请求**: ```http POST /v3/admin/order/60123456789012/cancel/on-trip Authorization: Bearer {admin_jwt} Content-Type: application/json { "cancelReason": "客户中途突发疾病", "returnAmount": 2500.00, "returnRemark": "已用 2 天住宿+用车+导游,扣除 5880 元" } ``` **典型 - 响应**: ```json { "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 | ✅ | 状态机事件代码(枚举见 §6.17) | `@NotBlank` | | `reason` | String | ❌ | 操作原因(按 event 强制要求时必填) | — | | `payload` | Map\ | ❌ | 事件相关额外数据(不同 event 含义不同) | — | #### 出参(`Result`) | 字段 | 类型 | 说明 | |------|------|------| | `success` | Boolean | 是否成功 | | `oldStatus` | String | 变更前粗状态 | | `newStatus` | String | 变更后粗状态 | | `oldFlowStatus` | String | 变更前细状态 | | `newFlowStatus` | String | 变更后细状态 | | `triggeredEvents` | List\ | 副作用事件列表(枚举见 §6.18) | #### 错误码 | code | 含义 | |------|------| | `581020` | 订单不存在 | | `581021` | 无权访问该订单 | | `581060` | `eventCode` 枚举非法 | | `581061` | 当前状态不允许该 event(状态机迁移非法) | | `581062` | `reason` 必填但未传(如 `CANCEL` event) | | `581063` | 前置 checklist 未全通过(如 `CONFIRM` event 时需 §3.15 全 ✅) | #### 业务边界 - ✅ **状态机驱动**:触发条件由后端状态机定义,前端只传 `eventCode`,不需要懂迁移规则 - ⚠️ **`CONFIRM` event 强约束**:调用前必须先调 §3.15 confirm-checklist 且 `allPassed=true`,否则返 `581063` - ⚠️ **副作用异步**:`triggeredEvents` 中 `ASYNC_*` 前缀的事件是异步执行的,本接口返回时副作用可能未完成(用 status-log Tab §3.7 跟踪) #### 示例 **典型(确认锁单) - 请求**: ```http POST /v3/admin/order/60123456789012/transition Authorization: Bearer {admin_jwt} Content-Type: application/json { "eventCode": "CONFIRM", "reason": "定制师确认所有前置条件已完成", "payload": {} } ``` **典型 - 响应**: ```json { "code": 200, "data": { "success": true, "oldStatus": "定制中", "newStatus": "待出行", "oldFlowStatus": "待确认", "newFlowStatus": "待出行", "triggeredEvents": ["ASYNC_CONTRACT_GENERATE", "ASYNC_INSURANCE_ISSUE"] }, "msg": "success" } ``` **异常(checklist 未通过 581063) - 请求**:(同上 `eventCode=CONFIRM`,但订单存在未完善出行人) **异常 - 响应**: ```json { "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`) | 字段 | 类型 | 说明 | |------|------|------| | `allPassed` | Boolean | 是否全部通过(任一项不通过则 false) | | `items` | List\ | 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.14 `eventCode=CONFIRM` 触发) #### 示例 **典型(未通过) - 请求**: ```http GET /v3/admin/order/60123456789012/confirm-checklist Authorization: Bearer {admin_jwt} ``` **典型(未通过) - 响应**: ```json { "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" } ``` **典型(全通过) - 请求**:(同上) **典型(全通过) - 响应**: ```json { "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 入参过滤 | 值 | 说明 | |----|------| | `待支付` | 创单后默认 | | `待完善` | 订金到账后进入 | | `定制中` | 出行人 + 房车齐后 | | `已确认` | — | | `出行中` | — | | `已完成` | — | | `已取消` | — | ### 6.3 flowStatus(订单细状态) **使用字段**:§3.1 出参 / §3.2 出参 / §3.3 main / §3.2 入参过滤 | 值 | 说明 | |----|------| | `待支付订金` | 创单后默认细状态 | | `待支付尾款` | — | | `待补全信息` | 订金到账后 | | `待提交房型` | — | | `待抢房` | — | | `配房中` | — | | `待提交用车` | — | | `车控处理中` | — | | `待确认` | 房车齐后 | | `待出行` | 确认锁单后 | | `出行中` | — | | `已完成` | — | | `已取消` | — | > 完整 flowStatus 枚举见订单状态机文档(§1C 推送时补全)。 ### 6.4 consultantSource(定制师分配来源) **使用字段**:§3.1 出参 / §3.3 main | 值 | 说明 | |----|------| | `DEFAULT_ASSIGNED` | 系统默认分配(轮询) | | `LINK_BOUND` | 链接绑定(客户扫定制师专属码) | | `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` | 值 | 说明 | |----|------| | `PAY_DEPOSIT` | 客户支付订金 | | `PAY_FULL` | 客户支付全款 | | `SET_PENDING_BALANCE` | 切到「待支付尾款」细状态 | | `SET_PENDING_DEPARTURE` | 切到「待出行」细状态(系统时机到达) | | `CONFIRM` | 定制师确认锁单(需先通过 §3.15 checklist) | | `INITIATE_REFUND` | 发起退款 | | `CANCEL` | 取消订单 | | `DEPART` | 标记出发(订单进入「出行中」) | | `FINISH` | 标记完成 | ### 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.14 `eventCode=CONFIRM`,否则后端拒绝(`581063`) --- ## 13. 关联 - **API 设计文档**: `docs/order-v3/api/API-SPEC-V5.49.html` §1.1 ~ §1.4 - **SRS 业务规格**: `docs/order-v3/srs/order-cloud-v3-srs-v5.49.html` §F1 创单 / §1.0i 模型 / §1.3 创单流程 - **数据库 Schema**: `docs/order-v3/database/DATABASE-SCHEMA-V5.49.html` §1.1 order_main / §1.2 order_tag - **后端负责人**: @yaosutu --- ## 📝 后续追加计划 §1 模块 15 接口全部首推完毕。后续若有接口字段调整 / 错误码新增 / 业务边界变化,通过追加 commit 扩充本文件。