feat(ui): 营销站 UI/UE/UX 治理 P0→P3 收官
复评(impeccable critique)全部 Priority Issues 与 Minor Observations 落地: - P0 数字口径:MetricsBasisNote 单一真源 + metrics-basis.test fs 防线,接入 products/solutions/services/home/about;纯渲染端加角注,不动 DB/seed 值 - P1 转化断头路:敬请期待态 + 404 语境出口 + services 空态双出口 - P1 首页并卡:TrustSection 早鸟横幅并入 CasesSection 单张深色共创卡 - P2 CTA 治理:CONSULT_CTA_ALLOWLIST 白名单 + 逐字符扫描器,/contact CTA 全归一 - P3 polish:footer 补 服务/公司列、contact 死三元/空槽/toast、GlobalErrorTracker 幂等日志 - 文档同源:PRODUCT/CONTEXT 动效带统一 180–280ms;DESIGN.md 立 The 10px Floor; font-floor.test 守卫禁止再引入 <10px(保留 10/11px 有意 Bain 微标签) Gates: type-check 0 · jest 1581/132 · lint 0e/126w · contrast 7/7 · headings 10/10
This commit is contained in:
@@ -10,7 +10,10 @@ import { ArrowRight, Lightbulb, Database, Layers, Code, Puzzle, Server, Quote, C
|
||||
import { cn } from '@/lib/utils';
|
||||
import { EASE_OUT } from '@/components/ui/page-decoration';
|
||||
import { CTAButton } from '@/components/ui/cta-button';
|
||||
import { MetricsBasisNote } from '@/components/ui/metrics-basis-note';
|
||||
import { COMPANY_INFO, TRUST_SIGNALS, EARLY_ACCESS } from '@/lib/constants';
|
||||
import { canonicalCtaLabel, CTA_LABELS } from '@/lib/constants/cta-labels';
|
||||
import { canonicalTrustSource } from '@/lib/constants/company';
|
||||
import { useSiteConfig } from '@/lib/site-config';
|
||||
import { useReducedMotion } from '@/hooks/use-reduced-motion';
|
||||
import { type NewsItem } from '@/lib/constants/news';
|
||||
@@ -100,13 +103,6 @@ const FALLBACK_INSIGHTS = [
|
||||
date: '2026-07',
|
||||
href: '/services/software',
|
||||
},
|
||||
{
|
||||
tag: '共创',
|
||||
title: '首批客户共创计划:与早期客户共同打磨产品',
|
||||
desc: '以真实运营数据验证业务改善,成果在获得客户授权后公开。',
|
||||
date: '2026-06',
|
||||
href: '/contact',
|
||||
},
|
||||
];
|
||||
|
||||
// ===== 创始人观点兜底(对标 Accenture CEO Quote,人格化背书)=====
|
||||
@@ -171,7 +167,7 @@ function HeroSection({ heroData }: {
|
||||
|
||||
const heading = heroData?.heading || heroData?.headingBottom || '让每一家企业都拥有数据驱动的决策能力';
|
||||
const subheading = heroData?.subheading || heroData?.description || '';
|
||||
const ctaLabel = heroData?.ctaLabel || '预约咨询';
|
||||
const ctaLabel = canonicalCtaLabel(heroData?.ctaLabel) || CTA_LABELS.consult;
|
||||
const ctaHref = heroData?.ctaHref || '/contact';
|
||||
const secondaryCtaLabel = heroData?.secondaryCtaLabel || '查看产品矩阵';
|
||||
const secondaryCtaHref = heroData?.secondaryCtaHref || '/products';
|
||||
@@ -300,28 +296,17 @@ function HeroStatsBand({ stats }: { stats?: Record<string, any>[] }) {
|
||||
))}
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
<MetricsBasisNote className="mt-6" />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// ===== 信任/成果区:可验证信任信号 + 首批客户共创标签 =====
|
||||
// 共创计划默认状态条目(如实呈现,无真实案例时不虚构客户)
|
||||
const DEFAULT_EARLY_ACCESS_STATUS = [
|
||||
{ label: '共创进行中', desc: '我们正与首批客户共同打磨产品与方案,以真实运营数据验证业务改善。' },
|
||||
{ label: '产品内测中', desc: '自研产品(如睿视 NovaVis)处于内测阶段,成熟后正式发布。' },
|
||||
{ label: '成果授权公开', desc: '案例与可量化成果在获得客户授权后公示——经得起衡量。' },
|
||||
];
|
||||
|
||||
// ===== 信任/成果区:可验证信任信号 =====
|
||||
function TrustSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
|
||||
const eyebrow = pageCopy?.trustEyebrow || '值得信赖';
|
||||
const titleLines = (pageCopy?.trustTitle || '以可衡量的成果\n赢得长期信任').split('\n');
|
||||
const signals = (pageCopy?.trustSignals?.length ? pageCopy.trustSignals : TRUST_SIGNALS) as typeof TRUST_SIGNALS;
|
||||
const earlyLabel = pageCopy?.earlyAccessLabel || EARLY_ACCESS.label;
|
||||
const earlyDesc = pageCopy?.earlyAccessDesc || EARLY_ACCESS.desc;
|
||||
const earlyTitle = (pageCopy?.earlyAccessTitle as string) || '首批客户共创计划';
|
||||
const earlyCtaLabel = (pageCopy?.earlyAccessCtaLabel as string) || '成为共创客户';
|
||||
const earlyStatus = (pageCopy?.earlyAccessStatus?.length ? pageCopy.earlyAccessStatus : DEFAULT_EARLY_ACCESS_STATUS) as typeof DEFAULT_EARLY_ACCESS_STATUS;
|
||||
|
||||
return (
|
||||
<section className="relative py-20 sm:py-28 md:py-36 overflow-hidden bg-bg-secondary" data-testid="trust-section">
|
||||
@@ -350,44 +335,12 @@ function TrustSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
|
||||
</div>
|
||||
<p className="text-sm text-text-secondary leading-relaxed mb-4 flex-1">{item.desc}</p>
|
||||
<div className="text-xs text-text-muted border-t border-border-primary pt-3">
|
||||
数据来源:{item.source}
|
||||
数据来源:{canonicalTrustSource(item.source)}
|
||||
</div>
|
||||
</div>
|
||||
</StaggerReveal>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 首批客户共创计划:如实呈现共创/内测/授权公开状态,不虚构客户 */}
|
||||
<StaggerReveal staggerDelay={0.05}>
|
||||
<div className="p-6 sm:p-8 bg-brand-bg border border-[rgba(196,30,58,0.15)]" data-testid="early-access-banner">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
|
||||
{earlyLabel}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="text-xl sm:text-2xl font-bold text-ink mb-3">
|
||||
{earlyTitle}
|
||||
</h3>
|
||||
<p className="text-sm text-text-secondary leading-relaxed mb-6 max-w-2xl">
|
||||
{earlyDesc}
|
||||
</p>
|
||||
<div className="grid sm:grid-cols-3 gap-4 mb-8">
|
||||
{earlyStatus.map((s) => (
|
||||
<div key={s.label} className="p-4 bg-bg-primary border border-brand/10">
|
||||
<div className="text-sm font-semibold text-brand-ink mb-1">{s.label}</div>
|
||||
<div className="text-xs text-text-secondary leading-relaxed">{s.desc}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<StaticLink
|
||||
href="/contact"
|
||||
className="group inline-flex shrink-0 items-center min-h-6 gap-2 text-sm font-semibold text-ink hover:text-brand-ink transition-colors"
|
||||
>
|
||||
<span>{earlyCtaLabel}</span>
|
||||
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
|
||||
</StaticLink>
|
||||
</div>
|
||||
</StaggerReveal>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
@@ -538,7 +491,7 @@ function InsightsSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
|
||||
</p>
|
||||
<div className="pt-6 border-t border-border-primary">
|
||||
<span className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors">
|
||||
阅读全文
|
||||
了解详情
|
||||
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
|
||||
</span>
|
||||
</div>
|
||||
@@ -596,13 +549,16 @@ function ServicesSection({ services, pageCopy }: { services?: Record<string, any
|
||||
))}
|
||||
</div>
|
||||
{(service as any).metrics && (
|
||||
<div className="flex gap-6 mb-8 pb-8 border-b border-border-primary">
|
||||
{(service as any).metrics.map((m: any, j: number) => (
|
||||
<div key={j}>
|
||||
<div className="text-2xl sm:text-3xl font-black text-ink leading-none mb-1">{m.value}</div>
|
||||
<div className="text-xs text-text-muted font-medium">{m.label}</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="mb-8 pb-8 border-b border-border-primary">
|
||||
<div className="flex gap-6 mb-2">
|
||||
{(service as any).metrics.map((m: any, j: number) => (
|
||||
<div key={j}>
|
||||
<div className="text-2xl sm:text-3xl font-black text-ink leading-none mb-1">{m.value}</div>
|
||||
<div className="text-xs text-text-muted font-medium">{m.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<MetricsBasisNote />
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-auto pt-2">
|
||||
@@ -700,16 +656,9 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
|
||||
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[1.05] mb-8">
|
||||
<StyledTitle lines={casesTitleLines} />
|
||||
</h2>
|
||||
<p className="text-text-secondary leading-relaxed text-lg mb-8">
|
||||
<p className="text-text-secondary leading-relaxed text-lg">
|
||||
{casesDesc}
|
||||
</p>
|
||||
<StaticLink
|
||||
href="/contact"
|
||||
className="group inline-flex items-center min-h-6 gap-3 text-ink font-semibold text-sm"
|
||||
>
|
||||
成为首批共创客户
|
||||
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand-ink" />
|
||||
</StaticLink>
|
||||
</ScrollReveal>
|
||||
<ScrollReveal delay={0.15}>
|
||||
<div className="relative overflow-hidden rounded-[2rem] bg-dark-bg p-10 sm:p-12 h-full flex flex-col shadow-card">
|
||||
@@ -748,7 +697,7 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
|
||||
</ol>
|
||||
<div className="mt-auto">
|
||||
<CTAButton href="/contact" dataTestId="cases-co-creation-cta">
|
||||
成为首批共创客户
|
||||
{CTA_LABELS.consult}
|
||||
</CTAButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -980,7 +929,7 @@ function NewsSection({ news, pageCopy }: { news?: NewsItem[]; pageCopy?: HomePag
|
||||
function CTASection({ heroData, pageCopy }: { heroData?: Record<string, any> | null; pageCopy?: HomePageCopy | null }) {
|
||||
const ctaTitleLine1 = heroData?.ctaTitleLine1 || pageCopy?.ctaTitleLine1 || '准备好开始了吗?';
|
||||
const ctaTitleLine2 = heroData?.ctaTitleLine2 || pageCopy?.ctaTitleLine2 || '让数据真正转化为业务增长';
|
||||
const ctaLabel = heroData?.ctaLabel || pageCopy?.ctaLabel || '预约咨询';
|
||||
const ctaLabel = canonicalCtaLabel(heroData?.ctaLabel || (pageCopy?.ctaLabel as string)) || CTA_LABELS.consult;
|
||||
const ctaHref = heroData?.ctaHref || '/contact';
|
||||
|
||||
return (
|
||||
@@ -1009,7 +958,7 @@ export default function HomeContentV15({ services, cases, stats, heroData, news,
|
||||
pageCopy?: HomePageCopy | null;
|
||||
}) {
|
||||
return (
|
||||
<main>
|
||||
<div>
|
||||
{/* 1. Hero:浅色 editorial 画布 + 品牌红单电压(参考 Accenture Radical Relevance) */}
|
||||
<HeroSection heroData={heroData} />
|
||||
|
||||
@@ -1039,6 +988,6 @@ export default function HomeContentV15({ services, cases, stats, heroData, news,
|
||||
|
||||
{/* 9. CTA:克制强调,品牌红仅用于按钮 */}
|
||||
<CTASection heroData={heroData} pageCopy={pageCopy} />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user