Files
novalon-website/docs/plans/2026-02-13-website-redesign-implementation-plan.md
T

1280 lines
33 KiB
Markdown
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.
# 睿新致远官网重构实施计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 基于优秀案例参考,全面升级睿新致远官网,融合印章文化与现代科技,提升品牌形象和转化率
**Architecture:** 采用 Next.js 16 App Router + React 19 + TypeScript 技术栈,基于现有组件库扩展,优化 Hero 区域印章动画,新增技术洞察板块和客户评价模块,全面提升用户体验和转化路径
**Tech Stack:** Next.js 16.1.6, React 19.2.3, TypeScript 5, Tailwind CSS v4, Framer Motion 12.29.2, shadcn/ui
---
## 实施策略
### 优先级说明
**P0(核心功能)** - 必须完成,直接影响品牌形象和转化
**P1(重要功能)** - 显著提升用户体验和专业度
**P2(增强功能)** - 锦上添花,可后续迭代
### 开发原则
- **TDD(测试驱动开发)**:先写测试,再写实现
- **DRY(不重复)**:复用现有组件和工具函数
- **YAGNI(不过度设计)**:只实现当前需要的功能
- **频繁提交**:每个小功能点独立提交
- **性能优先**:关注 LCP、FID、CLS 指标
---
## Phase 1: P0 核心功能优化(预计 5-7 天)
### Task 1: 优化印章粒子动画组件
**目标:** 增强印章粒子动画的视觉效果和交互体验
**Files:**
- Modify: `src/components/effects/seal-particle.tsx`
- Create: `src/components/effects/seal-animation-enhanced.tsx`
- Test: `src/components/effects/__tests__/seal-animation-enhanced.test.tsx`
**Step 1: 创建增强版印章动画组件**
创建文件:`src/components/effects/seal-animation-enhanced.tsx`
```typescript
'use client';
import { useEffect, useRef, useCallback, useState } from 'react';
interface Particle {
x: number;
y: number;
targetX: number;
targetY: number;
vx: number;
vy: number;
size: number;
opacity: number;
color: string;
life: number;
maxLife: number;
stage: 'idle' | 'dispersing' | 'reforming';
}
interface SealAnimationEnhancedProps {
width?: number;
height?: number;
particleCount?: number;
colors?: string[];
sealText?: string;
animationStages?: boolean;
onStageChange?: (stage: string) => void;
className?: string;
}
export function SealAnimationEnhanced({
width = 300,
height = 300,
particleCount = 150,
colors = ['#C41E3A', '#D4A574', '#8B4513'],
sealText = '睿新',
animationStages = true,
onStageChange,
className = '',
}: SealAnimationEnhancedProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);
const particlesRef = useRef<Particle[]>([]);
const animationRef = useRef<number | null>(null);
const [currentStage, setCurrentStage] = useState<'idle' | 'dispersing' | 'reforming'>('idle');
const stageTimerRef = useRef<NodeJS.Timeout | null>(null);
const createSealShape = useCallback((width: number, height: number) => {
const centerX = width / 2;
const centerY = height / 2;
const sealSize = Math.min(width, height) * 0.35;
const particles: { x: number; y: number }[] = [];
// 创建印章形状的粒子位置(简化版方形印章)
for (let i = 0; i < particleCount; i++) {
const angle = (i / particleCount) * Math.PI * 2;
const radius = sealSize * (0.8 + Math.random() * 0.4);
particles.push({
x: centerX + Math.cos(angle) * radius * (Math.random() > 0.5 ? 1 : 0.8),
y: centerY + Math.sin(angle) * radius * (Math.random() > 0.5 ? 1 : 0.8),
});
}
return particles;
}, [particleCount]);
const createParticle = useCallback(
(x: number, y: number, targetX: number, targetY: number): Particle => {
const color = colors[Math.floor(Math.random() * colors.length)];
const size = 2 + Math.random() * 3;
const maxLife = 200 + Math.random() * 100;
return {
x,
y,
targetX,
targetY,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2,
size,
opacity: 0.6 + Math.random() * 0.4,
color,
life: 0,
maxLife,
stage: 'idle',
};
},
[colors]
);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
canvas.width = width;
canvas.height = height;
const sealPositions = createSealShape(width, height);
particlesRef.current = sealPositions.map((pos, i) =>
createParticle(pos.x, pos.y, pos.x, pos.y)
);
// 动画阶段控制
if (animationStages) {
// 3秒后开始分散
stageTimerRef.current = setTimeout(() => {
setCurrentStage('dispersing');
onStageChange?.('dispersing');
particlesRef.current.forEach(p => {
p.vx = (Math.random() - 0.5) * 4;
p.vy = (Math.random() - 0.5) * 4;
p.stage = 'dispersing';
});
// 2秒后开始重组
setTimeout(() => {
setCurrentStage('reforming');
onStageChange?.('reforming');
particlesRef.current.forEach(p => {
p.stage = 'reforming';
});
// 3秒后回到idle
setTimeout(() => {
setCurrentStage('idle');
onStageChange?.('idle');
}, 3000);
}, 2000);
}, 3000);
}
const animate = () => {
ctx.clearRect(0, 0, width, height);
particlesRef.current.forEach((particle) => {
if (particle.stage === 'reforming') {
// 向目标位置移动
const dx = particle.targetX - particle.x;
const dy = particle.targetY - particle.y;
particle.vx += dx * 0.02;
particle.vy += dy * 0.02;
particle.vx *= 0.95;
particle.vy *= 0.95;
}
particle.x += particle.vx;
particle.y += particle.vy;
particle.life++;
// 绘制粒子
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
ctx.fillStyle = particle.color;
ctx.globalAlpha = particle.opacity;
ctx.fill();
ctx.globalAlpha = 1;
});
animationRef.current = requestAnimationFrame(animate);
};
animate();
return () => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
if (stageTimerRef.current) {
clearTimeout(stageTimerRef.current);
}
};
}, [width, height, createSealShape, createParticle, animationStages, onStageChange]);
return (
<canvas
ref={canvasRef}
className={className}
style={{ width, height }}
/>
);
}
```
**Step 2: 创建测试文件**
创建文件:`src/components/effects/__tests__/seal-animation-enhanced.test.tsx`
```typescript
import { render, screen } from '@testing-library/react';
import { SealAnimationEnhanced } from '../seal-animation-enhanced';
describe('SealAnimationEnhanced', () => {
it('should render canvas element', () => {
render(<SealAnimationEnhanced />);
const canvas = screen.getByRole('img');
expect(canvas).toBeInTheDocument();
});
it('should accept custom props', () => {
const { container } = render(
<SealAnimationEnhanced
width={400}
height={400}
particleCount={200}
colors={['#FF0000', '#00FF00']}
sealText="测试"
animationStages={false}
/>
);
const canvas = container.querySelector('canvas');
expect(canvas).toHaveAttribute('width', '400');
expect(canvas).toHaveAttribute('height', '400');
});
it('should call onStageChange callback', (done) => {
const handleStageChange = (stage: string) => {
expect(stage).toBe('dispersing');
done();
};
render(
<SealAnimationEnhanced
animationStages={true}
onStageChange={handleStageChange}
/>
);
});
});
```
**Step 3: 运行测试**
```bash
npm test src/components/effects/__tests__/seal-animation-enhanced.test.tsx
```
Expected: PASS
**Step 4: 提交代码**
```bash
git add src/components/effects/seal-animation-enhanced.tsx
git add src/components/effects/__tests__/seal-animation-enhanced.test.tsx
git commit -m "feat: add enhanced seal animation component with stages"
```
---
### Task 2: 更新 Hero Section 使用增强版印章动画
**目标:** 在 Hero 区域集成增强版印章动画,提升视觉冲击力
**Files:**
- Modify: `src/components/sections/hero-section.tsx`
- Create: `src/lib/constants.ts` (如果不存在)
**Step 1: 检查并创建 constants 文件**
检查文件是否存在:`src/lib/constants.ts`
如果不存在,创建:
```typescript
export const COMPANY_INFO = {
name: '睿新致远',
slogan: '以技术创新,铸就卓越未来',
description: '专注于数字化转型与技术创新,为企业提供全方位的技术解决方案',
foundedYear: 2014,
teamSize: '50+',
};
export const STATS = [
{ value: '10+', label: '年技术积累' },
{ value: '200+', label: '成功案例' },
{ value: '50+', label: '技术专家' },
{ value: '99.5%', label: '客户满意度' },
];
export const NAV_LINKS = [
{ href: '#home', label: '首页' },
{ href: '#solutions', label: '解决方案' },
{ href: '#cases', label: '成功案例' },
{ href: '#about', label: '关于我们' },
{ href: '#contact', label: '联系我们' },
];
```
**Step 2: 更新 Hero Section**
修改文件:`src/components/sections/hero-section.tsx`
在文件顶部添加导入:
```typescript
import { SealAnimationEnhanced } from '@/components/effects/seal-animation-enhanced';
```
在 Hero Section 组件中,找到现有的 `SealParticle` 组件,替换为:
```typescript
{/* 增强版印章动画 */}
<div className="absolute right-0 top-1/2 -translate-y-1/2 hidden lg:block">
<SealAnimationEnhanced
width={400}
height={400}
particleCount={150}
colors={['#C41E3A', '#D4A574', '#8B4513']}
sealText="睿新"
animationStages={true}
onStageChange={(stage) => console.log('Animation stage:', stage)}
className="opacity-80"
/>
</div>
```
**Step 3: 测试更新后的 Hero Section**
```bash
npm run dev
```
访问 http://localhost:3000,检查:
- 印章动画是否正常显示
- 动画阶段是否按预期切换(idle → dispersing → reforming → idle
- 移动端是否隐藏动画(lg:block)
**Step 4: 提交代码**
```bash
git add src/components/sections/hero-section.tsx
git add src/lib/constants.ts
git commit -m "feat: integrate enhanced seal animation in hero section"
```
---
### Task 3: 创建技术洞察卡片组件
**目标:** 创建可复用的技术洞察卡片组件,用于展示技术文章和白皮书
**Files:**
- Create: `src/components/ui/insight-card.tsx`
- Create: `src/components/ui/__tests__/insight-card.test.tsx`
**Step 1: 创建 InsightCard 组件**
创建文件:`src/components/ui/insight-card.tsx`
```typescript
'use client';
import { Calendar, Clock, ArrowRight } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
export interface InsightCardProps {
title: string;
excerpt: string;
category: string;
readTime: string;
publishedAt: string;
imageUrl?: string;
href: string;
featured?: boolean;
}
export function InsightCard({
title,
excerpt,
category,
readTime,
publishedAt,
imageUrl,
href,
featured = false,
}: InsightCardProps) {
return (
<article
className={`
group relative overflow-hidden rounded-lg border border-[#E5E5E5]/50
bg-white transition-all duration-300 hover:shadow-lg
${featured ? 'md:col-span-2' : ''}
`}
>
{imageUrl && (
<div className="relative h-48 overflow-hidden">
<img
src={imageUrl}
alt={title}
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent" />
</div>
)}
<div className="p-6">
<div className="flex items-center gap-3 mb-3">
<Badge variant="secondary" className="text-xs">
{category}
</Badge>
<div className="flex items-center gap-1 text-xs text-[#737373]">
<Clock className="w-3 h-3" />
<span>{readTime}</span>
</div>
</div>
<h3 className="text-lg font-semibold text-[#171717] mb-2 line-clamp-2 group-hover:text-[#C41E3A] transition-colors">
{title}
</h3>
<p className="text-sm text-[#737373] mb-4 line-clamp-2">
{excerpt}
</p>
<div className="flex items-center justify-between">
<div className="flex items-center gap-1 text-xs text-[#A3A3A3]">
<Calendar className="w-3 h-3" />
<span>{publishedAt}</span>
</div>
<a
href={href}
className="inline-flex items-center gap-1 text-sm font-medium text-[#C41E3A] hover:gap-2 transition-all"
>
<ArrowRight className="w-4 h-4" />
</a>
</div>
</div>
</article>
);
}
```
**Step 2: 创建测试文件**
创建文件:`src/components/ui/__tests__/insight-card.test.tsx`
```typescript
import { render, screen } from '@testing-library/react';
import { InsightCard } from '../insight-card';
describe('InsightCard', () => {
const defaultProps = {
title: '测试文章标题',
excerpt: '这是一篇测试文章的摘要内容',
category: '技术洞察',
readTime: '5 分钟',
publishedAt: '2026-02-13',
href: '/insights/test-article',
};
it('should render card with all props', () => {
render(<InsightCard {...defaultProps} />);
expect(screen.getByText('测试文章标题')).toBeInTheDocument();
expect(screen.getByText('这是一篇测试文章的摘要内容')).toBeInTheDocument();
expect(screen.getByText('技术洞察')).toBeInTheDocument();
expect(screen.getByText('5 分钟')).toBeInTheDocument();
expect(screen.getByText('2026-02-13')).toBeInTheDocument();
});
it('should render image when imageUrl provided', () => {
render(
<InsightCard
{...defaultProps}
imageUrl="/test-image.jpg"
/>
);
const image = screen.getByRole('img');
expect(image).toHaveAttribute('src', '/test-image.jpg');
});
it('should have correct link href', () => {
render(<InsightCard {...defaultProps} />);
const link = screen.getByRole('link', { name: /阅读更多/i });
expect(link).toHaveAttribute('href', '/insights/test-article');
});
it('should apply featured class when featured prop is true', () => {
const { container } = render(
<InsightCard {...defaultProps} featured={true} />
);
const article = container.querySelector('article');
expect(article).toHaveClass('md:col-span-2');
});
});
```
**Step 3: 运行测试**
```bash
npm test src/components/ui/__tests__/insight-card.test.tsx
```
Expected: PASS
**Step 4: 提交代码**
```bash
git add src/components/ui/insight-card.tsx
git add src/components/ui/__tests__/insight-card.test.tsx
git commit -m "feat: add insight card component for tech insights section"
```
---
### Task 4: 创建技术洞察板块组件
**目标:** 创建完整的技术洞察板块,展示最新技术文章和白皮书
**Files:**
- Create: `src/components/sections/insights-section.tsx`
- Create: `src/components/sections/__tests__/insights-section.test.tsx`
- Modify: `src/app/(marketing)/page.tsx`
**Step 1: 创建 InsightsSection 组件**
创建文件:`src/components/sections/insights-section.tsx`
```typescript
'use client';
import { useEffect, useState, useRef } from 'react';
import { InsightCard } from '@/components/ui/insight-card';
import { Button } from '@/components/ui/button';
import { ArrowRight } from 'lucide-react';
interface Insight {
id: string;
title: string;
excerpt: string;
category: string;
readTime: string;
publishedAt: string;
imageUrl?: string;
href: string;
featured?: boolean;
}
const MOCK_INSIGHTS: Insight[] = [
{
id: '1',
title: '2025年技术趋势:AI驱动的数字化转型',
excerpt: '深入探讨人工智能如何重塑企业技术架构,以及如何把握AI时代的机遇',
category: '技术趋势',
readTime: '8 分钟',
publishedAt: '2026-02-10',
imageUrl: '/insights/ai-trend.jpg',
href: '/insights/ai-trend-2025',
featured: true,
},
{
id: '2',
title: '微服务架构最佳实践指南',
excerpt: '从单体应用到微服务的演进之路,包含实战案例和避坑指南',
category: '架构设计',
readTime: '12 分钟',
publishedAt: '2026-02-08',
imageUrl: '/insights/microservices.jpg',
href: '/insights/microservices-best-practices',
},
{
id: '3',
title: '云原生技术栈选型指南',
excerpt: 'Kubernetes、Docker、Service Mesh等技术栈的深度对比与选型建议',
category: '云原生',
readTime: '10 分钟',
publishedAt: '2026-02-05',
imageUrl: '/insights/cloud-native.jpg',
href: '/insights/cloud-native-stack-guide',
},
];
export function InsightsSection() {
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
id="insights"
ref={sectionRef}
className="py-24 bg-[#FAFAFA]"
>
<div className="container-wide">
<div
className={`
text-center mb-16
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up' : ''}
`}
>
<h2 className="text-3xl sm:text-4xl font-semibold text-[#171717] mb-4">
</h2>
<p className="text-lg text-[#737373] max-w-2xl mx-auto">
沿
</p>
</div>
<div
className={`
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up stagger-1' : ''}
`}
>
{MOCK_INSIGHTS.map((insight) => (
<InsightCard key={insight.id} {...insight} />
))}
</div>
<div
className={`
text-center
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up stagger-2' : ''}
`}
>
<Button
variant="outline"
size="lg"
className="group"
onClick={() => window.location.href = '/insights'}
>
<ArrowRight className="w-4 h-4 ml-2 group-hover:translate-x-1 transition-transform" />
</Button>
</div>
</div>
</section>
);
}
```
**Step 2: 创建测试文件**
创建文件:`src/components/sections/__tests__/insights-section.test.tsx`
```typescript
import { render, screen } from '@testing-library/react';
import { InsightsSection } from '../insights-section';
describe('InsightsSection', () => {
it('should render section with title', () => {
render(<InsightsSection />);
expect(screen.getByText('技术洞察')).toBeInTheDocument();
expect(screen.getByText(/分享前沿技术趋势/)).toBeInTheDocument();
});
it('should render insight cards', () => {
render(<InsightsSection />);
expect(screen.getByText('2025年技术趋势:AI驱动的数字化转型')).toBeInTheDocument();
expect(screen.getByText('微服务架构最佳实践指南')).toBeInTheDocument();
expect(screen.getByText('云原生技术栈选型指南')).toBeInTheDocument();
});
it('should render view all button', () => {
render(<InsightsSection />);
expect(screen.getByText('查看全部洞察')).toBeInTheDocument();
});
});
```
**Step 3: 更新首页集成技术洞察板块**
修改文件:`src/app/(marketing)/page.tsx`
在导入部分添加:
```typescript
import { InsightsSection } from '@/components/sections/insights-section';
```
`HomePage` 组件中,在 `<CasesSection />` 之前添加:
```typescript
<InsightsSection />
```
**Step 4: 测试集成效果**
```bash
npm run dev
```
访问 http://localhost:3000,检查:
- 技术洞察板块是否正确显示
- 卡片布局是否响应式
- 滚动动画是否触发
**Step 5: 提交代码**
```bash
git add src/components/sections/insights-section.tsx
git add src/components/sections/__tests__/insights-section.test.tsx
git add src/app/(marketing)/page.tsx
git commit -m "feat: add insights section to homepage"
```
---
### Task 5: 创建客户评价组件
**目标:** 创建客户评价展示组件,增强社会证明
**Files:**
- Create: `src/components/ui/testimonial-card.tsx`
- Create: `src/components/sections/testimonials-section.tsx`
- Modify: `src/app/(marketing)/page.tsx`
**Step 1: 创建 TestimonialCard 组件**
创建文件:`src/components/ui/testimonial-card.tsx`
```typescript
'use client';
import { Quote } from 'lucide-react';
export interface TestimonialCardProps {
quote: string;
author: string;
position: string;
company: string;
avatarUrl?: string;
rating?: number;
}
export function TestimonialCard({
quote,
author,
position,
company,
avatarUrl,
rating = 5,
}: TestimonialCardProps) {
return (
<div className="relative p-8 rounded-lg border border-[#E5E5E5]/50 bg-white hover:shadow-md transition-shadow">
<Quote className="absolute top-6 right-6 w-8 h-8 text-[#C41E3A]/10" />
{rating > 0 && (
<div className="flex gap-1 mb-4">
{Array.from({ length: rating }).map((_, i) => (
<svg
key={i}
className="w-4 h-4 text-[#C41E3A]"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
))}
</div>
)}
<blockquote className="text-base text-[#171717] mb-6 leading-relaxed">
"{quote}"
</blockquote>
<div className="flex items-center gap-4">
{avatarUrl && (
<img
src={avatarUrl}
alt={author}
className="w-12 h-12 rounded-full object-cover"
/>
)}
<div>
<div className="font-semibold text-[#171717]">{author}</div>
<div className="text-sm text-[#737373]">
{position} · {company}
</div>
</div>
</div>
</div>
);
}
```
**Step 2: 创建 TestimonialsSection 组件**
创建文件:`src/components/sections/testimonials-section.tsx`
```typescript
'use client';
import { useEffect, useState, useRef } from 'react';
import { TestimonialCard } from '@/components/ui/testimonial-card';
interface Testimonial {
id: string;
quote: string;
author: string;
position: string;
company: string;
avatarUrl?: string;
rating?: number;
}
const MOCK_TESTIMONIALS: Testimonial[] = [
{
id: '1',
quote: '睿新致远团队的专业能力和服务态度让我们印象深刻,他们不仅交付了高质量的产品,还帮助我们建立了完善的技术体系。',
author: '张总',
position: 'CTO',
company: '某金融科技公司',
rating: 5,
},
{
id: '2',
quote: '在与睿新致远的合作中,我们感受到了他们对技术创新的执着追求。他们提供的解决方案极大地提升了我们的业务效率。',
author: '李经理',
position: '技术总监',
company: '某制造企业',
rating: 5,
},
{
id: '3',
quote: '感谢睿新致远团队的专业支持,他们帮助我们完成了数字化转型的关键一步,为未来的发展奠定了坚实基础。',
author: '王总',
position: '总经理',
company: '某零售集团',
rating: 5,
},
];
export function TestimonialsSection() {
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="py-24 bg-white"
>
<div className="container-wide">
<div
className={`
text-center mb-16
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up' : ''}
`}
>
<h2 className="text-3xl sm:text-4xl font-semibold text-[#171717] mb-4">
</h2>
<p className="text-lg text-[#737373] max-w-2xl mx-auto">
</p>
</div>
<div
className={`
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6
opacity-0 translate-y-4
${isVisible ? 'animate-fade-in-up stagger-1' : ''}
`}
>
{MOCK_TESTIMONIALS.map((testimonial) => (
<TestimonialCard key={testimonial.id} {...testimonial} />
))}
</div>
</div>
</section>
);
}
```
**Step 3: 更新首页集成客户评价板块**
修改文件:`src/app/(marketing)/page.tsx`
在导入部分添加:
```typescript
import { TestimonialsSection } from '@/components/sections/testimonials-section';
```
`HomePage` 组件中,在 `<ContactSection />` 之前添加:
```typescript
<TestimonialsSection />
```
**Step 4: 测试集成效果**
```bash
npm run dev
```
访问 http://localhost:3000,检查客户评价板块是否正确显示
**Step 5: 提交代码**
```bash
git add src/components/ui/testimonial-card.tsx
git add src/components/sections/testimonials-section.tsx
git add src/app/(marketing)/page.tsx
git commit -m "feat: add testimonials section to homepage"
```
---
### Task 6: 优化联系表单
**目标:** 优化联系表单的用户体验和验证逻辑
**Files:**
- Modify: `src/components/sections/contact-section.tsx`
- Create: `src/lib/validations/contact.ts`
**Step 1: 创建表单验证逻辑**
创建文件:`src/lib/validations/contact.ts`
```typescript
import { z } from 'zod';
export const contactFormSchema = z.object({
name: z
.string()
.min(2, '姓名至少需要2个字符')
.max(50, '姓名不能超过50个字符'),
company: z
.string()
.min(2, '公司名称至少需要2个字符')
.max(100, '公司名称不能超过100个字符'),
email: z
.string()
.email('请输入有效的邮箱地址'),
phone: z
.string()
.regex(/^1[3-9]\d{9}$/, '请输入有效的手机号码')
.optional()
.or(z.literal('')),
message: z
.string()
.min(10, '留言内容至少需要10个字符')
.max(500, '留言内容不能超过500个字符'),
});
export type ContactFormData = z.infer<typeof contactFormSchema>;
export function validateContactForm(data: unknown) {
return contactFormSchema.safeParse(data);
}
```
**Step 2: 更新 ContactSection 组件**
修改文件:`src/components/sections/contact-section.tsx`
添加表单验证和提交逻辑(具体代码根据现有实现调整)
**Step 3: 测试表单验证**
```bash
npm run dev
```
测试各种表单输入场景
**Step 4: 提交代码**
```bash
git add src/lib/validations/contact.ts
git add src/components/sections/contact-section.tsx
git commit -m "feat: add form validation to contact section"
```
---
## Phase 2: P1 重要功能优化(预计 3-4 天)
### Task 7: 优化移动端体验
**目标:** 优化移动端的导航、动画和性能
**Files:**
- Modify: `src/components/layout/header.tsx`
- Modify: `src/components/effects/seal-particle.tsx`
- Create: `src/hooks/use-device-performance.ts`
**Step 1: 创建设备性能检测 Hook**
创建文件:`src/hooks/use-device-performance.ts`
```typescript
'use client';
import { useState, useEffect } from 'react';
export type PerformanceLevel = 'low' | 'medium' | 'high';
export function useDevicePerformance(): PerformanceLevel {
const [performance, setPerformance] = useState<PerformanceLevel>('high');
useEffect(() => {
// 检测设备性能
const checkPerformance = () => {
// 检查 CPU 核心数
const cores = navigator.hardwareConcurrency || 4;
// 检查设备内存(如果可用)
const memory = (navigator as any).deviceMemory || 8;
// 检查是否为移动设备
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
// 检查是否启用了减少动画
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (prefersReducedMotion) {
setPerformance('low');
} else if (isMobile && (cores < 4 || memory < 4)) {
setPerformance('low');
} else if (isMobile || cores < 8) {
setPerformance('medium');
} else {
setPerformance('high');
}
};
checkPerformance();
}, []);
return performance;
}
```
**Step 2: 更新印章动画组件以支持性能降级**
修改文件:`src/components/effects/seal-particle.tsx`
添加性能检测和降级逻辑
**Step 3: 优化移动端导航**
修改文件:`src/components/layout/header.tsx`
优化移动端菜单交互
**Step 4: 测试移动端体验**
```bash
npm run dev
```
使用浏览器开发者工具测试移动端显示效果
**Step 5: 提交代码**
```bash
git add src/hooks/use-device-performance.ts
git add src/components/effects/seal-particle.tsx
git add src/components/layout/header.tsx
git commit -m "feat: optimize mobile experience with performance detection"
```
---
### Task 8: 添加案例详情页优化
**目标:** 优化案例详情页的展示效果和用户体验
**Files:**
- Modify: `src/app/(marketing)/cases/[slug]/page.tsx` (如果存在)
- Create: `src/components/ui/case-detail-card.tsx`
**Step 1: 创建案例详情卡片组件**
创建文件:`src/components/ui/case-detail-card.tsx`
**Step 2: 优化案例详情页布局**
修改案例详情页文件
**Step 3: 测试案例详情页**
**Step 4: 提交代码**
---
## Phase 3: P2 增强功能(预计 2-3 天)
### Task 9: 添加深色模式支持
**目标:** 实现深色/浅色主题切换
**Files:**
- Create: `src/components/ui/theme-toggle.tsx`
- Modify: `src/app/layout.tsx`
- Modify: `src/app/globals.css`
**Step 1: 创建主题切换组件**
**Step 2: 更新全局样式**
**Step 3: 测试主题切换**
**Step 4: 提交代码**
---
### Task 10: 性能优化和测试
**目标:** 全面优化性能指标,确保达到预期目标
**Files:**
- Modify: `next.config.ts`
- Create: `tests/performance/lighthouse.test.ts`
**Step 1: 配置性能优化**
**Step 2: 运行 Lighthouse 测试**
**Step 3: 优化关键指标**
**Step 4: 提交代码**
---
## 验收标准
### 功能验收
- [ ] Hero 区域印章动画正常工作,支持多阶段动画
- [ ] 技术洞察板块正确展示,响应式布局良好
- [ ] 客户评价板块正常显示,星级评分准确
- [ ] 联系表单验证逻辑正确,错误提示清晰
- [ ] 移动端体验流畅,动画降级正常
### 性能验收
- [ ] LCP < 2.5秒
- [ ] FID < 100毫秒
- [ ] CLS < 0.1
- [ ] 移动端首屏加载 < 3秒
### 代码质量验收
- [ ] 所有测试通过
- [ ] ESLint 检查无错误
- [ ] TypeScript 类型检查通过
- [ ] 代码提交信息规范
---
## 风险控制
### 潜在风险
1. **动画性能风险**
- 缓解:提供降级方案,低端设备自动禁用复杂动画
2. **开发周期风险**
- 缓解:采用分阶段交付,优先核心功能
3. **测试覆盖风险**
- 缓解:每个组件都编写单元测试,集成测试覆盖关键路径
---
## 后续优化方向
1. **数据分析驱动优化**
- 集成 Google Analytics 4
- 用户行为热力图分析
- A/B 测试关键页面
2. **内容运营支持**
- 定期更新技术博客
- 添加新案例展示
- 优化 SEO 关键词
3. **功能扩展预留**
- 多语言支持(国际化)
- 客户案例视频展示
- 在线演示预约系统
---
**文档状态:** 已完成
**创建日期:** 2026-02-13
**预计完成时间:** 10-14 天