"use client" import { type ReactNode, Suspense } from "react" import { AlertCircle } from "lucide-react" import { EmptyState } from "@/shared/components/ui/empty-state" import { Card, CardContent, CardHeader } from "@/shared/components/ui/card" import { Skeleton } from "@/shared/components/ui/skeleton" import { useTranslations } from "next-intl" import { SectionErrorBoundary } from "@/shared/components/section-error-boundary" /** * 分区骨架屏变体 * * 不同数据区块使用不同骨架布局,提供更贴近真实内容的加载占位。 */ type SkeletonVariant = "stats" | "card" | "chart" | "table" | "list" export function DashboardSectionSkeleton({ variant = "card", }: { variant?: SkeletonVariant }): ReactNode { switch (variant) { case "stats": return (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) case "chart": return ( ) case "table": return ( {Array.from({ length: 5 }).map((_, i) => ( ))} ) case "list": return ( {Array.from({ length: 4 }).map((_, i) => (
))}
) case "card": default: return ( ) } } /** * 仪表盘分区包装器 * * 组合 Error Boundary + Suspense + 骨架屏,包裹每个独立数据区块。 * 单个区块出错或加载中时,仅影响该区块,不波及整页。 * * 使用共享 SectionErrorBoundary 替代模块特定的 DashboardSectionErrorBoundary 类。 * * V4(P3-1)新增 `ariaLabel` prop:传入时渲染 `
`, * 使键盘用户可按逻辑顺序遍历各 Widget,提升 a11y。 * * @example * * * */ export function DashboardSection({ children, variant = "card", ariaLabel, }: { children: ReactNode variant?: SkeletonVariant /** 传入时渲染为可聚焦的 region,提升键盘导航 a11y */ ariaLabel?: string }): ReactNode { const t = useTranslations("dashboard.error") const fallback = (): ReactNode => ( window.location.reload() }} className="h-auto border-none shadow-none" /> ) const content = ( }> {children} ) if (ariaLabel) { return (
{content}
) } return content }