// src/views/Community/index.js
import React, { useEffect, useRef, lazy, Suspense } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import {
fetchPopularKeywords,
fetchHotEvents
} from '@/store/slices/communityDataSlice';
import {
Box,
Container,
useColorModeValue,
useBreakpointValue,
Skeleton,
} from '@chakra-ui/react';
// 导入组件
import DynamicNewsCard from './components/DynamicNewsCard';
import HotEventsSection from './components/HotEventsSection';
// ⚡ HeroPanel 懒加载:包含 ECharts (~600KB),首屏不需要立即渲染
const HeroPanel = lazy(() => import('./components/HeroPanel'));
// 导入自定义 Hooks
import { useEventData } from './hooks/useEventData';
import { useEventFilters } from './hooks/useEventFilters';
import { useCommunityEvents } from './hooks/useCommunityEvents';
import { logger } from '@/utils/logger';
import { useNotification } from '@/contexts/NotificationContext';
import { PROFESSIONAL_COLORS } from '@/constants/professionalTheme';
import { flushPendingEventsBeforeUnload } from '@/utils/trackingHelpers';
// 导航栏已由 MainLayout 提供,无需在此导入
const Community = () => {
const navigate = useNavigate();
const location = useLocation(); // ⚡ 获取当前路由信息(用于判断是否在 /community 页面)
const dispatch = useDispatch();
// Redux状态
const { popularKeywords, hotEvents } = useSelector(state => state.communityData);
// 专业配色 - 深色主题
const bgColor = PROFESSIONAL_COLORS.background.primary;
// Ref:用于首次滚动到内容区域
const containerRef = useRef(null);
// 响应式容器宽度
const containerMaxW = useBreakpointValue({
base: '100%', // 移动端:全宽
sm: '100%', // 小屏:全宽
md: '100%', // 中屏:全宽
lg: '1200px', // 大屏:1200px
xl: '1400px', // 超大屏:1400px
});
// 响应式内边距
const containerPx = useBreakpointValue({
base: 2, // 移动端:最小内边距
sm: 3,
md: 4,
lg: 6,
});
// ⚡ 通知权限引导
const { browserPermission, requestBrowserPermission, registerEventUpdateCallback } = useNotification();
// ⚡ DynamicNewsCard 的 ref(用于触发刷新)
const dynamicNewsCardRef = useRef(null);
// 🎯 初始化Community埋点Hook
const communityEvents = useCommunityEvents({ navigate });
// 自定义 Hooks
const { filters, updateFilters, handlePageChange, handleEventClick, handleViewDetail } = useEventFilters({
navigate
});
const { events, pagination, loading, lastUpdateTime } = useEventData(filters);
// 加载热门关键词和热点事件(动态新闻由 DynamicNewsCard 内部管理)
useEffect(() => {
dispatch(fetchPopularKeywords());
dispatch(fetchHotEvents());
}, [dispatch]);
// ⚡ 页面卸载前刷新待发送的 PostHog 事件(性能优化)
useEffect(() => {
window.addEventListener('beforeunload', flushPendingEventsBeforeUnload);
return () => {
window.removeEventListener('beforeunload', flushPendingEventsBeforeUnload);
};
}, []);
// 🎯 追踪新闻列表查看(当事件列表加载完成后)
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]);
/**
* ⚡ 【核心逻辑】注册 Socket 新事件回调 - 当收到新事件时智能刷新列表
*
* 工作流程:
* 1. Socket 收到 'new_event' 事件 → NotificationContext 触发所有注册的回调
* 2. 本回调被触发 → 检查当前路由是否为 /community
* 3. 如果在 /community 页面 → 调用 DynamicNewsCard.refresh() 方法
* 4. DynamicNewsCard 根据模式和滚动位置决定是否刷新:
* - 纵向模式 + 第1页 → 刷新列表
* - 纵向模式 + 其他页 → 不刷新(避免打断用户)
* - 平铺模式 + 滚动在顶部 → 刷新列表
* - 平铺模式 + 滚动不在顶部 → 仅显示 Toast 提示
*
* 设计要点:
* - 使用 registerEventUpdateCallback 注册回调,返回的函数用于清理
* - 路由检查:只在 /community 页面触发刷新
* - 智能刷新:由 DynamicNewsCard 根据上下文决定刷新策略
* - 自动清理:组件卸载时自动注销回调
*/
useEffect(() => {
// 定义回调函数
const handleNewEvent = (eventData) => {
console.log('[Community] 🔔 收到新事件通知', {
currentPath: location.pathname,
eventData,
});
// 检查是否在 /community 页面
if (location.pathname === '/community') {
console.log('[Community] ✅ 当前在事件中心页面,触发 DynamicNewsCard 刷新');
// 调用 DynamicNewsCard 的 refresh 方法(智能刷新)
if (dynamicNewsCardRef.current) {
dynamicNewsCardRef.current.refresh();
} else {
console.warn('[Community] ⚠️ DynamicNewsCard ref 不可用,无法触发刷新');
}
} else {
console.log('[Community] ⏭️ 当前不在事件中心页面,跳过刷新', {
currentPath: location.pathname,
});
}
};
// 注册回调(返回清理函数)
const unregister = registerEventUpdateCallback(handleNewEvent);
console.log('[Community] ✅ 已注册 Socket 事件更新回调');
// 组件卸载时清理
return () => {
if (unregister) {
unregister();
console.log('[Community] 🧹 已注销 Socket 事件更新回调');
}
};
}, [location.pathname, registerEventUpdateCallback]); // 依赖路由变化重新注册
return (
{/* 主内容区域 */}
{/* ⚡ 顶部说明面板(懒加载):产品介绍 + 沪深指数 + 热门概念词云 */}
}>
{/* 实时要闻·动态追踪 - 横向滚动 */}
{/* 热点事件区域 - 移至底部 */}
);
};
export default Community;