Browse Source

Merge branch 'master' of http://39.98.38.2:13000/dumingliang/sh-model-platform

nanjingliujinyu 4 months ago
parent
commit
187cf38adc
30 changed files with 542 additions and 50 deletions
  1. 2 2
      ruoyi-ui/.env.development
  2. BIN
      ruoyi-ui/src/assets/map/img/blue-circle.png
  3. BIN
      ruoyi-ui/src/assets/map/img/left-title.png
  4. BIN
      ruoyi-ui/src/assets/map/img/lefttitle-bg.png
  5. BIN
      ruoyi-ui/src/assets/map/img/square-black.png
  6. BIN
      ruoyi-ui/src/assets/map/img/square-brown.png
  7. BIN
      ruoyi-ui/src/assets/map/img/square-green.png
  8. BIN
      ruoyi-ui/src/assets/map/img/square-pink.png
  9. BIN
      ruoyi-ui/src/assets/map/img/square-yellow.png
  10. BIN
      ruoyi-ui/src/assets/map/img/Ⅰ.png
  11. BIN
      ruoyi-ui/src/assets/map/img/Ⅱ.png
  12. BIN
      ruoyi-ui/src/assets/map/img/Ⅲ.png
  13. BIN
      ruoyi-ui/src/assets/map/img/Ⅳ.png
  14. BIN
      ruoyi-ui/src/assets/map/img/Ⅴ.png
  15. BIN
      ruoyi-ui/src/assets/map/img/劣Ⅴ.png
  16. BIN
      ruoyi-ui/src/assets/map/img/取消.png
  17. BIN
      ruoyi-ui/src/assets/map/img/台风.png
  18. BIN
      ruoyi-ui/src/assets/map/img/站点.png
  19. BIN
      ruoyi-ui/src/assets/map/img/组件-弹窗.png
  20. BIN
      ruoyi-ui/src/assets/map/img/维修.png
  21. BIN
      ruoyi-ui/src/assets/map/img/视频监控.png
  22. BIN
      ruoyi-ui/src/assets/map/img/风场.png
  23. 0 0
      ruoyi-ui/src/assets/map/json/stnmData.json
  24. 0 0
      ruoyi-ui/src/assets/map/json/stnmMath.json
  25. BIN
      ruoyi-ui/src/assets/styles/css/ALIMAMASHUHEITI-BOLD.TTF
  26. BIN
      ruoyi-ui/src/assets/styles/css/Alibaba-PuHuiTi-Regular.ttf
  27. 14 0
      ruoyi-ui/src/assets/styles/css/font.css
  28. 3 0
      ruoyi-ui/src/main.js
  29. 9 0
      ruoyi-ui/src/views/map/components/iconDropDialog.vue
  30. 514 48
      ruoyi-ui/src/views/map/index.vue

+ 2 - 2
ruoyi-ui/.env.development

@@ -10,8 +10,8 @@ VITE_APP_BASE_Title = '/sh'
 # 若依管理系统/生产环境
 VITE_APP_BASE_API = '/sh-api'
 
-VITE_DEV_PATH = 'http://localhost:8082'
-# VITE_DEV_PATH = 'http://39.98.38.2:18082/sh-api'
+# VITE_DEV_PATH = 'http://localhost:8082'
+VITE_DEV_PATH = 'http://39.98.38.2:18082/sh-api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli
 VITE_BUILD_COMPRESS = gzip

BIN
ruoyi-ui/src/assets/map/img/blue-circle.png


BIN
ruoyi-ui/src/assets/map/img/left-title.png


BIN
ruoyi-ui/src/assets/map/img/lefttitle-bg.png


BIN
ruoyi-ui/src/assets/map/img/square-black.png


BIN
ruoyi-ui/src/assets/map/img/square-brown.png


BIN
ruoyi-ui/src/assets/map/img/square-green.png


BIN
ruoyi-ui/src/assets/map/img/square-pink.png


BIN
ruoyi-ui/src/assets/map/img/square-yellow.png


BIN
ruoyi-ui/src/assets/map/img/Ⅰ.png


BIN
ruoyi-ui/src/assets/map/img/Ⅱ.png


