feat(cms): 添加 CMS 内容管理系统与 Admin 管理后台

- 新增 Prisma + SQLite 数据库模型 (Category, Content, Media, User 等)
- 新增 Admin 管理后台 (认证、内容管理、媒体管理)
- 新增 CMS API 路由 (CRUD, 草稿/发布, 重新验证)
- 新增 CMS 内容版本的历史归档页面
- 新增 components/cms 内容渲染组件
- 新增 components/admin 管理后台 UI 组件
- 更新 Contact API 路由
This commit is contained in:
张翔
2026-07-07 06:53:58 +08:00
parent 829d83522c
commit b5245f9aa2
87 changed files with 25659 additions and 0 deletions
+510
View File
@@ -0,0 +1,510 @@
'use client';
import { useRef } from 'react';
import { motion, useScroll, useTransform } from 'framer-motion';
import { StaticLink } from '@/components/ui/static-link';
import { SectionHeader } from '@/components/sections/section-header';
import { ScrollReveal } from '@/components/ui/scroll-reveal';
import { ProductCard } from '@/components/sections/product-card';
import { QuestionCard } from '@/components/sections/question-card';
import { CaseCard } from '@/components/sections/case-card';
import { InsightCard } from '@/components/sections/insight-card';
import { StatsBar } from '@/components/sections/stats-bar';
import { IndustryGrid } from '@/components/sections/industry-grid';
import { CTASection } from '@/components/sections/cta-section';
import { ScrollProgress } from '@/components/ui/scroll-progress';
import { useReducedMotion } from '@/hooks/use-reduced-motion';
import {
ArrowRight,
BarChart3, Cpu, Globe, Factory, ShoppingCart, Stethoscope,
GraduationCap, Building, Shield, Users,
Database, LineChart, Cloud, Brain,
} from 'lucide-react';
// ============================================================
// Design Tokens
// ============================================================
const INK = '#0F1419';
const CREAM = '#F3F0EB';
const EASE = [0.22, 1, 0.36, 1] as const;
const SECTION = 'py-20 md:py-36 lg:py-44';
const CONTAINER = 'max-w-[1280px] mx-auto px-5 sm:px-8 lg:px-16';
// ============================================================
// Data
// ============================================================
const PRODUCTS = [
{ icon: <Database className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--color-brand)]" strokeWidth={1.8} />, title: 'ERP 管理系统', description: '覆盖财务、采购、销售、库存、生产全链路,支撑企业核心运营', href: '/products/erp', badge: '旗舰' },
{ icon: <Users className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--color-brand)]" strokeWidth={1.8} />, title: 'CRM 客户管理', description: '从线索到回款的全生命周期客户关系管理', href: '/products/crm', badge: '旗舰' },
{ icon: <LineChart className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--color-brand)]" strokeWidth={1.8} />, title: 'BI 数据平台', description: '让数据说话,从报表到预测辅助决策', href: '/products/bi' },
{ icon: <Globe className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--color-brand)]" strokeWidth={1.8} />, title: 'CMS 内容平台', description: '建站、运营、分发一体化内容管理', href: '/products/cms' },
{ icon: <Brain className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--color-brand)]" strokeWidth={1.8} />, title: 'AI 智能平台', description: '大模型驱动的企业级 AI 应用与自动化', href: '/products/ai', badge: '新品' },
{ icon: <Cloud className="w-5 h-5 sm:w-6 sm:h-6 text-[var(--color-brand)]" strokeWidth={1.8} />, title: '协同办公', description: '审批、公文、协作、知识管理一站式平台', href: '/products/oa' },
];
const STRATEGIC_QUESTIONS = [
{
question: '我们的数字化投入,是否真正带来了业务增长?',
description: '许多企业在数字化上投入巨大,却难以量化 ROI。我们帮助您建立可衡量的数字化价值评估体系,让每一分投入都可见、可追踪、可优化。',
href: '/services/consulting',
},
{
question: '核心系统如何选型、落地与集成,才能支撑业务持续增长?',
description: 'ERP、BI、CRM 等核心系统的评估、实施与无缝集成,确保技术架构稳健可扩展,避免"上线即落后"的困境。',
href: '/products',
},
{
question: '数据如何从成本中心转变为真正的企业资产?',
description: '数据治理、商业智能分析与信息安全体系,让数据驱动决策而非成为风险。',
href: '/solutions',
},
{
question: '面对 AI 浪潮,我们的企业准备好了吗?',
description: 'AI 不是选择题,而是必答题。我们从 AI 成熟度评估到场景落地,帮助您找到最适合的 AI 应用路径,避免盲目跟风。',
href: '/services/ai',
},
];
const CASE_STUDIES = [
{
industry: '智能制造',
title: '某大型制造企业 ERP 全面升级',
challenge: '原有系统无法支撑业务增长,数据孤岛严重,生产排程效率低下。',
solution: '从选型到全模块上线仅 30 天,打通财务、生产、供应链全链路数据。',
context: '原有系统无法支撑业务增长,数据孤岛严重,生产排程效率低下。从选型到全模块上线仅 30 天。',
impact: [{ value: '40%', label: '生产效率提升' }, { value: '30天', label: '核心系统上线' }],
quote: '睿新团队不仅完成了系统升级,更帮助我们建立了数据驱动的运营体系。',
author: 'CTO,某上市制造企业',
},
{
industry: '贸易零售',
title: '连锁零售全渠道数字化升级',
challenge: '线上线下数据割裂,库存管理混乱,会员体系无法统一。',
solution: '打通全渠道数据,重构供应链与库存管理,统一会员运营体系。',
context: '线上线下数据割裂,库存管理混乱,会员体系无法统一。打通全渠道数据,重构供应链与库存管理。',
impact: [{ value: '25%', label: '营收增长' }, { value: '50%', label: '库存周转优化' }],
quote: '从咨询到落地,睿新团队展现出了超出预期的专业能力和责任心。',
author: 'CEO,某区域零售龙头',
},
{
industry: '医疗健康',
title: '三甲医院数据合规与患者服务',
challenge: '在满足严格合规要求的同时优化患者服务体验,临床数据与运营数据割裂。',
solution: '建立统一数据中台,打通临床与运营数据,构建合规数据治理体系。',
context: '在满足严格合规要求的同时优化患者服务体验,打通临床数据与运营数据。',
impact: [{ value: '100%', label: '合规达标' }, { value: '60%', label: '患者满意度提升' }],
quote: '在医疗数据合规领域,睿新的专业度在行业中非常难得。',
author: '信息科主任,某三甲医院',
},
];
const INSIGHTS_FEATURED = [
{
tag: '白皮书',
title: '2026 中国企业数字化转型趋势报告',
desc: '基于 500+ 企业调研数据,深度解析制造、零售、医疗三大行业数字化成熟度与关键趋势。',
image: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80',
},
{
tag: '案例研究',
title: '从数据孤岛到智能决策:一家制造企业的三年数字化之路',
desc: '深度复盘某上市制造企业如何通过分阶段数字化实现 40% 效率提升。',
image: 'https://images.unsplash.com/photo-1504384308090-c894fdcc538d?w=800&q=80',
},
];
const INSIGHTS_LIST = [
{ tag: '观点', title: 'AI 时代,中小企业如何避免"为了数字化而数字化"', desc: '从投入产出比出发,讨论中小企业在 AI 浪潮中的务实策略。', date: '2026-06-15' },
{ tag: '方法论', title: '数字化转型的四个阶段:评估、规划、实施、优化', desc: '我们总结的经过 500+ 项目验证的数字化转型方法论。', date: '2026-06-08' },
{ tag: '行业洞察', title: '制造业数字化转型的五大误区', desc: '避开常见陷阱,让数字化投入真正转化为业务价值。', date: '2026-05-28' },
];
const INDUSTRIES = [
{ icon: Factory, name: '智能制造', count: '120+ 案例' },
{ icon: ShoppingCart, name: '贸易零售', count: '80+ 案例' },
{ icon: Building, name: '金融业', count: '60+ 案例' },
{ icon: Stethoscope, name: '医疗健康', count: '40+ 案例' },
{ icon: Cpu, name: '汽车零部件', count: '45+ 案例' },
{ icon: BarChart3, name: '能源化工', count: '35+ 案例' },
{ icon: Shield, name: '物流供应链', count: '40+ 案例' },
{ icon: GraduationCap, name: '教育', count: '30+ 案例' },
];
const TRUST_STATS = [
{ number: '12', unit: '年', label: '行业深耕', desc: '核心团队平均从业经验 12 年以上' },
{ number: '500', unit: '+', label: '企业客户', desc: '覆盖制造、零售、医疗等多个行业' },
{ number: '98', unit: '%', label: '客户续约率', desc: '年度客户续约率行业领先' },
{ number: '150', unit: '+', label: '专业顾问', desc: '技术+业务复合型团队' },
{ number: '6', unit: '款', label: '自研产品', desc: '覆盖数据、协同、AI 等核心领域' },
{ number: '30', unit: '天', label: '平均交付周期', desc: '敏捷迭代,快速验证业务价值' },
];
// ============================================================
// Section 1: Hero — Deep Ink Background
// ============================================================
function HeroSection() {
const shouldReduceMotion = useReducedMotion();
const heroRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: heroRef,
offset: ['start start', 'end start'],
});
const opacity = useTransform(scrollYProgress, [0, 0.6], [1, 0]);
const scale = useTransform(scrollYProgress, [0, 0.6], [1, 0.95]);
const y = useTransform(scrollYProgress, [0, 0.6], [0, 30]);
const bgOrbY = useTransform(scrollYProgress, [0, 1], [0, 80]);
const gridY = useTransform(scrollYProgress, [0, 1], [0, -40]);
return (
<section
ref={heroRef}
className="relative min-h-[100svh] flex items-center overflow-hidden"
style={{ background: INK }}
>
{/* Atmosphere — subtle gradient orbs (parallax: slowest, moves down) */}
<motion.div
className="absolute inset-0 z-0 pointer-events-none"
style={{ y: shouldReduceMotion ? 0 : bgOrbY }}
>
<div className="absolute w-[600px] md:w-[900px] h-[600px] md:h-[900px] rounded-full blur-[120px] md:blur-[140px] opacity-[0.12]"
style={{
background: 'radial-gradient(circle, rgba(196,30,58,0.4), transparent 70%)',
top: '-30%', right: '-15%',
}}
/>
<div className="absolute w-[400px] md:w-[600px] h-[400px] md:h-[600px] rounded-full blur-[100px] md:blur-[120px] opacity-[0.06]"
style={{
background: 'radial-gradient(circle, rgba(10,14,20,0.3), transparent 70%)',
bottom: '-20%', left: '-10%',
}}
/>
</motion.div>
{/* Grid texture (parallax: medium speed, moves up) */}
<motion.div
className="absolute inset-0 z-[1] pointer-events-none opacity-[0.025]"
style={{
y: shouldReduceMotion ? 0 : gridY,
backgroundImage: `linear-gradient(rgba(255,255,255,0.5) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.5) 1px, transparent 1px)`,
backgroundSize: '60px 60px',
maskImage: 'radial-gradient(ellipse 70% 60% at 50% 40%, black 30%, transparent 70%)',
}}
/>
{/* Content */}
<motion.div
className="relative z-10 w-full max-w-[1280px] mx-auto px-5 sm:px-8 lg:px-16 py-32 md:py-40 lg:py-48"
style={{ opacity, scale, y }}
>
<div className="max-w-[720px]">
{/* Eyebrow */}
<motion.div
className="text-[10px] sm:text-[11px] tracking-[4px] sm:tracking-[5px] uppercase font-medium mb-6 md:mb-8"
style={{ color: 'var(--color-brand)' }}
initial={shouldReduceMotion ? {} : { opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1, ease: EASE }}
>
</motion.div>
{/* Title */}
<motion.h1
className="font-sans text-[clamp(36px,10vw,88px)] font-black leading-[1.04] tracking-[-1.5px] sm:tracking-[-2.5px] text-white mb-6 md:mb-8"
initial={shouldReduceMotion ? {} : { opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.7, delay: 0.2, ease: EASE }}
>
<br />
<span style={{ color: 'var(--color-brand)' }}> 3 </span>
</motion.h1>
{/* Subtitle — answer-first: quantified results */}
<motion.div
className="flex flex-wrap gap-x-6 gap-y-2 mb-8 md:mb-10"
initial={shouldReduceMotion ? {} : { opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.35, ease: EASE }}
>
<span className="text-[14px] sm:text-base font-medium" style={{ color: 'rgba(255,255,255,0.6)' }}>
<span style={{ color: 'var(--color-brand)', fontWeight: 700 }}>500+</span>
</span>
<span className="text-[14px] sm:text-base font-medium" style={{ color: 'rgba(255,255,255,0.6)' }}>
<span style={{ color: 'var(--color-brand)', fontWeight: 700 }}>2.8x</span> ROI
</span>
<span className="text-[14px] sm:text-base font-medium" style={{ color: 'rgba(255,255,255,0.6)' }}>
<span style={{ color: 'var(--color-brand)', fontWeight: 700 }}>40%</span>
</span>
</motion.div>
{/* Strategic question */}
<motion.p
className="font-sans text-[14px] sm:text-base italic mb-10 md:mb-12"
style={{ color: 'rgba(255,255,255,0.4)' }}
initial={shouldReduceMotion ? {} : { opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.45, ease: EASE }}
>
</motion.p>
{/* CTAs */}
<motion.div
className="flex flex-col sm:flex-row gap-3 sm:gap-5 items-start sm:items-center mb-12 md:mb-20"
initial={shouldReduceMotion ? {} : { opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.55, ease: EASE }}
>
<StaticLink
href="/contact"
className="min-h-[44px] min-w-[44px] active:scale-[0.98] transition-transform duration-150 inline-flex items-center justify-center gap-2.5 px-6 sm:px-8 py-3.5 text-sm font-medium text-white rounded-sm transition-all duration-300 hover:-translate-y-0.5"
style={{ background: 'var(--color-brand)' }}
>
<ArrowRight className="w-4 h-4" />
</StaticLink>
<StaticLink
href="/products"
className="min-h-[44px] inline-flex items-center gap-2 text-sm font-normal transition-all duration-300 border-b hover:border-white/25"
style={{ color: 'rgba(255,255,255,0.45)', borderColor: 'rgba(255,255,255,0.1)', padding: '12px 0' }}
>
</StaticLink>
</motion.div>
{/* Metrics row */}
<motion.div
className="flex gap-8 md:gap-16 flex-wrap"
initial={shouldReduceMotion ? {} : { opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.7, ease: EASE }}
>
{[
{ value: '12', unit: '', label: '年行业深耕' },
{ value: '500', unit: '+', label: '企业客户信任' },
{ value: '98', unit: '%', label: '客户年度续约率' },
].map(item => (
<div key={item.label} className="flex flex-col">
<div className="font-sans tabular-nums text-[28px] sm:text-[32px] md:text-[36px] font-bold text-white leading-none mb-1 tracking-[-1px]">
{item.value}
<span style={{ color: 'var(--color-brand)', fontSize: '0.5em' }}>{item.unit}</span>
</div>
<div className="text-[10px] sm:text-[11px] tracking-[1px] text-white/25">
{item.label}
</div>
</div>
))}
</motion.div>
</div>
</motion.div>
{/* Scroll indicator — desktop only */}
<div className="absolute bottom-8 md:bottom-10 left-1/2 -translate-x-1/2 z-10 hidden md:flex flex-col items-center gap-2.5">
<div className="w-px h-10 relative overflow-hidden bg-white/[0.06]">
<motion.div
className="absolute top-0 left-0 w-full h-[20%] bg-white/20"
animate={{ y: [0, 30, 0] }}
transition={{ duration: 2.5, repeat: Infinity, ease: 'easeInOut' }}
/>
</div>
<span className="text-[9px] tracking-[4px] text-white/10">SCROLL</span>
</div>
</section>
);
}
// ============================================================
// Section 2: Product Matrix — Paper White Background
// ============================================================
function ProductMatrixSection() {
return (
<section className={SECTION} style={{ background: 'var(--color-bg-primary)' }}>
<div className={CONTAINER}>
<SectionHeader
label="Products"
title="覆盖数字化"
highlight="全生命周期"
desc="6 款自研产品,支撑企业核心业务场景"
/>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
{PRODUCTS.map((product, i) => (
<ScrollReveal key={i} delay={i * 0.06}>
<ProductCard {...product} />
</ScrollReveal>
))}
</div>
</div>
</section>
);
}
// ============================================================
// Section 3: Strategic Questions — Cream Background [Porsche-style]
// ============================================================
function StrategicQuestionsSection() {
return (
<section className={SECTION} style={{ background: CREAM }}>
<div className={CONTAINER}>
<SectionHeader
label="Strategic Questions"
title="先问对问题"
highlight="再做对事"
desc="在启动任何数字化项目之前,先找到正确的方向"
/>
<div>
{STRATEGIC_QUESTIONS.map((item, i) => (
<ScrollReveal key={i} delay={i * 0.08}>
<QuestionCard
question={item.question}
description={item.description}
href={item.href}
/>
</ScrollReveal>
))}
</div>
</div>
</section>
);
}
// ============================================================
// Section 4: Client Results — Deep Ink Background [Bain-style]
// ============================================================
function CaseStudiesSection() {
return (
<section className={SECTION} style={{ background: INK }}>
<div className={CONTAINER}>
<SectionHeader
label="Client Results"
title="500+ 企业的"
highlight="增长实践"
desc="不以项目上线为终点,以客户业务改善为衡量标准"
light
/>
<div className="grid lg:grid-cols-3 gap-px rounded-sm overflow-hidden"
style={{ background: 'rgba(255,255,255,0.03)' }}>
{CASE_STUDIES.map((cs, i) => (
<ScrollReveal key={i} delay={i * 0.1}>
<CaseCard {...cs} />
</ScrollReveal>
))}
</div>
<ScrollReveal delay={0.3}>
<div className="text-center mt-8 md:mt-12">
<StaticLink
href="/solutions"
className="min-h-[44px] inline-flex items-center gap-2 text-[13px] font-medium transition-colors duration-300 text-white/50 hover:text-white group"
>
<ArrowRight className="w-3.5 h-3.5 transition-transform duration-300 group-hover:translate-x-1" />
</StaticLink>
</div>
</ScrollReveal>
</div>
</section>
);
}
// ============================================================
// Section 5: Insights — Paper White Background [Accenture-style]
// ============================================================
function InsightsSection() {
return (
<section className={SECTION} style={{ background: 'var(--color-bg-primary)' }}>
<div className={CONTAINER}>
<SectionHeader
label="Insights"
title="把握数字化"
highlight="前沿趋势"
desc="基于 500+ 项目实践的研究成果与行业观点"
/>
{/* Featured insights — 2 large cards */}
<div className="grid md:grid-cols-2 gap-4 sm:gap-6 mb-6 md:mb-8">
{INSIGHTS_FEATURED.map((insight, i) => (
<ScrollReveal key={i} delay={i * 0.1}>
<InsightCard featured {...insight} />
</ScrollReveal>
))}
</div>
{/* Secondary insights — 3 small cards */}
<div className="grid sm:grid-cols-2 md:grid-cols-3 gap-px rounded-sm overflow-hidden"
style={{ background: 'var(--color-border-primary)' }}>
{INSIGHTS_LIST.map((insight, i) => (
<ScrollReveal key={i} delay={i * 0.06}>
<InsightCard {...insight} />
</ScrollReveal>
))}
</div>
</div>
</section>
);
}
// ============================================================
// Section 6: Industry Selector — Paper White Background
// ============================================================
function IndustrySelectorSection() {
return (
<section className={SECTION} style={{ background: CREAM }}>
<div className={CONTAINER}>
<SectionHeader
label="Industries"
title="8 大行业"
highlight="深度实践"
desc="深入行业场景,理解业务逻辑,提供真正落地的解决方案"
/>
<ScrollReveal delay={0.1}>
<p className="font-sans text-[18px] sm:text-[20px] md:text-[22px] font-semibold mb-8 md:mb-10 leading-relaxed text-[var(--color-text-primary)]">
<span style={{ color: 'var(--color-brand)' }}></span>
</p>
</ScrollReveal>
<ScrollReveal delay={0.15}>
<IndustryGrid items={INDUSTRIES} />
</ScrollReveal>
</div>
</section>
);
}
// ============================================================
// Section 7: Trust Proof — Paper White Background
// ============================================================
function TrustSection() {
return (
<section className={SECTION} style={{ background: 'var(--color-bg-primary)' }}>
<div className={CONTAINER}>
<SectionHeader
label="Trust"
title="98% 客户"
highlight="续约率"
desc="数字会说话,信任是合作的基础"
/>
<StatsBar items={TRUST_STATS} />
</div>
</section>
);
}
// ============================================================
// Main Export
// ============================================================
export default function HomeContent() {
return (
<main className="min-h-screen">
<ScrollProgress />
<HeroSection />
<ProductMatrixSection />
<StrategicQuestionsSection />
<CaseStudiesSection />
<InsightsSection />
<IndustrySelectorSection />
<TrustSection />
<CTASection />
</main>
);
}