/* ===================================================================== * 网络层(api.js) * 统一调用 /api/* 接口;localStorage 只保存 token 与 username(绝不保存密码)。 * ===================================================================== */ export class ApiError extends Error { constructor(message, status) { super(message); this.status = status; } } export async function api(path, { method = "GET", body } = {}) { const headers = { "Content-Type": "application/json" }; const token = localStorage.getItem("token"); if (token) headers["Authorization"] = `Bearer ${token}`; let res; try { res = await fetch(path, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) }); } catch (err) { throw new ApiError("网络请求失败,请稍后再试", 0); } let json = null; try { json = await res.json(); } catch (err) { /* 忽略非 JSON 响应 */ } if (!json || typeof json.success === "undefined") { throw new ApiError(`服务器响应异常(${res.status})`, res.status); } if (!json.success) throw new ApiError(json.message || "请求失败", res.status); return json.data; } // multipart 表单提交(普通字段 + 单个文件),用于项目管理等 export async function uploadForm(path, fields = {}, file = null, method = "POST") { const form = new FormData(); for (const [key, value] of Object.entries(fields)) { if (value !== undefined && value !== null && value !== "") form.append(key, String(value)); } if (file) form.append("file", file); const headers = {}; const token = localStorage.getItem("token"); if (token) headers["Authorization"] = `Bearer ${token}`; const res = await fetch(path, { method, headers, body: form }); let json = null; try { json = await res.json(); } catch (err) { /* 忽略非 JSON 响应 */ } if (!json || !json.success) throw new ApiError((json && json.message) || "操作失败", res.status); return json.data; } // multipart 上传(头像/图片/项目文件),返回 {url, filename, size} export async function uploadFile(path, file, extra = {}) { const form = new FormData(); form.append("file", file); // extra:附加字段(如上传文档时携带文章分区 category,供后端校验) for (const [key, value] of Object.entries(extra)) form.append(key, value); const headers = {}; const token = localStorage.getItem("token"); if (token) headers["Authorization"] = `Bearer ${token}`; const res = await fetch(path, { method: "POST", headers, body: form }); let json = null; try { json = await res.json(); } catch (err) { /* 忽略非 JSON 响应 */ } if (!json || !json.success) throw new ApiError((json && json.message) || "上传失败", res.status); return json.data; }