109 lines
2.9 KiB
TypeScript
109 lines
2.9 KiB
TypeScript
|
|
import { Button } from '@nice/ui/components/button';
|
|||
|
|
import { IconChevronLeft, IconChevronRight } from '@tabler/icons-react';
|
|||
|
|
import { useArticlesContext } from './context';
|
|||
|
|
|
|||
|
|
export function ArticlePagination() {
|
|||
|
|
const { pagination, setCurrentPage } = useArticlesContext();
|
|||
|
|
|
|||
|
|
const { currentPage, pageSize, totalPages, totalCount } = pagination;
|
|||
|
|
|
|||
|
|
if (totalPages <= 1) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const startItem = (currentPage - 1) * pageSize + 1;
|
|||
|
|
const endItem = Math.min(currentPage * pageSize, totalCount || 0);
|
|||
|
|
|
|||
|
|
// 生成页码数组
|
|||
|
|
const getPageNumbers = (): number[] => {
|
|||
|
|
const pages: number[] = [];
|
|||
|
|
const maxVisible = 5; // 最多显示5个页码
|
|||
|
|
|
|||
|
|
if (totalPages <= maxVisible) {
|
|||
|
|
// 总页数不超过最大显示数,显示全部
|
|||
|
|
for (let i = 1; i <= totalPages; i++) {
|
|||
|
|
pages.push(i);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 总页数超过最大显示数,需要智能显示
|
|||
|
|
if (currentPage <= 3) {
|
|||
|
|
// 当前页在前面,显示前4页和最后一页
|
|||
|
|
for (let i = 1; i <= 4; i++) {
|
|||
|
|
pages.push(i);
|
|||
|
|
}
|
|||
|
|
pages.push(-1); // 省略号
|
|||
|
|
pages.push(totalPages);
|
|||
|
|
} else if (currentPage >= totalPages - 2) {
|
|||
|
|
// 当前页在后面,显示第一页和后4页
|
|||
|
|
pages.push(1);
|
|||
|
|
pages.push(-1); // 省略号
|
|||
|
|
for (let i = totalPages - 3; i <= totalPages; i++) {
|
|||
|
|
pages.push(i);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 当前页在中间,显示第一页、当前页前后各一页、最后一页
|
|||
|
|
pages.push(1);
|
|||
|
|
pages.push(-1); // 省略号
|
|||
|
|
for (let i = currentPage - 1; i <= currentPage + 1; i++) {
|
|||
|
|
pages.push(i);
|
|||
|
|
}
|
|||
|
|
pages.push(-2); // 省略号
|
|||
|
|
pages.push(totalPages);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return pages;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="flex items-center justify-between p-4 border-t bg-muted/10">
|
|||
|
|
<div className="text-sm text-muted-foreground">
|
|||
|
|
显示 {startItem} 到 {endItem} 项,共 {totalCount || 0} 项
|
|||
|
|
</div>
|
|||
|
|
<div className="flex items-center gap-2">
|
|||
|
|
<Button
|
|||
|
|
variant="outline"
|
|||
|
|
size="sm"
|
|||
|
|
onClick={() => setCurrentPage(currentPage - 1)}
|
|||
|
|
disabled={currentPage === 1}
|
|||
|
|
className="h-9 px-3"
|
|||
|
|
>
|
|||
|
|
<IconChevronLeft className="h-4 w-4 mr-1" />
|
|||
|
|
上一页
|
|||
|
|
</Button>
|
|||
|
|
|
|||
|
|
<div className="flex items-center gap-1">
|
|||
|
|
{getPageNumbers().map((page, index) =>
|
|||
|
|
page === -1 || page === -2 ? (
|
|||
|
|
<span key={`ellipsis-${index}`} className="px-2 text-muted-foreground">
|
|||
|
|
...
|
|||
|
|
</span>
|
|||
|
|
) : (
|
|||
|
|
<Button
|
|||
|
|
key={page}
|
|||
|
|
variant={currentPage === page ? 'default' : 'outline'}
|
|||
|
|
size="sm"
|
|||
|
|
onClick={() => setCurrentPage(page)}
|
|||
|
|
className="h-9 w-9"
|
|||
|
|
>
|
|||
|
|
{page}
|
|||
|
|
</Button>
|
|||
|
|
),
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<Button
|
|||
|
|
variant="outline"
|
|||
|
|
size="sm"
|
|||
|
|
onClick={() => setCurrentPage(currentPage + 1)}
|
|||
|
|
disabled={currentPage === totalPages}
|
|||
|
|
className="h-9 px-3"
|
|||
|
|
>
|
|||
|
|
下一页
|
|||
|
|
<IconChevronRight className="h-4 w-4 ml-1" />
|
|||
|
|
</Button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|