From f1e4e5843ff9ae37ccecd0ea391911f67de0e50d Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Sat, 29 Mar 2025 16:02:53 +0800
Subject: [PATCH] feat: 机巢点击交互

---
 src/assets/images/home/mapPopUpBox/titleImg.png   |    0 
 src/assets/images/home/mapPopUpBox/itembg.png     |    0 
 src/views/Home/useAggregation.js                  |   74 ++++++++++++--
 src/views/Home/MapPopUpBox.vue                    |  166 +++++++++++++++++++++++++++++++++
 src/assets/images/home/mapPopUpBox/mapPopUpBg.png |    0 
 src/views/Home/Home.vue                           |    3 
 6 files changed, 233 insertions(+), 10 deletions(-)

diff --git a/src/assets/images/home/mapPopUpBox/itembg.png b/src/assets/images/home/mapPopUpBox/itembg.png
new file mode 100644
index 0000000..37209f4
--- /dev/null
+++ b/src/assets/images/home/mapPopUpBox/itembg.png
Binary files differ
diff --git a/src/assets/images/home/mapPopUpBox/mapPopUpBg.png b/src/assets/images/home/mapPopUpBox/mapPopUpBg.png
new file mode 100644
index 0000000..f4897af
--- /dev/null
+++ b/src/assets/images/home/mapPopUpBox/mapPopUpBg.png
Binary files differ
diff --git a/src/assets/images/home/mapPopUpBox/titleImg.png b/src/assets/images/home/mapPopUpBox/titleImg.png
new file mode 100644
index 0000000..03e6505
--- /dev/null
+++ b/src/assets/images/home/mapPopUpBox/titleImg.png
Binary files differ
diff --git a/src/views/Home/Home.vue b/src/views/Home/Home.vue
index 50174fe..6139619 100644
--- a/src/views/Home/Home.vue
+++ b/src/views/Home/Home.vue
@@ -10,6 +10,9 @@
 import HomeLeft from '@/views/Home/components/HomeLeft/HomeLeft.vue';
 import SearchBox from '@/views/Home/SearchBox.vue';
 import { useAggregation } from '@/views/Home/useAggregation';
+import MapPopUpBox from '@/views/Home/MapPopUpBox.vue';
+import { render } from 'vue';
+
 
 useAggregation()
 </script>
