119 lines
2.9 KiB
JavaScript
119 lines
2.9 KiB
JavaScript
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 };
|