// 图片上传与短时签名 URL (与 server/routes/images.js 对应) import { API_BASE } from "./config"; import { getToken } from "./index"; function base(p: string) { return API_BASE ? API_BASE + p : p; } function authHeaders(): Record { const t = getToken(); return t ? { Authorization: `Bearer ${t}` } : {}; } async function request(method: string, path: string, body?: unknown): Promise { const headers: Record = { "Content-Type": "application/json", ...authHeaders() }; let res: Response; try { res = await fetch(base(path), { method, headers, body: body === undefined ? undefined : JSON.stringify(body) }); } catch { throw new Error("网络错误,请检查网络连接"); } let data: unknown = null; try { data = await res.json(); } catch { /* no body */ } if (!res.ok) { const msg = (data as { error?: string } | null)?.error ?? `请求失败 (${res.status})`; if (res.status === 401) localStorage.removeItem("storage_user"); throw new Error(msg); } return data as T; } // 上传: multipart/form-data, 返回暂存文件名 (挂到物品后由服务端归入家庭目录) export async function uploadImage(file: File): Promise { const fd = new FormData(); fd.append("file", file); let res: Response; try { res = await fetch(base("/api/images"), { method: "POST", headers: authHeaders(), body: fd }); } catch { throw new Error("网络错误,请检查网络连接"); } let data: unknown = null; try { data = await res.json(); } catch { /* no body */ } if (!res.ok) { const msg = (data as { error?: string } | null)?.error ?? `上传失败 (${res.status})`; throw new Error(msg); } return (data as { path: string }).path; } // 生成短时签名 URL (15 分钟), 供 直接使用 export function signImagePath(path: string) { return request<{ url: string }>("POST", "/api/images/sign", { path }); } // 带鉴权的输入框支持 (web 浏览器限制多, 移动端/桌面经 Tauri shell 无缝) export function imageAuthHeader(): Record { const t = getToken(); return t ? { Authorization: `Bearer ${t}` } : {}; }