diff --git a/.gitignore b/.gitignore
index 2b3446a..3d379e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
node_modules/
dist/
-docs/
apps/*/dist/
.env
.env.local
diff --git a/AGENTS.md b/AGENTS.md
index 121f5d8..0514fe5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -268,7 +268,7 @@ yarn dev:mp-weixin
- TypeScript 项目使用 strict 模式,新增代码应有明确类型,避免 `any`。
- `WonderQ-MiniAPP` 使用 Vue 3 SFC、`
diff --git a/WonderQ-MiniAPP/src/pages/detail/components/DetailHero.vue b/WonderQ-MiniAPP/src/pages/detail/components/DetailHero.vue
new file mode 100644
index 0000000..e9df33a
--- /dev/null
+++ b/WonderQ-MiniAPP/src/pages/detail/components/DetailHero.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+ {{ presentation.eyebrow }}
+
+
+ {{ presentation.duration }}
+
+
+
+
+
+
+
diff --git a/WonderQ-MiniAPP/src/pages/detail/components/DetailInfoCard.vue b/WonderQ-MiniAPP/src/pages/detail/components/DetailInfoCard.vue
new file mode 100644
index 0000000..ebea96e
--- /dev/null
+++ b/WonderQ-MiniAPP/src/pages/detail/components/DetailInfoCard.vue
@@ -0,0 +1,56 @@
+
+
+
+
+ {{ title }}
+ {{ eyebrow }}
+
+
+
+ {{
+ paragraph }}
+
+
+
+
+
+ {{ item }}
+
+
+
+
+
+ 费用包含
+
+ ✓ {{ item
+ }}
+
+
+
+ 费用不含
+
+ × {{ item
+ }}
+
+
+
+
+
+ 暂无评价
+ 完成一次旅行后,欢迎留下你的体验
+
+
+
+
+
diff --git a/WonderQ-MiniAPP/src/pages/detail/components/DetailMediaGallery.vue b/WonderQ-MiniAPP/src/pages/detail/components/DetailMediaGallery.vue
new file mode 100644
index 0000000..ca62ce3
--- /dev/null
+++ b/WonderQ-MiniAPP/src/pages/detail/components/DetailMediaGallery.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WonderQ-MiniAPP/src/pages/detail/components/DetailOverviewCard.vue b/WonderQ-MiniAPP/src/pages/detail/components/DetailOverviewCard.vue
new file mode 100644
index 0000000..70b20b5
--- /dev/null
+++ b/WonderQ-MiniAPP/src/pages/detail/components/DetailOverviewCard.vue
@@ -0,0 +1,49 @@
+
+
+ {{ presentation.title }}
+
+
+
+ 参考起价
+
+ ¥{{ formatWan(product.price) }}
+ 万起/人
+
+
+
+
+
+
+ {{ item.label }}
+ {{ item.value }}
+
+
+
+
+
+
diff --git a/WonderQ-MiniAPP/src/pages/detail/components/detailPresentation.ts b/WonderQ-MiniAPP/src/pages/detail/components/detailPresentation.ts
new file mode 100644
index 0000000..11a3f6f
--- /dev/null
+++ b/WonderQ-MiniAPP/src/pages/detail/components/detailPresentation.ts
@@ -0,0 +1,93 @@
+import { stripTitle } from "@/lib/data";
+import type { Product } from "@/lib/types";
+
+export type DetailPresentation = {
+ eyebrow: string;
+ duration: string;
+ title: string;
+ subtitle: string;
+ intro: string;
+ highlights: string[];
+ included: string[];
+ excluded: string[];
+ notes: string[];
+ gallery: string[];
+};
+
+const fallbackGallery = [
+ "https://www.zurnal24.si/media/img/5e/d5/9526a56dba168aa136f3.jpeg",
+ "https://genk.mediacdn.vn/139269124445442048/2024/4/27/10-23-sinkhole-1714189653945948438879.jpg",
+ "https://p2.cri.cn/M00/89/21/rBABC2aHnWeACxj5AAAAAAAAAAA159.1000x566.jpg",
+ "https://dimg04.c-ctrip.com/images/0EQ5712000ca7t504EC0E_W_640_10000.jpg?proc=autoorient",
+];
+
+function getDuration(title: string) {
+ return title.match(/\d+天\d+晚/)?.[0] ?? "5天4晚";
+}
+
+function getTextBlocks(product: Product) {
+ return (product.detailSections ?? [])
+ .flatMap((section) => section.blocks)
+ .filter(
+ (block): block is { type: "text"; text: string } => block.type === "text",
+ )
+ .map((block) => block.text.trim())
+ .filter(Boolean);
+}
+
+export function createDetailPresentation(product: Product): DetailPresentation {
+ const title = stripTitle(product.title);
+ const combinedText = `${product.title} ${product.summary ?? ""}`;
+ const isCaveRoute =
+ combinedText.includes("洞") || combinedText.includes("探险");
+ const detailTexts = getTextBlocks(product);
+ const apiImages = (product.images ?? [])
+ .slice()
+ .sort((left, right) => left.sortOrder - right.sortOrder)
+ .map((image) => image.url.trim())
+ .filter(Boolean);
+
+ return {
+ eyebrow: product.tags[0] || "玩法推荐",
+ duration: getDuration(product.title),
+ title: isCaveRoute ? "地心探险大环线" : title,
+ subtitle:
+ product.subtitle || `${product.destinationName || "贵州"}·小包团路线`,
+ intro:
+ detailTexts[0] ||
+ product.summary ||
+ "沿着贵州山地的自然纹理深入探索,把核心景观、在地体验和轻户外节奏安排在一条线路里。",
+ highlights: isCaveRoute
+ ? [
+ "深入喀斯特洞穴与地下河,安排专业向导陪同",
+ "小团出行,按同行人的体力和兴趣灵活调整",
+ "山野咖啡与自然景观穿插,留出松弛的停留时间",
+ "行程前由服务管家确认天气、装备和接送细节",
+ ]
+ : [
+ "核心景观串联,减少无效往返和重复换乘",
+ "小团出行,按同行人的节奏灵活调整",
+ "在地体验与舒适住宿合理衔接",
+ "行程前由服务管家确认天气、装备和接送细节",
+ ],
+ included: [
+ "行程内用车与接送服务",
+ "列明景点门票和体验项目",
+ "服务管家行前确认与途中跟进",
+ "行程内住宿及方案中注明的服务",
+ ],
+ excluded: [
+ "往返大交通及个人消费",
+ "未列明餐食和自选体验",
+ "因个人原因产生的额外费用",
+ ],
+ notes: [
+ "贵州多山多雨,请准备防滑鞋、轻便雨具和薄外套。",
+ "溶洞、漂流、徒步等体验会根据天气和同行人体力适当调整。",
+ "页面价格为参考起价,最终方案以出行日期、人数和资源确认结果为准。",
+ ],
+ gallery: Array.from(
+ new Set([product.image, ...apiImages, ...fallbackGallery]),
+ ).slice(0, 6),
+ };
+}
diff --git a/WonderQ-MiniAPP/src/pages/detail/index.vue b/WonderQ-MiniAPP/src/pages/detail/index.vue
new file mode 100644
index 0000000..92279d7
--- /dev/null
+++ b/WonderQ-MiniAPP/src/pages/detail/index.vue
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/README.md b/docs/README.md
index cdaabb6..01bab8f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -9,15 +9,21 @@
1. `backend-api-service.md`
2. `backend-plan.md`
3. `admin-api-requirements.md`
-4. `module-config-api.md`
-5. `public-api.md`
+4. `wanfa-api.md`
+5. `concierge-api.md`
+6. `detail-api.md`
+7. `module-config-api.md`
+8. `public-api.md`
管理前端开发:
1. `integration-workflow.md`
2. `admin-api-requirements.md`
-3. `module-config-api.md`
-4. `development-status.md`
+3. `wanfa-api.md`
+4. `concierge-api.md`
+5. `detail-api.md`
+6. `module-config-api.md`
+7. `development-status.md`
MiniAPP 前台开发:
@@ -36,12 +42,18 @@ MiniAPP 前台开发:
| `backend-plan.md` | 当前 FastAPI 后端定位、业务模块、近期优先级和安全部署原则 | 后端 |
| `admin-api-requirements.md` | Admin UI 必需的 Admin API 主契约 | 后端、管理前端 |
| `module-config-api.md` | 页面模块配置 CRUD 的唯一细节契约 | 后端、管理前端 |
+| `wanfa-api.md` | 玩法分类和路线管理 API 的补充契约 | 后端、管理前端 |
+| `concierge-api.md` | 管家顾问资料管理 API 的补充契约 | 后端、管理前端 |
+| `detail-api.md` | 详情展示内容管理 API 的补充契约 | 后端、管理前端 |
| `public-api.md` | MiniAPP 对接后端的 Public API 契约 | 后端、MiniAPP |
## 文档边界
- `public-api.md` 是 MiniAPP 对接后端的唯一 Public API 契约。
- `admin-api-requirements.md` 是 Admin UI 对接后端的主契约。
+- `wanfa-api.md` 是玩法分类和路线管理的 Admin API 补充契约。
+- `concierge-api.md` 是管家顾问资料管理的 Admin API 补充契约。
+- `detail-api.md` 是详情展示内容管理的 Admin API 补充契约。
- `module-config-api.md` 是页面模块 CRUD 细节的唯一权威文档。
- `integration-workflow.md` 只写联调流程,不重复接口字段。
- `development-status.md` 只记录当前状态,不替代测试结果。
@@ -51,4 +63,4 @@ MiniAPP 前台开发:
- 文档示例不得写入真实 Token、JWT secret、客服链接、企业 ID、手机号或生产环境变量值。
- `.env`、`.env.local` 和生产配置不进入文档目录。
-- 涉及重置数据、发布、回滚、迁移或生产操作的文档,需要明确风险和验证方式。
\ No newline at end of file
+- 涉及重置数据、发布、回滚、迁移或生产操作的文档,需要明确风险和验证方式。
diff --git a/docs/admin-api-requirements.md b/docs/admin-api-requirements.md
index e09bb68..be6fc8e 100644
--- a/docs/admin-api-requirements.md
+++ b/docs/admin-api-requirements.md
@@ -2,6 +2,12 @@
本文档描述 `WonderQ-Admin-UI` 当前使用的 Admin API。接口负责站点内容维护、素材、发布和需求线索管理。
+玩法分类和路线管理的字段、嵌套路由、排序与删除约束见 [wanfa-api.md](./wanfa-api.md)。该文档是本主契约的玩法领域补充,适用端为 `WonderQ-Admin` 和 `WonderQ-Admin-UI`。
+
+管家顾问资料管理的字段、图片、排序与删除约束见 [concierge-api.md](./concierge-api.md)。该文档是本主契约的管家领域补充,适用端为 `WonderQ-Admin` 和 `WonderQ-Admin-UI`。
+
+详情展示内容的字段、图片、排序与商品领域隔离约束见 [detail-api.md](./detail-api.md)。该文档是本主契约的详情领域补充,适用端为 `WonderQ-Admin` 和 `WonderQ-Admin-UI`。
+
## 通用约定
- API 前缀:`/api/admin`。
diff --git a/docs/concierge-api.md b/docs/concierge-api.md
new file mode 100644
index 0000000..5754089
--- /dev/null
+++ b/docs/concierge-api.md
@@ -0,0 +1,301 @@
+# 管家管理 Admin API
+
+> 适用端:`WonderQ-Admin`、`WonderQ-Admin-UI`。
+>
+> 状态:待实现契约。本文件参考 `WonderQ-MiniAPP/src/pages/concierge/components/conciergeTypes.ts` 定义管家顾问资料,以及管理端需要的查询、维护和排序接口。它不是 MiniAPP Public API 文档。
+
+## 领域边界
+
+管家管理只维护管家顾问卡片资料:
+
+- 头像、姓名和职位。
+- 服务详情条目,包括图标和说明文案。
+- 添加管家时展示的二维码。
+- 顾问启用状态和展示顺序。
+
+本接口不负责:
+
+- 需求线索、客户、客服会话或登录。
+- 订单、预订、商品和商品图片关联。
+- 管家页面 Hero 文案和服务原则内容。
+
+当前 `WonderQ-MiniAPP/src/pages/concierge/index.vue` 中的 Hero、原则和顾问数据仍是本地静态内容;本契约落地后,Admin UI 维护顾问数据,MiniAPP 再通过独立的 Public API 消费已发布内容。
+
+## 接口清单
+
+API 前缀为 `/api/admin`,除登录接口外均需要后台 JWT。
+
+| 方法 | 路径 | 用途 |
+| --- | --- | --- |
+| `GET` | `/api/admin/concierge/advisors` | 获取全部管家顾问 |
+| `POST` | `/api/admin/concierge/advisors` | 新增管家顾问 |
+| `PATCH` | `/api/admin/concierge/advisors/{advisorId}` | 编辑管家顾问 |
+| `DELETE` | `/api/admin/concierge/advisors/{advisorId}` | 删除管家顾问 |
+| `PATCH` | `/api/admin/concierge/advisors/reorder` | 调整管家顾问展示顺序 |
+
+## 通用约定
+
+- 请求和响应使用 JSON,字段使用 camelCase。
+- 所有管理接口需要 `Authorization: Bearer `。
+- `GET` 默认返回启用和停用的全部顾问,按 `sortOrder` 升序返回,供管理端完整维护。
+- 创建、编辑、删除和排序成功后写入审计日志,再提交事务。
+- 变更接口返回最新顾问对象;排序接口返回排序后的 `items`。
+- ID 由后端生成并作为非空字符串返回。
+- 空列表返回 `[]`,不能返回 `null` 或省略字段。
+- 失败响应沿用 Admin API 约定,包含 `message`、`code` 和可选的 `details`。
+
+## 数据类型
+
+`conciergeTypes.ts` 是 MiniAPP 渲染模型,当前没有 `id`、`isActive` 和 `sortOrder`。为了支持 Admin UI 编辑、删除和排序,Admin API 在渲染字段之外增加管理元数据;MiniAPP Public API 适配时可以移除这些管理字段。
+
+```ts
+type ConciergeDetail = {
+ icon: string;
+ label: string;
+};
+
+type ConciergeAdvisorContent = {
+ avatar: string;
+ name: string;
+ role: string;
+ details: ConciergeDetail[];
+ qrImage: string;
+};
+
+type ConciergeAdvisorRecord = ConciergeAdvisorContent & {
+ id: string;
+ isActive: boolean;
+ sortOrder: number;
+ createdAt: string;
+ updatedAt: string;
+};
+
+type ConciergeAdvisorCreate = {
+ avatar: string;
+ name: string;
+ role: string;
+ details: ConciergeDetail[];
+ qrImage: string;
+ isActive?: boolean;
+ sortOrder?: number;
+};
+
+type ConciergeAdvisorPatch = Partial;
+
+type ConciergeAdvisorListResponse = {
+ advisors: ConciergeAdvisorRecord[];
+};
+
+type ConciergeReorderRequest = {
+ itemIds: string[];
+};
+```
+
+## 字段约束
+
+| 字段 | 类型 | 必填 | 约束和用途 |
+| --- | --- | --- | --- |
+| `id` | `string` | 响应必填 | 顾问稳定标识,由后端生成。Admin UI 不使用姓名作为编辑、删除或 React `key`。 |
+| `avatar` | `string` | 是 | 顾问头像 URL,前台按圆形头像展示。 |
+| `name` | `string` | 是 | 顾问姓名,去除首尾空白后不得为空。 |
+| `role` | `string` | 是 | 顾问职位或英文职称,去除首尾空白后不得为空。 |
+| `details` | `ConciergeDetail[]` | 是 | 服务详情列表,保留数组顺序;允许为空数组。 |
+| `details[].icon` | `string` | 是 | `uni-icons` 使用的图标名称,例如 `calendar`、`navigate`。 |
+| `details[].label` | `string` | 是 | 服务详情文案,去除首尾空白后不得为空。 |
+| `qrImage` | `string` | 是 | 添加管家时展示的二维码图片 URL。接口只保存图片 URL,不保存二维码原始 payload。 |
+| `isActive` | `boolean` | 响应必填 | 是否在已发布前台内容中展示,创建默认 `true`。 |
+| `sortOrder` | `number` | 响应必填 | 非负整数,数值越小越靠前;创建时未传则追加到末尾。 |
+| `createdAt` | `string` | 响应必填 | ISO 8601 创建时间。 |
+| `updatedAt` | `string` | 响应必填 | ISO 8601 最后更新时间。 |
+
+头像和二维码应使用已上传素材的最终 URL。服务端应校验必填文本、URL 格式、`details` 数组结构和 `sortOrder` 非负整数;具体文本最大长度由后端 schema 统一定义,并同步到 Admin UI 表单校验。
+
+## 接口详情
+
+### 获取全部顾问
+
+```http
+GET /api/admin/concierge/advisors
+Authorization: Bearer
+```
+
+成功响应:
+
+```json
+{
+ "advisors": [
+ {
+ "id": "advisor-001",
+ "avatar": "https://example.test/assets/advisor-avatar.jpg",
+ "name": "示例顾问",
+ "role": "SENIOR TRAVEL ADVISOR",
+ "details": [
+ { "icon": "calendar", "label": "服务经验:8年" },
+ { "icon": "navigate", "label": "擅长领域:自然探索" }
+ ],
+ "qrImage": "https://example.test/assets/advisor-qr.png",
+ "isActive": true,
+ "sortOrder": 0,
+ "createdAt": "2026-01-01T00:00:00Z",
+ "updatedAt": "2026-01-01T00:00:00Z"
+ }
+ ]
+}
+```
+
+### 新增顾问
+
+```http
+POST /api/admin/concierge/advisors
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求:
+
+```json
+{
+ "avatar": "https://example.test/assets/advisor-avatar.jpg",
+ "name": "示例顾问",
+ "role": "SENIOR TRAVEL ADVISOR",
+ "details": [
+ { "icon": "calendar", "label": "服务经验:8年" },
+ { "icon": "navigate", "label": "擅长领域:自然探索" }
+ ],
+ "qrImage": "https://example.test/assets/advisor-qr.png",
+ "isActive": true
+}
+```
+
+成功返回 `201` 和新建的 `ConciergeAdvisorRecord`。未传 `sortOrder` 时追加到当前最大顺序之后。
+
+### 编辑顾问
+
+```http
+PATCH /api/admin/concierge/advisors/{advisorId}
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求体为 `ConciergeAdvisorPatch`,只更新提交的字段。例如只更新服务详情:
+
+```json
+{
+ "details": [
+ { "icon": "calendar", "label": "服务经验:10年" },
+ { "icon": "navigate", "label": "擅长领域:亲子与自然探索" }
+ ]
+}
+```
+
+成功返回更新后的 `ConciergeAdvisorRecord`。不存在的顾问返回 `404 CONCIERGE_ADVISOR_NOT_FOUND`。
+
+### 删除顾问
+
+```http
+DELETE /api/admin/concierge/advisors/{advisorId}
+Authorization: Bearer
+```
+
+删除成功返回:
+
+```json
+{ "id": "advisor-001" }
+```
+
+删除后应重新规范化剩余顾问的 `sortOrder`,从 `0` 开始连续编号。若业务要求至少保留一名启用顾问,服务端在删除最后一名启用顾问时返回 `409 CONCIERGE_LAST_ACTIVE_ADVISOR`,否则允许删除并由前台处理空状态。
+
+### 调整顾问顺序
+
+```http
+PATCH /api/admin/concierge/advisors/reorder
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求必须完整包含当前全部顾问 ID,不能重复:
+
+```json
+{ "itemIds": ["advisor-002", "advisor-001"] }
+```
+
+成功响应:
+
+```json
+{ "items": [] }
+```
+
+其中 `items` 为更新 `sortOrder` 后的 `ConciergeAdvisorRecord[]`。缺少 ID、包含未知 ID 或出现重复 ID 时返回 `400 CONCIERGE_REORDER_INVALID`。
+
+## 图片与素材
+
+Admin UI 使用现有素材上传接口获取图片 URL:
+
+```http
+POST /api/admin/media-assets/upload
+```
+
+建议管家页面上传时使用 `group=concierge`,头像和二维码分别将返回的 `url` 写入 `avatar` 和 `qrImage`。API 不接受 base64 图片,也不在管家表中复制图片二进制内容。
+
+二维码必须作为图片 URL 保存,不能把真实个人微信号、手机号或二维码 payload 写入文档、前端类型或接口日志。
+
+## Admin UI 对接要求
+
+Admin UI 应按以下方式调用:
+
+1. 进入管家页面时调用 `GET /api/admin/concierge/advisors`,按 `sortOrder` 渲染全部顾问。
+2. 列表展示头像、姓名、职位、详情数量、启用状态和编辑/删除操作。
+3. 新增和编辑表单维护头像、姓名、职位、详情列表、二维码和启用状态。
+4. `details` 使用可增删的重复字段编辑器,提交时保留用户排列顺序,不把多个详情拼成一个字符串。
+5. 上移或下移顾问时提交完整顾问 ID 列表,不直接修改本地 `sortOrder` 后假设保存成功。
+6. 删除前要求二次确认;处理最后一名启用顾问的 `409` 提示。
+7. 处理 `401`、`404`、`409`、`422` 和 `5xx`,保存或排序请求进行中禁用重复提交。
+8. 图片上传失败时不得提交旧草稿中的空 URL;表单应保留其他已填写字段,允许用户重试上传。
+
+建议的 Admin UI API 封装函数:
+
+```ts
+getConciergeAdvisors();
+createConciergeAdvisor(input: ConciergeAdvisorCreate);
+updateConciergeAdvisor(advisorId: string, input: ConciergeAdvisorPatch);
+deleteConciergeAdvisor(advisorId: string);
+reorderConciergeAdvisors(itemIds: string[]);
+```
+
+## 与当前 MiniAPP 类型的映射
+
+当前 `conciergeTypes.ts` 的 `ConciergeAdvisor` 仅包含前台渲染字段:
+
+```ts
+type ConciergeAdvisor = {
+ avatar: string;
+ name: string;
+ role: string;
+ details: Array<{ icon: string; label: string }>;
+ qrImage: string;
+};
+```
+
+Admin API 返回的 `ConciergeAdvisorRecord` 可以通过以下方式映射为前台模型:
+
+```ts
+const advisor: ConciergeAdvisor = {
+ avatar: record.avatar,
+ name: record.name,
+ role: record.role,
+ details: record.details,
+ qrImage: record.qrImage,
+};
+```
+
+只有 `isActive === true` 的记录进入已发布 Public 内容;`id`、`sortOrder`、`createdAt` 和 `updatedAt` 属于管理元数据,不应要求前台组件展示。
+
+## 后端落地边界
+
+本契约落地时需要由 `WonderQ-Admin` 补充对应 ORM 模型、迁移、schema、路由、序列化和审计日志;由 `WonderQ-Admin-UI` 补充 API 类型、请求封装、管家列表、表单和排序交互。当前后端没有 `/api/admin/concierge/*` 路由,Admin UI 的管家入口仍是空态,MiniAPP 顾问数据仍在 `index.vue` 中静态定义。
+
+相关文档:
+
+- [Admin API 主契约](./admin-api-requirements.md)
+- [玩法管理 Admin API](./wanfa-api.md)
+- [管家数据类型](../WonderQ-MiniAPP/src/pages/concierge/components/conciergeTypes.ts)
diff --git a/docs/detail-api.md b/docs/detail-api.md
new file mode 100644
index 0000000..b78edb2
--- /dev/null
+++ b/docs/detail-api.md
@@ -0,0 +1,294 @@
+# 详情展示管理 Admin API
+
+> 适用端:`WonderQ-Admin`、`WonderQ-Admin-UI`。
+>
+> 状态:待实现契约。本文件参考 `WonderQ-MiniAPP/src/pages/detail/components/detailPresentation.ts` 定义详情页展示数据。当前 `detailPresentation.ts` 仍依赖已移除的 `Product` 类型,后端也没有详情管理接口;本契约采用与商品领域解耦的详情展示模型,不恢复 Product、ProductImage 或订单关联。
+
+## 领域边界
+
+详情管理只维护详情页可编辑的展示内容:
+
+- 详情页识别键、标题眉标、出行时长和标题文案。
+- 详情介绍、行程亮点、费用包含、费用不含和注意事项。
+- 详情页图片画廊及图片顺序。
+- 启用状态和详情列表顺序。
+
+本接口不负责:
+
+- 商品、商品价格、商品库存或商品详情表。
+- Product、ProductImage 或任何商品外键。
+- 订单、预订、收藏、评价或线索。
+- 详情页底部的电话、管家联系和预订动作。
+
+`key` 是详情展示内容自己的稳定业务键,不得设计为 Product ID 外键。详情页如何从玩法、页面入口或其他前台上下文定位 `key`,由前台导航契约另行约定。
+
+## 与 `detailPresentation.ts` 的关系
+
+`detailPresentation.ts` 当前是前台展示适配器,不是持久化模型:
+
+- `eyebrow`、`duration`、`title`、`subtitle`、`intro`、`highlights`、`included`、`excluded`、`notes`、`gallery` 组成最终展示对象。
+- 当前实现从 `Product` 的标题、摘要、标签、详情区块和图片数组推导部分字段。
+- 当前实现对洞穴/探险路线生成另一组固定亮点,并使用固定费用说明和注意事项。
+- 当前实现会将主图、接口图片和 fallback 图片去重后截取前 6 张。
+
+新的 Admin API 应直接维护最终展示字段;Admin UI 不应复刻这些推导逻辑,也不应依赖已移除的 Product 字段。
+
+## 接口清单
+
+API 前缀为 `/api/admin`,除登录接口外均需要后台 JWT。
+
+| 方法 | 路径 | 用途 |
+| --- | --- | --- |
+| `GET` | `/api/admin/details` | 获取全部详情展示配置 |
+| `GET` | `/api/admin/details/{detailId}` | 获取单个详情展示配置 |
+| `POST` | `/api/admin/details` | 新增详情展示配置 |
+| `PATCH` | `/api/admin/details/{detailId}` | 编辑详情展示配置 |
+| `DELETE` | `/api/admin/details/{detailId}` | 删除详情展示配置 |
+| `PATCH` | `/api/admin/details/reorder` | 调整详情展示配置顺序 |
+
+## 通用约定
+
+- 请求和响应使用 JSON,字段使用 camelCase。
+- 所有管理接口需要 `Authorization: Bearer `。
+- `GET /details` 返回启用和停用的全部配置,按 `sortOrder` 升序返回。
+- 创建、编辑、删除和排序成功后写入审计日志,再提交事务。
+- 创建和编辑返回最新详情对象;排序接口返回排序后的 `items`。
+- ID 由后端生成并作为非空字符串返回;`key` 由调用方提供并保持稳定。
+- 空列表返回 `[]`,不能返回 `null` 或省略字段。
+- 失败响应沿用 Admin API 约定,包含 `message`、`code` 和可选的 `details`。
+
+## 数据类型
+
+以下内容字段与 `DetailPresentation` 保持兼容,管理端补充 `id`、`key`、状态和审计时间:
+
+```ts
+type DetailPresentation = {
+ eyebrow: string;
+ duration: string;
+ title: string;
+ subtitle: string;
+ intro: string;
+ highlights: string[];
+ included: string[];
+ excluded: string[];
+ notes: string[];
+ gallery: string[];
+};
+
+type DetailRecord = DetailPresentation & {
+ id: string;
+ key: string;
+ isActive: boolean;
+ sortOrder: number;
+ createdAt: string;
+ updatedAt: string;
+};
+
+type DetailCreate = DetailPresentation & {
+ key: string;
+ isActive?: boolean;
+ sortOrder?: number;
+};
+
+type DetailPatch = Partial;
+
+type DetailListResponse = {
+ details: DetailRecord[];
+};
+
+type DetailReorderRequest = {
+ itemIds: string[];
+};
+```
+
+## 字段约束
+
+| 字段 | 类型 | 必填 | 约束和用途 |
+| --- | --- | --- | --- |
+| `id` | `string` | 响应必填 | 后端生成的记录 ID,仅供管理端识别记录。 |
+| `key` | `string` | 是 | 详情展示稳定键;建议使用小写字母、数字和中划线,例如 `classic-panorama`。不得关联 Product 表。 |
+| `eyebrow` | `string` | 是 | 详情页顶部眉标,例如“玩法推荐”。 |
+| `duration` | `string` | 是 | 展示用时长,例如“5天4晚”;接口保存最终文案,不要求前端从标题正则提取。 |
+| `title` | `string` | 是 | 详情页主标题。 |
+| `subtitle` | `string` | 是 | 详情页副标题或目的地说明。 |
+| `intro` | `string` | 是 | “详细介绍”区域的主介绍文案。 |
+| `highlights` | `string[]` | 是 | “行程亮点”列表,保留数组顺序。 |
+| `included` | `string[]` | 是 | “费用包含”列表,保留数组顺序。 |
+| `excluded` | `string[]` | 是 | “费用不含”列表,保留数组顺序。 |
+| `notes` | `string[]` | 是 | “注意事项”列表,保留数组顺序。 |
+| `gallery` | `string[]` | 是 | 详情图片 URL 列表,按展示顺序返回;建议最多 6 张以匹配当前前台逻辑。 |
+| `isActive` | `boolean` | 响应必填 | 是否进入已发布前台内容,创建默认 `true`。 |
+| `sortOrder` | `number` | 响应必填 | 非负整数,数值越小越靠前;创建时未传则追加到末尾。 |
+| `createdAt` | `string` | 响应必填 | ISO 8601 创建时间。 |
+| `updatedAt` | `string` | 响应必填 | ISO 8601 最后更新时间。 |
+
+服务端应校验 `key` 唯一、文本字段去除首尾空白后不为空、数组元素为非空字符串、`gallery` 为 URL 列表、`sortOrder` 为非负整数。具体文本最大长度由后端 schema 统一定义,并同步到 Admin UI 表单校验。
+
+## 接口详情
+
+### 获取详情列表
+
+```http
+GET /api/admin/details
+Authorization: Bearer
+```
+
+成功响应:
+
+```json
+{
+ "details": [
+ {
+ "id": "detail-001",
+ "key": "classic-panorama",
+ "eyebrow": "玩法推荐",
+ "duration": "5天4晚",
+ "title": "经典贵州全景",
+ "subtitle": "贵州·瀑布、苗寨、古城与山地风光",
+ "intro": "沿着贵州山地的自然纹理深入探索。",
+ "highlights": ["核心景观串联", "小团出行,按同行人节奏调整"],
+ "included": ["行程内用车与接送服务"],
+ "excluded": ["往返大交通及个人消费"],
+ "notes": ["贵州多山多雨,请准备防滑鞋和轻便雨具。"],
+ "gallery": ["https://example.test/assets/detail-01.jpg"],
+ "isActive": true,
+ "sortOrder": 0,
+ "createdAt": "2026-01-01T00:00:00Z",
+ "updatedAt": "2026-01-01T00:00:00Z"
+ }
+ ]
+}
+```
+
+### 获取单个详情
+
+```http
+GET /api/admin/details/{detailId}
+Authorization: Bearer
+```
+
+成功返回单个 `DetailRecord`。记录不存在返回 `404 DETAIL_NOT_FOUND`。
+
+### 新增详情
+
+```http
+POST /api/admin/details
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求体为 `DetailCreate`。成功返回 `201` 和新建的 `DetailRecord`;未传 `sortOrder` 时追加到当前列表末尾。
+
+### 编辑详情
+
+```http
+PATCH /api/admin/details/{detailId}
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求体为 `DetailPatch`,只更新提交的字段。修改 `key` 时仍须保证全局唯一。成功返回更新后的 `DetailRecord`;记录不存在返回 `404 DETAIL_NOT_FOUND`,`key` 冲突返回 `409 DETAIL_KEY_EXISTS`。
+
+### 删除详情
+
+```http
+DELETE /api/admin/details/{detailId}
+Authorization: Bearer
+```
+
+成功返回:
+
+```json
+{ "id": "detail-001" }
+```
+
+删除后应重新规范化剩余记录的 `sortOrder`,从 `0` 开始连续编号。详情记录没有 Product、订单或线索外键,因此删除不触发跨领域级联操作。
+
+### 调整详情顺序
+
+```http
+PATCH /api/admin/details/reorder
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求必须完整包含当前全部详情 ID,不能重复:
+
+```json
+{ "itemIds": ["detail-002", "detail-001"] }
+```
+
+成功返回:
+
+```json
+{ "items": [] }
+```
+
+其中 `items` 为更新 `sortOrder` 后的 `DetailRecord[]`。缺少 ID、包含未知 ID 或出现重复 ID 时返回 `400 DETAIL_REORDER_INVALID`。
+
+## 图片与素材
+
+Admin UI 使用现有素材上传接口获取图片 URL:
+
+```http
+POST /api/admin/media-assets/upload
+```
+
+建议详情页图片使用 `group=detail`,将返回的 `url` 按用户排列顺序写入 `gallery`。接口只保存图片 URL,不创建 ProductImage 表或商品图片关联。
+
+当前 `detailPresentation.ts` 的 fallback 图片属于前台兜底逻辑。Admin API 正式接入后,Admin UI 不应把 fallback 图片自动写入数据库;应由运营人员明确上传和排序详情图片。
+
+## Admin UI 对接要求
+
+Admin UI 应按以下方式调用:
+
+1. 进入详情管理页时调用 `GET /api/admin/details`,按 `sortOrder` 渲染详情列表。
+2. 新增和编辑表单维护 `key`、眉标、时长、标题、副标题、介绍和四组列表文案。
+3. `highlights`、`included`、`excluded`、`notes` 使用可增删的重复字段编辑器,提交时保留数组顺序,不拼接成换行字符串。
+4. 使用图片上传接口维护 `gallery`,支持新增、删除和调整图片顺序。
+5. 上移或下移详情时提交完整详情 ID 列表,不直接修改本地 `sortOrder` 后假设保存成功。
+6. 删除前要求二次确认;删除成功后以接口返回或重新查询的数据更新列表。
+7. 处理 `401`、`404`、`409`、`422` 和 `5xx`,保存、上传或排序进行中禁用重复提交。
+8. 详情编辑器不得出现 Product ID、ProductImage ID、库存、订单或预订字段。
+
+建议的 Admin UI API 封装函数:
+
+```ts
+getDetails();
+getDetail(detailId: string);
+createDetail(input: DetailCreate);
+updateDetail(detailId: string, input: DetailPatch);
+deleteDetail(detailId: string);
+reorderDetails(itemIds: string[]);
+```
+
+## 与前台展示模型的映射
+
+Admin API 返回的 `DetailRecord` 可以映射为 `DetailPresentation`:
+
+```ts
+const presentation: DetailPresentation = {
+ eyebrow: record.eyebrow,
+ duration: record.duration,
+ title: record.title,
+ subtitle: record.subtitle,
+ intro: record.intro,
+ highlights: record.highlights,
+ included: record.included,
+ excluded: record.excluded,
+ notes: record.notes,
+ gallery: record.gallery,
+};
+```
+
+接入时应优先使用接口已保存的最终文案和图片顺序,不再依赖 `stripTitle`、标题时长正则、洞穴路线分支或 fallbackGallery 生成同一字段。
+
+## 后端落地边界
+
+本契约落地时需要由 `WonderQ-Admin` 补充对应 ORM 模型、迁移、schema、路由、序列化和审计日志;由 `WonderQ-Admin-UI` 补充 API 类型、请求封装、详情列表、编辑器、图片管理和排序交互。当前后端没有 `/api/admin/details` 路由,Admin UI 没有详情管理入口,`detailPresentation.ts` 也不是可直接作为后端契约的完整类型来源。
+
+相关文档:
+
+- [Admin API 主契约](./admin-api-requirements.md)
+- [管家管理 Admin API](./concierge-api.md)
+- [详情展示适配器](../WonderQ-MiniAPP/src/pages/detail/components/detailPresentation.ts)
diff --git a/docs/guanjia-api.md b/docs/guanjia-api.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/home-api.md b/docs/home-api.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/wanfa-api.md b/docs/wanfa-api.md
new file mode 100644
index 0000000..1fd56e8
--- /dev/null
+++ b/docs/wanfa-api.md
@@ -0,0 +1,325 @@
+# 玩法管理 Admin API
+
+> 适用端:`WonderQ-Admin`、`WonderQ-Admin-UI`。
+>
+> 状态:待实现契约。本文件参考 `WonderQ-MiniAPP/src/pages/play/components/playData.ts` 定义玩法分类和路线的数据结构,以及管理端需要的查询、维护和排序接口。它不是 MiniAPP Public API 文档。
+
+## 领域边界
+
+玩法管理只维护玩法分类和路线卡片内容:
+
+- 分类名称和展示顺序。
+- 路线标题、副标题、封面、路线数量和需求关键词。
+- 分类与路线的新增、编辑、删除和排序。
+
+玩法领域不负责:
+
+- 商品、商品详情、预订或订单。
+- 目的地实体和目的地维护。
+- 线索创建或线索跟进。
+- Product、ProductImage 或其他已移除商品关联表。
+
+`routeCount` 只是前台卡片展示数量,不是 Product 表的外键或实时关联统计。
+
+## 接口清单
+
+API 前缀为 `/api/admin`,除登录接口外均需要后台 JWT。
+
+| 方法 | 路径 | 用途 |
+| --- | --- | --- |
+| `GET` | `/api/admin/wanfa/categories` | 获取全部玩法分类及其路线 |
+| `POST` | `/api/admin/wanfa/categories` | 新增玩法分类 |
+| `PATCH` | `/api/admin/wanfa/categories/{categoryId}` | 编辑玩法分类 |
+| `DELETE` | `/api/admin/wanfa/categories/{categoryId}` | 删除玩法分类 |
+| `PATCH` | `/api/admin/wanfa/categories/reorder` | 调整玩法分类顺序 |
+| `POST` | `/api/admin/wanfa/categories/{categoryId}/routes` | 新增分类路线 |
+| `PATCH` | `/api/admin/wanfa/categories/{categoryId}/routes/{routeId}` | 编辑分类路线 |
+| `DELETE` | `/api/admin/wanfa/categories/{categoryId}/routes/{routeId}` | 删除分类路线 |
+| `PATCH` | `/api/admin/wanfa/categories/{categoryId}/routes/reorder` | 调整分类内路线顺序 |
+
+## 通用约定
+
+- 请求和响应使用 JSON,字段使用 camelCase。
+- 所有管理接口需要 `Authorization: Bearer `。
+- 创建、编辑、删除和排序成功后写入审计日志,再提交事务。
+- 变更接口返回最新变更对象;排序接口返回排序后的 `items`。
+- ID 由后端生成并作为非空字符串返回。初始化迁移时应优先保留 `playData.ts` 中已有的稳定 ID。
+- 分类和路线的数组顺序就是管理端和前台的展示顺序,接口不要求前端依赖 `sortOrder` 字段。
+- 空集合返回 `[]`,不能返回 `null` 或省略字段。
+- 失败响应沿用 Admin API 约定,包含 `message`、`code` 和可选的 `details`。
+
+## 数据类型
+
+以下类型与 `playData.ts` 保持字段兼容。管理端接口不应向前台模型强制增加商品 ID、预订 ID 或数据库关联字段。
+
+```ts
+type WanfaConfig = {
+ categories: WanfaCategory[];
+};
+
+type WanfaCategory = {
+ id: string;
+ label: string;
+ routes: WanfaRoute[];
+};
+
+type WanfaRoute = {
+ id: string;
+ title: string;
+ subtitle: string;
+ image: string;
+ routeCount: number;
+ demandKeyword: string;
+};
+
+type WanfaCategoryCreate = {
+ label: string;
+};
+
+type WanfaCategoryPatch = {
+ label?: string;
+};
+
+type WanfaRouteCreate = {
+ title: string;
+ subtitle: string;
+ image: string;
+ routeCount: number;
+ demandKeyword: string;
+};
+
+type WanfaRoutePatch = Partial;
+
+type WanfaReorderRequest = {
+ itemIds: string[];
+};
+```
+
+## 字段约束
+
+| 字段 | 类型 | 必填 | 约束和用途 |
+| --- | --- | --- | --- |
+| `category.id` | `string` | 响应必填 | 分类稳定标识,例如 `family-route`。创建时由后端生成。 |
+| `category.label` | `string` | 是 | 左侧分类显示名称,去除首尾空白后不得为空。 |
+| `category.routes` | `WanfaRoute[]` | 响应必填 | 当前分类下的路线,按展示顺序返回。 |
+| `route.id` | `string` | 响应必填 | 路线稳定标识,例如 `family-water`。创建时由后端生成。 |
+| `route.title` | `string` | 是 | 路线卡片标题,去除首尾空白后不得为空。 |
+| `route.subtitle` | `string` | 是 | 路线卡片副标题或目的地说明。 |
+| `route.image` | `string` | 是 | 可直接用于图片组件的封面 URL。 |
+| `route.routeCount` | `number` | 是 | 卡片右下角展示的路线数量,服务端应校验为不小于 0 的整数。 |
+| `route.demandKeyword` | `string` | 是 | 跳转需求页时可使用的预填关键词,去除首尾空白后不得为空。 |
+
+字段最大长度应由后端 schema 统一定义,并同步到 Admin UI 表单校验;在未形成统一长度常量前,前端不能通过截断文本代替服务端校验。
+
+## 接口详情
+
+### 获取分类及路线
+
+```http
+GET /api/admin/wanfa/categories
+Authorization: Bearer
+```
+
+成功响应:
+
+```json
+{
+ "categories": [
+ {
+ "id": "family-route",
+ "label": "亲子路线",
+ "routes": [
+ {
+ "id": "family-water",
+ "title": "亲子玩水",
+ "subtitle": "贵州·轻松节奏与自然课堂",
+ "image": "https://example.test/assets/family-water.jpg",
+ "routeCount": 4,
+ "demandKeyword": "亲子玩水"
+ }
+ ]
+ }
+ ]
+}
+```
+
+### 新增分类
+
+```http
+POST /api/admin/wanfa/categories
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求:
+
+```json
+{ "label": "亲子路线" }
+```
+
+成功返回 `201` 和新分类对象,初始 `routes` 为 `[]`,并追加到分类列表末尾。
+
+### 编辑分类
+
+```http
+PATCH /api/admin/wanfa/categories/{categoryId}
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求只允许修改分类名称:
+
+```json
+{ "label": "家庭路线" }
+```
+
+成功返回更新后的 `WanfaCategory`。不存在的分类返回 `404 WANFA_CATEGORY_NOT_FOUND`。
+
+### 删除分类
+
+```http
+DELETE /api/admin/wanfa/categories/{categoryId}
+Authorization: Bearer
+```
+
+为避免误删路线,分类仍包含路线时不得级联删除,应返回 `409 WANFA_CATEGORY_NOT_EMPTY`。删除前由 Admin UI 提示先移除分类内路线。删除成功返回:
+
+```json
+{ "id": "family-route" }
+```
+
+### 分类排序
+
+```http
+PATCH /api/admin/wanfa/categories/reorder
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求必须完整包含当前全部分类 ID,不能重复:
+
+```json
+{ "itemIds": ["photo-route", "family-route", "healing-route"] }
+```
+
+成功返回:
+
+```json
+{ "items": [] }
+```
+
+其中 `items` 为排序后的 `WanfaCategory[]`。缺少 ID、包含未知 ID 或出现重复 ID 时返回 `400 WANFA_CATEGORY_REORDER_INVALID`。
+
+### 新增路线
+
+```http
+POST /api/admin/wanfa/categories/{categoryId}/routes
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求:
+
+```json
+{
+ "title": "亲子玩水",
+ "subtitle": "贵州·轻松节奏与自然课堂",
+ "image": "https://example.test/assets/family-water.jpg",
+ "routeCount": 4,
+ "demandKeyword": "亲子玩水"
+}
+```
+
+成功返回 `201` 和新建的 `WanfaRoute`,并追加到对应分类路线末尾。分类不存在返回 `404 WANFA_CATEGORY_NOT_FOUND`。
+
+### 编辑路线
+
+```http
+PATCH /api/admin/wanfa/categories/{categoryId}/routes/{routeId}
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求体为 `WanfaRoutePatch`,只更新提交的字段。成功返回更新后的 `WanfaRoute`;分类或路线不存在时分别返回 `404 WANFA_CATEGORY_NOT_FOUND` 或 `404 WANFA_ROUTE_NOT_FOUND`。
+
+### 删除路线
+
+```http
+DELETE /api/admin/wanfa/categories/{categoryId}/routes/{routeId}
+Authorization: Bearer
+```
+
+成功返回 `{ "id": "..." }`。删除后,分类内路线保持原有相对顺序。
+
+### 分类内路线排序
+
+```http
+PATCH /api/admin/wanfa/categories/{categoryId}/routes/reorder
+Authorization: Bearer
+Content-Type: application/json
+```
+
+请求必须完整包含该分类当前全部路线 ID,不能重复:
+
+```json
+{ "itemIds": ["family-grassland", "family-water", "family-village"] }
+```
+
+成功返回排序后的路线:
+
+```json
+{ "items": [] }
+```
+
+分类不存在返回 `404 WANFA_CATEGORY_NOT_FOUND`;路线 ID 不完整、重复或不属于该分类时返回 `400 WANFA_ROUTE_REORDER_INVALID`。
+
+## 当前本地数据映射
+
+迁移初始数据时,分类和路线应按以下 ID 与顺序导入:
+
+| 分类 ID | 分类名称 | 路线 ID(当前顺序) |
+| --- | --- | --- |
+| `family-route` | 亲子路线 | `family-water`、`family-village`、`family-grassland` |
+| `photo-route` | 旅拍路线 | `miao-photo`、`peak-photo`、`terrace-photo` |
+| `healing-route` | 疗愈路线 | `mountain-healing`、`hot-spring-healing`、`river-healing` |
+| `team-building` | 团建 | `team-challenge`、`team-stream`、`team-culture` |
+| `guizhou-panorama` | 贵州全景 | `classic-panorama`、`mountain-panorama`、`wild-panorama` |
+| `private-custom` | 私人定制 | `private-family`、`private-business`、`private-wild` |
+
+图片别名的当前解析规则位于 `playData.ts` 的 `routeImageByAsset` 和 `resolveRouteImage`:已配置别名解析为完整远程 URL,完整 `http` URL 直接使用,其他值按 `/assets/guizhou/{image}.jpg` 解析。Admin API 建议保存最终 URL,Admin UI 通过现有媒体上传接口获取 URL 后再提交 `image`。
+
+## Admin UI 对接要求
+
+Admin UI 应按以下方式调用:
+
+1. 进入玩法管理页时调用 `GET /api/admin/wanfa/categories`,以返回数组顺序渲染分类和路线。
+2. 添加分类调用 `POST /categories`;编辑和删除分类分别调用对应 `PATCH`、`DELETE`。
+3. 添加、编辑和删除路线使用分类嵌套路由。
+4. 上移或下移分类时提交完整分类 ID 列表;上移或下移路线时提交完整路线 ID 列表。
+5. 每次变更成功后以接口返回数据更新本地状态;必要时重新请求列表,不直接拼接数据库字段。
+6. 删除非空分类前展示阻止性提示,不自动级联删除路线。
+7. 处理 `401`、`404`、`409`、`422` 和 `5xx`,并在保存中禁用重复提交。
+
+建议的 Admin UI API 封装函数:
+
+```ts
+getWanfaCategories();
+createWanfaCategory(input: WanfaCategoryCreate);
+updateWanfaCategory(categoryId: string, input: WanfaCategoryPatch);
+deleteWanfaCategory(categoryId: string);
+reorderWanfaCategories(itemIds: string[]);
+createWanfaRoute(categoryId: string, input: WanfaRouteCreate);
+updateWanfaRoute(categoryId: string, routeId: string, input: WanfaRoutePatch);
+deleteWanfaRoute(categoryId: string, routeId: string);
+reorderWanfaRoutes(categoryId: string, itemIds: string[]);
+```
+
+## 后端落地边界
+
+本契约落地时需要由 `WonderQ-Admin` 补充对应 ORM 模型、迁移、schema、路由、序列化和审计日志;由 `WonderQ-Admin-UI` 补充 API 类型、请求封装、表单和排序交互。接口实现前不要把 `playData.ts` 的静态数据误认为已存在的数据库或 API 数据。
+
+相关文档:
+
+- [Admin API 主契约](./admin-api-requirements.md)
+- [页面模块配置契约](./module-config-api.md)
+- [玩法本地数据](../WonderQ-MiniAPP/src/pages/play/components/playData.ts)