xto-fronted 0.4.93 → 0.4.95

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 (92) hide show
  1. package/dist/assets/404-C9Uh6Uu-.css +1 -0
  2. package/dist/assets/404-zjGLLssH.js +1 -0
  3. package/dist/assets/_plugin-vue_export-helper-DlAUqK2U.js +1 -0
  4. package/dist/assets/index-B5xc4gQB.css +1 -0
  5. package/dist/assets/index-BDgOY6Rp.js +1 -0
  6. package/dist/assets/index-BIoRANs0.js +1 -0
  7. package/dist/assets/index-BRR97dc6.js +1 -0
  8. package/dist/assets/index-Bz0BgZQ1.js +1 -0
  9. package/dist/assets/index-CAdztNsv.css +1 -0
  10. package/dist/assets/index-CCXrcISf.css +1 -0
  11. package/dist/assets/index-CfpZmcpk.css +1 -0
  12. package/dist/assets/index-CwJSA85U.js +1 -0
  13. package/dist/assets/index-CwRA10ac.js +1 -0
  14. package/dist/assets/index-D8NDxq9d.js +1 -0
  15. package/dist/assets/index-DEB6-Iv_.js +2 -0
  16. package/dist/assets/index-DM4Ezclc.css +1 -0
  17. package/dist/assets/index-DYv7nImj.css +1 -0
  18. package/dist/assets/index-t-2Y0KhA.css +1 -0
  19. package/dist/assets/vendor-CUVPinTg.js +13 -0
  20. package/dist/assets/vue-vendor-DeJXJVbN.js +29 -0
  21. package/dist/assets/xto-base-CL2NKZJJ.css +1 -0
  22. package/dist/assets/xto-base-PwLGsxxb.js +1 -0
  23. package/dist/assets/xto-business--V1F5Gwb.css +1 -0
  24. package/dist/assets/xto-core-CtL4zKiV.js +1 -0
  25. package/dist/assets/xto-data-MxZsiJgi.css +1 -0
  26. package/dist/assets/xto-data-bCXQa7fT.js +1 -0
  27. package/dist/assets/xto-feedback-Bxx38c3P.css +1 -0
  28. package/dist/assets/xto-feedback-CPydp0kn.js +1 -0
  29. package/dist/assets/xto-form-Cu6q3VLG.css +1 -0
  30. package/dist/assets/xto-form-bywohdAf.js +1 -0
  31. package/dist/assets/xto-layout-BDD6sSlM.css +1 -0
  32. package/dist/assets/xto-navigation-Bbdpine9.js +1 -0
  33. package/dist/assets/xto-navigation-XfpyMpEo.css +1 -0
  34. package/dist/components/Layout/MixTopMenu.vue.d.ts +6 -1
  35. package/dist/components/Layout/Sidebar.vue.d.ts +2 -0
  36. package/dist/components/Layout/TopMenu.vue.d.ts +6 -1
  37. package/dist/components/Layout/index.vue.d.ts +6 -1
  38. package/dist/{index-D59X6HmM.js → index-3ekBp4iW.js} +2 -2
  39. package/dist/{index-Cp8kqjtv.js → index-58aI1w0v.js} +2 -2
  40. package/dist/{index-me_Uu2lk.js → index-A_B_Ap_A.js} +1560 -1590
  41. package/dist/{index-lJrh5CFc.js → index-B5DLfOYb.js} +23 -23
  42. package/dist/index-BAmYUT0G.js +189 -0
  43. package/dist/{index-B4U8Dy2W.js → index-BK4Mut6H.js} +2 -2
  44. package/dist/index-BRvi9qW-.js +515 -0
  45. package/dist/index-BVGW4DDQ.js +189 -0
  46. package/dist/index-BXg94yA2.js +515 -0
  47. package/dist/index-Bmf0YbVq.js +189 -0
  48. package/dist/index-C2-a5KSQ.js +4233 -0
  49. package/dist/index-CAHSv7LK.js +4285 -0
  50. package/dist/index-CeZ0CSSs.js +641 -0
  51. package/dist/index-Cf8E7FM1.js +4270 -0
  52. package/dist/index-CgyQqbdx.js +189 -0
  53. package/dist/index-ChowNrlU.js +641 -0
  54. package/dist/index-D25KzR0I.js +479 -0
  55. package/dist/index-DCBIjLHy.js +515 -0
  56. package/dist/index-DEYOivza.js +641 -0
  57. package/dist/index-DReodgBw.js +4233 -0
  58. package/dist/index-DjERNRXX.js +515 -0
  59. package/dist/index-LSdsO2Ox.js +479 -0
  60. package/dist/index-UJixTdep.js +479 -0
  61. package/dist/index-gBlRG4kk.js +479 -0
  62. package/dist/index-xWU3J3OH.js +641 -0
  63. package/dist/index.es.js +1 -1
  64. package/dist/index.html +28 -0
  65. package/dist/index.umd.js +8 -8
  66. package/dist/style.css +1 -1
  67. package/package.json +91 -91
  68. package/src/App.vue +48 -48
  69. package/src/assets/styles/_dark.scss +639 -639
  70. package/src/assets/styles/_root.scss +183 -183
  71. package/src/assets/styles/_variables.scss +69 -69
  72. package/src/assets/styles/index.scss +460 -460
  73. package/src/components/Layout/MixTopMenu.vue +8 -1
  74. package/src/components/Layout/Sidebar.vue +200 -198
  75. package/src/components/Layout/SidebarMenuItem.vue +158 -158
  76. package/src/components/Layout/TopMenu.vue +1177 -1170
  77. package/src/components/Layout/index.vue +199 -192
  78. package/src/composables/useI18n.ts +43 -43
  79. package/src/index.ts +100 -100
  80. package/src/router/layoutRoute.ts +59 -59
  81. package/src/stores/index.ts +15 -15
  82. package/src/stores/locale.ts +66 -66
  83. package/src/types/json-bigint.d.ts +18 -18
  84. package/src/types/xto.d.ts +172 -172
  85. package/src/utils/request.ts +184 -184
  86. package/src/views/dashboard/index.vue +545 -545
  87. package/src/views/error/403.vue +251 -251
  88. package/src/views/error/404.vue +253 -253
  89. package/src/views/login/index.vue +586 -586
  90. package/src/views/system/menu/index.vue +690 -690
  91. package/src/views/system/role/index.vue +583 -583
  92. package/src/views/system/user/index.vue +655 -655
