export type ApiSession = { baseUrl: string token: string } type RequestOptions = { method?: string body?: unknown token?: string } let configuredBaseUrl = normalizeBaseUrl(import.meta.env.VITE_API_BASE_URL ?? 'http://127.0.0.1:18080') export function setApiBaseUrl(baseUrl: string) { configuredBaseUrl = normalizeBaseUrl(baseUrl) } export function getApiBaseUrl() { return configuredBaseUrl } export async function login(email: string, password: string): Promise { const response = await apiRequest<{ token: string }>('/api/auth/login', { method: 'POST', body: { email, password }, }) return { baseUrl: configuredBaseUrl, token: response.token } } export async function apiRequest(path: string, options: RequestOptions = {}): Promise { const isFormData = typeof FormData !== 'undefined' && options.body instanceof FormData const requestBody = options.body === undefined ? undefined : isFormData ? options.body : JSON.stringify(options.body) const response = await fetch(`${configuredBaseUrl}${path}`, { method: options.method ?? 'GET', headers: { ...(isFormData ? {} : { 'Content-Type': 'application/json' }), ...(options.token ? { Authorization: `Bearer ${options.token}` } : {}), }, body: requestBody as BodyInit | undefined, }) if (!response.ok) { let message = `请求失败:${response.status}` try { const payload = await response.json() if (typeof payload.error === 'string') message = payload.error } catch { // Keep the status-based message when the server does not return JSON. } throw new Error(message) } if (response.status === 204) { return undefined as T } const text = await response.text() if (text.trim() === '') { return undefined as T } return JSON.parse(text) as T } function normalizeBaseUrl(value: string) { const trimmed = value.trim() return trimmed.endsWith('/') ? trimmed.slice(0, -1) : trimmed }