Sfoglia il codice sorgente

feat(圩区详情): 添加圩区AI内涝识别功能及监控点展示

- 新增圩区详情右侧面板,包含降雨预报和降雨量图表
- 实现AI内涝识别功能,显示积水点统计和状态
- 添加监控点查看功能,支持图片展示
- 引入三张城市积水图片作为监控点示例
- 调整部分样式和布局
BAI 2 settimane fa
parent
commit
597fe02a50

BIN
src/assets/images/城市积水1.png


BIN
src/assets/images/城市积水2.png


BIN
src/assets/images/城市积水3.png


+ 372 - 3
src/views/waterStation/index.vue

@@ -260,6 +260,66 @@
       </div>
     </div>
     
+    <!-- 右侧面板 - 圩区详情 -->
+    <div class="right-panel" v-else-if="selectedPolderDetail === 'konggang' && !showHydrologyDetail">
+      <div class="right-panel-3d">
+        <!-- 降雨预报和降雨量 -->
+        <m-card title="降雨预报" class="water-station-card water-station-card-top" :width="398" :height="320">
+          <div class="rainfall-forecast-panel">
+            <!-- 降雨预报卡片 -->
+            <div class="forecast-cards">
+              <div class="forecast-card" v-for="(forecast, index) in rainfallForecast" :key="index">
+                <div class="forecast-date">{{ forecast.date }}</div>
+                <div class="forecast-icon" :class="forecast.icon"></div>
+                <div class="forecast-desc">{{ forecast.desc }}</div>
+                <div class="forecast-temp">{{ forecast.temp }}</div>
+              </div>
+            </div>
+            
+            <!-- 降雨量柱状图 -->
+            <div class="rainfall-chart-container">
+              <h4 class="chart-title">降雨量</h4>
+              <VChart ref="rainfallChart" :option="polderRainfallChartOption" :autoresize="true" style="width: 100%; height: 120px;" />
+            </div>
+          </div>
+        </m-card>
+        
+        <!-- 圩区AI内涝识别 -->
+        <m-card title="圩区AI内涝识别" class="water-station-card water-station-card-bottom" :width="398" :height="480">
+          <div class="waterlogging-detection-panel">
+            <!-- 内涝统计 -->
+            <div class="waterlogging-stats">
+              <div class="stat-item">
+                <div class="stat-label">积水点数量</div>
+                <div class="stat-value">{{ waterloggingStats.count }}/{{ waterloggingStats.total }}</div>
+              </div>
+              <div class="stat-item">
+                <div class="stat-label">是否积水</div>
+                <div class="stat-value" :class="{ 'status-active': !waterloggingStats.isWaterlogging, 'status-inactive': waterloggingStats.isWaterlogging }">{{ waterloggingStats.isWaterlogging ? '是' : '否' }}</div>
+              </div>
+            </div>
+            
+            <!-- 监控点查看按钮 -->
+            <div class="monitoring-button-container">
+              <button class="monitoring-button" @click="showMonitoringPoints = !showMonitoringPoints">
+                {{ showMonitoringPoints ? '收起监控点' : '查看监控点' }}
+              </button>
+            </div>
+            
+            <!-- 监控点图片 -->
+            <div class="monitoring-points" v-if="showMonitoringPoints">
+              <div class="monitoring-point" v-for="(point, index) in monitoringPoints" :key="index">
+                <div class="point-name">{{ point.name }}</div>
+                <div class="point-image">
+                  <img :src="point.image" alt="监控点" />
+                </div>
+              </div>
+            </div>
+          </div>
+        </m-card>
+      </div>
+    </div>
+    
     <!-- 孔巷联圩详情 -->
     <template v-if="selectedPolderDetail === 'konggang' && !showHydrologyDetail">
       <!-- 侧边开关控制 -->
@@ -319,6 +379,11 @@ import TopStats from "./TopStats.vue"
 import mSvglineAnimation from "@/components/mSvglineAnimation/index.vue"
 import gsap from "gsap"
 
