- 新增客片案例全流程功能,包含前台页面、管理端配置、后端API、数据库迁移与文档 - 新增团队共创详情页面与对应接口 - 重构玩法模块:将静态playData替换为动态API获取,拆分类型定义到playTypes.ts - 优化vite构建配置与环境变量处理,调整详情页操作栏文案 - 更新全量相关文档与配图,新增客片案例、团队共创API文档 - 新增测试用例,完善数据归一化逻辑 - 调整路由配置与环境变量示例文件
156 lines
6.0 KiB
Markdown
156 lines
6.0 KiB
Markdown
# 团队共创详情接口契约
|
||
|
||
> 适用端:`WonderQ-Admin`、`WonderQ-Admin-UI`、`WonderQ-MiniAPP`。
|
||
> 目标:复用 `HomeTeamBuilding` 表,维护首页团队共创卡片和沉浸式详情页内容。
|
||
|
||
## 领域边界
|
||
|
||
- 团队共创卡片和详情共用一条 `HomeTeamBuilding` 记录。
|
||
- 详情封面复用 `image`,不新增独立详情表或第二张 hero 图片。
|
||
- `detailSubtitle` 是详情首屏副标题。
|
||
- `detailParagraphs` 是按阅读顺序保存的正文段落数组。
|
||
- Admin UI 使用正文 textarea 的“空行分隔段落”约定;后端保存前会清洗首尾空白和空段落。
|
||
- 首页卡片仍保留 `demandKeyword`,但点击行为改为详情页;该字段仅作为其他需求入口的普通文案,不建立商品或订单外键。
|
||
|
||
## 数据类型
|
||
|
||
```ts
|
||
type HomeTeamBuilding = {
|
||
id: string;
|
||
tag: string;
|
||
title: string;
|
||
description: string;
|
||
image: string;
|
||
demandKeyword: string;
|
||
detailSubtitle: string;
|
||
detailParagraphs: string[];
|
||
isActive: boolean;
|
||
sortOrder: number;
|
||
createdAt: string;
|
||
updatedAt: string;
|
||
};
|
||
|
||
type HomeTeamBuildingCreate = {
|
||
tag: string;
|
||
title: string;
|
||
description: string;
|
||
image: string;
|
||
demandKeyword: string;
|
||
detailSubtitle?: string;
|
||
detailParagraphs?: string[];
|
||
isActive?: boolean;
|
||
sortOrder?: number;
|
||
};
|
||
|
||
type HomeTeamBuildingPatch = Partial<HomeTeamBuildingCreate>;
|
||
```
|
||
|
||
兼容规则:旧客户端不提交详情字段时,后端使用模型默认值;迁移 `0020_home_team_building_details` 会把已有记录的副标题回填为 `description`,正文回填为 `[description]`。Public 序列化时仍会对空值做相同 fallback。
|
||
|
||
## Admin API
|
||
|
||
前缀为 `/api/admin`,需要 `Authorization: Bearer <admin-jwt>`。既有列表、创建、编辑、删除和排序路径保持不变:
|
||
|
||
| 方法 | 路径 | 用途 |
|
||
| --- | --- | --- |
|
||
| `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` | 调整团队共创顺序 |
|
||
|
||
创建或编辑请求示例:
|
||
|
||
```json
|
||
{
|
||
"tag": "户外挑战",
|
||
"title": "山野挑战,共创极境",
|
||
"description": "洞穴、瀑降与协作,适合 10-30 人。",
|
||
"image": "https://example.test/assets/team-building.jpg",
|
||
"demandKeyword": "户外团建",
|
||
"detailSubtitle": "越过山丘,向来处去",
|
||
"detailParagraphs": [
|
||
"真正的贵州,从未被写进流水线的攻略里。",
|
||
"把会议室换成山野,让团队重新认识彼此。"
|
||
],
|
||
"isActive": true
|
||
}
|
||
```
|
||
|
||
约束:
|
||
|
||
- 文本字段去除首尾空白后不得为空;详情副标题最大 160 字,正文最多 30 段。
|
||
- `detailParagraphs` 保存时过滤空段落;编辑接口显式传空正文会返回 `422`。
|
||
- 图片只接受 HTTP(S) URL;排序值为非负整数。
|
||
- 列表接口返回启用和停用记录,按 `sortOrder` 升序;删除和排序继续写审计日志。
|
||
- 迁移只新增两列,不改变旧字段和现有接口路径;本次实现不自动执行迁移。
|
||
|
||
## Public API
|
||
|
||
### 首页摘要
|
||
|
||
```http
|
||
GET /api/public/home
|
||
```
|
||
|
||
首页响应中的 `teamBuildings` 只返回卡片摘要:
|
||
|
||
```ts
|
||
type PublicHomeTeamBuildingSummary = {
|
||
id: string;
|
||
tag: string;
|
||
title: string;
|
||
description: string;
|
||
image: string;
|
||
demandKeyword: string;
|
||
};
|
||
```
|
||
|
||
### 详情
|
||
|
||
```http
|
||
GET /api/public/home/team-buildings/{teamBuildingId}
|
||
```
|
||
|
||
无需鉴权。成功响应:
|
||
|
||
```ts
|
||
type PublicHomeTeamBuildingDetail = PublicHomeTeamBuildingSummary & {
|
||
detailSubtitle: string;
|
||
detailParagraphs: string[];
|
||
};
|
||
```
|
||
|
||
错误响应:
|
||
|
||
| 状态码 | 场景 |
|
||
| --- | --- |
|
||
| `404` | ID 不存在或团队共创已停用 |
|
||
| `5xx` | 服务端异常;MiniAPP 进入本地 fallback |
|
||
|
||
响应中的 `detailSubtitle` 为空时返回 `description`;`detailParagraphs` 为空时返回 `[description]`。Public API 不返回管理端状态、排序和审计字段。
|
||
|
||
## MiniAPP 联调约定
|
||
|
||
1. 首页通过 `/api/public/home` 加载团队共创卡片。
|
||
2. `openTeamBuilding(item)` 调用 `goTeamBuildingDetail(item.id)`,跳转 `/pages/team-buildings/detail?id={teamBuildingId}`。
|
||
3. 详情页调用 `fetchPublicTeamBuildingDetail(teamBuildingId)`,成功后通过 `normalizeHomeTeamBuildingDetail` 归一化。
|
||
4. 请求失败时按 ID 查找 `homeTeamBuildingFallback`;命中则展示模拟网络图片、标题、副标题和正文,并提示“接口暂不可用,当前展示模拟数据”。
|
||
5. 无 ID、ID 不存在且无 fallback 时展示未找到状态,并提供返回首页操作。
|
||
6. 页面必须覆盖 loading、接口失败、空正文和未找到状态;详情布局使用 TailwindCSS,不新增页面级自定义样式。
|
||
|
||
## 三端联调顺序
|
||
|
||
1. 在 `WonderQ-Admin` 执行 `python -m alembic upgrade head`,仅在确认目标数据库后执行。
|
||
2. 启动后端并验证 `GET /health`。
|
||
3. 在 Admin UI 创建或编辑团队共创,填写详情副标题和正文;正文 textarea 使用空行分段。
|
||
4. 验证 Admin API 返回详情字段,Public 首页只返回摘要。
|
||
5. 在 MiniAPP 首页点击团队共创卡片,确认 URL 携带正确 ID。
|
||
6. 验证详情接口成功展示最新内容;停止后端后确认按 ID fallback 并显示提示。
|
||
|
||
## 变更文件
|
||
|
||
- 后端:`WonderQ-Admin/app/models.py`、`app/schemas.py`、`app/serializers.py`、`app/routers/public.py`、`alembic/versions/0020_home_team_building_details.py`。
|
||
- 管理端:`WonderQ-Admin-UI/src/api.ts`、`src/pages/structure/HomeContentPage.tsx`、`src/components/admin/HomeContentEditor.tsx`、`src/components/admin/HomeContentCardRail.tsx`。
|
||
- 前台:`WonderQ-MiniAPP/src/pages/home/components/homeTeamBuildingData.ts`、`src/lib/types.ts`、`src/lib/api.ts`、`src/lib/navigation.ts`、`src/pages/home/index.vue`、`src/pages/team-buildings/detail.vue`、`src/pages.json`。
|