feat: 新增路线详情关联管家顾问及相关功能
详细变更如下: - 更新 .gitignore 文件,添加 pnpm-store 忽略规则 - 新增数据库迁移脚本,为 DetailRecord 添加可空的 conciergeAdvisorId 字段用于关联管家顾问 - 完善 Admin 后台玩法详情编辑器,支持选择关联的管家顾问并校验合法性 - 公共 API 支持返回已启用的管家顾问完整数据,不在详情表中冗余存储管家资料 - 小程序端新增详情页联系管家入口、个人页最近浏览历史功能 - 更新所有相关文档与测试用例,修复下拉选择框的 z-index 样式问题
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
- 详情页识别键、标题眉标、出行时长和标题文案。
|
||||
- 详情介绍、行程亮点、费用包含、费用不含和注意事项。
|
||||
- 详情页图片画廊及图片顺序。
|
||||
- 详情页可选的联系管家顾问 ID;顾问资料仍由管家领域维护。
|
||||
- 启用状态和详情列表顺序。
|
||||
|
||||
本接口不负责:
|
||||
@@ -18,7 +19,7 @@
|
||||
- 商品、商品价格、商品库存或商品详情表。
|
||||
- Product、ProductImage 或任何商品外键。
|
||||
- 订单、预订、收藏、评价或线索。
|
||||
- 详情页底部的电话、管家联系和预订动作。
|
||||
- 管家顾问的头像、二维码、服务详情和管家 CRUD;详情只保存顾问 ID。
|
||||
|
||||
`key` 固定使用玩法路线 ID(即服务端生成的 `WanfaRoute.id` UUID),但 `DetailRecord` 不建立数据库外键。详情页通过 `/pages/detail/index?routeId={key}` 定位内容;详情记录删除不会跨领域级联删除路线或其他数据。
|
||||
|
||||
@@ -80,6 +81,7 @@ type DetailPresentation = {
|
||||
type DetailRecord = DetailPresentation & {
|
||||
id: string;
|
||||
key: string;
|
||||
conciergeAdvisorId: string | null;
|
||||
isActive: boolean;
|
||||
sortOrder: number;
|
||||
createdAt: string;
|
||||
@@ -88,10 +90,20 @@ type DetailRecord = DetailPresentation & {
|
||||
|
||||
type PublicDetail = Omit<DetailPresentation, "key"> & {
|
||||
key: string;
|
||||
conciergeAdvisor: PublicConciergeAdvisor | null;
|
||||
};
|
||||
|
||||
type PublicConciergeAdvisor = {
|
||||
avatar: string;
|
||||
name: string;
|
||||
role: string;
|
||||
details: Array<{ icon: string; label: string }>;
|
||||
qrImage: string;
|
||||
};
|
||||
|
||||
type DetailCreate = DetailPresentation & {
|
||||
key: string;
|
||||
conciergeAdvisorId?: string | null;
|
||||
isActive?: boolean;
|
||||
sortOrder?: number;
|
||||
};
|
||||
@@ -123,6 +135,7 @@ type DetailReorderRequest = {
|
||||
| `excluded` | `string[]` | 是 | “费用不含”列表,保留数组顺序。 |
|
||||
| `notes` | `string[]` | 是 | “注意事项”列表,保留数组顺序。 |
|
||||
| `gallery` | `string[]` | 是 | 详情图片 URL 列表,按展示顺序返回;建议最多 6 张以匹配当前前台逻辑。 |
|
||||
| `conciergeAdvisorId` | `string \| null` | 否 | 关联的管家顾问 ID;不建立数据库外键,空字符串保存为 `null`。 |
|
||||
| `isActive` | `boolean` | 响应必填 | 是否进入已发布前台内容,创建默认 `true`。 |
|
||||
| `sortOrder` | `number` | 响应必填 | 非负整数,数值越小越靠前;创建时未传则追加到末尾。 |
|
||||
| `createdAt` | `string` | 响应必填 | ISO 8601 创建时间。 |
|
||||
@@ -187,7 +200,7 @@ Authorization: Bearer <admin-jwt>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
请求体为 `DetailCreate`。成功返回 `201` 和 `data` 内新建的 `DetailRecord`;未传 `sortOrder` 时追加到当前列表末尾。
|
||||
请求体为 `DetailCreate`。成功返回 `201` 和 `data` 内新建的 `DetailRecord`;未传 `sortOrder` 时追加到当前列表末尾。`conciergeAdvisorId` 传空字符串时归一化为 `null`,传入不存在的顾问 ID 返回 `422 DETAIL_CONCIERGE_ADVISOR_INVALID`。
|
||||
|
||||
### 编辑详情
|
||||
|
||||
@@ -267,10 +280,11 @@ type PublicDetail = {
|
||||
excluded: string[];
|
||||
notes: string[];
|
||||
gallery: string[];
|
||||
conciergeAdvisor: PublicConciergeAdvisor | null;
|
||||
};
|
||||
```
|
||||
|
||||
不存在、停用或未配置详情时返回 `404`。MiniAPP 请求失败或字段不完整时,按 `key` 查找本地 fallback;找不到 fallback 时展示未找到和重试状态。该页面暂不提供价格、收藏、在线订阅、预订、订单或管家联系动作。
|
||||
不存在、停用或未配置详情时返回 `404`。详情未配置顾问、顾问不存在或顾问已停用时,详情仍正常返回,但 `conciergeAdvisor` 为 `null`。MiniAPP 请求失败或字段不完整时,按 `key` 查找本地 fallback;fallback 不伪造管家数据,找不到 fallback 时展示未找到和重试状态。详情页仅在返回有效顾问时展示“联系管家”入口。
|
||||
|
||||
## 图片与素材
|
||||
|
||||
@@ -288,14 +302,14 @@ POST /api/admin/media-assets/upload
|
||||
|
||||
Admin UI 应按以下方式调用:
|
||||
|
||||
1. 玩法页加载时同时调用玩法分类和 `GET /api/admin/details`;详情编辑器嵌入现有路线编辑抽屉,不新增侧边菜单。
|
||||
1. 玩法页加载时同时调用玩法分类、`GET /api/admin/details` 和 `GET /api/admin/concierge/advisors`;详情编辑器嵌入现有路线编辑抽屉,不新增侧边菜单。
|
||||
2. 新增和编辑表单维护眉标、时长、标题、副标题、介绍和四组列表文案;保存路线时以已保存的路线 ID 作为详情 `key`。
|
||||
3. `highlights`、`included`、`excluded`、`notes` 使用可增删的重复字段编辑器,提交时保留数组顺序,不拼接成换行字符串。
|
||||
4. 使用图片上传接口维护 `gallery`,支持新增、删除和调整图片顺序。
|
||||
5. 上移或下移详情时提交完整详情 ID 列表,不直接修改本地 `sortOrder` 后假设保存成功。
|
||||
6. 删除前要求二次确认;删除成功后以接口返回或重新查询的数据更新列表。
|
||||
7. 处理 `401`、`404`、`409`、`422` 和 `5xx`,保存、上传或排序进行中禁用重复提交。
|
||||
8. 详情编辑器不得出现 Product ID、ProductImage ID、库存、订单、价格或预订字段;详情保存失败时明确提示路线摘要已保存、详情需要重试。
|
||||
8. 详情编辑器不得出现 Product ID、ProductImage ID、库存、订单、价格或预订字段;联系管家使用顾问 ID 选择器;详情保存失败时明确提示路线摘要已保存、详情需要重试。
|
||||
|
||||
建议的 Admin UI API 封装函数:
|
||||
|
||||
@@ -310,7 +324,7 @@ reorderDetails(itemIds: string[]);
|
||||
|
||||
## 与前台展示模型的映射
|
||||
|
||||
Admin API 返回的 `DetailRecord` 可以映射为 `DetailPresentation`:
|
||||
Public API 返回的 `PublicDetail` 可以直接映射为 MiniAPP 的 `DetailPresentation`;Admin API 返回的 `DetailRecord` 只包含 `conciergeAdvisorId`,不复制管家资料:
|
||||
|
||||
```ts
|
||||
const presentation: DetailPresentation = {
|
||||
@@ -325,6 +339,7 @@ const presentation: DetailPresentation = {
|
||||
excluded: record.excluded,
|
||||
notes: record.notes,
|
||||
gallery: record.gallery,
|
||||
conciergeAdvisor: publicDetail.conciergeAdvisor ?? null,
|
||||
};
|
||||
```
|
||||
|
||||
@@ -332,7 +347,7 @@ const presentation: DetailPresentation = {
|
||||
|
||||
## 后端落地边界
|
||||
|
||||
当前实现由 `WonderQ-Admin` 的 `DetailRecord` 模型、`0021_detail_records` 迁移、Admin/Public 路由和审计日志提供能力;由 `WonderQ-Admin-UI` 在玩法路线编辑抽屉中维护详情;由 `WonderQ-MiniAPP` 调用 Public 详情接口并按路线 ID fallback。迁移文件只负责生成和初始化详情记录,不自动执行数据库升级。
|
||||
当前实现由 `WonderQ-Admin` 的 `DetailRecord` 模型、`0021_detail_records`、`0022_opaque_ids` 和 `0023_detail_concierge_advisor` 迁移、Admin/Public 路由和审计日志提供能力;由 `WonderQ-Admin-UI` 在玩法路线编辑抽屉中维护详情及顾问 ID;由 `WonderQ-MiniAPP` 调用 Public 详情接口并按路线 ID fallback。迁移文件只负责生成和初始化详情记录,不自动执行数据库升级。顾问资料始终从管家领域实时读取,不复制到详情表。
|
||||
|
||||
相关文档:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user