BIN
ruoyi-ui/src/assets/map/img/Ⅲ.png


BIN
ruoyi-ui/src/assets/map/img/Ⅳ.png


BIN
ruoyi-ui/src/assets/map/img/Ⅴ.png


BIN
ruoyi-ui/src/assets/map/img/劣Ⅴ.png


BIN
ruoyi-ui/src/assets/map/img/取消.png


BIN
ruoyi-ui/src/assets/map/img/台风.png


BIN
ruoyi-ui/src/assets/map/img/站点.png


BIN
ruoyi-ui/src/assets/map/img/组件-弹窗.png


BIN
ruoyi-ui/src/assets/map/img/维修.png


BIN
ruoyi-ui/src/assets/map/img/视频监控.png


BIN
ruoyi-ui/src/assets/map/img/风场.png


File diff suppressed because it is too large
+ 0 - 0
ruoyi-ui/src/assets/map/json/stnmData.json


File diff suppressed because it is too large
+ 0 - 0
ruoyi-ui/src/assets/map/json/stnmMath.json


BIN
ruoyi-ui/src/assets/styles/css/ALIMAMASHUHEITI-BOLD.TTF


BIN
ruoyi-ui/src/assets/styles/css/Alibaba-PuHuiTi-Regular.ttf


+ 14 - 0
ruoyi-ui/src/assets/styles/css/font.css

@@ -0,0 +1,14 @@
+@charset "UTF-8";
+
+@font-face {
+  font-family: "ALIMAMASHUHEITI";
+  src: url('./ALIMAMASHUHEITI-BOLD.TTF') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: "PuHuiTi";
+  src: url('./Alibaba-PuHuiTi-Regular.ttf') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}

+ 3 - 0
ruoyi-ui/src/main.js

@@ -53,6 +53,9 @@ import DictTag from "@/components/DictTag";
 import * as echarts from 'echarts';
 import JsonViewer from 'vue-json-viewer'
 import 'vue-json-viewer/style.css'
+// 字体
+import './assets/styles/css/font.css'
+
 const pinia = createPinia()
 const app = createApp(App);
 

+ 9 - 0
ruoyi-ui/src/views/map/components/iconDropDialog.vue

@@ -0,0 +1,9 @@
+<template>
+  <div class="">
+    
+  </div>
+</template>
+
+<script setup></script>
+
+<style scoped lang="scss"></style>

+ 514 - 48
ruoyi-ui/src/views/map/index.vue

@@ -2,15 +2,81 @@
   <div class="map-index">
     <div id="mapChart"></div>
     <div class="map-left">
-      <div class="map-left-top">
-        <div class="left-top-title"></div>
+      <div class="left-title">模型列表</div>
+      <div class="left-tree">
+        <el-tree
+          :data="data"
+          :props="defaultProps"
+          show-checkbox
+          node-key="id"
+          :default-expanded-keys="[1, 8]"
+          :default-checked-keys="[1]"
+          @node-click="handleNodeClick"
+          @check-change="handleCheckChange"
+        />
       </div>
-      <div class="map-left-center">
-        <div class="left-center-title"></div>
+    </div>
+    <div class="map-right">
+      <div class="right-title">模型数据展示</div>
+      <div class="right-top-title">
+        <img src="@/assets/map/img/站点.png"/>
+        <span>预报站点信息</span>
       </div>
