Files
WonderQ-Admin/docs/miniapp-public-api.md
duanshuwen 1aac3c64b2 feat(hotelGroups): add offer display fields and related logic
- Add new database columns (coverImage, priceAmount, priceUnit, tags, status) to HotelGroup model
- Create hotel_group_dict serializer to handle image/coverImage synchronization and tag formatting
- Update site config endpoints to use the new serializer and filter published hotel groups
- Add Alembic migration for the new database schema changes
- Update test fixtures and API contract tests for the new fields
- Revise public and admin API documentation to document the new hotel group fields and usage rules
2026-07-03 22:44:57 +08:00

22 KiB
Raw Blame History

WonderQ-MiniAPP Public API 对接文档

最后更新2026-07-02

本文档定义 WonderQ-MiniAPP 前台 H5/小程序对接 WonderQ-Admin 后端所需的 Public API 契约。当前 MiniAPP 主动调用站点配置、产品列表和线索提交 3 个接口;后端已存在的健康检查、产品详情和目的地列表接口建议继续保留,供后续前台按需接入。

基础约定

  • 基础地址由 MiniAPP 环境变量 VITE_API_BASE_URL 控制;为空时前台按同源 /api 请求。
  • Public API 不要求前台登录认证。
  • 请求和响应均使用 JSON字符集为 UTF-8。
  • 图片字段应返回可被 H5 和微信小程序访问的 URL现有前台兼容 /assets/... 形式。
  • 列表字段建议返回空数组,不建议返回 nullMiniAPP 对站点配置和产品列表有本地兜底内容。
  • 错误响应需提供可展示信息,兼容 { "message": "..." } 或 FastAPI 默认 { "detail": "..." }。不要暴露内部异常、真实环境变量、Token、JWT secret、客服链接或企业 ID。

数据类型

HeroSlide

字段 类型 必填 说明
id string 轮播图 ID
title string 主标题
kicker string | null 辅助短文案
image string 图片 URL
targetType string | null 点击目标类型
targetValue string | null 点击目标值
isActive boolean 是否启用
sortOrder number 后台排序值Public API 按该字段升序输出

Destination

字段 类型 必填 说明
id string 目的地 ID
name string 目的地名称
image string | null 图片 URL
isHot boolean 是否热门
isActive boolean 是否启用
sortOrder number 后台排序值Public API 按该字段升序输出
aliases Array<{ id: string; alias: string }> 搜索别名

Theme

字段 类型 必填 说明
id string 主题 ID
label string 主题名称
image string 主题图片 URL
targetType string | null 点击目标类型
targetValue string | null 点击目标值
isActive boolean 是否启用
sortOrder number 后台排序值Public API 按该字段升序输出

CtaBanner

字段 类型 必填 说明
id string 服务卡片 ID
alt string 服务标题,展示在“更多服务”卡片上
image string 服务卡片背景图 URL
targetType string | null 点击目标类型
targetValue string | null 点击目标值
isActive boolean 是否启用
sortOrder number 后台排序值Public API 按该字段升序输出

Campaign

字段 类型 必填 说明
id string 活动 ID
slug string 活动标识
title string 活动标题
description string | null 活动描述
coverImage string | null 活动封面图
priceAmount number | null 参考起价,单位按 priceUnit 展示
priceUnit string | null 价格单位文案,默认 起/人
tags string[] 活动卡片标签,最多 3 个
status string 活动状态Public API 只返回 published
startsAt string | null 活动开始时间
endsAt string | null 活动结束时间

RouteSection

RouteSection 用于描述首页“精选线路”下的动态运营分组。后台可按任务新增、编辑、删除和排序分组MiniAPP 不应依赖固定分组 ID只按接口返回的分组顺序和 productIds 渲染。

字段 类型 必填 说明
id string 后端生成的分组 ID客户端只用于列表 key 和商品关联,不作为固定业务枚举
title string 分组标题
subtitle string | null 分组副文案
productIds string[] 该分组包含的产品 ID产品详情来自 /api/public/products.items
isActive boolean 是否启用Public API 通常只返回启用分组
sortOrder number 后台展示顺序Public API 按该字段升序输出

