53 KiB
网站优化重构实施计划
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: 统一网站交互模式、优化首页结构、统一配色方案,提升用户体验和品牌一致性。
Architecture: 采用 Next.js App Router 架构,服务详情页使用故事化叙事风格,移除模态框交互,统一使用独立页面。首页精简 About Section,新增 Cases Section。
Tech Stack: Next.js 16, React 19, TypeScript, Tailwind CSS, Framer Motion
实施阶段概览
阶段 1: 服务详情页重构(高优先级)
- 创建服务详情页面
- 删除服务详情模态框
- 修改服务卡片添加链接
阶段 2: 首页结构优化(高优先级)
- 精简首页 About Section
- 新增首页 Cases Section
- 更新首页 Section 顺序
阶段 3: 导航与链接统一(中优先级)
- 更新导航链接
- 创建服务列表页
- 更新 Footer 链接
阶段 4: 配色方案统一(中优先级)
- 移除紫色,统一使用品牌红
- 更新所有相关组件
阶段 1: 服务详情页重构
Task 1.1: 创建服务详情页面
Files:
- Create:
src/app/(marketing)/services/[id]/page.tsx - Create:
src/app/(marketing)/services/[id]/client.tsx
Step 1: 创建服务详情客户端组件
// src/app/(marketing)/services/[id]/client.tsx
'use client';
import { useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent } from '@/components/ui/card';
import { PageHeader } from '@/components/ui/page-header';
import {
ArrowLeft,
CheckCircle2,
TrendingUp,
Users,
Target,
Clock,
MessageCircle,
ArrowRight
} from 'lucide-react';
import { SERVICES, CASES } from '@/lib/constants';
interface ServiceDetailClientProps {
service: typeof SERVICES[number];
}
const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
Code: () => (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
),
Cloud: () => (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>
),
BarChart3: () => (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
),
Shield: () => (
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
),
};
const challenges = {
software: [
{ title: '需求不明确', description: '业务部门提不出清晰需求,开发团队反复返工' },
{ title: '技术选型困难', description: '技术栈更新快,不知道该选什么技术方案' },
{ title: '项目延期', description: '开发进度难以把控,上线时间一拖再拖' },
{ title: '维护成本高', description: '系统上线后问题不断,运维压力巨大' },
],
cloud: [
{ title: '资源浪费', description: '服务器资源利用率低,成本居高不下' },
{ title: '扩展困难', description: '业务增长时系统无法快速扩容' },
{ title: '迁移风险', description: '担心数据丢失、业务中断' },
{ title: '安全顾虑', description: '不确定云端数据是否安全' },
],
data: [
{ title: '数据孤岛', description: '各系统数据分散,无法整合分析' },
{ title: '决策盲区', description: '缺乏数据支撑,决策凭感觉' },
{ title: '报表滞后', description: '手工制作报表,时效性差' },
{ title: '价值难挖', description: '数据很多,但不知道怎么用' },
],
security: [
{ title: '安全漏洞', description: '系统存在未知漏洞,随时可能被攻击' },
{ title: '合规压力', description: '监管要求越来越严,不知如何应对' },
{ title: '内部威胁', description: '员工操作不规范,数据泄露风险' },
{ title: '应急能力弱', description: '安全事件发生后不知所措' },
],
};
const outcomes = {
software: [
{ value: '30%', label: '开发效率提升' },
{ value: '50%', label: '返工率降低' },
{ value: '100%', label: '按时交付率' },
],
cloud: [
{ value: '40%', label: '成本降低' },
{ value: '99.9%', label: '可用性保障' },
{ value: '10x', label: '弹性扩展能力' },
],
data: [
{ value: '70%', label: '决策效率提升' },
{ value: '实时', label: '数据更新' },
{ value: '100+', label: '可视化报表' },
],
security: [
{ value: '99%', label: '漏洞修复率' },
{ value: '100%', label: '合规达标' },
{ value: '24/7', label: '安全监控' },
],
};
export function ServiceDetailClient({ service }: ServiceDetailClientProps) {
const [isVisible, setIsVisible] = useState(false);
const contentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry?.isIntersecting) {
setIsVisible(true);
}
},
{ threshold: 0.1 }
);
if (contentRef.current) {
observer.observe(contentRef.current);
}
return () => observer.disconnect();
}, []);
const serviceChallenges = challenges[service.id as keyof typeof challenges] || [];
const serviceOutcomes = outcomes[service.id as keyof typeof outcomes] || [];
const relatedCases = CASES.slice(0, 2);
const Icon = iconMap[service.icon];
return (
<main className="min-h-screen bg-white">
<div className="relative overflow-hidden bg-gradient-to-b from-[#FAFAFA] to-white">
<div className="container-wide relative z-10 pt-32 pb-20">
<Link href="/services">
<Button variant="ghost" className="text-[#5C5C5C] hover:text-[#C41E3A] hover:bg-[#C41E3A]/10">
<ArrowLeft className="w-4 h-4 mr-2" />
返回服务列表
</Button>
</Link>
<div className="max-w-4xl mt-8">
<div className="flex items-center gap-4 mb-6">
<div className="w-16 h-16 bg-[#C41E3A] rounded-2xl flex items-center justify-center text-white">
{Icon && <Icon />}
</div>
<div>
<Badge className="mb-2 bg-[#C41E3A]/10 text-[#C41E3A] hover:bg-[#C41E3A]/20">
核心业务
</Badge>
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-semibold text-[#1C1C1C]">
{service.title}
</h1>
</div>
</div>
<p className="text-lg text-[#5C5C5C] leading-relaxed">
{service.description}
</p>
</div>
</div>
</div>
<div ref={contentRef} className="container-wide py-12 md:py-16">
<div className="max-w-4xl mx-auto space-y-16">
<section className="bg-gradient-to-br from-[#FFFBF5] to-white rounded-2xl p-8 border border-[#C41E3A]/20">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 bg-[#C41E3A] rounded-xl flex items-center justify-center">
<MessageCircle className="w-6 h-6 text-white" />
</div>
<h2 className="text-2xl font-semibold text-[#1C1C1C]">
您可能面临的挑战
</h2>
</div>
<div className="grid md:grid-cols-2 gap-4">
{serviceChallenges.map((challenge, index) => (
<div
key={index}
className="p-4 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors"
>
<h3 className="font-semibold text-[#1C1C1C] mb-2">{challenge.title}</h3>
<p className="text-sm text-[#5C5C5C]">{challenge.description}</p>
</div>
))}
</div>
</section>
<section className="bg-gradient-to-br from-[#F5F7FA] to-white rounded-2xl p-8 border border-[#E5E5E5]">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 bg-[#C41E3A] rounded-xl flex items-center justify-center">
<Target className="w-6 h-6 text-white" />
</div>
<h2 className="text-2xl font-semibold text-[#1C1C1C]">
我们如何帮助您
</h2>
</div>
<p className="text-lg text-[#5C5C5C] leading-relaxed mb-6">
{service.overview}
</p>
<div className="space-y-3">
{service.features.map((feature, index) => (
<div key={index} className="flex items-start gap-3">
<CheckCircle2 className="w-5 h-5 text-[#C41E3A] mt-0.5 flex-shrink-0" />
<span className="text-[#1C1C1C]">{feature}</span>
</div>
))}
</div>
</section>
<section className="bg-gradient-to-br from-[#FFFBF5] to-white rounded-2xl p-8 border border-[#C41E3A]/20">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 bg-[#C41E3A] rounded-xl flex items-center justify-center">
<Clock className="w-6 h-6 text-white" />
</div>
<h2 className="text-2xl font-semibold text-[#1C1C1C]">
服务流程
</h2>
</div>
<div className="space-y-4">
{service.process.map((step, index) => (
<div key={index} className="flex items-start gap-4">
<div className="w-10 h-10 bg-[#C41E3A] rounded-full flex items-center justify-center flex-shrink-0 text-white font-semibold">
{index + 1}
</div>
<div className="flex-1 pb-4">
<p className="text-[#1C1C1C] font-medium">{step}</p>
</div>
</div>
))}
</div>
</section>
<section className="bg-gradient-to-br from-[#F5F7FA] to-white rounded-2xl p-8 border border-[#E5E5E5]">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 bg-[#C41E3A] rounded-xl flex items-center justify-center">
<TrendingUp className="w-6 h-6 text-white" />
</div>
<h2 className="text-2xl font-semibold text-[#1C1C1C]">
您将获得的改变
</h2>
</div>
<div className="grid sm:grid-cols-3 gap-4">
{serviceOutcomes.map((outcome, index) => (
<div
key={index}
className="p-6 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors text-center"
>
<div className="text-3xl font-bold text-[#C41E3A] mb-2">
{outcome.value}
</div>
<div className="text-sm text-[#5C5C5C]">{outcome.label}</div>
</div>
))}
</div>
<div className="mt-6 p-4 bg-white rounded-lg border border-[#E5E5E5]">
<p className="text-sm text-[#5C5C5C]">
{service.benefits.map(b => b).join(';')}
</p>
</div>
</section>
<section className="bg-gradient-to-br from-[#FFFBF5] to-white rounded-2xl p-8 border border-[#C41E3A]/20">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 bg-[#C41E3A] rounded-xl flex items-center justify-center">
<Users className="w-6 h-6 text-white" />
</div>
<h2 className="text-2xl font-semibold text-[#1C1C1C]">
相关案例
</h2>
</div>
<div className="grid md:grid-cols-2 gap-4">
{relatedCases.map((caseItem) => (
<Link
key={caseItem.id}
href={`/cases/${caseItem.id}`}
className="group p-4 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors"
>
<Badge variant="secondary" className="mb-2">
{caseItem.industry}
</Badge>
<h3 className="font-semibold text-[#1C1C1C] group-hover:text-[#C41E3A] transition-colors">
{caseItem.title}
</h3>
<p className="text-sm text-[#5C5C5C] mt-2 line-clamp-2">
{caseItem.description}
</p>
</Link>
))}
</div>
</section>
<div className="flex justify-center gap-4 pt-8 border-t border-[#E5E5E5]">
<Button variant="outline" size="lg" asChild>
<Link href="/services">
查看其他服务
</Link>
</Button>
<Button size="lg" className="bg-[#C41E3A] hover:bg-[#A01830] text-white" asChild>
<Link href="/contact">
开始您的转型之旅
<ArrowRight className="ml-2 w-4 h-4" />
</Link>
</Button>
</div>
</div>
</div>
</main>
);
}
Step 2: 创建服务详情页面入口
// src/app/(marketing)/services/[id]/page.tsx
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { SERVICES } from '@/lib/constants';
import { ServiceDetailClient } from './client';
export async function generateStaticParams() {
return SERVICES.map((service) => ({
id: service.id,
}));
}
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
const { id } = await params;
const service = SERVICES.find((s) => s.id === id);
if (!service) {
return {
title: '服务未找到',
};
}
return {
title: `${service.title} - 睿新致远`,
description: service.description,
};
}
export default async function ServiceDetailPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const service = SERVICES.find((s) => s.id === id);
if (!service) {
notFound();
}
return <ServiceDetailClient service={service} />;
}
Step 3: 验证文件创建成功
Run: ls -la src/app/\(marketing\)/services/
Expected: 目录和文件已创建
Step 4: Commit
git add src/app/\(marketing\)/services/
git commit -m "feat: add service detail page with storytelling style"
Task 1.2: 创建服务列表页面
Files:
- Create:
src/app/(marketing)/services/page.tsx
Step 1: 创建服务列表页面
// src/app/(marketing)/services/page.tsx
'use client';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent } from '@/components/ui/card';
import { PageHeader } from '@/components/ui/page-header';
import { ArrowRight, Code, Cloud, BarChart3, Shield } from 'lucide-react';
import { SERVICES } from '@/lib/constants';
const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
Code,
Cloud,
BarChart3,
Shield,
};
export default function ServicesPage() {
const contentRef = useRef(null);
const isContentInView = useInView(contentRef, { once: true, margin: '-100px' });
return (
<div className="min-h-screen bg-white">
<PageHeader
title="核心业务"
description="专业技术团队,为您提供全方位的数字化解决方案"
/>
<div className="container-wide relative z-10 py-16" ref={contentRef}>
<div className="max-w-6xl mx-auto">
<div className="grid md:grid-cols-2 gap-8">
{SERVICES.map((service, index) => {
const Icon = iconMap[service.icon];
return (
<motion.div
key={service.id}
initial={{ opacity: 0, y: 20 }}
animate={isContentInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<Link
href={`/services/${service.id}`}
className="group bg-white rounded-2xl border border-[#E5E5E5] overflow-hidden hover:shadow-xl transition-all duration-300 block h-full"
>
<div className="p-8">
<div className="flex items-start gap-4 mb-4">
<div className="w-14 h-14 rounded-xl bg-[#F5F5F5] flex items-center justify-center group-hover:bg-[#C41E3A] transition-all duration-300">
{Icon && <Icon className="w-7 h-7 text-[#1C1C1C] group-hover:text-white transition-colors" />}
</div>
<div className="flex-1">
<h3 className="text-xl font-semibold text-[#1C1C1C] mb-2 group-hover:text-[#C41E3A] transition-colors">
{service.title}
</h3>
<p className="text-[#5C5C5C] text-sm leading-relaxed">
{service.description}
</p>
</div>
</div>
<div className="mt-6 pt-4 border-t border-[#E5E5E5]">
<div className="flex flex-wrap gap-2 mb-4">
{service.features.slice(0, 3).map((feature, idx) => (
<Badge key={idx} variant="secondary" className="text-xs">
{feature.split(':')[0]}
</Badge>
))}
</div>
<div className="flex items-center text-[#C41E3A] font-medium group-hover:translate-x-2 transition-transform">
了解详情
<ArrowRight className="w-4 h-4 ml-2" />
</div>
</div>
</div>
</Link>
</motion.div>
);
})}
</div>
</div>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isContentInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.4 }}
className="bg-[#F5F5F5] py-16"
>
<div className="container-wide text-center">
<h2 className="text-3xl font-bold text-[#1C1C1C] mb-6">
准备开始您的数字化转型之旅?
</h2>
<p className="text-lg text-[#5C5C5C] mb-8 max-w-2xl mx-auto">
让我们与您同行,共创美好未来
</p>
<Button
size="lg"
className="bg-[#C41E3A] hover:bg-[#A01830] text-white"
asChild
>
<Link href="/contact">
立即咨询
<ArrowRight className="ml-2 w-4 h-4" />
</Link>
</Button>
</div>
</motion.div>
</div>
);
}
Step 2: 验证文件创建成功
Run: ls -la src/app/\(marketing\)/services/page.tsx
Expected: 文件已创建
Step 3: Commit
git add src/app/\(marketing\)/services/page.tsx
git commit -m "feat: add services list page"
Task 1.3: 修改服务卡片组件添加链接
Files:
- Modify:
src/components/sections/services-section.tsx
Step 1: 移除模态框相关代码,添加链接
Read: src/components/sections/services-section.tsx
Replace entire file with:
'use client';
import { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import Link from 'next/link';
import { Code, Cloud, BarChart3, Shield, ArrowRight } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { SERVICES } from '@/lib/constants';
const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
Code,
Cloud,
BarChart3,
Shield,
};
export function ServicesSection() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: '-100px' });
return (
<section id="solutions" aria-labelledby="solutions-heading" className="py-24 bg-white relative overflow-hidden" ref={ref}>
<div className="absolute top-1/3 left-0 w-[400px] h-[400px] bg-[rgba(196,30,58,0.03)] rounded-full blur-3xl" />
<div className="absolute top-1/3 right-0 w-[300px] h-[300px] 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="solutions-heading" className="text-4xl md:text-5xl font-bold text-[#1C1C1C] mb-4">
我们的 <span className="text-[#C41E3A]">核心业务</span>
</h2>
<p className="text-lg text-[#5C5C5C] max-w-2xl mx-auto">
专业技术团队,为您提供全方位的数字化解决方案
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{SERVICES.map((service, index) => {
const Icon = iconMap[service.icon];
return (
<motion.div
key={service.id}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<Link href={`/services/${service.id}`}>
<Card className="p-6 h-full group cursor-pointer border-[#E5E5E5] hover:border-[#C41E3A] transition-colors">
<CardContent className="p-0">
<div className="w-12 h-12 rounded-xl bg-[#F5F5F5] flex items-center justify-center mb-4 group-hover:bg-[#C41E3A] transition-all duration-300">
{Icon && <Icon className="w-6 h-6 text-[#1C1C1C] group-hover:text-white transition-colors" />}
</div>
<h3 className="text-xl font-semibold text-[#1C1C1C] mb-3 group-hover:text-[#C41E3A] transition-colors">{service.title}</h3>
<p className="text-[#5C5C5C] text-sm leading-relaxed">{service.description}</p>
<div className="mt-4 flex items-center text-[#C41E3A] text-sm font-medium opacity-0 group-hover:opacity-100 transition-opacity">
了解详情
<ArrowRight className="ml-1 w-4 h-4" />
</div>
</CardContent>
</Card>
</Link>
</motion.div>
);
})}
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.4 }}
className="text-center mt-12"
>
<Button variant="outline" size="lg" className="group" asChild>
<Link href="/services">
查看全部服务
<ArrowRight className="ml-2 w-4 h-4 transition-transform group-hover:translate-x-1" />
</Link>
</Button>
</motion.div>
</div>
</section>
);
}
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/components/sections/services-section.tsx
git commit -m "refactor: remove modal, add link navigation for services"
Task 1.4: 删除服务详情模态框组件
Files:
- Delete:
src/components/services/service-detail-modal.tsx
Step 1: 删除模态框组件文件
Run: rm src/components/services/service-detail-modal.tsx
Step 2: 验证删除成功
Run: ls src/components/services/
Expected: 目录为空或不存在
Step 3: 如果目录为空,删除目录
Run: rmdir src/components/services/ 2>/dev/null || true
Step 4: Commit
git add -A
git commit -m "refactor: remove service detail modal component"
阶段 2: 首页结构优化
Task 2.1: 精简首页 About Section
Files:
- Modify:
src/components/sections/about-section.tsx
Step 1: 精简 About Section 内容
Read: src/components/sections/about-section.tsx
Replace entire file with:
'use client';
import { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import Link from 'next/link';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { COMPANY_INFO, STATS } from '@/lib/constants';
import { ArrowRight } from 'lucide-react';
export function AboutSection() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: '-100px' });
return (
<section id="about" className="py-24 bg-[#FAFAFA] relative" ref={ref}>
<div className="absolute inset-0 bg-[linear-gradient(rgba(28,28,28,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(28,28,28,0.02)_1px,transparent_1px)] bg-[size:40px_40px]" />
<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="max-w-4xl mx-auto"
>
<div className="text-center mb-12">
<h2 className="text-4xl md:text-5xl font-bold text-[#1C1C1C] mb-6">
关于 <span className="tracking-tight font-calligraphy text-[#C41E3A]" style={{ fontWeight: 'normal', WebkitFontSmoothing: 'antialiased', MozOsxFontSmoothing: 'grayscale', textRendering: 'optimizeLegibility' }}>{COMPANY_INFO.shortName}</span>
</h2>
<p className="text-lg text-[#5C5C5C] mb-8">
{COMPANY_INFO.slogan}
</p>
</div>
<div className="bg-white rounded-2xl p-8 mb-12 border border-[#E5E5E5]">
<p className="text-lg text-[#5C5C5C] leading-relaxed text-center mb-6">
"企业需要的,不是一个高高在上的'专家',也不是一个做完就跑的'卖家',而是一个能坐下来、一起想办法的同行者。"
</p>
<p className="text-[#1C1C1C] font-medium text-center">
我们只做一件事:成为您数字化转型路上,信得过的成长伙伴。
</p>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.2 }}
className="grid grid-cols-2 md:grid-cols-4 gap-6 mb-12"
>
{STATS.map((stat, idx) => (
<Card key={idx} className="text-center border-[#E5E5E5]">
<CardContent className="pt-6">
<div className="text-3xl sm:text-4xl font-bold text-[#C41E3A] mb-2">{stat.value}</div>
<div className="text-sm text-[#5C5C5C]">{stat.label}</div>
</CardContent>
</Card>
))}
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.3 }}
className="text-center"
>
<Button size="lg" variant="outline" className="group" asChild>
<Link href="/about">
了解更多关于我们
<ArrowRight className="ml-2 w-4 h-4 transition-transform group-hover:translate-x-1" />
</Link>
</Button>
</motion.div>
</motion.div>
</div>
</section>
);
}
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/components/sections/about-section.tsx
git commit -m "refactor: simplify about section on homepage"
Task 2.2: 创建首页 Cases Section
Files:
- Create:
src/components/sections/cases-section.tsx
Step 1: 创建 Cases Section 组件
// src/components/sections/cases-section.tsx
'use client';
import { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import Link from 'next/link';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { CASES } from '@/lib/constants';
import { ArrowRight, Building2, TrendingUp } from 'lucide-react';
export function CasesSection() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: '-100px' });
const featuredCases = CASES.slice(0, 3);
return (
<section id="cases" className="py-24 bg-white relative overflow-hidden" ref={ref}>
<div className="absolute top-1/3 left-0 w-[400px] h-[400px] bg-[rgba(196,30,58,0.03)] rounded-full blur-3xl" />
<div className="absolute top-1/3 right-0 w-[300px] h-[300px] 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 className="text-4xl md:text-5xl font-bold text-[#1C1C1C] mb-4">
与谁同行,<span className="text-[#C41E3A]">决定能走多远</span>
</h2>
<p className="text-lg text-[#5C5C5C] max-w-2xl mx-auto">
我们与优秀的企业同行,共同成长,共创未来
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{featuredCases.map((caseItem, index) => (
<motion.div
key={caseItem.id}
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: 0.1 + index * 0.1 }}
>
<Link href={`/cases/${caseItem.id}`}>
<Card className="h-full group cursor-pointer border-[#E5E5E5] hover:border-[#C41E3A] transition-colors overflow-hidden">
<div className="relative h-40 bg-gradient-to-br from-[#F5F5F5] to-[#E5E5E5] flex items-center justify-center">
<Building2 className="w-16 h-16 text-[#C41E3A]/20 group-hover:scale-110 transition-transform duration-300" />
<div className="absolute top-4 right-4">
<Badge className="bg-white/90 text-[#1C1C1C] hover:bg-white">
{caseItem.industry}
</Badge>
</div>
</div>
<CardContent className="p-6">
<div className="flex items-center gap-2 mb-3">
<Building2 className="w-4 h-4 text-[#C41E3A]" />
<span className="text-sm text-[#5C5C5C]">{caseItem.client}</span>
</div>
<h3 className="text-lg font-semibold text-[#1C1C1C] mb-3 group-hover:text-[#C41E3A] transition-colors">
{caseItem.title}
</h3>
<p className="text-[#5C5C5C] text-sm line-clamp-2 mb-4">
{caseItem.description}
</p>
{caseItem.results.length > 0 && (
<div className="flex items-center gap-2 text-[#C41E3A]">
<TrendingUp className="w-4 h-4" />
<span className="text-sm font-medium">{caseItem.results[0].value}</span>
<span className="text-sm text-[#5C5C5C]">{caseItem.results[0].label}</span>
</div>
)}
</CardContent>
</Card>
</Link>
</motion.div>
))}
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.4 }}
className="text-center mt-12"
>
<Button variant="outline" size="lg" className="group" asChild>
<Link href="/cases">
查看更多案例
<ArrowRight className="ml-2 w-4 h-4 transition-transform group-hover:translate-x-1" />
</Link>
</Button>
</motion.div>
</div>
</section>
);
}
Step 2: 验证文件创建成功
Run: ls -la src/components/sections/cases-section.tsx
Expected: 文件已创建
Step 3: Commit
git add src/components/sections/cases-section.tsx
git commit -m "feat: add cases section to homepage"
Task 2.3: 更新首页 Section 顺序
Files:
- Modify:
src/app/(marketing)/page.tsx
Step 1: 更新首页导入和 Section 顺序
Read: src/app/(marketing)/page.tsx
Replace entire file with:
"use client";
import dynamic from 'next/dynamic';
import { Header } from "@/components/layout/header";
import { Footer } from "@/components/layout/footer";
import { HeroSection } from "@/components/sections/hero-section";
import { SectionSkeleton } from "@/components/ui/loading-skeleton";
const ServicesSection = dynamic(
() => import('@/components/sections/services-section').then(mod => ({ default: mod.ServicesSection })),
{
loading: () => <SectionSkeleton />,
ssr: true
}
);
const ProductsSection = dynamic(
() => import('@/components/sections/products-section').then(mod => ({ default: mod.ProductsSection })),
{
loading: () => <SectionSkeleton />,
ssr: true
}
);
const CasesSection = dynamic(
() => import('@/components/sections/cases-section').then(mod => ({ default: mod.CasesSection })),
{
loading: () => <SectionSkeleton />,
ssr: true
}
);
const AboutSection = dynamic(
() => import('@/components/sections/about-section').then(mod => ({ default: mod.AboutSection })),
{
loading: () => <SectionSkeleton />,
ssr: true
}
);
const NewsSection = dynamic(
() => import('@/components/sections/news-section').then(mod => ({ default: mod.NewsSection })),
{
loading: () => <SectionSkeleton />,
ssr: true
}
);
const ContactSection = dynamic(
() => import('@/components/sections/contact-section').then(mod => ({ default: mod.ContactSection })),
{
loading: () => <SectionSkeleton />,
ssr: true
}
);
export default function HomePage() {
return (
<main className="min-h-screen bg-white dark:bg-[var(--color-bg-primary)]">
<Header />
<HeroSection />
<ServicesSection />
<ProductsSection />
<CasesSection />
<AboutSection />
<NewsSection />
<ContactSection />
<Footer />
</main>
);
}
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/app/\(marketing\)/page.tsx
git commit -m "refactor: update homepage section order with cases section"
阶段 3: 导航与链接统一
Task 3.1: 更新导航链接
Files:
- Modify:
src/lib/constants.ts - Modify:
src/components/layout/header.tsx
Step 1: 更新导航配置
Read: src/lib/constants.ts
Find the NAVIGATION constant and replace with:
// Navigation Items - 独立页面导航
export const NAVIGATION = [
{ id: 'home', label: '首页', href: '/' },
{ id: 'services', label: '核心业务', href: '/services' },
{ id: 'products', label: '产品服务', href: '/products' },
{ id: 'about', label: '关于我们', href: '/about' },
{ id: 'news', label: '新闻动态', href: '/news' },
{ id: 'contact', label: '联系我们', href: '/contact' },
] as const;
Step 2: 更新 Header 组件
Read: src/components/layout/header.tsx
Replace the navigation handling logic to use Link instead of anchor scroll:
'use client';
import { useState, useEffect, useCallback, useRef } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Menu, X } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { Button } from '@/components/ui/button';
import { COMPANY_INFO, NAVIGATION } from '@/lib/constants';
import { useFocusTrap } from '@/hooks/use-focus-trap';
export function Header() {
const [isOpen, setIsOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);
const pathname = usePathname();
const focusTrapRef = useFocusTrap<HTMLDivElement>(isOpen);
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 20);
};
window.addEventListener('scroll', handleScroll, { passive: true });
handleScroll();
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
setIsOpen(!isOpen);
}
if (e.key === 'Escape' && isOpen) {
setIsOpen(false);
}
}, [isOpen]);
return (
<>
<header
className={`
fixed top-0 left-0 right-0 z-50
transition-all duration-300 ease-out
${isScrolled
? 'bg-white/95 backdrop-blur-xl border-b border-[#E2E8F0] shadow-sm'
: 'bg-transparent'
}
`}
>
<div className="container-wide">
<div className="flex items-center justify-between h-16">
<Link
href="/"
className="flex items-center group focus:outline-none focus:ring-2 focus:ring-[#C41E3A] focus:ring-offset-2 rounded-sm"
>
<img
src="/logo.svg"
alt={COMPANY_INFO.name}
className="h-8 w-auto transition-transform duration-200 group-hover:scale-105"
/>
</Link>
<nav className="hidden md:flex items-center gap-1" role="navigation" aria-label="主导航">
{NAVIGATION.map((item) => (
<Link
key={item.id}
href={item.href}
className={`
relative px-3 py-1.5 text-sm font-medium
transition-all duration-300
focus:outline-none focus:ring-2 focus:ring-[#C41E3A] focus:ring-offset-2 rounded-sm
${pathname === item.href || (item.href !== '/' && pathname.startsWith(item.href))
? 'text-[#1C1C1C]'
: 'text-[#3D3D3D] hover:text-[#1C1C1C]'
}
`}
aria-current={pathname === item.href ? 'page' : undefined}
>
{item.label}
{(pathname === item.href || (item.href !== '/' && pathname.startsWith(item.href))) && (
<motion.span
layoutId="activeNav"
className="absolute bottom-0 left-1/2 -translate-x-1/2 w-6 h-0.5 bg-[#C41E3A] rounded-full"
transition={{ type: "spring", stiffness: 380, damping: 30 }}
/>
)}
</Link>
))}
</nav>
<div className="hidden md:flex items-center gap-3">
<Button
size="sm"
asChild
>
<Link href="/contact">立即咨询</Link>
</Button>
</div>
<button
className="md:hidden p-2 -mr-2 text-[#3D3D3D] hover:text-[#1C1C1C] transition-colors focus:outline-none focus:ring-2 focus:ring-[#C41E3A] focus:ring-offset-2 rounded-sm"
onClick={() => setIsOpen(!isOpen)}
onKeyDown={handleKeyDown}
aria-expanded={isOpen}
aria-controls="mobile-menu"
aria-label={isOpen ? '关闭菜单' : '打开菜单'}
>
{isOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
</button>
</div>
</div>
</header>
<AnimatePresence>
{isOpen && (
<motion.div
ref={focusTrapRef}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-40 md:hidden"
>
<div
className="absolute inset-0 bg-black/20 backdrop-blur-sm"
onClick={() => setIsOpen(false)}
aria-hidden="true"
/>
<motion.div
initial={{ y: -20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: -20, opacity: 0 }}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
className="absolute top-16 left-0 right-0 bg-white/95 backdrop-blur-xl border-b border-[#E2E8F0] shadow-lg"
id="mobile-menu"
role="navigation"
aria-label="移动端导航"
>
<nav className="container-wide py-4">
{NAVIGATION.map((item, index) => (
<motion.div
key={item.id}
initial={{ x: -20, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{ delay: index * 0.05 }}
>
<Link
href={item.href}
onClick={() => setIsOpen(false)}
className={`
block px-4 py-3 text-base font-medium
transition-all duration-300
border-l-2
focus:outline-none focus:ring-2 focus:ring-[#C41E3A] focus:ring-inset
${pathname === item.href || (item.href !== '/' && pathname.startsWith(item.href))
? 'text-[#1C1C1C] border-[#C41E3A] bg-[#FEF2F4]'
: 'text-[#3D3D3D] border-transparent hover:text-[#1C1C1C] hover:bg-[#F5F5F5]'
}
`}
>
{item.label}
</Link>
</motion.div>
))}
<div className="mt-4 px-4 pt-4 border-t border-[#E2E8F0] space-y-3">
<Button
className="w-full"
asChild
>
<Link href="/contact" onClick={() => setIsOpen(false)}>
联系我们
</Link>
</Button>
</div>
</nav>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</>
);
}
Step 3: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 4: Commit
git add src/lib/constants.ts src/components/layout/header.tsx
git commit -m "refactor: update navigation to use independent page links"
Task 3.2: 创建产品列表页面
Files:
- Create:
src/app/(marketing)/products/page.tsx
Step 1: 创建产品列表页面
// src/app/(marketing)/products/page.tsx
'use client';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { useInView } from 'framer-motion';
import { useRef } from 'react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { PageHeader } from '@/components/ui/page-header';
import { ArrowRight, Check, TrendingUp } from 'lucide-react';
import { PRODUCTS } from '@/lib/constants';
export default function ProductsPage() {
const contentRef = useRef(null);
const isContentInView = useInView(contentRef, { once: true, margin: '-100px' });
return (
<div className="min-h-screen bg-white">
<PageHeader
title="产品服务"
description="自主研发的企业级产品,助力企业高效运营,实现数字化转型"
/>
<div className="container-wide relative z-10 py-16" ref={contentRef}>
<div className="max-w-6xl mx-auto">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{PRODUCTS.map((product, index) => (
<motion.div
key={product.id}
initial={{ opacity: 0, y: 20 }}
animate={isContentInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<Link href={`/products/${product.id}`}>
<Card className="h-full group cursor-pointer border-[#E5E5E5] hover:border-[#C41E3A] transition-colors">
<CardHeader>
<Badge variant="secondary" className="w-fit mb-3">
{product.category}
</Badge>
<CardTitle className="group-hover:text-[#C41E3A] transition-colors">{product.title}</CardTitle>
</CardHeader>
<CardContent className="flex-1 flex flex-col">
<CardDescription className="text-base leading-relaxed mb-4 flex-1">
{product.description}
</CardDescription>
<div className="mb-4">
<p className="text-sm font-medium text-[#1C1C1C] mb-2">核心功能</p>
<div className="flex flex-wrap gap-1.5">
{product.features.slice(0, 4).map((feature, idx) => (
<span
key={idx}
className="inline-flex items-center text-xs px-2 py-1 bg-[#FAFAFA] text-[#3D3D3D] rounded border border-[#E5E5E5]"
>
<Check className="w-3 h-3 mr-1 text-[#C41E3A]" />
{feature}
</span>
))}
</div>
</div>
<div className="mb-4">
<p className="text-sm font-medium text-[#1C1C1C] mb-2 flex items-center">
<TrendingUp className="w-4 h-4 mr-1 text-[#C41E3A]" />
核心价值
</p>
<ul className="space-y-1">
{product.benefits.map((benefit, idx) => (
<li key={idx} className="text-xs text-[#5C5C5C] flex items-start">
<span className="text-[#C41E3A] mr-1.5">•</span>
{benefit}
</li>
))}
</ul>
</div>
<Button variant="outline" className="w-full mt-auto group-hover:bg-[#C41E3A] group-hover:text-white group-hover:border-[#C41E3A] transition-colors">
了解详情
<ArrowRight className="ml-2 w-4 h-4" />
</Button>
</CardContent>
</Card>
</Link>
</motion.div>
))}
</div>
</div>
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={isContentInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.4 }}
className="bg-[#F5F5F5] py-16"
>
<div className="container-wide text-center">
<h2 className="text-3xl font-bold text-[#1C1C1C] mb-6">
需要定制化解决方案?
</h2>
<p className="text-lg text-[#5C5C5C] mb-8 max-w-2xl mx-auto">
我们的专业团队可以根据您的业务需求,提供量身定制的产品开发和系统集成服务
</p>
<Button
size="lg"
className="bg-[#C41E3A] hover:bg-[#A01830] text-white"
asChild
>
<Link href="/contact">
联系我们
<ArrowRight className="ml-2 w-4 h-4" />
</Link>
</Button>
</div>
</motion.div>
</div>
);
}
Step 2: 验证文件创建成功
Run: ls -la src/app/\(marketing\)/products/page.tsx
Expected: 文件已创建
Step 3: Commit
git add src/app/\(marketing\)/products/page.tsx
git commit -m "feat: add products list page"
Task 3.3: 更新 Footer 链接
Files:
- Modify:
src/components/layout/footer.tsx
Step 1: 更新 Footer 导航链接
Read: src/components/layout/footer.tsx
Replace the navigation links section with:
<div>
<h3 className="font-semibold text-lg mb-6 text-[#1C1C1C]">快速链接</h3>
<ul className="space-y-3">
{NAVIGATION.map((item) => (
<li key={item.id}>
<Link
href={item.href}
className="text-[#3D3D3D] hover:text-[#C41E3A] transition-colors"
>
{item.label}
</Link>
</li>
))}
</ul>
</div>
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/components/layout/footer.tsx
git commit -m "refactor: update footer navigation links"
阶段 4: 配色方案统一
Task 4.1: 更新案例详情页配色
Files:
- Modify:
src/app/(marketing)/cases/[id]/client.tsx
Step 1: 将紫色替换为品牌红
Read: src/app/(marketing)/cases/[id]/client.tsx
Replace all occurrences of:
#4F46E5→#C41E3Argba(79,70,229,→rgba(196,30,58,
Key replacements:
// Before
<div className="w-12 h-12 bg-[#4F46E5] rounded-xl flex items-center justify-center">
// After
<div className="w-12 h-12 bg-[#C41E3A] rounded-xl flex items-center justify-center">
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/app/\(marketing\)/cases/\[id\]/client.tsx
git commit -m "style: unify color scheme to brand red in case detail page"
Task 4.2: 更新 Solutions 页面配色
Files:
- Modify:
src/app/(marketing)/solutions/page.tsx
Step 1: 将紫色替换为品牌红
Read: src/app/(marketing)/solutions/page.tsx
Replace all occurrences of:
#4F46E5→#C41E3Argba(79,70,229,→rgba(196,30,58,
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/app/\(marketing\)/solutions/page.tsx
git commit -m "style: unify color scheme to brand red in solutions page"
Task 4.3: 更新 Products Section 配色
Files:
- Modify:
src/components/sections/products-section.tsx
Step 1: 将紫色替换为品牌红
Read: src/components/sections/products-section.tsx
Replace all occurrences of:
#4F46E5→#C41E3Argba(79,70,229,→rgba(196,30,58,
Step 2: 验证修改
Run: npm run lint
Expected: 无 lint 错误
Step 3: Commit
git add src/components/sections/products-section.tsx
git commit -m "style: unify color scheme to brand red in products section"
阶段 5: 清理与验证
Task 5.1: 删除旧的 Solutions 页面(可选)
Files:
- Delete:
src/app/(marketing)/solutions/(如果与 services 重复)
Step 1: 检查是否需要删除
Run: ls -la src/app/\(marketing\)/solutions/
如果 solutions 页面与 services 功能重复,考虑重定向或删除。
Step 2: 如果决定保留,更新导航
确保导航指向正确的页面。
Task 5.2: 运行完整测试
Step 1: 运行 lint 检查
Run: npm run lint
Expected: 无错误
Step 2: 运行类型检查
Run: npm run typecheck || npx tsc --noEmit
Expected: 无类型错误
Step 3: 运行构建
Run: npm run build
Expected: 构建成功
Step 4: 本地测试
Run: npm run dev
手动测试以下页面:
/- 首页/services- 服务列表/services/[id]- 服务详情/products- 产品列表/products/[id]- 产品详情/cases- 案例列表/cases/[id]- 案例详情/about- 关于我们/news- 新闻列表/contact- 联系我们
Task 5.3: 最终提交
Step 1: 检查所有更改
Run: git status
Step 2: 提交所有更改
git add -A
git commit -m "refactor: complete website optimization - unified navigation, colors, and structure"
实施完成检查清单
- 服务详情页创建完成
- 服务列表页创建完成
- 服务模态框已删除
- 首页 About Section 已精简
- 首页 Cases Section 已添加
- 导航链接已统一
- 产品列表页已创建
- Footer 链接已更新
- 配色方案已统一
- Lint 检查通过
- 类型检查通过
- 构建成功
- 手动测试通过