@@ -1,546 +1,546 @@
1
- <script setup lang="ts">
2
- import { ref } from 'vue'
3
- import { Progress } from '@xto/data'
4
-
5
- const stats = ref([
6
- { title: '用户总数', value: 1234, icon: '👥', color: '#1677ff', trend: '+12.5%', trendUp: true },
7
- { title: '今日访问', value: 567, icon: '👀', color: '#52c41a', trend: '+8.2%', trendUp: true },
8
- { title: '订单数量', value: 890, icon: '📦', color: '#faad14', trend: '-3.1%', trendUp: false },
9
- { title: '销售金额', value: 123456, icon: '💰', color: '#ff4d4f', trend: '+15.8%', trendUp: true }
10
- ])
11
-
12
- const activities = ref([
13
- { user: '张三', action: '登录系统', time: '2分钟前', type: 'success', avatar: '张' },
14
- { user: '李四', action: '修改了用户信息', time: '5分钟前', type: 'warning', avatar: '李' },
15
- { user: '王五', action: '创建了新订单', time: '10分钟前', type: 'info', avatar: '王' },
16
- { user: '赵六', action: '删除了测试数据', time: '30分钟前', type: 'danger', avatar: '赵' },
17
- { user: '钱七', action: '更新了系统配置', time: '1小时前', type: 'primary', avatar: '钱' }
18
- ])
19
-
20
- const quickLinks = ref([
21
- { title: '用户管理', path: '/system/user', icon: '👤', desc: '管理系统用户' },
22
- { title: '角色管理', path: '/system/role', icon: '👥', desc: '角色权限配置' },
23
- { title: '菜单管理', path: '/system/menu', icon: '📋', desc: '菜单路由管理' },
24
- { title: '系统设置', path: '/system', icon: '⚙️', desc: '系统参数配置' }
25
- ])
26
-
27
- const systemInfo = ref([
28
- { label: '系统版本', value: 'v1.0.0' },
29
- { label: 'Vue 版本', value: '3.4.21' },
30
- { label: '构建工具', value: 'Vite 5' },
31
- { label: 'UI 组件库', value: 'XTO UI' }
32
- ])
33
- </script>
34
-
35
- <template>
36
- <div class="dashboard">
37
- <!-- 统计卡片 -->
38
- <div class="stats-section">
39
- <div v-for="stat in stats" :key="stat.title" class="stat-card">
40
- <div class="stat-icon" :style="{ background: `linear-gradient(135deg, ${stat.color}20 0%, ${stat.color}10 100%)` }">
41
- <span>{{ stat.icon }}</span>
42
- </div>
43
- <div class="stat-content">
44
- <div class="stat-title">{{ stat.title }}</div>
45
- <div class="stat-value" :style="{ color: stat.color }">
46
- {{ stat.value.toLocaleString() }}
47
- </div>
48
- <div class="stat-trend" :class="{ up: stat.trendUp, down: !stat.trendUp }">
49
- <svg v-if="stat.trendUp" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
50
- <path d="M7 17l5-5 5 5M7 7l5 5 5-5"/>
51
- </svg>
52
- <svg v-else viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
53
- <path d="M7 7l5 5 5-5M7 17l5-5 5 5"/>
54
- </svg>
55
- <span>{{ stat.trend }}</span>
56
- </div>
57
- </div>
58
- <div class="stat-decoration" :style="{ background: `linear-gradient(135deg, ${stat.color}08 0%, transparent 100%)` }"></div>
59
- </div>
60
- </div>
61
-
62
- <!-- 主体内容 -->
63
- <div class="main-section">
64
- <!-- 快捷入口 -->
65
- <div class="quick-section">
66
- <div class="section-header">
67
- <h3>快捷入口</h3>
68
- <span class="section-badge">4 个入口</span>
69
- </div>
70
- <div class="quick-grid">
71
- <router-link
72
- v-for="link in quickLinks"
73
- :key="link.path"
74
- :to="link.path"
75
- class="quick-card"
76
- >
77
- <div class="quick-icon">{{ link.icon }}</div>
78
- <div class="quick-info">
79
- <div class="quick-title">{{ link.title }}</div>
80
- <div class="quick-desc">{{ link.desc }}</div>
81
- </div>
82
- <div class="quick-arrow">
83
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
84
- <path d="M9 18l6-6-6-6"/>
85
- </svg>
86
- </div>
87
- </router-link>
88
- </div>
89
- </div>
90
-
91
- <!-- 最近活动 -->
92
- <div class="activity-section">
93
- <div class="section-header">
94
- <h3>最近活动</h3>
95
- <a href="#" class="section-link">查看全部</a>
96
- </div>
97
- <div class="activity-list">
98
- <div v-for="(activity, index) in activities" :key="index" class="activity-item">
99
- <div class="activity-avatar" :class="activity.type">
100
- {{ activity.avatar }}
101
- </div>
102
- <div class="activity-content">
103
- <div class="activity-main">
104
- <span class="activity-user">{{ activity.user }}</span>
105
- <span class="activity-action">{{ activity.action }}</span>
106
- </div>
107
- <div class="activity-time">{{ activity.time }}</div>
108
- </div>
109
- <div class="activity-dot" :class="activity.type"></div>
110
- </div>
111
- </div>
112
- </div>
113
- </div>
114
-
115
- <!-- 系统信息 -->
116
- <div class="system-section">
117
- <div class="section-header">
118
- <h3>系统信息</h3>
119
- </div>
120
- <div class="system-grid">
121
- <div class="system-info-list">
122
- <div v-for="info in systemInfo" :key="info.label" class="info-item">
123
- <span class="info-label">{{ info.label }}</span>
124
- <span class="info-value">{{ info.value }}</span>
125
- </div>
126
- </div>
127
- <div class="system-status">
128
- <div class="status-item">
129
- <div class="status-header">
130
- <span class="status-label">服务器状态</span>
131
- <span class="status-value">75%</span>
132
- </div>
133
- <Progress :percentage="75" status="success" />
134
- </div>
135
- <div class="status-item">
136
- <div class="status-header">
137
- <span class="status-label">内存使用</span>
138
- <span class="status-value">45%</span>
139
- </div>
140
- <Progress :percentage="45" />
141
- </div>
142
- <div class="status-item">
143
- <div class="status-header">
144
- <span class="status-label">CPU 使用率</span>
145
- <span class="status-value">32%</span>
146
- </div>
147
- <Progress :percentage="32" />
148
- </div>
149
- </div>
150
- </div>
151
- </div>
152
- </div>
153
- </template>
154
-
155
- <style lang="scss" scoped>
156
- .dashboard {
157
- padding: 24px;
158
- background: var(--bg-color-page);
159
- min-height: 100%;
160
- }
161
-
162
- // 统计卡片
163
- .stats-section {
164
- display: grid;
165
- grid-template-columns: repeat(4, 1fr);
166
- gap: 20px;
167
- margin-bottom: 24px;
168
-
169
- @media (max-width: 1200px) {
170
- grid-template-columns: repeat(2, 1fr);
171
- }
172
-
173
- @media (max-width: 768px) {
174
- grid-template-columns: 1fr;
175
- }
176
- }
177
-
178
- .stat-card {
179
- position: relative;
180
- display: flex;
181
- align-items: flex-start;
182
- gap: 16px;
183
- padding: 20px;
184
- background: var(--bg-color);
185
- border-radius: var(--border-radius-large);
186
- box-shadow: var(--box-shadow-card);
187
- transition: all 0.3s ease;
188
- overflow: hidden;
189
-
190
- &:hover {
191
- box-shadow: var(--box-shadow-card-hover);
192
- transform: translateY(-4px);
193
-
194
- .stat-decoration {
195
- opacity: 1;
196
- }
197
- }
198
-
199
- .stat-icon {
200
- width: 52px;
201
- height: 52px;
202
- display: flex;
203
- align-items: center;
204
- justify-content: center;
205
- border-radius: var(--border-radius-large);
206
- flex-shrink: 0;
207
-
208
- span {
209
- font-size: 26px;
210
- }
211
- }
212
-
213
- .stat-content {
214
- flex: 1;
215
- min-width: 0;
216
- }
217
-
218
- .stat-title {
219
- font-size: 14px;
220
- color: var(--color-text-secondary);
221
- margin-bottom: 8px;
222
- }
223
-
224
- .stat-value {
225
- font-size: 28px;
226
- font-weight: 600;
227
- line-height: 1.2;
228
- margin-bottom: 8px;
229
- }
230
-
231
- .stat-trend {
232
- display: inline-flex;
233
- align-items: center;
234
- gap: 4px;
235
- font-size: 12px;
236
- padding: 2px 8px;
237
- border-radius: 12px;
238
-
239
- svg {
240
- width: 14px;
241
- height: 14px;
242
- }
243
-
244
- &.up {
245
- color: var(--color-success);
246
- background: var(--color-success-lighter);
247
- }
248
-
249
- &.down {
250
- color: var(--color-danger);
251
- background: var(--color-danger-lighter);
252
- }
253
- }
254
-
255
- .stat-decoration {
256
- position: absolute;
257
- top: 0;
258
- right: 0;
259
- width: 100px;
260
- height: 100px;
261
- border-radius: 50%;
262
- opacity: 0;
263
- transition: opacity 0.3s ease;
264
- }
265
- }
266
-
267
- // 主体内容
268
- .main-section {
269
- display: grid;
270
- grid-template-columns: repeat(2, 1fr);
271
- gap: 24px;
272
- margin-bottom: 24px;
273
-
274
- @media (max-width: 992px) {
275
- grid-template-columns: 1fr;
276
- }
277
- }
278
-
279
- .section-header {
280
- display: flex;
281
- justify-content: space-between;
282
- align-items: center;
283
- margin-bottom: 20px;
284
-
285
- h3 {
286
- font-size: 16px;
287
- font-weight: 600;
288
- color: var(--color-text-primary);
289
- }
290
-
291
- .section-badge {
292
- font-size: 12px;
293
- color: var(--color-text-placeholder);
294
- background: var(--color-fill);
295
- padding: 4px 10px;
296
- border-radius: 12px;
297
- }
298
-
299
- .section-link {
300
- font-size: 14px;
301
- color: var(--color-primary);
302
- text-decoration: none;
303
- transition: color 0.2s;
304
-
305
- &:hover {
306
- color: var(--color-primary-dark-1);
307
- }
308
- }
309
- }
310
-
311
- // 快捷入口
312
- .quick-section {
313
- background: var(--bg-color);
314
- border-radius: var(--border-radius-large);
315
- padding: 20px;
316
- box-shadow: var(--box-shadow-card);
317
- }
318
-
319
- .quick-grid {
320
- display: flex;
321
- flex-direction: column;
322
- gap: 12px;
323
- }
324
-
325
- .quick-card {
326
- display: flex;
327
- align-items: center;
328
- gap: 16px;
329
- padding: 16px;
330
- background: var(--color-fill-light);
331
- border-radius: var(--border-radius-base);
332
- text-decoration: none;
333
- transition: all 0.2s ease;
334
-
335
- &:hover {
336
- background: var(--color-primary-light-6);
337
- transform: translateX(4px);
338
-
339
- .quick-arrow {
340
- color: var(--color-primary);
341
- transform: translateX(4px);
342
- }
343
- }
344
-
345
- .quick-icon {
346
- width: 44px;
347
- height: 44px;
348
- display: flex;
349
- align-items: center;
350
- justify-content: center;
351
- background: var(--bg-color);
352
- border-radius: var(--border-radius-base);
353
- font-size: 22px;
354
- flex-shrink: 0;
355
- }
356
-
357
- .quick-info {
358
- flex: 1;
359
- min-width: 0;
360
- }
361
-
362
- .quick-title {
363
- font-size: 15px;
364
- font-weight: 500;
365
- color: var(--color-text-primary);
366
- margin-bottom: 4px;
367
- }
368
-
369
- .quick-desc {
370
- font-size: 13px;
371
- color: var(--color-text-secondary);
372
- }
373
-
374
- .quick-arrow {
375
- width: 24px;
376
- height: 24px;
377
- display: flex;
378
- align-items: center;
379
- justify-content: center;
380
- color: var(--color-text-placeholder);
381
- transition: all 0.2s ease;
382
-
383
- svg {
384
- width: 16px;
385
- height: 16px;
386
- }
387
- }
388
- }
389
-
390
- // 最近活动
391
- .activity-section {
392
- background: var(--bg-color);
393
- border-radius: var(--border-radius-large);
394
- padding: 20px;
395
- box-shadow: var(--box-shadow-card);
396
- }
397
-
398
- .activity-list {
399
- display: flex;
400
- flex-direction: column;
401
- }
402
-
403
- .activity-item {
404
- display: flex;
405
- align-items: flex-start;
406
- gap: 12px;
407
- padding: 14px 0;
408
- border-bottom: 1px solid var(--color-border-lighter);
409
- position: relative;
410
-
411
- &:last-child {
412
- border-bottom: none;
413
- }
414
- }
415
-
416
- .activity-avatar {
417
- width: 36px;
418
- height: 36px;
419
- display: flex;
420
- align-items: center;
421
- justify-content: center;
422
- border-radius: 50%;
423
- font-size: 14px;
424
- font-weight: 500;
425
- flex-shrink: 0;
426
-
427
- &.success { background: var(--color-success-lighter); color: var(--color-success); }
428
- &.warning { background: var(--color-warning-lighter); color: var(--color-warning); }
429
- &.info { background: var(--color-info-lighter); color: var(--color-info); }
430
- &.danger { background: var(--color-danger-lighter); color: var(--color-danger); }
431
- &.primary { background: var(--color-primary-light-6); color: var(--color-primary); }
432
- }
433
-
434
- .activity-content {
435
- flex: 1;
436
- min-width: 0;
437
- }
438
-
439
- .activity-main {
440
- margin-bottom: 4px;
441
- }
442
-
443
- .activity-user {
444
- font-size: 14px;
445
- font-weight: 500;
446
- color: var(--color-text-primary);
447
- margin-right: 8px;
448
- }
449
-
450
- .activity-action {
451
- font-size: 14px;
452
- color: var(--color-text-secondary);
453
- }
454
-
455
- .activity-time {
456
- font-size: 12px;
457
- color: var(--color-text-placeholder);
458
- }
459
-
460
- .activity-dot {
461
- position: absolute;
462
- left: -20px;
463
- top: 50%;
464
- transform: translateY(-50%);
465
- width: 8px;
466
- height: 8px;
467
- border-radius: 50%;
468
- opacity: 0.6;
469
-
470
- &.success { background: var(--color-success); }
471
- &.warning { background: var(--color-warning); }
472
- &.info { background: var(--color-info); }
473
- &.danger { background: var(--color-danger); }
474
- &.primary { background: var(--color-primary); }
475
- }
476
-
477
- // 系统信息
478
- .system-section {
479
- background: var(--bg-color);
480
- border-radius: var(--border-radius-large);
481
- padding: 20px;
482
- box-shadow: var(--box-shadow-card);
483
- }
484
-
485
- .system-grid {
486
- display: grid;
487
- grid-template-columns: 1fr 1.5fr;
488
- gap: 24px;
489
-
490
- @media (max-width: 768px) {
491
- grid-template-columns: 1fr;
492
- }
493
- }
494
-
495
- .system-info-list {
496
- display: flex;
497
- flex-direction: column;
498
- gap: 12px;
499
- }
500
-
501
- .info-item {
502
- display: flex;
503
- justify-content: space-between;
504
- align-items: center;
505
- padding: 12px 16px;
506
- background: var(--color-fill-light);
507
- border-radius: var(--border-radius-base);
508
-
509
- .info-label {
510
- font-size: 14px;
511
- color: var(--color-text-secondary);
512
- }
513
-
514
- .info-value {
515
- font-size: 14px;
516
- font-weight: 500;
517
- color: var(--color-text-primary);
518
- }
519
- }
520
-
521
- .system-status {
522
- display: flex;
523
- flex-direction: column;
524
- gap: 16px;
525
- }
526
-
527
- .status-item {
528
- .status-header {
529
- display: flex;
530
- justify-content: space-between;
531
- align-items: center;
532
- margin-bottom: 8px;
533
- }
534
-
535
- .status-label {
536
- font-size: 14px;
537
- color: var(--color-text-secondary);
538
- }
539
-
540
- .status-value {
541
- font-size: 14px;
542
- font-weight: 500;
543
- color: var(--color-text-primary);
544
- }
545
- }
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { Progress } from '@xto/data'
4
+
5
+ const stats = ref([
6
+ { title: '用户总数', value: 1234, icon: '👥', color: '#1677ff', trend: '+12.5%', trendUp: true },
7
+ { title: '今日访问', value: 567, icon: '👀', color: '#52c41a', trend: '+8.2%', trendUp: true },
8
+ { title: '订单数量', value: 890, icon: '📦', color: '#faad14', trend: '-3.1%', trendUp: false },
9
+ { title: '销售金额', value: 123456, icon: '💰', color: '#ff4d4f', trend: '+15.8%', trendUp: true }
10
+ ])
11
+
12
+ const activities = ref([
13
+ { user: '张三', action: '登录系统', time: '2分钟前', type: 'success', avatar: '张' },
14
+ { user: '李四', action: '修改了用户信息', time: '5分钟前', type: 'warning', avatar: '李' },
15
+ { user: '王五', action: '创建了新订单', time: '10分钟前', type: 'info', avatar: '王' },
16
+ { user: '赵六', action: '删除了测试数据', time: '30分钟前', type: 'danger', avatar: '赵' },
17
+ { user: '钱七', action: '更新了系统配置', time: '1小时前', type: 'primary', avatar: '钱' }
18
+ ])
19
+
20
+ const quickLinks = ref([
21
+ { title: '用户管理', path: '/system/user', icon: '👤', desc: '管理系统用户' },
22
+ { title: '角色管理', path: '/system/role', icon: '👥', desc: '角色权限配置' },
23
+ { title: '菜单管理', path: '/system/menu', icon: '📋', desc: '菜单路由管理' },
24
+ { title: '系统设置', path: '/system', icon: '⚙️', desc: '系统参数配置' }
25
+ ])
26
+
27
+ const systemInfo = ref([
28
+ { label: '系统版本', value: 'v1.0.0' },
29
+ { label: 'Vue 版本', value: '3.4.21' },
30
+ { label: '构建工具', value: 'Vite 5' },
31
+ { label: 'UI 组件库', value: 'XTO UI' }
32
+ ])
33
+ </script>
34
+
35
+ <template>
36
+ <div class="dashboard">
37
+ <!-- 统计卡片 -->
38
+ <div class="stats-section">
39
+ <div v-for="stat in stats" :key="stat.title" class="stat-card">
40
+ <div class="stat-icon" :style="{ background: `linear-gradient(135deg, ${stat.color}20 0%, ${stat.color}10 100%)` }">
41
+ <span>{{ stat.icon }}</span>
42
+ </div>
43
+ <div class="stat-content">
44
+ <div class="stat-title">{{ stat.title }}</div>
45
+ <div class="stat-value" :style="{ color: stat.color }">
46
+ {{ stat.value.toLocaleString() }}
47
+ </div>
48
+ <div class="stat-trend" :class="{ up: stat.trendUp, down: !stat.trendUp }">
49
+ <svg v-if="stat.trendUp" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
50
+ <path d="M7 17l5-5 5 5M7 7l5 5 5-5"/>
51
+ </svg>
52
+ <svg v-else viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
53
+ <path d="M7 7l5 5 5-5M7 17l5-5 5 5"/>
54
+ </svg>
55
+ <span>{{ stat.trend }}</span>
56
+ </div>
57
+ </div>
58
+ <div class="stat-decoration" :style="{ background: `linear-gradient(135deg, ${stat.color}08 0%, transparent 100%)` }"></div>
59
+ </div>
60
+ </div>
61
+
62
+ <!-- 主体内容 -->
63
+ <div class="main-section">
64
+ <!-- 快捷入口 -->
65
+ <div class="quick-section">
66
+ <div class="section-header">
67
+ <h3>快捷入口</h3>
68
+ <span class="section-badge">4 个入口</span>
69
+ </div>
70
+ <div class="quick-grid">
71
+ <router-link
72
+ v-for="link in quickLinks"
73
+ :key="link.path"
74
+ :to="link.path"
75
+ class="quick-card"
76
+ >
77
+ <div class="quick-icon">{{ link.icon }}</div>
78
+ <div class="quick-info">
79
+ <div class="quick-title">{{ link.title }}</div>
80
+ <div class="quick-desc">{{ link.desc }}</div>
81
+ </div>
82
+ <div class="quick-arrow">
83
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
84
+ <path d="M9 18l6-6-6-6"/>
85
+ </svg>
86
+ </div>
87
+ </router-link>
88
+ </div>
89
+ </div>
90
+
91
+ <!-- 最近活动 -->
92
+ <div class="activity-section">
93
+ <div class="section-header">
94
+ <h3>最近活动</h3>
95
+ <a href="#" class="section-link">查看全部</a>
96
+ </div>
97
+ <div class="activity-list">
98
+ <div v-for="(activity, index) in activities" :key="index" class="activity-item">
99
+ <div class="activity-avatar" :class="activity.type">
100
+ {{ activity.avatar }}
101
+ </div>
102
+ <div class="activity-content">
103
+ <div class="activity-main">
104
+ <span class="activity-user">{{ activity.user }}</span>
105
+ <span class="activity-action">{{ activity.action }}</span>
106
+ </div>
107
+ <div class="activity-time">{{ activity.time }}</div>
108
+ </div>
109
+ <div class="activity-dot" :class="activity.type"></div>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- 系统信息 -->
116
+ <div class="system-section">
117
+ <div class="section-header">
118
+ <h3>系统信息</h3>
119
+ </div>
120
+ <div class="system-grid">
121
+ <div class="system-info-list">
122
+ <div v-for="info in systemInfo" :key="info.label" class="info-item">
123
+ <span class="info-label">{{ info.label }}</span>
124
+ <span class="info-value">{{ info.value }}</span>
125
+ </div>
126
+ </div>
127
+ <div class="system-status">
128
+ <div class="status-item">
129
+ <div class="status-header">
130
+ <span class="status-label">服务器状态</span>
131
+ <span class="status-value">75%</span>
132
+ </div>
133
+ <Progress :percentage="75" status="success" />
134
+ </div>
135
+ <div class="status-item">
136
+ <div class="status-header">
137
+ <span class="status-label">内存使用</span>
138
+ <span class="status-value">45%</span>
139
+ </div>
140
+ <Progress :percentage="45" />
141
+ </div>
142
+ <div class="status-item">
143
+ <div class="status-header">
144
+ <span class="status-label">CPU 使用率</span>
145
+ <span class="status-value">32%</span>
146
+ </div>
147
+ <Progress :percentage="32" />
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </template>
154
+
155
+ <style lang="scss" scoped>
156
+ .dashboard {
157
+ padding: 24px;
158
+ background: var(--bg-color-page);
159
+ min-height: 100%;
160
+ }
161
+
162
+ // 统计卡片
163
+ .stats-section {
164
+ display: grid;
165
+ grid-template-columns: repeat(4, 1fr);
166
+ gap: 20px;
167
+ margin-bottom: 24px;
168
+
169
+ @media (max-width: 1200px) {
170
+ grid-template-columns: repeat(2, 1fr);
171
+ }
172
+
173
+ @media (max-width: 768px) {
174
+ grid-template-columns: 1fr;
175
+ }
176
+ }
177
+
178
+ .stat-card {
179
+ position: relative;
180
+ display: flex;
181
+ align-items: flex-start;
182
+ gap: 16px;
183
+ padding: 20px;
184
+ background: var(--bg-color);
185
+ border-radius: var(--border-radius-large);
186
+ box-shadow: var(--box-shadow-card);
187
+ transition: all 0.3s ease;
188
+ overflow: hidden;
189
+
190
+ &:hover {
191
+ box-shadow: var(--box-shadow-card-hover);
192
+ transform: translateY(-4px);
193
+
194
+ .stat-decoration {
195
+ opacity: 1;
196
+ }
197
+ }
198
+
199
+ .stat-icon {
200
+ width: 52px;
201
+ height: 52px;
202
+ display: flex;
203
+ align-items: center;
204
+ justify-content: center;
205
+ border-radius: var(--border-radius-large);
206
+ flex-shrink: 0;
207
+
208
+ span {
209
+ font-size: 26px;
210
+ }
211
+ }
212
+
213
+ .stat-content {
214
+ flex: 1;
215
+ min-width: 0;
216
+ }
217
+
218
+ .stat-title {
219
+ font-size: 14px;
220
+ color: var(--color-text-secondary);
221
+ margin-bottom: 8px;
222
+ }
223
+
224
+ .stat-value {
225
+ font-size: 28px;
226
+ font-weight: 600;
227
+ line-height: 1.2;
228
+ margin-bottom: 8px;
229
+ }
230
+
231
+ .stat-trend {
232
+ display: inline-flex;
233
+ align-items: center;
234
+ gap: 4px;
235
+ font-size: 12px;
236
+ padding: 2px 8px;
237
+ border-radius: 12px;
238
+
239
+ svg {
240
+ width: 14px;
241
+ height: 14px;
242
+ }
243
+
244
+ &.up {
245
+ color: var(--color-success);
246
+ background: var(--color-success-lighter);
247
+ }
248
+
249
+ &.down {
250
+ color: var(--color-danger);
251
+ background: var(--color-danger-lighter);
252
+ }
253
+ }
254
+
255
+ .stat-decoration {
256
+ position: absolute;
257
+ top: 0;
258
+ right: 0;
259
+ width: 100px;
260
+ height: 100px;
261
+ border-radius: 50%;
262
+ opacity: 0;
263
+ transition: opacity 0.3s ease;
264
+ }
265
+ }
266
+
267
+ // 主体内容
268
+ .main-section {
269
+ display: grid;
270
+ grid-template-columns: repeat(2, 1fr);
271
+ gap: 24px;
272
+ margin-bottom: 24px;
273
+
274
+ @media (max-width: 992px) {
275
+ grid-template-columns: 1fr;
276
+ }
277
+ }
278
+
279
+ .section-header {
280
+ display: flex;
281
+ justify-content: space-between;
282
+ align-items: center;
283
+ margin-bottom: 20px;
284
+
285
+ h3 {
286
+ font-size: 16px;
287
+ font-weight: 600;
288
+ color: var(--color-text-primary);
289
+ }
290
+
291
+ .section-badge {
292
+ font-size: 12px;
293
+ color: var(--color-text-placeholder);
294
+ background: var(--color-fill);
295
+ padding: 4px 10px;
296
+ border-radius: 12px;
297
+ }
298
+
299
+ .section-link {
300
+ font-size: 14px;
301
+ color: var(--color-primary);
302
+ text-decoration: none;
303
+ transition: color 0.2s;
304
+
305
+ &:hover {
306
+ color: var(--color-primary-dark-1);
307
+ }
308
+ }
309
+ }
310
+
311
+ // 快捷入口
312
+ .quick-section {
313
+ background: var(--bg-color);
314
+ border-radius: var(--border-radius-large);
315
+ padding: 20px;
316
+ box-shadow: var(--box-shadow-card);
317
+ }
318
+
319
+ .quick-grid {
320
+ display: flex;
321
+ flex-direction: column;
322
+ gap: 12px;
323
+ }
324
+
325
+ .quick-card {
326
+ display: flex;
327
+ align-items: center;
328
+ gap: 16px;
329
+ padding: 16px;
330
+ background: var(--color-fill-light);
331
+ border-radius: var(--border-radius-base);
332
+ text-decoration: none;
333
+ transition: all 0.2s ease;
334
+
335
+ &:hover {
336
+ background: var(--color-primary-light-6);
337
+ transform: translateX(4px);
338
+
339
+ .quick-arrow {
340
+ color: var(--color-primary);
341
+ transform: translateX(4px);
342
+ }
343
+ }
344
+
345
+ .quick-icon {
346
+ width: 44px;
347
+ height: 44px;
348
+ display: flex;
349
+ align-items: center;
350
+ justify-content: center;
351
+ background: var(--bg-color);
352
+ border-radius: var(--border-radius-base);
353
+ font-size: 22px;
354
+ flex-shrink: 0;
355
+ }
356
+
357
+ .quick-info {
358
+ flex: 1;
359
+ min-width: 0;
360
+ }
361
+
362
+ .quick-title {
363
+ font-size: 15px;
364
+ font-weight: 500;
365
+ color: var(--color-text-primary);
366
+ margin-bottom: 4px;
367
+ }
368
+
369
+ .quick-desc {
370
+ font-size: 13px;
371
+ color: var(--color-text-secondary);
372
+ }
373
+
374
+ .quick-arrow {
375
+ width: 24px;
376
+ height: 24px;
377
+ display: flex;
378
+ align-items: center;
379
+ justify-content: center;
380
+ color: var(--color-text-placeholder);
381
+ transition: all 0.2s ease;
382
+
383
+ svg {
384
+ width: 16px;
385
+ height: 16px;
386
+ }
387
+ }
388
+ }
389
+
390
+ // 最近活动
391
+ .activity-section {
392
+ background: var(--bg-color);
393
+ border-radius: var(--border-radius-large);
394
+ padding: 20px;
395
+ box-shadow: var(--box-shadow-card);
396
+ }
397
+
398
+ .activity-list {
399
+ display: flex;
400
+ flex-direction: column;
401
+ }
402
+
403
+ .activity-item {
404
+ display: flex;
405
+ align-items: flex-start;
406
+ gap: 12px;
407
+ padding: 14px 0;
408
+ border-bottom: 1px solid var(--color-border-lighter);
409
+ position: relative;
410
+
411
+ &:last-child {
412
+ border-bottom: none;
413
+ }
414
+ }
415
+
416
+ .activity-avatar {
417
+ width: 36px;
418
+ height: 36px;
419
+ display: flex;
420
+ align-items: center;
421
+ justify-content: center;
422
+ border-radius: 50%;
423
+ font-size: 14px;
424
+ font-weight: 500;
425
+ flex-shrink: 0;
426
+
427
+ &.success { background: var(--color-success-lighter); color: var(--color-success); }
428
+ &.warning { background: var(--color-warning-lighter); color: var(--color-warning); }
429
+ &.info { background: var(--color-info-lighter); color: var(--color-info); }
430
+ &.danger { background: var(--color-danger-lighter); color: var(--color-danger); }
431
+ &.primary { background: var(--color-primary-light-6); color: var(--color-primary); }
432
+ }
433
+
434
+ .activity-content {
435
+ flex: 1;
436
+ min-width: 0;
437
+ }
438
+
439
+ .activity-main {
440
+ margin-bottom: 4px;
441
+ }
442
+
443
+ .activity-user {
444
+ font-size: 14px;
445
+ font-weight: 500;
446
+ color: var(--color-text-primary);
447
+ margin-right: 8px;
448
+ }
449
+
450
+ .activity-action {
451
+ font-size: 14px;
452
+ color: var(--color-text-secondary);
453
+ }
454
+
455
+ .activity-time {
456
+ font-size: 12px;
457
+ color: var(--color-text-placeholder);
458
+ }
459
+
460
+ .activity-dot {
461
+ position: absolute;
462
+ left: -20px;
463
+ top: 50%;
464
+ transform: translateY(-50%);
465
+ width: 8px;
466
+ height: 8px;
467
+ border-radius: 50%;
468
+ opacity: 0.6;
469
+
470
+ &.success { background: var(--color-success); }
471
+ &.warning { background: var(--color-warning); }
472
+ &.info { background: var(--color-info); }
473
+ &.danger { background: var(--color-danger); }
474
+ &.primary { background: var(--color-primary); }
475
+ }
476
+
477
+ // 系统信息
478
+ .system-section {
479
+ background: var(--bg-color);
480
+ border-radius: var(--border-radius-large);
481
+ padding: 20px;
482
+ box-shadow: var(--box-shadow-card);
483
+ }
484
+
485
+ .system-grid {
486
+ display: grid;
487
+ grid-template-columns: 1fr 1.5fr;
488
+ gap: 24px;
489
+
490
+ @media (max-width: 768px) {
491
+ grid-template-columns: 1fr;
492
+ }
493
+ }
494
+
495
+ .system-info-list {
496
+ display: flex;
497
+ flex-direction: column;
498
+ gap: 12px;
499
+ }
500
+
501
+ .info-item {
502
+ display: flex;
503
+ justify-content: space-between;
504
+ align-items: center;
505
+ padding: 12px 16px;
506
+ background: var(--color-fill-light);
507
+ border-radius: var(--border-radius-base);
508
+
509
+ .info-label {
510
+ font-size: 14px;
511
+ color: var(--color-text-secondary);
512
+ }
513
+
514
+ .info-value {
515
+ font-size: 14px;
516
+ font-weight: 500;
517
+ color: var(--color-text-primary);
518
+ }
519
+ }
520
+
521
+ .system-status {
522
+ display: flex;
523
+ flex-direction: column;
524
+ gap: 16px;
525
+ }
526
+
527
+ .status-item {
528
+ .status-header {
529
+ display: flex;
530
+ justify-content: space-between;
531
+ align-items: center;
532
+ margin-bottom: 8px;
533
+ }
534
+
535
+ .status-label {
536
+ font-size: 14px;
537
+ color: var(--color-text-secondary);
538
+ }
539
+
540
+ .status-value {
541
+ font-size: 14px;
542
+ font-weight: 500;
543
+ color: var(--color-text-primary);
544
+ }
545
+ }
546
546
  </style>