89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
'use client'
|
|
import {Table as TableRoot, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@/components/ui/table'
|
|
import {ColumnDef, flexRender, getCoreRowModel, useReactTable} from '@tanstack/react-table'
|
|
import {Pagination, PaginationProps} from '@/components/ui/pagination'
|
|
import {Loader} from 'lucide-react'
|
|
import {merge} from '@/lib/utils'
|
|
|
|
export type DataTableProps<T> = {
|
|
data: T[]
|
|
status: 'load' | 'done' | 'fail'
|
|
columns: ColumnDef<T>[]
|
|
pagination: PaginationProps
|
|
classNames?: {
|
|
headRow?: string
|
|
dataRow?: string
|
|
}
|
|
}
|
|
|
|
export default function DataTable<T extends Record<string, unknown>>(props: DataTableProps<T>) {
|
|
|
|
const table = useReactTable({
|
|
data: props.data,
|
|
columns: props.columns,
|
|
getCoreRowModel: getCoreRowModel(),
|
|
manualPagination: true,
|
|
rowCount: props.pagination.total,
|
|
state: {
|
|
pagination: {
|
|
pageIndex: props.pagination.page,
|
|
pageSize: props.pagination.size,
|
|
},
|
|
columnFilters: [],
|
|
},
|
|
})
|
|
|
|
return (<>
|
|
{/* 数据表*/}
|
|
<div className={`rounded-md relative bg-card`}>
|
|
<TableRoot>
|
|
<TableHeader>
|
|
{table.getHeaderGroups().map(group => (
|
|
<TableRow key={group.id}>
|
|
{group.headers.map(header => (
|
|
<TableHead key={header.id} colSpan={header.colSpan}>
|
|
{header.isPlaceholder ? null : flexRender(
|
|
header.column.columnDef.header,
|
|
header.getContext(),
|
|
)}
|
|
</TableHead>
|
|
))}
|
|
</TableRow>
|
|
))}
|
|
</TableHeader>
|
|
<TableBody>
|
|
{props.status === 'fail' ? (
|
|
<TableRow>
|
|
<TableCell colSpan={props.columns.length} className={`text-center text-fail`}>加载失败</TableCell>
|
|
</TableRow>
|
|
) : !props.data?.length ? (
|
|
<TableRow>
|
|
<TableCell colSpan={props.columns.length} className={`text-center`}>暂无数据</TableCell>
|
|
</TableRow>
|
|
) : table.getRowModel().rows.map(row => (
|
|
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'} className={merge('h-14', props.classNames?.dataRow)}>
|
|
{row.getVisibleCells().map(cell => (
|
|
<TableCell key={cell.id}>
|
|
{flexRender(
|
|
cell.column.columnDef.cell,
|
|
cell.getContext(),
|
|
)}
|
|
</TableCell>
|
|
))}
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</TableRoot>
|
|
{props.status === 'load' && (
|
|
<div className={`absolute inset-0 bg-white/10 backdrop-blur-xs flex items-center justify-center gap-2 transition`}>
|
|
<Loader className={`animate-spin`}/>
|
|
<span>加载中</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 分页器 */}
|
|
<Pagination {...props.pagination}/>
|
|
</>)
|
|
}
|