Files
novalon-website/src/components/detail/detail-cta-section.tsx
T
zhangxiang a366bd1400 fix(qa): 第五轮系统性质量保障缺陷修复 + 单元/集成测试
安全/鉴权:登出清服务端 httpOnly 令牌、登录 IP 限流前置 bcrypt、停用账号
令牌在 6 个内联 role handler 失效、admin/items 存在性 oracle 认证前置、
同意偏好 sanitize fail-closed、api-crypto 按 HTTP 方法判体。

CMS:workflow 状态更新+审计收进交互式 $transaction(失败即回滚)、编辑器
richtext 走 textarea 防换行损毁、array/object 子字段按作用域读写防污染、
about/contact/erp-upgrade 补 ISR revalidate 与路由映射。

UI/a11y:AnimatedCounter 入视口前显起点、CLS 累计上报、MetricCard 动画入
effect 并卸载取消 rAF、后台状态四态映射/搜索防抖+序号守卫/媒体单 input/
吞错改横幅/表单 label-aria 关联。

新增对应判别性单测与 pagination/rate-limit/client-ip/sanitize/validate-content-data
等模块及 tests-integration 真库集成层。
2026-09-28 10:48:07 +08:00

90 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { motion } from 'framer-motion';
import { ArrowRight, MessageCircle } from 'lucide-react';
import type { HeroTheme } from '@/lib/constants/hero-themes';
interface DetailCTASectionProps {
theme: HeroTheme;
title?: string;
description?: string;
primaryAction: { label: string; href: string };
secondaryAction?: { label: string; href: string };
}
export function DetailCTASection({
theme: _theme,
title = '准备好开始了吗?',
description = '联系我们,获取专属方案和报价',
primaryAction,
secondaryAction,
}: DetailCTASectionProps) {
return (
<section className="relative py-24 sm:py-32 md:py-40 overflow-hidden bg-brand-section">
{/* 背景纹理 */}
<div className="absolute inset-0 pointer-events-none opacity-[0.04]"
style={{
backgroundImage: `radial-gradient(circle at 25% 25%, rgba(255,255,255,0.3) 1px, transparent 1px)`,
backgroundSize: '48px 48px',
}}
/>
{/* 装饰光斑容器:overflow-hidden 防止 500px blur 圆撑大 section scrollHeight(伪文本裁剪误报源) */}
<div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 right-1/4 w-[500px] h-[500px] bg-white/[0.03] rounded-full blur-[140px]" />
</div>
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
<motion.div
initial={{ opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 0.28, ease: [0.22, 1, 0.36, 1] }}
className="max-w-3xl"
>
{/* 标签 */}
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/10 text-white/80 text-sm font-medium mb-8 border border-white/20">
<MessageCircle className="w-4 h-4" />
免费咨询
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-white tracking-tight leading-[0.95] mb-10">
{title}
</h2>
<p className="text-lg md:text-xl text-white/70 max-w-2xl leading-relaxed mb-12">
{description}
</p>
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-5">
<a
href={primaryAction.href}
className="group inline-flex items-center gap-3 px-10 py-4 bg-white text-brand font-bold text-base hover:bg-white/90 transition-all duration-200"
>
<span>{primaryAction.label}</span>
<ArrowRight className="w-5 h-5 transition-transform duration-normal group-hover:translate-x-1" />
</a>
{secondaryAction && (
<a
href={secondaryAction.href}
className="group inline-flex items-center gap-2.5 px-8 py-4 text-white/80 font-semibold text-sm border border-white/30 hover:border-white/60 hover:text-white hover:bg-white/10 transition-all duration-200"
>
{secondaryAction.label}
</a>
)}
</div>
<motion.p
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.5, duration: 0.28 }}
className="mt-10 text-sm text-white/70"
>
平均响应时间 &lt; 2小时 · 7×24小时技术支持 · 无需预付费用
</motion.p>
</motion.div>
</div>
</section>
);
}