生产管理系统前端 - 地块档案管理页面开发
This commit is contained in:
188
crop-x/src/components/ui/data-pagination.tsx
Normal file
188
crop-x/src/components/ui/data-pagination.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import React from 'react';
|
||||
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, MoreHorizontal } from 'lucide-react';
|
||||
import { Button } from './button';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface DataPaginationProps {
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
pageSize: number;
|
||||
totalItems: number;
|
||||
startIndex: number;
|
||||
endIndex: number;
|
||||
onPageChange: (page: number) => void;
|
||||
onPageSizeChange: (size: number) => void;
|
||||
canPreviousPage: boolean;
|
||||
canNextPage: boolean;
|
||||
pageSizeOptions?: number[];
|
||||
}
|
||||
|
||||
export function DataPagination({
|
||||
currentPage,
|
||||
totalPages,
|
||||
pageSize,
|
||||
totalItems,
|
||||
startIndex,
|
||||
endIndex,
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
canPreviousPage,
|
||||
canNextPage,
|
||||
pageSizeOptions = [10, 30, 50, 100],
|
||||
}: DataPaginationProps) {
|
||||
// 生成页码数组
|
||||
const generatePageNumbers = () => {
|
||||
const pages: (number | 'ellipsis')[] = [];
|
||||
const maxVisiblePages = 5;
|
||||
|
||||
if (totalPages <= maxVisiblePages) {
|
||||
// 如果总页数少,显示所有页码
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
} else {
|
||||
// 总是显示第一页
|
||||
pages.push(1);
|
||||
|
||||
if (currentPage > 3) {
|
||||
pages.push('ellipsis');
|
||||
}
|
||||
|
||||
// 显示当前页附近的页码
|
||||
const startPage = Math.max(2, currentPage - 1);
|
||||
const endPage = Math.min(totalPages - 1, currentPage + 1);
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
|
||||
if (currentPage < totalPages - 2) {
|
||||
pages.push('ellipsis');
|
||||
}
|
||||
|
||||
// 总是显示最后一页
|
||||
if (totalPages > 1) {
|
||||
pages.push(totalPages);
|
||||
}
|
||||
}
|
||||
|
||||
return pages;
|
||||
};
|
||||
|
||||
const pageNumbers = generatePageNumbers();
|
||||
|
||||
if (totalItems === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="border-t bg-background">
|
||||
<div className="flex flex-col gap-4 px-4 py-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
{/* 左侧:每页显示数量 */}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-muted-foreground hidden sm:inline">每页显示</span>
|
||||
<Select
|
||||
value={pageSize.toString()}
|
||||
onValueChange={(value) => onPageSizeChange(Number(value))}
|
||||
>
|
||||
<SelectTrigger className="h-9 w-[70px]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent side="top">
|
||||
{pageSizeOptions.map((size) => (
|
||||
<SelectItem key={size} value={size.toString()}>
|
||||
{size}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="text-sm text-muted-foreground">条</span>
|
||||
</div>
|
||||
|
||||
{/* 中间:分页器 */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 第一页 */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onPageChange(1)}
|
||||
disabled={!canPreviousPage}
|
||||
className="h-9 w-9 p-0 hidden sm:flex"
|
||||
>
|
||||
<ChevronsLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
{/* 上一页 */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onPageChange(currentPage - 1)}
|
||||
disabled={!canPreviousPage}
|
||||
className="h-9 w-9 p-0"
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
{/* 页码 */}
|
||||
<div className="flex items-center gap-1">
|
||||
{pageNumbers.map((page, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{page === 'ellipsis' ? (
|
||||
<div className="flex h-9 w-9 items-center justify-center">
|
||||
<MoreHorizontal className="h-4 w-4 text-muted-foreground" />
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
variant={currentPage === page ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => onPageChange(page)}
|
||||
className={cn(
|
||||
'h-9 w-9 p-0',
|
||||
currentPage === page && 'bg-green-600 hover:bg-green-700 text-white'
|
||||
)}
|
||||
>
|
||||
{page}
|
||||
</Button>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 下一页 */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onPageChange(currentPage + 1)}
|
||||
disabled={!canNextPage}
|
||||
className="h-9 w-9 p-0"
|
||||
>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
{/* 最后一页 */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onPageChange(totalPages)}
|
||||
disabled={!canNextPage}
|
||||
className="h-9 w-9 p-0 hidden sm:flex"
|
||||
>
|
||||
<ChevronsRight className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 右侧:统计信息 */}
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<span className="hidden sm:inline">
|
||||
显示 <span className="font-medium text-foreground">{startIndex}</span> 至{' '}
|
||||
<span className="font-medium text-foreground">{endIndex}</span> 条,
|
||||
</span>
|
||||
<span>
|
||||
共 <span className="font-medium text-foreground">{totalItems}</span> 条
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user