/* eslint-disable @next/next/no-img-element */ import React, { useState, useMemo } from 'react'; interface DownloadEpisodeSelectorProps { /** 是否显示弹窗 */ isOpen: boolean; /** 关闭弹窗回调 */ onClose: () => void; /** 总集数 */ totalEpisodes: number; /** 剧集标题 */ episodesTitles?: string[]; /** 视频标题 */ videoTitle: string; /** 当前集数索引(0开始) */ currentEpisodeIndex: number; /** 下载回调 - 支持批量下载 */ onDownload: (episodeIndexes: number[], offlineMode: boolean) => void; /** 是否启用离线下载功能 */ enableOfflineDownload?: boolean; /** 是否有离线下载权限(管理员或站长) */ hasOfflinePermission?: boolean; } /** * 下载选集面板组件 */ const DownloadEpisodeSelector: React.FC = ({ isOpen, onClose, totalEpisodes, episodesTitles = [], videoTitle, currentEpisodeIndex, onDownload, enableOfflineDownload = false, hasOfflinePermission = false, }) => { // 多选状态 - 使用 Set 存储选中的集数索引 const [selectedEpisodes, setSelectedEpisodes] = useState>( new Set([currentEpisodeIndex]) ); // 离线下载模式 const [offlineMode, setOfflineMode] = useState(false); // 每页显示的集数 const episodesPerPage = 50; const pageCount = Math.ceil(totalEpisodes / episodesPerPage); // 当前分页索引(0 开始) const initialPage = Math.floor(currentEpisodeIndex / episodesPerPage); const [currentPage, setCurrentPage] = useState(initialPage); // 是否倒序显示 const [descending, setDescending] = useState(false); // 根据 descending 状态计算实际显示的分页索引 const displayPage = useMemo(() => { if (descending) { return pageCount - 1 - currentPage; } return currentPage; }, [currentPage, descending, pageCount]); // 升序分页标签 const categoriesAsc = useMemo(() => { return Array.from({ length: pageCount }, (_, i) => { const start = i * episodesPerPage + 1; const end = Math.min(start + episodesPerPage - 1, totalEpisodes); return { start, end }; }); }, [pageCount, episodesPerPage, totalEpisodes]); // 根据 descending 状态决定分页标签的排序和内容 const categories = useMemo(() => { if (descending) { return [...categoriesAsc] .reverse() .map(({ start, end }) => `${end}-${start}`); } return categoriesAsc.map(({ start, end }) => `${start}-${end}`); }, [categoriesAsc, descending]); const handleCategoryClick = (index: number) => { if (descending) { setCurrentPage(pageCount - 1 - index); } else { setCurrentPage(index); } }; const handleEpisodeClick = (episodeIndex: number) => { setSelectedEpisodes((prev) => { const newSet = new Set(prev); if (newSet.has(episodeIndex)) { newSet.delete(episodeIndex); } else { newSet.add(episodeIndex); } return newSet; }); }; const handleSelectAll = () => { const allEpisodes = Array.from({ length: totalEpisodes }, (_, i) => i); setSelectedEpisodes(new Set(allEpisodes)); }; const handleClearAll = () => { setSelectedEpisodes(new Set()); }; const handleDownload = () => { const episodeIndexes = Array.from(selectedEpisodes).sort((a, b) => a - b); onDownload(episodeIndexes, offlineMode); onClose(); }; const currentStart = currentPage * episodesPerPage; const currentEnd = Math.min(currentStart + episodesPerPage - 1, totalEpisodes - 1); if (!isOpen) return null; return (
{/* 标题栏 */}

选择要下载的集数

{videoTitle}

{/* 离线下载开关 - 仅管理员和站长可见 */} {enableOfflineDownload && hasOfflinePermission && (
{/* 服务器图标 */}

服务器离线下载

{offlineMode && ( 已启用 )}

开启后将在服务器端下载视频文件,支持断点续传和后台下载

{/* 开关 */}
)} {/* 分页标签 */} {pageCount > 1 && (
{categories.map((label, idx) => { const isActive = idx === displayPage; return ( ); })}
{/* 向上/向下按钮 */}
)} {/* 集数网格 */}
{(() => { const len = currentEnd - currentStart + 1; const episodes = Array.from({ length: len }, (_, i) => descending ? currentEnd - i : currentStart + i ); return episodes; })().map((episodeIndex) => { const isSelected = selectedEpisodes.has(episodeIndex); const isCurrent = episodeIndex === currentEpisodeIndex; const episodeNumber = episodeIndex + 1; return ( ); })}
{/* 底部操作栏 */}
已选择: {selectedEpisodes.size === 0 ? ( 未选择任何集数 ) : selectedEpisodes.size === 1 ? ( <> 第 {Array.from(selectedEpisodes)[0] + 1} 集 {Array.from(selectedEpisodes)[0] === currentEpisodeIndex && ( (当前播放) )} ) : ( {selectedEpisodes.size} 集 )}
); }; export default DownloadEpisodeSelector;