Răsfoiți Sursa

修改水文站站测验平台

BAI 6 zile în urmă
părinte
comite
621cd2424b

+ 32 - 0
src/App.vue

@@ -3,7 +3,39 @@
   <CesiumMap />
 </template>
 <script setup>
+import { onMounted, onBeforeUnmount } from 'vue'
 import CesiumMap from './components/CesiumMap.vue'
+import autofit from 'autofit.js'
+
+const initAutoFit = () => {
+  autofit.init({
+    designWidth: 1920,
+    designHeight: 1080,
+    el: '#app',
+    resize: true,
+    unit: 'px',
+    debug: false,
+    maxWidth: 1920,
+    maxHeight: 1080,
+    fontScale: true
+  })
+  autofit.elRectification('#cesiumContainer')
+}
+
+const handleResize = () => {
+  if (typeof autofit !== 'undefined' && typeof autofit.resize === 'function') {
+    autofit.resize()
+  }
+}
+
+onMounted(() => {
+  initAutoFit()
+  window.addEventListener('resize', handleResize)
+})
+
+onBeforeUnmount(() => {
+  window.removeEventListener('resize', handleResize)
+})
 </script>
 <style>
 * {

BIN
src/assets/images/Heilin/icon/cap/ADCP.png


BIN
src/assets/images/Heilin/icon/cap/H-adcp.png


BIN
src/assets/images/Heilin/icon/cap/地下水.png


BIN
src/assets/images/Heilin/icon/cap/水土保持.png


BIN
src/assets/images/Heilin/icon/cap/缆道.png


BIN
src/assets/images/Heilin/icon/cap/蒸发量.png


BIN
src/assets/images/Heilin/icon/cap/视频.png


BIN
src/assets/images/Heilin/icon/cap/量水堰.png


BIN
src/assets/images/Heilin/icon/cap/雷达.png


BIN
src/assets/images/Heilin/icon/shebei.png


BIN
src/assets/images/Heilin/icon/weilianjie.png


BIN
src/assets/images/Heilin/icon/wejieru.png


BIN
src/assets/images/Heilin/icon/yilianjie.png


+ 25 - 3
src/components/CesiumMap.vue

@@ -37,6 +37,13 @@ const popupPosition = ref({ x: 0, y: 0 })
 
 const router = useRouter()
 
+const DESIGN_WIDTH = 1920
+const DESIGN_HEIGHT = 1080
+
+const getScaleRatio = () => {
+  return Math.min(window.innerWidth / DESIGN_WIDTH, window.innerHeight / DESIGN_HEIGHT)
+}
+
 const poiData = ref({
   name: '黑林水文站',
   waterLevel: '3.25',
@@ -180,14 +187,20 @@ const addPoiMarker = () => {
     const handler = new Cesium.ScreenSpaceEventHandler(viewer.value.scene.canvas)
     
     handler.setInputAction((movement) => {
-      // 尝试拾取所有对象
-      const pickedObjects = viewer.value.scene.drillPick(movement.position)
+      const scaleRatio = getScaleRatio()
+      const correctedX = movement.position.x / scaleRatio
+      const correctedY = movement.position.y / scaleRatio
+      
+      const pickedObjects = viewer.value.scene.drillPick(new Cesium.Cartesian2(correctedX, correctedY))
       for (let i = 0; i < pickedObjects.length; i++) {
         const pickedObj = pickedObjects[i]
         if (Cesium.defined(pickedObj) && pickedObj.id) {
           if (pickedObj.id.id === 'heilin-station' || pickedObj.id.id === 'heilin-station-click') {
             showPopup.value = true
-            popupPosition.value = { x: movement.position.x - 120, y: movement.position.y - 150 }
+            popupPosition.value = { 
+              x: movement.position.x - 120, 
+              y: movement.position.y - 150 
+            }
             break
           }
         }
@@ -358,9 +371,18 @@ onMounted(async () => {
   }
 
   addPoiMarker()
+  
+  window.addEventListener('resize', handleResize)
 })
 
+const handleResize = () => {
+  if (viewer.value) {
+    viewer.value.resize()
+  }
+}
+
 onUnmounted(() => {
+  window.removeEventListener('resize', handleResize)
   if (blinkInterval) {
     clearInterval(blinkInterval)
   }

+ 12 - 0
src/router/index.js

@@ -1,6 +1,8 @@
 import { createRouter, createWebHistory } from 'vue-router'
 import HomeView from '../views/HomeView.vue'
 import HeilinStationView from '../views/HeilinStationView.vue'
+import SimulationView from '../views/SimulationView.vue'
+import LiangShuiYanView from '../views/LiangShuiYanView.vue'
 
 const routes = [
   {
@@ -12,6 +14,16 @@ const routes = [
     path: '/heilin-station',
     name: 'heilin-station',
     component: HeilinStationView
+  },
+  {
+    path: '/simulation',
+    name: 'simulation',
+    component: SimulationView
+  },
+  {
+    path: '/liangshuiyan',
+    name: 'liangshuiyan',
+    component: LiangShuiYanView
   }
 ]
 

+ 21 - 14
src/views/HeilinStationView.vue

@@ -15,10 +15,10 @@
       <div class="sub-title left-2" @click="showDetailModal = true">
         测站详情
       </div>
-      <div class="sub-title right-2">
-        测验模拟
+      <div class="sub-title right-2" @click="goToSimulation">
+        测控平台
       </div>
-      <div class="sub-title right-3">
+      <div class="sub-title right-3" @click="showDetailModal = true">
         更多
       </div>
       
@@ -209,11 +209,11 @@
                 <div class="card-value">22.5<span class="unit">%</span></div>
               </div>
                 <div class="water-card">
-                  <div class="card-title">10-20cm含水量</div>
+                  <div class="card-title">20cm含水量</div>
                   <div class="card-value">25.8<span class="unit">%</span></div>
                 </div>
                 <div class="water-card">
-                  <div class="card-title">20-30cm含水量</div>
+                  <div class="card-title">30cm含水量</div>
                   <div class="card-value">28.2<span class="unit">%</span></div>
                 </div>
                 <div class="water-card">
@@ -386,6 +386,10 @@ const goBack = () => {
   router.push('/')
 }
 
+const goToSimulation = () => {
+  router.push('/simulation')
+}
+
 const changeMainImage = (imageUrl) => {
   mainImageUrl.value = imageUrl
   // 提取图片名称作为 alt 文本
@@ -809,19 +813,19 @@ onMounted(() => {
 }
 
 .sub-title.left-1 {
-  left: 300px;
+  left: 180px;
 }
 
 .sub-title.left-2 {
-  left: 450px;
+  left: 400px;
 }
 
 .sub-title.right-2 {
-  right: 300px;
+  right: 400px;
 }
 
 .sub-title.right-3 {
-  right: 150px;
+  right: 200px;
 }
 
 .main-content {
@@ -831,7 +835,7 @@ onMounted(() => {
   padding: 130px 20px 20px;
   gap: 20px;
   overflow: hidden;
-  z-index: 4;
+  z-index: 3;
 }
 
 .left-sidebar {
@@ -1075,14 +1079,14 @@ onMounted(() => {
   display: grid;
   grid-template-columns: repeat(4, 1fr);
   gap: 8px;
-  margin: 0 10px;
+  margin: 0 5px;
 }
 
 .water-card {
   background: rgba(0, 60, 120, 0.5);
   border: 1px solid rgba(0, 213, 255, 0.3);
   border-radius: 4px;
-  padding: 8px;
+  padding: 6px 4px;
   text-align: center;
   transition: all 0.3s ease;
 }
@@ -1093,9 +1097,12 @@ onMounted(() => {
 }
 
 .card-title {
-  font-size: 12px;
+  font-size: 11px;
   color: #ffffff;
-  margin-bottom: 5px;
+  margin-bottom: 4px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
 
 .card-value {

+ 1017 - 0
src/views/LiangShuiYanView.vue

@@ -0,0 +1,1017 @@
+<template>
+    <div class="dashboard">
+        <!-- 背景和基础元素 -->
+        <div class="station-bg"></div>
+
+        <div class="bottom-bg"></div>
+        <div class="top-title"></div>
+        <div class="system-title">数字孪生黑林小流域</div>
+
+        <!-- 顶部按钮 -->
+        <div class="sub-title left-1" @click="goBack">
+            首页
+        </div>
+        <div class="sub-title left-2" @click="showDetailModal = true">
+            测站详情
+        </div>
+        <div class="sub-title right-2" @click="goToSimulation">
+            测控平台
+        </div>
+        <div class="sub-title right-3" @click="showDetailModal = true">
+            更多
+        </div>
+
+        <!-- 主要内容区域 -->
+        <div class="main-content">
+
+            <!-- 中间空间 -->
+            <div class="center-space">
+                <div class="poi-container">
+                    <div class="poi-item" style="left: 512px; top: 704px;">
+                        <div class="poi-label">水位自记台</div>
+                        <img src="/src/assets/images/Heilin/POI.png" alt="POI图标" class="poi-icon" />
+                    </div>
+                    <div class="poi-item" style="left: 1260px; top: 980px;">
+                        <div class="poi-label">水土保持观测场</div>
+                        <img src="/src/assets/images/Heilin/POI.png" alt="POI图标" class="poi-icon" />
+                    </div>
+                    <div class="poi-item" style="left: 724px; top: 883px;">
+                        <div class="poi-label">缆道房</div>
+                        <img src="/src/assets/images/Heilin/POI.png" alt="POI图标" class="poi-icon" />
+                    </div>
+                    <div class="poi-item" style="left: 979px; top: 855px;">
+                        <div class="poi-label">降雨观测场</div>
+                        <img src="/src/assets/images/Heilin/POI.png" alt="POI图标" class="poi-icon" />
+                    </div>
+                    <div class="poi-item" style="left: 1173px; top: 801px;">
+                        <div class="poi-label">地下水监测井</div>
+                        <img src="/src/assets/images/Heilin/POI.png" alt="POI图标" class="poi-icon" />
+                    </div>
+                </div>
+            </div>
+
+        </div>
+
+        <!-- 渐变装饰层(四周暗角) -->
+        <GradientOverlay />
+
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import GradientOverlay from '../components/gradient-overlay.vue'
+import * as echarts from 'echarts'
+
+const router = useRouter()
+const mainImageUrl = ref('/src/assets/images/Heilin/图6.png')
+const mainImageAlt = ref('水文站图片 6')
+const selectedMonitor = ref('图5')
+const showDetailModal = ref(false)
+const combinedChart = ref(null)
+const evaporationChart = ref(null)
+const soilMoistureChart = ref(null)
+
+const goBack = () => {
+  router.push('/')
+}
+
+const goToSimulation = () => {
+  router.push('/simulation')
+}
+
+const changeMainImage = (imageUrl) => {
+  mainImageUrl.value = imageUrl
+  const parts = imageUrl.split('/')
+  const imageName = parts[parts.length - 1]
+  mainImageAlt.value = `水文站图片${imageName.split('.')[0]}`
+}
+
+const closeModal = () => {
+  showDetailModal.value = false
+}
+
+const drawCombinedChart = () => {
+  const container = combinedChart.value
+  if (!container) return
+  
+  const chart = echarts.init(container)
+  
+  const months = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
+  const waterLevel = [32.5, 32.8, 33.2, 33.8, 34.5, 35.2, 36.0, 35.8, 35.0, 34.2, 33.5, 32.8]
+  const flow = [10, 12, 15, 20, 35, 50, 80, 65, 40, 25, 18, 12]
+  const rainfall = [20, 25, 30, 45, 60, 85, 120, 100, 70, 40, 25, 15]
+  
+  const option = {
+    title: {
+      text: '',
+      left: 'center'
+    },
+    tooltip: {
+      trigger: 'axis'
+    },
+    legend: {
+      data: ['水位', '流量', '降雨量'],
+      top: 0,
+      textStyle: {
+        color: '#ffffff'
+      }
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      top: '15%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: months,
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.8)'
+        }
+      },
+      axisLabel: {
+        color: '#ffffff'
+      }
+    },
+    yAxis: [
+      {
+        type: 'value',
+        name: '水位(m)',
+        nameTextStyle: {
+          color: '#ffffff'
+        },
+        axisLine: {
+          lineStyle: {
+            color: 'rgba(255, 255, 255, 0.8)'
+          }
+        },
+        axisLabel: {
+          color: '#ffffff'
+        },
+        splitLine: {
+          lineStyle: {
+            color: 'rgba(255, 255, 255, 0.2)'
+          }
+        }
+      },
+      {
+        type: 'value',
+        name: '流量(m³/s)',
+        nameTextStyle: {
+          color: '#ffffff'
+        },
+        axisLine: {
+          lineStyle: {
+            color: 'rgba(255, 255, 255, 0.8)'
+          }
+        },
+        axisLabel: {
+          color: '#ffffff'
+        },
+        splitLine: {
+          show: false
+        }
+      }
+    ],
+    series: [
+      {
+        name: '水位',
+        type: 'line',
+        data: waterLevel,
+        lineStyle: {
+          color: 'rgba(0, 100, 255, 1)',
+          width: 2
+        },
+        itemStyle: {
+          color: 'rgba(0, 100, 255, 1)'
+        }
+      },
+      {
+        name: '流量',
+        type: 'line',
+        yAxisIndex: 1,
+        data: flow,
+        lineStyle: {
+          color: 'rgba(0, 255, 255, 1)',
+          width: 2
+        },
+        itemStyle: {
+          color: 'rgba(0, 255, 255, 1)'
+        }
+      },
+      {
+        name: '降雨量',
+        type: 'bar',
+        data: rainfall,
+        itemStyle: {
+          color: 'rgba(78, 205, 196, 0.7)'
+        }
+      }
+    ]
+  }
+  
+  chart.setOption(option)
+  
+  window.addEventListener('resize', () => {
+    chart.resize()
+  })
+}
+
+const drawEvaporationChart = () => {
+  const container = evaporationChart.value
+  if (!container) return
+  
+  const chart = echarts.init(container)
+  
+  const months = ['1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10 月', '11 月', '12 月']
+  const evaporation = [45, 52, 68, 85, 105, 120, 135, 125, 95, 72, 55, 48]
+  
+  const option = {
+    title: {
+      text: '',
+      left: 'center'
+    },
+    tooltip: {
+      trigger: 'axis'
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      top: '15%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: months,
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.8)'
+        }
+      },
+      axisLabel: {
+        color: '#ffffff'
+      }
+    },
+    yAxis: {
+      type: 'value',
+      name: '蒸发量(mm)',
+      nameTextStyle: {
+        color: '#ffffff'
+      },
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.8)'
+        }
+      },
+      axisLabel: {
+        color: '#ffffff'
+      },
+      splitLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.2)'
+        }
+      }
+    },
+    series: [
+      {
+        name: '蒸发量',
+        type: 'line',
+        data: evaporation,
+        lineStyle: {
+          color: 'rgba(255, 165, 2, 1)',
+          width: 2
+        },
+        itemStyle: {
+          color: 'rgba(255, 165, 2, 1)'
+        },
+        symbol: 'circle',
+        symbolSize: 6
+      }
+    ]
+  }
+  
+  chart.setOption(option)
+  
+  window.addEventListener('resize', () => {
+    chart.resize()
+  })
+}
+
+const drawSoilMoistureChart = () => {
+  const container = soilMoistureChart.value
+  if (!container) return
+  
+  const chart = echarts.init(container)
+  
+  const months = ['1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10 月', '11 月', '12 月']
+  const soilMoisture = [18, 19, 21, 23, 25, 28, 30, 29, 26, 23, 20, 18]
+  
+  const option = {
+    title: {
+      text: '',
+      left: 'center'
+    },
+    tooltip: {
+      trigger: 'axis'
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      top: '15%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: months,
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.8)'
+        }
+      },
+      axisLabel: {
+        color: '#ffffff'
+      }
+    },
+    yAxis: {
+      type: 'value',
+      name: '含水量(%)',
+      nameTextStyle: {
+        color: '#ffffff'
+      },
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.8)'
+        }
+      },
+      axisLabel: {
+        color: '#ffffff'
+      },
+      splitLine: {
+        lineStyle: {
+          color: 'rgba(255, 255, 255, 0.2)'
+        }
+      }
+    },
+    series: [
+      {
+        name: '含水量',
+        type: 'line',
+        data: soilMoisture,
+        lineStyle: {
+          color: 'rgba(78, 205, 196, 1)',
+          width: 2
+        },
+        itemStyle: {
+          color: 'rgba(78, 205, 196, 1)'
+        }
+      }
+    ]
+  }
+  
+  chart.setOption(option)
+  
+  window.addEventListener('resize', () => {
+    chart.resize()
+  })
+}
+
+onMounted(() => {
+  drawCombinedChart()
+  drawEvaporationChart()
+  drawSoilMoistureChart()
+  
+  window.addEventListener('resize', () => {
+    drawCombinedChart()
+    drawEvaporationChart()
+    drawSoilMoistureChart()
+  })
+})
+</script>
+
+<style scoped>
+.dashboard {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  position: relative;
+}
+
+.bottom-bg {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/Heilin/WPS图片(1).jpeg');
+  background-size: 100% 100%;
+  background-position: 0 0;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 3;
+}
+
+.station-bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/Heilin/图6.png');
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 2;
+}
+
+.top-title {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/顶部大标题.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 4;
+}
+
+.system-title {
+  position: absolute;
+  top: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+  font-size: 36px;
+  font-weight: bold;
+  background: linear-gradient(to bottom, #ffffff 50%, #00d5ff 100%);
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
+  text-shadow: 0 0 1px rgba(2, 217, 255, 0.205);
+  z-index: 4;
+  pointer-events: none;
+}
+
+.sub-title {
+  position: absolute;
+  top: 30px;
+  width: 151px;
+  height: 63px;
+  background-image: url('/src/assets/images/顶部小标题.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  display: flex;
+  align-items: flex-start;
+  padding-top: 10px;
+  justify-content: center;
+  font-size: 16px;
+  font-weight: bold;
+  color: #e0fcff;
+  text-shadow: 0 0 5px rgba(0, 212, 255, 0.8);
+  z-index: 4;
+  cursor: pointer;
+  transition: transform 0.3s ease;
+}
+
+.sub-title:hover {
+  transform: scale(1.05);
+}
+
+.sub-title.left-1 {
+  left: 300px;
+}
+
+.sub-title.left-2 {
+  left: 450px;
+}
+
+.sub-title.right-2 {
+  right: 200px;
+}
+
+.sub-title.right-3 {
+  right: 50px;
+}
+
+.main-content {
+  position: relative;
+  display: flex;
+  height: calc(100% - 120px);
+  margin-top: 120px;
+  padding: 20px;
+  z-index: 3;
+}
+
+.left-sidebar {
+  flex: 1;
+  margin-right: 20px;
+}
+
+.left-container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.right-sidebar {
+  width: 400px;
+  display: flex;
+  flex-direction: column;
+}
+
+.data-card {
+  width: 100%;
+  background: rgba(0, 20, 40, 0.7);
+  border-radius: 4px;
+  overflow: hidden;
+  box-shadow: 0 0 10px rgba(0, 212, 255, 0.2);
+}
+
+.panel-header {
+  height: 50px;
+  background-image: url('/src/assets/images/数据小标题.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  display: flex;
+  align-items: flex-start;
+  justify-content: space-between;
+  padding: 6px 20px 0;
+  cursor: pointer;
+}
+
+.panel-header h3 {
+  margin: 0;
+  font-size: 18px;
+  font-weight: bold;
+  color: #e0fcff;
+  text-shadow: 0 0 5px rgba(0, 212, 255, 0.5);
+  padding-left: 20px;
+}
+
+.panel-content {
+  font-size: 16px;
+  line-height: 1;
+  width: 100%;
+  color: #ffffff;
+}
+
+.station-intro {
+  min-height: 500px;
+}
+
+.station-intro .panel-content {
+  padding: 15px;
+}
+
+.image-section {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 15px;
+  height: 250px;
+}
+
+.thumbnail-list {
+  width: 80px;
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+}
+
+.thumbnail-list img {
+  width: 100%;
+  height: 45px;
+  object-fit: cover;
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.thumbnail-list img:hover {
+  border-color: rgba(0, 212, 255, 0.8);
+  box-shadow: 0 0 5px rgba(0, 212, 255, 0.5);
+}
+
+.main-image {
+  flex: 1;
+  border-radius: 4px;
+  overflow: hidden;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.main-image img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.monitor-select {
+  width: 100%;
+}
+
+.select-wrapper {
+  position: relative;
+  width: 100%;
+}
+
+.select-wrapper .camera-icon {
+  position: absolute;
+  left: 10px;
+  top: 50%;
+  transform: translateY(-50%);
+  font-size: 16px;
+  z-index: 10;
+  pointer-events: none;
+}
+
+.select-wrapper select {
+  width: 100%;
+  padding: 8px 10px 8px 30px;
+  background: rgba(0, 40, 80, 0.8);
+  border: 1px solid rgba(0, 212, 255, 0.3);
+  border-radius: 4px;
+  color: #e0fcff;
+  font-size: 14px;
+  cursor: pointer;
+  appearance: none;
+  -webkit-appearance: none;
+  -moz-appearance: none;
+}
+
+.select-wrapper select option {
+  background: rgba(0, 40, 80, 0.9);
+  color: #e0fcff;
+}
+
+.monitor-image {
+  margin-top: 10px;
+  width: 100%;
+  height: 200px;
+  border-radius: 4px;
+  overflow: hidden;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.monitor-image img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.center-space {
+  flex: 1;
+  position: relative;
+  overflow: hidden;
+}
+
+.poi-container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.poi-item {
+  position: absolute;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.poi-item:hover {
+  transform: scale(1.1);
+}
+
+.poi-label {
+  margin-bottom: 5px;
+  font-size: 12px;
+  color: #ffffff;
+  background: rgba(0, 0, 0, 0.6);
+  padding: 2px 8px;
+  border-radius: 4px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.poi-icon {
+  width: 32px;
+  height: 32px;
+  animation: float 3s ease-in-out infinite;
+}
+
+@keyframes float {
+  0%, 100% {
+    transform: translateY(0);
+    filter: drop-shadow(0 0 5px rgba(0, 213, 255, 0.5));
+  }
+  50% {
+    transform: translateY(-10px);
+    filter: drop-shadow(0 0 10px rgba(0, 213, 255, 0.8));
+  }
+}
+
+.right-container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.data-card-1 {
+  min-height: 380px;
+}
+
+.data-card-2 {
+  min-height: 290px;
+}
+
+.data-card-3 {
+  min-height: 320px;
+}
+
+.water-level-cards {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 10px;
+}
+
+.water-card {
+  flex: 1;
+  background: rgba(0, 40, 80, 0.6);
+  border-radius: 4px;
+  padding: 10px;
+  text-align: center;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.card-title {
+  font-size: 12px;
+  color: #62f6fb;
+  margin-bottom: 4px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.card-value {
+  font-size: 18px;
+  font-weight: bold;
+  color: #ffffff;
+  text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
+}
+
+.card-value.warning {
+  color: #ffa502;
+  text-shadow: 0 0 8px rgba(255, 165, 2, 0.8);
+}
+
+.card-value.danger {
+  color: #ff4757;
+  text-shadow: 0 0 8px rgba(255, 71, 87, 0.8);
+}
+
+.card-value.highlight {
+  color: #ff4757;
+  text-shadow: 0 0 8px rgba(255, 71, 87, 0.8);
+}
+
+.card-value.low {
+  color: #4ecdc4;
+  text-shadow: 0 0 8px rgba(78, 205, 196, 0.8);
+}
+
+.unit {
+  font-size: 12px;
+  margin-left: 2px;
+  opacity: 0.8;
+}
+
+.chart-container {
+  width: 100%;
+  height: 250px;
+  border-radius: 4px;
+  overflow: hidden;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 20, 40, 0.8);
+  backdrop-filter: blur(5px);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  background: rgba(0, 30, 60, 0.95);
+  border: 1px solid rgba(0, 213, 255, 0.5);
+  border-radius: 8px;
+  box-shadow: 0 0 30px rgba(0, 213, 255, 0.4);
+  width: 800px;
+  max-width: 90vw;
+  max-height: 80vh;
+  overflow-y: auto;
+  z-index: 1001;
+}
+
+.modal-header {
+  background: linear-gradient(90deg, rgba(0, 60, 120, 0.9), rgba(0, 100, 150, 0.7));
+  padding: 15px 20px;
+  border-bottom: 1px solid rgba(0, 213, 255, 0.4);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.modal-header h2 {
+  font-size: 18px;
+  font-weight: bold;
+  color: #00ffff;
+  margin: 0;
+  text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+.close-btn {
+  font-size: 24px;
+  color: #7bbef6;
+  cursor: pointer;
+  background: none;
+  border: none;
+  padding: 0;
+  transition: color 0.3s;
+}
+
+.close-btn:hover {
+  color: #ffffff;
+}
+
+.modal-body {
+  padding: 20px;
+}
+
+.station-info-header {
+  margin-bottom: 20px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid rgba(0, 213, 255, 0.3);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.station-basic {
+  flex: 1;
+}
+
+.station-name {
+  font-size: 24px;
+  font-weight: bold;
+  color: #00ffff;
+  margin: 0 0 10px 0;
+  text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+.station-code,
+.station-basin {
+  font-size: 14px;
+  color: #e0fcff;
+  margin: 0;
+}
+
+.station-qr {
+  width: 120px;
+  height: 120px;
+  border: 2px solid rgba(0, 213, 255, 0.5);
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.station-qr img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.detail-section {
+  margin-bottom: 20px;
+}
+
+.detail-section h4 {
+  font-size: 16px;
+  font-weight: bold;
+  color: #62f6fb;
+  margin: 0 0 10px 0;
+  text-shadow: 0 0 3px rgba(0, 212, 255, 0.5);
+}
+
+.detail-section p {
+  font-size: 14px;
+  color: #e0fcff;
+  line-height: 1.6;
+}
+
+.data-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 10px;
+}
+
+.data-item {
+  background: rgba(0, 40, 80, 0.6);
+  padding: 10px;
+  border-radius: 4px;
+  border: 1px solid rgba(0, 213, 255, 0.3);
+}
+
+.data-label {
+  font-size: 12px;
+  color: #62f6fb;
+  margin-bottom: 4px;
+}
+
+.data-value {
+  font-size: 14px;
+  font-weight: bold;
+  color: #00ffff;
+}
+
+.extreme-data {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.data-row {
+  display: flex;
+  align-items: flex-start;
+  gap: 10px;
+}
+
+.data-label {
+  font-size: 14px;
+  color: #62f6fb;
+  font-weight: bold;
+  flex-shrink: 0;
+}
+
+.data-value {
+  font-size: 14px;
+  font-weight: bold;
+  color: #00ffff;
+  flex-shrink: 0;
+}
+
+.data-text {
+  font-size: 14px;
+  color: #e0fcff;
+  flex: 1;
+}
+
+.base-info {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.supplement-info {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.more-btn {
+  font-size: 12px;
+  color: #62f6fb;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  padding: 4px 8px;
+  border: 1px solid rgba(0, 213, 255, 0.3);
+  border-radius: 4px;
+}
+
+.more-btn:hover {
+  color: #00ffff;
+  border-color: rgba(0, 213, 255, 0.8);
+  box-shadow: 0 0 5px rgba(0, 213, 255, 0.5);
+}
+</style>

+ 991 - 0
src/views/SimulationView.vue

@@ -0,0 +1,991 @@
+<template>
+  <div class="dashboard">
+    <div class="background-image"></div>
+    <div class="top-title"></div>
+    <div class="system-title">测控平台 - 黑林水文站</div>
+    
+    <!-- 渐变装饰层(四周暗角) -->
+    <GradientOverlay />
+    
+    <!-- 顶部按钮 -->
+    <div class="sub-title left-1" @click="goBack">
+      首页
+    </div>
+    <div class="sub-title left-2" @click="goBackToStation">
+      测站详情
+    </div>
+    <div class="sub-title right-2">
+      测控平台
+    </div>
+    <div class="sub-title right-3" @click="showDetailModal = true">
+      更多
+    </div>
+    
+    <!-- 主要内容区域 -->
+    <div class="main-content">
+      <!-- 设备状态概览 -->
+      <div class="status-overview">
+        <div class="status-card total-devices">
+          <div class="status-icon total">
+            <img src="/src/assets/images/Heilin/icon/shebei.png" alt="设备总数" />
+          </div>
+          <div class="status-info">
+            <div class="status-label">接入总数</div>
+            <div class="status-value">{{ deviceStatus.total }}台</div>
+          </div>
+        </div>
+        <div class="status-card offline-devices">
+          <div class="status-icon offline">
+            <img src="/src/assets/images/Heilin/icon/weilianjie.png" alt="离线设备" />
+          </div>
+          <div class="status-info">
+            <div class="status-label">离线数量</div>
+            <div class="status-value">{{ deviceStatus.offline }}台</div>
+          </div>
+        </div>
+        <div class="status-card online-devices">
+          <div class="status-icon online">
+            <img src="/src/assets/images/Heilin/icon/yilianjie.png" alt="在线设备" />
+          </div>
+          <div class="status-info">
+            <div class="status-label">在线数量</div>
+            <div class="status-value">{{ deviceStatus.online }}台</div>
+          </div>
+        </div>
+        <div class="status-card unconnected-devices">
+          <div class="status-icon unconnected">
+            <img src="/src/assets/images/Heilin/icon/wejieru.png" alt="未接入设备" />
+          </div>
+          <div class="status-info">
+            <div class="status-label">未接入</div>
+            <div class="status-value">{{ deviceStatus.unconnected }}台</div>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 设备测验内容卡片 -->
+      <div class="device-cards">
+        <div 
+          v-for="device in devices" 
+          :key="device.id" 
+          class="device-card"
+          :class="{ active: selectedDeviceId === device.id }"
+          @click="handleDeviceClick(device.name)"
+        >
+          <div class="device-icon">
+            <img :src="getDeviceIcon(device.name)" :alt="device.name" />
+          </div>
+          <div class="device-name">{{ device.name }}</div>
+          <div class="device-status" :class="device.statusClass">
+            {{ device.statusText }}
+          </div>
+        </div>
+      </div>
+      
+      <!-- 选中设备详情 -->
+      <div v-if="selectedDevice" class="device-detail">
+        <div class="detail-header">
+          <h3>{{ selectedDevice.name }} - 详细信息</h3>
+          <button class="close-btn" @click="selectedDevice = null">×</button>
+        </div>
+        <div class="detail-content">
+          <div class="detail-item">
+            <label>设备ID:</label>
+            <span>{{ selectedDevice.id }}</span>
+          </div>
+          <div class="detail-item">
+            <label>设备类型:</label>
+            <span>{{ selectedDevice.type }}</span>
+          </div>
+          <div class="detail-item">
+            <label>设备状态:</label>
+            <span :class="selectedDevice.statusClass">{{ selectedDevice.statusText }}</span>
+          </div>
+          <div class="detail-item">
+            <label>最后在线:</label>
+            <span>{{ selectedDevice.lastOnline }}</span>
+          </div>
+          <div class="detail-item">
+            <label>测量参数:</label>
+            <span>{{ selectedDevice.parameters }}</span>
+          </div>
+          <div class="detail-item">
+            <label>设备位置:</label>
+            <span>{{ selectedDevice.location }}</span>
+          </div>
+        </div>
+        <div class="detail-actions">
+          <button class="btn-primary" @click="startMeasurement(selectedDevice.id)">
+            开始测量
+          </button>
+          <button class="btn-secondary" @click="restartDevice(selectedDevice.id)">
+            重启设备
+          </button>
+          <button class="btn-secondary" @click="updateFirmware(selectedDevice.id)">
+            更新固件
+          </button>
+        </div>
+      </div>
+    </div>
+    
+    <!-- 渐变装饰层(四周暗角) -->
+    <GradientOverlay />
+    
+    <!-- 详情弹窗 -->
+    <div v-if="showDetailModal" class="modal-overlay" @click="closeModal">
+      <div class="modal-content" @click.stop>
+        <div class="modal-header">
+          <h2>测控平台详细信息</h2>
+          <span class="close-btn" @click="closeModal">×</span>
+        </div>
+        <div class="modal-body">
+          <!-- 基本信息区域 -->
+          <div class="station-info-header">
+            <div class="station-basic">
+              <h3 class="station-name">测控平台系统</h3>
+              <p class="station-code">系统版本:v1.0.0</p>
+            </div>
+          </div>
+          
+          <!-- 详细信息区域 -->
+          <div class="station-info-detail">
+            <h4>系统功能</h4>
+            <ul>
+              <li>设备状态实时监测</li>
+              <li>远程测量控制</li>
+              <li>设备固件管理</li>
+              <li>测量数据分析</li>
+              <li>异常报警处理</li>
+            </ul>
+            
+            <h4>支持设备类型</h4>
+            <ul>
+              <li>双轨雷达测速</li>
+              <li>原扫雷达</li>
+              <li>缆道测流</li>
+              <li>视频测流(御)</li>
+              <li>视频测流(王)</li>
+              <li>时差法测流</li>
+              <li>H-ADCP测流</li>
+              <li>超声波测流</li>
+              <li>其他测流方式</li>
+              <li>V-ADCP测流</li>
+              <li>同步测流</li>
+            </ul>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="btn-primary" @click="closeModal">关闭</button>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import GradientOverlay from '../components/gradient-overlay.vue'
+
+export default {
+  name: 'ControlPlatformView',
+  components: {
+    GradientOverlay
+  },
+  data() {
+    return {
+      showDetailModal: false,
+      selectedDeviceId: null,
+      deviceStatus: {
+        total: 11,
+        offline: 0,
+        online: 2,
+        unconnected: 9
+      },
+      devices: [
+        {
+          id: 'device-001',
+          name: '双轨雷达测速',
+          type: '雷达测速',
+          status: 100,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-10 14:30:25',
+          parameters: '流速、流向',
+          location: '黑林水文站监测点1'
+        },
+        {
+          id: 'device-002',
+          name: '原扫雷达',
+          type: '雷达监测',
+          status: 85,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-10 14:28:12',
+          parameters: '流速分布',
+          location: '黑林水文站监测点2'
+        },
+        {
+          id: 'device-003',
+          name: '缆道测流',
+          type: '缆道系统',
+          status: 100,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-10 14:32:45',
+          parameters: '流量、水位',
+          location: '黑林水文站监测点3'
+        },
+        {
+          id: 'device-004',
+          name: '视频测流(御)',
+          type: '视频监测',
+          status: 0,
+          statusText: '离线',
+          statusClass: 'status-offline',
+          lastOnline: '2026-03-09 18:45:30',
+          parameters: '水面流速',
+          location: '黑林水文站监测点4'
+        },
+        {
+          id: 'device-005',
+          name: '地下水',
+          type: '视频监测',
+          status: 0,
+          statusText: '离线',
+          statusClass: 'status-offline',
+          lastOnline: '2026-03-09 17:20:15',
+          parameters: '水面流速',
+          location: '黑林水文站监测点5'
+        },
+        {
+          id: 'device-006',
+          name: '时差法测流',
+          type: '声学测流',
+          status: 100,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-09 16:10:45',
+          parameters: '流速、流量',
+          location: '黑林水文站监测点6'
+        },
+        {
+          id: 'device-007',
+          name: 'H-ADCP测流',
+          type: '声学多普勒',
+          status: 100,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-09 15:30:20',
+          parameters: '流速剖面',
+          location: '黑林水文站监测点7'
+        },
+        {
+          id: 'device-008',
+          name: '量水堰',
+          type: '超声波',
+          status: 100,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-09 14:25:10',
+          parameters: '流速',
+          location: '黑林水文站监测点8'
+        },
+        {
+          id: 'device-009',
+          name: '水土保持',
+          type: '其他',
+          status: 0,
+          statusText: '离线',
+          statusClass: 'status-offline',
+          lastOnline: '2026-03-09 13:15:40',
+          parameters: '自定义',
+          location: '黑林水文站监测点9'
+        },
+        {
+          id: 'device-010',
+          name: 'V-ADCP测流',
+          type: '声学多普勒',
+          status: 100,
+          statusText: '在线',
+          statusClass: 'status-normal',
+          lastOnline: '2026-03-09 12:45:25',
+          parameters: '垂直流速剖面',
+          location: '黑林水文站监测点10'
+        },
+        {
+          id: 'device-011',
+          name: '蒸发量',
+          type: '同步系统',
+          status: 0,
+          statusText: '离线',
+          statusClass: 'status-offline',
+          lastOnline: '2026-03-09 11:30:15',
+          parameters: '多参数同步',
+          location: '黑林水文站监测点11'
+        }
+      ]
+    }
+  },
+  computed: {
+    selectedDevice() {
+      return this.devices.find(device => device.id === this.selectedDeviceId)
+    }
+  },
+  methods: {
+    goBack() {
+      this.$router.push('/')
+    },
+    
+    goBackToStation() {
+      this.$router.push('/heilin-station')
+    },
+    
+    showDetail() {
+      this.showDetailModal = true
+    },
+    
+    closeModal() {
+      this.showDetailModal = false
+    },
+    
+    selectDevice(deviceId) {
+      this.selectedDeviceId = deviceId
+    },
+    
+    handleDeviceClick(deviceName) {
+      if (deviceName === '量水堰') {
+        this.$router.push('/liangshuiyan')
+      } else {
+        this.selectedDeviceId = null
+      }
+    },
+    
+    getDeviceIcon(name) {
+      const iconMap = {
+        '双轨雷达测速': '/src/assets/images/Heilin/icon/cap/雷达.png',
+        '原扫雷达': '/src/assets/images/Heilin/icon/cap/雷达.png',
+        '缆道测流': '/src/assets/images/Heilin/icon/cap/缆道.png',
+        '视频测流(御)': '/src/assets/images/Heilin/icon/cap/视频.png',
+        '地下水': '/src/assets/images/Heilin/icon/cap/地下水.png',
+        '时差法测流': '/src/assets/images/Heilin/icon/cap/ADCP.png',
+        'H-ADCP测流': '/src/assets/images/Heilin/icon/cap/H-adcp.png',
+        '量水堰': '/src/assets/images/Heilin/icon/cap/量水堰.png',
+        '水土保持': '/src/assets/images/Heilin/icon/cap/水土保持.png',
+        'V-ADCP测流': '/src/assets/images/Heilin/icon/cap/ADCP.png',
+        '蒸发量': '/src/assets/images/Heilin/icon/cap/蒸发量.png'
+      }
+      return iconMap[name] || '/src/assets/images/Heilin/icon/cap/雷达.png'
+    },
+    
+    startMeasurement(deviceId) {
+      // 模拟开始测量
+      console.log('开始测量设备:', deviceId)
+      this.$message({
+        message: '测量已开始',
+        type: 'success'
+      })
+    },
+    
+    restartDevice(deviceId) {
+      // 模拟重启设备
+      console.log('重启设备:', deviceId)
+      this.$message({
+        message: '设备重启中...',
+        type: 'info'
+      })
+    },
+    
+    updateFirmware(deviceId) {
+      // 模拟更新固件
+      console.log('更新固件:', deviceId)
+      this.$message({
+        message: '固件更新中...',
+        type: 'info'
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.dashboard {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  position: relative;
+  background: linear-gradient(135deg, rgba(0, 20, 40, 0.95), rgba(0, 40, 80, 0.8));
+  z-index: 2;
+}
+
+.background-image {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: url('/src/assets/images/Heilin/背景图3.jpg') no-repeat center center;
+  background-size: cover;
+  opacity: 0.3;
+  pointer-events: none;
+  z-index: 1;
+}
+
+.top-title {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/顶部大标题1.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 3;
+  opacity: 0.9;
+}
+
+.system-title {
+  position: absolute;
+  top: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+  font-size: 36px;
+  font-weight: bold;
+  background: linear-gradient(to bottom, #ffffff 50%, #00d5ff 100%);
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
+  text-shadow: 0 0 1px rgba(2, 217, 255, 0.205);
+  z-index: 4;
+  pointer-events: none;
+}
+
+.sub-title {
+  position: absolute;
+  top: 30px;
+  width: 151px;
+  height: 63px;
+  background-image: url('/src/assets/images/顶部小标题.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  display: flex;
+  align-items: flex-start;
+  padding-top: 10px;
+  justify-content: center;
+  font-size: 16px;
+  font-weight: bold;
+  color: #e0fcff;
+  text-shadow: 0 0 5px rgba(0, 212, 255, 0.8);
+  z-index: 4;
+  cursor: pointer;
+  transition: transform 0.3s ease;
+}
+
+.sub-title:hover {
+  transform: scale(1.05);
+}
+
+.sub-title.left-1 {
+  left: 300px;
+}
+
+.sub-title.left-2 {
+  left: 450px;
+}
+
+.sub-title.right-2 {
+  right: 200px;
+}
+
+.sub-title.right-3 {
+  right: 50px;
+}
+
+.main-content {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  height: calc(100% - 120px);
+  margin-top: 120px;
+  padding: 20px;
+  z-index: 3;
+  gap: 30px;
+}
+
+/* 设备状态概览 */
+.status-overview {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+.status-card {
+  background: rgba(0, 40, 80, 0.6);
+  border: 1px solid rgba(0, 213, 255, 0.3);
+  border-radius: 12px;
+  padding: 20px;
+  display: flex;
+  align-items: center;
+  gap: 20px;
+  backdrop-filter: blur(10px);
+  transition: all 0.3s ease;
+}
+
+.status-card:hover {
+  border-color: rgba(0, 213, 255, 0.8);
+  box-shadow: 0 0 20px rgba(0, 213, 255, 0.4);
+  transform: translateY(-2px);
+}
+
+.status-icon {
+  width: 80px;
+  height: 80px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.status-icon img {
+  width: 100px;
+  height: 100px;
+  object-fit: contain;
+}
+
+.status-info {
+  flex: 1;
+}
+
+.status-label {
+  font-size: 14px;
+  color: #e0fcff;
+  margin-bottom: 5px;
+}
+
+.status-value {
+  font-size: 24px;
+  font-weight: bold;
+  color: #00ffff;
+  text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+/* 设备测验内容卡片 */
+.device-cards {
+  display: grid;
+  grid-template-columns: repeat(6, 1fr);
+  gap: 30px;
+  flex: 1;
+  overflow-y: auto;
+  padding-right: 10px;
+  max-height: 100%;
+}
+
+.device-card {
+  background: rgba(0, 40, 80, 0.6);
+  border: 1px solid rgba(0, 213, 255, 0.3);
+  border-radius: 4px;
+  width: 250px;
+  height: 300px;
+  padding: 10px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  gap: 15px;
+  backdrop-filter: blur(10px);
+  cursor: pointer;
+  transition: all 0.3s ease;
+  position: relative;
+  overflow: hidden;
+}
+
+.device-card::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 3px;
+  background: linear-gradient(90deg, #00d5ff, #62f6fb);
+  transform: scaleX(0);
+  transition: transform 0.3s ease;
+}
+
+.device-card:hover {
+  border-color: rgba(0, 213, 255, 0.8);
+  box-shadow: 0 0 20px rgba(0, 213, 255, 0.4);
+  transform: translateY(-2px);
+}
+
+.device-card:hover::before {
+  transform: scaleX(1);
+}
+
+.device-card.active {
+  border-color: rgba(0, 213, 255, 0.8);
+  box-shadow: 0 0 20px rgba(0, 213, 255, 0.6);
+}
+
+.device-card.active::before {
+  transform: scaleX(1);
+}
+
+.device-icon {
+  width: 150px;
+  height: 150px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1;
+}
+
+.device-icon img {
+  width: 150px;
+  height: 150px;
+  object-fit: contain;
+}
+
+.device-name {
+  font-size: 32px;
+  font-weight: bold;
+  color: #ffffff;
+  text-align: center;
+  z-index: 1;
+  word-break: break-all;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+}
+
+.device-status {
+  font-size: 18px;
+  font-weight: bold;
+  padding: 6px 12px;
+  border-radius: 4px;
+  z-index: 1;
+}
+
+.status-normal {
+  color: #00ff88;
+  background: rgba(0, 255, 136, 0.2);
+  border: 1px solid rgba(0, 255, 136, 0.4);
+}
+
+.status-offline {
+  color: #ff6b6b;
+  background: rgba(255, 107, 107, 0.2);
+  border: 1px solid rgba(255, 107, 107, 0.4);
+}
+
+.status-warning {
+  color: #ffa502;
+  background: rgba(255, 165, 2, 0.2);
+  border: 1px solid rgba(255, 165, 2, 0.4);
+}
+
+/* 设备详情 */
+.device-detail {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  background: rgba(0, 30, 60, 0.95);
+  border: 1px solid rgba(0, 213, 255, 0.5);
+  border-radius: 12px;
+  box-shadow: 0 0 30px rgba(0, 213, 255, 0.4);
+  width: 600px;
+  max-width: 90vw;
+  max-height: 80vh;
+  overflow-y: auto;
+  z-index: 1000;
+}
+
+.detail-header {
+  background: linear-gradient(90deg, rgba(0, 60, 120, 0.9), rgba(0, 100, 150, 0.7));
+  padding: 15px 20px;
+  border-bottom: 1px solid rgba(0, 213, 255, 0.4);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.detail-header h3 {
+  font-size: 18px;
+  font-weight: bold;
+  color: #00ffff;
+  margin: 0;
+  text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+.close-btn {
+  font-size: 24px;
+  color: #7bbef6;
+  cursor: pointer;
+  background: none;
+  border: none;
+  padding: 0;
+  transition: color 0.3s;
+}
+
+.close-btn:hover {
+  color: #ffffff;
+}
+
+.detail-content {
+  padding: 20px;
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.detail-item {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+}
+
+.detail-item label {
+  font-size: 14px;
+  color: #62f6fb;
+  font-weight: bold;
+  width: 100px;
+  flex-shrink: 0;
+}
+
+.detail-item span {
+  font-size: 14px;
+  color: #e0fcff;
+  flex: 1;
+}
+
+.detail-actions {
+  padding: 20px;
+  border-top: 1px solid rgba(0, 213, 255, 0.3);
+  display: flex;
+  gap: 10px;
+  justify-content: flex-end;
+}
+
+.btn-primary {
+  background: linear-gradient(90deg, rgba(0, 100, 200, 0.8), rgba(0, 150, 255, 0.6));
+  border: 1px solid rgba(0, 213, 255, 0.5);
+  border-radius: 4px;
+  color: #ffffff;
+  padding: 10px 20px;
+  font-size: 14px;
+  font-weight: bold;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.btn-primary:hover {
+  background: linear-gradient(90deg, rgba(0, 120, 255, 0.9), rgba(0, 180, 255, 0.7));
+  box-shadow: 0 0 10px rgba(0, 213, 255, 0.6);
+}
+
+.btn-secondary {
+  background: rgba(0, 60, 120, 0.6);
+  border: 1px solid rgba(0, 213, 255, 0.3);
+  border-radius: 4px;
+  color: #e0fcff;
+  padding: 10px 20px;
+  font-size: 14px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.btn-secondary:hover {
+  background: rgba(0, 80, 160, 0.8);
+  border-color: rgba(0, 213, 255, 0.6);
+}
+
+/* 详情弹窗样式 */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 20, 40, 0.8);
+  backdrop-filter: blur(5px);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  background: rgba(0, 30, 60, 0.95);
+  border: 1px solid rgba(0, 213, 255, 0.5);
+  border-radius: 8px;
+  box-shadow: 0 0 30px rgba(0, 213, 255, 0.4);
+  width: 800px;
+  max-width: 90vw;
+  max-height: 80vh;
+  overflow-y: auto;
+  z-index: 1001;
+}
+
+.modal-header {
+  background: linear-gradient(90deg, rgba(0, 60, 120, 0.9), rgba(0, 100, 150, 0.7));
+  padding: 15px 20px;
+  border-bottom: 1px solid rgba(0, 213, 255, 0.4);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.modal-header h2 {
+  font-size: 18px;
+  font-weight: bold;
+  color: #00ffff;
+  margin: 0;
+  text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+.modal-body {
+  padding: 20px;
+}
+
+.station-info-header {
+  margin-bottom: 20px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid rgba(0, 213, 255, 0.3);
+}
+
+.station-basic {
+  text-align: center;
+}
+
+.station-name {
+  font-size: 24px;
+  font-weight: bold;
+  color: #00ffff;
+  margin: 0 0 10px 0;
+  text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+.station-code {
+  font-size: 14px;
+  color: #e0fcff;
+  margin: 0;
+}
+
+.station-info-detail {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.station-info-detail h4 {
+  font-size: 16px;
+  font-weight: bold;
+  color: #62f6fb;
+  margin: 0 0 10px 0;
+  text-shadow: 0 0 3px rgba(0, 212, 255, 0.5);
+}
+
+.station-info-detail ul {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+}
+
+.station-info-detail li {
+  font-size: 14px;
+  color: #e0fcff;
+  padding-left: 20px;
+  position: relative;
+}
+
+.station-info-detail li::before {
+  content: '•';
+  position: absolute;
+  left: 0;
+  color: #00d5ff;
+  font-weight: bold;
+}
+
+.modal-footer {
+  padding: 15px 20px;
+  border-top: 1px solid rgba(0, 213, 255, 0.3);
+  display: flex;
+  justify-content: center;
+}
+
+/* 响应式设计 */
+@media (max-width: 1200px) {
+  .status-overview {
+    grid-template-columns: repeat(2, 1fr);
+  }
+  
+  .device-cards {
+    grid-template-columns: repeat(6, 1fr);
+  }
+}
+
+@media (max-width: 768px) {
+  .sub-title {
+    width: 120px;
+    height: 50px;
+    font-size: 14px;
+  }
+  
+  .sub-title.left-1 {
+    left: 100px;
+  }
+  
+  .sub-title.left-2 {
+    left: 230px;
+  }
+  
+  .sub-title.right-2 {
+    right: 150px;
+  }
+  
+  .sub-title.right-3 {
+    right: 20px;
+  }
+  
+  .system-title {
+    font-size: 24px;
+  }
+  
+  .status-overview {
+    grid-template-columns: 1fr;
+  }
+  
+  .device-cards {
+    grid-template-columns: repeat(6, 1fr);
+  }
+  
+  .device-detail {
+    width: 95vw;
+  }
+}
+
+/* 滚动条样式 */
+.device-cards::-webkit-scrollbar {
+  width: 8px;
+}
+
+.device-cards::-webkit-scrollbar-track {
+  background: rgba(0, 60, 120, 0.3);
+  border-radius: 4px;
+}
+
+.device-cards::-webkit-scrollbar-thumb {
+  background: rgba(0, 213, 255, 0.5);
+  border-radius: 4px;
+}
+
+.device-cards::-webkit-scrollbar-thumb:hover {
+  background: rgba(0, 213, 255, 0.8);
+}
+</style>