You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
3.6 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { ask, message } from "@tauri-apps/api/dialog";
import { invoke } from "@tauri-apps/api/tauri";
import { open } from "@tauri-apps/api/shell";
import type {
AppLogPaths,
NativeConfirmOptions,
ShowErrorNativeOptions,
} from "./types";
/**
* 统一封装原生确认框。
*/
export async function confirmNative(options: NativeConfirmOptions): Promise<boolean> {
try {
return await ask(options.message, {
title: options.title,
okLabel: options.okLabel,
cancelLabel: options.cancelLabel,
});
} catch (error) {
throw new Error(`打开确认框失败: ${String(error)}`);
}
}
async function fetchLogPaths(): Promise<AppLogPaths> {
return await invoke<AppLogPaths>("get_log_paths");
}
const ERROR_DIALOG_MAX_LINES = 6;
/** 报错弹窗正文:最多 6 行;超过时保留前 5 行完整内容,第 6 行仅显示「...」。 */
function truncateErrorTextForDialog(text: string): string {
const normalized = text.replace(/\r\n/g, "\n");
const lines = normalized.split("\n");
if (lines.length <= ERROR_DIALOG_MAX_LINES) {
return normalized;
}
return `${lines.slice(0, ERROR_DIALOG_MAX_LINES - 1).join("\n")}\n...`;
}
/**
* 原生错误提示。`options.logActions === "file"` 时正文仅展示错误信息(最多 6 行,第 6 行可为「...」),
* 并提供「打开日志文件」/「确定」:前者用系统默认程序打开 app.log后者仅关闭对话框。
*/
export async function showErrorNative(
content: string,
title = "错误",
options?: ShowErrorNativeOptions,
): Promise<void> {
const body = truncateErrorTextForDialog(content);
const logActions = options?.logActions ?? "none";
if (logActions === "none") {
try {
await message(body, { title, type: "error" });
} catch (error) {
throw new Error(`打开错误提示框失败: ${String(error)}`);
}
return;
}
let paths: AppLogPaths;
try {
paths = await fetchLogPaths();
} catch {
try {
await message(body, { title, type: "error" });
} catch (error) {
throw new Error(`打开错误提示框失败: ${String(error)}`);
}
return;
}
try {
const openFile = await ask(body, {
title,
type: "error",
okLabel: "打开日志文件",
cancelLabel: "确定",
});
if (openFile) {
await open(paths.logFile);
}
} catch (error) {
try {
const fallback = truncateErrorTextForDialog(
`${content}\n无法打开日志文件${String(error)}`,
);
await message(fallback, {
title,
type: "error",
});
} catch (inner) {
throw new Error(`打开错误提示框失败: ${String(inner)}`);
}
}
}
/**
* 报错并可选择打开 app.log正文仅错误摘要等价于 `logActions: "file"`)。
*/
export async function showErrorNativeWithLog(
content: string,
title = "错误",
): Promise<void> {
return showErrorNative(content, title, { logActions: "file" });
}
/**
* 原生信息提示(单按钮),用于非错误类说明。
*/
export async function showInfoNative(
content: string,
title = "提示",
): Promise<void> {
try {
await message(content, { title, type: "info" });
} catch (error) {
throw new Error(`打开提示框失败: ${String(error)}`);
}
}
/**
* 原生警告提示(非 Element 浮层),用于校验提示等。
*/
export async function showWarningNative(
content: string,
title = "提示",
): Promise<void> {
try {
await message(content, { title, type: "warning" });
} catch (error) {
throw new Error(`打开警告提示框失败: ${String(error)}`);
}
}