Files
WonderQ-Project/docs/home-api.md
duanshuwen cda8069630 docs: 清理过时文档,新增首页API契约并更新相关内容
- 删除backend-plan.md、backend-api-service.md等多份过时项目文档
- 新增home-api.md规范首页三类内容的Admin API补充契约
- 更新docs/README.md的文档清单与展示格式
- 优化integration-workflow.md、admin-api-requirements.md等文档的表格与内容
- 为WonderQ-MiniAPP的homeExperienceData.ts新增API适配类型与归一化函数
2026-08-18 20:00:25 +08:00

15 KiB
Raw Blame History

首页内容管理 Admin API

适用端:WonderQ-Admin、WonderQ-Admin-UI。

状态:待实现契约。本文件参考 WonderQ-MiniAPP/src/pages/home/components/homeExperienceData.ts、homeTeamBuildingData.ts 和 homeWildArchivesData.ts 定义首页卡片内容,以及管理端需要的查询、维护和排序接口。它是首页内容的 Admin API 补充契约,不是 MiniAPP Public API 文档。

领域边界

首页内容管理只维护三类首页卡片:

  • 体验推荐:徽标、分类、标题、英文标题、封面和需求关键词。
  • 团队共创:标签、标题、描述、封面和需求关键词。
  • 极境视界:案例标题、封面和需求关键词。

本领域不负责:

  • 顶部轮播、车辆选项、需求表单或其他站点模块;这些内容遵循 Admin API 主契约。
  • 商品、Product、ProductImage、详情、价格、库存、订单或预订。
  • 线索创建和线索跟进。

demandKeyword 只是点击卡片后预填需求页的普通字符串,不是商品 ID、路线 ID、订单 ID,也不建立数据库外键。

当前首页仍直接使用三个文件中的 mock 数组。Admin API 接入前,这些数组继续作为前台 fallback;本文件不代表接口已经在 WonderQ-Admin 或 WonderQ-Admin-UI 中实现。

接口清单

API 前缀为 /api/admin,除登录接口外均需要后台 JWT。

方法 路径 用途
GET /api/admin/home/experiences 获取全部体验推荐卡片
POST /api/admin/home/experiences 新增体验推荐卡片
PATCH /api/admin/home/experiences/{experienceId} 编辑体验推荐卡片
DELETE /api/admin/home/experiences/{experienceId} 删除体验推荐卡片
PATCH /api/admin/home/experiences/reorder 调整体验推荐卡片顺序
GET /api/admin/home/team-buildings 获取全部团队共创卡片
POST /api/admin/home/team-buildings 新增团队共创卡片
PATCH /api/admin/home/team-buildings/{teamBuildingId} 编辑团队共创卡片
DELETE /api/admin/home/team-buildings/{teamBuildingId} 删除团队共创卡片
PATCH /api/admin/home/team-buildings/reorder 调整团队共创卡片顺序
GET /api/admin/home/wild-archives 获取全部极境视界案例
POST /api/admin/home/wild-archives 新增极境视界案例
PATCH /api/admin/home/wild-archives/{archiveId} 编辑极境视界案例
DELETE /api/admin/home/wild-archives/{archiveId} 删除极境视界案例
PATCH /api/admin/home/wild-archives/reorder 调整极境视界案例顺序

通用约定

  • 请求和响应使用 JSON,字段使用 camelCase。
  • 所有管理接口需要 Authorization: Bearer <admin-jwt>。
  • GET 返回启用和停用的全部记录,按 sortOrder 升序返回,供 Admin UI 完整维护。
  • 创建、编辑、删除和排序成功后写入审计日志,再提交事务。
  • 创建和编辑返回最新记录;排序接口返回排序后的 items。
  • ID 由后端生成并作为非空字符串返回。初始化迁移时应优先保留三个 mock 文件中的稳定 ID。
  • 空集合返回 [],不能返回 null 或省略字段。
  • 所有资源的 sortOrder 从 0 开始,数值越小越靠前;新增未传排序时追加到末尾。
  • 失败响应沿用 Admin API 主契约,包含 message、code 和可选的 details。

