From bb1a2a686cce84a9784fcd1e0076e41c41594116 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Wed, 02 Apr 2025 11:52:15 +0800
Subject: [PATCH] feat: 机巢聚合60%

---
 src/views/Home/useUavHome/useUavHome.js                      |  157 ++++++++++++++++++++++++++-------------
 src/views/Home/components/HomeLeft/OverviewNext.vue          |   14 +-
 src/api/home/machineNest.js                                  |    4 
 src/views/Home/components/HomeLeft/InspectionRaskDetails.vue |    1 
 .prettierrc.json                                             |    2 
 src/api/home/aggregation.js                                  |   17 ++++
 src/views/Home/useUavHome/MapPopUpBox.vue                    |   17 ++--
 src/api/home/index.js                                        |    3 
 8 files changed, 141 insertions(+), 74 deletions(-)

diff --git a/.prettierrc.json b/.prettierrc.json
index 93a9551..53cd5bc 100644
--- a/.prettierrc.json
+++ b/.prettierrc.json
@@ -1,5 +1,5 @@
 {
-  "printWidth": 100,
+  "printWidth": 120,
   "tabWidth": 2,
   "semi": true,
   "singleAttributePerLine": false,
diff --git a/src/api/home/aggregation.js b/src/api/home/aggregation.js
new file mode 100644
index 0000000..eb33377
--- /dev/null
+++ b/src/api/home/aggregation.js
@@ -0,0 +1,17 @@
+import request from '@/axios';
+
+
+export const getDeviceRegionCount = () => {
+  return request({
+    url: '/drone-device-core/manage/api/v1/devices/getDeviceRegionCount',
+    method: 'get',
+  });
+};
+
+
+export const getDeviceRegion = () => {
+  return request({
+    url: '/drone-device-core/manage/api/v1/devices/getDeviceRegion',
+    method: 'get',
+  });
+};
diff --git a/src/api/home/index.js b/src/api/home/index.js
index 51cfbeb..b5af252 100644
--- a/src/api/home/index.js
+++ b/src/api/home/index.js
@@ -1,10 +1,11 @@
 import request from '@/axios';
 
 // 巡检总任务数量
-export const getTotalJobNum = () => {
+export const getTotalJobNum = (params) => {
   return request({
     url: '/drone-device-core/wayline/waylineJobInfo/totalJobNum',
     method: 'get',
+    params
   });
 };
 
diff --git a/src/api/home/machineNest.js b/src/api/home/machineNest.js
index c3045d5..41fcb4f 100644
--- a/src/api/home/machineNest.js
+++ b/src/api/home/machineNest.js
@@ -1,11 +1,11 @@
 import request from '@/axios';
 
 // 机巢统计
-export const getDeviceInfoNum = () => {
+export const getDeviceInfoNum = (params) => {
   return request({
     url: '/drone-device-core/manage/api/v1/devices/getDeviceInfoNum',
     method: 'get',
-    params: {},
+    params,
   });
 };
 // 机巢列表
diff --git a/src/views/Home/components/HomeLeft/InspectionRaskDetails.vue b/src/views/Home/components/HomeLeft/InspectionRaskDetails.vue
index eb154df..4e921be 100644
--- a/src/views/Home/components/HomeLeft/InspectionRaskDetails.vue
+++ b/src/views/Home/components/HomeLeft/InspectionRaskDetails.vue
@@ -182,7 +182,6 @@
 
       .value {
         font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
-        margin-left: 8px;
         font-size: 26px;
       }
     }
diff --git a/src/views/Home/components/HomeLeft/OverviewNext.vue b/src/views/Home/components/HomeLeft/OverviewNext.vue
index 2e9e4da..f3cd6d8 100644
--- a/src/views/Home/components/HomeLeft/OverviewNext.vue
+++ b/src/views/Home/components/HomeLeft/OverviewNext.vue
@@ -94,12 +94,12 @@
 const tableList = ref([]);
 // 机巢列表数据
 const getTableList = () => {
-  const params = { 
-    nickname: searchText.value, 
-    is_execute: false, 
-    type: 1, 
-    current: pageParams.value.current, 
-    size: pageParams.value.size 
+  const params = {
+    nickname: searchText.value,
+    is_execute: false,
+    type: 1,
+    current: pageParams.value.current,
+    size: pageParams.value.size
   };
   selectDevicePage(params).then((res) => {
     // if (res.data.code !== 0) return;
@@ -173,8 +173,8 @@
       line-height: 19px;
       .value {
         font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
-        margin-left: 8px;
         font-size: 26px;
+        text-align: center;
       }
     }
     .status {
diff --git a/src/views/Home/useUavHome/MapPopUpBox.vue b/src/views/Home/useUavHome/MapPopUpBox.vue
index 6a89de9..6af857b 100644
--- a/src/views/Home/useUavHome/MapPopUpBox.vue
+++ b/src/views/Home/useUavHome/MapPopUpBox.vue
@@ -3,7 +3,7 @@
     <div class="header">
       <div class="headerLeft">
         <img class="header-image" src="../../../assets/images/home/mapPopUpBox/titleImg.png" alt="" />
-        <div class="header-title">安义县机场</div>
+        <div class="header-title">{{props.data.region_name}}</div>
       </div>
       <el-icon class="header-close" @click="props.removeLabel">
         <Close />
@@ -12,11 +12,11 @@
     <div class="info">
       <div class="info-item">
         机巢数:
-        <div class="num">10</div>
+        <div class="num">{{props.data.device_num}}</div>
       </div>
       <div class="info-item">
         任务数:
-        <div class="num">32</div>
+        <div class="num">{{props.data.jobNum}}</div>
       </div>
     </div>
     <div class="status-title">机巢状态</div>
@@ -31,14 +31,13 @@
 <script setup>
 import { Close } from '@element-plus/icons-vue';
 
+const props = defineProps(['data', 'removeLabel']);
 const list = [
-  { name: '执行中', value: '1', color: '#FFA768' },
-  { name: '在线', value: '20', color: '#8EFFAC' },
-  { name: '离线', value: '14', color: '#FFFFFF' },
-  { name: '异常', value: '25', color: '#FF6262' },
+  { name: '空闲中', value: props.data.ex_num || 0, color: '#FFA768' },
+  { name: '作业', value:props.data.leisure_num || 0, color: '#8EFFAC' },
+  { name: '离线中', value: props.data.offline_num || 0, color: '#FFFFFF' },
 ];
 
-const props = defineProps(['data', 'removeLabel']);
 </script>
 <style scoped lang="scss">
 .mapPopUpBox {
@@ -133,7 +132,7 @@
 
   .status-list {
     display: flex;
-    justify-content: space-between;
+    justify-content: space-evenly;
     align-items: center;
 
     .status-item {
diff --git a/src/views/Home/useUavHome/useUavHome.js b/src/views/Home/useUavHome/useUavHome.js
index 296d876..53a4123 100644
--- a/src/views/Home/useUavHome/useUavHome.js
+++ b/src/views/Home/useUavHome/useUavHome.js
@@ -7,6 +7,10 @@
 import { getCenterPoint } from '@/utils/cesium/mapUtil';
 import cesiumOperation from '@/utils/cesium-tsa';
 import { HeadingPitchRange } from 'cesium';
+import { getDeviceRegion, getDeviceRegionCount } from '@/api/home/aggregation';
+import _ from 'lodash';
+import { getDeviceInfoNum } from '@/api/home/machineNest';
+import { getTotalJobNum } from '@/api/home';
 
 /**
  * 机巢聚合功能
@@ -15,14 +19,15 @@
   const { flyTo } = cesiumOperation();
 
   let scalingJudgment = [
-    { name: '县', value: [0, 48651], gJson: null, height: 31753,show:false },
-    { name: '市', value: [48651, 314863], gJson: null, height: 257731,show:false },
-    { name: '省', value: [314863, 3796280000], gJson: null, height: 1987280,show:false, },
+    { name: '县', splashedList: [], gJson: null, show: false, value: [0, 48651], height: 31753 },
+    { name: '市', splashedList: [], gJson: null, show: false, value: [48651, 314863], height: 257731 },
+    { name: '省', splashedList: [], gJson: null, show: false, value: [314863, 3796280000], height: 1987280 },
   ];
   let viewer = null;
   let active = null;
   let handler = null;
   let positionC3 = null;
+  let currentEntity = null;
   const listenerHeight = () => {
     determineScaling();
     viewer.camera.moveEnd.addEventListener(determineScaling);
@@ -30,20 +35,21 @@
 
   // 确定缩放比例
   const determineScaling = index => {
-    console.log(8989);
+    console.log('确定缩放比例');
     if (!viewer) return;
     let height = viewer.camera.positionCartographic.height;
     // 根据高度展示对应的 gJson
     for (let [index, item] of scalingJudgment.entries()) {
       if (!item.show) return;
       if (height > item.value[0] && height <= item.value[1]) {
+        if (active === item.name) return;
         active = item.name;
         removeEntities();
         removeLabel();
-        if (item.gJson && item.name !== '县'){
-          aggregation(item)
-        }else{
-          splashed()
+        if (item.gJson && item.name !== '县') {
+          aggregation(item);
+        } else {
+          splashed(item);
         }
         break;
       }
@@ -65,56 +71,76 @@
   const store = useStore();
   const selectedAreaCode = computed(() => store.state.user.selectedAreaCode);
 
+  function getDeviceCount() {
+    return getDeviceRegionCount().then(res => {
+      return res?.data?.data || [];
+    });
+  }
+
+  function getDeviceList() {
+    return getDeviceRegion().then(res => {
+      return res?.data?.data || [];
+    });
+  }
+
   watch(
     selectedAreaCode,
     async (newValue, oldValue) => {
       if (newValue) {
+        const list = await getDeviceCount();
+        const splashedList = await getDeviceList();
+        console.log(list);
+        console.log(splashedList);
         const code = newValue.slice(0, 6);
         const hierarchy = convertToHierarchy(code);
         const jsonPath = hierarchy.join('/');
-        console.log(jsonPath);
         const { VITE_APP_BASE } = import.meta.env;
+        const defaultDir = `${VITE_APP_BASE}public/geoJson/100000/`;
+        scalingJudgment = scalingJudgment.map(item => ({ ...item, show: true }));
         if (hierarchy.length === 1) {
-          scalingJudgment = scalingJudgment.map(item => ({...item,show:true}))
           scalingJudgment[0].gJson = null;
-          scalingJudgment[1].gJson = await import(
-            `${VITE_APP_BASE}public/geoJson/100000/${jsonPath}/indexDistrict.json`
-          );
-          scalingJudgment[2].gJson = await import(
-            `${VITE_APP_BASE}public/geoJson/100000/${jsonPath}/index.json`
-          );
-          const center = getCenterPoint(scalingJudgment[2].gJson.features.map(item => item.properties.center))
-          flyTo({longitude: center.lng, latitude: center.lat},0,scalingJudgment[2].height)
-          // determineScaling(2);
+          scalingJudgment[0].splashedList = splashedList;
+          const gJson1 = await import(/* @vite-ignore */ `${defaultDir}${jsonPath}/indexDistrict.json`);
+          const gJson1Copy = JSON.parse(JSON.stringify(gJson1));
+          const gJson2 = await import(/* @vite-ignore */ `${defaultDir}${jsonPath}/index.json`);
+          const gJson2Copy = JSON.parse(JSON.stringify(gJson2));
+          const findFun = (item1, item) => Number(item1.region_code.slice(0, 6)) === item.properties.adcode;
+          scalingJudgment[1].gJson = {
+            ...gJson1Copy,
+            features: gJson1Copy.features.map(item => ({
+              ...item,
+              data: list.flatMap(item => item.childrens || []).find(item1 => findFun(item1, item)),
+            })),
+          };
+          scalingJudgment[2].gJson = {
+            ...gJson2Copy,
+            features: gJson2Copy.features.map(item => ({ ...item, data: list.find(item1 => findFun(item1, item)) })),
+          };
+          const { lng, lat } = getCenterPoint(gJson2Copy.features.map(item => item.properties.center));
+          flyTo({ longitude: lng, latitude: lat }, 0, scalingJudgment[2].height);
         }
         if (hierarchy.length === 2) {
-          scalingJudgment = scalingJudgment.map(item => ({...item,show:true}))
+          const gJson1 = await import(/* @vite-ignore */ `${defaultDir}${jsonPath}/index.json`);
           scalingJudgment[0].gJson = null;
-          scalingJudgment[1].gJson = await import(
-            `${VITE_APP_BASE}public/geoJson/100000/${jsonPath}/index.json`
-          );
+          scalingJudgment[1].gJson = JSON.parse(JSON.stringify(gJson1));
           scalingJudgment[2].gJson = null;
           scalingJudgment[2].show = false;
-          const center = getCenterPoint(scalingJudgment[1].gJson.features.map(item => item.properties.center))
-          flyTo({longitude: center.lng, latitude: center.lat},0,scalingJudgment[1].height)
-          // determineScaling(1);
+          const center = getCenterPoint(scalingJudgment[1].gJson.features.map(item => item.properties.center));
+          flyTo({ longitude: center.lng, latitude: center.lat }, 0, scalingJudgment[1].height);
         }
         if (hierarchy.length === 3) {
-          const gJson = await import(
-            `${VITE_APP_BASE}public/geoJson/100000/${jsonPath.slice(0, -7)}/index.json`
-          );
+          const gJson = await import(/* @vite-ignore */ `${defaultDir}${jsonPath.slice(0, -7)}/index.json`);
           const gJson1 = gJson.features.find(
             item => item.properties.adcode === Number(hierarchy[hierarchy.length - 1])
           );
           // scalingJudgment[0].gJson = { type: "FeatureCollection", features: [gJson1] }
-          scalingJudgment[0].gJson = null
+          scalingJudgment[0].gJson = null;
           scalingJudgment[1].gJson = null;
-          scalingJudgment[1].show = null;
+          scalingJudgment[1].show = false;
           scalingJudgment[2].gJson = null;
           scalingJudgment[2].show = false;
-          const center = gJson1.properties.center
-          flyTo({longitude: center[0], latitude: center[1]},0,scalingJudgment[0].height)
-          // determineScaling(0);
+          const center = gJson1.properties.center;
+          flyTo({ longitude: center[0], latitude: center[1] }, 0, scalingJudgment[0].height);
         }
       }
     },
@@ -122,16 +148,13 @@
   );
 
   //散点机巢
-  function splashed() {
-    for (let i = 0; i < 50; i++) {
+  function splashed(row) {
+    row.splashedList.forEach(item => {
       viewer.entities.add({
-        position: Cesium.Cartesian3.fromDegrees(
-          115.89 + Math.random() * 0.2,
-          28.68 + Math.random() * 0.2
-        ),
+        position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude),
         label: {
           // 随机整数
-          text: Math.floor(Math.random() * 100) + '号机巢',
+          text: item.nickname,
           font: '14pt monospace',
           fillColor: Cesium.Color.WHITE,
           outlineColor: Cesium.Color.BLACK,
@@ -145,8 +168,13 @@
           width: 24,
           height: 24,
         },
+        properties: {
+          customData: {
+            data: item,
+          },
+        },
       });
-    }
+    });
   }
 
   // 聚合机巢
@@ -155,6 +183,8 @@
     const featuresList = item.gJson.features.map(item => ({
       name: item.properties.name,
       position: item.properties.center,
+      data: item.data,
+      id: item.region_code,
     }));
     // 遍历特征并添加实体
     featuresList.forEach(feature => {
@@ -165,7 +195,7 @@
         position: position,
         label: {
           // 随机整数
-          text: feature.name + Math.floor(Math.random() * 100),
+          text: feature.name + feature.data.total_device_count,
           font: '14pt monospace',
           fillColor: Cesium.Color.WHITE,
           outlineColor: Cesium.Color.BLACK,
@@ -182,7 +212,7 @@
         properties: {
           id: feature.id,
           customData: {
-            name: feature.name,
+            data: feature.data,
           },
         },
       });
@@ -213,8 +243,8 @@
   };
 
   // 获取弹框box
-  const getLabelDom = () => {
-    const vNode = h(MapPopUpBox, { data: '参数', removeLabel });
+  const getLabelDom = data => {
+    const vNode = h(MapPopUpBox, { data, removeLabel });
     const tooltipContainer = document.createElement('div');
     tooltipContainer.id = 'mapPopUpBox';
     tooltipContainer.style.position = 'absolute';
@@ -229,7 +259,9 @@
   const labelBox = () => {
     let dom = document.querySelector('#mapPopUpBox');
     if (!dom) {
-      dom = getLabelDom();
+      const data = { ...currentEntity.requestData, ...currentEntity.customData };
+      console.log(data);
+      dom = getLabelDom(data);
     }
     const screenPosition = viewer.scene.cartesianToCanvasCoordinates(positionC3);
     if (screenPosition) {
@@ -240,14 +272,36 @@
   };
 
   // 左键单机事件
-  const singleMachineEvent = click => {
+  const singleMachineEvent = async click => {
     const pickedObject = viewer.scene.pick(click.position);
     if (Cesium.defined(pickedObject) && pickedObject.id) {
       const entity = pickedObject.id;
+      currentEntity = entity;
       positionC3 = entity?.position?._value;
       if (!positionC3) return;
-      viewer.scene.postRender.removeEventListener(labelBox);
+      removeLabel();
+      const customData = entity.properties.customData._value.data
+      console.log(customData);
+      if (customData.device_sn){
+        // todo
+        return
+      }
+      const areaCode = customData.region_code;
+      const res = await getDeviceInfoNum({ areaCode });
+      const resJob = await getTotalJobNum({ areaCode })
+      currentEntity = {
+        ...entity,
+        requestData: {...res.data.data,jobNum:resJob.data.data},
+        customData: entity.properties.customData._value.data
+      };
       viewer.scene.postRender.addEventListener(labelBox);
+    }
+  };
+
+  const removeDom = () => {
+    const dom = document.querySelector('#mapPopUpBox');
+    if (dom && dom.parentNode) {
+      dom.parentNode.removeChild(dom);
     }
   };
 
@@ -259,10 +313,7 @@
   // 移除弹框标签
   const removeLabel = () => {
     viewer.scene.postRender.removeEventListener(labelBox);
-    const dom = document.querySelector('#mapPopUpBox');
-    if (dom && dom.parentNode) {
-      dom.parentNode.removeChild(dom);
-    }
+    removeDom();
   };
 
   // 移除所有监听事件,变量置空

--
Gitblit v1.9.3