Selaa lähdekoodia

调整首页数据看板页面样式布局

yawuga 7 kuukautta sitten
vanhempi
sitoutus
0f3815a76b
2 muutettua tiedostoa jossa 818 lisäystä ja 503 poistoa
  1. 20 4
      src/layout/index.vue
  2. 798 499
      src/views/index.vue

+ 20 - 4
src/layout/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
     <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
-    <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
-    <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
-      <div :class="{'fixed-header':fixedHeader}">
+    <sidebar v-if="!sidebar.hide && !isFullscreenMode" class="sidebar-container"/>
+    <div :class="{hasTagsView:needTagsView && !isFullscreenMode,sidebarHide:sidebar.hide || isFullscreenMode, fullscreenContainer: isFullscreenMode}" class="main-container">
+      <div v-if="!isFullscreenMode" :class="{'fixed-header':fixedHeader}">
         <navbar @setLayout="setLayout"/>
         <tags-view v-if="needTagsView"/>
       </div>
@@ -38,12 +38,16 @@ export default {
       needTagsView: state => state.settings.tagsView,
       fixedHeader: state => state.settings.fixedHeader
     }),
+    isFullscreenMode() {
+      return this.$route.query.fullscreen === 'true'
+    },
     classObj() {
       return {
         hideSidebar: !this.sidebar.opened,
         openSidebar: this.sidebar.opened,
         withoutAnimation: this.sidebar.withoutAnimation,
-        mobile: this.device === 'mobile'
+        mobile: this.device === 'mobile',
+        fullscreenMode: this.isFullscreenMode
       }
     },
     variables() {
@@ -107,4 +111,16 @@ export default {
   .mobile .fixed-header {
     width: 100%;
   }
+
+  .fullscreenMode {
+    .main-container.fullscreenContainer {
+      margin-left: 0 !important;
+      width: 100% !important;
+    }
+  }
+
+  .fullscreenContainer {
+    margin-left: 0;
+    width: 100%;
+  }
 </style>

+ 798 - 499
src/views/index.vue

@@ -1,212 +1,239 @@
 <template>
-  <div class="dashboard-container">
-    <!-- 页面头部 -->
+  <div class="cockpit-dashboard" :class="{ 'fullscreen-mode': isFullscreenMode }">
+    <!-- 顶部区域 -->
     <header class="dashboard-header">
-      <div class="title-section">
-        <h1 class="dashboard-title">智慧农业数据看板</h1>
-        <p class="dashboard-subtitle">{{ getCurrentFarmDescription() }}</p>
+      <div class="header-left">
+        <div class="title-section">
+          <h1 class="dashboard-title">智慧农业驾驶舱</h1>
+          <p class="dashboard-subtitle">{{ getCurrentFarmDescription() }}</p>
+        </div>
       </div>
-      <div class="action-buttons">
-        <div class="location-selector-group">
-          <el-cascader
-            v-model="selectedLocation"
-            :options="locationOptions"
-            :props="cascaderProps"
-            size="medium"
-            style="width: 240px"
-            placeholder="请选择农场或地块"
-            clearable>
-          </el-cascader>
+      
+      <div class="header-right">
+        <div class="action-buttons">
+          <div class="location-selector-group">
+            <el-cascader
+              v-model="selectedLocation"
+              :options="locationOptions"
+              :props="cascaderProps"
+              size="small"
+              style="width: 200px"
+              placeholder="选择农场/地块"
+              clearable>
+            </el-cascader>
+            <el-button 
+              icon="el-icon-check" 
+              type="primary" 
+              size="small"
+              class="btn-confirm"
+              @click="confirmLocationChange"
+              :disabled="!hasLocationChanged">
+              确认
+            </el-button>
+          </div>
           <el-button 
-            icon="el-icon-check" 
-            type="primary" 
-            size="medium" 
-            @click="confirmLocationChange"
-            :disabled="!hasLocationChanged">
-            确认
+            icon="el-icon-refresh" 
+            type="success" 
+            size="small"
+            class="btn-refresh"
+            @click="refreshData">
+            刷新
           </el-button>
           <el-button 
-            icon="el-icon-close" 
-            size="medium" 
-            @click="clearLocation">
-            清空
+            icon="el-icon-full-screen" 
+            type="warning" 
+            size="small"
+            class="btn-fullscreen"
+            @click="openFullscreenCockpit">
+            全屏驾驶舱
           </el-button>
         </div>
-        <el-button icon="el-icon-refresh" type="success" size="medium" @click="refreshData">
-          刷新数据
-        </el-button>
-        <el-button icon="el-icon-monitor" type="warning" size="medium" @click="goToDigitalDashboard" style="font-weight: bold;">
-          🚀 农业数字化决策大屏
-        </el-button>
       </div>
     </header>
 
-    <!-- 数据概览卡片 -->
-    <div class="overview-section">
-      <div class="overview-grid">
-        <div class="overview-card" v-for="(item, index) in overviewData" :key="index">
-          <div class="card-icon" :style="{ backgroundColor: item.color }">
-            <i :class="item.icon"></i>
+    <!-- 主体区域 -->
+    <div class="dashboard-body">
+      <!-- 左侧面板 -->
+      <div class="dashboard-left">
+        <!-- 农机数量统计 -->
+        <div class="panel-card">
+          <div class="panel-header">
+            <h3 class="panel-title">葡萄生长状况</h3>
+            <el-radio-group v-model="cropTimeRange" size="mini">
+              <el-radio-button label="week">本周</el-radio-button>
+              <el-radio-button label="month">本月</el-radio-button>
+              <el-radio-button label="season">本季</el-radio-button>
+            </el-radio-group>
           </div>
-          <div class="card-content">
-            <div class="card-value">{{ item.value }}</div>
-            <div class="card-label">{{ item.label }}</div>
-            <div class="card-change" :class="item.trend">
-              <i :class="item.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom'"></i>
-              {{ item.change }}
+          <div class="panel-content">
+            <div class="chart-wrapper">
+              <div id="cropStatusChart"></div>
+            </div>
+            <div class="chart-legend-mini">
+              <div class="legend-item-mini" v-for="item in getCurrentCropLegend()" :key="item.name">
+                <span class="legend-dot" :style="{ background: item.color }"></span>
+                <span class="legend-text">{{ item.name }} ({{ item.value }}亩)</span>
+              </div>
             </div>
           </div>
         </div>
-      </div>
-    </div>
-
-    <!-- 主要内容区域 -->
-    <div class="main-content">
-      <!-- 农场分布地图 -->
-      <div class="content-section">
-        <div class="section-header">
-          <h2 class="section-title">农场分布图</h2>
-        </div>
-        <div class="map-container">
-          <div id="farmMap"></div>
-        </div>
-      </div>
 
-      <!-- 环境监测区域 -->
-      <div class="content-section">
-        <div class="section-header">
-          <h2 class="section-title">环境监测</h2>
-        </div>
-        
-        <div class="environment-grid">
-          <div class="env-card">
-            <div class="env-header">
-              <span class="env-title">温度监测</span>
-              <span class="env-value">26.5°C</span>
-            </div>
-            <div class="env-chart" id="temperatureChart"></div>
-            <div class="env-status normal">正常</div>
-          </div>
-          
-          <div class="env-card">
-            <div class="env-header">
-              <span class="env-title">湿度监测</span>
-              <span class="env-value">68%</span>
+        <!-- 设备运行状态 -->
+        <div class="panel-card">
+          <div class="panel-header">
+            <h3 class="panel-title">设备运行状态</h3>
+            <div class="device-summary-mini">
+              <span>总: {{ deviceStats.total }}</span>
+              <span class="online-text">在线: {{ deviceStats.online }}</span>
             </div>
-            <div class="env-chart" id="humidityChart"></div>
-            <div class="env-status normal">正常</div>
           </div>
-          
-          <div class="env-card">
-            <div class="env-header">
-              <span class="env-title">土壤监测</span>
-              <span class="env-value">良好</span>
+          <div class="panel-content">
+            <div class="chart-wrapper">
+              <div id="deviceStatusChart"></div>
             </div>
-            <div class="env-chart" id="soilChart"></div>
-            <div class="env-status good">良好</div>
-          </div>
-          
-          <div class="env-card">
-            <div class="env-header">
-              <span class="env-title">光照监测</span>
-              <span class="env-value">85%</span>
+            <div class="device-stats-mini">
+              <div class="stat-item">
+                <span class="stat-label">在线率</span>
+                <span class="stat-value success">{{ Math.round(deviceStats.online / deviceStats.total * 100) }}%</span>
+              </div>
+              <div class="stat-item">
+                <span class="stat-label">离线</span>
+                <span class="stat-value danger">{{ deviceStats.offline }}台</span>
+              </div>
             </div>
-            <div class="env-chart" id="lightChart"></div>
-            <div class="env-status normal">正常</div>
           </div>
         </div>
-      </div>
 
-      <!-- 葡萄与设备状态 -->
-      <div class="content-row">
-        <div class="content-card half-width">
-          <div class="card-header">
-            <h3 class="card-title">葡萄生长状况</h3>
-            <div class="time-range">
-              <el-radio-group v-model="cropTimeRange" size="mini">
-                <el-radio-button label="week">本周</el-radio-button>
-                <el-radio-button label="month">本月</el-radio-button>
-                <el-radio-button label="season">本季</el-radio-button>
-              </el-radio-group>
-            </div>
-          </div>
-          <div class="chart-container">
-            <div id="cropStatusChart"></div>
+        <!-- 环境监测 -->
+        <div class="panel-card">
+          <div class="panel-header">
+            <h3 class="panel-title">环境监测</h3>
           </div>
-          <div class="chart-legend">
-            <div class="legend-item" v-for="item in getCurrentCropLegend()" :key="item.name">
-              <span class="legend-color" :style="{ background: item.color }"></span>
-              {{ item.name }} ({{ item.value }}亩)
+          <div class="panel-content">
+            <div class="env-grid-mini">
+              <div class="env-item">
+                <div class="env-name">温度</div>
+                <div class="env-value-text">26.5°C</div>
+                <div class="env-chart-mini" id="temperatureChart"></div>
+              </div>
+              <div class="env-item">
+                <div class="env-name">湿度</div>
+                <div class="env-value-text">68%</div>
+                <div class="env-chart-mini" id="humidityChart"></div>
+              </div>
+              <div class="env-item">
+                <div class="env-name">土壤</div>
+                <div class="env-value-text">良好</div>
+                <div class="env-chart-mini" id="soilChart"></div>
+              </div>
+              <div class="env-item">
+                <div class="env-name">光照</div>
+                <div class="env-value-text">85%</div>
+                <div class="env-chart-mini" id="lightChart"></div>
+              </div>
             </div>
           </div>
         </div>
-        
-        <div class="content-card half-width">
-          <div class="card-header">
-            <h3 class="card-title">设备运行状态</h3>
-            <div class="device-summary">
-              <span class="device-count">总设备: {{ deviceStats.total }}</span>
-              <span class="device-online">在线: {{ deviceStats.online }}</span>
-            </div>
-          </div>
-          <div class="chart-container">
-            <div id="deviceStatusChart"></div>
+      </div>
+
+      <!-- 中央地图区域 -->
+      <div class="dashboard-center">
+        <div class="map-wrapper">
+          <div class="map-header">
+            <h3 class="map-title">农场地图</h3>
           </div>
-          <div class="device-stats">
-            <div class="stats-item">
-              <span class="stats-label">在线率</span>
-              <span class="stats-value">{{ Math.round(deviceStats.online / deviceStats.total * 100) }}%</span>
-            </div>
-            <div class="stats-item">
-              <span class="stats-label">离线设备</span>
-              <span class="stats-value offline">{{ deviceStats.offline }}</span>
-            </div>
+          <div class="map-container-full">
+            <div id="farmMap"></div>
           </div>
         </div>
       </div>
 
-      <!-- 生产数据与告警信息 -->
-      <div class="content-row">
-        <div class="content-card half-width">
-          <div class="card-header">
-            <h3 class="card-title">生产数据统计</h3>
-            <div class="time-range">
-              <el-radio-group v-model="productionTimeRange" size="mini">
-                <el-radio-button label="month">本月</el-radio-button>
-                <el-radio-button label="quarter">本季</el-radio-button>
-                <el-radio-button label="year">本年</el-radio-button>
-              </el-radio-group>
-            </div>
+      <!-- 右侧面板 -->
+      <div class="dashboard-right">
+        <!-- 生产数据统计 -->
+        <div class="panel-card">
+          <div class="panel-header">
+            <h3 class="panel-title">生产数据统计</h3>
+            <el-radio-group v-model="productionTimeRange" size="mini">
+              <el-radio-button label="month">月</el-radio-button>
+              <el-radio-button label="quarter">季</el-radio-button>
+              <el-radio-button label="year">年</el-radio-button>
+            </el-radio-group>
           </div>
-          <div class="chart-container">
-            <div id="productionChart"></div>
+          <div class="panel-content">
+            <div class="chart-wrapper">
+              <div id="productionChart"></div>
+            </div>
           </div>
         </div>
-        
-        <div class="content-card half-width">
-          <div class="card-header">
-            <h3 class="card-title">系统告警</h3>
-            <el-badge :value="alertCount" class="alert-badge" type="warning">
-              <span class="alert-text">待处理告警</span>
+
+        <!-- 系统告警 -->
+        <div class="panel-card">
+          <div class="panel-header">
+            <h3 class="panel-title">系统告警</h3>
+            <el-badge :value="alertCount" class="badge-mini" type="danger">
+              <span class="badge-text">待处理</span>
             </el-badge>
           </div>
-          <div class="alert-list">
-            <div class="alert-item" v-for="alert in alertList" :key="alert.id" :class="alert.level">
-              <div class="alert-icon">
-                <i :class="getAlertIcon(alert.level)"></i>
+          <div class="panel-content">
+            <div class="alert-list-mini">
+              <div class="alert-item-mini" v-for="alert in alertList" :key="alert.id" :class="alert.level">
+                <div class="alert-icon-mini">
+                  <i :class="getAlertIcon(alert.level)"></i>
+                </div>
+                <div class="alert-info">
+                  <div class="alert-title-mini">{{ alert.title }}</div>
+                  <div class="alert-time-mini">{{ alert.time }}</div>
+                </div>
+                <div class="alert-status-mini" :class="alert.status">
+                  {{ getAlertStatusText(alert.status) }}
+                </div>
               </div>
-              <div class="alert-content">
-                <div class="alert-title">{{ alert.title }}</div>
-                <div class="alert-time">{{ alert.time }}</div>
+            </div>
+          </div>
+        </div>
+
+        <!-- 农事任务执行进度 -->
+        <div class="panel-card">
+          <div class="panel-header">
+            <h3 class="panel-title">农事任务执行进度</h3>
+          </div>
+          <div class="panel-content">
+            <div class="task-progress-wrapper">
+              <div class="task-chart-container">
+                <div id="taskProgressChart"></div>
               </div>
-              <div class="alert-status" :class="alert.status">
-                {{ getAlertStatusText(alert.status) }}
+              <div class="task-stats-grid">
+                <div class="task-stat-item">
+                  <div class="stat-value total">{{ taskStats.total }}</div>
+                  <div class="stat-label">总任务数</div>
+                </div>
+                <div class="task-stat-item">
+                  <div class="stat-value completed">{{ taskStats.completed }}</div>
+                  <div class="stat-label">已完成</div>
+                </div>
+                <div class="task-stat-item">
+                  <div class="stat-value pending">{{ taskStats.pending }}</div>
+                  <div class="stat-label">待执行</div>
+                </div>
               </div>
             </div>
           </div>
         </div>
       </div>
-
+    </div>
+    
+    <!-- 底部汇总数据卡片 - 浮在地图上方 -->
+    <div class="dashboard-summary-bottom">
+      <div class="overview-card-mini" v-for="(item, index) in overviewData" :key="index">
+        <div class="card-icon-mini" :style="{ backgroundColor: item.color }">
+          <i :class="item.icon"></i>
+        </div>
+        <div class="card-info">
+          <div class="card-value-mini">{{ item.value }}</div>
+          <div class="card-label-mini">{{ item.label }}</div>
+        </div>
+      </div>
     </div>
   </div>
 </template>
@@ -225,6 +252,17 @@ export default {
 
       alertCount: 5,
       
+      // 农事任务统计数据
+      taskStats: {
+        total: 12,        // 总任务数
+        completed: 9,     // 已完成
+        pending: 3,       // 待执行
+        completionRate: 75 // 完成率
+      },
+      
+      // 全屏模式标志
+      isFullscreenMode: false,
+      
       // 级联选择器配置
       cascaderProps: {
         checkStrictly: true, // 允许选择任意一级
@@ -373,6 +411,9 @@ export default {
     // 初始化确认的位置为默认状态(全部农场)
     this.confirmedLocation = [];
     
+    // 检测是否为全屏模式
+    this.isFullscreenMode = this.$route.query.fullscreen === 'true';
+    
     this.$nextTick(() => {
       // 等待页面完全渲染后再初始化图表
       this.waitForElementsAndInit();
@@ -435,6 +476,14 @@ export default {
       window.open(`${baseUrl}/agri-digital/dashboard`, '_blank');
     },
     
+    openFullscreenCockpit() {
+      // 打开全屏驾驶舱
+      const baseUrl = window.location.origin;
+      const currentPath = this.$route.path;
+      // 添加 fullscreen=true 参数
+      window.open(`${baseUrl}${currentPath}?fullscreen=true`, '_blank');
+    },
+    
     getCurrentFarmDescription() {
       const currentSelection = this.getCurrentSelection();
       
@@ -873,6 +922,7 @@ export default {
       // 初始化其他图表
       this.initEnvironmentCharts();
       this.initProductionChart();
+      this.initTaskProgressChart();
       this.initFarmMap();
     },
     
@@ -921,6 +971,7 @@ export default {
       this.initCropStatusChart();
       this.initDeviceStatusChart();
       this.initProductionChart();
+      this.initTaskProgressChart();
       this.initFarmMap();
       
       console.log('Charts initialization completed');
@@ -1170,6 +1221,73 @@ export default {
       });
     },
     
+    initTaskProgressChart() {
+      const chartElement = document.getElementById('taskProgressChart');
+      if (!chartElement) {
+        console.error('taskProgressChart element not found');
+        return;
+      }
+      
+      const chart = this.$echarts.init(chartElement);
+      chart.setOption({
+        tooltip: {
+          trigger: 'item',
+          formatter: '{b}: {c}个 ({d}%)'
+        },
+        legend: {
+          show: false
+        },
+        series: [{
+          name: '任务进度',
+          type: 'pie',
+          radius: ['50%', '75%'],
+          center: ['50%', '50%'],
+          avoidLabelOverlap: false,
+          label: {
+            show: true,
+            position: 'center',
+            formatter: '{d}%',
+            fontSize: 24,
+            fontWeight: 'bold',
+            color: '#52c41a'
+          },
+          emphasis: {
+            label: {
+              show: true,
+              fontSize: 28,
+              fontWeight: 'bold'
+            }
+          },
+          labelLine: {
+            show: false
+          },
+          data: [
+            { 
+              value: this.taskStats.completed, 
+              name: '已完成', 
+              itemStyle: { 
+                color: {
+                  type: 'linear',
+                  x: 0, y: 0, x2: 0, y2: 1,
+                  colorStops: [
+                    { offset: 0, color: '#52c41a' },
+                    { offset: 1, color: '#73d13d' }
+                  ]
+                }
+              }
+            },
+            { 
+              value: this.taskStats.pending, 
+              name: '待执行', 
+              itemStyle: { 
+                color: 'rgba(255, 255, 255, 0.15)'
+              }
+            }
+          ]
+        }]
+      });
+    },
+    
     initFarmMap() {
       const mapElement = document.getElementById('farmMap');
       if (!mapElement) {
@@ -1185,13 +1303,20 @@ export default {
       }
       
       try {
-        // 初始化高德地图
+        // 初始化高德地图 - 使用纯卫星影像图层(无路网)
+        // 图层说明:
+        // - TileLayer.Satellite: 卫星影像底图(纯影像,无道路标注)
+        // 如需添加路网图层,可添加: new AMap.TileLayer.RoadNet()
+        // 如需切换回矢量地图,可使用 mapStyle: 'amap://styles/whitesmoke' 并移除 layers 配置
         this.farmMap = new AMap.Map('farmMap', {
           zoom: 10,
           center: [117.015029, 34.197274], // 默认中心点
-          mapStyle: 'amap://styles/whitesmoke', // 清新风格
           viewMode: '2D',
-          resizeEnable: true
+          resizeEnable: true,
+          layers: [
+            new AMap.TileLayer.Satellite()  // 卫星影像底图(纯影像)
+            // new AMap.TileLayer.RoadNet() // 路网图层(已注释,如需显示道路名称可取消注释)
+          ]
         });
         
         // 等待地图加载完成
@@ -2472,480 +2597,654 @@ export default {
 </script>
 
 <style scoped lang="scss">
-.dashboard-container {
-  padding: 24px;
-  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-  min-height: 100vh;
+// ============ 驾驶舱整体布局 ============
+.cockpit-dashboard {
+  width: 100%;
+  height: 100vh;
+  overflow: hidden;
+  background: #001528;
+  display: flex;
+  flex-direction: column;
+  color: #fff;
+  
+  &.fullscreen-mode {
+    // 全屏模式下可以进一步定制样式
+    .dashboard-header {
+      height: 80px;
+    }
+  }
 }
 
+// ============ 头部区域 ============
 .dashboard-header {
+  height: 100px;
+  background: linear-gradient(180deg, #002140 0%, #001528 100%);
+  border-bottom: 2px solid rgba(24, 144, 255, 0.3);
   display: flex;
-  justify-content: space-between;
-  align-items: flex-start;
-  margin-bottom: 32px;
+  align-items: center;
+  padding: 0 20px;
+  gap: 20px;
+  flex-shrink: 0;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
   
-  .title-section {
-    .dashboard-title {
-      font-size: 32px;
-      font-weight: 700;
-      color: #1f2937;
-      margin: 0 0 8px 0;
-      background: linear-gradient(135deg, #10b981, #059669);
-      -webkit-background-clip: text;
-      -webkit-text-fill-color: transparent;
-      background-clip: text;
-    }
+  .header-left {
+    flex: 1;
     
-    .dashboard-subtitle {
-      font-size: 16px;
-      color: #6b7280;
-      margin: 0;
+    .title-section {
+      .dashboard-title {
+        font-size: 24px;
+        font-weight: 700;
+        color: #fff;
+        margin: 0 0 4px 0;
+        background: linear-gradient(135deg, #1890ff, #36cfc9);
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+        background-clip: text;
+        text-shadow: 0 0 20px rgba(24, 144, 255, 0.5);
+      }
+      
+      .dashboard-subtitle {
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.65);
+        margin: 0;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
     }
   }
   
-  .action-buttons {
-    display: flex;
-    gap: 12px;
-    align-items: center;
+  .header-right {
+    flex: 0 0 auto;
     
-    .location-selector-group {
+    .action-buttons {
       display: flex;
       gap: 8px;
       align-items: center;
-      padding: 8px;
-      background: #f8fafc;
-      border-radius: 8px;
-      border: 1px solid #e5e7eb;
       
-      .el-cascader {
-        background: white;
+      .location-selector-group {
+        display: flex;
+        gap: 6px;
+        align-items: center;
+        padding: 6px 10px;
+        background: rgba(24, 144, 255, 0.08);
+        border-radius: 6px;
+        border: 1px solid rgba(24, 144, 255, 0.3);
       }
-    }
-  }
-}
-
-.overview-section {
-  margin-bottom: 32px;
-  
-  .overview-grid {
-    display: grid;
-    grid-template-columns: repeat(4, 1fr);
-    gap: 24px;
-  }
-  
-  .overview-card {
-    background: white;
-    border-radius: 16px;
-    padding: 24px;
-    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
-    transition: all 0.3s ease;
-    border: 1px solid #e5e7eb;
-    
-    &:hover {
-      transform: translateY(-4px);
-      box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.15);
-    }
-    
-    display: flex;
-    align-items: center;
-    gap: 16px;
-    
-    .card-icon {
-      width: 64px;
-      height: 64px;
-      border-radius: 16px;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      color: white;
-      font-size: 24px;
-    }
-    
-    .card-content {
-      flex: 1;
       
-      .card-value {
-        font-size: 28px;
-        font-weight: 700;
-        color: #1f2937;
-        line-height: 1;
-        margin-bottom: 4px;
+      // ============ 自定义按钮样式 ============
+      
+      // 确认按钮 - 青绿色
+      .btn-confirm {
+        background: #00C48F !important;
+        border-color: #00C48F !important;
+        color: #ffffff !important;
+        border-radius: 6px;
+        font-weight: 500;
+        transition: all 0.3s ease;
+        
+        &:hover:not(:disabled) {
+          background: #00E5A0 !important;
+          border-color: #00E5A0 !important;
+          box-shadow: 0 0 12px rgba(0, 196, 143, 0.5);
+          transform: translateY(-1px);
+        }
+        
+        &:active:not(:disabled) {
+          transform: translateY(0);
+        }
+        
+        &:disabled {
+          background: rgba(0, 196, 143, 0.3) !important;
+          border-color: rgba(0, 196, 143, 0.3) !important;
+          color: rgba(255, 255, 255, 0.5) !important;
+          cursor: not-allowed;
+        }
       }
       
-      .card-label {
-        font-size: 14px;
-        color: #6b7280;
-        margin-bottom: 8px;
+      // 刷新按钮 - 科技蓝
+      .btn-refresh {
+        background: #409EFF !important;
+        border-color: #409EFF !important;
+        color: #ffffff !important;
+        border-radius: 6px;
+        font-weight: 500;
+        transition: all 0.3s ease;
+        
+        &:hover {
+          background: #66b1ff !important;
+          border-color: #66b1ff !important;
+          box-shadow: 0 0 12px rgba(64, 158, 255, 0.5);
+          transform: translateY(-1px);
+        }
+        
+        &:active {
+          transform: translateY(0);
+        }
       }
       
-      .card-change {
-        font-size: 12px;
-        font-weight: 600;
-        display: flex;
-        align-items: center;
-        gap: 4px;
+      // 全屏驾驶舱按钮 - 高亮蓝色
+      .btn-fullscreen {
+        background: linear-gradient(135deg, #2E65F3 0%, #00A6FF 100%) !important;
+        border-color: transparent !important;
+        color: #ffffff !important;
+        border-radius: 6px;
+        font-weight: 500;
+        transition: all 0.3s ease;
+        box-shadow: 0 2px 8px rgba(46, 101, 243, 0.3);
         
-        &.up {
-          color: #10b981;
+        &:hover {
+          background: linear-gradient(135deg, #4578ff 0%, #1eb8ff 100%) !important;
+          box-shadow: 0 4px 16px rgba(46, 101, 243, 0.6);
+          transform: translateY(-1px);
         }
         
-        &.down {
-          color: #ef4444;
+        &:active {
+          transform: translateY(0);
         }
       }
     }
   }
 }
 
-.main-content {
-  .content-section {
-    margin-bottom: 32px;
+// ============ 主体区域 ============
+.dashboard-body {
+  flex: 1;
+  display: flex;
+  gap: 12px;
+  padding: 12px;
+  overflow: hidden;
+  
+  // 左侧面板
+  .dashboard-left {
+    width: 320px;
+    flex-shrink: 0;
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+    overflow-y: auto;
     
-    .section-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 20px;
-      
-      .section-title {
-        font-size: 20px;
-        font-weight: 600;
-        color: #1f2937;
-        margin: 0;
-      }
+    &::-webkit-scrollbar {
+      width: 4px;
+    }
+    
+    &::-webkit-scrollbar-thumb {
+      background: rgba(24, 144, 255, 0.3);
+      border-radius: 2px;
     }
   }
   
-  .content-row {
-    display: grid;
-    grid-template-columns: 1fr 1fr;
-    gap: 24px;
-    margin-bottom: 32px;
+  // 中央地图区域
+  .dashboard-center {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
   }
   
-  .content-card {
-    background: white;
-    border-radius: 16px;
-    padding: 24px;
-    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
-    border: 1px solid #e5e7eb;
-    
-    &.half-width {
-      width: 100%;
+  // 右侧面板
+  .dashboard-right {
+    width: 320px;
+    flex-shrink: 0;
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+    overflow-y: auto;
+    
+    &::-webkit-scrollbar {
+      width: 4px;
+    }
+    
+    &::-webkit-scrollbar-thumb {
+      background: rgba(24, 144, 255, 0.3);
+      border-radius: 2px;
+    }
+  }
+}
+
+// ============ 面板卡片通用样式 ============
+.panel-card {
+  background: rgba(0, 33, 64, 0.6);
+  border: 1px solid rgba(24, 144, 255, 0.3);
+  border-radius: 8px;
+  overflow: hidden;
+  backdrop-filter: blur(10px);
+  
+  .panel-header {
+    background: rgba(24, 144, 255, 0.1);
+    border-bottom: 1px solid rgba(24, 144, 255, 0.3);
+    padding: 10px 16px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    
+    .panel-title {
+      font-size: 14px;
+      font-weight: 600;
+      color: #1890ff;
+      margin: 0;
+      text-shadow: 0 0 10px rgba(24, 144, 255, 0.5);
     }
     
-    .card-header {
+    .device-summary-mini {
+      font-size: 11px;
+      color: rgba(255, 255, 255, 0.65);
       display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 20px;
-      
-      .card-title {
-        font-size: 18px;
-        font-weight: 600;
-        color: #1f2937;
-        margin: 0;
-      }
+      gap: 8px;
       
-      .device-summary {
-        display: flex;
-        gap: 16px;
-        font-size: 14px;
-        
-        .device-count {
-          color: #6b7280;
-        }
-        
-        .device-online {
-          color: #10b981;
-          font-weight: 600;
-        }
+      .online-text {
+        color: #52c41a;
       }
     }
+  }
+  
+  .panel-content {
+    padding: 12px;
+  }
+}
+
+// ============ 图表容器 ============
+.chart-wrapper {
+  height: 180px;
+  width: 100%;
+  
+  #cropStatusChart,
+  #deviceStatusChart,
+  #productionChart {
+    width: 100% !important;
+    height: 100% !important;
+  }
+}
+
+.chart-legend-mini {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 8px;
+  margin-top: 10px;
+  
+  .legend-item-mini {
+    display: flex;
+    align-items: center;
+    gap: 6px;
+    font-size: 11px;
+    color: rgba(255, 255, 255, 0.85);
+    
+    .legend-dot {
+      width: 8px;
+      height: 8px;
+      border-radius: 50%;
+      flex-shrink: 0;
+    }
     
-    .chart-container {
-      height: 300px;
-      width: 100%;
-      min-height: 300px;
-      
-      #cropStatusChart,
-      #deviceStatusChart,
-      #productionChart {
-        width: 100% !important;
-        height: 100% !important;
-        min-height: 300px;
-      }
+    .legend-text {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
     }
   }
 }
 
-.environment-grid {
-  display: grid;
-  grid-template-columns: repeat(4, 1fr);
-  gap: 20px;
+// 设备统计
+.device-stats-mini {
+  display: flex;
+  justify-content: space-around;
+  margin-top: 10px;
+  padding-top: 10px;
+  border-top: 1px solid rgba(24, 144, 255, 0.2);
   
-  .env-card {
-    background: white;
-    border-radius: 12px;
-    padding: 20px;
-    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-    border: 1px solid #e5e7eb;
-    
-    .env-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 16px;
+  .stat-item {
+    text-align: center;
+    
+    .stat-label {
+      display: block;
+      font-size: 11px;
+      color: rgba(255, 255, 255, 0.65);
+      margin-bottom: 4px;
+    }
+    
+    .stat-value {
+      font-size: 16px;
+      font-weight: 600;
       
-      .env-title {
-        font-size: 14px;
-        color: #6b7280;
-        font-weight: 500;
+      &.success {
+        color: #52c41a;
       }
       
-      .env-value {
-        font-size: 20px;
-        font-weight: 700;
-        color: #1f2937;
+      &.danger {
+        color: #ff4d4f;
       }
     }
+  }
+}
+
+// 环境监测网格
+.env-grid-mini {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 10px;
+  
+  .env-item {
+    background: rgba(24, 144, 255, 0.05);
+    border: 1px solid rgba(24, 144, 255, 0.2);
+    border-radius: 6px;
+    padding: 10px;
+    text-align: center;
     
-    .env-chart {
-      height: 80px;
-      margin-bottom: 16px;
+    .env-name {
+      font-size: 11px;
+      color: rgba(255, 255, 255, 0.65);
+      margin-bottom: 4px;
     }
     
-    .env-status {
-      text-align: center;
-      padding: 6px 12px;
-      border-radius: 20px;
-      font-size: 12px;
+    .env-value-text {
+      font-size: 14px;
       font-weight: 600;
-      
-      &.normal {
-        background: #d1fae5;
-        color: #065f46;
-      }
-      
-      &.good {
-        background: #dbeafe;
-        color: #1e40af;
-      }
-      
-      &.warning {
-        background: #fef3c7;
-        color: #92400e;
-      }
+      color: #1890ff;
+      margin-bottom: 6px;
+    }
+    
+    .env-chart-mini {
+      height: 40px;
+      width: 100%;
     }
   }
 }
 
-.alert-list {
-  max-height: 300px;
+// ============ 告警列表 ============
+.alert-list-mini {
+  max-height: 320px;
   overflow-y: auto;
   
-  .alert-item {
+  &::-webkit-scrollbar {
+    width: 4px;
+  }
+  
+  &::-webkit-scrollbar-thumb {
+    background: rgba(24, 144, 255, 0.3);
+    border-radius: 2px;
+  }
+  
+  .alert-item-mini {
     display: flex;
     align-items: center;
-    gap: 12px;
-    padding: 16px;
-    border-bottom: 1px solid #f3f4f6;
+    gap: 10px;
+    padding: 10px;
+    border-bottom: 1px solid rgba(24, 144, 255, 0.1);
     transition: background-color 0.2s;
     
     &:hover {
-      background: #f9fafb;
+      background: rgba(24, 144, 255, 0.08);
     }
     
     &:last-child {
       border-bottom: none;
     }
     
-    .alert-icon {
-      width: 32px;
-      height: 32px;
-      border-radius: 8px;
+    .alert-icon-mini {
+      width: 28px;
+      height: 28px;
+      border-radius: 6px;
       display: flex;
       align-items: center;
       justify-content: center;
+      font-size: 14px;
       color: white;
+      flex-shrink: 0;
     }
     
-    &.warning .alert-icon {
-      background: #f59e0b;
+    &.warning .alert-icon-mini {
+      background: #faad14;
     }
     
-    &.error .alert-icon {
-      background: #ef4444;
+    &.error .alert-icon-mini {
+      background: #ff4d4f;
     }
     
-    &.info .alert-icon {
-      background: #3b82f6;
+    &.info .alert-icon-mini {
+      background: #1890ff;
     }
     
-    .alert-content {
+    .alert-info {
       flex: 1;
+      min-width: 0;
       
-      .alert-title {
-        font-size: 14px;
-        color: #1f2937;
+      .alert-title-mini {
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.85);
         font-weight: 500;
-        margin-bottom: 4px;
+        margin-bottom: 2px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
       }
       
-      .alert-time {
-        font-size: 12px;
-        color: #6b7280;
+      .alert-time-mini {
+        font-size: 10px;
+        color: rgba(255, 255, 255, 0.45);
       }
     }
     
-    .alert-status {
-      font-size: 12px;
-      padding: 4px 8px;
-      border-radius: 12px;
+    .alert-status-mini {
+      font-size: 10px;
+      padding: 2px 6px;
+      border-radius: 10px;
       font-weight: 500;
+      flex-shrink: 0;
       
       &.pending {
-        background: #fef3c7;
-        color: #92400e;
+        background: rgba(250, 173, 20, 0.2);
+        color: #faad14;
       }
       
       &.processing {
-        background: #dbeafe;
-        color: #1e40af;
+        background: rgba(24, 144, 255, 0.2);
+        color: #1890ff;
       }
       
       &.resolved {
-        background: #d1fae5;
-        color: #065f46;
+        background: rgba(82, 196, 26, 0.2);
+        color: #52c41a;
       }
     }
   }
 }
 
-.map-container {
-  background: white;
-  border-radius: 16px;
-  padding: 24px;
-  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
-  border: 1px solid #e5e7eb;
-  height: 400px;
-  
-  #farmMap {
-    width: 100%;
-    height: 100%;
+.badge-mini {
+  .badge-text {
+    color: rgba(255, 255, 255, 0.65);
+    font-size: 11px;
   }
 }
 
-.chart-legend {
+// ============ 地图区域 ============
+.map-wrapper {
+  height: 100%;
   display: flex;
-  flex-wrap: wrap;
-  gap: 16px;
-  margin-top: 16px;
-  justify-content: center;
+  flex-direction: column;
+  background: rgba(0, 33, 64, 0.6);
+  border: 1px solid rgba(24, 144, 255, 0.3);
+  border-radius: 8px;
+  overflow: hidden;
+  backdrop-filter: blur(10px);
   
-  .legend-item {
-    display: flex;
-    align-items: center;
-    gap: 6px;
-    font-size: 12px;
-    color: #6b7280;
+  .map-header {
+    background: rgba(24, 144, 255, 0.1);
+    border-bottom: 1px solid rgba(24, 144, 255, 0.3);
+    padding: 10px 16px;
     
-    .legend-color {
-      width: 12px;
-      height: 12px;
-      border-radius: 2px;
+    .map-title {
+      font-size: 14px;
+      font-weight: 600;
+      color: #1890ff;
+      margin: 0;
+      text-shadow: 0 0 10px rgba(24, 144, 255, 0.5);
+    }
+  }
+  
+  .map-container-full {
+    flex: 1;
+    position: relative;
+    overflow: hidden;
+    
+    #farmMap {
+      width: 100%;
+      height: 100%;
+      background: #0a1929;
     }
   }
 }
 
-.device-stats {
+// ============ 底部汇总数据卡片 ============
+.dashboard-summary-bottom {
+  position: absolute;
+  bottom: 24px;
+  left: 50%;
+  transform: translateX(-50%);
+  z-index: 2;
   display: flex;
-  justify-content: space-around;
-  margin-top: 16px;
-  padding-top: 16px;
-  border-top: 1px solid #f3f4f6;
+  gap: 16px;
+  max-width: calc(100% - 680px); // 左右各留出340px空间(面板320px + 间距20px)
+  pointer-events: auto;
   
-  .stats-item {
-    text-align: center;
+  .overview-card-mini {
+    background: rgba(0, 33, 64, 0.85);
+    backdrop-filter: blur(10px);
+    border: 1px solid rgba(24, 144, 255, 0.4);
+    border-radius: 10px;
+    padding: 14px 18px;
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    transition: all 0.3s ease;
+    min-width: 160px;
+    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
     
-    .stats-label {
-      display: block;
-      font-size: 12px;
-      color: #6b7280;
-      margin-bottom: 4px;
+    &:hover {
+      background: rgba(0, 33, 64, 0.95);
+      border-color: rgba(24, 144, 255, 0.6);
+      box-shadow: 0 6px 20px rgba(24, 144, 255, 0.4);
+      transform: translateY(-2px);
     }
     
-    .stats-value {
-      font-size: 18px;
-      font-weight: 600;
-      color: #10b981;
+    .card-icon-mini {
+      width: 44px;
+      height: 44px;
+      border-radius: 10px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 20px;
+      color: #fff;
+      flex-shrink: 0;
+    }
+    
+    .card-info {
+      flex: 1;
       
-      &.offline {
-        color: #ef4444;
+      .card-value-mini {
+        font-size: 22px;
+        font-weight: 700;
+        color: #fff;
+        line-height: 1;
+        margin-bottom: 4px;
+      }
+      
+      .card-label-mini {
+        font-size: 12px;
+        color: rgba(255, 255, 255, 0.75);
+        white-space: nowrap;
       }
     }
   }
 }
 
-.alert-badge {
-  .alert-text {
-    color: #6b7280;
-    font-size: 14px;
-  }
-}
-
-// 响应式设计
-@media (max-width: 1200px) {
-  .overview-grid {
-    grid-template-columns: repeat(2, 1fr);
-  }
-  
-  .environment-grid {
-    grid-template-columns: repeat(2, 1fr);
+// 响应式:小屏幕下调整卡片布局
+@media (max-width: 1400px) {
+  .dashboard-summary-bottom {
+    max-width: calc(100% - 100px);
+    flex-wrap: wrap;
+    justify-content: center;
+    
+    .overview-card-mini {
+      min-width: 140px;
+      padding: 12px 14px;
+      
+      .card-icon-mini {
+        width: 38px;
+        height: 38px;
+        font-size: 18px;
+      }
+      
+      .card-value-mini {
+        font-size: 18px !important;
+      }
+      
+      .card-label-mini {
+        font-size: 11px !important;
+      }
+    }
   }
 }
 
-@media (max-width: 768px) {
-  .dashboard-container {
-    padding: 16px;
-  }
+// ============ 农事任务执行进度 ============
+.task-progress-wrapper {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
   
-  .dashboard-header {
-    flex-direction: column;
-    gap: 16px;
+  .task-chart-container {
+    height: 140px;
+    width: 100%;
     
-    .title-section .dashboard-title {
-      font-size: 24px;
+    #taskProgressChart {
+      width: 100% !important;
+      height: 100% !important;
     }
+  }
+  
+  .task-stats-grid {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    gap: 8px;
     
-    .action-buttons {
-      flex-direction: column;
-      width: 100%;
-      gap: 16px;
+    .task-stat-item {
+      text-align: center;
+      padding: 8px;
+      background: rgba(24, 144, 255, 0.05);
+      border: 1px solid rgba(24, 144, 255, 0.15);
+      border-radius: 6px;
+      transition: all 0.3s ease;
+      
+      &:hover {
+        background: rgba(24, 144, 255, 0.1);
+        border-color: rgba(24, 144, 255, 0.3);
+      }
       
-      .location-selector-group {
-        flex-direction: column;
-        width: 100%;
+      .stat-value {
+        font-size: 18px;
+        font-weight: 700;
+        line-height: 1;
+        margin-bottom: 4px;
         
-        .el-cascader {
-          width: 100% !important;
+        &.total {
+          color: #1890ff;
         }
         
-        .el-button {
-          width: 100%;
+        &.completed {
+          color: #52c41a;
         }
+        
+        &.pending {
+          color: #faad14;
+        }
+      }
+      
+      .stat-label {
+        font-size: 11px;
+        color: rgba(255, 255, 255, 0.65);
       }
     }
   }
-  
-  .overview-grid,
-  .environment-grid {
-    grid-template-columns: 1fr;
-  }
-  
-  .content-row {
-    grid-template-columns: 1fr;
-  }
 }
 </style>