主要更新: - 修复了所有主要的代码逻辑错误 - 实现了完整的任务清理系统 - 添加了系统设置页面的任务清理管理功能 - 修复了API调用认证问题 - 优化了密码加密和验证机制 - 统一了错误处理模式 - 添加了详细的文档和测试工具 新增功能: - 任务清理管理界面 - 任务归档和清理日志 - API监控和诊断工具 - 完整的测试套件 技术改进: - 修复了Repository方法调用错误 - 统一了模型方法调用 - 改进了类型安全性 - 优化了代码结构和可维护性
308 lines
8.5 KiB
Markdown
308 lines
8.5 KiB
Markdown
# 任务完成后作品保存流程说明
|
||
|
||
## 🎯 **功能概述**
|
||
|
||
当任务执行成功后,系统会自动将结果保存到用户的"我的作品"中,并将相关信息添加到数据库中。用户可以通过API接口查看、管理自己的作品。
|
||
|
||
## 📋 **完整流程**
|
||
|
||
### 1. **任务执行成功触发**
|
||
```
|
||
外部API返回结果 → TaskQueueService.updateTaskAsCompleted()
|
||
```
|
||
|
||
### 2. **任务队列状态更新**
|
||
```java
|
||
// TaskQueueService.updateTaskAsCompleted()
|
||
taskQueue.updateStatus(TaskQueue.QueueStatus.COMPLETED);
|
||
taskQueueRepository.save(taskQueue);
|
||
```
|
||
|
||
### 3. **积分处理**
|
||
```java
|
||
// 扣除冻结的积分
|
||
userService.deductFrozenPoints(taskQueue.getTaskId());
|
||
```
|
||
|
||
### 4. **作品创建**
|
||
```java
|
||
// 创建用户作品
|
||
UserWork work = userWorkService.createWorkFromTask(taskQueue.getTaskId(), resultUrl);
|
||
```
|
||
|
||
### 5. **作品数据提取**
|
||
```java
|
||
// UserWorkService.createWorkFromTask()
|
||
// 检查是否已存在作品(防重复)
|
||
Optional<UserWork> existingWork = userWorkRepository.findByTaskId(taskId);
|
||
if (existingWork.isPresent()) {
|
||
return existingWork.get(); // 返回已存在的作品
|
||
}
|
||
|
||
// 从原始任务中提取数据
|
||
TextToVideoTask task = textToVideoTaskRepository.findByTaskId(taskId);
|
||
// 或
|
||
ImageToVideoTask task = imageToVideoTaskRepository.findByTaskId(taskId);
|
||
```
|
||
|
||
### 6. **作品信息设置**
|
||
```java
|
||
// UserWorkService.createTextToVideoWork() 或 createImageToVideoWork()
|
||
UserWork work = new UserWork();
|
||
work.setUsername(task.getUsername()); // 用户名
|
||
work.setTaskId(task.getTaskId()); // 任务ID
|
||
work.setWorkType(UserWork.WorkType.TEXT_TO_VIDEO); // 作品类型
|
||
work.setTitle(generateTitle(task.getPrompt())); // 自动生成标题
|
||
work.setDescription("文生视频作品"); // 作品描述
|
||
work.setPrompt(task.getPrompt()); // 原始提示词
|
||
work.setResultUrl(resultUrl); // 结果视频URL
|
||
work.setDuration(String.valueOf(task.getDuration()) + "s"); // 视频时长
|
||
work.setAspectRatio(task.getAspectRatio()); // 宽高比
|
||
work.setQuality(task.isHdMode() ? "HD" : "SD"); // 画质
|
||
work.setPointsCost(task.getCostPoints()); // 消耗积分
|
||
work.setStatus(UserWork.WorkStatus.COMPLETED); // 作品状态
|
||
work.setCompletedAt(LocalDateTime.now()); // 完成时间
|
||
```
|
||
|
||
### 7. **数据库保存**
|
||
```java
|
||
// 保存到数据库
|
||
work = userWorkRepository.save(work);
|
||
```
|
||
|
||
### 8. **原始任务状态更新**
|
||
```java
|
||
// 更新原始任务状态
|
||
updateOriginalTaskStatus(taskQueue, "COMPLETED", resultUrl, null);
|
||
```
|
||
|
||
## 🗄️ **数据库表结构**
|
||
|
||
### user_works 表
|
||
```sql
|
||
CREATE TABLE user_works (
|
||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||
username VARCHAR(100) NOT NULL COMMENT '用户名',
|
||
task_id VARCHAR(50) NOT NULL UNIQUE COMMENT '任务ID',
|
||
work_type ENUM('TEXT_TO_VIDEO', 'IMAGE_TO_VIDEO') NOT NULL COMMENT '作品类型',
|
||
title VARCHAR(200) COMMENT '作品标题',
|
||
description TEXT COMMENT '作品描述',
|
||
prompt TEXT COMMENT '生成提示词',
|
||
result_url VARCHAR(500) COMMENT '结果视频URL',
|
||
thumbnail_url VARCHAR(500) COMMENT '缩略图URL',
|
||
duration VARCHAR(10) COMMENT '视频时长',
|
||
aspect_ratio VARCHAR(10) COMMENT '宽高比',
|
||
quality VARCHAR(20) COMMENT '画质',
|
||
file_size VARCHAR(20) COMMENT '文件大小',
|
||
points_cost INT NOT NULL DEFAULT 0 COMMENT '消耗积分',
|
||
status ENUM('PROCESSING', 'COMPLETED', 'FAILED', 'DELETED') NOT NULL DEFAULT 'PROCESSING' COMMENT '作品状态',
|
||
is_public BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否公开',
|
||
view_count INT NOT NULL DEFAULT 0 COMMENT '浏览次数',
|
||
like_count INT NOT NULL DEFAULT 0 COMMENT '点赞次数',
|
||
download_count INT NOT NULL DEFAULT 0 COMMENT '下载次数',
|
||
tags VARCHAR(500) COMMENT '标签',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
completed_at DATETIME COMMENT '完成时间'
|
||
);
|
||
```
|
||
|
||
## 🔌 **API接口**
|
||
|
||
### 获取我的作品列表
|
||
```
|
||
GET /api/works/my-works?page=0&size=10
|
||
Authorization: Bearer <token>
|
||
|
||
Response:
|
||
{
|
||
"success": true,
|
||
"data": [
|
||
{
|
||
"id": 1,
|
||
"username": "user1",
|
||
"taskId": "txt2vid_123",
|
||
"workType": "TEXT_TO_VIDEO",
|
||
"title": "一只可爱的小猫...",
|
||
"description": "文生视频作品",
|
||
"prompt": "一只可爱的小猫在花园里玩耍",
|
||
"resultUrl": "https://example.com/video.mp4",
|
||
"duration": "10s",
|
||
"aspectRatio": "16:9",
|
||
"quality": "HD",
|
||
"pointsCost": 80,
|
||
"status": "COMPLETED",
|
||
"isPublic": false,
|
||
"viewCount": 0,
|
||
"likeCount": 0,
|
||
"downloadCount": 0,
|
||
"createdAt": "2024-01-01T10:00:00",
|
||
"completedAt": "2024-01-01T10:05:00"
|
||
}
|
||
],
|
||
"totalElements": 1,
|
||
"totalPages": 1,
|
||
"currentPage": 0,
|
||
"size": 10,
|
||
"stats": {
|
||
"completedCount": 1,
|
||
"processingCount": 0,
|
||
"failedCount": 0,
|
||
"totalPointsCost": 80,
|
||
"totalCount": 1,
|
||
"publicCount": 0
|
||
}
|
||
}
|
||
```
|
||
|
||
### 获取作品详情
|
||
```
|
||
GET /api/works/{workId}
|
||
Authorization: Bearer <token>
|
||
|
||
Response:
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": 1,
|
||
"username": "user1",
|
||
"taskId": "txt2vid_123",
|
||
"workType": "TEXT_TO_VIDEO",
|
||
"title": "一只可爱的小猫...",
|
||
"description": "文生视频作品",
|
||
"prompt": "一只可爱的小猫在花园里玩耍",
|
||
"resultUrl": "https://example.com/video.mp4",
|
||
"duration": "10s",
|
||
"aspectRatio": "16:9",
|
||
"quality": "HD",
|
||
"pointsCost": 80,
|
||
"status": "COMPLETED",
|
||
"isPublic": false,
|
||
"viewCount": 1,
|
||
"likeCount": 0,
|
||
"downloadCount": 0,
|
||
"createdAt": "2024-01-01T10:00:00",
|
||
"completedAt": "2024-01-01T10:05:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🛡️ **安全特性**
|
||
|
||
### 1. **防重复创建**
|
||
- 检查是否已存在相同任务ID的作品
|
||
- 如果存在则返回已存在的作品,不创建新作品
|
||
|
||
### 2. **权限控制**
|
||
- 只有作品所有者可以查看、编辑、删除作品
|
||
- 通过JWT Token验证用户身份
|
||
|
||
### 3. **数据完整性**
|
||
- 事务保证数据一致性
|
||
- 作品创建失败不影响任务完成状态
|
||
|
||
### 4. **异常处理**
|
||
- 完善的错误处理机制
|
||
- 详细的日志记录
|
||
|
||
## 📊 **作品管理功能**
|
||
|
||
### 1. **作品查看**
|
||
- 分页获取用户作品列表
|
||
- 获取作品详细信息
|
||
- 作品统计信息
|
||
|
||
### 2. **作品编辑**
|
||
- 修改作品标题
|
||
- 修改作品描述
|
||
- 设置作品标签
|
||
- 设置作品公开状态
|
||
|
||
### 3. **作品互动**
|
||
- 作品点赞
|
||
- 作品下载记录
|
||
- 浏览次数统计
|
||
|
||
### 4. **作品删除**
|
||
- 软删除作品
|
||
- 保留数据完整性
|
||
|
||
## 🔄 **定时任务**
|
||
|
||
### 清理过期失败作品
|
||
```java
|
||
@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
|
||
public void cleanupExpiredFailedWorks() {
|
||
// 清理超过30天的失败作品
|
||
int cleanedCount = userWorkService.cleanupExpiredFailedWorks();
|
||
}
|
||
```
|
||
|
||
## 🧪 **测试验证**
|
||
|
||
系统包含完整的集成测试,验证:
|
||
- 文生视频任务完成后作品创建
|
||
- 图生视频任务完成后作品创建
|
||
- 重复作品创建处理
|
||
- 作品标题生成
|
||
- 用户作品列表获取
|
||
- 作品统计信息
|
||
|
||
## 📝 **使用示例**
|
||
|
||
### 前端调用示例
|
||
```javascript
|
||
// 获取我的作品列表
|
||
const getMyWorks = async (page = 0, size = 10) => {
|
||
const response = await fetch(`/api/works/my-works?page=${page}&size=${size}`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
const data = await response.json();
|
||
return data;
|
||
};
|
||
|
||
// 获取作品详情
|
||
const getWorkDetail = async (workId) => {
|
||
const response = await fetch(`/api/works/${workId}`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
const data = await response.json();
|
||
return data;
|
||
};
|
||
|
||
// 更新作品信息
|
||
const updateWork = async (workId, updateData) => {
|
||
const response = await fetch(`/api/works/${workId}`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(updateData)
|
||
});
|
||
const data = await response.json();
|
||
return data;
|
||
};
|
||
```
|
||
|
||
## ✅ **系统状态**
|
||
|
||
当前系统已经完全实现了任务完成后作品保存功能:
|
||
|
||
1. **✅ 任务完成触发作品创建**
|
||
2. **✅ 作品信息自动提取和设置**
|
||
3. **✅ 作品数据保存到数据库**
|
||
4. **✅ 我的作品API接口完整**
|
||
5. **✅ 权限控制和安全验证**
|
||
6. **✅ 防重复创建机制**
|
||
7. **✅ 异常处理和日志记录**
|
||
8. **✅ 完整的测试覆盖**
|
||
|
||
用户现在可以在任务完成后,通过"我的作品"功能查看和管理自己生成的所有视频作品。
|
||
|
||
|