Files
novalon-website/src/components/sections/team-section.tsx
T
张翔 e83ecddfe5 refactor(project): 全面清理项目代码并重命名项目
- 移除无用文件和空文件夹,清理 effects 和 scripts 目录
- 将项目从 ruixin-website-react 重命名为 novalon-website-react
- 修复所有测试用例,确保 731 个测试全部通过
- 优化组件导入路径和测试 mock 设置
- 更新项目配置文件和依赖管理

关联任务:项目清理与重构
2026-04-27 12:56:22 +08:00

158 lines
6.5 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 { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import { StaticLink } from '@/components/ui/static-link';
import { RippleButton } from '@/components/ui/ripple-button';
import { ArrowRight, Briefcase, GraduationCap, Target, Users } from 'lucide-react';
const TEAM_MEMBERS = [
{
name: '创始人兼CEO',
initials: 'CEO',
specialties: ['企业战略', '数字化转型', '组织管理'],
bio: '15年+企业服务经验,深耕数字化转型领域,擅长从战略高度为企业规划数字化路径。',
icon: Target,
accentColor: 'from-[#C41E3A] to-[#E85D75]',
},
{
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,
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 } : {}}
transition={{ duration: 0.6 }}
className="text-center max-w-3xl mx-auto mb-16"
>
<h2 id="team-heading" className="text-4xl md:text-5xl font-bold text-[#1C1C1C] mb-6">
<span className="text-[#C41E3A] font-calligraphy"></span>
</h2>
<p className="text-lg text-[#5C5C5C] leading-relaxed">
IT企业的核心团队
</p>
</motion.div>
{/* 团队数据概览 */}
<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={member.name}
initial={{ opacity: 0, y: 30 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: 0.2 + idx * 0.12 }}
>
<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>
</div>
</motion.div>
);
})}
</div>
{/* CTA */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.6 }}
className="text-center"
>
<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="w-4 h-4" />
</RippleButton>
</StaticLink>
</motion.div>
</div>
</section>
);
}