|
|
@@ -0,0 +1,185 @@
|
|
|
+import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
|
|
+import { ElMessage as Message, ElMessageBox as MessageBox, ElLoading as Loading } from 'element-plus';
|
|
|
+
|
|
|
+// 加载动画的并发管理
|
|
|
+const activeRequests = new Set<string>();
|
|
|
+let loadingObj = null;
|
|
|
+/**
|
|
|
+ * 关闭加载动画
|
|
|
+ * 当所有请求完成时,关闭加载动画
|
|
|
+ */
|
|
|
+function loadingClose(requestId: string) {
|
|
|
+ activeRequests.delete(requestId);
|
|
|
+ if (activeRequests.size === 0 && loadingObj) {
|
|
|
+ loadingObj.close();
|
|
|
+ loadingObj = null
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 创建一个axios实例,用于发送HTTP请求
|
|
|
+ * 配置了请求拦截器和响应拦截器,支持加载动画和错误提示
|
|
|
+ */
|
|
|
+const service = axios.create({
|
|
|
+ timeout: 5000, // 设置请求超时时间
|
|
|
+});
|
|
|
+
|
|
|
+// 请求拦截器
|
|
|
+service.interceptors.request.use(
|
|
|
+ (config: AxiosRequestConfig) => {
|
|
|
+ // 在发送请求之前做些什么,例如添加 token
|
|
|
+ const token = localStorage.getItem('token');
|
|
|
+ if (token) {
|
|
|
+ config.headers['Authorization'] = `Bearer ${token}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果配置中启用了加载动画,则显示加载动画
|
|
|
+ if (config.loading) {
|
|
|
+ const requestId = `${Date.now()}-${Math.random()}`;
|
|
|
+ activeRequests.add(requestId);
|
|
|
+ if (activeRequests.size === 1) {
|
|
|
+ loadingObj = Loading.service({
|
|
|
+ lock: true,
|
|
|
+ text: '请稍候',
|
|
|
+ background: 'rgba(0, 0, 0, 0)',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ config.requestId = requestId; // 将 requestId 挂载到 config 上
|
|
|
+ }
|
|
|
+
|
|
|
+ return config;
|
|
|
+ },
|
|
|
+ (error: AxiosError) => {
|
|
|
+ // 对请求错误做些什么
|
|
|
+ return Promise.reject(error);
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
+// 响应拦截器
|
|
|
+service.interceptors.response.use(
|
|
|
+ (response: AxiosResponse) => {
|
|
|
+ // 对响应数据做点什么
|
|
|
+ const res = response.data;
|
|
|
+
|
|
|
+ // 如果配置中启用了加载动画,则关闭加载动画
|
|
|
+ if (response.config?.loading && response.config.requestId) {
|
|
|
+ loadingClose(response.config.requestId as string);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果自定义状态码不为0,则判断为错误
|
|
|
+ if (res.code !== 0) {
|
|
|
+ switch (res.code) {
|
|
|
+ default:
|
|
|
+ if (response.config.showErrorMessage) {
|
|
|
+ if (res.message?.length > 30 || res.code === 400011) {
|
|
|
+ let message = '<div style="white-space: pre-line; max-height: 500px; overflow: auto;">' + res.message + '</div>' || 'Error';
|
|
|
+ MessageBox.alert(message, '提示', {
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ Message({
|
|
|
+ message: res.message || 'Error',
|
|
|
+ type: 'error',
|
|
|
+ duration: 5 * 1000,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Promise.reject(res || 'Error');
|
|
|
+ } else {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ (error: AxiosError) => {
|
|
|
+ // 对响应错误做点什么
|
|
|
+ let errMessage = '';
|
|
|
+
|
|
|
+ // 如果配置中启用了加载动画,则关闭加载动画
|
|
|
+ if (error.config?.loading && error.config.requestId) {
|
|
|
+ loadingClose(error.config.requestId as string);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (error.response) {
|
|
|
+ switch (error.response.status) {
|
|
|
+ case 400: errMessage = '请求错误(400)'; break;
|
|
|
+ case 401: errMessage = '登录失效'; break;
|
|
|
+ case 403: errMessage = '拒绝访问(403)'; break;
|
|
|
+ case 404: errMessage = '请求出错(404)'; break;
|
|
|
+ case 408: errMessage = '请求超时(408)'; break;
|
|
|
+ case 500: errMessage = '服务器错误(500)'; break;
|
|
|
+ case 501: errMessage = '服务未实现(501)'; break;
|
|
|
+ case 502: errMessage = '网络错误(502)'; break;
|
|
|
+ case 503: errMessage = '服务不可用(503)'; break;
|
|
|
+ case 504: errMessage = '网络超时(504)'; break;
|
|
|
+ case 505: errMessage = 'HTTP版本不受支持(505)'; break;
|
|
|
+ default: errMessage = '连接出错!';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ errMessage = '未知错误';
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果配置中启用了错误提示,则显示错误信息
|
|
|
+ if (error.config?.showErrorMessage) {
|
|
|
+ if (error.message && error.message.includes('timeout')) {
|
|
|
+ Message({
|
|
|
+ message: '请求超时!',
|
|
|
+ type: 'error',
|
|
|
+ duration: 5 * 1000,
|
|
|
+ });
|
|
|
+ } else if (errMessage) {
|
|
|
+ Message({
|
|
|
+ message: errMessage,
|
|
|
+ type: 'error',
|
|
|
+ duration: 5 * 1000,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对响应错误做处理
|
|
|
+ return Promise.reject(error);
|
|
|
+ }
|
|
|
+);
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 发起 GET 请求
|
|
|
+ *
|
|
|
+ * @template T 泛型,表示返回数据的类型
|
|
|
+ * @param {string} url 请求的 URL
|
|
|
+ * @param {any} [params] 请求参数
|
|
|
+ * @returns {Promise<T>} 返回一个 Promise,解析为响应数据
|
|
|
+ */
|
|
|
+export function GET<T>(url: string, params?: any): Promise<T> {
|
|
|
+ return service.get(url, {
|
|
|
+ params: params,
|
|
|
+ loading: params?.loading ?? false,
|
|
|
+ showErrorMessage: params?.showErrorMessage ?? true,
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 发起 POST 请求
|
|
|
+ *
|
|
|
+ * @template T 泛型,表示返回数据的类型
|
|
|
+ * @param {string} url 请求的 URL
|
|
|
+ * @param {any} [data] 请求体
|
|
|
+ * @param {any} [config] 请求配置
|
|
|
+ * @returns {Promise<T>} 返回一个 Promise,解析为响应数据
|
|
|
+ */
|
|
|
+export function POST<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
|
|
+ return service.post(url, data, {
|
|
|
+ ...config,
|
|
|
+ loading: config?.loading ?? true,
|
|
|
+ showErrorMessage: config?.showErrorMessage ?? true,
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 导出配置好的 axios 实例
|
|
|
+export default service;
|