Files
vf_react/src/views/Home/HomePage.js
zdl bca2ad4f81 feat: 实现的功能 Home 页面追踪(2个事件)
**Home 页面**:
1. **页面访问** - 了解流量来源、登录转化率
2. **功能卡片点击** - 识别最受欢迎的功能
3. **推荐功能效果** - 分析特色功能(新闻中心)的点击率
2025-10-28 21:24:42 +08:00

390 lines
14 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/views/Home/HomePage.js - 专业投资分析平台
import React, { useEffect, useCallback } from 'react';
import {
Box,
Container,
Heading,
Text,
Card,
CardBody,
Badge,
Button,
Flex,
VStack,
HStack,
SimpleGrid,
useBreakpointValue
} from '@chakra-ui/react';
import { useAuth } from '../../contexts/AuthContext';
import { useNavigate } from 'react-router-dom';
import heroBg from '../../assets/img/BackgroundCard1.png';
import '../../styles/home-animations.css';
import { logger } from '../../utils/logger';
import MidjourneyHeroSection from '../Community/components/MidjourneyHeroSection';
import { usePostHogTrack } from '../../hooks/usePostHogRedux';
import { ACQUISITION_EVENTS } from '../../lib/constants';
export default function HomePage() {
const { user, isAuthenticated } = useAuth(); // ⚡ 移除 isLoading不再依赖它
const navigate = useNavigate();
const { track } = usePostHogTrack(); // PostHog 追踪
const [imageLoaded, setImageLoaded] = React.useState(false);
// 响应式配置
const heroHeight = useBreakpointValue({ base: '60vh', md: '80vh', lg: '100vh' });
const headingSize = useBreakpointValue({ base: 'xl', md: '3xl', lg: '4xl' });
const headingLetterSpacing = useBreakpointValue({ base: '-1px', md: '-1.5px', lg: '-2px' });
const heroTextSize = useBreakpointValue({ base: 'md', md: 'lg', lg: 'xl' });
const containerPx = useBreakpointValue({ base: 10, md: 10, lg: 10 });
const showDecorations = useBreakpointValue({ base: false, md: true });
// 保留原有的调试信息
useEffect(() => {
logger.debug('HomePage', 'AuthContext状态', {
userId: user?.id,
username: user?.username,
nickname: user?.nickname,
isAuthenticated,
hasUser: !!user
});
}, [user?.id, isAuthenticated]); // 只依赖 user.id,避免无限循环
// 🎯 PostHog 追踪:页面浏览
useEffect(() => {
track(ACQUISITION_EVENTS.LANDING_PAGE_VIEWED, {
timestamp: new Date().toISOString(),
is_authenticated: isAuthenticated,
user_id: user?.id || null,
});
}, [track, isAuthenticated, user?.id]);
// 核心功能配置 - 5个主要功能
const coreFeatures = [
{
id: 'news-catalyst',
title: '新闻中心',
description: '实时新闻事件分析,捕捉市场催化因子',
icon: '📊',
color: 'yellow',
url: '/community',
badge: '核心',
featured: true
},
{
id: 'concepts',
title: '概念中心',
description: '热门概念与主题投资分析追踪',
icon: '🎯',
color: 'purple',
url: '/concepts',
badge: '热门'
},
{
id: 'stocks',
title: '个股信息汇总',
description: '全面的个股基本面信息整合',
icon: '📈',
color: 'blue',
url: '/stocks',
badge: '全面'
},
{
id: 'limit-analyse',
title: '涨停板块分析',
description: '涨停板数据深度分析与规律挖掘',
icon: '🚀',
color: 'green',
url: '/limit-analyse',
badge: '精准'
},
{
id: 'company',
title: '个股罗盘',
description: '个股全方位分析与投资决策支持',
icon: '🧭',
color: 'orange',
url: '/company?scode=688256',
badge: '专业'
},
{
id: 'trading-simulation',
title: '模拟盘交易',
description: '100万起始资金体验真实交易环境',
icon: '💰',
color: 'teal',
url: '/trading-simulation',
badge: '实战'
}
];
// @TODO 如何区分内部链接和外部链接?
const handleProductClick = useCallback((feature) => {
// 🎯 PostHog 追踪:功能卡片点击
track(ACQUISITION_EVENTS.FEATURE_CARD_CLICKED, {
feature_id: feature.id,
feature_title: feature.title,
feature_url: feature.url,
is_featured: feature.featured || false,
link_type: feature.url.startsWith('http') ? 'external' : 'internal',
});
// 原有导航逻辑
if (feature.url.startsWith('http')) {
// 外部链接,直接打开
window.open(feature.url, '_blank');
} else {
// 内部路由
navigate(feature.url);
}
}, [track, navigate]);
return (
<Box>
{/* 开发调试信息 */}
{/* {process.env.NODE_ENV === 'development' && (
<Box bg="rgba(0, 0, 0, 0.8)" color="yellow.200" p={2} fontSize="xs" zIndex={1000} position="relative">
认证: {isAuthenticated ? '✅' : '❌'} | 用户: {user?.nickname || '无'}
</Box>
)} */}
{/* Hero Section - 深色科技风格 */}
<Box
position="relative"
minH={heroHeight}
bg="linear-gradient(135deg, #0E0C15 0%, #15131D 50%, #252134 100%)"
overflow="hidden"
>
{/* 背景图片和装饰 - 优化:延迟加载 */}
<Box
position="absolute"
top="0"
right="0"
w="50%"
h="100%"
bgImage={imageLoaded ? `url(${heroBg})` : 'none'}
bgSize="cover"
bgPosition="center"
opacity={imageLoaded ? 0.3 : 0}
transition="opacity 0.5s ease-in"
_after={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(90deg, rgba(14, 12, 21, 0.9) 0%, rgba(14, 12, 21, 0.3) 100%)'
}}
/>
{/* 预加载背景图片 */}
<Box display="none">
<img
src={heroBg}
alt=""
onLoad={() => setImageLoaded(true)}
onError={() => setImageLoaded(true)}
/>
</Box>
{/* 装饰性几何图形 - 移动端隐藏 */}
{showDecorations && (
<>
<Box
position="absolute"
top="20%"
left="10%"
w={{ base: '100px', md: '150px', lg: '200px' }}
h={{ base: '100px', md: '150px', lg: '200px' }}
borderRadius="50%"
bg="rgba(255, 215, 0, 0.1)"
filter="blur(80px)"
className="float-animation"
/>
<Box
position="absolute"
bottom="30%"
right="20%"
w={{ base: '80px', md: '120px', lg: '150px' }}
h={{ base: '80px', md: '120px', lg: '150px' }}
borderRadius="50%"
bg="rgba(138, 43, 226, 0.1)"
filter="blur(60px)"
className="float-animation-reverse"
/>
</>
)}
<Container maxW="7xl" position="relative" zIndex={30} px={containerPx}>
<VStack spacing={{ base: 8, md: 12, lg: 16 }} align="stretch" minH={heroHeight} justify="center">
{/* 主标题区域 */}
<VStack spacing={{ base: 4, md: 5, lg: 6 }} textAlign="center" pt={{ base: 4, md: 6, lg: 8 }}>
<Heading
size={headingSize}
color="white"
fontWeight="900"
letterSpacing={headingLetterSpacing}
lineHeight="shorter"
>
智能投资分析平台
</Heading>
<Text fontSize={heroTextSize} color="whiteAlpha.800" maxW={{ base: '100%', md: '2xl', lg: '3xl' }} lineHeight="tall" px={{ base: 4, md: 0 }}>
专业投资研究工具助您把握市场机遇
</Text>
</VStack>
{/* 核心功能面板 */}
<Box pb={{ base: 8, md: 12 }}>
<VStack spacing={{ base: 6, md: 8 }}>
{/* 新闻中心 - 突出显示 */}
<Card
bg="transparent"
border="2px solid"
borderColor="yellow.400"
borderRadius={{ base: '2xl', md: '3xl' }}
overflow="hidden"
position="relative"
shadow="2xl"
w="100%"
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(135deg, rgba(255, 215, 0, 0.1) 0%, rgba(255, 165, 0, 0.05) 100%)',
zIndex: 0
}}
>
<CardBody p={{ base: 6, md: 8 }} position="relative" zIndex={1}>
{/* 响应式布局:移动端纵向,桌面端横向 */}
<Flex
direction={{ base: 'column', md: 'row' }}
align={{ base: 'stretch', md: 'center' }}
justify={{ base: 'flex-start', md: 'space-between' }}
gap={{ base: 4, md: 6 }}
>
<Flex align="center" gap={{ base: 4, md: 6 }} flex={1}>
<Box
p={{ base: 3, md: 4 }}
borderRadius={{ base: 'lg', md: 'xl' }}
bg="yellow.400"
color="black"
>
<Text fontSize={{ base: '2xl', md: '3xl' }}>{coreFeatures[0].icon}</Text>
</Box>
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
<HStack>
<Heading size={{ base: 'lg', md: 'xl' }} color="white">
{coreFeatures[0].title}
</Heading>
<Badge colorScheme="yellow" variant="solid" fontSize={{ base: 'xs', md: 'sm' }}>
{coreFeatures[0].badge}
</Badge>
</HStack>
<Text color="whiteAlpha.800" fontSize={{ base: 'md', md: 'lg' }} maxW={{ md: 'md' }} lineHeight="tall">
{coreFeatures[0].description}
</Text>
</VStack>
</Flex>
<Button
colorScheme="yellow"
size={{ base: 'md', md: 'lg' }}
borderRadius="full"
fontWeight="bold"
w={{ base: '100%', md: 'auto' }}
onClick={() => handleProductClick(coreFeatures[0])}
minH="44px"
flexShrink={0}
>
进入功能
</Button>
</Flex>
</CardBody>
</Card>
{/* 其他5个功能 */}
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={{ base: 4, md: 5, lg: 6 }} w="100%">
{coreFeatures.slice(1).map((feature) => (
<Card
key={feature.id}
bg="whiteAlpha.100"
backdropFilter="blur(10px)"
border="1px solid"
borderColor="whiteAlpha.200"
borderRadius={{ base: 'xl', md: '2xl' }}
transition="all 0.3s ease"
_hover={{
bg: 'whiteAlpha.200',
borderColor: `${feature.color}.400`,
transform: 'translateY(-4px)',
shadow: '2xl'
}}
_active={{
bg: 'whiteAlpha.200',
borderColor: `${feature.color}.400`,
transform: 'translateY(-2px)'
}}
onClick={() => handleProductClick(feature)}
minH={{ base: 'auto', md: '180px' }}
>
<CardBody p={{ base: 5, md: 6 }}>
<VStack spacing={{ base: 3, md: 4 }} align="start" h="100%">
<HStack>
<Box
p={{ base: 2, md: 3 }}
borderRadius="lg"
bg={`${feature.color}.50`}
border="1px solid"
borderColor={`${feature.color}.200`}
>
<Text fontSize={{ base: 'xl', md: '2xl' }}>{feature.icon}</Text>
</Box>
<Badge colorScheme={feature.color} variant="solid" fontSize={{ base: 'xs', md: 'sm' }}>
{feature.badge}
</Badge>
</HStack>
<VStack align="start" spacing={{ base: 1, md: 2 }} flex={1}>
<Heading size={{ base: 'md', md: 'lg' }} color="white">
{feature.title}
</Heading>
<Text color="whiteAlpha.800" fontSize={{ base: 'xs', md: 'sm' }} lineHeight="tall">
{feature.description}
</Text>
</VStack>
<Button
colorScheme={feature.color}
size={{ base: 'md', md: 'sm' }}
variant="outline"
alignSelf="flex-end"
w={{ base: '100%', md: 'auto' }}
minH="44px"
onClick={(e) => {
e.stopPropagation();
handleProductClick(feature);
}}
>
使用
</Button>
</VStack>
</CardBody>
</Card>
))}
</SimpleGrid>
</VStack>
</Box>
{/* Midjourney风格英雄区域 */}
<MidjourneyHeroSection />
</VStack>
</Container>
</Box>
</Box>
);
}