/** ========================================================= Vision UI PRO React - v1.0.0 ========================================================= Product Page: https://www.creative-tim.com/product/vision-ui-dashboard-pro-react Copyright 2021 Creative Tim (https://www.creative-tim.com/) Design and Coded by Simmmple & Creative Tim ========================================================= The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Visionware. */ import React, { useEffect, useRef } from "react"; import { useDispatch } from 'react-redux'; import { useLocation } from 'react-router-dom'; // Routes import AppRoutes from './routes'; // Providers import AppProviders from './providers/AppProviders'; // Components import GlobalComponents from './components/GlobalComponents'; // Hooks import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler'; // Redux import { initializePostHog } from './store/slices/posthogSlice'; // Utils import { logger } from './utils/logger'; // PostHog 追踪 import { trackEvent, trackEventAsync } from '@lib/posthog'; // Contexts import { useAuth } from '@contexts/AuthContext'; /** * AppContent - 应用核心内容 * 负责 PostHog 初始化和渲染路由 */ function AppContent() { const dispatch = useDispatch(); const location = useLocation(); const { isAuthenticated } = useAuth(); // ✅ 使用 Ref 存储页面进入时间和路径(避免闭包问题) const pageEnterTimeRef = useRef(Date.now()); const currentPathRef = useRef(location.pathname); // 🎯 PostHog Redux 初始化 useEffect(() => { dispatch(initializePostHog()); logger.info('App', 'PostHog Redux 初始化已触发'); }, [dispatch]); // ✅ 首次访问追踪 useEffect(() => { const hasVisited = localStorage.getItem('has_visited'); if (!hasVisited) { const urlParams = new URLSearchParams(location.search); // ⚡ 使用异步追踪,不阻塞页面渲染 trackEventAsync('first_visit', { referrer: document.referrer || 'direct', utm_source: urlParams.get('utm_source'), utm_medium: urlParams.get('utm_medium'), utm_campaign: urlParams.get('utm_campaign'), landing_page: location.pathname, timestamp: new Date().toISOString() }); localStorage.setItem('has_visited', 'true'); } }, [location.search, location.pathname]); // ✅ 页面浏览时长追踪 useEffect(() => { // 计算上一个页面的停留时长 const calculateAndTrackDuration = () => { const exitTime = Date.now(); const duration = Math.round((exitTime - pageEnterTimeRef.current) / 1000); // 秒 // 只追踪停留时间 > 1 秒的页面(过滤快速跳转) if (duration > 1) { // ⚡ 使用异步追踪,不阻塞页面切换 trackEventAsync('page_view_duration', { path: currentPathRef.current, duration_seconds: duration, is_authenticated: isAuthenticated, timestamp: new Date().toISOString() }); } }; // 路由切换时追踪上一个页面的时长 if (currentPathRef.current !== location.pathname) { calculateAndTrackDuration(); // 更新为新页面 currentPathRef.current = location.pathname; pageEnterTimeRef.current = Date.now(); } // 页面关闭/刷新时追踪时长 const handleBeforeUnload = () => { calculateAndTrackDuration(); }; window.addEventListener('beforeunload', handleBeforeUnload); return () => { window.removeEventListener('beforeunload', handleBeforeUnload); }; }, [location.pathname, isAuthenticated]); return ; } /** * App - 应用根组件 * 设置全局错误处理,提供 Provider 和全局组件 */ export default function App() { // 全局错误处理 useGlobalErrorHandler(); return ( ); }