WQQ 7 цаг өмнө
parent
commit
b072623af4

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
public/黑林下游堤防.geojson


+ 108 - 1
src/components/CesiumMap.vue

@@ -29,7 +29,7 @@ import * as Cesium from 'cesium'
 import 'cesium/Build/CesiumUnminified/Widgets/widgets.css'
 import { useRouter } from 'vue-router'
 
-const emit = defineEmits(['toggleMap'])
+const emit = defineEmits(['toggleMap', 'loadEmbankmentWarningData'])
 
 const viewer = ref(null)
 const showPopup = ref(false)
@@ -43,6 +43,10 @@ const props = defineProps({
   simulationData: {
     type: Object,
     default: () => ({})
+  },
+  loadEmbankmentWarning: {
+    type: Boolean,
+    default: false
   }
 })
 
@@ -260,10 +264,113 @@ const updateMapMarkers = () => {
   }
 }
 
+const updateEmbankmentWarning = () => {
+  if (!viewer.value) return
+  
+  const simulationData = props.simulationData || {}
+  const waterLevel = parseFloat(simulationData.heilinStation?.waterLevel) || 3.25
+  
+  // 只有在有预演数据时才更新堤防颜色
+  if (!simulationData.heilinStation) return
+  
+  for (let i = 0; i < viewer.value.dataSources.length; i++) {
+    const dataSource = viewer.value.dataSources.get(i)
+    if (dataSource && dataSource.name === '堤防预警') {
+      const entities = dataSource.entities.values
+      for (const entity of entities) {
+        const properties = entity.properties
+        if (properties && properties.Stage_Warn && properties.Stage_Guar) {
+          const stageWarn = properties.Stage_Warn.getValue()
+          const stageGuar = properties.Stage_Guar.getValue()
+          
+          let warningLevel = 0
+          if (waterLevel >= stageGuar) {
+            warningLevel = 4
+          } else if (waterLevel >= stageWarn) {
+            warningLevel = 2
+          }
+          
+          if (warningLevel === 4) {
+            entity.polyline.material = Cesium.Color.fromCssColorString('#ff6b6b')
+          } else if (warningLevel === 2) {
+            entity.polyline.material = Cesium.Color.fromCssColorString('#ffd93d')
+          } else {
+            entity.polyline.material = Cesium.Color.fromCssColorString('#22c55e')
+          }
+        }
+      }
+    }
+  }
+}
+
 watch(() => props.simulationData, () => {
   updateMapMarkers()
+  updateEmbankmentWarning()
 }, { deep: true, immediate: true })
 
