/* eslint-disable react-hooks/exhaustive-deps */ import { Clock, Target, Tv, List, BarChart3 } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; import { formatTimeToHHMM, parseCustomTimeFormat } from '@/lib/time'; interface EpgProgram { start: string; end: string; title: string; } interface EpgScrollableRowProps { programs: EpgProgram[]; currentTime?: Date; isLoading?: boolean; } type ViewMode = 'list' | 'timeline'; export default function EpgScrollableRow({ programs, currentTime = new Date(), isLoading = false, }: EpgScrollableRowProps) { const containerRef = useRef(null); const timelineHorizontalRef = useRef(null); const timelineVerticalRef = useRef(null); const [isHovered, setIsHovered] = useState(false); const [currentPlayingIndex, setCurrentPlayingIndex] = useState(-1); const [viewMode, setViewMode] = useState('list'); // 处理滚轮事件,实现横向滚动 const handleWheel = (e: WheelEvent) => { if (isHovered && containerRef.current) { e.preventDefault(); // 阻止默认的竖向滚动 const container = containerRef.current; const scrollAmount = e.deltaY * 4; // 增加滚动速度 // 根据滚轮方向进行横向滚动 container.scrollBy({ left: scrollAmount, behavior: 'smooth' }); } }; // 阻止页面竖向滚动 const preventPageScroll = (e: WheelEvent) => { if (isHovered) { e.preventDefault(); } }; // 自动滚动到正在播放的节目(列表视图) const scrollToCurrentProgram = () => { if (containerRef.current) { const currentProgramIndex = programs.findIndex(program => isCurrentlyPlaying(program)); if (currentProgramIndex !== -1) { const programElement = containerRef.current.children[currentProgramIndex] as HTMLElement; if (programElement) { const container = containerRef.current; const programLeft = programElement.offsetLeft; const containerWidth = container.clientWidth; const programWidth = programElement.offsetWidth; // 计算滚动位置,使正在播放的节目居中显示 const scrollLeft = programLeft - (containerWidth / 2) + (programWidth / 2); container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' }); } } } }; // 自动滚动到正在播放的节目(时间线视图) const scrollToCurrentProgramTimeline = () => { const currentProgramIndex = programs.findIndex(program => isCurrentlyPlaying(program)); if (currentProgramIndex === -1) return; // 横向时间线 if (timelineHorizontalRef.current && window.innerWidth >= 768) { const programElement = timelineHorizontalRef.current.children[currentProgramIndex] as HTMLElement; if (programElement) { const container = timelineHorizontalRef.current; const programLeft = programElement.offsetLeft; const containerWidth = container.clientWidth; const programWidth = programElement.offsetWidth; const scrollLeft = programLeft - (containerWidth / 2) + (programWidth / 2); container.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' }); } } // 竖向时间线 else if (timelineVerticalRef.current) { const programElement = timelineVerticalRef.current.children[currentProgramIndex] as HTMLElement; if (programElement) { // 找到包含滚动的父容器 const scrollContainer = timelineVerticalRef.current.parentElement; if (scrollContainer) { const programTop = programElement.offsetTop; const containerHeight = scrollContainer.clientHeight; const programHeight = programElement.offsetHeight; const scrollTop = programTop - (containerHeight / 2) + (programHeight / 2); scrollContainer.scrollTo({ top: Math.max(0, scrollTop), behavior: 'smooth' }); } } } }; useEffect(() => { if (isHovered) { // 鼠标悬停时阻止页面滚动 document.addEventListener('wheel', preventPageScroll, { passive: false }); document.addEventListener('wheel', handleWheel, { passive: false }); } else { // 鼠标离开时恢复页面滚动 document.removeEventListener('wheel', preventPageScroll); document.removeEventListener('wheel', handleWheel); } return () => { document.removeEventListener('wheel', preventPageScroll); document.removeEventListener('wheel', handleWheel); }; }, [isHovered]); // 组件加载后自动滚动到正在播放的节目 useEffect(() => { // 延迟执行,确保DOM完全渲染 const timer = setTimeout(() => { // 初始化当前正在播放的节目索引 const initialPlayingIndex = programs.findIndex(program => isCurrentlyPlaying(program)); setCurrentPlayingIndex(initialPlayingIndex); scrollToCurrentProgram(); }, 100); return () => clearTimeout(timer); }, [programs, currentTime]); // 定时刷新正在播放状态 useEffect(() => { // 每分钟刷新一次正在播放状态 const interval = setInterval(() => { // 更新当前正在播放的节目索引 const newPlayingIndex = programs.findIndex(program => { try { const start = parseCustomTimeFormat(program.start); const end = parseCustomTimeFormat(program.end); return currentTime >= start && currentTime < end; } catch { return false; } }); if (newPlayingIndex !== currentPlayingIndex) { setCurrentPlayingIndex(newPlayingIndex); // 如果正在播放的节目发生变化,自动滚动到新位置 scrollToCurrentProgram(); } }, 60000); // 60秒 = 1分钟 return () => clearInterval(interval); }, [programs, currentTime, currentPlayingIndex]); // 切换视图时自动跳转到当前播放位置 useEffect(() => { // 延迟执行,确保DOM完全渲染 const timer = setTimeout(() => { if (viewMode === 'list') { scrollToCurrentProgram(); } else if (viewMode === 'timeline') { scrollToCurrentProgramTimeline(); } }, 100); return () => clearTimeout(timer); }, [viewMode]); // 格式化时间显示 const formatTime = (timeString: string) => { return formatTimeToHHMM(timeString); }; // 判断节目是否正在播放 const isCurrentlyPlaying = (program: EpgProgram) => { try { const start = parseCustomTimeFormat(program.start); const end = parseCustomTimeFormat(program.end); return currentTime >= start && currentTime < end; } catch { return false; } }; // 计算节目时长(分钟) const getProgramDuration = (program: EpgProgram) => { try { const start = parseCustomTimeFormat(program.start); const end = parseCustomTimeFormat(program.end); return (end.getTime() - start.getTime()) / (1000 * 60); // 转换为分钟 } catch { return 30; // 默认30分钟 } }; // 计算当前时间在时间线上的位置百分比 const getCurrentTimePosition = () => { if (programs.length === 0) return 0; try { const firstProgram = programs[0]; const lastProgram = programs[programs.length - 1]; const startTime = parseCustomTimeFormat(firstProgram.start).getTime(); const endTime = parseCustomTimeFormat(lastProgram.end).getTime(); const currentTimeMs = currentTime.getTime(); if (currentTimeMs < startTime) return 0; if (currentTimeMs > endTime) return 100; return ((currentTimeMs - startTime) / (endTime - startTime)) * 100; } catch { return 0; } }; // 加载中状态 if (isLoading) { return (

今日节目单

加载节目单...
); } // 无节目单状态 if (!programs || programs.length === 0) { return (

