做一次大更新.

This commit is contained in:
2025-06-02 03:19:36 +08:00
parent 7d814d7737
commit 0c4e8b089a
5 changed files with 396 additions and 276 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useContext, useCallback } from 'react';
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';
@@ -10,195 +10,201 @@ 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' },
];
const LIMIT = 20;
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 categories = [
{ label: '15min', idx: 0 },
{ label: '30min', idx: 1 },
{ label: '60min', idx: 2 },
{ label: '大于60min', idx: 3 },
];
const scrollRef = useRef(0);
const limit = 20;
const getInitialParams = () => {
const storedParams = localStorage.getItem('params');
if (storedParams) {
return JSON.parse(storedParams);
} else {
return {
lastCategory: 0,
history: {
0: { lastPage: 1, scrollPos: 0 },
1: { lastPage: 1, scrollPos: 0 },
2: { lastPage: 1, scrollPos: 0 },
3: { lastPage: 1, scrollPos: 0 },
},
};
}
};
const [params, setParams] = useState(getInitialParams());
const [pagination, setPagination] = useState({
movies: [],
page: params.history[params.lastCategory].lastPage,
total: 1,
length: 1,
// 初始化状态,直接使用 categories 中的 value 值
const [params, setParams] = usePersistedState('params', {
lastCategory: categories[0].value, // 直接使用 '15min' 这样的值
history: categories.reduce((acc, category) => ({
...acc,
[category.value]: { lastPage: 1, scrollPos: 0 } // 使用 category.value 作为键
}), {})
});
const [movies, setMovies] = useState([]);
const [pagination, setPagination] = useState({ page: 1, total: 0, pages: 1 });
const fetchMovies = useCallback(async (category, page) => {
setLoading(true);
try {
// 直接使用 category 值,不需要转换
const response = await axios.get(
`${window.location.origin}/movie/?page=${page}&limit=${limit}&category=${category}`
`/movie/?page=${page}&limit=${LIMIT}&category=${encodeURIComponent(category)}`
);
if (response.status === 200) {
const data = response.data.data;
const { items, total } = response.data.data;
if (data.items.length === 0 && page > 1) {
fetchMovies(category, page - 1);
} else {
setPagination({
movies: data.items,
page: page,
total: data.total,
length: Math.ceil(data.total / limit),
});
if (items.length === 0 && page > 1) {
setParams(prev => ({
...prev,
history: {
...prev.history,
[category]: {
...(prev.history[category] || { lastPage: 1, scrollPos: 0 }),
lastPage: page - 1
}
}
}));
return;
}
setMovies(items);
setPagination({
page,
total,
pages: Math.ceil(total / LIMIT)
});
requestAnimationFrame(() => {
window.scrollTo(0, scrollRef.current);
});
}
} catch (error) {
console.error('Error fetching movies:', error);
} finally {
setLoading(false);
}
}, [window.location.origin, limit]);
}, [setParams]);
useEffect(() => {
const currentCategory = params.lastCategory;
const currentPage = params.history[currentCategory].lastPage;
fetchMovies(currentCategory, currentPage);
}, [fetchMovies, params]);
const updateParams = useCallback((newParams) => {
setParams((prevParams) => {
const updatedParams = { ...prevParams, ...newParams };
localStorage.setItem('params', JSON.stringify(updatedParams));
return updatedParams;
});
}, []);
const handlePageChange = useCallback(
(event, page) => {
const currentCategory = params.lastCategory;
updateParams({
history: {
...params.history,
[currentCategory]: { ...params.history[currentCategory], lastPage: page },
},
});
fetchMovies(currentCategory, page);
},
[fetchMovies, params, updateParams]
);
// 导致递归刷新
const handleCategoryChange = useCallback(
(category) => {
const currentPage = params.history[category].lastPage;
fetchMovies(category, currentPage);
const currentCategory = params.lastCategory;
updateParams({
lastCategory: category,
history: {
...params.history,
[currentCategory]: { ...params.history[currentCategory], scrollPos: window.scrollY },
},
});
},
[fetchMovies, params, updateParams]
);
const handleRenderComplete = useCallback(() => {
const { scrollPos } = params.history[params.lastCategory];
window.scrollTo(0, scrollPos);
const getCurrentCategoryAndPage = useCallback(() => {
// 直接从 params 中获取 lastCategory,确保它是 categories 中的 value 值
const lastCategory = params.lastCategory || categories[0].value;
const categoryHistory = params.history[lastCategory] || { lastPage: 1, scrollPos: 0 };
return {
category: lastCategory,
page: categoryHistory.lastPage
};
}, [params]);
const handleMovieCardClick = () => {
const currentCategory = params.lastCategory;
updateParams({
history: {
...params.history,
[currentCategory]: { ...params.history[currentCategory], scrollPos: window.scrollY },
},
useEffect(() => {
const { category, page } = getCurrentCategoryAndPage();
scrollRef.current = params.history[category]?.scrollPos || 0;
fetchMovies(category, page);
}, [getCurrentCategoryAndPage, fetchMovies, params.history]);
const handleCategoryChange = useCallback((category) => {
scrollRef.current = window.scrollY;
const currentCategory = params.lastCategory || categories[0].value;
setParams(prev => {
const newHistory = {
...prev.history,
[currentCategory]: {
...(prev.history[currentCategory] || { lastPage: 1, scrollPos: 0 }),
scrollPos: scrollRef.current
},
[category]: {
...(prev.history[category] || { lastPage: 1, scrollPos: 0 })
}
};
return {
...prev,
lastCategory: category, // 直接存储传入的 category 值
history: newHistory
};
});
};
}, [params.lastCategory, setParams]);
const handlePageChange = useCallback((_, page) => {
scrollRef.current = window.scrollY;
const lastCategory = params.lastCategory || categories[0].value;
setParams(prev => ({
...prev,
history: {
...prev.history,
[lastCategory]: {
...(prev.history[lastCategory] || { lastPage: 1, scrollPos: 0 }),
lastPage: page
}
}
}));
}, [params.lastCategory, setParams]);
const handleMovieCardClick = useCallback(() => {
scrollRef.current = window.scrollY;
const lastCategory = params.lastCategory || categories[0].value;
setParams(prev => ({
...prev,
history: {
...prev.history,
[lastCategory]: {
...(prev.history[lastCategory] || { lastPage: 1, scrollPos: 0 }),
scrollPos: scrollRef.current
}
}
}));
}, [params.lastCategory, setParams]);
return (
<Container style={{ marginTop: 20 }}>
<CategoryNav
categories={categories}
currentCategory={params.lastCategory}
currentCategory={params.lastCategory || categories[0].value}
onCategoryChange={handleCategoryChange}
/>
<PaginationWrapper page={pagination.page} length={pagination.length} onPageChange={handlePageChange} />
<Pagination
count={pagination.pages}
page={pagination.page}
onChange={handlePageChange}
sx={{ my: 2, display: 'flex', justifyContent: 'center' }}
/>
{loading ? (
<Loading />
<CircularProgress sx={{ display: 'block', margin: '20px auto' }} />
) : (
<MoviesGrid
movies={pagination.movies}
config={config}
onRenderComplete={handleRenderComplete}
onMovieCardClick={handleMovieCardClick}
/>
<Grid container spacing={2} sx={{ mt: 0.5 }}>
{movies.map((item) => (
<Grid item xs={6} sm={4} md={3} lg={2} key={item.filename}>
<Link
to={`/res/${item.filename}`}
style={{ textDecoration: 'none', paddingBottom: 10 }}
onClick={handleMovieCardClick}
>
<MovieCard movie={item} config={config} />
</Link>
</Grid>
))}
</Grid>
)}
<PaginationWrapper page={pagination.page} length={pagination.length} onPageChange={handlePageChange} />
<Pagination
count={pagination.pages}
page={pagination.page}
onChange={handlePageChange}
sx={{ my: 2, display: 'flex', justifyContent: 'center' }}
/>
</Container>
);
};
const PaginationWrapper = ({ page, length, onPageChange }) => (
<Grid container justifyContent="center" style={{ marginTop: 20, marginBottom: 20 }}>
<Pagination count={length} page={page} onChange={onPageChange} />
</Grid>
);
const MoviesGrid = ({ movies, config, onRenderComplete, onMovieCardClick }) => {
useEffect(() => {
onRenderComplete();
}, [movies, onRenderComplete]);
return (
<Grid container spacing={2} style={{ marginTop: 3 }}>
{movies.map((item) => (
<Grid item xs={6} sm={4} md={3} lg={2}
style={{ display: 'flex', justifyContent: 'space-between' }}
key={item.filename}
>
<Link
to={`/res/${item.filename}`}
style={{ textDecoration: 'none', paddingBottom: 10 }}
onClick={onMovieCardClick} // 修改这里
>
<MovieCard movie={item} config={config} />
</Link>
</Grid>
))}
</Grid>
);
};
const Loading = () => (
<Grid container justifyContent="center" style={{ marginTop: 20 }}>
<CircularProgress />
</Grid>
);
export default Main;

View File

@@ -9,7 +9,7 @@ const CategoryNav = ({ categories, currentCategory, onCategoryChange }) => {
};
return (
<Tabs
value={currentCategory}
onChange={handleChange}
@@ -21,7 +21,7 @@ const CategoryNav = ({ categories, currentCategory, onCategoryChange }) => {
centered
>
{categories.map((category, idx) => (
<Tab key={category.label} label={category.label} value={idx} />
<Tab key={category.label} label={category.label} value={category.label} />
))}
</Tabs>
);