生产管理系统前端 - 地块档案管理页面开发

This commit is contained in:
2025-10-29 14:13:51 +08:00
parent 5d34bc3643
commit df8e6bf515
11 changed files with 2633 additions and 44 deletions

View 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>
);
}