// src/views/Community/index.js import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { fetchPopularKeywords, fetchHotEvents, fetchDynamicNews, selectDynamicNewsWithLoading } from '../../store/slices/communityDataSlice'; import { Box, Container, useColorModeValue, } from '@chakra-ui/react'; // 导入组件 import EventTimelineCard from './components/EventTimelineCard'; import DynamicNewsCard from './components/DynamicNewsCard'; import MarketReviewCard from './components/MarketReviewCard'; import HotEventsSection from './components/HotEventsSection'; import EventModals from './components/EventModals'; // 导入自定义 Hooks import { useEventData } from './hooks/useEventData'; import { useEventFilters } from './hooks/useEventFilters'; import { useCommunityEvents } from './hooks/useCommunityEvents'; // 导入时间工具函数 import { getCurrentTradingTimeRange, getMarketReviewTimeRange, filterEventsByTimeRange } from '../../utils/tradingTimeUtils'; import { logger } from '../../utils/logger'; import { useNotification } from '../../contexts/NotificationContext'; import { usePostHogTrack } from '../../hooks/usePostHogRedux'; import { RETENTION_EVENTS } from '../../lib/constants'; // 导航栏已由 MainLayout 提供,无需在此导入 const Community = () => { const navigate = useNavigate(); const dispatch = useDispatch(); const { track } = usePostHogTrack(); // PostHog 追踪(保留用于兼容) // Redux状态 const { popularKeywords, hotEvents } = useSelector(state => state.communityData); const { data: allCachedEvents, loading: dynamicNewsLoading, error: dynamicNewsError, total: dynamicNewsTotal, cachedCount: dynamicNewsCachedCount } = useSelector(selectDynamicNewsWithLoading); // Chakra UI hooks const bgColor = useColorModeValue('gray.50', 'gray.900'); // Ref:用于滚动到实时事件时间轴 const eventTimelineRef = useRef(null); const hasScrolledRef = useRef(false); // 标记是否已滚动 const containerRef = useRef(null); // 用于首次滚动到内容区域 // ⚡ 通知权限引导 const { showCommunityGuide } = useNotification(); // Modal/Drawer状态 const [selectedEvent, setSelectedEvent] = useState(null); const [selectedEventForStock, setSelectedEventForStock] = useState(null); // 🎯 初始化Community埋点Hook const communityEvents = useCommunityEvents({ navigate }); // 自定义 Hooks const { filters, updateFilters, handlePageChange, handleEventClick, handleViewDetail } = useEventFilters({ navigate, onEventClick: (event) => setSelectedEventForStock(event), eventTimelineRef }); const { events, pagination, loading, lastUpdateTime } = useEventData(filters); // 计算市场复盘的时间范围和过滤后的事件 const marketReviewData = useMemo(() => { const timeRange = getMarketReviewTimeRange(); const filteredEvents = filterEventsByTimeRange(events, timeRange.startTime, timeRange.endTime); logger.debug('Community', '市场复盘时间范围', { description: timeRange.description, rangeType: timeRange.rangeType, eventCount: filteredEvents.length }); return { events: filteredEvents, timeRange }; }, [events]); // 加载热门关键词和热点事件(动态新闻由 DynamicNewsCard 内部管理) useEffect(() => { dispatch(fetchPopularKeywords()); dispatch(fetchHotEvents()); }, [dispatch]); // 每5分钟刷新一次动态新闻(使用 prependMode 追加到头部) useEffect(() => { const interval = setInterval(() => { dispatch(fetchDynamicNews({ page: 1, per_page: 10, // 获取最新的10条 prependMode: true // 追加到头部,不清空缓存 })); }, 5 * 60 * 1000); return () => clearInterval(interval); }, [dispatch]); // 🎯 PostHog 追踪:页面浏览 // useEffect(() => { // track(RETENTION_EVENTS.COMMUNITY_PAGE_VIEWED, { // timestamp: new Date().toISOString(), // has_hot_events: hotEvents && hotEvents.length > 0, // has_keywords: popularKeywords && popularKeywords.length > 0, // }); // }, [track]); // 只在组件挂载时执行一次 // 🎯 追踪新闻列表查看(当事件列表加载完成后) useEffect(() => { if (events && events.length > 0 && !loading) { communityEvents.trackNewsListViewed({ totalCount: pagination?.total || events.length, sortBy: filters.sort, importance: filters.importance, dateRange: filters.date_range, industryFilter: filters.industry_code, }); } }, [events, loading, pagination, filters]); // ⚡ 首次访问社区时,延迟显示权限引导 useEffect(() => { if (showCommunityGuide) { const timer = setTimeout(() => { logger.info('Community', '显示社区权限引导'); showCommunityGuide(); }, 5000); // 延迟 5 秒,让用户先浏览页面 return () => clearTimeout(timer); } }, [showCommunityGuide]); // 只在组件挂载时执行一次 // ⚡ 首次进入页面时滚动到内容区域(考虑导航栏高度) useEffect(() => { // 延迟执行,确保DOM已完全渲染 const timer = setTimeout(() => { if (containerRef.current) { // 滚动到容器顶部,自动考虑导航栏的高度 containerRef.current.scrollIntoView({ behavior: 'auto', block: 'start', inline: 'nearest' }); } }, 0); return () => clearTimeout(timer); }, []); // 空依赖数组,只在组件挂载时执行一次 // ⚡ 滚动到实时事件区域(由搜索框聚焦触发) const scrollToTimeline = useCallback(() => { if (!hasScrolledRef.current && eventTimelineRef.current) { eventTimelineRef.current.scrollIntoView({ behavior: 'smooth', // 平滑滚动动画 block: 'start', // 元素顶部对齐视口顶部,标题正好可见 inline: 'nearest' // 水平方向最小滚动 }); hasScrolledRef.current = true; // 标记已滚动 logger.debug('Community', '用户触发搜索,滚动到实时事件时间轴'); } }, []); return ( {/* 主内容区域 */} {/* 热点事件区域 */} {/* 实时要闻·动态追踪 - 横向滚动 */} {/* 市场复盘 - 左右布局 */} {/* {}} /> */} {/* 实时事件 - 原纵向列表 */} {/* */} {/* 事件弹窗 */} setSelectedEvent(null), event: selectedEvent, onEventClose: () => setSelectedEvent(null) }} stockDrawerState={{ visible: !!selectedEventForStock, event: selectedEventForStock, onClose: () => setSelectedEventForStock(null) }} /> ); }; export default Community;