Files
omniai-web/src/utils/errorReporting.ts
T
stringadmin f5a75074a4 feat: 邮箱注册验证 + 9项功能修复与优化
【认证系统】
- 新增邮箱验证码注册/登录流程 (sendEmailCode / verifyEmail / forgotPassword / resetPassword)
- register-email 现在需要验证码
- 服务端新增 email_verification_codes 表 + patch-email-verification.js
- App.tsx 登录后 emailVerified 检查提醒
- keyServerClient token 显式传递修复 401 错误

【电商模块】
- 自动推进: 策划完成后自动生成分镜图/视频
- 模特图选项 (性别/年龄/种族/体型/场景) 注入 AI 提示词
- 任务持久化指纹修复 (图片数量替代 blob URL)
- 新增「视频换装」入口 (happyhorse-1.0-video-edit)

【剧本评分】
- 新增 .docx/.doc Word 文档支持 (ZIP解压+XML提取)
- 历史记录支持点击查看/恢复评测结果

【画布】
- ReactFlow 节点禁止内置拖拽避免冲突
- 连接线拖拽弹窗优化 (预览线不消失, 弹窗跟踪鼠标)

【页面修复】
- 首页轮播图改为 aspect-ratio: 16/9 解决尺寸问题
- 资产库新增悬停删除按钮
- scriptEvalClient 改用服务端 /api/ai/chat 端点
- TokenUsagePage 未登录跳过 API 调用
2026-06-03 20:19:07 +08:00

63 lines
1.9 KiB
TypeScript

const ERROR_REPORT_ENDPOINT = "/api/client-errors";
const CLIENT_ERROR_REPORTING_ENABLED = import.meta.env.VITE_ENABLE_CLIENT_ERROR_REPORTING === "1";
interface ErrorReport {
message: string;
stack?: string;
source: "boundary" | "unhandled" | "rejection" | "manual";
url: string;
timestamp: number;
userAgent: string;
sessionId?: string;
}
let reportQueue: ErrorReport[] = [];
let flushTimer: ReturnType<typeof setTimeout> | null = null;
function getSessionId(): string | undefined {
try {
const raw = localStorage.getItem("omniai:session") || sessionStorage.getItem("omniai:session");
if (!raw) return undefined;
const parsed = JSON.parse(raw);
return parsed?.user?.sessionId ?? undefined;
} catch {
return undefined;
}
}
function flush() {
if (reportQueue.length === 0) return;
const batch = reportQueue.splice(0, 10);
const baseUrl = import.meta.env.VITE_API_BASE_URL || "";
const url = `${baseUrl}${ERROR_REPORT_ENDPOINT}`;
const token = localStorage.getItem("omniai:token") || sessionStorage.getItem("omniai:token") || "";
const headers: Record<string, string> = { "Content-Type": "application/json" };
if (token) headers["Authorization"] = `Bearer ${token}`;
navigator.sendBeacon?.(url, new Blob([JSON.stringify({ errors: batch })], { type: "application/json" }));
}
function scheduleFlush() {
if (flushTimer) return;
flushTimer = setTimeout(() => {
flushTimer = null;
flush();
}, 2000);
}
export function reportError(error: unknown, source: ErrorReport["source"] = "manual") {
if (!CLIENT_ERROR_REPORTING_ENABLED) return;
const err = error instanceof Error ? error : new Error(String(error));
const report: ErrorReport = {
message: err.message,
stack: err.stack?.slice(0, 2000),
source,
url: window.location.href,
timestamp: Date.now(),
userAgent: navigator.userAgent,
sessionId: getSessionId(),
};
reportQueue.push(report);
scheduleFlush();
}