@lingxiteam/ebe-utils 0.0.24 → 0.0.27

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.
@@ -0,0 +1,399 @@
1
+ import {
2
+ closeProgressMsg,
3
+ openProgressMsg,
4
+ showProgressNotification,
5
+ } from '@/components/ProgressComp';
6
+ import { APPID } from '@/constants';
7
+ import engineServices from '@/services/api/engine';
8
+ import fileServices from '@/services/api/file';
9
+ import { messageApi } from '@/utils/messageApi';
10
+ import security from '@/utils/Security';
11
+ /**
12
+ * 文件保存方法
13
+ * @param data
14
+ * @param filename
15
+ */
16
+ const saveBlobFile = ({ data, fileName }: any) => {
17
+ if (typeof (window as any).chrome !== 'undefined') {
18
+ // chrome
19
+ const link = document.createElement('a');
20
+ let href = window.URL.createObjectURL(new Blob([data]));
21
+ const format = typeof fileName === 'string' && fileName.split('.').pop();
22
+ if (/(csv|xls)$/.test(format as string) && typeof data === 'string') {
23
+ href = `data:text/${format};charset=utf-8,\ufeff${encodeURIComponent(
24
+ data,
25
+ )}`;
26
+ }
27
+ link.href = href; // eslint-disable-line
28
+ link.download = fileName;
29
+ link.click();
30
+ } else if (typeof (window as any).navigator.msSaveBlob !== 'undefined') {
31
+ // ie
32
+ const blob = new Blob([data], {
33
+ type: 'application/force-download',
34
+ }); // eslint-disable-line
35
+ (window as any).navigator.msSaveBlob(blob, fileName);
36
+ } else {
37
+ // firefox
38
+ const file = new File([data], fileName, {
39
+ type: 'application/force-download',
40
+ }); // eslint-disable-line
41
+ window.open(URL.createObjectURL(file));
42
+ }
43
+ };
44
+
45
+ const getFileName = (fileContentStr: string, newFileName?: string) => {
46
+ let fileName: string = '';
47
+ let suffix: string = '';
48
+ if (fileContentStr) {
49
+ fileName =
50
+ fileContentStr.split('filename=').pop()?.replace(/\"/g, '') || '';
51
+ const result = fileContentStr.match(
52
+ /(?:.*filename\*|filename)=(?:([^'"]*)''|("))([^;]+)\2(?:[;`\n]|$)/,
53
+ );
54
+ if (result && result[3]) {
55
+ fileName = result[3].replace(/['"]/g, '').replace(/[+]/g, '%20');
56
+ }
57
+ suffix = fileName.split('.').pop() || '';
58
+ fileName = decodeURIComponent(fileName);
59
+ }
60
+
61
+ if (newFileName) {
62
+ if (!/\./.test(newFileName)) {
63
+ fileName = `${newFileName}.${suffix}`;
64
+ } else {
65
+ fileName = newFileName;
66
+ }
67
+ }
68
+ return fileName;
69
+ };
70
+
71
+ const isErrorStatus = (status: number) => {
72
+ switch (status) {
73
+ case 400:
74
+ case 401:
75
+ case 403:
76
+ case 404:
77
+ case 500:
78
+ case 501:
79
+ case 502:
80
+ case 503:
81
+ case 413:
82
+ return true;
83
+ default:
84
+ return false;
85
+ }
86
+ };
87
+
88
+ const exportServiceMap = {
89
+ sql: engineServices.exportSqlDatasByAsync,
90
+ object: engineServices.exportInstsByAsync,
91
+ multiExport: engineServices.exportMultiServiceResultByAsync,
92
+ };
93
+
94
+ const exportPathMap = {
95
+ sql: engineServices.exportSqlDatasApiPath(),
96
+ object: engineServices.exportInstsApiPath(),
97
+ multiExport: engineServices.exportMultiServiceResultPath(),
98
+ };
99
+ const downloadByXMLHttpRequest = (params: {
100
+ newFileName?: string;
101
+ onError?: any;
102
+ methodPath: string;
103
+ downloadIndex?: string;
104
+ }) => {
105
+ const { newFileName, onError, methodPath, downloadIndex } = params;
106
+
107
+ if (window.XMLHttpRequest) {
108
+ const xhr = new XMLHttpRequest(); // ActiveXObject只存在于IE7及以下,无需兼容
109
+ xhr.open('GET', methodPath, true);
110
+ xhr.responseType = 'blob'; // 设置接受类型
111
+ const headers: any = {
112
+ 'Content-Type': 'application/json',
113
+ // 'X-B-TARGET-ID': pageId,
114
+ 'X-B-AUTH': '1',
115
+ 'APP-ID': APPID,
116
+ };
117
+ Object.keys(headers).forEach((header) => {
118
+ xhr.setRequestHeader(header, headers[header]); // 设置请求头参数
119
+ });
120
+ xhr.setRequestHeader(
121
+ 'X-SIGN',
122
+ security.createHttpSignStr(methodPath, {
123
+ method: 'GET',
124
+ headers,
125
+ body: '',
126
+ search: '',
127
+ }),
128
+ );
129
+ xhr.withCredentials = true;
130
+ xhr.onprogress = (evt) => {
131
+ // 展示下载进度条
132
+ if (evt.lengthComputable) {
133
+ const percentComplete = Math.round((evt.loaded * 100) / evt.total);
134
+ openProgressMsg(downloadIndex, newFileName, percentComplete, '下载');
135
+ }
136
+ };
137
+ xhr.onload = async () => {
138
+ const data = xhr.response; // 获取响应体数据
139
+ if (xhr.status === 200) {
140
+ const fileName: string = getFileName(
141
+ xhr.getResponseHeader('Content-Disposition') || '',
142
+ newFileName,
143
+ );
144
+ saveBlobFile({
145
+ data,
146
+ fileName,
147
+ });
148
+ } else if (isErrorStatus(xhr.status)) {
149
+ messageApi.error('下载失败');
150
+ } else {
151
+ const errMessage = data;
152
+ let errorMessage = '';
153
+ try {
154
+ errorMessage = JSON.parse(errMessage)?.message || '下载失败';
155
+ } catch {
156
+ errorMessage = '下载失败';
157
+ }
158
+ messageApi.error(errorMessage);
159
+ if (typeof onError === 'function') {
160
+ onError(errorMessage);
161
+ }
162
+ }
163
+ closeProgressMsg(downloadIndex);
164
+ };
165
+ xhr.ontimeout = () => {
166
+ xhr.abort(); // 取消请求
167
+ };
168
+ xhr.send();
169
+ }
170
+ };
171
+
172
+ /**
173
+ * 批量文件下载
174
+ * @param fileId
175
+ * @param newFileName
176
+ * @param onError
177
+ * @param messageApi
178
+ * @param zip
179
+ */
180
+ const batchDownloadFileByIds = (params: any) => {
181
+ const { fileIds, zip } = params;
182
+
183
+ downloadByXMLHttpRequest({
184
+ methodPath: fileServices.batchDownloadFileByIds(fileIds, { zip }),
185
+ downloadIndex: `${fileIds}_${Math.random()}`,
186
+ ...params,
187
+ });
188
+ };
189
+ // 异步导出文件并显示进度
190
+ export const exportFileShowProgressAsync = async (exportParams: any) => {
191
+ const {
192
+ fileOrigin,
193
+ fileName,
194
+ params = {},
195
+ onSuccess,
196
+ onFail,
197
+ downloadIndex,
198
+ } = exportParams;
199
+ let timeoutId: number | null = null;
200
+ let percent = 0;
201
+ let isStop = false;
202
+ // @ts-ignore
203
+ const serviceApi = exportServiceMap[fileOrigin];
204
+ const applyId = await serviceApi(params, {});
205
+ const messageConfig = {
206
+ title: fileName ? `导出-${fileName}` : undefined,
207
+ key: downloadIndex,
208
+ onCancel: () => {
209
+ if (timeoutId) {
210
+ isStop = true;
211
+ clearTimeout(timeoutId);
212
+ }
213
+ },
214
+ };
215
+ const requestProgress = async (isPolled = true) => {
216
+ try {
217
+ const { fileId, statusCd, requestJson, responseJson, failReason } =
218
+ await engineServices.getImportExportApply({ applyId }, {});
219
+ // 点击取消时候刚好触发了下一次接口,接口未回调时
220
+ if (isStop) return -1;
221
+ let requestObj: {
222
+ descriptor?: {
223
+ [key: string]: any;
224
+ };
225
+ } = {};
226
+ let responseObj: {
227
+ total?: number;
228
+ currentCount?: number;
229
+ } = {};
230
+ try {
231
+ requestObj = JSON.parse(requestJson) || {};
232
+ responseObj = JSON.parse(responseJson) || {};
233
+ } catch (e) {
234
+ console.log(e);
235
+ }
236
+ let showLoading: boolean = false;
237
+ const { total = 0, currentCount = 0 } = responseObj;
238
+ if (!responseJson || (percent === 100 && statusCd === 1)) {
239
+ // 上一次导出进程还未结束,无法返回进度
240
+ // 已经导出完全但进程还未结束
241
+ showLoading = true;
242
+ } else {
243
+ percent = +((+currentCount / +total) * 100).toFixed(2);
244
+ }
245
+ showProgressNotification({
246
+ ...messageConfig,
247
+ message: showLoading
248
+ ? undefined
249
+ : `总记录${total}条,已生成数据${currentCount}条,剩余${
250
+ total - currentCount
251
+ }条完成到处。`,
252
+ percent,
253
+ showLoading,
254
+ loadingText:
255
+ percent === 100
256
+ ? 'export.process.downloading'
257
+ : 'export.process.handling',
258
+ });
259
+ if (statusCd === 1 && isPolled) {
260
+ polledRequest();
261
+ } else if (statusCd === 10) {
262
+ onSuccess?.();
263
+ showProgressNotification({
264
+ ...messageConfig,
265
+ percent: 100,
266
+ btn: () => null,
267
+ duration: 1,
268
+ });
269
+ if (fileId) {
270
+ const newFileName: string | undefined =
271
+ fileName || requestObj?.descriptor?.filename;
272
+ batchDownloadFileByIds({
273
+ fileIds: fileId,
274
+ newFileName,
275
+ onError: (errorMessage: any) => {
276
+ messageApi.error(errorMessage);
277
+ },
278
+ });
279
+ }
280
+ } else if (statusCd === -1) {
281
+ showProgressNotification({
282
+ ...messageConfig,
283
+ type: 'error',
284
+ percent,
285
+ message: failReason || '导出失败,稍后请重试。',
286
+ btn: () => null,
287
+ duration: 2,
288
+ });
289
+ onFail?.();
290
+ }
291
+ return statusCd;
292
+ } catch (e) {
293
+ onFail?.();
294
+ return -1;
295
+ }
296
+ };
297
+ const polledRequest = (requestFlag = false) => {
298
+ if (applyId && (timeoutId || requestFlag)) {
299
+ timeoutId = window.setTimeout(async () => {
300
+ await requestProgress();
301
+ }, 1500);
302
+ }
303
+ };
304
+ const status = await requestProgress(false);
305
+ if (status === 1) {
306
+ // 如果未导出则定时轮询
307
+ polledRequest(true);
308
+ }
309
+ };
310
+ // 导出文件显示进度条
311
+ export const exportFileShowProgress = async (exportParams: {
312
+ fileOrigin: any;
313
+ methodType?: 'POST' | undefined;
314
+ fileName: any;
315
+ params?: {} | undefined;
316
+ onSuccess?: any;
317
+ onFail?: any;
318
+ downloadIndex: any;
319
+ async: any;
320
+ }) => {
321
+ const {
322
+ fileOrigin,
323
+ methodType = 'POST',
324
+ fileName,
325
+ params = {},
326
+ onSuccess,
327
+ onFail,
328
+ downloadIndex,
329
+ async,
330
+ } = exportParams;
331
+
332
+ const _downloadIndex = downloadIndex || `${fileName}_${Math.random()}`;
333
+ if (async === 'async') {
334
+ await exportFileShowProgressAsync({
335
+ ...exportParams,
336
+ downloadIndex: _downloadIndex,
337
+ });
338
+ return;
339
+ }
340
+
341
+ if (fileOrigin && window.XMLHttpRequest) {
342
+ const xhr = new XMLHttpRequest(); // ActiveXObject只存在于IE7及以下,无需兼容
343
+ // @ts-ignore
344
+ const methodPath = exportPathMap[fileOrigin];
345
+ xhr.open(methodType, methodPath, true);
346
+ xhr.responseType = 'blob'; // 设置接受类型
347
+ const headers: any = {
348
+ 'Content-Type': 'application/json',
349
+ // 'X-B-TARGET-ID': pageId,
350
+ 'X-B-AUTH': '1',
351
+ 'APP-ID': APPID,
352
+ };
353
+ Object.keys(headers).forEach((header) => {
354
+ xhr.setRequestHeader(header, headers[header]); // 设置请求头参数
355
+ });
356
+ xhr.setRequestHeader(
357
+ 'X-SIGN',
358
+ security.createHttpSignStr(methodPath, {
359
+ method: methodType,
360
+ headers,
361
+ body: JSON.stringify(params) || '',
362
+ search: '',
363
+ }),
364
+ );
365
+ xhr.withCredentials = true;
366
+ xhr.onprogress = (evt) => {
367
+ // 展示下载进度条
368
+ if (evt.lengthComputable) {
369
+ const percentComplete = Math.round((evt.loaded * 100) / evt.total);
370
+ openProgressMsg(_downloadIndex, fileName, percentComplete, '导出');
371
+ }
372
+ };
373
+ xhr.onload = async () => {
374
+ const data = xhr.response; // 获取响应体数据
375
+ if (xhr.status === 200) {
376
+ saveBlobFile({
377
+ data,
378
+ fileName: getFileName(
379
+ xhr.getResponseHeader('Content-Disposition') || '',
380
+ fileName,
381
+ ),
382
+ });
383
+ if (typeof onSuccess === 'function') {
384
+ onSuccess();
385
+ }
386
+ } else if (typeof onFail === 'function') {
387
+ onFail();
388
+ } else {
389
+ messageApi.error('导出失败');
390
+ }
391
+ closeProgressMsg(_downloadIndex);
392
+ };
393
+ xhr.ontimeout = () => {
394
+ closeProgressMsg(_downloadIndex);
395
+ xhr.abort(); // 取消请求
396
+ };
397
+ xhr.send(JSON.stringify(params));
398
+ }
399
+ };
@@ -68,26 +68,31 @@ const transformContent = (value: string) => {
68
68
  }
69
69
  return finalContent;
70
70
  };
71
- const messageApi = (
72
- type: 'info' | 'success' | 'error' | 'warning' | 'loading' | 'warn',
73
- content: string,
74
- duration?: number,
75
- ) => {
76
- switch (type) {
77
- case 'info':
78
- return message.info(transformContent(content), duration);
79
- case 'success':
80
- return message.success(transformContent(content), duration);
81
- case 'error':
82
- return message.error(transformContent(content), duration);
83
- case 'warning':
84
- case 'warn':
85
- return message.warning(transformContent(content), duration);
86
- case 'loading':
87
- return message.loading(transformContent(content), duration);
88
- default:
89
- return message.info(transformContent(content), duration);
90
- }
71
+ const messageApi = {
72
+ info: (content: string, duration?: number) => {
73
+ return message.info(transformContent(content), duration);
74
+ },
75
+ success: (content: string, duration?: number) => {
76
+ return message.success(transformContent(content), duration);
77
+ },
78
+ error: (content: string, duration?: number) => {
79
+ return message.error(transformContent(content), duration);
80
+ },
81
+ warning: (content: string, duration?: number) => {
82
+ return message.warning(transformContent(content), duration);
83
+ },
84
+ warn: (content: string, duration?: number) => {
85
+ return message.warning(transformContent(content), duration);
86
+ },
87
+ loading: (content: string, duration?: number) => {
88
+ return message.loading(transformContent(content), duration);
89
+ },
90
+ destroy: () => {
91
+ return message.destroy();
92
+ },
93
+ hidden: () => {
94
+ return message.destroy();
95
+ },
91
96
  };
92
97
 
93
98
  const MessageApiModal = Modal;