refactor: axios methods and env

This commit is contained in:
xiaoxian521 2021-12-04 01:16:50 +08:00
parent a845d4f237
commit 11bf711838
25 changed files with 522 additions and 585 deletions

14
.env
View File

@ -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" ] ]

View File

@ -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"

View File

@ -1,2 +1,5 @@
# public path
VITE_PUBLIC_PATH = /manages/
# 线上环境项目打包路径
VITE_PUBLIC_PATH = /
# 线上环境后端地址
VITE_PROXY_DOMAIN_REAL = ""

View File

@ -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 };

View File

@ -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;
}

View File

@ -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",

89
pnpm-lock.yaml generated
View File

@ -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:
{

View File

@ -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 });
};

View File

@ -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 });
};

View File

@ -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 });
// };

View File

@ -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<undefined> => {
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;

View File

@ -33,3 +33,8 @@ export type setType = {
fixedHeader: boolean;
hiddenSideBar: boolean;
};
export type userType = {
token: string;
name?: string;
};

84
src/store/modules/user.ts Normal file
View File

@ -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<void>((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);
}

43
src/utils/auth.ts Normal file
View File

@ -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);
}

25
src/utils/http/README.md Normal file
View File

@ -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 });
```

View File

@ -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"];

View File

@ -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<cancelTokenType> = [];
// 记录当前这一次cancelToken的key
private currentCancelTokenKey = "";
public get cancelTokenList(): Array<cancelTokenType> {
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<Array<cancelTokenType>>(
(res: Array<cancelTokenType>, 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<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: EnclosureHttpRequestConfig
): Promise<T> {
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<T>(
url: string,
params?: T,
config?: EnclosureHttpRequestConfig
): Promise<T> {
return this.request<T>("post", url, params, config);
}
public get<T>(
url: string,
params?: T,
config?: EnclosureHttpRequestConfig
): Promise<T> {
return this.request<T>("get", url, params, config);
}
}
export default EnclosureHttp;

View File

@ -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<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: PureHttpRequestConfig
): Promise<T> {
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<T>(
url: string,
params?: T,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("post", url, params, config);
}
// 单独抽离的get工具函数
public get<T>(
url: string,
params?: T,
config?: PureHttpRequestConfig
): Promise<T> {
return this.request<T>("get", url, params, config);
}
}
export const http = new PureHttp();

View File

@ -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<cancelTokenType>;
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<T>(
method: RequestMethods,
url: string,
param?: AxiosRequestConfig,
axiosConfig?: EnclosureHttpRequestConfig
): Promise<T>;
post<T>(
url: string,
params?: T,
config?: EnclosureHttpRequestConfig
): Promise<T>;
get<T>(
url: string,
params?: T,
config?: EnclosureHttpRequestConfig
axiosConfig?: PureHttpRequestConfig
): Promise<T>;
post<T>(url: string, params?: T, config?: PureHttpRequestConfig): Promise<T>;
get<T>(url: string, params?: T, config?: PureHttpRequestConfig): Promise<T>;
}

View File

@ -1,29 +0,0 @@
import { EnclosureHttpRequestConfig } from "./types.d";
export function excludeProps<T extends { [key: string]: any }>(
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
};
}

View File

@ -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();

View File

@ -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<Data>;
private static env = loadEnv();
constructor() {
this.db = new LowSync<Data>(
new LocalStorage<Data>(`${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();

View File

@ -1,11 +1,9 @@
<script setup lang="ts">
import { ref } from "vue";
import { loadEnv } from "@build/index";
const { VITE_PUBLIC_PATH } = loadEnv();
const url = ref(
process.env.NODE_ENV === "production"
? "/manages/html/button.html"
: "/html/button.html"
);
const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
</script>
<template>

16
types/global.d.ts vendored
View File

@ -65,21 +65,9 @@ declare global {
declare interface ViteEnv {
VITE_PORT: number;
VITE_TITLE: string;
VITE_VERSION: string;
VITE_USE_MOCK: boolean;
VITE_USE_PWA: boolean;
VITE_PUBLIC_PATH: string;
VITE_PROXY: [string, string][];
VITE_GLOB_APP_TITLE: string;
VITE_GLOB_APP_SHORT_NAME: string;
VITE_USE_CDN: boolean;
VITE_DROP_CONSOLE: boolean;
VITE_BUILD_COMPRESS: "gzip" | "brotli" | "none";
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean;
VITE_LEGACY: boolean;
VITE_USE_IMAGEMIN: boolean;
VITE_GENERATE_UI: string;
VITE_PROXY_DOMAIN: string;
VITE_PROXY_DOMAIN_REAL: string;
}
declare interface ServerConfigs {

View File

@ -1,41 +1,40 @@
import { resolve } from "path";
import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import { warpperEnv } from "./build/utils";
import { createProxy } from "./build/proxy";
import { viteMockServe } from "vite-plugin-mock";
import svgLoader from "vite-svg-loader";
import vueJsx from "@vitejs/plugin-vue-jsx";
import { warpperEnv, regExps } from "./build";
import { viteMockServe } from "vite-plugin-mock";
import styleImport from "vite-plugin-style-import";
import ElementPlus from "unplugin-element-plus/vite";
import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
// 当前执行node命令时文件夹的地址工作目录
const root: string = process.cwd();
// 路径查找
const pathResolve = (dir: string): string => {
return resolve(__dirname, ".", dir);
};
// 设置别名
const alias: Record<string, string> = {
"/@": pathResolve("src"),
"@build": pathResolve("build"),
//解决开发环境下的警告 You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle.
//解决开发环境下的警告
"vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js"
};
const root: string = process.cwd();
export default ({ command, mode }: ConfigEnv): UserConfigExport => {
const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY } = warpperEnv(
loadEnv(mode, root)
);
const {
VITE_PORT,
VITE_PUBLIC_PATH,
VITE_PROXY_DOMAIN,
VITE_PROXY_DOMAIN_REAL
} = warpperEnv(loadEnv(mode, root));
const prodMock = true;
return {
/**
*
* /manages/ /manages/
* @default '/'
*/
base:
process.env.NODE_ENV === "production" ? "/manages/" : VITE_PUBLIC_PATH,
base: VITE_PUBLIC_PATH,
root,
resolve: {
alias
@ -44,18 +43,27 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
server: {
// 是否开启 https
https: false,
/**
*
* @default 3000
*/
// 端口号
port: VITE_PORT,
host: "0.0.0.0",
// 本地跨域代理
proxy: createProxy(VITE_PROXY)
proxy:
VITE_PROXY_DOMAIN_REAL.length > 0
? {
[VITE_PROXY_DOMAIN]: {
target: VITE_PROXY_DOMAIN_REAL,
// ws: true,
changeOrigin: true,
rewrite: (path: string) => regExps(path, VITE_PROXY_DOMAIN)
}
}
: null
},
plugins: [
vue(),
// jsx、tsx语法支持
vueJsx(),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: [
@ -112,10 +120,11 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
customThemeCssFileName: scopeName => scopeName
}
}),
// svg组件化支持
svgLoader(),
// 按需加载vxe-table
styleImport({
libs: [
// 按需加载vxe-table
{
libraryName: "vxe-table",
esModule: true,
@ -126,6 +135,7 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
]
}),
ElementPlus({}),
// mock支持
viteMockServe({
mockPath: "mock",
localEnabled: command === "serve",
@ -147,7 +157,6 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"]
},
build: {
// @ts-ignore
sourcemap: false,
brotliSize: false,
// 消除打包大小超过500kb警告