Browse Source

优化用户界面体验-首页重构

wenkai 2 weeks ago
parent
commit
fd6e0a12c7

+ 1 - 1
package.json

@@ -29,7 +29,7 @@
     "await-to-js": "3.0.0",
     "axios": "1.8.4",
     "crypto-js": "4.2.0",
-    "echarts": "5.6.0",
+    "echarts": "^5.6.0",
     "element-plus": "2.9.8",
     "file-saver": "2.0.5",
     "highlight.js": "11.9.0",

+ 8 - 0
src/api/monitor/online/index.ts

@@ -34,3 +34,11 @@ export function delOnline(tokenId: string) {
     method: 'delete'
   });
 }
+
+// 获取当前登录用户数量
+export function countOnlineUser() {
+  return request({
+    url: '/monitor/online/count',
+    method: 'get'
+  });
+}

+ 11 - 0
src/api/system/article/index.ts

@@ -61,3 +61,14 @@ export const delArticle = (id: string | number | Array<string | number>) => {
     method: 'delete'
   });
 };
+
+/**
+ * 查询文章数量
+ * @returns {*}
+ */
+export const getArticleCount = () => {
+  return request({
+    url: '/system/article/count',
+    method: 'get'
+  });
+};

+ 1 - 0
src/api/system/gameAthlete/index.ts

@@ -61,3 +61,4 @@ export const delGameAthlete = (athleteId: string | number | Array<string | numbe
     method: 'delete'
   });
 };
+

+ 12 - 0
src/api/system/gameEvent/index.ts

@@ -74,3 +74,15 @@ export const getEventIdNameMap = () => {
     method: 'get'
   });
 };
+
+/**
+ * 查询赛事数量
+ * @returns {*}
+ */
+
+export const getEventCount = () => {
+  return request({
+    url: '/system/gameEvent/count',
+    method: 'get'
+  });
+};

+ 11 - 0
src/api/system/gameEventProject/index.ts

@@ -61,3 +61,14 @@ export const delGameEventProject = (projectId: string | number | Array<string |
     method: 'delete'
   });
 };
+
+/**
+ * 查询赛事项目数量
+ * @returns {*}
+ */
+export const getEventProjectCount = () => {
+  return request({
+    url: '/system/gameEventProject/count',
+    method: 'get'
+  });
+};

+ 11 - 0
src/api/system/gameReferee/index.ts

@@ -61,3 +61,14 @@ export const delGameReferee = (refereeId: string | number | Array<string | numbe
     method: 'delete'
   });
 };
+
+/**
+ * 查询裁判数量
+ * @returns {*}
+ */
+export const getRefereeCount = () => {
+  return request({
+    url: '/system/gameReferee/count',
+    method: 'get'
+  });
+};

+ 11 - 0
src/api/system/gameTeam/index.ts

@@ -61,3 +61,14 @@ export const delGameTeam = (teamId: string | number | Array<string | number>) =>
     method: 'delete'
   });
 };
+
+/**
+ * 查询参赛队伍数量
+ * @returns {*}
+ */
+export const getTeamCount = () => {
+  return request({
+    url: '/system/gameTeam/count',
+    method: 'get'
+  });
+};

+ 693 - 131
src/views/index.vue

@@ -1,164 +1,726 @@
 <template>
