vue2server7 7.0.18 → 7.0.20
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/frontEnd/src/components/NumberRange.vue +95 -202
- package/frontEnd/src/pages/TablePage.vue +228 -162
- package/package.json +1 -1
- package/test/777 +24 -0
- package/test/1/main.ts +0 -52
- package/test/1/utils/charts.ts +0 -38
- package/test/1/utils/color.ts +0 -110
- package/test/1/utils/date.ts +0 -9
- package/test/1/utils/request/Axios.ts +0 -294
- package/test/1/utils/request/AxiosCancel.ts +0 -67
- package/test/1/utils/request/AxiosTransform.ts +0 -63
- package/test/1/utils/request/index.ts +0 -231
- package/test/1/utils/request/utils.ts +0 -53
- package/test/1/utils/route/constant.ts +0 -14
- package/test/1/utils/route/index.ts +0 -110
- package/test/1/utils/version-check.worker.ts +0 -58
- package/test/1/utils/version-update.ts +0 -150
- package/test/1/version-hot-update.md +0 -277
- package/test/1/vite-plugin-version.ts +0 -35
- package/test/1/vite.config.ts +0 -46
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AxiosError,
|
|
3
|
-
AxiosInstance,
|
|
4
|
-
AxiosRequestConfig,
|
|
5
|
-
AxiosRequestHeaders,
|
|
6
|
-
AxiosResponse,
|
|
7
|
-
InternalAxiosRequestConfig,
|
|
8
|
-
} from 'axios';
|
|
9
|
-
import axios from 'axios';
|
|
10
|
-
import cloneDeep from 'lodash/cloneDeep';
|
|
11
|
-
import debounce from 'lodash/debounce';
|
|
12
|
-
import isFunction from 'lodash/isFunction';
|
|
13
|
-
import throttle from 'lodash/throttle';
|
|
14
|
-
import { stringify } from 'qs';
|
|
15
|
-
|
|
16
|
-
import { ContentTypeEnum } from '@/constants';
|
|
17
|
-
import type { AxiosRequestConfigRetry, RequestOptions, Result } from '@/types/axios';
|
|
18
|
-
|
|
19
|
-
import { AxiosCanceler } from './AxiosCancel';
|
|
20
|
-
import type { CreateAxiosOptions } from './AxiosTransform';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Axios 模块
|
|
24
|
-
*/
|
|
25
|
-
export class VAxios {
|
|
26
|
-
/**
|
|
27
|
-
* Axios实例句柄
|
|
28
|
-
* @private
|
|
29
|
-
*/
|
|
30
|
-
private instance: AxiosInstance;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Axios配置
|
|
34
|
-
* @private
|
|
35
|
-
*/
|
|
36
|
-
private readonly options: CreateAxiosOptions;
|
|
37
|
-
|
|
38
|
-
constructor(options: CreateAxiosOptions) {
|
|
39
|
-
this.options = options;
|
|
40
|
-
this.instance = axios.create(options);
|
|
41
|
-
this.setupInterceptors();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 创建Axios实例
|
|
46
|
-
* @param config
|
|
47
|
-
* @private
|
|
48
|
-
*/
|
|
49
|
-
private createAxios(config: CreateAxiosOptions): void {
|
|
50
|
-
this.instance = axios.create(config);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 获取数据处理类
|
|
55
|
-
* @private
|
|
56
|
-
*/
|
|
57
|
-
private getTransform() {
|
|
58
|
-
const { transform } = this.options;
|
|
59
|
-
return transform;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 获取Axios实例
|
|
64
|
-
*/
|
|
65
|
-
getAxios(): AxiosInstance {
|
|
66
|
-
return this.instance;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 配置Axios
|
|
71
|
-
* @param config
|
|
72
|
-
*/
|
|
73
|
-
configAxios(config: CreateAxiosOptions) {
|
|
74
|
-
if (!this.instance) return;
|
|
75
|
-
this.createAxios(config);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* 设置公共头部信息
|
|
80
|
-
* @param headers
|
|
81
|
-
*/
|
|
82
|
-
setHeader(headers: Record<string, string>): void {
|
|
83
|
-
if (!this.instance) return;
|
|
84
|
-
Object.assign(this.instance.defaults.headers, headers);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 设置拦截器
|
|
89
|
-
* @private
|
|
90
|
-
*/
|
|
91
|
-
private setupInterceptors() {
|
|
92
|
-
const transform = this.getTransform();
|
|
93
|
-
if (!transform) return;
|
|
94
|
-
|
|
95
|
-
const { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } =
|
|
96
|
-
transform;
|
|
97
|
-
const axiosCanceler = new AxiosCanceler();
|
|
98
|
-
|
|
99
|
-
// 请求拦截器
|
|
100
|
-
this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
|
101
|
-
// 如果忽略取消令牌,则不会取消重复的请求
|
|
102
|
-
// @ts-expect-error 请求参数通过嵌套赋值
|
|
103
|
-
const { ignoreCancelToken } = config.requestOptions;
|
|
104
|
-
const ignoreCancel = ignoreCancelToken ?? this.options.requestOptions?.ignoreCancelToken;
|
|
105
|
-
if (!ignoreCancel) axiosCanceler.addPending(config);
|
|
106
|
-
|
|
107
|
-
if (requestInterceptors && isFunction(requestInterceptors)) {
|
|
108
|
-
config = requestInterceptors(config, this.options) as InternalAxiosRequestConfig;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return config;
|
|
112
|
-
}, undefined);
|
|
113
|
-
|
|
114
|
-
// 请求错误处理
|
|
115
|
-
if (requestInterceptorsCatch && isFunction(requestInterceptorsCatch)) {
|
|
116
|
-
this.instance.interceptors.request.use(undefined, requestInterceptorsCatch);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// 响应结果处理
|
|
120
|
-
this.instance.interceptors.response.use((res: AxiosResponse) => {
|
|
121
|
-
if (res) axiosCanceler.removePending(res.config);
|
|
122
|
-
if (responseInterceptors && isFunction(responseInterceptors)) {
|
|
123
|
-
res = responseInterceptors(res);
|
|
124
|
-
}
|
|
125
|
-
return res;
|
|
126
|
-
}, undefined);
|
|
127
|
-
|
|
128
|
-
// 响应错误处理
|
|
129
|
-
if (responseInterceptorsCatch && isFunction(responseInterceptorsCatch)) {
|
|
130
|
-
this.instance.interceptors.response.use(undefined, (error) => responseInterceptorsCatch(error, this.instance));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* 支持 FormData 请求格式
|
|
136
|
-
* @param config
|
|
137
|
-
*/
|
|
138
|
-
supportFormData(config: AxiosRequestConfig) {
|
|
139
|
-
const headers = config.headers || (this.options.headers as AxiosRequestHeaders);
|
|
140
|
-
const contentType = headers?.['Content-Type'] || headers?.['content-type'];
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
contentType !== ContentTypeEnum.FormURLEncoded ||
|
|
144
|
-
!Reflect.has(config, 'data') ||
|
|
145
|
-
config.method?.toUpperCase() === 'GET'
|
|
146
|
-
) {
|
|
147
|
-
return config;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
...config,
|
|
152
|
-
data: stringify(config.data, { arrayFormat: 'brackets' }),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 支持 params 序列化
|
|
158
|
-
* @param config
|
|
159
|
-
*/
|
|
160
|
-
supportParamsStringify(config: AxiosRequestConfig) {
|
|
161
|
-
const headers = config.headers || this.options.headers;
|
|
162
|
-
const contentType = headers?.['Content-Type'] || headers?.['content-type'];
|
|
163
|
-
|
|
164
|
-
if (contentType === ContentTypeEnum.FormURLEncoded || !Reflect.has(config, 'params')) {
|
|
165
|
-
return config;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return {
|
|
169
|
-
...config,
|
|
170
|
-
paramsSerializer: (params: any) => stringify(params, { arrayFormat: 'brackets' }),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
175
|
-
return this.request({ ...config, method: 'GET' }, options);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
179
|
-
return this.request({ ...config, method: 'POST' }, options);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
183
|
-
return this.request({ ...config, method: 'PUT' }, options);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
187
|
-
return this.request({ ...config, method: 'DELETE' }, options);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
patch<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
191
|
-
return this.request({ ...config, method: 'PATCH' }, options);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* 上传文件封装
|
|
196
|
-
* @param key 文件所属的key
|
|
197
|
-
* @param file 文件
|
|
198
|
-
* @param config 请求配置
|
|
199
|
-
* @param options
|
|
200
|
-
*/
|
|
201
|
-
upload<T = any>(key: string, file: File, config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
|
|
202
|
-
const params: FormData = config.params ?? new FormData();
|
|
203
|
-
params.append(key, file);
|
|
204
|
-
|
|
205
|
-
return this.request(
|
|
206
|
-
{
|
|
207
|
-
...config,
|
|
208
|
-
method: 'POST',
|
|
209
|
-
headers: {
|
|
210
|
-
'Content-Type': ContentTypeEnum.FormData,
|
|
211
|
-
},
|
|
212
|
-
params,
|
|
213
|
-
},
|
|
214
|
-
options,
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* 请求封装
|
|
220
|
-
* @param config
|
|
221
|
-
* @param options
|
|
222
|
-
*/
|
|
223
|
-
request<T = any>(config: AxiosRequestConfigRetry, options?: RequestOptions): Promise<T> {
|
|
224
|
-
const { requestOptions } = this.options;
|
|
225
|
-
|
|
226
|
-
if (requestOptions.throttle !== undefined && requestOptions.debounce !== undefined) {
|
|
227
|
-
throw new Error('throttle and debounce cannot be set at the same time');
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (requestOptions.throttle && requestOptions.throttle.delay !== 0) {
|
|
231
|
-
return new Promise((resolve) => {
|
|
232
|
-
throttle(() => resolve(this.synthesisRequest(config, options)), requestOptions.throttle.delay);
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (requestOptions.debounce && requestOptions.debounce.delay !== 0) {
|
|
237
|
-
return new Promise((resolve) => {
|
|
238
|
-
debounce(() => resolve(this.synthesisRequest(config, options)), requestOptions.debounce.delay);
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return this.synthesisRequest(config, options);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* 请求方法
|
|
247
|
-
* @private
|
|
248
|
-
*/
|
|
249
|
-
private async synthesisRequest<T = any>(config: AxiosRequestConfigRetry, options?: RequestOptions): Promise<T> {
|
|
250
|
-
let conf: CreateAxiosOptions = cloneDeep(config);
|
|
251
|
-
const transform = this.getTransform();
|
|
252
|
-
|
|
253
|
-
const { requestOptions } = this.options;
|
|
254
|
-
|
|
255
|
-
const opt: RequestOptions = { ...requestOptions, ...options };
|
|
256
|
-
|
|
257
|
-
const { beforeRequestHook, requestCatchHook, transformRequestHook } = transform || {};
|
|
258
|
-
if (beforeRequestHook && isFunction(beforeRequestHook)) {
|
|
259
|
-
conf = beforeRequestHook(conf, opt);
|
|
260
|
-
}
|
|
261
|
-
conf.requestOptions = opt;
|
|
262
|
-
|
|
263
|
-
conf = this.supportFormData(conf);
|
|
264
|
-
// 支持params数组参数格式化,因axios默认的toFormData即为brackets方式,无需配置paramsSerializer为qs,有需要可解除注释,参数参考qs文档
|
|
265
|
-
// conf = this.supportParamsStringify(conf);
|
|
266
|
-
|
|
267
|
-
return new Promise((resolve, reject) => {
|
|
268
|
-
this.instance
|
|
269
|
-
.request<any, AxiosResponse<Result>>(!config.retryCount ? conf : config)
|
|
270
|
-
.then((res: AxiosResponse<Result>) => {
|
|
271
|
-
if (transformRequestHook && isFunction(transformRequestHook)) {
|
|
272
|
-
try {
|
|
273
|
-
const ret = transformRequestHook(res, opt);
|
|
274
|
-
resolve(ret);
|
|
275
|
-
} catch (err) {
|
|
276
|
-
reject(err || new Error('请求错误!'));
|
|
277
|
-
}
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
resolve(res as unknown as Promise<T>);
|
|
281
|
-
})
|
|
282
|
-
.catch((e: Error | AxiosError) => {
|
|
283
|
-
if (requestCatchHook && isFunction(requestCatchHook)) {
|
|
284
|
-
reject(requestCatchHook(e, opt));
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
if (axios.isAxiosError(e)) {
|
|
288
|
-
// 在这里重写Axios的错误信息
|
|
289
|
-
}
|
|
290
|
-
reject(e);
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import type { AxiosRequestConfig, Canceler } from 'axios';
|
|
2
|
-
import axios from 'axios';
|
|
3
|
-
import isFunction from 'lodash/isFunction';
|
|
4
|
-
|
|
5
|
-
// 存储请求与取消令牌的键值对列表
|
|
6
|
-
let pendingMap = new Map<string, Canceler>();
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 获取请求Url
|
|
10
|
-
* @param config
|
|
11
|
-
*/
|
|
12
|
-
export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @description 请求管理器
|
|
16
|
-
*/
|
|
17
|
-
export class AxiosCanceler {
|
|
18
|
-
/**
|
|
19
|
-
* 添加请求到列表中
|
|
20
|
-
* @param config
|
|
21
|
-
*/
|
|
22
|
-
addPending(config: AxiosRequestConfig) {
|
|
23
|
-
this.removePending(config);
|
|
24
|
-
const url = getPendingUrl(config);
|
|
25
|
-
config.cancelToken =
|
|
26
|
-
config.cancelToken ||
|
|
27
|
-
new axios.CancelToken((cancel) => {
|
|
28
|
-
if (!pendingMap.has(url)) {
|
|
29
|
-
// 如果当前没有相同请求就添加
|
|
30
|
-
pendingMap.set(url, cancel);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 移除现有的所有请求
|
|
37
|
-
*/
|
|
38
|
-
removeAllPending() {
|
|
39
|
-
pendingMap.forEach((cancel) => {
|
|
40
|
-
if (cancel && isFunction(cancel)) cancel();
|
|
41
|
-
});
|
|
42
|
-
pendingMap.clear();
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* 移除指定请求
|
|
47
|
-
* @param config
|
|
48
|
-
*/
|
|
49
|
-
removePending(config: AxiosRequestConfig) {
|
|
50
|
-
const url = getPendingUrl(config);
|
|
51
|
-
|
|
52
|
-
if (pendingMap.has(url)) {
|
|
53
|
-
// If there is a current request identifier in pending,
|
|
54
|
-
// the current request needs to be cancelled and removed
|
|
55
|
-
const cancel = pendingMap.get(url);
|
|
56
|
-
if (cancel) cancel(url);
|
|
57
|
-
pendingMap.delete(url);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 重置
|
|
63
|
-
*/
|
|
64
|
-
reset() {
|
|
65
|
-
pendingMap = new Map<string, Canceler>();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
-
|
|
3
|
-
import type { RequestOptions, Result } from '@/types/axios';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @description 创建Axios实例配置
|
|
7
|
-
*/
|
|
8
|
-
export interface CreateAxiosOptions extends AxiosRequestConfig {
|
|
9
|
-
/**
|
|
10
|
-
* 请求验证方案
|
|
11
|
-
*
|
|
12
|
-
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
|
13
|
-
*/
|
|
14
|
-
authenticationScheme?: string;
|
|
15
|
-
/**
|
|
16
|
-
* 请求数据处理
|
|
17
|
-
*/
|
|
18
|
-
transform?: AxiosTransform;
|
|
19
|
-
/**
|
|
20
|
-
* 请求配置
|
|
21
|
-
*/
|
|
22
|
-
requestOptions?: RequestOptions;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Axios请求数据处理 抽象类
|
|
27
|
-
*/
|
|
28
|
-
export abstract class AxiosTransform {
|
|
29
|
-
/**
|
|
30
|
-
* 请求前钩子
|
|
31
|
-
*/
|
|
32
|
-
beforeRequestHook?: (_config: AxiosRequestConfig, _options: RequestOptions) => AxiosRequestConfig;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 数据处理前钩子
|
|
36
|
-
*/
|
|
37
|
-
transformRequestHook?: <T = any>(_res: AxiosResponse<Result>, _options: RequestOptions) => T;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 请求失败钩子
|
|
41
|
-
*/
|
|
42
|
-
requestCatchHook?: <T = any>(_e: Error | AxiosError, _options: RequestOptions) => Promise<T>;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* 请求拦截器
|
|
46
|
-
*/
|
|
47
|
-
requestInterceptors?: (_config: AxiosRequestConfig, _options: CreateAxiosOptions) => AxiosRequestConfig;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 响应拦截器
|
|
51
|
-
*/
|
|
52
|
-
responseInterceptors?: (_res: AxiosResponse) => AxiosResponse;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 请求拦截器错误处理
|
|
56
|
-
*/
|
|
57
|
-
requestInterceptorsCatch?: (_error: AxiosError) => void;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 响应拦截器错误处理
|
|
61
|
-
*/
|
|
62
|
-
responseInterceptorsCatch?: (_error: AxiosError, _instance: AxiosInstance) => void;
|
|
63
|
-
}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
// axios配置 可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
|
|
2
|
-
import type { AxiosInstance } from 'axios';
|
|
3
|
-
import isString from 'lodash/isString';
|
|
4
|
-
import merge from 'lodash/merge';
|
|
5
|
-
import { MessagePlugin } from 'tdesign-vue-next';
|
|
6
|
-
|
|
7
|
-
import { ContentTypeEnum } from '@/constants';
|
|
8
|
-
import { useUserStore } from '@/store';
|
|
9
|
-
|
|
10
|
-
import { VAxios } from './Axios';
|
|
11
|
-
import type { AxiosTransform, CreateAxiosOptions } from './AxiosTransform';
|
|
12
|
-
import { formatRequestDate, joinTimestamp, setObjToUrlParams } from './utils';
|
|
13
|
-
|
|
14
|
-
const host = import.meta.env.VITE_IS_REQUEST_PROXY !== 'true' ? '' : import.meta.env.VITE_API_URL;
|
|
15
|
-
|
|
16
|
-
// 数据处理,方便区分多种处理方式
|
|
17
|
-
const transform: AxiosTransform = {
|
|
18
|
-
// 处理请求数据。如果数据不是预期格式,可直接抛出错误
|
|
19
|
-
transformRequestHook: (res, options) => {
|
|
20
|
-
const { isTransformResponse, isReturnNativeResponse } = options;
|
|
21
|
-
|
|
22
|
-
// 如果204无内容直接返回
|
|
23
|
-
const method = res.config.method?.toLowerCase();
|
|
24
|
-
if (res.status === 204 && ['put', 'patch', 'delete'].includes(method)) {
|
|
25
|
-
return res;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
|
29
|
-
if (isReturnNativeResponse) {
|
|
30
|
-
return res;
|
|
31
|
-
}
|
|
32
|
-
// 不进行任何处理,直接返回
|
|
33
|
-
// 用于页面代码可能需要直接获取code,data,message这些信息时开启
|
|
34
|
-
if (!isTransformResponse) {
|
|
35
|
-
return res.data;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 错误的时候返回
|
|
39
|
-
const { data } = res;
|
|
40
|
-
if (!data) {
|
|
41
|
-
throw new Error('请求接口错误');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// 这里 code为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
|
|
45
|
-
const { code } = data;
|
|
46
|
-
|
|
47
|
-
// 这里逻辑可以根据项目进行修改
|
|
48
|
-
const hasSuccess = data && code === 200;
|
|
49
|
-
if (hasSuccess) {
|
|
50
|
-
return data.data;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
throw new Error(`请求接口错误, 错误码: ${code}`);
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
// 请求前处理配置
|
|
57
|
-
beforeRequestHook: (config, options) => {
|
|
58
|
-
const { apiUrl, isJoinPrefix, urlPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;
|
|
59
|
-
|
|
60
|
-
// 添加接口前缀
|
|
61
|
-
if (isJoinPrefix && urlPrefix && isString(urlPrefix)) {
|
|
62
|
-
config.url = `${urlPrefix}${config.url}`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 将baseUrl拼接
|
|
66
|
-
if (apiUrl && isString(apiUrl)) {
|
|
67
|
-
config.url = `${apiUrl}${config.url}`;
|
|
68
|
-
}
|
|
69
|
-
const params = config.params || {};
|
|
70
|
-
const data = config.data || false;
|
|
71
|
-
|
|
72
|
-
if (formatDate && data && !isString(data)) {
|
|
73
|
-
formatRequestDate(data);
|
|
74
|
-
}
|
|
75
|
-
if (config.method?.toUpperCase() === 'GET') {
|
|
76
|
-
if (!isString(params)) {
|
|
77
|
-
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
|
|
78
|
-
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
|
|
79
|
-
} else {
|
|
80
|
-
// 兼容restful风格
|
|
81
|
-
config.url = `${config.url + params}${joinTimestamp(joinTime, true)}`;
|
|
82
|
-
config.params = undefined;
|
|
83
|
-
}
|
|
84
|
-
} else if (!isString(params)) {
|
|
85
|
-
if (formatDate) {
|
|
86
|
-
formatRequestDate(params);
|
|
87
|
-
}
|
|
88
|
-
if (
|
|
89
|
-
Reflect.has(config, 'data') &&
|
|
90
|
-
config.data &&
|
|
91
|
-
(Object.keys(config.data).length > 0 || data instanceof FormData)
|
|
92
|
-
) {
|
|
93
|
-
config.data = data;
|
|
94
|
-
config.params = params;
|
|
95
|
-
} else {
|
|
96
|
-
// 非GET请求如果没有提供data,则将params视为data
|
|
97
|
-
config.data = params;
|
|
98
|
-
config.params = undefined;
|
|
99
|
-
}
|
|
100
|
-
if (joinParamsToUrl) {
|
|
101
|
-
config.url = setObjToUrlParams(config.url as string, { ...config.params, ...config.data });
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
// 兼容restful风格
|
|
105
|
-
config.url += params;
|
|
106
|
-
config.params = undefined;
|
|
107
|
-
}
|
|
108
|
-
return config;
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
// 请求拦截器处理
|
|
112
|
-
requestInterceptors: (config, options) => {
|
|
113
|
-
// 请求之前处理config
|
|
114
|
-
const userStore = useUserStore();
|
|
115
|
-
const { token } = userStore;
|
|
116
|
-
config.headers['x-skip-crypto'] = 'dev_debug_token_123';
|
|
117
|
-
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
|
|
118
|
-
// jwt token
|
|
119
|
-
(config as Recordable).headers.Authorization = options.authenticationScheme
|
|
120
|
-
? `${options.authenticationScheme} ${token}`
|
|
121
|
-
: token;
|
|
122
|
-
}
|
|
123
|
-
return config;
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
// 响应拦截器处理
|
|
127
|
-
responseInterceptors: (res) => {
|
|
128
|
-
return res;
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
// 响应错误处理
|
|
132
|
-
responseInterceptorsCatch: async (error: any, instance: AxiosInstance) => {
|
|
133
|
-
const { config, response } = error;
|
|
134
|
-
// 获取服务器返回的错误数据
|
|
135
|
-
const errorData = response?.data;
|
|
136
|
-
const errorMessage = errorData?.message || error.message || '请求失败';
|
|
137
|
-
|
|
138
|
-
// 401 未授权:清除 token 并跳转登录页
|
|
139
|
-
if (response?.status === 401) {
|
|
140
|
-
const userStore = useUserStore();
|
|
141
|
-
userStore.logout();
|
|
142
|
-
const currentPath = window.location.hash ? window.location.hash.slice(1) : window.location.pathname;
|
|
143
|
-
if (currentPath !== '/login') {
|
|
144
|
-
window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`;
|
|
145
|
-
}
|
|
146
|
-
return Promise.reject(error);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// 弹出错误提示
|
|
150
|
-
await MessagePlugin.error(errorMessage);
|
|
151
|
-
|
|
152
|
-
if (!config || !config.requestOptions.retry) {
|
|
153
|
-
// 将错误信息附加到 error 对象上,方便调用方获取
|
|
154
|
-
error.message = errorMessage;
|
|
155
|
-
error.data = errorData;
|
|
156
|
-
return Promise.reject(error);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
config.retryCount = config.retryCount || 0;
|
|
160
|
-
|
|
161
|
-
if (config.retryCount >= config.requestOptions.retry.count) {
|
|
162
|
-
error.message = errorMessage;
|
|
163
|
-
error.data = errorData;
|
|
164
|
-
return Promise.reject(error);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
config.retryCount += 1;
|
|
168
|
-
|
|
169
|
-
const backoff = new Promise((resolve) => {
|
|
170
|
-
setTimeout(() => {
|
|
171
|
-
resolve(config);
|
|
172
|
-
}, config.requestOptions.retry.delay || 1);
|
|
173
|
-
});
|
|
174
|
-
config.headers = { ...config.headers, 'Content-Type': ContentTypeEnum.Json };
|
|
175
|
-
return backoff.then((config) => instance.request(config));
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
|
180
|
-
return new VAxios(
|
|
181
|
-
merge(
|
|
182
|
-
<CreateAxiosOptions>{
|
|
183
|
-
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
|
|
184
|
-
// 例如: authenticationScheme: 'Bearer'
|
|
185
|
-
authenticationScheme: '',
|
|
186
|
-
// 超时
|
|
187
|
-
timeout: 10 * 1000,
|
|
188
|
-
// 携带Cookie
|
|
189
|
-
withCredentials: false,
|
|
190
|
-
// 头信息
|
|
191
|
-
headers: { 'Content-Type': ContentTypeEnum.Json },
|
|
192
|
-
// 数据处理方式
|
|
193
|
-
transform,
|
|
194
|
-
// 配置项,下面的选项都可以在独立的接口请求中覆盖
|
|
195
|
-
requestOptions: {
|
|
196
|
-
// 接口地址
|
|
197
|
-
apiUrl: host,
|
|
198
|
-
// 是否自动添加接口前缀
|
|
199
|
-
isJoinPrefix: true,
|
|
200
|
-
// 接口前缀
|
|
201
|
-
// 例如: https://www.baidu.com/api
|
|
202
|
-
// urlPrefix: '/api'
|
|
203
|
-
urlPrefix: import.meta.env.VITE_API_URL_PREFIX,
|
|
204
|
-
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
|
|
205
|
-
isReturnNativeResponse: false,
|
|
206
|
-
// 需要对返回数据进行处理
|
|
207
|
-
isTransformResponse: true,
|
|
208
|
-
// post请求的时候添加参数到url
|
|
209
|
-
joinParamsToUrl: false,
|
|
210
|
-
// 格式化提交参数时间
|
|
211
|
-
formatDate: true,
|
|
212
|
-
// 是否加入时间戳
|
|
213
|
-
joinTime: true,
|
|
214
|
-
// 是否忽略请求取消令牌
|
|
215
|
-
// 如果启用,则重复请求时不进行处理
|
|
216
|
-
// 如果禁用,则重复请求时会取消当前请求
|
|
217
|
-
ignoreCancelToken: true,
|
|
218
|
-
// 是否携带token
|
|
219
|
-
withToken: true,
|
|
220
|
-
// 重试
|
|
221
|
-
retry: {
|
|
222
|
-
count: 0,
|
|
223
|
-
delay: 1000,
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
opt || {},
|
|
228
|
-
),
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
export const request = createAxios();
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import isObject from 'lodash/isObject';
|
|
2
|
-
import isString from 'lodash/isString';
|
|
3
|
-
|
|
4
|
-
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
|
5
|
-
|
|
6
|
-
export function joinTimestamp<T extends boolean>(_join: boolean, _restful: T): T extends true ? string : object;
|
|
7
|
-
|
|
8
|
-
export function joinTimestamp(join: boolean, restful = false): string | object {
|
|
9
|
-
if (!join) {
|
|
10
|
-
return restful ? '' : {};
|
|
11
|
-
}
|
|
12
|
-
const now = new Date().getTime();
|
|
13
|
-
if (restful) {
|
|
14
|
-
return `?_t=${now}`;
|
|
15
|
-
}
|
|
16
|
-
return { _t: now };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// 格式化提交参数时间
|
|
20
|
-
export function formatRequestDate(params: Recordable) {
|
|
21
|
-
if (Object.prototype.toString.call(params) !== '[object Object]') {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
for (const key in params) {
|
|
26
|
-
if (params[key] && params[key]._isAMomentObject) {
|
|
27
|
-
params[key] = params[key].format(DATE_TIME_FORMAT);
|
|
28
|
-
}
|
|
29
|
-
if (isString(key)) {
|
|
30
|
-
const value = params[key];
|
|
31
|
-
if (value) {
|
|
32
|
-
try {
|
|
33
|
-
params[key] = isString(value) ? value.trim() : value;
|
|
34
|
-
} catch (error: any) {
|
|
35
|
-
throw new Error(error);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
if (isObject(params[key])) {
|
|
40
|
-
formatRequestDate(params[key]);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 将对象转为Url参数
|
|
46
|
-
export function setObjToUrlParams(baseUrl: string, obj: { [index: string]: any }): string {
|
|
47
|
-
let parameters = '';
|
|
48
|
-
for (const key in obj) {
|
|
49
|
-
parameters += `${key}=${encodeURIComponent(obj[key])}&`;
|
|
50
|
-
}
|
|
51
|
-
parameters = parameters.replace(/&$/, '');
|
|
52
|
-
return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters;
|
|
53
|
-
}
|