Initial project commit

This commit is contained in:
2026-05-09 16:40:29 +08:00
commit 02b0259a9e
267 changed files with 54891 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
import { API_BASE } from "./config";
let isRefreshing = false;
let pendingQueue = [];
const isHtmlLike = (value) =>
typeof value === "string" && value.trim().startsWith("<");
export const extractList = (payload) => {
if (Array.isArray(payload?.items)) return payload.items;
if (Array.isArray(payload?.data)) return payload.data;
if (Array.isArray(payload)) return payload;
return [];
};
const doRequest = (options) => {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync("access_token");
uni.request({
url: API_BASE + options.url,
method: options.method || "GET",
data: options.data,
header: {
"Content-Type": "application/json",
...(token ? { Authorization: `Bearer ${token}` } : {}),
...options.header,
},
success: (res) => resolve(res),
fail: (err) => reject(err),
});
});
};
const tryRefreshToken = () => {
return new Promise((resolve, reject) => {
const rt = uni.getStorageSync("refresh_token");
if (!rt) return reject(new Error("no_refresh_token"));
uni.request({
url: API_BASE + "/auth/refresh",
method: "POST",
header: { "Content-Type": "application/json" },
data: { refresh_token: rt },
success: (res) => {
if (res.statusCode >= 200 && res.statusCode < 300) {
const { access_token, refresh_token } = res.data;
uni.setStorageSync("access_token", access_token);
if (refresh_token) uni.setStorageSync("refresh_token", refresh_token);
resolve();
} else {
reject(new Error("refresh_failed"));
}
},
fail: () => reject(new Error("refresh_network_error")),
});
});
};
const goLogin = () => {
uni.removeStorageSync("access_token");
uni.removeStorageSync("refresh_token");
const pages = getCurrentPages();
const current = pages[pages.length - 1];
const route = current ? `/${current.route}` : "";
if (route !== "/pages/login/index") {
uni.navigateTo({ url: "/pages/login/index" });
}
};
const handleError = (res) => {
const code = res.statusCode;
if (code === 403) return "没有权限执行此操作";
if (code === 404) return "请求的资源不存在";
if (code === 409) return "数据冲突,请刷新重试";
if (code === 422) {
const detail = res.data?.detail;
if (Array.isArray(detail) && detail.length > 0) {
return detail.map((d) => d.msg || d.message).join("");
}
}
if (code === 429) return "操作过于频繁,请稍后再试";
if (code >= 500) return "服务器繁忙,请稍后重试";
const raw = res.data?.message || res.data?.detail || "请求失败";
return typeof raw === "string" ? raw : JSON.stringify(raw);
};
const request = (options) => {
return new Promise((resolve, reject) => {
doRequest(options)
.then((res) => {
if (isHtmlLike(res.data)) {
const msg = "接口返回异常,请检查网络或服务状态";
uni.showToast({ title: msg, icon: "none" });
return reject(new Error(msg));
}
if (res.statusCode === 401) {
if (isRefreshing) {
pendingQueue.push({ options, resolve, reject });
return;
}
isRefreshing = true;
tryRefreshToken()
.then(() => {
isRefreshing = false;
doRequest(options).then((r2) => {
if (r2.statusCode >= 200 && r2.statusCode < 300) {
resolve(r2.data);
} else {
const msg = handleError(r2);
uni.showToast({ title: msg, icon: "none" });
reject(new Error(msg));
}
});
pendingQueue.forEach((p) => {
doRequest(p.options).then((r2) => {
if (r2.statusCode >= 200 && r2.statusCode < 300) {
p.resolve(r2.data);
} else {
p.reject(new Error(handleError(r2)));
}
});
});
pendingQueue = [];
})
.catch(() => {
isRefreshing = false;
pendingQueue.forEach((p) => p.reject(new Error("登录已过期")));
pendingQueue = [];
goLogin();
reject(new Error("登录已过期,请重新登录"));
});
return;
}
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data);
} else {
const msg = handleError(res);
uni.showToast({ title: msg, icon: "none" });
reject(new Error(msg));
}
})
.catch((err) => {
uni.showToast({ title: "网络连接失败,请检查网络", icon: "none" });
reject(err);
});
});
};
export const get = (url, data) => request({ url, method: "GET", data });
export const post = (url, data) => request({ url, method: "POST", data });
export const put = (url, data) => request({ url, method: "PUT", data });
export const del = (url, data) => request({ url, method: "DELETE", data });
export default request;