-      <div class="map-left-bottom">
-        <div class="left-bottom-title"></div>
+        <div class="station-table">
+          <el-scrollbar style="height: 100%;">
+            <table>
+              <thead>
+                <tr> 
+                  <td class="table-index">序号</td>
+                  <td class="table-head">站码</td>
+                  <td class="table-head">站名</td>
+                  <td class="table-head">实时潮位</td>
+                  <td class="table-head">发生时间</td>
+                  <td class="table-head">警戒潮位</td>
+                  <td class="table-head">距离警戒</td>
+                  <td class="table-head">预报潮位</td>
+                  <td class="table-head">发生时间</td>
+                  <td class="table-head">距离警戒</td>
+                </tr>
+              </thead>
+              <tbody>
+                <tr 
+                v-for="(item,index) in StnmData.data" 
+                :key="index" 
+                >
+                  <td class="table-index">{{index+1}}</td>
+                  <td class="table-tbody">{{item.stationName}}</td>
+                  <td class="table-tbody">{{ item.stationCode}}</td>
+                  <td class="table-tbody"></td>
+                  <td class="table-tbody"></td>
+                  <td class="table-tbody"></td>
+                  <td class="table-tbody"></td>
+                  <td class="table-tbody"></td>
+                  <td class="table-tbody"></td>
+                  <td class="table-tbody"></td>
+                </tr>
+              </tbody>
+            </table>
+          </el-scrollbar>
+        </div>
+    </div>
+    <!-- 可拖拽图标组 -->
+    <div 
+      class="map-fcicon" 
+      :style="{ left: fcPosition.x + 'px', top: fcPosition.y + 'px' }"
+      v-show="showIcon"
+      @mousedown="startDrag"
+    ></div>
+    <div 
+      class="dialog" 
+      v-if="showDialog" 
+      :style="{ left: dialogPosition.x + 'px', top: dialogPosition.y + 'px' }"
+    >
+      <div class="dialog-header" @mousedown="startDialogDrag">
+        风场
+        <button class="close-btn" @click="closeDialog">×</button>
       </div>
+      <div class="dialog-body"></div>
     </div>
   </div>
 </template>
@@ -29,26 +95,70 @@ import Fill from "ol/style/Fill";
 import Feature from 'ol/Feature';
 import Stroke from "ol/style/Stroke";
 import Overlay from 'ol/Overlay';
+import StnmData from "@/assets/map/json/stnmData.json";
+import red_trangle from "@/assets/map/img/Ⅳ.png";
 
 const mapChart = ref(null);
 const mapCenter = ref([121.472644, 31.231706]);
-const mapZoom = ref(10);
-const mapCheckbox = ref({
-  wyhChecked: true,
-  tphChecked: true,
-  xmhChecked: false,
-  xmhChecked_js: false,
-  wyhChecked_lh: false,
-  zdChecked: false,
-  lzspChecked: false,
-  thsyChecked: false,
-  thlzChecked: false,
-  zysyChecked: false,
-  wrjzysyChecked: false,
-});
+const mapZoom = ref(9);
+const data = [
+  {
+    id:1,
+    label: '上海市城区洪涝仿真模型',
+    children: [
+      {
+        id:8,
+        label: '上海市城区洪涝仿真模型-1',
+      },
+    ],
+  },
+  {
+    id:2,
+    label: '上海沿海风暴潮预报模型',
+  },
+  {
+    id:3,
+    label: '黄浦江水系水文分析预报数值模拟',
+  },
+  {
+    id:4,
+    label: '苏州河水系水情预报模型',
+  },
+  {
+    id:5,
+    label: '内涝风险实时预警与预报',
+  },
+  {
+    id:6,
+    label: '上海市中心城区排水系统模型',
+  },
+  {
+    id:7,
+    label: '温带风暴潮预报模型',
+  },
+]
+
+const defaultProps = {
+  children: 'children',
+  label: 'label',
+}
+const stnmVectorLayer = ref(null);
+const popupOverlays = ref([]);// 存储弹窗的引用
+        const showIcon = ref(true);
+        const showDialog = ref(false);
+        const isDragging = ref(false);
+        
+        const fcPosition = ref({ x: 280, y: 40 });
+        const dialogPosition = ref({ x: 0, y: 0 });
+        
+        const dragStartPosition = ref({ x: 0, y: 0 });
+        const isDraggingDialog = ref(false);
+        const dialogDragStart = ref({ x: 0, y: 0 });
 
 onMounted(() => {
   initMap();
+  console.log('StnmData',StnmData);
+  
 });
 
 const initMap = () => { 
@@ -85,10 +195,169 @@ const initMap = () => {
       scaleLine:false,//不显示比例尺控件
     })
   });
