陈龙 2 роки тому
батько
коміт
180273f01d

+ 1 - 1
README.md

@@ -367,7 +367,7 @@ export default router
 
 通过引入axios库的ts版本即可配置
 ```js
-import axiosInstance, { AxiosResponseProps } from '@/uitls/request'
+import axiosInstance from '@/utils/request'
 
 export const getList = (params: any) => {
 	return axiosInstance.get("/common/code/logisticsInfo/getOrderByPhone", { params: params || {} });

+ 1 - 0
package.json

@@ -11,6 +11,7 @@
   },
   "dependencies": {
     "axios": "^0.26.1",
+    "lodash-es": "^4.17.21",
     "pinia": "^2.0.20",
     "vant": "^3.4.6",
     "vue": "^3.2.25",

+ 6 - 0
pnpm-lock.yaml

@@ -6,6 +6,7 @@ specifiers:
   '@vitejs/plugin-vue': ^2.2.0
   axios: ^0.26.1
   lib-flexible: ^0.3.2
+  lodash-es: ^4.17.21
   pinia: ^2.0.20
   postcss-pxtorem: ^5.1.1
   sass: ^1.49.9
@@ -20,6 +21,7 @@ specifiers:
 
 dependencies:
   axios: 0.26.1
+  lodash-es: 4.17.21
   pinia: 2.0.23_l7r24p6nevbtlimqmqcwa3ouhu
   vant: 3.6.4_vue@3.2.41
   vue: 3.2.41
@@ -850,6 +852,10 @@ packages:
     resolution: {integrity: sha512-9yowMWA70tKhKdCJDaltY0mNQG4OWo7pWKScnTp9aiSxS7s20ZYlwBRE3335nweOf5qKXVC7sDxJwMPM8/MFZg==}
     dev: true
 
+  /lodash-es/4.17.21:
+    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+    dev: false
+
   /lower-case/2.0.2:
     resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
     dependencies:

+ 9 - 2
src/api/home.ts

@@ -1,6 +1,13 @@
 import { apiUrl } from '@/const/api';
-import axiosInstance, { AxiosResponseProps } from '@/uitls/request';
+import http from '@/utils/request';
 
 export const getTest = (params?: any) => {
-	return axiosInstance.get(apiUrl.TEST_PROXY, { params: params || {} });
+	return http.request({
+		url: '/api/newsqa/v1/query/inner/publish/modules/list',
+		method: 'get',
+		params
+	},
+    {
+      isTransformResponse: true,
+    });
 };

+ 5 - 2
src/api/orders.ts

@@ -1,5 +1,8 @@
-import axiosInstance, { AxiosResponseProps } from '@/uitls/request'
+import http from '@/utils/request'
 
 export const getList = (params: any) => {
-	return axiosInstance.get("/common/code/logisticsInfo/getLogisticsByOrderId", { params: params || {} });
+	return http.request({
+		url: '/common/code/logisticsInfo/getLogisticsByOrderId',
+		method: 'get',
+	});
 }

+ 60 - 0
src/api/user.ts

@@ -0,0 +1,60 @@
+import http from '@/utils/request';
+
+export interface BasicResponseModel<T = any> {
+  code: number;
+  message: string;
+  result: T;
+}
+
+export interface BasicPageParams {
+  pageNumber: number;
+  pageSize: number;
+  total: number;
+}
+
+/**
+ * @description: 获取用户信息
+ */
+export function getUserInfo() {
+  return http.request({
+    url: '/admin_info',
+    method: 'get',
+  });
+}
+
+/**
+ * @description: 用户登录
+ */
+export function login(params) {
+  return http.request<BasicResponseModel>(
+    {
+      url: '/login',
+      method: 'POST',
+      params,
+    }
+  );
+}
+
+/**
+ * @description: 用户修改密码
+ */
+export function changePassword(params, uid) {
+  return http.request(
+    {
+      url: `/user/u${uid}/changepw`,
+      method: 'POST',
+      params,
+    }
+  );
+}
+
+/**
+ * @description: 用户登出
+ */
+export function logout(params) {
+  return http.request({
+    url: '/login/logout',
+    method: 'POST',
+    params,
+  });
+}

+ 3 - 2
src/components/interactions/RequestLoading.vue

@@ -5,15 +5,16 @@ export default {
 </script>
 
 <script setup lang="ts">
-import { vuexStore } from "@/store";
+import { useLoadingStore } from "@/store/loading";
 import { computed, defineComponent, reactive, ref, toRefs, watch } from "vue";
 
 let timer = null;
+const loadingStore = useLoadingStore()
 
 const useLoading = () => {
   const state = reactive({
     loadedText: "加载中...",
-    isLoading: computed(() => vuexStore.state.isLoading),
+    isLoading: computed(() => loadingStore.getLoading),
   });
   return toRefs(state);
 };

+ 35 - 0
src/enums/httpEnum.ts

@@ -0,0 +1,35 @@
+/**
+ * @description: 请求结果集
+ */
+ export enum ResultEnum {
+    SUCCESS = 200,
+    ERROR = -1,
+    TIMEOUT = 10042,
+    TYPE = 'success',
+  }
+  
+  /**
+   * @description: 请求方法
+   */
+  export enum RequestEnum {
+    GET = 'GET',
+    POST = 'POST',
+    PATCH = 'PATCH',
+    PUT = 'PUT',
+    DELETE = 'DELETE',
+  }
+  
+  /**
+   * @description:  常用的contentTyp类型
+   */
+  export enum ContentTypeEnum {
+    // json
+    JSON = 'application/json;charset=UTF-8',
+    // json
+    TEXT = 'text/plain;charset=UTF-8',
+    // form-data 一般配合qs
+    FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
+    // form-data  上传
+    FORM_DATA = 'multipart/form-data;charset=UTF-8',
+  }
+  

+ 7 - 2
src/main.ts

@@ -1,7 +1,7 @@
 import { createApp } from 'vue';
 import App from './App.vue';
 import router from './router';
-import { vuexStore, piniaStore } from './store';
+import { setupStore } from '@/store';
 
 // 移动端适配
 import 'lib-flexible/flexible.js';
@@ -15,4 +15,9 @@ import { vantPlugins } from './plugins/vant.js';
 //全局公共组件
 import components from './plugins/components.js';
 
-createApp(App).use(vuexStore).use(piniaStore).use(router).use(vantPlugins).use(components).mount('#app');
+const app = createApp(App)
+
+// 挂载状态管理
+setupStore(app);
+
+app.use(router).use(vantPlugins).use(components).mount('#app');

+ 61 - 0
src/plugins/VisitAmount.vue

@@ -0,0 +1,61 @@
+<template>
+  <div ref="chartRef" :style="{ height, width }"></div>
+</template>
+<script lang="ts">
+  import { defineComponent, onMounted, ref, Ref } from 'vue';
+  import { useECharts } from '@/hooks/web/useECharts';
+  import { basicProps } from './props';
+
+  export default defineComponent({
+    props: basicProps,
+    setup() {
+      const chartRef = ref<HTMLDivElement | null>(null);
+      const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
+
+      onMounted(() => {
+        setOptions({
+          tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+              lineStyle: {
+                width: 1,
+                color: '#019680',
+              },
+            },
+          },
+          grid: { left: '1%', right: '1%', top: '2  %', bottom: 0, containLabel: true },
+          xAxis: {
+            type: 'category',
+            data: [
+              '1月',
+              '2月',
+              '3月',
+              '4月',
+              '5月',
+              '6月',
+              '7月',
+              '8月',
+              '9月',
+              '10月',
+              '11月',
+              '12月',
+            ],
+          },
+          yAxis: {
+            type: 'value',
+            max: 8000,
+            splitNumber: 4,
+          },
+          series: [
+            {
+              data: [3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000, 3200, 4800],
+              type: 'bar',
+              barMaxWidth: 80,
+            },
+          ],
+        });
+      });
+      return { chartRef };
+    },
+  });
+</script>

+ 7 - 26
src/store/index.ts

@@ -1,29 +1,10 @@
-import { createStore } from "vuex";
-import { createPinia } from "pinia";
+import type { App } from 'vue';
+import { createPinia } from 'pinia';
 
-export const vuexStore = createStore({
-    state: {
-        isLoading: false,
-        userName: ""
-    },
-    getters: {
+const store = createPinia();
 
-    },
-    mutations: {
-        changeIsLoading(state, val) {
-            state.isLoading = val;
-        },
+export function setupStore(app: App<Element>) {
+  app.use(store);
+}
 
-        getUserNmae(state, data) {
-            state.userName = data;
-        }
-
-    },
-    actions: {
-
-    },
-    modules: {},
-});
-
-
-export const piniaStore = createPinia();
+export { store };

+ 20 - 0
src/store/loading.ts

@@ -0,0 +1,20 @@
+import { defineStore } from "pinia"
+
+export const useLoadingStore = defineStore({
+    id: 'loading',
+    state: () => {
+        return {
+            loading: false
+        }
+    },
+    getters: {
+        getLoading(): boolean {
+            return this.loading;
+        },
+    },
+    actions: {
+        setLoading(data) {
+            this.loading = data
+        }
+    }
+})

+ 29 - 0
src/store/test.ts

@@ -0,0 +1,29 @@
+import { createStore } from "vuex";
+import { createPinia } from "pinia";
+
+export const vuexStore = createStore({
+    state: {
+        isLoading: false,
+        userName: ""
+    },
+    getters: {
+
+    },
+    mutations: {
+        changeIsLoading(state, val) {
+            state.isLoading = val;
+        },
+
+        getUserNmae(state, data) {
+            state.userName = data;
+        }
+
+    },
+    actions: {
+
+    },
+    modules: {},
+});
+
+
+export const piniaStore = createPinia();

+ 100 - 0
src/store/user.ts

@@ -0,0 +1,100 @@
+import { defineStore } from 'pinia';
+import { store } from '@/store';
+import { ResultEnum } from '@/enums/httpEnum';
+
+import { getUserInfo, login } from '@/api/user';
+import { storage } from '@/utils/Storage';
+
+const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用户token
+const CURRENT_USER = 'CURRENT-USER'; // 当前用户信息
+
+export interface IUserState {
+  token: string;
+  username: string;
+  welcome: string;
+  avatar: string;
+  info: any;
+}
+
+export const useUserStore = defineStore({
+  id: 'app-user',
+  state: (): IUserState => ({
+    token: storage.get(ACCESS_TOKEN, ''),
+    username: '',
+    welcome: '',
+    avatar: '',
+    info: storage.get(CURRENT_USER, {}),
+  }),
+  getters: {
+    getToken(): string {
+      return this.token;
+    },
+    getAvatar(): string {
+      return this.avatar;
+    },
+    getNickname(): string {
+      return this.username;
+    },
+    getUserInfo(): object {
+      return this.info;
+    },
+  },
+  actions: {
+    setToken(token: string) {
+      this.token = token;
+    },
+    setAvatar(avatar: string) {
+      this.avatar = avatar;
+    },
+    setUserInfo(info) {
+      this.info = info;
+    },
+    // 登录
+    async login(userInfo) {
+      try {
+        const response = await login(userInfo);
+        const { result, code } = response;
+        if (code === ResultEnum.SUCCESS) {
+          const ex = 7 * 24 * 60 * 60 * 1000;
+          storage.set(ACCESS_TOKEN, result.token, ex);
+          storage.set(CURRENT_USER, result, ex);
+          this.setToken(result.token);
+          this.setUserInfo(result);
+        }
+        return Promise.resolve(response);
+      } catch (e) {
+        return Promise.reject(e);
+      }
+    },
+
+    // 获取用户信息
+    GetInfo() {
+      const that = this;
+      return new Promise((resolve, reject) => {
+        getUserInfo()
+          .then((res) => {
+            const result = res;
+            that.setUserInfo(result);
+            that.setAvatar(result.avatar);
+            resolve(res);
+          })
+          .catch((error) => {
+            reject(error);
+          });
+      });
+    },
+
+    // 登出
+    async logout() {
+      this.setUserInfo('');
+      storage.remove(ACCESS_TOKEN);
+      storage.remove(CURRENT_USER);
+      return Promise.resolve('');
+    },
+  },
+});
+
+// Need to be used outside the setup
+export function useUserStoreWidthOut() {
+  return useUserStore(store);
+}

+ 0 - 85
src/uitls/request.ts

@@ -1,85 +0,0 @@
-/** 
- *  @author TalkTao
- * @description  接口封装
-*/
-import { vuexStore } from "@/store/index";
-import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, Method } from "axios";
-export interface AxiosResponseProps {
-    code?: number;
-    status?: number;
-    data?: any;
-    datas?: any;
-    msg?: string | null;
-}
-class HttpRequest {
-    private readonly baseURL: string;
-    private readonly withCredentials: boolean;
-    private readonly timeout: number;
-    constructor() {
-        //获取当前环境的api地址
-        this.baseURL = import.meta.env.VITE_BASE_URL as string;
-        this.withCredentials = true;
-        this.timeout = 1000 * 60;
-    }
-    //初始化get请求
-    getInitConfig(): AxiosRequestConfig {
-        return {
-            baseURL: this.baseURL,
-            withCredentials: this.withCredentials,
-            timeout: this.timeout,
-        };
-    }
-    interceptors(instance: AxiosInstance) {
-
-        // 定义存放请求接口数组
-        let requestList = [];
-        const setLoadingToFalse = response => {
-            requestList
-                .filter(item => item.url == response.config.url && item.method == response.config.method)
-                .forEach(item => (item.isLoading = false));
-
-            //所有请求都加载完才让加载提示消失
-            if (requestList.every(item => !item.isLoading)) vuexStore.commit("changeIsLoading", false);
-        };
-
-        instance.interceptors.request.use(
-            (config: any) => {
-                // 不用判断请求loading的路由
-                let ignoreLoadingUrls = ["/login"];
-                console.log(config)
-                if (!ignoreLoadingUrls.includes(config.url)) {
-
-                    if (requestList.length < 10) {
-                        requestList.unshift({ ...config, isLoading: true });
-                    } else {
-                        requestList = [...requestList.slice(0, 9), { ...config, isLoading: true }];
-                    }
-                    vuexStore.commit("changeIsLoading", true);
-                }
-                console.log('==relist==')
-                console.log(requestList)
-                return config;
-            },
-            error => Promise.reject(error + '请求错误')
-        );
-
-        instance.interceptors.response.use(
-            response => {
-                setLoadingToFalse(response);
-                return response.data;
-            },
-            error => {
-                if (error.response.status == 301) { }
-                setLoadingToFalse(error);
-                return Promise.reject(error.response?.data);
-            }
-        );
-    }
-    request(): AxiosInstance {
-        const instance = axios.create(this.getInitConfig());
-        this.interceptors(instance);
-        return instance;
-    }
-}
-const http = new HttpRequest();
-export default http.request();

+ 127 - 0
src/utils/Storage.ts

@@ -0,0 +1,127 @@
+// 默认缓存期限为7天
+const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
+
+/**
+ * 创建本地缓存对象
+ * @param {string=} prefixKey -
+ * @param {Object} [storage=localStorage] - sessionStorage | localStorage
+ */
+export const createStorage = ({ prefixKey = '', storage = localStorage } = {}) => {
+  /**
+   * 本地缓存类
+   * @class Storage
+   */
+  const Storage = class {
+    private storage = storage;
+    private prefixKey?: string = prefixKey;
+
+    private getKey(key: string) {
+      return `${this.prefixKey}${key}`.toUpperCase();
+    }
+
+    /**
+     * @description 设置缓存
+     * @param {string} key 缓存键
+     * @param {*} value 缓存值
+     * @param expire
+     */
+    set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
+      const stringData = JSON.stringify({
+        value,
+        expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
+      });
+      this.storage.setItem(this.getKey(key), stringData);
+    }
+
+    /**
+     * 读取缓存
+     * @param {string} key 缓存键
+     * @param {*=} def 默认值
+     */
+    get(key: string, def: any = null) {
+      const item = this.storage.getItem(this.getKey(key));
+      if (item) {
+        try {
+          const data = JSON.parse(item);
+          const { value, expire } = data;
+          // 在有效期内直接返回
+          if (expire === null || expire >= Date.now()) {
+            return value;
+          }
+          this.remove(key);
+        } catch (e) {
+          return def;
+        }
+      }
+      return def;
+    }
+
+    /**
+     * 从缓存删除某项
+     * @param {string} key
+     */
+    remove(key: string) {
+      this.storage.removeItem(this.getKey(key));
+    }
+
+    /**
+     * 清空所有缓存
+     * @memberOf Cache
+     */
+    clear(): void {
+      this.storage.clear();
+    }
+
+    /**
+     * 设置cookie
+     * @param {string} name cookie 名称
+     * @param {*} value cookie 值
+     * @param {number=} expire 过期时间
+     * 如果过期时间为设置,默认关闭浏览器自动删除
+     * @example
+     */
+    setCookie(name: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
+      document.cookie = `${this.getKey(name)}=${value}; Max-Age=${expire}`;
+    }
+
+    /**
+     * 根据名字获取cookie值
+     * @param name
+     */
+    getCookie(name: string): string {
+      const cookieArr = document.cookie.split('; ');
+      for (let i = 0, length = cookieArr.length; i < length; i++) {
+        const kv = cookieArr[i].split('=');
+        if (kv[0] === this.getKey(name)) {
+          return kv[1];
+        }
+      }
+      return '';
+    }
+
+    /**
+     * 根据名字删除指定的cookie
+     * @param {string} key
+     */
+    removeCookie(key: string) {
+      this.setCookie(key, 1, -1);
+    }
+
+    /**
+     * 清空cookie,使所有cookie失效
+     */
+    clearCookie(): void {
+      const keys = document.cookie.match(/[^ =;]+(?==)/g);
+      if (keys) {
+        for (let i = keys.length; i--; ) {
+          document.cookie = keys[i] + '=0;expire=' + new Date(0).toUTCString();
+        }
+      }
+    }
+  };
+  return new Storage();
+};
+
+export const storage = createStorage();
+
+export default Storage;

+ 118 - 0
src/utils/is.ts

@@ -0,0 +1,118 @@
+const toString = Object.prototype.toString;
+
+/**
+ * @description: 判断值是否未某个类型
+ */
+export function is(val: unknown, type: string) {
+  return toString.call(val) === `[object ${type}]`;
+}
+
+/**
+ * @description:  是否为函数
+ */
+export function isFunction<T = Function>(val: unknown): val is T {
+  return is(val, 'Function') || is(val, 'AsyncFunction');
+}
+
+/**
+ * @description: 是否已定义
+ */
+export const isDef = <T = unknown>(val?: T): val is T => {
+  return typeof val !== 'undefined';
+};
+
+export const isUnDef = <T = unknown>(val?: T): val is T => {
+  return !isDef(val);
+};
+/**
+ * @description: 是否为对象
+ */
+export const isObject = (val: any): val is Record<any, any> => {
+  return val !== null && is(val, 'Object');
+};
+
+/**
+ * @description:  是否为时间
+ */
+export function isDate(val: unknown): val is Date {
+  return is(val, 'Date');
+}
+
+/**
+ * @description:  是否为数值
+ */
+export function isNumber(val: unknown): val is number {
+  return is(val, 'Number');
+}
+
+/**
+ * @description:  是否为AsyncFunction
+ */
+export function isAsyncFunction<T = any>(val: unknown): val is () => Promise<T> {
+  return is(val, 'AsyncFunction');
+}
+
+/**
+ * @description:  是否为promise
+ */
+export function isPromise<T = any>(val: unknown): val is Promise<T> {
+  return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch);
+}
+
+/**
+ * @description:  是否为字符串
+ */
+export function isString(val: unknown): val is string {
+  return is(val, 'String');
+}
+
+/**
+ * @description:  是否为boolean类型
+ */
+export function isBoolean(val: unknown): val is boolean {
+  return is(val, 'Boolean');
+}
+
+/**
+ * @description:  是否为数组
+ */
+export function isArray(val: any): val is Array<any> {
+  return val && Array.isArray(val);
+}
+
+/**
+ * @description: 是否客户端
+ */
+export const isClient = () => {
+  return typeof window !== 'undefined';
+};
+
+/**
+ * @description: 是否为浏览器
+ */
+export const isWindow = (val: any): val is Window => {
+  return typeof window !== 'undefined' && is(val, 'Window');
+};
+
+export const isElement = (val: unknown): val is Element => {
+  return isObject(val) && !!val.tagName;
+};
+
+export const isServer = typeof window === 'undefined';
+
+// 是否为图片节点
+export function isImageDom(o: Element) {
+  return o && ['IMAGE', 'IMG'].includes(o.tagName);
+}
+
+export function isNull(val: unknown): val is null {
+  return val === null;
+}
+
+export function isNullAndUnDef(val: unknown): val is null | undefined {
+  return isUnDef(val) && isNull(val);
+}
+
+export function isNullOrUnDef(val: unknown): val is null | undefined {
+  return isUnDef(val) || isNull(val);
+}

+ 156 - 0
src/utils/request.ts

@@ -0,0 +1,156 @@
+/** 
+ *  @author TalkTao
+ * @description  接口封装
+*/
+import { useLoadingStore } from "@/store/loading";
+import { useUserStoreWidthOut } from "@/store/user"
+import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, Method } from "axios";
+import { cloneDeep } from 'lodash-es';
+import { Result, RequestOptions, CreateAxiosOptions } from './types';
+import { ResultEnum } from '@/enums/httpEnum';
+
+class HttpRequest {
+    private readonly baseURL: string;
+    private readonly withCredentials: boolean;
+    private readonly timeout: number;
+
+    private axiosInstance: AxiosInstance;
+    private options: CreateAxiosOptions;
+
+    constructor(options: CreateAxiosOptions) {
+        this.options = options;
+        //获取当前环境的api地址
+        this.baseURL = import.meta.env.VITE_BASE_URL as string;
+        this.withCredentials = true;
+        this.timeout = 1000 * 60;
+        this.axiosInstance = axios.create(this.getInitConfig());
+        this.interceptors(this.axiosInstance);
+    }
+    //初始化get请求
+    getInitConfig(): AxiosRequestConfig {
+        return {
+            baseURL: this.baseURL,
+            withCredentials: this.withCredentials,
+            timeout: this.timeout,
+        };
+    }
+
+    interceptors(instance: AxiosInstance) {
+        // 定义存放请求接口数组
+        let requestList = [];
+        const loadingStore = useLoadingStore();
+        const setLoadingToFalse = response => {
+            requestList
+                .filter(item => item.url == response.config.url && item.method == response.config.method)
+                .forEach(item => (item.isLoading = false));
+
+            //所有请求都加载完才让加载提示消失
+            if (requestList.every(item => !item.isLoading)) loadingStore.setLoading(false);
+        };
+        // 请求拦截器
+        instance.interceptors.request.use(
+            (config: any) => {
+                // 不用判断请求loading的路由
+                let ignoreLoadingUrls = ["/login"];
+                if (!ignoreLoadingUrls.includes(config.url)) {
+                    if (requestList.length < 10) {
+                        requestList.unshift({ ...config, isLoading: true });
+                    } else {
+                        requestList = [...requestList.slice(0, 9), { ...config, isLoading: true }];
+                    }
+                    loadingStore.setLoading(true);
+                }
+                // 请求之前处理config
+                const userStore = useUserStoreWidthOut();
+                const token = userStore.getToken;
+                if (!token) { }
+                config.headers['token'] = token
+                return config;
+            },
+            error => Promise.reject(error + '请求错误')
+        );
+        // 响应拦截器
+        instance.interceptors.response.use(
+            response => {
+                setLoadingToFalse(response);
+                if(response.data.code == 'loginTimeout'){ }
+                return response.data;
+            },
+            error => {
+                if (error.response.status == 301) { }
+                setLoadingToFalse(error);
+                return Promise.reject(error.response?.data);
+            }
+        );
+    }
+
+    /**
+     * @description: 处理请求数据
+     */
+    transformRequestData(res: AxiosResponse<Result>, options: RequestOptions){
+        const { data } = res
+        const {
+            isTransformResponse
+        } = options;
+
+        if (!data) {
+            // return '[HTTP] Request has no return value';
+            throw new Error('请求出错,请稍候重试');
+        }
+        // 用于页面代码可能需要直接获取code,data,message这些信息时开启
+        if(!isTransformResponse){
+            return data
+        }
+        //  这里 code,result,message为 后台统一的字段,需要修改为项目自己的接口返回格式
+        const { code, result, message } = data;
+        // 接口请求成功,直接返回结果
+        if (code === ResultEnum.SUCCESS) {
+            return result;
+        }
+    }
+
+    /**
+    * @description:   请求方法
+    */
+    request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
+        let conf: AxiosRequestConfig = cloneDeep(config);
+
+        const { requestOptions } = this.options;
+
+        const opt: RequestOptions = Object.assign({}, requestOptions, options);
+
+        // @ts-ignore
+        conf.requestOptions = opt;
+
+        return new Promise((resolve, reject) => {
+            this.axiosInstance
+            .request<any, AxiosResponse<Result>>(conf)
+            .then((res: AxiosResponse<Result>) => {
+                // 请求是否被取消
+                const isCancel = axios.isCancel(res);
+                if (!isCancel) {
+                    try {
+                        const ret = this.transformRequestData(res, opt);
+                        console.log(res)
+                        resolve(ret);
+                    } catch (err) {
+                        reject(err || new Error('request error!'));
+                    }
+                    return;
+                }
+                resolve(res as unknown as Promise<T>);
+            })
+            .catch((e: Error) => {
+                reject(e);
+            });
+        });
+    }
+}
+const http = new HttpRequest({
+    // 配置项,下面的选项都可以在独立的接口请求中覆盖
+    requestOptions: {
+      // 需要对返回数据进行处理
+      isTransformResponse: true
+    }
+  });
+export default http

+ 46 - 0
src/utils/types.ts

@@ -0,0 +1,46 @@
+export interface CreateAxiosOptions {
+    requestOptions?: RequestOptions;
+}
+export interface RequestOptions {
+  // 请求参数拼接到url
+  joinParamsToUrl?: boolean;
+  // 格式化请求参数时间
+  formatDate?: boolean;
+  // 是否显示提示信息
+  isShowMessage?: boolean;
+  // 是否解析成JSON
+  isParseToJson?: boolean;
+  // 成功的文本信息
+  successMessageText?: string;
+  // 是否显示成功信息
+  isShowSuccessMessage?: boolean;
+  // 是否显示失败信息
+  isShowErrorMessage?: boolean;
+  // 错误的文本信息
+  errorMessageText?: string;
+  // 是否加入url
+  joinPrefix?: boolean;
+  // 接口地址, 不填则使用默认apiUrl
+  apiUrl?: string;
+  // 请求拼接路径
+  urlPrefix?: string;
+  // 错误消息提示类型
+  errorMessageMode?: 'none' | 'modal';
+  // 是否添加时间戳
+  joinTime?: boolean;
+  // 不进行任何处理,直接返回
+  isTransformResponse?: boolean;
+  // 是否返回原生响应头
+  isReturnNativeResponse?: boolean;
+  //忽略重复请求
+  ignoreCancelToken?: boolean;
+  // 是否携带token
+  withToken?: boolean;
+}
+
+export interface Result<T = any> {
+  code: number;
+  type?: 'success' | 'error' | 'warning';
+  message: string;
+  result?: T;
+}

+ 0 - 1
src/views/home/Home.vue

@@ -38,7 +38,6 @@ const getTestData = async () => {
 onMounted(() => {
   console.log('====')
   getTestData();
-  getTestData();
 });
 </script>