数据类型

体验推荐

homeExperienceData.ts 已包含前台渲染类型和 API 过渡类型。Admin API 的完整记录应补充管理元数据:

type HomeExperience = {
  id: string;
  badge: string;
  category: string;
  title: string;
  englishTitle: string;
  image: string;
  demandKeyword: string;
};

type HomeExperienceApiItem = {
  id?: string | null;
  badge?: string | null;
  category?: string | null;
  title?: string | null;
  englishTitle?: string | null;
  image?: string | null;
  demandKeyword?: string | null;
  isActive?: boolean | null;
  sortOrder?: number | null;
};

type HomeExperienceRecord = HomeExperience & {
  isActive: boolean;
  sortOrder: number;
  createdAt: string;
  updatedAt: string;
};

type HomeExperienceCreate = Omit<HomeExperience, "id"> & {
  isActive?: boolean;
  sortOrder?: number;
};

type HomeExperiencePatch = Partial<HomeExperienceCreate>;

团队共创

homeTeamBuildingData.ts 当前只包含前台渲染字段,管理端记录增加状态、排序和审计时间:

type HomeTeamBuilding = {
  id: string;
  tag: string;
  title: string;
  description: string;
  image: string;
  demandKeyword: string;
};

type HomeTeamBuildingRecord = HomeTeamBuilding & {
  isActive: boolean;
  sortOrder: number;
  createdAt: string;
  updatedAt: string;
};

type HomeTeamBuildingCreate = Omit<HomeTeamBuilding, "id"> & {
  isActive?: boolean;
  sortOrder?: number;
};

type HomeTeamBuildingPatch = Partial<HomeTeamBuildingCreate>;

极境视界

homeWildArchivesData.ts 当前只包含前台渲染字段,管理端记录增加状态、排序和审计时间:

type HomeWildArchive = {
  id: string;
  title: string;
  image: string;
  demandKeyword: string;
};

type HomeWildArchiveRecord = HomeWildArchive & {
  isActive: boolean;
  sortOrder: number;
  createdAt: string;
  updatedAt: string;
};

type HomeWildArchiveCreate = Omit<HomeWildArchive, "id"> & {
  isActive?: boolean;
  sortOrder?: number;
};

type HomeWildArchivePatch = Partial<HomeWildArchiveCreate>;

列表响应和排序请求统一使用以下结构:

type HomeListResponse<T> = {
  items: T[];
};

type HomeReorderRequest = {
  itemIds: string[];
};

字段约束

资源 字段 类型 必填 约束和用途
体验推荐 badge string 是 卡片徽标,去除首尾空白后不得为空。
体验推荐 category string 是 体验分类文案,去除首尾空白后不得为空。
体验推荐 title string 是 卡片主标题,去除首尾空白后不得为空。
体验推荐 englishTitle string 是 卡片英文标题,去除首尾空白后不得为空。
体验推荐 image string 是 可直接用于图片组件的封面 URL。
体验推荐 demandKeyword string 是 点击后预填需求页的关键词。
团队共创 tag string 是 卡片标签,去除首尾空白后不得为空。
团队共创 title string 是 卡片标题,去除首尾空白后不得为空。
团队共创 description string 是 卡片描述,去除首尾空白后不得为空。
团队共创 image string 是 可直接用于图片组件的封面 URL。
团队共创 demandKeyword string 是 点击后预填需求页的关键词。
极境视界 title string 是 案例标题,去除首尾空白后不得为空。
极境视界 image string 是 案例图片 URL。
极境视界 demandKeyword string 是 点击后预填需求页的关键词。
全部资源 isActive boolean 响应必填 是否进入已发布前台内容,创建默认 true。
全部资源 sortOrder number 响应必填 非负整数,数值越小越靠前。
全部资源 createdAt string 响应必填 ISO 8601 创建时间。
全部资源 updatedAt string 响应必填 ISO 8601 最后更新时间。

