b93929eb1a
- 添加公共分页组件,支持上边显示、分页大小10 - 侧边栏/Header按Liner风格优化,添加动画效果 - 异常处理列表支持分页和明细弹窗 - 任务结果页面支持已匹配列表分页 - 修复Dialog弹窗背景透明问题 - 新增dropdown-menu组件 - 添加parsed_file_record模型和回填脚本 - 前端枚举中文化
138 lines
4.0 KiB
TypeScript
138 lines
4.0 KiB
TypeScript
"use client";
|
||
|
||
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react";
|
||
import { Button } from "@/components/ui/button";
|
||
import {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from "@/components/ui/select";
|
||
|
||
export interface PaginationProps {
|
||
/** 当前页码(从 1 开始) */
|
||
page: number;
|
||
/** 每页条数 */
|
||
pageSize: number;
|
||
/** 总条数 */
|
||
total: number;
|
||
/** 页码或每页条数变化时的回调 */
|
||
onChange: (page: number, pageSize: number) => void;
|
||
/** 可选的每页条数选项,默认 [10, 20, 50] */
|
||
pageSizeOptions?: number[];
|
||
/** 是否显示每页条数选择器,默认 true */
|
||
showPageSizeSelector?: boolean;
|
||
}
|
||
|
||
export function Pagination({
|
||
page,
|
||
pageSize,
|
||
total,
|
||
onChange,
|
||
pageSizeOptions = [10, 20, 50],
|
||
showPageSizeSelector = true,
|
||
}: PaginationProps) {
|
||
const totalPages = Math.ceil(total / pageSize);
|
||
const start = total > 0 ? (page - 1) * pageSize + 1 : 0;
|
||
const end = Math.min(page * pageSize, total);
|
||
|
||
return (
|
||
<div className="flex items-center justify-between px-4 py-3 border-t">
|
||
<div className="flex items-center gap-4">
|
||
{showPageSizeSelector && (
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-sm text-muted-foreground">每页</span>
|
||
<Select
|
||
value={String(pageSize)}
|
||
onValueChange={(val) => onChange(1, Number(val))}
|
||
>
|
||
<SelectTrigger className="h-8 w-[70px]">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent side="top">
|
||
{pageSizeOptions.map((size) => (
|
||
<SelectItem key={size} value={String(size)}>
|
||
{size}
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
<span className="text-sm text-muted-foreground">条</span>
|
||
</div>
|
||
)}
|
||
{total > 0 && (
|
||
<span className="text-sm text-muted-foreground">
|
||
显示 {start}-{end},共 {total} 条
|
||
</span>
|
||
)}
|
||
</div>
|
||
|
||
<div className="flex items-center gap-1">
|
||
<Button
|
||
variant="outline"
|
||
size="icon"
|
||
className="h-8 w-8"
|
||
onClick={() => onChange(1, pageSize)}
|
||
disabled={page <= 1}
|
||
>
|
||
<ChevronsLeft className="h-4 w-4" />
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="icon"
|
||
className="h-8 w-8"
|
||
onClick={() => onChange(page - 1, pageSize)}
|
||
disabled={page <= 1}
|
||
>
|
||
<ChevronLeft className="h-4 w-4" />
|
||
</Button>
|
||
|
||
<div className="flex items-center gap-1 mx-1">
|
||
{Array.from({ length: Math.min(totalPages, 5) }, (_, i) => {
|
||
let pageNum: number;
|
||
if (totalPages <= 5) {
|
||
pageNum = i + 1;
|
||
} else if (page <= 3) {
|
||
pageNum = i + 1;
|
||
} else if (page >= totalPages - 2) {
|
||
pageNum = totalPages - 4 + i;
|
||
} else {
|
||
pageNum = page - 2 + i;
|
||
}
|
||
return (
|
||
<Button
|
||
key={pageNum}
|
||
variant={pageNum === page ? "default" : "outline"}
|
||
size="sm"
|
||
className="h-8 w-9"
|
||
onClick={() => onChange(pageNum, pageSize)}
|
||
>
|
||
{pageNum}
|
||
</Button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
<Button
|
||
variant="outline"
|
||
size="icon"
|
||
className="h-8 w-8"
|
||
onClick={() => onChange(page + 1, pageSize)}
|
||
disabled={page >= totalPages}
|
||
>
|
||
<ChevronRight className="h-4 w-4" />
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="icon"
|
||
className="h-8 w-8"
|
||
onClick={() => onChange(totalPages, pageSize)}
|
||
disabled={page >= totalPages}
|
||
>
|
||
<ChevronsRight className="h-4 w-4" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
);
|
||
} |