UI design restructure ~85%: design system complete, four-layer narrative model implemented, Consulting Professional aesthetic established. CMS-ification ~75%: all pages integrated with CMS data layer, seed script covers all content types, ISR + dynamic rendering enabled. Archive 12 legacy component versions to _archive/. Quality gates: type-check, 992 tests, coverage all passing.
629 lines
28 KiB
TypeScript
629 lines
28 KiB
TypeScript
'use client';
|
||
|
||
import { useEffect, useRef, useState } from 'react';
|
||
import { motion, useMotionValue, useTransform } from 'framer-motion';
|
||
import { ScrollReveal, StaggerReveal } from '@/components/ui/scroll-reveal';
|
||
|
||
import { Badge } from '@/components/ui/badge';
|
||
import {
|
||
ArrowRight,
|
||
Quote, CheckCircle2,
|
||
Zap, Award,
|
||
} from 'lucide-react';
|
||
import { cn } from '@/lib/utils';
|
||
import { SectionLabel, EASE_OUT } from '@/components/ui/page-decoration';
|
||
|
||
|
||
function MagneticButton({ children, href, variant = 'primary', className }: { children: React.ReactNode; href: string; variant?: 'primary' | 'secondary'; className?: string }) {
|
||
const ref = useRef<HTMLAnchorElement>(null);
|
||
const [position, setPosition] = useState({ x: 0, y: 0 });
|
||
|
||
const handleMouseMove = (e: React.MouseEvent) => {
|
||
if (!ref.current) return;
|
||
const rect = ref.current.getBoundingClientRect();
|
||
const x = (e.clientX - rect.left - rect.width / 2) * 0.15;
|
||
const y = (e.clientY - rect.top - rect.height / 2) * 0.15;
|
||
setPosition({ x, y });
|
||
};
|
||
|
||
const handleMouseLeave = () => {
|
||
setPosition({ x: 0, y: 0 });
|
||
};
|
||
|
||
return (
|
||
<motion.a
|
||
ref={ref}
|
||
href={href}
|
||
animate={{ x: position.x, y: position.y }}
|
||
transition={{ duration: 0.3, ease: EASE_OUT }}
|
||
onMouseMove={handleMouseMove}
|
||
onMouseLeave={handleMouseLeave}
|
||
className={cn(
|
||
'group relative inline-flex items-center gap-3 px-12 py-6 font-semibold text-base overflow-hidden transition-transform duration-200',
|
||
variant === 'primary'
|
||
? 'bg-brand text-white'
|
||
: 'text-ink border border-border-primary hover:border-border-secondary hover:bg-bg-secondary',
|
||
className
|
||
)}
|
||
>
|
||
{variant === 'primary' && (
|
||
<div className="absolute inset-0 bg-black/20 translate-y-full group-hover:translate-y-0 transition-transform duration-500 ease-out" />
|
||
)}
|
||
<span className="relative z-10">{children}</span>
|
||
<ArrowRight className="w-5 h-5 relative z-10 transition-transform duration-500 group-hover:translate-x-2" />
|
||
</motion.a>
|
||
);
|
||
}
|
||
|
||
function HeroSection({ heroData, stats }: { heroData?: Record<string, any> | null; stats?: Record<string, any>[] }) {
|
||
const containerRef = useRef<HTMLDivElement>(null);
|
||
const scrollProgress = useMotionValue(0);
|
||
|
||
useEffect(() => {
|
||
const element = containerRef.current;
|
||
if (!element) return;
|
||
|
||
const updateProgress = () => {
|
||
const rect = element.getBoundingClientRect();
|
||
const raw = rect.height > 0 ? -rect.top / rect.height : 0;
|
||
scrollProgress.set(Math.max(0, Math.min(1, raw)));
|
||
};
|
||
|
||
updateProgress();
|
||
window.addEventListener('scroll', updateProgress, { passive: true });
|
||
window.addEventListener('resize', updateProgress);
|
||
return () => {
|
||
window.removeEventListener('scroll', updateProgress);
|
||
window.removeEventListener('resize', updateProgress);
|
||
};
|
||
}, [scrollProgress]);
|
||
|
||
const y = useTransform(scrollProgress, [0, 1], [0, 160]);
|
||
const opacity = useTransform(scrollProgress, [0, 0.7], [1, 0.15]);
|
||
|
||
// 兼容新旧数据字段
|
||
const eyebrow = heroData?.eyebrow || '';
|
||
const heading = heroData?.heading || heroData?.headingBottom || '';
|
||
const subheading = heroData?.subheading || heroData?.description || '';
|
||
const ctaLabel = heroData?.ctaLabel || '预约咨询';
|
||
const ctaHref = heroData?.ctaHref || '/contact';
|
||
const secondaryCtaLabel = heroData?.secondaryCtaLabel || '';
|
||
const secondaryCtaHref = heroData?.secondaryCtaHref || '#';
|
||
|
||
const hasValidStats = stats?.length && stats[0]?.value;
|
||
const displayStats = hasValidStats ? stats!.slice(0, 4) : [];
|
||
|
||
if (!heroData) {
|
||
return (
|
||
<section className="relative min-h-screen flex items-center overflow-hidden bg-white">
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 text-center">
|
||
<p className="text-text-muted text-lg">首页 Hero 内容未配置</p>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<section
|
||
ref={containerRef}
|
||
className="relative min-h-screen flex items-center overflow-hidden bg-white"
|
||
>
|
||
<motion.div
|
||
style={{ y, opacity }}
|
||
className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10 w-full py-32 sm:py-40 md:py-48 lg:py-56"
|
||
>
|
||
<div className="max-w-4xl">
|
||
{/* 眉标 Badge */}
|
||
{eyebrow && (
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6, delay: 0.1, ease: EASE_OUT }}
|
||
className="mb-8 sm:mb-10"
|
||
>
|
||
<span className="inline-flex items-center gap-2 px-3 py-1.5 bg-brand/[0.08] border border-brand/20 rounded-full">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-brand" />
|
||
<span className="text-[13px] font-semibold text-brand tracking-[0.08em] uppercase">
|
||
{eyebrow}
|
||
</span>
|
||
</span>
|
||
</motion.div>
|
||
)}
|
||
|
||
{/* 主标题 — Bain 风格:大号加粗 + 品牌红关键词 */}
|
||
<motion.h1
|
||
initial={{ opacity: 0, y: 40 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.8, delay: 0.2, ease: EASE_OUT }}
|
||
className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-black text-ink leading-[0.92] tracking-tightest mb-10 sm:mb-12"
|
||
>
|
||
<span className="relative">
|
||
{heading}
|
||
</span>
|
||
</motion.h1>
|
||
|
||
{/* 数据指标条 — Bain 风格:答案优先,数据先行 */}
|
||
{displayStats.length > 0 && (
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 30 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.7, delay: 0.4, ease: EASE_OUT }}
|
||
className="flex flex-wrap gap-6 sm:gap-10 md:gap-14 mb-10 sm:mb-12"
|
||
>
|
||
{displayStats.map((stat, i) => (
|
||
<div key={i} className="flex items-baseline gap-2">
|
||
<span className="text-3xl sm:text-4xl md:text-5xl font-black text-brand tabular-nums leading-none">
|
||
{stat.value}
|
||
</span>
|
||
<span className="text-sm text-text-muted whitespace-nowrap">
|
||
{stat.label}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</motion.div>
|
||
)}
|
||
|
||
{/* 副标题 */}
|
||
{subheading && (
|
||
<motion.p
|
||
initial={{ opacity: 0, y: 30 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.7, delay: 0.5, ease: EASE_OUT }}
|
||
className="text-lg sm:text-xl text-text-secondary/70 max-w-2xl leading-relaxed mb-12 sm:mb-14"
|
||
>
|
||
{subheading}
|
||
</motion.p>
|
||
)}
|
||
|
||
{/* CTA 按钮组 */}
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 30 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.7, delay: 0.6, ease: EASE_OUT }}
|
||
className="flex flex-col sm:flex-row sm:items-center gap-4 sm:gap-6"
|
||
>
|
||
<MagneticButton href={ctaHref}>{ctaLabel}</MagneticButton>
|
||
{secondaryCtaLabel && (
|
||
<a
|
||
href={secondaryCtaHref}
|
||
className="group inline-flex items-center gap-2 text-sm font-medium text-text-secondary hover:text-ink transition-colors duration-200 py-4"
|
||
>
|
||
{secondaryCtaLabel}
|
||
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
|
||
</a>
|
||
)}
|
||
</motion.div>
|
||
</div>
|
||
</motion.div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
function ServicesSection({ services }: { services?: Record<string, any>[] }) {
|
||
const hasValidData = services?.length && services[0]?.highlights;
|
||
const SERVICES = hasValidData ? services : [];
|
||
if (SERVICES.length === 0) {
|
||
return (
|
||
<section className="relative py-28 overflow-hidden bg-white">
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 text-center">
|
||
<p className="text-text-muted text-lg">暂无服务数据</p>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
return (
|
||
<section className="relative py-28 sm:py-36 md:py-44 lg:py-56 overflow-hidden bg-white">
|
||
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-border-primary to-transparent" />
|
||
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
|
||
<div className="max-w-3xl mb-20 sm:mb-28 md:mb-36">
|
||
<ScrollReveal>
|
||
<SectionLabel>核心服务</SectionLabel>
|
||
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-6xl font-black text-ink tracking-tight leading-[0.95] mt-6">
|
||
从战略到落地,
|
||
<br />
|
||
可量化的一站式服务
|
||
</h2>
|
||
</ScrollReveal>
|
||
</div>
|
||
|
||
<div className="grid md:grid-cols-3 gap-px bg-border-primary">
|
||
{/* 首张卡片:战略咨询 — 全宽突出 */}
|
||
{(() => {
|
||
const first = SERVICES[0];
|
||
if (!first) return null;
|
||
return (
|
||
<StaggerReveal className="md:col-span-3" staggerDelay={0.05}>
|
||
<a
|
||
href={first.href}
|
||
className="group relative block p-8 sm:p-10 md:p-12 lg:p-14 transition-all duration-500 hover:bg-bg-secondary overflow-hidden bg-white"
|
||
>
|
||
<div className="relative z-10 flex flex-col md:flex-row md:items-start gap-8 md:gap-16">
|
||
<div className="w-14 h-14 flex items-center justify-center bg-bg-secondary text-text-secondary group-hover:text-ink transition-colors duration-300 shrink-0">
|
||
{first.icon}
|
||
</div>
|
||
<div className="flex-1">
|
||
<div className="mb-6">
|
||
<h3 className="text-sm text-text-muted mb-3 font-medium">
|
||
{first.subtitle}
|
||
</h3>
|
||
<h3 className="text-xl lg:text-2xl font-bold text-ink transition-colors duration-300">
|
||
{first.title}
|
||
</h3>
|
||
</div>
|
||
<p className="text-text-secondary leading-relaxed mb-8 text-sm max-w-2xl">
|
||
{first.desc}
|
||
</p>
|
||
<div className="flex flex-wrap gap-2 mb-10">
|
||
{first.highlights.map((h: string, j: number) => (
|
||
<span
|
||
key={j}
|
||
className="px-3 py-1.5 text-xs text-text-muted border border-border-primary group-hover:border-border-secondary group-hover:text-text-secondary transition-all duration-300 font-medium"
|
||
>
|
||
{h}
|
||
</span>
|
||
))}
|
||
</div>
|
||
{(first as any).metrics && (
|
||
<div className="flex flex-wrap gap-10 mb-10 pb-10 border-b border-border-primary">
|
||
{(first as any).metrics.map((m: any, j: number) => (
|
||
<div key={j}>
|
||
<div className="text-3xl sm:text-4xl font-black text-brand tracking-tightest mb-1">
|
||
{m.value}
|
||
</div>
|
||
<div className="text-xs text-text-muted font-medium">
|
||
{m.label}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors duration-300">
|
||
<span>了解详情</span>
|
||
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</a>
|
||
</StaggerReveal>
|
||
);
|
||
})()}
|
||
|
||
{/* 其余三张卡片:并排 */}
|
||
{SERVICES.slice(1).map((service, i) => (
|
||
<StaggerReveal key={i} staggerDelay={0.05}>
|
||
<a
|
||
href={service.href}
|
||
className="group relative block p-8 sm:p-10 md:p-12 lg:p-14 transition-all duration-500 hover:bg-bg-secondary overflow-hidden bg-white h-full flex flex-col"
|
||
>
|
||
<div className="relative z-10 flex flex-col flex-1">
|
||
<div className="flex items-start justify-between mb-10">
|
||
<div className="w-12 h-12 flex items-center justify-center bg-bg-secondary text-text-secondary group-hover:text-ink transition-colors duration-300">
|
||
{service.icon}
|
||
</div>
|
||
</div>
|
||
<div className="mb-6">
|
||
<h3 className="text-sm text-text-muted mb-3 font-medium">
|
||
{service.subtitle}
|
||
</h3>
|
||
<h3 className="text-xl lg:text-2xl font-bold text-ink transition-colors duration-300">
|
||
{service.title}
|
||
</h3>
|
||
</div>
|
||
<p className="text-text-secondary leading-relaxed mb-8 text-sm">
|
||
{service.desc}
|
||
</p>
|
||
<div className="flex flex-wrap gap-2 mb-8">
|
||
{service.highlights.map((h: string, j: number) => (
|
||
<span
|
||
key={j}
|
||
className="px-3 py-1.5 text-xs text-text-muted border border-border-primary group-hover:border-border-secondary group-hover:text-text-secondary transition-all duration-300 font-medium"
|
||
>
|
||
{h}
|
||
</span>
|
||
))}
|
||
</div>
|
||
{(service as any).metrics && (
|
||
<div className="flex gap-6 mb-8 pb-8 border-b border-border-primary">
|
||
{(service as any).metrics.map((m: any, j: number) => (
|
||
<div key={j}>
|
||
<div className="text-2xl sm:text-3xl font-black text-brand tracking-tightest mb-1">
|
||
{m.value}
|
||
</div>
|
||
<div className="text-[11px] text-text-muted font-medium">
|
||
{m.label}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
<div className="mt-auto pt-2">
|
||
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors duration-300">
|
||
<span>了解详情</span>
|
||
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</a>
|
||
</StaggerReveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
function TrustSection() {
|
||
const items = [
|
||
{ title: '私有化部署', desc: '核心数据不出境,满足金融、医疗、政务合规要求' },
|
||
{ title: '资深团队', desc: '平均 10 年以上企业级系统交付经验' },
|
||
{ title: '全栈自研', desc: '从底层架构到前端交互,核心技术自主可控' },
|
||
{ title: '长期陪跑', desc: '上线不是终点,持续迭代陪伴业务成长' },
|
||
];
|
||
|
||
return (
|
||
<section className="relative py-20 sm:py-24 md:py-28 lg:py-32 overflow-hidden bg-bg-secondary">
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
|
||
<ScrollReveal className="mb-12 sm:mb-16 md:mb-20">
|
||
<div className="flex items-center gap-3 mb-6">
|
||
<div className="w-10 h-px bg-brand" />
|
||
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
|
||
值得信赖
|
||
</span>
|
||
</div>
|
||
<h2 className="font-sans text-xl sm:text-2xl md:text-3xl lg:text-4xl font-black text-ink tracking-tight leading-tight">
|
||
12年深耕,500+项目验证的交付能力
|
||
</h2>
|
||
</ScrollReveal>
|
||
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-px bg-border-primary">
|
||
{items.map((item, i) => (
|
||
<StaggerReveal key={item.title} staggerDelay={0.05}>
|
||
<div className="bg-bg-secondary p-8 sm:p-10 h-full transition-all duration-300 hover:bg-white group">
|
||
<div className="flex items-start gap-4">
|
||
<div className="w-8 h-8 flex items-center justify-center bg-brand/10 text-brand font-bold text-sm shrink-0 transition-colors duration-300 group-hover:bg-brand group-hover:text-white">
|
||
{String(i + 1).padStart(2, '0')}
|
||
</div>
|
||
<div>
|
||
<h3 className="text-base font-bold text-ink mb-2">{item.title}</h3>
|
||
<p className="text-sm text-text-secondary leading-relaxed">{item.desc}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</StaggerReveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
function CasesSection({ cases }: { cases?: Record<string, any>[] }) {
|
||
const hasValidData = cases?.length && cases[0]?.metrics;
|
||
const CASES = hasValidData ? cases : [];
|
||
if (CASES.length === 0) {
|
||
return (
|
||
<section className="relative py-28 overflow-hidden bg-dark-bg">
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 text-center">
|
||
<p className="text-dark-text-muted text-lg">暂无案例数据</p>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
return (
|
||
<section className="relative py-28 sm:py-36 md:py-44 lg:py-56 overflow-hidden bg-dark-bg">
|
||
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-dark-border to-transparent" />
|
||
<div className="absolute inset-0 pointer-events-none">
|
||
<div className="absolute top-1/4 left-1/4 w-[400px] h-[400px] bg-brand/[0.03] rounded-full blur-[120px]" />
|
||
<div className="absolute bottom-1/3 right-1/4 w-[500px] h-[500px] bg-accent-blue/[0.02] rounded-full blur-[140px]" />
|
||
</div>
|
||
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
|
||
<div className="flex flex-col md:flex-row md:items-end md:justify-between gap-8 sm:gap-10 mb-20 sm:mb-28 md:mb-36">
|
||
<ScrollReveal className="md:max-w-3xl">
|
||
<div className="flex items-center gap-3 mb-6">
|
||
<div className="w-10 h-px bg-brand" />
|
||
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
|
||
客户案例
|
||
</span>
|
||
</div>
|
||
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-6xl font-black text-dark-text-primary tracking-tight leading-[0.95] mt-6">
|
||
每一个项目,
|
||
<br />
|
||
都以业务改善为衡量标准
|
||
</h2>
|
||
</ScrollReveal>
|
||
<ScrollReveal delay={0.1}>
|
||
<a
|
||
href="/cases"
|
||
className="group inline-flex items-center gap-3 text-dark-text-primary font-semibold text-sm"
|
||
>
|
||
查看全部案例
|
||
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-dark-text-muted group-hover:text-brand" />
|
||
</a>
|
||
</ScrollReveal>
|
||
</div>
|
||
|
||
<div className="space-y-16">
|
||
{CASES.map((caseItem, i) => (
|
||
<ScrollReveal key={i} delay={i * 0.15}>
|
||
<article className="group relative overflow-hidden border border-dark-border hover:border-dark-border/80 transition-all duration-500 bg-dark-bg-secondary">
|
||
<div className="relative z-10">
|
||
<div className="p-10 sm:p-12 lg:p-16 pb-0">
|
||
<div className="flex items-center gap-4 mb-10">
|
||
<Badge className="bg-dark-bg-tertiary text-dark-text-primary border-transparent">
|
||
{caseItem.industry}
|
||
</Badge>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-8 sm:gap-10 pb-12 border-b border-dark-border">
|
||
{caseItem.metrics.map((metric: Record<string, any>, j: number) => (
|
||
<div key={j}>
|
||
<motion.div
|
||
className={cn(
|
||
'text-5xl sm:text-6xl lg:text-7xl font-black mb-4 leading-none tracking-tightest',
|
||
j === 0 ? 'text-brand' : 'text-dark-text-primary'
|
||
)}
|
||
initial={{ opacity: 0 }}
|
||
whileInView={{ opacity: 1 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 0.4, delay: 0.1 * j }}
|
||
>
|
||
{metric.value}
|
||
</motion.div>
|
||
<div className="mb-4">
|
||
<div className="h-1 bg-dark-border rounded-full overflow-hidden">
|
||
<motion.div
|
||
className={cn(
|
||
'h-full rounded-full',
|
||
j === 0 ? 'bg-brand' : 'bg-dark-text-primary/60'
|
||
)}
|
||
initial={{ width: 0 }}
|
||
whileInView={{ width: `${(metric as any).progress || 50}%` }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 1, delay: 0.3 + 0.1 * j, ease: 'easeOut' }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-3">
|
||
<div className={cn('w-8 h-px', j === 0 ? 'bg-brand' : 'bg-dark-border')} />
|
||
<div className="text-dark-text-secondary font-medium text-sm">{metric.label}</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-10 sm:px-12 lg:px-16 pt-12">
|
||
<h3 className="text-xl lg:text-2xl font-bold mb-10 leading-tight text-dark-text-primary">
|
||
{caseItem.title}
|
||
</h3>
|
||
</div>
|
||
|
||
<div className="px-10 sm:px-12 lg:px-16 pb-12">
|
||
<div className="space-y-8">
|
||
<div>
|
||
<div className="flex items-center gap-3 mb-5">
|
||
<Award className="w-4 h-4 text-dark-text-muted" />
|
||
<span className="text-xs font-semibold text-dark-text-muted tracking-wide">
|
||
挑战
|
||
</span>
|
||
</div>
|
||
<p className="text-dark-text-secondary leading-relaxed text-sm">
|
||
{caseItem.challenge}
|
||
</p>
|
||
</div>
|
||
|
||
{(caseItem as any).insight && (
|
||
<div className="border-t-2 border-brand bg-brand/[0.04] p-5 pr-6">
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<span className="text-xs font-bold text-brand tracking-wide">
|
||
关键洞察
|
||
</span>
|
||
</div>
|
||
<p className="text-dark-text-primary leading-relaxed text-sm font-medium">
|
||
{(caseItem as any).insight}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
<div>
|
||
<div className="flex items-center gap-3 mb-5">
|
||
<Zap className="w-4 h-4 text-dark-text-muted" />
|
||
<span className="text-xs font-semibold text-dark-text-muted tracking-wide">
|
||
解决方案
|
||
</span>
|
||
</div>
|
||
<p className="text-dark-text-secondary leading-relaxed text-sm">
|
||
{caseItem.solution}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="px-10 sm:px-12 lg:px-16 pb-12">
|
||
<div className="p-6 sm:p-8 bg-dark-bg-tertiary/50 border border-dark-border">
|
||
<div className="flex items-center gap-3 mb-4">
|
||
<CheckCircle2 className="w-4 h-4 text-brand" />
|
||
<span className="text-xs font-bold text-brand tracking-wide">
|
||
业务成果
|
||
</span>
|
||
</div>
|
||
<p className="text-dark-text-primary leading-relaxed text-sm font-medium">
|
||
{caseItem.result}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{caseItem.testimonial?.quote && (
|
||
<div className="px-10 sm:px-12 lg:px-16 pb-12 lg:pb-16 pt-10 border-t border-dark-border">
|
||
<div className="flex items-start gap-4">
|
||
<Quote className="w-8 h-8 shrink-0 mt-0.5 text-dark-text-muted" />
|
||
<div>
|
||
<p className="text-dark-text-secondary italic leading-relaxed mb-4 text-sm">
|
||
“{caseItem.testimonial.quote}”
|
||
</p>
|
||
<p className="text-xs text-dark-text-muted">
|
||
— {caseItem.testimonial.author}
|
||
{caseItem.testimonial.role && `,${caseItem.testimonial.role}`}
|
||
{caseItem.testimonial.company && ` · ${caseItem.testimonial.company}`}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</article>
|
||
</ScrollReveal>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
function CTASection({ heroData }: { heroData?: Record<string, any> | null }) {
|
||
const ctaTitleLine1 = heroData?.ctaTitleLine1 || '';
|
||
const ctaTitleLine2 = heroData?.ctaTitleLine2 || '';
|
||
const ctaLabel = heroData?.ctaLabel || '';
|
||
const ctaHref = heroData?.ctaHref || '#';
|
||
|
||
return (
|
||
<section
|
||
className="relative py-32 sm:py-40 md:py-52 lg:py-60 overflow-hidden bg-dark-bg"
|
||
>
|
||
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-dark-border to-transparent" />
|
||
<div className="absolute inset-0 pointer-events-none">
|
||
<div className="absolute top-1/3 right-1/4 w-[500px] h-[500px] bg-brand/[0.04] rounded-full blur-[140px]" />
|
||
</div>
|
||
|
||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
|
||
<ScrollReveal className="max-w-3xl">
|
||
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-6xl xl:text-7xl font-black text-dark-text-primary tracking-tightest leading-[0.9] mb-12 sm:mb-16 md:mb-20">
|
||
{ctaTitleLine1 && <>{ctaTitleLine1}<br /></>}
|
||
<span className="text-brand">{ctaTitleLine2 || '真正转化为业务增长'}</span>
|
||
</h2>
|
||
<MagneticButton href={ctaHref}>{ctaLabel || '预约咨询'}</MagneticButton>
|
||
</ScrollReveal>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|
||
|
||
export default function HomeContentV13({ services, cases, stats, heroData }: {
|
||
services?: Record<string, any>[];
|
||
cases?: Record<string, any>[];
|
||
stats?: Record<string, any>[];
|
||
heroData?: Record<string, any> | null;
|
||
}) {
|
||
return (
|
||
<main>
|
||
<HeroSection heroData={heroData} stats={stats} />
|
||
<ServicesSection services={services} />
|
||
<TrustSection />
|
||
<CasesSection cases={cases} />
|
||
<CTASection heroData={heroData} />
|
||
</main>
|
||
);
|
||
}
|