zant-admin 1.0.4 → 2.0.1

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 (94) hide show
  1. package/README.en.md +414 -25
  2. package/README.md +460 -285
  3. package/bin/cli.js +3 -3
  4. package/bin/generator.js +502 -502
  5. package/bin/prompts.js +158 -158
  6. package/bin/utils.js +133 -133
  7. package/package.json +2 -2
  8. package/public/logo.png +0 -0
  9. package/src/App.vue +16 -16
  10. package/src/api/methods/department.js +36 -0
  11. package/src/api/methods/employee.js +22 -0
  12. package/src/api/methods/logError.js +8 -8
  13. package/src/api/methods/logOperation.js +8 -8
  14. package/src/api/methods/login.js +6 -6
  15. package/src/api/methods/position.js +26 -0
  16. package/src/api/methods/quartz.js +36 -36
  17. package/src/api/methods/region.js +16 -16
  18. package/src/api/methods/sysAccount.js +29 -29
  19. package/src/api/methods/sysDict.js +29 -29
  20. package/src/api/methods/sysDictItem.js +26 -26
  21. package/src/api/methods/sysMenu.js +42 -42
  22. package/src/api/methods/sysRole.js +35 -35
  23. package/src/api/methods/sysUser.js +25 -25
  24. package/src/api/methods/system.js +15 -15
  25. package/src/api/request.js +225 -225
  26. package/src/assets/css/style.css +2 -2
  27. package/src/assets/css/zcui.css +1023 -1023
  28. package/src/assets/imgs/logo.png +0 -0
  29. package/src/assets/imgs/md/console.png +0 -0
  30. package/src/assets/imgs/md/login.png +0 -0
  31. package/src/assets/imgs/md/menu.png +0 -0
  32. package/src/assets/imgs/md/serviceMonitoring.png +0 -0
  33. package/src/assets/imgs/md/statistics.png +0 -0
  34. package/src/components/FormTable.vue +5 -19
  35. package/src/components/IconPicker.vue +351 -351
  36. package/src/components/MainPage.vue +838 -838
  37. package/src/components/details/logErrorDetails.vue +58 -58
  38. package/src/components/details/logOperationDetails.vue +76 -76
  39. package/src/components/edit/QuartzEdit.vue +221 -221
  40. package/src/components/edit/SysAccountEdit.vue +185 -185
  41. package/src/components/edit/SysDictEdit.vue +116 -116
  42. package/src/components/edit/SysDictItemEdit.vue +136 -136
  43. package/src/components/edit/SysRoleEdit.vue +111 -111
  44. package/src/components/edit/organizationalStructure/DepartmentEdit.vue +162 -0
  45. package/src/components/edit/organizationalStructure/EmployeeEdit.vue +295 -0
  46. package/src/components/edit/organizationalStructure/PositionEdit.vue +166 -0
  47. package/src/components/edit/sysMenuEdit.vue +2 -1
  48. package/src/config/index.js +74 -74
  49. package/src/directives/permission.js +49 -49
  50. package/src/main.js +37 -37
  51. package/src/router/index.js +4 -6
  52. package/src/stores/config.js +43 -43
  53. package/src/stores/dict.js +33 -33
  54. package/src/stores/menu.js +81 -81
  55. package/src/stores/user.js +21 -21
  56. package/src/utils/baseEcharts.js +661 -661
  57. package/src/utils/dictTemplate.js +26 -26
  58. package/src/utils/regionUtils.js +173 -173
  59. package/src/utils/useFormCRUD.js +59 -59
  60. package/src/views/baiscstatis/center.vue +474 -474
  61. package/src/views/baiscstatis/iframePage.vue +29 -29
  62. package/src/views/baiscstatis/notFound.vue +192 -192
  63. package/src/views/console.vue +821 -821
  64. package/src/views/demo/button.vue +269 -269
  65. package/src/views/demo/importexport.vue +119 -119
  66. package/src/views/demo/region.vue +322 -322
  67. package/src/views/demo/statistics.vue +214 -214
  68. package/src/views/home.vue +6 -6
  69. package/src/views/login.vue +264 -149
  70. package/src/views/operations/log/logError.vue +78 -78
  71. package/src/views/operations/log/logLogin.vue +66 -66
  72. package/src/views/operations/log/logOperation.vue +103 -103
  73. package/src/views/operations/log/logQuartz.vue +56 -56
  74. package/src/views/operations/quartz.vue +179 -179
  75. package/src/views/operations/serviceMonitoring.vue +134 -134
  76. package/src/views/organizationalStructure/department.vue +194 -0
  77. package/src/views/organizationalStructure/employee.vue +234 -0
  78. package/src/views/organizationalStructure/position.vue +196 -0
  79. package/src/views/system/sysAccount.vue +128 -128
  80. package/src/views/system/sysDict.vue +159 -159
  81. package/src/views/system/sysDictItem.vue +118 -118
  82. package/src/views/system/sysMenu.vue +225 -225
  83. package/src/views/system/sysRole.vue +207 -207
  84. package/src/assets/imgs/md/1.png +0 -0
  85. package/src/assets/imgs/md/10.png +0 -0
  86. package/src/assets/imgs/md/11.png +0 -0
  87. package/src/assets/imgs/md/2.png +0 -0
  88. package/src/assets/imgs/md/3.png +0 -0
  89. package/src/assets/imgs/md/4.png +0 -0
  90. package/src/assets/imgs/md/5.png +0 -0
  91. package/src/assets/imgs/md/6.png +0 -0
  92. package/src/assets/imgs/md/7.png +0 -0
  93. package/src/assets/imgs/md/8.png +0 -0
  94. package/src/assets/imgs/md/9.png +0 -0
