feat(design): Vibe design optimization — Hero, Bento grids, trust layer, narrative

升级全站体验:首页 Hero 改为产品视觉 + 单一 CTA 转化布局;产品矩阵/服务/方案改
为 Bento 非对称网格(ERP 2x2 大卡 + BI 1x2);补齐信任层(可验证信号 + 来源标注)
与「问题→方法→结果」章节式叙事;新增 hero-product-visual 与 bento-grid 可复用组件;
统一动效与品牌视觉资产。新增对应单测、UJ-11 用户旅程测试并更新视觉回归基线快照。
This commit is contained in:
2026-08-19 14:43:27 +08:00
parent f3f4e78c51
commit 713186d552
35 changed files with 1576 additions and 79 deletions
@@ -0,0 +1,148 @@
import { describe, it, expect, jest } from '@jest/globals';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import SolutionsContentV3 from './solutions-content-v3';
import type { Solution } from '@/lib/constants/solutions';
import type { Product } from '@/lib/constants/products';
jest.mock('framer-motion', () => ({
motion: {
div: ({ children, initial, animate, whileInView, viewport, className, ...props }: any) => (
<div
data-testid="motion-div"
data-initial={JSON.stringify(initial)}
data-animate={JSON.stringify(animate)}
data-while-inview={JSON.stringify(whileInView)}
data-viewport={JSON.stringify(viewport)}
className={className}
{...props}
>
{children}
</div>
),
h1: ({ children, className, ...props }: any) => (
<h1 data-testid="motion-h1" className={className} {...props}>{children}</h1>
),
p: ({ children, className, ...props }: any) => (
<p data-testid="motion-p" className={className} {...props}>{children}</p>
),
span: ({ children, className, ...props }: any) => (
<span data-testid="motion-span" className={className} {...props}>{children}</span>
),
a: ({ children, href, className, ...props }: any) => (
<a href={href} className={className} data-testid="motion-a" {...props}>{children}</a>
),
},
useInView: jest.fn(() => true),
AnimatePresence: ({ children }: any) => <>{children}</>,
}));
jest.mock('@/components/ui/static-link', () => ({
StaticLink: ({ children, href, className, ...props }: any) => (
<a href={href} className={className} data-testid="static-link" {...props}>{children}</a>
),
}));
jest.mock('lucide-react', () => {
const mockIcon = (name: string) => {
const Icon = (props: any) => <svg data-testid={`icon-${name.toLowerCase()}`} className={props.className} />;
Icon.displayName = name;
return Icon;
};
return {
ArrowUpRight: mockIcon('arrow-up-right'),
Factory: mockIcon('factory'),
ShoppingCart: mockIcon('shopping-cart'),
Heart: mockIcon('heart'),
GraduationCap: mockIcon('graduation-cap'),
Shield: mockIcon('shield'),
Truck: mockIcon('truck'),
};
});
const mockSolutions: Solution[] = [
{
id: 'manufacturing',
industry: '制造业',
title: '智能制造数字化转型方案',
subtitle: '端到端制造数字化',
description: '面向制造企业的整体转型方案',
challenges: ['数据孤岛', '库存积压'],
solutions: ['ERP 集成', 'BI 分析'],
relatedProducts: ['erp', 'bi'],
valueProposition: {
headline: '价值主张',
points: [{ icon: 'Factory', title: '降本增效', description: '描述' }],
},
suiteCombination: {
primaryProducts: ['erp'],
complementaryServices: ['consulting'],
rationale: '理由',
},
painPoints: ['数据孤岛'],
outcomes: [{ value: '30%', label: '效率提升' }],
recommendedProducts: ['erp', 'bi'],
},
{
id: 'retail',
industry: '贸易零售',
title: '零售数字化解决方案',
subtitle: '全渠道零售数字化',
description: '面向零售企业的数字化方案',
challenges: ['渠道割裂'],
solutions: ['CRM 统一'],
relatedProducts: ['crm', 'bi'],
valueProposition: {
headline: '价值主张',
points: [{ icon: 'ShoppingCart', title: '提升转化', description: '描述' }],
},
suiteCombination: {
primaryProducts: ['crm'],
complementaryServices: ['consulting'],
rationale: '理由',
},
painPoints: ['渠道割裂'],
outcomes: [{ value: '3x', label: '转化率提升' }],
recommendedProducts: ['crm', 'bi'],
},
];
const mockProducts: Product[] = [
{
id: 'erp',
title: '睿新ERP管理系统',
description: 'ERP',
image: '/erp.png',
category: '企业旗舰系列',
categoryId: 'enterprise',
status: '已发布',
overview: '概述',
features: [],
benefits: [],
process: [],
specs: [],
tags: [],
heroThemeId: 'erp',
caseStudies: [],
dataProofs: [],
certifications: [],
bundle: 'enterprise',
},
];
describe('SolutionsContentV3 - 非对称方案卡片', () => {
it('makes the first solution a featured full-width card', () => {
render(<SolutionsContentV3 solutions={mockSolutions} products={mockProducts} />);
expect(screen.getByTestId('solution-card-manufacturing')).toHaveAttribute('data-featured', 'true');
expect(screen.getByTestId('solution-card-manufacturing').className).toContain('md:col-span-2');
expect(screen.getByTestId('solution-card-retail')).toHaveAttribute('data-featured', 'false');
});
it('renders solution industries', () => {
render(<SolutionsContentV3 solutions={mockSolutions} products={mockProducts} />);
expect(screen.getByText('制造业')).toBeInTheDocument();
expect(screen.getByText('贸易零售')).toBeInTheDocument();
});
});