+// 引入监控点图片
+import cityFlood1 from "@/assets/images/城市积水1.png"
+import cityFlood2 from "@/assets/images/城市积水2.png"
+import cityFlood3 from "@/assets/images/城市积水3.png"
+
 defineProps({
   selectedPolderDetail: {
     type: String,
@@ -569,7 +634,7 @@ const currentWaterLevelChartOption = computed(() => {
       left: '4%',
       top: '12%',
       right: '10%',
-      bottom: '13%',
+      bottom: '18%',
       containLabel: true
     },
     legend: {
@@ -953,6 +1018,105 @@ const rainfallChartOption = ref({
   ]
 })
 
+// 降雨预报数据
+const rainfallForecast = ref([
+  { date: '今天', icon: 'rainy', desc: '小雨', temp: '4°C' },
+  { date: '明天', icon: 'cloudy', desc: '多云', temp: '6°C' },
+  { date: '后天', icon: 'sunny', desc: '晴', temp: '8°C' },
+  { date: '周四', icon: 'rainy', desc: '中雨', temp: '5°C' }
+])
+
+// 降雨量图表配置
+const polderRainfallChartOption = ref({
+  grid: {
+    left: '5%',
+    top: '20%',
+    right: '5%',
+    bottom: '15%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00'],
+    axisLine: {
+      lineStyle: {
+        color: 'rgba(48, 220, 255, 0.6)'
+      }
+    },
+    axisLabel: {
+      color: 'rgba(255, 255, 255, 0.8)',
+      fontSize: 9
+    }
+  },
+  yAxis: {
+    type: 'value',
+    min: 0,
+    max: 5,
+    axisLine: {
+      lineStyle: {
+        color: 'rgba(48, 220, 255, 0.6)'
+      }
+    },
+    axisLabel: {
+      color: 'rgba(255, 255, 255, 0.8)',
+      fontSize: 9,
+      formatter: '{value} mm'
+    },
+    splitLine: {
+      lineStyle: {
+        color: 'rgba(48, 220, 255, 0.2)'
+      }
+    }
+  },
+  tooltip: {
+    trigger: 'axis',
+    backgroundColor: 'rgba(0, 20, 40, 0.9)',
+    borderColor: 'rgba(48, 220, 255, 0.5)',
+    textStyle: {
+      color: '#fff'
+    }
+  },
+  series: [
+    {
+      name: '降雨量',
+      type: 'bar',
+      barWidth: '20%',
+      data: [0.2, 0.5, 1.2, 0.8, 0.3, 0.1, 0.2, 0.4],
+      itemStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          {
+            offset: 0,
+            color: 'rgba(48, 220, 255, 0.8)'
+          },
+          {
+            offset: 1,
+            color: 'rgba(48, 220, 255, 0.3)'
+          }
+        ]),
+        shadowColor: 'rgba(48, 220, 255, 0.6)',
+        shadowBlur: 10
+      }
+    }
+  ]
+})
+
+// 内涝识别数据
+const waterloggingStats = ref({
+  count: 0,
+  total: 15,
+  isWaterlogging: false
+})
+
+// 监控点数据
+const monitoringPoints = ref([
+  { name: '监控点1', image: cityFlood1 },
+  { name: '监控点2', image: cityFlood2 },
+  { name: '监控点3', image: cityFlood3 }
+])
+
+// 显示监控点状态
+const showMonitoringPoints = ref(true)
+
 // 组件挂载时执行动画
 onMounted(() => {
   nextTick(() => {
@@ -1764,8 +1928,8 @@ onMounted(() => {
 
 .polder-layer-controls {
   position: absolute;
-  right: 20px;
-  top: 50%;
+  right: 420px;
+  top: 65%;
   transform: translateY(-50%);
   display: flex;
   flex-direction: column;
@@ -1911,4 +2075,209 @@ onMounted(() => {
     height: 100% !important;
   }
 }
+
+.rainfall-forecast-panel {
+  height: 100%;
+  padding: 8px;
+  box-sizing: border-box;
+  background: rgba(0, 30, 60, 0.5);
+  border-radius: 6px;
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.forecast-cards {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 6px;
+}
+
+.forecast-card {
+  background: rgba(0, 100, 150, 0.3);
+  border: 1px solid rgba(48, 220, 255, 0.3);
+  border-radius: 4px;
+  padding: 6px;
+  text-align: center;
+  
+  .forecast-date {
+    font-size: 10px;
+    color: rgba(255, 255, 255, 0.9);
+    margin-bottom: 4px;
+  }
+  
+  .forecast-icon {
+    width: 32px;
+    height: 32px;
+    margin: 0 auto 4px;
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center;
+  }
+  
+  .forecast-icon.rainy {
+    background-image: url('@/assets/images/rain.svg');
+  }
+  
+  .forecast-icon.cloudy {
+    background-image: url('@/assets/images/storm.svg');
+  }
+  
+  .forecast-icon.sunny {
+    background-image: url('@/assets/images/heat.svg');
+  }
+  
+  .forecast-desc {
+    font-size: 10px;
+    color: #30dcff;
+    margin-bottom: 2px;
+  }
+  
+  .forecast-temp {
+    font-size: 9px;
+    color: rgba(255, 255, 255, 0.8);
+  }
+}
+
+.rainfall-chart-container {
+  flex: 1;
+  background: rgba(0, 100, 150, 0.2);
+  border: 1px solid rgba(48, 220, 255, 0.3);
+  border-radius: 4px;
+  padding: 6px;
+  min-height: 100px;
+  
+  .chart-title {
+    font-size: 10px;
+    color: #30dcff;
+    margin-bottom: 4px;
+    text-align: center;
+    font-weight: bold;
+  }
+  
+  :deep(.echarts-container) {
+    width: 100% !important;
+    height: 100% !important;
+  }
+}
+
+.waterlogging-detection-panel {
+  height: 100%;
+  padding: 10px;
+  box-sizing: border-box;
+  background: rgba(0, 30, 60, 0.5);
+  border-radius: 6px;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.waterlogging-stats {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 8px;
+}
+
+.waterlogging-stats .stat-item {
+  background: rgba(0, 100, 150, 0.3);
+  border: 1px solid rgba(48, 220, 255, 0.3);
+  border-radius: 4px;
+  padding: 10px;
+  text-align: center;
+  
+  .stat-label {
+    font-size: 12px;
+    color: rgba(255, 255, 255, 0.9);
+    margin-bottom: 4px;
+  }
+  
+  .stat-value {
+    font-size: 18px;
+    font-weight: bold;
+    color: #30dcff;
+    font-family: "D-DIN";
+    
+    &.status-active {
+      color: #00ff88;
+      text-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
+    }
+    
+    &.status-inactive {
+      color: #ff6b6b;
+    }
+  }
+}
+
+.monitoring-button-container {
+  display: flex;
+  justify-content: center;
+  margin: 5px 0;
+}
+
+.monitoring-button {
+  background: linear-gradient(135deg, rgba(48, 220, 255, 0.3) 0%, rgba(0, 191, 255, 0.2) 100%);
+  border: 1px solid rgba(48, 220, 255, 0.4);
+  border-radius: 4px;
+  padding: 6px 12px;
+  color: #30dcff;
+  font-size: 12px;
+  font-weight: bold;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    background: linear-gradient(135deg, rgba(48, 220, 255, 0.4) 0%, rgba(0, 191, 255, 0.3) 100%);
+    border-color: rgba(48, 220, 255, 0.6);
+    box-shadow: 0 0 8px rgba(48, 220, 255, 0.3);
+  }
+}
+
+.monitoring-points {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  overflow-y: auto;
+  
+  &::-webkit-scrollbar {
+    width: 4px;
+  }
+  
+  &::-webkit-scrollbar-track {
+    background: rgba(0, 0, 0, 0.3);
+  }
+  
+  &::-webkit-scrollbar-thumb {
+    background: rgba(48, 220, 255, 0.4);
+    border-radius: 2px;
+  }
+}
+
+.monitoring-point {
+  background: rgba(0, 100, 150, 0.3);
+  border: 1px solid rgba(48, 220, 255, 0.3);
+  border-radius: 4px;
+  padding: 8px;
+  
+  .point-name {
+    font-size: 12px;
+    color: #30dcff;
+    margin-bottom: 4px;
+    font-weight: bold;
+  }
+  
+  .point-image {
+    width: 100%;
+    height: 120px;
+    border-radius: 4px;
+    overflow: hidden;
+    border: 1px solid rgba(48, 220, 255, 0.3);
+    
+    img {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+    }
+  }
+}
 </style>