@jetlinks-web/core 2.2.19 → 2.3.1
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 +214 -52
- package/dist/index.mjs +2 -3
- package/package.json +3 -3
- package/src/axios.ts +532 -267
- package/src/fetch.ts +225 -195
- package/src/type.ts +15 -6
package/src/axios.ts
CHANGED
|
@@ -1,354 +1,560 @@
|
|
|
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
|
+
}
|
|
70
141
|
|
|
71
|
-
|
|
72
|
-
config.
|
|
142
|
+
const controller = new AbortController()
|
|
143
|
+
config.signal = controller.signal
|
|
144
|
+
config.__requestKey = key
|
|
145
|
+
|
|
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
|
+
}
|
|
240
|
+
|
|
241
|
+
originalRequest._retry = true
|
|
242
|
+
this.isRefreshing = true
|
|
113
243
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if(loginResult){
|
|
129
|
-
const token = getToken() // 更新请求头, 修改全部的token
|
|
130
|
-
originalRequest.headers[TOKEN_KEY] = token;
|
|
131
|
-
failedQueue.forEach(a => a.resolve(token));
|
|
132
|
-
return instance(originalRequest);
|
|
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
|
+
const result = this.options.handleError(description, _status, err as any)
|
|
313
|
+
// 如果 handleError 返回了 Promise,则返回它以替换原始错误
|
|
314
|
+
if (result && typeof result.then === 'function') {
|
|
315
|
+
return result
|
|
316
|
+
}
|
|
317
|
+
}
|
|
183
318
|
|
|
184
|
-
|
|
185
|
-
if (options) {
|
|
186
|
-
_options = Object.assign(_options, options)
|
|
319
|
+
return Promise.reject(err)
|
|
187
320
|
}
|
|
188
321
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
322
|
+
/**
|
|
323
|
+
* 取消所有进行中的请求
|
|
324
|
+
*/
|
|
325
|
+
abortAllRequests(): void {
|
|
326
|
+
this.pendingRequests.forEach((controller) => controller.abort())
|
|
327
|
+
this.pendingRequests.clear()
|
|
328
|
+
}
|
|
194
329
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
)
|
|
330
|
+
/**
|
|
331
|
+
* 取消特定请求
|
|
332
|
+
*/
|
|
333
|
+
abortRequest(requestKey: string): void {
|
|
334
|
+
const controller = this.pendingRequests.get(requestKey)
|
|
335
|
+
if (controller) {
|
|
336
|
+
controller.abort()
|
|
337
|
+
this.pendingRequests.delete(requestKey)
|
|
338
|
+
}
|
|
339
|
+
}
|
|
199
340
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
)
|
|
204
|
-
|
|
341
|
+
/**
|
|
342
|
+
* 获取当前进行中的请求数量
|
|
343
|
+
*/
|
|
344
|
+
getPendingRequestsCount(): number {
|
|
345
|
+
return this.pendingRequests.size
|
|
346
|
+
}
|
|
205
347
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
348
|
+
/**
|
|
349
|
+
* HTTP 方法封装 - POST
|
|
350
|
+
*/
|
|
351
|
+
post<T = any>(url: string, data: any = {}, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
352
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
353
|
+
method: 'POST',
|
|
354
|
+
url,
|
|
355
|
+
data,
|
|
356
|
+
...ext
|
|
357
|
+
})
|
|
358
|
+
}
|
|
214
359
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
360
|
+
/**
|
|
361
|
+
* HTTP 方法封装 - GET
|
|
362
|
+
*/
|
|
363
|
+
get<T = any>(url: string, params: any = undefined, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
364
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
365
|
+
method: 'GET',
|
|
366
|
+
url,
|
|
367
|
+
params,
|
|
368
|
+
...ext
|
|
369
|
+
})
|
|
370
|
+
}
|
|
223
371
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
372
|
+
/**
|
|
373
|
+
* HTTP 方法封装 - PUT
|
|
374
|
+
*/
|
|
375
|
+
put<T = any>(url: string, data: any = {}, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
376
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
377
|
+
method: 'PUT',
|
|
378
|
+
url,
|
|
379
|
+
data,
|
|
380
|
+
...ext
|
|
381
|
+
})
|
|
382
|
+
}
|
|
232
383
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
384
|
+
/**
|
|
385
|
+
* HTTP 方法封装 - PATCH
|
|
386
|
+
*/
|
|
387
|
+
patch<T = any>(url: string, data: any = {}, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
388
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
389
|
+
method: 'PATCH',
|
|
390
|
+
url,
|
|
391
|
+
data,
|
|
392
|
+
...ext
|
|
393
|
+
})
|
|
394
|
+
}
|
|
241
395
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
396
|
+
/**
|
|
397
|
+
* HTTP 方法封装 - DELETE
|
|
398
|
+
*/
|
|
399
|
+
remove<T = any>(url: string, params: any = undefined, ext?: any): Promise<AxiosResponseRewrite<T>> {
|
|
400
|
+
return this.getInstance()<any, AxiosResponseRewrite<T>>({
|
|
401
|
+
method: 'DELETE',
|
|
402
|
+
url,
|
|
403
|
+
params,
|
|
404
|
+
...ext
|
|
405
|
+
})
|
|
406
|
+
}
|
|
250
407
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
408
|
+
/**
|
|
409
|
+
* 获取流数据 - GET
|
|
410
|
+
*/
|
|
411
|
+
getStream(url: string, params?: any, ext?: any): Promise<any> {
|
|
412
|
+
return this.get(url, params, { responseType: 'arraybuffer', ...ext })
|
|
413
|
+
}
|
|
254
414
|
|
|
255
|
-
|
|
256
|
-
|
|
415
|
+
/**
|
|
416
|
+
* 获取流数据 - POST
|
|
417
|
+
*/
|
|
418
|
+
postStream(url: string, data: any, ext?: any): Promise<any> {
|
|
419
|
+
return this.post(url, data, { responseType: 'arraybuffer', ...ext })
|
|
420
|
+
}
|
|
257
421
|
}
|
|
258
422
|
|
|
259
|
-
|
|
260
|
-
|
|
423
|
+
// 创建默认的 AxiosService 实例
|
|
424
|
+
const defaultAxiosService = new AxiosService()
|
|
425
|
+
|
|
426
|
+
// 导出默认实例和工厂函数
|
|
427
|
+
export const createAxiosService = (options?: Partial<ExtendedOptions>): AxiosService => {
|
|
428
|
+
const service = new AxiosService(options)
|
|
429
|
+
service.initialize()
|
|
430
|
+
return service
|
|
261
431
|
}
|
|
262
432
|
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Request 类 - 业务请求封装
|
|
436
|
+
* 默认使用全局共享的 axios 实例,特殊情况可传入自定义实例
|
|
437
|
+
*/
|
|
263
438
|
export class Request {
|
|
439
|
+
private _instance?: AxiosInstance
|
|
264
440
|
|
|
265
|
-
constructor(public basePath: string) {
|
|
441
|
+
constructor(public basePath: string, instance?: AxiosInstance) {
|
|
266
442
|
this.basePath = basePath.startsWith('/') ? basePath : `/${basePath}`
|
|
443
|
+
this._instance = instance
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* 获取 axios 实例
|
|
448
|
+
* 延迟获取以确保全局实例已初始化
|
|
449
|
+
*/
|
|
450
|
+
private get instance(): AxiosInstance {
|
|
451
|
+
return this._instance || defaultAxiosService.getInstance()
|
|
267
452
|
}
|
|
268
453
|
|
|
269
454
|
private requestWrapper<T = any>(
|
|
270
455
|
defaultUrl: string,
|
|
271
|
-
defaultMethod: 'post'| 'get'| 'put'| 'patch'| 'remove'| 'getStream'| 'postStream',
|
|
456
|
+
defaultMethod: 'post' | 'get' | 'put' | 'patch' | 'remove' | 'getStream' | 'postStream',
|
|
272
457
|
dataOrParams: any = {},
|
|
273
458
|
options: RequestOptions = {}
|
|
274
459
|
): Promise<AxiosResponseRewrite<T>> {
|
|
275
460
|
const { url = defaultUrl, method = defaultMethod, ...rest } = options
|
|
276
|
-
|
|
461
|
+
const fn = this[method] as (url: string, dataOrParams: any, options?: any) => Promise<AxiosResponseRewrite<T>>
|
|
462
|
+
return fn.call(this, url, dataOrParams, rest)
|
|
277
463
|
}
|
|
278
464
|
|
|
279
465
|
/**
|
|
280
466
|
* 分页查询
|
|
281
|
-
* @param
|
|
282
|
-
* @param
|
|
467
|
+
* @param data 查询参数
|
|
468
|
+
* @param options 请求配置
|
|
283
469
|
*/
|
|
284
|
-
page<T = any>(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
470
|
+
page<T = any>(
|
|
471
|
+
data: any = {},
|
|
472
|
+
options: RequestOptions = {
|
|
473
|
+
url: undefined,
|
|
474
|
+
method: undefined
|
|
475
|
+
}
|
|
476
|
+
): Promise<AxiosResponseRewrite<PageResult<T>>> {
|
|
288
477
|
return this.requestWrapper<PageResult<T>>('/_query', 'post', data, options)
|
|
289
478
|
}
|
|
290
479
|
|
|
291
480
|
/**
|
|
292
481
|
* 不分页查询
|
|
293
|
-
* @param
|
|
294
|
-
* @param
|
|
482
|
+
* @param data 查询参数
|
|
483
|
+
* @param options 请求配置
|
|
295
484
|
*/
|
|
296
|
-
noPage<T = any>(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
485
|
+
noPage<T = any>(
|
|
486
|
+
data: any = {},
|
|
487
|
+
options: RequestOptions = {
|
|
488
|
+
url: undefined,
|
|
489
|
+
method: undefined
|
|
490
|
+
}
|
|
491
|
+
): Promise<AxiosResponseRewrite<T[]>> {
|
|
300
492
|
return this.requestWrapper<T[]>('/_query/no-paging', 'post', { paging: false, ...data }, options)
|
|
301
493
|
}
|
|
302
494
|
|
|
303
495
|
/**
|
|
304
496
|
* 详情查询
|
|
305
|
-
* @param
|
|
306
|
-
* @param
|
|
307
|
-
* @param
|
|
497
|
+
* @param id 详情ID
|
|
498
|
+
* @param params 查询参数
|
|
499
|
+
* @param options 请求配置
|
|
308
500
|
*/
|
|
309
|
-
detail<T = any>(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
501
|
+
detail<T = any>(
|
|
502
|
+
id: string,
|
|
503
|
+
params?: any,
|
|
504
|
+
options: RequestOptions = {
|
|
505
|
+
url: undefined,
|
|
506
|
+
method: undefined
|
|
507
|
+
}
|
|
508
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
313
509
|
return this.requestWrapper<T>(`/${id}/detail`, 'get', params, options)
|
|
314
510
|
}
|
|
315
511
|
|
|
316
512
|
/**
|
|
317
513
|
* 保存
|
|
318
|
-
* @param
|
|
319
|
-
* @param
|
|
514
|
+
* @param data 保存参数
|
|
515
|
+
* @param options 请求配置
|
|
320
516
|
*/
|
|
321
|
-
save<T = any>(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
517
|
+
save<T = any>(
|
|
518
|
+
data: any = {},
|
|
519
|
+
options: RequestOptions = {
|
|
520
|
+
url: undefined,
|
|
521
|
+
method: undefined
|
|
522
|
+
}
|
|
523
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
325
524
|
return this.requestWrapper<T>('', 'post', data, options)
|
|
326
525
|
}
|
|
327
526
|
|
|
328
527
|
/**
|
|
329
528
|
* 更新
|
|
330
|
-
* @param
|
|
331
|
-
* @param
|
|
529
|
+
* @param data 更新参数
|
|
530
|
+
* @param options 请求配置
|
|
332
531
|
*/
|
|
333
|
-
update<T extends UpdateResult>(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
532
|
+
update<T extends UpdateResult>(
|
|
533
|
+
data: any = {},
|
|
534
|
+
options: RequestOptions = {
|
|
535
|
+
url: undefined,
|
|
536
|
+
method: undefined
|
|
537
|
+
}
|
|
538
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
337
539
|
return this.requestWrapper<T>('', 'patch', data, options)
|
|
338
540
|
}
|
|
339
541
|
|
|
340
542
|
/**
|
|
341
543
|
* 删除
|
|
342
|
-
* @param
|
|
343
|
-
* @param
|
|
344
|
-
* @param
|
|
544
|
+
* @param id 删除ID
|
|
545
|
+
* @param params 请求参数
|
|
546
|
+
* @param options 请求配置
|
|
345
547
|
* @example ${basePath}/${id}
|
|
346
548
|
*/
|
|
347
|
-
delete<T = any>(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
549
|
+
delete<T = any>(
|
|
550
|
+
id: string,
|
|
551
|
+
params?: any,
|
|
552
|
+
options: RequestOptions = {
|
|
553
|
+
url: undefined,
|
|
554
|
+
method: undefined
|
|
555
|
+
}
|
|
556
|
+
): Promise<AxiosResponseRewrite<T>> {
|
|
557
|
+
return this.requestWrapper<T>(`/${id}`, 'remove', params, options)
|
|
352
558
|
}
|
|
353
559
|
|
|
354
560
|
/**
|
|
@@ -357,39 +563,98 @@ export class Request {
|
|
|
357
563
|
* @param type
|
|
358
564
|
* @param options
|
|
359
565
|
*/
|
|
360
|
-
batch<T = any>(data = {}, type?: string, options?: RequestOptions) {
|
|
566
|
+
batch<T = any>(data = {}, type?: string, options?: RequestOptions): Promise<AxiosResponseRewrite<T>> {
|
|
361
567
|
const url = `/_batch${type ? '/' + type : ''}`
|
|
362
568
|
return this.requestWrapper<T>(url, 'post', data, options)
|
|
363
569
|
}
|
|
364
570
|
|
|
365
|
-
post<T = any>(url: string, data?: any, options?: any) {
|
|
366
|
-
return
|
|
571
|
+
post<T = any>(url: string, data?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
572
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
573
|
+
method: 'POST',
|
|
574
|
+
url: `${this.basePath}${url}`,
|
|
575
|
+
data,
|
|
576
|
+
...options
|
|
577
|
+
})
|
|
367
578
|
}
|
|
368
579
|
|
|
369
|
-
get<T = any>(url: string, params?: any, options?: any) {
|
|
370
|
-
return
|
|
580
|
+
get<T = any>(url: string, params?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
581
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
582
|
+
method: 'GET',
|
|
583
|
+
url: `${this.basePath}${url}`,
|
|
584
|
+
params,
|
|
585
|
+
...options
|
|
586
|
+
})
|
|
371
587
|
}
|
|
372
588
|
|
|
373
|
-
put<T = any>(url: string, data?: any, options?: any) {
|
|
374
|
-
return
|
|
589
|
+
put<T = any>(url: string, data?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
590
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
591
|
+
method: 'PUT',
|
|
592
|
+
url: `${this.basePath}${url}`,
|
|
593
|
+
data,
|
|
594
|
+
...options
|
|
595
|
+
})
|
|
375
596
|
}
|
|
376
597
|
|
|
377
|
-
patch<T = any>(url: string, data?: any, options?: any) {
|
|
378
|
-
return
|
|
598
|
+
patch<T = any>(url: string, data?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
599
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
600
|
+
method: 'PATCH',
|
|
601
|
+
url: `${this.basePath}${url}`,
|
|
602
|
+
data,
|
|
603
|
+
...options
|
|
604
|
+
})
|
|
379
605
|
}
|
|
380
606
|
|
|
381
|
-
remove<T = any>(url: string, params?: any, options?: any) {
|
|
382
|
-
return
|
|
607
|
+
remove<T = any>(url: string, params?: any, options?: any): Promise<AxiosResponseRewrite<T>> {
|
|
608
|
+
return this.instance<any, AxiosResponseRewrite<T>>({
|
|
609
|
+
method: 'DELETE',
|
|
610
|
+
url: `${this.basePath}${url}`,
|
|
611
|
+
params,
|
|
612
|
+
...options
|
|
613
|
+
})
|
|
383
614
|
}
|
|
384
615
|
|
|
385
|
-
getStream(url: string, params?: any, options?: any) {
|
|
386
|
-
return get(`${
|
|
616
|
+
getStream(url: string, params?: any, options?: any): Promise<any> {
|
|
617
|
+
return this.get(`${url}`, params, { responseType: 'arraybuffer', ...options })
|
|
387
618
|
}
|
|
388
619
|
|
|
389
|
-
postStream(url: string, data?: any, options?: any) {
|
|
390
|
-
return post(`${
|
|
620
|
+
postStream(url: string, data?: any, options?: any): Promise<any> {
|
|
621
|
+
return this.post(`${url}`, data, { responseType: 'arraybuffer', ...options })
|
|
391
622
|
}
|
|
392
623
|
}
|
|
393
624
|
|
|
625
|
+
// 导出默认 request 对象(保持向后兼容)
|
|
626
|
+
export const request = {
|
|
627
|
+
post: defaultAxiosService.post.bind(defaultAxiosService),
|
|
628
|
+
get: defaultAxiosService.get.bind(defaultAxiosService),
|
|
629
|
+
put: defaultAxiosService.put.bind(defaultAxiosService),
|
|
630
|
+
patch: defaultAxiosService.patch.bind(defaultAxiosService),
|
|
631
|
+
remove: defaultAxiosService.remove.bind(defaultAxiosService),
|
|
632
|
+
getStream: defaultAxiosService.getStream.bind(defaultAxiosService),
|
|
633
|
+
postStream: defaultAxiosService.postStream.bind(defaultAxiosService)
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// 导出便捷函数(保持向后兼容)
|
|
637
|
+
export const post = defaultAxiosService.post.bind(defaultAxiosService)
|
|
638
|
+
export const get = defaultAxiosService.get.bind(defaultAxiosService)
|
|
639
|
+
export const put = defaultAxiosService.put.bind(defaultAxiosService)
|
|
640
|
+
export const patch = defaultAxiosService.patch.bind(defaultAxiosService)
|
|
641
|
+
export const remove = defaultAxiosService.remove.bind(defaultAxiosService)
|
|
642
|
+
export const getStream = defaultAxiosService.getStream.bind(defaultAxiosService)
|
|
643
|
+
export const postStream = defaultAxiosService.postStream.bind(defaultAxiosService)
|
|
394
644
|
|
|
645
|
+
// 导出工具函数
|
|
646
|
+
export const abortAllRequests = () => defaultAxiosService.abortAllRequests()
|
|
647
|
+
|
|
648
|
+
export const getInstance = () => defaultAxiosService.getInstance()
|
|
649
|
+
|
|
650
|
+
// 导出 axios 实例(兼容旧代码)
|
|
651
|
+
export let instance: AxiosInstance
|
|
652
|
+
|
|
653
|
+
// 导出初始化函数(兼容旧代码)
|
|
654
|
+
export const crateAxios = (options: ExtendedOptions) => {
|
|
655
|
+
defaultAxiosService.initialize(options)
|
|
656
|
+
instance = defaultAxiosService.getInstance()
|
|
657
|
+
}
|
|
395
658
|
|
|
659
|
+
// 导出默认服务实例
|
|
660
|
+
export default defaultAxiosService
|