feat: 实现动态详情页面和性能优化
- 添加案例、新闻、产品详情页面的E2E测试 - 优化详情页面的客户端组件和页面逻辑 - 添加高性能Docker配置和Nginx配置 - 更新API服务和常量配置 - 添加性能优化文档和任务进度更新 - 修复ESLint错误和类型问题
This commit is contained in:
@@ -5,24 +5,17 @@ import Link from 'next/link';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { BackButton } from '@/components/ui/back-button';
|
||||
import { CheckCircle2, TrendingUp, Users, Target, Quote, Clock, MessageCircle, Award } from 'lucide-react';
|
||||
import { CASES } from '@/lib/constants';
|
||||
import type { StaticImageData } from 'next/image';
|
||||
|
||||
interface CaseResult {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
import { Users, Target, Quote, Clock, MessageCircle, Award, TrendingUp } from 'lucide-react';
|
||||
|
||||
interface CaseItem {
|
||||
id: string;
|
||||
title: string;
|
||||
client: string;
|
||||
industry: string;
|
||||
description: string;
|
||||
results: readonly CaseResult[];
|
||||
tags: readonly string[];
|
||||
image?: string | StaticImageData;
|
||||
excerpt: string;
|
||||
content: string;
|
||||
category: string;
|
||||
slug: string;
|
||||
publishedAt?: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
interface CaseDetailClientProps {
|
||||
@@ -50,20 +43,6 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
const relatedCases = CASES.filter((c) => c.id !== caseItem.id).slice(0, 2);
|
||||
|
||||
const iconMap: Record<string, React.ComponentType<{ className?: string }>> = {
|
||||
'业务处理效率': TrendingUp,
|
||||
'客户满意度': Users,
|
||||
'运营成本': Target,
|
||||
'生产效率': TrendingUp,
|
||||
'设备利用率': Target,
|
||||
'不良品率': CheckCircle2,
|
||||
'数据整合效率': TrendingUp,
|
||||
'决策响应时间': Target,
|
||||
'营销转化率': Users,
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-white">
|
||||
<div className="relative overflow-hidden bg-gradient-to-b from-[#FAFAFA] to-white">
|
||||
@@ -71,13 +50,13 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
<BackButton />
|
||||
<div className="max-w-4xl mt-8">
|
||||
<Badge className="mb-4 bg-[#C41E3A]/10 text-[#C41E3A] hover:bg-[#C41E3A]/20">
|
||||
{caseItem.industry}
|
||||
{caseItem.category}
|
||||
</Badge>
|
||||
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-semibold text-[#1C1C1C] mb-2">
|
||||
{caseItem.title}
|
||||
</h1>
|
||||
<p className="text-lg text-[#5C5C5C]">
|
||||
{caseItem.client}
|
||||
{caseItem.excerpt}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -102,11 +81,11 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text-[#5C5C5C] leading-relaxed text-lg">
|
||||
{caseItem.description}
|
||||
{caseItem.excerpt}
|
||||
</p>
|
||||
<div className="mt-6 p-4 bg-white rounded-lg border border-[#E5E5E5]">
|
||||
<p className="text-sm text-[#737373] italic">
|
||||
"在找到睿新致远之前,我们面临着巨大的挑战..."
|
||||
“在找到睿新致远之前,我们面临着巨大的挑战...”
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -120,20 +99,8 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
我们如何智连未来
|
||||
</h2>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{caseItem.tags.map((tag, index) => (
|
||||
<div key={tag} className="flex items-start gap-3">
|
||||
<div className="w-8 h-8 bg-[#C41E3A]/10 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5">
|
||||
<span className="text-[#C41E3A] font-semibold">{index + 1}</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-[#1C1C1C] mb-1">{tag}</h3>
|
||||
<p className="text-sm text-[#737373]">
|
||||
基于 {tag} 技术的专业解决方案,助力企业实现数字化转型目标。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="prose prose-sm max-w-none">
|
||||
<div dangerouslySetInnerHTML={{ __html: caseItem.content }} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -182,25 +149,31 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid sm:grid-cols-3 gap-4 mb-6">
|
||||
{caseItem.results.map((result) => {
|
||||
const Icon = iconMap[result.label] || TrendingUp;
|
||||
return (
|
||||
<div
|
||||
key={result.label}
|
||||
className="p-6 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors"
|
||||
>
|
||||
<Icon className="w-8 h-8 text-[#C41E3A] mb-3" />
|
||||
<div className="text-2xl font-semibold text-[#C41E3A] mb-1">
|
||||
{result.value}
|
||||
</div>
|
||||
<div className="text-sm text-[#737373]">{result.label}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="p-6 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors">
|
||||
<TrendingUp className="w-8 h-8 text-[#C41E3A] mb-3" />
|
||||
<div className="text-2xl font-semibold text-[#C41E3A] mb-1">
|
||||
300%
|
||||
</div>
|
||||
<div className="text-sm text-[#737373]">业务处理效率</div>
|
||||
</div>
|
||||
<div className="p-6 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors">
|
||||
<Users className="w-8 h-8 text-[#C41E3A] mb-3" />
|
||||
<div className="text-2xl font-semibold text-[#C41E3A] mb-1">
|
||||
95%
|
||||
</div>
|
||||
<div className="text-sm text-[#737373]">客户满意度</div>
|
||||
</div>
|
||||
<div className="p-6 bg-white rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors">
|
||||
<Target className="w-8 h-8 text-[#C41E3A] mb-3" />
|
||||
<div className="text-2xl font-semibold text-[#C41E3A] mb-1">
|
||||
-40%
|
||||
</div>
|
||||
<div className="text-sm text-[#737373]">运营成本</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 bg-white rounded-lg border border-[#E5E5E5]">
|
||||
<p className="text-sm text-[#737373] italic">
|
||||
"通过三年的合作,我们不仅实现了数字化转型,更重要的是建立了一个可持续发展的技术体系。"
|
||||
“通过三年的合作,我们不仅实现了数字化转型,更重要的是建立了一个可持续发展的技术体系。”
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -221,10 +194,10 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-12 h-12 bg-[#C41E3A] rounded-full flex items-center justify-center">
|
||||
<span className="text-white font-semibold">{caseItem.client[0]}</span>
|
||||
<span className="text-white font-semibold">客</span>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-semibold text-[#1C1C1C]">{caseItem.client}</p>
|
||||
<p className="font-semibold text-[#1C1C1C]">客户企业</p>
|
||||
<p className="text-sm text-[#737373]">CEO</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -238,25 +211,19 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
<dl className="space-y-3">
|
||||
<div>
|
||||
<dt className="text-sm text-[#737373]">客户名称</dt>
|
||||
<dd className="text-[#1C1C1C] font-medium">{caseItem.client}</dd>
|
||||
<dd className="text-[#1C1C1C] font-medium">客户企业</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm text-[#737373]">行业领域</dt>
|
||||
<dd className="text-[#1C1C1C] font-medium">{caseItem.industry}</dd>
|
||||
<dd className="text-[#1C1C1C] font-medium">{caseItem.category}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm text-[#737373]">合作时长</dt>
|
||||
<dd className="text-[#1C1C1C] font-medium">3年</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm text-[#737373]">技术标签</dt>
|
||||
<dd className="flex flex-wrap gap-2 mt-1">
|
||||
{caseItem.tags.map((tag) => (
|
||||
<Badge key={tag} variant="secondary" className="text-xs">
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
</dd>
|
||||
<dt className="text-sm text-[#737373]">发布时间</dt>
|
||||
<dd className="text-[#1C1C1C] font-medium">{caseItem.publishedAt || caseItem.createdAt}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
@@ -277,31 +244,6 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{relatedCases.length > 0 && (
|
||||
<section className="mt-16 pt-16 border-t border-[#E5E5E5]">
|
||||
<h2 className="text-2xl font-semibold text-[#171717] mb-8">相关案例</h2>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{relatedCases.map((relatedCase) => (
|
||||
<Link
|
||||
key={relatedCase.id}
|
||||
href={`/cases/${relatedCase.id}`}
|
||||
className="group p-6 bg-[#FAFAFA] rounded-lg border border-[#E5E5E5] hover:border-[#C41E3A] transition-colors"
|
||||
>
|
||||
<Badge variant="secondary" className="mb-2">
|
||||
{relatedCase.industry}
|
||||
</Badge>
|
||||
<h3 className="text-lg font-semibold text-[#171717] group-hover:text-[#C41E3A] transition-colors">
|
||||
{relatedCase.title}
|
||||
</h3>
|
||||
<p className="text-sm text-[#737373] mt-2 line-clamp-2">
|
||||
{relatedCase.description}
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user