Skip to content

Commit

Permalink
feat: 支持路径别名、新增axios封装
Browse files Browse the repository at this point in the history
  • Loading branch information
pumelotea committed Jun 21, 2022
1 parent 10afc28 commit 82bf213
Show file tree
Hide file tree
Showing 38 changed files with 379 additions and 42 deletions.
3 changes: 3 additions & 0 deletions .env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NODE_ENV = 'development'
VITE_APP_OSS = 'https://oss.injs.jsxww.cn'
VITE_APP_API = 'https://api.op.injs.jsxww.cn'
3 changes: 3 additions & 0 deletions .env.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NODE_ENV = 'production'
VITE_APP_OSS = 'https://oss.injs.jsxww.cn'
VITE_APP_API = 'https://api.op.injs.jsxww.cn'
3 changes: 3 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
NODE_ENV = 'production'
VITE_APP_OSS = 'https://oss.injs.jsxww.cn'
VITE_APP_API = 'https://api.op.injs.jsxww.cn'
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"private": true,
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"dev": "vite --mode dev",
"build-test": "vite build --mode test",
"build-prod": "vite build --mode prod",
"preview": "vite preview"
},
"dependencies": {
Expand Down
Binary file added public/9c67d262-f53e-4358-9f99-beef9538e579.mp4
Binary file not shown.
4 changes: 2 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import {
NMessageProvider, NConfigProvider, zhCN, dateZhCN
} from 'naive-ui'
import {theme} from "./global/config";
import HappyBoot from "./HappyBoot.vue";
import {theme} from "@/global/config";
import HappyBoot from "@/HappyBoot.vue";
</script>
<template>
Expand Down
2 changes: 1 addition & 1 deletion src/HappyBoot.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import HbAdminDevTool from "./components/dev/HbAdminDevTool.vue";
import HbAdminDevTool from "@/components/dev/HbAdminDevTool.vue";
import { useMessage } from 'naive-ui'
window.$message = useMessage()
</script>
Expand Down
6 changes: 3 additions & 3 deletions src/components/HbAdminHead.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import { NIcon,NBadge,NAvatar,NSwitch,NCarousel,NDivider,NDropdown,useMessage, NText, NBreadcrumb,NBreadcrumbItem } from "naive-ui"
import { Moon,SunnyOutline,Notifications } from "@vicons/ionicons5"
import {ref, h, onMounted, computed} from "vue"
import {isDarkTheme} from "../global/config";
import framework from "../global/framework";
import {isDarkTheme} from "@/global/config";
import framework from "@/global/framework";
import { CubeOutline } from "@vicons/ionicons5"
import {useRouter} from "vue-router";
import security from "../global/security";
import security from "@/global/security";
const router = useRouter()
Expand Down
2 changes: 1 addition & 1 deletion src/components/HbAdminLogo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
NGradientText
} from "naive-ui"
import {isMenuCollapsed} from "../global/config";
import {isMenuCollapsed} from "@/global/config";
import {computed} from "vue";
const enterActiveClass = computed(()=>{
return !isMenuCollapsed.value ? 'animate__animated animate__slideInRight animate__faster' : 'animate__animated animate__slideInLeft animate__faster'
Expand Down
2 changes: 1 addition & 1 deletion src/components/HbAdminMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {NIcon, NMenu} from "naive-ui"
import {
CubeOutline
} from "@vicons/ionicons5"
import framework from '../global/framework'
import framework from '@/global/framework'
import {useRouter} from "vue-router";
const router = useRouter()
Expand Down
2 changes: 1 addition & 1 deletion src/components/HbAdminNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
CloseCircleSharp,
CubeOutline
} from "@vicons/ionicons5"
import framework from '.././global/framework'
import framework from '@/global/framework'
import {h, nextTick, ref, watch} from "vue";
import {useRouter} from "vue-router";
Expand Down
2 changes: 1 addition & 1 deletion src/components/HbAdminOnlineUserList.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import {NAvatar,NSpace,NBadge,NLayout,NLayoutHeader} from "naive-ui";
import {isMenuCollapsed} from "../global/config";
import {isMenuCollapsed} from "@/global/config";
import {computed} from "vue";
const enterActiveClass = computed(()=>{
return !isMenuCollapsed.value ? 'animate__animated animate__slideInRight animate__faster' : 'animate__animated animate__slideInLeft animate__faster'
Expand Down
2 changes: 1 addition & 1 deletion src/components/HbAdminSimpleChart.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup>
import * as echarts from 'echarts';
import {computed, nextTick, onMounted, ref, watch} from "vue";
import {isDark,isMenuCollapsed} from "../global/config";
import {isDark,isMenuCollapsed} from "@/global/config";
import {useWindowSize, useDebounceFn} from '@vueuse/core'
Expand Down
2 changes: 1 addition & 1 deletion src/components/HbAdminUserCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {NAvatar,NLayout,NLayoutHeader,NIcon,NButton,NBadge,NSpace} from "naive-u
import {
EarthOutline
} from "@vicons/ionicons5"
import {isMenuCollapsed} from "../global/config";
import {isMenuCollapsed} from "@/global/config";
import security from "../global/security";
import {computed, ref} from "vue";
Expand Down
8 changes: 4 additions & 4 deletions src/components/dev/HbAdminDevTool.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup>
import {NCard, NSpace, NButton, NTag, NCode, NTable, useMessage,NAlert} from "naive-ui";
import framework from "../../global/framework";
import security from "../../global/security";
import hljs from 'highlight.js/lib/core'
import javascript from 'highlight.js/lib/languages/javascript'
import framework from "@/global/framework";
import security from "@/global/security";
import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';
import {onMounted, ref, watch} from "vue";
hljs.registerLanguage('javascript', javascript)
Expand Down
15 changes: 15 additions & 0 deletions src/global/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import request from '../http';

// demo 代码
// export default {
// middleViewData: data => request.get('/jscApi/middleViewData', { data }), // 正常请求
// cancelReq: data => request.get('http://localhost:3003/jscApi/middleViewData', { data, cancelRequest: true }), // 测试取消请求
// reqAgainSend: data => request.get('/equ/equTypeList11', { data, retry: 3, retryDelay: 1000 }), // 测试请求重发,除了原请求外还会重发3次
// cacheEquList: data => request.get('/equ/equList', { data, cache: true, setExpireTime: 30000 }), // 测试缓存请求带参数:setExpireTime 为缓存有效时间ms
// cacheEquListParams: data => request.get('/equ/equList', { data, cache: true }) // 测试缓存请求参数值不一样
// };


export default {
getCaptcha: () => request.get('/captcha')
}
44 changes: 44 additions & 0 deletions src/global/http/cancelRepeatRquest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 取消重复请求
/* 假如用户重复点击按钮,先后提交了 A 和 B 这两个完全相同(考虑请求路径、方法、参数)的请求,我们可以从以下几种拦截方案中选择其一:
1. 取消 A 请求,只发出 B 请求(会导致A请求已经发出去,被后端处理了)
2. 取消 B 请求,只发出 A 请求
3. 取消 B 请求,只发出 A 请求,把收到的 A 请求的返回结果也作为 B 请求的返回结果
第3种方案需要做监听处理增加了复杂性,结合我们实际的业务需求,最后采用了第2种方案来实现,即:
只发第一个请求。在 A 请求还处于 pending 状态时,后发的所有与 A 重复的请求都取消,实际只发出 A 请求,直到 A 请求结束(成功/失败)才停止对这个请求的拦截。
*/
import Axios from 'axios';
import { generateReqKey } from './commonFuns';

// addPendingRequest :用于把当前请求信息添加到pendingRequest对象 中;
const pendingRequest = new Map(); // Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
export function addPendingRequest(config) {
if (config.cancelRequest) {
const requestKey = generateReqKey(config);
if (pendingRequest.has(requestKey)) {
config.cancelToken = new Axios.CancelToken(cancel => {
// cancel 函数的参数会作为 promise 的 error 被捕获
cancel(`${config.url} 请求已取消`);
});
} else {
config.cancelToken =
config.cancelToken ||
new Axios.CancelToken(cancel => {
pendingRequest.set(requestKey, cancel);
});
}
}
}

// removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
export function removePendingRequest(response) {
if (response && response.config && response.config.cancelRequest) {
const requestKey = generateReqKey(response.config);
// 判断是否有这个 key
if (pendingRequest.has(requestKey)) {
const cancelToken = pendingRequest.get(requestKey);
cancelToken(requestKey);
pendingRequest.delete(requestKey);
}
}
}

29 changes: 29 additions & 0 deletions src/global/http/commonFuns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Qs from 'qs';

// generateReqKey :用于根据当前请求的信息,生成请求 Key;
export function generateReqKey(config) {
// 响应的时候,response.config 中的data 是一个JSON字符串,所以需要转换一下
if (config && config.data && isJsonStr(config.data)) {
config.data = JSON.parse(config.data);
}
const { method, url, params, data } = config; // 请求方式,参数,请求地址,
return [method, url, Qs.stringify(params), Qs.stringify(data)].join('&'); // 拼接
}

// 判断一个字符串是否为JSON字符串
export let isJsonStr = str => {
if (typeof str == 'string') {
try {
let obj = JSON.parse(str);
if (typeof obj == 'object' && obj) {
return true;
} else {
return false;
}
} catch (e) {
console.log('error:' + str + '!!!' + e);
return false;
}
}
};

83 changes: 83 additions & 0 deletions src/global/http/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import security from '../security';
import framework from "../framework";
import Axios from 'axios';
import {addPendingRequest, removePendingRequest} from './cancelRepeatRquest'; // 取消重复请求
import {againRequest} from './requestAgainSend'; // 请求重发
import {requestInterceptor as cacheReqInterceptor, responseInterceptor as cacheResInterceptor} from './requestCache';
import router from "../router";

// 返回结果处理
// 自定义约定接口返回{code: xxx, data: xxx, msg:'err message'}
const responseHandle = {
0: response => {
return response.data;
},
401: response => {
window.$message.error('登录状态已过期,请重新登录!')
security.signOut()
router.push('/login')
},
default: response => {
window.$message.error(response.data.message)
return Promise.reject(response);
}
};

const axios = Axios.create({
baseURL: import.meta.env['VITE_APP_API'] || '',
timeout: 60000
});

// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// clientId
config.headers.clientId = framework.getTracker().clientId
// 请求头用于接口token 认证
security.getToken() && (config.headers['Authorization'] = security.getToken());

if (config.method.toLocaleLowerCase() === 'post' || config.method.toLocaleLowerCase() === 'put') {
// 参数统一处理,请求都使用data传参
config.data = config.data.data;
} else if (config.method.toLocaleLowerCase() === 'get' || config.method.toLocaleLowerCase() === 'delete') {
// 参数统一处理
config.params = config.data;
} else {
window.$message.error('不允许的请求方法:' + config.method);
}
// pendding 中的请求,后续请求不发送(由于存放的peddingMap 的key 和参数有关,所以放在参数处理之后)
addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中
// 请求缓存
cacheReqInterceptor(config, axios);
return config;
},
function (error) {
return Promise.reject(error);
}
);

// 添加响应拦截器
axios.interceptors.response.use(
response => {
// 响应正常时候就从pendingRequest对象中移除请求
removePendingRequest(response);
cacheResInterceptor(response);
return responseHandle[response.data.code === '' ? 'default' : response.data.code](response);
},
error => {
// 从pending 列表中移除请求
removePendingRequest(error.config || {});
// 需要特殊处理请求被取消的情况
if (!Axios.isCancel(error)) {
// 请求重发
return againRequest(error, axios);
}
// 请求缓存处理方式
if (Axios.isCancel(error) && error.message.data && error.message.data.config.cache) {
return Promise.resolve(error.message.data.data.data); // 返回结果数据
}
return Promise.reject(error);
}
);
export default axios;

38 changes: 38 additions & 0 deletions src/global/http/requestAgainSend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 实现 请求错误时重新发送接口
import { isJsonStr } from './commonFuns';
/**
* @param {失败信息} err
* @param {实例化的单例} axios
* @returns
*/
export function againRequest(err, axios) {
let config = err.config;
// config.retry 具体接口配置的重发次数
if (!config || !config.retry) return Promise.reject(err);

// 设置用于记录重试计数的变量 默认为0
config.__retryCount = config.__retryCount || 0;

// 判断是否超过了重试次数
if (config.__retryCount >= config.retry) {
return Promise.reject(err);
}
// 重试次数
config.__retryCount += 1;

// 延时处理
var backoff = new Promise(function(resolve) {
setTimeout(function() {
resolve();
}, config.retryDelay || 1000);
});
// 重新发起axios请求
return backoff.then(function() {
// 判断是否是JSON字符串
// TODO: 未确认config.data再重发时变为字符串的原因
if (config.data && isJsonStr(config.data)) {
config.data = JSON.parse(config.data);
}
return axios(config);
});
}
Loading

0 comments on commit 82bf213

Please sign in to comment.