# 私人定制完整流程（C端提交 + 管理端处理） - 前端对接指南

> **日期**: 2026-03-19
> **后端状态**: ✅ 已完成，测试环境已部署
> **涉及模块**: hl-mp-service（C端BFF）、hl-order-service（管理端+内部接口）、hl-product-service（定制产品）
> **Knife4j 文档**: `192.168.100.236:8080/doc.html`
>   - C端：左侧选 "C端 - 定制需求接口"
>   - 管理端：左侧选 "订单服务 - 私人定制管理"

---

## 业务流程总览

```
用户(小程序)                        管理员(后台)
    │                                   │
    ├─ 提交定制需求 ──────────────────→  │
    │   POST /mp/custom/submit          │
    │                                   ├─ 查看定制请求列表
    │                                   │   GET /admin/order/customize/page
    │                                   │
    │                                   ├─ 查看请求详情
    │                                   │   GET /admin/order/customize/{id}
    │                                   │
    │                                   ├─ 接受请求（分配定制师）
    │                                   │   PUT /admin/order/customize/{id}/accept
    │                                   │
    │                                   ├─ 回复/报价（关联产品）
    │  ← 收到通知 ──────────────────────┤   PUT /admin/order/customize/{id}/reply
    │                                   │
    │                                   ├─ 标记完成
    │  ← 收到通知 ──────────────────────┤   PUT /admin/order/customize/{id}/complete
    │                                   │
    ├─ 查看定制需求列表                   │
    │   GET /mp/custom/list              │
    │                                   │
    ├─ 查看需求详情                      │
    │   GET /mp/custom/detail            │
    │                                   │
    ├─ 查看已完成的定制产品               │
    │   GET /mp/custom/product/{id}      │
    │                                   │
    ├─ 取消定制需求                      │
    │   POST /mp/custom/{id}/cancel      │
    │                                   │
    └─ 下单购买定制产品                   │
        POST /mp/order/create            │
```

---

## 一、C端接口（小程序，需登录）

### 接口清单

| # | 接口 | 方法 | 路径 | 说明 |
|---|------|------|------|------|
| 1 | 提交定制需求 | POST | `/mp/custom/submit` | 用户发起定制请求 |
| 2 | 定制需求列表 | GET | `/mp/custom/list` | 分页查询我的定制需求 |
| 3 | 定制需求详情 | GET | `/mp/custom/detail` | 查看单条定制需求 |
| 4 | 取消定制需求 | POST | `/mp/custom/{requestId}/cancel` | 取消待处理/处理中的需求 |
| 5 | 已完成定制产品详情 | GET | `/mp/custom/product/{productId}` | 查看定制产品方案 |
| 6 | 我的已完成定制产品列表 | GET | `/mp/custom/products` | 所有已完成的定制产品 |

---

### 接口 C1：提交定制需求

```
POST /mp/custom/submit
Content-Type: application/json
Authorization: Bearer {token}
```

#### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| designerId | Long | 否 | 指定定制师ID（不传则系统分配） |
| destination | String | 否 | 目标地区，如"云南大理"，最长200字 |
| travelPurpose | String | 否 | 旅游目的（字典：`travel_purpose`） |
| requestType | String | 否 | 需求类型（字典：`customize_request_type`） |
| startDate | String | 否 | 期望出发日期，格式 `yyyy-MM-dd` |
| endDate | String | 否 | 期望结束日期，格式 `yyyy-MM-dd` |
| days | Integer | 否 | 期望天数（1~365） |
| adultCount | Integer | 否 | 成人数（至少1，最多99） |
| childCount | Integer | 否 | 儿童数（0~99） |
| budget | String | 否 | 预算范围（字典：`customize_budget`） |
| requirements | String | 否 | 详细需求描述，最长2000字 |
| contactPhone | String | 否 | 联系电话，最长20字 |
| contactName | String | 否 | 联系人，最长50字 |

