# 点赞 & 收藏功能设计 > 所属端:公众端 + 超管端联动 > 状态:已实现 > 创建日期:2026-03-31 > 最后更新:2026-03-31 ## 概述 为 UGC 绘本创作社区的作品添加点赞和收藏交互能力,提升用户参与感和内容发现效率。 ## 现状 - 数据库:`user_work_likes` 和 `user_work_favorites` 表已存在(含唯一约束) - `UserWork` 表已有 `likeCount`、`favoriteCount` 冗余计数字段 - 前端:Gallery 和 Detail 页面已展示计数数字,但无交互按钮 - 后端:无任何点赞/收藏 API ## API 设计 ### 公众端 API | 方法 | 路径 | 说明 | 鉴权 | |------|------|------|------| | POST | `/api/public/works/:id/like` | 点赞/取消点赞(toggle) | 需登录 | | POST | `/api/public/works/:id/favorite` | 收藏/取消收藏(toggle) | 需登录 | | GET | `/api/public/works/:id/interaction` | 查询当前用户对该作品的交互状态 | 需登录 | | GET | `/api/public/mine/favorites` | 我的收藏列表 | 需登录 | ### 请求/响应 #### POST /works/:id/like ```json // Response { "liked": true, "likeCount": 42 } ``` #### POST /works/:id/favorite ```json // Response { "favorited": true, "favoriteCount": 18 } ``` #### GET /works/:id/interaction ```json // Response { "liked": true, "favorited": false } ``` #### GET /mine/favorites ```json // Response { "list": [ { "id": 1, "workId": 10, "createTime": "2026-03-31T...", "work": { "id": 10, "title": "...", "coverUrl": "...", "likeCount": 42, "viewCount": 100, "creator": { "id": 1, "nickname": "...", "avatar": "..." } } } ], "total": 5, "page": 1, "pageSize": 12 } ``` ## 后端实现 ### 新增文件 - `backend/src/public/interaction.service.ts` — 交互服务 ### 核心逻辑 **点赞 toggle**: 1. 查询 `UserWorkLike` 是否存在该记录 2. 存在 → 删除记录 + `likeCount` 减 1 3. 不存在 → 创建记录 + `likeCount` 加 1 4. 使用事务保证一致性 **收藏 toggle**:同上逻辑,操作 `UserWorkFavorite` 和 `favoriteCount` **交互状态查询**: - 批量查询 like + favorite 记录是否存在 - 广场详情接口中嵌入调用(已登录时返回交互状态) ## 前端改动 ### 作品详情页 (Detail.vue) - stats-row 改为交互按钮栏:点赞按钮 + 收藏按钮 - 已点赞/收藏时图标实心 + 主题色高亮 - 点击触发 toggle API,乐观更新计数 ### 广场页 (Gallery.vue) - 卡片 stats 区域的心形图标改为可点击 - 点击点赞(阻止冒泡,不跳转详情) - 乐观更新 + 简单动效 ### 新增页面 - `/p/mine/favorites` — 我的收藏页面 - 个人中心 Index.vue 增加「我的收藏」菜单入口 ### API 定义 ```typescript // api/public.ts export const publicInteractionApi = { like: (workId: number) => publicApi.post(`/public/works/${workId}/like`), favorite: (workId: number) => publicApi.post(`/public/works/${workId}/favorite`), getInteraction: (workId: number) => publicApi.get(`/public/works/${workId}/interaction`), myFavorites: (params?: { page?: number; pageSize?: number }) => publicApi.get('/public/mine/favorites', { params }), } ``` ## 交互细节 - 未登录用户点击点赞/收藏 → 跳转登录页 - 乐观更新:点击后立即更新 UI,API 失败时回滚 - 点赞按钮动效:心形图标缩放弹跳 - 自己的作品也可以点赞/收藏(不做限制)