docs(test): 添加设计文档、测试规范与 E2E 测试套件

- 新增 ADR 架构决策记录 (Design DNA 集成与深化)
- 新增 CMS 系统设计文档
- 新增实施计划文档 (Phase1-3)
- 新增 Bain 品牌升级设计规格
- 新增 E2E 分层测试套件 (P1-P4)
- 新增视觉回归测试配置
- 新增光效分析、视觉验证等辅助脚本
- 更新验收测试报告
This commit is contained in:
张翔
2026-07-07 06:54:25 +08:00
parent 8def296301
commit 636bc4ecde
31 changed files with 9262 additions and 41 deletions
@@ -0,0 +1,599 @@
# 第一阶段:打好地基(Accenture 骨架)实现计划
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
**目标:** 建立工业化、可扩展的设计系统基础,完成组件库清理和核心模块搭建
**架构:** 以 Accenture 工业化设计系统为骨架,完善三级设计令牌体系,统一组件库版本,搭建服务网格和数据条核心模块
**技术栈:** Next.js 14 + TypeScript + Tailwind CSS + CSS Variables + Framer Motion
---
## 文件结构总览
| 文件 | 操作 | 职责 |
|------|------|------|
| `src/app/globals.css` | 修改 | 设计令牌三级结构整理、金色残留清理、补充组件令牌 |
| `tailwind.config.js` | 修改 | 令牌映射优化、新组件令牌注册 |
| `src/components/sections/section-header.tsx` | 修改 | 金色→品牌红、样式优化、移除 font-serif |
| `src/components/sections/stats-bar.tsx` | 修改 | 样式升级、移除 font-serif、品牌色优化 |
| `src/components/sections/case-card.tsx` | 修改 | 金色残留清理 |
| `src/components/sections/insight-card.tsx` | 修改 | 金色残留清理 |
| `src/app/(marketing)/home-content.tsx` | 修改 | 金色残留清理 |
| `src/components/ui/scroll-reveal.tsx` | 修改 | 统一为唯一 ScrollReveal 组件 |
| `src/components/sections/scroll-reveal.tsx` | 删除 | 重复组件,迁移到 ui/ |
| `src/components/sections/service-grid.tsx` | 新建 | Accenture 式服务网格组件 |
| `src/components/sections/service-card.tsx` | 新建 | 服务卡片(编号 + 4px 色条) |
| `src/app/(marketing)/_archive/` | 移动 | 归档所有 v1 内容文件 |
| `src/components/content/sections.tsx` | 修改 | 已有内容组件,无需大改 |
---
### 任务 1:设计令牌体系完善与金色残留清理
**文件:**
- 修改:`src/app/globals.css`
- 修改:`tailwind.config.js`
#### 1.1 金色残留清理
- [ ] **步骤 1:定位所有金色配色引用**
运行搜索确认所有金色相关代码位置:
- `--color-gold-text`
- `--color-gold`
- `#C9A84C`
- `gold` 相关变量
涉及文件:section-header.tsx、case-card.tsx、insight-card.tsx、home-content.tsx
- [ ] **步骤 2:全局清理金色 CSS 变量**
在 globals.css 中删除所有 gold 相关变量,替换为品牌色或移除:
- `--color-gold-text` → 不再使用,统一用 `--color-brand``--color-text-muted`
- `--color-gold` → 直接删除
- [ ] **步骤 3:验证无金色残留**
运行搜索确认零结果:
```bash
grep -r "gold\|C9A84C" src/ --include="*.tsx" --include="*.css" --include="*.ts"
```
预期:0 个匹配
#### 1.2 三级令牌命名规范梳理
- [ ] **步骤 4:确认 base tokens(基础令牌)已完整**
检查 globals.css 中的基础令牌(颜色、字体、间距、圆角、阴影、动效),确保:
- 颜色:墨色、品牌色、辅助色、背景色、文字色、边框色、功能色 —— 全部存在
- 排版:字号、行高、字间距 —— 全部存在
- 间距:xs 到 6xl —— 全部存在
- 圆角:xs 到 full —— 全部存在
- 阴影:xs 到 xl + brand + glow —— 全部存在
- 动效:时长、缓动、stagger —— 全部存在
- [ ] **步骤 5:确认 semantic tokens(语义令牌)已完整**
检查语义化命名:
- `--color-bg-primary/secondary/tertiary`
- `--color-text-primary/secondary/tertiary/muted`
- `--color-border-primary/secondary`
- `--color-link/link-hover`
- `--color-success/warning/error/info`
- [ ] **步骤 6:补充 component tokens(组件令牌)**
在 globals.css 已有的组件令牌基础上,补充缺失项:
`/* === 组件令牌层(Component Tokens=== */` 区域补充:
```css
/* 导航 */
--nav-height: 4rem;
--nav-height-md: 4.5rem;
--nav-item-padding-x: 1rem;
--nav-item-padding-y: 0.75rem;
/* 标签/徽章 */
--badge-height: 1.5rem;
--badge-padding-x: 0.625rem;
--badge-font-size: 0.75rem;
--badge-border-radius: var(--radius-sm);
/* 输入框 */
--input-height: 2.75rem;
--input-padding-x: 1rem;
--input-border-radius: var(--radius-sm);
/* 下拉菜单 */
--dropdown-min-width: 12rem;
--dropdown-padding: 0.5rem;
--dropdown-border-radius: var(--radius-md);
--dropdown-shadow: var(--shadow-lg);
/* 模态框 */
--modal-max-width: 32rem;
--modal-padding: 2rem;
--modal-border-radius: var(--radius-xl);
--modal-shadow: var(--shadow-xl);
/* 表格 */
--table-row-height: 3rem;
--table-cell-padding-x: 1rem;
--table-cell-padding-y: 0.75rem;
/* 标签页 */
--tab-height: 2.75rem;
--tab-padding-x: 1.25rem;
--tab-border-radius: var(--radius-sm);
/* 提示框 */
--alert-padding-y: 1rem;
--alert-padding-x: 1.25rem;
--alert-border-radius: var(--radius-md);
```
- [ ] **步骤 7:同步更新 tailwind.config.js**
在 tailwind.config.js 的 theme.extend 中补充新组件令牌的映射(如果需要作为 Tailwind 工具类使用的话)。
- [ ] **步骤 8:运行 TypeScript 检查**
```bash
npx tsc --noEmit
```
预期:0 errors
---
### 任务 2:组件库系统化清理
**文件:**
- 删除:`src/components/sections/scroll-reveal.tsx`(重复,保留 ui/ 下的)
- 移动:所有 v1 内容文件到 `_archive/`
- 修改:所有引用了 sections/scroll-reveal 的文件
#### 2.1 重复组件清理
- [ ] **步骤 1:确认 ui/scroll-reveal.tsx 是主版本**
读取 `src/components/ui/scroll-reveal.tsx` 确认其功能完整。
- [ ] **步骤 2:更新所有引用路径**
将所有从 `@/components/sections/scroll-reveal` 的导入改为从 `@/components/ui/scroll-reveal` 导入。
搜索引用:
```bash
grep -r "from.*sections/scroll-reveal" src/ --include="*.tsx" --include="*.ts"
```
逐个修改导入路径。
- [ ] **步骤 3:删除 sections/scroll-reveal.tsx**
```bash
rm src/components/sections/scroll-reveal.tsx
```
#### 2.2 v1 内容文件归档
- [ ] **步骤 4:确认所有 v1 内容文件列表**
| 文件 | 当前位置 | 目标位置 |
|------|---------|---------|
| services-content-v1.tsx | `services/` | `_archive/` |
| service-detail-content-v1.tsx | `services/` | `_archive/` |
| team-content-v1.tsx | `team/` | `_archive/` |
| news-content-v1.tsx | `news/` | `_archive/` |
| news-detail-content-v1.tsx | `news/` | `_archive/` |
| about-content-v1.tsx | `about/` | `_archive/` |
| solutions-content-v1.tsx | `solutions/` | `_archive/` |
| solution-detail-content-v1.tsx | `solutions/` | `_archive/` |
| product-detail-content-v1.tsx | `products/` | `_archive/` |
| products-content-v1.tsx | `products/` | `_archive/` |
| erp-upgrade-content-v1.tsx | `products/erp-upgrade/` | `_archive/` |
| contact-content-v1.tsx | `contact/` | `_archive/` |
- [ ] **步骤 5:确认 v1 文件无引用**
搜索确认没有页面文件还在 import v1 内容:
```bash
grep -r "content-v1" src/app --include="*.tsx" --include="*.ts" | grep -v "_archive"
```
预期:0 个结果(除 _archive 外)
- [ ] **步骤 6:移动到 _archive 目录**
将所有 v1 文件移动到 `src/app/(marketing)/_archive/` 目录。
移动后验证:
```bash
ls src/app/\(marketing\)/_archive/ | grep v1
```
预期:12 个文件
#### 2.3 金色残留组件修复
- [ ] **步骤 7:修复 SectionHeader 组件**
修改 `src/components/sections/section-header.tsx`
1. 删除所有 `--color-gold-text``#C9A84C` 引用
2. Eyebrow label 颜色改为 `var(--color-brand)`(品牌红贯穿)
3. 移除 `font-serif` 类,改为系统 sans 字体
4. 优化样式,符合 Accenture 风格
- [ ] **步骤 8:修复 CaseCard 组件**
修改 `src/components/sections/case-card.tsx`
1. 删除金色相关变量引用
2. 替换为品牌色或中性色
- [ ] **步骤 9:修复 InsightCard 组件**
修改 `src/components/sections/insight-card.tsx`
1. 删除金色相关变量引用
2. 替换为品牌色或中性色
- [ ] **步骤 10:修复 home-content.tsx**
修改 `src/app/(marketing)/home-content.tsx`
1. 删除金色相关变量引用
2. 替换为品牌色或中性色
- [ ] **步骤 11:验证金色残留为零**
```bash
grep -r "gold\|C9A84C" src/ --include="*.tsx" --include="*.css" --include="*.ts" | grep -v "_archive" | grep -v node_modules
```
预期:0 个结果
- [ ] **步骤 12:运行 TypeScript 检查**
```bash
npx tsc --noEmit
```
预期:0 errors
---
### 任务 3:服务网格模块(Accenture 式)
**文件:**
- 新建:`src/components/sections/service-grid.tsx`
- 新建:`src/components/sections/service-card.tsx`
#### 3.1 ServiceCard 组件
- [ ] **步骤 1:创建 ServiceCard 组件**
`src/components/sections/service-card.tsx` 创建服务卡片组件:
```tsx
'use client';
import { motion } from 'framer-motion';
import { useReducedMotion } from '@/hooks/use-reduced-motion';
import Link from 'next/link';
export type ServiceColor = 'blue' | 'teal' | 'amber' | 'purple';
interface ServiceCardProps {
number: string;
title: string;
description: string;
color: ServiceColor;
href: string;
className?: string;
delay?: number;
}
const colorMap: Record<ServiceColor, string> = {
blue: 'var(--color-accent-blue)',
teal: 'var(--color-accent-teal)',
amber: 'var(--color-accent-amber)',
purple: 'var(--color-accent-purple)',
};
export function ServiceCard({
number,
title,
description,
color,
href,
className = '',
delay = 0,
}: ServiceCardProps) {
const shouldReduceMotion = useReducedMotion();
const accentColor = colorMap[color];
return (
<motion.div
className={`group relative bg-[var(--color-bg-primary)] rounded-[var(--radius-lg)] overflow-hidden transition-all duration-[var(--transition-normal)] ease-[var(--ease-ink)] hover:-translate-y-1 hover:shadow-[var(--shadow-lg)] ${className}`}
initial={shouldReduceMotion ? {} : { opacity: 0, y: 24 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-40px' }}
transition={{ duration: 0.6, delay, ease: [0.22, 1, 0.36, 1] }}
>
{/* 左侧 4px 色条 */}
<div
className="absolute left-0 top-0 bottom-0 w-1 transition-all duration-[var(--transition-normal)] group-hover:w-1.5"
style={{ backgroundColor: accentColor }}
/>
<div className="p-6 md:p-8 pl-6 md:pl-8">
{/* 大号背景编号 */}
<div
className="absolute top-4 right-6 text-[5rem] font-black leading-none select-none pointer-events-none transition-opacity duration-[var(--transition-normal)] group-hover:opacity-10"
style={{ color: 'var(--color-border-light)', opacity: 0.06 }}
aria-hidden="true"
>
{number}
</div>
{/* 编号标签 */}
<div
className="text-xs font-bold tracking-[0.18em] uppercase mb-4"
style={{ color: accentColor }}
>
{number}
</div>
{/* 标题 */}
<h3 className="text-xl md:text-2xl font-bold mb-3 leading-tight" style={{ color: 'var(--color-text-primary)' }}>
{title}
</h3>
{/* 描述 */}
<p className="text-sm md:text-base leading-relaxed mb-6" style={{ color: 'var(--color-text-secondary)' }}>
{description}
</p>
{/* 链接 */}
<Link
href={href}
className="inline-flex items-center text-sm font-medium transition-colors duration-[var(--transition-fast)]"
style={{ color: 'var(--color-brand)' }}
>
<svg
className="ml-1.5 w-4 h-4 transform transition-transform duration-[var(--transition-fast)] group-hover:translate-x-1"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</Link>
</div>
</motion.div>
);
}
```
- [ ] **步骤 2:验证组件无 TypeScript 错误**
```bash
npx tsc --noEmit src/components/sections/service-card.tsx
```
预期:0 errors
#### 3.2 ServiceGrid 组件
- [ ] **步骤 3:创建 ServiceGrid 组件**
`src/components/sections/service-grid.tsx` 创建服务网格组件:
```tsx
'use client';
import { ServiceCard, type ServiceColor } from './service-card';
import { SectionHeader } from './section-header';
interface ServiceItem {
number: string;
title: string;
description: string;
color: ServiceColor;
href: string;
}
interface ServiceGridProps {
label?: string;
title: string;
highlight?: string;
desc?: string;
items: ServiceItem[];
className?: string;
}
export function ServiceGrid({
label = '我们的服务',
title,
highlight,
desc,
items,
className = '',
}: ServiceGridProps) {
return (
<section className={`section-padding ${className}`}>
<div className="container-x">
<SectionHeader label={label} title={title} highlight={highlight} desc={desc} />
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
{items.map((item, index) => (
<ServiceCard
key={item.number}
number={item.number}
title={item.title}
description={item.description}
color={item.color}
href={item.href}
delay={index * 0.1}
/>
))}
</div>
</div>
</section>
);
}
```
- [ ] **步骤 4:验证组件无 TypeScript 错误**
```bash
npx tsc --noEmit src/components/sections/service-grid.tsx
```
预期:0 errors
- [ ] **步骤 5:在首页集成 ServiceGrid 做测试**
在 home-content.tsx 中临时添加一个使用示例,确保组件能正常渲染。测试后保留或根据实际内容结构调整。
---
### 任务 4:数据条组件升级(Stats Bar)
**文件:**
- 修改:`src/components/sections/stats-bar.tsx`
#### 4.1 StatsBar 样式升级
- [ ] **步骤 1:优化 StatsBar 组件**
修改 `src/components/sections/stats-bar.tsx`
1. 移除 `font-serif`,改为 sans 字体
2. 优化颜色使用,确保品牌红正确使用
3. 增强数字滚动动画(优化缓动曲线)
4. 增加 tabular-nums 数字等宽
5. 优化间距和响应式布局
6. 统一使用 CSS 变量而非内联样式中的硬编码值
关键改动:
```tsx
// 数字样式
className="font-sans tabular-nums text-[clamp(2.5rem,5vw,4rem)] font-extrabold leading-none mb-2 tracking-[-0.02em]"
// 品牌色单位
<span style={{ color: 'var(--color-brand)', fontSize: '0.4em', fontWeight: 700 }}>
{item.unit}
</span>
// 标签样式
className="text-xs sm:text-sm font-medium mb-2 tracking-[0.08em] uppercase"
```
- [ ] **步骤 2:验证组件无 TypeScript 错误**
```bash
npx tsc --noEmit src/components/sections/stats-bar.tsx
```
预期:0 errors
---
### 任务 5:页面布局规范统一
**文件:**
- 修改:`src/app/globals.css`(补充布局相关工具类)
- 检查:核心页面的 Section 间距一致性
#### 5.1 12 列网格确认
- [ ] **步骤 1:确认 Tailwind 默认 12 列网格可用**
检查 tailwind.config.js,确保:
- `grid-cols-1``grid-cols-12` 可用(Tailwind 默认支持)
- `gap` 间距与设计令牌对齐
- [ ] **步骤 2:补充布局工具类**
在 globals.css 的 `@layer utilities` 中确认以下类存在:
- `.container-x` ✅ 已存在
- `.section-padding` ✅ 已存在
确认响应式断点正确:
- sm: 640px
- md: 768px
- lg: 1024px
- xl: 1280px
- 2xl: 1536px
#### 5.2 Section 间距规范检查
- [ ] **步骤 3:抽查 3 个核心页面的 Section 间距**
检查页面:
1. 首页(home-content.tsx
2. 服务列表页(services-content-v2.tsx
3. 关于页(about-content-v2.tsx
确保所有 Section 统一使用 `section-padding` 类,间距一致。
如发现不一致,记录并修复。
---
### 任务 6:第一阶段验收
#### 6.1 代码质量检查
- [ ] **步骤 1TypeScript 类型检查**
```bash
npx tsc --noEmit
```
预期:0 errors
- [ ] **步骤 2:生产构建**
```bash
npm run build
```
预期:构建成功,无报错
- [ ] **步骤 3ESLint 检查**
```bash
npx eslint src/ --ext .ts,.tsx
```
预期:0 errorswarning 可接受)
#### 6.2 功能验证
- [ ] **步骤 4:启动开发服务器**
```bash
npm run dev
```
- [ ] **步骤 5:视觉验证清单**
在浏览器中验证:
1. ✅ 金色配色完全消失,品牌红正确贯穿
2. ✅ SectionHeader 样式正常(eyebrow 品牌红、字体 sans
3. ✅ StatsBar 数字滚动正常
4. ✅ ServiceGrid 服务卡片渲染正常(编号 + 色条)
5. ✅ 页面布局无错乱
6. ✅ 响应式布局正常(移动端/平板/桌面)
7. ✅ 暗色模式切换正常
8. ✅ 无控制台错误
---
## 验收标准
第一阶段完成标志:
1. ✅ 金色配色零残留
2. ✅ 三级设计令牌体系完善(base + semantic + component
3. ✅ 重复组件清理完成(scroll-reveal 统一)
4. ✅ v1 内容文件全部归档
5. ✅ ServiceGrid + ServiceCard 组件可用
6. ✅ StatsBar 样式升级完成
7. ✅ TypeScript 0 errors
8. ✅ 生产构建成功
9. ✅ 核心页面视觉正常
完成后,项目设计系统完成度从 40/100 → 65/100。
@@ -0,0 +1,242 @@
# 第二阶段实现计划:确立品牌(Bain 血肉)
> 基于设计规格:`docs/superpowers/specs/2026-06-29-phase2-bain-brand-clarity-design.md`
> 前置条件:第一阶段(Accenture 骨架)已完成
## 总览
**目标:** 借鉴 Bain & Company 的品牌清晰度,让网站从"有骨架"升级到"有血肉"
**预计任务数:** 5 个核心任务
**预计修改文件:** ~10 个
**验收标准:** TypeScript 0 errors + ESLint 0 errors + 视觉验证通过
---
## 任务 1:首页 Hero 重构(答案优先)
**优先级:**
**依赖:**
### 改动文件
- `src/app/(marketing)/home-content.tsx`HeroSection 部分)
### 具体改动
1. **标题改为结论型**
- 当前:"让每一次数字化转型掷地有声"
- 改为:"数字化转型成功率提升 3 倍"
- "3 倍"用品牌红高亮
2. **副标题强化量化成果**
- 当前:"12 年深耕,为 500+ 中国企业提供从战略到落地的全链路数字化服务"
- 改为:"500+ 企业验证 · 平均 ROI 提升 2.8 倍 · 项目交付周期缩短 40%"
3. **Hero 指标行优化**
- 从 4 个精简到 3 个最核心 KPI
- 数字字号放大,增加视觉冲击力
- 单位用品牌红
4. **战略问句优化**
- 位置:Hero 底部,指标行下方
- 内容:"您的企业,准备好迎接下一阶段的增长了吗?"
- 样式:斜体 + 低对比度 + 适当留白
### 验收标准
- [ ] Hero 首屏 3 秒内能看懂核心价值
- [ ] 标题含品牌红关键词,占比 ≤ 30%
- [ ] 3 个核心 KPI 清晰展示
- [ ] 战略问句引导往下探索
---
## 任务 2:品牌红贯穿优化
**优先级:**
**依赖:**
### 改动文件
- `src/components/sections/section-header.tsx`
- `src/app/(marketing)/home-content.tsx`(抽查)
- `src/app/(marketing)/services/services-content-v2.tsx`(抽查)
- `src/app/(marketing)/about/about-content-v2.tsx`(抽查)
### 具体改动
1. **SectionHeader 增加品牌红装饰**
- 在 Eyebrow 标签左侧增加 4px 品牌红竖线
- 与 Eyebrow 文字垂直对齐,高度等于文字高度
2. **每页品牌红触达点检查**
- 首页:Hero 关键词 + CTA 按钮 + Section 标签 + 数据高亮 → ✅ 满足
- 服务页:服务卡片色条 + CTA 按钮 + Section 标签 → ✅ 满足
- 关于页:数据高亮 + CTA 按钮 + Section 标签 → ✅ 满足
3. **品牌红面积检查**
- 确保每页品牌红面积 ≤ 10%
- 禁止大面积背景色使用品牌红
4. **统一链接 hover 态**
- 所有文本链接 hover 时变为品牌红
- 过渡动画 200ms ease-out
### 验收标准
- [ ] SectionHeader 有品牌红装饰线
- [ ] 每页品牌红触达点 ≥ 3 个
- [ ] 品牌红面积 ≤ 10%
- [ ] 链接 hover 态统一为品牌红
---
## 任务 3:案例卡片重构(Bain 三段式)
**优先级:**
**依赖:**
### 改动文件
- `src/components/sections/case-card.tsx`
### 具体改动
1. **接口改造**
```typescript
interface CaseCardProps {
industry: string;
title: string;
challenge: string; // 新增
solution: string; // 新增
impact: {
value: string;
label: string;
}[];
href: string;
className?: string;
}
```
2. **三段式布局**
- 顶部:行业标签 + 标题
- 中部:挑战 + 方案(文字较小,信息密度高)
- 底部:成果数字(超大字号,视觉权重 ≥ 50%)
3. **成果区域视觉强化**
- 数字超大字号 + tabular-nums
- 数字品牌红,单位灰色
- hover 时数字微放大(scale 1.02
- 数字与数字之间用细线分隔
4. **保留现有功能**
- 背景图片 + 渐变遮罩
- hover 顶部渐变装饰线
- 滚动入场动画
### 验收标准
- [ ] 案例卡片采用三段式结构
- [ ] 成果数字视觉权重 ≥ 50%
- [ ] hover 时数字微放大
- [ ] TypeScript 类型检查通过
---
## 任务 4:内容策略优化
**优先级:** 中
**依赖:** 无
### 改动文件
- `src/app/(marketing)/home-content.tsx`Section 标题)
### 具体改动
1. **首页各 Section 标题改为结论型**
| 当前标题 | 改为结论型 |
|---------|-----------|
| 我们的服务 | 覆盖数字化全生命周期 |
| 核心优势 | 成功率提升 3 倍的方法论 |
| 精选案例 | 500+ 企业的增长实践 |
| 行业洞见 | 把握数字化前沿趋势 |
| 客户评价 | 96% 客户选择继续合作 |
2. **答案优先的文案结构**
- 每个 Section 先给结论(标题)
- 再给 2-3 个支撑论据
- 数据用品牌红高亮
3. **每段文字 ≤ 3 行**
- 超过 3 行则拆分为点列
- 保持可读性和节奏
### 验收标准
- [ ] 关键 Section 标题为结论型表述
- [ ] 文案结构符合"结论优先"原则
- [ ] 每段文字 ≤ 3 行
---
## 任务 5:极简留白优化
**优先级:** 中
**依赖:** 无
### 改动文件
- `src/app/(marketing)/home-content.tsx`
- `src/app/globals.css`(可选,增加工具类)
### 具体改动
1. **Hero 区域增加留白**
- 桌面端:上下留白从当前值增加到 ≥ 20vh
- 内容垂直居中更宽松
- 减少视觉元素,聚焦核心信息
2. **CTA 区域增加留白**
- 桌面端:上下留白 ≥ 120px
- 内容中心化,最大宽度收窄到 max-w-3xl
- 增加呼吸感
3. **节奏变化**
- 形成"信息密度 → 大留白 → 再信息密度"的节奏
- Hero(大留白)→ 服务网格(信息密度)→ Stats Bar(中密度)→ 案例(中密度)→ CTA(大留白)
4. **可选:增加 CSS 工具类**
- `section-padding-lg`:营销页大间距
- `content-narrow`:内容收窄类
### 验收标准
- [ ] Hero 区域留白比例符合 Bain 式极简美学
- [ ] CTA 区域留白充足,内容聚焦
- [ ] 页面节奏有张有弛
- [ ] 响应式布局正常
---
## 总体验收
### 功能验收
- [ ] 首页首屏 3 秒内能看懂核心价值
- [ ] 每页品牌红触达点 ≥ 3 个且面积 ≤ 10%
- [ ] 案例卡片采用 Bain 式三段式结构
- [ ] 关键 Section 标题为结论型表述
- [ ] Hero、CTA 区域留白比例符合 Bain 式极简美学
### 技术验收
- [ ] TypeScript 类型检查通过(0 errors
- [ ] ESLint 检查通过(0 errors
- [ ] 构建成功,无报错
- [ ] 响应式布局正常(sm/md/lg/xl 断点)
### 设计验收
- [ ] 品牌红使用符合"朱砂点睛"原则
- [ ] 信息层级清晰,对比强烈
- [ ] 留白有节奏感,不拥挤也不空洞
- [ ] 数据呈现方式专业、有说服力
---
## 执行顺序
```
任务1(Hero重构) → 任务2(品牌红贯穿) → 任务3(案例卡片) → 任务4(内容策略) → 任务5(留白优化) → 总体验收
```
**并行可能性:** 任务 2、4、5 可以部分并行,因为它们修改的文件不同。
@@ -0,0 +1,198 @@
# 第三阶段实现计划:塑造个性(Porsche 点睛)
> 前置条件:第一阶段(Accenture骨架)+ 第二阶段(Bain血肉)已完成
> 核心原则:克制是金,动效只为品牌叙事服务,不炫技
## 总览
**目标:** 用精巧的动效为网站注入灵魂,传递"技术驱动变革"的品牌故事
**预计任务数:** 5 个核心任务
**验收标准:** TypeScript 0 errors + ESLint 0 errors + 动效流畅不卡顿
---
## 任务 1:滚动视差增强(Hero + 关键 Section
**优先级:**
**依赖:**
### 改动文件
- `src/app/(marketing)/home-content.tsx`Hero 部分)
- `src/components/sections/stats-bar.tsx`(数字渐进式出现)
### 具体改动
1. **Hero 多层视差**
- 背景光晕层:滚动时缓慢下移(速率 0.3x)
- 网格纹理层:滚动时缓慢上移(速率 0.15x)
- 内容层:正常滚动,但有淡出效果(已有)
- 三层速率差异创造深度感
2. **StatsBar 数字渐进式"生长"**
- 从 0 增长到目标值的 countUp 动画(已有,优化缓动)
- 数字出现时伴随轻微的 scale 从 0.9 → 1
- 单位和标签延迟 200ms 出现
### 验收标准
- [ ] Hero 有多层视差深度感
- [ ] 数字滚动动画流畅自然
- [ ] 所有动效使用 transform + opacity,性能良好
- [ ] 尊重 prefers-reduced-motion 设置
---
## 任务 2:品牌动效叙事线
**优先级:**
**依赖:**
### 改动文件
- `src/components/sections/service-card.tsx`(色条动画)
- `src/components/sections/case-card.tsx`(成果数字点亮)
- `src/components/sections/section-header.tsx`(装饰线生长动画)
### 具体改动
1. **ServiceCard 左侧色条"生长"动画**
- 入场时:色条从高度 0 → 完整高度
- 从下往上生长,速率 0.4s ease-out
- 比卡片内容早 100ms 开始
2. **SectionHeader 装饰线动画**
- 入场时:装饰线从 0 高度 → 完整高度
- 与 eyebrow 文字同步出现
3. **CaseCard 成果数字"点亮"**
- 入场时:数字从灰色 → 白色 + 轻微放大
- 延迟 200ms,在挑战/方案文字之后出现
- 象征"从问题到成果"的叙事
### 验收标准
- [ ] ServiceCard 色条有生长动画
- [ ] SectionHeader 装饰线有入场动画
- [ ] CaseCard 成果数字有延迟点亮效果
- [ ] 动效形成品牌叙事线,不堆砌
---
## 任务 3:微动效精细化
**优先级:**
**依赖:**
### 改动文件
- `src/components/ui/button.tsx`hover 填充动画)
- `src/components/sections/product-card.tsx`hover 微动效)
- `src/components/ui/static-link.tsx` 或全局 CSS(链接下划线动画)
### 具体改动
1. **Button hover:从左到右颜色填充**
- 背景色从左往右滑入,不是突然变色
- 时长 250msease-out
- 文字保持在最上层
2. **卡片 hover 精细化**
- 上浮 2px → 4px(更明显但克制)
- 阴影从浅到深的过渡
- 边框颜色的微妙变化
3. **链接 hover:下划线扩展**
- 文本链接 hover 时,下划线从中间向两边扩展
- 使用伪元素实现,不影响布局
### 验收标准
- [ ] 按钮有从左到右的填充动画
- [ ] 卡片 hover 动效细腻自然
- [ ] 链接有下划线扩展动画
- [ ] 所有动效时长 ≤ 300ms,不拖沓
---
## 任务 4:滚动进度指示器
**优先级:**
**依赖:**
### 改动文件
- 新建 `src/components/ui/scroll-progress.tsx`
- `src/app/(marketing)/layout.tsx` 或首页引入
### 具体改动
1. **顶部细进度条**
- 高度 2px,固定在页面顶部
- 品牌红渐变填充,随滚动增长
- 轻量化,z-index 很高但不干扰内容
2. **可配置选项**
- 可选颜色(默认品牌红)
- 可选高度(默认 2px
- 可选位置(顶部/底部,默认顶部)
### 验收标准
- [ ] 进度条随滚动平滑增长
- [ ] 不干扰页面内容
- [ ] 性能良好,不影响滚动流畅度
---
## 任务 5:页面入场与过渡优化
**优先级:**
**依赖:**
### 改动文件
- `src/app/(marketing)/home-content.tsx`Hero 入场优化)
- 全局 CSS(过渡曲线统一)
### 具体改动
1. **首屏渐进式入场**
- 背景层先出现(淡入)
- 内容层后出现(上移 + 淡入)
- 各元素按层级依次入场,有节奏感
2. **动效曲线统一**
- 全站使用统一的 ease-out 曲线
- 快速开始,缓慢结束(cubic-bezier(0.22, 1, 0.36, 1)
- 模拟物理世界的减速感
### 验收标准
- [ ] 首屏入场有层次感、节奏感
- [ ] 动效曲线统一自然
- [ ] 完全尊重 prefers-reduced-motion
---
## 总体验收
### 功能验收
- [ ] Hero 有多层视差深度感
- [ ] 品牌红元素形成叙事流动线
- [ ] 微动效细腻自然,不炫技
- [ ] 滚动进度指示器工作正常
- [ ] 页面入场有层次感
### 技术验收
- [ ] TypeScript 类型检查通过(0 errors
- [ ] ESLint 检查通过(0 errors
- [ ] 构建成功,无报错
- [ ] 所有动效使用 transform + opacity,性能良好
- [ ] 完全尊重 prefers-reduced-motion 设置
### 设计验收
- [ ] 动效克制,只为品牌叙事服务
- [ ] 动效曲线统一自然
- [ ] 不干扰阅读和操作
- [ ] 整体传达"技术驱动变革"的品牌故事
---
## 执行顺序
```
任务1(视差增强) → 任务2(品牌叙事线) → 任务3(微动效) → 任务4(进度指示器) → 任务5(入场优化) → 总体验收
```
**并行可能性:** 任务 2、3 可以部分并行,修改的组件不同。
@@ -0,0 +1,671 @@
# Novalon CMS 自研系统实现计划
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
**目标:** 构建与 Novalon 技术栈深度融合的自研 Headless CMS 系统,实现内容模型定义、内容管理、动态页面渲染、主题配置等核心能力。
**架构:** 采用 Broadleaf CMS 核心设计思想(ContentModel + ContentItem + ContentZone + ThemeField),基于 Java 21 + Spring Boot + PostgreSQL 构建后端服务,React + ProLayout 构建管理后台,Next.js 前端通过统一 SDK 接入。前端优先实现 SDK 与动态渲染层,后端 API 按接口契约并行开发。
**技术栈:**
- 后端:Java 21 + Spring Boot WebFlux + PostgreSQL + Flyway + Spring Security
- 管理端:React 18 + ProLayout + Zustand + Ant Design 5(对齐 novalon-manage-system
- 前端网站:Next.js 14 + TypeScript + ISR/SSG
- 数据校验:Zod(前端)+ Jakarta Validation(后端)
---
## 一、系统架构总览
### 1.1 整体架构图
```
┌─────────────────────────────────────────────────────────────┐
│ 前端展示层(Website) │
│ Next.js 14 + CMS SDK + 动态渲染器 │
└──────────────────────────────┬──────────────────────────────┘
│ RESTful API
┌──────────────────────────────▼──────────────────────────────┐
│ CMS 服务层(Backend
│ Java 21 + Spring Boot WebFlux + PostgreSQL + Flyway │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ 内容模型 │ │ 内容项 │ │ 内容区域 │ │ 主题配置 │ │
│ │ 管理 │ │ 管理 │ │ 管理 │ │ 管理 │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ 媒体资源 │ │ 版本管理 │ │ 审计日志 │ │ 权限/SSO │ │
│ │ 管理 │ │ 与草稿 │ │ │ │ 集成 │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────┘ │
└──────────────────────────────┬──────────────────────────────┘
┌──────────────────────────────▼──────────────────────────────┐
│ 管理后台(Admin) │
│ React 18 + ProLayout + Zustand + Ant Design 5 │
│ (对齐 novalon-manage-system 架构规范) │
└─────────────────────────────────────────────────────────────┘
```
### 1.2 核心领域模型(源自 Broadleaf CMS 设计)
| 模型 | 表名 | 职责 | 对应 Broadleaf 概念 |
|------|------|------|-------------------|
| ContentModel | `cms_content_model` | 定义内容类型的 schema(字段、类型、校验) | ContentModel |
| ContentItem | `cms_content_item` | 实际的内容数据,基于 model 动态字段 | ContentItem |
| ContentZone | `cms_content_zone` | 页面中的可编辑区域定义 | ContentZone |
| ThemeConfig | `cms_theme_config` | 站点主题、设置、SEO 等配置 | ThemeField |
| MediaAsset | `cms_media_asset` | 媒体资源管理 | - |
| ContentVersion | `cms_content_version` | 内容版本与草稿 | - |
| AuditLog | `cms_audit_log` | 操作审计日志 | - |
---
## 二、文件结构设计
### 2.1 当前项目(novalon-website)新增文件
```
src/
├── lib/
│ └── cms/ # CMS 前端 SDK
│ ├── types.ts # 类型定义(ContentModel/ContentItem 等)
│ ├── client.ts # API 客户端封装
│ ├── renderer.ts # 内容渲染工具函数
│ └── index.ts # barrel 导出
├── components/
│ └── cms/ # CMS 渲染组件
│ ├── ContentRenderer.tsx # 动态内容渲染器
│ ├── SectionRenderer.tsx # Section 级渲染器(ContentZone
│ ├── FieldRenderer.tsx # 字段级渲染器
│ └── index.ts
└── app/
└── api/
└── cms/ # 前端 BFF 层(可选)
└── [...path]/route.ts
```
### 2.2 后端服务(novalon-cms,独立项目)
```
novalon-cms/
├── cms-gateway/ # API 网关模块
├── cms-common/ # 公共工具模块
├── cms-db/ # 数据访问层(实体 + Repository
├── cms-content/ # 内容管理模块(model/item/zone
├── cms-media/ # 媒体资源模块
├── cms-theme/ # 主题配置模块
├── cms-admin/ # 管理端 API
└── cms-sys/ # 系统管理(用户/权限/审计)
```
### 2.3 管理后台(novalon-manage-system 扩展)
```
src/
├── pages/
│ └── cms/
│ ├── content-model/ # 内容模型管理
│ ├── content-item/ # 内容项管理
│ ├── content-zone/ # 内容区域管理
│ ├── media/ # 媒体库
│ └── theme/ # 主题配置
├── stores/
│ └── cms.ts # CMS 状态管理
└── services/
└── cms.ts # CMS API 服务
```
---
## 三、阶段划分与里程碑
### 阶段一:前端 SDK + 动态渲染(当前项目,立即启动)
**目标:** 在当前 Next.js 项目中建立 CMS 接入层,定义完整的类型系统和渲染架构,为后端 API 开发提供契约。
**交付物:**
- CMS 类型定义系统
- API Client SDK(带 mock 数据支持)
- 动态 Section 渲染器
- 案例模块迁移试点(从 constants → CMS 数据结构)
### 阶段二:后端核心服务(Java 团队并行)
**目标:** 实现 CMS 核心数据模型和 CRUD API。
**交付物:**
- 数据库表结构 + Flyway 迁移脚本
- ContentModel CRUD API
- ContentItem CRUD API + 版本管理
- ContentZone API
- 权限集成 + 审计日志
### 阶段三:管理后台开发
**目标:** 在 novalon-manage-system 中扩展 CMS 管理模块。
**交付物:**
- 内容模型可视化编辑器
- 内容项编辑器(动态表单)
- 媒体资源管理
- 主题配置面板
### 阶段四:全链路联调 + 内容迁移
**目标:** 前后端打通,完成所有内容模块迁移。
**交付物:**
- 全模块 CMS 接入
- 内容迁移脚本
- ISR/SSG 缓存策略
- 上线
---
## 四、详细任务清单
### 任务 1:CMS 类型系统定义
**文件:**
- 创建:`src/lib/cms/types.ts`
- 创建:`src/lib/cms/index.ts`
**内容:** 定义以下核心类型
```typescript
// 字段类型枚举
export type FieldType =
| 'text' // 单行文本
| 'textarea' // 多行文本
| 'richtext' // 富文本
| 'number' // 数字
| 'boolean' // 布尔
| 'date' // 日期
| 'datetime' // 日期时间
| 'image' // 图片
| 'media' // 媒体资源
| 'reference' // 引用其他内容项
| 'references' // 引用多个内容项
| 'json' // JSON 结构
| 'array' // 数组
| 'object'; // 嵌套对象
// 字段定义
export interface FieldDefinition {
name: string;
type: FieldType;
label: string;
required?: boolean;
description?: string;
placeholder?: string;
defaultValue?: unknown;
validation?: {
min?: number;
max?: number;
pattern?: string;
custom?: string;
};
options?: Array<{ label: string; value: string | number | boolean }>;
referenceModel?: string; // reference 类型关联的 model code
ui?: {
component?: string; // 指定 UI 组件
width?: 'full' | 'half' | 'third';
helpText?: string;
};
fields?: FieldDefinition[]; // object/array 类型的嵌套字段
}
// 内容模型
export interface ContentModel {
id: string;
code: string; // 唯一标识,如 'case-study'
name: string;
description?: string;
fields: FieldDefinition[];
isPageType: boolean; // 是否为页面类型(支持 URL 路由)
urlPattern?: string; // URL 模式,如 '/cases/{slug}'
hasVersions: boolean; // 是否启用版本管理
hasDraft: boolean; // 是否启用草稿
icon?: string;
createdAt: string;
updatedAt: string;
}
// 内容状态
export type ContentStatus = 'draft' | 'review' | 'published' | 'archived';
// 内容项
export interface ContentItem {
id: string;
modelId: string;
modelCode: string;
title: string;
slug?: string;
status: ContentStatus;
data: Record<string, unknown>; // 动态字段数据,结构由 model 定义
version: number;
publishedAt?: string;
createdBy: string;
updatedBy: string;
createdAt: string;
updatedAt: string;
}
// 内容区域
export interface ContentZone {
id: string;
code: string; // 区域唯一标识,如 'home-hero'
name: string;
description?: string;
pageCode?: string; // 所属页面
allowedModels: string[]; // 允许的内容模型 codes
items: Array<{
itemId: string;
item?: ContentItem;
sortOrder: number;
config?: Record<string, unknown>; // 区域级配置
}>;
}
// 主题配置
export interface ThemeConfig {
id: string;
siteName: string;
siteDescription: string;
logo?: string;
favicon?: string;
colors: {
primary: string;
secondary: string;
accent: string;
background: string;
text: string;
};
seo: {
defaultTitle: string;
defaultDescription: string;
defaultKeywords: string;
ogImage?: string;
};
social: {
wechat?: string;
weibo?: string;
linkedin?: string;
github?: string;
};
settings: Record<string, unknown>; // 其他自定义设置
}
// 分页查询参数
export interface ContentQueryParams {
modelCode: string;
status?: ContentStatus;
page?: number;
pageSize?: number;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
filters?: Record<string, string | number | boolean>;
search?: string;
}
// 分页结果
export interface PaginatedResult<T> {
items: T[];
total: number;
page: number;
pageSize: number;
totalPages: number;
}
```
---
### 任务 2CMS API Client SDK
**文件:**
- 创建:`src/lib/cms/client.ts`
- 修改:`src/lib/cms/index.ts`
**内容:** 封装 CMS API 客户端,支持真实 API 和 mock 模式
```typescript
// 配置
interface CmsClientConfig {
baseUrl: string;
apiKey?: string;
timeout?: number;
mockMode?: boolean; // 开发阶段使用 mock 数据
}
// 客户端类
class CmsClient {
constructor(config: CmsClientConfig) {}
// 内容模型相关
async getModels(): Promise<ContentModel[]> {}
async getModel(code: string): Promise<ContentModel> {}
// 内容项相关
async getItems(params: ContentQueryParams): Promise<PaginatedResult<ContentItem>> {}
async getItem(id: string): Promise<ContentItem> {}
async getItemBySlug(modelCode: string, slug: string): Promise<ContentItem> {}
// 内容区域相关
async getZone(code: string): Promise<ContentZone> {}
async getZonesByPage(pageCode: string): Promise<ContentZone[]> {}
// 主题配置相关
async getThemeConfig(): Promise<ThemeConfig> {}
// 工具方法
async withType<T extends Record<string, unknown>>(
item: ContentItem
): Promise<T> {}
}
```
---
### 任务 3:动态 Section 渲染器(ContentZone 实现)
**文件:**
- 创建:`src/components/cms/SectionRenderer.tsx`
- 创建:`src/components/cms/FieldRenderer.tsx`
- 创建:`src/components/cms/ContentRenderer.tsx`
- 创建:`src/components/cms/index.ts`
**核心设计思想:**
- ContentZone = 页面上的一个可编辑区域
- 每个 Zone 包含多个 ContentItem
- 每个 ContentItem 根据其 model type 选择对应的渲染组件
```typescript
// 组件注册表
interface SectionComponentRegistry {
[modelCode: string]: React.ComponentType<{ data: any; config?: any }>;
}
// SectionRenderer: 渲染单个 ContentZone
function SectionRenderer({ zoneCode, fallback }: {
zoneCode: string;
fallback?: React.ReactNode;
}) {}
// ContentRenderer: 渲染单个 ContentItem
function ContentRenderer({ item }: { item: ContentItem }) {}
// FieldRenderer: 渲染单个字段
function FieldRenderer({
field, value
}: {
field: FieldDefinition;
value: unknown;
}) {}
```
---
### 任务 4:案例模块迁移试点
**目标:** 将现有的案例数据从 `constants/cases.ts` 迁移为 CMS 数据结构,验证类型系统和渲染器的正确性。
**文件:**
- 修改:`src/lib/cms/mock-data.ts`(新建 mock 数据)
- 修改:`src/app/(marketing)/cases/cases-content-v1.tsx`
- 修改:`src/app/(marketing)/cases/[slug]/client.tsx`
**迁移内容:**
- 定义 `case-study` 内容模型(对应 CaseStudy 接口)
- 将 6 个案例转为 ContentItem 格式
- 列表页和详情页改为从 CMS Client 获取数据
- 保留 mock 模式,后端 API 完成后无缝切换
---
### 任务 5:后端 API 接口契约
**文件:**
- 创建:`docs/cms/api-contract.md`
**核心 API 列表:**
| 模块 | Method | Path | 说明 |
|------|--------|------|------|
| 内容模型 | GET | `/api/cms/models` | 获取所有内容模型 |
| 内容模型 | GET | `/api/cms/models/{code}` | 获取单个模型定义 |
| 内容模型 | POST | `/api/cms/models` | 创建内容模型 |
| 内容模型 | PUT | `/api/cms/models/{code}` | 更新内容模型 |
| 内容项 | GET | `/api/cms/items` | 分页查询内容项 |
| 内容项 | GET | `/api/cms/items/{id}` | 获取内容项详情 |
| 内容项 | GET | `/api/cms/items/slug/{modelCode}/{slug}` | 按 slug 获取 |
| 内容项 | POST | `/api/cms/items` | 创建内容项 |
| 内容项 | PUT | `/api/cms/items/{id}` | 更新内容项 |
| 内容项 | POST | `/api/cms/items/{id}/publish` | 发布内容 |
| 内容项 | POST | `/api/cms/items/{id}/unpublish` | 下架内容 |
| 内容区域 | GET | `/api/cms/zones/{code}` | 获取区域内容 |
| 内容区域 | PUT | `/api/cms/zones/{code}` | 更新区域配置 |
| 主题配置 | GET | `/api/cms/theme` | 获取主题配置 |
| 主题配置 | PUT | `/api/cms/theme` | 更新主题配置 |
| 媒体资源 | GET | `/api/cms/media` | 媒体列表 |
| 媒体资源 | POST | `/api/cms/media/upload` | 上传媒体 |
---
## 五、数据模型详细设计
### 5.1 cms_content_model(内容模型表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键 |
| code | varchar(100) UNIQUE | 模型唯一编码 |
| name | varchar(200) | 模型名称 |
| description | varchar(500) | 描述 |
| fields_json | jsonb | 字段定义 JSON |
| is_page_type | boolean | 是否为页面类型 |
| url_pattern | varchar(200) | URL 模式 |
| has_versions | boolean | 是否启用版本 |
| has_draft | boolean | 是否启用草稿 |
| icon | varchar(50) | 图标 |
| created_by | varchar(100) | 创建人 |
| updated_by | varchar(100) | 更新人 |
| created_at | timestamp | 创建时间 |
| updated_at | timestamp | 更新时间 |
| deleted | boolean | 逻辑删除 |
### 5.2 cms_content_item(内容项表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键 |
| model_id | bigint FK | 关联模型 ID |
| model_code | varchar(100) | 冗余模型编码 |
| title | varchar(500) | 内容标题 |
| slug | varchar(200) | URL slug |
| status | varchar(20) | 状态:draft/review/published/archived |
| data_json | jsonb | 内容数据 JSON |
| version | int | 当前版本号 |
| published_at | timestamp | 发布时间 |
| created_by | varchar(100) | 创建人 |
| updated_by | varchar(100) | 更新人 |
| created_at | timestamp | 创建时间 |
| updated_at | timestamp | 更新时间 |
| deleted | boolean | 逻辑删除 |
索引:`(model_code, status, created_at)``(model_code, slug)` 唯一索引
### 5.3 cms_content_version(内容版本表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键 |
| item_id | bigint FK | 内容项 ID |
| version | int | 版本号 |
| data_json | jsonb | 版本数据快照 |
| status | varchar(20) | 版本状态 |
| change_log | varchar(500) | 变更说明 |
| created_by | varchar(100) | 创建人 |
| created_at | timestamp | 创建时间 |
### 5.4 cms_content_zone(内容区域表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键 |
| code | varchar(100) UNIQUE | 区域编码 |
| name | varchar(200) | 区域名称 |
| description | varchar(500) | 描述 |
| page_code | varchar(100) | 所属页面 |
| allowed_models | varchar(500) | 允许的模型 codes(逗号分隔) |
| items_json | jsonb | 区域内内容项配置(顺序、附加配置) |
| created_at | timestamp | 创建时间 |
| updated_at | timestamp | 更新时间 |
### 5.5 cms_theme_config(主题配置表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键(单表单记录,id=1) |
| config_json | jsonb | 完整配置 JSON |
| updated_by | varchar(100) | 更新人 |
| updated_at | timestamp | 更新时间 |
### 5.6 cms_media_asset(媒体资源表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键 |
| name | varchar(200) | 文件名称 |
| path | varchar(500) | 存储路径 |
| url | varchar(500) | 访问 URL |
| mime_type | varchar(100) | MIME 类型 |
| size | bigint | 文件大小(字节) |
| width | int | 图片宽度 |
| height | int | 图片高度 |
| alt | varchar(200) | 替代文本 |
| storage_type | varchar(20) | 存储类型:local/oss/s3 |
| created_by | varchar(100) | 创建人 |
| created_at | timestamp | 创建时间 |
### 5.7 cms_audit_log(审计日志表)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | bigint PK | 主键 |
| module | varchar(50) | 模块:model/item/zone/theme/media |
| target_id | bigint | 操作对象 ID |
| action | varchar(50) | 操作:create/update/delete/publish/unpublish |
| operator | varchar(100) | 操作人 |
| before_json | jsonb | 操作前数据 |
| after_json | jsonb | 操作后数据 |
| ip | varchar(50) | IP 地址 |
| user_agent | varchar(500) | User Agent |
| created_at | timestamp | 操作时间 |
---
## 六、安全与权限设计
### 6.1 权限模型
| 角色 | 权限说明 |
|------|----------|
| 超级管理员 | 所有权限 |
| CMS 管理员 | 内容模型管理、内容管理、用户管理 |
| 内容编辑 | 内容创建、编辑、提交审核 |
| 内容审核 | 内容审核、发布、下架 |
| 访客 | 仅查看(前端 API) |
### 6.2 API 安全
- 管理端 API:走现有 SSO + 权限体系
- 前端 API:仅读取 published 状态内容,无需鉴权(或 API Key 限流)
- 敏感操作:写入操作必须有审计日志
- 数据隔离:按业务线/租户隔离(预留)
---
## 七、性能优化策略
### 7.1 前端侧
- **ISR/SSG**:内容页使用 Next.js ISR,内容变更时触发 revalidate
- **缓存策略**
- 内容列表:10 分钟缓存 + stale-while-revalidate
- 内容详情:1 小时缓存,发布时主动失效
- 主题配置:构建时注入,运行时热更新
- **图片优化**:使用 Next.js Image + CDN 加速
### 7.2 后端侧
- **数据库索引**:按查询模式建立合理索引
- **Redis 缓存**:热点内容数据缓存
- **读写分离**:读操作走从库
- **CDN 加速**:媒体资源走 CDN
---
## 八、与现有系统的集成
### 8.1 用户/权限集成
- 复用 novalon-manage-system 的用户体系和权限框架
- SSO 单点登录
- 统一的角色/权限管理界面
### 8.2 审计集成
- 接入现有审计日志系统
- CMS 操作日志同步到统一审计平台
### 8.3 监控集成
- 接入现有监控体系(Prometheus + Grafana
- 关键指标:API 响应时间、错误率、内容发布量
---
## 九、风险与应对
| 风险 | 概率 | 影响 | 应对策略 |
|------|------|------|----------|
| 动态字段查询性能 | 中 | 高 | 合理设计索引,必要时引入 ES 做全文检索 |
| 富文本编辑器选型 | 低 | 中 | 预研 Tiptap/Lexical,留接口抽象层可替换 |
| 内容迁移成本 | 中 | 中 | 开发迁移脚本,分批迁移,先迁移更新频繁的模块 |
| 管理后台开发量 | 高 | 中 | 优先开发核心功能,可视化编辑器可后置,先用动态表单 |
---
## 十、里程碑验收标准
### 阶段一验收(前端 SDK
- [ ] 完整的 TypeScript 类型定义
- [ ] CMS Client SDKmock 模式可用)
- [ ] 动态 Section 渲染器(支持 3 种以上内容类型)
- [ ] 案例模块试点完成(列表 + 详情)
- [ ] 单元测试覆盖率 ≥ 80%
### 阶段二验收(后端核心)
- [ ] 7 张核心表 + Flyway 迁移脚本
- [ ] 30+ 个 RESTful API
- [ ] 内容版本管理(草稿/发布/回滚)
- [ ] 审计日志完整
- [ ] 权限集成完成
- [ ] API 单元测试覆盖率 ≥ 80%
### 阶段三验收(管理后台)
- [ ] 内容模型可视化编辑器
- [ ] 动态表单内容编辑器
- [ ] 媒体资源管理(上传/列表/删除)
- [ ] 主题配置面板
- [ ] 操作审计日志查看
### 阶段四验收(全链路)
- [ ] 所有内容模块迁移完成(案例/新闻/产品/解决方案/服务)
- [ ] 前后端联调通过
- [ ] 性能达标(LCP < 2s
- [ ] 安全扫描通过
- [ ] 内容迁移脚本验证通过
@@ -0,0 +1,662 @@
# Bain 品牌清晰度升级(方案 B 中度 Bain 化)实现计划
> **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。
**目标:** 将首页 Bain 化升级——答案优先 Hero + 结论化标题 + 成果前置案例 + 精准品牌红 + 留白节奏校准
**架构:** 基于 `home-content-v11.tsx` 创建 v12 版本,按 5 大任务逐步改造,最后切换首页入口到 v12。不改动 CMS 版本(后续再同步)。
**技术栈:** React 18 + TypeScript + Tailwind CSS + Framer Motion
**起点文件:** `src/app/(marketing)/home-content-v11.tsx`
**终点文件:** `src/app/(marketing)/home-content-v12.tsx`
**入口切换:** `src/app/(marketing)/page.tsx`
---
## 文件清单
| 文件 | 操作 | 职责 |
|------|------|------|
| `src/app/(marketing)/home-content-v12.tsx` | 新建(从 v11 复制) | Bain 化升级后的首页主文件 |
| `src/app/(marketing)/page.tsx` | 修改 | 切换入口从 CMS → v12 |
---
## 任务 1:复制 v11 为 v12 基础版本
**文件:**
- 创建:`src/app/(marketing)/home-content-v12.tsx`(从 v11 复制)
- [ ] **步骤 1:复制 v11 为 v12**
```bash
cp src/app/(marketing)/home-content-v11.tsx src/app/(marketing)/home-content-v12.tsx
```
- [ ] **步骤 2:验证文件存在且可编译**
```bash
npx tsc --noEmit src/app/(marketing)/home-content-v12.tsx
```
预期:无类型错误(与 v11 一致)
- [ ] **步骤 3Commit**
```bash
git add src/app/(marketing)/home-content-v12.tsx
git commit -m "feat: copy home-content-v11 as base for v12 bain upgrade"
```
---
## 任务 2:Hero 区 Bain 化重构(答案优先)
**文件:**
- 修改:`src/app/(marketing)/home-content-v12.tsx``HeroSection` 函数
### 2.1 标题改造
- [ ] **步骤 1:修改主标题文案**
将 HeroSection 内的 h1 标题从:
```tsx
<div className="block"></div>
<div className="block mt-5">
<span></span>
<span className="relative inline-block ml-4">
<span className="relative text-brand font-extrabold">
<motion.span ... />
</span>
</span>
</div>
```
改为:
```tsx
<div className="block"></div>
<div className="block mt-5">
<span className="relative inline-block">
<span className="relative text-brand font-extrabold">
3
<motion.span
className="absolute -bottom-3 left-0 w-full h-[3px] bg-brand"
style={{ transformOrigin: 'left' }}
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ duration: 0.9, delay: 1.3, ease: EASE_OUT }}
/>
</span>
</span>
</div>
```
- [ ] **步骤 2:副标题改为战略性提问**
将 p 副标题从:
```tsx
```
改为:
```tsx
```
并添加 `italic``opacity-60` 类(保持现有 text-dark-text-secondary,额外降低对比度)。
### 2.2 增加快速信任锚点行
- [ ] **步骤 3:在标题和 CTA 之间增加信任锚点行**
在 subtitle 的 `<motion.p>` 之后、CTA 的 `<motion.div>` 之前,插入:
```tsx
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.4, ease: EASE_OUT }}
className="flex flex-wrap gap-x-8 gap-y-2 mb-10 sm:mb-12 md:mb-16"
>
<span className="text-sm sm:text-base font-medium text-dark-text-secondary">
<span className="text-brand font-bold">500+</span>
</span>
<span className="text-sm sm:text-base font-medium text-dark-text-secondary">
<span className="text-brand font-bold">2.8x</span> ROI
</span>
<span className="text-sm sm:text-base font-medium text-dark-text-secondary">
<span className="text-brand font-bold">40%</span>
</span>
</motion.div>
```
### 2.3 布局改造:去掉右侧卡片,底部增加数据条
- [ ] **步骤 4:移除右侧 12 年卡片(lg:col-span-3 的那栏)**
删除 grid 内第二个 `<motion.div>`(从 `className="hidden lg:block lg:col-span-3"` 开始的整块),并将第一栏从 `lg:col-span-9` 改为 `lg:col-span-8`
- [ ] **步骤 5:在 CTA 按钮下方增加底部数据条**
在 CTA 按钮的 `<motion.div>` 之后、grid 关闭之前,插入底部数据条:
```tsx
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1, delay: 0.85, ease: EASE_OUT }}
className="mt-16 sm:mt-20 md:mt-24 pt-10 border-t border-white/10"
>
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 md:gap-10">
{[
{ value: '12', suffix: '年', label: '行业深耕', sub: '经验沉淀', highlight: true },
{ value: '500', suffix: '+', label: '企业客户', sub: '累计服务' },
{ value: '98', suffix: '%', label: '客户续约', sub: '年度续约率' },
{ value: '6', suffix: '款', label: '自研产品', sub: '全链路覆盖' },
].map((item, i) => (
<div key={i}>
<div className="text-3xl sm:text-4xl font-bold tracking-tight mb-2">
<span className={item.highlight ? 'text-brand' : 'text-white'}>{item.value}</span>
<span className={item.highlight ? 'text-brand font-bold' : 'text-white font-bold'}>{item.suffix}</span>
</div>
<div className="text-white font-semibold text-sm mb-0.5">{item.label}</div>
<div className="text-xs text-dark-text-muted">{item.sub}</div>
</div>
))}
</div>
</motion.div>
```
### 2.4 调整 Hero 垂直留白
- [ ] **步骤 6:增加 Hero 垂直内边距**
将内容容器的 `py-28 sm:py-36 md:py-44 lg:py-56` 改为 `py-32 sm:py-40 md:py-48 lg:py-60`(增加约 15-20%)。
- [ ] **步骤 7:验证 Hero 编译通过**
```bash
npx tsc --noEmit src/app/(marketing)/home-content-v12.tsx
```
预期:0 errors
- [ ] **步骤 8Commit**
```bash
git add src/app/(marketing)/home-content-v12.tsx
git commit -m "feat(home-v12): hero bain-style重构 - 答案优先+量化结论+底部数据条"
```
---
## 任务 3:Section 标题结论化 + 留白节奏校准
**文件:**
- 修改:`src/app/(marketing)/home-content-v12.tsx` 的所有 Section 标题
### 3.1 StatsSection 标题
- [ ] **步骤 1:修改 Stats 标题**
将 StatsSection 内的 h2 从:
```tsx
<br />
```
改为:
```tsx
12 <br />500+
```
### 3.2 ServicesSection 标题
- [ ] **步骤 2:修改 Services 标题**
将 ServicesSection 内的 h2 从:
```tsx
```
改为:
```tsx
```
### 3.3 IndustriesSection 标题
- [ ] **步骤 3:修改 Industries 标题**
将 IndustriesSection 内的 h2 从:
```tsx
<br />
```
改为:
```tsx
6 <br />
```
### 3.4 CasesSection 标题
- [ ] **步骤 4:修改 Cases 标题**
将 CasesSection 内的 h2 从:
```tsx
```
改为:
```tsx
```
### 3.5 ApproachSection 标题
- [ ] **步骤 5:修改 Approach 标题**
将 ApproachSection 内的 h2 从:
```tsx
<br />
```
改为:
```tsx
500+
```
### 3.6 InsightsSection 标题
- [ ] **步骤 6:修改 Insights 标题**
将 InsightsSection 内的 h2 从:
```tsx
```
改为:
```tsx
```
### 3.7 CTASection 标题
- [ ] **步骤 7:修改 CTA 标题**
将 CTASection 内的 h2 从:
```tsx
<br />
<span ...></span>
```
改为:
```tsx
<br />
<span ...></span>
```
(保持 SVG 下划线装饰,只改文字内容)
### 3.8 留白节奏校准
- [ ] **步骤 8:调整所有 Section 的垂直间距**
按梯度调整 py 值:
- Hero / CTA:最大留白 → `py-32 sm:py-40 md:py-52 lg:py-60`
- Stats / Cases:中等留白 → `py-28 sm:py-36 md:py-44 lg:py-52`
- Services / Industries / Approach / Insights:标准留白 → `py-24 sm:py-32 md:py-40 lg:py-48`
- [ ] **步骤 9:调整标题区与内容区的间距**
将各 Section 标题与内容的间距(mb-16/mb-20/mb-28)整体增加约 20%
- `mb-16``mb-20`
- `mb-20``mb-24`
- `mb-28``mb-32`
- [ ] **步骤 10:验证编译通过**
```bash
npx tsc --noEmit src/app/(marketing)/home-content-v12.tsx
```
预期:0 errors
- [ ] **步骤 11Commit**
```bash
git add src/app/(marketing)/home-content-v12.tsx
git commit -m "feat(home-v12): section标题结论化 + 留白节奏校准"
```
---
## 任务 4:案例模块成果前置(Bain 式数据冲击力)
**文件:**
- 修改:`src/app/(marketing)/home-content-v12.tsx``CasesSection`
### 4.1 案例卡片布局翻转
- [ ] **步骤 1:重写案例卡片结构——成果前置**
将 CasesSection 内每个 case 的 grid 结构从"左文右数"改为"顶数下文"
原结构(5 列 grid,左 3 右 2):
```tsx
<div className="grid lg:grid-cols-5 gap-0">
<div className="lg:col-span-3 p-14 lg:p-20 ...">
... // + ...
</div>
<div className="lg:col-span-2 p-14 lg:p-20 ...">
... Key Results ...
</div>
</div>
```
改为(单列,顶部成果数字,下方内容):
```tsx
<div className="p-10 sm:p-14 lg:p-16">
{/* 顶部:成果数字横跨全宽 */}
<div className="mb-12 pb-12 border-b border-white/10">
<div className="text-[11px] text-dark-text-muted mb-8 tracking-[0.25em] uppercase font-bold">
Key Results
</div>
<div className="grid grid-cols-3 gap-6 md:gap-10">
{caseItem.metrics.map((metric, j) => (
<div key={j}>
<motion.div
className="text-5xl lg:text-7xl font-bold mb-3 tracking-tight"
whileInView={{ x: 0, opacity: 1 }}
initial={{ x: -20, opacity: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.15 + j * 0.1, ease: EASE_OUT }}
>
<span className={j === 0 ? 'text-brand' : 'text-white'}>{metric.value}</span>
</motion.div>
<div className="flex items-center gap-3">
<div className={cn('w-10 h-px', j === 0 ? 'bg-brand' : 'bg-white/20')} />
<div className="text-sm text-dark-text-secondary font-medium">{metric.label}</div>
</div>
</div>
))}
</div>
</div>
{/* 中部:标签 + 标题 */}
<div className="flex items-center gap-5 mb-8">
<Badge className={cn(caseItem.bgClass, 'text-white border-transparent')}>
{caseItem.industry}
</Badge>
<span className="text-[11px] text-dark-text-muted tracking-wide font-semibold">
CASE #{String(i + 1).padStart(2, '0')}
</span>
</div>
<h3 className={cn(
'text-2xl lg:text-3xl font-bold mb-10 leading-tight transition-colors duration-400',
'text-white group-hover:text-brand'
)}>
{caseItem.title}
</h3>
{/* 下部:成果要点 + 方案要点 + 挑战要点 */}
<div className="space-y-8 mb-12">
{/* 成果 */}
<div>
<div className="flex items-center gap-3 mb-4">
<CheckCircle2 className={cn('w-4 h-4', caseItem.colorClass)} />
<span className={cn('text-sm font-bold', caseItem.colorClass)}></span>
</div>
<ul className="space-y-2.5 pl-7">
<li className="text-dark-text-secondary leading-relaxed text-sm">
线 {caseItem.industry === '智能制造' ? '< 48 小时' : '< 1 周'}
</li>
<li className="text-dark-text-secondary leading-relaxed text-sm">
{caseItem.metrics[0]?.label} {caseItem.metrics[0]?.value}
</li>
<li className="text-dark-text-secondary leading-relaxed text-sm">
{caseItem.metrics[1]?.label} {caseItem.metrics[1]?.value}
</li>
</ul>
</div>
{/* 方案 */}
<div>
<div className="flex items-center gap-3 mb-4">
<Zap className={cn('w-4 h-4', caseItem.colorClass)} />
<span className={cn('text-sm font-bold', caseItem.colorClass)}></span>
</div>
<ul className="space-y-2.5 pl-7">
<li className="text-dark-text-secondary leading-relaxed text-sm">
{caseItem.solution.split('。')[0]}
</li>
<li className="text-dark-text-secondary leading-relaxed text-sm">
{caseItem.solution.split('。')[1] || '行业最佳实践 + 企业定制化结合'}
</li>
</ul>
</div>
{/* 挑战 */}
<div>
<div className="flex items-center gap-3 mb-4">
<Target className={cn('w-4 h-4', caseItem.colorClass)} />
<span className={cn('text-sm font-bold', caseItem.colorClass)}></span>
</div>
<ul className="space-y-2.5 pl-7">
<li className="text-dark-text-secondary leading-relaxed text-sm">
{caseItem.challenge.split('')[0]}
</li>
<li className="text-dark-text-secondary leading-relaxed text-sm">
{caseItem.challenge.split('')[1] || '决策效率低下'}
</li>
</ul>
</div>
</div>
{/* 底部:客户证言 */}
<div className="flex items-start gap-5 pt-8 border-t border-white/10">
<Quote className={cn('w-8 h-8 shrink-0 mt-0.5 opacity-40', caseItem.colorClass)} />
<div>
<p className="text-dark-text-secondary italic leading-relaxed mb-4 text-sm">
&ldquo;{caseItem.quote}&rdquo;
</p>
<p className="text-xs text-dark-text-muted">
{caseItem.author}{caseItem.author}
</p>
</div>
</div>
</div>
```
注意:需要从 lucide-react 额外导入 `CheckCircle2, Zap, Target`(如果未导入的话)。
### 4.2 卡片顶部色条保留
- [ ] **步骤 2:保留卡片顶部 hover 色条**
将原有的顶部色条 `div``absolute top-0 left-0 w-full h-1 scale-x-0 group-hover:scale-x-100`)保留在新结构的最外层容器顶部。
- [ ] **步骤 3:验证编译通过**
```bash
npx tsc --noEmit src/app/(marketing)/home-content-v12.tsx
```
预期:0 errors
- [ ] **步骤 4Commit**
```bash
git add src/app/(marketing)/home-content-v12.tsx
git commit -m "feat(home-v12): 案例模块成果前置 + 要点式内容结构"
```
---
## 任务 5:品牌红精准贯穿(朱砂点睛 2.0)
**文件:**
- 修改:`src/app/(marketing)/home-content-v12.tsx`
### 5.1 减少服务卡片的品牌红
- [ ] **步骤 1:服务卡片左侧 hover 色条改为白色**
将 ServicesSection 内服务卡片的左侧色条(`w-1 scale-y-0 group-hover:scale-y-100`)的颜色从品牌色改为 `bg-white/20`hover 时 `bg-white/40`),移除动态颜色计算。
- [ ] **步骤 2:服务卡片"了解详情"link 文字改为白色,hover 才出红**
将服务卡片底部 `了解详情` 链接的颜色从 `service.colorClass` 改为 `text-white/70`,并添加 `group-hover:text-brand` 的 hover 效果。
### 5.2 减少行业卡片的品牌红
- [ ] **步骤 3:行业卡片图标统一白色,移除彩色**
将 IndustriesSection 内行业卡片的图标颜色类(`ind.colorClass`)统一改为 `text-white/80`,移除彩色图标。将 Badge 的颜色也统一为白色边框样式。
### 5.3 减少交付方法的品牌红
- [ ] **步骤 4:Approach 步骤数字改为白色,hover 才出红**
将 ApproachSection 内步骤数字(`text-brand`)改为 `text-white/80`,并添加 `group-hover:text-brand` 过渡效果。连接线保持品牌红。
### 5.4 Stats 区品牌红精简
- [ ] **步骤 5:Stats 只保留第 1 个指标的后缀品牌红,其余白色**
将 StatItem 组件内的 suffix 品牌红逻辑改为:只有第一个(index 0)才用品牌红,其余用白色。或者更简单——传入一个 `highlight` prop 控制。
修改方案:在 STATS 数组里给第一项加 `highlight: true`,然后在 StatItem 里根据 `highlight` prop 决定 suffix 颜色。
### 5.5 验证首页品牌红 5 处清单
对照以下 5 处清单逐一验证:
- [ ] **步骤 6:验证 Hero 主标题关键词品牌红**
- [ ] **步骤 7:验证 Hero CTA 主按钮品牌红**
- [ ] **步骤 8:验证案例首个成果数字品牌红**
- [ ] **步骤 9:验证 Section Eyebrow 下划线品牌红**
- [ ] **步骤 10:验证 CTA 区主按钮 + 关键词品牌红**
- [ ] **步骤 11:验证编译通过**
```bash
npx tsc --noEmit src/app/(marketing)/home-content-v12.tsx
```
预期:0 errors
- [ ] **步骤 12Commit**
```bash
git add src/app/(marketing)/home-content-v12.tsx
git commit -m "feat(home-v12): 品牌红精准贯穿 - 朱砂点睛2.0,5处强记忆点"
```
---
## 任务 6:切换首页入口 + 全面验证
### 6.1 切换入口
- [ ] **步骤 1:修改 page.tsx 引入 v12**
`src/app/(marketing)/page.tsx` 从:
```tsx
import HomeContentCms from './home-content-cms';
export default function HomePage() {
return <HomeContentCms />;
}
```
改为:
```tsx
import HomeContentV12 from './home-content-v12';
export default function HomePage() {
return <HomeContentV12 />;
}
```
### 6.2 类型检查与构建
- [ ] **步骤 2TypeScript 全量类型检查**
```bash
npx tsc --noEmit
```
预期:0 errors
- [ ] **步骤 3ESLint 检查**
```bash
npm run lint
```
预期:0 errors
- [ ] **步骤 4:生产构建**
```bash
npm run build
```
预期:构建成功,无 error
### 6.3 启动开发服务器验证
- [ ] **步骤 5:启动开发服务器**
```bash
npm run dev
```
(非阻塞,等待 3 秒后检查状态)
- [ ] **步骤 6:用浏览器验证首页效果**
打开 http://localhost:3000,检查:
- Hero 标题是否为"数字化转型 成功率提升 3 倍"
- 快速信任锚点行是否显示(500+企业验证 · 2.8x平均ROI · 40%交付周期缩短)
- 底部数据条 4 个指标是否显示
- 各 Section 标题是否已结论化
- 案例模块成果是否前置(顶部数字)
- 品牌红使用是否克制(约 5 处强记忆点)
### 6.4 Commit 切换
- [ ] **步骤 7Commit 入口切换**
```bash
git add src/app/(marketing)/page.tsx
git commit -m "feat: 切换首页入口到 v12 (Bain品牌清晰度升级)"
```
---
## 验收检查清单
### 功能验收
- [ ] 首页首屏 3 秒内能看懂核心价值(量化结论 + 信任锚点)
- [ ] 所有 Section 标题为结论型表述(非描述/分类)
- [ ] 案例模块成果前置,第一眼看到核心数字
- [ ] 首页品牌红触达点 ≈ 5 处,视觉面积 ≤ 5%
- [ ] Hero、CTA 区域留白比例符合 Bain 式极简美学
### 技术验收
- [ ] TypeScript 类型检查通过(0 errors
- [ ] ESLint 检查通过(0 errors
- [ ] Next.js 生产构建成功,无报错
- [ ] 响应式布局正常(sm/md/lg/xl 四断点)
- [ ] 无新增性能问题(Lighthouse Performance ≥ 90 保持)
### 设计验收
- [ ] 品牌红使用符合"朱砂点睛 2.0"原则(少而精)
- [ ] 信息层级清晰,标题/正文/辅助对比强烈
- [ ] 留白有节奏感,不拥挤也不空洞
- [ ] 数据呈现方式专业、有说服力
- [ ] 整体 Bain 气质明显,但保留 Accenture 信息密度和 Porsche 品质感
---
## 回滚方案
如发现问题,可快速回滚:
```bash
git revert HEAD # 回滚入口切换 commit
```
或手动将 `page.tsx` 改回 CMS 版本。
---
## 后续迭代
- **方案 C(深度 Bain 化,可选)**:模块重排 + 极简大留白 + 纯排版驱动
- **CMS 同步**:将 v12 的 Bain 化设计同步到 CMS 版本的组件和 mock 数据中
- **内页推广**:将 Bain 化策略(结论化标题 + 答案优先 + 精准品牌红)推广到产品/方案/服务等内页