zy-vue-library/axios/index.js

409 lines
13 KiB
JavaScript
Raw Normal View History

2025-10-22 11:19:51 +08:00
import axios from "axios";
import { ElMessage } from "element-plus";
import dayjs from 'dayjs'
import useRequestLoading from "../hooks/useRequestLoading/index.js";
import { getBaseUrl } from "../utils/index.js";
import CryptoJS from "crypto-js";
import {aesDecrypt} from "../aesSecret/index.js";
/**
* Axios服务类
*/
class AxiosService {
constructor() {
/**
* Axios配置选项
*/
this.config = {
router: null,
store: null,
tokenRefreshUrl: '/sys/refreshToken',
loginPath: '/login',
tokenRefreshInterval: 5, // 分钟
baseURL: getBaseUrl(),
timeout: 1000 * 60 * 10,
requestParamsSign: {
use: false,
key: ''
},
responseParamsDecrypt: {
use: false,
}
};
this.loading = useRequestLoading();
this.isTipTokenFailure = false;
}
/**
* 配置axios插件
* @param {Object} [config] - 配置选项
* @param {Object} config.router - Vue Router实例
* @param {Object} config.store - token的piniaStore
* @param {string} [config.tokenRefreshUrl="/sys/refreshToken"] - token刷新接口URL
* @param {string} [config.loginPath="/login"] - 登录页面路由
* @param {number} [config.tokenRefreshInterval=5] - token刷新间隔分钟
* @param {string} [config.baseURL=getBaseUrl()] - API基础URL
* @param {number} [config.timeout=60000] - 请求超时时间毫秒
* @param {Object} [config.requestParamsSign] - 请求参数是否签名
* @param {boolean} [config.requestParamsSign.use=false] - 是否使用签名
* @param {string} [config.requestParamsSign.key] - 签名密钥
* @param {Object} [config.responseParamsDecrypt] - 响应参数是否需要解密
* @param {boolean} [config.responseParamsDecrypt.use=false] - 是否需要解密
*/
configure(config = {}) {
if (!config.router) throw new Error('router 参数必传');
if (!config.store) throw new Error('store 参数必传');
this.config = { ...this.config, ...config };
// 设置默认配置
axios.defaults.baseURL = this.config.baseURL;
axios.defaults.timeout = this.config.timeout;
// 清除现有拦截器
axios.interceptors.request.clear();
axios.interceptors.response.clear();
// 重新设置拦截器
this.setupInterceptors();
}
/**
* token刷新逻辑
*/
async refreshToken() {
const currentRoute = this.config.router.currentRoute?.value;
if (currentRoute?.meta?.isLogin) {
const store = this.config.store;
if (store.getTokenTime) {
const diffMinutes = dayjs().diff(dayjs(store.getTokenTime), "minute");
if (diffMinutes >= this.config.tokenRefreshInterval) {
await store.setTokenTime(dayjs().format("YYYY-MM-DD HH:mm:ss"));
await this.postRequest(this.config.tokenRefreshUrl);
}
}
}
}
/**
* 请求参数签名
*/
requestParamsSign(params) {
if (!this.config.requestParamsSign.key) throw new Error('请传入签名密钥');
const Timestamp = new Date().getTime();
const cloneParams = { ...params };
const keys = Object.keys(cloneParams).sort();
const sortData = {};
for (let i = 0; i < keys.length; i++) {
if (cloneParams[keys[i]] !== null && cloneParams[keys[i]] !== undefined) {
sortData[keys[i]] = cloneParams[keys[i]];
}
}
const Sign = CryptoJS.MD5(
Timestamp +
JSON.stringify(sortData) +
this.config.requestParamsSign.key
).toString();
return {
Sign,
Timestamp,
};
}
/**
* 设置拦截器
*/
setupInterceptors() {
// 请求拦截器
axios.interceptors.request.use(
async (request) => {
request.headers.Token = this.config.store.getToken;
let params = request.data || request.params || {};
// 根据配置决定是否启用参数签名
if (this.config.requestParamsSign.use) {
const { Timestamp, Sign } = this.requestParamsSign(params);
request.headers.Timestamp = Timestamp;
request.headers.Sign = Sign;
}
this.loading.value = true;
return request;
},
(error) => Promise.reject(error)
);
// 响应拦截器
axios.interceptors.response.use(
(response) => {
if (this.config.responseParamsDecrypt.use) response.data = { ...response.data, ...aesDecrypt(response.data.data)}
this.loading.value = false;
if (response.data.code === 401) {
if (!this.isTipTokenFailure) {
this.isTipTokenFailure = true;
ElMessage.error("登录失效,请重新登录");
this.config.router.push(this.config.loginPath);
this.isTipTokenFailure = false;
}
return Promise.reject(response.data.msg);
} else {
this.refreshToken().then();
}
return response;
},
(error) => {
if (error && error.response) {
if (import.meta.env.DEV) ElMessage.error(`连接错误${error.response.status}`);
} else ElMessage.error(error.message);
return Promise.reject(error.message);
}
);
}
/**
* 发送POST请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @returns {Promise} - 返回Promise对象包含请求结果
*/
postRequest(url, params = {}) {
return new Promise((resolve, reject) => {
axios
.post(url, params)
.then((res) => {
if (res.data.result === "success") {
resolve(res.data);
} else {
ElMessage.error(res.data.msg || "系统开小差了");
reject(res.data);
}
})
.catch((err) => {
reject(err);
});
});
}
/**
* 获取GET请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @param {string} splicingURL - URL拼接字符串
* @returns {Promise} - 返回Promise对象包含请求结果
*/
getRequest(url, params = {}, splicingURL = "") {
return new Promise((resolve, reject) => {
axios
.get(url + (splicingURL ? "/" + splicingURL : ""), {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
params,
})
.then((res) => {
if (res.data.result === "success") {
resolve(res.data);
} else {
ElMessage.error(res.data.msg || "系统开小差了");
reject(res.data);
}
})
.catch((err) => {
reject(err);
});
});
}
/**
* 获取PUT请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @returns {Promise} - 返回Promise对象包含请求结果
*/
putRequest(url, params = {}) {
return new Promise((resolve, reject) => {
axios
.put(url, params)
.then((res) => {
if (res.data.result === "success") {
resolve(res.data);
} else {
ElMessage.error(res.data.msg || "系统开小差了");
reject(res.data);
}
})
.catch((err) => {
reject(err);
});
});
}
/**
* 获取DELETE请求
* @param {string} url - 请求URL
* @param {Object} params - 删除参数
* @param {string} splicingURL - URL拼接字符串
* @returns {Promise} - 返回Promise对象包含请求结果
*/
deleteRequest(url, params = {}, splicingURL = "") {
return new Promise((resolve, reject) => {
axios
.delete(url + (splicingURL ? "/" + splicingURL : ""), { data: params })
.then((res) => {
if (res.data.result === "success") {
resolve(res.data);
} else {
ElMessage.error(res.data.msg || "系统开小差了");
reject(res.data);
}
})
.catch((err) => {
reject(err);
});
});
}
/**
* 获取PATCH请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @param {string} splicingURL - URL拼接字符串
* @returns {Promise} - 返回Promise对象包含请求结果
*/
patchRequest(url, params = {}, splicingURL = "") {
return new Promise((resolve, reject) => {
axios
.patch(url + (splicingURL ? "/" + splicingURL : ""), params)
.then((res) => {
if (res.data.result === "success") {
resolve(res.data);
} else {
ElMessage.error(res.data.msg || "系统开小差了")
reject(res.data);
}
})
.catch((err) => {
reject(err);
});
});
}
/**
* 上传文件请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @returns {Promise} - 返回Promise对象包含请求结果
*/
uploadRequest(url, params = {}) {
return new Promise((resolve, reject) => {
axios
.post(url, params, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => {
if (res.data.result === "success") {
resolve(res.data);
} else {
ElMessage.error(res.data.msg || "系统开小差了");
reject(res.data);
}
})
.catch((err) => {
reject(err);
});
});
}
}
/**
* 配置axios插件
* @param {Object} [config] - 配置选项
* @param {Object} config.router - Vue Router实例
* @param {Object} config.store - token的piniaStore
* @param {string} [config.tokenRefreshUrl="/sys/refreshToken"] - token刷新接口URL
* @param {string} [config.loginPath="/login"] - 登录页面路由
* @param {number} [config.tokenRefreshInterval=5] - token刷新间隔分钟
* @param {string} [config.baseURL=getBaseUrl()] - API基础URL
* @param {number} [config.timeout=60000] - 请求超时时间毫秒
* @param {Object} [config.requestParamsSign] - 请求参数是否签名
* @param {boolean} [config.requestParamsSign.use=false] - 是否使用签名
* @param {string} [config.requestParamsSign.key] - 签名密钥
* @param {Object} [config.responseParamsDecrypt] - 响应参数是否需要解密
* @param {boolean} [config.responseParamsDecrypt.use=false] - 是否需要解密
*/
export function configureAxios(config = {}) {
if(!window.axiosService) window.axiosService = new AxiosService();
return axiosService.configure(config);
}
/**
* 发送POST请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @returns {Promise} - 返回Promise对象包含请求结果
*/
export function postRequest(url, params = {}) {
if (!window.axiosService) throw new Error('未配置Axios请先调用 configureAxios');
return window.axiosService.postRequest(url, params);
}
/**
* 获取GET请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @param {string} splicingURL - URL拼接字符串
* @returns {Promise} - 返回Promise对象包含请求结果
*/
export function getRequest(url, params = {}, splicingURL = "") {
if (!window.axiosService) throw new Error('未配置Axios请先调用 configureAxios');
return window.axiosService.getRequest(url, params, splicingURL);
}
/**
* 获取PUT请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @returns {Promise} - 返回Promise对象包含请求结果
*/
export function putRequest(url, params = {}) {
if (!window.axiosService) throw new Error('未配置Axios请先调用 configureAxios');
return window.axiosService.putRequest(url, params);
}
/**
* 获取DELETE请求
* @param {string} url - 请求URL
* @param {Object} params - 删除参数
* @param {string} splicingURL - URL拼接字符串
* @returns {Promise} - 返回Promise对象包含请求结果
*/
export function deleteRequest(url, params = {}, splicingURL = "") {
if (!window.axiosService) throw new Error('未配置Axios请先调用 configureAxios');
return window.axiosService.deleteRequest(url, params, splicingURL);
}
/**
* 获取PATCH请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @param {string} splicingURL - URL拼接字符串
* @returns {Promise} - 返回Promise对象包含请求结果
*/
export function patchRequest(url, params = {}, splicingURL = "") {
if (!window.axiosService) throw new Error('未配置Axios请先调用 configureAxios');
return window.axiosService.patchRequest(url, params, splicingURL);
}
/**
* 上传文件请求
* @param {string} url - 请求URL
* @param {Object} params - 请求参数
* @returns {Promise} - 返回Promise对象包含请求结果
*/
export function uploadRequest(url, params = {}) {
if (!window.axiosService) throw new Error('未配置Axios请先调用 configureAxios');
return window.axiosService.uploadRequest(url, params);
}