Files
1818web-hoduan/广场功能实现方案.md
2025-11-14 17:41:15 +08:00

685 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 广场功能完整实现方案
## 一、功能概述
用户可以将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