@jetlinks-web/core 2.2.19 → 2.3.0
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/index.d.ts +213 -51
- package/dist/index.mjs +2 -3
- package/package.json +3 -3
- package/src/axios.ts +528 -267
- package/src/fetch.ts +225 -195
- package/src/type.ts +14 -5
package/src/axios.ts
CHANGED
|
@@ -1,354 +1,556 @@
|
|
|
1
1
|
import { TOKEN_KEY, BASE_API, LOCAL_BASE_API } from '@jetlinks-web/constants'
|
|
2
|
-
import {getToken, randomString} from '@jetlinks-web/utils'
|
|
2
|
+
import { getToken, randomString } from '@jetlinks-web/utils'
|
|
3
3
|
import axios from 'axios'
|
|
4
|
+
import type { AxiosInstance } from 'axios'
|
|
5
|
+
import { isFunction, isObject } from 'lodash-es'
|
|
6
|
+
|
|
4
7
|
import type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
handleReconnect: () => Promise.resolve(),
|
|
25
|
-
isCreateTokenRefresh: false
|
|
8
|
+
Options,
|
|
9
|
+
ExpandRequestConfig,
|
|
10
|
+
ExpandAxiosResponse,
|
|
11
|
+
AxiosResponseRewrite,
|
|
12
|
+
ExpandAxiosError,
|
|
13
|
+
RequestOptions,
|
|
14
|
+
PageResult,
|
|
15
|
+
UpdateResult
|
|
16
|
+
} from './type'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 扩展的 Options 接口,添加重复请求控制
|
|
20
|
+
*/
|
|
21
|
+
export interface ExtendedOptions extends Options {
|
|
22
|
+
/**
|
|
23
|
+
* 是否取消重复请求,只保留最后一次
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
cancelDuplicateRequests?: boolean
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* AxiosService 类 - 封装所有 axios 相关功能
|
|
31
|
+
*/
|
|
32
|
+
export class AxiosService {
|
|
33
|
+
private instance: AxiosInstance | null = null
|
|
34
|
+
private options: ExtendedOptions
|
|
35
|
+
private failedQueue: Array<{ resolve: (token: string) => void; reject: (error: any) => void }> = []
|
|
36
|
+
private isRefreshing = false
|
|
37
|
+
private pendingRequests = new Map<string, AbortController>()
|
|
38
|
+
private isApp = (window as any).__MICRO_APP_ENVIRONMENT__
|
|
39
|
+
|
|
40
|
+
constructor(options?: Partial<ExtendedOptions>) {
|
|
41
|
+
this.options = {
|
|
42
|
+
filter_url: [],
|
|
43
|
+
code: 200,
|
|
44
|
+
codeKey: 'status',
|
|
45
|
+
timeout: 1000 * 15,
|
|
46
|
+
handleRequest: undefined,
|
|
47
|
+
handleResponse: undefined,
|
|
48
|
+
handleError: undefined,
|
|
49
|
+
langKey: 'lang',
|
|
50
|
+
requestOptions: (config) => ({}),
|
|
51
|
+
tokenExpiration: () => {},
|
|
52
|
+
handleReconnect: () => Promise.resolve(),
|
|
53
|
+
isCreateTokenRefresh: false,
|
|
54
|
+
cancelDuplicateRequests: false, // 默认关闭
|
|
55
|
+
...options
|
|
56
|
+
}
|
|
30
57
|
|
|
31
|
-
|
|
58
|
+
// 如果已经存在全局实例,使用它
|
|
59
|
+
if ((window as any).JetlinksCore?.instance) {
|
|
60
|
+
this.instance = (window as any).JetlinksCore.instance
|
|
61
|
+
}
|
|
62
|
+
}
|
|
32
63
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
64
|
+
/**
|
|
65
|
+
* 初始化 axios 实例
|
|
66
|
+
*/
|
|
67
|
+
initialize(options?: Partial<ExtendedOptions>): void {
|
|
68
|
+
if (options) {
|
|
69
|
+
this.options = { ...this.options, ...options }
|
|
70
|
+
}
|
|
36
71
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
72
|
+
this.instance = axios.create({
|
|
73
|
+
withCredentials: false,
|
|
74
|
+
timeout: this.options.timeout,
|
|
75
|
+
baseURL: BASE_API
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
this.instance.interceptors.request.use(
|
|
79
|
+
(config) => this.handleRequest(config as ExpandRequestConfig),
|
|
80
|
+
(error) => this.errorHandler(error)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
this.instance.interceptors.response.use(
|
|
84
|
+
(response) => this.handleResponse(response as unknown as ExpandAxiosResponse),
|
|
85
|
+
(error) => this.errorHandler(error as ExpandAxiosError<any>)
|
|
86
|
+
)
|
|
40
87
|
}
|
|
41
88
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
89
|
+
/**
|
|
90
|
+
* 获取 axios 实例
|
|
91
|
+
*/
|
|
92
|
+
getInstance(): AxiosInstance {
|
|
93
|
+
if (!this.instance) {
|
|
94
|
+
this.initialize()
|
|
95
|
+
}
|
|
96
|
+
return this.instance!
|
|
97
|
+
}
|
|
48
98
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
99
|
+
/**
|
|
100
|
+
* 生成请求的唯一标识
|
|
101
|
+
* 如果启用了 cancelDuplicateRequests,则基于 method + url + params/data
|
|
102
|
+
* 否则使用随机字符串
|
|
103
|
+
*/
|
|
104
|
+
private generateRequestKey(config: ExpandRequestConfig): string {
|
|
105
|
+
|
|
106
|
+
// 统一接口请求的唯一标识
|
|
107
|
+
const method = config.method?.toUpperCase() || 'GET'
|
|
108
|
+
const url = config.url || ''
|
|
109
|
+
|
|
110
|
+
// 序列化参数,用于判断是否为同一请求
|
|
111
|
+
const params = config.params || {}
|
|
112
|
+
const data = config.data || {}
|
|
113
|
+
const payload = method === 'GET' ? params : data
|
|
114
|
+
|
|
115
|
+
// 生成稳定的请求标识
|
|
116
|
+
let payloadStr = ''
|
|
117
|
+
try {
|
|
118
|
+
payloadStr = JSON.stringify(payload, Object.keys(payload).sort())
|
|
119
|
+
} catch {
|
|
120
|
+
payloadStr = randomString(16) // 降级为随机标识
|
|
121
|
+
}
|
|
54
122
|
|
|
55
|
-
|
|
56
|
-
config.headers[_options.langKey] = lang
|
|
123
|
+
return `${method}:${url}:${payloadStr}`
|
|
57
124
|
}
|
|
58
125
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
126
|
+
/**
|
|
127
|
+
* 记录请求 - 支持 AbortController
|
|
128
|
+
*/
|
|
129
|
+
private requestRecords(config: ExpandRequestConfig): void {
|
|
130
|
+
if (!this.options.cancelDuplicateRequests) {
|
|
131
|
+
return
|
|
132
|
+
}
|
|
63
133
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
134
|
+
const key = this.generateRequestKey(config)
|
|
135
|
+
|
|
136
|
+
// 如果启用了取消重复请求,且存在相同的请求,则取消前一个
|
|
137
|
+
if (this.pendingRequests.has(key)) {
|
|
138
|
+
this.pendingRequests.get(key)?.abort()
|
|
139
|
+
this.pendingRequests.delete(key)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const controller = new AbortController()
|
|
143
|
+
config.signal = controller.signal
|
|
144
|
+
config.__requestKey = key
|
|
70
145
|
|
|
71
|
-
|
|
72
|
-
config.headers[TOKEN_KEY] = token
|
|
146
|
+
this.pendingRequests.set(key, controller)
|
|
73
147
|
}
|
|
74
148
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
149
|
+
/**
|
|
150
|
+
* 请求拦截器处理
|
|
151
|
+
*/
|
|
152
|
+
private handleRequest(config: ExpandRequestConfig): ExpandRequestConfig {
|
|
153
|
+
this.requestRecords(config)
|
|
154
|
+
const token = getToken()
|
|
155
|
+
const lang = localStorage.getItem(this.options.langKey!)
|
|
156
|
+
const localBaseApi = localStorage.getItem(LOCAL_BASE_API)
|
|
157
|
+
|
|
158
|
+
if (lang) {
|
|
159
|
+
config.headers[this.options.langKey!] = lang
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (localBaseApi && !config.baseURL) {
|
|
163
|
+
const _url = config.url!.startsWith('/') ? config.url : `/${config.url}`
|
|
164
|
+
config.url = localBaseApi + _url
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 没有token,并且该接口需要token校验
|
|
168
|
+
if (!token && !this.options.filter_url?.some((url) => config.url?.includes(url))) {
|
|
169
|
+
this.options.tokenExpiration?.()
|
|
170
|
+
return config
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!config.headers[TOKEN_KEY]) {
|
|
174
|
+
config.headers[TOKEN_KEY] = token
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (this.options.requestOptions && isFunction(this.options.requestOptions)) {
|
|
178
|
+
const extraOptions = this.options.requestOptions(config)
|
|
179
|
+
if (extraOptions && isObject(extraOptions)) {
|
|
180
|
+
for (const key in extraOptions) {
|
|
181
|
+
config[key] = extraOptions[key]
|
|
182
|
+
}
|
|
80
183
|
}
|
|
81
184
|
}
|
|
185
|
+
|
|
186
|
+
return config
|
|
82
187
|
}
|
|
83
188
|
|
|
84
|
-
|
|
85
|
-
|
|
189
|
+
/**
|
|
190
|
+
* 响应拦截器处理
|
|
191
|
+
*/
|
|
192
|
+
private handleResponse(response: ExpandAxiosResponse): any {
|
|
193
|
+
const __key = response.config?.__requestKey
|
|
194
|
+
if (__key) {
|
|
195
|
+
this.pendingRequests.delete(__key)
|
|
196
|
+
}
|
|
86
197
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
198
|
+
if (this.options.handleResponse && isFunction(this.options.handleResponse)) {
|
|
199
|
+
return this.options.handleResponse(response)
|
|
200
|
+
}
|
|
91
201
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
202
|
+
if (response.data instanceof ArrayBuffer) {
|
|
203
|
+
return response
|
|
204
|
+
}
|
|
96
205
|
|
|
97
|
-
|
|
98
|
-
return response
|
|
99
|
-
}
|
|
206
|
+
const status = response.data[this.options.codeKey || 'status']
|
|
100
207
|
|
|
101
|
-
|
|
208
|
+
// 增加业务接口处理成功判断方式,只需要判断返回参数包含:success为true
|
|
209
|
+
if (
|
|
210
|
+
typeof response.data === 'object' &&
|
|
211
|
+
typeof response.data.success === 'undefined'
|
|
212
|
+
) {
|
|
213
|
+
response.data.success = status === this.options.code
|
|
214
|
+
}
|
|
102
215
|
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
typeof response.data === 'object' &&
|
|
106
|
-
typeof response.data.success === 'undefined'
|
|
107
|
-
) {
|
|
108
|
-
response.data.success = status === _options.code
|
|
216
|
+
return response.data
|
|
109
217
|
}
|
|
110
218
|
|
|
111
|
-
|
|
112
|
-
|
|
219
|
+
/**
|
|
220
|
+
* Token 刷新处理
|
|
221
|
+
*/
|
|
222
|
+
private async createTokenRefreshHandler(err: ExpandAxiosError<any>): Promise<any> {
|
|
223
|
+
const originalRequest = err.config!
|
|
224
|
+
|
|
225
|
+
if (this.isRefreshing) {
|
|
226
|
+
// 记录之后失败的请求
|
|
227
|
+
return new Promise((resolve, reject) => {
|
|
228
|
+
this.failedQueue.push({ resolve, reject })
|
|
229
|
+
})
|
|
230
|
+
.then((_token) => {
|
|
231
|
+
if (originalRequest.signal?.aborted) {
|
|
232
|
+
return Promise.reject(new axios.Cancel('Request aborted'))
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
originalRequest.headers[TOKEN_KEY] = _token
|
|
236
|
+
return this.instance!(originalRequest)
|
|
237
|
+
})
|
|
238
|
+
.catch((err) => Promise.reject(err))
|
|
239
|
+
}
|
|
113
240
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
failedQueue.forEach(a => a.resolve(token));
|
|
132
|
-
return instance(originalRequest);
|
|
241
|
+
originalRequest._retry = true
|
|
242
|
+
this.isRefreshing = true
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const loginResult = await this.options.handleReconnect?.()
|
|
246
|
+
if (loginResult) {
|
|
247
|
+
const token = getToken() // 更新请求头, 修改全部的token
|
|
248
|
+
originalRequest.headers[TOKEN_KEY] = token
|
|
249
|
+
this.failedQueue.forEach((a) => a.resolve(token))
|
|
250
|
+
return this.instance!(originalRequest)
|
|
251
|
+
}
|
|
252
|
+
} catch (err) {
|
|
253
|
+
this.failedQueue.forEach((cb) => cb.reject(err))
|
|
254
|
+
throw err
|
|
255
|
+
} finally {
|
|
256
|
+
this.failedQueue = []
|
|
257
|
+
this.isRefreshing = false
|
|
133
258
|
}
|
|
134
|
-
} catch (err) {
|
|
135
|
-
failedQueue.forEach(cb => cb.reject(err));
|
|
136
|
-
throw err;
|
|
137
|
-
} finally {
|
|
138
|
-
failedQueue = [];
|
|
139
|
-
isRefreshing = false;
|
|
140
259
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
case 403:
|
|
151
|
-
case 500:
|
|
152
|
-
description = (`${data?.message}`).substring(0, 90)
|
|
153
|
-
break;
|
|
154
|
-
case 401:
|
|
155
|
-
description = err.response.data.result?.text || '用户未登录';
|
|
156
|
-
_options.tokenExpiration?.(err)
|
|
157
|
-
if(_options.isCreateTokenRefresh){
|
|
158
|
-
return createTokenRefreshHandler(err)
|
|
159
|
-
}
|
|
160
|
-
break;
|
|
161
|
-
case 404:
|
|
162
|
-
description = err?.response?.data?.message || `${data?.error} ${data?.path}`
|
|
163
|
-
break;
|
|
164
|
-
default:
|
|
165
|
-
break;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 错误处理
|
|
263
|
+
*/
|
|
264
|
+
private async errorHandler(err: ExpandAxiosError<any>): Promise<any> {
|
|
265
|
+
// 清理请求记录
|
|
266
|
+
const __key = err.config?.__requestKey
|
|
267
|
+
if (__key) {
|
|
268
|
+
this.pendingRequests.delete(__key)
|
|
166
269
|
}
|
|
167
|
-
} else if (err.response === undefined) {
|
|
168
|
-
description = err.message.includes('timeout') ? '接口响应超时' : err.message
|
|
169
|
-
_status = 'timeout'
|
|
170
|
-
}
|
|
171
270
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
271
|
+
// 如果是用户主动取消的请求,不做错误处理
|
|
272
|
+
if (axios.isCancel(err as any)) {
|
|
273
|
+
return Promise.reject(err)
|
|
274
|
+
}
|
|
175
275
|
|
|
176
|
-
|
|
177
|
-
|
|
276
|
+
let description = err.response?.message || 'Error'
|
|
277
|
+
let _status: string | number = 0
|
|
278
|
+
|
|
279
|
+
const response = err.response
|
|
280
|
+
if (response) {
|
|
281
|
+
const { data, status } = response
|
|
282
|
+
_status = status
|
|
283
|
+
|
|
284
|
+
switch (status) {
|
|
285
|
+
case 400:
|
|
286
|
+
case 403:
|
|
287
|
+
case 500:
|
|
288
|
+
description = `${data?.message}`.substring(0, 90)
|
|
289
|
+
break
|
|
290
|
+
case 401:
|
|
291
|
+
description = (data as any)?.result?.text || '用户未登录'
|
|
292
|
+
this.options.tokenExpiration?.(err as any)
|
|
293
|
+
if (this.options.isCreateTokenRefresh) {
|
|
294
|
+
return this.createTokenRefreshHandler(err)
|
|
295
|
+
}
|
|
296
|
+
break
|
|
297
|
+
case 404:
|
|
298
|
+
description = data?.message || `${(data as any)?.error} ${(data as any)?.path}`
|
|
299
|
+
break
|
|
300
|
+
default:
|
|
301
|
+
break
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
const errAny = err as any
|
|
305
|
+
if (errAny.message) {
|
|
306
|
+
description = errAny.message.includes('timeout') ? '接口响应超时' : errAny.message
|
|
307
|
+
_status = 'timeout'
|
|
308
|
+
}
|
|
309
|
+
}
|
|
178
310
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
311
|
+
if (this.options.handleError && isFunction(this.options.handleError)) {
|
|
312
|
+
this.options.handleError(description, _status, err as any)
|
|
313
|
+
}
|
|
183
314
|
|
|
184
|
-
|
|
185
|
-
if (options) {
|
|
186
|
-
_options = Object.assign(_options, options)
|
|
315
|
+
return Promise.reject(err)
|
|
187
316
|
}
|
|
188
317
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
318
|
+
/**
|
|
319
|
+
* 取消所有进行中的请求
|
|
320
|
+
*/
|
|
321
|
+
abortAllRequests(): void {
|
|
322
|
+
this.pendingRequests.forEach((controller) => controller.abort())
|
|
323
|
+
this.pendingRequests.clear()
|
|
324
|
+
}
|
|
194
325
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
)
|
|
326
|
+
/**
|
|
327
|
+
* 取消特定请求
|
|
328
|
+
*/
|
|
329
|
+
abortRequest(requestKey: string): void {
|
|
330
|
+
const controller = this.pendingRequests.get(requestKey)
|
|
331
|
+
if (controller) {
|
|
332
|
+
controller.abort()
|
|
333
|
+
this.pendingRequests.delete(requestKey)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
199
336
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
)
|
|
204
|
-
|
|
337
|
+
/**
|
|
338
|
+
* 获取当前进行中的请求数量
|
|
339
|
+
*/
|
|
340
|
+
getPendingRequestsCount(): number {
|
|
341
|
+
return this.pendingRequests.size
|
|
342
|
+
}
|
|
205
343
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
344
|
+
/**
|
|
345
|
+
* HTTP 方法封装 - POST
|
|
346
|
+
*/
|
|
347
|
+
post<T = any>(url: string, data: any = {}, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
348
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
349
|
+
method: 'POST',
|
|
350
|
+
url,
|
|
351
|
+
data,
|
|
352
|
+
...ext
|
|
353
|
+
})
|
|
354
|
+
}
|
|
214
355
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
356
|
+
/**
|
|
357
|
+
* HTTP 方法封装 - GET
|
|
358
|
+
*/
|
|
359
|
+
get<T = any>(url: string, params: any = undefined, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
360
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
361
|
+
method: 'GET',
|
|
362
|
+
url,
|
|
363
|
+
params,
|
|
364
|
+
...ext
|
|
365
|
+
})
|
|
366
|
+
}
|
|
223
367
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
368
|
+
/**
|
|
369
|
+
* HTTP 方法封装 - PUT
|
|
370
|
+
*/
|
|
371
|
+
put<T = any>(url: string, data: any = {}, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
372
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
373
|
+
method: 'PUT',
|
|
374
|
+
url,
|
|
375
|
+
data,
|
|
376
|
+
...ext
|
|
377
|
+
})
|
|
378
|
+
}
|
|
232
379
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
380
|
+
/**
|
|
381
|
+
* HTTP 方法封装 - PATCH
|
|
382
|
+
*/
|
|
383
|
+
patch<T = any>(url: string, data: any = {}, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
384
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
385
|
+
method: 'PATCH',
|
|
386
|
+
url,
|
|
387
|
+
data,
|
|
388
|
+
...ext
|
|
389
|
+
})
|
|
390
|
+
}
|
|
241
391
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
392
|
+
/**
|
|
393
|
+
* HTTP 方法封装 - DELETE
|
|
394
|
+
*/
|
|
395
|
+
remove<T = any>(url: string, params: any = undefined, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
396
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
397
|
+
method: 'DELETE',
|
|
398
|
+
url,
|
|
399
|
+
params,
|
|
400
|
+
...ext
|
|
401
|
+
})
|
|
402
|
+
}
|
|
250
403
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
404
|
+
/**
|
|
405
|
+
* 获取流数据 - GET
|
|
406
|
+
*/
|
|
407
|
+
getStream(url: string, params?: any, ext?: any): Promise<any> {
|
|
408
|
+
return this.get(url, params, { responseType: 'arraybuffer', ...ext })
|
|
409
|
+
}
|
|
254
410
|
|
|
255
|
-
|
|
256
|
-
|
|
411
|
+
/**
|
|
412
|
+
* 获取流数据 - POST
|
|
413
|
+
*/
|
|
414
|
+
postStream(url: string, data: any, ext?: any): Promise<any> {
|
|
415
|
+
return this.post(url, data, { responseType: 'arraybuffer', ...ext })
|
|
416
|
+
}
|
|
257
417
|
}
|
|
258
418
|
|
|
259
|
-
|
|
260
|
-
|
|
419
|
+
// 创建默认的 AxiosService 实例
|
|
420
|
+
const defaultAxiosService = new AxiosService()
|
|
421
|
+
|
|
422
|
+
// 导出默认实例和工厂函数
|
|
423
|
+
export const createAxiosService = (options?: Partial<ExtendedOptions>): AxiosService => {
|
|
424
|
+
const service = new AxiosService(options)
|
|
425
|
+
service.initialize()
|
|
426
|
+
return service
|
|
261
427
|
}
|
|
262
428
|
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Request 类 - 业务请求封装
|
|
432
|
+
* 默认使用全局共享的 axios 实例,特殊情况可传入自定义实例
|
|
433
|
+
*/
|
|
263
434
|
export class Request {
|
|
435
|
+
private _instance?: AxiosInstance
|
|
264
436
|
|
|
265
|
-
constructor(public basePath: string) {
|
|
437
|
+
constructor(public basePath: string, instance?: AxiosInstance) {
|
|
266
438
|
this.basePath = basePath.startsWith('/') ? basePath : `/${basePath}`
|
|
439
|
+
this._instance = instance
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* 获取 axios 实例
|
|
444
|
+
* 延迟获取以确保全局实例已初始化
|
|
445
|
+
*/
|
|
446
|
+
private get instance(): AxiosInstance {
|
|
447
|
+
return this._instance || defaultAxiosService.getInstance()
|
|
267
448
|
}
|
|
268
449
|
|
|
269
450
|
private requestWrapper<T = any>(
|
|
270
451
|
defaultUrl: string,
|
|
271
|
-
defaultMethod: 'post'| 'get'| 'put'| 'patch'| 'remove'| 'getStream'| 'postStream',
|
|
452
|
+
defaultMethod: 'post' | 'get' | 'put' | 'patch' | 'remove' | 'getStream' | 'postStream',
|
|
272
453
|
dataOrParams: any = {},
|
|
273
454
|
options: RequestOptions = {}
|
|
274
455
|
): Promise<AxiosResponseRewrite<T>> {
|
|
275
456
|
const { url = defaultUrl, method = defaultMethod, ...rest } = options
|
|
276
|
-
|
|
457
|
+
const fn = this[method] as (url: string, dataOrParams: any, options?: any) => Promise<AxiosResponseRewrite<T>>
|
|
458
|
+
return fn.call(this, url, dataOrParams, rest)
|
|
277
459
|
}
|
|
278
460
|
|
|
279
461
|
/**
|
|
280
462
|
* 分页查询
|
|
281
|
-
* @param
|
|
282
|
-
* @param
|
|
463
|
+
* @param data 查询参数
|
|
464
|
+
* @param options 请求配置
|
|
283
465
|
*/
|
|
284
|
-
page<T = any>(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
466
|
+
page<T = any>(
|
|
467
|
+
data: any = {},
|
|
468
|
+
options: RequestOptions = {
|
|
469
|
+
url: undefined,
|
|
470
|
+
method: undefined
|
|
471
|
+
}
|
|
472
|
+
): Promise<AxiosResponseRewrite<PageResult<T>>> {
|
|
288
473
|
return this.requestWrapper<PageResult<T>>('/_query', 'post', data, options)
|
|
289
474
|
}
|
|
290
475
|
|
|
291
476
|
/**
|
|
292
477
|
* 不分页查询
|
|
293
|
-
* @param
|
|
294
|
-
* @param
|
|
478
|
+
* @param data 查询参数
|
|
479
|
+
* @param options 请求配置
|
|
295
480
|
*/
|
|
296
|
-
noPage<T = any>(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
481
|
+
noPage<T = any>(
|
|
482
|
+
data: any = {},
|
|
483
|
+
options: RequestOptions = {
|
|
484
|
+
url: undefined,
|
|
485
|
+
method: undefined
|
|
486
|
+
}
|
|
487
|
+
): Promise<AxiosResponseRewrite<T[]>> {
|
|
300
488
|
return this.requestWrapper<T[]>('/_query/no-paging', 'post', { paging: false, ...data }, options)
|
|
301
489
|
}
|
|
302
490
|
|
|
303
491
|
/**
|
|
304
492
|
* 详情查询
|
|
305
|
-
* @param
|
|
306
|
-
* @param
|
|
307
|
-
* @param
|
|
493
|
+
* @param id 详情ID
|
|
494
|
+
* @param params 查询参数
|
|
495
|
+
* @param options 请求配置
|
|
308
496
|
*/
|
|
309
|
-
detail<T = any>(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
497
|
+
detail<T = any>(
|
|
498
|
+
id: string,
|
|
499
|
+
params?: any,
|
|
500
|
+
options: RequestOptions = {
|
|
501
|
+
url: undefined,
|
|
502
|
+
method: undefined
|
|
503
|
+
}
|
|
504
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
313
505
|
return this.requestWrapper<T>(`/${id}/detail`, 'get', params, options)
|
|
314
506
|
}
|
|
315
507
|
|
|
316
508
|
/**
|
|
317
509
|
* 保存
|
|
318
|
-
* @param
|
|
319
|
-
* @param
|
|
510
|
+
* @param data 保存参数
|
|
511
|
+
* @param options 请求配置
|
|
320
512
|
*/
|
|
321
|
-
save<T = any>(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
513
|
+
save<T = any>(
|
|
514
|
+
data: any = {},
|
|
515
|
+
options: RequestOptions = {
|
|
516
|
+
url: undefined,
|
|
517
|
+
method: undefined
|
|
518
|
+
}
|
|
519
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
325
520
|
return this.requestWrapper<T>('', 'post', data, options)
|
|
326
521
|
}
|
|
327
522
|
|
|
328
523
|
/**
|
|
329
524
|
* 更新
|
|
330
|
-
* @param
|
|
331
|
-
* @param
|
|
525
|
+
* @param data 更新参数
|
|
526
|
+
* @param options 请求配置
|
|
332
527
|
*/
|
|
333
|
-
update<T extends UpdateResult>(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
528
|
+
update<T extends UpdateResult>(
|
|
529
|
+
data: any = {},
|
|
530
|
+
options: RequestOptions = {
|
|
531
|
+
url: undefined,
|
|
532
|
+
method: undefined
|
|
533
|
+
}
|
|
534
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
337
535
|
return this.requestWrapper<T>('', 'patch', data, options)
|
|
338
536
|
}
|
|
339
537
|
|
|
340
538
|
/**
|
|
341
539
|
* 删除
|
|
342
|
-
* @param
|
|
343
|
-
* @param
|
|
344
|
-
* @param
|
|
540
|
+
* @param id 删除ID
|
|
541
|
+
* @param params 请求参数
|
|
542
|
+
* @param options 请求配置
|
|
345
543
|
* @example ${basePath}/${id}
|
|
346
544
|
*/
|
|
347
|
-
delete<T = any>(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
545
|
+
delete<T = any>(
|
|
546
|
+
id: string,
|
|
547
|
+
params?: any,
|
|
548
|
+
options: RequestOptions = {
|
|
549
|
+
url: undefined,
|
|
550
|
+
method: undefined
|
|
551
|
+
}
|
|
552
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
553
|
+
return this.requestWrapper<T>(`/${id}`, 'remove', params, options)
|
|
352
554
|
}
|
|
353
555
|
|
|
354
556
|
/**
|
|
@@ -357,39 +559,98 @@ export class Request {
|
|
|
357
559
|
* @param type
|
|
358
560
|
* @param options
|
|
359
561
|
*/
|
|
360
|
-
batch<T = any>(data = {}, type?: string, options?: RequestOptions) {
|
|
562
|
+
batch<T = any>(data = {}, type?: string, options?: RequestOptions): Promise<AxiosResponseRewrite<T>> {
|
|
361
563
|
const url = `/_batch${type ? '/' + type : ''}`
|
|
362
564
|
return this.requestWrapper<T>(url, 'post', data, options)
|
|
363
565
|
}
|
|
364
566
|
|
|
365
|
-
post<T = any>(url: string, data?: any, options?: any) {
|
|
366
|
-
return
|
|
567
|
+
post<T = any>(url: string, data?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
568
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
569
|
+
method: 'POST',
|
|
570
|
+
url: `${this.basePath}${url}`,
|
|
571
|
+
data,
|
|
572
|
+
...options
|
|
573
|
+
})
|
|
367
574
|
}
|
|
368
575
|
|
|
369
|
-
get<T = any>(url: string, params?: any, options?: any) {
|
|
370
|
-
return
|
|
576
|
+
get<T = any>(url: string, params?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
577
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
578
|
+
method: 'GET',
|
|
579
|
+
url: `${this.basePath}${url}`,
|
|
580
|
+
params,
|
|
581
|
+
...options
|
|
582
|
+
})
|
|
371
583
|
}
|
|
372
584
|
|
|
373
|
-
put<T = any>(url: string, data?: any, options?: any) {
|
|
374
|
-
return
|
|
585
|
+
put<T = any>(url: string, data?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
586
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
587
|
+
method: 'PUT',
|
|
588
|
+
url: `${this.basePath}${url}`,
|
|
589
|
+
data,
|
|
590
|
+
...options
|
|
591
|
+
})
|
|
375
592
|
}
|
|
376
593
|
|
|
377
|
-
patch<T = any>(url: string, data?: any, options?: any) {
|
|
378
|
-
return
|
|
594
|
+
patch<T = any>(url: string, data?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
595
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
596
|
+
method: 'PATCH',
|
|
597
|
+
url: `${this.basePath}${url}`,
|
|
598
|
+
data,
|
|
599
|
+
...options
|
|
600
|
+
})
|
|
379
601
|
}
|
|
380
602
|
|
|
381
|
-
remove<T = any>(url: string, params?: any, options?: any) {
|
|
382
|
-
return
|
|
603
|
+
remove<T = any>(url: string, params?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
604
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
605
|
+
method: 'DELETE',
|
|
606
|
+
url: `${this.basePath}${url}`,
|
|
607
|
+
params,
|
|
608
|
+
...options
|
|
609
|
+
})
|
|
383
610
|
}
|
|
384
611
|
|
|
385
|
-
getStream(url: string, params?: any, options?: any) {
|
|
386
|
-
return get(`${
|
|
612
|
+
getStream(url: string, params?: any, options?: any): Promise<any> {
|
|
613
|
+
return this.get(`${url}`, params, { responseType: 'arraybuffer', ...options })
|
|
387
614
|
}
|
|
388
615
|
|
|
389
|
-
postStream(url: string, data?: any, options?: any) {
|
|
390
|
-
return post(`${
|
|
616
|
+
postStream(url: string, data?: any, options?: any): Promise<any> {
|
|
617
|
+
return this.post(`${url}`, data, { responseType: 'arraybuffer', ...options })
|
|
391
618
|
}
|
|
392
619
|
}
|
|
393
620
|
|
|
621
|
+
// 导出默认 request 对象(保持向后兼容)
|
|
622
|
+
export const request = {
|
|
623
|
+
post: defaultAxiosService.post.bind(defaultAxiosService),
|
|
624
|
+
get: defaultAxiosService.get.bind(defaultAxiosService),
|
|
625
|
+
put: defaultAxiosService.put.bind(defaultAxiosService),
|
|
626
|
+
patch: defaultAxiosService.patch.bind(defaultAxiosService),
|
|
627
|
+
remove: defaultAxiosService.remove.bind(defaultAxiosService),
|
|
628
|
+
getStream: defaultAxiosService.getStream.bind(defaultAxiosService),
|
|
629
|
+
postStream: defaultAxiosService.postStream.bind(defaultAxiosService)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// 导出便捷函数(保持向后兼容)
|
|
633
|
+
export const post = defaultAxiosService.post.bind(defaultAxiosService)
|
|
634
|
+
export const get = defaultAxiosService.get.bind(defaultAxiosService)
|
|
635
|
+
export const put = defaultAxiosService.put.bind(defaultAxiosService)
|
|
636
|
+
export const patch = defaultAxiosService.patch.bind(defaultAxiosService)
|
|
637
|
+
export const remove = defaultAxiosService.remove.bind(defaultAxiosService)
|
|
638
|
+
export const getStream = defaultAxiosService.getStream.bind(defaultAxiosService)
|
|
639
|
+
export const postStream = defaultAxiosService.postStream.bind(defaultAxiosService)
|
|
394
640
|
|
|
641
|
+
// 导出工具函数
|
|
642
|
+
export const abortAllRequests = () => defaultAxiosService.abortAllRequests()
|
|
643
|
+
|
|
644
|
+
export const getInstance = () => defaultAxiosService.getInstance()
|
|
645
|
+
|
|
646
|
+
// 导出 axios 实例(兼容旧代码)
|
|
647
|
+
export let instance: AxiosInstance
|
|
648
|
+
|
|
649
|
+
// 导出初始化函数(兼容旧代码)
|
|
650
|
+
export const crateAxios = (options: ExtendedOptions) => {
|
|
651
|
+
defaultAxiosService.initialize(options)
|
|
652
|
+
instance = defaultAxiosService.getInstance()
|
|
653
|
+
}
|
|
395
654
|
|
|
655
|
+
// 导出默认服务实例
|
|
656
|
+
export default defaultAxiosService
|