#### 响应示例

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "requestId": 2029926129876320258,
    "userId": 2026279738275856300,
    "designerId": null,
    "destination": "呼伦贝尔",
    "travelPurpose": "FAMILY",
    "requestType": "FAMILY_TRIP",
    "startDate": "2026-07-01",
    "endDate": "2026-07-07",
    "days": 7,
    "adultCount": 2,
    "childCount": 1,
    "budget": "BUDGET_10000_20000",
    "requirements": "希望安排亲子活动，孩子3岁",
    "contactPhone": "13800138000",
    "contactName": "张三",
    "status": "PENDING",
    "statusLabel": "待处理",
    "designerName": null,
    "designerAvatar": null,
    "productId": null,
    "reply": null,
    "repliedAt": null,
    "createTime": "2026-03-19T10:30:00",
    "updateTime": "2026-03-19T10:30:00"
  }
}
```

#### 响应字段

| 字段 | 类型 | 说明 |
|------|------|------|
| requestId | Long | 定制请求ID |
| userId | Long | 用户ID |
| designerId | Long | 指定定制师ID（未指定则null） |
| destination | String | 目标地区 |
| travelPurpose | String | 旅游目的（字典：`travel_purpose`） |
| requestType | String | 需求类型（字典：`customize_request_type`） |
| startDate | String | 期望出发日期 |
| endDate | String | 期望结束日期 |
| days | Integer | 期望天数 |
| adultCount | Integer | 成人数 |
| childCount | Integer | 儿童数 |
| budget | String | 预算范围（字典：`customize_budget`） |
| requirements | String | 详细需求描述 |
| contactPhone | String | 联系电话 |
| contactName | String | 联系人 |
| status | String | 状态（字典：`customize_request_status`） |
| statusLabel | String | 状态中文标签 |
| designerName | String | 定制师姓名（未分配时null） |
| designerAvatar | String | 定制师头像URL |
| productId | Long | 关联产品ID（定制完成后才有值） |
| reply | String | 定制师回复内容 |
| repliedAt | String | 回复时间 |
| createTime | String | 创建时间 |
| updateTime | String | 更新时间 |

---

### 接口 C2：定制需求列表

```
GET /mp/custom/list?page=1&pageSize=20
Authorization: Bearer {token}
```

#### 请求参数

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| page | int | 否 | 1 | 页码 |
| pageSize | int | 否 | 20 | 每页条数 |

#### 响应示例

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "requestId": 2029926129876320258,
        "userId": 2026279738275856300,
        "destination": "呼伦贝尔",
        "travelPurpose": "FAMILY",
        "requestType": "FAMILY_TRIP",
        "startDate": "2026-07-01",
        "days": 7,
        "adultCount": 2,
        "childCount": 1,
        "budget": "BUDGET_10000_20000",
        "status": "DESIGNING",
        "statusLabel": "设计中",
        "designerName": "李设计师",
        "designerAvatar": "https://oss.example.com/avatar.jpg",
        "createTime": "2026-03-19T10:30:00"
      }
    ],
    "total": 3,
    "page": 1,
    "pageSize": 20
  }
}
```

---

### 接口 C3：定制需求详情

```
GET /mp/custom/detail?id={requestId}
Authorization: Bearer {token}
```

#### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | Long | ✅ | 定制请求ID |

#### 响应

同接口 C1 的响应字段（完整的 `MpCustomizeRequestVO`）。

**前端关键逻辑**：
- 当 `status` 为 `QUOTED` 或 `COMPLETED` 且 `productId` 不为null → 展示"查看定制方案"按钮
- 当 `status` 为 `PENDING` / `ACCEPTED` / `DESIGNING` → 展示"取消定制"按钮

---

### 接口 C4：取消定制需求

```
POST /mp/custom/{requestId}/cancel
Authorization: Bearer {token}
```

#### 请求参数

| 参数 | 类型 | 位置 | 必填 | 说明 |
|------|------|------|------|------|
| requestId | Long | 路径 | ✅ | 定制请求ID |

#### 业务规则

- ✅ 可取消状态：`PENDING`（待处理）、`ACCEPTED`（已接受）、`DESIGNING`（设计中）
- ❌ 不可取消状态：`QUOTED`（已报价）、`COMPLETED`（已完成）、`CANCELLED`（已取消）

#### 响应

同接口 C1 的响应字段，status 变为 `CANCELLED`。

---

### 接口 C5/C6：已完成定制产品

详见已有文档：`2026-03-19_custom_product_query.md`

---

## 二、管理端接口（后台，需管理员登录）

### 接口清单

| # | 接口 | 方法 | 路径 | 说明 |
|---|------|------|------|------|
| 1 | 定制请求列表 | GET | `/admin/order/customize/page` | 分页+搜索+筛选 |
| 2 | 定制请求详情 | GET | `/admin/order/customize/{requestId}` | 完整信息 |
| 3 | 接受请求 | PUT | `/admin/order/customize/{requestId}/accept` | 分配定制师 |
| 4 | 回复/报价 | PUT | `/admin/order/customize/{requestId}/reply` | 回复或关联产品 |
| 5 | 标记完成 | PUT | `/admin/order/customize/{requestId}/complete` | 定制完成 |

