Files
TurboHR/frontend/src/components/ui/Pagination.tsx
T
freedakgmail a2e9ba55c2 feat: 20260809 系统优化 - 全部28项问题修复(P0×6+P1×16+P2×6)
P0: 福利批量参保/离职证明下载防乱码/考勤模板合并Sheet/补卡修改/附件在线查看删除
P1: 分页pageSize修复/离职导出筛选/撤回删除草稿/加班费自动计算/考勤加班汇总/证据链异常详情/制度催办/模板导入Word/社保封顶保底/校验字段提示/职务字段/社保费用明细/弹窗防误关/身份证查重/证明员工下拉/培训批量
P2: 离职流程去重/社保基数覆盖输入/薪税入口改名/添加员工引导/绩效模板清理
2026-08-09 11:59:02 +08:00

97 lines
3.2 KiB
TypeScript
Raw 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.
import clsx from 'clsx'
import { ChevronLeft, ChevronRight } from 'lucide-react'
import { setPageSize } from '../../lib/pageSize'
interface PaginationProps {
page: number // 当前页(1-based
pageSize: number // 每页条数
total: number // 总条数
onPageChange: (page: number) => void
onPageSizeChange?: (size: number) => void
pageSizeOptions?: number[]
}
export default function Pagination({
page,
pageSize,
total,
onPageChange,
onPageSizeChange,
pageSizeOptions = [10, 20, 50, 100, 200],
}: PaginationProps) {
const totalPages = Math.max(1, Math.ceil(total / pageSize))
const start = total === 0 ? 0 : (page - 1) * pageSize + 1
const end = Math.min(page * pageSize, total)
// 生成页码按钮(最多显示 7 个)
const pages: (number | '...')[] = []
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) pages.push(i)
} else {
pages.push(1)
if (page > 3) pages.push('...')
const s = Math.max(2, page - 1)
const e = Math.min(totalPages - 1, page + 1)
for (let i = s; i <= e; i++) pages.push(i)
if (page < totalPages - 2) pages.push('...')
pages.push(totalPages)
}
return (
<div className="flex items-center justify-between gap-4 py-2">
{/* 左侧:条数信息 + 每页条数选择 */}
<div className="flex items-center gap-3 text-sm text-gray-500">
<span> {total} </span>
{onPageSizeChange && (
<select
className="border rounded px-1.5 py-0.5 text-sm text-gray-600 focus:outline-none focus:border-primary"
value={pageSize}
onChange={(e) => { setPageSize(Number(e.target.value)); onPageSizeChange?.(Number(e.target.value)) }}
>
{pageSizeOptions.map((n) => (
<option key={n} value={n}>{n} /</option>
))}
</select>
)}
<span> {start}-{end} </span>
</div>
{/* 右侧:页码导航 */}
<div className="flex items-center gap-1">
<button
className="p-1 rounded text-gray-500 hover:text-gray-700 hover:bg-gray-100 disabled:opacity-30 disabled:cursor-not-allowed"
disabled={page <= 1}
onClick={() => onPageChange(page - 1)}
>
<ChevronLeft className="w-4 h-4" />
</button>
{pages.map((p, i) =>
p === '...' ? (
<span key={`ellipsis-${i}`} className="px-2 text-gray-500 text-sm"></span>
) : (
<button
key={p}
className={clsx(
'min-w-[28px] h-7 rounded text-sm font-medium transition-colors',
p === page
? 'bg-primary text-white'
: 'text-gray-600 hover:bg-gray-100',
)}
onClick={() => onPageChange(p)}
>
{p}
</button>
),
)}
<button
className="p-1 rounded text-gray-500 hover:text-gray-700 hover:bg-gray-100 disabled:opacity-30 disabled:cursor-not-allowed"
disabled={page >= totalPages}
onClick={() => onPageChange(page + 1)}
>
<ChevronRight className="w-4 h-4" />
</button>
</div>
</div>
)
}