2025-09-25 13:32:47 +08:00
|
|
|
|
import axios from "axios";
|
|
|
|
|
|
import { errorCodeType } from "./error-code-type";
|
|
|
|
|
|
import { ElMessage } from "element-plus";
|
|
|
|
|
|
import store from "@/store/index";
|
|
|
|
|
|
|
|
|
|
|
|
const service = axios.create({
|
|
|
|
|
|
baseURL: "/api",
|
2025-10-30 10:08:30 +08:00
|
|
|
|
timeout: 60 * 1000 * 3,
|
2025-09-25 13:32:47 +08:00
|
|
|
|
headers: { "Content-Type": "application/json;charset=utf-8" },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 认证状态管理
|
|
|
|
|
|
let isAuthenticated = false;
|
|
|
|
|
|
let isAuthenticating = false;
|
|
|
|
|
|
const requestQueue: Array<() => void> = [];
|
|
|
|
|
|
|
|
|
|
|
|
// 执行队列中的请求
|
|
|
|
|
|
const executeQueue = () => {
|
|
|
|
|
|
while (requestQueue.length > 0) {
|
|
|
|
|
|
const nextRequest = requestQueue.shift();
|
|
|
|
|
|
if (nextRequest) nextRequest();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 请求拦截器
|
|
|
|
|
|
service.interceptors.request.use(
|
|
|
|
|
|
(config) => {
|
|
|
|
|
|
const isAuthRequest = config.url === "/cn_authenticate";
|
|
|
|
|
|
|
|
|
|
|
|
if (!isAuthRequest) {
|
|
|
|
|
|
if (isAuthenticating) {
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
|
requestQueue.push(() => {
|
|
|
|
|
|
resolve(service(config));
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const token = window.sessionStorage.getItem("token");
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
config.headers["Authorization"] = `Bearer ${token}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isAuthenticated) {
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
|
requestQueue.push(() => {
|
|
|
|
|
|
resolve(service(config));
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (isAuthenticating) {
|
|
|
|
|
|
return Promise.reject({ message: "认证中", isHandled: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
isAuthenticating = true;
|
|
|
|
|
|
config.headers["Authorization"] = "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// get请求参数处理(保持原逻辑)
|
|
|
|
|
|
// if (config.method === "get" && config.params) {
|
|
|
|
|
|
// // 这里用 toLowerCase() 确保兼容
|
|
|
|
|
|
// let url = config.url + "?";
|
|
|
|
|
|
// for (const propName of Object.keys(config.params)) {
|
|
|
|
|
|
// const value = config.params[propName];
|
|
|
|
|
|
// const part = encodeURIComponent(propName) + "=";
|
|
|
|
|
|
// if (value !== null && typeof value !== "undefined") {
|
|
|
|
|
|
// if (typeof value === "object") {
|
|
|
|
|
|
// for (const key of Object.keys(value)) {
|
|
|
|
|
|
// const params = propName + "[" + key + "]";
|
|
|
|
|
|
// const subPart = encodeURIComponent(params) + "=";
|
|
|
|
|
|
// url += subPart + encodeURIComponent(value[key]) + "&";
|
|
|
|
|
|
// }
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// url += part + encodeURIComponent(value) + "&";
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// url = url.slice(0, -1);
|
|
|
|
|
|
// config.params = {};
|
|
|
|
|
|
// config.url = url;
|
|
|
|
|
|
// }
|
|
|
|
|
|
return config;
|
|
|
|
|
|
},
|
|
|
|
|
|
(error) => {
|
|
|
|
|
|
console.log(error);
|
|
|
|
|
|
return Promise.reject(error);
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 响应拦截器(保持原逻辑,略作兼容处理)
|
|
|
|
|
|
let refreshQueue: any = [];
|
|
|
|
|
|
let isRefreshing = false;
|
|
|
|
|
|
|
|
|
|
|
|
service.interceptors.response.use(
|
|
|
|
|
|
(res) => {
|
|
|
|
|
|
if (res.config.url === "/cn_authenticate") {
|
|
|
|
|
|
isAuthenticating = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (res.data.code === "A0000") {
|
|
|
|
|
|
isAuthenticated = true;
|
|
|
|
|
|
setTimeout(executeQueue, 1000);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
isAuthenticated = false;
|
|
|
|
|
|
setTimeout(executeQueue, 1000);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const code = res.data["code"] || "A0000";
|
|
|
|
|
|
const msg =
|
|
|
|
|
|
errorCodeType(code) || res.data["msg"] || errorCodeType("default");
|
|
|
|
|
|
|
|
|
|
|
|
if (code === "A0000") {
|
|
|
|
|
|
return Promise.resolve(res.data);
|
|
|
|
|
|
} else if (code === "A0025") {
|
|
|
|
|
|
isAuthenticated = false;
|
|
|
|
|
|
const originalRequest = res.config;
|
|
|
|
|
|
|
|
|
|
|
|
if (!isRefreshing) {
|
|
|
|
|
|
isRefreshing = true;
|
|
|
|
|
|
return store
|
|
|
|
|
|
.dispatch(
|
|
|
|
|
|
"loginAction",
|
|
|
|
|
|
JSON.parse(window.localStorage.getItem("adminInfo") || "{}")
|
|
|
|
|
|
)
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
isAuthenticated = true;
|
|
|
|
|
|
refreshQueue.forEach((callback: any) => callback());
|
|
|
|
|
|
refreshQueue = [];
|
|
|
|
|
|
return service(originalRequest);
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error("刷新失败:", err);
|
|
|
|
|
|
refreshQueue.forEach((callback: any) => callback());
|
|
|
|
|
|
refreshQueue = [];
|
|
|
|
|
|
return Promise.reject(err);
|
|
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
isRefreshing = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
|
refreshQueue.push(() => resolve(service(originalRequest)));
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return Promise.reject(res.data);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
(error) => {
|
|
|
|
|
|
if (error.isHandled) return Promise.reject(error);
|
|
|
|
|
|
|
|
|
|
|
|
if (error.config?.url === "/cn_authenticate") {
|
|
|
|
|
|
isAuthenticating = false;
|
|
|
|
|
|
isAuthenticated = false;
|
|
|
|
|
|
setTimeout(executeQueue, 1000);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log("err" + error);
|
|
|
|
|
|
let { message } = error;
|
|
|
|
|
|
if (message === "Network Error") {
|
|
|
|
|
|
message = "后端接口连接异常";
|
|
|
|
|
|
} else if (message.includes("timeout")) {
|
|
|
|
|
|
message = "系统接口请求超时";
|
|
|
|
|
|
} else if (message.includes("Request failed with status code")) {
|
|
|
|
|
|
message = `系统接口${message.substr(message.length - 3)}异常`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Promise.reject(error);
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
export default service;
|