"use client" import * as React from "react" import { ColumnDef, ColumnFiltersState, ColumnSizingState, flexRender, getCoreRowModel, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, SortingState, useReactTable, VisibilityState, } from "@tanstack/react-table" import { IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronsLeft, IconChevronsRight, IconLayoutColumns, IconPlus, } from "@tabler/icons-react" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import type { ScanEngine } from "@/types/engine.types" // 组件属性类型定义 interface EngineDataTableProps { data: ScanEngine[] columns: ColumnDef[] onAddNew?: () => void searchPlaceholder?: string searchColumn?: string addButtonText?: string } /** * 扫描引擎数据表格组件 * 用于显示和管理扫描引擎数据 * 包含搜索、分页、列显示控制等功能 */ export function EngineDataTable({ data = [], columns, onAddNew, searchPlaceholder = "搜索引擎名称...", searchColumn = "name", addButtonText = "新建引擎", }: EngineDataTableProps) { // 表格状态管理 const [columnVisibility, setColumnVisibility] = React.useState({}) const [columnFilters, setColumnFilters] = React.useState([]) const [sorting, setSorting] = React.useState([]) const [columnSizing, setColumnSizing] = React.useState({}) const [pagination, setPagination] = React.useState<{ pageIndex: number pageSize: number }>({ pageIndex: 0, pageSize: 10, }) // 过滤有效数据 const validData = React.useMemo(() => { return (data || []).filter( (item) => item && typeof item.id !== "undefined" && item.id !== null ) }, [data]) // 创建表格实例 const table = useReactTable({ data: validData, columns, state: { sorting, columnVisibility, columnFilters, pagination, columnSizing, }, enableColumnResizing: true, columnResizeMode: 'onChange', onColumnSizingChange: setColumnSizing, getRowId: (row) => row.id.toString(), onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onColumnVisibilityChange: setColumnVisibility, onPaginationChange: setPagination, getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFacetedRowModel: getFacetedRowModel(), getFacetedUniqueValues: getFacetedUniqueValues(), }) return (
{/* 工具栏 */}
{/* 搜索框 */}
table.getColumn(searchColumn)?.setFilterValue(event.target.value) } className="max-w-sm" />
{/* 右侧操作按钮 */}
{/* 列显示控制 */} {table .getAllColumns() .filter( (column) => typeof column.accessorFn !== "undefined" && column.getCanHide() ) .map((column) => { const columnNameMap: Record = { name: "引擎名称", type: "类型", description: "描述", tools: "关联工具", updated_at: "更新时间", } return ( column.toggleVisibility(!!value) } > {columnNameMap[column.id] || column.id} ) })} {/* 添加新记录按钮 */} {onAddNew ? ( ) : null}
{/* 表格容器 */}
{/* 表头 */} {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} {header.column.getCanResize() && (
header.column.resetSize()} className="absolute -right-2.5 top-0 h-full w-8 cursor-col-resize select-none touch-none bg-transparent flex justify-center" >
)} ) })} ))} {/* 表体 */} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext() )} ))} )) ) : ( 暂无数据 )}
{/* 分页控制 */}
{/* 分页控制器 */}
{/* 每页显示数量选择 */}
{/* 页码信息 */}
Page {table.getState().pagination.pageIndex + 1} of{" "} {table.getPageCount()}
{/* 分页按钮 */}
) }