# 广场功能完整实现方案

## 一、功能概述

用户可以将AI生成的作品发布到广场，其他用户可以浏览、点赞、按类型筛选查询作品。

### 核心功能
1. **发布作品** - 用户将任务结果发布到广场
2. **浏览广场** - 按类型、热度、时间查询作品
3. **作品详情** - 查看单个作品详细信息
4. **点赞/取消点赞** - 用户可以对作品点赞
5. **统计数据** - 浏览量、点赞数、分享数统计
6. **个人作品** - 查看自己发布的作品
7. **删除作品** - 用户可以删除自己的作品

---

## 二、数据库设计

已在 `V10__add_plaza_feature.sql` 中定义了以下表：

### 1. plaza_work（广场作品表）
```sql
- id: 主键
- work_no: 作品编号（唯一）
- user_id: 发布者ID
- task_no: 关联任务编号
- task_type: 任务类型（text_to_image/image_to_video等）
- model_name: 使用的模型
- prompt: 生成提示词
- result_url: 作品URL
- image_url: 参考图URL（可选）
- title: 作品标题
- description: 作品描述
- tags: 标签（JSON）
- view_count, like_count, share_count: 统计数据
- is_public: 是否公开
- status: 状态（draft/published/hidden）
- create_time, update_time, is_deleted
```

### 2. plaza_work_like（点赞表）
```sql
- id: 主键
- work_id: 作品ID
- user_id: 点赞用户ID
- create_time: 点赞时间
- 唯一索引：(work_id, user_id)
```

### 3. plaza_work_view（浏览记录表）
```sql
- id: 主键
- work_id: 作品ID
- user_id: 浏览用户ID（可空）
- ip_address: IP地址
- view_time: 浏览时间
```

---

## 三、API 接口设计

### 基础路径
所有接口以 `/user/plaza` 开头

### 1. 发布作品
```
POST /user/plaza/works/publish
```

**请求参数:**
```json
{
  "taskNo": "TASK-20251026183750127-8554",
  "title": "战场气氛短视频",
  "description": "根据参考图生成的恢弘战场场景",
  "tags": ["视频", "战争", "特效"],
  "isPublic": true
}
```

**响应示例:**
```json
{
  "code": 200,
  "message": "success",
  "data": {
    "workNo": "WORK-20251026185630123-4567",
    "taskNo": "TASK-20251026183750127-8554",
    "taskType": "image_to_video",
    "modelName": "sc_sora2_img_landscape_15s_small",
    "prompt": "根据参考图展现出一个100秒左右的战场短视频...",
    "resultUrl": "https://oss-1818ai-user-img.oss-cn-hangzhou.aliyuncs.com/result.mp4",
    "imageUrl": "https://oss-1818ai-user-img.oss-cn-hangzhou.aliyuncs.com/ref.png",
    "title": "战场气氛短视频",
    "description": "根据参考图生成的恢弘战场场景",
    "tags": ["视频", "战争", "特效"],
    "viewCount": 0,
    "likeCount": 0,
    "isLiked": false,
    "createTime": "2025-10-26T18:56:30"
  }
}
```

---

### 2. 查询广场作品列表
```
GET /user/plaza/works/list
```

**请求参数:**
- `page`: 页码（默认1）
- `size`: 每页数量（默认20）
- `taskType`: 任务类型筛选（可选：text_to_image/image_to_video等）
- `sortBy`: 排序方式（可选：latest-最新/hot-最热，默认latest）

**示例:**
```
GET /user/plaza/works/list?page=1&size=20&taskType=text_to_image&sortBy=hot
```

**响应示例:**
```json
{
  "code": 200,
  "message": "success",
  "data": {
    "total": 156,
    "list": [
      {
        "workNo": "WORK-20251026185630123-4567",
        "taskType": "text_to_image",
        "modelName": "sc_soraimg_text_1x1",
        "prompt": "一只可爱的橘猫在窗台晒太阳",
        "resultUrl": "https://oss-.../cat.png",
        "title": "窗台上的橘猫",
        "tags": ["猫咪", "温馨", "治愈"],
        "viewCount": 1245,
        "likeCount": 89,
        "isLiked": false,
        "author": {
          "userId": 17563793187762127,
          "nickname": "AI创作者",
          "avatarUrl": "https://oss-.../avatar.jpg"
        },
        "createTime": "2025-10-26T18:56:30"
      }
      // ... 更多作品
    ]
  }
}
```