Public API 输出规则:

  • GET /api/public/site-config 只返回启用的 routeSections
  • routeSections[].productIds 只包含已发布商品 ID未发布、归档或不存在的商品不得出现在 Public 响应中。
  • 动态分组按后台 sortOrder 升序返回,productIds 的顺序就是用户侧商品卡展示顺序。
  • MiniAPP 会按 productIds 匹配 /api/public/products.items[].id;接口缺失、routeSections 为空或没有可匹配商品时回退 src/content.ts 的本地精选线路兜底内容。

HomeCard

HomeCard 用于首页“万趣用车”等普通内容卡片模块。MiniAPP 只消费卡片展示字段,不在这些模块里读取商品本体或线路商品关联。

字段 类型 必填 说明
id string 后端生成的卡片 ID
title string 卡片标题
description string | null 卡片描述
image string | null 卡片封面图 URL为空时客户端可使用本地兜底图
isActive boolean 是否启用Public API 通常只返回启用卡片
sortOrder number 后台展示顺序Public API 按该字段升序输出

HotelCard

HotelCard 用于首页“特色酒店”模块。该模块按管理端“特价优惠”同类配置方式维护标题、描述、价格、标签、封面图和发布状态,但仍然只代表首页酒店展示卡片,不绑定商品本体。

字段 类型 必填 说明
id string 后端生成的酒店卡片 ID
title string 酒店卡片标题
description string | null 酒店卡片描述
image string | null 兼容旧字段;后端会与 coverImage 保持一致
coverImage string | null 酒店封面图主字段MiniAPP 优先使用该字段
priceAmount number | null 价格数值,前端可按页面需要展示
priceUnit string | null 价格单位文案,例如 起/晚
tags string[] 酒店标签,最多 3 个
status "draft" | "published" 发布状态Public API 只返回 published
isActive boolean 是否启用Public API 只返回启用项
sortOrder number 后台展示顺序Public API 按该字段升序输出

Public API 输出规则:

  • GET /api/public/site-config 只返回 status="published"isActive=truehotelGroups
  • GET /api/public/site-config 只返回启用的 vehicleOptions
  • 两个数组按后台 sortOrder 升序返回。
  • hotelGroups 字段缺失、数组为空或没有可用图片时MiniAPP 使用 src/content.ts 的本地特色酒店内容兜底;酒店图片优先取 coverImage,再取 image
  • vehicleOptions 字段缺失、数组为空或图片为空时MiniAPP 使用 src/content.ts 的本地万趣用车内容兜底。

PublicProduct

字段 类型 必填 说明
id string 后端产品 UUID
sourceId number | null 历史采集产品 ID前台可用于兼容旧数据
title string 产品标题
subtitle string | null 副标题
destination { id: string; name: string } | null 目的地信息
priceAmount number | null 参考起价,单位按后端内容约定
priceUnit string | null 价格单位文案
tags string[] 标签列表
coverImage string | null 封面图 URL
summary string | null 摘要
images Array<ProductImage> 图集
detailSections ProductDetailSection[] | null 产品详情分区
status string 产品状态,前台主要消费 published 内容

ProductImage

字段 类型 必填 说明
id string 图片 ID
url string 图片 URL
alt string | null 图片说明
sortOrder number 排序值

ProductDetailSection

字段 类型 必填 说明
key string 分区 key例如 overviewitineraryservicenoticepricemanager
label string Tab 展示文案
title string | null 分区标题
blocks ProductDetailBlock[] 内容块

ProductDetailBlock 支持两种结构:

{ "type": "text", "text": "文本内容" }
{ "type": "image", "url": "/assets/example.jpg", "alt": "图片说明" }

接口清单

GET /health

用于服务健康检查。

响应示例

{
  "ok": true,
  "service": "miniapp-api"
}

