From 11bf711838ebb34c7c6f6e6342da51ecb4d8a2c0 Mon Sep 17 00:00:00 2001 From: xiaoxian521 <1923740402@qq.com> Date: Sat, 4 Dec 2021 01:16:50 +0800 Subject: [PATCH] refactor: axios methods and env --- .env | 14 +- .env.development | 18 +- .env.production | 7 +- build/{utils.ts => index.ts} | 25 ++- build/proxy.ts | 19 --- package.json | 4 + pnpm-lock.yaml | 89 +++++++++- src/api/mock.ts | 8 +- src/api/routes.ts | 2 +- src/api/user.ts | 11 +- src/config/index.ts | 8 +- src/store/modules/types.ts | 5 + src/store/modules/user.ts | 84 +++++++++ src/utils/auth.ts | 43 +++++ src/utils/http/README.md | 25 +++ src/utils/http/config.ts | 32 ---- src/utils/http/core.ts | 236 -------------------------- src/utils/http/index.ts | 168 +++++++++++++++++- src/utils/http/types.d.ts | 51 +++--- src/utils/http/utils.ts | 29 ---- src/utils/storage/cookie.ts | 53 ------ src/utils/storage/db.ts | 93 ---------- src/views/components/button/index.vue | 8 +- types/global.d.ts | 16 +- vite.config.ts | 59 ++++--- 25 files changed, 522 insertions(+), 585 deletions(-) rename build/{utils.ts => index.ts} (61%) delete mode 100644 build/proxy.ts create mode 100644 src/store/modules/user.ts create mode 100644 src/utils/auth.ts create mode 100644 src/utils/http/README.md delete mode 100644 src/utils/http/config.ts delete mode 100644 src/utils/http/core.ts delete mode 100644 src/utils/http/utils.ts delete mode 100644 src/utils/storage/cookie.ts delete mode 100644 src/utils/storage/db.ts diff --git a/.env b/.env index d9f3a7812..da26759b0 100644 --- a/.env +++ b/.env @@ -1,14 +1,2 @@ -# port +# 项目本地运行端口号 VITE_PORT = 8848 -# title -VITE_TITLE = vue-pure-admin -# version -VITE_VERSION = 2.6.0 -# open -VITE_OPEN = false - -# public path -VITE_PUBLIC_PATH = / - -# Cross-domain proxy, you can configure multiple -VITE_PROXY = [ ["/api", "http://127.0.0.1:3000" ] ] diff --git a/.env.development b/.env.development index d9f3a7812..23c4c72fa 100644 --- a/.env.development +++ b/.env.development @@ -1,14 +1,12 @@ -# port +# 项目本地运行端口号 VITE_PORT = 8848 -# title -VITE_TITLE = vue-pure-admin -# version -VITE_VERSION = 2.6.0 -# open -VITE_OPEN = false -# public path +# 开发环境读取配置文件路径 VITE_PUBLIC_PATH = / -# Cross-domain proxy, you can configure multiple -VITE_PROXY = [ ["/api", "http://127.0.0.1:3000" ] ] +# 开发环境代理 +VITE_PROXY_DOMAIN = /api + +# 开发环境后端地址 +VITE_PROXY_DOMAIN_REAL = "http://127.0.0.1:3000" + diff --git a/.env.production b/.env.production index d6e1ff425..eace0a9ae 100644 --- a/.env.production +++ b/.env.production @@ -1,2 +1,5 @@ -# public path -VITE_PUBLIC_PATH = /manages/ +# 线上环境项目打包路径 +VITE_PUBLIC_PATH = / + +# 线上环境后端地址 +VITE_PROXY_DOMAIN_REAL = "" diff --git a/build/utils.ts b/build/index.ts similarity index 61% rename from build/utils.ts rename to build/index.ts index 92f4b8daf..c70fb1cfe 100644 --- a/build/utils.ts +++ b/build/index.ts @@ -1,5 +1,12 @@ +// 处理环境变量 const warpperEnv = (envConf: Recordable): ViteEnv => { - const ret: any = {}; + // 此处为默认值,无需修改 + const ret: ViteEnv = { + VITE_PORT: 8848, + VITE_PUBLIC_PATH: "", + VITE_PROXY_DOMAIN: "", + VITE_PROXY_DOMAIN_REAL: "" + }; for (const envName of Object.keys(envConf)) { let realName = envConf[envName].replace(/\\n/g, "\n"); @@ -9,13 +16,6 @@ const warpperEnv = (envConf: Recordable): ViteEnv => { if (envName === "VITE_PORT") { realName = Number(realName); } - if (envName === "VITE_PROXY" && realName) { - try { - realName = JSON.parse(realName.replace(/'/g, '"')); - } catch (error) { - realName = ""; - } - } ret[envName] = realName; if (typeof realName === "string") { process.env[envName] = realName; @@ -25,8 +25,15 @@ const warpperEnv = (envConf: Recordable): ViteEnv => { } return ret; }; + +// 跨域代理重写 +const regExps = (value: string, reg: string): string => { + return value.replace(new RegExp(reg, "g"), ""); +}; + +// 环境变量 const loadEnv = (): ViteEnv => { return import.meta.env; }; -export { loadEnv, warpperEnv }; +export { warpperEnv, regExps, loadEnv }; diff --git a/build/proxy.ts b/build/proxy.ts deleted file mode 100644 index 7cae8eba0..000000000 --- a/build/proxy.ts +++ /dev/null @@ -1,19 +0,0 @@ -type ProxyItem = [string, string]; - -type ProxyList = ProxyItem[]; - -const regExps = (value: string, reg: string): string => { - return value.replace(new RegExp(reg, "g"), ""); -}; - -export function createProxy(list: ProxyList = []) { - const ret: any = {}; - for (const [prefix, target] of list) { - ret[prefix] = { - target: target, - changeOrigin: true, - rewrite: (path: string) => regExps(path, prefix) - }; - } - return ret; -} diff --git a/package.json b/package.json index 6e34e385e..b65158631 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "element-plus": "1.2.0-beta.3", "element-resize-detector": "^1.2.3", "font-awesome": "^4.7.0", + "js-cookie": "^3.0.1", "lodash-es": "^4.17.21", "lowdb": "^3.0.0", "mitt": "^3.0.0", @@ -54,6 +55,7 @@ "path": "^0.12.7", "path-to-regexp": "^6.2.0", "pinia": "^2.0.0-rc.14", + "qs": "^6.10.1", "remixicon": "^2.5.0", "resize-observer-polyfill": "^1.5.1", "responsive-storage": "^1.0.11", @@ -76,9 +78,11 @@ "@commitlint/cli": "13.1.0", "@commitlint/config-conventional": "13.1.0", "@types/element-resize-detector": "1.1.3", + "@types/js-cookie": "^3.0.1", "@types/mockjs": "1.0.3", "@types/node": "14.14.14", "@types/nprogress": "0.2.0", + "@types/qs": "^6.9.7", "@typescript-eslint/eslint-plugin": "4.31.0", "@typescript-eslint/parser": "4.31.0", "@vitejs/plugin-vue": "^1.9.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0adee696f..ef44ebbfb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,11 @@ specifiers: "@logicflow/core": 0.7.1 "@logicflow/extension": 0.7.1 "@types/element-resize-detector": 1.1.3 + "@types/js-cookie": ^3.0.1 "@types/mockjs": 1.0.3 "@types/node": 14.14.14 "@types/nprogress": 0.2.0 + "@types/qs": ^6.9.7 "@typescript-eslint/eslint-plugin": 4.31.0 "@typescript-eslint/parser": 4.31.0 "@vitejs/plugin-vue": ^1.9.4 @@ -41,6 +43,7 @@ specifiers: eslint-plugin-vue: 7.17.0 font-awesome: ^4.7.0 husky: 7.0.2 + js-cookie: ^3.0.1 lint-staged: 11.1.2 lodash-es: ^4.17.21 lowdb: ^3.0.0 @@ -54,6 +57,7 @@ specifiers: postcss-import: 14.0.0 prettier: 2.3.2 pretty-quick: 3.1.1 + qs: ^6.10.1 remixicon: ^2.5.0 resize-observer-polyfill: ^1.5.1 responsive-storage: ^1.0.11 @@ -105,6 +109,7 @@ dependencies: element-plus: 1.2.0-beta.3_vue@3.2.21 element-resize-detector: 1.2.3 font-awesome: 4.7.0 + js-cookie: 3.0.1 lodash-es: 4.17.21 lowdb: 3.0.0 mitt: 3.0.0 @@ -113,6 +118,7 @@ dependencies: path: 0.12.7 path-to-regexp: 6.2.0 pinia: 2.0.2_typescript@4.4.2+vue@3.2.21 + qs: 6.10.1 remixicon: 2.5.0 resize-observer-polyfill: 1.5.1 responsive-storage: 1.0.11_vue@3.2.21 @@ -135,9 +141,11 @@ devDependencies: "@commitlint/cli": 13.1.0 "@commitlint/config-conventional": 13.1.0 "@types/element-resize-detector": 1.1.3 + "@types/js-cookie": 3.0.1 "@types/mockjs": 1.0.3 "@types/node": 14.14.14 "@types/nprogress": 0.2.0 + "@types/qs": 6.9.7 "@typescript-eslint/eslint-plugin": 4.31.0_f4e6dc0776b3600ef484e3c64a523136 "@typescript-eslint/parser": 4.31.0_eslint@7.30.0+typescript@4.4.2 "@vitejs/plugin-vue": 1.9.4_vite@2.6.14 @@ -1094,6 +1102,13 @@ packages: } dev: true + /@types/js-cookie/3.0.1: + resolution: + { + integrity: sha512-7wg/8gfHltklehP+oyJnZrz9XBuX5ZPP4zB6UsI84utdlkRYLnOm2HfpLXazTwZA+fpGn0ir8tGNgVnMEleBGQ== + } + dev: true + /@types/json-schema/7.0.9: resolution: { @@ -1173,6 +1188,13 @@ packages: } dev: true + /@types/qs/6.9.7: + resolution: + { + integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + } + dev: true + /@types/resolve/1.17.1: resolution: { @@ -1958,6 +1980,16 @@ packages: engines: { node: ">=6" } dev: true + /call-bind/1.0.2: + resolution: + { + integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + } + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.1 + dev: false + /callsites/3.1.0: resolution: { @@ -3604,7 +3636,6 @@ packages: { integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== } - dev: true /functional-red-black-tree/1.0.1: resolution: { integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= } @@ -3633,6 +3664,17 @@ packages: engines: { node: 6.* || 8.* || >= 10.* } dev: true + /get-intrinsic/1.1.1: + resolution: + { + integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + } + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.2 + dev: false + /get-own-enumerable-property-symbols/3.0.2: resolution: { @@ -3823,6 +3865,14 @@ packages: engines: { node: ">=8" } dev: true + /has-symbols/1.0.2: + resolution: + { + integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + } + engines: { node: ">= 0.4" } + dev: false + /has/1.0.3: resolution: { @@ -3831,7 +3881,6 @@ packages: engines: { node: ">= 0.4.0" } dependencies: function-bind: 1.1.1 - dev: true /hash-sum/2.0.0: resolution: @@ -4176,6 +4225,14 @@ packages: resolution: { integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= } dev: true + /js-cookie/3.0.1: + resolution: + { + integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw== + } + engines: { node: ">=12" } + dev: false + /js-tokens/4.0.0: resolution: { @@ -4837,6 +4894,13 @@ packages: resolution: { integrity: sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= } dev: true + /object-inspect/1.11.0: + resolution: + { + integrity: sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + } + dev: false + /on-finished/2.3.0: resolution: { integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= } engines: { node: ">= 0.8" } @@ -5371,6 +5435,16 @@ packages: engines: { node: ">=0.6.0", teleport: ">=0.2.0" } dev: true + /qs/6.10.1: + resolution: + { + integrity: sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + } + engines: { node: ">=0.6" } + dependencies: + side-channel: 1.0.4 + dev: false + /queue-microtask/1.2.3: resolution: { @@ -5744,6 +5818,17 @@ packages: engines: { node: ">=8" } dev: true + /side-channel/1.0.4: + resolution: + { + integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + } + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.1 + object-inspect: 1.11.0 + dev: false + /signal-exit/3.0.5: resolution: { diff --git a/src/api/mock.ts b/src/api/mock.ts index 9701c797a..02a8bea25 100644 --- a/src/api/mock.ts +++ b/src/api/mock.ts @@ -1,11 +1,11 @@ import { http } from "../utils/http"; // 地图数据 -export const mapJson = (data?: object) => { - return http.request("get", "/getMapInfo", data); +export const mapJson = (params?: object) => { + return http.request("get", "/getMapInfo", { params }); }; // echarts数据 -export const echartsJson = (data?: object) => { - return http.request("get", "/getEchartsInfo", data); +export const echartsJson = (params?: object) => { + return http.request("get", "/getEchartsInfo", { params }); }; diff --git a/src/api/routes.ts b/src/api/routes.ts index bbd3527bf..4d438813a 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -1,5 +1,5 @@ import { http } from "../utils/http"; export const getAsyncRoutes = (data?: object) => { - return http.request("get", "/getAsyncRoutes", data); + return http.request("get", "/getAsyncRoutes", { data }); }; diff --git a/src/api/user.ts b/src/api/user.ts index 64758b0e8..a9bac54d0 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -13,5 +13,14 @@ export const getVerify = (): userType => { // 登录 export const getLogin = (data: object) => { - return http.request("post", "/login", data); + return http.request("post", "/login", { data }); }; + +// 刷新token +export const refreshToken = (data: object) => { + return http.request("post", "/refreshToken", { data }); +}; + +// export const searchVague = (data: object) => { +// return http.request("post", "/searchVague", { data }); +// }; diff --git a/src/config/index.ts b/src/config/index.ts index c747e1622..7b0426a94 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,6 +1,9 @@ import { App } from "vue"; import axios from "axios"; +import { loadEnv } from "@build/index"; + let config: object = {}; +const { VITE_PUBLIC_PATH } = loadEnv(); const setConfig = (cfg?: unknown) => { config = Object.assign(config, cfg); @@ -30,10 +33,7 @@ export const getServerConfig = async (app: App): Promise => { return axios({ baseURL: "", method: "get", - url: - process.env.NODE_ENV === "production" - ? "/manages/serverConfig.json" - : "/serverConfig.json" + url: `${VITE_PUBLIC_PATH}serverConfig.json` }) .then(({ data: config }) => { let $config = app.config.globalProperties.$config; diff --git a/src/store/modules/types.ts b/src/store/modules/types.ts index 710af07d9..d6c11281d 100644 --- a/src/store/modules/types.ts +++ b/src/store/modules/types.ts @@ -33,3 +33,8 @@ export type setType = { fixedHeader: boolean; hiddenSideBar: boolean; }; + +export type userType = { + token: string; + name?: string; +}; diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts new file mode 100644 index 000000000..1ec1ea65f --- /dev/null +++ b/src/store/modules/user.ts @@ -0,0 +1,84 @@ +import { defineStore } from "pinia"; +import { store } from "/@/store"; +import { userType } from "./types"; +import { useRouter } from "vue-router"; +import { getLogin, refreshToken } from "/@/api/user"; +import { storageLocal, storageSession } from "/@/utils/storage"; +import { getToken, setToken, removeToken } from "/@/utils/auth"; +import { useMultiTagsStoreHook } from "/@/store/modules/multiTags"; + +const data = getToken(); +let token = ""; +let name = ""; +if (data) { + const dataJson = JSON.parse(data); + if (dataJson) { + token = dataJson?.accessToken; + name = dataJson?.name ?? "admin"; + } +} + +export const useUserStore = defineStore({ + id: "pure-user", + state: (): userType => ({ + token, + name + }), + actions: { + SET_TOKEN(token) { + this.token = token; + }, + SET_NAME(name) { + this.name = name; + }, + // 登入 + async loginByUsername(data) { + return new Promise((resolve, reject) => { + getLogin(data) + .then(data => { + if (data) { + setToken(data); + resolve(); + } + }) + .catch(error => { + reject(error); + }); + }); + }, + // 登出 清空缓存 + logOut() { + this.token = ""; + this.name = ""; + removeToken(); + storageLocal.clear(); + storageSession.clear(); + useMultiTagsStoreHook().handleTags("equal", [ + { + path: "/welcome", + parentPath: "/", + meta: { + title: "message.hshome", + icon: "el-icon-s-home", + i18n: true, + showLink: true + } + } + ]); + useRouter().push("/login"); + }, + // 刷新token + async refreshToken(data) { + return refreshToken(data).then(data => { + if (data) { + setToken(data); + return data; + } + }); + } + } +}); + +export function useUserStoreHook() { + return useUserStore(store); +} diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 000000000..ea02bce14 --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,43 @@ +import Cookies from "js-cookie"; +import { useUserStoreHook } from "/@/store/modules/user"; + +const TokenKey = "authorized-token"; + +type paramsMapType = { + name: string; + expires: number; + accessToken: string; +}; + +// 获取token +export function getToken() { + // 此处与TokenKey相同,此写法解决初始化时Cookies中不存在TokenKey报错 + return Cookies.get("authorized-token"); +} + +// 设置token以及过期时间(cookies、sessionStorage各一份) +// 后端需要将用户信息和token以及过期时间都返回给前端,过期时间主要用于刷新token +export function setToken(data) { + const { accessToken, expires, name } = data; + // 提取关键信息进行存储 + const paramsMap: paramsMapType = { + name, + expires: Date.now() + parseInt(expires), + accessToken + }; + const dataString = JSON.stringify(paramsMap); + useUserStoreHook().SET_TOKEN(accessToken); + useUserStoreHook().SET_NAME(name); + expires > 0 + ? Cookies.set(TokenKey, dataString, { + expires: expires / 86400000 + }) + : Cookies.set(TokenKey, dataString); + sessionStorage.setItem(TokenKey, dataString); +} + +// 删除token +export function removeToken() { + Cookies.remove(TokenKey); + sessionStorage.removeItem(TokenKey); +} diff --git a/src/utils/http/README.md b/src/utils/http/README.md new file mode 100644 index 000000000..5b661e692 --- /dev/null +++ b/src/utils/http/README.md @@ -0,0 +1,25 @@ +## 用法 + +### Get 请求 + +``` +import { http } from "/@/utils/http"; + +// params传参 +http.request('get', '/xxx', { params: param }); + +// url拼接传参 +http.request('get', '/xxx?message=' + msg); +``` + +### Post 请求 + +``` +import { http } from "/@/utils/http"; + +// params传参 +http.request('get', '/xxx', { params: param }); + +// data传参 +http.request('get', '/xxx', { data: param }); +``` diff --git a/src/utils/http/config.ts b/src/utils/http/config.ts deleted file mode 100644 index a4c3845fb..000000000 --- a/src/utils/http/config.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AxiosRequestConfig } from "axios"; -import { excludeProps } from "./utils"; -/** - * 默认配置 - */ -export const defaultConfig: AxiosRequestConfig = { - baseURL: "", - //10秒超时 - timeout: 10000, - headers: { - Accept: "application/json, text/plain, */*", - "Content-Type": "application/json", - "X-Requested-With": "XMLHttpRequest" - } -}; - -export function genConfig(config?: AxiosRequestConfig): AxiosRequestConfig { - if (!config) { - return defaultConfig; - } - - const { headers } = config; - if (headers && typeof headers === "object") { - defaultConfig.headers = { - ...defaultConfig.headers, - ...headers - }; - } - return { ...excludeProps(config!, "headers"), ...defaultConfig }; -} - -export const METHODS = ["post", "get", "put", "delete", "option", "patch"]; diff --git a/src/utils/http/core.ts b/src/utils/http/core.ts deleted file mode 100644 index 623f1e990..000000000 --- a/src/utils/http/core.ts +++ /dev/null @@ -1,236 +0,0 @@ -import Axios, { - AxiosRequestConfig, - CancelTokenStatic, - AxiosInstance -} from "axios"; - -import NProgress from "../progress"; - -import { genConfig } from "./config"; - -import { transformConfigByMethod } from "./utils"; - -import { - cancelTokenType, - RequestMethods, - EnclosureHttpRequestConfig, - EnclosureHttpResoponse, - EnclosureHttpError -} from "./types.d"; - -class EnclosureHttp { - constructor() { - this.httpInterceptorsRequest(); - this.httpInterceptorsResponse(); - } - // 初始化配置对象 - private static initConfig: EnclosureHttpRequestConfig = {}; - - // 保存当前Axios实例对象 - private static axiosInstance: AxiosInstance = Axios.create(genConfig()); - - // 保存 EnclosureHttp实例 - private static EnclosureHttpInstance: EnclosureHttp; - - // axios取消对象 - private CancelToken: CancelTokenStatic = Axios.CancelToken; - - // 取消的凭证数组 - private sourceTokenList: Array = []; - - // 记录当前这一次cancelToken的key - private currentCancelTokenKey = ""; - - public get cancelTokenList(): Array { - return this.sourceTokenList; - } - - // eslint-disable-next-line class-methods-use-this - public set cancelTokenList(value) { - throw new Error("cancelTokenList不允许赋值"); - } - - /** - * @description 私有构造不允许实例化 - * @returns void 0 - */ - // constructor() {} - - /** - * @description 生成唯一取消key - * @param config axios配置 - * @returns string - */ - // eslint-disable-next-line class-methods-use-this - private static genUniqueKey(config: EnclosureHttpRequestConfig): string { - return `${config.url}--${JSON.stringify(config.data)}`; - } - - /** - * @description 取消重复请求 - * @returns void 0 - */ - private cancelRepeatRequest(): void { - const temp: { [key: string]: boolean } = {}; - - this.sourceTokenList = this.sourceTokenList.reduce>( - (res: Array, cancelToken: cancelTokenType) => { - const { cancelKey, cancelExecutor } = cancelToken; - if (!temp[cancelKey]) { - temp[cancelKey] = true; - res.push(cancelToken); - } else { - cancelExecutor(); - } - return res; - }, - [] - ); - } - - /** - * @description 删除指定的CancelToken - * @returns void 0 - */ - private deleteCancelTokenByCancelKey(cancelKey: string): void { - this.sourceTokenList = - this.sourceTokenList.length < 1 - ? this.sourceTokenList.filter( - cancelToken => cancelToken.cancelKey !== cancelKey - ) - : []; - } - - /** - * @description 拦截请求 - * @returns void 0 - */ - - private httpInterceptorsRequest(): void { - EnclosureHttp.axiosInstance.interceptors.request.use( - (config: EnclosureHttpRequestConfig) => { - const $config = config; - NProgress.start(); // 每次切换页面时,调用进度条 - const cancelKey = EnclosureHttp.genUniqueKey($config); - $config.cancelToken = new this.CancelToken( - (cancelExecutor: (cancel: any) => void) => { - this.sourceTokenList.push({ cancelKey, cancelExecutor }); - } - ); - this.cancelRepeatRequest(); - this.currentCancelTokenKey = cancelKey; - // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 - if (typeof config.beforeRequestCallback === "function") { - config.beforeRequestCallback($config); - return $config; - } - if (EnclosureHttp.initConfig.beforeRequestCallback) { - EnclosureHttp.initConfig.beforeRequestCallback($config); - return $config; - } - return $config; - }, - error => { - return Promise.reject(error); - } - ); - } - - /** - * @description 清空当前cancelTokenList - * @returns void 0 - */ - public clearCancelTokenList(): void { - this.sourceTokenList.length = 0; - } - - /** - * @description 拦截响应 - * @returns void 0 - */ - private httpInterceptorsResponse(): void { - const instance = EnclosureHttp.axiosInstance; - instance.interceptors.response.use( - (response: EnclosureHttpResoponse) => { - const $config = response.config; - // 请求每次成功一次就删除当前canceltoken标记 - const cancelKey = EnclosureHttp.genUniqueKey($config); - this.deleteCancelTokenByCancelKey(cancelKey); - - NProgress.done(); - // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 - if (typeof $config.beforeResponseCallback === "function") { - $config.beforeResponseCallback(response); - return response.data; - } - if (EnclosureHttp.initConfig.beforeResponseCallback) { - EnclosureHttp.initConfig.beforeResponseCallback(response); - return response.data; - } - return response.data; - }, - (error: EnclosureHttpError) => { - const $error = error; - // 判断当前的请求中是否在 取消token数组理存在,如果存在则移除(单次请求流程) - if (this.currentCancelTokenKey) { - const haskey = this.sourceTokenList.filter( - cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey - ).length; - if (haskey) { - this.sourceTokenList = this.sourceTokenList.filter( - cancelToken => - cancelToken.cancelKey !== this.currentCancelTokenKey - ); - this.currentCancelTokenKey = ""; - } - } - $error.isCancelRequest = Axios.isCancel($error); - NProgress.done(); - // 所有的响应异常 区分来源为取消请求/非取消请求 - return Promise.reject($error); - } - ); - } - - public request( - method: RequestMethods, - url: string, - param?: AxiosRequestConfig, - axiosConfig?: EnclosureHttpRequestConfig - ): Promise { - const config = transformConfigByMethod(param, { - method, - url, - ...axiosConfig - } as EnclosureHttpRequestConfig); - // 单独处理自定义请求/响应回掉 - return new Promise((resolve, reject) => { - EnclosureHttp.axiosInstance - .request(config) - .then((response: undefined) => { - resolve(response); - }) - .catch((error: any) => { - reject(error); - }); - }); - } - - public post( - url: string, - params?: T, - config?: EnclosureHttpRequestConfig - ): Promise { - return this.request("post", url, params, config); - } - - public get( - url: string, - params?: T, - config?: EnclosureHttpRequestConfig - ): Promise { - return this.request("get", url, params, config); - } -} - -export default EnclosureHttp; diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts index 7421343f7..2c99fa56a 100644 --- a/src/utils/http/index.ts +++ b/src/utils/http/index.ts @@ -1,2 +1,166 @@ -import EnclosureHttp from "./core"; -export const http = new EnclosureHttp(); +import Axios, { AxiosInstance, AxiosRequestConfig } from "axios"; +import { + resultType, + PureHttpError, + RequestMethods, + PureHttpResoponse, + PureHttpRequestConfig +} from "./types.d"; +import qs from "qs"; +import NProgress from "../progress"; +// import { loadEnv } from "@build/index"; +import { getToken } from "/@/utils/auth"; +import { useUserStoreHook } from "/@/store/modules/user"; + +// 加载环境变量 VITE_PROXY_DOMAIN(开发环境) VITE_PROXY_DOMAIN_REAL(打包后的线上环境) +// const { VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL } = loadEnv(); + +// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1 +const defaultConfig: AxiosRequestConfig = { + // baseURL: + // process.env.NODE_ENV === "production" + // ? VITE_PROXY_DOMAIN_REAL + // : VITE_PROXY_DOMAIN, + // 当前使用mock模拟请求,将baseURL制空,如果你的环境用到了http请求,请删除下面的baseURL启用上面的baseURL,并将11行、16行代码注释取消 + baseURL: "", + timeout: 10000, + headers: { + Accept: "application/json, text/plain, */*", + "Content-Type": "application/json", + "X-Requested-With": "XMLHttpRequest" + }, + // 数组格式参数序列化 + paramsSerializer: params => qs.stringify(params, { indices: false }) +}; + +class PureHttp { + constructor() { + this.httpInterceptorsRequest(); + this.httpInterceptorsResponse(); + } + // 初始化配置对象 + private static initConfig: PureHttpRequestConfig = {}; + + // 保存当前Axios实例对象 + private static axiosInstance: AxiosInstance = Axios.create(defaultConfig); + + // 请求拦截 + private httpInterceptorsRequest(): void { + PureHttp.axiosInstance.interceptors.request.use( + (config: PureHttpRequestConfig) => { + const $config = config; + // 开启进度条动画 + NProgress.start(); + // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 + if (typeof config.beforeRequestCallback === "function") { + config.beforeRequestCallback($config); + return $config; + } + if (PureHttp.initConfig.beforeRequestCallback) { + PureHttp.initConfig.beforeRequestCallback($config); + return $config; + } + const token = getToken(); + if (token) { + const data = JSON.parse(token); + const now = new Date().getTime(); + const expired = parseInt(data.expires) - now <= 0; + if (expired) { + // token过期刷新 + useUserStoreHook() + .refreshToken(data) + .then((res: resultType) => { + config.headers["Authorization"] = "Bearer " + res.accessToken; + return $config; + }); + } else { + config.headers["Authorization"] = "Bearer " + data.accessToken; + return $config; + } + } else { + return $config; + } + }, + error => { + return Promise.reject(error); + } + ); + } + + // 响应拦截 + private httpInterceptorsResponse(): void { + const instance = PureHttp.axiosInstance; + instance.interceptors.response.use( + (response: PureHttpResoponse) => { + const $config = response.config; + // 关闭进度条动画 + NProgress.done(); + // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉 + if (typeof $config.beforeResponseCallback === "function") { + $config.beforeResponseCallback(response); + return response.data; + } + if (PureHttp.initConfig.beforeResponseCallback) { + PureHttp.initConfig.beforeResponseCallback(response); + return response.data; + } + return response.data; + }, + (error: PureHttpError) => { + const $error = error; + $error.isCancelRequest = Axios.isCancel($error); + // 关闭进度条动画 + NProgress.done(); + // 所有的响应异常 区分来源为取消请求/非取消请求 + return Promise.reject($error); + } + ); + } + + // 通用请求工具函数 + public request( + method: RequestMethods, + url: string, + param?: AxiosRequestConfig, + axiosConfig?: PureHttpRequestConfig + ): Promise { + const config = { + method, + url, + ...param, + ...axiosConfig + } as PureHttpRequestConfig; + + // 单独处理自定义请求/响应回掉 + return new Promise((resolve, reject) => { + PureHttp.axiosInstance + .request(config) + .then((response: undefined) => { + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); + } + + // 单独抽离的post工具函数 + public post( + url: string, + params?: T, + config?: PureHttpRequestConfig + ): Promise { + return this.request("post", url, params, config); + } + + // 单独抽离的get工具函数 + public get( + url: string, + params?: T, + config?: PureHttpRequestConfig + ): Promise { + return this.request("get", url, params, config); + } +} + +export const http = new PureHttp(); diff --git a/src/utils/http/types.d.ts b/src/utils/http/types.d.ts index 444c04283..985cc3785 100644 --- a/src/utils/http/types.d.ts +++ b/src/utils/http/types.d.ts @@ -1,50 +1,39 @@ import Axios, { - AxiosRequestConfig, - Canceler, - AxiosResponse, Method, - AxiosError + AxiosError, + AxiosResponse, + AxiosRequestConfig } from "axios"; -import { METHODS } from "./config"; - -export type cancelTokenType = { cancelKey: string; cancelExecutor: Canceler }; +export type resultType = { + accessToken?: string; +}; export type RequestMethods = Extract< Method, "get" | "post" | "put" | "delete" | "patch" | "option" | "head" >; -export interface EnclosureHttpRequestConfig extends AxiosRequestConfig { - beforeRequestCallback?: (request: EnclosureHttpRequestConfig) => void; // 请求发送之前 - beforeResponseCallback?: (response: EnclosureHttpResoponse) => void; // 相应返回之前 -} - -export interface EnclosureHttpResoponse extends AxiosResponse { - config: EnclosureHttpRequestConfig; -} - -export interface EnclosureHttpError extends AxiosError { +export interface PureHttpError extends AxiosError { isCancelRequest?: boolean; } -export default class EnclosureHttp { - cancelTokenList: Array; - clearCancelTokenList(): void; +export interface PureHttpResoponse extends AxiosResponse { + config: PureHttpRequestConfig; +} + +export interface PureHttpRequestConfig extends AxiosRequestConfig { + beforeRequestCallback?: (request: PureHttpRequestConfig) => void; + beforeResponseCallback?: (response: PureHttpResoponse) => void; +} + +export default class PureHttp { request( method: RequestMethods, url: string, param?: AxiosRequestConfig, - axiosConfig?: EnclosureHttpRequestConfig - ): Promise; - post( - url: string, - params?: T, - config?: EnclosureHttpRequestConfig - ): Promise; - get( - url: string, - params?: T, - config?: EnclosureHttpRequestConfig + axiosConfig?: PureHttpRequestConfig ): Promise; + post(url: string, params?: T, config?: PureHttpRequestConfig): Promise; + get(url: string, params?: T, config?: PureHttpRequestConfig): Promise; } diff --git a/src/utils/http/utils.ts b/src/utils/http/utils.ts deleted file mode 100644 index a5a621b7a..000000000 --- a/src/utils/http/utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { EnclosureHttpRequestConfig } from "./types.d"; - -export function excludeProps( - origin: T, - prop: string -): { [key: string]: T } { - return Object.keys(origin) - .filter(key => !prop.includes(key)) - .reduce((res, key) => { - res[key] = origin[key]; - return res; - }, {} as { [key: string]: T }); -} - -export function transformConfigByMethod( - params: any, - config: EnclosureHttpRequestConfig -): EnclosureHttpRequestConfig { - const { method } = config; - const props = ["delete", "get", "head", "options"].includes( - method!.toLocaleLowerCase() - ) - ? "params" - : "data"; - return { - ...config, - [props]: params - }; -} diff --git a/src/utils/storage/cookie.ts b/src/utils/storage/cookie.ts deleted file mode 100644 index 24849acb4..000000000 --- a/src/utils/storage/cookie.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { loadEnv } from "@build/utils"; -import { merge } from "lodash-es"; -import tsCookies from "typescript-cookie/dist/src/compat"; - -class Cookies { - private static env = loadEnv(); - constructor() {} - /** - * 存储 cookie 值 - * @param name - * @param value - * @param cookieSetting - */ - set(name = "default", value = "", cookieSetting = {}) { - const currentCookieSetting = { - expires: 1 - }; - merge(currentCookieSetting, cookieSetting); - tsCookies.set( - `${Cookies.env.VITE_TITLE}-${Cookies.env.VITE_VERSION}-${name}`, - value, - currentCookieSetting - ); - } - /** - * 拿到 cookie 值 - * @param name - * @returns - */ - get(name = "default") { - return tsCookies.get( - `${Cookies.env.VITE_TITLE}-${Cookies.env.VITE_VERSION}-${name}` - ); - } - /** - * 拿到 cookie 全部的值 - * @returns - */ - getAll() { - return tsCookies.get(); - } - /** - * 删除 cookie - * @param name - */ - remove(name = "default") { - tsCookies.remove( - `${Cookies.env.VITE_TITLE}-${Cookies.env.VITE_VERSION}-${name}` - ); - } -} - -export const cookies = new Cookies(); diff --git a/src/utils/storage/db.ts b/src/utils/storage/db.ts deleted file mode 100644 index bd3cfe3de..000000000 --- a/src/utils/storage/db.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { loadEnv } from "@build/utils"; -import { LocalStorage, LowSync } from "lowdb"; -import { chain, cloneDeep } from "lodash-es"; -import { storageLocal } from "."; -import { cookies } from "./cookie"; -type Data = { - database: {}; - sys: {}; -}; -/** - * db 数据存储,采用 LocalStorage存储 - */ -class DB { - private db: LowSync; - private static env = loadEnv(); - constructor() { - this.db = new LowSync( - new LocalStorage(`${DB.env.VITE_TITLE}-${DB.env.VITE_VERSION}`) - ); - this.initialization(); - // @ts-ignore - this.db.chain = chain(this.db.data); - } - private initialization() { - this.db.data = storageLocal.getItem( - `${DB.env.VITE_TITLE}-${DB.env.VITE_VERSION}` - ) || { database: {}, sys: {} }; - this.db.write(); - } - /** - * 检查路径是否存在 不存在的话初始化 - * @param param0 - * @returns path - */ - pathInit({ - dbName = "database", - path = "", - user = true, - validator = () => true, - defaultValue = "" - }): string { - const uuid = cookies.get("uuid") || "ghost-uuid"; - const currentPath = `${dbName}.${user ? `user.${uuid}` : "public"}${ - path ? `.${path}` : "" - }`; - // @ts-ignore - const value = this.db.chain.get(currentPath).value(); - // @ts-ignore - if (!(value !== undefined && validator(value))) { - // @ts-ignore - this.db.chain.set(currentPath, defaultValue).value(); - this.db.write(); - } - return currentPath; - } - /** - *将数据存储到指定位置 | 路径不存在会自动初始化 - * - * 效果类似于取值 dbName.path = value - * @param param0 - */ - dbSet({ dbName = "database", path = "", value = "", user = false }): void { - const currentPath = this.pathInit({ - dbName, - path, - user - }); - // @ts-ignore - this.db.chain.set(currentPath, value).value(); - this.db.write(); - } - /** - * 获取数据 - * - * 效果类似于取值 dbName.path || defaultValue - * @param param0 - * @returns - */ - dbGet({ - dbName = "database", - path = "", - defaultValue = "", - user = false - }): any { - // @ts-ignore - const values = this.db.chain - .get(this.pathInit({ dbName, path, user, defaultValue })) - .value(); - return cloneDeep(values); - } -} - -export const db = new DB(); diff --git a/src/views/components/button/index.vue b/src/views/components/button/index.vue index d086c4d3e..f77fb5104 100644 --- a/src/views/components/button/index.vue +++ b/src/views/components/button/index.vue @@ -1,11 +1,9 @@