+watch(() => props.loadEmbankmentWarning, async (newVal) => {
+  if (newVal) {
+    await loadEmbankmentWarningData()
+    emit('loadEmbankmentWarningData')
+  } else {
+    // 移除堤防图层
+    if (viewer.value) {
+      for (let i = viewer.value.dataSources.length - 1; i >= 0; i--) {
+        const dataSource = viewer.value.dataSources.get(i)
+        if (dataSource && dataSource.name === '堤防预警') {
+          viewer.value.dataSources.remove(dataSource)
+        }
+      }
+    }
+  }
+})
+
+const loadEmbankmentWarningData = async () => {
+  if (!viewer.value) return
+  
+  try {
+    const response = await fetch('/黑林下游堤防.geojson')
+    const geojson = await response.json()
+    
+    const embankmentDataSource = await Cesium.GeoJsonDataSource.load(geojson, {
+      stroke: Cesium.Color.fromCssColorString('#22c55e'),
+      strokeWidth: 4,
+      fill: Cesium.Color.fromCssColorString('#22c55e').withAlpha(0.3)
+    })
+    
+    embankmentDataSource.name = '堤防预警'
+    viewer.value.dataSources.add(embankmentDataSource)
+    
+    const entities = embankmentDataSource.entities.values
+    for (const entity of entities) {
+      entity.polyline.width = 4
+      // 根据WarningLevel设置颜色
+      const properties = entity.properties
+      if (properties && properties.WarningLevel) {
+        const warningLevel = properties.WarningLevel.getValue()
+        console.log('堤防ID:', properties.DikeID?.getValue(), '预警级别:', warningLevel)
+        if (warningLevel === 0 || warningLevel === 1) {
+          entity.polyline.material = Cesium.Color.fromCssColorString('#22c55e') // 正常 - 绿色
+        } else if (warningLevel === 2 || warningLevel === 3) {
+          entity.polyline.material = Cesium.Color.fromCssColorString('#ffd93d') // 超警 - 黄色
+        } else if (warningLevel === 4) {
+          entity.polyline.material = Cesium.Color.fromCssColorString('#ff6b6b') // 超保 - 红色
+        } else {
+          entity.polyline.material = Cesium.Color.fromCssColorString('#22c55e') // 默认为绿色
+        }
+      } else {
+        entity.polyline.material = Cesium.Color.fromCssColorString('#22c55e') // 默认为绿色
+      }
+    }
+    
+    // 不再自动调整视角,保持当前视角
+    
+    console.log('堤防预警数据加载成功')
+  } catch (error) {
+    console.error('加载堤防预警数据失败:', error)
+  }
+}
+
 const createPoiImage = () => {
   const canvas = document.createElement('canvas')
   canvas.width = 40

+ 347 - 122
src/components/HydrologyForecastPanel.vue

@@ -63,9 +63,26 @@
         </div>
       </div>
 
+      <div class="data-card mt-20">
+        <div class="card-header" @click="toggleRainfallProcess">
+          <h3 class="card-title">雨量过程线</h3>
+          <div class="header-actions">
+            <span class="toggle-btn">{{ rainfallProcessExpanded ? '▼' : '▶' }}</span>
+          </div>
+        </div>
+        <div v-if="rainfallProcessExpanded" class="card-body">
+          <div class="rainfall-process-content">
+            <div class="chart-box">
+              <div class="chart-title">未来{{ selectedTimeRange === '24h' ? '24' : selectedTimeRange === '48h' ? '48' : '72' }}小时雨量过程</div>
+              <canvas id="rainfallProcessChart" width="300" height="180"></canvas>
+            </div>
+          </div>
+        </div>
+      </div>
+
       <div class="data-card mt-20">
         <div class="card-header" @click="toggleHydrologyForecast">
-          <h3 class="card-title">水位预报</h3>
+          <h3 class="card-title">黑林水位预报</h3>
           <div class="header-actions">
             <span class="toggle-btn">{{ hydrologyForecastExpanded ? '▼' : '▶' }}</span>
           </div>
@@ -75,29 +92,7 @@
             <div class="chart-box">
               <div class="chart-container-wrapper">
                 <div class="chart-header">
-                  <div class="chart-title">未来24小时水位预报</div>
-                  <div class="station-dropdown">
-                    <div class="dropdown-toggle" @click="toggleDropdown">
-                      <span class="selected-text">{{ selectedStation === 'heilin' ? '黑林' : '小塔山' }}</span>
-                      <span class="dropdown-arrow">{{ dropdownOpen ? '▲' : '▼' }}</span>
-                    </div>
-                    <div v-if="dropdownOpen" class="dropdown-menu" @click.stop>
-                      <div 
-                        class="dropdown-item" 
-                        :class="{ active: selectedStation === 'heilin' }"
-                        @click="selectStation('heilin')"
-                      >
-                        黑林水文站
-                      </div>
-                      <div 
-                        class="dropdown-item" 
-                        :class="{ active: selectedStation === 'xiaotaishan' }"
-                        @click="selectStation('xiaotaishan')"
-                      >
-                        小塔山水库
-                      </div>
-                    </div>
-                  </div>
+                  <div class="chart-title">未来{{ selectedTimeRange === '24h' ? '24' : selectedTimeRange === '48h' ? '48' : '72' }}小时水位预报</div>
                 </div>
                 <canvas id="forecastWaterLevelChart" width="300" height="180"></canvas>
               </div>
@@ -119,45 +114,12 @@
                       </div>
                     </div>
                   </div>
-                  <div class="station-divider"></div>
-                  <div class="station-row">
-                    <div class="station-name">小塔山水库</div>
-                    <div class="extreme-values">
-                      <div class="extreme-value">
-                        <span class="extreme-label">最高</span>
-                        <span class="extreme-number">18.8m</span>
-                        <span class="extreme-time">(18:00)</span>
-                      </div>
-                      <div class="extreme-value">
-                        <span class="extreme-label">最低</span>
-                        <span class="extreme-number">18.2m</span>
-                        <span class="extreme-time">(00:00)</span>
-                      </div>
-                    </div>
-                  </div>
                 </div>
               </div>
             </div>
           </div>
         </div>
       </div>
-
-      <div class="data-card mt-20">
-        <div class="card-header" @click="toggleFlowForecast">
-          <h3 class="card-title">流量预报</h3>
-          <div class="header-actions">
-            <span class="toggle-btn">{{ flowForecastExpanded ? '▼' : '▶' }}</span>
-          </div>
-        </div>
-        <div v-if="flowForecastExpanded" class="card-body">
-          <div class="flow-forecast-content">
-            <div class="chart-box">
-              <div class="chart-title">未来72小时流量预报</div>
-              <canvas id="forecastFlowChart" width="300" height="180"></canvas>
-            </div>
-          </div>
-        </div>
-      </div>
     </div>
 
     <div class="right-sidebar">
@@ -192,38 +154,72 @@
           </div>
         </div>
         <div class="data-card">
-        <div class="card-header">
-          <h3 class="card-title">水库水文预报</h3>
+        <div class="card-header" @click="toggleFlowForecast">
+          <h3 class="card-title">流量预报</h3>
+          <div class="header-actions">
+            <span class="toggle-btn">{{ flowForecastExpanded ? '▼' : '▶' }}</span>
+          </div>
         </div>
-        <div class="card-body">
-          <div class="reservoir-section">
-            <div class="section-title">入库流量预报</div>
+        <div v-if="flowForecastExpanded" class="card-body">
+          <div class="flow-forecast-content">
             <div class="chart-box">
-              <canvas id="inflowForecastChart" width="300" height="150"></canvas>
+              <div class="chart-title">未来{{ selectedTimeRange === '24h' ? '24' : selectedTimeRange === '48h' ? '48' : '72' }}小时流量预报</div>
+              <canvas id="forecastFlowChart" width="300" height="180"></canvas>
             </div>
           </div>
-
-          <div class="reservoir-section mt-15">
-            <div class="section-title">出库流量预报</div>
-            <div class="chart-box">
-              <canvas id="outflowCombinedChart" width="300" height="150"></canvas>
-            </div>
+        </div>
+      </div>
+      <div class="data-card mt-20">
+        <div class="card-header" @click="toggleXiaotaishanWaterLevel">
+          <h3 class="card-title">小塔山水位预报</h3>
+          <div class="header-actions">
+            <span class="toggle-btn">{{ xiaotaishanWaterLevelExpanded ? '▼' : '▶' }}</span>
           </div>
-
-          <div class="reservoir-section mt-15">
-            <div class="section-title">水库蓄水量、库容变化</div>
+        </div>
+        <div v-if="xiaotaishanWaterLevelExpanded" class="card-body">
+          <div class="forecast-content">
             <div class="chart-box">
-              <canvas id="storageCapacityChart" width="300" height="120"></canvas>
-            </div>
-            <div class="chart-box mt-10">
-              <canvas id="capacityPieChart" width="300" height="180"></canvas>
-            </div>
-            <div class="forecast-info">
-              预报 {{ selectedTimeRange === '24h' ? '24h' : (selectedTimeRange === '48h' ? '48h' : '72h') }} 后蓄水量 {{ selectedTimeRange === '24h' ? '235' : (selectedTimeRange === '48h' ? '238' : '242') }} 万 m³,占用库容 {{ selectedTimeRange === '24h' ? '78' : (selectedTimeRange === '48h' ? '79' : '81') }}%
+              <div class="chart-container-wrapper">
+                <div class="chart-header">
+                  <div class="chart-title">未来{{ selectedTimeRange === '24h' ? '24' : selectedTimeRange === '48h' ? '48' : '72' }}小时水位预报</div>
+                </div>
+                <canvas id="xiaotaishanWaterLevelChart" width="300" height="180"></canvas>
+              </div>
+              <div class="extreme-water-level">
+                <div class="extreme-item">
+                  <div class="extreme-title">预报水位极值</div>
+                  <div class="station-row">
+                    <div class="station-name">小塔山水库</div>
+                    <div class="extreme-values">
+                      <div class="extreme-value">
+                        <span class="extreme-label">最高</span>
+                        <span class="extreme-number">18.8m</span>
+                        <span class="extreme-time">(18:00)</span>
+                      </div>
+                      <div class="extreme-value">
+                        <span class="extreme-label">最低</span>
+                        <span class="extreme-number">18.2m</span>
+                        <span class="extreme-time">(00:00)</span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
             </div>
           </div>
         </div>
       </div>
+      <div class="data-card mt-20">
+        <div class="card-header">
+          <h3 class="card-title">入库流量预报</h3>
+        </div>
+        <div class="card-body">
+          <div class="chart-box no-background">
+            <div class="chart-title">未来{{ selectedTimeRange === '24h' ? '24' : selectedTimeRange === '48h' ? '48' : '72' }}小时的流量预报</div>
+            <canvas id="inflowForecastChart" width="300" height="150"></canvas>
+          </div>
+        </div>
+      </div>
       </div>
     </div>
   </div>
@@ -239,25 +235,26 @@ export default {
   components: {
     DataCard
   },
+  emits: ['updateForecastData'],
   data() {
     return {
       rainfallDateRange: '',
       hydrologyForecastExpanded: true,
       districtRainfallExpanded: true,
       flowForecastExpanded: true,
+      rainfallProcessExpanded: true,
+      xiaotaishanWaterLevelExpanded: true,
       warningLevelExpanded: true,
       forecastStationsExpanded: true,
       forecastSummaryExpanded: true,
-      selectedStation: 'heilin',
-      dropdownOpen: false,
+
       selectedTimeRange: '24h',
       timeRangeDropdownOpen: false,
       forecastWaterLevelChart: null,
+      xiaotaishanWaterLevelChart: null,
       forecastFlowChart: null,
+      rainfallProcessChart: null,
       inflowForecastChart: null,
-      outflowCombinedChart: null,
-      storageCapacityChart: null,
-      capacityPieChart: null,
       rainfallMapImage: rainfallMapImage,
       isPlaying: false,
       playInterval: null,
@@ -364,6 +361,46 @@ export default {
     },
     updateChartsForTime() {
       this.initCharts()
+      this.emitForecastData()
+    },
+    emitForecastData() {
+      const is24h = this.selectedTimeRange === '24h'
+      const is48h = this.selectedTimeRange === '48h'
+      
+      const heilinData24h = [2.5, 2.8, 3.5, 4.2, 3.8]
+      const heilinData48h = [2.5, 2.8, 3.5, 4.2, 3.9]
+      const heilinData72h = [2.5, 2.8, 3.5, 4.2, 3.9, 3.5, 3.2]
+      
+      const xiaotaishanData24h = [18.2, 18.3, 18.5, 18.8, 18.6]
+      const xiaotaishanData48h = [18.2, 18.3, 18.5, 18.8, 18.7]
+      const xiaotaishanData72h = [18.2, 18.3, 18.5, 18.8, 18.7, 18.5, 18.4]
+      
+      const heilinWaterLevel = is24h ? heilinData24h[this.currentTimeIndex] : (is48h ? heilinData48h[this.currentTimeIndex] : heilinData72h[this.currentTimeIndex])
+      const xiaotaishanWaterLevel = is24h ? xiaotaishanData24h[this.currentTimeIndex] : (is48h ? xiaotaishanData48h[this.currentTimeIndex] : xiaotaishanData72h[this.currentTimeIndex])
+      
+      const flowData24h = [45.2, 52.8, 68.5, 62.3, 58.0]
+      const flowData48h = [45.2, 52.8, 68.5, 62.3, 56.5]
+      const flowData72h = [45.2, 52.8, 68.5, 62.3, 55.7, 48.2, 42.5]
+      
+      const heilinFlow = is24h ? flowData24h[this.currentTimeIndex] : (is48h ? flowData48h[this.currentTimeIndex] : flowData72h[this.currentTimeIndex])
+      
+      const storageData24h = [220, 225, 230, 235, 232]
+      const storageData48h = [220, 225, 230, 235, 238]
+      const storageData72h = [220, 225, 230, 235, 242, 240, 238]
+      
+      const xiaotaishanStorage = is24h ? storageData24h[this.currentTimeIndex] : (is48h ? storageData48h[this.currentTimeIndex] : storageData72h[this.currentTimeIndex])
+      
+      this.$emit('updateForecastData', {
+        heilinStation: {
+          waterLevel: heilinWaterLevel.toFixed(2),
+          flow: heilinFlow.toFixed(1),
+          rainfall: '0.5'
+        },
+        reservoir: {
+          waterLevel: xiaotaishanWaterLevel.toFixed(2),
+          storage: xiaotaishanStorage.toFixed(1)
+        }
+      })
     },
     toggleHydrologyForecast() {
       this.hydrologyForecastExpanded = !this.hydrologyForecastExpanded
@@ -384,6 +421,22 @@ export default {
         }, 100)
       }
     },
+    toggleRainfallProcess() {
+      this.rainfallProcessExpanded = !this.rainfallProcessExpanded
+      if (this.rainfallProcessExpanded) {
+        setTimeout(() => {
+          this.initRainfallProcessChart()
+        }, 100)
+      }
+    },
+    toggleXiaotaishanWaterLevel() {
+      this.xiaotaishanWaterLevelExpanded = !this.xiaotaishanWaterLevelExpanded
+      if (this.xiaotaishanWaterLevelExpanded) {
+        setTimeout(() => {
+          this.initXiaotaishanWaterLevelChart()
+        }, 100)
+      }
+    },
     toggleWarningLevel() {
       this.warningLevelExpanded = !this.warningLevelExpanded
     },
@@ -393,12 +446,7 @@ export default {
     toggleForecastSummary() {
       this.forecastSummaryExpanded = !this.forecastSummaryExpanded
     },
-    toggleDropdown(event) {
-      event.stopPropagation()
-      this.dropdownOpen = !this.dropdownOpen
-    },
     handleOutsideClick() {
-      this.dropdownOpen = false
       this.timeRangeDropdownOpen = false
     },
     toggleTimeRangeDropdown(event) {
@@ -411,47 +459,36 @@ export default {
       this.resetTimeline()
       setTimeout(() => {
         this.initForecastWaterLevelChart()
+        this.initXiaotaishanWaterLevelChart()
         this.initForecastFlowChart()
+        this.initRainfallProcessChart()
         this.initInflowForecastChart()
-        this.initOutflowCombinedChart()
-        this.initStorageCapacityChart()
-        this.initCapacityPieChart()
-      }, 100)
-    },
-    selectStation(station) {
-      this.selectedStation = station
-      this.dropdownOpen = false
-      setTimeout(() => {
-        this.initForecastWaterLevelChart()
       }, 100)
     },
+
     initCharts() {
       this.initForecastWaterLevelChart()
+      this.initXiaotaishanWaterLevelChart()
       this.initForecastFlowChart()
+      this.initRainfallProcessChart()
       this.initInflowForecastChart()
-      this.initOutflowCombinedChart()
-      this.initStorageCapacityChart()
-      this.initCapacityPieChart()
     },
     destroyCharts() {
       if (this.forecastWaterLevelChart) {
         this.forecastWaterLevelChart.dispose()
       }
+      if (this.xiaotaishanWaterLevelChart) {
+        this.xiaotaishanWaterLevelChart.dispose()
+      }
       if (this.forecastFlowChart) {
         this.forecastFlowChart.dispose()
       }
+      if (this.rainfallProcessChart) {
+        this.rainfallProcessChart.dispose()
+      }
       if (this.inflowForecastChart) {
         this.inflowForecastChart.dispose()
       }
-      if (this.outflowCombinedChart) {
-        this.outflowCombinedChart.dispose()
-      }
-      if (this.storageCapacityChart) {
-        this.storageCapacityChart.dispose()
-      }
-      if (this.capacityPieChart) {
-        this.capacityPieChart.dispose()
-      }
     },
     initForecastWaterLevelChart() {
       if (document.getElementById('forecastWaterLevelChart')) {
@@ -459,7 +496,7 @@ export default {
           this.forecastWaterLevelChart.dispose()
         }
         this.forecastWaterLevelChart = echarts.init(document.getElementById('forecastWaterLevelChart'))
-        const currentData = this.stationData[this.selectedStation]
+        const currentData = this.stationData['heilin']
         
         const is24h = this.selectedTimeRange === '24h'
         const is48h = this.selectedTimeRange === '48h'
@@ -472,16 +509,7 @@ export default {
         const heilinData48h = [2.5, 2.8, 3.5, 4.2, 3.9]
         const heilinData72h = [2.5, 2.8, 3.5, 4.2, 3.9, 3.5, 3.2]
         
-        const xiaotaishanData24h = [18.2, 18.3, 18.5, 18.8, 18.6]
-        const xiaotaishanData48h = [18.2, 18.3, 18.5, 18.8, 18.7]
-        const xiaotaishanData72h = [18.2, 18.3, 18.5, 18.8, 18.7, 18.5, 18.4]
-        
-        let waterLevelData
-        if (this.selectedStation === 'heilin') {
-          waterLevelData = is24h ? heilinData24h : (is48h ? heilinData48h : heilinData72h)
-        } else {
-          waterLevelData = is24h ? xiaotaishanData24h : (is48h ? xiaotaishanData48h : xiaotaishanData72h)
-        }
+        let waterLevelData = is24h ? heilinData24h : (is48h ? heilinData48h : heilinData72h)
         
         const warningLevelData = is24h 
           ? [currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel]
@@ -652,6 +680,196 @@ export default {
         this.forecastFlowChart.setOption(option)
       }
     },
+    initXiaotaishanWaterLevelChart() {
+      if (document.getElementById('xiaotaishanWaterLevelChart')) {
+        if (this.xiaotaishanWaterLevelChart) {
+          this.xiaotaishanWaterLevelChart.dispose()
+        }
+        this.xiaotaishanWaterLevelChart = echarts.init(document.getElementById('xiaotaishanWaterLevelChart'))
+        const currentData = this.stationData['xiaotaishan']
+        
+        const is24h = this.selectedTimeRange === '24h'
+        const is48h = this.selectedTimeRange === '48h'
+        
+        const xAxisData24h = ['00:00', '06:00', '12:00', '18:00', '次日00:00']
+        const xAxisData48h = ['00:00', '12:00', '24:00', '36:00', '48:00']
+        const xAxisData72h = ['00:00', '12:00', '24:00', '36:00', '48:00', '60:00', '72:00']
+        
+        const xiaotaishanData24h = [18.2, 18.3, 18.5, 18.8, 18.6]
+        const xiaotaishanData48h = [18.2, 18.3, 18.5, 18.8, 18.7]
+        const xiaotaishanData72h = [18.2, 18.3, 18.5, 18.8, 18.7, 18.5, 18.4]
+        
+        let waterLevelData = is24h ? xiaotaishanData24h : (is48h ? xiaotaishanData48h : xiaotaishanData72h)
+        
+        const warningLevelData = is24h 
+          ? [currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel]
+          : (is48h ? [currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel] : [currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel, currentData.warningLevel])
+        
+        const option = {
+          animation: false,
+          tooltip: {
+            trigger: 'axis'
+          },
+          grid: {
+            left: '3%',
+            right: '4%',
+            bottom: '8%',
+            top: '15%',
+            containLabel: true
+          },
+          xAxis: {
+            type: 'category',
+            boundaryGap: false,
+            data: is24h ? xAxisData24h : (is48h ? xAxisData48h : xAxisData72h),
+            axisLine: {
+              lineStyle: {
+                color: '#7bbef6'
+              }
+            },
+            axisLabel: {
+              color: '#7bbef6'
+            }
+          },
+          yAxis: {
+            type: 'value',
+            name: '水位(m)',
+            nameTextStyle: {
+              color: '#7bbef6'
+            },
+            min: currentData.min,
+            max: currentData.max,
+            axisLine: {
+              lineStyle: {
+                color: '#7bbef6'
+              }
+            },
+            axisLabel: {
+              color: '#7bbef6'
+            },
+            splitLine: {
+              lineStyle: {
+                color: 'rgba(123, 190, 246, 0.2)'
+              }
+            }
+          },
+          series: [
+            {
+              name: '预报水位',
+              type: 'line',
+              data: waterLevelData,
+              lineStyle: {
+                color: '#62f6fb',
+                width: 2
+              },
+              itemStyle: {
+                color: '#62f6fb'
+              },
+              areaStyle: {
+                color: 'rgba(98, 246, 251, 0.2)'
+              }
+            },
+            {
+              name: '警戒水位',
+              type: 'line',
+              data: warningLevelData,
+              symbol: 'none',
+              lineStyle: {
+                color: '#ff6b6b',
+                width: 2,
+                type: 'dashed'
+              }
+            }
+          ]
+        }
+        this.xiaotaishanWaterLevelChart.setOption(option)
+      }
+    },
+    initRainfallProcessChart() {
+      if (document.getElementById('rainfallProcessChart')) {
+        if (this.rainfallProcessChart) {
+          this.rainfallProcessChart.dispose()
+        }
+        this.rainfallProcessChart = echarts.init(document.getElementById('rainfallProcessChart'))
+        
+        const is24h = this.selectedTimeRange === '24h'
+        const is48h = this.selectedTimeRange === '48h'
+        
+        const xAxisData24h = ['00:00', '06:00', '12:00', '18:00', '次日00:00']
+        const xAxisData48h = ['00:00', '12:00', '24:00', '36:00', '48:00']
+        const xAxisData72h = ['00:00', '12:00', '24:00', '36:00', '48:00', '60:00', '72:00']
+        
+        const rainfallData24h = [5, 12, 25, 18, 8]
+        const rainfallData48h = [5, 12, 25, 18, 10]
+        const rainfallData72h = [5, 12, 25, 18, 10, 5, 2]
+        
+        const option = {
+          animation: false,
+          tooltip: {
+            trigger: 'axis'
+          },
+          grid: {
+            left: '3%',
+            right: '4%',
+            bottom: '8%',
+            top: '15%',
+            containLabel: true
+          },
+          xAxis: {
+            type: 'category',
+            boundaryGap: false,
+            data: is24h ? xAxisData24h : (is48h ? xAxisData48h : xAxisData72h),
+            axisLine: {
+              lineStyle: {
+                color: '#7bbef6'
+              }
+            },
+            axisLabel: {
+              color: '#7bbef6'
+            }
+          },
+          yAxis: {
+            type: 'value',
+            name: '雨量(mm)',
+            nameTextStyle: {
+              color: '#7bbef6'
+            },
+            min: 0,
+            max: 50,
+            axisLine: {
+              lineStyle: {
+                color: '#7bbef6'
+              }
+            },
+            axisLabel: {
+              color: '#7bbef6'
+            },
+            splitLine: {
+              lineStyle: {
+                color: 'rgba(123, 190, 246, 0.2)'
+              }
+            }
+          },
+          series: [
+            {
+              name: '预报雨量',
+              type: 'line',
+              data: is24h ? rainfallData24h : (is48h ? rainfallData48h : rainfallData72h),
+              lineStyle: {
+                color: '#ff6b6b',
+                width: 2
+              },
+              itemStyle: {
+                color: '#ff6b6b'
+              },
+              areaStyle: {
+                color: 'rgba(255, 107, 107, 0.2)'
+              }
+            }
+          ]
+        }
+        this.rainfallProcessChart.setOption(option)
+      }
+    },
     initInflowForecastChart() {
       if (document.getElementById('inflowForecastChart')) {
         if (this.inflowForecastChart) {
@@ -1295,6 +1513,13 @@ export default {
   margin-top: 20px;
 }
 
+.chart-box.no-background {
+  background: transparent;
+  border: none;
+  box-shadow: none;
+  padding: 0;
+}
+
 .data-card {
   width: 100%;
   background: rgba(0, 20, 40, 0.7);

+ 22 - 6
src/components/HydrologySimulationPanel.vue

@@ -238,6 +238,7 @@ export default {
   },
   mounted() {
     setTimeout(() => {
+      this.updateTimeLabels()
       this.generateTimeData()
       this.initHeilinChart()
       this.initReservoirChart()
@@ -261,6 +262,7 @@ export default {
   methods: {
     selectScenario(value) {
       this.selectedScenario = value
+      this.updateTimeLabels()
       this.emitScenarioAndRisk()
     },
     selectScheme(value) {
@@ -275,6 +277,18 @@ export default {
       const riskLevel = this.riskLevelText
       this.$emit('updateScenarioAndRisk', { scenario, riskLevel, selectedScenario: this.selectedScenario })
     },
+    updateTimeLabels() {
+      // 根据选择的情景设置时间轴标签
+      if (this.selectedScenario === 'storm72') {
+        // 72小时情景
+        this.timeLabels = ['0h', '6h', '12h', '18h', '24h', '30h', '36h', '42h', '48h', '54h', '60h', '66h', '72h']
+      } else {
+        // 24小时情景
+        this.timeLabels = ['0h', '6h', '12h', '18h', '24h']
+      }
+      // 重置时间索引
+      this.currentTimeIndex = 0
+    },
     startSimulation() {
       this.currentTimeIndex = 0
       this.generateTimeData()
@@ -345,7 +359,9 @@ export default {
       
       this.$emit('updateSimulationData', {
         heilinStation: heilinData,
-        reservoir: reservoirData
+        reservoir: reservoirData,
+        timeIndex: this.currentTimeIndex,
+        timeLabel: this.timeLabels[this.currentTimeIndex] || '0h'
       })
     },
     highlightChartPoint() {
@@ -1064,7 +1080,7 @@ export default {
 .section-title {
   font-size: 14px;
   color: #7bbef6;
-  margin: 5px 0 12px;
+  margin: 3px 0 6px;
   font-weight: bold;
 }
 
@@ -1080,7 +1096,7 @@ export default {
   display: flex;
   align-items: center;
   gap: 10px;
-  padding: 10px 12px;
+  padding: 6px 10px;
   background: rgba(0, 20, 40, 0.5);
   border: 1px solid rgba(0, 212, 255, 0.2);
   border-radius: 4px;
@@ -1137,13 +1153,13 @@ export default {
 .section-divider {
   height: 1px;
   background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.4), transparent);
-  margin: 18px 0;
+  margin: 10px 0;
 }
 
 .start-btn {
   width: 100%;
-  margin-top: 20px;
-  padding: 12px 20px;
+  margin-top: 12px;
+  padding: 10px 20px;
   background: linear-gradient(135deg, #0ea5e9, #06b6d4);
   border: none;
   border-radius: 6px;

+ 290 - 9
src/components/HydrologyWarningPanel.vue

@@ -57,6 +57,57 @@
         </div>
       </div>
     </div>
+
+    <div class="right-sidebar">
+      <div class="data-card" @click="loadEmbankmentWarning">
+        <div class="card-header">
+          <h3 class="card-title">堤防预警</h3>
+        </div>
+        <div class="card-body">
+          <div class="pie-chart-container">
+            <div id="embankmentPieChart" class="pie-chart"></div>
+            <div class="pie-center-text">{{ activeEmbankmentName || '堤防统计' }}</div>
+          </div>
+          <div class="embankment-summary">
+            <div class="embankment-summary-item warning">
+              <span class="embankment-summary-label">超警戒:</span>
+              <span class="embankment-summary-value">{{ embankmentStatsData[1].value }}个</span>
+            </div>
+            <div class="embankment-summary-item danger">
+              <span class="embankment-summary-label">超保证:</span>
+              <span class="embankment-summary-value">{{ embankmentStatsData[2].value }}个</span>
+            </div>
+          </div>
+          <div class="embankment-warning-list">
+            <div 
+              v-for="(item, index) in embankmentWarningList" 
+              :key="index"
+              class="embankment-warning-item"
+              :class="item.level"
+            >
+              <div class="embankment-warning-header">
+                <div class="embankment-warning-name">{{ item.name }}</div>
+                <div class="embankment-warning-level" :class="item.level">{{ item.levelText }}</div>
+              </div>
+              <div class="embankment-warning-content">
+                <div class="embankment-warning-info">
+                  <span class="info-label">位置:</span>
+                  <span class="info-value">{{ item.location }}</span>
+                </div>
+                <div class="embankment-warning-info">
+                  <span class="info-label">预警内容:</span>
+                  <span class="info-value">{{ item.content }}</span>
+                </div>
+                <div class="embankment-warning-info">
+                  <span class="info-label">预警时间:</span>
+                  <span class="info-value">{{ item.time }}</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -109,34 +160,73 @@ export default {
           level: 'orange',
           levelText: '橙色',
           isWarning: true
+        }
+      ],
+      embankmentWarningList: [
+        {
+          name: '青口河段堤防中游',
+          location: '黑林河段',
+          content: '水位接近警戒水位,需加强巡查',
+          time: '3月10日 14:30',
+          level: 'yellow',
+          levelText: '黄色'
         },
         {
-          time: '3月10日 10:00',
-          location: '陡沟站',
-          content: '流量超阈值',
-          level: 'red',
-          levelText: '红色',
-          isWarning: true
+          name: '青口河段堤防上游',
+          location: '小塔山水库下游',
+          content: '库水位上涨,注意泄洪安全',
+          time: '3月10日 12:15',
+          level: 'orange',
+          levelText: '橙色'
         }
       ],
       warningPieChart: null,
       warningStatsData: [
-        { value: 5, name: '正常' },
+        { value: 6, name: '正常' },
         { value: 2, name: '超警戒' },
-        { value: 1, name: '超保证' }
+        { value: 0, name: '超保证' }
+      ],
+      embankmentWarningList: [
+        {
+          name: '青口河段堤防中游',
+          location: '黑林河段',
+          content: '水位接近警戒水位,需加强巡查',
+          time: '3月10日 14:30',
+          level: 'yellow',
+          levelText: '黄色'
+        },
+        {
+          name: '青口河段堤防上游',
+          location: '小塔山水库下游',
+          content: '库水位上涨,注意泄洪安全',
+          time: '3月10日 12:15',
+          level: 'orange',
+          levelText: '橙色'
+        }
+      ],
+      embankmentPieChart: null,
+      embankmentStatsData: [
+        { value: 0, name: '正常' },
+        { value: 0, name: '超警戒' },
+        { value: 0, name: '超保证' }
       ],
-      activeWarningName: ''
+      activeEmbankmentName: ''
     }
   },
   mounted() {
+    this.calculateEmbankmentStats()
     setTimeout(() => {
       this.initWarningPieChart()
+      this.initEmbankmentPieChart()
     }, 100)
   },
   beforeUnmount() {
     if (this.warningPieChart) {
       this.warningPieChart.dispose()
     }
+    if (this.embankmentPieChart) {
+      this.embankmentPieChart.dispose()
+    }
   },
   methods: {
     initWarningPieChart() {
@@ -201,6 +291,80 @@ export default {
           this.activeWarningName = ''
         })
       }
+    },
+    initEmbankmentPieChart() {
+      if (document.getElementById('embankmentPieChart')) {
+        if (this.embankmentPieChart) {
+          this.embankmentPieChart.dispose()
+        }
+        this.embankmentPieChart = echarts.init(document.getElementById('embankmentPieChart'))
+        const option = {
+          animation: false,
+          tooltip: {
+            trigger: 'item',
+            formatter: '{b}: {c}个 ({d}%)'
+          },
+          legend: {
+            orient: 'vertical',
+            right: 10,
+            top: 'center',
+            textStyle: {
+              color: '#7bbef6',
+              fontSize: 12
+            }
+          },
+          series: [
+            {
+              name: '堤防统计',
+              type: 'pie',
+              radius: ['45%', '70%'],
+              center: ['35%', '50%'],
+              avoidLabelOverlap: false,
+              label: {
+                show: false
+              },
+              emphasis: {
+                label: {
+                  show: true,
+                  fontSize: 14,
+                  fontWeight: 'bold',
+                  color: '#e0fcff'
+                }
+              },
+              labelLine: {
+                show: false
+              },
+              data: this.embankmentStatsData,
+              itemStyle: {
+                color: function(params) {
+                  const colors = ['#22c55e', '#ffd93d', '#ff6b6b']
+                  return colors[params.dataIndex]
+                }
+              }
+            }
+          ]
+        }
+        this.embankmentPieChart.setOption(option)
+        
+        this.embankmentPieChart.on('mouseover', (params) => {
+          this.activeEmbankmentName = params.name
+        })
+        
+        this.embankmentPieChart.on('mouseout', () => {
+          this.activeEmbankmentName = ''
+        })
+      }
+    },
+    loadEmbankmentWarning() {
+      this.$emit('loadEmbankmentWarning')
+    },
+    calculateEmbankmentStats() {
+      // 根据用户要求设置统计数据
+      this.embankmentStatsData = [
+        { value: 8, name: '正常' },
+        { value: 8, name: '超警戒' },
+        { value: 2, name: '超保证' }
+      ]
     }
   }
 }
@@ -288,6 +452,40 @@ export default {
   color: #ff6b6b;
 }
 
+.embankment-summary {
+  display: flex;
+  justify-content: center;
+  gap: 30px;
+  margin: 15px 0;
+  padding: 10px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+}
+
+.embankment-summary-item {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+
+.embankment-summary-label {
+  color: #7bbef6;
+  font-size: 14px;
+}
+
+.embankment-summary-value {
+  font-size: 16px;
+  font-weight: bold;
+}
+
+.embankment-summary-item.warning .embankment-summary-value {
+  color: #ffd93d;
+}
+
+.embankment-summary-item.danger .embankment-summary-value {
+  color: #ff6b6b;
+}
+
 .warning-list {
   margin-top: 15px;
   padding-top: 15px;
@@ -440,4 +638,87 @@ export default {
 .warning-list-item.red .warning-list-level {
   color: #ff6b6b;
 }
+
+.embankment-warning-list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.embankment-warning-item {
+  padding: 12px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.embankment-warning-item.yellow {
+  border-color: #ffd93d;
+}
+
+.embankment-warning-item.orange {
+  border-color: #f97316;
+}
+
+.embankment-warning-item.red {
+  border-color: #ff6b6b;
+}
+
+.embankment-warning-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+  padding-bottom: 8px;
+  border-bottom: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.embankment-warning-name {
+  font-size: 14px;
+  font-weight: bold;
+  color: #62f6fb;
+}
+
+.embankment-warning-level {
+  padding: 4px 8px;
+  border-radius: 3px;
+  font-size: 12px;
+  font-weight: bold;
+}
+
+.embankment-warning-level.yellow {
+  background: rgba(255, 217, 61, 0.2);
+  color: #ffd93d;
+}
+
+.embankment-warning-level.orange {
+  background: rgba(249, 115, 22, 0.2);
+  color: #f97316;
+}
+
+.embankment-warning-level.red {
+  background: rgba(255, 107, 107, 0.2);
+  color: #ff6b6b;
+}
+
+.embankment-warning-content {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.embankment-warning-info {
+  display: flex;
+  gap: 5px;
+}
+
+.info-label {
+  color: #7bbef6;
+  font-size: 12px;
+}
+
+.info-value {
+  color: #e0fcff;
+  font-size: 12px;
+}
 </style>

+ 29 - 1
src/views/HomeView.vue

@@ -11,6 +11,7 @@
         @toggleMap="toggleMap" 
         :simulationTime="simulationTime"
         :simulationData="simulationData"
+        :loadEmbankmentWarning="loadEmbankmentWarning"
       />
     </div>
     
@@ -62,9 +63,12 @@
       :activeSecondaryTab="activeSecondaryTab"
       :simulationTime="simulationTime"
       :simulationData="simulationData"
+      :loadEmbankmentWarning="loadEmbankmentWarning"
       @selectSecondaryTab="selectSecondaryTab"
       @updateSimulationTime="updateSimulationTime"
       @updateSimulationData="updateSimulationData"
+      @loadEmbankmentWarning="handleLoadEmbankmentWarning"
+      @updateForecastData="handleUpdateForecastData"
     />
     
     <!-- 水资源调配视图 -->
@@ -95,6 +99,7 @@ export default {
       activeTab: '流域总览',
       activeSecondaryTab: '水文预报',
       showMap: true,
+      loadEmbankmentWarning: false,
       simulationTime: 0,
       simulationData: {
         heilinStation: {
@@ -112,12 +117,26 @@ export default {
   methods: {
     selectTab(tab) {
       this.activeTab = tab
-      if (tab === '水文四预') {
+      if (tab === '水文四预' || tab === '水资源调配') {
         this.activeSecondaryTab = '水文预报'
       }
+      // 只有在水文预警页面时才显示堤防图层
+      if (tab !== '水文四预') {
+        this.loadEmbankmentWarning = false
+      }
     },
     selectSecondaryTab(tab) {
       this.activeSecondaryTab = tab
+      // 在水文预警和水文预演页面时显示堤防图层
+      if (this.activeTab === '水文四预' && (tab === '水文预警' || tab === '水文预演')) {
+        // 先设为false,再设为true,触发重新加载
+        this.loadEmbankmentWarning = false
+        this.$nextTick(() => {
+          this.loadEmbankmentWarning = true
+        })
+      } else if (this.activeTab === '水文四预' && tab !== '水文预警') {
+        this.loadEmbankmentWarning = false
+      }
     },
     toggleMap(show) {
       this.showMap = show
@@ -127,6 +146,15 @@ export default {
     },
     updateSimulationData(data) {
       this.simulationData = { ...this.simulationData, ...data }
+    },
+    handleLoadEmbankmentWarning() {
+      // 在水文预警和水文预演页面时显示堤防图层
+      if (this.activeTab === '水文四预' && (this.activeSecondaryTab === '水文预警' || this.activeSecondaryTab === '水文预演')) {
+        this.loadEmbankmentWarning = true
+      }
+    },
+    handleUpdateForecastData(data) {
+      this.simulationData = { ...this.simulationData, ...data }
     }
   }
 }

+ 19 - 3
src/views/HydrologyForecastView.vue

@@ -31,8 +31,14 @@
       </div>
     </div>
 
-    <HydrologyForecastPanel v-if="activeSecondaryTab === '水文预报'" />
-    <HydrologyWarningPanel v-if="activeSecondaryTab === '水文预警'" />
+    <HydrologyForecastPanel 
+      v-if="activeSecondaryTab === '水文预报'" 
+      @updateForecastData="handleUpdateForecastData"
+    />
+    <HydrologyWarningPanel 
+      v-if="activeSecondaryTab === '水文预警'" 
+      @loadEmbankmentWarning="handleLoadEmbankmentWarning"
+    />
     <HydrologySimulationPanel 
       v-if="activeSecondaryTab === '水文预演'" 
       :simulationTime="simulationTime"
@@ -76,6 +82,10 @@ export default {
     simulationData: {
       type: Object,
       default: () => ({})
+    },
+    loadEmbankmentWarning: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -85,7 +95,7 @@ export default {
       riskLevel: '正常'
     }
   },
-  emits: ['selectSecondaryTab', 'updateSimulationTime', 'updateSimulationData'],
+  emits: ['selectSecondaryTab', 'updateSimulationTime', 'updateSimulationData', 'loadEmbankmentWarning', 'updateForecastData'],
   methods: {
     selectSecondaryTab(tab) {
       this.$emit('selectSecondaryTab', tab)
@@ -94,6 +104,12 @@ export default {
       this.selectedScenario = selectedScenario
       this.scenarioLabel = scenario
       this.riskLevel = riskLevel
+    },
+    handleLoadEmbankmentWarning() {
+      this.$emit('loadEmbankmentWarning')
+    },
+    handleUpdateForecastData(data) {
+      this.$emit('updateSimulationData', data)
     }
   }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно