@minilo/utils 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/config.js +20 -20
- package/dist/config/guider.js +55 -52
- package/dist/config/index.js +6 -6
- package/dist/config/storageManager.js +100 -92
- package/dist/config/types.js +2 -2
- package/dist/config/updateCssVariables.js +77 -79
- package/dist/constrant/index.js +11 -11
- package/dist/func/color.js +10 -10
- package/dist/func/common.js +58 -54
- package/dist/func/index.js +4 -4
- package/dist/func/merge.js +2 -2
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useLogout.d.ts +8 -0
- package/dist/hooks/useLogout.d.ts.map +1 -0
- package/dist/hooks/useLogout.js +55 -0
- package/dist/hooks/useLogout.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/request/index.js +123 -131
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/func/common.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* @return {*}
|
|
7
7
|
*/
|
|
8
8
|
export function isHttp(url) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const regex = /^https?:\/\//i;
|
|
10
|
+
return regex.test(url);
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* @description 递归查找当前path对应的所有层级路由,为面包屑提供数据
|
|
@@ -19,26 +19,27 @@ export function isHttp(url) {
|
|
|
19
19
|
* @return {*} {BreadcrumbItem[]}
|
|
20
20
|
*/
|
|
21
21
|
export function findLevelRoutes(menuList, targetPath, parentPaths = []) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
for (const item of menuList) {
|
|
23
|
+
// 当前项的完整路径(父级路径 + 当前path)
|
|
24
|
+
const currentPaths = [
|
|
25
|
+
...parentPaths,
|
|
26
|
+
{
|
|
27
|
+
path: item.path,
|
|
28
|
+
name: item.name
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
// 找到目标路径,返回完整层级
|
|
32
|
+
if (item.path === targetPath) {
|
|
33
|
+
return currentPaths;
|
|
34
|
+
}
|
|
35
|
+
// 有子菜单则递归查找
|
|
36
|
+
if (item.children && item.children.length) {
|
|
37
|
+
const result = findLevelRoutes(item.children, targetPath, currentPaths);
|
|
38
|
+
if (result.length)
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
34
41
|
}
|
|
35
|
-
//
|
|
36
|
-
if (item.children && item.children.length) {
|
|
37
|
-
const result = findLevelRoutes(item.children, targetPath, currentPaths)
|
|
38
|
-
if (result.length) return result
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return [] // 未找到
|
|
42
|
+
return []; // 未找到
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
45
|
* @description 查找菜单栏中当前path对应的菜单项
|
|
@@ -49,14 +50,16 @@ export function findLevelRoutes(menuList, targetPath, parentPaths = []) {
|
|
|
49
50
|
* @return {*} {(MenuDataItem | null)}
|
|
50
51
|
*/
|
|
51
52
|
export function findMenuItem(items, targetPath) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
for (const item of items) {
|
|
54
|
+
if (item.path === targetPath)
|
|
55
|
+
return item;
|
|
56
|
+
if (item.children) {
|
|
57
|
+
const found = findMenuItem(item.children, targetPath);
|
|
58
|
+
if (found)
|
|
59
|
+
return found;
|
|
60
|
+
}
|
|
57
61
|
}
|
|
58
|
-
|
|
59
|
-
return null
|
|
62
|
+
return null;
|
|
60
63
|
}
|
|
61
64
|
/**
|
|
62
65
|
* @description 将options数组转换为对象,渲染
|
|
@@ -67,15 +70,16 @@ export function findMenuItem(items, targetPath) {
|
|
|
67
70
|
* @return {*} {(Record<string | number, string>)}
|
|
68
71
|
*/
|
|
69
72
|
export function transOptionsToObject(options, inverse) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
const obj = {};
|
|
74
|
+
options.forEach((item) => {
|
|
75
|
+
if (!inverse) {
|
|
76
|
+
obj[item.value] = item.label;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
obj[item.label] = item.value;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return obj;
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
81
85
|
* @description 根据多层级键路径从对象中获取值
|
|
@@ -86,21 +90,21 @@ export function transOptionsToObject(options, inverse) {
|
|
|
86
90
|
* @returns {any} 路径对应的 value 或 defaultValue
|
|
87
91
|
*/
|
|
88
92
|
export function getNestedValue(obj, path, defaultValue) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
// 将路径按 '.' 分割成数组(支持处理空字符串和连续点的情况)
|
|
94
|
-
const keys = path.split('.').filter((key) => key !== '')
|
|
95
|
-
// 逐层访问对象属性
|
|
96
|
-
return keys.reduce((current, key) => {
|
|
97
|
-
// 如果当前值不是对象,直接返回默认值(避免访问非对象的属性)
|
|
98
|
-
if (typeof current !== 'object' || current === null) {
|
|
99
|
-
return defaultValue
|
|
93
|
+
// 处理边界情况:如果obj不是对象或path为空,直接返回默认值
|
|
94
|
+
if (typeof obj !== 'object' || obj === null || !path) {
|
|
95
|
+
return defaultValue;
|
|
100
96
|
}
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
// 将路径按 '.' 分割成数组(支持处理空字符串和连续点的情况)
|
|
98
|
+
const keys = path.split('.').filter((key) => key !== '');
|
|
99
|
+
// 逐层访问对象属性
|
|
100
|
+
return keys.reduce((current, key) => {
|
|
101
|
+
// 如果当前值不是对象,直接返回默认值(避免访问非对象的属性)
|
|
102
|
+
if (typeof current !== 'object' || current === null) {
|
|
103
|
+
return defaultValue;
|
|
104
|
+
}
|
|
105
|
+
// 访问下一级属性
|
|
106
|
+
return current[key] !== undefined ? current[key] : defaultValue;
|
|
107
|
+
}, obj);
|
|
104
108
|
}
|
|
105
109
|
/**
|
|
106
110
|
* @description 将驼峰命名法转换为连字符命名法
|
|
@@ -110,7 +114,7 @@ export function getNestedValue(obj, path, defaultValue) {
|
|
|
110
114
|
* @return {*}
|
|
111
115
|
*/
|
|
112
116
|
export function kebabCase(key) {
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
const result = key.replace(/([A-Z])/g, ' $1').trim();
|
|
118
|
+
return result.split(' ').join('-').toLowerCase();
|
|
115
119
|
}
|
|
116
|
-
//# sourceMappingURL=common.js.map
|
|
120
|
+
//# sourceMappingURL=common.js.map
|
package/dist/func/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './color'
|
|
2
|
-
export * from './merge'
|
|
3
|
-
export * from './common'
|
|
4
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
export * from './color';
|
|
2
|
+
export * from './merge';
|
|
3
|
+
export * from './common';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
package/dist/func/merge.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { defu as merge } from 'defu'
|
|
2
|
-
//# sourceMappingURL=merge.js.map
|
|
1
|
+
export { defu as merge } from 'defu';
|
|
2
|
+
//# sourceMappingURL=merge.js.map
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,aAAa,CAAA"}
|
package/dist/hooks/index.js
CHANGED
package/dist/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,uBAAuB,CAAA;AACrC,cAAc,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogout.d.ts","sourceRoot":"","sources":["../../hooks/useLogout.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,eAAe,MAAM,GAAG;;CAgDjD,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useRouter } from 'vue-router'
|
|
2
|
+
import { useUserStore, useRoutesStore, useConfigStore } from '@minilo/store'
|
|
3
|
+
import { ElMessageBox, ElMessage } from 'element-plus'
|
|
4
|
+
import { LOGIN_PATH } from '../constrant'
|
|
5
|
+
/**
|
|
6
|
+
* 登出功能 Hook
|
|
7
|
+
* @param getInitStore - 可选,获取 initStore 的函数
|
|
8
|
+
*/
|
|
9
|
+
export const useLogout = (getInitStore) => {
|
|
10
|
+
const router = useRouter()
|
|
11
|
+
const userStore = useUserStore()
|
|
12
|
+
const routesStore = useRoutesStore()
|
|
13
|
+
const configStore = useConfigStore()
|
|
14
|
+
/**
|
|
15
|
+
* 执行登出操作
|
|
16
|
+
* @param showConfirm 是否显示确认对话框,默认为 true
|
|
17
|
+
*/
|
|
18
|
+
const logout = async (showConfirm = true) => {
|
|
19
|
+
if (showConfirm) {
|
|
20
|
+
try {
|
|
21
|
+
await ElMessageBox.confirm('确定要退出登录吗?', '提示', {
|
|
22
|
+
confirmButtonText: '确定',
|
|
23
|
+
cancelButtonText: '取消',
|
|
24
|
+
type: 'warning'
|
|
25
|
+
})
|
|
26
|
+
} catch {
|
|
27
|
+
// 用户取消登出
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
userStore.logout()
|
|
33
|
+
routesStore.resetRoutes()
|
|
34
|
+
configStore.resetConfig()
|
|
35
|
+
if (getInitStore) {
|
|
36
|
+
const initStore = getInitStore()
|
|
37
|
+
initStore.resetRouters()
|
|
38
|
+
}
|
|
39
|
+
ElMessage.success('退出登录成功')
|
|
40
|
+
router.replace({
|
|
41
|
+
path: LOGIN_PATH,
|
|
42
|
+
query: {
|
|
43
|
+
redirect: encodeURIComponent(router.currentRoute.value.fullPath)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('登出失败:', error)
|
|
48
|
+
ElMessage.error('退出登录失败')
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
logout
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=useLogout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogout.js","sourceRoot":"","sources":["../../hooks/useLogout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,YAAwB,EAAE,EAAE;IACpD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC;;;OAGG;IACH,MAAM,MAAM,GAAG,KAAK,EAAE,WAAW,GAAG,IAAI,EAAE,EAAE;QAC1C,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE;oBAC5C,iBAAiB,EAAE,IAAI;oBACvB,gBAAgB,EAAE,IAAI;oBACtB,IAAI,EAAE,SAAS;iBAChB,CAAC,CAAA;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;gBACT,OAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,SAAS,CAAC,MAAM,EAAE,CAAA;YAClB,WAAW,CAAC,WAAW,EAAE,CAAA;YACzB,WAAW,CAAC,WAAW,EAAE,CAAA;YACzB,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;gBAChC,SAAS,CAAC,YAAY,EAAE,CAAA;YAC1B,CAAC;YACD,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;YAC3B,MAAM,CAAC,OAAO,CAAC;gBACb,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE;oBACL,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC;iBACjE;aACF,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAC7B,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAC3B,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,MAAM;KACP,CAAA;AACH,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default as cloneDeep } from 'lodash.clonedeep'
|
|
2
|
-
export * from './func'
|
|
3
|
-
export * from './config'
|
|
4
|
-
export * from './constrant'
|
|
5
|
-
export * from './request'
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
|
1
|
+
export { default as cloneDeep } from 'lodash.clonedeep';
|
|
2
|
+
export * from './func';
|
|
3
|
+
export * from './config';
|
|
4
|
+
export * from './constrant';
|
|
5
|
+
export * from './request';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default as cloneDeep } from 'lodash.clonedeep'
|
|
2
|
-
export * from './func'
|
|
3
|
-
export * from './config'
|
|
4
|
-
export * from './constrant'
|
|
5
|
-
export * from './request'
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
export { default as cloneDeep } from 'lodash.clonedeep';
|
|
2
|
+
export * from './func';
|
|
3
|
+
export * from './config';
|
|
4
|
+
export * from './constrant';
|
|
5
|
+
export * from './request';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
package/dist/request/index.js
CHANGED
|
@@ -1,159 +1,151 @@
|
|
|
1
|
-
import axios from 'axios'
|
|
2
|
-
import { ElMessage } from 'element-plus'
|
|
3
|
-
import { merge } from '../func'
|
|
4
|
-
export * from 'axios'
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { ElMessage } from 'element-plus';
|
|
3
|
+
import { merge } from '../func';
|
|
4
|
+
export * from 'axios';
|
|
5
5
|
/**
|
|
6
6
|
* 取消所有 pending 状态的请求
|
|
7
7
|
*/
|
|
8
8
|
export const cancelAllRequests = () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
9
|
+
pendingRequests.forEach((source) => {
|
|
10
|
+
source.cancel('所有请求已被取消');
|
|
11
|
+
});
|
|
12
|
+
pendingRequests.clear();
|
|
13
|
+
};
|
|
14
14
|
/**
|
|
15
15
|
* 根据URL取消相关请求
|
|
16
16
|
* @param {String} url 要取消请求的URL
|
|
17
17
|
*/
|
|
18
18
|
export const cancelRequestsByUrl = (url) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
19
|
+
Array.from(pendingRequests.entries()).forEach(([key, source]) => {
|
|
20
|
+
if (key.includes(url)) {
|
|
21
|
+
source.cancel(`与${url}相关的请求已被取消`);
|
|
22
|
+
pendingRequests.delete(key);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
26
|
// 创建请求实例
|
|
27
|
-
export const initRequestInstance = (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
baseURL: '/', // 从环境变量获取基础URL
|
|
34
|
-
timeout: 10000, // 超时时间
|
|
35
|
-
headers: {
|
|
36
|
-
'Content-Type': 'application/json;charset=utf-8'
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
const instance = axios.create(axiosConfig)
|
|
40
|
-
// 请求拦截器
|
|
41
|
-
instance.interceptors.request.use(
|
|
42
|
-
(config) => {
|
|
43
|
-
interceptorsRequestFn(config)
|
|
44
|
-
// 添加请求到pending列表,处理重复请求
|
|
45
|
-
addPendingRequest(config)
|
|
46
|
-
// 可以在这里添加其他请求处理逻辑,如请求加载动画等
|
|
47
|
-
return config
|
|
48
|
-
},
|
|
49
|
-
(error) => {
|
|
50
|
-
// 请求错误处理
|
|
51
|
-
return Promise.reject(error)
|
|
52
|
-
}
|
|
53
|
-
)
|
|
54
|
-
// 响应拦截器
|
|
55
|
-
instance.interceptors.response.use(
|
|
56
|
-
(response) => {
|
|
57
|
-
interceptorsResponseFn(response)
|
|
58
|
-
// 从pending列表移除请求
|
|
59
|
-
removePendingRequest(response.config)
|
|
60
|
-
const data = response.data
|
|
61
|
-
// 根据实际后端接口规范处理响应
|
|
62
|
-
if (data.code === 200) {
|
|
63
|
-
return Promise.resolve({
|
|
64
|
-
...response,
|
|
65
|
-
...data,
|
|
66
|
-
data: data.data
|
|
67
|
-
})
|
|
68
|
-
} else {
|
|
69
|
-
// 非成功状态,显示错误信息
|
|
70
|
-
ElMessage.error(data.msg || '请求失败')
|
|
71
|
-
return Promise.reject(new Error(data.msg || '请求失败'))
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
(error) => {
|
|
75
|
-
console.log('请求发生错误>>>>>>>>>>>>>>>>>>:', error)
|
|
76
|
-
// 请求完成后从pending列表移除
|
|
77
|
-
if (error.config) {
|
|
78
|
-
removePendingRequest(error.config)
|
|
79
|
-
}
|
|
80
|
-
// 处理取消请求的错误
|
|
81
|
-
if (axios.isCancel(error)) {
|
|
82
|
-
console.warn('请求已被取消:', error.message)
|
|
83
|
-
return Promise.reject(new Error('请求已被取消'))
|
|
84
|
-
}
|
|
85
|
-
// 处理网络错误
|
|
86
|
-
if (!window.navigator.onLine) {
|
|
87
|
-
ElMessage.error('网络连接已断开,请检查网络')
|
|
88
|
-
return Promise.reject(new Error('网络连接已断开'))
|
|
89
|
-
}
|
|
90
|
-
// 处理HTTP错误状态码
|
|
91
|
-
const { response } = error
|
|
92
|
-
if (response) {
|
|
93
|
-
switch (response.status) {
|
|
94
|
-
case 401:
|
|
95
|
-
ElMessage.error('身份验证失败,请重新登录')
|
|
96
|
-
// 可以在这里添加跳转到登录页的逻辑
|
|
97
|
-
break
|
|
98
|
-
case 403:
|
|
99
|
-
ElMessage.error('没有权限执行此操作')
|
|
100
|
-
break
|
|
101
|
-
case 404:
|
|
102
|
-
ElMessage.error('请求的资源不存在')
|
|
103
|
-
break
|
|
104
|
-
case 500:
|
|
105
|
-
ElMessage.error('服务器内部错误')
|
|
106
|
-
break
|
|
107
|
-
default:
|
|
108
|
-
ElMessage.error(`请求错误: ${response.status}`)
|
|
27
|
+
export const initRequestInstance = (extendConfig = {}, interceptorsRequestFn = () => { }, interceptorsResponseFn = () => { }) => {
|
|
28
|
+
const axiosConfig = merge({}, extendConfig, {
|
|
29
|
+
baseURL: '/', // 从环境变量获取基础URL
|
|
30
|
+
timeout: 10000, // 超时时间
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json;charset=utf-8'
|
|
109
33
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
34
|
+
});
|
|
35
|
+
const instance = axios.create(axiosConfig);
|
|
36
|
+
// 请求拦截器
|
|
37
|
+
instance.interceptors.request.use((config) => {
|
|
38
|
+
interceptorsRequestFn(config);
|
|
39
|
+
// 添加请求到pending列表,处理重复请求
|
|
40
|
+
addPendingRequest(config);
|
|
41
|
+
// 可以在这里添加其他请求处理逻辑,如请求加载动画等
|
|
42
|
+
return config;
|
|
43
|
+
}, (error) => {
|
|
44
|
+
// 请求错误处理
|
|
45
|
+
return Promise.reject(error);
|
|
46
|
+
});
|
|
47
|
+
// 响应拦截器
|
|
48
|
+
instance.interceptors.response.use((response) => {
|
|
49
|
+
interceptorsResponseFn(response);
|
|
50
|
+
// 从pending列表移除请求
|
|
51
|
+
removePendingRequest(response.config);
|
|
52
|
+
const data = response.data;
|
|
53
|
+
// 根据实际后端接口规范处理响应
|
|
54
|
+
if (data.code === 200) {
|
|
55
|
+
return Promise.resolve({
|
|
56
|
+
...response,
|
|
57
|
+
...data,
|
|
58
|
+
data: data.data
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// 非成功状态,显示错误信息
|
|
63
|
+
ElMessage.error(data.msg || '请求失败');
|
|
64
|
+
return Promise.reject(new Error(data.msg || '请求失败'));
|
|
65
|
+
}
|
|
66
|
+
}, (error) => {
|
|
67
|
+
console.log('请求发生错误>>>>>>>>>>>>>>>>>>:', error);
|
|
68
|
+
// 请求完成后从pending列表移除
|
|
69
|
+
if (error.config) {
|
|
70
|
+
removePendingRequest(error.config);
|
|
71
|
+
}
|
|
72
|
+
// 处理取消请求的错误
|
|
73
|
+
if (axios.isCancel(error)) {
|
|
74
|
+
console.warn('请求已被取消:', error.message);
|
|
75
|
+
return Promise.reject(new Error('请求已被取消'));
|
|
76
|
+
}
|
|
77
|
+
// 处理网络错误
|
|
78
|
+
if (!window.navigator.onLine) {
|
|
79
|
+
ElMessage.error('网络连接已断开,请检查网络');
|
|
80
|
+
return Promise.reject(new Error('网络连接已断开'));
|
|
81
|
+
}
|
|
82
|
+
// 处理HTTP错误状态码
|
|
83
|
+
const { response } = error;
|
|
84
|
+
if (response) {
|
|
85
|
+
switch (response.status) {
|
|
86
|
+
case 401:
|
|
87
|
+
ElMessage.error('身份验证失败,请重新登录');
|
|
88
|
+
// 可以在这里添加跳转到登录页的逻辑
|
|
89
|
+
break;
|
|
90
|
+
case 403:
|
|
91
|
+
ElMessage.error('没有权限执行此操作');
|
|
92
|
+
break;
|
|
93
|
+
case 404:
|
|
94
|
+
ElMessage.error('请求的资源不存在');
|
|
95
|
+
break;
|
|
96
|
+
case 500:
|
|
97
|
+
ElMessage.error('服务器内部错误');
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
ElMessage.error(`请求错误: ${response.status}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
ElMessage.error('请求失败,请稍后重试');
|
|
105
|
+
}
|
|
106
|
+
return Promise.reject(error);
|
|
107
|
+
});
|
|
108
|
+
return instance;
|
|
109
|
+
};
|
|
118
110
|
// 存储当前正在进行的请求
|
|
119
|
-
const pendingRequests = new Map()
|
|
111
|
+
const pendingRequests = new Map();
|
|
120
112
|
/**
|
|
121
113
|
* 生成请求唯一标识
|
|
122
114
|
* @param {Object} config 请求配置
|
|
123
115
|
* @returns {String} 唯一标识
|
|
124
116
|
*/
|
|
125
117
|
export const generateRequestKey = (config) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
118
|
+
const { method, url, params, data } = config;
|
|
119
|
+
// 序列化参数,确保相同参数生成相同key
|
|
120
|
+
const paramsStr = params ? JSON.stringify(params) : '';
|
|
121
|
+
const dataStr = data ? JSON.stringify(data) : '';
|
|
122
|
+
return `${method}-${url}-${paramsStr}-${dataStr}`;
|
|
123
|
+
};
|
|
132
124
|
/**
|
|
133
125
|
* 添加请求到pending列表
|
|
134
126
|
* @param {Object} config 请求配置
|
|
135
127
|
*/
|
|
136
128
|
export const addPendingRequest = (config) => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
129
|
+
const requestKey = generateRequestKey(config);
|
|
130
|
+
// 如果存在相同请求,则取消之前的请求
|
|
131
|
+
if (pendingRequests.has(requestKey)) {
|
|
132
|
+
const cancelToken = pendingRequests.get(requestKey);
|
|
133
|
+
cancelToken.cancel(`重复请求被取消: ${config.url}`);
|
|
134
|
+
pendingRequests.delete(requestKey);
|
|
135
|
+
}
|
|
136
|
+
// 创建新的取消令牌
|
|
137
|
+
const source = axios.CancelToken.source();
|
|
138
|
+
config.cancelToken = source.token;
|
|
139
|
+
pendingRequests.set(requestKey, source);
|
|
140
|
+
};
|
|
149
141
|
/**
|
|
150
142
|
* 从pending列表移除请求
|
|
151
143
|
* @param {Object} config 请求配置
|
|
152
144
|
*/
|
|
153
145
|
export const removePendingRequest = (config) => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
//# sourceMappingURL=index.js.map
|
|
146
|
+
const requestKey = generateRequestKey(config);
|
|
147
|
+
if (pendingRequests.has(requestKey)) {
|
|
148
|
+
pendingRequests.delete(requestKey);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=index.js.map
|