-  <div class="app-container home">
-    <el-row :gutter="20">
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>RuoYi-Vue-Plus多租户管理系统</h2>
-        <p>
-          RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架)
-          <br />
-          * 前端开发框架 Vue3、TS、Element Plus<br />
-          * 后端开发框架 Spring Boot<br />
-          * 容器框架 Undertow 基于 Netty 的高性能容器<br />
-          * 权限认证框架 Sa-Token 支持多终端认证系统<br />
-          * 关系数据库 MySQL 适配 8.X 最低 5.7<br />
-          * 缓存数据库 Redis 适配 6.X 最低 4.X<br />
-          * 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br />
-          * 数据库框架 p6spy 更强劲的 SQL 分析<br />
-          * 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br />
-          * 序列化框架 Jackson 统一使用 jackson 高效可靠<br />
-          * Redis客户端 Redisson 性能强劲、API丰富<br />
-          * 分布式限流 Redisson 全局、请求IP、集群ID 多种限流<br />
-          * 分布式锁 Lock4j 注解锁、工具锁 多种多样<br />
-          * 分布式幂等 Lock4j 基于分布式锁实现<br />
-          * 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br />
-          * 分布式任务调度 SnailJob 高性能 高可靠 易扩展<br />
-          * 文件存储 Minio 本地存储<br />
-          * 文件存储 七牛、阿里、腾讯 云存储<br />
-          * 监控框架 SpringBoot-Admin 全方位服务监控<br />
-          * 校验框架 Validation 增强接口安全性 严谨性<br />
-          * Excel框架 FastExcel(原Alibaba EasyExcel) 性能优异 扩展性强<br />
-          * 文档框架 SpringDoc、javadoc 无注解零入侵基于java注释<br />
-          * 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性<br />
-          * 代码生成器 适配MP、SpringDoc规范化代码 一键生成前后端代码<br />
-          * 部署方式 Docker 容器编排 一键部署业务集群<br />
-          * 国际化 SpringMessage Spring标准国际化方案<br />
-        </p>
-        <p><b>当前版本:</b> <span>v5.4.1</span></p>
-        <p>
-          <el-tag type="danger">&yen;免费开源</el-tag>
-        </p>
-        <p>
-          <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
-          <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
-          <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')"
-            >更新日志</el-button
-          >
-        </p>
+  <div class="dashboard-container">
+    <!-- 顶部标题区域 -->
+    <div class="dashboard-header">
+      <h1 class="dashboard-title">
+        <el-icon class="title-icon">
+          <TrendCharts />
+        </el-icon>
+        赛事管理系统仪表板
+      </h1>
+      <p class="dashboard-subtitle">实时监控赛事数据,洞察运营状况</p>
+    </div>
+
+    <!-- 统计卡片区域 -->
+    <div class="stats-grid">
+      <div class="stat-card" v-for="(item, index) in statsData" :key="index">
+        <div class="stat-icon" :style="{ backgroundColor: item.color }">
+          <el-icon :size="24">
+            <component :is="item.icon" />
+          </el-icon>
+        </div>
+        <div class="stat-content">
+          <div class="stat-value">{{ item.loading ? '-' : item.value }}</div>
+          <div class="stat-label">{{ item.label }}</div>
+        </div>
+      </div>
+    </div>
+    <!-- 快速操作区域 -->
+    <el-card class="quick-actions-card">
+      <template #header>
+        <div class="card-header">
+          <span>快速操作</span>
+          <el-icon>
+            <Operation />
+          </el-icon>
+        </div>
+      </template>
+      <div class="quick-actions">
+        <el-button
+          v-for="action in quickActions"
+          :key="action.name"
+          :type="action.type"
+          :icon="action.icon"
+          @click="handleQuickAction(action.action)"
+          class="action-btn"
+        >
+          {{ action.name }}
+        </el-button>
+      </div>
+    </el-card>
+    <!-- 图表和详细信息区域 -->
+    <el-row :gutter="20" class="charts-section">
+      <!-- 数据分布饼图 -->
+      <el-col :xs="24" :sm="24" :md="12" :lg="8">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="card-header">
+              <span>数据分布</span>
+              <el-icon>
+                <PieChart />
+              </el-icon>
+            </div>
+          </template>
+          <div id="pieChart" class="chart-container"></div>
+        </el-card>
+      </el-col>
+
+      <!-- 趋势图表 -->
+      <el-col :xs="24" :sm="24" :md="12" :lg="8">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="card-header">
+              <span>数据趋势</span>
+              <el-icon>
+                <TrendCharts />
+              </el-icon>
+            </div>
+          </template>
+          <div id="lineChart" class="chart-container"></div>
+        </el-card>
+      </el-col>
+
+      <!-- 系统信息 -->
+      <el-col :xs="24" :sm="24" :md="24" :lg="8">
+        <el-card class="chart-card">
+          <template #header>
+            <div class="card-header">
+              <span>系统信息</span>
+              <el-icon>
+                <Monitor />
+              </el-icon>
+            </div>
+          </template>
+          <div class="system-info">
+            <div class="info-item">
+              <span class="info-label">系统版本</span>
+              <span class="info-value">v5.4.1</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">运行状态</span>
+              <el-tag type="success">正常运行</el-tag>
+            </div>
+            <div class="info-item">
+              <span class="info-label">在线用户</span>
+              <span class="info-value">{{ onlineUsers }}</span>
+            </div>
+            <div class="info-item">
+              <span class="info-label">数据更新</span>
+              <span class="info-value">{{ lastUpdateTime }}</span>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <!-- 最新动态 -->
+    <el-row :gutter="20" class="activity-section">
+      <el-col :xs="24" :sm="24" :md="12">
+        <el-card class="activity-card">
+          <template #header>
+            <div class="card-header">
+              <span>最新赛事</span>
+              <el-icon>
+                <Calendar />
+              </el-icon>
+            </div>
+          </template>
+          <div class="activity-list">
+            <div v-for="event in recentEvents" :key="event.id" class="activity-item">
+              <div class="activity-dot"></div>
+              <div class="activity-content">
+                <div class="activity-title">{{ event.eventName }}</div>
+                <div class="activity-time">{{ event.updateTime }}</div>
+              </div>
+            </div>
+          </div>
+        </el-card>
       </el-col>
 
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2>
-        <p>
-          RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
-          <br />
-          * 前端开发框架 Vue3、TS、Element UI<br />
-          * 后端开发框架 Spring Boot<br />
-          * 微服务开发框架 Spring Cloud、Spring Cloud Alibaba<br />
-          * 容器框架 Undertow 基于 XNIO 的高性能容器<br />
-          * 权限认证框架 Sa-Token、Jwt 支持多终端认证系统<br />
-          * 关系数据库 MySQL 适配 8.X 最低 5.7<br />
-          * 关系数据库 Oracle 适配 11g 12c<br />
-          * 关系数据库 PostgreSQL 适配 13 14<br />
-          * 关系数据库 SQLServer 适配 2017 2019<br />
-          * 缓存数据库 Redis 适配 6.X 最低 5.X<br />
-          * 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
-          * 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
-          * 服务网关 Spring Cloud Gateway 响应式高性能网关<br />
-          * 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br />
-          * RPC远程调用 Apache Dubbo 原生态使用体验、高性能<br />
-          * 分布式限流熔断 Alibaba Sentinel 无侵入、高扩展<br />
-          * 分布式事务 Alibaba Seata 无侵入、高扩展 支持 四种模式<br />
-          * 分布式消息队列 Apache Kafka 高性能高速度<br />
-          * 分布式消息队列 Apache RocketMQ 高可用功能多样<br />
-          * 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br />
-          * 分布式搜索引擎 ElasticSearch 业界知名<br />
-          * 分布式链路追踪 Apache SkyWalking 链路追踪、网格分析、度量聚合、可视化<br />
-          * 分布式日志中心 ELK 业界成熟解决方案<br />
-          * 分布式监控 Prometheus、Grafana 全方位性能监控<br />
-          * 其余与 Vue 版本一致<br />
-        </p>
-        <p><b>当前版本:</b> <span>v2.4.1</span></p>
-        <p>
-          <el-tag type="danger">&yen;免费开源</el-tag>
-        </p>
-        <p>
-          <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
-          <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button>
-          <el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')"
-            >更新日志</el-button
-          >
-        </p>
+      <el-col :xs="24" :sm="24" :md="12">
+        <el-card class="activity-card">
+          <template #header>
+            <div class="card-header">
+              <span>系统公告</span>
+              <el-icon>
+                <Bell />
+              </el-icon>
+            </div>
+          </template>
+          <div class="activity-list">
+            <div v-for="notice in systemNotices" :key="notice.id" class="activity-item">
+              <div class="activity-dot notice"></div>
+              <div class="activity-content">
+                <div class="activity-title">{{ notice.noticeTitle }}</div>
+                <div class="activity-time">{{ notice.createTime }}</div>
+              </div>
+            </div>
+          </div>
+        </el-card>
       </el-col>
     </el-row>