---

### 接口 A1：定制请求列表（分页）

```
GET /admin/order/customize/page?page=1&pageSize=20
Authorization: Bearer {admin-token}
```

#### 请求参数

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| keyword | String | 否 | | 搜索关键词（联系人/目标地区/需求描述） |
| status | String | 否 | | 状态过滤（字典：`customize_request_status`） |
| designerId | Long | 否 | | 定制师ID过滤 |
| sortBy | String | 否 | createTime | 排序字段：`createTime` / `startDate` |
| sortDir | String | 否 | desc | 排序方向：`desc` / `asc` |
| page | int | 否 | 1 | 页码 |
| pageSize | int | 否 | 20 | 每页条数（最大100） |

#### 响应示例

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "records": [
      {
        "requestId": 2029926129876320258,
        "userId": 2026279738275856300,
        "destination": "呼伦贝尔",
        "travelPurpose": "FAMILY",
        "requestType": "FAMILY_TRIP",
        "startDate": "2026-07-01",
        "days": 7,
        "adultCount": 2,
        "childCount": 1,
        "budget": "BUDGET_10000_20000",
        "status": "PENDING",
        "statusLabel": "待处理",
        "designerName": null,
        "designerAvatar": null,
        "createTime": "2026-03-19T10:30:00"
      }
    ],
    "total": 15,
    "page": 1,
    "pageSize": 20
  }
}
```

#### 响应字段（CustomizeRequestListVO）

| 字段 | 类型 | 说明 |
|------|------|------|
| requestId | Long | 请求ID |
| userId | Long | 用户ID |
| destination | String | 目标地区 |
| travelPurpose | String | 旅游目的（字典：`travel_purpose`） |
| requestType | String | 需求类型（字典：`customize_request_type`） |
| startDate | String | 期望出发日期 |
| days | Integer | 期望天数 |
| adultCount | Integer | 成人数 |
| childCount | Integer | 儿童数 |
| budget | String | 预算范围（字典：`customize_budget`） |
| status | String | 状态（字典：`customize_request_status`） |
| statusLabel | String | 状态中文标签 |
| designerName | String | 定制师姓名 |
| designerAvatar | String | 定制师头像URL |
| createTime | String | 创建时间 |

#### 使用场景

管理后台"私人定制"列表页：
1. 顶部筛选栏：状态下拉（全部/待处理/已接受/设计中/已报价/已完成/已取消）+ 关键词搜索 + 定制师筛选
2. 表格展示：目标地区、需求类型、出发日期、天数、人数、预算、定制师、状态、创建时间
3. 操作按钮根据状态显示（见下方状态机）

---

### 接口 A2：定制请求详情

```
GET /admin/order/customize/{requestId}
Authorization: Bearer {admin-token}
```

#### 请求参数

| 参数 | 类型 | 位置 | 必填 | 说明 |
|------|------|------|------|------|
| requestId | Long | 路径 | ✅ | 定制请求ID |

#### 响应字段（CustomizeRequestVO）

同接口 C1 的完整响应字段（24个字段）。管理端可看到所有信息包括联系人电话等。

---

### 接口 A3：接受定制请求

```
PUT /admin/order/customize/{requestId}/accept
Authorization: Bearer {admin-token}
```

#### 请求参数

| 参数 | 类型 | 位置 | 必填 | 说明 |
|------|------|------|------|------|
| requestId | Long | 路径 | ✅ | 定制请求ID |

无请求体。管理员ID从token中自动获取。

#### 业务规则

- 仅 `PENDING`（待处理）状态可接受
- 如果用户未指定定制师（designerId为null），自动分配当前操作人为定制师
- 如果用户已指定定制师，保留原定制师
- 状态变更：`PENDING` → `ACCEPTED`

#### 响应

返回更新后的完整 `CustomizeRequestVO`（status=ACCEPTED，designerName/designerAvatar 已填充）。

---

### 接口 A4：回复/报价

```
PUT /admin/order/customize/{requestId}/reply
Content-Type: application/json
Authorization: Bearer {admin-token}
```

#### 请求参数

| 参数 | 类型 | 位置 | 必填 | 说明 |
|------|------|------|------|------|
| requestId | Long | 路径 | ✅ | 定制请求ID |

#### 请求体（AdminReplyRequest）

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| reply | String | ✅ | 回复内容，最长2000字 |
| productId | Long | 否 | 关联的定制产品ID（已创建定制产品后传入） |

#### 业务规则

- 仅 `ACCEPTED`（已接受）或 `DESIGNING`（设计中）状态可回复
- **仅填写 reply**：状态变为 `DESIGNING`（设计中）
- **同时传 productId**：状态变为 `QUOTED`（已报价），C端用户可通过 productId 查看产品方案

#### 响应示例

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "requestId": 2029926129876320258,
    "status": "QUOTED",
    "statusLabel": "已报价",
    "reply": "您好！我为您设计了一套7天6晚的呼伦贝尔亲子游方案，请查看。",
    "productId": 2029926131830865921,
    "repliedAt": "2026-03-19T14:00:00",
    "designerName": "李设计师",
    "..."
  }
}
```

