feat: 实现管理后台 W1-W3 假数据界面
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { message } from "@/utils/notify";
|
||||
import type { ApiEnvelope, ApiErrorBody } from "./types";
|
||||
|
||||
export class ApiError extends Error {
|
||||
readonly code: string;
|
||||
readonly httpStatus: number;
|
||||
readonly data?: unknown;
|
||||
|
||||
constructor(code: string, msg: string, httpStatus = 400, data?: unknown) {
|
||||
super(msg);
|
||||
this.name = "ApiError";
|
||||
this.code = code;
|
||||
this.httpStatus = httpStatus;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
||||
|
||||
export interface RequestOptions {
|
||||
method?: HttpMethod;
|
||||
body?: unknown;
|
||||
headers?: Record<string, string>;
|
||||
/** 为 true 时不弹出错误提示(由调用方处理) */
|
||||
silent?: boolean;
|
||||
rawBody?: BodyInit | null;
|
||||
contentType?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理接口请求封装:自动带 credentials 与 X-Nixmsg-Request: 1,错误直接 message 显示。
|
||||
* W4 接真实后端时页面不必改,只需让 admin 模块走本函数。
|
||||
*/
|
||||
export async function requestAdmin<T>(path: string, opts: RequestOptions = {}): Promise<T> {
|
||||
const method = opts.method ?? (opts.body != null || opts.rawBody != null ? "POST" : "GET");
|
||||
const headers: Record<string, string> = {
|
||||
"X-Nixmsg-Request": "1",
|
||||
...opts.headers,
|
||||
};
|
||||
|
||||
let body: BodyInit | undefined | null = opts.rawBody;
|
||||
if (opts.rawBody === undefined && opts.body !== undefined) {
|
||||
headers["Content-Type"] = opts.contentType ?? "application/json";
|
||||
body = JSON.stringify(opts.body);
|
||||
} else if (opts.contentType) {
|
||||
headers["Content-Type"] = opts.contentType;
|
||||
}
|
||||
|
||||
const res = await fetch(path, {
|
||||
method,
|
||||
credentials: "include",
|
||||
headers,
|
||||
body: body ?? undefined,
|
||||
});
|
||||
|
||||
let envelope: ApiEnvelope<T>;
|
||||
try {
|
||||
envelope = (await res.json()) as ApiEnvelope<T>;
|
||||
} catch {
|
||||
const err = new ApiError("internal", `响应不是 JSON(HTTP ${res.status})`, res.status);
|
||||
if (!opts.silent) {
|
||||
message.error(err.message);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (typeof envelope !== "object" || envelope === null) {
|
||||
const err = new ApiError("internal", "响应格式无效", res.status);
|
||||
if (!opts.silent) {
|
||||
message.error(err.message);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (envelope.ok) {
|
||||
return envelope.data;
|
||||
}
|
||||
|
||||
const errBody: ApiErrorBody = envelope.error ?? { code: "internal", message: "未知错误" };
|
||||
const err = new ApiError(errBody.code, errBody.message, res.status, "data" in envelope ? envelope.data : undefined);
|
||||
if (!opts.silent) {
|
||||
message.error(err.message);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
Reference in New Issue
Block a user