refactor: 优化网站页面结构和数据展示
- 增强服务数据模型,添加 challenges 和 outcomes 字段 - 简化统计数据配置,改为静态定义 - 重构多个页面组件,优化代码结构 - 新增产品、服务、解决方案相关的布局和组件 - 更新样式和动画配置 - 优化测试用例和类型定义 - 修复 ESLint 错误:移除不必要的 useEffect 和未使用的导入
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
export { ProductHeroSection } from './product-hero-section';
|
||||
export { ProductOverviewSection } from './product-overview-section';
|
||||
export { ProductFeaturesSection } from './product-features-section';
|
||||
export { ProductBenefitsSection } from './product-benefits-section';
|
||||
export { ProductProcessSection } from './product-process-section';
|
||||
export { ProductSpecsSection } from './product-specs-section';
|
||||
export { ProductPricingSection } from './product-pricing-section';
|
||||
export { ProductCTASection } from './product-cta-section';
|
||||
@@ -0,0 +1,68 @@
|
||||
'use client';
|
||||
|
||||
import { useRef } from 'react';
|
||||
import { ScrollReveal, slideInLeftVariants } from '@/components/ui/scroll-animations';
|
||||
import { StaggerContainer, StaggerItem, InkCard, CountUp } from '@/lib/animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
interface ProductBenefitsSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
function extractNumber(text: string): { number: number; suffix: string } | null {
|
||||
const match = text.match(/(\d+)%/);
|
||||
if (match) {
|
||||
return { number: parseInt(match[1]!, 10), suffix: '%' };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function BenefitCard({ benefit }: { benefit: string }) {
|
||||
const numberInfo = extractNumber(benefit);
|
||||
|
||||
return (
|
||||
<StaggerItem>
|
||||
<InkCard
|
||||
className="p-6 md:p-8 bg-white rounded-2xl border border-[#E5E5E5] hover:border-[#C41E3A]/30 transition-colors"
|
||||
hoverScale={1.02}
|
||||
hoverShadow="0 20px 40px rgba(196, 30, 58, 0.08)"
|
||||
>
|
||||
{numberInfo && (
|
||||
<div className="mb-4">
|
||||
<span className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-[#C41E3A] to-[#E85D75] bg-clip-text text-transparent">
|
||||
<CountUp
|
||||
end={numberInfo.number}
|
||||
suffix={numberInfo.suffix}
|
||||
duration={2000}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-lg text-[#1C1C1C] leading-relaxed">{benefit}</p>
|
||||
</InkCard>
|
||||
</StaggerItem>
|
||||
);
|
||||
}
|
||||
|
||||
export function ProductBenefitsSection({ product }: ProductBenefitsSectionProps) {
|
||||
const ref = useRef<HTMLElement>(null);
|
||||
|
||||
return (
|
||||
<section id="benefits" ref={ref} className="relative py-20 md:py-28 bg-white overflow-hidden">
|
||||
<div className="container-wide">
|
||||
<ScrollReveal variants={slideInLeftVariants} className="mb-12">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-[#1C1C1C] text-left">
|
||||
产品优势
|
||||
</h2>
|
||||
</ScrollReveal>
|
||||
|
||||
<StaggerContainer className="grid md:grid-cols-2 gap-6 max-w-5xl">
|
||||
{product.benefits.map((benefit, index) => (
|
||||
<BenefitCard key={index} benefit={benefit} />
|
||||
))}
|
||||
</StaggerContainer>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
'use client';
|
||||
|
||||
import { Phone } from 'lucide-react';
|
||||
import { InkReveal, FadeUp, FloatingElement, RippleButton } from '@/lib/animations';
|
||||
|
||||
export function ProductCTASection() {
|
||||
return (
|
||||
<section className="relative py-24 md:py-32 bg-gradient-to-r from-[#C41E3A] to-[#E85D75] overflow-hidden">
|
||||
{/* 右上角装饰圆形 */}
|
||||
<FloatingElement amplitude={8} duration={5} delay={0.5} className="absolute -top-20 -right-20 pointer-events-none">
|
||||
<div className="w-[280px] h-[280px] bg-white/10 rounded-full" />
|
||||
</FloatingElement>
|
||||
|
||||
{/* 左下角装饰圆形 */}
|
||||
<FloatingElement amplitude={6} duration={4} delay={1} className="absolute -bottom-16 -left-16 pointer-events-none">
|
||||
<div className="w-[220px] h-[220px] bg-white/10 rounded-full" />
|
||||
</FloatingElement>
|
||||
|
||||
<div className="container-wide">
|
||||
<div className="max-w-3xl mx-auto text-center">
|
||||
<InkReveal delay={0}>
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-white mb-6">
|
||||
产品即将上市
|
||||
</h2>
|
||||
</InkReveal>
|
||||
|
||||
<FadeUp delay={0.15}>
|
||||
<p className="text-lg text-white/90 mb-10">
|
||||
我们正在全力研发中,敬请期待。如有合作意向,欢迎联系我们。
|
||||
</p>
|
||||
</FadeUp>
|
||||
|
||||
<FadeUp delay={0.3}>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<RippleButton
|
||||
href="/contact"
|
||||
rippleColor="rgba(196, 30, 58, 0.3)"
|
||||
className="bg-white text-[#C41E3A] px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center w-full sm:w-auto"
|
||||
>
|
||||
联系我们
|
||||
</RippleButton>
|
||||
|
||||
<RippleButton
|
||||
href="tel:+8613800138000"
|
||||
rippleColor="rgba(255, 255, 255, 0.2)"
|
||||
className="bg-transparent border-2 border-white text-white px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center w-full sm:w-auto"
|
||||
>
|
||||
<Phone className="w-4 h-4 mr-2" />
|
||||
电话咨询
|
||||
</RippleButton>
|
||||
</div>
|
||||
</FadeUp>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
'use client';
|
||||
|
||||
import { useRef, Fragment } from 'react';
|
||||
import { InkReveal, FadeUp, InkCard, PulseElement } from '@/lib/animations';
|
||||
import { RippleButton } from '@/lib/animations';
|
||||
import { ScrollReveal, inkRevealVariants, slideInLeftVariants } from '@/components/ui/scroll-animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
interface ProductFeaturesSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
function FeatureItem({
|
||||
feature,
|
||||
index,
|
||||
}: {
|
||||
feature: string;
|
||||
index: number;
|
||||
}) {
|
||||
// 解析功能标题和描述(中文冒号分隔)
|
||||
const colonIndex = feature.indexOf(':');
|
||||
const title = colonIndex > -1 ? feature.substring(0, colonIndex) : feature;
|
||||
const description = colonIndex > -1 ? feature.substring(colonIndex + 1) : '';
|
||||
|
||||
// 编号格式化
|
||||
const number = String(index + 1).padStart(2, '0');
|
||||
|
||||
return (
|
||||
<div className="min-h-[50vh] flex items-center py-16">
|
||||
<div className="container-wide">
|
||||
<div className="max-w-6xl mx-auto grid md:grid-cols-2 gap-12 items-center">
|
||||
{/* 左侧:编号和文字 */}
|
||||
<div className="order-2 md:order-1">
|
||||
{/* 编号 - InkReveal 模糊揭示 */}
|
||||
<InkReveal delay={0}>
|
||||
<span className="block text-7xl md:text-8xl font-mono text-[#C41E3A]/10 mb-4">
|
||||
{number}
|
||||
</span>
|
||||
</InkReveal>
|
||||
|
||||
{/* 功能标题 - ScrollReveal + slideInLeft */}
|
||||
<ScrollReveal variants={slideInLeftVariants} delay={0.1}>
|
||||
<h3 className="text-2xl md:text-3xl font-bold text-[#1C1C1C] mb-4">
|
||||
{title}
|
||||
</h3>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* 功能描述 - FadeUp */}
|
||||
{description && (
|
||||
<FadeUp delay={0.2}>
|
||||
<p className="text-lg text-[#5C5C5C] leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
</FadeUp>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 右侧:InkCard 弹簧物理悬浮 + PulseElement 脉冲同心圆 */}
|
||||
<div className="order-1 md:order-2">
|
||||
<InkCard
|
||||
className="aspect-square rounded-2xl bg-white border border-[#E5E5E5] shadow-lg flex items-center justify-center"
|
||||
hoverScale={1.03}
|
||||
hoverShadow="0 25px 50px rgba(196, 30, 58, 0.15)"
|
||||
>
|
||||
<PulseElement scale={1.08} duration={2.5}>
|
||||
<div className="w-24 h-24 rounded-full bg-[#C41E3A]/10 flex items-center justify-center">
|
||||
<div className="w-12 h-12 rounded-full bg-[#C41E3A]/20" />
|
||||
</div>
|
||||
</PulseElement>
|
||||
</InkCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ProductFeaturesSection({ product }: ProductFeaturesSectionProps) {
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
|
||||
return (
|
||||
<section id="features" ref={sectionRef} className="relative bg-[#F8F8F8] overflow-hidden">
|
||||
{/* 标题 - ScrollReveal + inkRevealVariants 模糊揭示 */}
|
||||
<div className="pt-32 md:pt-40 pb-16">
|
||||
<div className="container-wide">
|
||||
<ScrollReveal variants={inkRevealVariants} delay={0}>
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-[#1C1C1C] text-center mb-4">
|
||||
核心功能
|
||||
</h2>
|
||||
</ScrollReveal>
|
||||
<ScrollReveal variants={inkRevealVariants} delay={0.1}>
|
||||
<p className="text-lg text-[#5C5C5C] text-center max-w-2xl mx-auto">
|
||||
全方位覆盖企业核心业务场景
|
||||
</p>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 功能列表 */}
|
||||
{product.features.map((feature, index) => (
|
||||
<Fragment key={index}>
|
||||
<FeatureItem feature={feature} index={index} />
|
||||
{(index === 1 || index === 3) && (
|
||||
<div className="py-8">
|
||||
<div className="container-wide">
|
||||
<div className="max-w-2xl mx-auto bg-white rounded-2xl border border-[#E5E5E5] p-6 md:p-8 text-center shadow-sm">
|
||||
<p className="text-[#1C1C1C] font-semibold text-lg mb-4">
|
||||
想了解更多功能细节?
|
||||
</p>
|
||||
<p className="text-[#5C5C5C] mb-6">
|
||||
预约一次 30 分钟在线演示,了解产品如何适配您的业务
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
||||
<RippleButton
|
||||
href="/contact"
|
||||
rippleColor="rgba(196, 30, 58, 0.3)"
|
||||
className="bg-[#C41E3A] hover:bg-[#A01830] text-white px-6 py-3 rounded-lg font-semibold inline-flex items-center justify-center"
|
||||
>
|
||||
预约演示
|
||||
</RippleButton>
|
||||
<RippleButton
|
||||
href="/contact"
|
||||
rippleColor="rgba(196, 30, 58, 0.2)"
|
||||
className="border border-[#E5E5E5] text-[#5C5C5C] hover:text-[#C41E3A] hover:border-[#C41E3A]/30 px-6 py-3 rounded-lg font-semibold inline-flex items-center justify-center"
|
||||
>
|
||||
获取方案
|
||||
</RippleButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
import { InkReveal, SealStamp, FloatingElement } from '@/lib/animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
const InkBackground = dynamic(
|
||||
() => import('@/components/ui/ink-decoration').then(mod => ({ default: mod.InkBackground })),
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
const DataParticleFlow = dynamic(
|
||||
() => import('@/components/effects/data-particle-flow').then(mod => ({ default: mod.DataParticleFlow })),
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
interface ProductHeroSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
export function ProductHeroSection({ product }: ProductHeroSectionProps) {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry?.isIntersecting) {
|
||||
setIsVisible(true);
|
||||
}
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
);
|
||||
|
||||
if (sectionRef.current) {
|
||||
observer.observe(sectionRef.current);
|
||||
}
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section
|
||||
ref={sectionRef}
|
||||
className="relative min-h-screen flex items-center justify-center overflow-hidden bg-gradient-to-b from-white to-[#F8F8F8]"
|
||||
>
|
||||
{/* 背景特效 */}
|
||||
<InkBackground />
|
||||
<DataParticleFlow
|
||||
particleCount={80}
|
||||
color="#C41E3A"
|
||||
intensity="subtle"
|
||||
shape="square"
|
||||
effect="pulse"
|
||||
/>
|
||||
|
||||
{/* 内容 */}
|
||||
<div className="container-wide relative z-10 py-32 md:py-40">
|
||||
<div className="max-w-4xl mx-auto text-center">
|
||||
{/* 分类标签 - 印章按压效果 */}
|
||||
<SealStamp
|
||||
delay={0.1}
|
||||
className="inline-block px-4 py-2 bg-[#C41E3A]/20 rounded-full text-[#C41E3A] text-sm mb-6"
|
||||
>
|
||||
即将上市
|
||||
</SealStamp>
|
||||
|
||||
{/* 产品名称 - 模糊揭示入场 */}
|
||||
<InkReveal delay={0.2}>
|
||||
<h1 className="text-4xl md:text-6xl lg:text-7xl font-bold text-[#1C1C1C] mb-6">
|
||||
{product.title}
|
||||
</h1>
|
||||
</InkReveal>
|
||||
|
||||
{/* 价值主张 - 模糊揭示入场 */}
|
||||
<InkReveal delay={0.4}>
|
||||
<p className="text-lg md:text-xl text-[#5C5C5C] leading-relaxed mb-10 max-w-2xl mx-auto">
|
||||
{product.description}
|
||||
</p>
|
||||
</InkReveal>
|
||||
|
||||
{/* CTA 按钮 */}
|
||||
<InkReveal delay={0.6}>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<span className="border-2 border-[#D9D9D9] text-[#999999] px-8 py-4 rounded-lg text-lg font-semibold inline-flex items-center justify-center cursor-not-allowed select-none">
|
||||
敬请期待
|
||||
</span>
|
||||
</div>
|
||||
</InkReveal>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 滚动指示器 - 浮动元素包裹 */}
|
||||
<FloatingElement
|
||||
amplitude={10}
|
||||
duration={1.5}
|
||||
delay={1}
|
||||
className="absolute bottom-8 left-1/2 -translate-x-1/2"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isVisible ? { opacity: 1 } : {}}
|
||||
transition={{ duration: 0.6, delay: 1 }}
|
||||
>
|
||||
<div className="text-[#999999]">
|
||||
<ChevronDown className="w-8 h-8" />
|
||||
</div>
|
||||
</motion.div>
|
||||
</FloatingElement>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
'use client';
|
||||
|
||||
import { InkReveal } from '@/lib/animations';
|
||||
import { ScrollReveal, slideInLeftVariants } from '@/components/ui/scroll-animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
interface ProductOverviewSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
export function ProductOverviewSection({ product }: ProductOverviewSectionProps) {
|
||||
return (
|
||||
<section id="overview" className="relative py-16 md:py-20 bg-white overflow-hidden">
|
||||
<div className="container-wide">
|
||||
<div className="max-w-3xl">
|
||||
{/* 标题 - 左对齐,slideInLeft 入场 */}
|
||||
<ScrollReveal variants={slideInLeftVariants} delay={0}>
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-[#1C1C1C] mb-4">
|
||||
产品概述
|
||||
</h2>
|
||||
</ScrollReveal>
|
||||
|
||||
{/* 朱砂红装饰线 - InkReveal 入场 */}
|
||||
<InkReveal delay={0.2}>
|
||||
<div className="w-16 h-1 bg-[#C41E3A] rounded-full mb-8" />
|
||||
</InkReveal>
|
||||
|
||||
{/* 概述文字 - InkReveal 包裹整段,替代 TextReveal */}
|
||||
<InkReveal delay={0.3}>
|
||||
<p className="text-lg md:text-xl text-[#5C5C5C] leading-relaxed">
|
||||
{product.overview}
|
||||
</p>
|
||||
</InkReveal>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
'use client';
|
||||
|
||||
import { Check } from 'lucide-react';
|
||||
import { InkCard } from '@/components/ui/animated-card';
|
||||
import { ScrollReveal, inkRevealVariants } from '@/components/ui/scroll-animations';
|
||||
import { FloatingElement, PulseElement, RippleButton } from '@/lib/animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
interface ProductPricingSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
const pricingFeatures = {
|
||||
base: ['核心功能模块', '私有化部署', '标准技术支持', '系统培训'],
|
||||
standard: ['全部功能模块', '私有化部署', '优先技术支持', '系统培训', '数据迁移服务', '定制化配置'],
|
||||
enterprise: ['全部功能模块', '私有化部署', '专属技术支持', '系统培训', '数据迁移服务', '定制化开发', 'SLA服务保障', '驻场支持'],
|
||||
};
|
||||
|
||||
function PricingCard({
|
||||
name,
|
||||
description,
|
||||
features,
|
||||
isRecommended = false,
|
||||
ctaText = '获取方案',
|
||||
}: {
|
||||
name: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
isRecommended?: boolean;
|
||||
ctaText?: string;
|
||||
}) {
|
||||
const cardContent = (
|
||||
<div
|
||||
className={`
|
||||
relative p-6 md:p-8 rounded-2xl
|
||||
${isRecommended
|
||||
? 'bg-white border-2 border-[#C41E3A] text-[#1C1C1C]'
|
||||
: 'bg-white border border-[#E5E5E5]'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{isRecommended && (
|
||||
<PulseElement scale={1.08} duration={2} className="absolute -top-3 left-1/2 -translate-x-1/2 z-10">
|
||||
<div className="bg-[#C41E3A] text-white px-4 py-1 rounded-full text-sm font-semibold whitespace-nowrap">
|
||||
推荐
|
||||
</div>
|
||||
</PulseElement>
|
||||
)}
|
||||
|
||||
<h3 className="text-xl font-semibold mb-2 text-[#1C1C1C]">{name}</h3>
|
||||
|
||||
<p className={`text-sm mb-6 text-[#5C5C5C]`}>
|
||||
{description}
|
||||
</p>
|
||||
|
||||
<ul className="space-y-3 mb-8">
|
||||
{features.map((feature, index) => (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<Check className="w-5 h-5 text-[#C41E3A]" />
|
||||
<span className="text-[#5C5C5C]">
|
||||
{feature}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<RippleButton
|
||||
href="/contact"
|
||||
rippleColor="rgba(196, 30, 58, 0.3)"
|
||||
className={`
|
||||
block w-full py-3 rounded-lg font-semibold text-center
|
||||
${isRecommended
|
||||
? 'bg-[#C41E3A] text-white'
|
||||
: 'border border-[#E5E5E5] text-[#5C5C5C] hover:text-[#C41E3A] hover:border-[#C41E3A]/30 bg-white'
|
||||
}
|
||||
`}
|
||||
>
|
||||
{ctaText}
|
||||
</RippleButton>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (isRecommended) {
|
||||
return (
|
||||
<FloatingElement amplitude={5} duration={4} className="my-0 md:-my-4">
|
||||
<InkCard hoverScale={1.03} className="h-full md:scale-105 md:z-10">
|
||||
{cardContent}
|
||||
</InkCard>
|
||||
</FloatingElement>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<InkCard hoverScale={1.02} className="h-full">
|
||||
{cardContent}
|
||||
</InkCard>
|
||||
);
|
||||
}
|
||||
|
||||
export function ProductPricingSection({ product }: ProductPricingSectionProps) {
|
||||
return (
|
||||
<section id="pricing" className="relative py-28 md:py-36 bg-[#F5F5F5] overflow-hidden">
|
||||
<div className="container-wide">
|
||||
<ScrollReveal variants={inkRevealVariants} className="mb-4">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-[#1C1C1C] text-center">
|
||||
版本对比
|
||||
</h2>
|
||||
</ScrollReveal>
|
||||
|
||||
<ScrollReveal variants={inkRevealVariants} className="mb-12">
|
||||
<p className="text-center text-[#5C5C5C] text-lg">
|
||||
根据企业规模和需求,选择最适合的部署方案
|
||||
</p>
|
||||
</ScrollReveal>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8 max-w-5xl mx-auto">
|
||||
<PricingCard
|
||||
name={product.pricing.base}
|
||||
description="适合中小企业基础需求"
|
||||
features={pricingFeatures.base}
|
||||
ctaText="了解标准版"
|
||||
/>
|
||||
<PricingCard
|
||||
name={product.pricing.standard}
|
||||
description="适合中型企业深度应用"
|
||||
features={pricingFeatures.standard}
|
||||
isRecommended
|
||||
ctaText="立即获取方案"
|
||||
/>
|
||||
<PricingCard
|
||||
name={product.pricing.enterprise}
|
||||
description="适合大型企业定制化需求"
|
||||
features={pricingFeatures.enterprise}
|
||||
ctaText="联系定制"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
'use client';
|
||||
|
||||
import { useRef } from 'react';
|
||||
import { ScrollReveal, inkRevealVariants } from '@/components/ui/scroll-animations';
|
||||
import { StaggerContainer, StaggerItem, SealStamp, FadeUp } from '@/lib/animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
interface ProductProcessSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
function ProcessStep({
|
||||
step,
|
||||
index,
|
||||
total,
|
||||
}: {
|
||||
step: string;
|
||||
index: number;
|
||||
total: number;
|
||||
}) {
|
||||
const colonIndex = step.indexOf(':');
|
||||
const title = colonIndex > -1 ? step.substring(0, colonIndex) : step;
|
||||
const description = colonIndex > -1 ? step.substring(colonIndex + 1) : '';
|
||||
|
||||
return (
|
||||
<StaggerItem className="flex items-start gap-6">
|
||||
<div className="flex-shrink-0">
|
||||
<SealStamp delay={index * 0.15}>
|
||||
<div className="w-12 h-12 rounded-full bg-[#C41E3A] flex items-center justify-center text-white font-bold text-lg">
|
||||
{index + 1}
|
||||
</div>
|
||||
</SealStamp>
|
||||
{index < total - 1 && (
|
||||
<div className="w-0.5 h-16 bg-gradient-to-b from-[#C41E3A]/40 to-[#C41E3A]/10 ml-6 mt-2" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<FadeUp delay={index * 0.1} className="flex-1 pb-8">
|
||||
<h3 className="text-xl font-semibold text-[#1C1C1C] mb-2">{title}</h3>
|
||||
{description && (
|
||||
<p className="text-[#5C5C5C] leading-relaxed">{description}</p>
|
||||
)}
|
||||
</FadeUp>
|
||||
</StaggerItem>
|
||||
);
|
||||
}
|
||||
|
||||
export function ProductProcessSection({ product }: ProductProcessSectionProps) {
|
||||
const ref = useRef<HTMLElement>(null);
|
||||
|
||||
return (
|
||||
<section id="process" ref={ref} className="relative py-24 md:py-32 bg-white overflow-hidden">
|
||||
<div className="container-wide">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<ScrollReveal variants={inkRevealVariants} className="mb-12 text-center">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-[#1C1C1C]">
|
||||
实施流程
|
||||
</h2>
|
||||
</ScrollReveal>
|
||||
|
||||
<StaggerContainer className="mt-8" staggerDelay={0.15}>
|
||||
{product.process.map((step, index) => (
|
||||
<ProcessStep
|
||||
key={index}
|
||||
step={step}
|
||||
index={index}
|
||||
total={product.process.length}
|
||||
/>
|
||||
))}
|
||||
</StaggerContainer>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
'use client';
|
||||
|
||||
import { useRef } from 'react';
|
||||
import { ScrollReveal, slideInLeftVariants } from '@/components/ui/scroll-animations';
|
||||
import { StaggerContainer, StaggerItem, InkCard } from '@/lib/animations';
|
||||
import type { Product } from '@/lib/constants/products';
|
||||
|
||||
interface ProductSpecsSectionProps {
|
||||
product: Product;
|
||||
}
|
||||
|
||||
export function ProductSpecsSection({ product }: ProductSpecsSectionProps) {
|
||||
const ref = useRef<HTMLElement>(null);
|
||||
|
||||
return (
|
||||
<section id="specs" ref={ref} className="relative py-20 md:py-28 bg-[#FAFAFA] overflow-hidden">
|
||||
<div className="container-wide">
|
||||
<ScrollReveal variants={slideInLeftVariants} className="mb-12 text-center">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-[#1C1C1C]">
|
||||
技术规格
|
||||
</h2>
|
||||
</ScrollReveal>
|
||||
|
||||
<StaggerContainer className="grid md:grid-cols-2 gap-4 max-w-3xl mx-auto">
|
||||
{product.specs.map((spec, index) => (
|
||||
<StaggerItem key={index}>
|
||||
<InkCard
|
||||
className="flex items-center gap-4 p-4 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A]/30 transition-colors"
|
||||
hoverScale={1.02}
|
||||
hoverShadow="0 12px 24px rgba(196, 30, 58, 0.06)"
|
||||
>
|
||||
<div className="w-1 h-8 bg-[#C41E3A] rounded-full flex-shrink-0" />
|
||||
<span className="text-[#1C1C1C]">{spec}</span>
|
||||
</InkCard>
|
||||
</StaggerItem>
|
||||
))}
|
||||
</StaggerContainer>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user