# ⚠️✨ 管理端代下单接口 v3 新增分享追踪字段 + consultantSource 枚举新增 SHARED

> **服务**: hl-order-service-v3
> **接口**: `POST /admin/v3/orders`
> **PR**: #2565 refactor(order-v3): [Agency PR-4 / PR-1] 订单创建补 5 项基础逻辑
> **日期**: 2026-05-18 23:55
> **影响页面**: 管理后台「代下单」流程 + 小程序下单（通过 hl-mp-service 透传同接口）

---

## 变了什么（前端视角）

### 1. 请求体新增 2 个非必填字段

`POST /admin/v3/orders` 的请求 body 新增以下字段，**不传或传 null 行为与改造前完全一致**：

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `sharerOpenid` | String | 否 | 分享人微信 openid，用于 C 端裂变追踪 / 佣金归属。落表 `order_info.sharer_openid`，admin 代下单时通常不传 |
| `customizerId` | Long | 否 | C 端分享归因：从分享链接中带入的定制师 adminId。校验通过则锁定为该定制师（`consultantSource = SHARED`），校验失败兜底系统默认定制师 |

**注意**：`customizerId` 类型必须是 **number（Long）**，不能传 string。

### 2. 响应体枚举 consultantSource 新增值 SHARED

`OrderCreateRespVO` 中 `consultantSource` 字段的枚举值新增 `SHARED`：

| 枚举值 | 含义 | 何时出现 |
|--------|------|---------|
| `DEFAULT_ASSIGNED` | 系统默认定制师 | C 端下单，customizerId 为空或校验不通过，且有系统默认定制师 |
| `LINK_BOUND` | 链接绑定定制师 | 历史逻辑（v2 遗留） |
| `MANUAL` | admin 手动指定 | admin 代下单时由 JWT adminId 指定 |
| `SHARED`（**新增**） | C 端分享锁定定制师 | C 端下单，customizerId 校验通过 |

### 3. 新增可能抛出的错误码

| code | message | 触发场景 |
|------|---------|---------|
| `581035` | 订金金额不得超过订单总额 | DEPOSIT 模式下订金金额 > 订单总额时触发 |

### 4. 行为收紧（字段名不变，错误码变化）

| 场景 | 旧行为 | 新行为 |
|------|--------|--------|
| Agency 无默认 mchId | 抛 `MCH_RESOLVE_FAILED` | 抛 `AGENCY_NO_DEFAULT_MCHID` |
| customerName / customerRemark 含 HTML 标签 | 原样入库 | XSS 过滤后入库（前端无感，被清掉的标签不会报错） |

---

## 前端要改的地方

### 管理后台 B 端

1. **consultantSource 展示标签**：若订单详情 / 列表有按 `consultantSource` 显示来源文案的地方，需补 `SHARED` 的 case，建议展示文案为**"分享锁定"**：

   ```js
   // 建议
   const consultantSourceLabel = {
     DEFAULT_ASSIGNED: '系统分配',
     LINK_BOUND: '链接绑定',
     MANUAL: '手动指定',
     SHARED: '分享锁定',   // 新增
   }
   ```

2. **错误码监控 / 提示**：若代下单流程中有按错误码展示错误提示，建议给 `581035` 加 case，文案直接透传后端 message：`"订金金额不得超过订单总额"`。

   若之前有对 `MCH_RESOLVE_FAILED` 的特殊提示逻辑，需同步改为 `AGENCY_NO_DEFAULT_MCHID`。

### 小程序 C 端（通过 hl-mp-service 透传）

3. **分享链接带 customizerId 下单**：从分享 URL 取出 `adminId`，下单时透传为 `customizerId`（参考 `07_feat_share_lock_customizer.md` 详细步骤）：

   ```js
   const customizerId = uni.getStorageSync('share_customizer_id') || null
   // 放入 POST /mp/order/create 或 POST /admin/v3/orders 的请求体
   ```

4. **分享追踪 sharerOpenid**：若小程序有分享溯源需求（如显示"由 XXX 分享"），可在下单时透传 `sharerOpenid`；不传也不影响下单流程。

---

## 接口详细定义

### POST /admin/v3/orders — 管理端 / C 端创建订单

- **使用场景**：管理后台代客户下单，或 C 端小程序通过 hl-mp-service 创建订单
- **方法**: `POST`
- **路径**: `/admin/v3/orders`（通过 gateway 路由到 hl-order-service-v3）

