"use client" import type { JSX } from "react" import { Component, type ErrorInfo, type ReactNode } from "react" import { useTranslations } from "next-intl" import { AlertCircle, RefreshCw } from "lucide-react" import { Button } from "@/shared/components/ui/button" interface BoundaryProps { children: ReactNode /** 自定义降级 UI(函数形式,优先级最高)。若提供则忽略 title/description/retryLabel */ fallback?: (error: Error, reset: () => void) => ReactNode /** 渲染失败时的标题(已国际化,默认取 {namespace}.error.boundaryTitle) */ title?: string /** 渲染失败时的描述(已国际化,默认取 {namespace}.error.boundaryDescription) */ description?: string /** 重试按钮文案(已国际化,默认取 {namespace}.error.retry) */ retryLabel?: string /** 错误回调(用于埋点/监控) */ onError?: (error: Error, info: ErrorInfo) => void } interface State { hasError: boolean error: Error | null } /** * 组件级 Error Boundary(类组件实现,承载错误捕获能力)。 * 不直接使用,请使用默认导出的函数式 `SectionErrorBoundary` 包装器以获得 i18n 支持。 * * 支持两种降级形式: * 1. `fallback`(函数 `(error, reset) => ReactNode`)— 完全自定义降级 UI(优先级最高) * 2. `title` / `description` / `retryLabel` — 默认降级 UI + i18n 文案 */ class SectionErrorBoundaryBase extends Component { constructor(props: BoundaryProps) { super(props) this.state = { hasError: false, error: null } } static getDerivedStateFromError(error: Error): State { return { hasError: true, error } } componentDidCatch(error: Error, errorInfo: ErrorInfo): void { console.error("[SectionErrorBoundary]", error, errorInfo) this.props.onError?.(error, errorInfo) } private handleRetry = (): void => { this.setState({ hasError: false, error: null }) } render(): ReactNode { if (this.state.hasError && this.state.error) { // 优先使用自定义 fallback if (this.props.fallback) { return this.props.fallback(this.state.error, this.handleRetry) } // 默认降级 UI return (
) } return this.props.children } } interface SectionErrorBoundaryProps { children: ReactNode /** i18n namespace,默认 "common"。需保证该 namespace 下存在 error.boundaryTitle / error.boundaryDescription / error.retry 键 */ namespace?: string /** 自定义降级 UI(函数形式,优先级最高)。若提供则忽略 title/description/retryLabel */ fallback?: (error: Error, reset: () => void) => ReactNode /** 显式覆盖标题(优先级高于 i18n 默认) */ title?: string /** 显式覆盖描述 */ description?: string /** 显式覆盖重试按钮文案 */ retryLabel?: string /** 错误回调(用于埋点/监控) */ onError?: (error: Error, info: ErrorInfo) => void } /** * 组件级 Error Boundary:包裹独立数据区块,防止单区块错误导致整页崩溃。 * 自动使用 next-intl 提供本地化文案;如需完全自定义可传入 `fallback` 函数。 * * @example * ```tsx * // 默认 i18n 文案 * * * * * // 完全自定义降级 UI * }> * * * ``` */ export function SectionErrorBoundary({ children, namespace = "common", fallback, title, description, retryLabel, onError, }: SectionErrorBoundaryProps): JSX.Element { const t = useTranslations(namespace) return ( {children} ) }