# Atlassian 风格品牌融合重构 实现计划 > **面向 AI 代理的工作者:** 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(`- [ ]`)语法来跟踪进度。 **目标:** 借鉴 Atlassian 信息架构,重构 Novalon 首页为"收敛但保留印记"的品牌融合风格,同步沉淀 6 个核心组件作为设计系统基础。 **架构:** 保持 Next.js 16 App Router + 静态导出架构不变。首页从单文件长滚动重构为 6 个独立 Section 组件 + 新导航组件。动效从粒子/水墨收敛为微交互。导航从 8 项平铺改为 4 核心 + 2 下拉。 **技术栈:** Next.js 16 + React 19 + Tailwind CSS 4 + Framer Motion 12 + Lucide React --- ## 整体架构图 ```mermaid graph TB subgraph "Phase 1: 首页重构 + 设计系统基础" T1[任务1: Design Token 更新] --> T2[任务2: 导航常量重构] T2 --> T3[任务3: MegaDropdown 组件] T3 --> T4[任务4: Header 重构] T4 --> T5[任务5: Hero Section 重构] T5 --> T6[任务6: StatsBar 组件] T6 --> T7[任务7: 社会证明 Section] T7 --> T8[任务8: ProductCard 组件] T8 --> T9[任务9: 产品矩阵 Section] T9 --> T10[任务10: ChallengeCard 组件] T10 --> T11[任务11: 挑战场景 Section] T11 --> T12[任务12: TestimonialBlock 组件] T12 --> T13[任务13: 客户成果 Section] T13 --> T14[任务14: CTASection 组件] T14 --> T15[任务15: CTA Section] T15 --> T16[任务16: 首页组装] T16 --> T17[任务17: 废弃动效清理] T17 --> T18[任务18: 集成测试与验证] end ``` ## 组件依赖图 ```mermaid graph LR subgraph "基础层" DT[Design Tokens
globals.css] NAV_CONST[Navigation Constants
navigation.ts] end subgraph "组件层" MD[MegaDropdown
mega-dropdown.tsx] PC[ProductCard
product-card.tsx] CC[ChallengeCard
challenge-card.tsx] SB[StatsBar
stats-bar.tsx] TB[TestimonialBlock
testimonial-block.tsx] CTA[CTASection
cta-section.tsx] end subgraph "Section 层" HDR[Header
header.tsx] HERO[HeroSection
hero-section.tsx] SOCIAL[SocialProofSection
social-proof-section.tsx] PROD[ProductMatrixSection
product-matrix-section.tsx] CHAL[ChallengeSection
challenge-section.tsx] TEST[TestimonialSection
testimonial-section.tsx] CTAS[CTASectionPage
cta-section-page.tsx] end subgraph "页面层" HOME[home-content.tsx] end DT --> MD & PC & CC & SB & TB & CTA NAV_CONST --> MD MD --> HDR PC --> PROD CC --> CHAL SB --> SOCIAL TB --> TEST CTA --> CTAS HDR & HERO & SOCIAL & PROD & CHAL & TEST & CTAS --> HOME ``` ## 数据流图 ```mermaid graph TD subgraph "数据源 (src/lib/constants/)" NAV[navigation.ts
NAVIGATION_V2] PRODS[products.ts
PRODUCTS] SOL[solutions.ts
SOLUTIONS] CASES[cases.ts
CASES] STATS[stats.ts
STATS] end NAV -->|导航项+下拉数据| HDR_COMP[Header] PRODS -->|4个产品| PROD_SEC[ProductMatrixSection] SOL -->|3个挑战场景| CHAL_SEC[ChallengeSection] CASES -->|testimonial+results| TEST_SEC[TestimonialSection] STATS -->|3个关键数据| SOCIAL_SEC[SocialProofSection] ``` ## 文件结构 ### 新建文件 | 文件 | 职责 | |------|------| | `src/components/layout/mega-dropdown.tsx` | 产品/解决方案矩阵下拉导航组件 | | `src/components/layout/mega-dropdown.test.tsx` | 下拉导航测试 | | `src/components/ui/product-card.tsx` | 朱砂红左边框产品卡片 | | `src/components/ui/product-card.test.tsx` | 产品卡片测试 | | `src/components/ui/challenge-card.tsx` | 痛点/场景入口卡片 | | `src/components/ui/challenge-card.test.tsx` | 场景卡片测试 | | `src/components/ui/stats-bar.tsx` | 三列数据统计条 | | `src/components/ui/stats-bar.test.tsx` | 统计条测试 | | `src/components/ui/testimonial-block.tsx` | 深色背景客户证言 | | `src/components/ui/testimonial-block.test.tsx` | 客户证言测试 | | `src/components/ui/cta-section.tsx` | 朱砂红渐变行动号召 | | `src/components/ui/cta-section.test.tsx` | CTA 测试 | | `src/components/sections/hero-section-v2.tsx` | 新 Hero Section | | `src/components/sections/hero-section-v2.test.tsx` | 新 Hero 测试 | | `src/components/sections/social-proof-section.tsx` | 社会证明 Section | | `src/components/sections/social-proof-section.test.tsx` | 社会证明测试 | | `src/components/sections/product-matrix-section.tsx` | 产品矩阵 Section | | `src/components/sections/product-matrix-section.test.tsx` | 产品矩阵测试 | | `src/components/sections/challenge-section.tsx` | 挑战场景 Section | | `src/components/sections/challenge-section.test.tsx` | 挑战场景测试 | | `src/components/sections/testimonial-section.tsx` | 客户成果 Section | | `src/components/sections/testimonial-section.test.tsx` | 客户成果测试 | | `src/components/sections/cta-section-page.tsx` | CTA Section | | `src/components/sections/cta-section-page.test.tsx` | CTA Section 测试 | ### 修改文件 | 文件 | 变更内容 | |------|---------| | `src/app/globals.css` | 新增场景色 Token、废弃动效相关 CSS | | `src/lib/constants/navigation.ts` | 新增 NAVIGATION_V2 常量 + MegaDropdown 数据结构 | | `src/lib/constants/stats.ts` | 新增 HOME_STATS 三列数据 | | `src/components/layout/header.tsx` | 集成 MegaDropdown,使用 NAVIGATION_V2 | | `src/app/(marketing)/home-content.tsx` | 替换为新 Section 组件 | | `src/components/sections/hero-section.tsx` | 保留旧版,新版本为 hero-section-v2.tsx | --- ## 任务 1:Design Token 更新 **文件:** - 修改:`src/app/globals.css` - [ ] **步骤 1:在 `:root` 中新增场景色变量** 在 `globals.css` 的 `:root` 块中,在 `/* 状态色 */` 注释之后添加: ```css /* 场景色 - 挑战卡片 */ --color-challenge-isolation: #FEF2F4; --color-challenge-isolation-hover: #FDE8EC; --color-challenge-growth: #FFFBEB; --color-challenge-growth-hover: #FEF3C7; --color-challenge-compliance: #F0FDF4; --color-challenge-compliance-hover: #DCFCE7; ``` - [ ] **步骤 2:验证 CSS 变量可用** 运行:`npx tsc --noEmit` 预期:无类型错误 - [ ] **步骤 3:Commit** ```bash git add src/app/globals.css git commit -m "feat: add challenge scenario color tokens to design system" ``` --- ## 任务 2:导航常量重构 **文件:** - 修改:`src/lib/constants/navigation.ts` - [ ] **步骤 1:编写失败的测试** 在 `src/lib/constants/navigation.test.ts`(新建)中: ```typescript import { describe, it, expect } from '@jest/globals'; import { NAVIGATION_V2, MEGA_DROPDOWN_DATA } from './navigation'; describe('NAVIGATION_V2', () => { it('has exactly 6 navigation items', () => { expect(NAVIGATION_V2).toHaveLength(6); }); it('contains product dropdown item', () => { const productItem = NAVIGATION_V2.find(item => item.id === 'products'); expect(productItem).toBeDefined(); expect(productItem?.hasDropdown).toBe(true); }); it('contains solutions dropdown item', () => { const solutionsItem = NAVIGATION_V2.find(item => item.id === 'solutions'); expect(solutionsItem).toBeDefined(); expect(solutionsItem?.hasDropdown).toBe(true); }); }); describe('MEGA_DROPDOWN_DATA', () => { it('has products dropdown with 4 items', () => { expect(MEGA_DROPDOWN_DATA.products).toHaveLength(4); }); it('has solutions dropdown with 4 items', () => { expect(MEGA_DROPDOWN_DATA.solutions).toHaveLength(4); }); it('each product has id, title, description, href', () => { MEGA_DROPDOWN_DATA.products.forEach(product => { expect(product).toHaveProperty('id'); expect(product).toHaveProperty('title'); expect(product).toHaveProperty('description'); expect(product).toHaveProperty('href'); }); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/lib/constants/navigation.test.ts --no-coverage` 预期:FAIL — `Cannot find module './navigation'` 或 `NAVIGATION_V2 is not exported` - [ ] **步骤 3:实现导航常量** 在 `src/lib/constants/navigation.ts` 中追加: ```typescript export interface NavigationItemV2 { id: string; label: string; href: string; hasDropdown?: boolean; dropdownKey?: string; } export interface MegaDropdownItem { id: string; title: string; description: string; href: string; } export interface MegaDropdownData { [key: string]: MegaDropdownItem[]; } export const NAVIGATION_V2: NavigationItemV2[] = [ { id: 'products', label: '产品', href: '/products', hasDropdown: true, dropdownKey: 'products' }, { id: 'solutions', label: '解决方案', href: '/solutions', hasDropdown: true, dropdownKey: 'solutions' }, { id: 'services', label: '服务', href: '/services' }, { id: 'cases', label: '案例', href: '/cases' }, { id: 'about', label: '关于我们', href: '/about' }, { id: 'contact', label: '联系我们', href: '/contact' }, ]; export const MEGA_DROPDOWN_DATA: MegaDropdownData = { products: [ { id: 'erp', title: 'ERP 管理系统', description: '财务·采购·销售·库存·生产', href: '/products/erp' }, { id: 'crm', title: 'CRM 客户管理', description: '线索·商机·合同·服务', href: '/products/crm' }, { id: 'bi', title: 'BI 数据平台', description: '报表·仪表盘·预测·决策', href: '/products/bi' }, { id: 'cms', title: 'CMS 内容平台', description: '建站·运营·分发·分析', href: '/products/cms' }, ], solutions: [ { id: 'manufacturing', title: '制造业', description: '智能制造·MES·质量管控', href: '/solutions/manufacturing' }, { id: 'retail', title: '零售业', description: '全渠道·会员·精准营销', href: '/solutions/retail' }, { id: 'education', title: '教育行业', description: '招生·教学·学情分析', href: '/solutions/education' }, { id: 'healthcare', title: '医疗健康', description: '临床·运营·患者服务', href: '/solutions/healthcare' }, ], }; ``` - [ ] **步骤 4:更新 index.ts 导出** 在 `src/lib/constants/index.ts` 中追加导出: ```typescript export { NAVIGATION_V2, MEGA_DROPDOWN_DATA } from './navigation'; export type { NavigationItemV2, MegaDropdownItem, MegaDropdownData } from './navigation'; ``` - [ ] **步骤 5:运行测试验证通过** 运行:`npx jest src/lib/constants/navigation.test.ts --no-coverage` 预期:PASS - [ ] **步骤 6:Commit** ```bash git add src/lib/constants/navigation.ts src/lib/constants/navigation.test.ts src/lib/constants/index.ts git commit -m "feat: add NAVIGATION_V2 and MEGA_DROPDOWN_DATA for mega dropdown navigation" ``` --- ## 任务 3:MegaDropdown 组件 **文件:** - 创建:`src/components/layout/mega-dropdown.tsx` - 创建:`src/components/layout/mega-dropdown.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx // src/components/layout/mega-dropdown.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import { describe, it, expect, vi } from 'vitest'; import { MegaDropdown } from './mega-dropdown'; import { MEGA_DROPDOWN_DATA } from '@/lib/constants'; describe('MegaDropdown', () => { it('renders trigger button with label', () => { render( ); expect(screen.getByText('产品')).toBeInTheDocument(); }); it('shows dropdown content when isOpen is true', () => { render( ); expect(screen.getByText('ERP 管理系统')).toBeInTheDocument(); }); it('hides dropdown content when isOpen is false', () => { render( ); expect(screen.queryByText('ERP 管理系统')).not.toBeInTheDocument(); }); it('calls onToggle when trigger is clicked', () => { const onToggle = vi.fn(); render( ); fireEvent.click(screen.getByText('产品')); expect(onToggle).toHaveBeenCalledTimes(1); }); it('renders each item with title, description and link', () => { render( ); MEGA_DROPDOWN_DATA.products.forEach(item => { expect(screen.getByText(item.title)).toBeInTheDocument(); expect(screen.getByText(item.description)).toBeInTheDocument(); }); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/layout/mega-dropdown.test.ts --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 MegaDropdown 组件** ```tsx // src/components/layout/mega-dropdown.tsx 'use client'; import { useRef, useEffect } from 'react'; import { ChevronDown } from 'lucide-react'; import { AnimatePresence, motion } from 'framer-motion'; import { StaticLink } from '@/components/ui/static-link'; import type { MegaDropdownItem } from '@/lib/constants'; interface MegaDropdownProps { label: string; items: MegaDropdownItem[]; isOpen: boolean; onToggle: () => void; } export function MegaDropdown({ label, items, isOpen, onToggle }: MegaDropdownProps) { const dropdownRef = useRef(null); useEffect(() => { function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { if (isOpen) { onToggle(); } } } document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [isOpen, onToggle]); return (
{isOpen && (
{items.map((item) => (
{item.title}
{item.description}
))}
)}
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/layout/mega-dropdown.test.ts --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/layout/mega-dropdown.tsx src/components/layout/mega-dropdown.test.tsx git commit -m "feat: add MegaDropdown component for product/solution matrix navigation" ``` --- ## 任务 4:Header 重构 **文件:** - 修改:`src/components/layout/header.tsx` - [ ] **步骤 1:编写失败的测试** 在 `src/components/layout/header.test.tsx` 中追加测试: ```tsx it('renders NAVIGATION_V2 items in desktop nav', () => { render(
); expect(screen.getByText('产品')).toBeInTheDocument(); expect(screen.getByText('解决方案')).toBeInTheDocument(); expect(screen.getByText('服务')).toBeInTheDocument(); expect(screen.getByText('案例')).toBeInTheDocument(); expect(screen.getByText('关于我们')).toBeInTheDocument(); expect(screen.getByText('联系我们')).toBeInTheDocument(); }); it('does not render old navigation items (核心业务, 新闻动态)', () => { render(
); expect(screen.queryByText('核心业务')).not.toBeInTheDocument(); expect(screen.queryByText('新闻动态')).not.toBeInTheDocument(); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/layout/header.test.tsx --no-coverage` 预期:FAIL — 新测试用例找不到"产品"等新导航项 - [ ] **步骤 3:重构 Header 组件** 在 `header.tsx` 中: 1. 将 `NAVIGATION` import 替换为 `NAVIGATION_V2, MEGA_DROPDOWN_DATA` 2. 将 `MegaDropdown` import 添加 3. 桌面导航渲染逻辑改为:遍历 `NAVIGATION_V2`,如果 `hasDropdown` 则渲染 `MegaDropdown`,否则渲染普通链接 4. 移除旧的 `NAVIGATION` 引用 5. 添加 `openDropdown` state 管理下拉开关 关键代码片段(替换桌面导航部分): ```tsx const [openDropdown, setOpenDropdown] = useState(null); // 在导航渲染中: {NAVIGATION_V2.map((item) => ( item.hasDropdown ? ( setOpenDropdown(openDropdown === item.id ? null : item.id)} /> ) : ( {item.label} ) ))} ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/layout/header.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/layout/header.tsx src/components/layout/header.test.tsx git commit -m "feat: refactor Header with NAVIGATION_V2 and MegaDropdown integration" ``` --- ## 任务 5:Hero Section 重构 **文件:** - 创建:`src/components/sections/hero-section-v2.tsx` - 创建:`src/components/sections/hero-section-v2.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx // src/components/sections/hero-section-v2.test.tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { HeroSectionV2 } from './hero-section-v2'; describe('HeroSectionV2', () => { it('renders brand tag NOVALON', () => { render(); expect(screen.getByText(/NOVALON/)).toBeInTheDocument(); }); it('renders main heading with calligraphy', () => { render(); const heading = screen.getByRole('heading', { level: 1 }); expect(heading).toBeInTheDocument(); expect(heading.textContent).toContain('智连未来'); }); it('renders two CTA buttons', () => { render(); expect(screen.getByText('预约演示')).toBeInTheDocument(); expect(screen.getByText('了解方案')).toBeInTheDocument(); }); it('renders subtitle text', () => { render(); expect(screen.getByText(/从战略规划到系统落地/)).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/sections/hero-section-v2.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 HeroSectionV2** ```tsx // src/components/sections/hero-section-v2.tsx 'use client'; import { useEffect, useRef, useState } from 'react'; import { motion } from 'framer-motion'; import { StaticLink } from '@/components/ui/static-link'; export function HeroSectionV2() { const [isVisible, setIsVisible] = useState(false); const sectionRef = useRef(null); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry?.isIntersecting) { setIsVisible(true); } }, { threshold: 0.1 } ); if (sectionRef.current) { observer.observe(sectionRef.current); } return () => observer.disconnect(); }, []); return (
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/sections/hero-section-v2.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/sections/hero-section-v2.tsx src/components/sections/hero-section-v2.test.tsx git commit -m "feat: add HeroSectionV2 with brand fusion style and dual CTAs" ``` --- ## 任务 6:StatsBar 组件 **文件:** - 创建:`src/components/ui/stats-bar.tsx` - 创建:`src/components/ui/stats-bar.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { StatsBar } from './stats-bar'; const mockStats = [ { value: '200+', label: '企业客户' }, { value: '15+', label: '行业覆盖' }, { value: '99.9%', label: '系统可用性' }, ]; describe('StatsBar', () => { it('renders all stat items', () => { render(); expect(screen.getByText('200+')).toBeInTheDocument(); expect(screen.getByText('15+')).toBeInTheDocument(); expect(screen.getByText('99.9%')).toBeInTheDocument(); }); it('renders all labels', () => { render(); expect(screen.getByText('企业客户')).toBeInTheDocument(); expect(screen.getByText('行业覆盖')).toBeInTheDocument(); expect(screen.getByText('系统可用性')).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/ui/stats-bar.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 StatsBar** ```tsx // src/components/ui/stats-bar.tsx 'use client'; import { AnimatedNumber } from './animated-number'; export interface StatItem { value: string; label: string; } interface StatsBarProps { stats: StatItem[]; } export function StatsBar({ stats }: StatsBarProps) { return (
{stats.map((stat) => (
{stat.value}
{stat.label}
))}
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/ui/stats-bar.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/ui/stats-bar.tsx src/components/ui/stats-bar.test.tsx git commit -m "feat: add StatsBar component for social proof data display" ``` --- ## 任务 7:社会证明 Section **文件:** - 创建:`src/components/sections/social-proof-section.tsx` - 创建:`src/components/sections/social-proof-section.test.tsx` - 修改:`src/lib/constants/stats.ts` - [ ] **步骤 1:在 stats.ts 中新增 HOME_STATS** ```typescript export const HOME_STATS: StatItem[] = [ { value: '200+', label: '企业客户' }, { value: '15+', label: '行业覆盖' }, { value: '99.9%', label: '系统可用性' }, ]; ``` - [ ] **步骤 2:编写测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { SocialProofSection } from './social-proof-section'; describe('SocialProofSection', () => { it('renders section with stats', () => { render(); expect(screen.getByText('200+')).toBeInTheDocument(); expect(screen.getByText('企业客户')).toBeInTheDocument(); }); it('has correct background class', () => { const { container } = render(); const section = container.querySelector('section'); expect(section?.className).toContain('bg-[#F5F5F5]'); }); }); ``` - [ ] **步骤 3:实现 SocialProofSection** ```tsx // src/components/sections/social-proof-section.tsx 'use client'; import { StatsBar } from '@/components/ui/stats-bar'; import { HOME_STATS } from '@/lib/constants/stats'; export function SocialProofSection() { return (
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/sections/social-proof-section.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/sections/social-proof-section.tsx src/components/sections/social-proof-section.test.tsx src/lib/constants/stats.ts git commit -m "feat: add SocialProofSection with HOME_STATS data" ``` --- ## 任务 8:ProductCard 组件 **文件:** - 创建:`src/components/ui/product-card.tsx` - 创建:`src/components/ui/product-card.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { ProductCard } from './product-card'; const mockProduct = { id: 'erp', title: 'ERP 管理系统', description: '财务·采购·销售·库存·生产', href: '/products/erp', }; describe('ProductCard', () => { it('renders product title', () => { render(); expect(screen.getByText('ERP 管理系统')).toBeInTheDocument(); }); it('renders product description', () => { render(); expect(screen.getByText('财务·采购·销售·库存·生产')).toBeInTheDocument(); }); it('renders link to product page', () => { render(); const link = screen.getByRole('link'); expect(link).toHaveAttribute('href', '/products/erp'); }); it('has left border accent', () => { const { container } = render(); const card = container.firstChild as HTMLElement; expect(card.className).toContain('border-l-[3px]'); expect(card.className).toContain('border-l-[#C41E3A]'); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/ui/product-card.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 ProductCard** ```tsx // src/components/ui/product-card.tsx import { StaticLink } from '@/components/ui/static-link'; interface ProductCardProps { id: string; title: string; description: string; href: string; } export function ProductCard({ title, description, href }: ProductCardProps) { return (

{title}

{description}

); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/ui/product-card.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/ui/product-card.tsx src/components/ui/product-card.test.tsx git commit -m "feat: add ProductCard component with brand-red left border" ``` --- ## 任务 9:产品矩阵 Section **文件:** - 创建:`src/components/sections/product-matrix-section.tsx` - 创建:`src/components/sections/product-matrix-section.test.tsx` - [ ] **步骤 1:编写测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { ProductMatrixSection } from './product-matrix-section'; describe('ProductMatrixSection', () => { it('renders section heading', () => { render(); expect(screen.getByText('核心产品')).toBeInTheDocument(); }); it('renders all 4 products', () => { render(); expect(screen.getByText('ERP 管理系统')).toBeInTheDocument(); expect(screen.getByText('CRM 客户管理')).toBeInTheDocument(); expect(screen.getByText('BI 数据平台')).toBeInTheDocument(); expect(screen.getByText('CMS 内容平台')).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/sections/product-matrix-section.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 ProductMatrixSection** ```tsx // src/components/sections/product-matrix-section.tsx 'use client'; import { ProductCard } from '@/components/ui/product-card'; import { PRODUCTS } from '@/lib/constants/products'; export function ProductMatrixSection() { return (

核心产品

{PRODUCTS.map((product) => ( ))}
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/sections/product-matrix-section.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/sections/product-matrix-section.tsx src/components/sections/product-matrix-section.test.tsx git commit -m "feat: add ProductMatrixSection with 2x2 product card grid" ``` --- ## 任务 10:ChallengeCard 组件 **文件:** - 创建:`src/components/ui/challenge-card.tsx` - 创建:`src/components/ui/challenge-card.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { ChallengeCard } from './challenge-card'; const mockChallenge = { id: 'isolation', icon: '🏭', title: '系统孤岛', subtitle: '数据不通', bgColor: '#FEF2F4', hoverBgColor: '#FDE8EC', href: '/solutions/manufacturing', }; describe('ChallengeCard', () => { it('renders icon', () => { render(); expect(screen.getByText('🏭')).toBeInTheDocument(); }); it('renders title and subtitle', () => { render(); expect(screen.getByText('系统孤岛')).toBeInTheDocument(); expect(screen.getByText('数据不通')).toBeInTheDocument(); }); it('renders link to solution page', () => { render(); const link = screen.getByRole('link'); expect(link).toHaveAttribute('href', '/solutions/manufacturing'); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/ui/challenge-card.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 ChallengeCard** ```tsx // src/components/ui/challenge-card.tsx import { StaticLink } from '@/components/ui/static-link'; interface ChallengeCardProps { id: string; icon: string; title: string; subtitle: string; bgColor: string; hoverBgColor: string; href: string; } export function ChallengeCard({ icon, title, subtitle, bgColor, hoverBgColor, href }: ChallengeCardProps) { return ( { (e.currentTarget as HTMLElement).style.backgroundColor = hoverBgColor; }} onMouseLeave={(e) => { (e.currentTarget as HTMLElement).style.backgroundColor = bgColor; }} >
{icon}

{title}

{subtitle}

); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/ui/challenge-card.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/ui/challenge-card.tsx src/components/ui/challenge-card.test.tsx git commit -m "feat: add ChallengeCard component for scenario entry points" ``` --- ## 任务 11:挑战场景 Section **文件:** - 创建:`src/components/sections/challenge-section.tsx` - 创建:`src/components/sections/challenge-section.test.tsx` - [ ] **步骤 1:编写测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { ChallengeSection } from './challenge-section'; describe('ChallengeSection', () => { it('renders section heading', () => { render(); expect(screen.getByText('您面临什么挑战?')).toBeInTheDocument(); }); it('renders three challenge cards', () => { render(); expect(screen.getByText('系统孤岛')).toBeInTheDocument(); expect(screen.getByText('增长瓶颈')).toBeInTheDocument(); expect(screen.getByText('合规风险')).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/sections/challenge-section.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 ChallengeSection** ```tsx // src/components/sections/challenge-section.tsx 'use client'; import { ChallengeCard } from '@/components/ui/challenge-card'; const CHALLENGES = [ { id: 'isolation', icon: '🏭', title: '系统孤岛', subtitle: '数据不通', bgColor: 'var(--color-challenge-isolation)', hoverBgColor: 'var(--color-challenge-isolation-hover)', href: '/solutions/manufacturing', }, { id: 'growth', icon: '📈', title: '增长瓶颈', subtitle: '效率低下', bgColor: 'var(--color-challenge-growth)', hoverBgColor: 'var(--color-challenge-growth-hover)', href: '/solutions/retail', }, { id: 'compliance', icon: '🔒', title: '合规风险', subtitle: '安全隐忧', bgColor: 'var(--color-challenge-compliance)', hoverBgColor: 'var(--color-challenge-compliance-hover)', href: '/solutions/healthcare', }, ]; export function ChallengeSection() { return (

您面临什么挑战?

{CHALLENGES.map((challenge) => ( ))}
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/sections/challenge-section.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/sections/challenge-section.tsx src/components/sections/challenge-section.test.tsx git commit -m "feat: add ChallengeSection with three scenario entry cards" ``` --- ## 任务 12:TestimonialBlock 组件 **文件:** - 创建:`src/components/ui/testimonial-block.tsx` - 创建:`src/components/ui/testimonial-block.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { TestimonialBlock } from './testimonial-block'; const mockTestimonial = { quote: '与睿新合作后,运营效率提升了40%', author: '某上市制造企业 CTO', results: [ { value: '40%', label: '效率提升' }, { value: '6月', label: '交付周期' }, ], }; describe('TestimonialBlock', () => { it('renders quote text', () => { render(); expect(screen.getByText(/运营效率提升了40%/)).toBeInTheDocument(); }); it('renders author attribution', () => { render(); expect(screen.getByText(/某上市制造企业 CTO/)).toBeInTheDocument(); }); it('renders result metrics', () => { render(); expect(screen.getByText('40%')).toBeInTheDocument(); expect(screen.getByText('效率提升')).toBeInTheDocument(); expect(screen.getByText('6月')).toBeInTheDocument(); expect(screen.getByText('交付周期')).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/ui/testimonial-block.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 TestimonialBlock** ```tsx // src/components/ui/testimonial-block.tsx interface TestimonialResult { value: string; label: string; } interface TestimonialBlockProps { quote: string; author: string; results: TestimonialResult[]; } export function TestimonialBlock({ quote, author, results }: TestimonialBlockProps) { return (

客户成果

“{quote}”

— {author}

{results.map((result) => (
{result.value}
{result.label}
))}
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/ui/testimonial-block.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/ui/testimonial-block.tsx src/components/ui/testimonial-block.test.tsx git commit -m "feat: add TestimonialBlock component with dark background and metrics" ``` --- ## 任务 13:客户成果 Section **文件:** - 创建:`src/components/sections/testimonial-section.tsx` - 创建:`src/components/sections/testimonial-section.test.tsx` - [ ] **步骤 1:编写测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { TestimonialSection } from './testimonial-section'; describe('TestimonialSection', () => { it('renders client testimonial quote', () => { render(); expect(screen.getByText(/客户成果/)).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/sections/testimonial-section.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 TestimonialSection** ```tsx // src/components/sections/testimonial-section.tsx 'use client'; import { TestimonialBlock } from '@/components/ui/testimonial-block'; import { CASES } from '@/lib/constants/cases'; export function TestimonialSection() { const featuredCase = CASES.find(c => c.testimonial) || CASES[0]; const testimonial = featuredCase.testimonial ? { quote: featuredCase.testimonial.quote, author: `${featuredCase.testimonial.author},${featuredCase.testimonial.role}`, results: featuredCase.results.slice(0, 3), } : { quote: featuredCase.description.slice(0, 60) + '...', author: featuredCase.client, results: featuredCase.results.slice(0, 3), }; return (
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/sections/testimonial-section.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/sections/testimonial-section.tsx src/components/sections/testimonial-section.test.tsx git commit -m "feat: add TestimonialSection using CASES data for client stories" ``` --- ## 任务 14:CTASection 组件 **文件:** - 创建:`src/components/ui/cta-section.tsx` - 创建:`src/components/ui/cta-section.test.tsx` - [ ] **步骤 1:编写失败的测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { CTASection } from './cta-section'; describe('CTASection', () => { it('renders heading', () => { render(); expect(screen.getByText('开启数字化转型之旅')).toBeInTheDocument(); }); it('renders subtitle when provided', () => { render(); expect(screen.getByText('免费咨询 · 专属方案')).toBeInTheDocument(); }); it('renders CTA button', () => { render(); const link = screen.getByText('立即咨询'); expect(link).toBeInTheDocument(); expect(link.closest('a')).toHaveAttribute('href', '/contact'); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/ui/cta-section.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 CTASection** ```tsx // src/components/ui/cta-section.tsx import { StaticLink } from '@/components/ui/static-link'; interface CTASectionProps { heading: string; subtitle?: string; buttonText?: string; buttonHref?: string; } export function CTASection({ heading, subtitle, buttonText = '立即咨询', buttonHref = '/contact', }: CTASectionProps) { return (

{heading}

{subtitle && (

{subtitle}

)} {buttonText}
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/ui/cta-section.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/ui/cta-section.tsx src/components/ui/cta-section.test.tsx git commit -m "feat: add CTASection component with brand-red gradient" ``` --- ## 任务 15:CTA Section 页面级 **文件:** - 创建:`src/components/sections/cta-section-page.tsx` - 创建:`src/components/sections/cta-section-page.test.tsx` - [ ] **步骤 1:编写测试** ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import { CTASectionPage } from './cta-section-page'; describe('CTASectionPage', () => { it('renders CTA with correct content', () => { render(); expect(screen.getByText('开启数字化转型之旅')).toBeInTheDocument(); expect(screen.getByText('免费咨询 · 专属方案 · 30天试用')).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/components/sections/cta-section-page.test.tsx --no-coverage` 预期:FAIL - [ ] **步骤 3:实现 CTASectionPage** ```tsx // src/components/sections/cta-section-page.tsx import { CTASection } from '@/components/ui/cta-section'; export function CTASectionPage() { return (
); } ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/components/sections/cta-section-page.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/components/sections/cta-section-page.tsx src/components/sections/cta-section-page.test.tsx git commit -m "feat: add CTASectionPage with homepage-specific CTA content" ``` --- ## 任务 16:首页组装 **文件:** - 修改:`src/app/(marketing)/home-content.tsx` - [ ] **步骤 1:编写测试** 在 `src/app/(marketing)/page.test.tsx`(如不存在则新建)中: ```tsx import { render, screen } from '@testing-library/react'; import { describe, it, expect } from 'vitest'; import HomeContent from './home-content'; describe('HomeContent V2', () => { it('renders new hero section', () => { render(); expect(screen.getByText('智连未来,成长伙伴')).toBeInTheDocument(); }); it('renders product matrix section', () => { render(); expect(screen.getByText('核心产品')).toBeInTheDocument(); }); it('renders challenge section', () => { render(); expect(screen.getByText('您面临什么挑战?')).toBeInTheDocument(); }); it('renders CTA section', () => { render(); expect(screen.getByText('开启数字化转型之旅')).toBeInTheDocument(); }); }); ``` - [ ] **步骤 2:运行测试验证失败** 运行:`npx jest src/app/\(marketing\)/page.test.tsx --no-coverage` 预期:FAIL — 找不到新 Section 内容 - [ ] **步骤 3:重构 home-content.tsx** 替换 `home-content.tsx` 的全部内容: ```tsx 'use client'; import dynamic from 'next/dynamic'; import { HeroSectionV2 } from '@/components/sections/hero-section-v2'; import { SectionSkeleton } from '@/components/ui/loading-skeleton'; import type { ReactNode } from 'react'; const SocialProofSection = dynamic( () => import('@/components/sections/social-proof-section').then(mod => ({ default: mod.SocialProofSection })), { loading: () => , ssr: false } ); const ProductMatrixSection = dynamic( () => import('@/components/sections/product-matrix-section').then(mod => ({ default: mod.ProductMatrixSection })), { loading: () => , ssr: false } ); const ChallengeSection = dynamic( () => import('@/components/sections/challenge-section').then(mod => ({ default: mod.ChallengeSection })), { loading: () => , ssr: false } ); const TestimonialSection = dynamic( () => import('@/components/sections/testimonial-section').then(mod => ({ default: mod.TestimonialSection })), { loading: () => , ssr: false } ); const CTASectionPage = dynamic( () => import('@/components/sections/cta-section-page').then(mod => ({ default: mod.CTASectionPage })), { loading: () => , ssr: false } ); function HomeContent({ heroStats }: { heroStats: ReactNode }) { return ( <> ); } export default HomeContent; ``` - [ ] **步骤 4:运行测试验证通过** 运行:`npx jest src/app/\(marketing\)/page.test.tsx --no-coverage` 预期:PASS - [ ] **步骤 5:Commit** ```bash git add src/app/\(marketing\)/home-content.tsx src/app/\(marketing\)/page.test.tsx git commit -m "feat: assemble homepage with new brand-fusion sections" ``` --- ## 任务 17:废弃动效清理 **文件:** - 修改:`src/components/effects/index.ts` - [ ] **步骤 1:从 effects/index.ts 移除废弃组件导出** 移除以下导出: - `InkBackground` / `InkTechFusion` - `DataParticleFlow` - `ParticleGalaxy` - `MouseInteractiveParticles` - `FluidWaveBackground` - `GeometricAbstract` - `GridLines` - `AdvancedFloatingEffects` 保留以下导出: - `SubtleDots` - `GradientFlow` / `GradientFlowOptimized` - `GradientOrbs` - `GlowEffect` - `ParallaxEffect` - `SealAnimationEnhanced` - [ ] **步骤 2:验证构建无报错** 运行:`npx tsc --noEmit` 预期:无类型错误(如果有引用废弃组件的文件,需更新引用) - [ ] **步骤 3:Commit** ```bash git add src/components/effects/index.ts git commit -m "chore: remove deprecated particle/ink effect exports from index" ``` --- ## 任务 18:集成测试与验证 - [ ] **步骤 1:运行全量单元测试** 运行:`npx jest --no-coverage` 预期:所有测试 PASS - [ ] **步骤 2:运行类型检查** 运行:`npx tsc --noEmit` 预期:无类型错误 - [ ] **步骤 3:运行构建** 运行:`npm run build` 预期:构建成功 - [ ] **步骤 4:启动开发服务器,手动验证首页** 运行:`npm run dev` 验证项: 1. 导航栏显示 6 项,"产品"和"解决方案"有下拉 2. Hero 白底 + 书法标题 + 双 CTA 3. 社会证明三列数字 4. 产品矩阵 2×2 卡片 + 朱砂红左边框 5. 挑战场景三列卡片 + 场景色 6. 客户成果深色背景 + 引言 7. CTA 朱砂红渐变 8. 无粒子/水墨动效 - [ ] **步骤 5:运行 Lighthouse 审计** 运行:`npm run lighthouse:mobile` 预期:Performance ≥ 90, Accessibility ≥ 95 - [ ] **步骤 6:最终 Commit** ```bash git add -A git commit -m "feat: complete Phase 1 of Atlassian-style brand fusion homepage redesign" ``` --- ## 自检清单 | 检查项 | 状态 | |--------|------| | 规格中每个 Section 都有对应任务 | ✅ Hero/SocialProof/ProductMatrix/Challenge/Testimonial/CTA | | 规格中每个组件都有对应任务 | ✅ MegaDropdown/ProductCard/ChallengeCard/StatsBar/TestimonialBlock/CTASection | | 无占位符(TODO/TBD/待定) | ✅ 所有步骤包含完整代码 | | 类型一致性 | ✅ NavigationItemV2/MegaDropdownItem/StatItem 等类型定义明确 | | 废弃动效清理有对应任务 | ✅ 任务 17 | | 集成验证有对应任务 | ✅ 任务 18 |