Ver Fonte

修改水文站页面

BAI há 1 semana atrás
pai
commit
dc07aca2d8

+ 7 - 0
package-lock.json

@@ -8,6 +8,7 @@
       "name": "heilin",
       "version": "0.0.0",
       "dependencies": {
+        "autofit.js": "^3.2.8",
         "axios": "^1.13.6",
         "cesium": "^1.139.1",
         "echarts": "^6.0.0",
@@ -1349,6 +1350,12 @@
         "node": ">= 4.0.0"
       }
     },
+    "node_modules/autofit.js": {
+      "version": "3.2.8",
+      "resolved": "https://registry.npmmirror.com/autofit.js/-/autofit.js-3.2.8.tgz",
+      "integrity": "sha512-albZNwDIXvcRneEDyZLW3uAIOH0cUQG/TnCGQ7jpfnL0gPn/+1ZNVRuEz3ZuzZvVkQ4HQRplGHjUeMRtPNxjLQ==",
+      "license": "MIT"
+    },
     "node_modules/autolinker": {
       "version": "4.1.5",
       "resolved": "https://registry.npmmirror.com/autolinker/-/autolinker-4.1.5.tgz",

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "autofit.js": "^3.2.8",
     "axios": "^1.13.6",
     "cesium": "^1.139.1",
     "echarts": "^6.0.0",

+ 4 - 1
src/App.vue

@@ -1,7 +1,10 @@
 <template>
   <router-view />
+  <CesiumMap />
 </template>
-
+<script setup>
+import CesiumMap from './components/CesiumMap.vue'
+</script>
 <style>
 * {
   margin: 0;

BIN
src/assets/images/Heilin/POI.png


BIN
src/assets/images/Heilin/测站二维码.png


+ 1 - 1
src/components/CesiumMap.vue

@@ -1,5 +1,5 @@
 <template>
-  <div id="cesiumContainer" style="width: 100%; height: 100%;"></div>
+  <div id="cesiumContainer" class="cesium-ignore-autofit" style="width: 100%; height: 100%; position: relative; z-index: 1; transform: none !important; zoom: 1 !important;"></div>
   
   <!-- POI详情弹窗 -->
   <div v-if="showPopup" class="poi-popup" :style="popupStyle">

+ 13 - 7
src/main.js

@@ -2,15 +2,21 @@ import { createApp } from 'vue'
 import './style.css'
 import App from './App.vue'
 import router from './router'
-import Autofit from './utils/autofit'
+import autofit from 'autofit.js'
 
 const app = createApp(App)
 app.use(router)
 app.mount('#app')
 
-// 初始化全局自适应
-const autofit = new Autofit()
-autofit.init()
-
-// 保存到全局对象,以便在其他地方访问
-window.autofit = autofit
+// 初始化autofit.js
+// 对于包含Cesium地图的页面,我们将在组件内部处理,不使用autofit
+// autofit.init({
+//     dh: 1920,
+//     dw: 1080,
+//     el: '#app', // 应用到整个app
+//     resize: true,
+//     fullScreen: true,
+//     designScale: 1,
+//     transition: 0.3, // 过渡时间设置为0.3秒
+//     cssMode: 'scale', // 使用'scale'模式
+// })

+ 2 - 2
src/style.css

@@ -57,8 +57,8 @@ button:focus-visible {
 }
 
 #app {
-  width: 100%;
-  height: 100%;
+  width: 1920px;
+  height: 1080px;
   margin: 0;
   padding: 0;
   text-align: left;

+ 0 - 58
src/utils/autofit.js

@@ -1,58 +0,0 @@
-class Autofit {
-  constructor(options = {}) {
-    this.options = {
-      designWidth: 1920,
-      designHeight: 1080,
-      container: '#app',
-      ...options
-    };
-    this.container = null;
-  }
-
-  init() {
-    // 获取容器元素
-    this.container = document.querySelector(this.options.container);
-    if (!this.container) {
-      console.error(`Container ${this.options.container} not found`);
-      return;
-    }
-
-    // 初始适配
-    this.fit();
-
-    // 监听窗口 resize 事件
-    window.addEventListener('resize', this.fit.bind(this));
-  }
-
-  fit() {
-    if (!this.container) return;
-
-    const { designWidth, designHeight } = this.options;
-    const windowWidth = window.innerWidth;
-    const windowHeight = window.innerHeight;
-
-    // 计算缩放比例
-    const scaleX = windowWidth / designWidth;
-    const scaleY = windowHeight / designHeight;
-    const scale = Math.min(scaleX, scaleY);
-
-    // 计算偏移量
-    const offsetX = (windowWidth - designWidth * scale) / 2;
-    const offsetY = (windowHeight - designHeight * scale) / 2;
-
-    // 应用变换
-    this.container.style.transform = `scale(${scale}) translate(${offsetX / scale}px, ${offsetY / scale}px)`;
-    this.container.style.transformOrigin = '0 0';
-    this.container.style.width = `${designWidth}px`;
-    this.container.style.height = `${designHeight}px`;
-    this.container.style.position = 'absolute';
-    this.container.style.left = '0';
-    this.container.style.top = '0';
-  }
-
-  destroy() {
-    window.removeEventListener('resize', this.fit.bind(this));
-  }
-}
-
-export default Autofit;

+ 913 - 155
src/views/HeilinStationView.vue

@@ -1,137 +1,154 @@
 <template>
   <div class="dashboard">
-    <div class="bottom-bg"></div>
+    <!-- 背景和基础元素 -->
     <div class="station-bg"></div>
-    <div class="top-title"></div>
-    <div class="system-title">数字孪生黑林小流域</div>
     
-    <!-- 返回按钮 -->
-    <button class="back-btn" @click="goBack">返回</button>
-    
-    <!-- 主要内容区域 -->
-    <div class="main-content">
-      <!-- 左侧面板区域 -->
-      <div class="left-sidebar">
-        <!-- 左侧面板1:水文站介绍 -->
-        <div class="data-card station-intro">
-          <div class="panel-header">
-            <h3>水文站介绍</h3>
-          </div>
-          <div class="panel-content">
-            <div class="image-section">
-              <div class="thumbnail-list">
-                <img src="/src/assets/images/Heilin/图2.jpeg" alt="水文站图片2" @click="changeMainImage('/src/assets/images/Heilin/图2.jpeg')" />
-                <img src="/src/assets/images/Heilin/图3.jpeg" alt="水文站图片3" @click="changeMainImage('/src/assets/images/Heilin/图3.jpeg')" />
-                <img src="/src/assets/images/Heilin/图4.jpeg" alt="水文站图片4" @click="changeMainImage('/src/assets/images/Heilin/图4.jpeg')" />
-                <img src="/src/assets/images/Heilin/图5.jpeg" alt="水文站图片5" @click="changeMainImage('/src/assets/images/Heilin/图5.jpeg')" />
-                <img src="/src/assets/images/Heilin/图6.png" alt="水文站图片6" @click="changeMainImage('/src/assets/images/Heilin/图6.png')" />
+
+      <div class="bottom-bg"></div>
+      <div class="top-title"></div>
+      <div class="system-title">数字孪生黑林小流域</div>
+      
+      <!-- 返回按钮 -->
+      <button class="back-btn" @click="goBack">返回</button>
+      
+      <!-- 主要内容区域 -->
+      <div class="main-content">
+        <!-- 左侧面板区域 -->
+        <div class="left-sidebar">
+          <!-- 左侧面板1:水文站介绍 -->
+          <div class="data-card station-intro">
+            <div class="panel-header">
+              <h3>水文站介绍</h3>
+              <span class="more-btn" @click="showDetailModal = true">更多</span>
+            </div>
+            <div class="panel-content">
+              <div class="image-section">
+                <div class="thumbnail-list">
+                  <img src="/src/assets/images/Heilin/图2.jpeg" alt="水文站图片2" @click="changeMainImage('/src/assets/images/Heilin/图2.jpeg')" />
+                  <img src="/src/assets/images/Heilin/图3.jpeg" alt="水文站图片3" @click="changeMainImage('/src/assets/images/Heilin/图3.jpeg')" />
+                  <img src="/src/assets/images/Heilin/图4.jpeg" alt="水文站图片4" @click="changeMainImage('/src/assets/images/Heilin/图4.jpeg')" />
+                  <img src="/src/assets/images/Heilin/图5.jpeg" alt="水文站图片5" @click="changeMainImage('/src/assets/images/Heilin/图5.jpeg')" />
+                  <img src="/src/assets/images/Heilin/图6.png" alt="水文站图片6" @click="changeMainImage('/src/assets/images/Heilin/图6.png')" />
+                </div>
+                <div class="main-image">
+                  <img :src="mainImageUrl" :alt="mainImageAlt" />
+                </div>
               </div>
-              <div class="main-image">
-                <img :src="mainImageUrl" :alt="mainImageAlt" />
+              <div class="station-text">
+                <p>黑林水文站位于江苏省连云港市赣榆区黑林镇,是沭河上游的重要水文监测站点。</p>
+                <p>建站于1958年,占地面积约2000平方米,主要负责监测沭河上游的水位、流量、降雨量等水文要素。</p>
+                <p>该站配备了先进的水文监测设备,包括自动水位计、流量计、雨量计等,实现了数据的自动采集和传输。</p>
+                <p>多年来,黑林水文站为当地的防洪抗旱、水资源管理和水环境保护提供了重要的科学依据。</p>
               </div>
             </div>
-            <div class="station-text">
-              <p>黑林水文站位于江苏省连云港市赣榆区黑林镇,是沭河上游的重要水文监测站点。</p>
-              <p>建站于1958年,占地面积约2000平方米,主要负责监测沭河上游的水位、流量、降雨量等水文要素。</p>
-              <p>该站配备了先进的水文监测设备,包括自动水位计、流量计、雨量计等,实现了数据的自动采集和传输。</p>
-              <p>多年来,黑林水文站为当地的防洪抗旱、水资源管理和水环境保护提供了重要的科学依据。</p>
-            </div>
-          </div>
-        </div>
-        
-        <!-- 左侧面板2:视频监控 -->
-        <div class="data-card mt-20 video-monitor">
-          <div class="panel-header">
-            <h3>视频监控</h3>
           </div>
-          <div class="panel-content">
-            <div class="video-image">
-              <img src="/src/assets/images/Heilin/图5.jpeg" alt="视频监控画面" />
+          
+          <!-- 左侧面板 2:监控画面列表 -->
+          <div class="data-card mt-20 video-monitor">
+            <div class="panel-header">
+              <h3>监控画面列表</h3>
+            </div>
+            <div class="panel-content">
+              <div class="monitor-select">
+                <div class="select-wrapper">
+                <span class="camera-icon">📹</span>
+                <select v-model="selectedMonitor">
+                  <option value="图5">七星关区赤水河赤水河河道</option>
+                  <option value="图2">监控点 2 - 河道</option>
+                  <option value="图3">监控点 3 - 大坝</option>
+                  <option value="图4">监控点 4 - 泵站</option>
+                  <option value="图5">监控点 5 - 变电站</option>
+                  <option value="图6">监控点 6 - 仓库</option>
+                </select>
+              </div>
+            </div>
+            <div class="monitor-image">
+              <img :src="'/src/assets/images/Heilin/' + (selectedMonitor === '图6' ? selectedMonitor + '.png' : selectedMonitor + '.jpeg')" :alt="selectedMonitor" />
             </div>
           </div>
         </div>
       </div>
       
       <!-- 中间空间 -->
-      <div class="center-space"></div>
+      <div class="center-space">
+        <div class="poi-container">
+          <div class="poi-item" style="left: 565px; top: 741px;">
+            <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: 895px;">
+            <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: 851px;">
+            <div class="poi-label">地下水监测井</div>
+            <img src="/src/assets/images/Heilin/POI.png" alt="POI图标" class="poi-icon" />
+          </div>
+        </div>
+      </div>
       
       <!-- 右侧面板区域 -->
       <div class="right-sidebar">
-        <!-- 右侧面板1:历史事件 -->
+        <!-- 右侧面板 1:监测数据 -->
         <div class="data-card">
           <div class="panel-header">
-            <h3>历史事件</h3>
+            <h3>监测数据</h3>
           </div>
           <div class="panel-content">
-            <div class="event-item">
-              <div class="event-date">2023-07-21</div>
-              <div class="event-title">暴雨洪水</div>
-              <div class="event-desc">受台风影响,黑林地区出现强降雨,沭河水位迅速上涨,本站测得最大流量120m³/s。</div>
-            </div>
-            <div class="event-item">
-              <div class="event-date">2022-06-15</div>
-              <div class="event-title">设备升级</div>
-              <div class="event-desc">完成水文监测设备升级,实现了数据的实时传输和远程监控。</div>
-            </div>
-            <div class="event-item">
-              <div class="event-date">2021-08-05</div>
-              <div class="event-title">洪水过程</div>
-              <div class="event-desc">沭河上游出现持续降雨,本站监测到完整的洪水过程,为防洪决策提供了重要依据。</div>
+            <!-- 第一行:水位卡片 -->
+            <div class="water-level-cards">
+              <div class="water-card">
+                <div class="card-title">实时水位</div>
+                <div class="card-value">36.25<span class="unit">m</span></div>
+              </div>
+              <div class="water-card">
+                <div class="card-title">警戒水位</div>
+                <div class="card-value warning">35.00<span class="unit">m</span></div>
+              </div>
+              <div class="water-card">
+                <div class="card-title">保证水位</div>
+                <div class="card-value danger">36.50<span class="unit">m</span></div>
+              </div>
+              <div class="water-card">
+                <div class="card-title">实测最高水位</div>
+                <div class="card-value highlight">36.46<span class="unit">m</span></div>
+              </div>
             </div>
-            <div class="event-item">
-              <div class="event-date">2020-05-10</div>
-              <div class="event-title">水质监测</div>
-              <div class="event-desc">开展水质监测工作,各项指标均符合国家地表水标准。</div>
+            <!-- 第二行:图表 -->
+            <div class="chart-container">
+              <canvas ref="combinedChart"></canvas>
             </div>
           </div>
         </div>
         
-        <!-- 右侧面板2:设备状态 -->
+        <!-- 右侧面板 2:蒸发量过程线 -->
         <div class="data-card mt-20">
           <div class="panel-header">
-            <h3>设备状态</h3>
+            <h3>蒸发量过程线</h3>
           </div>
           <div class="panel-content">
-            <div class="device-item">
-              <span class="label">水位计</span>
-              <span class="status online">在线</span>
-            </div>
-            <div class="device-item">
-              <span class="label">流量计</span>
-              <span class="status online">在线</span>
-            </div>
-            <div class="device-item">
-              <span class="label">雨量计</span>
-              <span class="status online">在线</span>
-            </div>
-            <div class="device-item">
-              <span class="label">水质监测仪</span>
-              <span class="status online">在线</span>
+            <div class="chart-container">
+              <canvas ref="evaporationChart"></canvas>
             </div>
           </div>
         </div>
         
-        <!-- 右侧面板3:实时数据 -->
+        <!-- 右侧面板 3:土壤含水量过程线 -->
         <div class="data-card mt-20">
           <div class="panel-header">
-            <h3>实时数据</h3>
+            <h3>土壤含水量过程线</h3>
           </div>
           <div class="panel-content">
-            <div class="realtime-item">
-              <span class="label">当前水位</span>
-              <span class="value">3.25m</span>
-            </div>
-            <div class="realtime-item">
-              <span class="label">当前流量</span>
-              <span class="value">12.5m³/s</span>
-            </div>
-            <div class="realtime-item">
-              <span class="label">当前降雨量</span>
-              <span class="value">0.5mm/h</span>
-            </div>
-            <div class="realtime-item">
-              <span class="label">水温</span>
-              <span class="value">18.5°C</span>
+            <div class="chart-container">
+              <canvas ref="soilMoistureChart"></canvas>
             </div>
           </div>
         </div>
@@ -140,6 +157,137 @@
     
     <!-- 渐变装饰层(四周暗角) -->
     <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">测站编码:640324</p>
+              <p class="station-basin">所在流域:青口河</p>
+            </div>
+            <div class="station-qr">
+              <img src="/src/assets/images/Heilin/测站二维码.png" alt="测站二维码" />
+            </div>
+          </div>
+          
+          <!-- 测站沿革 -->
+          <div class="detail-section">
+            <h4>测站沿革</h4>
+            <p>黑林水文站位于青口河中游,是集水面积 190 km²的重要控制站,也是小塔山水库入库控制断面。该站于 1976 年 7 月建站,采用黑林站冻结基面(1976 年设站时冻结,非黄海基面)。</p>
+          </div>
+          
+          <!-- 监测项目 -->
+          <div class="detail-section">
+            <h4>监测项目</h4>
+            <p>水位、流量、降雨量、水质、蒸发量、水土流失监测、地下水</p>
+          </div>
+          
+          <!-- 历史数据 -->
+          <div class="detail-section">
+            <h4>历史数据</h4>
+            <div class="data-grid">
+              <div class="data-item">
+                <span class="data-label">2024 年实测最大洪峰</span>
+                <span class="data-value">371 m³/s</span>
+              </div>
+              <div class="data-item">
+                <span class="data-label">多年平均蒸发量</span>
+                <span class="data-value">845.7 mm</span>
+              </div>
+            </div>
+          </div>
+          
+          <!-- 历史最高水位 -->
+          <div class="detail-section">
+            <h4>历史最高水位</h4>
+            <div class="extreme-data">
+              <div class="data-row">
+                <span class="data-label">水位:</span>
+                <span class="data-value highlight">36.46 m</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">出现时间:</span>
+                <span class="data-text">2024 年 7 月 7 日 11 时 36 分</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">对应洪峰:</span>
+                <span class="data-text">371 m³/s(2024 年 7 月实测)</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">背景:</span>
+                <span class="data-text">受沂沭河 1 号洪水与区域特大暴雨影响,为设站以来实测最高水位</span>
+              </div>
+            </div>
+          </div>
+          
+          <!-- 历史最低水位 -->
+          <div class="detail-section">
+            <h4>历史最低水位</h4>
+            <div class="extreme-data">
+              <div class="data-row">
+                <span class="data-label">水位:</span>
+                <span class="data-value low">32.10 m</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">出现时间:</span>
+                <span class="data-text">2019 年 12 月(枯水期)</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">说明:</span>
+                <span class="data-text">为长期监测资料整编成果,属流域典型枯水极值</span>
+              </div>
+            </div>
+          </div>
+          
+          <!-- 水位基面与说明 -->
+          <div class="detail-section">
+            <h4>水位基面与说明</h4>
+            <div class="base-info">
+              <div class="data-row">
+                <span class="data-label">基面:</span>
+                <span class="data-text">黑林站冻结基面(1976 年设站时冻结,非黄海基面)</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">警戒水位:</span>
+                <span class="data-value warning">35.00 m</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">保证水位:</span>
+                <span class="data-value danger">36.50 m</span>
+                <span class="data-note">(2024 年最高水位接近保证水位)</span>
+              </div>
+            </div>
+          </div>
+          
+          <!-- 补充信息 -->
+          <div class="detail-section">
+            <h4>补充信息</h4>
+            <div class="supplement-info">
+              <div class="data-row">
+                <span class="data-label">集水面积:</span>
+                <span class="data-text">190 km²(青口河中游控制站,小塔山水库入库控制断面)</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">建站时间:</span>
+                <span class="data-text">1976 年 7 月</span>
+              </div>
+              <div class="data-row">
+                <span class="data-label">监测项目:</span>
+                <span class="data-text">水位、流量、降水、含沙量、水质、气象辅助等</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -149,9 +297,13 @@ import { useRouter } from 'vue-router'
 import GradientOverlay from '../components/gradient-overlay.vue'
 
 const router = useRouter()
-const flowChart = ref(null)
-const mainImageUrl = ref('/src/assets/images/Heilin/图1.jpeg')
-const mainImageAlt = ref('水文站图片1')
+const mainImageUrl = ref('/src/assets/images/Heilin/图5.jpeg')
+const mainImageAlt = ref('水文站图片 5')
+const selectedMonitor = ref('图5')
+const showDetailModal = ref(false)
+const combinedChart = ref(null)
+const evaporationChart = ref(null)
+const soilMoistureChart = ref(null)
 
 const goBack = () => {
   router.push('/')
@@ -159,108 +311,308 @@ const goBack = () => {
 
 const changeMainImage = (imageUrl) => {
   mainImageUrl.value = imageUrl
-  // 提取图片名称作为alt文本
+  // 提取图片名称作为 alt 文本
   const parts = imageUrl.split('/')
   const imageName = parts[parts.length - 1]
   mainImageAlt.value = `水文站图片${imageName.split('.')[0]}`
 }
 
-const drawFlowChart = () => {
-  const canvas = flowChart.value
+const closeModal = () => {
+  showDetailModal.value = false
+}
+
+// 绘制综合图表(水位、流量、降雨量)
+const drawCombinedChart = () => {
+  const canvas = combinedChart.value
   if (!canvas) return
   
   const ctx = canvas.getContext('2d')
-  ctx.clearRect(0, 0, canvas.width, canvas.height)
+  const width = canvas.width = canvas.offsetWidth
+  const height = canvas.height = 180
+  const padding = { top: 30, right: 70, bottom: 25, left: 40 }
+  const chartWidth = width - padding.left - padding.right
+  const chartHeight = height - padding.top - padding.bottom
   
-  // 模拟流量数据
-  const data = [8, 12, 15, 10, 18, 22, 25, 20, 15, 12, 10, 14]
-  const labels = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
+  ctx.clearRect(0, 0, width, height)
   
-  // 计算画布尺寸
-  const width = canvas.width
-  const height = canvas.height
-  const padding = 40
-  const chartWidth = width - 2 * padding
-  const chartHeight = height - 2 * padding
+  // 模拟数据
+  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 maxValue = Math.max(...data)
-  const minValue = Math.min(...data)
-  const valueRange = maxValue - minValue
+  const maxWaterLevel = Math.max(...waterLevel)
+  const minWaterLevel = Math.min(...waterLevel)
+  const maxFlow = Math.max(...flow)
+  const maxRainfall = Math.max(...rainfall)
+  
+  // 绘制主轴线
+  ctx.strokeStyle = 'rgba(0, 213, 255, 0.8)'
+  ctx.lineWidth = 1.5
+  ctx.beginPath()
+  ctx.moveTo(padding.left, padding.top)
+  ctx.lineTo(padding.left, height - padding.bottom)
+  ctx.lineTo(width - padding.right, height - padding.bottom)
+  ctx.stroke()
   
   // 绘制网格
-  ctx.strokeStyle = 'rgba(0, 213, 255, 0.2)'
+  ctx.strokeStyle = 'rgba(0, 213, 255, 0.3)'
+  ctx.lineWidth = 0.8
+  for (let i = 0; i <= 5; i++) {
+    const y = padding.top + (chartHeight / 5) * i
+    ctx.beginPath()
+    ctx.moveTo(padding.left, y)
+    ctx.lineTo(width - padding.right, y)
+    ctx.stroke()
+  }
+  
+  // 绘制降雨量柱状图(从上往下)
+  const barWidth = chartWidth / months.length * 0.5
+  ctx.fillStyle = 'rgba(78, 205, 196, 0.7)'
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / months.length) * i + (chartWidth / months.length - barWidth) / 2
+    const barHeight = (rainfall[i] / maxRainfall) * chartHeight * 0.4
+    ctx.fillRect(x, padding.top, barWidth, barHeight)
+  }
+  
+  // 绘制水位线(蓝色)
+  ctx.strokeStyle = 'rgba(0, 100, 255, 1)'
+  ctx.lineWidth = 2
+  ctx.beginPath()
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    const y = padding.top + chartHeight - ((waterLevel[i] - minWaterLevel) / (maxWaterLevel - minWaterLevel)) * chartHeight
+    if (i === 0) {
+      ctx.moveTo(x, y)
+    } else {
+      ctx.lineTo(x, y)
+    }
+  }
+  ctx.stroke()
+  
+  // 绘制流量线(青蓝色)
+  ctx.strokeStyle = 'rgba(0, 255, 255, 1)'
+  ctx.lineWidth = 2
+  ctx.beginPath()
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    const y = padding.top + chartHeight - ((flow[i] / maxFlow) * chartHeight)
+    if (i === 0) {
+      ctx.moveTo(x, y)
+    } else {
+      ctx.lineTo(x, y)
+    }
+  }
+  ctx.stroke()
+  
+  // 绘制图例(顶部一字排开)
+  ctx.font = '10px Arial'
+  const legendItems = [
+    { color: 'rgba(0, 100, 255, 1)', text: '水位' },
+    { color: 'rgba(0, 255, 255, 1)', text: '流量' },
+    { color: 'rgba(78, 205, 196, 1)', text: '降雨量' }
+  ]
+  const legendX = padding.left
+  const legendY = 12
+  const legendGap = 60
+  
+  legendItems.forEach((item, index) => {
+    const x = legendX + index * legendGap
+    ctx.fillStyle = item.color
+    ctx.fillRect(x, legendY, 8, 8)
+    ctx.fillText(item.text, x + 12, legendY + 7)
+  })
+  
+  // 绘制流量侧轴线
+  ctx.strokeStyle = 'rgba(0, 255, 255, 0.8)'
   ctx.lineWidth = 1
+  ctx.setLineDash([5, 5])
+  ctx.beginPath()
+  ctx.moveTo(width - padding.right - 20, padding.top)
+  ctx.lineTo(width - padding.right - 20, height - padding.bottom)
+  ctx.stroke()
+  ctx.setLineDash([])
   
-  // 绘制水平网格线
+  // 流量侧轴线刻度
+  ctx.fillStyle = 'rgba(0, 255, 255, 0.9)'
+  ctx.font = '9px Arial'
   for (let i = 0; i <= 5; i++) {
-    const y = padding + (chartHeight / 5) * i
+    const y = padding.top + (chartHeight / 5) * i
     ctx.beginPath()
-    ctx.moveTo(padding, y)
-    ctx.lineTo(width - padding, y)
+    ctx.moveTo(width - padding.right - 20, y)
+    ctx.lineTo(width - padding.right - 15, y)
     ctx.stroke()
-    
-    // 绘制刻度
-    const value = maxValue - (valueRange / 5) * i
-    ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
-    ctx.font = '12px Arial'
-    ctx.textAlign = 'right'
-    ctx.fillText(value.toFixed(1), padding - 10, y + 4)
+    const value = Math.round(maxFlow - (maxFlow / 5) * i)
+    ctx.fillText(value, width - padding.right - 50, y + 3)
   }
+  ctx.fillText('m³/s', width - padding.right - 50, padding.top - 8)
   
-  // 绘制垂直网格线
-  for (let i = 0; i < labels.length; i++) {
-    const x = padding + (chartWidth / (labels.length - 1)) * i
+  // 绘制 X 轴标签
+  ctx.fillStyle = 'rgba(255, 255, 255, 0.9)'
+  ctx.font = '9px Arial'
+  ctx.textAlign = 'center'
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    ctx.fillText(months[i], x, height - 8)
+  }
+  
+  // 绘制 Y 轴标签
+  ctx.fillStyle = 'rgba(255, 255, 255, 0.9)'
+  ctx.font = '9px Arial'
+  ctx.textAlign = 'right'
+  for (let i = 0; i <= 5; i++) {
+    const y = padding.top + (chartHeight / 5) * i
+    const value = Math.round(minWaterLevel + (maxWaterLevel - minWaterLevel) / 5 * (5 - i))
+    ctx.fillText(value, padding.left - 8, y + 3)
+  }
+  ctx.fillText('m', padding.left - 8, padding.top - 8)
+}
+
+// 绘制蒸发量过程线
+const drawEvaporationChart = () => {
+  const canvas = evaporationChart.value
+  if (!canvas) return
+  
+  const ctx = canvas.getContext('2d')
+  const width = canvas.width = canvas.offsetWidth
+  const height = canvas.height = 200
+  const padding = { top: 20, right: 30, bottom: 30, left: 50 }
+  const chartWidth = width - padding.left - padding.right
+  const chartHeight = height - padding.top - padding.bottom
+  
+  ctx.clearRect(0, 0, width, height)
+  
+  // 模拟数据
+  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 maxEvaporation = Math.max(...evaporation)
+  const minEvaporation = Math.min(...evaporation)
+  
+  // 绘制网格
+  ctx.strokeStyle = 'rgba(0, 213, 255, 0.2)'
+  ctx.lineWidth = 1
+  for (let i = 0; i <= 5; i++) {
+    const y = padding.top + (chartHeight / 5) * i
     ctx.beginPath()
-    ctx.moveTo(x, padding)
-    ctx.lineTo(x, height - padding)
+    ctx.moveTo(padding.left, y)
+    ctx.lineTo(width - padding.right, y)
     ctx.stroke()
-    
-    // 绘制刻度
-    ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
-    ctx.font = '12px Arial'
-    ctx.textAlign = 'center'
-    ctx.fillText(labels[i], x, height - padding + 20)
   }
   
-  // 绘制流量曲线
-  ctx.strokeStyle = 'rgba(0, 255, 255, 1)'
+  // 绘制蒸发量线
+  ctx.strokeStyle = 'rgba(255, 165, 2, 1)'
   ctx.lineWidth = 2
   ctx.beginPath()
-  
-  for (let i = 0; i < data.length; i++) {
-    const x = padding + (chartWidth / (data.length - 1)) * i
-    const y = padding + chartHeight - ((data[i] - minValue) / valueRange) * chartHeight
-    
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    const y = padding.top + chartHeight - ((evaporation[i] - minEvaporation) / (maxEvaporation - minEvaporation)) * chartHeight
     if (i === 0) {
       ctx.moveTo(x, y)
     } else {
       ctx.lineTo(x, y)
     }
   }
+  ctx.stroke()
+  
+  // 绘制数据点
+  ctx.fillStyle = 'rgba(255, 165, 2, 1)'
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    const y = padding.top + chartHeight - ((evaporation[i] - minEvaporation) / (maxEvaporation - minEvaporation)) * chartHeight
+    ctx.beginPath()
+    ctx.arc(x, y, 3, 0, Math.PI * 2)
+    ctx.fill()
+  }
+  
+  // 绘制 X 轴标签
+  ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
+  ctx.textAlign = 'center'
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    ctx.fillText(months[i], x, height - 10)
+  }
+}
+
+// 绘制土壤含水量过程线
+const drawSoilMoistureChart = () => {
+  const canvas = soilMoistureChart.value
+  if (!canvas) return
+  
+  const ctx = canvas.getContext('2d')
+  const width = canvas.width = canvas.offsetWidth
+  const height = canvas.height = 200
+  const padding = { top: 20, right: 30, bottom: 30, left: 50 }
+  const chartWidth = width - padding.left - padding.right
+  const chartHeight = height - padding.top - padding.bottom
   
+  ctx.clearRect(0, 0, width, height)
+  
+  // 模拟数据
+  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 maxMoisture = Math.max(...soilMoisture)
+  const minMoisture = Math.min(...soilMoisture)
+  
+  // 绘制网格
+  ctx.strokeStyle = 'rgba(0, 213, 255, 0.2)'
+  ctx.lineWidth = 1
+  for (let i = 0; i <= 5; i++) {
+    const y = padding.top + (chartHeight / 5) * i
+    ctx.beginPath()
+    ctx.moveTo(padding.left, y)
+    ctx.lineTo(width - padding.right, y)
+    ctx.stroke()
+  }
+  
+  // 绘制土壤含水量线
+  ctx.strokeStyle = 'rgba(139, 90, 43, 1)'
+  ctx.lineWidth = 2
+  ctx.beginPath()
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    const y = padding.top + chartHeight - ((soilMoisture[i] - minMoisture) / (maxMoisture - minMoisture)) * chartHeight
+    if (i === 0) {
+      ctx.moveTo(x, y)
+    } else {
+      ctx.lineTo(x, y)
+    }
+  }
   ctx.stroke()
   
