forked from 77media/video-flow
3-调整动画
This commit is contained in:
parent
8d85eee872
commit
39c5e99c88
@ -58,7 +58,7 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
.videoContainer-qteKNi {
|
||||
flex: 3;
|
||||
/* flex: 3; */
|
||||
min-height: 0;
|
||||
display: flex
|
||||
;
|
||||
|
||||
@ -524,46 +524,114 @@ export default function WorkFlow() {
|
||||
}, [isLoading, currentStep, isGeneratingSketch, sketchCount, isGeneratingVideo, taskVideos.length, taskSketch.length]);
|
||||
|
||||
const renderSketchContent = () => {
|
||||
if (!taskObject) {
|
||||
|
||||
// 展示最终成片
|
||||
if (Number(currentStep) === 6) {
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-black/40 via-black/20 to-black/40 backdrop-blur-sm rounded-lg overflow-hidden">
|
||||
<motion.div
|
||||
className="flex flex-col items-center gap-4"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="relative w-full h-full rounded-lg overflow-hidden" onMouseEnter={() => setShowControls(true)} onMouseLeave={() => setShowControls(false)}>
|
||||
<div className="relative w-full h-full">
|
||||
{/* 背景模糊的视频 */}
|
||||
<motion.div
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 360],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
className="absolute inset-0 overflow-hidden"
|
||||
initial={{ filter: "blur(0px)", scale: 1, opacity: 1 }}
|
||||
animate={{ filter: "blur(20px)", scale: 1.1, opacity: 0.5 }}
|
||||
transition={{ duration: 0.8, ease: "easeInOut" }}
|
||||
>
|
||||
<Loader2 className="w-8 h-8 text-blue-500" />
|
||||
<video
|
||||
className="w-full h-full rounded-lg object-cover object-center"
|
||||
src={taskVideos[currentSketchIndex]?.url}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
/>
|
||||
</motion.div>
|
||||
<motion.p
|
||||
className="text-sm text-white/70"
|
||||
animate={{
|
||||
opacity: [0.5, 1, 0.5],
|
||||
}}
|
||||
|
||||
{/* 最终成片视频 */}
|
||||
<motion.div
|
||||
initial={{ clipPath: "inset(0 50% 0 50%)", filter: "blur(10px)" }}
|
||||
animate={{ clipPath: "inset(0 0% 0 0%)", filter: "blur(0px)" }}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
clipPath: { duration: 1.2, ease: [0.43, 0.13, 0.23, 0.96] },
|
||||
filter: { duration: 0.6, delay: 0.3 }
|
||||
}}
|
||||
className="relative z-10"
|
||||
>
|
||||
加载中...
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
<video
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
src={MOCK_FINAL_VIDEO.url}
|
||||
poster={MOCK_FINAL_VIDEO.thumbnail}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
{/* 操作按钮组 */}
|
||||
<AnimatePresence>
|
||||
{showControls && (
|
||||
<>
|
||||
{/* 顶部按钮组 */}
|
||||
<motion.div
|
||||
className="absolute top-4 right-4 z-10 flex gap-2"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<GlassIconButton
|
||||
icon={Edit3}
|
||||
tooltip="编辑分镜"
|
||||
onClick={() => handleEditModalOpen('4')}
|
||||
/>
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* 视频信息浮层 */}
|
||||
<motion.div
|
||||
className="absolute bottom-0 left-0 right-0 z-10 p-4 bg-gradient-to-t from-black/80 via-black/40 to-transparent"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 1, duration: 0.6 }}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<motion.div
|
||||
className="w-2 h-2 rounded-full bg-emerald-500"
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
opacity: [1, 0.6, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
<span className="text-sm font-medium text-white/90">最终成片</span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* 完成标记 */}
|
||||
<motion.div
|
||||
className="absolute top-4 right-4 px-3 py-1.5 rounded-full bg-emerald-500/20 backdrop-blur-sm
|
||||
border border-emerald-500/30 text-emerald-400 text-sm font-medium"
|
||||
initial={{ opacity: 0, scale: 0.8, x: 20 }}
|
||||
animate={{ opacity: 1, scale: 1, x: 0 }}
|
||||
transition={{ delay: 1.2, duration: 0.6 }}
|
||||
>
|
||||
制作完成
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 展示分镜视频
|
||||
if (Number(currentStep) > 2 && Number(currentStep) < 6) {
|
||||
return (
|
||||
<div
|
||||
@ -574,102 +642,71 @@ export default function WorkFlow() {
|
||||
{taskVideos[currentSketchIndex] ? (
|
||||
<ProgressiveReveal
|
||||
className="w-full h-full rounded-lg"
|
||||
{...presets.main}
|
||||
>
|
||||
<video
|
||||
ref={mainVideoRef}
|
||||
key={taskVideos[currentSketchIndex].url}
|
||||
className="w-full h-full rounded-lg object-cover object-center"
|
||||
src={taskVideos[currentSketchIndex].url}
|
||||
autoPlay={isVideoPlaying}
|
||||
muted
|
||||
loop={false}
|
||||
playsInline
|
||||
poster={taskSketch[currentSketchIndex]?.url}
|
||||
onEnded={() => {
|
||||
if (isVideoPlaying) {
|
||||
setCurrentSketchIndex(prev => (prev + 1) % taskVideos.length);
|
||||
customVariants={{
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
filter: "blur(20px)",
|
||||
clipPath: "inset(0 100% 0 0)"
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
filter: "blur(0px)",
|
||||
clipPath: "inset(0 0% 0 0)",
|
||||
transition: {
|
||||
duration: 1,
|
||||
ease: [0.43, 0.13, 0.23, 0.96],
|
||||
opacity: { duration: 0.8, ease: "easeOut" },
|
||||
filter: { duration: 0.6, ease: "easeOut" },
|
||||
clipPath: { duration: 0.8, ease: "easeInOut" }
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="relative w-full h-full">
|
||||
{/* 背景模糊的图片 */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<img
|
||||
className="w-full h-full object-cover filter blur-lg scale-110 opacity-50"
|
||||
src={taskSketch[currentSketchIndex]?.url}
|
||||
alt="background"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 视频 */}
|
||||
<motion.div
|
||||
initial={{ clipPath: "inset(0 100% 0 0)" }}
|
||||
animate={{ clipPath: "inset(0 0% 0 0)" }}
|
||||
transition={{ duration: 0.8, ease: [0.43, 0.13, 0.23, 0.96] }}
|
||||
className="relative z-10"
|
||||
>
|
||||
<video
|
||||
ref={mainVideoRef}
|
||||
key={taskVideos[currentSketchIndex].url}
|
||||
className="w-full h-full rounded-lg object-cover object-center"
|
||||
src={taskVideos[currentSketchIndex].url}
|
||||
autoPlay={isVideoPlaying}
|
||||
muted
|
||||
loop={false}
|
||||
playsInline
|
||||
poster={taskSketch[currentSketchIndex]?.url}
|
||||
onEnded={() => {
|
||||
if (isVideoPlaying) {
|
||||
setCurrentSketchIndex(prev => (prev + 1) % taskVideos.length);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</ProgressiveReveal>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center rounded-lg overflow-hidden relative">
|
||||
{/* 动态渐变背景 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 5,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
{/* 保持显示当前分镜草图 */}
|
||||
<img
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
src={taskSketch[currentSketchIndex]?.url}
|
||||
alt={`分镜草图 ${currentSketchIndex + 1}`}
|
||||
/>
|
||||
{/* 动态光效 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 opacity-50"
|
||||
style={{
|
||||
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
|
||||
}}
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="flex flex-col items-center gap-4 relative z-10"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<div className="relative">
|
||||
<motion.div
|
||||
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 180, 360],
|
||||
}}
|
||||
transition={{
|
||||
duration: 4,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
animate={{
|
||||
rotate: [0, 360],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
>
|
||||
</motion.div>
|
||||
</div>
|
||||
<motion.p
|
||||
className="text-sm text-white font-medium"
|
||||
animate={{
|
||||
opacity: [0.7, 1, 0.7],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
>
|
||||
正在生成分镜视频 {taskVideos.length + 1}/{taskSketch.length}
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -690,11 +727,6 @@ export default function WorkFlow() {
|
||||
tooltip="编辑分镜"
|
||||
onClick={() => handleEditModalOpen('3')}
|
||||
/>
|
||||
{/* <GlassIconButton
|
||||
icon={FileText}
|
||||
tooltip="显示脚本"
|
||||
onClick={() => console.log('显示脚本')}
|
||||
/> */}
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
@ -726,101 +758,7 @@ export default function WorkFlow() {
|
||||
);
|
||||
}
|
||||
|
||||
// 展示最终成片
|
||||
if (Number(currentStep) === 6) {
|
||||
return (
|
||||
<div className="relative w-full h-full rounded-lg overflow-hidden">
|
||||
<ProgressiveReveal
|
||||
className="w-full h-full rounded-lg"
|
||||
customVariants={{
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
filter: "blur(20px)",
|
||||
clipPath: "inset(0 50% 0 50%)"
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
filter: "blur(0px)",
|
||||
clipPath: "inset(0 0% 0 0%)",
|
||||
transition: {
|
||||
duration: 1.2,
|
||||
ease: [0.43, 0.13, 0.23, 0.96], // 自定义缓动函数
|
||||
opacity: { duration: 0.8, ease: "easeOut" },
|
||||
filter: { duration: 0.6, ease: "easeOut" },
|
||||
clipPath: { duration: 1, ease: "easeInOut", delay: 0.2 }
|
||||
}
|
||||
}
|
||||
}}
|
||||
loadingBgConfig={{
|
||||
fromColor: 'from-emerald-300',
|
||||
viaColor: 'via-cyan-400',
|
||||
toColor: 'to-blue-500',
|
||||
glowOpacity: 0.6,
|
||||
duration: 6
|
||||
}}
|
||||
>
|
||||
<div className="relative w-full h-full">
|
||||
{/* 最终成片视频 */}
|
||||
<video
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
src={MOCK_FINAL_VIDEO.url}
|
||||
poster={MOCK_FINAL_VIDEO.thumbnail}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
/>
|
||||
|
||||
{/* 视频信息浮层 */}
|
||||
<motion.div
|
||||
className="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/80 via-black/40 to-transparent"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 1, duration: 0.6 }}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<motion.div
|
||||
className="w-2 h-2 rounded-full bg-emerald-500"
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
opacity: [1, 0.6, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
<span className="text-sm font-medium text-white/90">最终成片</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<GlassIconButton
|
||||
icon={Edit3}
|
||||
tooltip="编辑成片"
|
||||
onClick={() => handleEditModalOpen('4')}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* 完成标记 */}
|
||||
<motion.div
|
||||
className="absolute top-4 right-4 px-3 py-1.5 rounded-full bg-emerald-500/20 backdrop-blur-sm
|
||||
border border-emerald-500/30 text-emerald-400 text-sm font-medium"
|
||||
initial={{ opacity: 0, scale: 0.8, x: 20 }}
|
||||
animate={{ opacity: 1, scale: 1, x: 0 }}
|
||||
transition={{ delay: 1.2, duration: 0.6 }}
|
||||
>
|
||||
制作完成
|
||||
</motion.div>
|
||||
</div>
|
||||
</ProgressiveReveal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 展示分镜草图
|
||||
return (
|
||||
<div
|
||||
className="relative w-full h-full rounded-lg"
|
||||
@ -890,31 +828,7 @@ export default function WorkFlow() {
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
animate={{
|
||||
rotate: [0, 360],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
>
|
||||
</motion.div>
|
||||
</div>
|
||||
<motion.p
|
||||
className="text-sm text-white font-medium"
|
||||
animate={{
|
||||
opacity: [0.7, 1, 0.7],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
>
|
||||
正在生成分镜草图 {sketchCount + 1}/{MOCK_SKETCH_COUNT}
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
</div>
|
||||
)}
|
||||
@ -936,11 +850,6 @@ export default function WorkFlow() {
|
||||
tooltip="编辑分镜"
|
||||
onClick={() => handleEditModalOpen('1')}
|
||||
/>
|
||||
{/* <GlassIconButton
|
||||
icon={FileText}
|
||||
tooltip="显示脚本"
|
||||
onClick={() => console.log('显示脚本')}
|
||||
/> */}
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
@ -968,7 +877,6 @@ export default function WorkFlow() {
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
|
||||
{/* 播放进度指示器 */}
|
||||
<AnimatePresence>
|
||||
@ -1003,67 +911,122 @@ export default function WorkFlow() {
|
||||
<>
|
||||
<div className="title-JtMejk">{taskObject?.projectName}:{taskObject?.taskName}</div>
|
||||
{/* 实时反馈当前 currentLoadingText */}
|
||||
<motion.div
|
||||
className="flex items-center gap-2 justify-center"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2
|
||||
}}
|
||||
/>
|
||||
<motion.p
|
||||
className="normalS400 subtitle-had8uE text-blue-500/80"
|
||||
key={currentLoadingText}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: 10 }}
|
||||
{currentLoadingText === '任务完成' ? (
|
||||
<motion.div
|
||||
className="flex items-center gap-3 justify-center"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<motion.div
|
||||
className="w-2 h-2 rounded-full bg-emerald-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="flex items-center gap-1.5"
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
hidden: { opacity: 0 },
|
||||
visible: { opacity: 1 }
|
||||
}}
|
||||
>
|
||||
<motion.span
|
||||
className="text-emerald-500 font-medium"
|
||||
variants={{
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: { opacity: 1, y: 0 }
|
||||
}}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
{currentLoadingText}
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
className="w-2 h-2 rounded-full bg-emerald-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2,
|
||||
delay: 0.3
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
className="flex items-center gap-2 justify-center"
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
{currentLoadingText}
|
||||
</motion.p>
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2,
|
||||
delay: 0.3
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2,
|
||||
delay: 0.6
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2
|
||||
}}
|
||||
/>
|
||||
<motion.p
|
||||
className="normalS400 subtitle-had8uE text-blue-500/80"
|
||||
key={currentLoadingText}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: 10 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
{currentLoadingText}
|
||||
</motion.p>
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2,
|
||||
delay: 0.3
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
opacity: [1, 0.5, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
repeatDelay: 0.2,
|
||||
delay: 0.6
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="media-Ocdu1O">
|
||||
<div className="videoContainer-qteKNi" ref={containerRef}>
|
||||
<div className="videoContainer-qteKNi" style={currentStep !== '6' ? { flex: 3 } : {}} ref={containerRef}>
|
||||
{isLoading ? (
|
||||
<Skeleton className="w-full aspect-video rounded-lg" />
|
||||
) : (
|
||||
@ -1091,169 +1054,132 @@ export default function WorkFlow() {
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseLeave={() => setIsDragging(false)}
|
||||
>
|
||||
{(Number(currentStep) > 2 && Number(currentStep) < 6) ? (
|
||||
{Number(currentStep) === 6 ? null : (
|
||||
<>
|
||||
{renderedVideos}
|
||||
{isGeneratingVideo && taskVideos.length < taskSketch.length && (
|
||||
<motion.div
|
||||
className="relative aspect-video rounded-lg overflow-hidden"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
{/* 动态渐变背景 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 5,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
/>
|
||||
{/* 动态光效 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 opacity-50"
|
||||
style={{
|
||||
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
|
||||
}}
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="relative">
|
||||
<motion.div
|
||||
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 180, 360],
|
||||
{(Number(currentStep) > 2 && Number(currentStep) < 6) ? (
|
||||
<>
|
||||
{taskSketch.map((sketch, index) => (
|
||||
<div
|
||||
key={`video-${index}`}
|
||||
className={`relative aspect-video rounded-lg overflow-hidden
|
||||
${currentSketchIndex === index ? 'ring-2 ring-blue-500 z-10' : 'hover:ring-2 hover:ring-blue-500/50'}`}
|
||||
onClick={() => !isDragging && setCurrentSketchIndex(index)}
|
||||
>
|
||||
<ProgressiveReveal
|
||||
{...presets.thumbnail}
|
||||
delay={index * 0.1}
|
||||
customVariants={{
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
scale: 0.95,
|
||||
filter: "blur(10px)"
|
||||
},
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
filter: "blur(0px)",
|
||||
transition: {
|
||||
duration: 0.8,
|
||||
ease: [0.23, 1, 0.32, 1],
|
||||
opacity: { duration: 0.6, ease: "easeInOut" },
|
||||
scale: { duration: 1, ease: "easeOut" },
|
||||
filter: { duration: 0.8, ease: "easeOut", delay: 0.2 }
|
||||
}
|
||||
}
|
||||
}}
|
||||
transition={{
|
||||
duration: 4,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
animate={{
|
||||
rotate: [0, 360],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
loadingBgConfig={{
|
||||
...presets.thumbnail.loadingBgConfig,
|
||||
glowOpacity: 0.4,
|
||||
duration: 4
|
||||
}}
|
||||
>
|
||||
</motion.div>
|
||||
<div className="w-full h-full transform hover:scale-105 transition-transform duration-500">
|
||||
{taskVideos[index] ? (
|
||||
<video
|
||||
className="w-full h-full object-cover"
|
||||
src={taskVideos[index].url}
|
||||
muted
|
||||
playsInline
|
||||
loop
|
||||
poster={sketch.url}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
className="w-full h-full object-cover"
|
||||
src={sketch.url}
|
||||
alt={`缩略图 ${index + 1}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ProgressiveReveal>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
|
||||
<span className="text-xs text-white/90">场景 {index + 1}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
|
||||
<span className="text-xs text-white/90">场景 {taskVideos.length + 1}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
) : Number(currentStep) === 6 ? (
|
||||
<motion.div
|
||||
className="relative aspect-video rounded-lg overflow-hidden"
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.6, delay: 1.4 }}
|
||||
>
|
||||
<video
|
||||
className="w-full h-full object-cover"
|
||||
src={MOCK_FINAL_VIDEO.url}
|
||||
poster={MOCK_FINAL_VIDEO.thumbnail}
|
||||
muted
|
||||
playsInline
|
||||
loop
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-black/40 backdrop-blur-sm">
|
||||
<span className="text-sm font-medium text-white">最终成片</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
) : (
|
||||
<>
|
||||
{renderedSketches}
|
||||
{isGeneratingSketch && sketchCount < MOCK_SKETCH_COUNT && (
|
||||
<motion.div
|
||||
className="relative aspect-video rounded-lg overflow-hidden"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
{/* 动态渐变背景 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 5,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
/>
|
||||
{/* 动态光效 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 opacity-50"
|
||||
style={{
|
||||
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
|
||||
}}
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="relative">
|
||||
<motion.div
|
||||
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 180, 360],
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{renderedSketches}
|
||||
{isGeneratingSketch && sketchCount < MOCK_SKETCH_COUNT && (
|
||||
<motion.div
|
||||
className="relative aspect-video rounded-lg overflow-hidden"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
{/* 动态渐变背景 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-gradient-to-r from-cyan-300 via-sky-400 to-blue-500"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 4,
|
||||
transition={{
|
||||
duration: 5,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
animate={{
|
||||
rotate: [0, 360],
|
||||
{/* 动态光效 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 opacity-50"
|
||||
style={{
|
||||
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
|
||||
}}
|
||||
transition={{
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
|
||||
<span className="text-xs text-white/90">场景 {sketchCount + 1}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
/>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="relative">
|
||||
<motion.div
|
||||
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 180, 360],
|
||||
}}
|
||||
transition={{
|
||||
duration: 4,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
|
||||
<span className="text-xs text-white/90">场景 {sketchCount + 1}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user