+  addStnm();
+};
+const addStnm = () => { 
+  let features = [];
+  let stationPopData = [];
+  const targetStations = ['绿华山', '横沙', '崇西闸', '金山嘴'];
+  StnmData.data.forEach(item => {
+    targetStations.includes(item.stationName) && stationPopData.push(item);
+      let point = new Point([item.lgtd, item.lttd]);
+      let feature = new Feature({
+        geometry: point,
+        name: item.stationName,
+        properties: item,
+      });
+      var style = new Style({
+        image: new Icon({
+          anchor: [0.5, 0.5],
+          scale: 0.08,
+          src: red_trangle,
+        }),
+      });
+      feature.setStyle(style);
+      features.push(feature);
+    })
+  let vectorSource = new VectorSource({
+    features: features,
+  });
+  stnmVectorLayer.value = new VectorLayer({
+    source: vectorSource,
+  });
+  mapChart.value.addLayer(stnmVectorLayer.value);
+  showPopupInfo(stationPopData);
+};
+// 显示地图坐标信息
+const showPopupInfo = (data) => {
+  data.forEach((station, index) => {
+    // 创建弹窗元素
+    const popupElement = document.createElement('div');
+    popupElement.className = 'custom-popup';
+    popupElement.id = `popup_${station.stationCode}`;
+    // 设置弹窗内容
+    popupElement.innerHTML = `
+        <div class="popup-title">${station.stationName} (${station.stationCode})</div>
+        <div class="popup-top">
+          <span>实时潮位:<span></span></span>
+          <span>发生时间:<span></span></span>
+          <span>警戒潮位:<span></span></span>
+          <span>距离警戒:<span></span></span>
+        </div>
+        <div class="popup-bottom">
+          <span>预报潮位:<span></span></span>
+          <span>发生时间:<span></span></span>
+          <span>距离警戒:<span></span></span>
+        </div>
+    `;
+    let popupOverlay = new Overlay({
+      element: popupElement,
+      positioning: "top-center",
+      stopEvent: false,
+      offset: [0, -200],
+    });
+    const coordinate = [station.lgtd, station.lttd];
+    popupOverlay.setPosition(coordinate);
+    mapChart.value.addOverlay(popupOverlay);
+    // 保存引用
+    popupOverlays.value.push(popupOverlay);
+  });
+};
+// 清除所有弹窗
+const clearPopups = () => {
+  popupOverlays.value.forEach(overlay => {
+    mapChart.value.removeOverlay(overlay);
+  });
+  popupOverlays.value = [];
+};
+
+const startDrag = (event) => {
+  isDragging.value = true;
+  dragStartPosition.value = {
+    x: event.clientX - fcPosition.value.x,
+    y: event.clientY - fcPosition.value.y
+  };
+          
+  window.addEventListener('mousemove', onMouseMove);
+  window.addEventListener('mouseup', onMouseUp);
+}; 
+const onMouseMove = (event) => {
+  if (!isDragging.value) return;
+          
+  fcPosition.value = {
+    x: event.clientX - dragStartPosition.value.x,
+    y: event.clientY - dragStartPosition.value.y
+  };
+  dialogPosition.value = {
+    x:fcPosition.value.x,
+    y:fcPosition.value.y
+  }
+}; 
+const onMouseUp = () => {
+  if (isDragging.value) {
+    showIcon.value = false;
+    showDialog.value = true;
+    isDragging.value = false;
+    window.removeEventListener('mousemove', onMouseMove);
+    window.removeEventListener('mouseup', onMouseUp);
+  }
+};     
+const startDialogDrag = (event) => {
+  isDraggingDialog.value = true;
+  dialogDragStart.value = {
+    x: event.clientX - dialogPosition.value.x,
+    y: event.clientY - dialogPosition.value.y
+  };
+          
+  window.addEventListener('mousemove', onDialogMouseMove);
+  window.addEventListener('mouseup', onDialogMouseUp);
+};    
+const onDialogMouseMove = (event) => {
+  if (!isDraggingDialog.value) return;
+          
+  dialogPosition.value = {
+    x: event.clientX - dialogDragStart.value.x,
+    y: event.clientY - dialogDragStart.value.y
+  };
+};
+        
+const onDialogMouseUp = () => {
+  isDraggingDialog.value = false;
+  window.removeEventListener('mousemove', onDialogMouseMove);
+  window.removeEventListener('mouseup', onDialogMouseUp);
+};
+        
+const closeDialog = () => {
+  showDialog.value = false;
+  showIcon.value = true;
+  fcPosition.value = {
+    x: 280,
+    y: 40
+  }
 };
