const BASE_URL = import.meta.env.VITE_API_BASE; const MOCK_DELAY = 300; const mock = (data, delay = MOCK_DELAY) => new Promise((resolve) => setTimeout(() => resolve(data), delay)); function parseJsonPreserveLongIds(text) { if (!text) return null; let result = ""; let inString = false; let escaped = false; for (let i = 0; i < text.length; i += 1) { const char = text[i]; if (inString) { result += char; if (escaped) { escaped = false; } else if (char === "\\") { escaped = true; } else if (char === "\"") { inString = false; } continue; } if (char === "\"") { inString = true; result += char; continue; } const startsNumber = char === "-" || (char >= "0" && char <= "9"); if (!startsNumber) { result += char; continue; } const start = i; if (char === "-") i += 1; while (i < text.length && text[i] >= "0" && text[i] <= "9") i += 1; const numberText = text.slice(start, i); const nextChar = text[i]; const isInteger = nextChar !== "." && nextChar !== "e" && nextChar !== "E"; const digitCount = numberText.startsWith("-") ? numberText.length - 1 : numberText.length; result += isInteger && digitCount >= 16 ? `"${numberText}"` : numberText; i -= 1; } return JSON.parse(result); } export const fetchApi = async (url, options = {}) => { const fullUrl = url.startsWith("http") ? url : BASE_URL + url; const token = localStorage.getItem("token"); const isFormData = options.body instanceof FormData; const config = { headers: { ...(isFormData ? {} : { "Content-Type": "application/json" }), ...(token ? { Authorization: `Bearer ${token}` } : {}), ...options.headers, }, ...options, }; try { const res = await fetch(fullUrl, config); const raw = await res.text(); const data = parseJsonPreserveLongIds(raw); if (!res.ok) { throw new Error(data.message || `请求失败: ${res.status}`); } return data; } catch (error) { console.error(`[API] ${options.method || "GET"} ${fullUrl}`, error); throw error; } }; export const get = (url, params, options = {}) => { const query = params ? "?" + new URLSearchParams(params).toString() : ""; return fetchApi(url + query, { ...options, method: "GET" }); }; export const post = (url, data, options = {}) => fetchApi(url, { ...options, method: "POST", body: JSON.stringify(data), }); export const postForm = (url, formData, options = {}) => fetchApi(url, { ...options, method: "POST", body: formData, }); export const put = (url, data, options = {}) => fetchApi(url, { ...options, method: "PUT", body: JSON.stringify(data), }); export const del = (url, data, options = {}) => { const config = { ...options, method: "DELETE" }; if (data) config.body = JSON.stringify(data); return fetchApi(url, config); }; export { mock };