Files
Storage/src/api/images.ts
T
2026-09-26 22:46:15 +08:00

64 lines
2.1 KiB
TypeScript

// 图片上传与短时签名 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<string, string> {
const t = getToken();
return t ? { Authorization: `Bearer ${t}` } : {};
}
async function request<T>(method: string, path: string, body?: unknown): Promise<T> {
const headers: Record<string, string> = { "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<string> {
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 分钟), 供 <img> 直接使用
export function signImagePath(path: string) {
return request<{ url: string }>("POST", "/api/images/sign", { path });
}
// 带鉴权的输入框支持 (web 浏览器限制多, 移动端/桌面经 Tauri shell 无缝)
export function imageAuthHeader(): Record<string, string> {
const t = getToken();
return t ? { Authorization: `Bearer ${t}` } : {};
}