GuLiMmo
2024-03-19 aec00ecc093be803860c8675cbe1c4c776a7cb4e
src/pages/page-web/projects/components/route-edit/index.vue
@@ -1,20 +1,34 @@
<template>
  <div class="route-edit-box">
    <div class="btn-group">
      <a-button type="text" @click="backPage">
        <template #icon>
          <ArrowLeftOutlined />
      <a-popover
        :visible="modfiyPopupShow"
        overlayClassName="popup-container"
        placement="leftBottom"
        :getPopupContainer="(triggerNode: any) => triggerNode.parentNode">
        <template #content>
          <div class="popup-text">返回将退出航线编辑器,您要保存吗?如果不保存,您更改的内容将会丢失。</div>
          <div class="btn-tool">
            <a-button size="small" class="btn-cancel" @click="modfiyPopupShow = false">取消</a-button>
            <a-button size="small" class="btn-cancel" @click="handleModfiySave(false)">不保存</a-button>
            <a-button size="small" type="primary" @click="handleModfiySave(true)">保存</a-button>
          </div>
        </template>
        返回
      </a-button>
      <setting>
        <a-button type="text" @click="backPage">
          <template #icon>
            <ArrowLeftOutlined />
          </template>
          返回
        </a-button>
      </a-popover>
      <div class="save-button" @click="saveWaylineFile">
        <SaveOutlined />
      </div>
      <setting v-model:loadCompleted="loadCompleted">
        <template #show>
          <a-button type="text" class="setting-btn">
            <div class="router-setting">
              <img
                class="wayline-icon"
                :src="getResource('wayline.png')"
                alt="icon" />
              <img class="wayline-icon" :src="getResource('wayline.png')" alt="icon" />
              <span class="text">航线设置</span>
              <CaretDownOutlined />
            </div>
@@ -23,10 +37,7 @@
      </setting>
    </div>
    <div class="wayline-info">
      <div
        class="info-box"
        v-for="(item, index) in waylineDetails"
        :key="index">
      <div class="info-box" v-for="(item, index) in waylineDetails" :key="index">
        <div class="title">{{ item.title }}</div>
        <div class="info">{{ item.value }}</div>
      </div>
@@ -37,50 +48,51 @@
        :key="index"
        :class="{ 'active-point': index == selectPointIndex }"
        @click="pointSelect(item, index)">
        <div class="graph">
          <div class="left"></div>
          <div class="right">{{ index + 1 }}</div>
        </div>
        <div class="graph-right">
          <div
            v-for="(event, index) in item.eventList"
            :key="index"
            class="s-event-icon">
            <a-tooltip placement="top">
              <template #title>
                {{ event.name }}
              </template>
              <img :src="event.icon" alt="icon" />
            </a-tooltip>
        <a-tooltip placement="top">
          <template #title>
            <span>{{ item.isUseGlobalHeight ? '跟随全局' : '不跟随全局' }}</span>
          </template>
          <div class="graph">
            <div class="left" :style="{ borderTopColor: item.isUseGlobalHeight ? '#61d396' : '#409eff' }"></div>
            <div class="right">{{ index + 1 }}</div>
          </div>
        </div>
        </a-tooltip>
        <contextMenu :menu="[{ title: '删除航点', value: { index, item } }]">
          <div class="graph-right">
            <div v-for="(event, index) in item.eventList" :key="index" class="s-event-icon">
              <a-tooltip placement="top">
                <template #title>
                  {{ event.name }}
                </template>
                <img :src="event.icon" alt="icon" />
              </a-tooltip>
            </div>
          </div>
        </contextMenu>
      </li>
    </ul>
  </div>
