265 lines
11 KiB
TypeScript

import React from 'react';
import { Film } from 'lucide-react';
import { TypewriterText } from './common/TypewriterText';
import { ContentCard } from './common/ContentCard';
import { SkeletonCard } from './common/SkeletonCard';
import { IconLoading } from './common/IconLoading';
import { ProgressBar } from './common/ProgressBar';
interface ProductionContent {
composition?: Array<{
id: string;
stableId: string;
element: string;
details: string;
status: string;
progress: number;
}>;
lighting?: {
stableId: string;
ambient: string;
artificial: string;
mood: string;
progress: number;
};
performance?: Array<{
id: string;
stableId: string;
aspect: string;
details: string;
quality: string;
progress: number;
}>;
sceneDetails?: {
stableId: string;
textures: string;
objects: string;
atmosphere: string;
progress: number;
};
technical?: Array<{
param: string;
value: string;
status: string;
}>;
renderOutput?: {
currentFrame: number;
totalFrames: number;
quality: string;
estimated: string;
};
}
interface VisualDirectorProps {
currentContent: ProductionContent;
isPlaying: boolean;
}
const VisualDirector: React.FC<VisualDirectorProps> = ({ currentContent, isPlaying }) => {
return (
<div className="grid grid-cols-2 gap-4 h-full">
{/* 左侧:画面构成和光影氛围 */}
<div className="space-y-4 overflow-y-auto">
{/* 画面构成要素 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Film} isActive={!currentContent.composition && isPlaying} color="#10b981" />
</h3>
<div className="space-y-3">
{currentContent.composition && currentContent.composition.length > 0 ? (
currentContent.composition.map((comp) => (
<ContentCard
key={comp.stableId}
className="bg-emerald-500/20 rounded-lg p-3"
>
<div className="flex justify-between items-center mb-2">
<span className="text-emerald-300 font-medium text-sm">{comp.element}</span>
<span className="text-emerald-400 text-xs">{comp.status}</span>
</div>
<div className="text-gray-300 text-xs mb-2">
<TypewriterText text={comp.details} stableId={comp.stableId} />
</div>
<ProgressBar progress={comp.progress} color="#10b981" />
</ContentCard>
))
) : (
Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-emerald-500/20 rounded-lg p-3 border border-emerald-500/30" />
))
)}
</div>
</div>
{/* 光影氛围营造 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Film} isActive={!currentContent.lighting && isPlaying} color="#10b981" />
</h3>
{currentContent.lighting ? (
<ContentCard className="space-y-3">
<div>
<div className="text-emerald-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.lighting.ambient} stableId={`${currentContent.lighting.stableId}-ambient`} />
</div>
</div>
<div>
<div className="text-emerald-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.lighting.artificial} stableId={`${currentContent.lighting.stableId}-artificial`} />
</div>
</div>
<div>
<div className="text-emerald-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.lighting.mood} stableId={`${currentContent.lighting.stableId}-mood`} />
</div>
</div>
<ProgressBar progress={currentContent.lighting.progress} color="#10b981" label="光影渲染" />
</ContentCard>
) : (
<div className="space-y-3">
{Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-emerald-500/20 rounded-lg p-3 border border-emerald-500/30" />
))}
<SkeletonCard className="h-2 bg-emerald-500/20 rounded-full border border-emerald-500/30" />
</div>
)}
</div>
</div>
{/* 右侧:角色表演和技术参数 */}
<div className="space-y-4 overflow-y-auto">
{/* 角色表演捕捉 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Film} isActive={!currentContent.performance && isPlaying} color="#10b981" />
</h3>
<div className="space-y-3">
{currentContent.performance ? (
currentContent.performance.map((perf) => (
<ContentCard
key={perf.stableId}
className="bg-emerald-400/20 rounded-lg p-3"
>
<div className="text-emerald-200 font-medium text-sm mb-1">{perf.aspect}</div>
<div className="text-gray-300 text-xs mb-2">
<TypewriterText text={perf.details} stableId={perf.stableId} />
</div>
<div className="text-emerald-300 text-xs mb-2">{perf.quality}</div>
<ProgressBar progress={perf.progress} color="#10b981" />
</ContentCard>
))
) : (
Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-emerald-500/20 rounded-lg p-3 border border-emerald-500/30" />
))
)}
</div>
</div>
{/* 场景细节渲染 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Film} isActive={!currentContent.sceneDetails && isPlaying} color="#10b981" />
</h3>
{currentContent.sceneDetails ? (
<ContentCard className="space-y-3">
<div>
<div className="text-emerald-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.sceneDetails.textures} stableId={`${currentContent.sceneDetails.stableId}-textures`} />
</div>
</div>
<div>
<div className="text-emerald-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.sceneDetails.objects} stableId={`${currentContent.sceneDetails.stableId}-objects`} />
</div>
</div>
<div>
<div className="text-emerald-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.sceneDetails.atmosphere} stableId={`${currentContent.sceneDetails.stableId}-atmosphere`} />
</div>
</div>
<ProgressBar progress={currentContent.sceneDetails.progress} color="#10b981" label="细节渲染" />
</ContentCard>
) : (
<div className="space-y-3">
{Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-emerald-500/20 rounded-lg p-3 border border-emerald-500/30" />
))}
<SkeletonCard className="h-2 bg-emerald-500/20 rounded-full border border-emerald-500/30" />
</div>
)}
</div>
{/* 技术参数控制 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Film} isActive={!currentContent.technical && isPlaying} color="#10b981" />
</h3>
{currentContent.technical ? (
<>
<div className="space-y-2">
{currentContent.technical.map((tech, index) => (
<div key={index} className="flex justify-between items-center p-2 bg-emerald-500/10 rounded">
<span className="text-emerald-300 text-sm">{tech.param}</span>
<span className="text-white text-sm font-mono">{tech.value}</span>
<span className={`text-xs px-2 py-1 rounded flex items-center space-x-1 ${
tech.status === 'optimized' ? 'bg-green-500/20 text-green-400' :
tech.status === 'processing' ? 'bg-yellow-500/20 text-yellow-400' :
'bg-blue-500/20 text-blue-400'
}`}>
<span>{tech.status}</span>
</span>
</div>
))}
</div>
{/* 渲染进度 */}
{currentContent.renderOutput && (
<div className="mt-4 pt-4 border-t border-emerald-500/30">
<div className="text-center mb-3">
<div className="text-2xl font-mono text-emerald-400 mb-1">
{Math.round((currentContent.renderOutput.currentFrame / currentContent.renderOutput.totalFrames) * 100)}%
</div>
<div className="text-sm text-gray-400"></div>
</div>
<div className="text-xs text-center space-y-1">
<div className="text-white">
: {currentContent.renderOutput.currentFrame}/{currentContent.renderOutput.totalFrames}
</div>
<div className="text-emerald-400">
: {currentContent.renderOutput.quality} | {currentContent.renderOutput.estimated}
</div>
</div>
</div>
)}
</>
) : (
<>
<div className="space-y-2">
{Array.from({length: 4}, (_, i) => (
<SkeletonCard key={i} className="h-10 bg-emerald-500/20 rounded border border-emerald-500/30" />
))}
</div>
<div className="mt-4 pt-4 border-t border-emerald-500/30">
<SkeletonCard className="h-20 bg-emerald-500/20 rounded-lg border border-emerald-500/30" />
</div>
</>
)}
</div>
</div>
</div>
);
};
export default VisualDirector;