-  // 填充曲线下方区域
-  ctx.fillStyle = 'rgba(0, 255, 255, 0.2)'
-  ctx.lineTo(width - padding, height - padding)
-  ctx.lineTo(padding, height - padding)
+  // 填充区域
+  ctx.fillStyle = 'rgba(139, 90, 43, 0.2)'
+  ctx.lineTo(padding.left + chartWidth, padding.top + chartHeight)
+  ctx.lineTo(padding.left, padding.top + chartHeight)
   ctx.closePath()
   ctx.fill()
+  
+  // 绘制 X 轴标签
+  ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
+  ctx.textAlign = 'center'
+  for (let i = 0; i < months.length; i++) {
+    const x = padding.left + (chartWidth / (months.length - 1)) * i
+    ctx.fillText(months[i], x, height - 10)
+  }
 }
 
 onMounted(() => {
-  drawFlowChart()
+  drawCombinedChart()
+  drawEvaporationChart()
+  drawSoilMoistureChart()
   
   // 监听窗口 resize 事件,重新绘制图表
-  window.addEventListener('resize', drawFlowChart)
+  window.addEventListener('resize', () => {
+    drawCombinedChart()
+    drawEvaporationChart()
+    drawSoilMoistureChart()
+  })
 })
 </script>
 
 <style scoped>
 .dashboard {
-  width: 1920px;
-  height: 1080px;
+  width: 100%;
+  height: 100%;
   overflow: hidden;
   position: relative;
 }
