diff --git a/src/views/Community/components/DynamicNewsCard.js b/src/views/Community/components/DynamicNewsCard.js index 47d4e428..ac83554f 100644 --- a/src/views/Community/components/DynamicNewsCard.js +++ b/src/views/Community/components/DynamicNewsCard.js @@ -30,7 +30,13 @@ import { TimeIcon } from '@chakra-ui/icons'; import EventScrollList from './DynamicNewsCard/EventScrollList'; import DynamicNewsDetailPanel from './DynamicNewsDetail'; import UnifiedSearchBox from './UnifiedSearchBox'; -import { fetchDynamicNews, toggleEventFollow, selectEventFollowStatus } from '../../../store/slices/communityDataSlice'; +import { + fetchDynamicNews, + toggleEventFollow, + selectEventFollowStatus, + selectVerticalEventsWithLoading, + selectFourRowEventsWithLoading +} from '../../../store/slices/communityDataSlice'; import { usePagination } from './DynamicNewsCard/hooks/usePagination'; import { PAGINATION_CONFIG } from './DynamicNewsCard/constants'; @@ -39,10 +45,6 @@ let dynamicNewsCardRenderCount = 0; /** * 实时要闻·动态追踪 - 事件展示卡片组件 - * @param {Array} allCachedEvents - 完整缓存事件列表(从 Redux 传入) - * @param {boolean} loading - 加载状态 - * @param {number} total - 服务端总数量 - * @param {number} cachedCount - 已缓存数量 * @param {Object} filters - 筛选条件 * @param {Array} popularKeywords - 热门关键词 * @param {Date} lastUpdateTime - 最后更新时间 @@ -53,11 +55,6 @@ let dynamicNewsCardRenderCount = 0; * @param {Object} ref - 用于滚动的ref */ const DynamicNewsCard = forwardRef(({ - allCachedEvents = [], - loading, - error, - total = 0, - cachedCount = 0, filters = {}, popularKeywords = [], lastUpdateTime, @@ -67,9 +64,6 @@ const DynamicNewsCard = forwardRef(({ onViewDetail, ...rest }, ref) => { - // 🔍 调试:记录每次渲染 - dynamicNewsCardRenderCount++; - console.log(`%c🔍 [DynamicNewsCard] 渲染 #${dynamicNewsCardRenderCount} - allCachedEvents.length=${allCachedEvents.length}, total=${total}`, 'color: #FF9800; font-weight: bold; font-size: 14px;'); const dispatch = useDispatch(); const toast = useToast(); const cardBg = useColorModeValue('white', 'gray.800'); @@ -78,6 +72,47 @@ const DynamicNewsCard = forwardRef(({ // 从 Redux 读取关注状态 const eventFollowStatus = useSelector(selectEventFollowStatus); + // 本地状态:模式(先初始化,后面会被 usePagination 更新) + const [currentMode, setCurrentMode] = useState('vertical'); + + // 根据当前模式从 Redux 读取对应的数据(添加默认值避免 undefined) + const verticalData = useSelector(selectVerticalEventsWithLoading) || {}; + const fourRowData = useSelector(selectFourRowEventsWithLoading) || {}; + + // 🔍 调试:从 Redux 读取数据 + console.log('%c[DynamicNewsCard] 从 Redux 读取数据', 'color: #3B82F6; font-weight: bold;', { + currentMode, + 'verticalData.data?.length': verticalData.data?.length || 0, + 'verticalData.total': verticalData.total, + 'verticalData.cachedCount': verticalData.cachedCount, + 'verticalData.loading': verticalData.loading, + 'fourRowData.data?.length': fourRowData.data?.length || 0, + 'fourRowData.total': fourRowData.total, + }); + + // 根据模式选择数据源(添加默认值避免解构失败) + const { + data: allCachedEvents = [], + loading = false, + error = null, + total = 0, + cachedCount = 0 + } = currentMode === 'four-row' ? fourRowData : verticalData; + + // 🔍 调试:选择的数据源 + console.log('%c[DynamicNewsCard] 选择的数据源', 'color: #3B82F6; font-weight: bold;', { + mode: currentMode, + 'allCachedEvents.length': allCachedEvents.length, + total, + cachedCount, + loading, + error + }); + + // 🔍 调试:记录每次渲染 + dynamicNewsCardRenderCount++; + console.log(`%c🔍 [DynamicNewsCard] 渲染 #${dynamicNewsCardRenderCount} - mode=${currentMode}, allCachedEvents.length=${allCachedEvents.length}, total=${total}`, 'color: #FF9800; font-weight: bold; font-size: 14px;'); + // 关注按钮点击处理 const handleToggleFollow = useCallback((eventId) => { dispatch(toggleEventFollow(eventId)); @@ -94,6 +129,8 @@ const DynamicNewsCard = forwardRef(({ const hasInitialized = useRef(false); // 追踪是否已自动选中过首个事件 const hasAutoSelectedFirstEvent = useRef(false); + // 追踪筛选条件 useEffect 是否是第一次渲染(避免初始加载时重复请求) + const isFirstRenderForFilters = useRef(true); // 使用分页 Hook const { @@ -119,6 +156,24 @@ const DynamicNewsCard = forwardRef(({ filters // 传递筛选条件 }); + // 同步 mode 到 currentMode + useEffect(() => { + setCurrentMode(mode); + }, [mode]); + + // 监听 error 状态,显示空数据提示 + useEffect(() => { + if (error && error.includes('暂无更多数据')) { + toast({ + title: '提示', + description: error, + status: 'info', + duration: 2000, + isClosable: true, + }); + } + }, [error, toast]); + // 四排模式的事件点击处理(打开弹窗) const handleFourRowEventClick = useCallback((event) => { console.log('%c🔲 [四排模式] 点击事件,打开详情弹窗', 'color: #8B5CF6; font-weight: bold;', { eventId: event.id, title: event.title }); @@ -126,34 +181,42 @@ const DynamicNewsCard = forwardRef(({ onModalOpen(); }, [onModalOpen]); - // 初始加载 - 只在组件首次挂载且未初始化时执行 + // 初始加载 - 只在组件首次挂载且对应模式数据为空时执行 useEffect(() => { if (!hasInitialized.current && allCachedEvents.length === 0) { hasInitialized.current = true; dispatch(fetchDynamicNews({ - page: PAGINATION_CONFIG.INITIAL_PAGE, - per_page: PAGINATION_CONFIG.CAROUSEL_PAGE_SIZE, - pageSize: PAGINATION_CONFIG.CAROUSEL_PAGE_SIZE, // 传递 pageSize 确保索引计算一致 + mode: mode, // 传递当前模式 + per_page: pageSize, + pageSize: pageSize, // 传递 pageSize 确保索引计算一致 clearCache: true, - ...filters // 应用初始筛选条件 + ...filters, // 先展开筛选条件 + page: PAGINATION_CONFIG.INITIAL_PAGE, // 然后覆盖 page 参数 })); } - }, [dispatch, allCachedEvents.length]); + }, [dispatch, allCachedEvents.length, mode, pageSize]); // ✅ 移除 filters 依赖,避免重复触发 // 监听筛选条件变化 - 清空缓存并重新请求数据 useEffect(() => { // 跳过初始加载(由上面的 useEffect 处理) if (!hasInitialized.current) return; + // 跳过第一次渲染(避免与初始加载 useEffect 重复) + if (isFirstRenderForFilters.current) { + isFirstRenderForFilters.current = false; + return; + } + console.log('%c🔍 [筛选] 筛选条件改变,重新请求数据', 'color: #8B5CF6; font-weight: bold;', filters); - // 筛选条件改变时,清空缓存并从第1页开始加载 + // 筛选条件改变时,清空对应模式的缓存并从第1页开始加载 dispatch(fetchDynamicNews({ - page: PAGINATION_CONFIG.INITIAL_PAGE, + mode: mode, // 传递当前模式 per_page: pageSize, pageSize: pageSize, clearCache: true, // 清空缓存 - ...filters // 应用新的筛选条件 + ...filters, // 先展开筛选条件 + page: PAGINATION_CONFIG.INITIAL_PAGE, // 然后覆盖 page 参数 })); }, [ filters.sort, @@ -161,9 +224,26 @@ const DynamicNewsCard = forwardRef(({ filters.q, filters.date_range, filters.industry_code, + mode, // 添加 mode 到依赖 + pageSize, // 添加 pageSize 到依赖 dispatch ]); // 只监听筛选参数的变化,不监听 page + // 监听模式切换 - 如果新模式数据为空,请求数据 + useEffect(() => { + if (hasInitialized.current && allCachedEvents.length === 0) { + console.log(`%c🔄 [模式切换] ${mode} 模式数据为空,开始加载`, 'color: #8B5CF6; font-weight: bold;'); + dispatch(fetchDynamicNews({ + mode: mode, + per_page: pageSize, + pageSize: pageSize, + clearCache: true, + ...filters, // 先展开筛选条件 + page: PAGINATION_CONFIG.INITIAL_PAGE, // 然后覆盖 page 参数 + })); + } + }, [mode]); // 只监听 mode 变化 + // 自动选中逻辑 - 只在首次加载时自动选中第一个事件,翻页时不自动选中 useEffect(() => { if (currentPageEvents.length > 0) {