forked from 77media/video-flow
100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
import React, { useState, useEffect, useMemo } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import Scriptwriter from './scriptwriter';
|
|
import StoryboardArtist from './storyboard-artist';
|
|
import VisualDirector from './visual-director';
|
|
import Editor from './editor';
|
|
import { storyboardData, productionData, editorData } from './mock-data';
|
|
|
|
|
|
// 思考指示器组件
|
|
const ThinkingDots = ({ show, text, color }: { show: boolean; text: string; color: string }) => {
|
|
if (!show) return null;
|
|
|
|
return (
|
|
<div className="flex items-center space-x-2">
|
|
<div className="flex space-x-1">
|
|
{[0, 1, 2].map((i) => (
|
|
<motion.div
|
|
key={i}
|
|
className="w-2 h-2 rounded-full"
|
|
style={{ backgroundColor: color }}
|
|
animate={{
|
|
scale: [1, 1.2, 1],
|
|
opacity: [0.5, 1, 0.5]
|
|
}}
|
|
transition={{
|
|
duration: 1.5,
|
|
repeat: Infinity,
|
|
delay: i * 0.2
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
<span className="text-white text-sm">{text}</span>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface WorkOfficeProps {
|
|
initialStage?: number;
|
|
currentContent: Record<string, any>;
|
|
thinkingText: string;
|
|
thinkingColor: string;
|
|
sketchType: string;
|
|
}
|
|
|
|
const WorkOffice: React.FC<WorkOfficeProps> = ({ initialStage = 0, currentContent, thinkingText, thinkingColor, sketchType }) => {
|
|
const [currentStage, setCurrentStage] = useState(initialStage);
|
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setCurrentStage(initialStage);
|
|
setIsPlaying(true);
|
|
}, [initialStage]);
|
|
|
|
|
|
// 使用 useMemo 缓存工作台组件
|
|
const currentWorkstation = useMemo(() => {
|
|
console.log('工作台组件重新渲染', currentContent);
|
|
switch (currentStage) {
|
|
case 0:
|
|
return <Scriptwriter currentContent={currentContent} isPlaying={isPlaying} />;
|
|
case 1:
|
|
return <StoryboardArtist currentContent={currentContent} isPlaying={isPlaying} sketchType={sketchType} />;
|
|
case 2:
|
|
return <VisualDirector currentContent={currentContent} isPlaying={isPlaying} />;
|
|
case 3:
|
|
return <Editor currentContent={currentContent} isPlaying={isPlaying} />;
|
|
default:
|
|
return null;
|
|
}
|
|
}, [currentStage, isPlaying, currentContent]);
|
|
|
|
// 使用 useMemo 缓存 ThinkingDots 组件
|
|
const thinkingDots = useMemo(() => (
|
|
<ThinkingDots
|
|
show={isPlaying}
|
|
text={thinkingText}
|
|
color={thinkingColor}
|
|
/>
|
|
), [isPlaying, thinkingText, thinkingColor]);
|
|
|
|
return (
|
|
<div className="h-full rounded-2xl overflow-hidden shadow-2xl relative">
|
|
{/* 正在加载的部分 文字显示 */}
|
|
<div className="absolute top-[0] left-1/2 -translate-x-1/2 z-10">
|
|
{thinkingDots}
|
|
</div>
|
|
|
|
{/* 工作台内容区域 */}
|
|
<div className="absolute left-0 right-0 top-[2rem] w-full aspect-video overflow-y-auto" style={{height: 'calc(100% - 7rem'}}>
|
|
{currentWorkstation}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// 使用 React.memo 包装组件
|
|
export default React.memo(WorkOffice);
|