'use client'; import React, { useRef, useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Trash2, RefreshCw, Play, Pause, Volume2, VolumeX, Upload, Library, Video, User, MapPin, Settings, Loader2, X, Plus } from 'lucide-react'; import { GlassIconButton } from './glass-icon-button'; import { cn } from '@/public/lib/utils'; import { ReplaceVideoModal } from './replace-video-modal'; import { MediaPropertiesModal } from './media-properties-modal'; import { DramaLineChart } from './drama-line-chart'; import { PersonDetection, PersonDetectionScene } from './person-detection'; import ShotEditor from './shot-editor/ShotEditor'; interface ShotTabContentProps { taskSketch: any[]; currentSketchIndex: number; onSketchSelect: (index: number) => void; isPlaying?: boolean; } export function ShotTabContent({ taskSketch = [], currentSketchIndex = 0, onSketchSelect, isPlaying: externalIsPlaying = true }: ShotTabContentProps) { const thumbnailsRef = useRef(null); const editorRef = 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'); const [isMediaPropertiesModalOpen, setIsMediaPropertiesModalOpen] = React.useState(false); const [triggerScan, setTriggerScan] = useState(false); const [detections, setDetections] = useState([]); const [scanState, setScanState] = useState<'idle' | 'scanning' | 'detected'>('idle'); // 监听外部播放状态变化 useEffect(() => { setIsPlaying(externalIsPlaying); }, [externalIsPlaying]); // 确保 taskSketch 是数组 const sketches = Array.isArray(taskSketch) ? taskSketch : []; // 自动滚动到选中项 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); } }; // 处理扫描开始 const handleScan = () => { if (scanState === 'detected') { // 如果已经有检测结果,点击按钮退出检测状态 setScanState('idle'); setDetections([]); // 清除检测结果 return; } setScanState('scanning'); // 模拟检测过程 setTimeout(() => { const mockDetections: PersonDetection[] = [ { id: '1', name: '人物1', position: { top: 0, left: 100, width: 100, height: 200 } } ]; setDetections(mockDetections); }, 5000); }; // 处理扫描超时/失败 const handleScanTimeout = () => { setScanState('idle'); setDetections([]); }; // 处理检测到结果 const handleDetectionsChange = (newDetections: PersonDetection[]) => { if (newDetections.length > 0 && scanState === 'scanning') { setScanState('detected'); } }; // 如果没有数据,显示空状态 if (sketches.length === 0) { return (

No sketch data

); } return (
{/* 上部分 */} {/* 分镜缩略图行 */}
{sketches.map((sketch, index) => ( onSketchSelect(index)} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} > ))}
{/* 视频描述行 - 单行滚动 */}
{sketches.map((video, index) => { const isActive = currentSketchIndex === index; return ( onSketchSelect(index)} initial={false} animate={{ scale: isActive ? 1.02 : 1, }} >
Shot {index + 1} {index < sketches.length - 1 && ( | )}
); })}
{/* 渐变遮罩 */}
{/* 下部分 */} {/* 视频预览和操作 */}
{/* 选中的视频预览 */} {/*
{/* 基础配置 */}
{ // 可以在这里添加其他逻辑 console.log('分镜添加成功'); }} /> {/* 重新生成按钮、新增分镜按钮 */}
editorRef.current?.addSegment()} className="flex items-center justify-center gap-2 px-4 py-3 bg-pink-500/10 hover:bg-pink-500/20 text-pink-500 rounded-lg transition-colors" whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} > Add Shot console.log('Regenerate')} 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 }} > Regenerate
{/* 替换视频弹窗 */} setIsReplaceModalOpen(false)} onVideoSelect={(video) => { console.log('Selected video:', video); setIsReplaceModalOpen(false); }} /> {/* Media Properties 弹窗 */} setIsMediaPropertiesModalOpen(false)} taskSketch={taskSketch} currentSketchIndex={currentSketchIndex} onSketchSelect={onSketchSelect} />
); }