mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-08-06 10:57:26 +08:00
235 lines
6.4 KiB
JavaScript
235 lines
6.4 KiB
JavaScript
import axios from "axios";
|
||
import { ElLoading } from "element-plus";
|
||
import { Message, Modal } from "@/utils/message";
|
||
import Storage from "./storage";
|
||
import { router } from "../router/index.js";
|
||
import store from "../vuex/store";
|
||
import { handleRefreshToken } from "@/api/index";
|
||
import { v4 as uuidv4 } from "uuid";
|
||
|
||
const qs = require("qs");
|
||
|
||
export const buyerUrl =
|
||
process.env.NODE_ENV === "development"
|
||
? BASE.API_DEV.buyer
|
||
: BASE.API_PROD.buyer;
|
||
|
||
let isRefreshToken = 0;
|
||
const refreshToken = getTokenDebounce();
|
||
|
||
/** 会员中心(/home/*)页面使用局部 loading,不启用全屏遮罩 */
|
||
function isMemberCenterRoute() {
|
||
try {
|
||
const path = router.currentRoute?.value?.path || "";
|
||
return path === "/home" || path.startsWith("/home/");
|
||
} catch {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
const service = axios.create({
|
||
timeout: 10000,
|
||
baseURL: buyerUrl,
|
||
paramsSerializer: (params) =>
|
||
qs.stringify(params, {
|
||
arrayFormat: "repeat",
|
||
}),
|
||
});
|
||
|
||
service.interceptors.request.use(
|
||
(config) => {
|
||
const { loading } = config;
|
||
const isPutPost = config.method === "put" || config.method === "post";
|
||
const isJson = config.headers["Content-Type"] === "application/json";
|
||
const isFile = config.headers["Content-Type"] === "multipart/form-data";
|
||
if (isPutPost && isJson) {
|
||
config.data = JSON.stringify(config.data);
|
||
}
|
||
if (isPutPost && !isFile && !isJson) {
|
||
config.data = qs.stringify(config.data, {
|
||
arrayFormat: "repeat",
|
||
});
|
||
}
|
||
|
||
const method = (config.method || "get").toLowerCase();
|
||
const isReadRequest = method === "get" || method === "head";
|
||
const shouldShowLoading =
|
||
loading === true ||
|
||
(!isReadRequest && loading !== false && !isMemberCenterRoute());
|
||
|
||
if (typeof window !== "undefined" && shouldShowLoading) {
|
||
config.loading = ElLoading.service({ fullscreen: true });
|
||
}
|
||
|
||
let uuid = Storage.getItem("uuid");
|
||
if (!uuid) {
|
||
uuid = uuidv4();
|
||
Storage.setItem("uuid", uuid);
|
||
}
|
||
config.headers["uuid"] = uuid;
|
||
|
||
const accessToken = Storage.getItem("accessToken");
|
||
if (accessToken && (config.needToken || config.optionalToken)) {
|
||
config.headers["accessToken"] = accessToken;
|
||
try {
|
||
const jwtData = JSON.parse(
|
||
decodeURIComponent(
|
||
escape(
|
||
window
|
||
.atob(accessToken.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"))
|
||
)
|
||
)
|
||
);
|
||
if (jwtData.exp < Math.round(new Date() / 1000)) {
|
||
refresh({ response: { config } });
|
||
}
|
||
} catch {
|
||
Storage.removeItem("accessToken");
|
||
Storage.removeItem("refreshToken");
|
||
}
|
||
}
|
||
|
||
return config;
|
||
},
|
||
(error) => Promise.reject(error)
|
||
);
|
||
|
||
function buildRejectError(error, errorData = {}) {
|
||
const message =
|
||
errorData.message ||
|
||
(error?.code === "ECONNABORTED" ? "连接超时,请稍候再试!" : "网络错误,请稍后再试!");
|
||
return Object.assign(new Error(message), { data: errorData });
|
||
}
|
||
|
||
async function refresh(error) {
|
||
const getTokenRes = await refreshToken();
|
||
if (getTokenRes === "success") {
|
||
if (error?.response?.config) {
|
||
error.response.config.headers.accessToken = Storage.getItem("accessToken");
|
||
return service(error.response.config);
|
||
}
|
||
router.go(0);
|
||
return new Promise(() => {});
|
||
}
|
||
Storage.removeItem("accessToken");
|
||
Storage.removeItem("refreshToken");
|
||
Storage.removeItem("userInfo");
|
||
Storage.setItem("cartNum", 0);
|
||
store.commit("SET_CARTNUM", 0);
|
||
const currentRoute = router.currentRoute.value;
|
||
Modal.confirm({
|
||
title: "请登录",
|
||
content: "请登录后执行此操作",
|
||
okText: "立即登录",
|
||
cancelText: "继续浏览",
|
||
onOk: () => {
|
||
router.push({
|
||
path: "/login",
|
||
query: {
|
||
rePath: currentRoute.path,
|
||
query: JSON.stringify(currentRoute.query),
|
||
},
|
||
});
|
||
},
|
||
onCancel: () => {
|
||
router.push("/");
|
||
Modal.remove();
|
||
},
|
||
});
|
||
return Promise.reject(new Error("登录已过期"));
|
||
}
|
||
|
||
service.interceptors.response.use(
|
||
async (response) => {
|
||
await closeLoading(response);
|
||
return response.data;
|
||
},
|
||
async (error) => {
|
||
if (typeof window === "undefined") return Promise.reject(error);
|
||
await closeLoading(error);
|
||
const errorResponse = error.response || {};
|
||
const errorData = errorResponse.data || {};
|
||
|
||
if (
|
||
errorResponse.status === 401 ||
|
||
errorResponse.status === 403 ||
|
||
error.response?.data?.code === 20004
|
||
) {
|
||
isRefreshToken++;
|
||
if (isRefreshToken === 1) {
|
||
isRefreshToken = 0;
|
||
return refresh(error);
|
||
}
|
||
return Promise.reject(buildRejectError(error, errorData));
|
||
}
|
||
if (errorResponse.status === 404) {
|
||
return Promise.reject(buildRejectError(error, { message: "请求的资源不存在" }));
|
||
}
|
||
if (error.message && !error.config?.skipMessage) {
|
||
const _message =
|
||
error.code === "ECONNABORTED"
|
||
? "连接超时,请稍候再试!"
|
||
: "网络错误,请稍后再试!";
|
||
Message.error(errorData.message || _message);
|
||
}
|
||
return Promise.reject(buildRejectError(error, errorData));
|
||
}
|
||
);
|
||
|
||
const closeLoading = (target) => {
|
||
if (!target.config || !target.config.loading) return true;
|
||
return new Promise((resolve) => {
|
||
setTimeout(() => {
|
||
target.config.loading.close();
|
||
resolve();
|
||
}, 200);
|
||
});
|
||
};
|
||
|
||
export const Method = {
|
||
GET: "get",
|
||
POST: "post",
|
||
PUT: "put",
|
||
DELETE: "delete",
|
||
};
|
||
|
||
export default function request(options) {
|
||
return service(options);
|
||
}
|
||
|
||
function getTokenDebounce() {
|
||
let lock = false;
|
||
let success = false;
|
||
return function () {
|
||
if (!lock) {
|
||
lock = true;
|
||
const oldRefreshToken = Storage.getItem("refreshToken");
|
||
handleRefreshToken(oldRefreshToken)
|
||
.then((res) => {
|
||
if (res.success) {
|
||
const { accessToken, refreshToken: newRefreshToken } = res.result;
|
||
Storage.setItem("accessToken", accessToken);
|
||
Storage.setItem("refreshToken", newRefreshToken);
|
||
success = true;
|
||
lock = false;
|
||
} else {
|
||
success = false;
|
||
lock = false;
|
||
}
|
||
})
|
||
.catch(() => {
|
||
success = false;
|
||
lock = false;
|
||
});
|
||
}
|
||
return new Promise((resolve) => {
|
||
const timer = setInterval(() => {
|
||
if (!lock) {
|
||
clearInterval(timer);
|
||
resolve(success ? "success" : "fail");
|
||
}
|
||
}, 500);
|
||
});
|
||
};
|
||
}
|