今日节目单

暂无节目单数据
); } return (

今日节目单

{/* 视图切换按钮 */}
{/* 当前播放按钮 */} {currentPlayingIndex !== -1 && ( )}
{/* 列表视图 */} {viewMode === 'list' && (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} >
{programs.map((program, index) => { // 使用 currentPlayingIndex 来判断播放状态,确保样式能正确更新 const isPlaying = index === currentPlayingIndex; const isFinishedProgram = index < currentPlayingIndex; const isUpcomingProgram = index > currentPlayingIndex; return (
{/* 时间显示在顶部 */}
{formatTime(program.start)} {formatTime(program.end)}
{/* 标题在中间,占据剩余空间 */}
{program.title}
{/* 正在播放状态在底部 */} {isPlaying && (
正在播放
)}
); })}
)} {/* 时间线视图 */} {viewMode === 'timeline' && (
{/* 电脑端:横向时间线 */}
{/* 时间线容器 - 可横向滚动 */}
{ const container = timelineHorizontalRef.current; if (container) { const handleWheel = (e: WheelEvent) => { if (container.scrollWidth > container.clientWidth) { e.preventDefault(); container.scrollLeft += e.deltaY * 4; } }; container.addEventListener('wheel', handleWheel, { passive: false }); (container as any)._wheelHandler = handleWheel; } }} onMouseLeave={(e) => { const container = timelineHorizontalRef.current; if (container && (container as any)._wheelHandler) { container.removeEventListener('wheel', (container as any)._wheelHandler); delete (container as any)._wheelHandler; } }} >
{programs.map((program, index) => { const isPlaying = index === currentPlayingIndex; const isFinished = index < currentPlayingIndex; const duration = getProgramDuration(program); return (
{/* 节目信息卡片 */}
{formatTime(program.start)} {Math.round(duration)}分钟
{program.title}
{isPlaying && (
正在播放
)}
{/* 时间线轴 */}
{/* 时间点 */}
{/* 右侧连接线 */} {index < programs.length - 1 && (
)}
); })}
{/* 手机端:竖向时间线 */}
{/* 时间线容器 */}
{programs.map((program, index) => { const isPlaying = index === currentPlayingIndex; const isFinished = index < currentPlayingIndex; const duration = getProgramDuration(program); return (
{/* 时间线轴 */}
{/* 时间点 */}
{/* 连接线 - 根据状态显示不同颜色 */} {index < programs.length - 1 && (
)}
{/* 节目信息 */}
{formatTime(program.start)} {Math.round(duration)}分钟
{program.title}
{isPlaying && (
正在播放
)}
); })}
)}
); }