From da67648220f86993fac22b8199165995df3d8563 Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期五, 21 三月 2025 17:35:51 +0800
Subject: [PATCH] 走航融合(待完成)

---
 src/model/SatelliteGrid.js                |  240 +++++++++++++++++++++++++++++
 src/views/underwaymix/UnderwayMixMode.vue |  108 ++++++++++++
 src/components/grid/GridSearch.vue        |   74 +++++++++
 src/components.d.ts                       |    1 
 src/views/HomePage.vue                    |   45 -----
 src/stores/grid-info.js                   |   11 +
 6 files changed, 424 insertions(+), 55 deletions(-)

diff --git a/src/components.d.ts b/src/components.d.ts
index 34b6c69..a0257ee 100644
--- a/src/components.d.ts
+++ b/src/components.d.ts
@@ -54,6 +54,7 @@
     FactorRadio: typeof import('./components/monitor/FactorRadio.vue')['default']
     FactorTrend: typeof import('./components/monitor/FactorTrend.vue')['default']
     GaugeChart: typeof import('./components/chart/GaugeChart.vue')['default']
+    GridSearch: typeof import('./components/grid/GridSearch.vue')['default']
     HistoricalTrajectory: typeof import('./components/animation/HistoricalTrajectory.vue')['default']
     MapLocation: typeof import('./components/map/MapLocation.vue')['default']
     MapScene: typeof import('./components/map/MapScene.vue')['default']
diff --git a/src/components/grid/GridSearch.vue b/src/components/grid/GridSearch.vue
new file mode 100644
index 0000000..c9d90a6
--- /dev/null
+++ b/src/components/grid/GridSearch.vue
@@ -0,0 +1,74 @@
+<template>
+  <CardDialog
+    v-model="dialogVisible"
+    title="缃戞牸淇℃伅"
+    draggable
+    :modal="false"
+    width="300px"
+  >
+    <template #default>
+      <el-form
+        :inline="false"
+        ref="formRef"
+        label-position="right"
+        label-width="100px"
+      >
+        <el-form-item label="缃戞牸缂栧彿锛�">
+          <div>
+            {{ data.cellIndex }}
+          </div>
+        </el-form-item>
+        <el-form-item label="缁忕含搴︼細">
+          <div>
+            {{ data.longitude + ', ' + data.latitude }}
+          </div>
+        </el-form-item>
+        <el-form-item label="PM2.5锛�">
+          <div>
+            {{ data.pm25 + ' 渭g/m鲁' }}
+          </div>
+        </el-form-item>
+        <el-form-item label="鍥涜嚦鑼冨洿锛�">
+          <div>/</div>
+        </el-form-item>
+      </el-form>
+    </template>
+    <template #footer> </template>
+  </CardDialog>
+</template>
+<script setup>
+import { ref, watch, computed } from 'vue';
+import { useGridStore } from '@/stores/grid-info';
+
+const gridStore = useGridStore();
+
+const dialogVisible = ref(false);
+
+const data = computed(() => {
+  if (gridStore.selectedGridCellAndDataDetail) {
+    return {
+      cellIndex: gridStore.selectedGridCellAndDataDetail.gridCell.cellIndex,
+      longitude: gridStore.selectedGridCellAndDataDetail.gridCell.longitude,
+      latitude: gridStore.selectedGridCellAndDataDetail.gridCell.latitude,
+      pm25: gridStore.selectedGridCellAndDataDetail.gridDataDetail.pm25
+    };
+  } else {
+    return {
+      cellIndex: '/',
+      longitude: '/',
+      latitude: '/',
+      pm25: '/'
+    };
+  }
+});
+
+watch(
+  () => gridStore.selectedGridCellAndDataDetail,
+  (nv, ov) => {
+    if (nv != ov) {
+      dialogVisible.value = true;
+    }
+  },
+  { deep: true }
+);
+</script>
diff --git a/src/model/SatelliteGrid.js b/src/model/SatelliteGrid.js
index 0067b78..cb547e9 100644
--- a/src/model/SatelliteGrid.js
+++ b/src/model/SatelliteGrid.js
@@ -394,20 +394,35 @@
     }
   }
 
