136 lines
4.5 KiB
JavaScript
136 lines
4.5 KiB
JavaScript
// src/views/Community/index.js
|
||
import React, { useState, useEffect, useRef } from 'react';
|
||
import { useNavigate } from 'react-router-dom';
|
||
import { useSelector, useDispatch } from 'react-redux';
|
||
import { fetchPopularKeywords, fetchHotEvents } from '../../store/slices/communityDataSlice';
|
||
import {
|
||
Box,
|
||
Container,
|
||
useColorModeValue,
|
||
} from '@chakra-ui/react';
|
||
|
||
// 导入组件
|
||
import EventTimelineCard from './components/EventTimelineCard';
|
||
import HotEventsSection from './components/HotEventsSection';
|
||
import EventModals from './components/EventModals';
|
||
|
||
// 导入自定义 Hooks
|
||
import { useEventData } from './hooks/useEventData';
|
||
import { useEventFilters } from './hooks/useEventFilters';
|
||
|
||
import { logger } from '../../utils/logger';
|
||
import { useNotification } from '../../contexts/NotificationContext';
|
||
|
||
// 导航栏已由 MainLayout 提供,无需在此导入
|
||
|
||
const Community = () => {
|
||
const navigate = useNavigate();
|
||
const dispatch = useDispatch();
|
||
|
||
// Redux状态
|
||
const { popularKeywords, hotEvents } = useSelector(state => state.communityData);
|
||
|
||
// Chakra UI hooks
|
||
const bgColor = useColorModeValue('gray.50', 'gray.900');
|
||
|
||
// Ref:用于滚动到实时事件时间轴
|
||
const eventTimelineRef = useRef(null);
|
||
const hasScrolledRef = useRef(false); // 标记是否已滚动
|
||
|
||
// ⚡ 通知权限引导
|
||
const { showCommunityGuide } = useNotification();
|
||
|
||
// Modal/Drawer状态
|
||
const [selectedEvent, setSelectedEvent] = useState(null);
|
||
const [selectedEventForStock, setSelectedEventForStock] = useState(null);
|
||
|
||
// 自定义 Hooks
|
||
const { filters, updateFilters, handlePageChange, handleEventClick, handleViewDetail } = useEventFilters({
|
||
navigate,
|
||
onEventClick: (event) => setSelectedEventForStock(event),
|
||
eventTimelineRef
|
||
});
|
||
|
||
const { events, pagination, loading, lastUpdateTime } = useEventData(filters);
|
||
|
||
// 加载热门关键词和热点事件(使用Redux,内部有缓存判断)
|
||
useEffect(() => {
|
||
dispatch(fetchPopularKeywords());
|
||
dispatch(fetchHotEvents());
|
||
}, [dispatch]);
|
||
|
||
// ⚡ 首次访问社区时,延迟显示权限引导
|
||
useEffect(() => {
|
||
if (showCommunityGuide) {
|
||
const timer = setTimeout(() => {
|
||
logger.info('Community', '显示社区权限引导');
|
||
showCommunityGuide();
|
||
}, 5000); // 延迟 5 秒,让用户先浏览页面
|
||
|
||
return () => clearTimeout(timer);
|
||
}
|
||
}, [showCommunityGuide]); // 只在组件挂载时执行一次
|
||
|
||
// ⚡ 页面渲染完成后1秒,自动滚动到实时事件时间轴
|
||
useEffect(() => {
|
||
// 只在第一次数据加载完成后滚动
|
||
if (!loading && !hasScrolledRef.current && eventTimelineRef.current) {
|
||
const timer = setTimeout(() => {
|
||
if (eventTimelineRef.current) {
|
||
eventTimelineRef.current.scrollIntoView({
|
||
behavior: 'smooth', // 平滑滚动动画
|
||
block: 'start', // 元素顶部对齐视口顶部,标题正好可见
|
||
inline: 'nearest' // 水平方向最小滚动
|
||
});
|
||
hasScrolledRef.current = true; // 标记已滚动
|
||
logger.debug('Community', '页面渲染完成,自动滚动到实时事件时间轴(顶部对齐)');
|
||
}
|
||
}, 1000); // 渲染完成后延迟1秒
|
||
|
||
return () => clearTimeout(timer);
|
||
}
|
||
}, [loading]); // 监听 loading 状态变化
|
||
|
||
return (
|
||
<Box minH="100vh" bg={bgColor}>
|
||
{/* 主内容区域 */}
|
||
<Container maxW="container.xl" pt={6} pb={8}>
|
||
{/* 热点事件区域 */}
|
||
<HotEventsSection events={hotEvents} />
|
||
|
||
{/* 实时事件 */}
|
||
<EventTimelineCard
|
||
ref={eventTimelineRef}
|
||
mt={6}
|
||
events={events}
|
||
loading={loading}
|
||
pagination={pagination}
|
||
filters={filters}
|
||
popularKeywords={popularKeywords}
|
||
lastUpdateTime={lastUpdateTime}
|
||
onSearch={updateFilters}
|
||
onPageChange={handlePageChange}
|
||
onEventClick={handleEventClick}
|
||
onViewDetail={handleViewDetail}
|
||
/>
|
||
</Container>
|
||
|
||
{/* 事件弹窗 */}
|
||
<EventModals
|
||
eventModalState={{
|
||
isOpen: !!selectedEvent,
|
||
onClose: () => setSelectedEvent(null),
|
||
event: selectedEvent,
|
||
onEventClose: () => setSelectedEvent(null)
|
||
}}
|
||
stockDrawerState={{
|
||
visible: !!selectedEventForStock,
|
||
event: selectedEventForStock,
|
||
onClose: () => setSelectedEventForStock(null)
|
||
}}
|
||
/>
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
export default Community; |