// 后端取数:全部走 /api/*(dev 由 vite 代理到 uvicorn,线上同源)。 // 失败不抛飞页面,返回空集,让 UI 显示「暂无数据」。 async function getJSON(url) { const r = await fetch(url) if (!r.ok) throw new Error(`${r.status} ${url}`) return r.json() } function qs(params) { const p = new URLSearchParams() for (const [k, v] of Object.entries(params)) { if (v !== undefined && v !== null && v !== '') p.set(k, v) } const s = p.toString() return s ? `?${s}` : '' } export async function fetchRuns() { try { return (await getJSON('/api/runs')).runs || [] } catch { return [] } } export async function fetchMethods(table) { try { return (await getJSON(`/api/methods${qs({ table })}`)).methods || [] } catch { return [] } } const EMPTY = { total: 0, page: 1, size: 30, items: [] } export async function fetchQueries({ method, run_id, page, size } = {}) { try { return await getJSON(`/api/queries${qs({ method, run_id, page, size })}`) } catch { return EMPTY } } export async function fetchSearch({ platform, method, ok, run_id, query, page, size } = {}) { try { return await getJSON(`/api/search${qs({ platform, method, ok, run_id, query, page, size })}`) } catch { return EMPTY } } // {query文本: {total, ok}} —— 列表页给每条 query 决定「搜索结果」按钮是否可点、显示几个 export async function fetchSearchSummary() { try { return (await getJSON('/api/search/summary')).summary || {} } catch { return {} } }