feat: 错误监控面板、生成通知、社区搜索、任务队列优化

- AdminMonitor: admin用户可见的客户端错误实时监控面板,右下角浮窗
- generationNotifier: 生成完成浏览器通知 + 站内Toast
- CommunityPage: 新增搜索框,标题/描述/标签模糊匹配,防抖300ms
- App.tsx: 全局unhandled error/rejection监听上报
- WorkbenchPage: 任务并发提示改为显示当前任务数
- serverConnection: 后端client-errors路由注册
- WelcomeSplash: 欢迎按钮全程显示

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-06-03 02:01:21 +08:00
parent 468d1d27dd
commit 4ed02aaad5
9 changed files with 411 additions and 6 deletions
+21
View File
@@ -16,6 +16,8 @@ import {
} from "@ant-design/icons";
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef } from "react";
import ErrorBoundary from "./components/ErrorBoundary";
import { reportError } from "./utils/errorReporting";
import { initNotificationPermission } from "./utils/generationNotifier";
import PageTransition from "./components/PageTransition";
import ToastContainer from "./components/toast/ToastContainer";
import { aiGenerationClient } from "./api/aiGenerationClient";
@@ -282,6 +284,25 @@ function App() {
}
}, []);
// Pre-warm notification permission (lazy, on first click)
useEffect(() => { initNotificationPermission(); }, []);
// Global unhandled error / rejection listeners — report to server
useEffect(() => {
const handleUnhandled = (event: ErrorEvent) => {
reportError(event.error || new Error(event.message), "unhandled");
};
const handleRejection = (event: PromiseRejectionEvent) => {
reportError(event.reason instanceof Error ? event.reason : new Error(String(event.reason)), "rejection");
};
window.addEventListener("error", handleUnhandled);
window.addEventListener("unhandledrejection", handleRejection);
return () => {
window.removeEventListener("error", handleUnhandled);
window.removeEventListener("unhandledrejection", handleRejection);
};
}, []);
// Initialize canvasWorkflow if null
useEffect(() => {
if (!canvasWorkflow) {