import React, { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import { SparklesIcon, ArrowRightIcon } from '@heroicons/react/24/outline'; import { VideoGenerationProject, MaterialCategory, MaterialAsset, VideoGenerationConfig, VideoGenerationStatus, MATERIAL_CATEGORY_CONFIG } from '../types/videoGeneration'; import { MaterialSelector } from '../components/video-generation/MaterialSelector'; import { CompactVideoConfigPanel } from '../components/video-generation/CompactVideoConfigPanel'; import { CentralVideoPreview } from '../components/video-generation/CentralVideoPreview'; import { TaskStatusPanel, VideoGenerationTask } from '../components/video-generation/TaskStatusPanel'; /** * 视频生成页面 * 支持素材选择、配置设置和视频生成预览 */ const VideoGeneration: React.FC = () => { const { projectId } = useParams<{ projectId?: string }>(); const [project, setProject] = useState(null); const [isLoading, setIsLoading] = useState(false); const [activeMaterialTab, setActiveMaterialTab] = useState(MaterialCategory.Model); const [isGenerating, setIsGenerating] = useState(false); const [isTaskPanelCollapsed, setIsTaskPanelCollapsed] = useState(false); const [tasks, setTasks] = useState([]); // 初始化项目 useEffect(() => { if (projectId) { loadProject(projectId); } else { createNewProject(); } }, [projectId]); const loadProject = async (id: string) => { setIsLoading(true); try { // 模拟API调用 await new Promise(resolve => setTimeout(resolve, 500)); // 模拟项目数据 const mockProject: VideoGenerationProject = { id, name: `视频生成项目 ${id}`, description: '基于AI的视频生成项目', selected_assets: {}, generation_config: { output_format: 'mp4', resolution: '1080p', frame_rate: 30, duration: 30, quality: 'high', audio_enabled: true, effects: [] }, status: VideoGenerationStatus.Pending, created_at: new Date().toISOString(), updated_at: new Date().toISOString() }; setProject(mockProject); } catch (error) { console.error('Failed to load project:', error); } finally { setIsLoading(false); } }; const createNewProject = () => { const newProject: VideoGenerationProject = { id: Date.now().toString(), name: '新建视频生成项目', description: '', selected_assets: {}, generation_config: { output_format: 'mp4', resolution: '1080p', frame_rate: 30, duration: 30, quality: 'high', audio_enabled: true, effects: [] }, status: VideoGenerationStatus.Pending, created_at: new Date().toISOString(), updated_at: new Date().toISOString() }; setProject(newProject); }; // 处理素材选择变化 const handleAssetsChange = (category: MaterialCategory, assets: MaterialAsset[]) => { if (!project) return; setProject(prev => ({ ...prev!, selected_assets: { ...prev!.selected_assets, [category]: assets }, updated_at: new Date().toISOString() })); }; // 处理配置变化 const handleConfigChange = (config: VideoGenerationConfig) => { if (!project) return; setProject(prev => ({ ...prev!, generation_config: config, updated_at: new Date().toISOString() })); }; // 生成视频 const handleGenerateVideo = async () => { if (!project) return; setIsGenerating(true); // 创建新任务 const newTask: VideoGenerationTask = { id: Date.now().toString(), name: `视频生成 - ${project.name}`, status: 'running', progress: 0, startTime: new Date().toISOString() }; setTasks(prev => [newTask, ...prev]); try { // 模拟视频生成过程 for (let i = 0; i <= 100; i += 10) { await new Promise(resolve => setTimeout(resolve, 300)); setTasks(prev => prev.map(task => task.id === newTask.id ? { ...task, progress: i } : task )); } // 完成任务 setTasks(prev => prev.map(task => task.id === newTask.id ? { ...task, status: 'completed' as const, progress: 100, endTime: new Date().toISOString(), duration: Math.floor((Date.now() - new Date(newTask.startTime!).getTime()) / 1000), outputPath: `/outputs/video_${newTask.id}.mp4` } : task )); setProject(prev => ({ ...prev!, status: VideoGenerationStatus.Completed, updated_at: new Date().toISOString() })); } catch (error) { console.error('Failed to generate video:', error); // 标记任务失败 setTasks(prev => prev.map(task => task.id === newTask.id ? { ...task, status: 'failed' as const, endTime: new Date().toISOString(), errorMessage: '视频生成失败,请重试' } : task )); setProject(prev => ({ ...prev!, status: VideoGenerationStatus.Failed, updated_at: new Date().toISOString() })); } finally { setIsGenerating(false); } }; // 任务管理函数 const handleCancelTask = (taskId: string) => { setTasks(prev => prev.map(task => task.id === taskId ? { ...task, status: 'cancelled' as const, endTime: new Date().toISOString() } : task )); }; const handleRetryTask = (taskId: string) => { const task = tasks.find(t => t.id === taskId); if (task) { handleGenerateVideo(); } }; const handleDeleteTask = (taskId: string) => { setTasks(prev => prev.filter(task => task.id !== taskId)); }; if (isLoading) { return (
加载项目中...
); } if (!project) { return (

项目加载失败

); } return (
{/* 顶部工具栏 */}

视频生成工作台

{project.name}

{/* 主要工作区域 */}
{/* 左侧素材区 */}
{/* 素材分类标签 */}
{Object.values(MaterialCategory).map((category) => { const config = MATERIAL_CATEGORY_CONFIG[category]; const selectedAssets = project.selected_assets[category] || []; const isActive = activeMaterialTab === category; return ( ); })}
{/* 素材列表 */}
handleAssetsChange(activeMaterialTab, assets)} allowMultiple={true} />
{/* 中央预览区 */}
{/* 视频预览区域 */}
{/* 底部参数设置区 */}
{/* 右侧任务状态区(可折叠) */}
{/* 折叠按钮 */}
{!isTaskPanelCollapsed && (

任务状态

)}
{/* 任务列表 */} {!isTaskPanelCollapsed && (
)}
); }; export default VideoGeneration;