111 lines
3.4 KiB
TypeScript
111 lines
3.4 KiB
TypeScript
// app/components/ui/Pagination.tsx
|
|
|
|
interface PaginationProps {
|
|
currentPage: number;
|
|
total: number;
|
|
pageSize: number;
|
|
onChange: (page: number) => void;
|
|
onPageSizeChange?: (pageSize: number) => void;
|
|
pageSizeOptions?: number[];
|
|
showTotal?: boolean;
|
|
showPageSizeChanger?: boolean;
|
|
}
|
|
|
|
export function Pagination({
|
|
currentPage,
|
|
total,
|
|
pageSize,
|
|
onChange,
|
|
onPageSizeChange,
|
|
pageSizeOptions = [10, 20, 50],
|
|
showTotal = true,
|
|
showPageSizeChanger = true
|
|
}: PaginationProps) {
|
|
const totalPages = Math.ceil(total / pageSize);
|
|
|
|
// 生成页码数组
|
|
const getPageNumbers = () => {
|
|
const pages = [];
|
|
const maxVisiblePages = 5;
|
|
|
|
if (totalPages <= maxVisiblePages) {
|
|
// 总页数小于等于最大可见页数,显示所有页码
|
|
for (let i = 1; i <= totalPages; i++) {
|
|
pages.push(i);
|
|
}
|
|
} else if (currentPage <= 3) {
|
|
// 当前页靠近开始
|
|
for (let i = 1; i <= maxVisiblePages; i++) {
|
|
pages.push(i);
|
|
}
|
|
} else if (currentPage >= totalPages - 2) {
|
|
// 当前页靠近结尾
|
|
for (let i = totalPages - maxVisiblePages + 1; i <= totalPages; i++) {
|
|
pages.push(i);
|
|
}
|
|
} else {
|
|
// 当前页在中间
|
|
for (let i = currentPage - 2; i <= currentPage + 2; i++) {
|
|
pages.push(i);
|
|
}
|
|
}
|
|
|
|
return pages;
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-wrap justify-between items-center p-4 gap-4">
|
|
{showTotal && (
|
|
<div className="ant-pagination-options">
|
|
<span className="text-sm font-normal">共 {total} 条</span>
|
|
{onPageSizeChange && showPageSizeChanger && (
|
|
<div className="flex items-center ml-3">
|
|
<select
|
|
className="form-select ant-pagination-options-size-changer"
|
|
value={pageSize}
|
|
onChange={(e) => onPageSizeChange(Number(e.target.value))}
|
|
aria-label="每页显示条数"
|
|
>
|
|
{pageSizeOptions.map(size => (
|
|
<option key={size} value={size}>{size} 条/页</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className="ant-pagination">
|
|
<button
|
|
className={`ant-pagination-item ant-pagination-prev ${currentPage <= 1 ? 'ant-pagination-disabled' : ''}`}
|
|
onClick={() => currentPage > 1 && onChange(currentPage - 1)}
|
|
disabled={currentPage <= 1}
|
|
aria-label="上一页"
|
|
>
|
|
<i className="ri-arrow-left-s-line"></i>
|
|
</button>
|
|
|
|
{getPageNumbers().map(page => (
|
|
<button
|
|
key={page}
|
|
className={`ant-pagination-item ${page === currentPage ? 'ant-pagination-item-active' : ''}`}
|
|
onClick={() => onChange(page)}
|
|
aria-label={`第${page}页`}
|
|
aria-current={page === currentPage ? 'page' : undefined}
|
|
>
|
|
{page}
|
|
</button>
|
|
))}
|
|
|
|
<button
|
|
className={`ant-pagination-item ant-pagination-next ${currentPage >= totalPages ? 'ant-pagination-disabled' : ''}`}
|
|
onClick={() => currentPage < totalPages && onChange(currentPage + 1)}
|
|
disabled={currentPage >= totalPages}
|
|
aria-label="下一页"
|
|
>
|
|
<i className="ri-arrow-right-s-line"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |