Files
WonderQ-Project/docs/public-api.md
2026-08-28 09:52:11 +08:00

350 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WonderQ MiniAPP Public API
本文档是 `WonderQ-MiniAPP` 当前使用的 Public API 契约。接口提供站点内容、首页卡片、玩法展示、管家展示、登录、出行需求提交和客户记录查询能力。
## 基础约定
- API 前缀:`/api/public`
- 响应使用 JSON时间使用 ISO 8601 字符串。
- 所有 `/health``/api/public/**` JSON 响应遵循 [三端统一 API 响应契约](./api-response-contract.md),成功业务对象位于 `data`,失败时 `data``null`
- 所有返回的持久化资源 `id` 都是稳定 UUID 字符串,不是标题、分类名或本地 mock 使用的语义 ID详情、列表和跳转必须复用同一个 ID。
- H5 本地开发通过 `/api` 代理访问后端。
- 内容接口失败时MiniAPP 使用 `src/content.ts` 的本地兜底内容。
## 接口清单
| 方法 | 路径 | 鉴权 | 用途 |
| ------ | ------------------------------ | ------------ | ------------------ |
| `GET` | `/health` | 否 | 服务健康检查 |
| `GET` | `/api/public/site-config` | 否 | 获取启用的站点内容 |
| `GET` | `/api/public/home` | 否 | 获取已启用的首页内容和玩法推荐 |
| `GET` | `/api/public/home/team-buildings/{teamBuildingId}` | 否 | 获取团队共创详情 |
| `GET` | `/api/public/home/wild-archives` | 否 | 获取客片案例更多列表 |
| `GET` | `/api/public/home/wild-archives/{archiveId}` | 否 | 获取客片案例详情和图片 |
| `GET` | `/api/public/wanfa/categories` | 否 | 获取玩法分类和路线 |
| `GET` | `/api/public/details/{key}` | 否 | 获取玩法路线详情 |
| `GET` | `/api/public/concierge/advisors` | 否 | 获取已启用的管家顾问 |
| `POST` | `/api/public/auth/phone-login` | 否 | 微信手机号登录 |
| `GET` | `/api/public/auth/me` | Customer JWT | 获取当前客户 |
| `POST` | `/api/public/leads` | 否 | 提交出行需求 |
| `GET` | `/api/public/customer/vehicle-demands` | Customer JWT | 查询当前客户的用车提交记录 |
| `GET` | `/api/public/customer/vehicle-demands/{leadId}` | Customer JWT | 查询当前客户的用车提交详情 |
| `POST` | `/api/public/customer/browse-history` | Customer JWT | 新增或更新浏览历史 |
| `GET` | `/api/public/customer/browse-history` | Customer JWT | 分页查询当前客户的浏览历史 |
## 站点配置
`GET /api/public/site-config` 返回以下稳定字段:
```ts
type SiteConfig = {
heroSlides: HeroSlide[];
vehicleOptions: VehicleOption[];
};
```
Public 响应只返回 `heroSlides``vehicleOptions` 的启用内容,其余旧首页配置模块不再返回。首页玩法推荐、团队共创和极境视界由 `/api/public/home` 及其详情接口提供;用车需求说明使用 MiniAPP 本地文案,实际提交走 `/api/public/leads`,不再依赖旧的 `vehicleService` 配置。
### 用车需求提交
`POST /api/public/leads` 的通用线索仍允许游客提交;`leadType=vehicle` 必须携带客户 JWT。服务端从 JWT 写入 `customerId`,客户端不得传入该字段。
```json
{
"leadType": "vehicle",
"contactName": "联系人",
"phone": "13800000000",
"sourcePage": "home-vehicle",
"vehicleDemand": {
"serviceType": "charter",
"charterDuration": "fullDay",
"travelDate": "2026-08-25",
"pickupTime": "09:00",
"pickupLocation": "贵阳北站",
"dropoffLocation": "黄果树景区",
"peopleCount": 5,
"luggageCount": 3,
"vehicleOptionId": "vehicle-option-uuid",
"vehicleOptionTitle": "多人商务车",
"specialRequirements": "需要儿童座椅"
}
}
```
服务端从 `vehicleDemand` 归一化 `destination``travelDate``peopleCount` 摘要字段。未登录、参数不完整或服务异常分别返回 `401``422``500`,失败时 `data``null`
### 客户用车记录
用车记录接口只返回当前客户自己的 `leadType=vehicle` 记录,必须携带 `Authorization: Bearer <customer-jwt>``customerId` 由服务端从 JWT 获取,客户端不能传入或用查询参数覆盖。
列表接口使用 `pageNum``pageSize` 分页,`pageSize` 最大为 50成功响应统一为
```ts
type PageResult<T> = {
items: T[];
total: number;
pageNum: number;
pageSize: number;
};
```
`GET /api/public/customer/vehicle-demands` 的列表项和 `GET /api/public/customer/vehicle-demands/{leadId}` 的详情项使用以下展示字段:
```ts
type CustomerVehicleDemandRecord = {
id: string;
status: "new" | "assigned" | "contacted" | "planning" | "won" | "invalid";
contactName: string | null;
phoneMasked: string;
destination: string | null;
travelDate: string | null;
peopleCount: number | null;
note: string | null;
vehicleDemand: VehicleDemandPayload;
createdAt: string;
updatedAt: string;
};
```
手机号只返回 `phoneMasked`,不返回原始手机号。详情接口对不属于当前客户的 `leadId` 统一返回 `404`
### 客户浏览历史
`POST /api/public/customer/browse-history` 只接收内容类型和内容 ID服务端根据内容读取当前标题和图片并保存
```json
{
"itemType": "wanfa-route",
"itemId": "route-uuid"
}
```
`itemType` 目前支持 `wanfa-route``team-building``wild-archive`。同一客户重复浏览同一内容时,服务端更新 `visitedAt`、标题和图片,不创建重复记录。成功响应为单条 `CustomerBrowseHistoryItem`;列表接口返回 `PageResult<CustomerBrowseHistoryItem>`
```ts
type CustomerBrowseHistoryItem = {
id: string;
itemType: "wanfa-route" | "team-building" | "wild-archive";
itemId: string;
title: string;
image: string;
visitedAt: string;
};
```
详情页成功读取后由 MiniAPP 异步写入浏览历史;接口失败时继续保留本地历史缓存,浏览历史列表可以展示本地兜底内容。
## 玩法展示
### `GET /api/public/wanfa/categories`
无需鉴权。接口按后台维护的分类和路线顺序返回 MiniAPP 玩法页所需的最小展示字段,不返回后台排序、审计和时间字段。
成功响应:
```ts
type PublicWanfaResponse = {
categories: PublicWanfaCategory[];
};
type PublicWanfaCategory = {
id: string;
label: string;
routes: PublicWanfaRoute[];
};
type PublicWanfaRoute = {
id: string;
title: string;
subtitle: string;
image: string;
routeCount: number;
demandKeyword: string;
};
```
MiniAPP 使用 `demandKeyword` 作为需求页预填关键词;接口失败或响应为空时,玩法页展示对应的错误、重试或空态。
### 路线详情
`GET /api/public/details/{key}` 无需鉴权,`key` 使用玩法路线 ID例如 `family-water`。成功响应只返回详情展示字段:
```ts
type PublicDetail = {
key: string;
eyebrow: string;
duration: string;
title: string;
subtitle: string;
intro: string;
highlights: string[];
included: string[];
excluded: string[];
notes: string[];
gallery: string[];
priceStartingValue: number | null;
priceUnit: "person" | "day" | "group" | null;
pricePeopleRange: string;
priceDescription: string;
conciergeAdvisor: {
avatar: string;
name: string;
role: string;
details: Array<{ icon: string; label: string }>;
qrImage: string;
} | null;
};
```
不存在、停用或未配置详情返回 `404`。关联管家未配置、已删除或已停用时 `conciergeAdvisor``null`。MiniAPP 路线详情页通过 `/pages/detail/index?routeId={key}` 进入;接口失败或字段不完整时按路线 ID 使用本地网络图片和模拟文案fallback 不伪造管家数据。仅当 `conciergeAdvisor` 有效时展示联系管家入口。
## 管家展示
### `GET /api/public/concierge/advisors`
无需鉴权。接口只返回后台启用的管家顾问,按后台维护顺序返回;不返回管理端 ID、启停状态、排序元数据和时间字段。
```ts
type PublicConciergeDetail = {
icon: string;
label: string;
};
type PublicConciergeAdvisor = {
avatar: string;
name: string;
role: string;
details: PublicConciergeDetail[];
qrImage: string;
};
type PublicConciergeResponse = {
advisors: PublicConciergeAdvisor[];
};
```
成功响应示例:
```json
{
"advisors": [
{
"avatar": "https://example.test/assets/advisor-avatar.jpg",
"name": "示例顾问",
"role": "SENIOR TRAVEL ADVISOR",
"details": [{ "icon": "calendar", "label": "服务经验8年" }],
"qrImage": "https://example.test/assets/advisor-qr.png"
}
]
}
```
无可用顾问时返回 `data: { "advisors": [] }`。MiniAPP 应处理 loading、错误、重试和空态不能依赖固定顾问姓名或本地模拟数组。
## 首页内容
### `GET /api/public/home`
无需鉴权。接口只返回后台启用的首页玩法推荐、团队共创和极境视界内容,按后台排序返回,不暴露管理元数据。为统一前台消费模型,玩法推荐列表放在 `experiences` 字段,响应中不再返回 `playRecommendations`
```ts
type PublicHomeResponse = {
experiences: HomeWanfaRecommendation[];
teamBuildings: HomeTeamBuilding[];
wildArchives: HomeWildArchive[];
};
type HomeWanfaRecommendation = {
id: string;
categoryId: string;
label: string;
routes: WanfaRoute[];
};
type WanfaRoute = {
id: string;
title: string;
subtitle: string;
image: string;
routeCount: number;
demandKeyword: string;
};
type HomeTeamBuilding = {
id: string;
tag: string;
title: string;
description: string;
image: string;
demandKeyword: string;
};
type PublicHomeTeamBuildingDetail = HomeTeamBuilding & {
detailSubtitle: string;
detailParagraphs: string[];
};
type HomeWildArchive = {
id: string;
title: string;
image: string;
demandKeyword: string;
photoCount: number;
};
```
无可用内容时,`experiences``teamBuildings``wildArchives` 均返回空数组。`experiences` 实际承载首页玩法推荐由首页内容域关联玩法分类后生成接口只返回启用的关联及分类当前路线MiniAPP 接口失败或字段不完整时使用对应空态,不再读取 `playRecommendations`
客片案例更多列表使用 `GET /api/public/home/wild-archives`,返回同样的摘要字段;详情使用 `GET /api/public/home/wild-archives/{archiveId}`,在摘要字段基础上增加 `images: string[]`。首页卡片点击详情,`查看更多` 点击案例列表,不再跳转需求页。
### 团队共创详情
`GET /api/public/home/team-buildings/{teamBuildingId}` 无需鉴权,只返回启用的团队共创详情。响应包含首页摘要字段,以及 `detailSubtitle``detailParagraphs`。不存在或已停用返回 `404`
详情页接口失败时MiniAPP 按 ID 使用 `homeTeamBuildingData.ts` 中的网络图片和模拟正文 fallback并显示接口不可用提示首页 `/api/public/home` 不返回 `detailParagraphs`,避免首页请求携带长正文。
### 通用字段
站点模块通常包含 `id``createdAt``updatedAt``isActive``sortOrder`。客户端按 `sortOrder` 消费排序模块,不依赖固定 ID。
图片字段(如 `image``gallery``avatar``qrImage`)始终返回可直接请求的公网 HTTP(S) URL。OSS 上传可使用内网 Endpoint但响应地址统一使用 `OSS_PUBLIC_BASE_URL`;历史内网 URL 会在响应时自动切换到公网 Host。OSS 配置为私有读时WonderQ-Admin 会在响应中生成短时 GET 签名 URL客户端应直接使用返回值不应持久化或自行修改签名参数。
旧需求页主视觉、特色卡片和需求表单已移除;需求页面只通过 `POST /api/public/leads` 提交实时线索,不再读取已删除的站点配置表。
## 登录接口
### `POST /api/public/auth/phone-login`
请求:
```json
{ "code": "wechat-phone-code" }
```
成功响应:
```json
{
"code": 200,
"msg": "success",
"data": {
"token": "<customer-jwt>",
"customer": { "id": "customer-id", "phoneMasked": "138****0000" }
}
}
```
### `GET /api/public/auth/me`
请求头:`Authorization: Bearer <customer-jwt>`
成功响应:
```json
{
"code": 200,
"msg": "success",
"data": { "id": "customer-id", "phoneMasked": "138****0000" }
}
```