9451814ca4
refactor: 重构页面结构和导航逻辑 fix: 修复移动端菜单导航和滚动行为 perf: 优化图片加载性能和资源请求 test: 添加端到端测试和性能测试用例 docs: 更新.gitignore文件 chore: 更新依赖和配置 style: 优化代码格式和类型安全 ci: 调整Playwright测试超时时间 build: 更新Next.js配置和构建选项
290 lines
12 KiB
TypeScript
290 lines
12 KiB
TypeScript
'use client';
|
||
|
||
import { useRef } from 'react';
|
||
import { useRouter } from 'next/navigation';
|
||
import Link from 'next/link';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Badge } from '@/components/ui/badge';
|
||
import { Breadcrumb } from '@/components/layout/breadcrumb';
|
||
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 router = useRouter();
|
||
const contentRef = useRef<HTMLDivElement>(null);
|
||
|
||
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">
|
||
<Breadcrumb items={[{ label: '核心业务', href: '/services' }, { label: service.title, href: `/services/${service.id}` }]} />
|
||
<div className="relative overflow-hidden bg-gradient-to-b from-[#FAFAFA] to-white">
|
||
<div className="container-wide relative z-10 pt-32 pb-20">
|
||
<Button
|
||
variant="ghost"
|
||
className="text-[#5C5C5C] hover:text-[#C41E3A] hover:bg-[#C41E3A]/10"
|
||
onClick={() => router.back()}
|
||
type="button"
|
||
>
|
||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||
返回
|
||
</Button>
|
||
<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]">
|
||
<Link href="/services">
|
||
<Button variant="outline" size="lg">
|
||
查看其他服务
|
||
</Button>
|
||
</Link>
|
||
<Link href="/contact">
|
||
<Button size="lg" className="bg-[#C41E3A] hover:bg-[#A01830] text-white">
|
||
开始您的转型之旅
|
||
<ArrowRight className="ml-2 w-4 h-4" />
|
||
</Button>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
);
|
||
}
|