#### 前端操作流程

```
1. 定制师在后台创建定制产品（product-service，productType=CUSTOM）
2. 产品设计完成后，回到定制请求页面
3. 点击"回复/报价"按钮 → 弹窗填写回复内容 + 选择关联产品
4. 调用此接口提交
5. C端用户在"我的定制"中看到状态变为"已报价"，可查看产品方案
```

---

### 接口 A5：标记完成

```
PUT /admin/order/customize/{requestId}/complete
Authorization: Bearer {admin-token}
```

#### 请求参数

| 参数 | 类型 | 位置 | 必填 | 说明 |
|------|------|------|------|------|
| requestId | Long | 路径 | ✅ | 定制请求ID |

无请求体。

#### 业务规则

- 仅 `QUOTED`（已报价）状态可标记完成
- 状态变更：`QUOTED` → `COMPLETED`
- 通常在用户确认方案或已下单后，定制师手动标记

#### 响应

返回更新后的完整 `CustomizeRequestVO`（status=COMPLETED）。

---

## 三、状态机与按钮显示

### 状态流转

```
PENDING(待处理) ──accept──→ ACCEPTED(已接受)
       │                        │
       │cancel                  │cancel
       ↓                        ↓
  CANCELLED              ──reply(仅文字)──→ DESIGNING(设计中)
                                                │
                                                │cancel
                                                ↓
                               ──reply(+productId)──→ QUOTED(已报价)
                                                         │
                                                    ──complete──→ COMPLETED(已完成)
```

### 管理端按钮显示

| 状态 | 可用操作 |
|------|---------|
| PENDING（待处理） | [接受请求] |
| ACCEPTED（已接受） | [回复] [报价] |
| DESIGNING（设计中） | [回复] [报价] |
| QUOTED（已报价） | [标记完成] |
| COMPLETED（已完成） | 无操作 |
| CANCELLED（已取消） | 无操作 |

### C端按钮显示

| 状态 | 可用操作 |
|------|---------|
| PENDING（待处理） | [取消定制] |
| ACCEPTED（已接受） | [取消定制] |
| DESIGNING（设计中） | [取消定制] |
| QUOTED（已报价） | [查看定制方案] |
| COMPLETED（已完成） | [查看定制方案] [去下单] |
| CANCELLED（已取消） | 无操作 |

---

## 四、关联字典

### customize_request_status（定制请求状态）

| dict_value | dict_label | 说明 |
|------------|-----------|------|
| PENDING | 待处理 | 用户刚提交，等待定制师接受 |
| ACCEPTED | 已接受 | 定制师已接受请求 |
| DESIGNING | 设计中 | 定制师正在设计方案 |
| QUOTED | 已报价 | 已关联产品，等待用户确认 |
| COMPLETED | 已完成 | 定制流程完结 |
| CANCELLED | 已取消 | 用户取消请求 |

### customize_request_type（需求类型）

| dict_value | dict_label |
|------------|-----------|
| FAMILY_TRIP | 亲子游 |
| HONEYMOON | 蜜月游 |
| GROUP_TRIP | 团建游 |
| SENIOR_TRIP | 银发游 |
| ADVENTURE | 探险游 |
| PHOTOGRAPHY | 摄影游 |
| CULTURE | 文化游 |
| OTHER | 其他 |

### travel_purpose（旅游目的）

| dict_value | dict_label |
|------------|-----------|
| LEISURE | 休闲度假 |
| ADVENTURE | 探险体验 |
| CULTURE | 文化探访 |
| FAMILY | 亲子陪伴 |
| ROMANCE | 浪漫旅行 |
| TEAM | 团队建设 |
| OTHER | 其他 |

### customize_budget（预算范围）

| dict_value | dict_label |
|------------|-----------|
| UNDER_3000 | 3000元以下/人 |
| BUDGET_3000_5000 | 3000-5000元/人 |
| BUDGET_5000_10000 | 5000-10000元/人 |
| BUDGET_10000_20000 | 10000-20000元/人 |
| ABOVE_20000 | 20000元以上/人 |
| NO_LIMIT | 不限预算 |

