import React, { useState, useEffect, useContext, useCallback, useRef } from 'react'; import axios from 'axios'; import Container from '@mui/material/Container'; import Grid from '@mui/material/Grid'; import Pagination from '@mui/material/Pagination'; import { Link } from 'react-router-dom'; import CircularProgress from '@mui/material/CircularProgress'; import TextField from '@mui/material/TextField'; import InputAdornment from '@mui/material/InputAdornment'; import IconButton from '@mui/material/IconButton'; import SearchIcon from '@mui/icons-material/Search'; import ClearIcon from '@mui/icons-material/Clear'; import ConfigContext from './Config'; import MovieCard from './components/MovieCard'; import CategoryNav from './components/CategoryNav'; const categories = [ { label: '15min', value: '15min' }, { label: '30min', value: '30min' }, { label: '60min', value: '60min' }, { label: '大于60min', value: '大于60min' }, { label: '最新添加', value: '最新添加' }, ]; // 新增搜索类别常量 const SEARCH_CATEGORY = 'search'; const LIMIT = 20; const DEFAULT_CATEGORY = categories[0].value; const usePersistedState = (key, defaultValue) => { const [state, setState] = useState(() => { const stored = localStorage.getItem(key); return stored ? JSON.parse(stored) : defaultValue; }); useEffect(() => { localStorage.setItem(key, JSON.stringify(state)); }, [key, state]); return [state, setState]; }; const Main = () => { const config = useContext(ConfigContext); const [loading, setLoading] = useState(false); const isFirstLoad = useRef(true); const scrollListenerActive = useRef(false); // 初始化状态 - 添加搜索相关状态 const [params, setParams] = usePersistedState('params', { lastCategory: DEFAULT_CATEGORY, history: Object.fromEntries([ ...categories.map(cat => [ cat.value, { lastPage: 1, scrollPos: 0 } ]), // 为搜索添加单独的历史记录 [SEARCH_CATEGORY, { lastPage: 1, scrollPos: 0 }] ]), // 新增搜索查询状态 searchQuery: '' }); const [movies, setMovies] = useState([]); const [pagination, setPagination] = useState({ page: 1, total: 0, pages: 1 }); const currentCategory = params.lastCategory || DEFAULT_CATEGORY; // 新增搜索输入状态 const [searchInput, setSearchInput] = useState(params.searchQuery || ''); // 滚动位置处理 const saveScrollPosition = useCallback((category = currentCategory) => { const currentScrollPos = window.scrollY; setParams(prev => { const updatedHistory = { ...prev.history, [category]: { ...(prev.history[category] || { lastPage: 1, scrollPos: 0 }), scrollPos: currentScrollPos } }; return { ...prev, history: updatedHistory }; }); }, [setParams, currentCategory]); const setupScrollListener = useCallback(() => { if (scrollListenerActive.current) return; const handleScroll = () => { clearTimeout(window.scrollTimer); window.scrollTimer = setTimeout(() => saveScrollPosition(), 100); }; window.addEventListener('scroll', handleScroll); scrollListenerActive.current = true; return () => { window.removeEventListener('scroll', handleScroll); clearTimeout(window.scrollTimer); scrollListenerActive.current = false; }; }, [saveScrollPosition]); const removeScrollListener = useCallback(() => { if (scrollListenerActive.current) { window.removeEventListener('scroll', window.scrollHandler); scrollListenerActive.current = false; } }, []); // 修改fetchMovies以支持搜索 const fetchMovies = useCallback(async (category, page, search = '') => { setLoading(true); try { const isSearch = category === SEARCH_CATEGORY; const isLatest = category === '最新添加'; let apiUrl = `/movie/list?page=${page}&limit=${LIMIT}`; if (isSearch) { // 搜索请求 apiUrl += `&search=${encodeURIComponent(search)}`; } else if (isLatest) { // 最新添加请求 apiUrl += `&sort=created_time&order=desc`; } else { // 分类请求 apiUrl += `&category=${encodeURIComponent(category)}`; } const response = await axios.get(apiUrl); if (response.status !== 200) return; const { items, total } = response.data.data; const totalPages = Math.ceil(total / LIMIT); if (items.length === 0 && page > 1) { setParams(prev => ({ ...prev, history: { ...prev.history, [category]: { ...prev.history[category], lastPage: page - 1 } } })); return; } setMovies(items); setPagination({ page, total, pages: totalPages }); } catch (error) { console.error('Error fetching movies:', error); } finally { setLoading(false); } }, [setParams]); // 恢复滚动位置 const restoreScrollPosition = useCallback((category) => { const scrollPos = params.history?.[category]?.scrollPos || 0; requestAnimationFrame(() => { setTimeout(() => window.scrollTo(0, scrollPos), 100); }); }, [params.history]); // 初始加载 useEffect(() => { if (!isFirstLoad.current) return; const category = currentCategory; const categoryHistory = params.history[category] || { lastPage: 1 }; // 如果是搜索类别,传递搜索查询 if (category === SEARCH_CATEGORY) { fetchMovies(category, categoryHistory.lastPage, params.searchQuery); } else { fetchMovies(category, categoryHistory.lastPage); } isFirstLoad.current = false; }, [fetchMovies, currentCategory, params.history, params.searchQuery]); // 数据加载完成后处理 useEffect(() => { if (loading || isFirstLoad.current) return; restoreScrollPosition(currentCategory); setupScrollListener(); }, [loading, restoreScrollPosition, currentCategory, setupScrollListener]); // 类别切换处理 - 修改以支持搜索类别 const handleCategoryChange = useCallback((newCategory) => { removeScrollListener(); saveScrollPosition(); setParams(prev => { const categoryHistory = prev.history[newCategory] || { lastPage: 1 }; // 如果是搜索类别,使用保存的搜索查询 if (newCategory === SEARCH_CATEGORY) { fetchMovies(newCategory, categoryHistory.lastPage, prev.searchQuery); } else { fetchMovies(newCategory, categoryHistory.lastPage); } return { ...prev, lastCategory: newCategory }; }); }, [removeScrollListener, saveScrollPosition, setParams, fetchMovies]); // 分页处理 - 修改以支持搜索 const handlePageChange = useCallback((_, page) => { removeScrollListener(); saveScrollPosition(); setParams(prev => ({ ...prev, history: { ...prev.history, [currentCategory]: { ...prev.history[currentCategory], lastPage: page, scrollPos: 0 } } })); // 如果是搜索类别,传递搜索查询 if (currentCategory === SEARCH_CATEGORY) { fetchMovies(currentCategory, page, params.searchQuery); } else { fetchMovies(currentCategory, page); } window.scrollTo(0, 0); }, [removeScrollListener, saveScrollPosition, setParams, fetchMovies, currentCategory, params.searchQuery]); // 电影卡片点击处理 const handleMovieCardClick = useCallback(() => { removeScrollListener(); saveScrollPosition(); }, [removeScrollListener, saveScrollPosition]); // 新增:处理搜索提交 const handleSearchSubmit = useCallback(() => { if (!searchInput.trim()) return; removeScrollListener(); saveScrollPosition(); setParams(prev => { // 更新搜索查询并切换到搜索类别 const updatedParams = { ...prev, lastCategory: SEARCH_CATEGORY, searchQuery: searchInput.trim(), history: { ...prev.history, [SEARCH_CATEGORY]: { ...prev.history[SEARCH_CATEGORY], lastPage: 1 // 新搜索总是从第一页开始 } } }; // 执行搜索请求 fetchMovies(SEARCH_CATEGORY, 1, searchInput.trim()); return updatedParams; }); }, [removeScrollListener, saveScrollPosition, setParams, fetchMovies, searchInput]); // 新增:清除搜索 const handleClearSearch = useCallback(() => { if (!searchInput) return; setSearchInput(''); // 如果当前在搜索类别,则清除后切换到默认类别 if (currentCategory === SEARCH_CATEGORY) { setParams(prev => ({ ...prev, lastCategory: DEFAULT_CATEGORY, searchQuery: '' })); // 获取默认类别的数据 const categoryHistory = params.history[DEFAULT_CATEGORY] || { lastPage: 1 }; fetchMovies(DEFAULT_CATEGORY, categoryHistory.lastPage); } else { // 不在搜索类别,只清除输入框 setParams(prev => ({ ...prev, searchQuery: '' })); } }, [currentCategory, fetchMovies, params.history, searchInput, setParams]); // 新增:处理搜索输入变化 const handleSearchChange = useCallback((e) => { setSearchInput(e.target.value); }, []); // 新增:处理搜索输入键盘事件 const handleSearchKeyDown = useCallback((e) => { if (e.key === 'Enter') { handleSearchSubmit(); } }, [handleSearchSubmit]); // 组件卸载清理 useEffect(() => removeScrollListener, [removeScrollListener]); // 分页组件复用 const paginationComponent = ( ); const handleRename = useCallback(async (oldName, newName) => { try { const response = await axios.post('/movie/rename', { old_name: oldName, new_name: newName }); if (response.data.code === 200) { // 重命名成功后重新加载当前页面数据 const category = params.lastCategory; const categoryHistory = params.history[category] || { lastPage: 1 }; if (category === SEARCH_CATEGORY) { await fetchMovies(category, categoryHistory.lastPage, params.searchQuery); } else { await fetchMovies(category, categoryHistory.lastPage); } } else { throw new Error(response.data.message || '重命名失败'); } } catch (error) { console.error('重命名错误:', error); throw error; } }, [fetchMovies, params.lastCategory, params.history, params.searchQuery]); return ( {/* 添加搜索框 */} ), endAdornment: searchInput && ( ) }} sx={{ mb: 2 }} /> {/* 显示当前搜索状态 */} {currentCategory === SEARCH_CATEGORY && (
搜索: "{params.searchQuery}" ({pagination.total} 个结果)
)} {paginationComponent} {loading ? ( ) : ( {movies.map(item => ( ))} )} {paginationComponent}
); }; export default Main;