'use client'; import React, { useRef, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Trash2, RefreshCw, Play, Pause, Volume2, VolumeX, Upload, Library, Wand2 } from 'lucide-react'; import { GlassIconButton } from './glass-icon-button'; import { cn } from '@/public/lib/utils'; import { ReplaceVideoModal } from './replace-video-modal'; interface VideoTabContentProps { taskSketch: any[]; currentSketchIndex: number; onSketchSelect: (index: number) => void; isPlaying?: boolean; } export function VideoTabContent({ taskSketch = [], currentSketchIndex = 0, onSketchSelect, isPlaying: externalIsPlaying = true }: VideoTabContentProps) { const thumbnailsRef = useRef(null); const videosRef = useRef(null); const videoPlayerRef = useRef(null); const [isPlaying, setIsPlaying] = React.useState(externalIsPlaying); const [isMuted, setIsMuted] = React.useState(false); const [progress, setProgress] = React.useState(0); const [isReplaceModalOpen, setIsReplaceModalOpen] = React.useState(false); const [activeReplaceMethod, setActiveReplaceMethod] = React.useState<'upload' | 'library' | 'generate'>('upload'); // 监听外部播放状态变化 useEffect(() => { setIsPlaying(externalIsPlaying); }, [externalIsPlaying]); // 确保 taskSketch 是数组 const sketches = Array.isArray(taskSketch) ? taskSketch : []; // 模拟视频数据 const mockVideos = sketches.map((_, index) => ({ id: `video-${index}`, url: 'https://example.com/video.mp4', // 替换为实际视频URL duration: '00:21', description: `这是第 ${index + 1} 个分镜的视频描述,包含了场景中的主要动作和表现。` })); // 自动滚动到选中项 useEffect(() => { if (thumbnailsRef.current && videosRef.current) { const thumbnailContainer = thumbnailsRef.current; const videoContainer = videosRef.current; const thumbnailWidth = thumbnailContainer.children[0]?.clientWidth ?? 0; const thumbnailGap = 16; // gap-4 = 16px const thumbnailScrollPosition = (thumbnailWidth + thumbnailGap) * currentSketchIndex; const videoElement = videoContainer.children[currentSketchIndex] as HTMLElement; const videoScrollPosition = videoElement?.offsetLeft ?? 0; thumbnailContainer.scrollTo({ left: thumbnailScrollPosition - thumbnailContainer.clientWidth / 2 + thumbnailWidth / 2, behavior: 'smooth' }); videoContainer.scrollTo({ left: videoScrollPosition - videoContainer.clientWidth / 2 + videoElement?.clientWidth / 2, behavior: 'smooth' }); } }, [currentSketchIndex]); // 视频播放控制 useEffect(() => { if (videoPlayerRef.current) { if (isPlaying) { videoPlayerRef.current.play().catch(() => { // 处理自动播放策略限制 setIsPlaying(false); }); } else { // videoPlayerRef.current.pause(); } } }, [isPlaying, currentSketchIndex]); // 更新进度条 const handleTimeUpdate = () => { if (videoPlayerRef.current) { const progress = (videoPlayerRef.current.currentTime / videoPlayerRef.current.duration) * 100; setProgress(progress); } }; // 如果没有数据,显示空状态 if (sketches.length === 0) { return (

暂无分镜数据

); } return (
{/* 上部分 */} {/* 分镜缩略图行 */}
{sketches.map((sketch, index) => ( onSketchSelect(index)} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} > ))}
{/* 视频描述行 - 单行滚动 */}
{mockVideos.map((video, index) => { const isActive = currentSketchIndex === index; return ( onSketchSelect(index)} initial={false} animate={{ scale: isActive ? 1.02 : 1, }} >
{video.description} {index < mockVideos.length - 1 && ( | )}
); })}
{/* 渐变遮罩 */}
{/* 中间部分 替换视频 可上传、素材库选择、生成视频 */}

替换视频

{ setActiveReplaceMethod('upload'); setIsReplaceModalOpen(true); }} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > 上传视频 { setActiveReplaceMethod('library'); setIsReplaceModalOpen(true); }} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > 素材库 { setActiveReplaceMethod('generate'); setIsReplaceModalOpen(true); }} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > 生成视频
{/* 下部分 */} {/* 左列:编辑项 截取视频、设置转场、调节音量 */}
{/* 视频截取 */}

视频截取

{/* 转场设置 */}

转场设置

{['淡入淡出', '滑动', '缩放'].map((transition) => ( {transition} ))}
{/* 音量调节 */}

音量调节

console.log('Volume:', e.target.value)} />
{/* 右列:视频预览和操作 */}
{/* 选中的视频预览 */} {/* 操作按钮 */}
console.log('删除分镜')} className="flex items-center justify-center gap-2 px-4 py-3 bg-red-500/10 hover:bg-red-500/20 text-red-500 rounded-lg transition-colors" whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > 删除分镜 console.log('重新生成')} className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-500/10 hover:bg-blue-500/20 text-blue-500 rounded-lg transition-colors" whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > 重新生成
{/* 替换视频弹窗 */} setIsReplaceModalOpen(false)} onVideoSelect={(video) => { console.log('Selected video:', video); setIsReplaceModalOpen(false); }} />
); }