Files
vf_react/src/views/Community/components/DynamicNewsCard/EventScrollList.js

190 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/views/Community/components/DynamicNewsCard/EventScrollList.js
// 横向滚动事件列表组件
import React, { useRef } from 'react';
import {
Box,
Flex,
useColorModeValue
} from '@chakra-ui/react';
import PaginationControl from './PaginationControl';
import VirtualizedFourRowGrid from './VirtualizedFourRowGrid';
import PageNavigationButton from './PageNavigationButton';
import ModeToggleButtons from './ModeToggleButtons';
import VerticalModeLayout from './VerticalModeLayout';
/**
* 事件列表组件 - 支持纵向和平铺两种展示模式
* @param {Array} events - 当前页的事件列表(服务端已分页)
* @param {Object} selectedEvent - 当前选中的事件
* @param {Function} onEventSelect - 事件选择回调
* @param {string} borderColor - 边框颜色
* @param {number} currentPage - 当前页码
* @param {number} totalPages - 总页数(由服务端返回)
* @param {Function} onPageChange - 页码改变回调
* @param {boolean} loading - 全局加载状态
* @param {number|null} loadingPage - 正在加载的目标页码(用于显示"正在加载第X页..."
* @param {string} mode - 展示模式:'vertical'(纵向分栏)| 'four-row'(平铺网格)
* @param {Function} onModeChange - 模式切换回调
* @param {boolean} hasMore - 是否还有更多数据
* @param {Object} eventFollowStatus - 事件关注状态 { [eventId]: { isFollowing, followerCount } }
* @param {Function} onToggleFollow - 关注按钮回调
*/
const EventScrollList = ({
events,
displayEvents, // 累积显示的事件列表(四排模式用)
isAccumulateMode, // 是否累积模式
loadNextPage, // 加载下一页(无限滚动)
loadPrevPage, // 加载上一页(双向无限滚动)
onFourRowEventClick, // 四排模式事件点击回调(打开弹窗)
selectedEvent,
onEventSelect,
borderColor,
currentPage,
totalPages,
onPageChange,
loading = false,
mode = 'vertical',
onModeChange,
hasMore = true,
eventFollowStatus = {},
onToggleFollow
}) => {
const scrollContainerRef = useRef(null);
// 所有 useColorModeValue 必须在组件顶层调用(不能在条件渲染中)
const timelineBg = useColorModeValue('gray.50', 'gray.700');
const timelineBorderColor = useColorModeValue('gray.400', 'gray.500');
const timelineTextColor = useColorModeValue('blue.600', 'blue.400');
// 滚动条颜色
const scrollbarTrackBg = useColorModeValue('#f1f1f1', '#2D3748');
const scrollbarThumbBg = useColorModeValue('#888', '#4A5568');
const scrollbarThumbHoverBg = useColorModeValue('#555', '#718096');
const getTimelineBoxStyle = () => {
return {
bg: timelineBg,
borderColor: timelineBorderColor,
borderWidth: '2px',
textColor: timelineTextColor,
boxShadow: 'sm',
};
};
return (
<Box>
{/* 顶部控制栏:模式切换按钮(左)+ 分页控制器(右) */}
<Flex justify="space-between" align="center" mb={2}>
{/* 模式切换按钮 */}
<ModeToggleButtons mode={mode} onModeChange={onModeChange} />
{/* 分页控制器(平铺模式不显示,使用无限滚动) */}
{totalPages > 1 && mode !== 'four-row' && (
<PaginationControl
currentPage={currentPage}
totalPages={totalPages}
onPageChange={onPageChange}
/>
)}
</Flex>
{/* 横向滚动区域 */}
<Box position="relative">
{/* 翻页导航按钮(平铺模式不显示,使用无限滚动) */}
{mode !== 'four-row' && (
<>
<PageNavigationButton
direction="prev"
currentPage={currentPage}
totalPages={totalPages}
onPageChange={onPageChange}
mode={mode}
/>
<PageNavigationButton
direction="next"
currentPage={currentPage}
totalPages={totalPages}
onPageChange={onPageChange}
mode={mode}
/>
</>
)}
{/* 事件卡片容器 */}
<Box
ref={scrollContainerRef}
overflowX="hidden"
overflowY="hidden"
maxH={mode === 'vertical' ? '820px' : 'none'}
pt={0}
pb={4}
px={2}
position="relative"
css={{
// 统一滚动条样式(支持横向和纵向)
'&::-webkit-scrollbar': {
width: '1px',
height: '1px',
},
'&::-webkit-scrollbar-track': {
background: scrollbarTrackBg,
borderRadius: '10px',
},
'&::-webkit-scrollbar-thumb': {
background: scrollbarThumbBg,
borderRadius: '10px',
},
'&::-webkit-scrollbar-thumb:hover': {
background: scrollbarThumbHoverBg,
},
scrollBehavior: 'smooth',
WebkitOverflowScrolling: 'touch',
}}
>
{/* 平铺网格模式 - 使用虚拟滚动 + 双向无限滚动 */}
{mode === 'four-row' && (
<VirtualizedFourRowGrid
events={displayEvents || events} // 使用累积列表(如果有)
selectedEvent={selectedEvent}
onEventSelect={onFourRowEventClick} // 四排模式点击打开弹窗
eventFollowStatus={eventFollowStatus}
onToggleFollow={onToggleFollow}
getTimelineBoxStyle={getTimelineBoxStyle}
borderColor={borderColor}
loadNextPage={loadNextPage} // 加载下一页
loadPrevPage={loadPrevPage} // 加载上一页(双向滚动)
hasMore={hasMore} // 是否还有更多数据
loading={loading} // 加载状态
/>
)}
{/* 纵向分栏模式 */}
{mode === 'vertical' && (
<VerticalModeLayout
displayEvents={displayEvents}
events={events}
selectedEvent={selectedEvent}
onEventSelect={onEventSelect}
eventFollowStatus={eventFollowStatus}
onToggleFollow={onToggleFollow}
getTimelineBoxStyle={getTimelineBoxStyle}
borderColor={borderColor}
loadNextPage={loadNextPage}
loadPrevPage={loadPrevPage}
hasMore={hasMore}
loading={loading}
scrollbarTrackBg={scrollbarTrackBg}
scrollbarThumbBg={scrollbarThumbBg}
scrollbarThumbHoverBg={scrollbarThumbHoverBg}
/>
)}
</Box>
</Box>
</Box>
);
};
export default EventScrollList;