---

### 3. 查询作品详情
```
GET /user/plaza/works/{workNo}
```

**响应示例:**
```json
{
  "code": 200,
  "message": "success",
  "data": {
    "workNo": "WORK-20251026185630123-4567",
    "taskType": "text_to_image",
    "modelName": "sc_soraimg_text_1x1",
    "prompt": "一只可爱的橘猫在窗台晒太阳，温馨的室内场景，柔和的光线",
    "resultUrl": "https://oss-.../cat.png",
    "imageUrl": null,
    "aspectRatio": "1:1",
    "title": "窗台上的橘猫",
    "description": "这是一个温馨治愈的作品，展现了橘猫慵懒晒太阳的画面。",
    "tags": ["猫咪", "温馨", "治愈"],
    "viewCount": 1246,
    "likeCount": 89,
    "shareCount": 12,
    "isLiked": false,
    "author": {
      "userId": 17563793187762127,
      "nickname": "AI创作者",
      "avatarUrl": "https://oss-.../avatar.jpg"
    },
    "createTime": "2025-10-26T18:56:30",
    "updateTime": "2025-10-26T19:15:42"
  }
}
```

---

### 4. 点赞/取消点赞
```
POST /user/plaza/works/{workNo}/like
DELETE /user/plaza/works/{workNo}/like
```

**响应示例:**
```json
{
  "code": 200,
  "message": "success",
  "data": {
    "isLiked": true,
    "likeCount": 90
  }
}
```

---

### 5. 查询我的作品
```
GET /user/plaza/my-works
```

**请求参数:**
- `page`: 页码
- `size`: 每页数量
- `status`: 状态筛选（可选：published/draft/hidden）

**响应格式:** 同广场作品列表

---

### 6. 删除作品
```
DELETE /user/plaza/works/{workNo}
```

**响应示例:**
```json
{
  "code": 200,
  "message": "删除成功",
  "data": null
}
```

---

### 7. 统计数据
```
GET /user/plaza/stats
```

**响应示例:**
```json
{
  "code": 200,
  "message": "success",
  "data": {
    "totalWorks": 5678,
    "totalViews": 123456,
    "totalLikes": 8901,
    "worksByType": {
      "text_to_image": 3456,
      "image_to_video": 1234,
      "text_to_video": 988
    }
  }
}
```

---

## 四、实现步骤

### 步骤1: 执行SQL脚本
```bash
mysql -u root -p 1818ai < V10__add_plaza_feature.sql
```

### 步骤2: 创建实体类
- ✅ `PlazaWork.java` - 已创建
- ✅ `PlazaWorkLike.java` - 已创建

### 步骤3: 创建DTO类
需要创建以下DTO：
- `PlazaWorkDto.java` - 包含各种请求和响应DTO
  - `PublishWorkRequest` - 发布作品请求
  - `WorkQueryRequest` - 查询作品请求
  - `WorkDetailResponse` - 作品详情响应
  - `WorkListResponse` - 作品列表响应
  - `WorkAuthorDto` - 作者信息DTO

### 步骤4: 创建Mapper接口
- `PlazaWorkMapper.java` - 作品数据访问
- `PlazaWorkLikeMapper.java` - 点赞数据访问

### 步骤5: 创建Service层
- `PlazaService.java` - 接口
- `PlazaServiceImpl.java` - 实现

### 步骤6: 创建Controller
- `PlazaController.java` - 用户端控制器

---

## 五、核心业务逻辑

### 1. 发布作品流程
```
1. 验证taskNo是否存在且属于当前用户
2. 验证任务状态是否为completed
3. 检查该任务是否已经发布过
4. 生成唯一的workNo
5. 从任务表复制数据到广场作品表
6. 设置标题、描述、标签等
7. 初始化统计数据（浏览、点赞等为0）
8. 返回作品信息
```

### 2. 查询列表流程
```
1. 构建查询条件（任务类型、公开性、状态）
2. 根据sortBy排序（latest/hot）
3. 分页查询
4. 关联查询用户信息（昵称、头像）
5. 判断当前用户是否点赞过（如果已登录）
6. 返回作品列表
```

