# 私人定制完整流程(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)