From 474e21507a4d46cc4f1db186e80e67ccd7a1c43a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Thu, 26 Feb 2026 21:23:17 +0800 Subject: [PATCH] feat: add service detail page with storytelling style --- src/app/(marketing)/services/[id]/client.tsx | 301 +++++++++++++++++++ src/app/(marketing)/services/[id]/page.tsx | 37 +++ 2 files changed, 338 insertions(+) create mode 100644 src/app/(marketing)/services/[id]/client.tsx create mode 100644 src/app/(marketing)/services/[id]/page.tsx diff --git a/src/app/(marketing)/services/[id]/client.tsx b/src/app/(marketing)/services/[id]/client.tsx new file mode 100644 index 0000000..ec52308 --- /dev/null +++ b/src/app/(marketing)/services/[id]/client.tsx @@ -0,0 +1,301 @@ +'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 { + 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> = { + Code: () => ( + + + + ), + Cloud: () => ( + + + + ), + BarChart3: () => ( + + + + ), + Shield: () => ( + + + + ), +}; + +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(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 ( +
+
+
+ + + +
+
+
+ {Icon && } +
+
+ + 核心业务 + +

+ {service.title} +

+
+
+

+ {service.description} +

+
+
+
+ +
+
+ +
+
+
+ +
+

+ 您可能面临的挑战 +

+
+
+ {serviceChallenges.map((challenge, index) => ( +
+

{challenge.title}

+

{challenge.description}

+
+ ))} +
+
+ +
+
+
+ +
+

+ 我们如何帮助您 +

+
+

+ {service.overview} +

+
+ {service.features.map((feature, index) => ( +
+ + {feature} +
+ ))} +
+
+ +
+
+
+ +
+

+ 服务流程 +

+
+
+ {service.process.map((step, index) => ( +
+
+ {index + 1} +
+
+

{step}

+
+
+ ))} +
+
+ +
+
+
+ +
+

+ 您将获得的改变 +

+
+
+ {serviceOutcomes.map((outcome, index) => ( +
+
+ {outcome.value} +
+
{outcome.label}
+
+ ))} +
+
+

+ {service.benefits.map(b => b).join(';')} +

+
+
+ +
+
+
+ +
+

+ 相关案例 +

+
+
+ {relatedCases.map((caseItem) => ( + + + {caseItem.industry} + +

+ {caseItem.title} +

+

+ {caseItem.description} +

+ + ))} +
+
+ +
+ + +
+
+
+
+ ); +} diff --git a/src/app/(marketing)/services/[id]/page.tsx b/src/app/(marketing)/services/[id]/page.tsx new file mode 100644 index 0000000..0755799 --- /dev/null +++ b/src/app/(marketing)/services/[id]/page.tsx @@ -0,0 +1,37 @@ +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 { + 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 ; +}