### 3. 点赞流程
```
1. 检查作品是否存在
2. 检查是否已经点赞
3. 插入点赞记录
4. 更新作品点赞数（+1）
5. 返回最新点赞状态
```

### 4. 浏览统计流程
```
1. 记录浏览日志（可选）
2. 更新作品浏览数（+1）
3. 防止频繁刷新（可加Redis缓存，同一用户1分钟内只计数一次）
```

---

## 六、前端调用示例

### 1. 发布作品到广场
```javascript
// 假设用户刚完成了一个任务，想发布到广场
async function publishToPlaza(taskNo) {
  const response = await fetch('http://localhost:8081/user/plaza/works/publish', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${YOUR_TOKEN}`
    },
    body: JSON.stringify({
      taskNo: taskNo,
      title: '我的AI创作',
      description: '这是我用AI生成的作品',
      tags: ['AI艺术', '创意'],
      isPublic: true
    })
  });
  
  const result = await response.json();
  console.log('发布成功:', result.data.workNo);
}
```

### 2. 浏览广场（按类型筛选）
```javascript
// 查询所有文生图作品
async function browsePlaza() {
  const response = await fetch(
    'http://localhost:8081/user/plaza/works/list?page=1&size=20&taskType=text_to_image&sortBy=hot',
    {
      headers: {
        'Authorization': `Bearer ${YOUR_TOKEN}`
      }
    }
  );
  
  const result = await response.json();
  console.log('广场作品:', result.data.list);
  
  // 渲染作品网格
  renderWorksGrid(result.data.list);
}

function renderWorksGrid(works) {
  works.forEach(work => {
    console.log(`
      作品：${work.title}
      作者：${work.author.nickname}
      点赞：${work.likeCount}
      浏览：${work.viewCount}
      图片：${work.resultUrl}
    `);
  });
}
```

### 3. 查看作品详情
```javascript
async function viewWorkDetail(workNo) {
  const response = await fetch(
    `http://localhost:8081/user/plaza/works/${workNo}`,
    {
      headers: {
        'Authorization': `Bearer ${YOUR_TOKEN}`
      }
    }
  );
  
  const result = await response.json();
  console.log('作品详情:', result.data);
  
  // 显示详情页
  showDetailModal(result.data);
}
```

### 4. 点赞作品
```javascript
async function likeWork(workNo) {
  const response = await fetch(
    `http://localhost:8081/user/plaza/works/${workNo}/like`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${YOUR_TOKEN}`
      }
    }
  );
  
  const result = await response.json();
  console.log('点赞成功，当前点赞数:', result.data.likeCount);
  
  // 更新UI
  updateLikeButton(workNo, result.data.isLiked, result.data.likeCount);
}

async function unlikeWork(workNo) {
  const response = await fetch(
    `http://localhost:8081/user/plaza/works/${workNo}/like`,
    {
      method: 'DELETE',
      headers: {
        'Authorization': `Bearer ${YOUR_TOKEN}`
      }
    }
  );
  
  const result = await response.json();
  console.log('取消点赞');
}
```

### 5. 查看我的作品
```javascript
async function getMyWorks() {
  const response = await fetch(
    'http://localhost:8081/user/plaza/my-works?page=1&size=10',
    {
      headers: {
        'Authorization': `Bearer ${YOUR_TOKEN}`
      }
    }
  );
  
  const result = await response.json();
  console.log('我的作品:', result.data.list);
}
```

---

## 七、React 完整示例

```jsx
import React, { useState, useEffect } from 'react';

