This commit is contained in:
fengchuanhn@gmail.com
2026-05-17 22:05:34 +08:00
parent 9dfeaa9e18
commit c70995fbc9
14 changed files with 428 additions and 148 deletions

View File

@@ -1,69 +1,59 @@
/** API 基址:开发走 Vite 代理 `/api`;生产可设 VITE_API_BASE_URL */
import { invoke } from "@tauri-apps/api/core";
/** API 路径前缀(实际 HTTP 由 Rust `api_request` 发出) */
const API_BASE = import.meta.env.VITE_API_BASE_URL || "/api/v1";
function formatValidationDetail(detail) {
if (!Array.isArray(detail)) {
return "请求参数无效";
}
const first = detail[0];
if (first?.msg) {
return String(first.msg);
}
return "请求参数无效";
function isTauri() {
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
}
/**
* @param {string} path - 相对路径,如 `/auth/register`
* @param {string} path - 相对 `/api/v1` 的路径,如 `/auth/login`
* @param {RequestInit} options
* @returns {Promise<{ ok: boolean, message: string, data?: unknown }>}
*/
export async function apiRequest(path, options = {}) {
const url = `${API_BASE}${path}`;
const headers = {
"Content-Type": "application/json",
...options.headers,
};
let res;
try {
res = await fetch(url, { ...options, headers });
} catch {
return { ok: false, message: "无法连接服务器,请确认后端已启动" };
}
let body = null;
try {
body = await res.json();
} catch {
body = null;
}
if (res.status === 422) {
if (!isTauri()) {
return {
ok: false,
message: formatValidationDetail(body?.detail),
message: "API 请求需在 Tauri 桌面端运行(由 Rust 代理并加解密)",
};
}
if (body && typeof body.ok === "boolean") {
return body;
const method = (options.method || "GET").toUpperCase();
let body;
if (options.body != null && options.body !== "") {
body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
}
if (res.status === 401) {
return { ok: false, message: "未登录或登录已过期" };
const headers = {};
if (options.headers) {
const h = options.headers;
if (h instanceof Headers) {
h.forEach((value, key) => {
headers[key] = value;
});
} else {
Object.assign(headers, h);
}
}
if (res.status === 403) {
return {
ok: false,
message: body?.detail || "无权限执行此操作",
};
}
const relPath = path.startsWith("/") ? path : `/${path}`;
return {
ok: false,
message: body?.message || `请求失败(${res.status}`,
};
try {
const result = await invoke("api_request", {
path: relPath,
method,
body: body ?? null,
headers: Object.keys(headers).length ? headers : null,
});
if (result && typeof result === "object" && "ok" in result) {
return result;
}
return { ok: false, message: "服务器返回格式异常" };
} catch (err) {
return { ok: false, message: String(err) };
}
}
export { API_BASE };