GET /api/public/site-config

用于首页轮播、目的地、主题入口和更多服务配置。MiniAPP 启动时会和产品列表并行请求该接口;接口不可用或关键数组为空时,前台会回退本地静态内容。

响应字段

字段 类型 说明
heroSlides HeroSlide[] 首页顶部轮播
destinations Destination[] 首页目的地入口
map Array<{ id: string; image: string; isActive?: boolean }> 贵州地图图片MiniAPP 当前消费 map[0].image
themes Theme[] 主题甄选入口
ctaBanners CtaBanner[] “更多服务”卡片配置
campaigns Campaign[] 活动元信息,可用于“特价优惠”入口;当前不包含活动产品结果列表
routeSections RouteSection[] “精选线路”子分组定义
hotelGroups HotelCard[] “特色酒店”卡片配置,只返回 published 且启用项
vehicleOptions HomeCard[] “万趣用车”卡片配置,只返回启用项

首页模块数据归属

首页模块 当前接口归属 说明
特价优惠 site-config.campaigns + /api/public/products 当前 Public API 只返回活动元信息不直接返回“特价优惠结果列表”。MiniAPP 若要展示活动线路,可按活动标题、标签或后续扩展的活动产品关联从 /api/public/products 中筛选。
精选线路 site-config.routeSections + /api/public/products routeSections 返回动态分组与 productIds;具体产品卡片数据由 /api/public/products.items 提供。后台可按任务新增、删除、停用和排序分组,用户侧不假设固定三组。
更多服务 site-config.ctaBanners 返回启用服务卡片,按后台排序展示;无有效配置时回退本地 bottomCtas 内容。
特色酒店 site-config.hotelGroups 返回 published 且启用的酒店卡片按后台排序展示MiniAPP 优先消费 coverImage,无有效配置时回退本地内容。
万趣用车 site-config.vehicleOptions 返回启用用车卡片,按后台排序展示;无有效配置时回退本地内容。

响应示例

{
  "heroSlides": [
    {
      "id": "hero-1",
      "title": "贵州小包团定制",
      "kicker": "万趣,你的小包团首选",
      "image": "/assets/guizhou/libo-xiaoqikong.jpg",
      "targetType": "search",
      "targetValue": "贵州",
      "isActive": true
    }
  ],
  "destinations": [
    {
      "id": "dest-1",
      "name": "荔波小七孔",
      "image": "/assets/guizhou/libo-xiaoqikong.jpg",
      "isHot": true,
      "isActive": true,
      "aliases": [{ "id": "alias-1", "alias": "小七孔" }]
    }
  ],
  "map": [
    {
      "id": "map-1",
      "image": "/assets/guizhou/guizhou-map.jpg",
      "isActive": true
    }
  ],
  "themes": [],
  "ctaBanners": [],
  "campaigns": [
    {
      "id": "campaign-1",
      "slug": "classic-deal",
      "title": "经典打卡特惠",
      "description": "经典首游活动",
      "coverImage": "/assets/guizhou/libo-xiaoqikong.jpg",
      "priceAmount": 162500,
      "priceUnit": "起/人",
      "tags": ["臻藏旅位", "赛事庆典"],
      "status": "published",
      "startsAt": null,
      "endsAt": null
    }
  ],
  "routeSections": [
    {
      "id": "route-section-001",
      "title": "经典人文打卡线路",
      "subtitle": "黄果树、荔波小七孔、千户苗寨、镇远古城、梵净山一次串联",
      "productIds": ["8a6e7c4f-0000-4000-9000-000000000001"],
      "isActive": true
    },
    {
      "id": "route-section-002",
      "title": "极限山野户外野咖线路",
      "subtitle": "溶洞、峡谷、漂流、峰林骑行和山野咖啡组合",
      "productIds": [],
      "isActive": true
    },
    {
      "id": "route-section-003",
      "title": "人文+户外综合混搭线路",
      "subtitle": "非遗村寨、古城夜游、自然轻探险和精品住宿同程安排",
      "productIds": [],
      "isActive": true
    }
  ],
  "hotelGroups": [
    {
      "id": "hotel-group-001",
      "title": "经典酒店",
      "description": "城市接驳、景区度假和温泉休整,适合首游贵州的小包团动线。",
      "image": "/assets/guizhou/bailian-hot-spring.jpg",
      "coverImage": "/assets/guizhou/bailian-hot-spring.jpg",
      "priceAmount": 68000,
      "priceUnit": "起/晚",
      "tags": ["温泉", "亲子"],
      "status": "published",
      "isActive": true,
      "sortOrder": 0
    }
  ],
  "vehicleOptions": [
    {
      "id": "vehicle-option-001",
      "title": "5座舒适用车",
      "description": "适合2-4人家庭或好友小团城市接送、景区穿梭更灵活。",
      "image": "/assets/guizhou/jiaxiu-tower.jpg",
      "isActive": true,
      "sortOrder": 0
    }
  ]
}