@@ -1,821 +1,821 @@
1
- <template>
2
- <div class="console-page">
3
- <!-- 页面标题区域 -->
4
- <div class="page-header">
5
- <div class="header-content">
6
- <div class="header-title">
7
- <h1>系统控制台</h1>
8
- <p>欢迎使用系统控制台,这里可以查看系统概览和重要信息</p>
9
- </div>
10
- <div class="header-time">
11
- <div class="time-display">{{ currentTime }}</div>
12
- <div class="date-display">{{ currentDate }}</div>
13
- </div>
14
- </div>
15
- </div>
16
-
17
- <!-- 统计卡片区域 -->
18
- <div class="stats-container">
19
- <div class="stat-card" v-for="(stat, index) in statsData" :key="index">
20
- <div class="stat-icon" :style="{ background: stat.gradient }">
21
- <component :is="stat.icon" />
22
- </div>
23
- <div class="stat-content">
24
- <div class="stat-value">{{ stat.value }}</div>
25
- <div class="stat-label">{{ stat.label }}</div>
26
- <div class="stat-trend" :class="stat.trend">
27
- <component :is="stat.trendIcon" />
28
- {{ stat.change }}
29
- </div>
30
- </div>
31
- </div>
32
- </div>
33
-
34
- <!-- 主要内容区域 -->
35
- <div class="main-content">
36
- <!-- 左侧内容 -->
37
- <div class="left-content">
38
- <!-- 访问量统计图表 -->
39
- <div class="chart-container">
40
- <div class="card-header">
41
- <h3>访问量统计</h3>
42
- <div class="chart-controls">
43
- <a-radio-group v-model:value="chartPeriod" size="small">
44
- <a-radio-button value="week">本周</a-radio-button>
45
- <a-radio-button value="month">本月</a-radio-button>
46
- <a-radio-button value="year">本年</a-radio-button>
47
- </a-radio-group>
48
- </div>
49
- </div>
50
- <div class="chart-wrapper" ref="visitChartRef"></div>
51
- </div>
52
-
53
- <!-- 系统信息 -->
54
- <div class="system-info-container">
55
- <div class="card-header">
56
- <h3>系统信息</h3>
57
- </div>
58
- <div class="info-grid">
59
- <div
60
- class="info-item"
61
- v-for="(info, index) in systemInfo"
62
- :key="index"
63
- >
64
- <div class="info-label">{{ info.label }}</div>
65
- <div class="info-value">{{ info.value }}</div>
66
- <div class="info-progress" v-if="info.progress">
67
- <div
68
- class="progress-bar"
69
- :style="{ width: info.progress + '%' }"
70
- ></div>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- </div>
76
-
77
- <!-- 右侧内容 -->
78
- <div class="right-content">
79
- <!-- 前端项目引用 -->
80
- <div class="dependencies-container">
81
- <div class="card-header">
82
- <h3>前端项目引用</h3>
83
- </div>
84
- <div class="dependencies-list">
85
- <div
86
- class="dependency-item"
87
- v-for="(dep, index) in dependencies"
88
- :key="index"
89
- >
90
- <div class="dep-name">{{ dep.name }}</div>
91
- <div class="dep-version">{{ dep.version }}</div>
92
- </div>
93
- </div>
94
- </div>
95
-
96
- <!-- 最新通知 -->
97
- <div class="notifications-container">
98
- <div class="card-header">
99
- <h3>最新通知</h3>
100
- <a-badge :count="notifications.length" />
101
- </div>
102
- <div class="notifications-list">
103
- <div
104
- class="notification-item"
105
- v-for="(item, index) in notifications"
106
- :key="index"
107
- >
108
- <div
109
- class="notification-icon"
110
- :style="{ backgroundColor: item.color }"
111
- >
112
- {{ item.icon }}
113
- </div>
114
- <div class="notification-content">
115
- <div class="notification-title">{{ item.title }}</div>
116
- <div class="notification-desc">{{ item.description }}</div>
117
- </div>
118
- </div>
119
- </div>
120
- </div>
121
-
122
- <!-- 最近活动 -->
123
- <div class="activities-container">
124
- <div class="card-header">
125
- <h3>最近活动</h3>
126
- </div>
127
- <div class="activities-list">
128
- <div
129
- class="activity-item"
130
- v-for="(activity, index) in recentActivities"
131
- :key="index"
132
- >
133
- <ClockCircleOutlined class="activity-icon" />
134
- <div class="activity-content">{{ activity.content }}</div>
135
- </div>
136
- </div>
137
- </div>
138
- </div>
139
- </div>
140
- </div>
141
- </template>
142
-
143
- <script setup>
144
- import { ref, reactive, onMounted, onUnmounted, computed, watch } from 'vue'
145
- import * as baseEcharts from '@/utils/baseEcharts'
146
- import {
147
- UserOutlined,
148
- ShoppingCartOutlined,
149
- DollarOutlined,
150
- MessageOutlined,
151
- ClockCircleOutlined,
152
- ArrowUpOutlined,
153
- ArrowDownOutlined,
154
- } from '@ant-design/icons-vue'
155
-
156
- // 创建图表容器引用
157
- const visitChartRef = ref(null)
158
- // 图表实例
159
- let visitChart = null
160
-
161
- // 图表周期选择
162
- const chartPeriod = ref('month')
163
-
164
- // 当前时间
165
- const currentTime = ref('')
166
- const currentDate = ref('')
167
-
168
- // 统计数据
169
- const stats = reactive({
170
- userCount: 1256,
171
- orderCount: 89,
172
- revenue: '12,580',
173
- messageCount: 5,
174
- })
175
-
176
- // 统计卡片数据
177
- const statsData = computed(() => [
178
- {
179
- label: '用户总数',
180
- value: stats.userCount,
181
- icon: UserOutlined,
182
- gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
183
- trend: 'up',
184
- trendIcon: ArrowUpOutlined,
185
- change: '12.5%',
186
- },
187
- {
188
- label: '今日订单',
189
- value: stats.orderCount,
190
- icon: ShoppingCartOutlined,
191
- gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
192
- trend: 'up',
193
- trendIcon: ArrowUpOutlined,
194
- change: '8.2%',
195
- },
196
- {
197
- label: '今日收入',
198
- value: `¥${stats.revenue}`,
199
- icon: DollarOutlined,
200
- gradient: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
201
- trend: 'down',
202
- trendIcon: ArrowDownOutlined,
203
- change: '3.1%',
204
- },
205
- {
206
- label: '未读消息',
207
- value: stats.messageCount,
208
- icon: MessageOutlined,
209
- gradient: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',
210
- trend: 'up',
211
- trendIcon: ArrowUpOutlined,
212
- change: '2条',
213
- },
214
- ])
215
-
216
- // 系统信息
217
- const systemInfo = ref([
218
- { label: '系统版本', value: 'v1.0.0' },
219
- { label: '运行时间', value: '15天2小时' },
220
- { label: '内存使用率', value: '65%', progress: 65 },
221
- { label: 'CPU使用率', value: '23%', progress: 23 },
222
- { label: '磁盘空间', value: '85GB/120GB', progress: 70 },
223
- ])
224
-
225
- // 前端项目引用
226
- const dependencies = ref([
227
- { name: 'Vue', version: 'v3.5.13' },
228
- { name: 'Vue Router', version: 'v4.4.5' },
229
- { name: 'Pinia', version: 'v2.2.6' },
230
- { name: 'Ant Design Vue', version: 'v4.2.6' },
231
- { name: 'Ant Design Icons Vue', version: 'v7.0.1' },
232
- { name: 'ECharts', version: 'v6.0.0' },
233
- { name: 'Day.js', version: 'v1.11.13' },
234
- { name: 'Alova', version: 'v3.2.6' },
235
- { name: 'File-saver', version: 'v2.0.5' },
236
- { name: 'Vite', version: 'v7.0.6' },
237
- ])
238
-
239
- // 通知列表
240
- const notifications = ref([
241
- {
242
- title: '系统维护通知',
243
- description: '系统将于今晚23:00进行维护,预计耗时2小时',
244
- color: '#1890ff',
245
- icon: '维',
246
- },
247
- {
248
- title: '新版本发布',
249
- description: 'v1.2.0版本已发布,新增多项功能',
250
- color: '#52c41a',
251
- icon: '新',
252
- },
253
- {
254
- title: '安全提醒',
255
- description: '请及时修改默认密码,确保账户安全',
256
- color: '#faad14',
257
- icon: '安',
258
- },
259
- ])
260
-
261
- // 最近活动
262
- const recentActivities = ref([
263
- { id: 1, content: '用户张三登录系统' },
264
- { id: 2, content: '订单#20231215001创建成功' },
265
- { id: 3, content: '报表数据已更新' },
266
- { id: 4, content: '系统备份完成' },
267
- ])
268
-
269
- // 更新时间函数
270
- const updateDateTime = () => {
271
- const now = new Date()
272
-
273
- // 更新时间
274
- currentTime.value = now.toLocaleTimeString('zh-CN', {
275
- hour: '2-digit',
276
- minute: '2-digit',
277
- second: '2-digit',
278
- })
279
-
280
- // 更新日期
281
- currentDate.value = now.toLocaleDateString('zh-CN', {
282
- year: 'numeric',
283
- month: 'long',
284
- day: 'numeric',
285
- weekday: 'long',
286
- })
287
- }
288
-
289
- // 初始化图表
290
- const initChart = () => {
291
- // 使用 baseEcharts 工具初始化折线图
292
- visitChart = baseEcharts.initLineChart(visitChartRef.value, '访问量')
293
-
294
- // 根据选择的周期获取不同的数据
295
- const getChartData = () => {
296
- switch (chartPeriod.value) {
297
- case 'week':
298
- return {
299
- xAxis: {
300
- data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
301
- },
302
- series: [
303
- {
304
- name: '访问量',
305
- data: [320, 450, 380, 420, 580, 620, 590],
306
- },
307
- {
308
- name: '独立访客',
309
- data: [220, 320, 280, 350, 480, 520, 490],
310
- },
311
- ],
312
- }
313
- case 'month':
314
- return {
315
- xAxis: {
316
- data: Array.from({ length: 30 }, (_, i) => `${i + 1}日`),
317
- },
318
- series: [
319
- {
320
- name: '访问量',
321
- data: Array.from(
322
- { length: 30 },
323
- () => Math.floor(Math.random() * 1000) + 500,
324
- ),
325
- },
326
- {
327
- name: '独立访客',
328
- data: Array.from(
329
- { length: 30 },
330
- () => Math.floor(Math.random() * 800) + 300,
331
- ),
332
- },
333
- ],
334
- }
335
- case 'year':
336
- return {
337
- xAxis: {
338
- data: [
339
- '1月',
340
- '2月',
341
- '3月',
342
- '4月',
343
- '5月',
344
- '6月',
345
- '7月',
346
- '8月',
347
- '9月',
348
- '10月',
349
- '11月',
350
- '12月',
351
- ],
352
- },
353
- series: [
354
- {
355
- name: '访问量',
356
- data: [
357
- 820, 932, 901, 934, 1290, 1330, 1320, 1540, 1200, 1100, 1380,
358
- 1420,
359
- ],
360
- },
361
- {
362
- name: '独立访客',
363
- data: [
364
- 620, 732, 701, 734, 1090, 1130, 1120, 1340, 1000, 900, 1180,
365
- 1220,
366
- ],
367
- },
368
- ],
369
- }
370
- default:
371
- return {
372
- xAxis: { data: [] },
373
- series: [],
374
- }
375
- }
376
- }
377
-
378
- // 获取数据并更新图表
379
- const chartData = getChartData()
380
- baseEcharts.updateLineChart({
381
- chartInstance: visitChart,
382
- data: chartData,
383
- shouldShowSlider: chartData.xAxis.data.length > 12,
384
- })
385
- }
386
-
387
- // 监听图表周期变化
388
- const handlePeriodChange = () => {
389
- initChart()
390
- }
391
-
392
- onMounted(() => {
393
- updateDateTime()
394
- // 每秒更新一次时间
395
- const timer = setInterval(updateDateTime, 1000)
396
- initChart()
397
-
398
- // 模拟数据更新
399
- setTimeout(() => {
400
- stats.orderCount = 92
401
- stats.revenue = '13,200'
402
- }, 3000)
403
-
404
- // 每30秒更新一次图表数据
405
- const chartTimer = setInterval(() => {
406
- initChart()
407
- }, 30000)
408
-
409
- // 监听图表周期变化
410
- const stopWatch = watch(chartPeriod, handlePeriodChange)
411
-
412
- onUnmounted(() => {
413
- clearInterval(timer)
414
- clearInterval(chartTimer)
415
- if (stopWatch) stopWatch()
416
- // 销毁图表实例,释放资源
417
- if (visitChart) {
418
- visitChart.dispose()
419
- visitChart = null
420
- }
421
- })
422
- })
423
- </script>
424
-
425
- <style scoped>
426
- .console-page {
427
- background: #f5f7fa;
428
- min-height: 100vh;
429
- font-family:
430
- -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
431
- Arial, sans-serif;
432
- }
433
-
434
- /* 页面标题区域 */
435
- .page-header {
436
- margin-bottom: 24px;
437
- background: #fff;
438
- border-radius: 12px;
439
- padding: 24px;
440
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
441
- }
442
-
443
- .header-content {
444
- display: flex;
445
- justify-content: space-between;
446
- align-items: center;
447
- }
448
-
449
- .header-title h1 {
450
- margin: 0;
451
- font-size: 28px;
452
- font-weight: 600;
453
- color: #1f2937;
454
- }
455
-
456
- .header-title p {
457
- margin: 8px 0 0 0;
458
- color: #6b7280;
459
- font-size: 14px;
460
- }
461
-
462
- .header-time {
463
- text-align: right;
464
- }
465
-
466
- .time-display {
467
- font-size: 24px;
468
- font-weight: 600;
469
- color: #1f2937;
470
- }
471
-
472
- .date-display {
473
- font-size: 14px;
474
- color: #6b7280;
475
- margin-top: 4px;
476
- }
477
-
478
- /* 统计卡片区域 */
479
- .stats-container {
480
- display: grid;
481
- grid-template-columns: repeat(4, 1fr);
482
- gap: 20px;
483
- margin-bottom: 24px;
484
- }
485
-
486
- .stat-card {
487
- background: #fff;
488
- border-radius: 12px;
489
- padding: 24px;
490
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
491
- display: flex;
492
- align-items: center;
493
- transition:
494
- transform 0.3s ease,
495
- box-shadow 0.3s ease;
496
- }
497
-
498
- .stat-card:hover {
499
- transform: translateY(-5px);
500
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
501
- }
502
-
503
- .stat-icon {
504
- width: 60px;
505
- height: 60px;
506
- border-radius: 12px;
507
- display: flex;
508
- align-items: center;
509
- justify-content: center;
510
- font-size: 24px;
511
- color: white;
512
- margin-right: 16px;
513
- }
514
-
515
- .stat-content {
516
- flex: 1;
517
- }
518
-
519
- .stat-value {
520
- font-size: 28px;
521
- font-weight: 600;
522
- color: #1f2937;
523
- line-height: 1;
524
- }
525
-
526
- .stat-label {
527
- margin-top: 4px;
528
- color: #6b7280;
529
- font-size: 14px;
530
- }
531
-
532
- .stat-trend {
533
- display: flex;
534
- align-items: center;
535
- margin-top: 8px;
536
- font-size: 12px;
537
- font-weight: 500;
538
- }
539
-
540
- .stat-trend.up {
541
- color: #10b981;
542
- }
543
-
544
- .stat-trend.down {
545
- color: #ef4444;
546
- }
547
-
548
- .stat-trend svg {
549
- margin-right: 4px;
550
- }
551
-
552
- /* 主要内容区域 */
553
- .main-content {
554
- display: grid;
555
- grid-template-columns: 2fr 1fr;
556
- gap: 24px;
557
- }
558
-
559
- /* 卡片标题样式 */
560
- .card-header {
561
- display: flex;
562
- justify-content: space-between;
563
- align-items: center;
564
- margin-bottom: 16px;
565
- }
566
-
567
- .card-header h3 {
568
- margin: 0;
569
- font-size: 18px;
570
- font-weight: 600;
571
- color: #1f2937;
572
- }
573
-
574
- /* 左侧内容 */
575
- .left-content {
576
- display: flex;
577
- flex-direction: column;
578
- gap: 24px;
579
- }
580
-
581
- /* 图表容器 */
582
- .chart-container {
583
- background: #fff;
584
- border-radius: 12px;
585
- padding: 24px;
586
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
587
- }
588
-
589
- .chart-wrapper {
590
- height: 300px;
591
- width: 100%;
592
- }
593
-
594
- /* 系统信息容器 */
595
- .system-info-container {
596
- background: #fff;
597
- border-radius: 12px;
598
- padding: 24px;
599
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
600
- }
601
-
602
- .info-grid {
603
- display: grid;
604
- grid-template-columns: repeat(2, 1fr);
605
- gap: 16px;
606
- }
607
-
608
- .info-item {
609
- padding: 12px;
610
- border-radius: 8px;
611
- background: #f9fafb;
612
- }
613
-
614
- .info-label {
615
- font-size: 12px;
616
- color: #6b7280;
617
- margin-bottom: 4px;
618
- }
619
-
620
- .info-value {
621
- font-size: 16px;
622
- font-weight: 600;
623
- color: #1f2937;
624
- margin-bottom: 8px;
625
- }
626
-
627
- .info-progress {
628
- height: 4px;
629
- background: #e5e7eb;
630
- border-radius: 2px;
631
- overflow: hidden;
632
- }
633
-
634
- .progress-bar {
635
- height: 100%;
636
- background: linear-gradient(90deg, #3b82f6, #1d4ed8);
637
- border-radius: 2px;
638
- transition: width 1s ease;
639
- }
640
-
641
- /* 右侧内容 */
642
- .right-content {
643
- display: flex;
644
- flex-direction: column;
645
- gap: 24px;
646
- }
647
-
648
- /* 依赖信息容器 */
649
- .dependencies-container {
650
- background: #fff;
651
- border-radius: 12px;
652
- padding: 24px;
653
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
654
- }
655
-
656
- .dependencies-list {
657
- display: grid;
658
- grid-template-columns: repeat(2, 1fr);
659
- gap: 12px;
660
- max-height: 300px;
661
- overflow-y: auto;
662
- }
663
-
664
- .dependency-item {
665
- display: flex;
666
- justify-content: space-between;
667
- align-items: center;
668
- padding: 8px 12px;
669
- border-radius: 6px;
670
- background: #f9fafb;
671
- transition: background 0.2s ease;
672
- }
673
-
674
- .dependency-item:hover {
675
- background: #f3f4f6;
676
- }
677
-
678
- .dep-name {
679
- font-size: 14px;
680
- color: #4b5563;
681
- }
682
-
683
- .dep-version {
684
- font-size: 12px;
685
- color: #6b7280;
686
- background: #e5e7eb;
687
- padding: 2px 6px;
688
- border-radius: 4px;
689
- }
690
-
691
- /* 通知容器 */
692
- .notifications-container {
693
- background: #fff;
694
- border-radius: 12px;
695
- padding: 24px;
696
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
697
- }
698
-
699
- .notifications-list {
700
- display: flex;
701
- flex-direction: column;
702
- gap: 12px;
703
- }
704
-
705
- .notification-item {
706
- display: flex;
707
- align-items: flex-start;
708
- padding: 12px;
709
- border-radius: 8px;
710
- background: #f9fafb;
711
- transition: background 0.2s ease;
712
- }
713
-
714
- .notification-item:hover {
715
- background: #f3f4f6;
716
- }
717
-
718
- .notification-icon {
719
- width: 32px;
720
- height: 32px;
721
- border-radius: 50%;
722
- display: flex;
723
- align-items: center;
724
- justify-content: center;
725
- color: white;
726
- font-size: 14px;
727
- margin-right: 12px;
728
- flex-shrink: 0;
729
- }
730
-
731
- .notification-content {
732
- flex: 1;
733
- }
734
-
735
- .notification-title {
736
- font-size: 14px;
737
- font-weight: 500;
738
- color: #1f2937;
739
- margin-bottom: 4px;
740
- }
741
-
742
- .notification-desc {
743
- font-size: 12px;
744
- color: #6b7280;
745
- }
746
-
747
- /* 活动容器 */
748
- .activities-container {
749
- background: #fff;
750
- border-radius: 12px;
751
- padding: 24px;
752
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
753
- }
754
-
755
- .activities-list {
756
- display: flex;
757
- flex-direction: column;
758
- gap: 12px;
759
- }
760
-
761
- .activity-item {
762
- display: flex;
763
- align-items: center;
764
- padding: 8px 0;
765
- border-bottom: 1px solid #f3f4f6;
766
- }
767
-
768
- .activity-item:last-child {
769
- border-bottom: none;
770
- }
771
-
772
- .activity-icon {
773
- color: #6b7280;
774
- margin-right: 12px;
775
- font-size: 14px;
776
- }
777
-
778
- .activity-content {
779
- font-size: 14px;
780
- color: #4b5563;
781
- }
782
-
783
- /* 响应式设计 */
784
- @media (max-width: 1200px) {
785
- .main-content {
786
- grid-template-columns: 1fr;
787
- }
788
-
789
- .stats-container {
790
- grid-template-columns: repeat(2, 1fr);
791
- }
792
- }
793
-
794
- @media (max-width: 768px) {
795
- .console-page {
796
- padding: 16px;
797
- }
798
-
799
- .header-content {
800
- flex-direction: column;
801
- align-items: flex-start;
802
- }
803
-
804
- .header-time {
805
- text-align: left;
806
- margin-top: 12px;
807
- }
808
-
809
- .stats-container {
810
- grid-template-columns: 1fr;
811
- }
812
-
813
- .info-grid {
814
- grid-template-columns: 1fr;
815
- }
816
-
817
- .dependencies-list {
818
- grid-template-columns: 1fr;
819
- }
820
- }
821
- </style>
1
+ <template>
2
+ <div class="console-page">
3
+ <!-- 页面标题区域 -->
4
+ <div class="page-header">
5
+ <div class="header-content">
6
+ <div class="header-title">
7
+ <h1>系统控制台</h1>
8
+ <p>欢迎使用系统控制台,这里可以查看系统概览和重要信息</p>
9
+ </div>
10
+ <div class="header-time">
11
+ <div class="time-display">{{ currentTime }}</div>
12
+ <div class="date-display">{{ currentDate }}</div>
13
+ </div>
14
+ </div>
15
+ </div>
16
+
17
+ <!-- 统计卡片区域 -->
18
+ <div class="stats-container">
19
+ <div class="stat-card" v-for="(stat, index) in statsData" :key="index">
20
+ <div class="stat-icon" :style="{ background: stat.gradient }">
21
+ <component :is="stat.icon" />
22
+ </div>
23
+ <div class="stat-content">
24
+ <div class="stat-value">{{ stat.value }}</div>
25
+ <div class="stat-label">{{ stat.label }}</div>
26
+ <div class="stat-trend" :class="stat.trend">
27
+ <component :is="stat.trendIcon" />
28
+ {{ stat.change }}
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <!-- 主要内容区域 -->
35
+ <div class="main-content">
36
+ <!-- 左侧内容 -->
37
+ <div class="left-content">
38
+ <!-- 访问量统计图表 -->
39
+ <div class="chart-container">
40
+ <div class="card-header">
41
+ <h3>访问量统计</h3>
42
+ <div class="chart-controls">
43
+ <a-radio-group v-model:value="chartPeriod" size="small">
44
+ <a-radio-button value="week">本周</a-radio-button>
45
+ <a-radio-button value="month">本月</a-radio-button>
46
+ <a-radio-button value="year">本年</a-radio-button>
47
+ </a-radio-group>
48
+ </div>
49
+ </div>
50
+ <div class="chart-wrapper" ref="visitChartRef"></div>
51
+ </div>
52
+
53
+ <!-- 系统信息 -->
54
+ <div class="system-info-container">
55
+ <div class="card-header">
56
+ <h3>系统信息</h3>
57
+ </div>
58
+ <div class="info-grid">
59
+ <div
60
+ class="info-item"
61
+ v-for="(info, index) in systemInfo"
62
+ :key="index"
63
+ >
64
+ <div class="info-label">{{ info.label }}</div>
65
+ <div class="info-value">{{ info.value }}</div>
66
+ <div class="info-progress" v-if="info.progress">
67
+ <div
68
+ class="progress-bar"
69
+ :style="{ width: info.progress + '%' }"
70
+ ></div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ </div>
76
+
77
+ <!-- 右侧内容 -->
78
+ <div class="right-content">
79
+ <!-- 前端项目引用 -->
80
+ <div class="dependencies-container">
81
+ <div class="card-header">
82
+ <h3>前端项目引用</h3>
83
+ </div>
84
+ <div class="dependencies-list">
85
+ <div
86
+ class="dependency-item"
87
+ v-for="(dep, index) in dependencies"
88
+ :key="index"
89
+ >
90
+ <div class="dep-name">{{ dep.name }}</div>
91
+ <div class="dep-version">{{ dep.version }}</div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+
96
+ <!-- 最新通知 -->
97
+ <div class="notifications-container">
98
+ <div class="card-header">
99
+ <h3>最新通知</h3>
100
+ <a-badge :count="notifications.length" />
101
+ </div>
102
+ <div class="notifications-list">
103
+ <div
104
+ class="notification-item"
105
+ v-for="(item, index) in notifications"
106
+ :key="index"
107
+ >
108
+ <div
109
+ class="notification-icon"
110
+ :style="{ backgroundColor: item.color }"
111
+ >
112
+ {{ item.icon }}
113
+ </div>
114
+ <div class="notification-content">
115
+ <div class="notification-title">{{ item.title }}</div>
116
+ <div class="notification-desc">{{ item.description }}</div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <!-- 最近活动 -->
123
+ <div class="activities-container">
124
+ <div class="card-header">
125
+ <h3>最近活动</h3>
126
+ </div>
127
+ <div class="activities-list">
128
+ <div
129
+ class="activity-item"
130
+ v-for="(activity, index) in recentActivities"
131
+ :key="index"
132
+ >
133
+ <ClockCircleOutlined class="activity-icon" />
134
+ <div class="activity-content">{{ activity.content }}</div>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </template>
142
+
143
+ <script setup>
144
+ import { ref, reactive, onMounted, onUnmounted, computed, watch } from 'vue'
145
+ import * as baseEcharts from '@/utils/baseEcharts'
146
+ import {
147
+ UserOutlined,
148
+ ShoppingCartOutlined,
149
+ DollarOutlined,
150
+ MessageOutlined,
151
+ ClockCircleOutlined,
152
+ ArrowUpOutlined,
153
+ ArrowDownOutlined,
154
+ } from '@ant-design/icons-vue'
155
+
156
+ // 创建图表容器引用
157
+ const visitChartRef = ref(null)
158
+ // 图表实例
159
+ let visitChart = null
160
+
161
+ // 图表周期选择
162
+ const chartPeriod = ref('month')
163
+
164
+ // 当前时间
165
+ const currentTime = ref('')
166
+ const currentDate = ref('')
167
+
168
+ // 统计数据
169
+ const stats = reactive({
170
+ userCount: 1256,
171
+ orderCount: 89,
172
+ revenue: '12,580',
173
+ messageCount: 5,
174
+ })
175
+
176
+ // 统计卡片数据
177
+ const statsData = computed(() => [
178
+ {
179
+ label: '用户总数',
180
+ value: stats.userCount,
181
+ icon: UserOutlined,
182
+ gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
183
+ trend: 'up',
184
+ trendIcon: ArrowUpOutlined,
185
+ change: '12.5%',
186
+ },
187
+ {
188
+ label: '今日订单',
189
+ value: stats.orderCount,
190
+ icon: ShoppingCartOutlined,
191
+ gradient: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
192
+ trend: 'up',
193
+ trendIcon: ArrowUpOutlined,
194
+ change: '8.2%',
195
+ },
196
+ {
197
+ label: '今日收入',
198
+ value: `¥${stats.revenue}`,
199
+ icon: DollarOutlined,
200
+ gradient: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
201
+ trend: 'down',
202
+ trendIcon: ArrowDownOutlined,
203
+ change: '3.1%',
204
+ },
205
+ {
206
+ label: '未读消息',
207
+ value: stats.messageCount,
208
+ icon: MessageOutlined,
209
+ gradient: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',
210
+ trend: 'up',
211
+ trendIcon: ArrowUpOutlined,
212
+ change: '2条',
213
+ },
214
+ ])
215
+
216
+ // 系统信息
217
+ const systemInfo = ref([
218
+ { label: '系统版本', value: 'v1.0.0' },
219
+ { label: '运行时间', value: '15天2小时' },
220
+ { label: '内存使用率', value: '65%', progress: 65 },
221
+ { label: 'CPU使用率', value: '23%', progress: 23 },
222
+ { label: '磁盘空间', value: '85GB/120GB', progress: 70 },
223
+ ])
224
+
225
+ // 前端项目引用
226
+ const dependencies = ref([
227
+ { name: 'Vue', version: 'v3.5.13' },
228
+ { name: 'Vue Router', version: 'v4.4.5' },
229
+ { name: 'Pinia', version: 'v2.2.6' },
230
+ { name: 'Ant Design Vue', version: 'v4.2.6' },
231
+ { name: 'Ant Design Icons Vue', version: 'v7.0.1' },
232
+ { name: 'ECharts', version: 'v6.0.0' },
233
+ { name: 'Day.js', version: 'v1.11.13' },
234
+ { name: 'Alova', version: 'v3.2.6' },
235
+ { name: 'File-saver', version: 'v2.0.5' },
236
+ { name: 'Vite', version: 'v7.0.6' },
237
+ ])
238
+
239
+ // 通知列表
240
+ const notifications = ref([
241
+ {
242
+ title: '系统维护通知',
243
+ description: '系统将于今晚23:00进行维护,预计耗时2小时',
244
+ color: '#1890ff',
245
+ icon: '维',
246
+ },
247
+ {
248
+ title: '新版本发布',
249
+ description: 'v1.2.0版本已发布,新增多项功能',
250
+ color: '#52c41a',
251
+ icon: '新',
252
+ },
253
+ {
254
+ title: '安全提醒',
255
+ description: '请及时修改默认密码,确保账户安全',
256
+ color: '#faad14',
257
+ icon: '安',
258
+ },
259
+ ])
260
+
261
+ // 最近活动
262
+ const recentActivities = ref([
263
+ { id: 1, content: '用户张三登录系统' },
264
+ { id: 2, content: '订单#20231215001创建成功' },
265
+ { id: 3, content: '报表数据已更新' },
266
+ { id: 4, content: '系统备份完成' },
267
+ ])
268
+
269
+ // 更新时间函数
270
+ const updateDateTime = () => {
271
+ const now = new Date()
272
+
273
+ // 更新时间
274
+ currentTime.value = now.toLocaleTimeString('zh-CN', {
275
+ hour: '2-digit',
276
+ minute: '2-digit',
277
+ second: '2-digit',
278
+ })
279
+
280
+ // 更新日期
281
+ currentDate.value = now.toLocaleDateString('zh-CN', {
282
+ year: 'numeric',
283
+ month: 'long',
284
+ day: 'numeric',
285
+ weekday: 'long',
286
+ })
287
+ }
288
+
289
+ // 初始化图表
290
+ const initChart = () => {
291
+ // 使用 baseEcharts 工具初始化折线图
292
+ visitChart = baseEcharts.initLineChart(visitChartRef.value, '访问量')
293
+
294
+ // 根据选择的周期获取不同的数据
295
+ const getChartData = () => {
296
+ switch (chartPeriod.value) {
297
+ case 'week':
298
+ return {
299
+ xAxis: {
300
+ data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
301
+ },
302
+ series: [
303
+ {
304
+ name: '访问量',
305
+ data: [320, 450, 380, 420, 580, 620, 590],
306
+ },
307
+ {
308
+ name: '独立访客',
309
+ data: [220, 320, 280, 350, 480, 520, 490],
310
+ },
311
+ ],
312
+ }
313
+ case 'month':
314
+ return {
315
+ xAxis: {
316
+ data: Array.from({ length: 30 }, (_, i) => `${i + 1}日`),
317
+ },
318
+ series: [
319
+ {
320
+ name: '访问量',
321
+ data: Array.from(
322
+ { length: 30 },
323
+ () => Math.floor(Math.random() * 1000) + 500,
324
+ ),
325
+ },
326
+ {
327
+ name: '独立访客',
328
+ data: Array.from(
329
+ { length: 30 },
330
+ () => Math.floor(Math.random() * 800) + 300,
331
+ ),
332
+ },
333
+ ],
334
+ }
335
+ case 'year':
336
+ return {
337
+ xAxis: {
338
+ data: [
339
+ '1月',
340
+ '2月',
341
+ '3月',
342
+ '4月',
343
+ '5月',
344
+ '6月',
345
+ '7月',
346
+ '8月',
347
+ '9月',
348
+ '10月',
349
+ '11月',
350
+ '12月',
351
+ ],
352
+ },
353
+ series: [
354
+ {
355
+ name: '访问量',
356
+ data: [
357
+ 820, 932, 901, 934, 1290, 1330, 1320, 1540, 1200, 1100, 1380,
358
+ 1420,
359
+ ],
360
+ },
361
+ {
362
+ name: '独立访客',
363
+ data: [
364
+ 620, 732, 701, 734, 1090, 1130, 1120, 1340, 1000, 900, 1180,
365
+ 1220,
366
+ ],
367
+ },
368
+ ],
369
+ }
370
+ default:
371
+ return {
372
+ xAxis: { data: [] },
373
+ series: [],
374
+ }
375
+ }
376
+ }
377
+
378
+ // 获取数据并更新图表
379
+ const chartData = getChartData()
380
+ baseEcharts.updateLineChart({
381
+ chartInstance: visitChart,
382
+ data: chartData,
383
+ shouldShowSlider: chartData.xAxis.data.length > 12,
384
+ })
385
+ }
386
+
387
+ // 监听图表周期变化
388
+ const handlePeriodChange = () => {
389
+ initChart()
390
+ }
391
+
392
+ onMounted(() => {
393
+ updateDateTime()
394
+ // 每秒更新一次时间
395
+ const timer = setInterval(updateDateTime, 1000)
396
+ initChart()
397
+
398
+ // 模拟数据更新
399
+ setTimeout(() => {
400
+ stats.orderCount = 92
401
+ stats.revenue = '13,200'
402
+ }, 3000)
403
+
404
+ // 每30秒更新一次图表数据
405
+ const chartTimer = setInterval(() => {
406
+ initChart()
407
+ }, 30000)
408
+
409
+ // 监听图表周期变化
410
+ const stopWatch = watch(chartPeriod, handlePeriodChange)
411
+
412
+ onUnmounted(() => {
413
+ clearInterval(timer)
414
+ clearInterval(chartTimer)
415
+ if (stopWatch) stopWatch()
416
+ // 销毁图表实例,释放资源
417
+ if (visitChart) {
418
+ visitChart.dispose()
419
+ visitChart = null
420
+ }
421
+ })
422
+ })
423
+ </script>
424
+
425
+ <style scoped>
426
+ .console-page {
427
+ background: #f5f7fa;
428
+ min-height: 100vh;
429
+ font-family:
430
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
431
+ Arial, sans-serif;
432
+ }
433
+
434
+ /* 页面标题区域 */
435
+ .page-header {
436
+ margin-bottom: 24px;
437
+ background: #fff;
438
+ border-radius: 12px;
439
+ padding: 24px;
440
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
441
+ }
442
+
443
+ .header-content {
444
+ display: flex;
445
+ justify-content: space-between;
446
+ align-items: center;
447
+ }
448
+
449
+ .header-title h1 {
450
+ margin: 0;
451
+ font-size: 28px;
452
+ font-weight: 600;
453
+ color: #1f2937;
454
+ }
455
+
456
+ .header-title p {
457
+ margin: 8px 0 0 0;
458
+ color: #6b7280;
459
+ font-size: 14px;
460
+ }
461
+
462
+ .header-time {
463
+ text-align: right;
464
+ }
465
+
466
+ .time-display {
467
+ font-size: 24px;
468
+ font-weight: 600;
469
+ color: #1f2937;
470
+ }
471
+
472
+ .date-display {
473
+ font-size: 14px;
474
+ color: #6b7280;
475
+ margin-top: 4px;
476
+ }
477
+
478
+ /* 统计卡片区域 */
479
+ .stats-container {
480
+ display: grid;
481
+ grid-template-columns: repeat(4, 1fr);
482
+ gap: 20px;
483
+ margin-bottom: 24px;
484
+ }
485
+
486
+ .stat-card {
487
+ background: #fff;
488
+ border-radius: 12px;
489
+ padding: 24px;
490
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
491
+ display: flex;
492
+ align-items: center;
493
+ transition:
494
+ transform 0.3s ease,
495
+ box-shadow 0.3s ease;
496
+ }
497
+
498
+ .stat-card:hover {
499
+ transform: translateY(-5px);
500
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
501
+ }
502
+
503
+ .stat-icon {
504
+ width: 60px;
505
+ height: 60px;
506
+ border-radius: 12px;
507
+ display: flex;
508
+ align-items: center;
509
+ justify-content: center;
510
+ font-size: 24px;
511
+ color: white;
512
+ margin-right: 16px;
513
+ }
514
+
515
+ .stat-content {
516
+ flex: 1;
517
+ }
518
+
519
+ .stat-value {
520
+ font-size: 28px;
521
+ font-weight: 600;
522
+ color: #1f2937;
523
+ line-height: 1;
524
+ }
525
+
526
+ .stat-label {
527
+ margin-top: 4px;
528
+ color: #6b7280;
529
+ font-size: 14px;
530
+ }
531
+
532
+ .stat-trend {
533
+ display: flex;
534
+ align-items: center;
535
+ margin-top: 8px;
536
+ font-size: 12px;
537
+ font-weight: 500;
538
+ }
539
+
540
+ .stat-trend.up {
541
+ color: #10b981;
542
+ }
543
+
544
+ .stat-trend.down {
545
+ color: #ef4444;
546
+ }
547
+
548
+ .stat-trend svg {
549
+ margin-right: 4px;
550
+ }
551
+
552
+ /* 主要内容区域 */
553
+ .main-content {
554
+ display: grid;
555
+ grid-template-columns: 2fr 1fr;
556
+ gap: 24px;
557
+ }
558
+
559
+ /* 卡片标题样式 */
560
+ .card-header {
561
+ display: flex;
562
+ justify-content: space-between;
563
+ align-items: center;
564
+ margin-bottom: 16px;
565
+ }
566
+
567
+ .card-header h3 {
568
+ margin: 0;
569
+ font-size: 18px;
570
+ font-weight: 600;
571
+ color: #1f2937;
572
+ }
573
+
574
+ /* 左侧内容 */
575
+ .left-content {
576
+ display: flex;
577
+ flex-direction: column;
578
+ gap: 24px;
579
+ }
580
+
581
+ /* 图表容器 */
582
+ .chart-container {
583
+ background: #fff;
584
+ border-radius: 12px;
585
+ padding: 24px;
586
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
587
+ }
588
+
589
+ .chart-wrapper {
590
+ height: 300px;
591
+ width: 100%;
592
+ }
593
+
594
+ /* 系统信息容器 */
595
+ .system-info-container {
596
+ background: #fff;
597
+ border-radius: 12px;
598
+ padding: 24px;
599
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
600
+ }
601
+
602
+ .info-grid {
603
+ display: grid;
604
+ grid-template-columns: repeat(2, 1fr);
605
+ gap: 16px;
606
+ }
607
+
608
+ .info-item {
609
+ padding: 12px;
610
+ border-radius: 8px;
611
+ background: #f9fafb;
612
+ }
613
+
614
+ .info-label {
615
+ font-size: 12px;
616
+ color: #6b7280;
617
+ margin-bottom: 4px;
618
+ }
619
+
620
+ .info-value {
621
+ font-size: 16px;
622
+ font-weight: 600;
623
+ color: #1f2937;
624
+ margin-bottom: 8px;
625
+ }
626
+
627
+ .info-progress {
628
+ height: 4px;
629
+ background: #e5e7eb;
630
+ border-radius: 2px;
631
+ overflow: hidden;
632
+ }
633
+
634
+ .progress-bar {
635
+ height: 100%;
636
+ background: linear-gradient(90deg, #3b82f6, #1d4ed8);
637
+ border-radius: 2px;
638
+ transition: width 1s ease;
639
+ }
640
+
641
+ /* 右侧内容 */
642
+ .right-content {
643
+ display: flex;
644
+ flex-direction: column;
645
+ gap: 24px;
646
+ }
647
+
648
+ /* 依赖信息容器 */
649
+ .dependencies-container {
650
+ background: #fff;
651
+ border-radius: 12px;
652
+ padding: 24px;
653
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
654
+ }
655
+
656
+ .dependencies-list {
657
+ display: grid;
658
+ grid-template-columns: repeat(2, 1fr);
659
+ gap: 12px;
660
+ max-height: 300px;
661
+ overflow-y: auto;
662
+ }
663
+
664
+ .dependency-item {
665
+ display: flex;
666
+ justify-content: space-between;
667
+ align-items: center;
668
+ padding: 8px 12px;
669
+ border-radius: 6px;
670
+ background: #f9fafb;
671
+ transition: background 0.2s ease;
672
+ }
673
+
674
+ .dependency-item:hover {
675
+ background: #f3f4f6;
676
+ }
677
+
678
+ .dep-name {
679
+ font-size: 14px;
680
+ color: #4b5563;
681
+ }
682
+
683
+ .dep-version {
684
+ font-size: 12px;
685
+ color: #6b7280;
686
+ background: #e5e7eb;
687
+ padding: 2px 6px;
688
+ border-radius: 4px;
689
+ }
690
+
691
+ /* 通知容器 */
692
+ .notifications-container {
693
+ background: #fff;
694
+ border-radius: 12px;
695
+ padding: 24px;
696
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
697
+ }
698
+
699
+ .notifications-list {
700
+ display: flex;
701
+ flex-direction: column;
702
+ gap: 12px;
703
+ }
704
+
705
+ .notification-item {
706
+ display: flex;
707
+ align-items: flex-start;
708
+ padding: 12px;
709
+ border-radius: 8px;
710
+ background: #f9fafb;
711
+ transition: background 0.2s ease;
712
+ }
713
+
714
+ .notification-item:hover {
715
+ background: #f3f4f6;
716
+ }
717
+
718
+ .notification-icon {
719
+ width: 32px;
720
+ height: 32px;
721
+ border-radius: 50%;
722
+ display: flex;
723
+ align-items: center;
724
+ justify-content: center;
725
+ color: white;
726
+ font-size: 14px;
727
+ margin-right: 12px;
728
+ flex-shrink: 0;
729
+ }
730
+
731
+ .notification-content {
732
+ flex: 1;
733
+ }
734
+
735
+ .notification-title {
736
+ font-size: 14px;
737
+ font-weight: 500;
738
+ color: #1f2937;
739
+ margin-bottom: 4px;
740
+ }
741
+
742
+ .notification-desc {
743
+ font-size: 12px;
744
+ color: #6b7280;
745
+ }
746
+
747
+ /* 活动容器 */
748
+ .activities-container {
749
+ background: #fff;
750
+ border-radius: 12px;
751
+ padding: 24px;
752
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
753
+ }
754
+
755
+ .activities-list {
756
+ display: flex;
757
+ flex-direction: column;
758
+ gap: 12px;
759
+ }
760
+
761
+ .activity-item {
762
+ display: flex;
763
+ align-items: center;
764
+ padding: 8px 0;
765
+ border-bottom: 1px solid #f3f4f6;
766
+ }
767
+
768
+ .activity-item:last-child {
769
+ border-bottom: none;
770
+ }
771
+
772
+ .activity-icon {
773
+ color: #6b7280;
774
+ margin-right: 12px;
775
+ font-size: 14px;
776
+ }
777
+
778
+ .activity-content {
779
+ font-size: 14px;
780
+ color: #4b5563;
781
+ }
782
+
783
+ /* 响应式设计 */
784
+ @media (max-width: 1200px) {
785
+ .main-content {
786
+ grid-template-columns: 1fr;
787
+ }
788
+
789
+ .stats-container {
790
+ grid-template-columns: repeat(2, 1fr);
791
+ }
792
+ }
793
+
794
+ @media (max-width: 768px) {
795
+ .console-page {
796
+ padding: 16px;
797
+ }
798
+
799
+ .header-content {
800
+ flex-direction: column;
801
+ align-items: flex-start;
802
+ }
803
+
804
+ .header-time {
805
+ text-align: left;
806
+ margin-top: 12px;
807
+ }
808
+
809
+ .stats-container {
810
+ grid-template-columns: 1fr;
811
+ }
812
+
813
+ .info-grid {
814
+ grid-template-columns: 1fr;
815
+ }
816
+
817
+ .dependencies-list {
818
+ grid-template-columns: 1fr;
819
+ }
820
+ }
821
+ </style>