+        
+onUnmounted(() => {
+  window.removeEventListener('mousemove', onMouseMove);
+  window.removeEventListener('mouseup', onMouseUp);
+  window.removeEventListener('mousemove', onDialogMouseMove);
+  window.removeEventListener('mouseup', onDialogMouseUp);
+});
 </script>
 
 <style scoped lang="scss">
+/*滚动条里面轨道*/
+::-webkit-scrollbar-track{
+  background-color: rgba(20, 19, 19,0);
+}
+/*关键设置 tbody出现滚动条*/ 
+::-webkit-scrollbar-thumb{                
+  background-color: rgba(58, 100, 179,0.5);    
+  border-radius: 8px 10px;    
+}
+  ::v-deep(.el-scrollbar) {
+    --el-scrollbar-bg-color: rgba(58, 100, 179);
+    --el-scrollbar-hover-bg-color: rgba(58, 100, 179);
+}
 .map-index{
   height: 100%;
   width: 100%;
@@ -99,42 +368,239 @@ const initMap = () => {
   }
   .map-left{
     position: absolute;
-    top: 0;
-    left: 0;
-    height: 100%;
-    width: 458px;
-    background: url("@/assets/map/img/left-box.png");
-    background-size: 100% 100%;
-    .map-left-top{
+    top: 1%;
+    left: 0.5%;
+    height: 98%;
+    width: 260px;
+    background:rgba(255,255,255,0.9);
+    border-radius: 8px;
+    .left-title{
       width: 100%;
-      height: 33%;
-      .left-top-title{
-        width: 88%;
-        height: 30px;
-        margin: 30px 0 10px 6%;
-        background-image: -webkit-linear-gradient(left, rgba(18, 150, 219, 1), rgba(71, 175, 229, 0));
-      }
+      height: 36px;
+      background: url("@/assets/map/img/left-title.png") no-repeat;
+      background-size: 100% 100%;
+      font-size: 16px;
+      font-family: 'PuHuiTi', sans-serif;
+      font-weight: bolder;
+      color: #fff;
+      text-align: center;
+      line-height: 34px;
+    }
+  }
+  .map-right{
+    position: absolute;
+    top: 1%;
+    right: 0.5%;
+    height: 98%;
+    width: 400px;
+    background:rgba(255,255,255,0.9);
+    border-radius: 8px;
+    .right-title{
+      width: 100%;
+      height: 36px;
+      background: url("@/assets/map/img/left-title.png") no-repeat;
+      background-size: 100% 100%;
+      font-size: 16px;
+      font-family: 'PuHuiTi', sans-serif;
+      font-weight: bolder;
+      color: #fff;
+      text-align: center;
+      line-height: 34px;
     }
-    .map-left-center{
+    .right-top-title{
       width: 100%;
-      height: 33%;
-      .left-center-title{
-        width: 88%;
-        height: 30px;
-        margin: 0 0 10px 6%;
-        background-image: -webkit-linear-gradient(left, rgba(18, 150, 219, 1), rgba(71, 175, 229, 0));
+      line-height: 30px;
+      padding: 10px;
+      display: flex;
+      img{
+        width: 30px;
+        height:30px;
+      }
+      span{
+        color: #000;
+        font-size: 16px;
+        font-family: 'PuHuiTi', sans-serif;
+        font-weight: bolder;
+        margin-left: 10px;
       }
     }
-    .map-left-bottom{
+  }
+}
+.station-table{
+  width: 94%;
+  margin:0 3%;
+  .table-index{
+    width: 40px;
+  }
+  .table-head{
+    width: 80px;
+  }
+  table{
+    width: 100%;
+    border-spacing: 0px;
+    border-collapse: collapse; /* 设置表格边框合并为单线 */
+    border-top: 2px solid #82bcfd;
+    border-bottom: 2px solid #82bcfd;
+    thead{
+      background-image: -webkit-linear-gradient(top, #ebf5ff, #fff);
+      color:#000;
+      font-size:14px;
+      font-family: 'PuHuiTi', sans-serif;
+      font-weight: bold;
       width: 100%;
-      height: 33%;
-      .left-bottom-title{
-        width: 88%;
-        height: 30px;
-        margin: 0 0 10px 6%;
-        background-image: -webkit-linear-gradient(left, rgba(18, 150, 219, 1), rgba(71, 175, 229, 0));
+      border-left: 1px solid #d3e8f9;
+      border-right: 1px solid #d3e8f9;
+      border-bottom: 1px solid #d3e8f9;
+      td{
+        text-align: center;
+        padding: 10px 0;
       }
     }
+  tbody{
+    color:#000;
+    font-size:12px;
+    font-family: 'PuHuiTi', sans-serif;
+    width: 100%;
+    border: 1px solid #d3e8f9;
+    border-top:none;
+    tr{
+      line-height: 28px;
+      background-image: -webkit-linear-gradient(top, #d7eaff, #fff);
+    }
+    td{
+      /* border-bottom: 1px solid #d4f0fc; */
+      text-align: center;
+      padding: 5px 0;
+    }
+  }
+}   
+  table tbody {
+  display: block;
+  height: 20vh !important;
+  overflow-y: scroll;
+  }
+  table thead,tbody tr {
+    display: table;
+    width: 100%;
+    table-layout: fixed;
+  }
+}
+    .map-fcicon {
+      position: absolute;
+      width: 40px;
+      height: 40px;
+      background-image: url("@/assets/map/img/风场.png");
+      background-repeat: no-repeat;
+      background-size: 50%;
+      background-position: center;
+      background-color: rgba(72, 174, 228);
+      color: white;
+      border-radius: 50%;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      cursor: grab;
+      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+      transition: transform 0.2s, box-shadow 0.2s;
+      z-index: 10;
+      .fc-img{
+        width: 25px;
+        height: 25px;
+      }
+    }
+    
+    .map-fcicon:hover {
+      transform: scale(1.1);
+      box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+    }
+    
+    .map-fcicon:active {
+      cursor: grabbing;
+    }
+    
+    .dialog {
+      position: absolute;
+      width: 300px;
+      background: white;
+      border-radius: 10px;
+      box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
+      overflow: hidden;
+      z-index: 100;
+    }
+    
+    .dialog-header {
+      padding: 5px;
+      background: rgba(52, 152, 219,0.8);
+      color: white;
+      cursor: move;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    
+    .dialog-body {
+      padding: 20px;
+      color: #2c3e50;
+    }
+    
+    .close-btn {
+      background: none;
+      border: none;
+      color: white;
+      font-size: 20px;
+      cursor: pointer;
+    }
+    
+    .drop-indicator {
+      position: absolute;
+      bottom: 20px;
+      left: 50%;
+      transform: translateX(-50%);
+      padding: 10px 20px;
+      background: #2ecc71;
+      color: white;
+      border-radius: 20px;
+      opacity: 0;
+      transition: opacity 0.3s;
+    }
+    
+    .drop-indicator.visible {
+      opacity: 1;
+    }
+</style>
+<style lang="scss">
+.custom-popup {
+  background: rgba(255, 255, 255, 0.95);
+  border-radius: 8px;
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
+  border: 1px solid #3498db;
+  width: 172px;
+  .popup-title{
+    width: 100%;
+    line-height: 15px;
+    background-color: rgba(255, 23, 0);
+    padding: 10px;  
+    text-align: center;
+    color: #fff;
+    font-size: 16px;
+  }
+  .popup-top{
+    padding:5px 10px;  
+    width: 100%;
+    background-color: rgba(58, 100, 179);
+    display: flex;
+    flex-direction: column;
+    color: #fff;
+    font-size: 14px;
+  }
+  .popup-bottom{
+    padding:5px 10px;  
+    width: 100%;
+    background-color: rgba(71, 146, 211);
+    display: flex;
+    flex-direction: column;
+    color: #fff;
+    font-size: 14px;
   }
 }
 </style>

Some files were not shown because too many files changed in this diff