diff --git a/src/views/Community/components/DynamicNewsCard.js b/src/views/Community/components/DynamicNewsCard.js index 2a4900b8..da1d0013 100644 --- a/src/views/Community/components/DynamicNewsCard.js +++ b/src/views/Community/components/DynamicNewsCard.js @@ -26,52 +26,20 @@ import UnifiedSearchBox from './UnifiedSearchBox'; import { fetchDynamicNews, toggleEventFollow, selectEventFollowStatus } from '../../../store/slices/communityDataSlice'; /** - * 实时要闻·动态追踪 - 事件展示卡片组件 - * @param {Array} allCachedEvents - 完整缓存事件列表(从 Redux 传入) - * @param {boolean} loading - 加载状态 - * @param {number} total - 服务端总数量 - * @param {number} cachedCount - 已缓存数量 - * @param {Object} filters - 筛选条件 - * @param {Array} popularKeywords - 热门关键词 - * @param {Date} lastUpdateTime - 最后更新时间 - * @param {Function} onSearch - 搜索回调 - * @param {Function} onSearchFocus - 搜索框获得焦点回调 - * @param {Function} onEventClick - 事件点击回调 - * @param {Function} onViewDetail - 查看详情回调 - * @param {Object} ref - 用于滚动的ref + * 分页逻辑自定义 Hook + * @param {Object} options - Hook 配置选项 + * @param {Array} options.allCachedEvents - 完整缓存事件列表 + * @param {number} options.total - 服务端总数量 + * @param {number} options.cachedCount - 已缓存数量 + * @param {Function} options.dispatch - Redux dispatch 函数 + * @param {Function} options.toast - Toast 通知函数 + * @returns {Object} 分页状态和方法 */ -const DynamicNewsCard = forwardRef(({ - allCachedEvents = [], - loading, - total = 0, - cachedCount = 0, - filters = {}, - popularKeywords = [], - lastUpdateTime, - onSearch, - onSearchFocus, - onEventClick, - onViewDetail, - ...rest -}, ref) => { - const dispatch = useDispatch(); - const toast = useToast(); - const cardBg = useColorModeValue('white', 'gray.800'); - const borderColor = useColorModeValue('gray.200', 'gray.700'); - - // 从 Redux 读取关注状态 - const eventFollowStatus = useSelector(selectEventFollowStatus); - - // 关注按钮点击处理 - const handleToggleFollow = useCallback((eventId) => { - dispatch(toggleEventFollow(eventId)); - }, [dispatch]); - +const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast }) => { // 本地状态 - const [selectedEvent, setSelectedEvent] = useState(null); - const [mode, setMode] = useState('carousel'); // 'carousel' 或 'grid',默认单排 - const [currentPage, setCurrentPage] = useState(1); // 当前页码 - const [loadingPage, setLoadingPage] = useState(null); // 正在加载的目标页码(用于 UX 提示) + const [currentPage, setCurrentPage] = useState(1); + const [loadingPage, setLoadingPage] = useState(null); + const [mode, setMode] = useState('carousel'); // 'carousel' 或 'grid' // 根据模式决定每页显示数量 const pageSize = mode === 'carousel' ? 5 : 10; @@ -335,6 +303,86 @@ const DynamicNewsCard = forwardRef(({ // 如果第1页数据完整,不发起请求,直接切换 }, [mode, allCachedEvents, total, dispatch]); + return { + // 状态 + currentPage, + mode, + loadingPage, + pageSize, + totalPages, + hasMore, + currentPageEvents, + + // 方法 + handlePageChange, + handleModeToggle + }; +}; + +/** + * 实时要闻·动态追踪 - 事件展示卡片组件 + * @param {Array} allCachedEvents - 完整缓存事件列表(从 Redux 传入) + * @param {boolean} loading - 加载状态 + * @param {number} total - 服务端总数量 + * @param {number} cachedCount - 已缓存数量 + * @param {Object} filters - 筛选条件 + * @param {Array} popularKeywords - 热门关键词 + * @param {Date} lastUpdateTime - 最后更新时间 + * @param {Function} onSearch - 搜索回调 + * @param {Function} onSearchFocus - 搜索框获得焦点回调 + * @param {Function} onEventClick - 事件点击回调 + * @param {Function} onViewDetail - 查看详情回调 + * @param {Object} ref - 用于滚动的ref + */ +const DynamicNewsCard = forwardRef(({ + allCachedEvents = [], + loading, + total = 0, + cachedCount = 0, + filters = {}, + popularKeywords = [], + lastUpdateTime, + onSearch, + onSearchFocus, + onEventClick, + onViewDetail, + ...rest +}, ref) => { + const dispatch = useDispatch(); + const toast = useToast(); + const cardBg = useColorModeValue('white', 'gray.800'); + const borderColor = useColorModeValue('gray.200', 'gray.700'); + + // 从 Redux 读取关注状态 + const eventFollowStatus = useSelector(selectEventFollowStatus); + + // 关注按钮点击处理 + const handleToggleFollow = useCallback((eventId) => { + dispatch(toggleEventFollow(eventId)); + }, [dispatch]); + + // 本地状态 + const [selectedEvent, setSelectedEvent] = useState(null); + + // 使用分页 Hook + const { + currentPage, + mode, + loadingPage, + pageSize, + totalPages, + hasMore, + currentPageEvents, + handlePageChange, + handleModeToggle + } = usePagination({ + allCachedEvents, + total, + cachedCount, + dispatch, + toast + }); + // 初始加载 useEffect(() => { if (allCachedEvents.length === 0) {