@@ -335,7 +687,8 @@ onMounted(() => {
   cursor: pointer;
   font-size: 14px;
   transition: all 0.3s ease;
-  z-index: 4;
+  z-index: 100;
+  pointer-events: auto;
 }
 
 .back-btn:hover {
@@ -362,6 +715,58 @@ onMounted(() => {
 
 .center-space {
   flex: 1;
+  position: relative;
+}
+
+.poi-container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  pointer-events: none;
+}
+
+.poi-item {
+  position: absolute;
+  transform: translate(-50%, -50%);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  pointer-events: auto;
+}
+
+.poi-icon {
+  width: 40px;
+  height: 40px;
+  object-fit: contain;
+  animation: pulse 2s infinite;
+  cursor: pointer;
+}
+
+.poi-label {
+  background: rgba(0, 60, 120, 0.9);
+  color: #ffffff;
+  padding: 4px 8px;
+  border-radius: 4px;
+  font-size: 12px;
+  margin-bottom: 5px;
+  white-space: nowrap;
+  border: 1px solid rgba(0, 213, 255, 0.5);
+  box-shadow: 0 0 5px rgba(0, 213, 255, 0.5);
+}
+
+@keyframes pulse {
+  0% {
+    transform: scale(1);
+    filter: drop-shadow(0 0 5px rgba(0, 213, 255, 0.5));
+  }
+  50% {
+    transform: scale(1.1);
+    filter: drop-shadow(0 0 10px rgba(0, 213, 255, 0.8));
+  }
+  100% {
+    transform: scale(1);
+    filter: drop-shadow(0 0 5px rgba(0, 213, 255, 0.5));
+  }
 }
 
 .right-sidebar {
@@ -477,6 +882,119 @@ onMounted(() => {
   min-height: 350px;
 }
 
+.monitor-select {
+  margin-bottom: 15px;
+}
+
+.select-wrapper {
+  position: relative;
+  background: linear-gradient(90deg, rgba(0, 60, 120, 0.9), rgba(0, 100, 150, 0.7));
+  border: 2px solid rgba(0, 213, 255, 0.5);
+  border-radius: 4px;
+  padding: 6px 12px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  box-shadow: 0 0 10px rgba(0, 213, 255, 0.3);
+}
+
+.camera-icon {
+  font-size: 16px;
+}
+
+.select-wrapper select {
+  flex: 1;
+  background: transparent;
+  border: none;
+  color: #ffffff;
+  font-size: 14px;
+  outline: none;
+  cursor: pointer;
+  font-family: Arial, sans-serif;
+}
+
+.select-wrapper select option {
+  background: rgba(0, 60, 120, 0.95);
+  color: #ffffff;
+  padding: 10px;
+}
+
+.monitor-image {
+  width: 100%;
+  height: 200px;
+  border-radius: 4px;
+  overflow: hidden;
+  border: 2px solid rgba(0, 212, 255, 0.3);
+  box-shadow: 0 0 15px rgba(0, 212, 255, 0.2);
+}
+
+.monitor-image img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.chart-container {
+  width: 100%;
+  height: 180px;
+  position: relative;
+  margin-top: 15px;
+}
+
+.water-level-cards {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 10px;
+}
+
+.water-card {
+  background: rgba(0, 60, 120, 0.5);
+  border: 1px solid rgba(0, 213, 255, 0.3);
+  border-radius: 4px;
+  padding: 10px;
+  text-align: center;
+  transition: all 0.3s ease;
+}
+
+.water-card:hover {
+  border-color: rgba(0, 213, 255, 0.8);
+  box-shadow: 0 0 10px rgba(0, 213, 255, 0.5);
+}
+
+.card-title {
+  font-size: 12px;
+  color: #62f6fb;
+  margin-bottom: 5px;
+}
+
+.card-value {
+  font-size: 18px;
+  font-weight: bold;
+  color: #00ffff;
+  text-shadow: 0 0 5px rgba(0, 213, 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: #ff6b6b;
+  text-shadow: 0 0 8px rgba(255, 107, 107, 0.8);
+}
+
+.unit {
+  font-size: 12px;
+  margin-left: 2px;
+  opacity: 0.8;
+}
+
 .video-image {
   width: 100%;
   height: 100%;
@@ -638,4 +1156,244 @@ onMounted(() => {
     padding: 15px;
   }
 }
+
+/* 弹窗样式 */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.7);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  background: linear-gradient(135deg, rgba(0, 26, 51, 0.95) 0%, rgba(0, 51, 102, 0.95) 100%);
+  border: 2px solid rgba(0, 213, 255, 0.5);
+  border-radius: 8px;
+  width: 800px;
+  max-height: 80vh;
+  overflow-y: auto;
+  box-shadow: 0 0 30px rgba(0, 213, 255, 0.5);
+}
+
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px;
+  border-bottom: 1px solid rgba(0, 213, 255, 0.3);
+}
+
+.modal-header h2 {
+  margin: 0;
+  font-size: 24px;
+  color: #e0fcff;
+  text-shadow: 0 0 10px rgba(0, 213, 255, 0.5);
+}
+
+.close-btn {
+  font-size: 32px;
+  color: #62f6fb;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.close-btn:hover {
+  color: #00ffff;
+  text-shadow: 0 0 10px rgba(0, 213, 255, 0.8);
+}
+
+.modal-body {
+  padding: 20px;
+}
+
+.detail-section {
+  margin-bottom: 20px;
+}
+
+.detail-section h4 {
+  margin: 0 0 10px 0;
+  font-size: 18px;
+  color: #00ffff;
+  text-shadow: 0 0 5px rgba(0, 213, 255, 0.5);
+  border-left: 3px solid rgba(0, 213, 255, 0.8);
+  padding-left: 10px;
+}
+
+.detail-section p {
+  margin: 0 0 8px 0;
+  font-size: 14px;
+  color: #e0fcff;
+  line-height: 1.6;
+}
+
+.detail-section p strong {
+  color: #62f6fb;
+}
+
+/* 弹窗头部信息布局 */
+.station-info-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px 20px;
+  background: rgba(0, 60, 120, 0.5);
+  border-radius: 6px;
+  margin-bottom: 20px;
+  border: 1px solid rgba(0, 213, 255, 0.3);
+}
+
+.station-basic {
+  flex: 1;
+}
+
+.station-name {
+  margin: 0 0 10px 0;
+  font-size: 28px;
+  color: #00ffff;
+  text-shadow: 0 0 10px rgba(0, 213, 255, 0.8);
+}
+
+.station-code,
+.station-basin {
+  margin: 5px 0;
+  font-size: 14px;
+  color: #e0fcff;
+}
+
+.station-qr {
+  width: 120px;
+  height: 120px;
+  border: 2px solid rgba(0, 213, 255, 0.5);
+  border-radius: 6px;
+  padding: 5px;
+  background: rgba(255, 255, 255, 0.95);
+}
+
+.station-qr img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+}
+
+/* 数据网格布局 */
+.data-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  margin-top: 10px;
+}
+
+.data-item {
+  background: rgba(0, 60, 120, 0.3);
+  border: 1px solid rgba(0, 213, 255, 0.2);
+  border-radius: 4px;
+  padding: 12px;
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+}
+
+.data-label {
+  font-size: 13px;
+  color: #62f6fb;
+}
+
+.data-value {
+  font-size: 18px;
+  font-weight: bold;
+  color: #00ffff;
+  text-shadow: 0 0 5px rgba(0, 213, 255, 0.5);
+}
+
+/* 极值数据样式 */
+.extreme-data,
+.base-info,
+.supplement-info {
+  background: rgba(0, 60, 120, 0.3);
+  border: 1px solid rgba(0, 213, 255, 0.2);
+  border-radius: 4px;
+  padding: 15px;
+  margin-top: 10px;
+}
+
+.data-row {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 10px;
+  gap: 10px;
+}
+
+.data-row:last-child {
+  margin-bottom: 0;
+}
+
+.data-label {
+  font-size: 14px;
+  color: #62f6fb;
+  min-width: 80px;
+  flex-shrink: 0;
+}
+
+.data-text {
+  font-size: 14px;
+  color: #e0fcff;
+  line-height: 1.6;
+  flex: 1;
+}
+
+.data-value {
+  font-size: 16px;
+  font-weight: bold;
+  color: #00ffff;
+  text-shadow: 0 0 5px rgba(0, 213, 255, 0.5);
+}
+
+.data-value.highlight {
+  color: #ff6b6b;
+  text-shadow: 0 0 8px rgba(255, 107, 107, 0.8);
+}
+
+.data-value.low {
+  color: #4ecdc4;
+  text-shadow: 0 0 8px rgba(78, 205, 196, 0.8);
+}
+
+.data-value.warning {
+  color: #ffa502;
+  text-shadow: 0 0 8px rgba(255, 165, 2, 0.8);
+}
+
+.data-value.danger {
+  color: #ff4757;
+  text-shadow: 0 0 8px rgba(255, 71, 87, 0.8);
+}
+
+.data-note {
+  font-size: 12px;
+  color: rgba(255, 255, 255, 0.6);
+  margin-left: 5px;
+}
+
+/* 更多按钮样式 */
+.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>