Files
update-server/admin-ui/src/api/simcae.ts
T

135 lines
3.2 KiB
TypeScript

import { getToken } from "@/utils/auth";
export class AdminApiError extends Error {
status: number;
body: unknown;
constructor(message: string, status: number, body: unknown) {
super(message);
this.name = "AdminApiError";
this.status = status;
this.body = body;
}
}
export function adminToken() {
return getToken()?.accessToken || localStorage.getItem("admin_token") || "";
}
export function friendlyError(error: unknown) {
const anyError = error as any;
if (anyError?.body?.detail) {
return typeof anyError.body.detail === "string"
? anyError.body.detail
: JSON.stringify(anyError.body.detail);
}
if (typeof anyError?.body === "string" && anyError.body) return anyError.body;
return anyError?.message || String(error || "未知错误");
}
export async function adminRequest<T = any>(
path: string,
options: {
method?: string;
json?: unknown;
body?: BodyInit;
headers?: Record<string, string>;
} = {}
): Promise<T> {
const headers = new Headers(options.headers || {});
const token = adminToken();
if (token) headers.set("X-Admin-Token", token);
let body = options.body;
if (options.json !== undefined) {
headers.set("Content-Type", "application/json");
body = JSON.stringify(options.json);
}
const response = await fetch(path, {
method: options.method || "GET",
headers,
body,
cache: "no-store"
});
const text = await response.text();
let parsed: unknown = null;
if (text) {
try {
parsed = JSON.parse(text);
} catch {
parsed = text;
}
}
if (!response.ok) {
throw new AdminApiError(
`HTTP ${response.status}: ${text || response.statusText}`,
response.status,
parsed
);
}
return parsed as T;
}
export async function copyText(text: string) {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
return;
}
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.opacity = "0";
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
textarea.remove();
}
export async function downloadAdminFile(
path: string,
filename: string,
options: {
method?: string;
json?: unknown;
body?: BodyInit;
headers?: Record<string, string>;
} = {}
) {
const headers = new Headers(options.headers || {});
headers.set("X-Admin-Token", adminToken());
let body = options.body;
if (options.json !== undefined) {
headers.set("Content-Type", "application/json");
body = JSON.stringify(options.json);
}
const response = await fetch(path, {
method: options.method || "GET",
cache: "no-store",
headers,
body
});
if (!response.ok) {
const text = await response.text();
throw new AdminApiError(
`HTTP ${response.status}: ${text || response.statusText}`,
response.status,
text
);
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);
}