import { getH3Base, getToken, setToken } from './utils'; export async function apiFetch(path, options = {}) { const base = getH3Base(); const url = path.startsWith('http') ? path : `${base}${path}`; const token = getToken(); const headers = { ...(options.headers || {}) }; if (token) { headers['Authorization'] = `Bearer ${token}`; } const res = await fetch(url, { ...options, headers }); if (res.status === 401) { setToken(''); const newToken = window.prompt('H3 访问令牌 (Token) 已过期或无效,请输入新令牌:'); if (newToken) { setToken(newToken); headers['Authorization'] = `Bearer ${newToken}`; return fetch(url, { ...options, headers }); } } return res; } export async function fetchJobs({ page = 1, limit = 20, q = '', status = '', kind = '', sort = 'desc', trash = false } = {}) { const params = new URLSearchParams(); if (trash) { params.set('trash', 'true'); params.set('limit', '50'); } else { // 服务端分页参数是 offset 不是 page,传 page 会被忽略(永远返回第一页) params.set('offset', String((page - 1) * limit)); params.set('limit', String(limit)); if (q) params.set('q', q); if (status) params.set('status', status); if (kind) params.set('kind', kind); if (sort) params.set('sort', sort); } const res = await apiFetch(`/v1/videos?${params.toString()}`); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function fetchJobDetail(id) { const res = await apiFetch(`/v1/videos/${id}`); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function createJob(body) { const res = await apiFetch('/v1/videos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function uploadAsset(file) { const fd = new FormData(); fd.append('file', file); const res = await apiFetch('/v1/assets', { method: 'POST', body: fd, }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function prioritizeJob(id) { const res = await apiFetch(`/v1/videos/${id}/prioritize`, { method: 'POST' }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function deleteJob(id) { const res = await apiFetch(`/v1/videos/${id}`, { method: 'DELETE' }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function restoreJob(id) { const res = await apiFetch(`/v1/videos/${id}/restore`, { method: 'POST' }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function cancelJob(id) { const res = await apiFetch(`/v1/videos/${id}/cancel`, { method: 'POST' }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function resetGpu() { const res = await apiFetch('/v1/admin/reset-gpu', { method: 'POST' }); if (!res.ok) throw new Error(await res.text()); return res.json(); } export async function fetchBackends() { const res = await apiFetch('/v1/backends'); if (!res.ok) return null; return res.json(); } export async function fetchComfyHistory(id) { const res = await apiFetch(`/v1/videos/${id}/comfy_history`); if (!res.ok) throw new Error(await res.text()); return res.json(); }