const API_BASE = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"; async function fetchWithAuth( url: string, options: RequestInit = {}, token?: string ) { const headers: Record = { "Content-Type": "application/json", ...((options.headers as Record) || {}), }; if (token) { headers["Authorization"] = `Bearer ${token}`; } const res = await fetch(`${API_BASE}${url}`, { ...options, headers }); if (res.status === 401) { if (typeof window !== "undefined") { window.location.href = "/login"; } throw new Error("登录已过期,请重新登录"); } if (!res.ok) { let errorDetail = `请求失败 (HTTP ${res.status})`; try { const error = await res.json(); errorDetail = error.detail || error.message || errorDetail; } catch { // 解析失败,使用默认错误信息 } throw new Error(errorDetail); } if (res.status === 204) { return null; } return res.json(); } export const api = { auth: { register: (data: { name: string; email: string; password: string }) => fetchWithAuth("/api/v1/auth/register", { method: "POST", body: JSON.stringify(data), }), login: (data: { email: string; password: string }) => fetchWithAuth("/api/v1/auth/login", { method: "POST", body: JSON.stringify(data), }), getMe: (token: string) => fetchWithAuth("/api/v1/auth/me", {}, token), forgotPassword: (email: string) => fetchWithAuth("/api/v1/auth/forgot-password", { method: "POST", body: JSON.stringify({ email }), }), resetPassword: (token: string, newPassword: string) => fetchWithAuth("/api/v1/auth/reset-password", { method: "POST", body: JSON.stringify({ token, new_password: newPassword }), }), verifyEmail: (email: string, code: string) => fetchWithAuth("/api/v1/auth/verify-email", { method: "POST", body: JSON.stringify({ email, code }), }), resendVerification: (email: string) => fetchWithAuth("/api/v1/auth/resend-verification", { method: "POST", body: JSON.stringify({ email }), }), changePassword: (token: string, oldPassword: string, newPassword: string) => fetchWithAuth("/api/v1/auth/change-password", { method: "PUT", body: JSON.stringify({ old_password: oldPassword, new_password: newPassword }), }, token), updateProfile: (token: string, data: { name?: string; avatar_url?: string }) => fetchWithAuth("/api/v1/auth/profile", { method: "PUT", body: JSON.stringify(data), }, token), }, queries: { list: (token: string) => fetchWithAuth("/api/v1/queries/", {}, token), create: (token: string, data: unknown) => fetchWithAuth("/api/v1/queries/", { method: "POST", body: JSON.stringify(data) }, token), update: (token: string, id: string, data: unknown) => fetchWithAuth(`/api/v1/queries/${id}`, { method: "PUT", body: JSON.stringify(data) }, token), delete: (token: string, id: string) => fetchWithAuth(`/api/v1/queries/${id}`, { method: "DELETE" }, token), runNow: (token: string, id: string) => fetchWithAuth(`/api/v1/queries/${id}/run-now`, { method: "POST" }, token), }, citations: { list: (token: string, params?: string) => fetchWithAuth(`/api/v1/citations/${params ? `?${params}` : ""}`, {}, token), getStats: (token: string) => fetchWithAuth("/api/v1/citations/stats/", {}, token), }, subscriptions: { getPlans: async () => { const res = await fetch(`${API_BASE}/api/v1/subscriptions/plans`); if (!res.ok) throw new Error("获取套餐失败"); return res.json(); }, getCurrent: async (token: string) => fetchWithAuth("/api/v1/subscriptions/current", {}, token), subscribe: async (token: string, plan: string) => fetchWithAuth("/api/v1/subscriptions/subscribe", { method: "POST", body: JSON.stringify({ plan }), }, token), cancel: async (token: string) => fetchWithAuth("/api/v1/subscriptions/cancel", { method: "POST" }, token), getHistory: async (token: string) => fetchWithAuth("/api/v1/subscriptions/history", {}, token), }, admin: { getStats: async (token: string) => fetchWithAuth("/api/v1/admin/stats", {}, token), getUsers: async (token: string, params?: { skip?: number; limit?: number; search?: string }) => { const query = params ? "?" + new URLSearchParams(Object.entries(params).filter(([, v]) => v !== undefined) as [string, string][]).toString() : ""; return fetchWithAuth(`/api/v1/admin/users${query}`, {}, token); }, getUserDetail: async (token: string, userId: string) => fetchWithAuth(`/api/v1/admin/users/${userId}`, {}, token), toggleUserActive: async (token: string, userId: string) => fetchWithAuth(`/api/v1/admin/users/${userId}/toggle-active`, { method: "POST" }, token), updateUserPlan: async (token: string, userId: string, plan: string) => fetchWithAuth(`/api/v1/admin/users/${userId}/update-plan`, { method: "PUT", body: JSON.stringify({ plan }), }, token), }, reports: { exportCSV: (token: string, queryId?: string) => { const query = queryId ? `?query_id=${queryId}` : ""; return fetchWithAuth(`/api/v1/reports/export/csv${query}`, {}, token); }, exportPDF: async (token: string, queryId?: string) => { const query = queryId ? `?query_id=${queryId}` : ""; const res = await fetch(`${API_BASE}/api/v1/reports/export/pdf${query}`, { headers: { Authorization: `Bearer ${token}` }, }); if (!res.ok) throw new Error("导出失败"); return res.blob(); }, }, };