vue3-admin-gpt 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.env.development +14 -0
  2. package/.env.production +14 -0
  3. package/LICENSE +21 -0
  4. package/README.en.md +106 -0
  5. package/README.md +104 -0
  6. package/build-zip.cjs +53 -0
  7. package/cli.js +110 -0
  8. package/jsconfig.json +9 -0
  9. package/package.json +92 -0
  10. package/public/index.html +20 -0
  11. package/public/robots.txt +2 -0
  12. package/rspack.config.js +282 -0
  13. package/rspack.js +162 -0
  14. package/src/App.vue +9 -0
  15. package/src/api/icon.js +9 -0
  16. package/src/api/router.js +9 -0
  17. package/src/api/table.js +25 -0
  18. package/src/api/tree.js +9 -0
  19. package/src/api/user.js +34 -0
  20. package/src/assets/error_images/401.png +0 -0
  21. package/src/assets/error_images/404.png +0 -0
  22. package/src/assets/error_images/cloud.png +0 -0
  23. package/src/assets/login_images/background.jpg +0 -0
  24. package/src/assets/logo.png +0 -0
  25. package/src/assets/qr_logo/lqr_logo.png +0 -0
  26. package/src/assets/vuejs-fill.svg +4 -0
  27. package/src/components/VabPageHeader/index.vue +133 -0
  28. package/src/config/index.js +7 -0
  29. package/src/config/net.config.js +20 -0
  30. package/src/config/permission.js +136 -0
  31. package/src/config/setting.config.js +62 -0
  32. package/src/config/settings.js +6 -0
  33. package/src/config/theme.config.js +14 -0
  34. package/src/layouts/EmptyLayout.vue +3 -0
  35. package/src/layouts/components/VabAppMain/index.vue +109 -0
  36. package/src/layouts/components/VabAvatar/index.vue +255 -0
  37. package/src/layouts/components/VabBreadcrumb/index.vue +61 -0
  38. package/src/layouts/components/VabFullScreen/index.vue +61 -0
  39. package/src/layouts/components/VabLogo/index.vue +94 -0
  40. package/src/layouts/components/VabNav/index.vue +176 -0
  41. package/src/layouts/components/VabSide/components/VabMenuItem.vue +80 -0
  42. package/src/layouts/components/VabSide/components/VabSideItem.vue +100 -0
  43. package/src/layouts/components/VabSide/components/VabSubmenu.vue +56 -0
  44. package/src/layouts/components/VabSide/index.vue +123 -0
  45. package/src/layouts/components/VabTabs/index.vue +500 -0
  46. package/src/layouts/components/VabTheme/index.vue +603 -0
  47. package/src/layouts/components/VabTop/index.vue +286 -0
  48. package/src/layouts/export.js +29 -0
  49. package/src/layouts/index.vue +339 -0
  50. package/src/main.js +40 -0
  51. package/src/plugins/echarts.js +4 -0
  52. package/src/plugins/index.js +44 -0
  53. package/src/plugins/support.js +16 -0
  54. package/src/router/index.js +400 -0
  55. package/src/store/index.js +26 -0
  56. package/src/store/modules/errorLog.js +27 -0
  57. package/src/store/modules/routes.js +60 -0
  58. package/src/store/modules/settings.js +73 -0
  59. package/src/store/modules/table.js +22 -0
  60. package/src/store/modules/tabsBar.js +109 -0
  61. package/src/store/modules/user.js +131 -0
  62. package/src/styles/element-variables.scss +13 -0
  63. package/src/styles/loading.scss +345 -0
  64. package/src/styles/nav-icons.scss +52 -0
  65. package/src/styles/normalize.scss +353 -0
  66. package/src/styles/spinner/dots.css +68 -0
  67. package/src/styles/spinner/gauge.css +104 -0
  68. package/src/styles/spinner/inner-circles.css +51 -0
  69. package/src/styles/spinner/plus.css +341 -0
  70. package/src/styles/themes/default.scss +1 -0
  71. package/src/styles/transition.scss +18 -0
  72. package/src/styles/vab.scss +476 -0
  73. package/src/styles/variables.scss +69 -0
  74. package/src/utils/accessToken.js +56 -0
  75. package/src/utils/eventBus.js +8 -0
  76. package/src/utils/handleRoutes.js +100 -0
  77. package/src/utils/index.js +231 -0
  78. package/src/utils/message.js +67 -0
  79. package/src/utils/pageTitle.js +11 -0
  80. package/src/utils/password.js +43 -0
  81. package/src/utils/permission.js +19 -0
  82. package/src/utils/request.js +187 -0
  83. package/src/utils/static.js +81 -0
  84. package/src/utils/vab.js +218 -0
  85. package/src/utils/validate.js +48 -0
  86. package/src/views/401.vue +302 -0
  87. package/src/views/404.vue +302 -0
  88. package/src/views/demo/index.vue +591 -0
  89. package/src/views/index/index.vue +1489 -0
  90. package/src/views/login/index.vue +456 -0
  91. package/src/views/register/index.vue +524 -0
  92. package/src/views/vab/calendar.vue +488 -0
  93. package/src/views/vab/campaign.vue +1006 -0
  94. package/src/views/vab/chart.vue +189 -0
  95. package/src/views/vab/customer.vue +666 -0
  96. package/src/views/vab/editor.vue +84 -0
  97. package/src/views/vab/form.vue +151 -0
  98. package/src/views/vab/help.vue +390 -0
  99. package/src/views/vab/icon.vue +113 -0
  100. package/src/views/vab/knowledge.vue +820 -0
  101. package/src/views/vab/nested/menu1/menu2/menu3.vue +29 -0
  102. package/src/views/vab/nested/menu1/menu2.vue +33 -0
  103. package/src/views/vab/nested/menu1.vue +33 -0
  104. package/src/views/vab/nested.vue +97 -0
  105. package/src/views/vab/notification.vue +416 -0
  106. package/src/views/vab/order.vue +507 -0
  107. package/src/views/vab/permissions.vue +214 -0
  108. package/src/views/vab/product.vue +724 -0
  109. package/src/views/vab/project.vue +559 -0
  110. package/src/views/vab/settings.vue +319 -0
  111. package/src/views/vab/statistics.vue +431 -0
  112. package/src/views/vab/table.vue +110 -0
  113. package/src/views/vab/task.vue +613 -0
  114. package/src/views/vab/team.vue +662 -0
  115. package/src/views/vab/tree.vue +44 -0
  116. package/src/views/vab/upload.vue +180 -0
  117. package/src/views/vab/vue3Demo/index.vue +103 -0
  118. package/src/views/vab/workflow.vue +863 -0
