feat: 营销页面HSI架构改造与四层叙事对齐

- 产品页:双区展示(企业套装+专业产品),分类筛选,统计数据更新
- 方案页:删除服务方式区域,替换为轻量关联推荐卡片
- 方案详情页:添加L3信任层条件渲染,使用V3 Hero+V2 CTA
- 独立产品页:从V1组件迁移到V2/V3
- 服务页:视觉升级与组件更新
- 首页:产品矩阵和CTA区域优化
This commit is contained in:
张翔
2026-06-07 16:21:15 +08:00
parent 724a00f582
commit 38ae991ea7
13 changed files with 740 additions and 727 deletions
+71 -170
View File
@@ -1,83 +1,25 @@
'use client';
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { motion } from 'framer-motion';
import { useReducedMotion } from '@/hooks/use-reduced-motion';
import { StaticLink } from '@/components/ui/static-link';
import { ArrowRight, Lightbulb, Cpu, Users, CheckCircle2, ChevronDown } from 'lucide-react';
import {
Lightbulb,
Cpu,
Users,
} from 'lucide-react';
import { MethodologySection } from '@/components/sections/methodology-section';
import { CTASection } from '@/components/sections/cta-section';
import { PageNav } from '@/components/layout/page-nav';
import { BreadcrumbSchema } from '@/components/seo/structured-data';
import { SwipeNavigation } from '@/hooks/use-swipe-gesture';
const modules = [
{
icon: Lightbulb,
title: '数字化转型咨询',
subtitle: '参谋伙伴 — 帮您看清前路,迈对第一步',
paragraphs: [
'数字化转型最大的成本,是走错方向的成本。',
'我们用行业智慧帮您洞察趋势,用理性分析帮您避开陷阱。',
'不堆砌概念,只帮您想清楚:该不该做、做什么、怎么做。',
],
values: ['行业趋势洞察报告', '数字化转型成熟度评估', '个性化实施路径规划'],
cta: '预约一次免费诊断',
ctaHref: '/contact',
accentColor: 'var(--color-brand-primary)',
accentBg: 'var(--color-brand-primary-bg)',
accentBorder: 'border-l-[var(--color-brand-primary)]',
},
{
icon: Cpu,
title: '信息技术解决方案',
subtitle: '技术伙伴 — 让技术真正为业务服务',
paragraphs: [
'我们不追逐"最火"的技术,只选择"最对"的技术。',
'将前沿技术深度融入您的业务场景,让每一行代码都产生业务价值。',
'您不必懂技术原理,只需要看见业务在增长。',
],
values: ['业务场景深度调研', '技术方案定制开发', '敏捷交付快速迭代'],
cta: '了解技术方案',
ctaHref: '/products',
accentColor: 'var(--color-accent-blue)',
accentBg: 'rgba(37, 99, 235, 0.08)',
accentBorder: 'border-l-[var(--color-accent-blue)]',
},
{
icon: Users,
title: '长期陪跑服务',
subtitle: '同行伙伴 — 从需求到落地,持续陪伴',
paragraphs: [
'当产品真正为您所用那天,才是我们成为伙伴的开始。',
'我们建立长效服务机制,定期回访、持续优化、随时响应。',
'在您需要的时候,我们始终在场。',
],
values: ['专属客户成功经理', '季度业务复盘会', '7×24小时响应通道'],
cta: '了解陪跑服务',
ctaHref: '/services',
accentColor: 'var(--color-success)',
accentBg: 'rgba(22, 163, 74, 0.08)',
accentBorder: 'border-l-[var(--color-success)]',
},
];
import { ListPageHeroV3 } from '@/components/detail-v2/list-page-hero-v3';
import { SolutionCardV3 } from '@/components/detail-v2/solution-service-card-v3';
import { SOLUTIONS } from '@/lib/constants/solutions';
export default function SolutionsPage() {
const shouldReduceMotion = useReducedMotion();
const fadeUp = shouldReduceMotion ? {} : { initial: { opacity: 0, y: 20 } };
const [expandedModules, setExpandedModules] = useState<Set<number>>(new Set([0]));
const toggleModule = (index: number) => {
setExpandedModules(prev => {
const next = new Set(prev);
if (next.has(index)) {
next.delete(index);
} else {
next.add(index);
}
return next;
});
};
return (
<div className="min-h-screen bg-[var(--color-bg-primary)]">
<BreadcrumbSchema items={[{ name: '首页', href: '/' }, { name: '解决方案', href: '/solutions' }]} />
@@ -87,118 +29,77 @@ export default function SolutionsPage() {
prevLabel="产品方案"
nextLabel="服务支持"
/>
<section className="pt-32 pb-16">
{/* Hero 区域 (V3) */}
<ListPageHeroV3
title="行业解决方案"
subtitle="针对不同行业的核心痛点,提供端到端数字化路径"
description="基于企业套装产品的行业化组合方案"
stats={[
{ value: '4', label: '行业方案' },
{ value: '6+', label: '核心产品' },
{ value: '100%', label: '自主可控' },
]}
/>
{/* 行业解决方案网格 */}
<section className="pb-16">
<div className="container-wide">
<PageNav items={[{ label: '解决方案' }]} />
<motion.div
{...fadeUp}
animate={shouldReduceMotion ? {} : { opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="max-w-3xl"
>
<p className="text-sm font-medium text-[var(--color-brand-primary)] mb-4 tracking-wide uppercase">Solutions</p>
<h1 className="text-4xl md:text-5xl font-bold text-[var(--color-text-primary)] mb-6 tracking-tight">
</h1>
<p className="text-lg text-[var(--color-text-muted)] leading-relaxed">
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{SOLUTIONS.map((solution) => (
<SolutionCardV3 key={solution.id} solution={solution} />
))}
</div>
</div>
</section>
<section className="pb-20">
{/* 方案→服务关联推荐 */}
<section className="py-16">
<div className="container-wide">
<div className="max-w-6xl mx-auto space-y-8">
{modules.map((module, index) => {
const anchorIds = ['consulting', 'tech', 'accompany'];
return (
<motion.section
key={index}
id={anchorIds[index]}
{...fadeUp}
whileInView={shouldReduceMotion ? {} : { opacity: 1, y: 0 }}
<motion.div
{...fadeUp}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
className="text-center mb-10"
>
<h2 className="text-2xl font-bold text-gray-900 lg:text-3xl mb-3">
</h2>
<p className="text-gray-600 max-w-2xl mx-auto">
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-4xl mx-auto">
{[
{ icon: Lightbulb, title: '数字化转型咨询', desc: '帮您看清前路,迈对第一步', href: '/services', bgColor: 'rgba(196,30,58,0.06)', color: '#C41E3A' },
{ icon: Cpu, title: '信息技术解决方案', desc: '让技术真正为业务服务', href: '/products', bgColor: 'rgba(37,99,235,0.06)', color: '#2563eb' },
{ icon: Users, title: '长期陪跑服务', desc: '从需求到落地,持续陪伴', href: '/services', bgColor: 'rgba(22,163,74,0.06)', color: '#16a34a' },
].map((item, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className={`p-8 md:p-12 rounded-xl border border-[var(--color-border-primary)] bg-[var(--color-bg-primary)] hover:border-[var(--color-border-primary)] transition-colors`}
transition={{ delay: i * 0.1 }}
>
<div className="flex items-start gap-4 mb-6">
<div className="w-12 h-12 rounded-xl flex items-center justify-center shrink-0" style={{ backgroundColor: module.accentBg }}>
<module.icon className="w-6 h-6" style={{ color: module.accentColor }} />
</div>
<div>
<h2 className="text-2xl font-bold text-[var(--color-text-primary)] mb-1">
{['一', '二', '三'][index]}{module.title}
</h2>
<p className="text-[var(--color-text-muted)]">{module.subtitle}</p>
</div>
</div>
<div className="space-y-4 mb-8">
<button
onClick={() => toggleModule(index)}
className="flex items-center gap-2 text-sm font-medium text-[var(--color-brand-primary)] hover:text-[var(--color-brand-primary-hover)] transition-colors group"
aria-expanded={expandedModules.has(index)}
<StaticLink
href={item.href}
className="block p-6 rounded-xl bg-white border border-gray-100 hover:border-gray-200 hover:shadow-md transition-all group"
>
<div
className="w-10 h-10 rounded-lg flex items-center justify-center mb-4"
style={{ backgroundColor: item.bgColor }}
>
<ChevronDown className={`w-4 h-4 transition-transform duration-200 ${expandedModules.has(index) ? 'rotate-180' : ''}`} />
{expandedModules.has(index) ? '收起详情' : '展开了解详情'}
</button>
<AnimatePresence>
{expandedModules.has(index) && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3, ease: [0.16, 1, 0.3, 1] }}
className="overflow-hidden"
>
{module.paragraphs.map((p, i) => (
<p key={i} className="text-[var(--color-text-primary)] leading-relaxed mb-3 last:mb-0">{p}</p>
))}
</motion.div>
)}
</AnimatePresence>
</div>
<div className="mb-8">
<h3 className="text-lg font-semibold text-[var(--color-text-primary)] mb-4 flex items-center gap-2">
<CheckCircle2 className="w-5 h-5" style={{ color: module.accentColor }} />
<item.icon className="w-5 h-5" style={{ color: item.color }} />
</div>
<h3 className="font-semibold text-gray-900 mb-1 group-hover:text-[#C41E3A] transition-colors">
{item.title}
</h3>
<div className="grid md:grid-cols-3 gap-3">
{module.values.map((value, i) => (
<div key={i} className="flex items-start gap-2 p-3 rounded-lg" style={{ backgroundColor: module.accentBg }}>
<div className="w-1.5 h-1.5 rounded-full mt-2 shrink-0" style={{ backgroundColor: module.accentColor }} />
<span className="text-sm text-[var(--color-text-primary)]">{value}</span>
</div>
))}
</div>
</div>
<div className="flex justify-center">
<StaticLink
href={module.ctaHref}
className="inline-flex items-center gap-2 px-6 py-3 rounded-lg border-2 font-medium transition-all duration-200 hover:text-white"
style={{
borderColor: module.accentColor,
color: module.accentColor,
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = module.accentColor;
e.currentTarget.style.color = '#fff';
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = 'transparent';
e.currentTarget.style.color = module.accentColor;
}}
>
{module.cta}
<ArrowRight className="w-4 h-4" />
</StaticLink>
</div>
</motion.section>
);
})}
<p className="text-sm text-gray-500">{item.desc}</p>
</StaticLink>
</motion.div>
))}
</div>
</div>
</section>