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:
@@ -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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user