feat: 实现动态详情页面和性能优化
- 添加案例、新闻、产品详情页面的E2E测试 - 优化详情页面的客户端组件和页面逻辑 - 添加高性能Docker配置和Nginx配置 - 更新API服务和常量配置 - 添加性能优化文档和任务进度更新 - 修复ESLint错误和类型问题
This commit is contained in:
@@ -2,20 +2,56 @@
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
import { useRef, useState, useEffect } 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 { TouchSwipe } from '@/components/ui/touch-swipe';
|
||||
import { CASES } from '@/lib/constants';
|
||||
import { ArrowRight, Building2, TrendingUp } from 'lucide-react';
|
||||
import { contentService } from '@/lib/api/services';
|
||||
import { ArrowRight, Building2 } from 'lucide-react';
|
||||
|
||||
interface CaseItem {
|
||||
id: string;
|
||||
title: string;
|
||||
excerpt: string;
|
||||
category: string;
|
||||
slug: string;
|
||||
}
|
||||
|
||||
export function CasesSection() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, margin: '-100px' });
|
||||
const [cases, setCases] = useState<CaseItem[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const featuredCases = CASES.slice(0, 3);
|
||||
useEffect(() => {
|
||||
const fetchCases = async () => {
|
||||
try {
|
||||
const casesData = await contentService.getCases(3);
|
||||
setCases(casesData);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch cases:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchCases();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<section id="cases" role="region" aria-labelledby="cases-heading" className="py-24 bg-white relative overflow-hidden">
|
||||
<div className="container-wide relative z-10">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#C41E3A] mx-auto mb-4" />
|
||||
<p className="text-[#5C5C5C]">加载中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section id="cases" role="region" aria-labelledby="cases-heading" className="py-24 bg-white relative overflow-hidden" ref={ref}>
|
||||
@@ -39,49 +75,40 @@ export function CasesSection() {
|
||||
|
||||
<TouchSwipe
|
||||
onSwipeLeft={() => {
|
||||
// 切换到下一个案例
|
||||
}}
|
||||
onSwipeRight={() => {
|
||||
// 切换到上一个案例
|
||||
}}
|
||||
className="md:hidden"
|
||||
>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{featuredCases.map((caseItem, index) => (
|
||||
{cases.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}`}>
|
||||
<Link href={`/cases/${caseItem.slug}`}>
|
||||
<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}
|
||||
{caseItem.category}
|
||||
</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>
|
||||
<span className="text-sm text-[#5C5C5C]">客户企业</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}
|
||||
{caseItem.excerpt}
|
||||
</p>
|
||||
{caseItem.results.length > 0 && caseItem.results[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>
|
||||
|
||||
Reference in New Issue
Block a user