-  setGridEvent(name, event) {
+  setGridEvent(tags, name, event) {
+    const { _mapViewsList, _gridDataDetailList } = this._getMapViews(...tags);
+
     if (!this.events.has(name)) {
       this.events.set(name, []);
     }
     const list = this.events.get(name);
     if (list.length > 0) {
       const lastEvent = list[list.length - 1];
-      this.mapViews.gridViews.forEach((polygon) => {
-        polygon.off(name, lastEvent);
+      _mapViewsList.forEach((v) => {
+        v.gridViews.forEach((polygon) => {
+          polygon.off(name, lastEvent);
+        });
       });
     }
+
     this.events.get(name).push(event);
-    this.mapViews.gridViews.forEach((polygon) => {
-      polygon.on(name, event);
+    _mapViewsList.forEach((v, i) => {
+      const gridDataDetailList = _gridDataDetailList[i];
+      v.gridViews.forEach((polygon) => {
+        const { gridCell } = polygon.getExtData();
+        const cellIndex = gridCell.cellIndex;
+        const gridDataDetail = gridDataDetailList.find(
+          (v) => v.cellId == cellIndex
+        );
+        polygon.on(name, (e) => {
+          event(gridCell, gridDataDetail);
+        });
+      });
     });
   }
 
@@ -516,7 +531,220 @@
    * @param {string} tag
    */
   drawHeatGrid(tag) {
-    
+    if (!this.mapViewsMap.has(tag) || !this.gridDataDetailMap.has(tag)) {
+      return;
+    }
+
+    const heatTag = `heat-${tag}`;
+    if (this.mapViewsMap.has(heatTag)) {
+      this.changeVisibility({
+        tags: [heatTag],
+        showGridViews: true
+      });
+    } else {
+      const _mapViews = this.mapViewsMap.get(tag);
+      const _gridDataDetail = this.gridDataDetailMap.get(tag);
+      // const groupId = _gridDataDetail[0].groupId;
+      // const cellId = _gridDataDetail.cellId;
+
+      const originCellIdList = _gridDataDetail.map((v) => v.cellId);
+      let headGridDataDetailList = [];
+
+      const width = 120;
+      const height = 90;
+      const eachwidth = 10;
+      const eachheight = 10;
+
+      const searchLength = 3;
+
+      const _dataMap = new Map();
+
+      _gridDataDetail.forEach((gdd) => {
+        const searchRes = this.search(
+          gdd,
+          width,
+          height,
+          eachwidth,
+          eachheight,
+          searchLength
+        );
+        if (searchRes.find(v=> v.cellId == 1670)) {
+          console.log();
+          
+        }
+        searchRes.forEach((e) => {
+          if (originCellIdList.indexOf(e.cellId) == -1) {
+            if (!_dataMap.has(e.cellId)) {
+              _dataMap.set(e.cellId, {
+                source: [],
+                res: {}
+              });
+            }
+            _dataMap.get(e.cellId).source.push(e);
+          }
+        });
+      });
+
+      _dataMap.forEach((v, k) => {
+        let total = 0,
+          count = v.source.length;
+        v.source.forEach((s) => {
+          total += s.pm25;
+        });
+        v.res = {
+          isHeatData: true,
+          groupId: v.source[0].groupId,
+          cellId: v.source[0].cellId,
+          pm25: count == 0 ? null : Math.round((total / count) * 10) / 10,
+          originData: v.source
+        };
+        headGridDataDetailList.push(v.res);
+      });
+      headGridDataDetailList = headGridDataDetailList.concat(_gridDataDetail);
+
+      // 閲嶆柊鎸夌収鐩戞祴鏁版嵁鎺掑簭骞舵爣璁版帓鍚�
+      headGridDataDetailList.sort((a, b) => {
+        return b.pm25 - a.pm25;
+      });
+      headGridDataDetailList.forEach((gdd, i) => {
+        gdd.rank = i + 1;
+      });
+
+      this.drawTagGrid({
+        tag: heatTag,
+        data: headGridDataDetailList,
+        // grid: {
+        //   style: {
+        //     isMixGridHighlight:
+        //       isMixGridHighlight == undefined ? true : isMixGridHighlight
+        //   }
+        // },
+        extData: {
+          name: `璧拌埅鐑姏鍥� - ${heatTag}`,
+          type: 2
+        }
+      });
+    }
+
+    return heatTag;
+  }
+
+  search(gdd, width, height, eachwidth, eachheight, searchLength) {
+    function getCellWidthRange(cellId, width, height) {
+      const total = width * height;
+      const x = Math.ceil(cellId / total) - 1;
+      let first = 1 + x * total,
+        last = width + x * total;
+
+      let scale = 0;
+      while (scale < height) {
+        const min = first + scale * width;
+        const max = last + scale * width;
+        if (cellId >= min && cellId <= max) {
+          return [min, max];
+        }
+        scale++;
+      }
+    }
+
+    const cellId = gdd.cellId;
+    // const minData = gdd.pm25 / 2
+    const dataOffset = (gdd.pm25 - gdd.pm25 / 2) / 3;
+
+    const hOffset = eachwidth;
+    const wOffset = 1;
+
+    const cellIdMin = 1;
+    const cellIdMax = width * height;
+
+    let searchWidth = 0 - searchLength,
+      searchHeight = 0 - searchLength;
+
+    const result = [];
+
+    const eachRange = getCellWidthRange(cellId, eachwidth, eachheight);
+    const groupRange = getCellWidthRange(
+      Math.ceil(cellId / (eachwidth * eachheight)),
+      width / eachwidth,
+      height / eachheight
+    );
+
+    for (let w = searchWidth; w <= searchLength; w++) {
+      // 鍏堣繘琛屾í鍚戠殑鍧愭爣鍙樻崲
+      let _cellId = cellId + w * wOffset;
+      if (_cellId < eachRange[0] || _cellId > eachRange[1]) {
+        const cellOffset =
+          _cellId < eachRange[0]
+            ? _cellId - eachRange[0]
+            : _cellId - eachRange[1];
+
+        const groupOffset = Math[cellOffset / eachwidth > 0 ? 'ceil' : 'floor'](
+          cellOffset / eachwidth
+        );
+
+        const newEachRange = eachRange.map(
+          (r) => r + groupOffset * eachwidth * eachheight
+        );
+
+        _cellId =
+          groupOffset > 0
+            ? newEachRange[0] + cellOffset - wOffset
+            : newEachRange[1] + cellOffset + wOffset;
+
+        const _groupId = Math.ceil(_cellId / (eachwidth * eachheight));
+
+        if (_groupId < groupRange[0] || _groupId > groupRange[1]) {
+          continue;
+        }
+      }
+
+      for (let h = searchHeight; h <= searchLength; h++) {
+        if (w == 0 && h == 0) continue;
+
+        const _eachRange = getCellWidthRange(_cellId, eachwidth, eachheight);
+        // if (_eachRange == undefined) {
+        //   console.log();
+
+        // }
+        const wOffset = _cellId - _eachRange[0];
+        let _resCellId = _cellId + h * hOffset;
+        if (_resCellId < cellIdMin || _resCellId > cellIdMax) continue;
+
+        const total = eachwidth * eachheight;
+        const x = Math.ceil(_cellId / total) - 1;
+        const eachCellIdMin = 1 + x * total;
+        const eachCellIdMax = total + x * total;
+        const topCell = eachCellIdMin + wOffset;
+        const bottomCell = eachCellIdMax - eachwidth + 1 + wOffset;
+        if (_resCellId < eachCellIdMin || _resCellId > eachCellIdMax) {
+          const cellOffset =
+            _resCellId < eachCellIdMin
+              ? _resCellId - topCell
+              : _resCellId - bottomCell;
+
+          const newTopCell =
+            cellOffset > 0
+              ? topCell + width * eachheight
+              : topCell - width * eachheight;
+          const newBottomCell =
+            cellOffset > 0
+              ? bottomCell + width * eachheight
+              : bottomCell - width * eachheight;
+
+          _resCellId =
+            cellOffset > 0
+              ? newTopCell + cellOffset - hOffset
+              : newBottomCell + cellOffset + hOffset;
+        }
+        result.push({
+          groupId: gdd.groupId,
+          cellId: _resCellId,
+          pm25: gdd.pm25 - Math.max(Math.abs(w), Math.abs(h)) * dataOffset
+        });
+      }
+    }
+
+    return result;
   }
 
   _getMapViews(...tags) {
diff --git a/src/stores/grid-info.js b/src/stores/grid-info.js
new file mode 100644
index 0000000..c193329
--- /dev/null
+++ b/src/stores/grid-info.js
@@ -0,0 +1,11 @@
+import { ref } from 'vue';
+import { defineStore } from 'pinia';
+
+// 璧拌埅璁惧
+export const useGridStore = defineStore('grid', () => {
+  const selectedSatelliteProxy = undefined;
+
+  const selectedGridCellAndDataDetail = ref(undefined);
+
+  return { selectedSatelliteProxy, selectedGridCellAndDataDetail };
+});
diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue
index e4cf5d3..b31d689 100644
--- a/src/views/HomePage.vue
+++ b/src/views/HomePage.vue
@@ -10,55 +10,14 @@
       <!-- <MapLocation></MapLocation> -->
       <SceneSearch></SceneSearch>
       <MapScene></MapScene>
+      <GridSearch></GridSearch>
     </el-row>
     <CoreMenu></CoreMenu>
     <router-view></router-view>
   </div>
 </template>
 
-<script setup>
-import { map, onMapMounted } from '@/utils/map/index_old';
-
-// let districtPolygon;
-// // 缁樺埗鍖哄幙杈圭晫
-// function drawDistrict(districtName, isNew) {
-//   onMapMounted(() => {
-//     if (districtPolygon && !isNew) {
-//       map.remove(districtPolygon);
-//       map.add(districtPolygon);
-//     } else {
-//       // eslint-disable-next-line no-undef
-//       var district = new AMap.DistrictSearch({
-//         extensions: 'all', //杩斿洖琛屾斂鍖鸿竟鐣屽潗鏍囩瓑鍏蜂綋淇℃伅
-//         level: 'district' //璁剧疆鏌ヨ琛屾斂鍖虹骇鍒负鍖�
-//       });
-//       district.search(districtName, function (status, result) {
-//         var bounds = result.districtList[0].boundaries; //鑾峰彇鏈濋槼鍖虹殑杈圭晫淇℃伅
-//         if (bounds) {
-//           for (var i = 0; i < bounds.length; i++) {
-//             //鐢熸垚琛屾斂鍖哄垝 polygon
-//             // eslint-disable-next-line no-undef
-//             districtPolygon = new AMap.Polygon({
-//               map: map, //鏄剧ず璇ヨ鐩栫墿鐨勫湴鍥惧璞�
-//               strokeWeight: 1, //杞粨绾垮搴�
-//               path: bounds[i], //澶氳竟褰㈣疆寤撶嚎鐨勮妭鐐瑰潗鏍囨暟缁�
-//               fillOpacity: 0.6, //澶氳竟褰㈠~鍏呴�忔槑搴�
-//               // fillColor: '#CCF3FF', //澶氳竟褰㈠~鍏呴鑹�
-//               fillColor: '#0077ff',
-//               // strokeColor: '#ffffff' //绾挎潯棰滆壊
-//               strokeColor: 'white', //绾挎潯棰滆壊
-//               zIndex: 9
-//             });
-//           }
-//           map.setFitView(); //灏嗚鐩栫墿璋冩暣鍒板悎閫傝閲�
-//         }
-//       });
-//     }
-//   });
-// }
-
-// drawDistrict('闀垮畞鍖�');
-</script>
+<script setup></script>
 
 <style scoped>
 .overlay-container {
diff --git a/src/views/underwaymix/UnderwayMixMode.vue b/src/views/underwaymix/UnderwayMixMode.vue
index 38a403a..c0dbe9b 100644
--- a/src/views/underwaymix/UnderwayMixMode.vue
+++ b/src/views/underwaymix/UnderwayMixMode.vue
@@ -59,6 +59,13 @@
                   @change="handleHeatMapClick"
                 >
                 </CheckButton>
+                <!-- <CheckButton
+                  active-text="鎼滅储缃戞牸"
+                  inactive-text="鎼滅储缃戞牸"
+                  :default-value="false"
+                  @change="handleHeatMapSearchClick"
+                >
+                </CheckButton> -->
               </el-row>
               <!-- <div class="m-t-8">缃戞牸瑕佺礌</div>
               <el-row class="m-t-8">
@@ -147,9 +154,11 @@
 import gridApi from '@/api/gridApi';
 import { SatelliteGrid } from '@/model/SatelliteGrid';
 import GridStyleTool from './component/GridStyleTool.vue';
+import { useGridStore } from '@/stores/grid-info';
+
+const gridStore = useGridStore();
 
 const satelliteGrid = new SatelliteGrid('璧拌埅铻嶅悎');
-
 const gridCtrls = ref([satelliteGrid]);
 
 // 鍊熺敤鍗槦閬ユ祴妯″潡涓殑100绫崇綉鏍�
@@ -173,6 +182,7 @@
 const gridDataDetailMap = new Map();
 
 const mixActive = ref(false);
+const heatActive = ref(false);
 const gridVisible = ref(true);
 const underwayVisible = ref(false);
 const rankVisible = ref(false);
@@ -216,7 +226,32 @@
 }
 
 function prepareGrid(gridInfo) {
-  satelliteGrid.gridPrepare(gridInfo);
+  satelliteGrid.gridPrepare(gridInfo, (polygon) => {
+    //榧犳爣绉诲叆浜嬩欢
+    polygon.on('mouseover', () => {
+      polygon.setOptions({
+        //淇敼澶氳竟褰㈠睘鎬х殑鏂规硶
+        strokeWeight: 2,
+        strokeColor: 'red'
+      });
+    });
+    //榧犳爣绉诲嚭浜嬩欢
+    polygon.on('mouseout', () => {
+      polygon.setOptions({
+        strokeWeight: 1,
+        strokeColor: 'white'
+      });
+    });
+  });
+  // satelliteGrid.setGridEvent('click', (gridCell, gridDataDetail) => {
+  //   // const polygon = e.target
+  //   // const { gridCell } = polygon.getExtData();
+  //   // const cellIndex = gridCell.cellIndex;
+  //   gridStore.selectedGridCellAndDataDetail = {
+  //     gridCell,
+  //     gridDataDetail
+  //   };
+  // });
 }
 
 // watch(mission, (nV, oV) => {
@@ -263,6 +298,16 @@
             type: 0
           }
         });
+        satelliteGrid.setGridEvent(
+          [d.id],
+          'click',
+          (gridCell, gridDataDetail) => {
+            gridStore.selectedGridCellAndDataDetail = {
+              gridCell,
+              gridDataDetail
+            };
+          }
+        );
         gridCtrls.value = [satelliteGrid];
         // gridCtrls.value = Array.from(satelliteGrid.mapViewsMap);
         // console.log(gridCtrls.value);
@@ -271,6 +316,7 @@
   });
 }
 