#### 请求参数（Body JSON）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `productId` | Long | 是 | 产品 ID |
| `productType` | String | 是 | 产品类型（CORE / ACTIVITY 等） |
| `startDate` | String | 是 | 出发日期，格式 `yyyy-MM-dd` |
| `adultCount` | Integer | 是 | 成人人数，≥ 1 |
| `childCount` | Integer | 否 | 儿童人数，默认 0 |
| `customerName` | String | 是 | 客户姓名（会走 XSS 过滤，HTML 标签会被清除） |
| `customerPhone` | String | 是 | 客户手机号 |
| `customerRemark` | String | 否 | 客户备注（会走 XSS 过滤） |
| `sharerOpenid` | String | 否 | **[新增]** 分享人微信 openid，C 端裂变追踪用 |
| `customizerId` | Long | 否 | **[新增]** 分享人定制师 adminId，校验通过则锁定为本单定制师 |

#### 请求示例（含新增字段）

```json
{
  "productId": 10001,
  "productType": "CORE",
  "startDate": "2026-06-01",
  "adultCount": 2,
  "childCount": 0,
  "customerName": "张三",
  "customerPhone": "13800138000",
  "customerRemark": "需要靠窗座位",
  "sharerOpenid": "oXXXXXXXXXXX",
  "customizerId": 50001
}
```

#### 响应结构

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "orderId": "202605181234567890",
    "orderNo": "HL202605181234",
    "totalAmount": 9800,
    "depositAmount": 2000,
    "consultantId": 50001,
    "consultantName": "李定制师",
    "consultantSource": "SHARED"
  }
}
```

#### 响应字段说明

| 字段 | 类型 | 说明 |
|------|------|------|
| `orderId` | String | 雪花 ID，前端按字符串处理（Long 精度问题） |
| `orderNo` | String | 可读订单号 |
| `totalAmount` | Integer | 订单总额（分） |
| `depositAmount` | Integer | 订金金额（分），DEPOSIT 模式下有值 |
| `consultantId` | Long | 绑定的定制师 adminId |
| `consultantName` | String | 定制师姓名 |
| `consultantSource` | String | 定制师来源枚举，见下表 |

#### consultantSource 枚举值完整列表

| 值 | 中文展示建议 | 触发场景 |
|----|------------|---------|
| `DEFAULT_ASSIGNED` | 系统分配 | C 端下单，customizerId 无效或未传，有系统默认定制师 |
| `LINK_BOUND` | 链接绑定 | 历史逻辑（v2 遗留，v3 基本不再出现） |
| `MANUAL` | 手动指定 | admin 代下单，由登录态 JWT adminId 指定 |
| `SHARED` | 分享锁定 | C 端下单，`customizerId` 校验通过（定制师有效且角色正确） |

---

## 错误码完整列表（本接口可能返回）

| code | message | 处理建议 |
|------|---------|---------|
| `200` | success | 正常 |
| `400` | 参数校验失败 | 检查必填字段 |
| `581035` | 订金金额不得超过订单总额 | **[新增]** 直接 toast 后端 message |
| `AGENCY_NO_DEFAULT_MCHID` | Agency 未配置默认收款账号 | 联系运营配置 agency 默认 mchId |

---

## 兼容性

- 请求字段仅新增非必填字段，**向后兼容**（旧版前端不传新字段行为不变）
- 响应枚举仅新增值不删值，**向后兼容**
- 无 DDL 变更，无需数据迁移
- 只需重启 `hl-order-service-v3`，`hl-mp-service` 无需重启

---

## customizerId 校验兜底语义（前端无需实现）

后端 `CustomizerValidator` 校验失败时**全部静默兜底为系统默认定制师，不报错**：

| 失败原因 | 触发条件 | 前端表现 |
|---------|---------|---------|
| `ADMIN_NOT_FOUND` | adminId 不存在 / 已删除 | 兜底随机，静默 |
| `INACTIVE_STATUS` | admin status ≠ ACTIVE | 兜底随机，静默 |
| `WRONG_ROLE` | admin roleKey ≠ CUSTOMIZER | 兜底随机，静默 |
| `FEIGN_ERROR` | user-service Feign 调用失败 | 兜底随机，静默 |
| `INVALID_INPUT` | customizerId == null / ≤ 0 | 兜底随机，静默 |

前端不需要对这些失败场景做任何处理。