diff --git a/src/views/Home/MapPopUpBox.vue b/src/views/Home/MapPopUpBox.vue
new file mode 100644
index 0000000..cc4d0e9
--- /dev/null
+++ b/src/views/Home/MapPopUpBox.vue
@@ -0,0 +1,166 @@
+<script setup>
+import { Close } from '@element-plus/icons-vue';
+
+const list = [
+  { name: '执行中', value: '1', color: '#FFA768' },
+  { name: '在线', value: '20', color: '#8EFFAC' },
+  { name: '离线', value: '14', color: '#FFFFFF' },
+  { name: '异常', value: '25', color: '#FF6262' },
+];
+
+const props = defineProps(['data', 'removeLabel']);
+</script>
+
+<template>
+  <div class="mapPopUpBox">
+    <div class="header">
+      <div class="headerLeft">
+        <img class="header-image" src="@/assets/images/home/MapPopUpBox/titleImg.png" alt="" />
+        <div class="header-title">安义县机场</div>
+      </div>
+      <el-icon class="header-close" @click="props.removeLabel">
+        <Close />
+      </el-icon>
+    </div>
+    <div class="info">
+      <div class="info-item">
+        机巢数:
+        <div class="num">10</div>
+      </div>
+      <div class="info-item">
+        任务数:
+        <div class="num">32</div>
+      </div>
+    </div>
+    <div class="status-title">机巢状态</div>
+    <div class="status-list">
+      <div v-for="item in list" :key="item.name" class="status-item">
+        <div class="status-value" :style="{ color: item.color }">{{ item.value }}</div>
+        <div class="status-name">{{ item.name }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.mapPopUpBox {
+  width: 418px;
+  height: 240px;
+  background: url('@/assets/images/home/MapPopUpBox/mapPopUpBg.png') no-repeat center / 100% 100%;
+  padding-left: 98px;
+
+  .header {
+    padding: 0 12px;
+    width: 320px;
+    height: 51px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+
+    .headerLeft {
+      display: flex;
+    }
+
+    img {
+      width: 26px;
+      height: 26px;
+    }
+
+    &-title {
+      font-family: YouSheBiaoTiHei, YouSheBiaoTiHei, serif;
+      font-weight: 400;
+      font-size: 26px;
+      line-height: 30px;
+      letter-spacing: 2px;
+      text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);
+      background: linear-gradient(180deg, #ffffff 41%, #35d0ff 86%);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+      margin-left: 4px;
+    }
+
+    &-close {
+      width: 25px;
+      height: 100%;
+      line-height: 100%;
+      display: flex;
+      align-items: center;
+      color: #9cd5ff;
+      pointer-events: all;
+      cursor: pointer;
+    }
+  }
+
+  .info {
+    height: 34px;
+    font-family: Source Han Sans CN, Source Han Sans CN, serif;
+    font-weight: 400;
+    font-size: 16px;
+    color: #ffffff;
+    line-height: 19px;
+    display: flex;
+    align-items: center;
+    padding-left: 15px;
+    gap: 0 20px;
+    margin: 18px 0;
+
+    .info-item {
+      display: flex;
+      align-items: center;
+
+      .num {
+        font-family: YouSheBiaoTiHei, YouSheBiaoTiHei, serif;
+        font-weight: 400;
+        font-size: 26px;
+        color: #ffffff;
+        line-height: 30px;
+      }
+    }
+  }
+
+  .status-title {
+    font-family: YouSheBiaoTiHei, YouSheBiaoTiHei, serif;
+    font-weight: 400;
+    font-size: 20px;
+    color: #ffffff;
+    line-height: 23px;
+    text-shadow: 0px 0px 12px rgba(68, 105, 255, 0.67);
+    padding-left: 15px;
+    margin-bottom: 14px;
+  }
+
+  .status-list {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .status-item {
+      width: 66px;
+      height: 54px;
+      background: url('@/assets/images/home/MapPopUpBox/itembg.png') no-repeat center / 100% 100%;
+      text-align: center;
+
+      .status-value {
+        font-family: YouSheBiaoTiHei, YouSheBiaoTiHei, serif;
+        font-weight: 400;
+        font-size: 26px;
+        color: #ffa768;
+        line-height: 17px;
+        text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
+        position: relative;
+        top: -3px;
+      }
+
+      .status-name {
+        font-family: Source Han Sans CN, Source Han Sans CN, serif;
+        font-weight: 400;
+        font-size: 14px;
+        color: #ffffff;
+        line-height: 16px;
+        position: relative;
+        top: -3px;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/Home/useAggregation.js b/src/views/Home/useAggregation.js
index 32756bd..db6ec45 100644
--- a/src/views/Home/useAggregation.js
+++ b/src/views/Home/useAggregation.js
@@ -4,19 +4,24 @@
 import jiangxishi from '@/assets/geojson/jiangxishi.json';
 import jiangxi from '@/assets/geojson/jiangxi.json';
 import zg from '@/assets/geojson/zg.json';
+import MapPopUpBox from '@/views/Home/MapPopUpBox.vue';
+import { render } from 'vue';
 
 /**
  * 机巢聚合功能
  */
 export const useAggregation = () => {
-  let viewer = null;
   const scalingJudgment = [
     { name: '县', value: [0, 48651], gJson: null },
     { name: '市', value: [48651, 314863], gJson: jiangxishi },
     { name: '省', value: [314863, 1169651], gJson: jiangxi },
     { name: '国', value: [1169651, 37962800], gJson: zg },
   ];
+  let viewer = null;
   const active = ref('');
+  let handler = null;
+  let labelDiv = null;
+  let positionC3 = null;
   const init = () => {
     determineScaling();
     viewer.camera.moveEnd.addEventListener(() => {
@@ -24,18 +29,15 @@
     });
   };
 
-  const removeFun = () => {
-    viewer.dataSources.removeAll(true);
-    viewer.entities.removeAll();
-  };
-
+  // 确定缩放比例
   const determineScaling = () => {
     let height = viewer.camera.positionCartographic.height;
     // 根据高度展示对应的 gJson
     for (let item of scalingJudgment) {
       if (height > item.value[0] && height <= item.value[1]) {
         if (active.value !== item.name) {
-          removeFun();
+          removeEntities();
+          removeLabel();
           active.value = item.name;
           item.gJson ? aggregation(item) : splashed();
         }
@@ -83,6 +85,7 @@
       if (!feature.position) return;
       const position = Cesium.Cartesian3.fromDegrees(feature.position[0], feature.position[1]);
       viewer.entities.add({
+        id: feature.id,
         position: position,
         label: {
           // 随机整数
@@ -99,6 +102,12 @@
           image: new Cesium.ConstantProperty(data2),
           width: 24,
           height: 24,
+        },
+        properties: {
+          id: feature.id,
+          customData: {
+            name: feature.name,
+          },
         },
       });
     });
@@ -118,15 +127,60 @@
     });
   };
 
+  const getLabelDom = () => {
+    const vNode = h(MapPopUpBox, { data: '参数',removeLabel });
+    const tooltipContainer = document.createElement('div');
+    tooltipContainer.style.position = 'absolute';
+    tooltipContainer.style.transform = 'translateY(-50%)';
+    tooltipContainer.style.pointerEvents = 'none';
+    document.querySelector('.page-index').append(tooltipContainer);
+    render(vNode, tooltipContainer);
+    return tooltipContainer;
+  };
+
+  const labelBox = () => {
+    if (!labelDiv) {
+      labelDiv = getLabelDom();
+    }
+    const screenPosition = viewer.scene.cartesianToCanvasCoordinates(positionC3);
+    if (screenPosition) {
+      labelDiv.style.left = `${screenPosition.x}px`;
+      labelDiv.style.top = `${screenPosition.y}px`;
+    }
+  };
+
+  const clickFun = click => {
+    const pickedObject = viewer.scene.pick(click.position);
+    if (Cesium.defined(pickedObject) && pickedObject.id) {
+      const entity = pickedObject.id;
+      positionC3 = entity.position._value;
+      viewer.scene.postRender.addEventListener(labelBox);
+    }
+  };
+
+  const removeEntities = () => {
+    viewer.dataSources.removeAll(true);
+    viewer.entities.removeAll();
+  };
+  const removeLabel = () => {
+    viewer.scene.postRender.removeEventListener(labelBox);
+    if (labelDiv && labelDiv.parentNode) {
+      labelDiv.parentNode.removeChild(labelDiv);
+      labelDiv = null;
+    }
+  };
+
   onUnmounted(() => {
-    console.log('xiezai');
-    removeFun();
+    removeEntities();
+    removeLabel();
+    handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
   });
 
   onMounted(() => {
-    console.log('触发');
     nextTick(() => {
       viewer = window.$viewer;
+      handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
+      handler.setInputAction(clickFun, Cesium.ScreenSpaceEventType.LEFT_CLICK);
       init();
     });
   });

--
Gitblit v1.9.3