a2e9ba55c2
P0: 福利批量参保/离职证明下载防乱码/考勤模板合并Sheet/补卡修改/附件在线查看删除 P1: 分页pageSize修复/离职导出筛选/撤回删除草稿/加班费自动计算/考勤加班汇总/证据链异常详情/制度催办/模板导入Word/社保封顶保底/校验字段提示/职务字段/社保费用明细/弹窗防误关/身份证查重/证明员工下拉/培训批量 P2: 离职流程去重/社保基数覆盖输入/薪税入口改名/添加员工引导/绩效模板清理
97 lines
3.2 KiB
TypeScript
97 lines
3.2 KiB
TypeScript
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>
|
||
)
|
||
}
|