GET /api/public/products

用于首页产品分区、搜索结果、活动页、目的地页、详情推荐和预订入口。当前 MiniAPP 一次拉取列表后在前端做搜索、筛选和推荐。

Query 参数

参数 类型 必填 默认值 说明
keyword string 关键词搜索,建议匹配产品标题、副标题、标签、目的地名称和目的地别名
destinationId string 按目的地 ID 筛选
status string published 产品状态
take number 48 返回数量,后端当前限制 1-100

响应字段

字段 类型 说明
items PublicProduct[] 产品列表

响应示例

{
  "items": [
    {
      "id": "8a6e7c4f-0000-4000-9000-000000000001",
      "sourceId": 101,
      "title": "黄果树瀑布小包团",
      "subtitle": "错峰入园,私家车接送",
      "destination": { "id": "dest-anshun", "name": "黄果树" },
      "priceAmount": 398000,
      "priceUnit": "起/人",
      "tags": ["贵州", "黄果树", "小包团"],
      "coverImage": "/assets/guizhou/huangguoshu.jpg",
      "summary": "适合首次到贵州的经典线路。",
      "images": [
        {
          "id": "img-1",
          "url": "/assets/guizhou/huangguoshu.jpg",
          "alt": "黄果树瀑布",
          "sortOrder": 0
        }
      ],
      "detailSections": [
        {
          "key": "overview",
          "label": "行程概述",
          "title": "小包团专属概览",
          "blocks": [{ "type": "text", "text": "按同行人、预算和体力强度重排行程。" }]
        }
      ],
      "status": "published"
    }
  ]
}

GET /api/public/products/{product_id}

后端已存在,建议保留给 MiniAPP 后续详情页按需拉取。当前 MiniAPP 主要通过产品列表缓存进入详情。

Path 参数

参数 类型 说明
product_id string 产品 UUID如果传入纯数字后端按 sourceId 查询

成功响应

返回单个 PublicProduct

异常响应

状态码 说明
404 产品不存在

示例:

{
  "detail": "线路不存在"
}

GET /api/public/destinations

后端已存在,建议保留给 MiniAPP 后续目的地页独立拉取。当前 MiniAPP 首页目的地来自 site-config.destinations

响应示例

{
  "items": [
    {
      "id": "dest-libo",
      "name": "荔波小七孔",
      "slug": "libo-xiaoqikong",
      "region": "黔南",
      "image": "/assets/guizhou/libo-xiaoqikong.jpg",
      "isHot": true,
      "sortOrder": 0,
      "isActive": true,
      "aliases": [{ "id": "alias-1", "alias": "小七孔" }]
    }
  ]
}

POST /api/public/leads

用于首页快速定制、搜索页快速定制、需求页和预订咨询页提交线索。

请求字段

