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

12 KiB
Raw Blame History

WonderQ MiniAPP Public API

本文档是 WonderQ-MiniAPP 当前使用的 Public API 契约。接口提供站点内容、首页卡片、玩法展示、管家展示、登录、出行需求提交和客户记录查询能力。

基础约定

  • API 前缀:/api/public
  • 响应使用 JSON时间使用 ISO 8601 字符串。
  • 所有 /health/api/public/** JSON 响应遵循 三端统一 API 响应契约,成功业务对象位于 data,失败时 datanull
  • 所有返回的持久化资源 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 返回以下稳定字段:

type SiteConfig = {
  heroSlides: HeroSlide[];
  vehicleOptions: VehicleOption[];
};

Public 响应只返回 heroSlidesvehicleOptions 的启用内容,其余旧首页配置模块不再返回。首页玩法推荐、团队共创和极境视界由 /api/public/home 及其详情接口提供;用车需求说明使用 MiniAPP 本地文案,实际提交走 /api/public/leads,不再依赖旧的 vehicleService 配置。

用车需求提交

POST /api/public/leads 的通用线索仍允许游客提交;leadType=vehicle 必须携带客户 JWT。服务端从 JWT 写入 customerId,客户端不得传入该字段。

{
  "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 归一化 destinationtravelDatepeopleCount 摘要字段。未登录、参数不完整或服务异常分别返回 401422500,失败时 datanull

客户用车记录

用车记录接口只返回当前客户自己的 leadType=vehicle 记录,必须携带 Authorization: Bearer <customer-jwt>customerId 由服务端从 JWT 获取,客户端不能传入或用查询参数覆盖。

列表接口使用 pageNumpageSize 分页,pageSize 最大为 50成功响应统一为

type PageResult<T> = {
  items: T[];
  total: number;
  pageNum: number;
  pageSize: number;
};

GET /api/public/customer/vehicle-demands 的列表项和 GET /api/public/customer/vehicle-demands/{leadId} 的详情项使用以下展示字段:

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服务端根据内容读取当前标题和图片并保存

{
  "itemType": "wanfa-route",
  "itemId": "route-uuid"
}

itemType 目前支持 wanfa-routeteam-buildingwild-archive。同一客户重复浏览同一内容时,服务端更新 visitedAt、标题和图片,不创建重复记录。成功响应为单条 CustomerBrowseHistoryItem;列表接口返回 PageResult<CustomerBrowseHistoryItem>

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 玩法页所需的最小展示字段,不返回后台排序、审计和时间字段。

成功响应:

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。成功响应只返回详情展示字段:

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。关联管家未配置、已删除或已停用时 conciergeAdvisornull。MiniAPP 路线详情页通过 /pages/detail/index?routeId={key} 进入;接口失败或字段不完整时按路线 ID 使用本地网络图片和模拟文案fallback 不伪造管家数据。仅当 conciergeAdvisor 有效时展示联系管家入口。

管家展示

GET /api/public/concierge/advisors

无需鉴权。接口只返回后台启用的管家顾问,按后台维护顺序返回;不返回管理端 ID、启停状态、排序元数据和时间字段。

type PublicConciergeDetail = {
  icon: string;
  label: string;
};

type PublicConciergeAdvisor = {
  avatar: string;
  name: string;
  role: string;
  details: PublicConciergeDetail[];
  qrImage: string;
};

type PublicConciergeResponse = {
  advisors: PublicConciergeAdvisor[];
};

成功响应示例:

{
  "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

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;
};

无可用内容时,experiencesteamBuildingswildArchives 均返回空数组。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} 无需鉴权,只返回启用的团队共创详情。响应包含首页摘要字段,以及 detailSubtitledetailParagraphs。不存在或已停用返回 404

详情页接口失败时MiniAPP 按 ID 使用 homeTeamBuildingData.ts 中的网络图片和模拟正文 fallback并显示接口不可用提示首页 /api/public/home 不返回 detailParagraphs,避免首页请求携带长正文。

通用字段

站点模块通常包含 idcreatedAtupdatedAtisActivesortOrder。客户端按 sortOrder 消费排序模块,不依赖固定 ID。

图片字段(如 imagegalleryavatarqrImage)始终返回可直接请求的公网 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

请求:

{ "code": "wechat-phone-code" }

成功响应:

{
  "code": 200,
  "msg": "success",
  "data": {
    "token": "<customer-jwt>",
    "customer": { "id": "customer-id", "phoneMasked": "138****0000" }
  }
}

GET /api/public/auth/me

请求头:Authorization: Bearer <customer-jwt>

成功响应:

{
  "code": 200,
  "msg": "success",
  "data": { "id": "customer-id", "phoneMasked": "138****0000" }
}