无人机管理后台前端(已迁走)
张含笑
2025-08-05 c832bf2e80ac465e71b7a1c1f7a59d4252030989
src/views/dataCenter/components/dataCenterMap.vue
@@ -1,49 +1,60 @@
<template>
  <el-dialog modal-class="mapDialog" v-model="isShow"  width="80%">
  <el-dialog modal-class="mapDialog" v-model="isShow" width="80%">
    <div class="mapBox">
      <div id="dataCenterMap" class="ztzf-cesium"></div>
      <div v-if="isShow" id="dataCenterMap" class="ztzf-cesium"></div>
    </div>
  </el-dialog>
</template>
<script setup>
import EventBus from '@/utils/eventBus';
import PanoramaPopup from '@/components/PanoramaPopup/PanoramaPopup.vue';
import { getMapInfoAPI } from '@/api/dataCenter/dataCenter';
import { useStore } from 'vuex';
import { PublicCesium } from '@/utils/cesium/publicCesium';
import { Cartesian3 } from 'cesium';
import * as Cesium from 'cesium';
import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue';
import { render } from 'vue';
import defaultIcon from '@/assets/images/dataCenter/datamap/eventCompleted.png';
import { render, nextTick, watch, onMounted, onBeforeUnmount, shallowRef, ref, h } from 'vue';
import panoramaPoint from '@/assets/images/panorama/panorama-point.png'; //全景图标
import defaultIcon from '@/assets/images/dataCenter/datamap/eventCompleted.png'; //默认图标
import activeIcon from '@/assets/images/dataCenter/datamap/activeevent.png'; // 激活图标
import { getEventActiveImage, getEventImage } from '@/utils/stateToImageMap/event'; //点
const emit = defineEmits(['lookDetail']);
const isShow = defineModel('show');
const viewerRef = shallowRef(null);
let viewer = null;
const viewInstance = shallowRef(null);
const store = useStore();
const currentAreaPosition = ref({ height: 1987280, latitude: 27.636112, longitude: 115.732975 });
let handler = null;
// 获取弹框box
const createLabelDom = data => {
console.log('data',data);
   const vNode = h(EventPopUpBox, { data, removeLabel })
      const tooltipContainer = document.createElement('div')
      tooltipContainer.id = 'mapPopUpBox'
      tooltipContainer.style.position = 'absolute'
      tooltipContainer.style.transform = 'translate(-50%,-135%)'
      tooltipContainer.style.pointerEvents = 'none'
      document.querySelector('#dataCenterMap').append(tooltipContainer)
      render(vNode, tooltipContainer)
      return tooltipContainer
};
const props = defineProps(['jobId', 'dotData']);
let currentClickEntity = null;
// 存储地图实体引用
const dataPointEntities = ref([]);
const isMapInitialized = ref(false); //地图加载
const dataPointList = ref([]);
const activeEntity = ref(null); // 当前激活的点
// 获取弹框box
const detailId = ref('');
const createLabelDom = data => {
  detailId.value = data;
  const vNode = h(EventPopUpBox, { data, removeLabel, detailClick });
  const tooltipContainer = document.createElement('div');
  tooltipContainer.id = 'mapPopUpBox';
  tooltipContainer.style.position = 'absolute';
  tooltipContainer.style.transform = 'translate(-50%,-125%)';
  tooltipContainer.style.pointerEvents = 'none';
  document.querySelector('#dataCenterMap')?.append(tooltipContainer);
  render(vNode, tooltipContainer);
  return tooltipContainer;
};
// 弹框位置刷新
const labelBoxUpdate = () => {
  if (!currentClickEntity) return;
  const mapPopUpBox = document.querySelector('#mapPopUpBox');
  let dom = mapPopUpBox
    ? mapPopUpBox
    : createLabelDom(currentClickEntity.properties.customData._value.data);
    : createLabelDom(currentClickEntity.properties?.customData._value.data || currentClickEntity);
  const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(
    currentClickEntity?.position?._value
  );
@@ -53,24 +64,58 @@
    dom.style.display = 'block';
  }
};
const removeDom = () => {
  const dom = document.querySelector('#mapPopUpBox');
  if (dom && dom.parentNode) {
    dom.parentNode.removeChild(dom);
  }
};
// 移除弹框标签
const removeLabel = () => {
  viewer?.scene.postRender.removeEventListener(labelBoxUpdate);
  removeDom();
};
// 点击去到详情页面
const detailClick = () => {
  removeLabel();
  // 给父组件传值
  // emit('update:show', false);  //关闭地图弹框
  emit('lookDetail', detailId.value);
};
// 恢复所有点的默认图标
const restoreAllIcons = () => {
  dataPointEntities.value.forEach(entity => {
    if (entity.billboard) {
      const status = entity?.properties?._customData?._value?.data.status;
      entity.billboard.image =
        status === 1 || status === null ? defaultIcon : getEventImage(status);
    }
  });
  activeEntity.value = null;
};
// 左键单机事件
const singleMachineEvent = async click => {
  let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id);
  if (!clickedEntities.length) return;
  let clickedEntities = click
    ? viewer?.scene.drillPick(click.position).map(item => item.id)
    : [currentClickEntity];
  if (!clickedEntities.length) {
    // 点击空白处恢复所有图标并移除弹窗
    restoreAllIcons();
    removeLabel();
    return;
  }
  currentClickEntity = clickedEntities[0];
  // 恢复所有点的默认图标
  restoreAllIcons();
  if (currentClickEntity.billboard) {
    const status = currentClickEntity?.properties?._customData?._value?.data.status;
    currentClickEntity.billboard.image =
      status === 1 || status === null ? activeIcon : getEventActiveImage(status);
    currentClickEntity.billboard.scale = 1; // 可选缩放效果
    activeEntity.value = currentClickEntity;
  }
  removeLabel();
  viewer.scene.postRender.addEventListener(labelBoxUpdate);
};
@@ -81,39 +126,31 @@
  handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas);
  handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};
