118 lines
4.0 KiB
TypeScript
Executable File
118 lines
4.0 KiB
TypeScript
Executable File
import { Checkbox } from '@nice/ui/components/checkbox';
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@nice/ui/components/table';
|
|
import { Skeleton } from '@nice/ui/components/skeleton';
|
|
import { IconFileText } from '@tabler/icons-react';
|
|
import { ArticleRow } from './article-row';
|
|
import { ArticleQuickEdit } from './article-quick-edit';
|
|
import { useArticlesContext } from './context';
|
|
import React from 'react';
|
|
|
|
interface ArticleTableProps {
|
|
hasFilters?: boolean; // 是否有筛选条件,用于显示不同的空状态信息
|
|
}
|
|
|
|
// 新增骨架屏组件
|
|
function ArticleTableSkeleton() {
|
|
return (
|
|
<>
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
<TableRow key={i} className="border-b-0">
|
|
<TableCell>
|
|
<Skeleton className="h-4 w-4" />
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-4 w-64" />
|
|
<Skeleton className="h-3 w-48" />
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Skeleton className="h-6 w-20 rounded-full" />
|
|
</TableCell>
|
|
<TableCell>
|
|
<Skeleton className="h-4 w-24" />
|
|
</TableCell>
|
|
<TableCell>
|
|
<Skeleton className="h-8 w-8 rounded-full" />
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-3 w-24" />
|
|
<Skeleton className="h-3 w-16" />
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="space-y-2">
|
|
<Skeleton className="h-3 w-24" />
|
|
<Skeleton className="h-3 w-16" />
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex justify-center gap-2">
|
|
<Skeleton className="h-7 w-7" />
|
|
<Skeleton className="h-7 w-7" />
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function ArticleTable({ hasFilters = false }: ArticleTableProps) {
|
|
const { articles, selectedArticles, quickEditId, handleSelectAll, isLoading } = useArticlesContext();
|
|
|
|
const isAllSelected = articles.length > 0 && articles.every((article) => selectedArticles.includes(article.id));
|
|
|
|
return (
|
|
<div className="overflow-auto flex-1">
|
|
<Table>
|
|
<TableHeader className="bg-muted/30 sticky top-0 z-10">
|
|
<TableRow className="border-b border-border hover:bg-transparent">
|
|
<TableHead className="w-12 py-4">
|
|
<Checkbox checked={isAllSelected} onCheckedChange={handleSelectAll} />
|
|
</TableHead>
|
|
<TableHead className="w-[45%] py-4 font-semibold">文章</TableHead>
|
|
<TableHead className="py-4 font-semibold">状态</TableHead>
|
|
<TableHead className="py-4 font-semibold">分类</TableHead>
|
|
<TableHead className="py-4 font-semibold">作者</TableHead>
|
|
<TableHead className="py-4 font-semibold">数据</TableHead>
|
|
<TableHead className="py-4 font-semibold">日期</TableHead>
|
|
<TableHead className="w-24 py-4 font-semibold text-center">操作</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{isLoading ? (
|
|
<ArticleTableSkeleton />
|
|
) : articles.length > 0 ? (
|
|
articles.map((article) => (
|
|
<React.Fragment key={article.id}>
|
|
<ArticleRow article={article} />
|
|
{quickEditId === article.id && <ArticleQuickEdit article={article} />}
|
|
</React.Fragment>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell colSpan={8} className="h-64 text-center">
|
|
<div className="flex flex-col items-center gap-3">
|
|
<div className="w-16 h-16 bg-muted/20 rounded-full flex items-center justify-center">
|
|
<IconFileText className="h-8 w-8 text-muted-foreground/50" />
|
|
</div>
|
|
<div className="space-y-1">
|
|
<div className="text-sm font-medium text-muted-foreground">
|
|
{hasFilters ? '没有找到符合条件的文章' : '还没有文章'}
|
|
</div>
|
|
<div className="text-xs text-muted-foreground">
|
|
{hasFilters ? '请尝试调整搜索条件' : '点击"新建文章"开始创作吧'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
);
|
|
}
|