服务端应校验所有必填文本、URL 格式和非负整数排序值;具体文本最大长度由后端 schema 统一定义,并同步到 Admin UI 表单校验。图片字段只保存最终 URL,不接受 base64,不在首页内容记录中保存图片二进制。

接口详情

以下规则适用于三类资源;路径中的资源名和 ID 参数以接口清单为准。

获取列表

GET /api/admin/home/experiences
Authorization: Bearer <admin-jwt>

团队共创和极境视界分别使用 /api/admin/home/team-buildings、/api/admin/home/wild-archives。

成功响应示例:

{
  "items": [
    {
      "id": "waterfall-descent",
      "badge": "玩过推荐",
      "category": "瀑降体验",
      "title": "悬崖瀑降",
      "englishTitle": "WATERFALL DESCENT",
      "image": "https://example.test/assets/waterfall-descent.jpg",
      "demandKeyword": "悬崖瀑降",
      "isActive": true,
      "sortOrder": 0,
      "createdAt": "2026-01-01T00:00:00Z",
      "updatedAt": "2026-01-01T00:00:00Z"
    }
  ]
}

接口返回启用和停用的全部记录;Admin UI 负责显示状态,不能让后端默认隐藏停用记录。

新增、编辑与删除

  • POST /api/admin/home/{resource}:请求体为对应资源的 Create 类型,成功返回 201 和新建记录;未传 sortOrder 时追加到末尾。
  • PATCH /api/admin/home/{resource}/{id}:请求体为对应资源的 Patch 类型,只更新提交字段;成功返回更新后的记录,不存在返回 404。
  • DELETE /api/admin/home/{resource}/{id}:成功返回 { "id": "..." },删除后重新规范化同一资源剩余记录的 sortOrder。

其中 {resource} 只能是 experiences、team-buildings 或 wild-archives;对应路径参数分别为 experienceId、teamBuildingId、archiveId。删除不触发商品、订单、预订或线索级联操作。

调整顺序

PATCH /api/admin/home/experiences/reorder
Authorization: Bearer <admin-jwt>
Content-Type: application/json

团队共创和极境视界分别使用 /api/admin/home/team-buildings/reorder、/api/admin/home/wild-archives/reorder。请求必须完整包含当前资源的全部 ID,不能重复:

{ "itemIds": ["cave-exploration", "waterfall-descent"] }

成功响应为 { "items": [] },其中 items 是更新 sortOrder 后的完整记录列表。缺少 ID、包含未知 ID 或出现重复 ID 时返回 400 HOME_REORDER_INVALID。

当前 fallback 与迁移映射

迁移初始数据时应保留以下稳定 ID、字段值和当前数组顺序:

体验推荐

顺序 ID 标题 需求关键词
0 waterfall-descent 悬崖瀑降 悬崖瀑降
1 cave-exploration 森林&探洞 地心探险

homeExperienceData.ts 当前的 normalizeHomeExperiences 具有以下过渡行为:

  • isActive === false 的 API 项被过滤。
  • 缺少有效 title 的 API 项被过滤。
  • 其余项目按 sortOrder 升序排列,未传排序时保持 API 原顺序。
  • 文案和图片字段为空时使用当前 fallback 对应位置的值。
  • API 没有有效项目时返回当前 homeExperienceMocks 的副本。

这些规则用于前台接入过渡,不应替代服务端校验。后端返回正式记录后,Admin UI 应提交完整字段,避免依赖位置 fallback。

团队共创

顺序 ID 标题 需求关键词
0 wild-challenge 山野挑战,共创极境 户外团建
1 canyon-teamwork 峡谷溯溪,默契同行 峡谷团建
2 village-gathering 苗寨共聚,认识彼此 贵州团建