// 清除所有数据点实体
const clearDataPoints = () => {
  if (!viewer) return;
  dataPointEntities.value.forEach(entity => {
    viewer.entities.remove(entity);
  });
  dataPointEntities.value = [];
  activeEntity.value = null;
};
const removeHandler = () => {
  handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
  handler?.destroy();
  handler = null;
};
const dataPointList = [
  {
    longitude: '115.85708286111111',
    latitude: '28.62837602777778',
  },
  {
    longitude: '115.8566981111111',
    latitude: '28.624613027777777',
  },
  {
    longitude: '115.85474438888889',
    latitude: '28.624930444444445',
  },
  {
    longitude: '115.85518375',
    latitude: '28.62479547222222',
  },
];
function renderDataPoint() {
  dataPointList.forEach((item, index) => {
    const sizeObj = { width: 30, height: 30 };
    viewer.entities.add({
      id: `renderDataPoint-${index}`,
      position: Cesium.Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude)),
const renderDataPoint = mapList => {
  if (!viewer || !mapList?.length) return;
  clearDataPoints();
  mapList.forEach((item, index) => {
    const entity = viewer?.entities.add({
      id: `dataCenter-point-${index}-${Date.now()}`,
      position: Cesium.Cartesian3.fromDegrees(
        Number(item.metadata.shootPosition.lng),
        Number(item.metadata.shootPosition.lat)
      ),
      label: {
        font: '12pt Source Han Sans CN',
        fillColor: Cesium.Color.WHITE,
@@ -121,11 +158,14 @@
        outlineWidth: 2,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, -9),
        eyeOffset: new Cesium.Cartesian3(0, 0, -9),
        pixelOffset: new Cesium.Cartesian2(0, 55),
      },
      billboard: {
        image: defaultIcon,
        ...sizeObj,
        image: item.status == null || item.status === 1 ? defaultIcon : getEventImage(item.status), // 初始为默认图标
        width: 40,
        height: 40,
        pixelOffset: new Cesium.Cartesian2(0, -15),
      },
      properties: {
        customData: {
@@ -133,67 +173,139 @@
        },
      },
    });
  });
}
    // 点击定位点位触发
    if (props.dotData.id === item.id) {
      currentClickEntity = entity;
      activeEntity.value = entity;
      singleMachineEvent();
    }
const initMap = () => {
  const publicCesiumInstance = new PublicCesium({
    dom: 'dataCenterMap',
    flatMode: false,
    terrain: false,
    mapFilter: true,
    dataPointEntities.value.push(entity);
  });
  viewerRef.value = publicCesiumInstance.getViewer();
  viewer = publicCesiumInstance.getViewer();
  const { longitude, latitude, height } = currentAreaPosition.value;
  const position = Cartesian3.fromDegrees(longitude, latitude, height);
  viewerRef.value.camera.flyTo({
    duration: 0,
    destination: position,
};
const initMap = () => {
  if (viewer || isMapInitialized.value) return;
  const container = document.getElementById('dataCenterMap');
  if (!container) {
    console.error('地图容器未找到');
    return;
  }
  try {
    const publicCesiumInstance = new PublicCesium({
      dom: 'dataCenterMap',
      flatMode: false,
      terrain: false,
      mapFilter: true,
    });
    viewer = publicCesiumInstance.getViewer();
    viewerRef.value = viewer;
    isViewerReady.value = true;
    // 初始化事件处理器
    handlerInit();
    isMapInitialized.value = true;
    if (dataPointList.value.length > 0) {
      renderDataPoint(dataPointList.value);
    }
  } catch (error) {
    console.error('地图初始化失败:', error);
  }
};
const flyToEntity = position => {
  const longitude = Number(position.lng);
  const latitude = Number(position.lat);
  viewer?.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 1000),
    duration: 1,
    orientation: {
      heading: Cesium.Math.toRadians(0.0),
      pitch: Cesium.Math.toRadians(-90.0),
      roll: 0.0,
    },
  });
  viewInstance.value = publicCesiumInstance;
};
// 地图接口
const loading = ref(false);
const getMapInfoAPIFun = async ids => {
  try {
    const res = await getMapInfoAPI(ids);
    dataPointList.value = res.data.data || [];
    if (isMapInitialized.value && viewer) {
      renderDataPoint(dataPointList.value);
    }
  } catch (error) {
    console.error('获取地图数据失败:', error);
  }
};
const isViewerReady = ref(false);
const initEntityOrPopup = data => {
  //地图点在范围内
  watch(
    () => isMapInitialized.value,
    ready => {
      if (ready) {
        flyToEntity(data.metadata.shootPosition);
        labelBoxUpdate();
      }
    },
    { deep: true, immediate: true } // 初始化时立即执行
  );
};
watch(
  () => props.jobId,
  newVal => {
    if (newVal) {
      getMapInfoAPIFun(newVal);
    }
  },
  { immediate: true }
);
// 监听对话框状态
watch(isShow, (newVal) => {
watch(isShow, newVal => {
  if (newVal) {
    nextTick(() => {
      initMap();
      handlerInit();
      renderDataPoint();
    });
  } else {
    // 对话框关闭时清理资源
    viewInstance.value?.viewerDestroy();
    // 清理资源
    if (viewer) {
      viewer.destroy();
      viewer = null;
    }
    isMapInitialized.value = false;
    removeHandler();
    clearDataPoints();
  }
});
onMounted(() => {
  nextTick(() => {
    initMap();
    handlerInit();
    renderDataPoint();
  });
onMounted(() => {});
onBeforeUnmount(() => {
  if (viewer) {
    viewer.destroy();
  }
  removeHandler();
  clearDataPoints();
});
onBeforeUnmount(() => {
  viewInstance.value?.viewerDestroy();
  removeHandler();
// 暴露方法给父组件
defineExpose({
  initEntityOrPopup,
});
</script>
<style >
<style>
.mapDialog .el-dialog__body {
  height: 700px !important;
  padding: 0 !important;
}
</style>
<style scoped lang="scss">
<style scoped lang="scss">
.mapBox {
  z-index: 2;
  height: 650px;