最新分类版本
This commit is contained in:
25
src/CategoryNav.js
Normal file
25
src/CategoryNav.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import Tabs from '@mui/material/Tabs';
|
||||
import Tab from '@mui/material/Tab';
|
||||
|
||||
const CategoryNav = ({ categories, currentCategory, onCategoryChange }) => {
|
||||
const handleChange = (event, newValue) => {
|
||||
onCategoryChange(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
value={currentCategory}
|
||||
onChange={handleChange}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
centered
|
||||
>
|
||||
{categories.map((category, idx) => (
|
||||
<Tab key={category.label} label={category.label} value={idx} />
|
||||
))}
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
export default CategoryNav;
|
||||
@@ -9,13 +9,24 @@ import Typography from '@mui/material/Typography';
|
||||
import Pagination from '@mui/material/Pagination';
|
||||
import { Link } from 'react-router-dom';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import ConfigContext from './Config';
|
||||
|
||||
import ConfigContext from './Config';
|
||||
import MovieCard from './MovieCard';
|
||||
import CategoryNav from './CategoryNav';
|
||||
|
||||
|
||||
const Main = () => {
|
||||
const config = useContext(ConfigContext);
|
||||
|
||||
const [currentCategory, setCurrentCategory] = useState(0);
|
||||
|
||||
const categories = [
|
||||
{ label: '15min', idx: 0 },
|
||||
{ label: '30min', idx: 1 },
|
||||
{ label: '60min', idx: 2 },
|
||||
{ label: '大于60min', idx: 3 },
|
||||
];
|
||||
|
||||
const [pagination, setPagination] = useState({
|
||||
movies: [],
|
||||
page: 1,
|
||||
@@ -25,24 +36,37 @@ const Main = () => {
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const limit = 12;
|
||||
const limit = 20;
|
||||
|
||||
const fetchMovies = async (page) => {
|
||||
const handleCategoryChange = (category) => {
|
||||
setCurrentCategory(category);
|
||||
fetchMovies(category, 1);
|
||||
};
|
||||
|
||||
|
||||
const fetchMovies = async (category, page) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${config.Host}/movie/?page=${page}&limit=${limit}`
|
||||
`${config.Host}/movie/?page=${page}&limit=${limit}&category=${category}`
|
||||
);
|
||||
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = response.data.data;
|
||||
setPagination({
|
||||
movies: data.items,
|
||||
page: page,
|
||||
total: data.total,
|
||||
length: Math.ceil(data.total / limit),
|
||||
});
|
||||
localStorage.setItem('lastPage', page);
|
||||
console.log(`${config.Host}/movie/?page=${page}&limit=${limit}&category=${category}`);
|
||||
if (data.items.length === 0 && page > 1) {
|
||||
// 如果返回的数据为空且请求的页码大于1,则尝试获取上一页的数据
|
||||
fetchMovies(page - 1);
|
||||
} else {
|
||||
setPagination({
|
||||
movies: data.items,
|
||||
page: page,
|
||||
total: data.total,
|
||||
length: Math.ceil(data.total / limit),
|
||||
});
|
||||
localStorage.setItem('lastPage', page);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching movies:', error);
|
||||
@@ -53,11 +77,11 @@ const Main = () => {
|
||||
|
||||
useEffect(() => {
|
||||
const lastPage = localStorage.getItem('lastPage') || 1;
|
||||
fetchMovies(lastPage);
|
||||
fetchMovies(currentCategory, lastPage);
|
||||
}, []);
|
||||
|
||||
const handlePageChange = (event, value) => {
|
||||
fetchMovies(value);
|
||||
fetchMovies(currentCategory, value);
|
||||
};
|
||||
|
||||
const truncateFilename = (filename, maxLength) => {
|
||||
@@ -65,9 +89,15 @@ const Main = () => {
|
||||
? filename.substring(0, maxLength - 3) + '...'
|
||||
: filename;
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<Container style={{ marginTop: 20 }}>
|
||||
<CategoryNav
|
||||
categories={categories}
|
||||
currentCategory={currentCategory}
|
||||
onCategoryChange={handleCategoryChange}
|
||||
/>
|
||||
<div style={{ textAlign: 'center', marginBottom: 20 }}>
|
||||
<Pagination
|
||||
count={pagination.length}
|
||||
@@ -79,6 +109,8 @@ const Main = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
{loading ? (
|
||||
<div
|
||||
@@ -92,50 +124,34 @@ const Main = () => {
|
||||
<CircularProgress />
|
||||
</div>
|
||||
) : (
|
||||
|
||||
|
||||
|
||||
<Grid container spacing={2} style={{ marginTop: 3 }}>
|
||||
{pagination.movies.map((item) => (
|
||||
<Grid
|
||||
item
|
||||
xs={6}
|
||||
sm={4}
|
||||
md={3}
|
||||
lg={2}
|
||||
style={{ display: 'flex', justifyContent: 'space-between' }}
|
||||
key={item.filename}
|
||||
{pagination.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 }}
|
||||
>
|
||||
<Link
|
||||
to={`/res/${item.filename}`}
|
||||
style={{ textDecoration: 'none', paddingBottom: 10 }}
|
||||
>
|
||||
<Card
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 200,
|
||||
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
||||
transition: 'box-shadow 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
boxShadow: '0 8px 12px rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CardMedia
|
||||
component="img"
|
||||
height="120"
|
||||
image={`${config.Host}/res/${item.image}`}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography>
|
||||
{truncateFilename(item.filename, 15)}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
<MovieCard movie={item} config={config} />
|
||||
</Link>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style={{ textAlign: 'center', marginTop: 20 }}>
|
||||
<Pagination
|
||||
count={pagination.length}
|
||||
|
||||
41
src/MovieCard.js
Normal file
41
src/MovieCard.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardMedia from '@mui/material/CardMedia';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
const MovieCard = ({ movie, config }) => {
|
||||
const truncateFilename = (filename, maxLength) => {
|
||||
return filename.length > maxLength
|
||||
? filename.substring(0, maxLength - 3) + '...'
|
||||
: filename;
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
style={{
|
||||
width: '100%',
|
||||
height: 200,
|
||||
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
||||
transition: 'box-shadow 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
boxShadow: '0 8px 12px rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CardMedia
|
||||
component="img"
|
||||
height="120"
|
||||
image={`${config.Host}/res/${movie.image}`}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography>{truncateFilename(movie.filename, 15)}</Typography>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
时长: {movie.duration} min
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default MovieCard;
|
||||
@@ -16,6 +16,7 @@ const VideoPlayer = () => {
|
||||
{filename}
|
||||
</Typography>
|
||||
<video
|
||||
autoPlay={true}
|
||||
controls
|
||||
style={{ width: '100%', maxHeight: '70vh' }}
|
||||
src={`${config.Host}/res/${filename}`}
|
||||
|
||||
Reference in New Issue
Block a user