60 lines
1.8 KiB
JavaScript
60 lines
1.8 KiB
JavaScript
export class ApiError extends Error {
|
||
constructor(message, status = 0, code = "error") {
|
||
super(message);
|
||
this.name = "ApiError";
|
||
this.status = status;
|
||
this.code = code;
|
||
}
|
||
}
|
||
|
||
function buildUrl(path, params) {
|
||
const url = new URL(path, window.location.origin);
|
||
if (params) {
|
||
for (const [key, value] of Object.entries(params)) {
|
||
if (value === null || value === undefined || value === "") continue;
|
||
url.searchParams.set(key, String(value));
|
||
}
|
||
}
|
||
return url;
|
||
}
|
||
|
||
export async function api(path, params) {
|
||
const response = await fetch(buildUrl(path, params), {
|
||
headers: { Accept: "application/json" },
|
||
credentials: "same-origin",
|
||
});
|
||
if (response.status === 401) {
|
||
window.location.href = "/login";
|
||
throw new ApiError("登录已失效,请重新登录", 401, "unauthorized");
|
||
}
|
||
let payload;
|
||
try {
|
||
payload = await response.json();
|
||
} catch {
|
||
throw new ApiError(`接口返回异常(HTTP ${response.status})`, response.status);
|
||
}
|
||
if (!response.ok || !payload.ok) {
|
||
const error = payload.error || {};
|
||
throw new ApiError(
|
||
error.message || `请求失败(HTTP ${response.status})`,
|
||
response.status,
|
||
error.code || "error",
|
||
);
|
||
}
|
||
return payload.data;
|
||
}
|
||
|
||
export async function health() {
|
||
const response = await fetch("/api/health", { credentials: "same-origin" });
|
||
if (!response.ok) throw new ApiError("无法连接看板服务", response.status);
|
||
const payload = await response.json();
|
||
return payload?.data ?? payload;
|
||
}
|
||
|
||
export async function session() {
|
||
const response = await fetch("/api/session", { credentials: "same-origin" });
|
||
if (!response.ok) throw new ApiError("无法连接看板服务", response.status);
|
||
const payload = await response.json();
|
||
return payload?.data ?? payload;
|
||
}
|