linqilong 1 hónapja
szülő
commit
3fddb19bf8

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 196 - 141
src/api/station.ts


+ 27 - 18
src/components/StationRightButtonGroup.vue

@@ -41,7 +41,7 @@ const station = computed(() => getStation(route.params.stcd));
 // 是否显示关卡按钮
 const hasLevel = computed(() => !!stationStore.stnm);
 // 水下地形
-const underwaterState = ref(true);
+const underwaterState = ref(false);
 // 水文站标签
 const hydrologicStationState = computed({
   get: () => basinStore.labelState['水文站'],
@@ -100,13 +100,14 @@ function formatWaterLevelTooltip(val: number) {
     case "波高":
       return (val).toFixed(2) as string
   }
-
 }
 
 function handleHome() {
   appStore.changeCurrentLevel('TaiHuMain')
   // 切换太湖流域视角
   appStore.changeCurrentView()
+  // 显示水文站标签
+  basinStore.setLabelState2('水文站', true)
 }
 
 async function handleSimulationModeChange(mode) {
@@ -248,15 +249,15 @@ function handleWavesChange(type) {
     wavesValue.value = '无'
   } else {
     wavesValue.value = type
-    const dateString = "20250429" // formatd(new Date(), "yyyyMMdd")
+    const dateString = "20250430" // formatd(new Date(), "yyyyMMdd")
 
-    let timeList = generateTimeList(dateString + '00', 2, 3);
+    const timeList = generateTimeList(dateString + '00', 2, 3);
     const timeScrollbarStore = useTimeScrollbarStore()
     timeScrollbarStore.setTimeScrollbarShow(true)
     timeScrollbarStore.setMax(timeList.length)
     const timeObj = extractList(timeList, 4)
 
-    for (let key in timeObj) {
+    for (const key in timeObj) {
       timeObj[key] = {
         style: {
           color: '#00c7e3',
@@ -287,22 +288,28 @@ watch(() => underwaterState.value, (value) => {
 })
 
 function handleWaves() {
-  if (route.path.indexOf('/waves') > -1) {
+  if (appStore.currentLevel === 'TaiHuMain') {
+    appStore.changeCurrentLevel('Demo')
+    router.push('/waves')
+  } else {
     stationStore.setStnm('')
     appStore.changeCurrentLevel('TaiHuMain')
     router.push('/');
-  } else {
-    appStore.changeCurrentLevel('Demo')
-    router.push('/waves')
   }
 }
 
 watch(() => route.path, (path) => {
   if (path.indexOf('/index') >= 0) {
+    // 显示水文站标签
+    basinStore.setLabelState2('水文站', true)
     showBtnList.value = ['home', 'view', 'label', 'waves', 'typhoon', 'underwater']
   } else if (path.indexOf('/waves') >= 0) {
+    // 关闭水文站标签
+    basinStore.setLabelState2('水文站', false)
     showBtnList.value = ['weather', 'simulation']
   } else if (path.indexOf('/yuyan') >= 0) {
+    // 关闭水文站标签
+    basinStore.setLabelState2('水文站', false)
     showBtnList.value = ['home', 'view', 'waves']
   }
 }, {immediate: true, deep: true})
@@ -350,8 +357,9 @@ watch(() => route.path, (path) => {
         </div>
       </template>
       <el-button-group>
-        <el-button v-for="item in ['晴','小雨','中雨','大雨']" :key="item"
-                   @click="Setting.setWeather(item)">{{ item }}
+        <el-button v-for="item in ['晴', '小雨', '中雨', '大雨']" :key="item" @click="Setting.setWeather(item)">{{
+            item
+          }}
         </el-button>
       </el-button-group>
     </el-popover>
@@ -398,7 +406,7 @@ watch(() => route.path, (path) => {
         </div>
       </template>
       <el-radio-group v-model="simulationMode" size="large" @change="handleSimulationModeChange">
-        <el-radio-button v-for="item in ['水位','雨量','波高','无']" :key="item" :label="item" :value="item"/>
+        <el-radio-button v-for="item in ['水位', '雨量', '波高', '无']" :key="item" :label="item" :value="item"/>
       </el-radio-group>
     </el-popover>
 
@@ -407,18 +415,17 @@ watch(() => route.path, (path) => {
       <icon :data="chat"/>
     </div>
 
-    <div class="right-btn-item" @click="appStore.setExpand(!appStore.isExpand)">
+    <div v-show="false" class="right-btn-item" @click="appStore.setExpand(!appStore.isExpand)">
       <img :src="backgroundSrc" alt="" style="position: absolute;"/>
       <icon :data="appStore.isExpand ? horizontalExpand : horizontalContract"/>
     </div>
 
     <div v-if="simulationMode !== '无'" class="slider-wrapper">
-      <div :style="{'background-image': `url(${waterSliderBackground})`}" class="water-level-slider-container">
+      <div :style="{ 'background-image': `url(${waterSliderBackground})` }" class="water-level-slider-container">
         <div class="water-level-slider-main">
           <el-slider v-model="waterLevel" :format-tooltip="formatWaterLevelTooltip" :marks="waterLevelMarks"
                      :max="waterLevelMax" :min="waterLevelMin" :step="waterLevelStep" height="90%" placement="right"
-                     tooltip-class="slider-tooltip" vertical
-                     @input="value => bus.emit('set-water-level', value)"/>
+                     tooltip-class="slider-tooltip" vertical @input="value => bus.emit('set-water-level', value)"/>
           <span class="water-level-slider-title">{{ simulationMode }}动态模拟</span>
         </div>
       </div>
@@ -455,7 +462,8 @@ watch(() => route.path, (path) => {
       z-index: 1;
     }
 
-    &:hover, &.active {
+    &:hover,
+    &.active {
       svg {
         fill: #00cbe6;
       }
@@ -527,7 +535,8 @@ watch(() => route.path, (path) => {
       z-index: 1;
     }
 
-    &:hover, &.active {
+    &:hover,
+    &.active {
       svg {
         fill: #00cbe6;
       }

+ 1 - 1
src/components/UePlayer.vue

@@ -24,7 +24,7 @@ onMounted(() => {
       ss: "ws://10.8.11.98:65",
       AutoConnect: true,
       AutoPlayVideo: true,
-      StartVideoMuted: false,
+      StartVideoMuted: true,
       KeyboardInput: false,
       TouchInput: true,
       HoveringMouse: true,

+ 0 - 1
src/components/chat.vue

@@ -14,7 +14,6 @@ const position = ref({
 
 bus.on('chat', (query: string) => {
   workflowsRun(query).then(res => {
-    console.log('outputs', res.data.outputs)
     if (res.data.outputs && res.data.outputs.answer && res.data.outputs.answer != 'null') {
       chatIframeRef.value.contentWindow.postMessage({answer: res.data.outputs.answer}, chatHost);
     }

+ 0 - 1
src/components/tag/DataTag.vue

@@ -24,7 +24,6 @@ watch(() => props.data, (val) => {
     }, {});
     waterQuery['STCD'] = route.params.stcd
     getWaterQualityAssessment([waterQuery]).then(res => {
-      console.log(res)
       if (res.result) {
 
       }

+ 1 - 1
src/permission.ts

@@ -17,7 +17,7 @@ router.beforeEach((to, from, next) => {
   //     next();
   //   } else {
   //     // 否则全部重定向到登录页
-  //     window.location.href = 'http://10.8.11.123:8089/cas/login?service=http://localhost/check'
+  //     window.location.href = 'http://10.8.11.123:8089/cas/login?service=http://192.168.137.184/check'
   //   }
   // }
 });

+ 1 - 0
src/stores/app.ts

@@ -6,6 +6,7 @@ import {View} from "@/utils/tdInstruction";
 
 export const useAppStore = defineStore('app', () => {
   const route = useRoute()
+
   // 底板类型
   const floorType = ref('ue')
   // 当前视角

+ 84 - 0
src/utils/slopeCalculation.ts

@@ -0,0 +1,84 @@
+/**
+ * 坡面计算
+ * @param data 环湖站点数据
+ *
+ *
+ */
+export function slopeCalculation(data: any[]) {
+// 数据处理:提取坐标和水位
+  const points = data.map(item => ({
+    x: parseFloat(item.x),
+    y: parseFloat(item.y),
+    h: parseFloat(item.value)
+  }));
+
+  // 执行计算并输出结果
+  try {
+    const result = calculateSlope(points);
+    console.log("平面方程: h =",
+      `${result.a.toFixed(6)}x + ${result.b.toFixed(6)}y + ${result.c.toFixed(2)}`);
+    console.log("坡度:", result.slope.toFixed(6), "米/经度纬度单位");
+    console.log("倾斜方向:", result.direction.toFixed(2) + "°(0°为正东,逆时针方向)");
+    return {
+      slope: result.slope.toFixed(6),
+      direction: result.direction.toFixed(2)
+    }
+  } catch (error: any) {
+    console.error("计算失败:", error.message);
+  }
+}
+
+// 平面方程:h = ax + by + c
+function calculateSlope(points: any[]) {
+  // 构建设计矩阵 A 和向量 h
+  const A = points.map(p => [p.x, p.y, 1]);
+  const h = points.map(p => p.h);
+
+  // 计算 A^T * A 和 A^T * h
+  const AT = A[0].map((_, colIdx) => A.map(row => row[colIdx])); // 转置矩阵
+  const ATA = AT.map(row =>
+    A[0].map((_, colIdx) =>
+      row.reduce((sum, val, i) => sum + val * A[i][colIdx], 0)
+    )
+  );
+  const ATh = AT.map(row =>
+    row.reduce((sum, val, i) => sum + val * h[i], 0)
+  );
+
+  // 解方程 ATA * [a, b, c]^T = ATh
+  const det = ATA[0][0] * (ATA[1][1] * ATA[2][2] - ATA[1][2] * ATA[2][1]) -
+    ATA[0][1] * (ATA[1][0] * ATA[2][2] - ATA[1][2] * ATA[2][0]) +
+    ATA[0][2] * (ATA[1][0] * ATA[2][1] - ATA[1][1] * ATA[2][0]);
+
+  if (Math.abs(det) < 1e-10) throw new Error("无法计算,数据共线");
+
+  const invDet = 1 / det;
+  const invATA = [
+    [
+      (ATA[1][1] * ATA[2][2] - ATA[1][2] * ATA[2][1]) * invDet,
+      (ATA[0][2] * ATA[2][1] - ATA[0][1] * ATA[2][2]) * invDet,
+      (ATA[0][1] * ATA[1][2] - ATA[0][2] * ATA[1][1]) * invDet
+    ],
+    [
+      (ATA[1][2] * ATA[2][0] - ATA[1][0] * ATA[2][2]) * invDet,
+      (ATA[0][0] * ATA[2][2] - ATA[0][2] * ATA[2][0]) * invDet,
+      (ATA[0][2] * ATA[1][0] - ATA[0][0] * ATA[1][2]) * invDet
+    ],
+    [
+      (ATA[1][0] * ATA[2][1] - ATA[1][1] * ATA[2][0]) * invDet,
+      (ATA[0][1] * ATA[2][0] - ATA[0][0] * ATA[2][1]) * invDet,
+      (ATA[0][0] * ATA[1][1] - ATA[0][1] * ATA[1][0]) * invDet
+    ]
+  ];
+
+  const a = invATA[0][0] * ATh[0] + invATA[0][1] * ATh[1] + invATA[0][2] * ATh[2];
+  const b = invATA[1][0] * ATh[0] + invATA[1][1] * ATh[1] + invATA[1][2] * ATh[2];
+  const c = invATA[2][0] * ATh[0] + invATA[2][1] * ATh[1] + invATA[2][2] * ATh[2];
+
+  // 计算坡度及方向
+  const slope = Math.sqrt(a ** 2 + b ** 2);
+  const direction = (Math.atan2(b, a) * 180 / Math.PI + 360) % 360; // 转换为0-360度
+
+  return {a, b, c, slope, direction};
+}
+

+ 3 - 3
src/utils/tdInstruction/label.ts

@@ -32,11 +32,11 @@ export function closeAllLabel() {
 const hydrologicStationStcds = [...stationList.filter(s => s.stcd).map(s => s.stcd), '63201999']
 
 async function addHydrologicStationPoints() {
-  const data = await getHydrologicStation().then(res => {
+  await getHydrologicStation().then(res => {
     const list = res.data.filter((d: any) => hydrologicStationStcds.includes(d.stcd))
     const data = [...list.map((d: any) => {
-      return {name: `${d.z}\n${d.stnm}`, type: "水文站", x: d.lgtd, y: d.lttd}
-    }), {name: "庙港", type: "水文站", x: "120.449466", y: "30.990836"}]
+      return {id: d.stnm, name: `${d.z}\n${d.stnm}`, type: "水文站", x: d.lgtd, y: d.lttd}
+    }), {id: "庙港", name: "庙港", type: "水文站", x: "120.449466", y: "30.990836"}]
 
     Point.addPoint(data, '水文站')
   })

+ 84 - 0
src/utils/tdInstruction/operate.ts

@@ -228,6 +228,7 @@ export function setStationData(data: any) {
       "id": data.name,
       "堤顶高程": data.damel,
       "保证水位": data.grz,
+      "青坎线": data.qingkang,
       "警戒水位": data.wrz,
       "当前水位": data.z,
     }
@@ -235,3 +236,86 @@ export function setStationData(data: any) {
   Bus.emit('emitUIInteraction', descriptor);
   console.log("-- 设置站点基础数据:", JSON.stringify(descriptor));
 }
+
+let strategyMapState = false
+
+export function strategyMap(direction: any) {
+  if (strategyMapState) {
+    updateStrategyMapCoord(direction)
+  } else {
+    addStrategyMap(direction)
+  }
+}
+
+/**
+ * 添加太湖湖面图层
+ * @param data
+ */
+export function addStrategyMap(direction: any) {
+  let descriptor = {
+    "command": "AddStrategyMap",
+    "data": {
+      "id": "strategymap_id",
+      "coord_type": "0",
+      "cad_mapkey": "ea",
+      "coord_z_type": "0",
+      "type": "5",
+      "is_gather": "true",
+      "animation_type": "0",
+      "start_coord": "119.938890, 31.106388",
+      "start_coord_z": "600",
+      "target_data": [
+        {
+          "target_coord": "120.405242, 31.444280",
+          "target_coord_z": "600",
+          "color": "ff0000"
+        }
+      ]
+    }
+  }
+  Bus.emit('emitUIInteraction', descriptor);
+  console.log("-- 添加太湖湖面图层:", JSON.stringify(descriptor));
+  strategyMapState = true
+}
+
+/**
+ * 更新太湖湖面图层
+ * @param data
+ */
+export function updateStrategyMapCoord(direction: any) {
+  let descriptor = {
+    "command": "UpdateStrategyMapCoord",
+    "data": {
+      "id": "strategymap_id",
+      "coord_type": "0",
+      "cad_mapkey": "ea",
+      "coord_z_type": "0",
+      "start_coord": "120.243630, 30.9273",
+      "start_coord_z": "100",
+      "target_data": [
+        {
+          "target_coord": "120.405242, 31.444280",
+          "target_coord_z": "200"
+        }
+      ]
+    }
+  }
+  Bus.emit('emitUIInteraction', descriptor);
+  console.log("-- 更新太湖湖面图层:", JSON.stringify(descriptor));
+}
+
+/**
+ * 删除太湖湖面图层
+ */
+export function deleteStrategyMap() {
+  let descriptor = {
+    "command": "DelLevel",
+    "data": {
+      "id": "strategymap_id",
+      "type": "3"
+    }
+  }
+  Bus.emit('emitUIInteraction', descriptor);
+  console.log("-- 删除太湖湖面图层:", JSON.stringify(descriptor));
+  strategyMapState = false
+}

+ 13 - 4
src/utils/tdInstruction/point.ts

@@ -2,10 +2,10 @@ import Bus from "@/utils/bus";
 
 const exitPoints = new Set()
 
-const exitType: any = {
+let exitType: any = {
   "堤防": [],
-  "video": [],
-  "hydrologicStation": [],
+  "视频点": [],
+  "水文站": [],
 }
 
 /**
@@ -78,14 +78,19 @@ export function deletePoint(type: string, data: any) {
     exitType[data].forEach((id: any) => {
       exitPoints.delete(id)
     })
+    exitType[data] = []
   } else if (type === "all") {
     descriptor.data = {
       "all": "true"
     }
     exitPoints.clear()
+    exitType = {
+      "堤防": [],
+      "视频点": [],
+      "水文站": [],
+    }
   }
 
-
   Bus.emit('emitUIInteraction', descriptor)
   console.log("-- 删除点", JSON.stringify(descriptor));
 }
@@ -265,6 +270,10 @@ function updatePointObj(point: any, type = "堤防") {
 }
 
 function updatePoint(data: any, type = "堤防") {
+  if (!data || data.length === 0) {
+    return
+  }
+
   let descriptor = {
     "command": "UpdateCustomPOILabel",
     "data": {

+ 4 - 2
src/utils/tdInstruction/setting.ts

@@ -11,8 +11,10 @@ export function setResolution(d: any) {
   }
 
   let descriptor = {
-    Category: "GetSize",
-    Data: data,
+    command: "GetSize",
+    data: {
+      Data: data,
+    }
   };
   Bus.emit('emitUIInteraction', descriptor)
   console.log("-- 设置分辨率", JSON.stringify(descriptor));

+ 13 - 2
src/views/Home.vue

@@ -1,11 +1,12 @@
 <script lang="ts" setup>
 import {onMounted, reactive} from 'vue'
 import RightFrame from '@/components/RightFrame.vue'
-import {View} from "@/utils/tdInstruction";
+import {Setting, View} from "@/utils/tdInstruction";
 import StationRightButtonGroup from "@/components/StationRightButtonGroup.vue";
 import {useBasinStore} from "@/stores/basin";
+import bus from "@/utils/bus";
 
-const store = useBasinStore()
+const basinStore = useBasinStore()
 const tableColumns = [
   {
     label: '监测点',
@@ -32,6 +33,16 @@ onMounted(() => {
   // 太湖视角
   View.changeView()
 })
+
+bus.on('handle_ue_response', data => {
+  // 底板初始化
+  if (data.Category === "APIAlready") {
+    // 设置分辨率
+    Setting.setResolution({x: 1912, y: 954})
+    // 显示水文站标签
+    basinStore.setLabelState2('水文站', true)
+  }
+})
 </script>
 <template>
   <right-frame>

+ 10 - 9
src/views/Waves.vue

@@ -1,9 +1,9 @@
 <script lang="ts" setup>
-import {onMounted, onUnmounted, reactive, ref} from 'vue'
+import {computed, onMounted, onUnmounted, reactive, ref} from 'vue'
 import RightFrame from '@/components/RightFrame.vue'
 import Card01 from '@/components/card/Card01.vue'
 import StripeTable from '@/components/StripeTable.vue'
-import {Label, Operate} from "@/utils/tdInstruction";
+import {Operate} from "@/utils/tdInstruction";
 import StationRightButtonGroup from "@/components/StationRightButtonGroup.vue";
 import {getYuyanDataList, getYuyanFanganList} from "@/api/yuyan";
 import {convertDate, removeDuplicates} from "@/utils/date";
@@ -14,11 +14,12 @@ import {getStationByName} from "@/assets/js/station"
 import {useAppStore} from "@/stores/app";
 import {useStationStore} from "@/stores/station";
 import bus from "@/utils/bus";
-import router from "@/router";
+import {useRouter} from "vue-router";
 
+const router = useRouter()
 const appStore = useAppStore()
 const stationStore = useStationStore()
-const station = ref(getStationByName(stationStore.stnm))
+const station = computed(() => getStationByName(stationStore.stnm))
 const timeScrollbarStore = useTimeScrollbarStore()
 const tableColumns = [
   // {
@@ -82,15 +83,13 @@ function handleCurrentChange(row) {
 
     timeScrollbarStore.setMarks(timeObj)
     timeScrollbarStore.sliderlTooltip = (value: number) => {
-      Label.setStationLabel('水文站', false)
       const date = timeList[value]
       const data = yuyanData.value.find(y => y.YMDHM.getTime() === date.getTime() && y.STCD === station.value.id)
-
-      let waves = 0
+      let waves: any = 0
       if (data.DATA >= 4) {
         waves = 1
       } else if (data.DATA >= 3) {
-        waves = data.DATA - 3
+        waves = ((data.DATA - 3) / 2).toFixed(1)
       } else if (data.DATA >= 1) {
         waves = 0
       }
@@ -114,12 +113,14 @@ onMounted(() => {
  */
 bus.on('handle_ue_response', (data: any) => {
   if (data.Category && data.Category === '三维堤防' && data.Data && data.Data.Type === '打开成功') {
+    if (station.value.name === '庙港') {
+      station.value['qingkang'] = '5.00'
+    }
     Operate.setStationData(station.value)
   }
 })
 
 onUnmounted(() => {
-  appStore.changeCurrentLevel('TaiHuMain')
   timeScrollbarStore.close()
 })
 </script>

+ 16 - 6
src/views/Yuyan.vue

@@ -3,7 +3,7 @@ import {onMounted, onUnmounted, reactive, ref} from 'vue'
 import RightFrame from '@/components/RightFrame.vue'
 import Card01 from '@/components/card/Card01.vue'
 import StripeTable from '@/components/StripeTable.vue'
-import {Label, Point, View} from "@/utils/tdInstruction";
+import {Operate, Point, View} from "@/utils/tdInstruction";
 import StationRightButtonGroup from "@/components/StationRightButtonGroup.vue";
 import {useBasinStore} from "@/stores/basin";
 import {getYuyanDataList, getYuyanFanganList} from "@/api/yuyan";
@@ -12,9 +12,10 @@ import {useTimeScrollbarStore} from "@/stores/timeScrollbar";
 import {extractList} from "@/utils/list";
 import {formatd} from "@/utils/ruoyi";
 import {stationList} from "@/assets/js/station"
+import {slopeCalculation} from "@/utils/slopeCalculation";
 
 const timeScrollbarStore = useTimeScrollbarStore()
-const store = useBasinStore()
+const basinStore = useBasinStore()
 const tableColumns = [
   // {
   //   label: '监测点',
@@ -48,7 +49,6 @@ function handleCurrentChange(row) {
         YMDHM: convertDate(item.YMDHM)
       }
     })
-    console.log(yuyanData.value)
 
     let timeList = removeDuplicates(yuyanData.value.map(y => y.YMDHM))
     timeScrollbarStore.setTimeScrollbarShow(true)
@@ -68,19 +68,28 @@ function handleCurrentChange(row) {
     timeScrollbarStore.sliderlTooltip = (value: number) => {
       const date = timeList[value]
       const list = yuyanData.value.filter(y => y.YMDHM.getTime() === date.getTime())
-      Point.addPoint(list.map(d => {
+      const data = list.map(d => {
         let station = stationList.find(s => s.id === d.STCD)
 
         if (!station) {
           console.log(`未找到${d.STCD}`)
         }
+
         return {
           id: d.STCD,
-          name: `${(d.DATA).toFixed(2)}\n${station.name}`,
+          name: `${station.name}`,
+          value: `${(d.DATA).toFixed(2)}`,
           type: "水文站",
           x: station.lgtd,
           y: station.lttd
         }
+      })
+
+      const res = slopeCalculation(data);
+      Operate.strategyMap(res.direction);
+
+      Point.addPoint(data.map(a => {
+        return {'id': a.id, 'name': `${a.value}\n${a.name}`, 'type': a.type, 'x': a.x, 'y': a.y}
       }), '水文站')
       return formatd(date, 'yyyy年MM月dd日hh时')
     }
@@ -96,8 +105,9 @@ onMounted(() => {
 })
 
 onUnmounted(() => {
+  Operate.deleteStrategyMap()
   timeScrollbarStore.close()
-  Label.setStationLabel('水文站', false)
+  basinStore.setLabelState2('水文站', false)
 })
 </script>
 <template>

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott