Files
vf_react/src/views/Home/HomePage.tsx
zdl 9ba2b7d424 feat: 小程序跳转改用明文 URL Scheme
- UrlSchemeLauncher: 使用明文 Scheme 格式,无需后端 API 生成
- HomePage: 修复 path 格式,去掉开头斜杠以匹配小程序后台配置

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-12 19:06:21 +08:00

169 lines
5.2 KiB
TypeScript
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.tsx
// 首页 - 专业投资分析平台
import React, { useEffect, useCallback, useRef } from 'react';
import { Box, Container, VStack, SimpleGrid } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { usePostHogTrack } from '@/hooks/usePostHogRedux';
import { useHomeResponsive } from '@/hooks/useHomeResponsive';
import { ACQUISITION_EVENTS } from '@/lib/constants';
import { CORE_FEATURES } from '@/constants/homeFeatures';
import { performanceMonitor } from '@/utils/performanceMonitor';
import type { Feature } from '@/types/home';
import { HeroHeader } from './components/HeroHeader';
import { FeaturedFeatureCard } from './components/FeaturedFeatureCard';
import { FeatureCard } from './components/FeatureCard';
import MiniProgramLauncher from '@/components/MiniProgramLauncher';
import { isMobileDevice } from '@/components/MiniProgramLauncher/hooks/useWechatEnvironment';
import '@/styles/home-animations.css';
/**
* 首页组件
* 展示平台核心功能,引导用户探索各个功能模块
*/
const HomePage: React.FC = () => {
const { user, isAuthenticated } = useAuth();
const navigate = useNavigate();
const { track } = usePostHogTrack();
// ⚡ 性能标记:渲染开始(组件函数执行时,使用 ref 避免严格模式下重复标记)
const hasMarkedStart = useRef(false);
if (!hasMarkedStart.current) {
performanceMonitor.mark('homepage-render-start');
hasMarkedStart.current = true;
}
// 响应式配置
const {
heroHeight,
headingSize,
headingLetterSpacing,
heroTextSize,
containerPx,
} = useHomeResponsive();
// ⚡ 性能标记渲染完成DOM 已挂载)
useEffect(() => {
performanceMonitor.mark('homepage-render-end');
}, []);
// PostHog 追踪:页面浏览
useEffect(() => {
track(ACQUISITION_EVENTS.LANDING_PAGE_VIEWED, {
timestamp: new Date().toISOString(),
is_authenticated: isAuthenticated,
user_id: user?.id || null,
});
}, [track, isAuthenticated, user?.id]);
// 功能卡片点击处理
const handleFeatureClick = useCallback((feature: Feature) => {
// PostHog 追踪:功能卡片点击
track(ACQUISITION_EVENTS.FEATURE_CARD_VIEWED, {
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]);
// 特色功能(第一个)
const featuredFeature = CORE_FEATURES[0];
// 其他功能
const regularFeatures = CORE_FEATURES.slice(1);
// 移动端判断(用于显示小程序入口)
const isMobile = isMobileDevice();
return (
<Box>
{/* Hero Section - 深色科技风格 */}
<Box
position="relative"
minH={heroHeight}
bg="linear-gradient(135deg, #0E0C15 0%, #15131D 50%, #252134 100%)"
overflow="hidden"
>
<Container maxW="7xl" position="relative" px={containerPx}>
<VStack
spacing={{ base: 5, md: 8, lg: 10 }}
align="stretch"
minH={heroHeight}
justify="center"
>
{/* 主标题区域 */}
<HeroHeader
headingSize={headingSize}
headingLetterSpacing={headingLetterSpacing}
heroTextSize={heroTextSize}
/>
{/* 核心功能面板 */}
<Box pb={{ base: 5, md: 8 }}>
<VStack spacing={{ base: 4, md: 5 }}>
{/* 特色功能卡片 - 新闻中心 */}
<FeaturedFeatureCard
feature={featuredFeature}
onClick={handleFeatureClick}
/>
{/* 其他功能卡片 */}
<SimpleGrid
columns={{ base: 1, md: 2, lg: 3 }}
spacing={{ base: 2, md: 3, lg: 4 }}
w="100%"
>
{regularFeatures.map((feature) => (
<FeatureCard
key={feature.id}
feature={feature}
onClick={handleFeatureClick}
/>
))}
</SimpleGrid>
</VStack>
</Box>
</VStack>
</Container>
</Box>
{/* 移动端右上角固定按钮 - 小程序入口 */}
{isMobile && (
<Box
position="fixed"
top="70px"
right="16px"
zIndex={1000}
>
<MiniProgramLauncher
path="pages/index/index"
buttonStyle={{
backgroundColor: '#07c160',
color: '#fff',
padding: '8px 16px',
fontSize: '14px',
fontWeight: '500',
borderRadius: '20px',
boxShadow: '0 2px 8px rgba(7, 193, 96, 0.3)',
}}
>
</MiniProgramLauncher>
</Box>
)}
</Box>
);
};
export default HomePage;