/* eslint-disable react-hooks/exhaustive-deps */ import { Clock, Target, Tv } 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; } export default function EpgScrollableRow({ programs, currentTime = new Date(), isLoading = false, }: EpgScrollableRowProps) { const containerRef = useRef(null); const [isHovered, setIsHovered] = useState(false); const [currentPlayingIndex, setCurrentPlayingIndex] = useState(-1); // 处理滚轮事件,实现横向滚动 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' }); } } } }; 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]); // 格式化时间显示 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; } }; // 加载中状态 if (isLoading) { return (

今日节目单

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

今日节目单

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

今日节目单

{currentPlayingIndex !== -1 && ( )}
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 && (
正在播放
)}
); })}
); }