-    <el-divider />
   </div>
 </template>
 
 <script setup name="Index" lang="ts">
-const goTarget = (url: string) => {
-  window.open(url, '__blank');
+import { ref, nextTick, onMounted } from 'vue';
+import { ElMessage } from 'element-plus';
+import { TrendCharts, PieChart, Monitor, Operation, Calendar, Bell } from '@element-plus/icons-vue';
+import * as echarts from 'echarts';
+import { getArticleCount } from '@/api/system/article';
+import { getEventCount, listGameEvent } from '@/api/system/gameEvent';
+import { getEventProjectCount } from '@/api/system/gameEventProject';
+import { getRefereeCount } from '@/api/system/gameReferee';
+import { getTeamCount } from '@/api/system/gameTeam';
+import { listNotice } from '@/api/system/notice';
+import { countOnlineUser } from '@/api/monitor/online';
+
+// 响应式数据
+const statsData = ref([
+  {
+    label: '文章数量',
+    value: 0,
+    icon: 'DataBoard',
+    color: '#409EFF',
+    loading: true
+  },
+  {
+    label: '参赛队伍',
+    value: 0,
+    icon: 'User',
+    color: '#67C23A',
+    loading: true
+  },
+  {
+    label: '赛事',
+    value: 0,
+    icon: 'Trophy',
+    color: '#E6A23C',
+    loading: true
+  },
+  {
+    label: '赛事项目',
+    value: 0,
+    icon: 'Promotion',
+    color: '#F56C6C',
+    loading: true
+  },
+  {
+    label: '裁判',
+    value: 0,
+    icon: 'Flag',
+    color: '#909399',
+    loading: true
+  }
+]);
+const router = useRouter();
+const onlineUsers = ref(1);
+const lastUpdateTime = ref('');
+
+const quickActions = ref([
+  { name: '新增赛事', type: 'primary' as const, icon: 'Plus', action: 'addEvent' },
+  { name: '参赛队伍管理', type: 'success' as const, icon: 'User', action: 'manageTeam' },
+  { name: '裁判管理', type: 'warning' as const, icon: 'Flag', action: 'manageReferees' },
+  { name: '数据导出', type: 'info' as const, icon: 'Download', action: 'exportData' },
+  { name: '刷新数据', type: 'default' as const, icon: 'Refresh', action: 'refresh' }
+]);
+
+const recentEvents = ref([]);
+
+const systemNotices = ref([]);
+
+/**
+ * 获取最新赛事
+ */
+const loadRecentEvents = async () => {
+  try {
+    const res = await listGameEvent({
+      pageNum: 1,
+      pageSize: 4
+    });
+    if (res.code === 200 && res.total > 0) {
+      recentEvents.value = res.rows;
+    }
+  } catch (error) {
+    console.error('加载最新赛事失败:', error);
+  }
+};
+
+/**
+ * 获取公告
+ */
+const loadNotice = async () => {
+  try {
+    const res = await listNotice({
+      pageNum: 1,
+      pageSize: 4,
+      noticeTitle: undefined,
+      createByName: undefined,
+      status: undefined,
+      noticeType: undefined
+    });
+    if (res.code === 200 && res.total > 0) {
+      systemNotices.value = res.rows;
+    }
+  } catch (error) {
+    console.error('加载公告失败:', error);
+  }
+};
+
+/**
+ * 获取统计数量
+ */
+const loadStatistics = async () => {
+  try {
+    // 并行请求所有统计接口
+    const results = await Promise.allSettled([getArticleCount(), getTeamCount(), getEventCount(), getEventProjectCount(), getRefereeCount()]);
+
+    let hasError = false;
+
+    // 处理文章数量
+    if (results[0].status === 'fulfilled') {
+      statsData.value[0].value = results[0].value.data || 0;
+    } else {
+      console.error('获取文章数量失败:', results[0].reason);
+      statsData.value[0].value = 0;
+      hasError = true;
+    }
+    statsData.value[0].loading = false;
+
+    // 处理参赛队伍数量
+    if (results[1].status === 'fulfilled') {
+      statsData.value[1].value = results[1].value.data || 0;
+    } else {
+      console.error('获取参赛队伍数量失败:', results[1].reason);
+      statsData.value[1].value = 0;
+      hasError = true;
+    }
+    statsData.value[1].loading = false;
+
+    // 处理赛事数量
+    if (results[2].status === 'fulfilled') {
+      statsData.value[2].value = results[2].value.data || 0;
+    } else {
+      console.error('获取赛事数量失败:', results[2].reason);
+      statsData.value[2].value = 0;
+      hasError = true;
+    }
+    statsData.value[2].loading = false;
+
+    // 处理赛事项目数量
+    if (results[3].status === 'fulfilled') {
+      statsData.value[3].value = results[3].value.data || 0;
+    } else {
+      console.error('获取赛事项目数量失败:', results[3].reason);
+      statsData.value[3].value = 0;
+      hasError = true;
+    }
+    statsData.value[3].loading = false;
+
+    // 处理裁判数量
+    if (results[4].status === 'fulfilled') {
+      statsData.value[4].value = results[4].value.data || 0;
+    } else {
+      console.error('获取裁判数量失败:', results[4].reason);
+      statsData.value[4].value = 0;
+      hasError = true;
+    }
+    statsData.value[4].loading = false;
+
+    // 如果有接口错误,显示提示
+    if (hasError) {
+      ElMessage({
+        message: '部分统计数据获取失败,请检查网络连接或稍后重试',
+        type: 'warning',
+        duration: 3000
+      });
+    }
+
+    // 初始化图表
+    nextTick(() => {
+      initCharts();
+    });
+  } catch (error) {
+    console.error('加载统计数据失败:', error);
+    ElMessage({
+      message: '统计数据加载失败,请检查网络连接',
+      type: 'error',
+      duration: 5000
+    });
+    // 设置所有统计数据为0并停止加载状态
+    statsData.value.forEach((item) => {
+      item.value = 0;
+      item.loading = false;
+    });
+  }
 };
+
+const initCharts = () => {
+  initPieChart();
+  initLineChart();
+};
+
+const initPieChart = () => {
+  const chartDom = document.getElementById('pieChart');
+  if (!chartDom) return;
+
+  const myChart = echarts.init(chartDom);
+  const option = {
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      orient: 'vertical',
+      left: 'left'
+    },
+    series: [
+      {
+        name: '数据分布',
+        type: 'pie',
+        radius: '50%',
+        data: [
+          { value: statsData.value[0].value, name: '文章' },
+          { value: statsData.value[1].value, name: '参赛队伍' },
+          { value: statsData.value[2].value, name: '赛事' },
+          { value: statsData.value[3].value, name: '项目' },
+          { value: statsData.value[4].value, name: '裁判' }
+        ],
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: 'rgba(0, 0, 0, 0.5)'
+          }
+        }
+      }
+    ]
+  };
+  myChart.setOption(option);
+};
+
+const initLineChart = () => {
+  const chartDom = document.getElementById('lineChart');
+  if (!chartDom) return;
+
+  const myChart = echarts.init(chartDom);
+  const option = {
+    tooltip: {
+      trigger: 'axis'
+    },
+    legend: {
+      data: ['注册数量', '赛事数量']
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: ['1月', '2月', '3月', '4月', '5月', '6月']
+    },
+    yAxis: {
+      type: 'value'
+    },
+    series: [
+      {
+        name: '注册数量',
+        type: 'line',
+        stack: 'Total',
+        data: [120, 132, 101, 134, 90, 230]
+      },
+      {
+        name: '赛事数量',
+        type: 'line',
+        stack: 'Total',
+        data: [220, 182, 191, 234, 290, 330]
+      }
+    ]
+  };
+  myChart.setOption(option);
+};
+
+const handleQuickAction = (action: string) => {
+  switch (action) {
+    case 'addEvent':
+      // 跳转到新增赛事页面
+      router.push(`/system/gameEvent/add`);
+      break;
+    case 'manageAthletes':
+      // 跳转到参赛队伍管理页面
+      router.push(`/game/gameTeam`);
+      break;
+    case 'manageReferees':
+      // 跳转到裁判管理页面
+      router.push(`/game/gameReferee`);
+      break;
+    case 'exportData':
+      // 导出数据
+      ElMessage({
+        message: '请到具体的管理页面进行导出',
+        type: 'info'
+      });
+      break;
+    case 'refresh':
+      // 刷新统计数据和最新赛事
+      getAllData();
+      ElMessage({
+        message: '正在刷新数据...',
+        type: 'info'
+      });
+      break;
+  }
+};
+
+const getOnlineUser = async () => {
+  const res = await countOnlineUser();
+  onlineUsers.value = res.data;
+};
+
+const updateTime = () => {
+  const now = new Date();
+  lastUpdateTime.value = now.toLocaleTimeString();
+};
+
+const getAllData = async () => {
+  loadStatistics();
+  loadRecentEvents();
+  loadNotice();
+  getOnlineUser();
+};
+
+onMounted(() => {
+  getAllData();
+  updateTime();
+  // 每分钟更新一次时间
+  setInterval(updateTime, 60000);
+});
 </script>
 
 <style lang="scss" scoped>
