import type { ReactNode } from "react"; import { cn } from "./utils/cn"; import { Loading } from "./loading"; import { Empty } from "./empty"; /** * DataTable - 通用数据表格 * * 用途:列表数据的标准展示容器,内置加载态、空态、行交互。 * 复用 Loading / Empty 组件保持一致的降级 UI。 * * @example * const columns: Column[] = [ * { key: "name", header: "姓名" }, * { key: "score", header: "分数", align: "right", render: (u) => u.score }, * ]; * u.id} /> */ /** 列对齐方式 */ export type ColumnAlign = "left" | "center" | "right"; /** 列定义 */ export interface Column { /** 唯一标识(用于 key) */ key: string; /** 表头内容 */ header: ReactNode; /** 自定义单元格渲染;未提供时取 row[key] */ render?: (row: T) => ReactNode; /** 自定义单元格类名 */ className?: string; /** 对齐方式 */ align?: ColumnAlign; /** 列宽(CSS 值,如 "200px" / "20%") */ width?: string; } export interface DataTableProps { /** 列定义 */ columns: Column[]; /** 数据数组 */ data: T[]; /** 加载态;为 true 时显示 Loading */ loading?: boolean; /** 空态自定义内容;未提供时使用默认 Empty */ empty?: ReactNode; /** 行点击回调 */ onRowClick?: (row: T) => void; /** 行 key 生成函数;未提供时使用索引 */ rowKey?: (row: T) => string; /** 自定义类名 */ className?: string; } const ALIGN_CLASS: Record = { left: "text-left", center: "text-center", right: "text-right", }; export function DataTable({ columns, data, loading, empty, onRowClick, rowKey, className, }: DataTableProps): ReactNode { if (loading) { return ; } if (data.length === 0) { return empty ?? ; } return (
{columns.map((col) => ( ))} {data.map((row, index) => { const key = rowKey ? rowKey(row) : String(index); return ( onRowClick(row) : undefined} className={cn( "border-b", onRowClick && "cursor-pointer hover:bg-muted", )} > {columns.map((col) => ( ))} ); })}
{col.header}
{col.render ? col.render(row) : null}
); }