字段 类型 必填 说明
phone string 联系方式。前台输入文案为“手机号 / 微信号”,后端当前会去除首尾空白并压缩连续空格
destination string 目的地或玩法
travelDate string 出行日期MiniAPP 当前传 YYYY-MM-DD 字符串
peopleCount number 出行人数,需大于 0
budgetMin number 最低预算,需大于等于 0
budgetMax number 最高预算,需大于等于 0
note string 补充说明,后端当前限制最长 1000 字符
sourcePage string 来源页面
sourceProductId string 来源产品 UUID

sourcePage 当前取值

来源
home_inline 首页快速定制入口
search_inline 搜索结果页快速定制入口
demand_page 提交需求页
product_consult 产品预订咨询页

请求示例

{
  "destination": "荔波小七孔",
  "phone": "187 8617 4929",
  "travelDate": "2027-01-01",
  "peopleCount": 2,
  "note": "咨询线路:黄果树瀑布小包团;方案偏好:经典人文",
  "sourcePage": "product_consult",
  "sourceProductId": "8a6e7c4f-0000-4000-9000-000000000001"
}

成功响应

状态码:201

{
  "id": "lead-uuid",
  "status": "new"
}

常见异常

状态码 场景
422 请求体校验失败,例如 phone 为空、peopleCount 小于等于 0、note 超长
500 服务端异常,响应不得暴露内部细节

MiniAPP 当前依赖说明

  • site-configproducts 会在应用启动时并行请求任一请求失败时MiniAPP 会回退到本地静态内容。
  • products.items 为空时MiniAPP 会使用本地产品兜底数据。
  • “精选线路”由 site-config.routeSections 定义动态分组标题、副文案和商品 ID 顺序,由 /api/public/products.items 提供产品详情;客户端不依赖固定分组 ID 或固定三组数量。
  • routeSections 缺失、为空或无法匹配到有效商品时MiniAPP 使用 src/content.ts 的本地精选线路内容回退。
  • ctaBanners 缺失或为空时MiniAPP 使用 src/content.ts 的本地 bottomCtas 内容回退。
  • “特色酒店”和“万趣用车”分别由 site-config.hotelGroupssite-config.vehicleOptions 提供;特色酒店优先使用 coverImage,字段缺失、数组为空或图片为空时使用本地内容兜底。
  • “特价优惠”当前没有独立 Public 结果列表字段;site-config.campaigns 只提供活动元信息,活动线路需通过产品标签/关键词筛选或后续扩展活动产品关联字段。
  • 产品搜索当前主要在前端执行,依赖 titletagsdestination.namesummary
  • 产品详情页当前使用已加载的产品列表数据;后续可改为进入详情页时请求 GET /api/public/products/{product_id}
  • 收藏、浏览历史和最近咨询记录由 MiniAPP 本地存储处理,不需要后端接口。
  • 企业微信客服由 MiniAPP 环境变量控制,不属于 WonderQ-Admin Public API文档和接口不得写入真实链接或企业 ID。

后端验证建议

  • GET /health 增加或保留健康检查测试。
  • GET /api/public/site-config 验证返回 JSON 包含 heroSlidesdestinationsmapthemesctaBannerscampaignsrouteSectionshotelGroupsvehicleOptions 数组字段。
  • GET /api/public/site-config 验证 routeSections 表达“精选线路”子分组;接口返回当前已配置且启用的分组,未配置时返回空数组并由 MiniAPP 本地内容兜底。
  • GET /api/public/site-config 验证 routeSections 只返回启用分组,且 productIds 不包含未发布商品。
  • GET /api/public/site-config 验证 hotelGroups 只返回 published 且启用卡片,包含 coverImage、价格和标签字段;验证 vehicleOptions 只返回启用卡片,并按 sortOrder 升序。
  • GET /api/public/products 验证响应结构为 { items: [...] },并覆盖 keyworddestinationIdstatustake 参数。
  • GET /api/public/products/{product_id} 验证 UUID、数字 sourceId 和 404 场景。
  • GET /api/public/destinations 验证只返回启用目的地及别名字段。
  • POST /api/public/leads 验证成功创建、phone 规范化、必填校验、人数/预算边界和备注长度限制。