| | |
| | | /* 基础颜色设置 */ |
| | | --background: var(--ai-surface); |
| | | --foreground: #1E2B63; |
| | | --foreground-rgb: 255, 255, 255; |
| | | --background-start-rgb: 10, 16, 51; |
| | | --background-end-rgb: 0, 0, 0; |
| | | --scrollbar-track: rgba(30, 43, 99, 0.1); |
| | | --scrollbar-thumb: rgba(106, 219, 255, 0.3); |
| | | } |
| | | |
| | | @theme inline { |
| | |
| | | :root { |
| | | --background: var(--ai-dark); |
| | | --foreground: #E9EFFD; |
| | | --foreground-rgb: 255, 255, 255; |
| | | --background-start-rgb: 0, 0, 0; |
| | | --background-end-rgb: 0, 0, 0; |
| | | } |
| | | } |
| | | |
| | | body { |
| | | background: var(--background); |
| | | color: var(--foreground); |
| | | background: linear-gradient(to bottom, |
| | | rgb(var(--background-start-rgb)), |
| | | rgb(var(--background-end-rgb))); |
| | | color: rgb(var(--foreground-rgb)); |
| | | font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | /* 滚动性能优化 */ |
| | | * { |
| | | -webkit-font-smoothing: antialiased; |
| | | -moz-osx-font-smoothing: grayscale; |
| | | } |
| | | |
| | | html, body { |
| | | scroll-behavior: smooth; |
| | | } |
| | | |
| | | /* 启用硬件加速 */ |
| | | .will-change-transform, |
| | | .motion-safe\:will-change-transform, |
| | | .motion-safe\:hover\:will-change-transform:hover, |
| | | canvas { |
| | | will-change: transform, opacity; |
| | | transform: translateZ(0); |
| | | backface-visibility: hidden; |
| | | } |
| | | |
| | | /* 优化滚动条 */ |
| | | ::-webkit-scrollbar { |
| | | width: 10px; |
| | | } |
| | | |
| | | ::-webkit-scrollbar-track { |
| | | background: var(--scrollbar-track); |
| | | } |
| | | |
| | | ::-webkit-scrollbar-thumb { |
| | | background: var(--scrollbar-thumb); |
| | | border-radius: 5px; |
| | | } |
| | | |
| | | ::-webkit-scrollbar-thumb:hover { |
| | | background: rgba(106, 219, 255, 0.5); |
| | | } |
| | | |
| | | /* 滚动优化类 */ |
| | | .smooth-scroll { |
| | | overflow-y: scroll; |
| | | scroll-behavior: smooth; |
| | | -webkit-overflow-scrolling: touch; |
| | | } |
| | | |
| | | /* 防止过度重排和重绘 */ |
| | | .motion-reduce { |
| | | transition-duration: 0.01ms !important; |
| | | animation-duration: 0.01ms !important; |
| | | animation-iteration-count: 1 !important; |
| | | } |
| | | |
| | | /* 导航栏特效样式 */ |
| | |
| | | children: React.ReactNode; |
| | | }) { |
| | | return ( |
| | | <html lang="zh"> |
| | | <body className={inter.className}> |
| | | <html lang="zh-CN" className="smooth-scroll"> |
| | | <body className={`${inter.className} overflow-x-hidden`}> |
| | | <ClientLayoutContent>{children}</ClientLayoutContent> |
| | | </body> |
| | | </html> |
| | |
| | | // 定义动画变体 |
| | | const fadeInUp = { |
| | | hidden: { opacity: 0, y: 50 }, |
| | | visible: { opacity: 1, y: 0, transition: { duration: 0.8, ease: "easeOut" } } |
| | | visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: "easeOut" } } |
| | | }; |
| | | |
| | | const fadeInLeft = { |
| | | hidden: { opacity: 0, x: -100 }, |
| | | visible: { opacity: 1, x: 0, transition: { duration: 0.7, ease: [0.25, 0.1, 0.25, 1] } } |
| | | visible: { opacity: 1, x: 0, transition: { duration: 0.5, ease: [0.25, 0.1, 0.25, 1] } } |
| | | }; |
| | | |
| | | const fadeInRight = { |
| | | hidden: { opacity: 0, x: 100 }, |
| | | visible: { opacity: 1, x: 0, transition: { duration: 0.7, ease: [0.25, 0.1, 0.25, 1] } } |
| | | visible: { opacity: 1, x: 0, transition: { duration: 0.5, ease: [0.25, 0.1, 0.25, 1] } } |
| | | }; |
| | | |
| | | const fadeInScale = { |
| | | hidden: { opacity: 0, scale: 0.95 }, |
| | | visible: { opacity: 1, scale: 1, transition: { duration: 0.8, ease: "easeOut" } } |
| | | visible: { opacity: 1, scale: 1, transition: { duration: 0.6, ease: "easeOut" } } |
| | | }; |
| | | |
| | | // 按钮出场动画 |
| | |
| | | opacity: 1, |
| | | y: 0, |
| | | transition: { |
| | | delay: i * 0.2, |
| | | duration: 0.6, |
| | | delay: i * 0.15, |
| | | duration: 0.4, |
| | | ease: [0.25, 0.1, 0.25, 1], |
| | | }, |
| | | }), |
| | |
| | | {/* 公司名称和目标描述 */} |
| | | <motion.div |
| | | initial={{ opacity: 0, y: 30 }} |
| | | animate={{ opacity: 1, y: 0 }} |
| | | transition={{ duration: 0.8, ease: "easeOut" }} |
| | | className="text-center mb-32 relative" |
| | | whileInView={{ opacity: 1, y: 0 }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.6, ease: "easeOut" }} |
| | | className="text-center mb-32 relative will-change-transform" |
| | | > |
| | | {/* 背景装饰效果 */} |
| | | <div className="absolute inset-0 -z-10 overflow-hidden pointer-events-none"> |
| | | <motion.div |
| | | className="absolute top-1/2 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-[#6ADBFF]/30 to-transparent" |
| | | initial={{ scaleX: 0 }} |
| | | animate={{ scaleX: 1 }} |
| | | whileInView={{ scaleX: 1 }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 1.2, delay: 0.3 }} |
| | | /> |
| | | <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"> |
| | | {[...Array(3)].map((_, i) => ( |
| | | {[...Array(2)].map((_, i) => ( |
| | | <motion.div |
| | | key={i} |
| | | className="absolute rounded-full border border-[#6ADBFF]/20" |
| | |
| | | top: "50%", |
| | | width: "160px", |
| | | height: "160px", |
| | | willChange: "transform, opacity" |
| | | }} |
| | | initial={{ scale: 0, x: "-50%", y: "-50%", opacity: 0.1 }} |
| | | animate={{ scale: [0, 5 + i], opacity: [0.2, 0] }} |
| | | whileInView={{ scale: [0, 5 + i], opacity: [0.2, 0] }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ |
| | | duration: 3, |
| | | repeat: Infinity, |
| | |
| | | <motion.h1 |
| | | className="text-4xl md:text-5xl font-bold mb-3 relative inline-block" |
| | | initial={{ opacity: 0, filter: "blur(10px)" }} |
| | | animate={{ opacity: 1, filter: "blur(0px)" }} |
| | | whileInView={{ opacity: 1, filter: "blur(0px)" }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.8, delay: 0.2 }} |
| | | > |
| | | <span className="text-transparent bg-clip-text bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB] relative"> |
| | |
| | | <motion.div |
| | | className="absolute inset-0 bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB]" |
| | | initial={{ scaleX: 0 }} |
| | | animate={{ scaleX: 1 }} |
| | | whileInView={{ scaleX: 1 }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.8, delay: 0.5, ease: "easeOut" }} |
| | | style={{ originX: 0 }} |
| | | /> |
| | |
| | | <motion.div |
| | | className="text-gray-300 max-w-2xl mx-auto text-lg relative" |
| | | initial={{ opacity: 0, y: 10 }} |
| | | animate={{ opacity: 1, y: 0 }} |
| | | whileInView={{ opacity: 1, y: 0 }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.6, delay: 0.7 }} |
| | | > |
| | | 智能化供应链管理, |
| | | <motion.span |
| | | className="inline-block text-[#6ADBFF] px-1" |
| | | initial={{ opacity: 0 }} |
| | | animate={{ opacity: 1 }} |
| | | whileInView={{ opacity: 1 }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.4, delay: 1.1 }} |
| | | > |
| | | AI模拟APS场景 |
| | |
| | | <motion.div |
| | | className="absolute left-1/2 bottom-[-22px] w-16 h-[2px] -translate-x-1/2" |
| | | initial={{ scale: 0 }} |
| | | animate={{ scale: 1 }} |
| | | whileInView={{ scale: 1 }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.5, delay: 1.2 }} |
| | | > |
| | | <div className="w-full h-full bg-gradient-to-r from-[#6ADBFF]/0 via-[#6ADBFF] to-[#6ADBFF]/0"></div> |
| | |
| | | custom={0} |
| | | initial="hidden" |
| | | whileInView="visible" |
| | | viewport={{ once: false, margin: "-150px" }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | variants={buttonVariants} |
| | | whileTap={{ scale: 0.97, transition: { duration: 0.1 } }} |
| | | className="group relative" |
| | | className="group relative will-change-transform" |
| | | > |
| | | <div className="absolute -inset-0.5 rounded-xl bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB] opacity-30 blur group-hover:opacity-100 group-hover:blur-md transition-all duration-500 group-hover:duration-200 group-active:opacity-70"></div> |
| | | <div className="relative flex items-center gap-2 px-10 py-4 rounded-lg backdrop-blur-sm bg-[#131C41]/90 border border-[#6ADBFF]/30 transition-all duration-300 shadow-[0_0_15px_rgba(106,219,255,0.15)] group-hover:shadow-[0_0_25px_rgba(106,219,255,0.25)] group-active:shadow-[0_0_10px_rgba(106,219,255,0.3)]"> |
| | |
| | | custom={1} |
| | | initial="hidden" |
| | | whileInView="visible" |
| | | viewport={{ once: false, margin: "-150px" }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | variants={buttonVariants} |
| | | whileTap={{ scale: 0.97, transition: { duration: 0.1 } }} |
| | | className="group relative" |
| | | className="group relative will-change-transform" |
| | | > |
| | | <div className="absolute -inset-0.5 rounded-xl bg-gradient-to-r from-[#FF6A88] to-[#5E72EB] opacity-30 blur group-hover:opacity-100 group-hover:blur-md transition-all duration-500 group-hover:duration-200 group-active:opacity-70"></div> |
| | | <div className="relative flex items-center gap-2 px-10 py-4 rounded-lg backdrop-blur-sm bg-[#131C41]/90 border border-[#FF6A88]/30 transition-all duration-300 shadow-[0_0_15px_rgba(255,106,136,0.15)] group-hover:shadow-[0_0_25px_rgba(255,106,136,0.25)] group-active:shadow-[0_0_10px_rgba(255,106,136,0.3)]"> |
| | |
| | | <motion.div |
| | | initial="hidden" |
| | | whileInView="visible" |
| | | viewport={{ once: false, margin: "-150px" }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | variants={fadeInLeft} |
| | | className="relative" |
| | | className="relative will-change-transform" |
| | | > |
| | | <div className="absolute -left-3 top-0 h-full w-1 bg-gradient-to-b from-[#6ADBFF] via-[#5E72EB] to-transparent"></div> |
| | | <div className="backdrop-blur-sm bg-white/5 rounded-xl p-8 border border-[#6ADBFF]/20 h-full"> |
| | |
| | | <motion.div |
| | | initial="hidden" |
| | | whileInView="visible" |
| | | viewport={{ once: false, margin: "-150px" }} |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | variants={fadeInRight} |
| | | className="relative" |
| | | className="relative will-change-transform" |
| | | > |
| | | <div className="absolute -left-3 top-0 h-full w-1 bg-gradient-to-b from-[#FF6A88] via-[#5E72EB] to-transparent"></div> |
| | | <div className="backdrop-blur-sm bg-white/5 rounded-xl p-8 border border-[#FF6A88]/20 h-full"> |
| | |
| | | <motion.div |
| | | initial={{ opacity: 0, y: 40 }} |
| | | whileInView={{ opacity: 1, y: 0 }} |
| | | viewport={{ once: false, margin: "-150px" }} |
| | | transition={{ duration: 0.7, ease: [0.25, 0.1, 0.25, 1], delay: 0.2 }} |
| | | className="mt-20 w-full grid grid-cols-2 md:grid-cols-4 gap-8" |
| | | viewport={{ once: false, margin: "-100px" }} |
| | | transition={{ duration: 0.5, ease: [0.25, 0.1, 0.25, 1], delay: 0.2 }} |
| | | className="mt-20 w-full grid grid-cols-2 md:grid-cols-4 gap-8 will-change-transform" |
| | | > |
| | | <div className="text-center"> |
| | | <div className="text-4xl font-bold text-[#6ADBFF] mb-2">98%</div> |
| | |
| | | |
| | | export default function SupplyChainAIMindMap() { |
| | | const canvasRef = useRef<HTMLCanvasElement>(null); |
| | | const nodesRef = useRef<Node[]>([ |
| | | { x: 0.15, y: 0.3, label: '采购', color: '#6ADBFF', icon: '📦' }, |
| | | { x: 0.35, y: 0.3, label: '生产', color: '#5E72EB', icon: '🏭' }, |
| | | { x: 0.65, y: 0.3, label: '配送', color: '#FF6A88', icon: '🚚' }, |
| | | { x: 0.85, y: 0.3, label: '客户', color: '#FF9D6A', icon: '👥' }, |
| | | { x: 0.85, y: 0.6, label: '需求预测', color: '#FF6A88', icon: '📊' }, |
| | | { x: 0.5, y: 0.5, label: '智能分析引擎', color: '#5E72EB', isAI: true }, |
| | | ]); |
| | | |
| | | useEffect(() => { |
| | | const canvas = canvasRef.current; |
| | |
| | | targetY: endY, |
| | | size: Math.random() * 2 + 1, |
| | | color: path.color, |
| | | speed: 0.5 + Math.random() * 1, |
| | | speed: 0.5 + Math.random() * 0.5, // 降低速度 |
| | | energy: 1, |
| | | phase: Math.random() * Math.PI * 2, |
| | | orbitRadius: Math.random() * 20 + 10, |
| | | orbitSpeed: (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1), |
| | | orbitRadius: Math.random() * 15 + 5, // 减小轨道半径 |
| | | orbitSpeed: (Math.random() * 0.08 + 0.03) * (Math.random() < 0.5 ? 1 : -1), // 降低轨道速度 |
| | | pathIndex, |
| | | lifespan: 0, |
| | | maxLifespan: 150 + Math.random() * 100 |
| | | maxLifespan: 150 + Math.random() * 50 // 减少最大寿命 |
| | | }; |
| | | |
| | | particles.push(particle); |
| | | |
| | | // 限制粒子总数,防止性能问题 |
| | | if (particles.length > 30) { |
| | | particles.shift(); |
| | | } |
| | | }; |
| | | |
| | | // 更新量子粒子 |
| | |
| | | |
| | | // 绘制场景 |
| | | const drawScene = () => { |
| | | if (!ctx) return; |
| | | |
| | | // 清除画布 |
| | | ctx.clearRect(0, 0, canvas.width, canvas.height); |
| | | |
| | | // 绘制科技感背景 |
| | | drawTechBackground(); |
| | | // 减少重复计算,预先计算常用值 |
| | | const canvasWidth = canvas.width; |
| | | const canvasHeight = canvas.height; |
| | | const time = Date.now() * 0.001; |
| | | |
| | | // 绘制技术背景 |
| | | drawTechBackground(ctx, canvasWidth, canvasHeight, time); |
| | | |
| | | // 绘制能量场路径 |
| | | drawEnergyFields(); |
| | |
| | | |
| | | // 绘制量子粒子 |
| | | drawQuantumParticles(); |
| | | |
| | | // 绘制AI节点 |
| | | const aiNode = nodesRef.current.find(node => node.isAI); |
| | | if (aiNode) { |
| | | drawAINode(aiNode.x * canvasWidth, aiNode.y * canvasHeight); |
| | | } |
| | | }; |
| | | |
| | | // 绘制科技感背景 |
| | | const drawTechBackground = () => { |
| | | const drawTechBackground = (ctx: CanvasRenderingContext2D, canvasWidth: number, canvasHeight: number, time: number) => { |
| | | const gridSize = 40; |
| | | const time = Date.now() * 0.001; |
| | | |
| | | // 绘制动态网格 |
| | | // 降低网格密度,仅绘制较少的线条 |
| | | ctx.strokeStyle = 'rgba(70, 130, 180, 0.05)'; |
| | | ctx.lineWidth = 0.5; |
| | | |
| | | for (let y = 0; y < canvas.height; y += gridSize) { |
| | | // 降低网格线频率 |
| | | for (let y = 0; y < canvasHeight; y += gridSize * 1.5) { |
| | | ctx.beginPath(); |
| | | ctx.moveTo(0, y); |
| | | ctx.lineTo(canvas.width, y); |
| | | ctx.lineTo(canvasWidth, y); |
| | | ctx.stroke(); |
| | | |
| | | // 添加波动效果 |
| | | // 对波动效果采样率降低 |
| | | ctx.beginPath(); |
| | | for (let x = 0; x < canvas.width; x += 5) { |
| | | const wave = Math.sin(x * 0.02 + time + y * 0.01) * 2; |
| | | for (let x = 0; x < canvasWidth; x += 10) { |
| | | const wave = Math.sin(x * 0.01 + time + y * 0.005) * 2; |
| | | ctx.lineTo(x, y + wave); |
| | | } |
| | | ctx.strokeStyle = 'rgba(70, 130, 180, 0.02)'; |
| | | ctx.stroke(); |
| | | } |
| | | |
| | | for (let x = 0; x < canvas.width; x += gridSize) { |
| | | for (let x = 0; x < canvasWidth; x += gridSize * 1.5) { |
| | | ctx.beginPath(); |
| | | ctx.moveTo(x, 0); |
| | | ctx.lineTo(x, canvas.height); |
| | | ctx.lineTo(x, canvasHeight); |
| | | ctx.strokeStyle = 'rgba(70, 130, 180, 0.05)'; |
| | | ctx.stroke(); |
| | | } |
| | | |
| | | // 添加随机光点 |
| | | for (let i = 0; i < 15; i++) { |
| | | const x = Math.random() * canvas.width; |
| | | const y = Math.random() * canvas.height; |
| | | const size = 2 + Math.sin(time * 2 + i) * 1; |
| | | // 减少光点数量 |
| | | for (let i = 0; i < 10; i++) { |
| | | const x = Math.random() * canvasWidth; |
| | | const y = Math.random() * canvasHeight; |
| | | const size = 2 + Math.sin(time * 1.5 + i) * 1; |
| | | |
| | | const gradient = ctx.createRadialGradient(x, y, 0, x, y, size * 2); |
| | | gradient.addColorStop(0, 'rgba(106, 219, 255, 0.2)'); |
| | |
| | | |
| | | // 绘制节点 |
| | | const drawNodes = () => { |
| | | // 节点配置 |
| | | const nodes: Node[] = [ |
| | | { x: 0.15, y: 0.3, label: '采购', color: '#6ADBFF', icon: '📦' }, |
| | | { x: 0.35, y: 0.3, label: '生产', color: '#5E72EB', icon: '🏭' }, |
| | | { x: 0.65, y: 0.3, label: '配送', color: '#FF6A88', icon: '🚚' }, |
| | | { x: 0.85, y: 0.3, label: '客户', color: '#FF9D6A', icon: '👥' }, |
| | | { x: 0.85, y: 0.6, label: '需求预测', color: '#FF6A88', icon: '📊' }, |
| | | { x: 0.5, y: 0.5, label: '智能分析引擎', color: '#5E72EB', isAI: true }, |
| | | ]; |
| | | |
| | | // 使用引用中的节点数据 |
| | | const nodes = nodesRef.current; |
| | | const time = Date.now() * 0.001; |
| | | |
| | | nodes.forEach(node => { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // 初始化粒子系统 |
| | | // 初始化粒子 |
| | | const initParticles = () => { |
| | | for (let i = 0; i < 40; i++) { |
| | | // 减少初始粒子数量 |
| | | for (let i = 0; i < 20; i++) { |
| | | setTimeout(() => createQuantumParticle(), i * 100); |
| | | } |
| | | }; |
| | | |
| | | // 定期添加新粒子 |
| | | // 定期添加新粒子,降低频率 |
| | | const particleInterval = setInterval(() => { |
| | | if (particles.length < 50) { |
| | | if (particles.length < 30) { |
| | | createQuantumParticle(); |
| | | } |
| | | }, 500); |
| | | }, 800); |
| | | |
| | | // 动画循环 |
| | | const animate = () => { |
| | | let lastTime = 0; |
| | | const targetFPS = 30; // 降低目标FPS以提高性能 |
| | | const frameInterval = 1000 / targetFPS; |
| | | |
| | | const animate = (timestamp = 0) => { |
| | | const animationId = requestAnimationFrame(animate); |
| | | |
| | | // 限制帧率以提高性能 |
| | | const deltaTime = timestamp - lastTime; |
| | | if (deltaTime < frameInterval) { |
| | | return animationId; |
| | | } |
| | | |
| | | // 记录当前时间 |
| | | lastTime = timestamp - (deltaTime % frameInterval); |
| | | |
| | | // 更新和绘制 |
| | | updateParticles(); |
| | | drawScene(); |
| | | requestAnimationFrame(animate); |
| | | |
| | | return animationId; |
| | | }; |
| | | |
| | | initParticles(); |
| | | animate(); |
| | | const animationId = animate(); |
| | | |
| | | return () => { |
| | | window.removeEventListener('resize', setCanvasSize); |
| | | clearInterval(particleInterval); |
| | | // 清理动画帧 |
| | | cancelAnimationFrame(animationId); |
| | | }; |
| | | }, []); |
| | | |