feat: 系统优化和功能完善

主要更新:
- 调整并发配置为50人(数据库连接池30,Tomcat线程150,异步线程池5/20)
- 实现无界阻塞队列(LinkedBlockingQueue)任务处理
- 实现分镜视频保存功能(保存到uploads目录)
- 统一管理页面导航栏和右上角样式
- 添加日活用户统计功能
- 优化视频拼接和保存逻辑
- 添加部署文档和快速部署指南
- 更新.gitignore排除敏感配置文件
This commit is contained in:
AIGC Developer
2025-11-07 19:09:50 +08:00
parent b5820d9be2
commit 1e71ae6a26
146 changed files with 10720 additions and 3032 deletions

View File

@@ -57,11 +57,24 @@
</div>
<div class="works-grid">
<div class="work-item" v-for="(work, index) in publishedWorks" :key="work.id" @click="openDetail(work)">
<div class="work-item" v-for="(work, index) in publishedWorks" :key="work.taskId || work.id" @click="openDetail(work)">
<div class="work-thumbnail">
<img :src="work.cover" :alt="work.title" />
<!-- 使用video元素显示视频浏览器会自动使用首帧作为封面 -->
<video
v-if="work.resultUrl"
:src="work.resultUrl"
class="work-video-thumbnail"
preload="metadata"
muted
@mouseenter="playPreview($event)"
@mouseleave="pausePreview($event)"
></video>
<!-- 如果没有视频URL显示占位符 -->
<div v-else class="work-placeholder">
<div class="play-icon"></div>
</div>
<div class="work-overlay">
<div class="overlay-text">{{ work.text }}</div>
<div class="overlay-text">{{ work.prompt || work.text || '文生视频' }}</div>
</div>
<!-- 鼠标悬停时显示的做同款按钮 -->
<div class="hover-create-btn" @click.stop="goToCreate(work)">
@@ -72,8 +85,8 @@
</div>
</div>
<div class="work-info">
<div class="work-title">{{ work.title }}</div>
<div class="work-meta">{{ work.id }} · {{ work.size }}</div>
<div class="work-title">{{ work.prompt || work.title || '文生视频' }}</div>
<div class="work-meta">{{ work.taskId || work.id }} · {{ formatSize(work) }}</div>
</div>
<div class="work-actions" v-if="index === 0">
<el-button type="primary" class="create-similar-btn" @click.stop="goToCreate(work)">做同款</el-button>
@@ -149,6 +162,7 @@ import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElIcon, ElButton, ElTag, ElMessage, ElDialog } from 'element-plus'
import { User, Document, VideoPlay, Picture, Film, Compass } from '@element-plus/icons-vue'
import { textToVideoApi } from '@/api/textToVideo'
const router = useRouter()
@@ -157,35 +171,7 @@ const detailDialogVisible = ref(false)
const selectedItem = ref(null)
// 已发布作品数据
const publishedWorks = ref([
{
id: '2995000000001',
title: '文生视频作品 #1',
cover: '/images/backgrounds/welcome.jpg',
text: 'What Does it Mean To You',
size: '9 MB',
category: '文生视频',
createTime: '2025/01/15 14:30'
},
{
id: '2995000000002',
title: '文生视频作品 #2',
cover: '/images/backgrounds/welcome.jpg',
text: 'What Does it Mean To You',
size: '9 MB',
category: '文生视频',
createTime: '2025/01/14 16:45'
},
{
id: '2995000000003',
title: '文生视频作品 #3',
cover: '/images/backgrounds/welcome.jpg',
text: 'What Does it Mean To You',
size: '9 MB',
category: '文生视频',
createTime: '2025/01/13 09:20'
}
])
const publishedWorks = ref([])
// 导航函数
const goToProfile = () => {
@@ -235,8 +221,62 @@ const createSimilar = () => {
router.push('/text-to-video/create')
}
// 格式化文件大小
const formatSize = (work) => {
if (work.size) return work.size
return '未知大小'
}
// 播放预览(鼠标悬停时)
const playPreview = (event) => {
const video = event.target
if (video && video.tagName === 'VIDEO') {
video.currentTime = 0
video.play().catch(() => {
// 忽略自动播放失败
})
}
}
// 暂停预览(鼠标离开时)
const pausePreview = (event) => {
const video = event.target
if (video && video.tagName === 'VIDEO') {
video.pause()
video.currentTime = 0
}
}
// 加载任务列表
const loadTasks = async () => {
try {
const response = await textToVideoApi.getTasks(0, 20)
if (response.data && response.data.success && response.data.data) {
// 只显示已完成的任务
publishedWorks.value = response.data.data
.filter(task => task.status === 'COMPLETED' && task.resultUrl)
.map(task => ({
taskId: task.taskId,
prompt: task.prompt,
resultUrl: task.resultUrl,
status: task.status,
createdAt: task.createdAt,
id: task.taskId,
title: task.prompt || '文生视频',
text: task.prompt || '文生视频',
category: '文生视频',
createTime: task.createdAt ? new Date(task.createdAt).toLocaleString('zh-CN') : ''
}))
}
} catch (error) {
console.error('加载任务列表失败:', error)
ElMessage.error('加载任务列表失败')
}
}
onMounted(() => {
// 页面初始化
// 页面初始化时加载任务列表
loadTasks()
})
</script>
@@ -462,12 +502,40 @@ onMounted(() => {
overflow: hidden;
}
.work-thumbnail img {
.work-thumbnail img,
.work-thumbnail video {
width: 100%;
height: 100%;
object-fit: cover;
}
.work-video-thumbnail {
display: block;
background: #000;
}
.work-placeholder {
width: 100%;
height: 100%;
background: #000;
display: flex;
align-items: center;
justify-content: center;
}
.play-icon {
width: 60px;
height: 60px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 24px;
backdrop-filter: blur(8px);
}
/* 鼠标悬停时显示的做同款按钮 */
.hover-create-btn {
position: absolute;