2025-07-04 15:46:31 +08:00

386 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React from 'react';
import { motion } from 'framer-motion';
import { Skeleton } from '@/components/ui/skeleton';
import {
Image,
Video,
CheckCircle,
Music,
Loader2,
User,
Scissors,
Tv
} from 'lucide-react';
interface TaskInfoProps {
isLoading: boolean;
taskObject: any;
currentLoadingText: string;
dataLoadError?: string | null;
}
// 根据加载文本返回对应的图标
const getStageIcon = (loadingText: string) => {
const text = loadingText.toLowerCase();
if (text.includes('sketch') || text.includes('草图')) {
return Image;
} else if (text.includes('video') || text.includes('视频')) {
return Video;
} else if (text.includes('character') || text.includes('角色')) {
return User;
} else if (text.includes('audio') || text.includes('音频')) {
return Music;
} else if (text.includes('post') || text.includes('后期')) {
return Scissors;
} else if (text.includes('final') || text.includes('最终')) {
return Tv;
} else if (text.includes('complete') || text.includes('完成')) {
return CheckCircle;
} else {
return Loader2;
}
};
export function TaskInfo({ isLoading, taskObject, currentLoadingText, dataLoadError }: TaskInfoProps) {
const StageIcon = getStageIcon(currentLoadingText);
if (isLoading) {
return (
<>
<motion.div
className="title-JtMejk text-center"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
{taskObject?.projectName ?
`${taskObject.projectName}${taskObject.taskName}` :
'正在加载项目信息...'
}
</motion.div>
{/* 加载状态显示 */}
<motion.div
className="flex items-center gap-2 justify-center mt-2"
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.div
className="flex items-center gap-2"
key={currentLoadingText}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 10 }}
transition={{ duration: 0.3 }}
>
<motion.div
className="text-blue-500"
animate={{
rotate: [0, 360],
scale: [1, 1.1, 1]
}}
transition={{
rotate: { duration: 2, repeat: Infinity, ease: "linear" },
scale: { duration: 1.5, repeat: Infinity, ease: "easeInOut" }
}}
>
<StageIcon className="w-5 h-5" />
</motion.div>
<motion.span
className="normalS400 subtitle-had8uE text-transparent bg-clip-text bg-gradient-to-r from-blue-600 via-cyan-500 to-purple-600"
animate={{
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "linear"
}}
style={{
backgroundSize: "300% 300%",
}}
>
{currentLoadingText}
</motion.span>
</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,
delay: 0.3
}}
/>
</motion.div>
{/* 错误提示 */}
{dataLoadError && (
<motion.div
className="mt-3 text-orange-600 text-sm text-center flex items-center justify-center gap-2"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<span className="w-2 h-2 bg-orange-500 rounded-full animate-pulse"></span>
{dataLoadError}
</motion.div>
)}
</>
);
}
return (
<>
<div className="title-JtMejk">
{taskObject?.projectName}{taskObject?.taskName}
</div>
{currentLoadingText === 'Task completed' ? (
<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-2"
initial="hidden"
animate="visible"
variants={{
hidden: { opacity: 0 },
visible: { opacity: 1 }
}}
>
<motion.div
className="text-emerald-500"
variants={{
hidden: { opacity: 0, scale: 0.8 },
visible: { opacity: 1, scale: 1 }
}}
transition={{ duration: 0.5 }}
>
<CheckCircle className="w-5 h-5" />
</motion.div>
<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 }}
>
<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.div
className="flex items-center gap-2"
key={currentLoadingText}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 10 }}
transition={{ duration: 0.3 }}
>
<motion.div
className="text-blue-500"
animate={{
rotate: [0, 360],
scale: [1, 1.1, 1]
}}
transition={{
scale: { duration: 1.5, repeat: Infinity, ease: "easeInOut" }
}}
>
<StageIcon className="w-5 h-5" />
</motion.div>
<motion.div
className="relative"
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 10 }}
transition={{ duration: 0.3 }}
>
{/* 背景发光效果 */}
<motion.div
className="absolute inset-0 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-purple-400 blur-sm"
animate={{
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "linear"
}}
style={{
backgroundSize: "200% 200%",
}}
>
<span className="normalS400 subtitle-had8uE">{currentLoadingText}</span>
</motion.div>
{/* 主文字 - 颜色填充动画 */}
<motion.div
className="relative z-10"
animate={{
scale: [1, 1.02, 1],
}}
transition={{
duration: 1.5,
repeat: Infinity,
ease: "easeInOut"
}}
>
<motion.span
className="normalS400 subtitle-had8uE text-transparent bg-clip-text bg-gradient-to-r from-blue-600 via-cyan-500 to-purple-600"
animate={{
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "linear"
}}
style={{
backgroundSize: "300% 300%",
}}
>
{currentLoadingText}
</motion.span>
</motion.div>
{/* 动态光点效果 */}
<motion.div
className="absolute left-0 top-1/2 transform -translate-y-1/2 w-2 h-2 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full blur-sm"
animate={{
x: [0, 200, 0],
opacity: [0, 1, 0],
scale: [0.5, 1, 0.5],
}}
transition={{
duration: 2.5,
repeat: Infinity,
ease: "easeInOut",
}}
/>
{/* 文字底部装饰线 */}
<motion.div
className="absolute bottom-0 left-0 h-0.5 bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500"
animate={{
width: ["0%", "100%", "0%"],
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
}}
transition={{
width: { duration: 2, repeat: Infinity, ease: "easeInOut" },
backgroundPosition: { duration: 1.5, repeat: Infinity, ease: "linear" }
}}
style={{
backgroundSize: "200% 200%",
}}
/>
</motion.div>
</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,
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>
)}
</>
);
}