/** Format raw DB / API errors into a brief in-app dialog payload. */ export type NotifyKind = "error" | "warning" | "info" | "success"; export type NotifyPayload = { id: string; kind: NotifyKind; title: string; message: string; detail?: string; tips?: string[]; /** auto-dismiss ms for toast mode; modal stays until closed */ mode: "modal" | "toast"; durationMs?: number; }; type Parsed = { kind: NotifyKind; title: string; message: string; detail?: string; tips?: string[]; }; export function formatDbError(raw: unknown): Parsed { const text = raw instanceof Error ? raw.message : String(raw ?? "未知错误"); const lower = text.toLowerCase(); // MySQL / MariaDB Access denied if (/error\s*1045|access denied for user/i.test(text)) { const noPassword = /using password:\s*NO/i.test(text); return { kind: "error", title: "认证失败", message: noPassword ? "未填密码,服务器拒绝空密码登录。" : "用户名或密码错误,或主机无权访问。", detail: text, }; } if (/error\s*2003|can't connect|connection refused|econnrefused/i.test(text) || lower.includes("connect")) { if (/refused|2003|econnrefused|timed out|timeout|unreachable/i.test(text)) { return { kind: "error", title: "无法连接", message: "主机不可达,或端口未开 / 服务未启动。", detail: text, }; } } if (/error\s*1049|unknown database/i.test(text)) { return { kind: "error", title: "库不存在", message: "数据库名不正确;可留空连接后再选。", detail: text, }; } if (/驱动开发中/.test(text)) { return { kind: "warning", title: "驱动开发中", message: text, }; } if (/开发中/.test(text)) { return { kind: "info", title: "即将推出", message: text.replace(/:开发中$/, "功能开发中。"), }; } return { kind: "error", title: "操作失败", message: text.length > 120 ? "发生错误,详见详情。" : text, detail: text.length > 120 ? text : undefined, }; } export function notifyId() { return crypto.randomUUID(); }