-.home {
-  blockquote {
-    padding: 10px 20px;
-    margin: 0 0 20px;
-    font-size: 17.5px;
-    border-left: 5px solid #eee;
+.dashboard-container {
+  padding: 20px;
+  background: #f5f7fa;
+  min-height: calc(100vh - 84px);
+}
+
+.dashboard-header {
+  text-align: center;
+  margin-bottom: 30px;
+
+  .dashboard-title {
+    font-size: 28px;
+    color: #303133;
+    margin: 0 0 10px 0;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 10px;
+
+    .title-icon {
+      color: #409eff;
+    }
   }
-  hr {
-    margin-top: 20px;
-    margin-bottom: 20px;
-    border: 0;
-    border-top: 1px solid #eee;
+
+  .dashboard-subtitle {
+    font-size: 16px;
+    color: #909399;
+    margin: 0;
   }
-  .col-item {
-    margin-bottom: 20px;
+}
+
+.stats-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+  gap: 20px;
+  margin-bottom: 30px;
+}
+
+.stat-card {
+  background: white;
+  border-radius: 12px;
+  padding: 24px;
+  display: flex;
+  align-items: center;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
+  transition: all 0.3s ease;
+
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.12);
   }
+}
 
-  ul {
-    padding: 0;
-    margin: 0;
+.stat-icon {
+  width: 60px;
+  height: 60px;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 16px;
+  color: white;
+}
+
+.stat-content {
+  flex: 1;
+}
+
+.stat-value {
+  font-size: 24px;
+  font-weight: bold;
+  color: #303133;
+  line-height: 1;
+  margin-bottom: 4px;
+}
+
+.stat-label {
+  font-size: 14px;
+  color: #909399;
+  margin-bottom: 8px;
+}
+
+.stat-trend {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  font-size: 12px;
+
+  &.up {
+    color: #67c23a;
+  }
+
+  &.down {
+    color: #f56c6c;
+  }
+}
+
+.charts-section {
+  margin-bottom: 30px;
+}
+
+.chart-card {
+  height: 400px;
+
+  .card-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-weight: bold;
+  }
+
+  .chart-container {
+    height: 320px;
   }
+}
 
-  font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  color: #676a6c;
-  overflow-x: hidden;
+.system-info {
+  .info-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 12px 0;
+    border-bottom: 1px solid #f0f0f0;
 
-  ul {
-    list-style-type: none;
+    &:last-child {
+      border-bottom: none;
+    }
   }
 
-  h4 {
-    margin-top: 0px;
+  .info-label {
+    color: #909399;
+    font-size: 14px;
   }
 
-  h2 {
-    margin-top: 10px;
-    font-size: 26px;
-    font-weight: 100;
+  .info-value {
+    color: #303133;
+    font-weight: 500;
   }
+}
 
-  p {
-    margin-top: 10px;
+.quick-actions-card {
+  margin-bottom: 30px;
+}
+
+.quick-actions {
+  display: flex;
+  gap: 16px;
+  flex-wrap: wrap;
 
-    b {
-      font-weight: 700;
+  .action-btn {
+    flex: 1;
+    min-width: 120px;
+  }
+}
+
+.activity-section {
+  .activity-card {
+    .card-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      font-weight: bold;
     }
   }
+}
+
+.activity-list {
+  .activity-item {
+    display: flex;
+    align-items: flex-start;
+    padding: 12px 0;
+    border-bottom: 1px solid #f0f0f0;
+
+    &:last-child {
+      border-bottom: none;
+    }
+  }
+
+  .activity-dot {
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    background: #409eff;
+    margin-top: 6px;
+    margin-right: 12px;
+    flex-shrink: 0;
+
+    &.notice {
+      background: #e6a23c;
+    }
+  }
+
+  .activity-content {
+    flex: 1;
+  }
+
+  .activity-title {
+    font-size: 14px;
+    color: #303133;
+    margin-bottom: 4px;
+  }
+
+  .activity-time {
+    font-size: 12px;
+    color: #909399;
+  }
+}
+
+@media (max-width: 768px) {
+  .dashboard-container {
+    padding: 16px;
+  }
+
+  .stats-grid {
+    grid-template-columns: 1fr;
+    gap: 16px;
+  }
 
-  .update-log {
-    ol {
-      display: block;
-      list-style-type: decimal;
-      margin-block-start: 1em;
-      margin-block-end: 1em;
-      margin-inline-start: 0;
-      margin-inline-end: 0;
-      padding-inline-start: 40px;
+  .quick-actions {
+    .action-btn {
+      min-width: 100px;
     }
   }
 }