Files
freedakgmail b93929eb1a feat: UI优化和功能完善
- 添加公共分页组件,支持上边显示、分页大小10
- 侧边栏/Header按Liner风格优化,添加动画效果
- 异常处理列表支持分页和明细弹窗
- 任务结果页面支持已匹配列表分页
- 修复Dialog弹窗背景透明问题
- 新增dropdown-menu组件
- 添加parsed_file_record模型和回填脚本
- 前端枚举中文化
2026-07-07 12:57:15 +08:00

138 lines
4.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"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>
);
}