</template>
<script setup lang="ts">
import _, { divide } from 'lodash'
import _ from 'lodash'
import * as Cesium from 'cesium'
import setting from './components/setting.vue'
import { ref, reactive, defineEmits, defineProps, watch, onMounted } from 'vue'
import { ArrowLeftOutlined, CaretDownOutlined } from '@ant-design/icons-vue'
import useKmzTsa, { kmlStr, template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
import { ref, defineEmits, defineProps, watch, onMounted } from 'vue'
import { ArrowLeftOutlined, CaretDownOutlined, SaveOutlined } from '@ant-design/icons-vue'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
import { useMyStore } from '/@/store'
import { analyzeKmzFile, getKmlParams } from '/@/utils/cesium/kmz'
import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial'
import { getPolylineLength } from '/@/utils/cesium/mapUtils'
import useMapDraw, { kmlEntities as globalEntities, selectPointIndex as pointIdx } from '/@/utils/cesium/use-map-draw'
import contextMenu from './components/content-menu.vue'
const store = useMyStore()
const { appContext }: any = getCurrentInstance()
const global = appContext.config.globalProperties
const {
  removeAllPoint,
  getEntityById,
  addPolyline,
  addRightClick,
  removeRightClickEvent,
} = cesiumOperation()
const kmzUtils = useKmzTsa()
const { removeAllPoint, getEntityById, addPolyline, removeAllDataSource, addRightClick, removeRightClickEvent } =
  cesiumOperation()
interface waylineDetails {
  title: string
@@ -95,6 +107,7 @@
interface tragetPoint {
  position: Cesium.Cartesian3
  isUseGlobalHeight: boolean
  eventList: eventParmas[]
}
@@ -102,160 +115,31 @@
  return new URL(`/src/assets/icons/${name}`, import.meta.url).href
}
const ellipsoid = global.$viewer.scene.globe.ellipsoid
const emits = defineEmits(['backFn'])
const props = defineProps<{
  details: any
  isCreateWayline: boolean
}>()
const filePath = computed(() => store.state.waylineTool.kmzPath)
// 对应事件
const eventList = reactive<eventParmas[]>([
  {
    key: 'takePhoto',
    name: '单拍',
    icon: getResource('waylinetool/camera.png'),
  },
  {
    key: 'startRecord',
    name: '开始录像',
    icon: getResource('waylinetool/camera-on.png'),
  },
  {
    key: 'stopRecord',
    name: '结束录像',
    icon: getResource('waylinetool/camera-off.png'),
  },
  {
    key: 'time',
    name: '开始等时间隔拍照',
    icon: getResource('waylinetool/shoot1.png'),
  },
  {
    key: 'distance',
    name: '开始等距间隔拍照',
    icon: getResource('waylinetool/shoot2.png'),
  },
  {
    key: 'zoom',
    name: '变焦',
    icon: getResource('waylinetool/fd.png'),
  },
  {
    key: 'customDirName',
    name: '创建新文件夹',
    icon: getResource('waylinetool/create-file.png'),
  },
  {
    key: 'gimbalRotate',
    distinguish: 'Yaw',
    name: '云台俯仰角',
    icon: getResource('waylinetool/holderyaw.png'),
  },
  {
    key: 'gimbalYawRotate',
    name: '云台偏航角',
    distinguish: 'pitch',
    icon: getResource('waylinetool/holdertilt.png'),
  },
  {
    key: 'rotateYaw',
    name: '飞行器偏航',
    icon: getResource('waylinetool/droneyaw.png'),
  },
  {
    key: 'hover',
    name: '悬停等待',
    icon: getResource('waylinetool/xt.png'),
  },
])
const tragetPointArr = ref<tragetPoint[]>([])
let kmlDataSource:
  | { entities: { values: { _children: any }[] }; show: boolean }
  | null
  | any = null
let kmlDataSource: { entities: { values: { _children: any }[] }; show: boolean } | null | any = null
let mouseRightClickEvent: any = null
// 初始化KML,判断当中存在多少事件
const initKML = () => {
  analyzeKmzFile(filePath.value).then((kmlRes) => {
    // 所有航点
    const points = getKmlParams(kmlRes, false, {
      name: 'Placemark',
      findRegx: '([\\s\\S]*?)',
      mode: 'g',
    })
    points?.forEach((point: string, index: number) => {
      // 当前点位事件
      const pointActions = getKmlParams(point, true, {
        name: 'actionGroup',
        findRegx: '([\\s\\S]*?)',
        mode: 'g',
      })
      const eventArr: eventParmas[] = []
      if (pointActions) {
        const actions =
          getKmlParams(pointActions[0], true, {
            name: 'action',
            findRegx: '([\\s\\S]*?)',
            mode: 'g',
          }) || []
        actions?.forEach((action) => {
          eventList.forEach((event: any) => {
            if (!event.distinguish) {
              action.includes(event.key) && eventArr.push(event)
            } else {
              const pitchAngle =
                getKmlParams(action, true, {
                  name: 'gimbalPitchRotateAngle',
                  findRegx: '([\\s\\S]*?)',
                }) || []
              const yawAngle =
                getKmlParams(action, true, {
                  name: 'gimbalYawRotateAngle',
                  findRegx: '([\\s\\S]*?)',
                }) || []
              if (!!Number(pitchAngle[1]) && event.distinguish === 'pitch') {
                eventArr.push(event)
              }
              if (!!Number(yawAngle[1]) && event.distinguish === 'yaw') {
                eventArr.push(event)
              }
            }
          })
          // 判断一共有多少个拍照模式
          const actionFunc = getKmlParams(point, true, {
            name: 'actionActuatorFunc',
            findRegx: 'takePhoto',
            mode: 'g',
          })
          if (actionFunc) {
            ;(waylineDetails[3] as any).value++
          }
        })
        tragetPointArr.value[index].eventList = eventArr
      }
      // 获取当前是否存在拍照模式
      const pointShootMode = getKmlParams(point, true, {
        name: 'shootType',
        findRegx: '([\\s\\S]*?)',
        mode: 'g',
      })
      if (pointShootMode) {
        pointShootMode.forEach((type: string) => {
          eventList.forEach((item: any) => {
            type.includes(item.key) && eventArr.push(item)
          })
        })
      }
    })
  })
}
// 绘制地图上的东西
let mapDraw: any = null
// 航线详情
const waylineDetails = ref<waylineDetails[]>([])
// 样式
const kmlEntities = ref<Cesium.Entity[]>([])
const loadCompleted = ref<boolean>(false)
// 编辑时初始化
const initDrawRoute = () => {
  const options = {
    camera: global.$viewer.scene.camera,
@@ -265,200 +149,46 @@
  if (kmlDataSource) {
    global.$viewer.dataSources.remove(kmlDataSource)
  }
  global.$viewer.dataSources
    .add(Cesium.KmlDataSource.load(filePath.value, options))
    .then((res: any) => {
      kmlDataSource = res
      createMapMarker(kmlDataSource)
      initKML()
      if (!mouseRightClickEvent) {
        // 添加右键事件
        addMapPointEvent()
      }
  global.$viewer.dataSources.add(Cesium.KmlDataSource.load(filePath.value, options)).then((res: any) => {
    kmlDataSource = res
    mapDraw = useMapDraw(kmlDataSource, [], filePath.value, global)
    const {
      drawWayline,
      waylineDetails: details,
      waylinePointsEvent,
      kmlEntities: entities,
      clearWaylineData,
    } = mapDraw
    clearWaylineData()
    drawWayline()
    kmzUtils.init(filePath.value).then((kmlRes) => {
      loadCompleted.value = true
    })
}
const kmlEntity = ref<any>([])
const waylineDetails = reactive<
  {
    title: string
    value: string | number
  }[]
>([
  {
    title: '航线长度',
    value: '0',
  },
  {
    title: '预计执行时间',
    value: '0',
  },
  {
    title: '航点',
    value: 0,
  },
  {
    title: '照片',
    value: 0,
  },
])
// 样式
const kmlEntities = ref<Cesium.Entity[]>([])
const ellipsoid = global.$viewer.scene.globe.ellipsoid
const createMapMarker = async (
  dataSource:
    | {
        entities: { values: { _children: any }[] }
        show: boolean
      }
    | any,
  entitiesList: Cesium.Entity[] = [],
) => {
  dataSource.show = false
  let kmlEntityArr = [...entitiesList]
  // kmlEntity.value = dataSource.entities.values
  if (dataSource) {
    kmlEntityArr = dataSource.entities.values[0]._children
    kmlEntities.value = kmlEntityArr
  }
  const cartesianArr: any[] = []
  let btmStartPoint = null
  // 获取所有的点位
  const kmlRes = await analyzeKmzFile(filePath.value)
  // 所有航点
  const points: string[] | any = getKmlParams(kmlRes, false, {
    name: 'Placemark',
    findRegx: '([\\s\\S]*?)',
    mode: 'g',
  })
  // 获取当前航线全局速度
  const getGlobalSpeed: any = getKmlParams(kmlRes, true, {
    name: 'autoFlightSpeed',
    findRegx: '([\\s\\S]*?)',
  })
  const speed = Number(getGlobalSpeed[1])
  // 修改点位样式信息等
  for (let i = 0; i < kmlEntityArr.length; i++) {
    const entity: any = kmlEntityArr[i]
    // 将cartographic3D坐标转换为正常坐标
    const c3Position = entity.position._value
    const c2Postion = ellipsoid.cartesianToCartographic(c3Position)
    const longitude = Cesium.Math.toDegrees(c2Postion.longitude)
    const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
    // 获取当前航点中的值
    const point = points[i]
    const getPointHeight: any = getKmlParams(point, true, {
      name: 'ellipsoidHeight',
      findRegx: '([\\s\\S]*?)',
    })
    const getHaeHeight: any = getKmlParams(point, true, {
      name: 'height',
      findRegx: '([\\s\\S]*?)',
    })
    const AslHeight = Number(getPointHeight[1])
    const HeaHeight = Number(getHaeHeight[1])
    entity.position = Cesium.Cartesian3.fromDegrees(
      longitude,
      latitude,
      AslHeight,
    )
    if (i === 0) {
      btmStartPoint = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
    }
    // 创建广告牌信息
    const billboard = createBillboard(`${i + 1}`, '#61d396')
    // 修改id
    entity._id = 'tragetPoint' + i
    // 修改广告牌样式
    entity.billboard = new Cesium.BillboardGraphics({
      image: billboard,
      pixelOffset: new Cesium.Cartesian2(0, -20),
    })
    entity.label = new Cesium.LabelGraphics({
      text: `ASL:${Math.round(AslHeight)}m\nHAE:${Math.round(HeaHeight)}m`,
      font: '13px monospace',
      showBackground: true,
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      disableDepthTestDistance: Number.POSITIVE_INFINITY,
      pixelOffset: new Cesium.Cartesian2(0, -40),
    })
    // 修改点的信息
    entity.point = new Cesium.PointGraphics({
      pixelSize: 20,
      color: Cesium.Color.GHOSTWHITE,
      outlineColor: Cesium.Color.BLACK,
    })
    // 创建虚线
    addPolyline({
      id: 'dashLine' + i,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights([
          longitude,
          latitude,
          AslHeight,
          longitude,
          latitude,
          0,
        ]),
        width: 1,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.WHITE,
        }),
    waylineDetails.value = details
    tragetPointArr.value = waylinePointsEvent.value
    watch(
      () => waylinePointsEvent.value,
      (val) => {
        tragetPointArr.value = val
      },
    })
    // 获取虚线中心点
    cartesianArr.push(entity.position._value)
    tragetPointArr.value[i] = {
      position: entity.position._value,
      eventList: [],
      {
        deep: true,
      },
    )
    kmlEntities.value = entities.value
    if (!mouseRightClickEvent) {
      // 添加右键事件
      addMapPointEvent()
    }
  }
  // 创建起飞位置
  global.$viewer.entities.add({
    id: 'dronePosition',
    position: btmStartPoint,
    billboard: {
      image: getResource('dock.png'),
      width: 36,
      height: 36,
    },
  })
  // 绘制链接线
  addPolyline({
    id: 'entityLine',
    polyline: {
      positions: [btmStartPoint, ...cartesianArr],
      width: 7,
      material: new ImageTrailMaterial({
        backgroundColor: Cesium.Color.fromBytes(96, 210, 149),
        image: getResource('arrow-right.png'),
        imageW: 7,
        duration: 0,
        animation: false,
      }),
      clampToGround: false, // 关闭贴地效果,保留高度
    },
  })
  dataSource.show = true
  const lineEntity = getEntityById('entityLine')
  // 获取距离
  const polylineLength: any = getPolylineLength(lineEntity).toFixed(1) || 0
  waylineDetails[0].value = polylineLength + 'm'
  // 航点数
  waylineDetails[2].value = cartesianArr.length
  // 计算时间
  const sportTime = polylineLength / speed
  // 判断有没有超过一分钟
  const time = sportTime / 60
  waylineDetails[1].value =
    Math.trunc(time) + ' m ' + Math.round((time % 1) * 60) + ' s'
  global.$viewer.flyTo(lineEntity, {
    offset: new Cesium.HeadingPitchRange(0, -90, 300),
  })
}
// const createPointOrPolyline = () => {}
// 新建航线初始化
const initCreateRoute = () => {
  mapDraw = useMapDraw('', [], '', global)
  const xml = kmzUtils.generateXML(xmlTemplate.value)
  mapDraw.drawWayline([], xml)
}
// 创建广告牌
const createBillboard = (title: string | number, color: string) => {
@@ -492,8 +222,10 @@
    global.$viewer.entities.remove(nextPointEntity)
    kmlEntities.value.forEach((entity: Cesium.Entity | any, i: number) => {
      entity.billboard.image = createBillboard(i + 1, '#61d396')
      entity.label.show = false
    })
    selectPointIndex.value = null
    pointIdx.value = null
    return
  }
  if (prevPointEntity) {
@@ -509,12 +241,7 @@
  const nextPoint = points[index + 1]?.position
  if (prevPoint) {
    // 获取中心点
    const centerPoint = Cesium.Cartesian3.lerp(
      currentPoint,
      prevPoint,
      0.5,
      new Cesium.Cartesian3(),
    )
    const centerPoint = Cesium.Cartesian3.lerp(currentPoint, prevPoint, 0.5, new Cesium.Cartesian3())
    // 获取两个点之间的距离
    let distance = Cesium.Cartesian3.distance(currentPoint, prevPoint)
    distance = Math.round(distance)
@@ -522,12 +249,7 @@
  }
  if (nextPoint) {
    // 获取中心点
    const centerPoint = Cesium.Cartesian3.lerp(
      currentPoint,
      nextPoint,
      0.5,
      new Cesium.Cartesian3(),
    )
    const centerPoint = Cesium.Cartesian3.lerp(currentPoint, nextPoint, 0.5, new Cesium.Cartesian3())
    // 获取两个点之间的距离
    let distance = Cesium.Cartesian3.distance(currentPoint, nextPoint)
    distance = Math.round(distance)
@@ -537,11 +259,22 @@
  kmlEntities.value.forEach((entity: Cesium.Entity | any, i: number) => {
    if (i === index) {
      entity.billboard.image = createBillboard(index + 1, '#f3be4f')
      const dashLineEntity: Cesium.Entity | any = getEntityById(`dashLine${i}`)
      dashLineEntity.polyline.material = new Cesium.PolylineDashMaterialProperty({
        color: Cesium.Color.fromBytes(235, 192, 99),
      })
      entity.label.show = true
    } else {
      entity.billboard.image = createBillboard(i + 1, '#61d396')
      const dashLineEntity: Cesium.Entity | any = getEntityById(`dashLine${i}`)
      dashLineEntity.polyline.material = new Cesium.PolylineDashMaterialProperty({
        color: Cesium.Color.WHITE,
      })
      entity.label.show = false
    }
  })
  selectPointIndex.value = index
  pointIdx.value = index
}
// 添加右键事件,弹出窗口
@@ -561,16 +294,11 @@
      },
      {
        class: 'add-next-point',
        title: `在${Number(selectPointIndex.value) + 1}号航点前插入`,
        title: `在${Number(selectPointIndex.value) + 1}号航点后插入`,
      },
    ]
    const defaultEvents = [
      { class: 'finally-point', title: '在最后航点新增航点' },
    ]
    const events =
      selectPointIndex.value !== null
        ? [...defaultEvents, ...pointEvents]
        : defaultEvents
    const defaultEvents = [{ class: 'finally-point', title: '在最后航点新增航点' }]
    const events = selectPointIndex.value !== null ? [...defaultEvents, ...pointEvents] : defaultEvents
    popupDom = createPointPopupDom(events)
    global.$viewer.container.appendChild(popupDom)
    popupDom.style.transform = `translate3d(${x}px, ${y}px, 0)`
@@ -620,87 +348,90 @@
  `
  return pointPopup
}
// 给DOM添加点击事件
const addMenuEvent = (dom: HTMLElement, position: Cesium.Cartesian2) => {
  dom.addEventListener('click', (e: any) => {
    removeCesiumChildDom(popupDom)
    const className = e.target.className
    const c3Position = global.$viewer.scene.globe.pick(
      global.$viewer.camera.getPickRay(position),
      global.$viewer.scene,
    )
    const c3Position = global.$viewer.scene.globe.pick(global.$viewer.camera.getPickRay(position), global.$viewer.scene)
    const c2Postion = ellipsoid.cartesianToCartographic(c3Position)
    const longitude = Cesium.Math.toDegrees(c2Postion.longitude)
    const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
    const height = 70
    const createPointPosition = Cesium.Cartesian3.fromDegrees(
      longitude,
      latitude,
      height,
    )
    let entity: Cesium.Entity | any = null
    // 获取全局高度
    const globalHeight: string = xmlTemplate.value.Folder.globalHeight['#text']
    const height = Number(globalHeight)
    // 右键点击的位置
    const createPointPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
    const entity: Cesium.Entity = global.$viewer.entities.add({
      position: createPointPosition,
    })
    // 起飞点海拔
    const takeOffRefPointAGLHeight = xmlTemplate.value.missionConfig.takeOffRefPointAGLHeight
    const posterHeight = Number(takeOffRefPointAGLHeight['#text'])
    // 当前点位个数
    const points = xmlTemplate.value.Folder.Placemark
    // 加入到解析的JSON对象中
    const setting = {
      Point: {
        coordinates: { '#text': `${longitude},${latitude}` },
      },
      index: { '#text': points.length },
      ellipsoidHeight: { '#text': height - posterHeight },
      height: { '#text': height },
      useGlobalHeadingParam: { '#text': 1 },
      useGlobalHeight: { '#text': 1 },
      useGlobalSpeed: { '#text': 1 },
      useGlobalTurnParam: { '#text': 1 },
      useStraightLine: { '#text': 1 },
      waypointHeadingParam: {
        waypointHeadingAngle: { '#text': 0 },
        waypointHeadingMode: { '#text': 'followWayline' },
        waypointHeadingPathMode: { '#text': 'followBadArc' },
        waypointHeadingPoiIndex: { '#text': 0 },
        waypointPoiPoint: { '#text': '0.000000,0.000000,0.000000' },
      },
      waypointSpeed: { '#text': 10 },
      waypointTurnParam: {
        waypointTurnDampingDist: { '#text': 0.2 },
        waypointTurnMode: { '#text': 'toPointAndStopWithDiscontinuityCurvature' },
      },
      isRisky: { '#text': 0 },
    }
    if (className === 'finally-point') {
      entity = global.$viewer.entities.add({
        position: createPointPosition,
        label: {
          text: 'ASL:70m',
          font: '13px monospace',
          showBackground: true,
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
          pixelOffset: new Cesium.Cartesian2(0, -40),
        },
        billboard: {
          image: createBillboard(tragetPointArr.value.length + 1, '#61d396'),
          pixelOffset: new Cesium.Cartesian2(0, -20),
        },
        point: {
          pixelSize: 20,
          color: Cesium.Color.GHOSTWHITE,
          outlineColor: Cesium.Color.BLACK,
        },
      })
      const prePostion =
        tragetPointArr.value[tragetPointArr.value.length - 1].position
      const polylinePositions = [prePostion, createPointPosition]
      addPolyline({
        polyline: {
          positions: polylinePositions,
          width: 7,
          material: new ImageTrailMaterial({
            backgroundColor: Cesium.Color.fromBytes(96, 210, 149),
            image: getResource('arrow-right.png'),
            imageW: 7,
            duration: 0,
            animation: false,
          }),
          clampToGround: false, // 关闭贴地效果,保留高度
        },
      })
      addPolyline({
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArrayHeights([
            longitude,
            latitude,
            height,
            longitude,
            latitude,
            0,
          ]),
          width: 1,
          material: new Cesium.PolylineDashMaterialProperty({
            color: Cesium.Color.WHITE,
          }),
        },
      })
      globalEntities.value.push(entity)
      xmlTemplate.value.Folder.Placemark.push(setting)
      tragetPointArr.value.push({
        position: createPointPosition,
        eventList: [],
        isUseGlobalHeight: Boolean(setting.useGlobalHeight['#text']),
      })
    }
    // clearCesiumMap()
    // createMapMarker(undefined, [...kmlEntities.value, entity])
    if (className === 'add-prev-point') {
      globalEntities.value.splice(selectPointIndex.value, 0, entity)
      xmlTemplate.value.Folder.Placemark.splice(selectPointIndex.value, 0, setting)
      tragetPointArr.value.splice(selectPointIndex.value, 0, {
        position: createPointPosition,
        eventList: [],
        isUseGlobalHeight: Boolean(setting.useGlobalHeight['#text']),
      })
    }
    if (className === 'add-next-point') {
      const index = _.cloneDeep(selectPointIndex.value + 1)
      globalEntities.value.splice(index, 0, entity)
      xmlTemplate.value.Folder.Placemark.splice(index, 0, setting)
      tragetPointArr.value.splice(index, 0, {
        position: createPointPosition,
        eventList: [],
        isUseGlobalHeight: Boolean(setting.useGlobalHeight['#text']),
      })
    }
    // 更新点位序号
    xmlTemplate.value.Folder.Placemark.forEach((placemark: { index: { [x: string]: number } }, index: number) => {
      placemark.index['#text'] = index
    })
    const xmlStr = kmzUtils.generateXML(xmlTemplate.value)
    mapDraw.drawWayline(globalEntities.value, xmlStr)
  })
}
@@ -712,8 +443,25 @@
  }
}
const modfiyPopupShow = ref<boolean>(false)
const backPage = () => {
  emits('backFn')
  if (isModify.value) {
    modfiyPopupShow.value = true
  } else {
    mapDraw.clearWaylineData()
    kmlStr.value = ''
    emits('backFn')
  }
}
const handleModfiySave = (isSave: boolean) => {
  if (isSave) {
    saveWaylineFile()
    modfiyPopupShow.value = false
  } else {
    mapDraw.clearWaylineData()
    kmlStr.value = ''
    emits('backFn')
  }
}
// 清空画布
const clearCesiumMap = () => {
@@ -727,10 +475,35 @@
  }
}
// 保存文件
const saveWaylineFile = () => {
  kmzUtils.save()
  mapDraw.clearWaylineData()
  kmlStr.value = ''
  emits('backFn')
}
// 判断当前文件是否被修改
const isModify = ref<boolean>(false)
watch(
  () => kmlStr.value,
  (val) => {
    isModify.value = true
  },
  {
    deep: true,
  },
)
onMounted(() => {
  // 清空画布
  clearCesiumMap()
  initDrawRoute()
  console.log(!!filePath.value)
  if (filePath.value) {
    initDrawRoute()
  } else {
    initCreateRoute()
  }
})
onUnmounted(() => {
@@ -756,9 +529,48 @@
    align-items: center;
    justify-content: flex-start;
    :deep() {
      .popup-container {
        .ant-popover-content {
          .ant-popover-arrow,
          .ant-popover-inner {
            border-color: #282828;
            background-color: #282828;
            box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
            .popup-text {
              color: #fff;
              width: 400px;
            }
            .btn-tool {
              margin-top: 10px;
              display: flex;
              justify-content: flex-end;
              .ant-btn {
                border: 0;
              }
              .btn-cancel {
                background-color: #3c3c3c;
                margin-right: 5px;
              }
            }
          }
        }
      }
    }
    .ant-btn {
      color: #fff;
    }
    .save-button {
      font-size: 20px;
      margin: 0 10px 0 auto;
      cursor: pointer;
      &:hover {
        color: #409eff;
      }
    }
    .setting-btn {
      background-color: #3c3c3c;
      margin-right: 10px;
@@ -810,6 +622,7 @@
    padding: 0;
    height: calc(100vh - 180px);
    overflow: auto;
    li {
      cursor: pointer;
      padding: 10px 0;
@@ -835,7 +648,7 @@
      }
      .graph-right {
        width: calc(100% - 40px);
        width: 100%;
        height: 30px;
        border-bottom: 1px solid #4f4f4f;
        display: flex;
@@ -860,8 +673,10 @@
    }
  }
}
.active-point {
  background-color: #3c3c3c;
  .graph {
    .left {
      border-top-color: #f3bf4e !important;