+let mixTag;
 function handleMixClick() {
   mixActive.value = !mixActive.value;
   const tags = fusionDataList.value
@@ -282,7 +328,17 @@
     showRankTxt: false
   });
   if (mixActive.value) {
-    satelliteGrid.mixGrid(tags);
+    mixTag = satelliteGrid.mixGrid(tags);
+    satelliteGrid.setGridEvent(
+      [mixTag],
+      'click',
+      (gridCell, gridDataDetail) => {
+        gridStore.selectedGridCellAndDataDetail = {
+          gridCell,
+          gridDataDetail
+        };
+      }
+    );
     gridCtrls.value = [satelliteGrid];
   } else {
     satelliteGrid.changeVisibility({
@@ -292,10 +348,50 @@
   }
 }
 
+let heatTag;
 function handleHeatMapClick() {
-  const tags = fusionDataList.value
-    .filter((v, i) => selectedfusionData.value.indexOf(i) != -1)
-    .map((v) => v.id);
+  heatActive.value = !heatActive.value;
+  satelliteGrid.changeVisibility({
+    showGridViews: false,
+    showDataTxt: false,
+    showRankTxt: false
+  });
+  if (heatActive.value) {
+    heatTag = satelliteGrid.drawHeatGrid(mixTag);
+    satelliteGrid.setGridEvent(
+      [heatTag],
+      'click',
+      (gridCell, gridDataDetail) => {
+        gridStore.selectedGridCellAndDataDetail = {
+          gridCell,
+          gridDataDetail
+        };
+      }
+    );
+    gridCtrls.value = [satelliteGrid];
+  } else {
+    satelliteGrid.changeVisibility({
+      tags: [mixTag],
+      showGridViews: true
+    });
+  }
+}
+
+function handleHeatMapSearchClick() {
+  const res = satelliteGrid.search(
+    {
+      groupId: 1,
+      cellId: 2893,
+      pm25: 50
+    },
+    120,
+    90,
+    10,
+    10,
+    3
+  );
+
+  console.log(res);
 }
 
 function handleGridClick() {

--
Gitblit v1.9.3