diff --git a/app/canvas/[id]/page.tsx b/app/canvas/[id]/page.tsx
index f1c5e90cb..c0587bfb3 100644
--- a/app/canvas/[id]/page.tsx
+++ b/app/canvas/[id]/page.tsx
@@ -70,6 +70,7 @@ import { CanvasChatPanel } from "@/components/canvas/CanvasChatPanel";
import { CanvasFileListPanel } from "@/components/canvas/CanvasFileListPanel";
import { ObjectPickerOverlay } from "@/components/canvas/ObjectPickerOverlay";
import { SceneFusionDialog } from "@/components/scene-fusion-dialog";
+import { ClientErrorBoundary } from "@/components/ui/client-error-boundary";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn, fetcher } from "@/lib/utils";
import {
@@ -1041,12 +1042,39 @@ export default function CanvasEditorPage({ params }: PageProps) {
-
+ {selectedAgentPresetId ? (
+
+
+
工作台加载失败
+
+ 当前生图工作台发生了前端异常,我已经切换到安全兜底状态。你可以先返回上一步再重新进入,或者告诉我继续修复。
+
+
+
+ }
+ >
+
+
+ ) : (
+
+
+
+
+
+
请先选择左侧生图模式
+
+ 选择生图模式后,这里才会加载独立的生图工作台,并显示图片槽位、补充要求和生成结果。
+
+
+
+ )}
diff --git a/components/ui/client-error-boundary.tsx b/components/ui/client-error-boundary.tsx
new file mode 100644
index 000000000..b4dd2f632
--- /dev/null
+++ b/components/ui/client-error-boundary.tsx
@@ -0,0 +1,38 @@
+"use client";
+
+import React from "react";
+
+interface ClientErrorBoundaryProps {
+ children: React.ReactNode;
+ fallback: React.ReactNode;
+}
+
+interface ClientErrorBoundaryState {
+ hasError: boolean;
+}
+
+export class ClientErrorBoundary extends React.Component<
+ ClientErrorBoundaryProps,
+ ClientErrorBoundaryState
+> {
+ constructor(props: ClientErrorBoundaryProps) {
+ super(props);
+ this.state = { hasError: false };
+ }
+
+ static getDerivedStateFromError() {
+ return { hasError: true };
+ }
+
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
+ console.error("[ClientErrorBoundary] Caught client error:", error, errorInfo);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return this.props.fallback;
+ }
+
+ return this.props.children;
+ }
+}