diff --git a/frontend/src/components/Pagination.jsx b/frontend/src/components/Pagination.jsx new file mode 100644 index 0000000..7e51e3b --- /dev/null +++ b/frontend/src/components/Pagination.jsx @@ -0,0 +1,87 @@ +import React, { useState, useEffect } from 'react' +import { ChevronLeft, ChevronRight, ChevronDown } from 'lucide-react' + +const Pagination = ({ + currentPage, + totalItems, + pageSize, + onPageChange, + onPageSizeChange, + pageSizeOptions = [10, 20, 50, 100] +}) => { + const totalPages = Math.ceil(totalItems / pageSize) + const [inputPage, setInputPage] = useState(currentPage) + + useEffect(() => { + setInputPage(currentPage) + }, [currentPage]) + + const handlePageSubmit = (e) => { + e.preventDefault() + let page = parseInt(inputPage) + if (isNaN(page)) page = 1 + if (page < 1) page = 1 + if (page > totalPages) page = totalPages + onPageChange(page) + setInputPage(page) + } + + if (totalItems === 0) return null + + return ( +
+ {/* Info */} +
+ 显示 {Math.min((currentPage - 1) * pageSize + 1, totalItems)} - {Math.min(currentPage * pageSize, totalItems)} 共 {totalItems} 条 +
+ +
+ {/* Page Size Selector */} +
+ + +
+ + {/* Navigation */} +
+ + + {/* Manual Input */} +
+ setInputPage(e.target.value)} + className="w-12 text-center py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent mx-1" + /> + / {totalPages} +
+ + +
+
+
+ ) +} + +export default Pagination diff --git a/frontend/src/pages/MistakeList.jsx b/frontend/src/pages/MistakeList.jsx index 5cc7146..065855b 100644 --- a/frontend/src/pages/MistakeList.jsx +++ b/frontend/src/pages/MistakeList.jsx @@ -5,7 +5,8 @@ import React, { useState, useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { mistakeAPI } from '../api/client' import Layout from '../components/Layout' -import { XCircle, Loader, Trash2, BookOpen, Play, ChevronLeft, ChevronRight } from 'lucide-react' +import Pagination from '../components/Pagination' +import { XCircle, Loader, Trash2, BookOpen, Play } from 'lucide-react' import toast from 'react-hot-toast' import { getQuestionTypeText, formatRelativeTime } from '../utils/helpers' @@ -185,48 +186,16 @@ export const MistakeList = () => { })} {/* Pagination */} - {total > limit && ( -
-
- 显示 {Math.min((page - 1) * limit + 1, total)} - {Math.min(page * limit, total)} 共 {total} 条 -
-
- - - {page} - - -
-
- )} - - {/* Limit Selector */} -
- -
+ { + setLimit(newLimit) + setPage(1) + }} + /> )} diff --git a/frontend/src/pages/QuestionBank.jsx b/frontend/src/pages/QuestionBank.jsx index e81e75f..9140784 100644 --- a/frontend/src/pages/QuestionBank.jsx +++ b/frontend/src/pages/QuestionBank.jsx @@ -4,7 +4,8 @@ import React, { useState, useEffect } from 'react' import { questionAPI } from '../api/client' import Layout from '../components/Layout' -import { FileText, Loader, ChevronLeft, ChevronRight, Search } from 'lucide-react' +import Pagination from '../components/Pagination' +import { FileText, Loader, Search } from 'lucide-react' import toast from 'react-hot-toast' import { getQuestionTypeText, formatRelativeTime } from '../utils/helpers' @@ -140,48 +141,16 @@ export const QuestionBank = () => { {/* Pagination */} - {total > limit && ( -
-
- 显示 {Math.min((page - 1) * limit + 1, total)} - {Math.min(page * limit, total)} 共 {total} 条 -
-
- - - {page} - - -
-
- )} - - {/* Limit Selector */} -
- -
+ { + setLimit(newLimit) + setPage(1) + }} + /> )