---

## 五、管理端页面布局建议

### 定制请求列表页

```
┌─────────────────────────────────────────────────────────────────┐
│  私人定制管理                                                     │
├─────────────────────────────────────────────────────────────────┤
│  状态: [全部 ▼]  定制师: [全部 ▼]  关键词: [____________] [搜索]  │
├─────┬──────┬──────┬───┬───┬─────┬──────┬─────┬────────┬────────┤
│ 目的地│需求类型│出发日期│天数│人数│  预算 │ 定制师 │ 状态 │ 创建时间 │  操作  │
├─────┼──────┼──────┼───┼───┼─────┼──────┼─────┼────────┼────────┤
│呼伦贝尔│亲子游  │07-01 │ 7 │2大1小│1~2万/人│ 李设计师│待处理│03-19 10:30│[接受]  │
│三亚   │蜜月游  │08-15 │ 5 │2大0小│5千~1万│  未分配 │待处理│03-18 09:00│[接受]  │
│大理   │文化游  │04-01 │ 3 │1大0小│不限   │ 王设计师│设计中│03-17 14:20│[回复]  │
└─────┴──────┴──────┴───┴───┴─────┴──────┴─────┴────────┴────────┘
```

### 定制请求详情页（弹窗或新页面）

```
┌─────────────────────────────────────────────┐
│  定制请求详情                     状态: 待处理  │
├─────────────────────────────────────────────┤
│  基本信息                                     │
│  目标地区: 呼伦贝尔                             │
│  需求类型: 亲子游                               │
│  旅游目的: 亲子陪伴                             │
│  出发日期: 2026-07-01 ~ 2026-07-07 (7天)      │
│  人数: 2成人 1儿童                              │
│  预算: 10000-20000元/人                        │
├─────────────────────────────────────────────┤
│  联系人                                       │
│  姓名: 张三                                    │
│  电话: 13800138000                             │
├─────────────────────────────────────────────┤
│  需求描述                                      │
│  希望安排亲子活动，孩子3岁                        │
├─────────────────────────────────────────────┤
│  定制师信息                                    │
│  定制师: 未分配                                 │
│  回复: 无                                      │
│  关联产品: 无                                   │
├─────────────────────────────────────────────┤
│                    [接受请求]                   │
└─────────────────────────────────────────────┘
```

---

## 六、完整调用示例

### 管理端：处理一个定制请求

```javascript
// 1. 加载列表（筛选待处理）
const list = await adminRequest.get('/admin/order/customize/page', {
  params: { status: 'PENDING', page: 1, pageSize: 20 }
})

// 2. 查看详情
const detail = await adminRequest.get(`/admin/order/customize/${requestId}`)

// 3. 接受请求（自动分配当前管理员为定制师）
await adminRequest.put(`/admin/order/customize/${requestId}/accept`)

// 4. 定制师创建定制产品（通过产品管理模块，productType=CUSTOM）
// ... 创建产品后获得 productId

// 5. 回复并关联产品
await adminRequest.put(`/admin/order/customize/${requestId}/reply`, {
  reply: '您好！我为您设计了一套呼伦贝尔亲子游方案，请查看。',
  productId: createdProductId
})

// 6. 用户确认后标记完成
await adminRequest.put(`/admin/order/customize/${requestId}/complete`)
```

### C端：提交并跟踪定制需求

```javascript
// 1. 提交定制需求
const res = await request.post('/mp/custom/submit', {
  destination: '呼伦贝尔',
  travelPurpose: 'FAMILY',
  requestType: 'FAMILY_TRIP',
  startDate: '2026-07-01',
  endDate: '2026-07-07',
  days: 7,
  adultCount: 2,
  childCount: 1,
  budget: 'BUDGET_10000_20000',
  requirements: '希望安排亲子活动',
  contactName: '张三',
  contactPhone: '13800138000'
})

// 2. 查看我的定制需求列表
const list = await request.get('/mp/custom/list', { params: { page: 1 } })

// 3. 查看详情
const detail = await request.get('/mp/custom/detail', { params: { id: requestId } })

// 4. 当状态变为 QUOTED/COMPLETED 且有 productId
if (detail.data.productId && ['QUOTED', 'COMPLETED'].includes(detail.data.status)) {
  const product = await request.get(`/mp/custom/product/${detail.data.productId}`)
  // 展示定制产品方案
}

// 5. 查看所有已完成的定制产品
const products = await request.get('/mp/custom/products')
```

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)
