# 点赞 & 收藏功能设计

> 所属端：公众端 + 超管端联动
> 状态：已实现
> 创建日期：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 失败时回滚
- 点赞按钮动效：心形图标缩放弹跳
- 自己的作品也可以点赞/收藏（不做限制）