// 广场组件
function PlazaPage() {
  const [works, setWorks] = useState([]);
  const [taskType, setTaskType] = useState('');
  const [sortBy, setSortBy] = useState('latest');
  const [page, setPage] = useState(1);
  
  useEffect(() => {
    loadWorks();
  }, [taskType, sortBy, page]);
  
  async function loadWorks() {
    const params = new URLSearchParams({
      page,
      size: 20,
      sortBy,
      ...(taskType && { taskType })
    });
    
    const response = await fetch(
      `http://localhost:8081/user/plaza/works/list?${params}`,
      {
        headers: {
          'Authorization': `Bearer ${localStorage.getItem('token')}`
        }
      }
    );
    
    const result = await response.json();
    setWorks(result.data.list);
  }
  
  async function handleLike(workNo, isLiked) {
    const method = isLiked ? 'DELETE' : 'POST';
    
    const response = await fetch(
      `http://localhost:8081/user/plaza/works/${workNo}/like`,
      {
        method,
        headers: {
          'Authorization': `Bearer ${localStorage.getItem('token')}`
        }
      }
    );
    
    if (response.ok) {
      // 刷新列表
      loadWorks();
    }
  }
  
  return (
    <div className="plaza-page">
      <h1>AI创作广场</h1>
      
      {/* 筛选器 */}
      <div className="filters">
        <select value={taskType} onChange={(e) => setTaskType(e.target.value)}>
          <option value="">全部类型</option>
          <option value="text_to_image">文生图</option>
          <option value="image_to_image">图生图</option>
          <option value="text_to_video">文生视频</option>
          <option value="image_to_video">图生视频</option>
        </select>
        
        <select value={sortBy} onChange={(e) => setSortBy(e.target.value)}>
          <option value="latest">最新发布</option>
          <option value="hot">最热门</option>
        </select>
      </div>
      
      {/* 作品网格 */}
      <div className="works-grid">
        {works.map(work => (
          <div key={work.workNo} className="work-card">
            <img src={work.resultUrl} alt={work.title} />
            <h3>{work.title}</h3>
            <p className="author">{work.author.nickname}</p>
            <div className="stats">
              <span>👁️ {work.viewCount}</span>
              <button onClick={() => handleLike(work.workNo, work.isLiked)}>
                {work.isLiked ? '❤️' : '🤍'} {work.likeCount}
              </button>
            </div>
            <div className="tags">
              {work.tags.map(tag => (
                <span key={tag} className="tag">{tag}</span>
              ))}
            </div>
          </div>
        ))}
      </div>
      
      {/* 分页 */}
      <div className="pagination">
        <button onClick={() => setPage(p => Math.max(1, p - 1))}>
          上一页
        </button>
        <span>第 {page} 页</span>
        <button onClick={() => setPage(p => p + 1)}>
          下一页
        </button>
      </div>
    </div>
  );
}

export default PlazaPage;
```

---

## 八、后续完善功能（可选）

### 1. 评论功能
- 创建 `plaza_work_comment` 表
- 支持评论和回复
- 评论点赞

### 2. 标签系统
- 创建 `plaza_tag` 标签表
- 支持热门标签推荐
- 按标签筛选作品

### 3. 用户关注
- 创建 `user_follow` 关注关系表
- 查看关注用户的作品
- 关注动态推送

### 4. 举报系统
- 创建 `plaza_report` 举报表
- 用户可以举报违规作品
- 管理员审核机制

### 5. 作品收藏
- 创建 `plaza_work_collect` 收藏表
- 用户收藏喜欢的作品
- 查看收藏列表

### 6. 分享功能
- 生成分享链接
- 分享到社交媒体
- 统计分享数据

---

## 九、性能优化建议

### 1. 缓存策略
- Redis 缓存热门作品列表
- 缓存用户点赞状态
- 缓存作品统计数据

### 2. CDN 加速
- 作品图片/视频通过 CDN 分发
- 提升加载速度

### 3. 数据库优化
- 对热点字段建立索引
- 分表存储历史数据
- 读写分离

### 4. 异步处理
- 浏览统计异步入库
- 点赞数更新异步化
- 使用消息队列

---

## 十、安全考虑

1. **内容审核**
   - 发布前自动审核（敏感词过滤）
   - 人工审核机制
   - 违规内容下架

2. **防刷机制**
   - 限制发布频率
   - 防止点赞刷数据
   - IP 限流

3. **权限控制**
   - 只能删除自己的作品
   - 未登录用户只能浏览
   - 隐私作品仅自己可见

---

## 总结

广场功能的核心是：
1. **数据模型** - 作品表、点赞表、浏览记录表
2. **API接口** - 发布、查询、点赞、删除等
3. **前端展示** - 瀑布流/网格布局、筛选排序、实时统计

按照本方案实施，可以快速搭建一个功能完善的AI作品广场。

下一步我会为你生成完整的 Java 代码（Mapper、Service、Controller）。