极境视界

顺序 ID 标题 需求关键词
0 hundred-meter-descent 百米自降 悬崖瀑降
1 shilong-cave 石龙洞 地心探险
2 cliff-current 绝壁迎流 峡谷探险
3 canyon-streaming 峡谷溯溪 峡谷溯溪

三个 mock 文件中的图片 URL 只作为初始化内容来源。正式数据应通过媒体上传接口获得最终 URL;不要把 mock 文件中的远程图片地址当成图片存储协议。

图片与素材

Admin UI 使用现有素材上传接口获取图片 URL:

POST /api/admin/media-assets/upload

建议首页内容使用 group=home,上传成功后将返回的 url 写入对应的 image 字段。接口只保存 URL,不接受 base64,也不创建 ProductImage 或商品图片关联。

Admin UI 对接要求

  1. 进入首页内容管理时分别请求三个列表接口,按 sortOrder 渲染对应分组。
  2. 体验推荐表单维护 badge、category、title、englishTitle、image 和 demandKeyword。
  3. 团队共创表单维护 tag、title、description、image 和 demandKeyword。
  4. 极境视界表单维护 title、image 和 demandKeyword。
  5. 三类资源都提供启用/停用、编辑、删除和上移/下移操作;排序时提交完整 ID 列表。
  6. 每次变更成功后以接口返回的记录或列表更新本地状态,不直接假设本地修改已经保存。
  7. 删除前要求二次确认;删除成功后接受服务端返回的重新排序结果。
  8. 处理 401、404、409、422 和 5xx,保存、上传和排序进行中禁用重复提交。
  9. 不在首页表单中出现 Product ID、ProductImage ID、价格、库存、订单或预订字段。
  10. 预览点击行为使用 demandKeyword;该字段为空时禁止提交,而不是由前端猜测或拼接商品标识。

建议的 Admin UI API 封装函数:

getHomeExperiences();
createHomeExperience(input: HomeExperienceCreate);
updateHomeExperience(experienceId: string, input: HomeExperiencePatch);
deleteHomeExperience(experienceId: string);
reorderHomeExperiences(itemIds: string[]);

getHomeTeamBuildings();
createHomeTeamBuilding(input: HomeTeamBuildingCreate);
updateHomeTeamBuilding(teamBuildingId: string, input: HomeTeamBuildingPatch);
deleteHomeTeamBuilding(teamBuildingId: string);
reorderHomeTeamBuildings(itemIds: string[]);

getHomeWildArchives();
createHomeWildArchive(input: HomeWildArchiveCreate);
updateHomeWildArchive(archiveId: string, input: HomeWildArchivePatch);
deleteHomeWildArchive(archiveId: string);
reorderHomeWildArchives(itemIds: string[]);

当前首页的“查看更多”按钮固定跳转需求关键词“极境视界”,不属于 HomeWildArchive 记录字段;如果未来需要后台配置该按钮,应另行增加首页 CTA 配置契约。

前后台数据边界

  • Admin API 返回启用和停用的完整记录,供管理端维护。
  • 未来 Public API 只返回已发布且启用的首页内容;Public API 的响应字段应与本契约的渲染字段兼容,但不应暴露 createdAt、updatedAt 等管理元数据。
  • MiniAPP 接入时再同步更新 src/lib/types.ts、src/lib/data.ts、首页组件和 docs/public-api.md;本次文档不改变现有 mock 消费路径。
  • 后端不得把 demandKeyword 解析成 Product 或订单关联;如需线路、详情或预订能力,应另立领域契约。

后端落地边界

本契约落地时需要由 WonderQ-Admin 补充对应 ORM 模型、迁移、schema、路由、序列化和审计日志;由 WonderQ-Admin-UI 补充 API 类型、请求封装、首页内容列表、表单、图片上传和排序交互。当前后端没有 /api/admin/home/* 路由,Admin UI 也未接入这三类首页数据。

相关文档: