@jetlinks-web/core 2.1.6 → 2.1.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetlinks-web/core",
3
- "version": "2.1.6",
3
+ "version": "2.1.8",
4
4
  "main": "index.ts",
5
5
  "module": "index.ts",
6
6
  "keywords": [
package/src/axios.ts CHANGED
@@ -47,7 +47,6 @@ interface RequestOptions {
47
47
  }
48
48
 
49
49
  let instance: AxiosInstance
50
-
51
50
  let _options: Options = {
52
51
  filter_url: [],
53
52
  code: 200,
@@ -61,20 +60,21 @@ let _options: Options = {
61
60
  tokenExpiration: () => {},
62
61
  }
63
62
 
63
+ const isApp = (window as any).__MICRO_APP_ENVIRONMENT__
64
64
  const controller = new AbortController();
65
65
 
66
66
  const handleRequest = (config: InternalAxiosRequestConfig) => {
67
67
  const token = getToken()
68
68
  const lang = localStorage.getItem(_options.langKey)
69
- const env = localStorage.getItem(LOCAL_BASE_API)
69
+ const localBaseApi = localStorage.getItem(LOCAL_BASE_API)
70
70
 
71
71
  if (lang) {
72
72
  config.headers[_options.langKey] = lang
73
73
  }
74
74
 
75
- if (env && !config.url.startsWith(env)) {
75
+ if (localBaseApi && !config.baseURL) {
76
76
  const _url = config.url.startsWith('/') ? config.url : `/${config.url}`
77
- config.url = env + _url
77
+ config.url = localBaseApi + _url
78
78
  }
79
79
 
80
80
  // 没有token,并且该接口需要token校验
package/src/websocket.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import { wsClient } from '@/utils/websocket';
1
2
  import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
2
3
  import { Observable, Subject, timer, Subscription, EMPTY } from 'rxjs';
3
4
  import { retry, catchError } from 'rxjs/operators';
4
5
  import { notification } from 'ant-design-vue';
6
+ import app from '@micro-zoe/micro-app'
7
+ import { log } from 'console';
5
8
 
6
9
  interface WebSocketMessage {
7
10
  type: string;
@@ -14,24 +17,32 @@ interface WebSocketMessage {
14
17
  }
15
18
 
16
19
  type WS_Options = {
17
- onError?: (message: WebSocketMessage) => void
20
+ onError?: (message: WebSocketMessage) => void
18
21
  }
19
22
 
23
+ const isApp = (window as any).__MICRO_APP_ENVIRONMENT__
24
+
20
25
  export class WebSocketClient {
21
26
  private ws: WebSocketSubject<WebSocketMessage> | null = null;
22
27
  private subscriptions = new Map<string, Subject<WebSocketMessage>>();
23
28
  private pendingSubscriptions = new Map<string, Subject<WebSocketMessage>>();
24
29
  private heartbeatSubscription: Subscription | null = null;
25
30
  private reconnectAttempts = 0;
26
- private readonly maxReconnectAttempts = 100;
31
+ private readonly maxReconnectAttempts = 2;
27
32
  private isConnected = false;
28
33
  private tempQueue: WebSocketMessage[] = []; // 缓存消息队列
29
34
  private url: string = '';
30
35
  private options: WS_Options = {}
36
+ private wsClient: WebSocketClient | undefined
31
37
 
32
38
  constructor(options?: WS_Options) {
33
39
  this.options = options || {};
34
40
  this.setupConnectionMonitor();
41
+ if (isApp) {
42
+ (window as any).microApp.addGlobalDataListener((data) => {
43
+ this.wsClient = data.wsClient
44
+ })
45
+ }
35
46
  }
36
47
 
37
48
  public initWebSocket(url: string) {
@@ -39,19 +50,21 @@ export class WebSocketClient {
39
50
  }
40
51
 
41
52
  private setupConnectionMonitor() {
42
- window.addEventListener('online', () => {
43
- console.log('Network is online, attempting to reconnect...');
44
- this.reconnect();
45
- });
53
+ if (!isApp) {
54
+ window.addEventListener('online', () => {
55
+ console.log('Network is online, attempting to reconnect...');
56
+ this.reconnect();
57
+ });
46
58
 
47
- window.addEventListener('offline', () => {
48
- console.log('Network is offline, caching subscriptions...');
49
- this.cacheSubscriptions();
50
- });
59
+ window.addEventListener('offline', () => {
60
+ console.log('Network is offline, caching subscriptions...');
61
+ this.cacheSubscriptions();
62
+ });
51
63
 
52
- window.addEventListener('beforeunload', () => {
53
- this.disconnect();
54
- });
64
+ window.addEventListener('beforeunload', () => {
65
+ this.disconnect();
66
+ });
67
+ }
55
68
  }
56
69
 
57
70
  private getReconnectDelay(): number {
@@ -64,6 +77,12 @@ export class WebSocketClient {
64
77
  }
65
78
 
66
79
  private setupWebSocket() {
80
+
81
+ if (isApp && this.wsClient) {
82
+ this.wsClient.setupWebSocket()
83
+ return
84
+ }
85
+
67
86
  if (this.ws || !this.url) {
68
87
  return;
69
88
  }
@@ -84,9 +103,17 @@ export class WebSocketClient {
84
103
  next: () => {
85
104
  console.log('WebSocket disconnected');
86
105
  this.isConnected = false;
87
- this.cacheSubscriptions();
88
- this.stopHeartbeat();
89
- this.reconnect();
106
+ const time = this.getReconnectDelay()
107
+ setTimeout(() => {
108
+ this.reconnectAttempts += 1;
109
+ if (this.reconnectAttempts > this.maxReconnectAttempts) {
110
+ return
111
+ }
112
+ this.cacheSubscriptions();
113
+ this.stopHeartbeat();
114
+ this.reconnect();
115
+ }, time)
116
+
90
117
  }
91
118
  }
92
119
  });
@@ -112,6 +139,10 @@ export class WebSocketClient {
112
139
  }
113
140
 
114
141
  private startHeartbeat() {
142
+ if (isApp && this.wsClient) {
143
+ this.wsClient.startHeartbeat()
144
+ return
145
+ }
115
146
  this.stopHeartbeat();
116
147
  this.heartbeatSubscription = timer(0, 2000).subscribe(() => {
117
148
  this.send({ type: 'ping' });
@@ -119,6 +150,11 @@ export class WebSocketClient {
119
150
  }
120
151
 
121
152
  private stopHeartbeat() {
153
+ if (isApp && this.wsClient) {
154
+ this.wsClient.stopHeartbeat()
155
+ return
156
+ }
157
+
122
158
  if (this.heartbeatSubscription) {
123
159
  this.heartbeatSubscription.unsubscribe();
124
160
  this.heartbeatSubscription = null;
@@ -126,16 +162,22 @@ export class WebSocketClient {
126
162
  }
127
163
 
128
164
  private handleMessage(message: WebSocketMessage) {
165
+
166
+ if (isApp && this.wsClient) {
167
+ this.wsClient.handleMessage(message)
168
+ return
169
+ }
170
+
129
171
  if (message.type === 'pong') {
130
172
  return;
131
173
  }
132
174
 
133
175
  if (message.type === 'error') {
134
- if (this.options.onError) {
135
- this.options.onError(message)
136
- } else {
137
- notification.error({ key: 'error', message: message.message });
138
- }
176
+ if (this.options.onError) {
177
+ this.options.onError(message)
178
+ } else {
179
+ notification.error({ key: 'error', message: message.message });
180
+ }
139
181
  return;
140
182
  }
141
183
 
@@ -151,6 +193,11 @@ export class WebSocketClient {
151
193
  }
152
194
 
153
195
  private processTempQueue() {
196
+ if (isApp && this.wsClient) {
197
+ this.wsClient.processTempQueue()
198
+ return
199
+ }
200
+
154
201
  while (this.tempQueue.length > 0) {
155
202
  const message = this.tempQueue.shift();
156
203
  if (message) {
@@ -160,11 +207,19 @@ export class WebSocketClient {
160
207
  }
161
208
 
162
209
  private cacheSubscriptions() {
210
+ if (isApp && this.wsClient) {
211
+ this.wsClient.cacheSubscriptions()
212
+ return
213
+ }
163
214
  this.pendingSubscriptions = new Map(this.subscriptions);
164
215
  this.subscriptions.clear();
165
216
  }
166
217
 
167
218
  private restoreSubscriptions() {
219
+ if (isApp && this.wsClient) {
220
+ this.wsClient.restoreSubscriptions()
221
+ return
222
+ }
168
223
  this.pendingSubscriptions.forEach((subject, id) => {
169
224
  this.subscriptions.set(id, subject);
170
225
  });
@@ -172,6 +227,10 @@ export class WebSocketClient {
172
227
  }
173
228
 
174
229
  private reconnect() {
230
+ if (isApp && this.wsClient) {
231
+ this.wsClient.reconnect()
232
+ return
233
+ }
175
234
  if (!this.isConnected && navigator.onLine) {
176
235
  this.ws = null;
177
236
  this.setupWebSocket();
@@ -179,10 +238,18 @@ export class WebSocketClient {
179
238
  }
180
239
 
181
240
  public connect() {
241
+ if (isApp && this.wsClient) {
242
+ this.wsClient.connect()
243
+ return
244
+ }
182
245
  this.setupWebSocket();
183
246
  }
184
247
 
185
248
  public disconnect() {
249
+ if (isApp && this.wsClient) {
250
+ this.wsClient.disconnect()
251
+ return
252
+ }
186
253
  if (this.ws) {
187
254
  this.ws.complete();
188
255
  this.ws = null;
@@ -194,6 +261,10 @@ export class WebSocketClient {
194
261
  }
195
262
 
196
263
  public send(message: WebSocketMessage) {
264
+ if (isApp && this.wsClient) {
265
+ this.wsClient.send(message)
266
+ return
267
+ }
197
268
  if (this.ws && this.isConnected) {
198
269
  this.ws.next(message);
199
270
  } else {
@@ -202,6 +273,15 @@ export class WebSocketClient {
202
273
  }
203
274
 
204
275
  public getWebSocket(id: string, topic: string, parameter: Record<string, any> = {}): Observable<WebSocketMessage> {
276
+ console.log('getWebSocket', this.wsClient, id)
277
+ if (isApp && this.wsClient) {
278
+ return this.wsClient.getWebSocket(
279
+ id,
280
+ topic,
281
+ parameter
282
+ )
283
+ }
284
+
205
285
  const subject = new Subject<WebSocketMessage>();
206
286
  this.subscriptions.set(id, subject);
207
287
 
@@ -235,9 +315,9 @@ export class WebSocketClient {
235
315
  * .subscribe(
236
316
  * message => console.log('Received:', message)
237
317
  * );
238
- *
318
+ *
239
319
  * // 清理
240
320
  * subscription.unsubscribe();
241
- *
321
+ *
242
322
  */
243
323
  export const wsClient = new WebSocketClient();
package/src/axios.ts~ DELETED
@@ -1,359 +0,0 @@
1
- import { TOKEN_KEY, BASE_API, LOCAL_BASE_API } from '@jetlinks-web/constants'
2
- import { getToken } from '@jetlinks-web/utils'
3
- import axios from 'axios'
4
- import type {
5
- AxiosInstance,
6
- AxiosResponse,
7
- AxiosError,
8
- InternalAxiosRequestConfig,
9
- } from 'axios'
10
- import type { AxiosResponseRewrite } from '@jetlinks-web/types'
11
- import {isFunction, isObject} from 'lodash-es'
12
-
13
- interface Options {
14
-
15
- tokenExpiration: (err: AxiosError<any>, response: AxiosResponse) => void
16
- filter_url?: Array<string>
17
- code?: number
18
- codeKey?: string
19
- timeout?: number
20
- handleRequest?: () => void
21
- /**
22
- * 用以获取localstorage中的lang
23
- */
24
- langKey?: string
25
- /**
26
- * response处理函数
27
- * @param response AxiosResponse实例
28
- */
29
- handleResponse?: (response: AxiosResponse) => void
30
- /**
31
- * 错误处理函数
32
- * @param msg 错误消息
33
- * @param status 错误code
34
- * @param error 错误实例
35
- */
36
- handleError?: (msg: string, status: string | number, error: AxiosError<any>) => void
37
- requestOptions?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Record<string, any>
38
-
39
- }
40
-
41
- interface RequestOptions {
42
- url?: string
43
- method?: string
44
- params?: any
45
- data?: any
46
- [key: string]: any
47
- }
48
-
49
- let instance: AxiosInstance
50
-
51
- let _options: Options = {
52
- filter_url: [],
53
- code: 200,
54
- codeKey: 'status',
55
- timeout: 1000 * 15,
56
- handleRequest: undefined,
57
- handleResponse: undefined,
58
- handleError: undefined,
59
- langKey: 'lang',
60
- requestOptions: (config) => ({}),
61
- tokenExpiration: () => {},
62
- }
63
-
64
- const controller = new AbortController();
65
-
66
- const handleRequest = (config: InternalAxiosRequestConfig) => {
67
- const token = getToken()
68
- const lang = localStorage.getItem(_options.langKey)
69
- const env = localStorage.getItem(LOCAL_BASE_API)
70
-
71
- if (lang) {
72
- config.headers[_options.langKey] = lang
73
- }
74
-
75
- if (!config.url.startsWith(env)) {
76
- const _url = config.url.startsWith('/') ? config.url : `/${config.url}`
77
- config.url = env + _url
78
- }
79
-
80
- // 没有token,并且该接口需要token校验
81
- if (!token && !_options.filter_url?.some((url) => config.url?.includes(url))) {
82
- // 跳转登录页
83
- _options.tokenExpiration?.()
84
- return config
85
- }
86
-
87
- if (!config.headers[TOKEN_KEY]) {
88
- config.headers[TOKEN_KEY] = token
89
- }
90
-
91
- if (_options.requestOptions && isFunction(_options.requestOptions)) {
92
- const extraOptions = _options.requestOptions(config)
93
- if (extraOptions && isObject(extraOptions)) {
94
- for (const key in extraOptions) {
95
- config[key] = extraOptions[key]
96
- }
97
- }
98
- }
99
-
100
-
101
- return config
102
- }
103
-
104
- const handleResponse = (response: AxiosResponse) => {
105
-
106
- if (_options.handleResponse && isFunction(_options.handleResponse)) {
107
- return _options.handleResponse(response)
108
- }
109
-
110
- if (response.data instanceof ArrayBuffer) {
111
- return response
112
- }
113
-
114
- const status = response.data[_options.codeKey || 'status']
115
-
116
- // 增加业务接口处理成功判断方式,只需要判断返回参数包含:success为true
117
- if (
118
- typeof response.data === 'object' &&
119
- typeof response.data.success === 'undefined'
120
- ) {
121
- response.data.success = status === _options.code
122
- }
123
-
124
- return response.data
125
- }
126
-
127
- const errorHandler = (err: AxiosError<any>) => {
128
- let description = err.response?.message || 'Error'
129
- let _status: string | number = 0
130
- if (err.response) {
131
- const {data, status} = err.response
132
- _status = status
133
- switch (status) {
134
- case 400:
135
- case 403:
136
- case 500:
137
- description = (`${data?.message}`).substring(0, 90)
138
- break;
139
- case 401:
140
- description = err.response.data.result.text || '用户未登录'
141
- _options.tokenExpiration?.(err, err.response)
142
- break;
143
- case 404:
144
- description = err?.response?.data?.message || `${data?.error} ${data?.path}`
145
- break;
146
- default:
147
- break;
148
- }
149
- } else if (err.response === undefined) {
150
- description = err.message.includes('timeout') ? '接口响应超时' : err.message
151
- _status = 'timeout'
152
- }
153
-
154
- if (_options.handleError && isFunction(_options.handleError)) {
155
- _options.handleError(description, _status, err)
156
- }
157
-
158
- return Promise.reject(err)
159
- }
160
-
161
- export const crateAxios = (options: Options) => {
162
- if (options) {
163
- _options = Object.assign(_options, options)
164
- }
165
-
166
- instance = axios.create({
167
- withCredentials: false,
168
- timeout: _options.timeout,
169
- baseURL: BASE_API
170
- })
171
-
172
- instance.interceptors.request.use(
173
- handleRequest,
174
- errorHandler
175
- )
176
-
177
- instance.interceptors.response.use(
178
- handleResponse,
179
- errorHandler
180
- )
181
- }
182
-
183
- export const post = <T = any>(url: string, data: any = {}, ext?: any) => {
184
- return (instance<any, AxiosResponseRewrite<T>>({
185
- method: 'POST',
186
- url,
187
- data,
188
- ...ext,
189
- }))
190
- }
191
-
192
- export const get = <T = any>(url: string, params: any = undefined, ext?: any) => {
193
- return instance<any, AxiosResponseRewrite<T>>({
194
- method: 'GET',
195
- url,
196
- params,
197
- ...ext,
198
- })
199
- }
200
-
201
- export const put = <T = any>(url: string, data: any = {}, ext?: any) => {
202
- return instance<any, AxiosResponseRewrite<T>>({
203
- method: 'PUT',
204
- url,
205
- data,
206
- ...ext,
207
- })
208
- }
209
-
210
- export const patch = <T = any>(url: string, data: any = {}, ext?: any) => {
211
- return instance<any, AxiosResponseRewrite<T>>({
212
- method: 'patch',
213
- url,
214
- data,
215
- ...ext,
216
- })
217
- }
218
-
219
- export const remove = <T = any>(url: string, params: any = undefined, ext?: any) => {
220
- return instance<any, AxiosResponseRewrite<T>>({
221
- method: 'DELETE',
222
- url,
223
- params,
224
- ...ext,
225
- })
226
- }
227
-
228
- export const getStream = (url: string, params?: any, ext?: any) => {
229
- return get(url, params, { responseType: 'arraybuffer', ...ext })
230
- }
231
-
232
- export const postStream = (url: string, data: any, ext?: any) => {
233
- return post(url, data, { responseType: 'arraybuffer', ...ext })
234
- }
235
-
236
- export const request = {
237
- post, get, put, patch, remove, getStream, postStream
238
- }
239
-
240
- export class Request {
241
- modulePath: string
242
-
243
- constructor(modulePath: string) {
244
- this.modulePath = modulePath
245
- }
246
-
247
- /**
248
- * 分页查询
249
- * @param {object} data 查询参数
250
- * @param {object} options 请求配置
251
- * @returns {Promise<AxiosResponse<any>>} 分页查询结果
252
- */
253
- page(data: any={}, options: RequestOptions= {
254
- url: undefined,
255
- method: undefined,
256
- }) {
257
- const { url='/_query', method = 'post', ...rest } = options
258
- return request[method](`${this.modulePath}${url}`, data, rest)
259
- }
260
-
261
- /**
262
- * 不分页查询
263
- * @param {object} data 查询参数
264
- * @param {object} options 请求配置
265
- * @returns {Promise<AxiosResponse<any>>} 不分页查询结果
266
- */
267
- noPage(data: any={}, options: RequestOptions = {
268
- url: undefined,
269
- method: undefined,
270
- }) {
271
- const { url='/_query/no-page', method = 'post', ...rest } = options
272
- return request[method](`${this.modulePath}${url}`, { paging: false, ...data}, rest)
273
- }
274
-
275
- /**
276
- * 详情查询
277
- * @param {string} id 详情ID
278
- * @param {object} params 查询参数
279
- * @param {object} options 请求配置
280
- * @returns {Promise<AxiosResponse<any>>} 详情查询结果
281
- */
282
- detail(id: string, params?: any, options: RequestOptions= {
283
- url: undefined,
284
- method: undefined,
285
- }) {
286
- const { url=`/${id}/detail`, method = 'get', ...rest } = options
287
- return request[method](`${this.modulePath}${url}`, params, rest)
288
- }
289
-
290
- /**
291
- * 保存
292
- * @param {object} data 保存参数
293
- * @param {object} options 请求配置
294
- * @returns {Promise<AxiosResponse<any>>} 保存结果
295
- */
296
- save(data: any={}, options: RequestOptions = {
297
- url: undefined,
298
- method: undefined,
299
- }) {
300
- const { url=``, method = 'post', ...rest } = options
301
- return request[method](`${this.modulePath}${url}`, data, rest)
302
- }
303
-
304
- /**
305
- * 更新
306
- * @param {object} data 更新参数
307
- * @param {object} options 请求配置
308
- * @returns {Promise<AxiosResponse<any>>} 更新结果
309
- */
310
- update(data: any={}, options: RequestOptions = {
311
- url: undefined,
312
- method: undefined,
313
- }) {
314
- const { url=``, method = 'patch', ...rest } = options
315
- return patch(`${this.modulePath}${url}`, data, rest)
316
- }
317
-
318
- /**
319
- * 删除
320
- * @param {string} id 删除ID
321
- * @param {object} options 请求配置
322
- * @returns {Promise<AxiosResponse<any>>} 删除结果
323
- */
324
- delete(id: string, params?: any, options: RequestOptions = {
325
- url: undefined,
326
- method: undefined,
327
- }) {
328
- const { url=`/${id}`, method = 'post', ...rest } = options
329
- return remove(`${this.modulePath}${url}`, params, rest)
330
- }
331
-
332
- post(...args) {
333
- const [url, data, options] = args
334
- return post(`${this.modulePath}${url}`, data, options)
335
- }
336
-
337
- get(...args) {
338
- const [url, params, options] = args
339
- return get(`${this.modulePath}${url}`, params, options)
340
- }
341
-
342
- put(...args) {
343
- const [url, data, options] = args
344
- return put(`${this.modulePath}${url}`, data, options)
345
- }
346
-
347
- patch(...args) {
348
- const [url, data, options] = args
349
- return patch(`${this.modulePath}${url}`, data, options)
350
- }
351
-
352
- remove(...args) {
353
- const [url, params, options] = args
354
- return remove(`${this.modulePath}${url}`, params, options)
355
- }
356
- }
357
-
358
-
359
-