async function adminFetch(path: string, init?: RequestInit): Promise { const response = await fetch(path, { ...init, credentials: 'include', headers: { Accept: 'application/json', ...(init?.body ? { 'Content-Type': 'application/json' } : {}), ...(init?.headers ?? {}), }, }); const payload = (await response.json().catch(() => ({}))) as { data?: T; message?: string; error?: { code: string; message: string }; }; if (!response.ok) { throw new Error(payload?.error?.message ?? payload?.message ?? `请求失败 (${response.status})`); } return (payload.data !== undefined ? payload.data : payload) as T; } export type AdminUser = { id: string; username: string; slug: string; email: string; displayName: string; role: string; status: string; balanceCents: number; createdAt: string; }; export type AdminSummary = { totalUsers: number; activeUsers: number; totalBalanceCents: number; llm?: { keyCount: number; selectedKeyName: string | null; globalModel: string | null; }; }; export type LlmKey = { id: string; name: string; provider: string; model?: string; models?: string[]; isSelected: boolean; createdAt?: string; }; export type LedgerEntry = { id: string; userId: string; username?: string; type: string; amountCents: number; note: string; createdAt: string; }; export type UsageRecord = { id: string; userId: string; username?: string; provider: string; model: string; inputTokens: number; outputTokens: number; costCents: number; createdAt: string; }; // ─── Summary ────────────────────────────────────────────────────────────────── export async function fetchAdminSummary() { return adminFetch<{ summary: AdminSummary }>('/admin-api/summary'); } // ─── Users ──────────────────────────────────────────────────────────────────── export async function fetchAdminUsers(params: { page?: number; pageSize?: number; search?: string; role?: string; status?: string; }) { const q = new URLSearchParams(); if (params.page) q.set('page', String(params.page)); if (params.pageSize) q.set('pageSize', String(params.pageSize)); if (params.search) q.set('search', params.search); if (params.role) q.set('role', params.role); if (params.status) q.set('status', params.status); return adminFetch<{ users: AdminUser[]; total: number; page: number; pageSize: number; totalPages: number }>( `/admin-api/users?${q}`, ); } export async function createAdminUser(body: { username: string; password: string; displayName?: string; role?: string; }) { return adminFetch<{ user: AdminUser }>('/admin-api/users', { method: 'POST', body: JSON.stringify(body), }); } export async function patchAdminUser( userId: string, patch: { role?: string; status?: string; displayName?: string; password?: string }, ) { return adminFetch<{ user: AdminUser }>(`/admin-api/users/${userId}`, { method: 'PATCH', body: JSON.stringify(patch), }); } export async function rechargeUser(userId: string, amountCents: number, note = '') { return adminFetch<{ user: AdminUser }>(`/admin-api/users/${userId}/recharge`, { method: 'POST', body: JSON.stringify({ amountCents, note }), }); } // ─── Billing ────────────────────────────────────────────────────────────────── export async function fetchAdminLedger(params: { page?: number; pageSize?: number } = {}) { const q = new URLSearchParams(); if (params.page) q.set('page', String(params.page)); if (params.pageSize) q.set('pageSize', String(params.pageSize)); return adminFetch<{ entries: LedgerEntry[]; total: number; page: number; totalPages: number }>( `/admin-api/ledger?${q}`, ); } export async function fetchAdminUsage(params: { page?: number; pageSize?: number } = {}) { const q = new URLSearchParams(); if (params.page) q.set('page', String(params.page)); if (params.pageSize) q.set('pageSize', String(params.pageSize)); return adminFetch<{ records: UsageRecord[]; total: number; page: number; totalPages: number }>( `/admin-api/usage?${q}`, ); } // ─── LLM Providers ─────────────────────────────────────────────────────────── export async function fetchLlmKeys() { return adminFetch<{ keys: LlmKey[] }>('/admin-api/llm-providers/keys'); } export async function createLlmKey(body: { name: string; provider: string; apiKey: string; model?: string; models?: string; baseUrl?: string; }) { return adminFetch<{ key: LlmKey }>('/admin-api/llm-providers/keys', { method: 'POST', body: JSON.stringify(body), }); } export async function patchLlmKey(keyId: string, patch: { name?: string; apiKey?: string; model?: string }) { return adminFetch<{ key: LlmKey }>(`/admin-api/llm-providers/keys/${keyId}`, { method: 'PATCH', body: JSON.stringify(patch), }); } export async function selectLlmKey(keyId: string) { return adminFetch(`/admin-api/llm-providers/keys/${keyId}/select`, { method: 'POST' }); } export async function deleteLlmKey(keyId: string) { return adminFetch(`/admin-api/llm-providers/keys/${keyId}`, { method: 'DELETE' }); } export async function testLlmKey(keyId: string) { return adminFetch<{ ok: boolean; model?: string; error?: string }>( `/admin-api/llm-providers/keys/${keyId}/test`, { method: 'POST' }, ); } export async function fetchLlmGlobal() { return adminFetch<{ settings: { model: string | null } }>('/admin-api/llm-providers/global'); } export async function putLlmGlobal(model: string) { return adminFetch('/admin-api/llm-providers/global', { method: 'PUT', body: JSON.stringify({ model }), }); } export async function syncLlmProviders() { return adminFetch<{ synced: number }>('/admin-api/llm-providers/sync', { method: 'POST' }); }