/** * MAF 多智能体会商 API 客户端地基。 * * 复用全局 `apiFetch`(自动注入 Authorization + credentials:include),这里只做: * - 拼 URL(`${getBackendBaseURL()}/api/maf-roundtable/...`) * - 统一 `res.ok` 检查 + detail 提取(仿 task-buttons 的 readJson) * - JSON 解析 * * 不在此做 snake_case ⇄ camelCase 转换——后端即 snake_case,类型层直传(见 types.ts)。 */ import { apiFetch } from "@/core/api/fetch-client"; import { getBackendBaseURL } from "@/core/config"; /** MAF roundtable 后端根路径(无尾斜杠)。 */ export const BASE = (): string => `${getBackendBaseURL()}/api/maf-roundtable`; /** * 检查 Response 并解析 JSON;失败时抛出带后端 `detail` 的 Error。 * * - 404 = 不存在或非本人(后端统一返回 404 防止泄漏他人资源存在性) * - 403 = 非所有者写(admin 也不能写别人的) * - 503 = 功能关闭 / store 未就绪 * * 这里不区分状态码语义,统一把 detail 透传给上层 toast/错误展示。 */ export async function readJson(res: Response, ctx: string): Promise { if (!res.ok) { const data = await res.json().catch(() => null); const detail = data && typeof data === "object" && "detail" in data ? String((data as { detail: unknown }).detail) : `${ctx} 失败(HTTP ${res.status})`; throw new Error(detail); } return (await res.json()) as T; } /** GET JSON 的快捷封装。 */ export async function getJson(url: string, ctx: string): Promise { const res = await apiFetch(url, { method: "GET" }); return readJson(res, ctx); } /** 发送 JSON body 的快捷封装。 */ export async function sendJson( url: string, method: "POST" | "PUT" | "DELETE" | "PATCH", body: unknown, ctx: string, ): Promise { const res = await apiFetch(url, { method, headers: { "Content-Type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body), }); return readJson(res, ctx); }