@@ -0,0 +1,476 @@
1
+ /**
2
+ * @description 全局样式
3
+ */
4
+
5
+ @charset "utf-8";
6
+
7
+ @import "./normalize.scss";
8
+ @import "./transition.scss";
9
+ @import "./loading.scss";
10
+ @import "./nav-icons.scss"; // 导入导航图标样式
11
+
12
+ $base: ".vab";
13
+
14
+ @mixin scrollbar {
15
+ max-height: 88vh;
16
+ margin-bottom: 0.5vh;
17
+ overflow-y: auto;
18
+
19
+ &::-webkit-scrollbar {
20
+ width: 0;
21
+ height: 0;
22
+ background: transparent;
23
+ }
24
+
25
+ &::-webkit-scrollbar-thumb {
26
+ background-color: rgba(144, 147, 153, 0.3);
27
+ border-radius: 10px;
28
+ }
29
+
30
+ &::-webkit-scrollbar-thumb:hover {
31
+ background-color: rgba(144, 147, 153, 0.3);
32
+ }
33
+ }
34
+
35
+ @mixin base-scrollbar {
36
+ &::-webkit-scrollbar {
37
+ width: 13px;
38
+ height: 13px;
39
+ }
40
+
41
+ &::-webkit-scrollbar-thumb {
42
+ background-color: rgba(0, 0, 0, 0.4);
43
+ background-clip: padding-box;
44
+ border: 3px solid transparent;
45
+ border-radius: 7px;
46
+ }
47
+
48
+ &::-webkit-scrollbar-thumb:hover {
49
+ background-color: rgba(0, 0, 0, 0.5);
50
+ }
51
+
52
+ &::-webkit-scrollbar-track {
53
+ background-color: transparent;
54
+ }
55
+
56
+ &::-webkit-scrollbar-track:hover {
57
+ background-color: #f8fafc;
58
+ }
59
+ }
60
+
61
+ img {
62
+ object-fit: cover;
63
+ }
64
+
65
+ a {
66
+ color: $base-color-blue;
67
+ text-decoration: none;
68
+ cursor: pointer;
69
+ }
70
+
71
+ * {
72
+ transition: $base-transition;
73
+ }
74
+
75
+ svg {
76
+ transition: none;
77
+
78
+ * {
79
+ transition: none;
80
+ }
81
+ }
82
+
83
+ html {
84
+ body {
85
+ position: relative;
86
+ height: 100vh;
87
+ padding: 0;
88
+ margin: 0;
89
+ font-family: Avenir, Helvetica, Arial, sans-serif;
90
+ font-size: $base-font-size-default;
91
+ color: #2c3e50;
92
+ background: #f6f8f9;
93
+ -webkit-font-smoothing: antialiased;
94
+ -moz-osx-font-smoothing: grayscale;
95
+
96
+ @include base-scrollbar;
97
+
98
+ div {
99
+ @include base-scrollbar;
100
+ }
101
+
102
+ svg,
103
+ i {
104
+ &:hover {
105
+ opacity: 0.8;
106
+ }
107
+ }
108
+
109
+ .v-modal {
110
+ backdrop-filter: blur(10px);
111
+ }
112
+
113
+ .el-tag + .el-tag {
114
+ margin-left: 10px;
115
+ }
116
+
117
+ .editor-toolbar {
118
+ .no-mobile,
119
+ .fa-question-circle {
120
+ display: none;
121
+ }
122
+ }
123
+
124
+ .el-divider--horizontal {
125
+ margin: 10px 0 25px 0;
126
+
127
+ .el-divider__text {
128
+ display: -webkit-box;
129
+ overflow: hidden;
130
+ text-overflow: ellipsis;
131
+ -webkit-line-clamp: 1;
132
+ -webkit-box-orient: vertical;
133
+ }
134
+ }
135
+
136
+ .el-image-viewer {
137
+ &__close {
138
+ .el-icon-circle-close {
139
+ color: $base-color-white;
140
+ }
141
+ }
142
+ }
143
+
144
+ .vue-admin-better-wrapper {
145
+ .app-main-container {
146
+ @include base-scrollbar;
147
+
148
+ > [class*="-container"] {
149
+ * {
150
+ transition: none;
151
+ }
152
+
153
+ padding: $base-padding;
154
+ background: $base-color-white;
155
+ }
156
+ }
157
+ }
158
+
159
+ /* 进度条开始 */
160
+ #nprogress {
161
+ position: fixed;
162
+ z-index: $base-z-index;
163
+
164
+ .bar {
165
+ background: $base-color-blue !important;
166
+ }
167
+
168
+ .peg {
169
+ box-shadow: 0 0 10px $base-color-blue, 0 0 5px $base-color-blue !important;
170
+ }
171
+ }
172
+
173
+ .el-table {
174
+ .el-table__body-wrapper {
175
+ @include base-scrollbar;
176
+ }
177
+
178
+ th {
179
+ background: #f5f7fa;
180
+ }
181
+
182
+ td,
183
+ th {
184
+ position: relative;
185
+ box-sizing: border-box;
186
+ padding: 7.5px 0;
187
+
188
+ .cell {
189
+ font-size: $base-font-size-default;
190
+ font-weight: normal;
191
+ color: #606266;
192
+
193
+ .el-image {
194
+ width: 50px;
195
+ height: 50px;
196
+ border-radius: $base-border-radius;
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ .el-pagination {
203
+ padding: 2px 5px;
204
+ margin: 15px 0 0 0;
205
+ font-weight: normal;
206
+ color: $base-color-black;
207
+ text-align: center;
208
+ }
209
+
210
+ .el-menu.el-menu--popup.el-menu--popup-right-start {
211
+ @include scrollbar;
212
+ }
213
+
214
+ .el-menu.el-menu--popup.el-menu--popup-bottom-start {
215
+ @include scrollbar;
216
+ }
217
+
218
+ .el-submenu__title i {
219
+ color: $base-color-white;
220
+ }
221
+
222
+ .el-dialog,
223
+ .el-message-box {
224
+ &__body {
225
+ border-top: 1px solid $base-border-color;
226
+
227
+ .el-form {
228
+ padding-right: 30px;
229
+ }
230
+ }
231
+
232
+ &__footer {
233
+ padding: $base-padding;
234
+ text-align: right;
235
+ border-top: 1px solid $base-border-color;
236
+ }
237
+
238
+ &__content {
239
+ padding: 20px 20px 20px 20px;
240
+ }
241
+ }
242
+
243
+ .el-card {
244
+ margin-bottom: 15px;
245
+ border-radius: 12px;
246
+ border: none;
247
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
248
+
249
+ &__body {
250
+ padding: $base-padding;
251
+ }
252
+ }
253
+
254
+ /* VabPageHeader 全局样式 - 高优先级 */
255
+ .page-header {
256
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
257
+ border-radius: 12px !important;
258
+ padding: 30px !important;
259
+ margin-bottom: 24px !important;
260
+ color: white !important;
261
+ box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3) !important;
262
+ border: none !important;
263
+
264
+ .header-content {
265
+ display: flex !important;
266
+ justify-content: space-between !important;
267
+ align-items: center !important;
268
+
269
+ .header-left {
270
+ .page-title {
271
+ font-size: 2rem !important;
272
+ font-weight: 700 !important;
273
+ margin: 0 0 8px 0 !important;
274
+ display: flex !important;
275
+ align-items: center !important;
276
+ gap: 12px !important;
277
+ color: white !important;
278
+
279
+ .vab-icon {
280
+ font-size: 1.8rem !important;
281
+ color: white !important;
282
+ }
283
+ }
284
+
285
+ .page-description {
286
+ font-size: 1rem !important;
287
+ opacity: 0.9 !important;
288
+ margin: 0 !important;
289
+ color: white !important;
290
+ }
291
+ }
292
+
293
+ .header-right {
294
+ display: flex !important;
295
+ align-items: center !important;
296
+ gap: 8px !important;
297
+ font-size: 1.1rem !important;
298
+ font-weight: 600 !important;
299
+ color: white !important;
300
+
301
+ .vab-icon {
302
+ font-size: 1.3rem !important;
303
+ color: white !important;
304
+ }
305
+ }
306
+ }
307
+ }
308
+
309
+ /* 响应式设计 */
310
+ @media (max-width: 768px) {
311
+ .page-header {
312
+ padding: 20px !important;
313
+
314
+ .header-content {
315
+ flex-direction: column !important;
316
+ gap: 16px !important;
317
+ text-align: center !important;
318
+
319
+ .header-left {
320
+ .page-title {
321
+ font-size: 1.5rem !important;
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ .select-tree-popper {
329
+ .el-scrollbar {
330
+ .el-scrollbar__view {
331
+ .el-select-dropdown__item {
332
+ height: auto;
333
+ max-height: 274px;
334
+ padding: 0;
335
+ overflow-y: auto;
336
+ line-height: 26px;
337
+ }
338
+ }
339
+ }
340
+ }
341
+
342
+ /* 扩展 el-divider 样式 */
343
+ .el-divider {
344
+ position: relative;
345
+ border: none;
346
+ background: linear-gradient(90deg, transparent, #e4e7ed, transparent);
347
+
348
+ &--horizontal {
349
+ height: 1px;
350
+ margin: 20px 0 30px 0;
351
+
352
+ .el-divider__text {
353
+ position: relative;
354
+ padding: 0 16px;
355
+ font-size: 14px;
356
+ font-weight: 500;
357
+ color: #606266;
358
+ background: #fff;
359
+ border-radius: 4px;
360
+
361
+ &::before {
362
+ content: "";
363
+ position: absolute;
364
+ top: 50%;
365
+ left: -8px;
366
+ width: 4px;
367
+ height: 4px;
368
+ margin-top: -2px;
369
+ background: #409eff;
370
+ border-radius: 50%;
371
+ }
372
+ }
373
+ }
374
+
375
+ &--vertical {
376
+ width: 1px;
377
+ height: 1em;
378
+ margin: 0 16px;
379
+ background: #e4e7ed;
380
+ }
381
+
382
+ /* 主题变体 */
383
+ &--primary {
384
+ background: linear-gradient(90deg, transparent, #409eff, transparent);
385
+
386
+ .el-divider__text {
387
+ color: #409eff;
388
+
389
+ &::before {
390
+ background: #409eff;
391
+ }
392
+ }
393
+ }
394
+
395
+ &--success {
396
+ background: linear-gradient(90deg, transparent, #67c23a, transparent);
397
+
398
+ .el-divider__text {
399
+ color: #67c23a;
400
+
401
+ &::before {
402
+ background: #67c23a;
403
+ }
404
+ }
405
+ }
406
+
407
+ &--warning {
408
+ background: linear-gradient(90deg, transparent, #e6a23c, transparent);
409
+
410
+ .el-divider__text {
411
+ color: #e6a23c;
412
+
413
+ &::before {
414
+ background: #e6a23c;
415
+ }
416
+ }
417
+ }
418
+
419
+ &--danger {
420
+ background: linear-gradient(90deg, transparent, #f56c6c, transparent);
421
+
422
+ .el-divider__text {
423
+ color: #f56c6c;
424
+
425
+ &::before {
426
+ background: #f56c6c;
427
+ }
428
+ }
429
+ }
430
+
431
+ /* 虚线样式 */
432
+ &--dashed {
433
+ background: none;
434
+ border-top: 1px dashed #e4e7ed;
435
+
436
+ .el-divider__text {
437
+ background: #fff;
438
+ }
439
+ }
440
+
441
+ /* 粗线样式 */
442
+ &--thick {
443
+ height: 2px;
444
+ background: linear-gradient(90deg, transparent, #409eff, transparent);
445
+ }
446
+ }
447
+ }
448
+
449
+ .side-container {
450
+ .el-menu--collapse {
451
+ .el-menu-item,
452
+ .el-sub-menu {
453
+ display: flex;
454
+ align-items: center;
455
+ justify-content: center;
456
+ }
457
+ }
458
+ .el-menu-item,
459
+ .el-sub-menu > .el-sub-menu__title {
460
+ * {
461
+ box-sizing: border-box;
462
+ }
463
+ box-sizing: border-box;
464
+ margin: 7px;
465
+ border-radius: 5px !important;
466
+
467
+ &:hover {
468
+ border-radius: 5px !important;
469
+ }
470
+
471
+ &.is-active {
472
+ background: $base-color-default !important;
473
+ }
474
+ }
475
+ }
476
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @description 全局主题变量配置
3
+ */
4
+ /* stylelint-disable */
5
+ @charset "utf-8";
6
+ //框架默认主题色
7
+ $base-color-default: #409eff;
8
+ //默认层级
9
+ $base-z-index: 999;
10
+ //横向布局纵向布局时菜单背景色
11
+ $base-menu-background: #21252b;
12
+ //菜单文字颜色
13
+ $base-menu-color: hsla(0, 0%, 100%, 0.95);
14
+ //菜单选中文字颜色
15
+ $base-menu-color-active: hsla(0, 0%, 100%, 0.95);
16
+ //菜单选中背景色
17
+ $base-menu-background-active: $base-color-default;
18
+ //标题颜色
19
+ $base-title-color: #fff;
20
+ //字体大小配置
21
+ $base-font-size-small: 12px;
22
+ $base-font-size-default: 14px;
23
+ $base-font-size-big: 16px;
24
+ $base-font-size-bigger: 18px;
25
+ $base-font-size-max: 22px;
26
+ $base-font-color: #606266;
27
+ $base-color-blue: $base-color-default;
28
+ $base-color-green: #41b882;
29
+ $base-color-white: #fff;
30
+ $base-color-black: #000;
31
+ $base-color-yellow: #ffa91b;
32
+ $base-color-orange: #ff6700;
33
+ $base-color-red: #f34d37;
34
+ $base-color-gray: rgba(0, 0, 0, 0.65);
35
+ $base-main-width: 1279px;
36
+ $base-border-radius: 4px;
37
+ $base-border-color: #dcdfe6;
38
+ //输入框高度
39
+ $base-input-height: 32px;
40
+ //默认paddiing
41
+ $base-padding: 20px;
42
+ //默认阴影
43
+ $base-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
44
+ //横向布局时top-bar、logo、一级菜单的高度
45
+ $base-top-bar-height: 65px;
46
+ //纵向布局时logo的高度
47
+ $base-logo-height: 75px;
48
+ //顶部nav-bar的高度
49
+ $base-nav-bar-height: 60px;
50
+ //顶部多标签页tabs-bar的高度
51
+ $base-tabs-bar-height: 55px;
52
+ //顶部多标签页tabs-bar中每一个item的高度
53
+ $base-tag-item-height: 34px;
54
+ //菜单li标签的高度
55
+ $base-menu-item-height: 50px;
56
+ //app-main的高度
57
+ $base-app-main-height: calc(100vh - #{$base-nav-bar-height} - #{$base-tabs-bar-height} - #{$base-padding} - #{$base-padding} - 55px - 55px);
58
+ //纵向布局时左侧导航未折叠时的宽度
59
+ $base-left-menu-width: 256px;
60
+ //纵向布局时左侧导航未折叠时右侧内容的宽度
61
+ $base-right-content-width: calc(100% - #{$base-left-menu-width});
62
+ //纵向布局时左侧导航已折叠时的宽度
63
+ $base-left-menu-width-min: 65px;
64
+ //纵向布局时左侧导航已折叠时右侧内容的宽度
65
+ $base-right-content-width-min: calc(100% - #{$base-left-menu-width-min});
66
+ //默认动画
67
+ $base-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), border 0s, background 0s, color 0s, font-size 0s;
68
+ //默认动画长
69
+ $base-transition-time: 0.3s;
@@ -0,0 +1,56 @@
1
+ import { storage, tokenTableName } from '@/config'
2
+
3
+ /**
4
+ * @description 获取accessToken
5
+ * @returns {string|ActiveX.IXMLDOMNode|Promise<any>|any|IDBRequest<any>|MediaKeyStatus|FormDataEntryValue|Function|Promise<Credential | null>}
6
+ */
7
+ export function getAccessToken() {
8
+ if (storage) {
9
+ if ('localStorage' === storage) {
10
+ return localStorage.getItem(tokenTableName)
11
+ } else if ('sessionStorage' === storage) {
12
+ return sessionStorage.getItem(tokenTableName)
13
+ } else {
14
+ return localStorage.getItem(tokenTableName)
15
+ }
16
+ } else {
17
+ return localStorage.getItem(tokenTableName)
18
+ }
19
+ }
20
+
21
+ /**
22
+ * @description 存储accessToken
23
+ * @param accessToken
24
+ * @returns {void|*}
25
+ */
26
+ export function setAccessToken(accessToken) {
27
+ if (storage) {
28
+ if ('localStorage' === storage) {
29
+ return localStorage.setItem(tokenTableName, accessToken)
30
+ } else if ('sessionStorage' === storage) {
31
+ return sessionStorage.setItem(tokenTableName, accessToken)
32
+ } else {
33
+ return localStorage.setItem(tokenTableName, accessToken)
34
+ }
35
+ } else {
36
+ return localStorage.setItem(tokenTableName, accessToken)
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @description 移除accessToken
42
+ * @returns {void|Promise<void>}
43
+ */
44
+ export function removeAccessToken() {
45
+ if (storage) {
46
+ if ('localStorage' === storage) {
47
+ return localStorage.removeItem(tokenTableName)
48
+ } else if ('sessionStorage' === storage) {
49
+ return sessionStorage.clear()
50
+ } else {
51
+ return localStorage.removeItem(tokenTableName)
52
+ }
53
+ } else {
54
+ return localStorage.removeItem(tokenTableName)
55
+ }
56
+ }
@@ -0,0 +1,8 @@
1
+ import { ref } from "vue";
2
+ import mitt from "mitt";
3
+
4
+ // 创建一个事件发射器实例
5
+ const emitter = mitt();
6
+
7
+ // 导出事件总线
8
+ export default emitter;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @description all模式渲染后端返回路由
3
+ * @param constantRoutes
4
+ * @returns {*}
5
+ */
6
+ export function convertRouter(asyncRoutes) {
7
+ // 处理空值情况
8
+ if (!asyncRoutes || !Array.isArray(asyncRoutes)) {
9
+ console.warn('后端返回的路由格式不正确或为空')
10
+ return []
11
+ }
12
+
13
+ return asyncRoutes
14
+ .map((route) => {
15
+ if (!route) return null
16
+
17
+ if (route.component) {
18
+ if (route.component === 'Layout') {
19
+ route.component = () => import('@/layouts')
20
+ } else if (route.component === 'EmptyLayout') {
21
+ route.component = () => import('@/layouts/EmptyLayout')
22
+ } else {
23
+ try {
24
+ const index = route.component.indexOf('views')
25
+ const path = index > 0 ? route.component.slice(index) : `views/${route.component}`
26
+ route.component = () =>
27
+ import(`@/${path}`).catch((err) => {
28
+ console.error(`路由组件加载失败: @/${path}`, err)
29
+ return import('@/views/404')
30
+ })
31
+ } catch (err) {
32
+ console.error(`路由组件解析失败: ${route.component}`, err)
33
+ route.component = () => import('@/views/404')
34
+ }
35
+ }
36
+ }
37
+
38
+ if (route.children) {
39
+ if (Array.isArray(route.children) && route.children.length) {
40
+ route.children = convertRouter(route.children)
41
+ // 过滤掉空路由
42
+ route.children = route.children.filter((child) => child !== null)
43
+ }
44
+ if (!route.children || route.children.length === 0) delete route.children
45
+ }
46
+
47
+ return route
48
+ })
49
+ .filter((route) => route !== null) // 过滤掉无效路由
50
+ }
51
+
52
+ /**
53
+ * @description 判断当前路由是否包含权限
54
+ * @param permissions
55
+ * @param route
56
+ * @returns {boolean|*}
57
+ */
58
+ function hasPermission(permissions, route) {
59
+ // 确保permissions是数组
60
+ if (!permissions || !Array.isArray(permissions)) {
61
+ return false
62
+ }
63
+
64
+ if (route.meta && route.meta.permissions) {
65
+ return permissions.some((role) => route.meta.permissions.includes(role))
66
+ } else {
67
+ return true
68
+ }
69
+ }
70
+
71
+ /**
72
+ * @description intelligence模式根据permissions数组拦截路由
73
+ * @param routes
74
+ * @param permissions
75
+ * @returns {[]}
76
+ */
77
+ export function filterAsyncRoutes(routes, permissions) {
78
+ // 处理无效参数
79
+ if (!routes || !Array.isArray(routes)) {
80
+ return []
81
+ }
82
+
83
+ if (!permissions || !Array.isArray(permissions)) {
84
+ return []
85
+ }
86
+
87
+ const finallyRoutes = []
88
+ routes.forEach((route) => {
89
+ if (!route) return
90
+
91
+ const item = { ...route }
92
+ if (hasPermission(permissions, item)) {
93
+ if (item.children && Array.isArray(item.children)) {
94
+ item.children = filterAsyncRoutes(item.children, permissions)
95
+ }
96
+ finallyRoutes.push(item)
97
+ }
98
+ })
99
+ return finallyRoutes
100
+ }