Jelajahi Sumber

修改水文站页面

BAI 1 Minggu lalu
induk
melakukan
bdd0650a79

TEMPAT SAMPAH
src/assets/images/Heilin/图1.jpeg


TEMPAT SAMPAH
src/assets/images/Heilin/图2.jpeg


TEMPAT SAMPAH
src/assets/images/Heilin/图3.jpeg


TEMPAT SAMPAH
src/assets/images/Heilin/图4.jpeg


TEMPAT SAMPAH
src/assets/images/Heilin/图5.jpeg


TEMPAT SAMPAH
src/assets/images/Heilin/图6.png


TEMPAT SAMPAH
src/assets/images/Heilin/水文站图.jpeg


+ 18 - 3
src/components/CesiumMap.vue

@@ -27,11 +27,16 @@
 import { ref, onMounted, onUnmounted, computed } from 'vue'
 import * as Cesium from 'cesium'
 import 'cesium/Build/CesiumUnminified/Widgets/widgets.css'
+import { useRouter } from 'vue-router'
+
+const emit = defineEmits(['toggleMap'])
 
 const viewer = ref(null)
 const showPopup = ref(false)
 const popupPosition = ref({ x: 0, y: 0 })
 
+const router = useRouter()
+
 const poiData = ref({
   name: '黑林水文站',
   waterLevel: '3.25',
@@ -225,9 +230,19 @@ const closePopup = () => {
 }
 
 const goToTwinStation = () => {
-  // 跳转到孪生水文站页面
-  // 这里假设通过事件通知父组件进行页面切换
-  window.dispatchEvent(new CustomEvent('selectTab', { detail: '孪生水文站' }))
+  // 执行平滑flyto动画到黑林水文站位置
+  const heilinPosition = Cesium.Cartesian3.fromDegrees(118.8770798, 35.0320627, 10000)
+  viewer.value.camera.flyTo({
+    destination: heilinPosition,
+    duration: 2.0,
+    easingFunction: Cesium.EasingFunction.SINE_IN_OUT
+  })
+  
+  // 延迟跳转到水文站详情页面
+  setTimeout(() => {
+    router.push('/heilin-station')
+  }, 2000)
+  
   closePopup()
 }
 

+ 6 - 0
src/router/index.js

@@ -1,11 +1,17 @@
 import { createRouter, createWebHistory } from 'vue-router'
 import HomeView from '../views/HomeView.vue'
+import HeilinStationView from '../views/HeilinStationView.vue'
 
 const routes = [
   {
     path: '/',
     name: 'home',
     component: HomeView
+  },
+  {
+    path: '/heilin-station',
+    name: 'heilin-station',
+    component: HeilinStationView
   }
 ]
 

+ 641 - 0
src/views/HeilinStationView.vue

@@ -0,0 +1,641 @@
+<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>
+              <div class="main-image">
+                <img :src="mainImageUrl" :alt="mainImageAlt" />
+              </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="视频监控画面" />
+            </div>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 中间空间 -->
+      <div class="center-space"></div>
+      
+      <!-- 右侧面板区域 -->
+      <div class="right-sidebar">
+        <!-- 右侧面板1:历史事件 -->
+        <div class="data-card">
+          <div class="panel-header">
+            <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>
+            <div class="event-item">
+              <div class="event-date">2020-05-10</div>
+              <div class="event-title">水质监测</div>
+              <div class="event-desc">开展水质监测工作,各项指标均符合国家地表水标准。</div>
+            </div>
+          </div>
+        </div>
+        
+        <!-- 右侧面板2:设备状态 -->
+        <div class="data-card mt-20">
+          <div class="panel-header">
+            <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>
+          </div>
+        </div>
+        
+        <!-- 右侧面板3:实时数据 -->
+        <div class="data-card mt-20">
+          <div class="panel-header">
+            <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>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <!-- 渐变装饰层(四周暗角) -->
+    <GradientOverlay />
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+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 goBack = () => {
+  router.push('/')
+}
+
+const changeMainImage = (imageUrl) => {
+  mainImageUrl.value = imageUrl
+  // 提取图片名称作为alt文本
+  const parts = imageUrl.split('/')
+  const imageName = parts[parts.length - 1]
+  mainImageAlt.value = `水文站图片${imageName.split('.')[0]}`
+}
+
+const drawFlowChart = () => {
+  const canvas = flowChart.value
+  if (!canvas) return
+  
+  const ctx = canvas.getContext('2d')
+  ctx.clearRect(0, 0, canvas.width, canvas.height)
+  
+  // 模拟流量数据
+  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月']
+  
+  // 计算画布尺寸
+  const width = canvas.width
+  const height = canvas.height
+  const padding = 40
+  const chartWidth = width - 2 * padding
+  const chartHeight = height - 2 * padding
+  
+  // 计算数据范围
+  const maxValue = Math.max(...data)
+  const minValue = Math.min(...data)
+  const valueRange = maxValue - minValue
+  
+  // 绘制网格
+  ctx.strokeStyle = 'rgba(0, 213, 255, 0.2)'
+  ctx.lineWidth = 1
+  
+  // 绘制水平网格线
+  for (let i = 0; i <= 5; i++) {
+    const y = padding + (chartHeight / 5) * i
+    ctx.beginPath()
+    ctx.moveTo(padding, y)
+    ctx.lineTo(width - padding, 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)
+  }
+  
+  // 绘制垂直网格线
+  for (let i = 0; i < labels.length; i++) {
+    const x = padding + (chartWidth / (labels.length - 1)) * i
+    ctx.beginPath()
+    ctx.moveTo(x, padding)
+    ctx.lineTo(x, height - padding)
+    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.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
+    
+    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.closePath()
+  ctx.fill()
+}
+
+onMounted(() => {
+  drawFlowChart()
+  
+  // 监听窗口 resize 事件,重新绘制图表
+  window.addEventListener('resize', drawFlowChart)
+})
+</script>
+
+<style scoped>
+.dashboard {
+  width: 1920px;
+  height: 1080px;
+  overflow: hidden;
+  position: relative;
+}
+
+.bottom-bg {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/Heilin/WPS图片(1).jpeg');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 3;
+}
+
+.station-bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/Heilin/水文站图.jpeg');
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 2;
+}
+
+.top-title {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-image: url('/src/assets/images/顶部大标题.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  pointer-events: none;
+  z-index: 4;
+}
+
+.system-title {
+  position: absolute;
+  top: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+  font-size: 36px;
+  font-weight: bold;
+  background: linear-gradient(to bottom, #ffffff 50%, #00d5ff 100%);
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
+  text-shadow: 0 0 1px rgba(2, 217, 255, 0.205);
+  z-index: 4;
+  pointer-events: none;
+}
+
+.back-btn {
+  position: absolute;
+  top: 20px;
+  left: 30px;
+  background: linear-gradient(90deg, rgba(0, 60, 120, 0.9), rgba(0, 100, 150, 0.7));
+  border: 1px solid rgba(0, 213, 255, 0.5);
+  color: #ffffff;
+  padding: 8px 16px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 14px;
+  transition: all 0.3s ease;
+  z-index: 4;
+}
+
+.back-btn:hover {
+  background: linear-gradient(90deg, rgba(0, 80, 160, 0.9), rgba(0, 120, 180, 0.7));
+  box-shadow: 0 0 10px rgba(0, 213, 255, 0.5);
+}
+
+.main-content {
+  position: relative;
+  display: flex;
+  height: calc(100% - 80px);
+  padding: 80px 20px 20px;
+  gap: 20px;
+  overflow: auto;
+  z-index: 4;
+}
+
+.left-sidebar {
+  width: 350px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.center-space {
+  flex: 1;
+}
+
+.right-sidebar {
+  width: 350px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.data-card {
+  width: 100%;
+  background: rgba(0, 20, 40, 0.7);
+  border-radius: 4px;
+  overflow: hidden;
+  box-shadow: 0 0 10px rgba(0, 212, 255, 0.2);
+}
+
+.panel-header {
+  height: 50px;
+  background-image: url('/src/assets/images/数据小标题.png');
+  background-size: 100% 100%;
+  background-position: center;
+  background-repeat: no-repeat;
+  display: flex;
+  align-items: flex-start;
+  justify-content: space-between;
+  padding: 6px 20px 0;
+  cursor: pointer;
+}
+
+.panel-header h3 {
+  margin: 0;
+  font-size: 18px;
+  font-weight: bold;
+  color: #e0fcff;
+  text-shadow: 0 0 5px rgba(0, 212, 255, 0.5);
+  padding-left: 20px;
+}
+
+.panel-content {
+  padding: 12px;
+  min-height: auto;
+  font-size: 16px;
+  line-height: 1.6;
+  margin-top: -10px;
+  color: #e0fcff;
+}
+
+.station-intro {
+  min-height: 500px;
+}
+
+.station-intro .panel-content {
+  padding: 15px;
+}
+
+.image-section {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 15px;
+  height: 250px;
+}
+
+.thumbnail-list {
+  width: 80px;
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+}
+
+.thumbnail-list img {
+  width: 100%;
+  height: 45px;
+  object-fit: cover;
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.thumbnail-list img:hover {
+  border-color: rgba(0, 212, 255, 0.8);
+  box-shadow: 0 0 5px rgba(0, 212, 255, 0.5);
+}
+
+.main-image {
+  flex: 1;
+  border-radius: 4px;
+  overflow: hidden;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.main-image img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.station-text {
+  font-size: 12px;
+  line-height: 1.4;
+}
+
+.station-text p {
+  margin-bottom: 6px;
+}
+
+.station-text p:last-child {
+  margin-bottom: 0;
+}
+
+.video-monitor {
+  min-height: 350px;
+}
+
+.video-image {
+  width: 100%;
+  height: 100%;
+  border-radius: 4px;
+  overflow: hidden;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+}
+
+.video-image img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.mt-20 {
+  margin-top: 20px;
+}
+
+.event-item {
+  padding: 10px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  margin-bottom: 8px;
+}
+
+.event-item:last-child {
+  margin-bottom: 0;
+}
+
+.event-date {
+  font-size: 12px;
+  color: #62f6fb;
+  margin-bottom: 5px;
+}
+
+.event-title {
+  font-size: 14px;
+  font-weight: bold;
+  color: #00ffff;
+  margin-bottom: 5px;
+  text-shadow: 0 0 3px rgba(0, 212, 255, 0.5);
+}
+
+.event-desc {
+  font-size: 13px;
+  color: #e0fcff;
+  line-height: 1.4;
+}
+
+.device-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 12px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  margin-bottom: 8px;
+}
+
+.device-item:last-child {
+  margin-bottom: 0;
+}
+
+.device-item .label {
+  font-size: 14px;
+  color: #62f6fb;
+}
+
+.device-item .status {
+  font-size: 14px;
+  font-weight: bold;
+  padding: 2px 8px;
+  border-radius: 10px;
+}
+
+.device-item .status.online {
+  color: #00ff00;
+  background: rgba(0, 255, 0, 0.2);
+  border: 1px solid rgba(0, 255, 0, 0.5);
+}
+
+.device-item .status.offline {
+  color: #ff0000;
+  background: rgba(255, 0, 0, 0.2);
+  border: 1px solid rgba(255, 0, 0, 0.5);
+}
+
+.realtime-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 12px;
+  background: rgba(0, 20, 40, 0.5);
+  border-radius: 4px;
+  border: 1px solid rgba(0, 212, 255, 0.2);
+  margin-bottom: 8px;
+}
+
+.realtime-item:last-child {
+  margin-bottom: 0;
+}
+
+.realtime-item .label {
+  font-size: 14px;
+  color: #62f6fb;
+}
+
+.realtime-item .value {
+  font-size: 16px;
+  font-weight: bold;
+  color: #00ffff;
+  text-shadow: 0 0 3px rgba(0, 212, 255, 0.5);
+}
+
+/* 响应式设计 */
+@media (max-width: 1200px) {
+  .dashboard {
+    width: 100%;
+    height: 100vh;
+  }
+  
+  .main-content {
+    flex-direction: column;
+  }
+  
+  .left-sidebar,
+  .center-space,
+  .right-sidebar {
+    flex: 1;
+  }
+  
+  .center-space {
+    height: 50px;
+  }
+  
+  .data-card {
+    max-height: none;
+  }
+}
+
+@media (max-width: 768px) {
+  .system-title {
+    font-size: 24px;
+  }
+  
+  .back-btn {
+    top: 15px;
+    left: 20px;
+  }
+  
+  .main-content {
+    padding: 70px 10px 10px;
+    gap: 10px;
+  }
+  
+  .panel-content {
+    padding: 15px;
+  }
+}
+</style>

+ 11 - 5
src/views/HomeView.vue

@@ -1,12 +1,12 @@
 <template>
   <div class="dashboard">
-    <div class="bottom-bg"></div>
+    <div class="bottom-bg" v-if="!showMap"></div>
     <div class="top-title"></div>
     <div class="system-title">数字孪生黑林小流域</div>
     
     <!-- 全局地图 -->
-    <div class="map-container">
-      <CesiumMap />
+    <div class="map-container" v-if="showMap">
+      <CesiumMap @toggleMap="toggleMap" />
     </div>
     
     <!-- 渐变装饰层(四周暗角) -->
@@ -132,7 +132,8 @@ export default {
   data() {
     return {
       activeTab: '流域总览',
-      activeSecondaryTab: '水文预报'
+      activeSecondaryTab: '水文预报',
+      showMap: true // 控制显示Cesium地图还是图片底图
     }
   },
   methods: {
@@ -146,6 +147,9 @@ export default {
     },
     selectSecondaryTab(tab) {
       this.activeSecondaryTab = tab
+    },
+    toggleMap(show) {
+      this.showMap = show
     }
   }
 }
@@ -165,7 +169,7 @@ export default {
   left: 0;
   width: 100%;
   height: 100%;
-  background-image: url('/src/assets/images/背景.png');
+  background-image: url('/src/assets/images/Heilin/WPS图片(1).jpeg');
   background-size: 100% 100%;
   background-position: center;
   background-repeat: no-repeat;
@@ -215,6 +219,8 @@ export default {
   pointer-events: auto;
 }
 
+
+
 .sub-title {
   position: absolute;
   top: 30px;

+ 4 - 0
vite.config.js

@@ -8,4 +8,8 @@ export default defineConfig({
     vue(),
     cesium()  // 添加 Cesium 插件
   ],
+  server: {
+    host: '127.0.0.1',
+    port: 5173
+  }
 })