refactor: 优化网站页面结构和数据展示

- 增强服务数据模型,添加 challenges 和 outcomes 字段
- 简化统计数据配置,改为静态定义
- 重构多个页面组件,优化代码结构
- 新增产品、服务、解决方案相关的布局和组件
- 更新样式和动画配置
- 优化测试用例和类型定义
- 修复 ESLint 错误:移除不必要的 useEffect 和未使用的导入
This commit is contained in:
张翔
2026-04-25 08:44:23 +08:00
parent 9650e56dcf
commit 40384ec024
77 changed files with 3751 additions and 1226 deletions
+99 -33
View File
@@ -4,34 +4,62 @@ import { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import { StaticLink } from '@/components/ui/static-link';
import { Button } from '@/components/ui/button';
import { ArrowRight, Shield, Building2, Users } from 'lucide-react';
import { RippleButton } from '@/lib/animations';
import { ArrowRight, Briefcase, GraduationCap, Target, Users } from 'lucide-react';
const TEAM_HIGHLIGHTS = [
const TEAM_MEMBERS = [
{
icon: Shield,
title: '12年+ 行业深耕',
description: '核心团队长期从事技术咨询、企业数字化等领域,积累了丰富的行业经验和最佳实践。',
name: '创始人兼CEO',
initials: 'CEO',
specialties: ['企业战略', '数字化转型', '组织管理'],
bio: '15年+企业服务经验,深耕数字化转型领域,擅长从战略高度为企业规划数字化路径。',
icon: Target,
accentColor: 'from-[#C41E3A] to-[#E85D75]',
},
{
icon: Building2,
title: '大型 IT 企业背景',
description: '开发团队成员来自多个大型传统 IT 企业,具备扎实的工程能力和规范化交付经验。',
name: '联合创始人兼CTO',
initials: 'CTO',
specialties: ['系统架构', '云原生', '微服务'],
bio: '12年+技术架构经验,主导过多个大型企业级系统的设计与交付,精通分布式系统。',
icon: GraduationCap,
accentColor: 'from-[#C41E3A] to-[#D94466]',
},
{
name: '技术总监',
initials: 'TD',
specialties: ['全栈开发', '数据工程', 'DevOps'],
bio: '10年+全栈开发经验,专注于高质量软件交付和工程效能提升,推动敏捷实践落地。',
icon: Briefcase,
accentColor: 'from-[#C41E3A] to-[#C41E3A]',
},
{
name: '咨询总监',
initials: 'CD',
specialties: ['业务咨询', '流程优化', '项目管理'],
bio: '10年+管理咨询经验,擅长客户需求深度分析和解决方案设计,确保项目精准落地。',
icon: Users,
title: '复合型技术团队',
description: '既懂技术又懂业务,能深入理解客户场景,提供真正落地的解决方案。',
accentColor: 'from-[#C41E3A] to-[#A01830]',
},
];
const TEAM_STATS = [
{ value: '12+', label: '年团队经验' },
{ value: '80%', label: '本科及以上学历' },
{ value: '4', label: '核心服务' },
{ value: '5+', label: '行业覆盖' },
];
export function TeamSection() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: '-100px' });
return (
<section id="team" role="region" aria-labelledby="team-heading" className="py-24 bg-[#FAFAFA] relative overflow-hidden" ref={ref}>
{/* 背景装饰 */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-[600px] h-[600px] bg-[rgba(196,30,58,0.02)] rounded-full blur-3xl" />
<div className="container-wide relative z-10">
{/* 标题区 */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
@@ -42,48 +70,86 @@ export function TeamSection() {
<span className="text-[#C41E3A] font-calligraphy"></span>
</h2>
<p className="text-lg text-[#5C5C5C] leading-relaxed">
12 + IT
IT企业的核心团队
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto mb-12">
{TEAM_HIGHLIGHTS.map((item, idx) => {
const Icon = item.icon;
{/* 团队数据概览 */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.1 }}
className="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-4xl mx-auto mb-16"
>
{TEAM_STATS.map((stat) => (
<div
key={stat.label}
className="text-center py-4 px-3 bg-white rounded-xl border border-[#E5E5E5]"
>
<div className="text-2xl sm:text-3xl font-bold bg-gradient-to-r from-[#C41E3A] to-[#E85D75] bg-clip-text text-transparent mb-1">
{stat.value}
</div>
<div className="text-xs sm:text-sm text-[#5C5C5C]">{stat.label}</div>
</div>
))}
</motion.div>
{/* 团队成员卡片 */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 max-w-6xl mx-auto mb-12">
{TEAM_MEMBERS.map((member, idx) => {
const Icon = member.icon;
return (
<motion.div
key={item.title}
initial={{ opacity: 0, y: 20 }}
key={member.name}
initial={{ opacity: 0, y: 30 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: 0.1 + idx * 0.15 }}
transition={{ duration: 0.5, delay: 0.2 + idx * 0.12 }}
>
<div className="bg-white rounded-2xl p-8 border border-[#E5E5E5] hover:border-[#C41E3A]/30 hover:shadow-lg transition-all duration-300 h-full text-center">
<div className="w-14 h-14 bg-[#C41E3A] rounded-2xl flex items-center justify-center mb-6 mx-auto">
<Icon className="w-7 h-7 text-white" />
<div className="bg-white rounded-2xl p-6 border border-[#E5E5E5] hover:border-[#C41E3A]/30 hover:shadow-lg transition-all duration-300 h-full flex flex-col group">
{/* 头像区 */}
<div className="flex items-center gap-4 mb-4">
<div className={`w-14 h-14 rounded-2xl bg-gradient-to-br ${member.accentColor} flex items-center justify-center shrink-0 group-hover:scale-105 transition-transform duration-300`}>
<Icon className="w-7 h-7 text-white" />
</div>
<div className="min-w-0">
<h3 className="text-base font-bold text-[#1C1C1C] truncate">{member.name}</h3>
<span className="text-xs text-[#C41E3A] font-medium">{member.initials}</span>
</div>
</div>
{/* 简介 */}
<p className="text-sm text-[#5C5C5C] leading-relaxed mb-4 flex-1">{member.bio}</p>
{/* 专业领域标签 */}
<div className="flex flex-wrap gap-1.5">
{member.specialties.map((spec) => (
<span
key={spec}
className="inline-flex items-center text-xs px-2.5 py-1 bg-[#FAFAFA] text-[#3D3D3D] rounded-full border border-[#E5E5E5] group-hover:border-[#C41E3A]/20 transition-colors"
>
{spec}
</span>
))}
</div>
<h3 className="text-lg font-bold text-[#1C1C1C] mb-3">{item.title}</h3>
<p className="text-sm text-[#5C5C5C] leading-relaxed">{item.description}</p>
</div>
</motion.div>
);
})}
</div>
{/* CTA */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.5 }}
transition={{ duration: 0.6, delay: 0.6 }}
className="text-center"
>
<Button
variant="outline"
size="lg"
asChild
>
<StaticLink href="/team">
<StaticLink href="/team">
<RippleButton className="inline-flex items-center gap-2 px-6 py-2.5 border border-[#E5E5E5] rounded-lg text-sm font-medium text-[#1C1C1C] hover:border-[#C41E3A] hover:text-[#C41E3A] transition-colors">
<ArrowRight className="ml-2 w-4 h-4" />
</StaticLink>
</Button>
<ArrowRight className="w-4 h-4" />
</RippleButton>
</StaticLink>
</motion.div>
</div>
</section>