@epxing/core 5.3.0-beta.2 → 5.3.0-beta.3
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/API.md +26 -25
- package/README.md +3 -1
- package/dist/.cache/route-chart-release/frontend/frame/public/js/ecStat.min.js +4 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts-wordcloud.min.js +4 -0
- package/dist/.cache/route-chart-release/frontend/frame/public/js/echarts.min.js +4 -0
- package/dist/_virtual/_plugin-vue_export-helper.js +10 -0
- package/dist/_virtual/jsencrypt.min.js +1 -1
- package/dist/assets/ecStat.min-BrTYPOXX.js +1 -0
- package/dist/assets/echarts-wordcloud.min-nWR4Hzny.js +3 -0
- package/dist/assets/echarts.min-DROS9E5X.js +45 -0
- package/dist/assets/role_select-DTqRlFNz.webp +0 -0
- package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/jsencrypt@3.5.4/_vendor/jsencrypt/bin/jsencrypt.min.js +1 -1
- package/dist/src/RootApp.js +54 -0
- package/dist/src/api/createHttp.js +6 -0
- package/dist/src/app-ui-settings.js +49 -0
- package/dist/src/axios.js +10 -15
- package/dist/src/chart-runtime-assets.js +9 -0
- package/dist/src/create-app.js +3 -6
- package/dist/src/index.js +2 -0
- package/dist/src/loadComponent.js +2 -2
- package/dist/src/menu-route.js +11 -0
- package/dist/src/mixins/component.js +3 -0
- package/dist/src/navigation-context.js +47 -0
- package/dist/src/navigation.js +43 -12
- package/dist/src/package-install.js +3 -2
- package/dist/src/plugins/element-plus.js +8 -8
- package/dist/src/public-api.js +4 -2
- package/dist/src/route-components.js +9 -0
- package/dist/src/router/config.js +7 -8
- package/dist/src/runtime-services.js +1 -1
- package/dist/src/runtime-utils/meta.js +3 -0
- package/dist/src/runtime-utils/pdf.viewer.js +31 -15
- package/dist/src/runtime-utils/util.js +29 -5
- package/dist/src/shared-packages.js +1 -3
- package/dist/src/store/modules/list.js +25 -3
- package/dist/src/store/modules/meta.js +49 -7
- package/dist/src/style-presets.js +4 -4
- package/dist/src/ui-settings.js +90 -18
- package/dist/src/views/App.js +48 -0
- package/dist/src/views/AppRoleSelect.js +233 -0
- package/dist/src/views/Error.js +210 -0
- package/dist/src/views/Module.js +173 -0
- package/dist/style.css +251 -0
- package/package.json +4 -4
- package/src/RootApp.vue +75 -0
- package/src/api/createHttp.js +7 -0
- package/src/api/index.js +47 -47
- package/src/app-ui-settings.js +31 -0
- package/src/axios.js +311 -318
- package/src/chart-runtime-assets.js +7 -0
- package/src/create-app.js +3 -7
- package/src/index.js +28 -28
- package/src/install.js +157 -157
- package/src/loadComponent.js +187 -187
- package/src/loadLibrary.js +99 -99
- package/src/menu-route.js +12 -1
- package/src/mixins/component.js +1464 -1461
- package/src/navigation-context.js +49 -0
- package/src/navigation.js +208 -176
- package/src/package-install.js +2 -1
- package/src/plugins/element-plus.js +302 -302
- package/src/plugins/frame.js +178 -178
- package/src/public-api.js +1 -0
- package/src/route-components.js +7 -0
- package/src/router/config.js +861 -864
- package/src/router/public.js +1 -1
- package/src/runtime-services.js +1 -1
- package/src/runtime-utils/fieldFactory.js +179 -179
- package/src/runtime-utils/meta.js +399 -378
- package/src/runtime-utils/pdf.viewer.js +672 -644
- package/src/runtime-utils/util.js +1357 -1330
- package/src/shared-packages.js +1 -3
- package/src/store/modules/config.js +351 -351
- package/src/store/modules/list.js +30 -3
- package/src/store/modules/locale.js +236 -236
- package/src/store/modules/meta.js +314 -265
- package/src/style-presets.js +4 -4
- package/src/ui-settings.js +84 -23
- package/src/views/App.vue +53 -0
- package/src/views/AppRoleSelect.vue +334 -0
- package/src/views/Error.vue +63 -0
- package/src/views/Module.vue +210 -0
- package/src/xss.js +26 -26
- package/types/app.d.ts +10 -10
- package/types/axios.d.ts +1 -1
- package/types/component-mixin.d.ts +1 -1
- package/types/field-factory.d.ts +1 -1
- package/types/global-mixin.d.ts +1 -1
- package/types/http.d.ts +1 -1
- package/types/index.d.ts +3 -0
- package/types/meta.d.ts +1 -1
- package/types/navigation.d.ts +21 -21
- package/types/pdf-viewer.d.ts +1 -1
- package/types/runtime.d.ts +13 -13
- package/types/store.d.ts +1 -1
- package/types/util.d.ts +2 -2
- /package/dist/{build → .cache/route-chart-release/frontend/frame/build}/stubs/empty-components.js +0 -0
- /package/dist/{src → .cache/route-chart-release/frontend/frame/src}/element-icons.names.js +0 -0
- /package/dist/{src → .cache/route-chart-release/frontend/frame/src}/element-plus.lazy.js +0 -0
- /package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/element-plus@2.14.3_vue@3.5.39_typescript@5.9.3_/_vendor/element-plus/dist/locale/en.js +0 -0
- /package/dist/{_vendor → frontend/frame/_vendor}/.pnpm/element-plus@2.14.3_vue@3.5.39_typescript@5.9.3_/_vendor/element-plus/dist/locale/zh-cn.js +0 -0
|
@@ -1,1330 +1,1357 @@
|
|
|
1
|
-
// import _router from '@epxing/core/src/router'
|
|
2
|
-
// 不 import store:本文件运行时全部经 window.store(store/index.js 挂载)访问。
|
|
3
|
-
// 原 import 是死导入,且构成 utils→store 反向边(4 个循环依赖的共同主干,P4 拆包 @epxing/utils 必须为叶子)。
|
|
4
|
-
import storage, { getXsrfToken } from '@epxing/utils/src/storage'
|
|
5
|
-
import { consumeUrlToken as consumeStoredUrlToken, getStoredToken, setStoredToken, removeStoredToken } from '@epxing/utils/src/token-storage'
|
|
6
|
-
import { isEqual, cloneDeep, isNil } from 'lodash-es'
|
|
7
|
-
import * as formula from '@epxing/utils/src/formula'
|
|
8
|
-
import { evalWith } from '@epxing/utils/src/eval-with'
|
|
9
|
-
import { useVuePlugin, getApp } from '@epxing/core/src/app'
|
|
10
|
-
// 纯函数层,零依赖(见 menu-route.js 头注释)——不会与 core 成环
|
|
11
|
-
import { resolveRouteRole } from '@epxing/core/src/menu-route'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
const {
|
|
70
|
-
const {
|
|
71
|
-
const {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
let
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const {
|
|
132
|
-
const {
|
|
133
|
-
const {
|
|
134
|
-
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
const {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
window.openedPopup
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const {
|
|
175
|
-
const {
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
window.store.commit('
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
delete query.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
client
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
image
|
|
218
|
-
|
|
219
|
-
canvas
|
|
220
|
-
canvas.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
image.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (id
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const {
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const {
|
|
278
|
-
const {
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const {
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const {
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const {
|
|
340
|
-
const {
|
|
341
|
-
const
|
|
342
|
-
const
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const {
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
//
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
frame.
|
|
410
|
-
frame.
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
removed
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
doc.
|
|
425
|
-
doc.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
//
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
listen(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
win.
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
listen(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
.then(
|
|
479
|
-
|
|
480
|
-
const
|
|
481
|
-
canvas
|
|
482
|
-
canvas.
|
|
483
|
-
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
//
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
case '
|
|
564
|
-
case '
|
|
565
|
-
case '
|
|
566
|
-
case 'currentDate
|
|
567
|
-
case 'currentDate.
|
|
568
|
-
case 'currentDate.
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
.
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
var
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
script
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
//
|
|
680
|
-
//
|
|
681
|
-
//
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
script
|
|
708
|
-
script.
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
//
|
|
718
|
-
//
|
|
719
|
-
//
|
|
720
|
-
//
|
|
721
|
-
//
|
|
722
|
-
//
|
|
723
|
-
//
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
//
|
|
733
|
-
//
|
|
734
|
-
//
|
|
735
|
-
//
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
//
|
|
754
|
-
//
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
var
|
|
768
|
-
var
|
|
769
|
-
var
|
|
770
|
-
var
|
|
771
|
-
var
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
node.
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
* @param
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
//
|
|
853
|
-
//
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
var
|
|
876
|
-
var
|
|
877
|
-
var
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
resolve(window.T)
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
.then(() => {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
const
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
return
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1
|
+
// import _router from '@epxing/core/src/router'
|
|
2
|
+
// 不 import store:本文件运行时全部经 window.store(store/index.js 挂载)访问。
|
|
3
|
+
// 原 import 是死导入,且构成 utils→store 反向边(4 个循环依赖的共同主干,P4 拆包 @epxing/utils 必须为叶子)。
|
|
4
|
+
import storage, { getXsrfToken } from '@epxing/utils/src/storage'
|
|
5
|
+
import { consumeUrlToken as consumeStoredUrlToken, getStoredToken, setStoredToken, removeStoredToken } from '@epxing/utils/src/token-storage'
|
|
6
|
+
import { isEqual, cloneDeep, isNil } from 'lodash-es'
|
|
7
|
+
import * as formula from '@epxing/utils/src/formula'
|
|
8
|
+
import { evalWith } from '@epxing/utils/src/eval-with'
|
|
9
|
+
import { useVuePlugin, getApp } from '@epxing/core/src/app'
|
|
10
|
+
// 纯函数层,零依赖(见 menu-route.js 头注释)——不会与 core 成环
|
|
11
|
+
import { resolveRouteRole } from '@epxing/core/src/menu-route'
|
|
12
|
+
import chartRuntimeAssets, { wordcloudUrl } from '../chart-runtime-assets'
|
|
13
|
+
// 安装旧库会等待兼容模块的动态 import;并发 script.onload 必须共享同一次安装。
|
|
14
|
+
const installingLibraries = new Map()
|
|
15
|
+
class Util {
|
|
16
|
+
constructor () {
|
|
17
|
+
this.sysId = ''
|
|
18
|
+
this.loadPlugins = {}
|
|
19
|
+
this.loadSystemLibrarys = {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getSysId () {
|
|
23
|
+
const searchSysId = this.search('FM_SYS_ID', window.location.search)
|
|
24
|
+
const hashSysId = this.search('FM_SYS_ID')
|
|
25
|
+
return hashSysId || searchSysId
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setSysId (sysId) {
|
|
29
|
+
const { CLIENT_ID = '' } = window.store.state.config
|
|
30
|
+
storage.set('EPX_FM_SYS_ID-' + CLIENT_ID, sysId)
|
|
31
|
+
this.sysId = sysId
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getPublicPath () {
|
|
35
|
+
return window.ROUTER_MODE === 'history' ? window.BASE_URL || '/' : './'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 运行时动态加载的三方库(echarts/pdf/tinymce/signature_pad 等)所在目录,相对 publicPath。
|
|
39
|
+
// 默认 'js/' —— 产品项目脚手架的 public/js 构建后就在 dist/js/,行为不变;
|
|
40
|
+
// 本平台把静态资源归入 dist/assets/js/,由其 config.js 注入 window.STATIC_JS_DIR 覆盖。
|
|
41
|
+
getStaticJsDir () {
|
|
42
|
+
return window.STATIC_JS_DIR || 'js/'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getRootPath () {
|
|
46
|
+
if (window.ROUTER_MODE === 'history') {
|
|
47
|
+
const reg = /\/((app|hall|login|system|page|s|task|feishuTask)\/.+)/g
|
|
48
|
+
return location.origin + (location.pathname === '/' ? '' : location.pathname.replace(reg, ''))
|
|
49
|
+
}
|
|
50
|
+
return location.origin + location.pathname + (location.pathname.endsWith('/') ? '#' : '/#')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getRoutePath () {
|
|
54
|
+
const router = window.router
|
|
55
|
+
const { fullPath } = router.currentRoute.value || {}
|
|
56
|
+
let path = fullPath
|
|
57
|
+
if (!path || path === '/') {
|
|
58
|
+
path = window.ROUTER_MODE === 'history' ? location.pathname : location.hash
|
|
59
|
+
const reg = /\/((app|hall|login|system|page|s|task|feishuTask)\/.+)/g
|
|
60
|
+
const flag = reg.exec(path)
|
|
61
|
+
if (flag) return RegExp.$1
|
|
62
|
+
}
|
|
63
|
+
return path
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getClientCode () {
|
|
67
|
+
// 1. 当前路由里取 2. clientConfig 2.当前路径中取- 判断是history还是hash
|
|
68
|
+
const router = window.router
|
|
69
|
+
const { params = {} } = router.currentRoute.value || {}
|
|
70
|
+
const { config = {} } = window.store.state || {}
|
|
71
|
+
const { clientConfig = {} } = config
|
|
72
|
+
const { CODE } = clientConfig
|
|
73
|
+
const clientCode = params.client || CODE
|
|
74
|
+
if (!clientCode) {
|
|
75
|
+
const path = this.getRoutePath()
|
|
76
|
+
let reg = /app\/role\/select\/(\w+)/
|
|
77
|
+
let regResult = reg.exec(path)
|
|
78
|
+
if (!regResult) {
|
|
79
|
+
reg = /[login|app|hall|system|client]\/(\w+)/
|
|
80
|
+
regResult = reg.exec(path)
|
|
81
|
+
}
|
|
82
|
+
return RegExp.$1
|
|
83
|
+
}
|
|
84
|
+
return clientCode
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
setToken (v, routeClientCode) {
|
|
88
|
+
const clientCode = routeClientCode || this.getClientCode()
|
|
89
|
+
setStoredToken(`${clientCode}-token`, v)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getToken (routeClientCode) {
|
|
93
|
+
const clientCode = routeClientCode || this.getClientCode()
|
|
94
|
+
return getStoredToken(`${clientCode}-token`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
removeToken (routeClientCode) {
|
|
98
|
+
const clientCode = routeClientCode || this.getClientCode()
|
|
99
|
+
removeStoredToken(`${clientCode}-token`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
consumeUrlToken (routeClientCode) {
|
|
103
|
+
const clientCode = routeClientCode || this.getClientCode()
|
|
104
|
+
return consumeStoredUrlToken(clientCode ? `${clientCode}-token` : '')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
search (name, path) {
|
|
108
|
+
if (!name) {
|
|
109
|
+
const searchStr = (path || window.location.hash || window.location.search).split('?')[1]
|
|
110
|
+
if (!searchStr) return
|
|
111
|
+
const searchArray = searchStr.split('&')
|
|
112
|
+
const searchObj = {}
|
|
113
|
+
searchArray.map(item => {
|
|
114
|
+
const key = item.split('=')[0]
|
|
115
|
+
const value = item.split('=')[1]
|
|
116
|
+
searchObj[key] = value
|
|
117
|
+
})
|
|
118
|
+
return searchObj
|
|
119
|
+
}
|
|
120
|
+
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
|
|
121
|
+
const searchStr = '?' + (path || window.location.hash || window.location.search).split('?')[1]
|
|
122
|
+
const r = searchStr.substr(1).match(reg)
|
|
123
|
+
if (r != null) {
|
|
124
|
+
return unescape(r[2])
|
|
125
|
+
} else {
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getCurrentLanguage (routeClientCode) {
|
|
131
|
+
const { config = {}, user = {} } = window.store.state || {}
|
|
132
|
+
const { clientConfig = {} } = config
|
|
133
|
+
const { userInfo = {} } = user
|
|
134
|
+
const { locale = {} } = window.store.state || {}
|
|
135
|
+
// 全仓字段名是 LANGUAGE_DEFAULT(20+ 处一致,ClientFormItem.vue 里它是真实的数据库
|
|
136
|
+
// attriName),这里原来错写成 DEFAULT_LANGUAGE,兜底分支因此恒为 undefined,已改正
|
|
137
|
+
const { CODE: configuredClientCode, LANGUAGE_DEFAULT: defaultLanguage } = clientConfig
|
|
138
|
+
const { LANGUAGE: userLanguage } = userInfo
|
|
139
|
+
const clientCode = routeClientCode || configuredClientCode
|
|
140
|
+
// INITIALIZE_LOCALE(store/modules/locale.js)已落地当前语言时优先取它——它是唯一同时
|
|
141
|
+
// 兼顾"客户是否启用多语言""用户/浏览器偏好""受支持语言集合"三者的权威来源
|
|
142
|
+
if (locale.clientCode === clientCode && locale.currentLocale) return locale.currentLocale
|
|
143
|
+
const storedLanguage = storage.get((clientCode || '') + '-language')
|
|
144
|
+
// routeClientCode 指定了别的客户(如引导期还没切到当前客户)时,不能用本客户的
|
|
145
|
+
// user/默认语言兜底——那两个值语义上属于 configuredClientCode,答非所问
|
|
146
|
+
const canUseLoadedDefaults = !routeClientCode || routeClientCode === configuredClientCode
|
|
147
|
+
return storedLanguage || (canUseLoadedDefaults ? userLanguage || defaultLanguage : '') || 'zh-CN'
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
setCurrentLanguage (language) {
|
|
151
|
+
return window.store.dispatch('CHANGE_LOCALE', language)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
isChineseLanguage (language = this.getCurrentLanguage()) {
|
|
155
|
+
return language === '010' || /^zh(?:-|$)/i.test(language || '')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
toPx (v) {
|
|
159
|
+
if (v) {
|
|
160
|
+
const str = String(v)
|
|
161
|
+
return str.includes('px') ? str : str + 'px'
|
|
162
|
+
}
|
|
163
|
+
return ''
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 返回登陆页
|
|
167
|
+
toLogin (clearPath) {
|
|
168
|
+
const router = window.router
|
|
169
|
+
if (window.openedPopup && window.openedPopup.length > 0) {
|
|
170
|
+
window.openedPopup.forEach(item => item.close())
|
|
171
|
+
window.openedPopup = []
|
|
172
|
+
}
|
|
173
|
+
// 获取当前应用信息
|
|
174
|
+
const { config = {} } = window.store.state || {}
|
|
175
|
+
const { appConfig = {} } = config
|
|
176
|
+
const { fullPath, params = {} } = router.currentRoute.value || {}
|
|
177
|
+
const clientCode = this.getClientCode()
|
|
178
|
+
const system = params.system || appConfig['SYSTEM|CODE']
|
|
179
|
+
const app = appConfig.CODE || params.app
|
|
180
|
+
|
|
181
|
+
this.removeToken()
|
|
182
|
+
|
|
183
|
+
window.store.commit('DELETE_USER')
|
|
184
|
+
window.store.commit('DELETE_TABS')
|
|
185
|
+
const path = this.getRoutePath()
|
|
186
|
+
// 删除_token参数
|
|
187
|
+
const pathname = path.split('?')[0]
|
|
188
|
+
if (fullPath && !fullPath.includes('/login')) {
|
|
189
|
+
const query = {}
|
|
190
|
+
let _path = ''
|
|
191
|
+
if (!(fullPath === '/' && pathname === '/')) {
|
|
192
|
+
_path = fullPath === '/' ? path : fullPath
|
|
193
|
+
}
|
|
194
|
+
if (_path) {
|
|
195
|
+
query.path = _path.replace(/(\?|&)(_token|client_code|client)=([\w|.]+)(&?)/g, '$1')
|
|
196
|
+
}
|
|
197
|
+
if (clearPath) delete query.path
|
|
198
|
+
delete query._token
|
|
199
|
+
router.push({
|
|
200
|
+
name: (appConfig['SYSTEM|CODE'] === 'epxing-frame' && appConfig.CODE === 'FM_SERVICE_HALL') ? 'hallLogin' : window.IP ? 'login' : 'localLogin',
|
|
201
|
+
params: {
|
|
202
|
+
// ⚠️ 键名必须是 client —— 路由定义是 /login/:client/:system/:app?。
|
|
203
|
+
// 写成 clientCode 会被 Vue Router 丢弃([Vue Router warn] Discarded invalid param(s)),
|
|
204
|
+
// 平时看不出来是因为 Router 4 按 name 跳转时会从**当前路由继承** client;
|
|
205
|
+
// 一旦当前路由没有 client(如落在 /#/),就变成 Missing required param "client" → 白屏。
|
|
206
|
+
client: clientCode,
|
|
207
|
+
system,
|
|
208
|
+
app
|
|
209
|
+
},
|
|
210
|
+
query
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
urlToBase64 (url) {
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
const image = new Image()
|
|
218
|
+
image.onload = function () {
|
|
219
|
+
const canvas = document.createElement('canvas')
|
|
220
|
+
canvas.width = this.width
|
|
221
|
+
canvas.height = this.height
|
|
222
|
+
// 将图片插入画布并开始绘制
|
|
223
|
+
canvas.getContext('2d').drawImage(image, 0, 0)
|
|
224
|
+
// result
|
|
225
|
+
const result = canvas.toDataURL('image/png')
|
|
226
|
+
resolve({ data: result, width: this.width, height: this.height })
|
|
227
|
+
}
|
|
228
|
+
image.setAttribute('crossOrigin', 'Anonymous')
|
|
229
|
+
image.src = url
|
|
230
|
+
// 图片加载失败的错误处理
|
|
231
|
+
image.onerror = () => {
|
|
232
|
+
reject(new Error('转换失败'))
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
getFileUrl (id, client, flag = true, useSignOrigin = false) {
|
|
238
|
+
// 兼容:第二个参数可传对象 { client, flag, useSignOrigin },旧的位置参数写法 (id, client, flag, useSignOrigin) 仍然可用
|
|
239
|
+
if (client !== null && typeof client === 'object') {
|
|
240
|
+
const options = client
|
|
241
|
+
client = options.client
|
|
242
|
+
flag = options.flag !== undefined ? options.flag : true
|
|
243
|
+
useSignOrigin = options.useSignOrigin || false
|
|
244
|
+
}
|
|
245
|
+
const { IP, BASE_PROJECT_NAME, BASE_SYSTEM_ID, BASE_CLIENT_ID, MINIO_IP, MINIO_FILE_URL } = window
|
|
246
|
+
if (!id) return
|
|
247
|
+
if (id.includes('http') || id.startsWith('data:image') || id.includes('//')) return id
|
|
248
|
+
|
|
249
|
+
if (id.includes('/')) return `${MINIO_IP || IP}${MINIO_FILE_URL || 'file-server'}${id}`
|
|
250
|
+
const { CODE: clientCode = BASE_CLIENT_ID } = window.store.state.config.clientConfig
|
|
251
|
+
const { 'SYSTEM|DOMAIN|CONTEXT': domainContext, 'SYSTEM|CODE': sysCode = BASE_SYSTEM_ID, 'SYSTEM|SIGN_ORIGIN': signOrigin } = window.store.state.config.appConfig
|
|
252
|
+
const projectName = domainContext || BASE_PROJECT_NAME
|
|
253
|
+
const baseUrl = IP ? `${IP}${projectName}/` : ''
|
|
254
|
+
const inter = `api/v1/${client || clientCode}/${sysCode}/download?id=${id}`
|
|
255
|
+
let flieUrl = baseUrl + inter
|
|
256
|
+
|
|
257
|
+
// 两处运算符优先级修复(vue3 侧与本次 token 续期修复各自独立发现同一处 bug):
|
|
258
|
+
// ① `client || clientCode + '-token'` 里 `+` 比 `||` 紧,实际是 `client || (clientCode + '-token')`
|
|
259
|
+
// —— 传了 client 实参时会去读 `<client>` 这个键(少了 `-token` 后缀),永远拿不到 token。
|
|
260
|
+
// 目前全仓没有调用方传非空 client,所以这条是**潜伏**的;但一旦有人传就悄悄失效。
|
|
261
|
+
// ② 结尾的 `|| ''` 同理会被 `+` 抢先而恒不生效;getStoredToken 内部已自带空串兜底
|
|
262
|
+
// (取不到时返回 `''` 而非 undefined),改用它之后不用再套这层 `|| ''`。
|
|
263
|
+
if (flag) flieUrl += '&EPXTID=' + btoa(getStoredToken((client || clientCode) + '-token')) + '&xsrf_token=' + getXsrfToken()
|
|
264
|
+
// 当系统配置了签名地址 SIGN_ORIGIN 时,按需将文件地址的域名替换为该地址
|
|
265
|
+
if (useSignOrigin && signOrigin) flieUrl = flieUrl.replace(/^https?:\/\/[^/]+/, signOrigin.replace(/\/+$/, ''))
|
|
266
|
+
return flieUrl
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getOfficeFileUrl (id, client, flag = true, useSignOrigin = false) {
|
|
270
|
+
// 兼容:第二个参数可传对象 { client, flag, useSignOrigin },旧的位置参数写法 (id, client, flag, useSignOrigin) 仍然可用
|
|
271
|
+
if (client !== null && typeof client === 'object') {
|
|
272
|
+
const options = client
|
|
273
|
+
client = options.client
|
|
274
|
+
flag = options.flag !== undefined ? options.flag : true
|
|
275
|
+
useSignOrigin = options.useSignOrigin || false
|
|
276
|
+
}
|
|
277
|
+
const { IP, BASE_PROJECT_NAME, BASE_SYSTEM_ID, BASE_CLIENT_ID } = window
|
|
278
|
+
const { CODE: clientCode = BASE_CLIENT_ID } = window.store.state.config.clientConfig
|
|
279
|
+
const { 'SYSTEM|DOMAIN|CONTEXT': domainContext, 'SYSTEM|CODE': sysCode = BASE_SYSTEM_ID, 'SYSTEM|SIGN_ORIGIN': signOrigin } = window.store.state.config.appConfig
|
|
280
|
+
const projectName = domainContext || BASE_PROJECT_NAME
|
|
281
|
+
const baseUrl = IP ? `${IP}${projectName}/` : ''
|
|
282
|
+
const inter = `api/v1/${client || clientCode}/${sysCode}/onlineview?fileId=${id}`
|
|
283
|
+
let flieUrl = baseUrl + inter
|
|
284
|
+
// 同 getFileUrl 的两处优先级问题,改法一致(详见那里的注释)。
|
|
285
|
+
if (flag) flieUrl += '&token=' + getStoredToken((client || clientCode) + '-token') + '&xsrf_token=' + getXsrfToken()
|
|
286
|
+
// 当系统配置了签名地址 SIGN_ORIGIN 时,按需将文件地址的域名替换为该地址
|
|
287
|
+
if (useSignOrigin && signOrigin) flieUrl = flieUrl.replace(/^https?:\/\/[^/]+/, signOrigin.replace(/\/+$/, ''))
|
|
288
|
+
return flieUrl
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ONLYOFFICE Document Server 地址,来自 config.js 的 window.ONLYOFFICE_URL(未配置返回空串,调用方据此降级)
|
|
292
|
+
// 建议配成与主站同源的反代路径(如 /onlyoffice),可同时避免 mixed content 与跨域问题
|
|
293
|
+
getOfficeServerUrl () {
|
|
294
|
+
const url = (window.ONLYOFFICE_URL || '').replace(/\/+$/, '')
|
|
295
|
+
if (!url) return ''
|
|
296
|
+
// 已是完整地址(含协议或 //)原样返回
|
|
297
|
+
if (!url.startsWith('/') || url.startsWith('//')) return url
|
|
298
|
+
// 相对路径:本地开发(localhost)返回相对,走 devServer 同源代理绕过跨域;
|
|
299
|
+
// 线上拼主站 window.IP 直连(前端与 onlyoffice 同域名则同源)
|
|
300
|
+
const host = window.location.hostname
|
|
301
|
+
if (host === 'localhost' || host === '127.0.0.1') return url
|
|
302
|
+
return (window.IP || '').replace(/\/+$/, '') + url
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
getAbsPath (path, params = {}) {
|
|
306
|
+
let paramStr = ''
|
|
307
|
+
for (const i in params) {
|
|
308
|
+
paramStr += '&' + i + '=' + params[i]
|
|
309
|
+
}
|
|
310
|
+
const { IP, BASE_PROJECT_NAME } = window
|
|
311
|
+
const { 'SYSTEM|DOMAIN|CONTEXT': domainContext } = window.store.state.config.appConfig
|
|
312
|
+
const projectName = domainContext || BASE_PROJECT_NAME
|
|
313
|
+
|
|
314
|
+
const { clientConfig = {} } = window.store.state.config
|
|
315
|
+
return (IP ? (IP + projectName) : '') + path + `?client=${clientConfig.CODE}` + '&xsrf_token=' + getXsrfToken() + paramStr
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
getPlatformRequestUrl (params = {}) {
|
|
319
|
+
const router = window.router
|
|
320
|
+
|
|
321
|
+
const { params: routeParams = {} } = router.currentRoute.value || {}
|
|
322
|
+
const { appConfig = {} } = window.store.state.config
|
|
323
|
+
const client = routeParams.client || appConfig['CLIENT|CODE']
|
|
324
|
+
const { IP, BASE_PROJECT_NAME, BASE_SYSTEM_ID, BASE_CLIENT_ID } = window
|
|
325
|
+
const baseUrl = IP ? `${IP}${BASE_PROJECT_NAME}/` : ''
|
|
326
|
+
const platformUrl = `api/v1/${BASE_CLIENT_ID}/${BASE_SYSTEM_ID}/${params.entityId}/${params.action}`
|
|
327
|
+
let paramStr = ''
|
|
328
|
+
for (const i in params) {
|
|
329
|
+
if (i !== 'action' && i !== 'entityId') {
|
|
330
|
+
paramStr += (paramStr.includes('?') ? '&' : '?') + i + '=' + params[i]
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
// 结尾 `|| ''` 同样会被 `+` 抢先而恒不生效(这里 client 已在上面解析好,没有键名那个问题);
|
|
334
|
+
// getStoredToken 内部已自带空串兜底,不用再套这层 `|| ''`。
|
|
335
|
+
return baseUrl + platformUrl + paramStr + '&token=' + getStoredToken(client + '-token') + '&xsrf_token=' + getXsrfToken()
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
getRequestUrl (params = {}, { requestKey = 'api' } = {}) {
|
|
339
|
+
const { IP, BASE_PROJECT_NAME, BASE_SYSTEM_ID, BASE_CLIENT_ID } = window
|
|
340
|
+
const { CODE: clientCode = BASE_CLIENT_ID } = window.store.state.config.clientConfig
|
|
341
|
+
const { 'SYSTEM|DOMAIN|CONTEXT': domainContext, 'SYSTEM|CODE': sysCode = BASE_SYSTEM_ID } = window.store.state.config.appConfig
|
|
342
|
+
const projectName = domainContext || BASE_PROJECT_NAME
|
|
343
|
+
const baseUrl = IP ? `${IP}${projectName}/` : ''
|
|
344
|
+
const platformUrl = `${requestKey}/v1/${clientCode}/${sysCode}/${params.entityId}/${params.action}`
|
|
345
|
+
let paramStr = ''
|
|
346
|
+
const xsrfToken = getXsrfToken()
|
|
347
|
+
if (xsrfToken) params.xsrf_token = xsrfToken
|
|
348
|
+
for (const i in params) {
|
|
349
|
+
if (i !== 'action' && i !== 'entityId') {
|
|
350
|
+
paramStr += (paramStr.includes('?') ? '&' : '?') + i + '=' + params[i]
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return baseUrl + platformUrl + paramStr
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
getSystemMeta (metaCode) {
|
|
357
|
+
const router = window.router
|
|
358
|
+
|
|
359
|
+
const { name, params: routeParams = {} } = router.currentRoute.value || {}
|
|
360
|
+
const { appConfig = {} } = window.store.state.config
|
|
361
|
+
const client = routeParams.client || appConfig['CLIENT|CODE']
|
|
362
|
+
const system = routeParams.system || appConfig['SYSTEM|CODE']
|
|
363
|
+
return name === 'hall' ? `${metaCode}@system@${client}` : `${metaCode}@${system}@${client}`
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
isWeiXin () {
|
|
367
|
+
var ua = window.navigator.userAgent.toLowerCase()
|
|
368
|
+
// 修复:ua.match() 返回数组(或 null),永远不会 === 字符串 'micromessenger',
|
|
369
|
+
// 原写法恒为 false——微信内嵌浏览器判断从未生效过。
|
|
370
|
+
// 移动端、Windows/Mac 桌面版微信以及企业微信的内置浏览器 UA 里都带 micromessenger
|
|
371
|
+
return ua.indexOf('micromessenger') !== -1
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
isFeishu () {
|
|
375
|
+
var ua = window.navigator.userAgent.toLowerCase()
|
|
376
|
+
if (ua.match(/Lark/i)) {
|
|
377
|
+
return true
|
|
378
|
+
} else {
|
|
379
|
+
return false
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
isDingTalk () {
|
|
384
|
+
const ua = navigator.userAgent.toLowerCase()
|
|
385
|
+
return ua.match(/dingtalk/i) !== null
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
isIos () {
|
|
389
|
+
var ua = window.navigator.userAgent.toLowerCase()
|
|
390
|
+
// eslint-disable-next-line
|
|
391
|
+
return !!ua.match(/i[^;]+;( U;)? CPU.+Mac OS X/i)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// 浏览器能否在页面内直接渲染 PDF。不能的话,给 iframe / a 标签赋 PDF 地址
|
|
395
|
+
// 会被当成文件下载(微信内置浏览器会直接弹「下载 / 用其他应用打开」)
|
|
396
|
+
canPreviewPdfInline () {
|
|
397
|
+
// 微信内置浏览器(含桌面版、企业微信)既不能内联渲染 PDF,也不支持网页发起打印
|
|
398
|
+
if (this.isWeiXin()) return false
|
|
399
|
+
if (typeof navigator.pdfViewerEnabled === 'boolean') return navigator.pdfViewerEnabled
|
|
400
|
+
// 老浏览器没有 pdfViewerEnabled,退回看是否注册了 PDF 处理器
|
|
401
|
+
const mimeTypes = navigator.mimeTypes || {}
|
|
402
|
+
return !!(mimeTypes['application/pdf'] || mimeTypes['application/x-google-chrome-pdf'])
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// 把一段 HTML 放进临时 iframe 打印,返回浏览器是否真的进入了打印流程。
|
|
406
|
+
// 打印的是 HTML 而不是 PDF,所以不会触发「下载 / 用其他应用打开」弹窗
|
|
407
|
+
printHtml (html) {
|
|
408
|
+
return new Promise(resolve => {
|
|
409
|
+
const frame = document.createElement('iframe')
|
|
410
|
+
frame.setAttribute('aria-hidden', 'true')
|
|
411
|
+
frame.style.cssText = 'position:fixed;right:0;bottom:0;width:0;height:0;border:0;opacity:0'
|
|
412
|
+
document.body.appendChild(frame)
|
|
413
|
+
let removed = false
|
|
414
|
+
const remove = () => {
|
|
415
|
+
if (removed) return
|
|
416
|
+
removed = true
|
|
417
|
+
if (frame.parentNode) frame.parentNode.removeChild(frame)
|
|
418
|
+
}
|
|
419
|
+
const doc = frame.contentDocument || (frame.contentWindow && frame.contentWindow.document)
|
|
420
|
+
if (!doc) {
|
|
421
|
+
remove()
|
|
422
|
+
return resolve(false)
|
|
423
|
+
}
|
|
424
|
+
doc.open()
|
|
425
|
+
doc.write(html)
|
|
426
|
+
doc.close()
|
|
427
|
+
// 图片是 dataURL,也要等它们解码完再打印,否则会打出空白页
|
|
428
|
+
const images = Array.prototype.slice.call(doc.images || [])
|
|
429
|
+
const loaded = images.map(img => img.complete
|
|
430
|
+
? Promise.resolve()
|
|
431
|
+
: new Promise(resolve => { img.onload = img.onerror = resolve }))
|
|
432
|
+
Promise.all(loaded).then(() => {
|
|
433
|
+
const win = frame.contentWindow
|
|
434
|
+
// print() 在有的浏览器里是异步的,过早移除 iframe 会打断打印
|
|
435
|
+
try { win.addEventListener('afterprint', remove) } catch (e) {}
|
|
436
|
+
const printed = this.printWindow(win)
|
|
437
|
+
// 没进打印流程就直接收掉,留着只是白占内存(图片是 dataURL,可能有好几 MB)
|
|
438
|
+
if (printed) setTimeout(remove, 60000)
|
|
439
|
+
else remove()
|
|
440
|
+
resolve(printed)
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// 调 print() 并判断浏览器是否真的进入了打印流程。
|
|
446
|
+
// 微信等内嵌浏览器没有打印栈,print() 会被静默吞掉,只能靠 beforeprint 判断
|
|
447
|
+
printWindow (win) {
|
|
448
|
+
if (!win || typeof win.print !== 'function') return false
|
|
449
|
+
let engaged = false
|
|
450
|
+
const mark = () => { engaged = true }
|
|
451
|
+
const mql = win.matchMedia ? win.matchMedia('print') : null
|
|
452
|
+
const listen = (target, on) => {
|
|
453
|
+
if (!target) return
|
|
454
|
+
try { target[on ? 'addEventListener' : 'removeEventListener']('beforeprint', mark) } catch (e) {}
|
|
455
|
+
}
|
|
456
|
+
listen(win, true)
|
|
457
|
+
listen(window, true)
|
|
458
|
+
if (mql && mql.addListener) mql.addListener(mark)
|
|
459
|
+
try {
|
|
460
|
+
win.focus()
|
|
461
|
+
win.print()
|
|
462
|
+
} catch (e) {
|
|
463
|
+
engaged = false
|
|
464
|
+
}
|
|
465
|
+
listen(win, false)
|
|
466
|
+
listen(window, false)
|
|
467
|
+
if (mql && mql.removeListener) mql.removeListener(mark)
|
|
468
|
+
return engaged
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 用 pdf.js 把 PDF 每页画成图片,绕开浏览器自带的 PDF 阅读器
|
|
472
|
+
pdfDocToImages (pdfDoc, scale = 3) {
|
|
473
|
+
if (!pdfDoc || typeof pdfDoc.getPage !== 'function') return Promise.resolve([])
|
|
474
|
+
const images = []
|
|
475
|
+
let chain = Promise.resolve()
|
|
476
|
+
for (let num = 1; num <= pdfDoc.numPages; num++) {
|
|
477
|
+
chain = chain
|
|
478
|
+
.then(() => pdfDoc.getPage(num))
|
|
479
|
+
.then(page => {
|
|
480
|
+
const viewport = page.getViewport({ scale })
|
|
481
|
+
const canvas = document.createElement('canvas')
|
|
482
|
+
canvas.width = viewport.width
|
|
483
|
+
canvas.height = viewport.height
|
|
484
|
+
const task = page.render({ canvasContext: canvas.getContext('2d'), viewport })
|
|
485
|
+
const done = task && task.promise ? task.promise : Promise.resolve()
|
|
486
|
+
return done.then(() => images.push(canvas.toDataURL('image/jpeg', 0.92)))
|
|
487
|
+
})
|
|
488
|
+
}
|
|
489
|
+
return chain.then(() => images)
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
getBrowserVersion () {
|
|
493
|
+
const ua = window.navigator.userAgent
|
|
494
|
+
if (window.opera) {
|
|
495
|
+
return {
|
|
496
|
+
browser: 'opera',
|
|
497
|
+
version: window.opera.version()
|
|
498
|
+
}
|
|
499
|
+
} else if (/AppleWebKit\/(\S+)/.test(ua)) {
|
|
500
|
+
if (/Chrome\/(\S+)/.test(ua)) {
|
|
501
|
+
return {
|
|
502
|
+
brower: 'chrome',
|
|
503
|
+
version: RegExp.$1
|
|
504
|
+
}
|
|
505
|
+
} else if (/Version\/(\S+)/.test(ua)) {
|
|
506
|
+
return {
|
|
507
|
+
brower: 'safari',
|
|
508
|
+
version: RegExp.$1
|
|
509
|
+
}
|
|
510
|
+
} else {
|
|
511
|
+
return {
|
|
512
|
+
brower: 'safari'
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
} else if (/KHTML\/(\S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)) {
|
|
516
|
+
return {
|
|
517
|
+
brower: 'konq',
|
|
518
|
+
version: RegExp.$1
|
|
519
|
+
}
|
|
520
|
+
} else if (/rv:([^\\)]+)\) Gecko\/\d{8}/.test(ua)) {
|
|
521
|
+
if (/Firefox\/(\S+)/.test(ua)) {
|
|
522
|
+
// 火狐浏览器
|
|
523
|
+
return {
|
|
524
|
+
brower: 'firefox',
|
|
525
|
+
version: RegExp.$1
|
|
526
|
+
}
|
|
527
|
+
} else {
|
|
528
|
+
// 其他情况
|
|
529
|
+
}
|
|
530
|
+
} else if (/MSIE ([^;]+)/.test(ua)) {
|
|
531
|
+
return {
|
|
532
|
+
brower: 'ie',
|
|
533
|
+
version: RegExp.$1
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return {}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
runExp (exp, point) {
|
|
540
|
+
if (!point) point = this
|
|
541
|
+
exp = ' ' + exp.trim()
|
|
542
|
+
// eslint-disable-next-line
|
|
543
|
+
const quickRegex = /([\s\+\-\*\/%&\(\|\^!\*~]\s*?)([a-zA-Z_$][a-zA-Z_$0-9]*?)/g
|
|
544
|
+
exp = exp.replace(quickRegex, (a, b, c) => {
|
|
545
|
+
return b + 'point.' + c
|
|
546
|
+
})
|
|
547
|
+
// eslint-disable-next-line no-new-func
|
|
548
|
+
const func = new Function('point', 'return ' + exp)
|
|
549
|
+
return func(point)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// 根据高级查询获取js表达式
|
|
553
|
+
runExpByScope (scopeList, data = {}) {
|
|
554
|
+
let str = ''
|
|
555
|
+
// Form data is null before its request resolves. Treat it as an empty record
|
|
556
|
+
// while evaluating visibility rules so legacy product pages can render.
|
|
557
|
+
const record = data || {}
|
|
558
|
+
// 由调用方 .call(组件实例) 进来,#{key} 相对组件实例取值
|
|
559
|
+
const that = this
|
|
560
|
+
// 当前时间变量:高级筛选里写 $[currentDate.date]/$[currentDate.month] 等(或 #{...})解析为当前时间,供日期判断
|
|
561
|
+
const getTimeVar = (key) => {
|
|
562
|
+
switch (key) {
|
|
563
|
+
case 'now':
|
|
564
|
+
case 'currentDate.time': return formula.NOW('YYYY-MM-DD HH:mm:ss') // 当前时间(精确到秒)
|
|
565
|
+
case 'today':
|
|
566
|
+
case 'currentDate':
|
|
567
|
+
case 'currentDate.date': return formula.NOW('YYYY-MM-DD') // 系统日期(精确到天)
|
|
568
|
+
case 'currentDate.month': return formula.NOW('YYYY-MM') // 当前月份(精确到月)
|
|
569
|
+
case 'currentDate.year': return formula.NOW('YYYY') // 当前年度(精确到年)
|
|
570
|
+
default: return null
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
try {
|
|
574
|
+
const router = window.router
|
|
575
|
+
// 高级查询里的 user.roleCode 取当前角色。菜单直达路由没有 role 段(末段是 menuKey),
|
|
576
|
+
// 直读 params.role 会得到 undefined,生成的表达式变成 "undefined"=='xxx'、按角色过滤
|
|
577
|
+
// 的数据范围整条失效。统一走 resolveRouteRole:URL 优先、其次 localStorage。
|
|
578
|
+
const currentRoleCode = resolveRouteRole(router.currentRoute.value)
|
|
579
|
+
scopeList.forEach((scope, index) => {
|
|
580
|
+
let { mode, values = '', field } = scope
|
|
581
|
+
const fieldInfo = this.$meta ? this.$meta.getAttribute(field) || {} : {}
|
|
582
|
+
const { dataType, optionType, isMultiple } = fieldInfo
|
|
583
|
+
if (/#\{(.+)\}/.test(values)) {
|
|
584
|
+
try {
|
|
585
|
+
const valueKey = values.replace(/^#\{(.+)\}$/, (match, key) => key)
|
|
586
|
+
const timeVar = getTimeVar(valueKey)
|
|
587
|
+
// 显式传作用域,不能靠直接 eval 捕获 that(见 eval-with.js)
|
|
588
|
+
values = timeVar != null ? timeVar : (evalWith(`that.${valueKey}`, { that }) || evalWith(`that.$query.${valueKey}`, { that }) || evalWith(`that.$tab.${valueKey}`, { that }) || '')
|
|
589
|
+
} catch (error) {
|
|
590
|
+
values = ''
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (/\$\[(.+)\]/.test(values)) {
|
|
594
|
+
try {
|
|
595
|
+
const valueKey = values.replace(/\$\[(.+)\]/, (match, key) => key)
|
|
596
|
+
const timeVar = getTimeVar(valueKey)
|
|
597
|
+
// 显式传作用域,不能靠直接 eval 捕获 that(见 eval-with.js)
|
|
598
|
+
values = timeVar != null ? timeVar : (evalWith(`that.${valueKey}`, { that }) || evalWith(`that.$query.${valueKey}`, { that }) || evalWith(`that.$tab.${valueKey}`, { that }) || '')
|
|
599
|
+
} catch (err) {
|
|
600
|
+
console.error(err)
|
|
601
|
+
values = ''
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
let valueArr = []
|
|
605
|
+
if (typeof values === 'string') {
|
|
606
|
+
values = values.replace(/[\r\n"]/g, '').replace(/\\$/g, '/')
|
|
607
|
+
if (!values) valueArr = []
|
|
608
|
+
else valueArr = values.split(',')
|
|
609
|
+
}
|
|
610
|
+
str += `${scope.lb || ''}`
|
|
611
|
+
const user = window.store.state.user.user || {}
|
|
612
|
+
// user.xxx 这类字段相对当前用户取值:显式传作用域,不能靠直接 eval 捕获 user(见 eval-with.js)
|
|
613
|
+
let fieldValue = field === 'user.roleCode' ? currentRoleCode : field.includes('user.') ? evalWith(field, { user }) : record[field] || ''
|
|
614
|
+
// eslint-disable-next-line no-new-wrappers
|
|
615
|
+
fieldValue = typeof fieldValue === 'string' ? fieldValue.replace(/[\r\n"]/g, '').replace(/\\$/g, '/') : fieldValue
|
|
616
|
+
if (mode === 'is_null' || mode === 'not_null' || mode === 'equal' || mode === 'not_equal') {
|
|
617
|
+
str += `"${fieldValue}"${mode === 'is_null' || mode === 'equal' ? '==' : '!='}${mode === 'equal' || mode === 'not_equal' ? `'${values}'` : '""'}`
|
|
618
|
+
} else if (['greater', 'greater_equal', 'less', 'less_equal'].includes(mode)) {
|
|
619
|
+
str += `${fieldValue}${mode === 'greater' ? '>' : mode === 'greater_equal' ? '>=' : mode === 'less' ? '<' : '<='}${values}`
|
|
620
|
+
} else if (['in', 'not_in', 'in_scope', 'not_in_scope'].includes(mode)) {
|
|
621
|
+
if (dataType) {
|
|
622
|
+
if (dataType === 'list' || dataType === 'object' || dataType === 'user' || dataType === 'dept') {
|
|
623
|
+
const multiple = isMultiple === '1' || optionType === 'multibox' || optionType === 'multiList'
|
|
624
|
+
str += `${mode === 'not_in' || mode === 'not_in_scope' ? '!' : ''}${multiple && fieldValue ? `"${fieldValue.split(',')}".includes("${values}")` : `${JSON.stringify(valueArr)}.includes("${fieldValue}")`}`
|
|
625
|
+
} else {
|
|
626
|
+
str += `${mode === 'not_in' || mode === 'not_in_scope' ? '!' : ''}${`"${fieldValue}".includes("${values}")`}`
|
|
627
|
+
}
|
|
628
|
+
} else {
|
|
629
|
+
str += `${mode === 'not_in' || mode === 'not_in_scope' ? '!' : ''}${valueArr.length > 1 ? `${JSON.stringify(valueArr)}.includes("${fieldValue}")` : `"${fieldValue}".includes("${values}")`}`
|
|
630
|
+
}
|
|
631
|
+
} else if (['begin', 'end'].includes(mode)) {
|
|
632
|
+
str += `"${fieldValue}".${mode === 'begin' ? 'startsWith' : 'endsWith'}('${values}')`
|
|
633
|
+
} else if (['date_greater', 'date_greater_equal', 'date_less', 'date_less_equal'].includes(mode)) {
|
|
634
|
+
str += `"${fieldValue}"${mode === 'date_greater' ? '>' : mode === 'date_greater_equal' ? '>=' : mode === 'date_less' ? '<' : '<='}'${values}'`
|
|
635
|
+
} else {
|
|
636
|
+
str += `${mode === 'not_like' ? '!' : ''}"${fieldValue}".includes(${values})`
|
|
637
|
+
}
|
|
638
|
+
str += `${scope.rb || ''} ${index === scopeList.length - 1 ? '' : scope.link === 'or' ? '||' : '&&'} `
|
|
639
|
+
})
|
|
640
|
+
// eslint-disable-next-line no-eval
|
|
641
|
+
const flag = eval(str)
|
|
642
|
+
return flag
|
|
643
|
+
} catch (error) {
|
|
644
|
+
console.error(error + ',str=' + str)
|
|
645
|
+
return false
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
awaitWrap (promise) {
|
|
650
|
+
return promise
|
|
651
|
+
.then(data => ({ error: null, data }))
|
|
652
|
+
.catch(error => ({ error, data: null }))
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
isLoadLibrary (systemCode) {
|
|
656
|
+
return this.loadSystemLibrarys[systemCode]
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
loadJS (options) {
|
|
660
|
+
var url = options.url
|
|
661
|
+
var callback = typeof options.callback === 'function' ? options.callback : function () {}
|
|
662
|
+
|
|
663
|
+
const script = document.createElement('script')
|
|
664
|
+
script.type = 'text/javascript'
|
|
665
|
+
// IE
|
|
666
|
+
if (script.readyState) {
|
|
667
|
+
script.onreadystatechange = function () {
|
|
668
|
+
if (script.readyState === 'loaded' || script.readyState === 'complete') {
|
|
669
|
+
script.onreadystatechange = null
|
|
670
|
+
callback()
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
} else {
|
|
674
|
+
// 其他浏览器
|
|
675
|
+
script.onload = function () {
|
|
676
|
+
callback()
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
// 失败也必须回调(同 loadCss 的 onerror 处理)。原先只绑 onload:URL 404 / 跨域被拦 /
|
|
680
|
+
// 文件服务抖动时回调永不触发 → usePlugin() 的 promise 永不 resolve → 等它的地方**无限期挂住**,
|
|
681
|
+
// 且 util.loadPlugins 把这个永远 pending 的 promise 缓存了,重试也一样挂、连报错都没有。
|
|
682
|
+
// 调用方提供 onerror 时明确返回失败;旧调用方继续收到回调,避免无限等待。
|
|
683
|
+
script.onerror = function () {
|
|
684
|
+
console.error('[util.loadJS] 加载失败:' + url)
|
|
685
|
+
if (options.onerror) options.onerror(new Error('脚本加载失败:' + url))
|
|
686
|
+
else callback()
|
|
687
|
+
}
|
|
688
|
+
script.src = url
|
|
689
|
+
document.getElementsByTagName('head')[0].appendChild(script)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
loadJs (file, cb) {
|
|
693
|
+
const that = this
|
|
694
|
+
if (!that.oldLibrary) that.oldLibrary = {}
|
|
695
|
+
if (window.library) {
|
|
696
|
+
for (const key in window.library) {
|
|
697
|
+
if (!that.oldLibrary[key]) that.oldLibrary[key] = {}
|
|
698
|
+
for (const compKey in (window.library[key] || {})) {
|
|
699
|
+
try {
|
|
700
|
+
that.oldLibrary[key][compKey] = cloneDeep(window.library[key][compKey])
|
|
701
|
+
} catch (error) {
|
|
702
|
+
console.error(compKey, error)
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
const script = document.createElement('script')
|
|
708
|
+
script.type = 'text/javascript'
|
|
709
|
+
script.src = file
|
|
710
|
+
script.onload = async function (js) {
|
|
711
|
+
const componentLibrary = window.library
|
|
712
|
+
// 远程库 install 去重(判据 name@version),2026-09-02 补。
|
|
713
|
+
//
|
|
714
|
+
// 为什么必须有:window.library 只累加、从不清空,而本 onload 会遍历它的**每一个** key。
|
|
715
|
+
// · 一个系统配了 N 个 js(产品库 + 项目库 + …)是串行加载的 → 第 1 个库被 install N 次;
|
|
716
|
+
// · 产品若已被**本地打进壳**(dev 壳的 app.use(hr)),它不进 window.library,
|
|
717
|
+
// 平台看不见 ⇒ 远程那份照样下载并再 install 一次。
|
|
718
|
+
// 双装时 app.component 有 `if (!component)` 守卫不会重,但 store.registerModule /
|
|
719
|
+
// router.addRoute 没守卫 —— 实测就是 [vuex] duplicate getter key: selectedPersons。
|
|
720
|
+
// 证据见 test/unit/load-js-install-dedup.test.js。
|
|
721
|
+
//
|
|
722
|
+
// ⚠️ 只在 app 已就绪时记账:useVuePlugin 在 _app 为空时是直接 return 的空操作,
|
|
723
|
+
// 那种情况下记了账就等于永久跳过,库再也装不上。
|
|
724
|
+
// 产品库自己的 install 也应查同一张表(见 docs/PROJECT-GUIDE.md),
|
|
725
|
+
// 覆盖本地打包那条平台看不见的路——两边合起来才是完整去重。
|
|
726
|
+
if (!window.__epxInstalledLibs__) window.__epxInstalledLibs__ = {}
|
|
727
|
+
const appReady = !!getApp()
|
|
728
|
+
for (const key in componentLibrary) {
|
|
729
|
+
const lib = componentLibrary[key]
|
|
730
|
+
const sig = key + '@' + ((lib && lib.version) || '')
|
|
731
|
+
if (!window.__epxInstalledLibs__[sig]) {
|
|
732
|
+
// ⚠️ 记账必须在 install **之后**。
|
|
733
|
+
// 产品库自己的 install 开头也查这张表(PROJECT-GUIDE 约定的幂等写法:
|
|
734
|
+
// `if (marks[sig]) return`)。先记账就会让它一进门就 return —— 表里有记录、
|
|
735
|
+
// 组件一个都没注册,症状是 window.__epxInstalledLibs__ 有 hr@3.0.1 但
|
|
736
|
+
// app 里 0 个 epx-hr-* 组件,且完全静默。
|
|
737
|
+
// 2026-09-04 product/hr 实测(两侧去重分两次提交,撞在一起才暴露)。
|
|
738
|
+
if (appReady) {
|
|
739
|
+
if (!installingLibraries.has(sig)) {
|
|
740
|
+
const install = Promise.resolve().then(() => useVuePlugin(lib, { store: window.store }))
|
|
741
|
+
.then(() => { window.__epxInstalledLibs__[sig] = { source: 'remote', at: Date.now() } })
|
|
742
|
+
.finally(() => installingLibraries.delete(sig))
|
|
743
|
+
installingLibraries.set(sig, install)
|
|
744
|
+
}
|
|
745
|
+
try { await installingLibraries.get(sig) } catch (error) { console.error(error) }
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const components = componentLibrary[key] || {}
|
|
749
|
+
for (const key in components) {
|
|
750
|
+
if (!window.componentLibrary[key]) window.componentLibrary[key] = components[key]
|
|
751
|
+
}
|
|
752
|
+
if (!isEqual(componentLibrary[key], that.oldLibrary[key])) {
|
|
753
|
+
// 修复:原写在 that(util 单例)上,全仓没有任何代码读 that.productLibrary,
|
|
754
|
+
// 改到 window 上才是这行代码的原意。develop 同期把 loadLibrary.js 的产品库识别
|
|
755
|
+
// 换成了引用快照对比(不再依赖这个全局),这里目前也没有实际读者——按 develop
|
|
756
|
+
// 原样保留这处写入(无害),不额外删減。
|
|
757
|
+
if (componentLibrary[key] && componentLibrary[key].version) window.productLibrary = componentLibrary[key]
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
cb && cb()
|
|
762
|
+
}
|
|
763
|
+
document.body.appendChild(script)
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
loadCss (options) {
|
|
767
|
+
var url = options.url
|
|
768
|
+
var callback = typeof options.callback === 'function' ? options.callback : function () {}
|
|
769
|
+
var id = options.id
|
|
770
|
+
var node = document.createElement('link')
|
|
771
|
+
var supportOnload = 'onload' in node
|
|
772
|
+
var isOldWebKit = +navigator.userAgent.replace(/.*(?:AppleWebKit|AndroidWebKit)\/?(\d+).*/i, '$1') < 536 // webkit旧内核做特殊处理
|
|
773
|
+
var protectNum = 300000 // 阈值10分钟,一秒钟执行pollCss 500次
|
|
774
|
+
|
|
775
|
+
node.rel = 'stylesheet'
|
|
776
|
+
node.type = 'text/css'
|
|
777
|
+
node.href = url
|
|
778
|
+
if (typeof id !== 'undefined') {
|
|
779
|
+
node.id = id
|
|
780
|
+
}
|
|
781
|
+
document.getElementsByTagName('head')[0].appendChild(node)
|
|
782
|
+
|
|
783
|
+
// for Old WebKit and Old Firefox
|
|
784
|
+
if (isOldWebKit || !supportOnload) {
|
|
785
|
+
// Begin after node insertion
|
|
786
|
+
const timer = setTimeout(function () {
|
|
787
|
+
pollCss(node, callback, 0)
|
|
788
|
+
clearTimeout(timer)
|
|
789
|
+
}, 1)
|
|
790
|
+
return
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (supportOnload) {
|
|
794
|
+
node.onload = onload
|
|
795
|
+
node.onerror = function () {
|
|
796
|
+
// 加载失败(404)
|
|
797
|
+
onload()
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
800
|
+
node.onreadystatechange = function () {
|
|
801
|
+
if (/loaded|complete/.test(node.readyState)) {
|
|
802
|
+
onload()
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
function onload () {
|
|
808
|
+
// 确保只跑一次下载操作
|
|
809
|
+
node.onload = node.onerror = node.onreadystatechange = null
|
|
810
|
+
|
|
811
|
+
// 清空node引用,在低版本IE,不清除会造成内存泄露
|
|
812
|
+
node = null
|
|
813
|
+
|
|
814
|
+
callback()
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// 循环判断css是否已加载成功
|
|
818
|
+
/*
|
|
819
|
+
* @param node -- link节点
|
|
820
|
+
* @param callback -- 回调函数
|
|
821
|
+
* @param step -- 计步器,避免无限循环
|
|
822
|
+
*/
|
|
823
|
+
function pollCss (node, callback, step) {
|
|
824
|
+
var sheet = node.sheet
|
|
825
|
+
var isLoaded
|
|
826
|
+
|
|
827
|
+
step += 1
|
|
828
|
+
|
|
829
|
+
// 保护,大于10分钟,则不再轮询
|
|
830
|
+
if (step > protectNum) {
|
|
831
|
+
isLoaded = true
|
|
832
|
+
|
|
833
|
+
// 清空node引用
|
|
834
|
+
node = null
|
|
835
|
+
|
|
836
|
+
callback()
|
|
837
|
+
return
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (isOldWebKit) {
|
|
841
|
+
// for WebKit < 536
|
|
842
|
+
if (sheet) {
|
|
843
|
+
isLoaded = true
|
|
844
|
+
}
|
|
845
|
+
} else if (sheet) {
|
|
846
|
+
// for Firefox < 9.0
|
|
847
|
+
try {
|
|
848
|
+
if (sheet.cssRules) {
|
|
849
|
+
isLoaded = true
|
|
850
|
+
}
|
|
851
|
+
} catch (ex) {
|
|
852
|
+
// 火狐特殊版本,通过特定值获知是否下载成功
|
|
853
|
+
// The value of `ex.name` is changed from "NS_ERROR_DOM_SECURITY_ERR"
|
|
854
|
+
// to "SecurityError" since Firefox 13.0. But Firefox is less than 9.0
|
|
855
|
+
// in here, So it is ok to just rely on "NS_ERROR_DOM_SECURITY_ERR"
|
|
856
|
+
if (ex.name === 'NS_ERROR_DOM_SECURITY_ERR') {
|
|
857
|
+
isLoaded = true
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const timer = setTimeout(function () {
|
|
863
|
+
if (isLoaded) {
|
|
864
|
+
// 延迟20ms是为了给下载的样式留够渲染的时间
|
|
865
|
+
callback()
|
|
866
|
+
} else {
|
|
867
|
+
pollCss(node, callback, step)
|
|
868
|
+
}
|
|
869
|
+
clearTimeout(timer)
|
|
870
|
+
}, 20)
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
dataURLtoBlob (dataurl) {
|
|
875
|
+
var arr = dataurl.split(',')
|
|
876
|
+
var mime = arr[0].match(/:(.*?);/)[1]
|
|
877
|
+
var bstr = atob(arr[1])
|
|
878
|
+
var n = bstr.length
|
|
879
|
+
var u8arr = new Uint8Array(n)
|
|
880
|
+
while (n--) {
|
|
881
|
+
u8arr[n] = bstr.charCodeAt(n)
|
|
882
|
+
}
|
|
883
|
+
return new Blob([u8arr], { type: mime })
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
dataURLtoFile (dataurl, filename) {
|
|
887
|
+
var arr = dataurl.split(','); var mime = arr[0].match(/:(.*?);/)[1]
|
|
888
|
+
var bstr = atob(arr[1]); var n = bstr.length; var u8arr = new Uint8Array(n)
|
|
889
|
+
while (n--) {
|
|
890
|
+
u8arr[n] = bstr.charCodeAt(n)
|
|
891
|
+
}
|
|
892
|
+
const blob = new Blob([u8arr], { type: mime })
|
|
893
|
+
|
|
894
|
+
return new File([blob], filename, { type: mime })
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
usePlugin (plugin) {
|
|
898
|
+
const loadFile = (files) => {
|
|
899
|
+
let fileNum = 0
|
|
900
|
+
return new Promise(resolve => {
|
|
901
|
+
for (const file of files) {
|
|
902
|
+
if (file.includes('api.map.baidu.com') || file.includes('api.tianditu.gov.cn')) {
|
|
903
|
+
this.loadJS({
|
|
904
|
+
url: file,
|
|
905
|
+
callback () {
|
|
906
|
+
fileNum++
|
|
907
|
+
if (fileNum === files.length) {
|
|
908
|
+
return resolve()
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
})
|
|
912
|
+
} else if (file.includes('.js')) {
|
|
913
|
+
this.loadJS({
|
|
914
|
+
url: file,
|
|
915
|
+
callback () {
|
|
916
|
+
fileNum++
|
|
917
|
+
if (fileNum === files.length) {
|
|
918
|
+
return resolve()
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
})
|
|
922
|
+
} else if (file.includes('.css')) {
|
|
923
|
+
this.loadCss({
|
|
924
|
+
url: file,
|
|
925
|
+
callback () {
|
|
926
|
+
fileNum++
|
|
927
|
+
if (fileNum === files.length) {
|
|
928
|
+
return resolve()
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
})
|
|
932
|
+
} else {
|
|
933
|
+
fileNum++
|
|
934
|
+
if (fileNum === files.length) {
|
|
935
|
+
return resolve()
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
})
|
|
940
|
+
}
|
|
941
|
+
if (this.loadPlugins[plugin]) return this.loadPlugins[plugin]
|
|
942
|
+
const publicPath = this.getPublicPath()
|
|
943
|
+
const jsDir = this.getStaticJsDir()
|
|
944
|
+
if (plugin === 'luckysheet') {
|
|
945
|
+
const loadPromise = loadFile([publicPath + 'luckysheet/pluginsCss.css', publicPath + 'luckysheet/plugins.css', publicPath + 'luckysheet/luckysheet.css', publicPath + 'luckysheet/iconfont.css', publicPath + 'luckysheet/plugin.js', publicPath + 'luckysheet/luckysheet.umd.js'])
|
|
946
|
+
.then(() => globalThis.luckysheet)
|
|
947
|
+
this.loadPlugins[plugin] = loadPromise
|
|
948
|
+
return loadPromise
|
|
949
|
+
} else if (plugin === 'BMap') {
|
|
950
|
+
const loadPromise = new Promise(resolve => {
|
|
951
|
+
const ak = window.BMAP_AK || 'zySbI4xZUSRVrbb9Ev3H5xg4hA1md1gh'
|
|
952
|
+
loadFile([`//api.map.baidu.com/api?v=3.0&ak=${ak}&callback=loadBMapCallback`])
|
|
953
|
+
.then(() => window.BMap)
|
|
954
|
+
window.loadBMapCallback = () => {
|
|
955
|
+
resolve(window.BMap)
|
|
956
|
+
}
|
|
957
|
+
})
|
|
958
|
+
|
|
959
|
+
this.loadPlugins[plugin] = loadPromise
|
|
960
|
+
return loadPromise
|
|
961
|
+
} else if (plugin === 'TMap') {
|
|
962
|
+
const loadPromise = new Promise(resolve => {
|
|
963
|
+
const ak = window.TMAP_AK || '83086471ebe2a3e5292841ecaa3f7055'
|
|
964
|
+
loadFile([`//api.tianditu.gov.cn/api?v=4.0&tk=${ak}&callback=loadTMapCallback`])
|
|
965
|
+
.then(() => window.T && resolve(window.T))
|
|
966
|
+
window.loadTMapCallback = () => {
|
|
967
|
+
resolve(window.T)
|
|
968
|
+
}
|
|
969
|
+
})
|
|
970
|
+
|
|
971
|
+
this.loadPlugins[plugin] = loadPromise
|
|
972
|
+
return loadPromise
|
|
973
|
+
} else if (plugin === 'tinymce') {
|
|
974
|
+
const loadPromise = loadFile([publicPath + jsDir + 'tinymce/tinymce.min.js'])
|
|
975
|
+
.then(() => window.tinymce)
|
|
976
|
+
this.loadPlugins[plugin] = loadPromise
|
|
977
|
+
return loadPromise
|
|
978
|
+
} else if (plugin === 'onlyoffice') {
|
|
979
|
+
// ONLYOFFICE Document Server 地址在 config.js 中配置(window.ONLYOFFICE_URL),未配置时不加载
|
|
980
|
+
const officeUrl = this.getOfficeServerUrl()
|
|
981
|
+
if (!officeUrl) return Promise.reject(new Error('未配置 ONLYOFFICE_URL'))
|
|
982
|
+
const loadPromise = loadFile([`${officeUrl}/web-apps/apps/api/documents/api.js`])
|
|
983
|
+
.then(() => {
|
|
984
|
+
if (!window.DocsAPI) throw new Error('文档服务加载失败')
|
|
985
|
+
return window.DocsAPI
|
|
986
|
+
})
|
|
987
|
+
.catch(err => {
|
|
988
|
+
// 失败的 promise 不能留在缓存里,否则后续重试直接拿到旧的失败结果
|
|
989
|
+
delete this.loadPlugins[plugin]
|
|
990
|
+
throw err
|
|
991
|
+
})
|
|
992
|
+
this.loadPlugins[plugin] = loadPromise
|
|
993
|
+
return loadPromise
|
|
994
|
+
} else if (plugin === 'echarts') {
|
|
995
|
+
// 显式配置静态目录的平台继续使用原地址;独立产品使用包内资源。
|
|
996
|
+
const files = window.STATIC_JS_DIR
|
|
997
|
+
? [publicPath + jsDir + 'echarts.min.js?v=6.0.0-full', publicPath + jsDir + 'ecStat.min.js']
|
|
998
|
+
: chartRuntimeAssets
|
|
999
|
+
const loadPromise = Promise.all(files.map(url => new Promise((resolve, reject) => {
|
|
1000
|
+
this.loadJS({ url, callback: resolve, onerror: reject })
|
|
1001
|
+
})))
|
|
1002
|
+
.then(() => {
|
|
1003
|
+
if (!globalThis.echarts || !globalThis.ecStat) throw new Error('图表资源加载失败,请检查 ECharts 和 ecStat 脚本')
|
|
1004
|
+
return globalThis.echarts
|
|
1005
|
+
})
|
|
1006
|
+
.catch(error => {
|
|
1007
|
+
delete this.loadPlugins[plugin]
|
|
1008
|
+
throw error
|
|
1009
|
+
})
|
|
1010
|
+
this.loadPlugins[plugin] = loadPromise
|
|
1011
|
+
return loadPromise
|
|
1012
|
+
} else if (plugin === 'echarts-wordcloud') {
|
|
1013
|
+
const url = window.STATIC_JS_DIR ? publicPath + jsDir + 'echarts-wordcloud.min.js' : wordcloudUrl
|
|
1014
|
+
const loadPromise = new Promise((resolve, reject) => {
|
|
1015
|
+
this.loadJS({ url, callback: resolve, onerror: reject })
|
|
1016
|
+
}).catch(error => {
|
|
1017
|
+
delete this.loadPlugins[plugin]
|
|
1018
|
+
throw error
|
|
1019
|
+
})
|
|
1020
|
+
this.loadPlugins[plugin] = loadPromise
|
|
1021
|
+
return loadPromise
|
|
1022
|
+
} else if (plugin === 'pdf') {
|
|
1023
|
+
const browerVersion = this.getBrowserVersion()
|
|
1024
|
+
const isOldChrome = (browerVersion.brower === 'chrome' || browerVersion.brower === 'firefox') && browerVersion.version.split('.')[0] < 92
|
|
1025
|
+
const isIos = this.isIos()
|
|
1026
|
+
const loadPromise = loadFile([publicPath + jsDir + plugin + (isOldChrome || isIos ? '.2.4.456.js' : '.min.js')])
|
|
1027
|
+
.then(() => {
|
|
1028
|
+
const pdf = globalThis.pdfjsLib
|
|
1029
|
+
pdf.disableWorker = true
|
|
1030
|
+
pdf.GlobalWorkerOptions.workerSrc = publicPath + jsDir + (isOldChrome || isIos ? 'pdf.worker.js' : 'pdf.worker.min.js')
|
|
1031
|
+
return pdf
|
|
1032
|
+
})
|
|
1033
|
+
this.loadPlugins[plugin] = loadPromise
|
|
1034
|
+
return loadPromise
|
|
1035
|
+
} else {
|
|
1036
|
+
const loadPromise = loadFile([publicPath + jsDir + plugin + '.min.js'])
|
|
1037
|
+
.then(() => global[plugin])
|
|
1038
|
+
this.loadPlugins[plugin] = loadPromise
|
|
1039
|
+
return loadPromise
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
utf8to16 (str) {
|
|
1044
|
+
var hexOut = false
|
|
1045
|
+
var out, i, len, c
|
|
1046
|
+
var char2, char3
|
|
1047
|
+
var charCode
|
|
1048
|
+
|
|
1049
|
+
out = hexOut ? [] : ''
|
|
1050
|
+
len = str.length
|
|
1051
|
+
i = 0
|
|
1052
|
+
while (i < len) {
|
|
1053
|
+
c = hexOut ? str[i++] : str.charCodeAt(i++)
|
|
1054
|
+
switch (c >> 4) {
|
|
1055
|
+
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
|
1056
|
+
// 0xxxxxxx
|
|
1057
|
+
hexOut ? out.push(str[i - 1]) : out += str.charAt(i - 1)
|
|
1058
|
+
break
|
|
1059
|
+
case 12: case 13:
|
|
1060
|
+
// 110x xxxx 10xx xxxx
|
|
1061
|
+
char2 = hexOut ? str[i++] : str.charCodeAt(i++)
|
|
1062
|
+
charCode = ((c & 0x1F) << 6) | (char2 & 0x3F); hexOut ? out.push(charCode) : out += String.fromCharCode(charCode)
|
|
1063
|
+
break
|
|
1064
|
+
case 14:
|
|
1065
|
+
// 1110 xxxx 10xx xxxx 10xx xxxx
|
|
1066
|
+
char2 = hexOut ? str[i++] : str.charCodeAt(i++)
|
|
1067
|
+
char3 = hexOut ? str[i++] : str.charCodeAt(i++)
|
|
1068
|
+
charCode = ((c & 0x0F) << 12) |
|
|
1069
|
+
((char2 & 0x3F) << 6) |
|
|
1070
|
+
((char3 & 0x3F) << 0)
|
|
1071
|
+
hexOut ? out.push(charCode) : out += String.fromCharCode(charCode)
|
|
1072
|
+
break
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
return out
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
genId (length = 3) {
|
|
1080
|
+
return Number(Math.random().toString().substr(3, length) + Date.now()).toString(36)
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
uuid () {
|
|
1084
|
+
if (crypto?.randomUUID) {
|
|
1085
|
+
return crypto.randomUUID()
|
|
1086
|
+
} else {
|
|
1087
|
+
const S4 = () => {
|
|
1088
|
+
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
|
|
1089
|
+
}
|
|
1090
|
+
return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
copyToClipboard (text, callback) {
|
|
1095
|
+
if (navigator.clipboard) {
|
|
1096
|
+
navigator.clipboard.writeText(text)
|
|
1097
|
+
// eslint-disable-next-line standard/no-callback-literal
|
|
1098
|
+
callback && callback(true)
|
|
1099
|
+
return
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
var copyInput = document.getElementById('COPY_INPUT')
|
|
1103
|
+
if (!copyInput) {
|
|
1104
|
+
copyInput = document.createElement('input')
|
|
1105
|
+
copyInput.setAttribute('id', 'COPY_INPUT')
|
|
1106
|
+
copyInput.style.position = 'fixed'
|
|
1107
|
+
copyInput.style.left = '-100%'
|
|
1108
|
+
copyInput.style.top = '0'
|
|
1109
|
+
copyInput.style.zIndex = -100
|
|
1110
|
+
copyInput.style.opacity = 0
|
|
1111
|
+
document.body.appendChild(copyInput)
|
|
1112
|
+
}
|
|
1113
|
+
copyInput.value = text
|
|
1114
|
+
copyInput.focus()
|
|
1115
|
+
copyInput.select()
|
|
1116
|
+
|
|
1117
|
+
// document.execCommand 可能会被废弃
|
|
1118
|
+
if (document.execCommand('copy')) {
|
|
1119
|
+
document.execCommand('copy')
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
copyInput.blur()
|
|
1123
|
+
|
|
1124
|
+
// eslint-disable-next-line standard/no-callback-literal
|
|
1125
|
+
callback && callback(true)
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
getQueryValue (path, obj) {
|
|
1129
|
+
if (!path || !obj) return ''
|
|
1130
|
+
const value = path.split('.').reduce((acc, key) => acc && acc[key], obj)
|
|
1131
|
+
return isNil(value) ? '' : value
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
getValueByPath (path, obj) {
|
|
1135
|
+
const keys = []
|
|
1136
|
+
let currentKey = ''
|
|
1137
|
+
let inBrackets = false
|
|
1138
|
+
|
|
1139
|
+
for (const char of path) {
|
|
1140
|
+
if (char === '[') {
|
|
1141
|
+
inBrackets = true
|
|
1142
|
+
if (currentKey) {
|
|
1143
|
+
keys.push(currentKey)
|
|
1144
|
+
currentKey = ''
|
|
1145
|
+
}
|
|
1146
|
+
} else if (char === ']') {
|
|
1147
|
+
inBrackets = false
|
|
1148
|
+
if (currentKey) {
|
|
1149
|
+
const newKey = currentKey.replace(/^['"](.+)['"]$/, '$1')
|
|
1150
|
+
keys.push(newKey)
|
|
1151
|
+
currentKey = ''
|
|
1152
|
+
}
|
|
1153
|
+
} else if (char === '.' && !inBrackets) {
|
|
1154
|
+
if (currentKey) {
|
|
1155
|
+
keys.push(currentKey)
|
|
1156
|
+
currentKey = ''
|
|
1157
|
+
}
|
|
1158
|
+
} else {
|
|
1159
|
+
currentKey += char
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
if (currentKey) {
|
|
1164
|
+
keys.push(currentKey)
|
|
1165
|
+
}
|
|
1166
|
+
return keys.reduce((acc, key) => acc && acc[key], obj)
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* 解析操作按钮「后续事件」的参数配置 afterTriggerParams
|
|
1171
|
+
* 支持的占位符:
|
|
1172
|
+
* $[res] 取接口返回值本身
|
|
1173
|
+
* $[res.a.b] 取接口返回值的深层字段
|
|
1174
|
+
* $[key] 取组件实例上的值,取不到再依次回退 $tab / $query / $pageParams / $compData,支持 a.b.c 深层路径
|
|
1175
|
+
* #[field] 取数据字段值
|
|
1176
|
+
* 整串就是一个占位符时保留取到的原始类型(对象 / 数组 / 数字),混在文案里则替换为文本
|
|
1177
|
+
* @param {Object} afterTriggerParams 页面配置的参数对象
|
|
1178
|
+
* @param {Object} [options]
|
|
1179
|
+
* @param {*} [options.res] 接口返回值,供 $[res] / $[res.x] 取值
|
|
1180
|
+
* @param {Object|Array} [options.data] #[field] 的取值数据:传对象取该条的字段值,
|
|
1181
|
+
* 传数组视为多条记录(批量操作),各条的值用逗号拼接
|
|
1182
|
+
* @param {Object} ctx 组件实例,作为 $[key] 的取值上下文
|
|
1183
|
+
* @returns {Object} 解析后的新参数对象,不修改入参
|
|
1184
|
+
*/
|
|
1185
|
+
formatAfterTriggerParams (afterTriggerParams, { res, data } = {}, ctx = {}) {
|
|
1186
|
+
const _params = { ...afterTriggerParams }
|
|
1187
|
+
// data 传数组 = 多条记录(批量操作),传对象 = 单条数据
|
|
1188
|
+
const isMultiple = Array.isArray(data)
|
|
1189
|
+
const rows = [].concat(data === undefined ? [] : data).filter(item => !isNil(item))
|
|
1190
|
+
const paramData = { ...ctx.$tab, ...ctx.$query, ...ctx.$pageParams, ...ctx.$compData }
|
|
1191
|
+
const blank = value => (isNil(value) ? '' : value)
|
|
1192
|
+
const getResValue = path => blank(this.getValueByPath(path, res))
|
|
1193
|
+
const getCtxValue = path => {
|
|
1194
|
+
const value = this.getValueByPath(path, ctx)
|
|
1195
|
+
// 组件实例上没有(或为空)时才回退到页签 / 路由 / 页面 / 组件参数
|
|
1196
|
+
return blank(isNil(value) || value === '' ? this.getValueByPath(path, paramData) : value)
|
|
1197
|
+
}
|
|
1198
|
+
const getDataValue = path => {
|
|
1199
|
+
const values = rows.map(item => this.getValueByPath(path, item))
|
|
1200
|
+
// 多条记录按逗号拼接(不过滤空值,保证多个 #[] 参数的列一一对应),与 $formatParams 的 #[] 规则一致
|
|
1201
|
+
return isMultiple ? values.map(item => blank(item)).join(',') : blank(values[0])
|
|
1202
|
+
}
|
|
1203
|
+
// 没传 res 的调用点不占用 res 前缀,按普通取值处理
|
|
1204
|
+
const hasRes = res !== undefined
|
|
1205
|
+
const getValue = (flag, path) => {
|
|
1206
|
+
if (flag === '#') return getDataValue(path)
|
|
1207
|
+
if (!hasRes) return getCtxValue(path)
|
|
1208
|
+
if (path === 'res') return blank(res)
|
|
1209
|
+
if (path.indexOf('res.') === 0) return getResValue(path.slice(4))
|
|
1210
|
+
return getCtxValue(path)
|
|
1211
|
+
}
|
|
1212
|
+
for (const key in _params) {
|
|
1213
|
+
const config = _params[key]
|
|
1214
|
+
if (typeof config !== 'string') continue
|
|
1215
|
+
// 整串只有一个占位符时直接取值,避免 String.replace 把对象等类型转成文本
|
|
1216
|
+
const isWhole = /^[$#]\[.+\]$/.test(config) && config.indexOf('$[', 2) === -1 && config.indexOf('#[', 2) === -1
|
|
1217
|
+
let value = config
|
|
1218
|
+
if (isWhole) {
|
|
1219
|
+
value = getValue(config[0], config.slice(2, -1))
|
|
1220
|
+
} else if (/[$#]\[.+\]/.test(config)) {
|
|
1221
|
+
value = config.replace(/([$#])\[((?:[^[\]]|\[[^\]]*\])+)\]/g, (match, flag, path) => getValue(flag, path))
|
|
1222
|
+
}
|
|
1223
|
+
_params[key] = blank(value)
|
|
1224
|
+
}
|
|
1225
|
+
return _params
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
evalExpression (el, data, errorValue = false) {
|
|
1229
|
+
const formulaLibrary = {}
|
|
1230
|
+
for (const key in formula) {
|
|
1231
|
+
formulaLibrary[key] = formula[key]
|
|
1232
|
+
}
|
|
1233
|
+
const _data = {}
|
|
1234
|
+
for (const key in data) {
|
|
1235
|
+
if (key && key !== '[object Object]') {
|
|
1236
|
+
if (!key.includes('#')) {
|
|
1237
|
+
if (key.includes('|')) {
|
|
1238
|
+
const newKey = key.replaceAll('|', '$')
|
|
1239
|
+
el.replaceAll(key.replaceAll('|', '.'), newKey)
|
|
1240
|
+
_data[newKey] = data[key]
|
|
1241
|
+
} else {
|
|
1242
|
+
_data[key] = data[key]
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
try {
|
|
1248
|
+
// eslint-disable-next-line no-new-func
|
|
1249
|
+
return new Function(...Object.keys(formulaLibrary), ...Object.keys(_data), `return ${el}`)(...Object.values(formulaLibrary), ...Object.values(_data))
|
|
1250
|
+
} catch (e) {
|
|
1251
|
+
// ⚠️ 这个 catch 是本函数几乎所有调用点共用的唯一失败通道(showIf / limitConditionEl /
|
|
1252
|
+
// dataFormat / markerCondition / showCondition,以及 $formatContent 内部的 {{...}} 分支等),
|
|
1253
|
+
// 不能整体降噪——公式/条件表达式真写错了(语法错、访问链错)时,控制台报错是唯一线索。
|
|
1254
|
+
//
|
|
1255
|
+
// 只对 ReferenceError("xxx is not defined")单独降级:这类错误专指表达式引用了一个
|
|
1256
|
+
// 不在本次 data/公式库作用域内的标识符,最典型的是 $formatContent 默认作用域
|
|
1257
|
+
// (...this.$tab, ...pageParams, ...this.$query, ...this.$compData)不包含 appConfig /
|
|
1258
|
+
// clientConfig 这类只按实例上下文解析的绑定——每次页面加载只要 $configs 里有形如
|
|
1259
|
+
// {{appConfig['CLIENT|CODE']}} 的占位符就会稳定触发。这是预期路径而非错误:component.js
|
|
1260
|
+
// $formatContent 自己的注释写明「表达式执行失败时保留原内容,占位符可继续交由下面的
|
|
1261
|
+
// $[...] 分支/$formatUrl 等按实例上下文解析」,失败后 el/占位符原样保留,不影响功能。
|
|
1262
|
+
// 其余错误类型(SyntaxError 等语法写挂了、TypeError 等运行时访问出错)大概率是页面配置
|
|
1263
|
+
// 里表达式真的写错了,继续用 error 级别,不跟着一起静音。
|
|
1264
|
+
if (e instanceof ReferenceError) {
|
|
1265
|
+
console.debug('[evalExpression] 标识符不在求值作用域内(占位符可能待其他解析器按实例上下文处理):', e.message, '| 表达式:', el)
|
|
1266
|
+
} else {
|
|
1267
|
+
console.error(e)
|
|
1268
|
+
}
|
|
1269
|
+
return errorValue
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
openWindow (url) {
|
|
1274
|
+
const a = document.createElement('a')
|
|
1275
|
+
a.href = url
|
|
1276
|
+
a.target = '_blank'
|
|
1277
|
+
document.body.appendChild(a)
|
|
1278
|
+
a.click()
|
|
1279
|
+
document.body.removeChild(a)
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
encrypt (content, key, { type } = {}) {
|
|
1283
|
+
if (type === 'aes') {
|
|
1284
|
+
return import('crypto-js').then(cryptoModule => {
|
|
1285
|
+
const CryptoJS = 'default' in cryptoModule ? cryptoModule.default : cryptoModule
|
|
1286
|
+
const base64Key = atob(key)
|
|
1287
|
+
const aesKey = CryptoJS.enc.Utf8.parse(base64Key.toString(CryptoJS.enc.Utf8))
|
|
1288
|
+
const encrypted = CryptoJS.AES.encrypt(content, aesKey, {
|
|
1289
|
+
mode: CryptoJS.mode.CBC,
|
|
1290
|
+
padding: CryptoJS.pad.Pkcs7
|
|
1291
|
+
})
|
|
1292
|
+
return encrypted.toString()
|
|
1293
|
+
})
|
|
1294
|
+
} else {
|
|
1295
|
+
return import('jsencrypt/bin/jsencrypt.min').then(module => {
|
|
1296
|
+
const JSEncrypt = module.default
|
|
1297
|
+
const encrypt = new JSEncrypt()
|
|
1298
|
+
encrypt.setPublicKey(key)
|
|
1299
|
+
return encrypt.encrypt(content)
|
|
1300
|
+
})
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
decrypt (content, { type, key }) {
|
|
1305
|
+
if (type === 'aes') {
|
|
1306
|
+
return import('crypto-js').then(cryptoModule => {
|
|
1307
|
+
const CryptoJS = 'default' in cryptoModule ? cryptoModule.default : cryptoModule
|
|
1308
|
+
const base64Key = atob(key)
|
|
1309
|
+
const aesKey = CryptoJS.enc.Utf8.parse(base64Key.toString(CryptoJS.enc.Utf8))
|
|
1310
|
+
const decrypted = CryptoJS.AES.decrypt(content, aesKey, {
|
|
1311
|
+
iv: key,
|
|
1312
|
+
mode: CryptoJS.mode.CBC,
|
|
1313
|
+
padding: CryptoJS.pad.Pkcs7
|
|
1314
|
+
})
|
|
1315
|
+
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8))
|
|
1316
|
+
})
|
|
1317
|
+
} else {
|
|
1318
|
+
return import('jsencrypt/bin/jsencrypt.min').then(module => {
|
|
1319
|
+
const JSEncrypt = module.default
|
|
1320
|
+
const encrypt = new JSEncrypt()
|
|
1321
|
+
encrypt.setPrivateKey(key)
|
|
1322
|
+
return encrypt.decrypt(content)
|
|
1323
|
+
})
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
appendCss (id, css) {
|
|
1328
|
+
const style = document.createElement('style')
|
|
1329
|
+
style.id = 'style_' + id
|
|
1330
|
+
style.textContent = css.replace(/:current/g, '.css_' + id).replace(/url\s*\(([\w+-/.\s]+)\)/g, (str, $1) => {
|
|
1331
|
+
return `url(${util.getFileUrl($1)})`
|
|
1332
|
+
})
|
|
1333
|
+
|
|
1334
|
+
style.setAttribute('type', 'text/css')
|
|
1335
|
+
document.head.appendChild(style)
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
removeCss (id) {
|
|
1339
|
+
const element = document.getElementById('style_' + id)
|
|
1340
|
+
if (element) document.head.removeChild(element)
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
const util = new Util()
|
|
1345
|
+
|
|
1346
|
+
// 环境工具绑定单例,按函数导入时保留 this 和加载缓存。
|
|
1347
|
+
export const getSystemMeta = (...args) => util.getSystemMeta(...args)
|
|
1348
|
+
export const getFileUrl = (...args) => util.getFileUrl(...args)
|
|
1349
|
+
export const getSysId = (...args) => util.getSysId(...args)
|
|
1350
|
+
export const toLogin = (...args) => util.toLogin(...args)
|
|
1351
|
+
export const usePlugin = (...args) => util.usePlugin(...args)
|
|
1352
|
+
// 产品会 .call(vm, ...) 传组件作用域,不能把它固定绑定到 util。
|
|
1353
|
+
export function runExpByScope (...args) {
|
|
1354
|
+
return util.runExpByScope.apply(this == null ? util : this, args)
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
export default util
|