From 52a426373c619415f876952b0de04af82564dd96 Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Wed, 06 Mar 2024 18:04:02 +0800
Subject: [PATCH] update:航线全局设置编辑、新增航点、事件编辑等

---
 src/utils/cesium/use-map-draw.ts                                         |  108 +++++---
 .prettierrc                                                              |   21 +
 src/pages/page-web/projects/components/route-edit/types/index.ts         |   28 ++
 src/pages/page-web/projects/components/route-edit/index.vue              |   11 
 src/utils/cesium/use-kmz-tsa.ts                                          |   57 +++
 src/utils/cesium/types/kml.ts                                            |  129 +++++++++
 src/pages/page-web/projects/components/route-edit/components/enums.ts    |    8 
 src/utils/cesium/kmz.ts                                                  |   46 ++-
 src/pages/page-web/projects/components/route-edit/components/setting.vue |  344 ++++++++++++++++++++++----
 9 files changed, 624 insertions(+), 128 deletions(-)

diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..b599f26
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,21 @@
+{
+    "arrowParens": "always",
+    "bracketSameLine": true,
+    "bracketSpacing": true,
+    "semi": false,
+    "experimentalTernaries": false,
+    "singleQuote": true,
+    "jsxSingleQuote": false,
+    "quoteProps": "as-needed",
+    "trailingComma": "all",
+    "singleAttributePerLine": false,
+    "htmlWhitespaceSensitivity": "css",
+    "vueIndentScriptAndStyle": false,
+    "proseWrap": "preserve",
+    "insertPragma": false,
+    "printWidth": 120,
+    "requirePragma": false,
+    "tabWidth": 2,
+    "useTabs": false,
+    "embeddedLanguageFormatting": "auto"
+}
\ No newline at end of file
diff --git a/src/pages/page-web/projects/components/route-edit/components/enums.ts b/src/pages/page-web/projects/components/route-edit/components/enums.ts
index 5642c7d..7d91e0b 100644
--- a/src/pages/page-web/projects/components/route-edit/components/enums.ts
+++ b/src/pages/page-web/projects/components/route-edit/components/enums.ts
@@ -5,4 +5,12 @@
                   安全起飞高度:是相对起飞点的高度值。\n
                   飞行器起飞后,会先上升至"安全起飞高度",再飞向航线起始点
                   `,
+  EGM96 = '绝对高度:航点高度值相对于海拔面/椭球面高度保持不变。',
+  relativeToStartPoint = '相对起飞点高度(ALT):航点高度值相对起飞点的高度保持不变。'
+}
+
+export enum heightModeEnums {
+  'WGS84',
+  'relativeToStartPoint',
+  'realTimeFollowSurface',
 }
diff --git a/src/pages/page-web/projects/components/route-edit/components/setting.vue b/src/pages/page-web/projects/components/route-edit/components/setting.vue
index d815c63..4f75774 100644
--- a/src/pages/page-web/projects/components/route-edit/components/setting.vue
+++ b/src/pages/page-web/projects/components/route-edit/components/setting.vue
@@ -1,21 +1,27 @@
 <template>
   <div class="setting">
-    <a-popover
-      placement="bottom"
-      trigger="click"
-      :getPopupContainer="(triggerNode: any) => triggerNode.parentNode">
+    <a-popover placement="bottom" trigger="click" :getPopupContainer="(triggerNode: any) => triggerNode.parentNode">
       <template #content>
         <div class="setting-content">
           <div class="start-point common">
             <div class="title">起飞点</div>
+            <div class="value">{{ missionConfigSetting.takeOffRefPoint ? '已设置' : '未设置' }}</div>
           </div>
           <div class="photo-setting common">
             <div class="title">拍照设置</div>
             <ul class="select-box">
-              <li class="select-item">广角照片</li>
-              <li class="select-item">变焦照片</li>
+              <li
+                class="select-item"
+                :style="{
+                  '--settingColor': folderSetting.payloadParam.imageFormat.includes(item.value) ? '#409eff' : '#3c3c3c',
+                }"
+                v-for="item in photoSetting"
+                :key="item.value"
+                @click="selectPhotoSetting(item.value)">
+                {{ item.title }}照片
+              </li>
             </ul>
-            <div class="auto-low-light">
+            <!-- <div class="auto-low-light">
               <div class="title">自动低光</div>
               <a-tooltip
                 placement="right"
@@ -25,17 +31,13 @@
                   checkedValue="lowLightSmartShooting"
                   unCheckedValue="normalPhoto" />
               </a-tooltip>
-            </div>
+            </div> -->
           </div>
           <!-- 爬升 -->
           <div class="climb-mode common">
-            <a-tooltip
-              placement="right"
-              :title="tipDescriptionEnums.climbModeTip">
+            <a-tooltip placement="right" :title="tipDescriptionEnums.climbModeTip">
               <div class="mode-box">
-                <a-radio-group
-                  v-model:value="setting.flyToWaylineMode"
-                  button-style="solid">
+                <a-radio-group v-model:value="missionConfigSetting.flyToWaylineMode" button-style="solid">
                   <a-radio-button value="safely">垂直爬升</a-radio-button>
                   <a-radio-button value="pointToPoint">倾斜爬升</a-radio-button>
                 </a-radio-group>
@@ -45,59 +47,67 @@
                   <img :src="climbImage" alt="climb-img" />
                 </div>
                 <ul class="parameter-btn">
-                  <li>+100</li>
-                  <li>+10</li>
+                  <li @click="numberControls(true, 100, 'takeOffSecurityHeight')">+100</li>
+                  <li @click="numberControls(true, 10, 'takeOffSecurityHeight')">+10</li>
                   <li>
-                    <span>{{ setting.takeOffSecurityHeight }}</span
+                    <span>{{ missionConfigSetting.takeOffSecurityHeight }}</span
                     >m
                   </li>
-                  <li>-100</li>
-                  <li>-10</li>
+                  <li @click="numberControls(false, 100, 'takeOffSecurityHeight')">-100</li>
+                  <li @click="numberControls(false, 10, 'takeOffSecurityHeight')">-10</li>
                 </ul>
               </div>
             </a-tooltip>
           </div>
           <!-- 高度模式 -->
           <div class="height-mode common">
-            <div class="title">航线高度模式</div>
-            <div class="mode-box">
-              <a-radio-group
-                v-model:value="setting.executeHeightMode"
-                button-style="solid">
-                <a-radio-button value="WGS84">绝对高度</a-radio-button>
-                <a-radio-button value="relativeToStartPoint"
-                  >相对起飞高度</a-radio-button
-                >
-                <a-radio-button value="realTimeFollowSurface"
-                  >相对地面高度</a-radio-button
-                >
-              </a-radio-group>
-            </div>
-            <div class="parameter-tool">
-              <div class="example-img">
-                <img :src="imgs[0]" alt="height-img" />
+            <a-tooltip
+              placement="right"
+              :title="tipDescriptionEnums[folderSetting.waylineCoordinateSysParam.heightMode]">
+              <div class="title">航线高度模式</div>
+              <div class="mode-box">
+                <a-radio-group v-model:value="folderSetting.waylineCoordinateSysParam.heightMode" button-style="solid">
+                  <a-radio-button v-for="item in heightModeSetting" :key="item.value" :value="item.value">{{
+                    item.title
+                  }}</a-radio-button>
+                </a-radio-group>
               </div>
-              <div class="parameter-btn">
-                <li>+100</li>
-                <li>+10</li>
-                <li>
-                  <span>{{ setting.executeHeight }}</span> m
-                </li>
-                <li>-100</li>
-                <li>-10</li>
+              <div class="parameter-tool">
+                <div class="example-img">
+                  <img
+                    :src="
+                      folderSetting.waylineCoordinateSysParam.heightMode === heightModeSetting[0].value
+                        ? heightModeSetting[0].img
+                        : heightModeSetting[1].img
+                    "
+                    alt="height-img" />
+                </div>
+                <div class="parameter-btn">
+                  <li @click="numberControls(true, 100, 'globalHeight')">+100</li>
+                  <li @click="numberControls(true, 10, 'globalHeight')">+10</li>
+                  <li>
+                    <span>{{ Number(folderSetting.globalHeight) }}</span> m
+                  </li>
+                  <li @click="numberControls(false, 100, 'globalHeight')">-100</li>
+                  <li @click="numberControls(false, 10, 'globalHeight')">-10</li>
+                </div>
               </div>
-            </div>
+            </a-tooltip>
           </div>
           <!-- 航线速度 -->
           <div class="speed-setting common">
             <div class="title">全局航线速度</div>
             <div class="speed-box">
-              <div class="subtract">-</div>
+              <div class="subtract" @click="numberControls(false, 1, 'autoFlightSpeed')">-</div>
               <div class="text">
-                <a-input-number :min="1" :max="15" class="value" v-model:value="setting.autoFlightSpeed">30</a-input-number>
+                <a-input-number
+                  :min="1"
+                  :max="15"
+                  class="value"
+                  v-model:value="folderSetting.autoFlightSpeed"></a-input-number>
                 m / s
               </div>
-              <div class="add">+</div>
+              <div class="add" @click="numberControls(true, 1, 'autoFlightSpeed')">+</div>
             </div>
           </div>
         </div>
@@ -108,8 +118,24 @@
 </template>
 
 <script setup lang="ts">
-import { min } from 'lodash'
+import { reactive, defineProps } from 'vue'
 import { tipDescriptionEnums } from './enums'
+import useKmzTsa, { kmlStr } from '/@/utils/cesium/use-kmz-tsa'
+import useMapDraw from '/@/utils/cesium/use-map-draw'
+import { getKmlParams } from '/@/utils/cesium/kmz'
+import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
+import type { missionConfig, payloadParam as payloadParamConfig, Folder } from '/@/utils/cesium/types/kml'
+const { appContext }: any = getCurrentInstance()
+const global = appContext.config.globalProperties
+
+const mapDraw = useMapDraw('', '', '', global)
+const { removeAllDataSource, removeAllPoint } = cesiumOperation()
+
+const kmzUtils = useKmzTsa()
+
+const props = defineProps({
+  loadCompleted: Boolean,
+})
 
 const getResource = (name: string) => {
   return new URL(`/src/assets/icons/${name}`, import.meta.url).href
@@ -119,17 +145,178 @@
 }
 
 const climbImage = getSvgResource('climb.svg')
-const imgs = [getSvgResource('xddm.svg')]
+const imgs = []
 
-const setting = reactive({
+const missionConfigSetting = reactive<missionConfig | any>({
   flyToWaylineMode: 'safely',
-  takeOffSecurityHeight: 80,
-  executeHeightMode: 'WGS84',
-  executeHeight: 80,
-  // normal: normalPhoto row-light: lowLightSmartShooting
-  orientedPhotoMode: 'normalPhoto',
-  autoFlightSpeed: 10
+  // 航线结束动作
+  finishAction: 'goHome',
+  // 失控是否继续执行航线
+  exitOnRCLost: 'goContinue',
+  // 失控动作
+  executeRCLostAction: 'goBack',
+  // 安全起飞高度
+  takeOffSecurityHeight: 20,
+  // 全局航线速度
+  globalTransitionalSpeed: 10,
+  // 参考起飞点
+  takeOffRefPoint: '',
+  // 参考起飞点海拔高度
+  takeOffRefPointAGLHeight: 0,
+  // 全局返航高度
+  globalRTHHeight: 100,
+  droneInfo: {
+    droneEnumValue: 67,
+    droneSubEnumValue: 0,
+  },
+  payloadInfo: {
+    payloadEnumValue: 52,
+    payloadSubEnumValue: 1,
+    payloadPositionIndex: 0,
+  },
 })
+
+// 拍照设置
+const photoSetting = reactive([
+  { title: '广角', value: 'wide' },
+  { title: '变焦', value: 'zoom' },
+  { title: '红外', value: 'ir' },
+])
+
+// 高度模式
+const heightModeSetting = reactive([
+  {
+    title: '绝对高度',
+    value: 'EGM96',
+    img: getSvgResource('jdgd.svg'),
+  },
+  {
+    title: '相对起飞高度',
+    value: 'relativeToStartPoint',
+    img: getSvgResource('xdqfd.svg'),
+  },
+])
+
+// folder设置
+const folderSetting = reactive<Folder | any>({
+  templateType: 'waypoint',
+  templateId: 0,
+  waylineCoordinateSysParam: {
+    coordinateMode: 'WGS84',
+    heightMode: 'EGM96',
+  },
+  autoFlightSpeed: 10,
+  globalHeight: 100,
+  payloadParam: {
+    payloadPositionIndex: 0,
+    imageFormat: '',
+  },
+  caliFlightEnable: 0,
+  gimbalPitchMode: 'manual',
+})
+
+// 计算
+const numberControls = (isAdd: boolean, computeVal: number, key: string) => {
+  if (isAdd) {
+    if (missionConfigSetting[key]) {
+      missionConfigSetting[key] += computeVal
+    } else {
+      folderSetting[key] += computeVal
+    }
+  } else {
+    if (missionConfigSetting[key]) {
+      missionConfigSetting[key] -= computeVal
+    } else {
+      folderSetting[key] -= computeVal
+    }
+  }
+
+  if (key === 'globalHeight') {
+    const entities = mapDraw.kmlEntities.value
+    removeAllDataSource()
+    removeAllPoint()
+    mapDraw.drawWayline(entities, kmlStr.value)
+  }
+}
+
+// 获取机场默认值
+watch(
+  () => props.loadCompleted,
+  (val) => {
+    if (val) {
+      getDefaultValue(missionConfigSetting)
+      getDefaultValue(folderSetting)
+    }
+  },
+)
+const getDefaultValue = (setting: any) => {
+  Object.keys(setting).forEach((key: string) => {
+    const param: RegExpMatchArray | any = getKmlParams(kmlStr.value, true, {
+      name: key,
+      findRegx: '([\\s\\S]*?)',
+    })
+    if (Object.prototype.toString.call(setting[key]) === '[object Object]') {
+      const value: RegExpMatchArray | any = getKmlParams(param[0], true, {
+        name: key,
+        findRegx: '([\\s\\S]*?)',
+      })
+      Object.keys(setting[key]).forEach((v) => {
+        const keyValue: RegExpMatchArray | any = getKmlParams(value[1], true, {
+          name: v,
+          findRegx: '([\\s\\S]*?)',
+        })
+        if (!Number(keyValue[1])) {
+          setting[key][v] = keyValue[1]
+        } else {
+          setting[key][v] = Number(keyValue[1])
+        }
+      })
+    } else {
+      if (!Number(param[1])) {
+        setting[key] = param[1]
+      } else {
+        setting[key] = Number(param[1])
+      }
+    }
+  })
+  return setting
+}
+
+// 全局设置写入kmz文件
+watch(
+  () => missionConfigSetting,
+  (settingVal) => {
+    if (!props.loadCompleted) return
+    kmzUtils.edit(settingVal, 'missionConfig', true)
+  },
+  {
+    deep: true,
+  },
+)
+
+// folder设置写入kmz文件
+watch(
+  () => folderSetting,
+  (newVal) => {
+    if (!props.loadCompleted) return
+    kmzUtils.edit(newVal, 'Folder', true)
+  },
+  {
+    deep: true,
+  },
+)
+
+// 拍照设置
+const selectPhotoSetting = (value: string) => {
+  const arr: string[] = folderSetting.payloadParam.imageFormat.split(',')
+  const index: number = arr.findIndex((item) => item === value)
+  if (index !== -1) {
+    arr.splice(index, 1)
+  } else {
+    arr.push(value)
+  }
+  folderSetting.payloadParam.imageFormat = arr.join(',')
+}
 </script>
 
 <style lang="scss" scoped>
@@ -139,51 +326,71 @@
     max-height: 80vh;
     overflow-y: auto;
     color: #fff;
+
     .common {
       background-color: #232323;
       border-radius: 10px;
       padding: 15px;
       margin-bottom: 16px;
+
       .title {
         font-weight: bold;
       }
+
       &:last-child {
         margin: 0;
       }
     }
+
+    .start-point {
+      display: flex;
+      justify-content: flex-start;
+      .value {
+        margin-left: auto;
+        color: #409eff;
+      }
+    }
+
     .photo-setting {
       .select-box {
         padding: 0;
         display: flex;
         margin-top: 10px;
+
         li {
           list-style-type: none;
           padding: 3px 15px;
           margin-left: 10px;
-          background-color: #409eff;
+          background-color: var(--settingColor);
           border-radius: 9999px;
           font-weight: bold;
           cursor: pointer;
+
           &:first-child {
             margin: 0;
           }
         }
       }
+
       .auto-low-light {
         display: flex;
+
         .title {
           font-weight: bold;
           margin-right: auto;
         }
       }
     }
+
     .height-mode,
     .climb-mode {
       .mode-box {
         margin-top: 10px;
+
         :deep() {
           .ant-radio-group {
             display: flex;
+
             .ant-radio-button-wrapper {
               flex: 1;
               text-align: center;
@@ -192,9 +399,11 @@
               color: #fff;
               font-weight: bold;
               border: 0;
+
               &::before {
                 background-color: #101010;
               }
+
               &-checked {
                 background-color: #409eff !important;
               }
@@ -202,19 +411,23 @@
           }
         }
       }
+
       .parameter-tool {
         margin-top: 15px;
         display: flex;
+
         .example-img {
           flex: 3;
           flex-shrink: 0;
           display: flex;
           justify-content: center;
           align-items: center;
+
           img {
             width: 100%;
           }
         }
+
         .parameter-btn {
           flex: 1;
           padding: 0;
@@ -223,6 +436,7 @@
           display: flex;
           flex-direction: column;
           align-items: center;
+
           li {
             width: 50px;
             border-radius: 3px;
@@ -234,10 +448,12 @@
             text-align: center;
             font-weight: bold;
             transition: all 0.3s ease-in-out;
+
             &:nth-child(3) {
               width: 100%;
               background-color: transparent;
               cursor: auto;
+
               span {
                 color: #409eff;
                 font-size: 23px;
@@ -245,6 +461,7 @@
                 margin-right: 5px;
               }
             }
+
             &:not(:nth-child(3)) {
               &:hover {
                 background-color: #5d5f61;
@@ -254,24 +471,29 @@
         }
       }
     }
+
     .speed-setting {
       .speed-box {
         margin-top: 10px;
         display: flex;
         justify-content: space-between;
         align-items: center;
+
         .text {
           font-weight: bolder;
+
           .value {
             color: #409eff;
             width: 60px;
             font-size: 30px;
             background-color: transparent;
             border: 0;
+
             :deep() {
               .ant-input-number-handler-wrap {
                 display: none;
               }
+
               .ant-input-number-input-wrap {
                 input {
                   font-weight: bolder;
@@ -280,6 +502,7 @@
             }
           }
         }
+
         .subtract,
         .add {
           width: 32px;
@@ -291,6 +514,7 @@
           background-color: #3c3c3c;
           border-radius: 3px;
           cursor: pointer;
+
           &:hover {
             background-color: #5d5f61;
           }
@@ -306,12 +530,15 @@
     .ant-popover-inner {
       background-color: #101010;
     }
+
     .ant-popover-arrow {
       border-top-color: #101010 !important;
       border-left-color: #101010 !important;
     }
+
     .ant-popover-inner {
       border-radius: 15px;
+
       .ant-popover-inner-content {
         padding: 16px;
       }
@@ -319,3 +546,4 @@
   }
 }
 </style>
+../../../../../../utils/cesium/types/kml
diff --git a/src/pages/page-web/projects/components/route-edit/index.vue b/src/pages/page-web/projects/components/route-edit/index.vue
index 4a2ec48..c568d50 100644
--- a/src/pages/page-web/projects/components/route-edit/index.vue
+++ b/src/pages/page-web/projects/components/route-edit/index.vue
@@ -10,7 +10,7 @@
       <div class="save-button">
         <SaveOutlined />
       </div>
-      <setting>
+      <setting v-model:loadCompleted="loadCompleted">
         <template #show>
           <a-button type="text" class="setting-btn">
             <div class="router-setting">
@@ -66,6 +66,7 @@
 import _ from 'lodash'
 import * as Cesium from 'cesium'
 import setting from './components/setting.vue'
+import useKmzTsa from '/@/utils/cesium/use-kmz-tsa'
 import { ref, reactive, defineEmits, defineProps, watch, onMounted } from 'vue'
 import { ArrowLeftOutlined, CaretDownOutlined, SaveOutlined } from '@ant-design/icons-vue'
 import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
@@ -129,6 +130,8 @@
 // 样式
 const kmlEntities = ref<Cesium.Entity[]>([])
 
+const loadCompleted = ref<boolean>(false)
+
 const initDrawRoute = () => {
   const options = {
     camera: global.$viewer.scene.camera,
@@ -148,12 +151,16 @@
         waylineDetails: details,
         waylinePointsEvent,
         kmlEntities: entities,
+        clearWaylineData
       } = mapDraw
+      clearWaylineData()
       drawWayline()
+      useKmzTsa().init(filePath.value).then(kmlRes => {
+        loadCompleted.value = true
+      })
       waylineDetails.value = details
       tragetPointArr.value = waylinePointsEvent.value
       kmlEntities.value = entities.value
-
       if (!mouseRightClickEvent) {
         // 添加右键事件
         addMapPointEvent()
diff --git a/src/pages/page-web/projects/components/route-edit/types/index.ts b/src/pages/page-web/projects/components/route-edit/types/index.ts
new file mode 100644
index 0000000..e74c5b3
--- /dev/null
+++ b/src/pages/page-web/projects/components/route-edit/types/index.ts
@@ -0,0 +1,28 @@
+export interface globalSetting {
+  flyToWaylineMode: string
+  // 航线结束动作
+  finishAction: string
+  // 失控是否继续执行航线
+  exitOnRCLost: string
+  // 失控动作
+  executeRCLostAction: string
+  // 安全起飞高度
+  takeOffSecurityHeight: 20
+  // 全局航线速度
+  globalTransitionalSpeed: number
+  // 参考起飞点
+  takeOffRefPoint: string
+  // 参考起飞点海拔高度
+  takeOffRefPointAGLHeight: number
+  // 全局返航高度
+  globalRTHHeight: number
+}
+
+export interface waylineSettingTypes {
+    // 航线高度模式
+  executeHeightMode: string,
+  executeHeight: number,
+  // normal: normalPhoto row-light: lowLightSmartShooting
+  // 拍照模式
+  orientedPhotoMode: number
+}
diff --git a/src/utils/cesium/kmz.ts b/src/utils/cesium/kmz.ts
index 47f3964..ed14c43 100644
--- a/src/utils/cesium/kmz.ts
+++ b/src/utils/cesium/kmz.ts
@@ -22,31 +22,47 @@
 export const getKmlParams = (
   source: string,
   isWpml: boolean,
-  params: { name: string; findRegx: string; mode?: string },
+  params: { name: string | undefined; findRegx: string; mode?: string },
 ) => {
   let regx = null
   if (isWpml) {
     if (params.mode) {
-      regx = new RegExp(
-        `<wpml:${params.name}>${params.findRegx}<\\/wpml:${params.name}>`,
-        params.mode,
-      )
+      regx = new RegExp(`<wpml:${params.name}>${params.findRegx}<\\/wpml:${params.name}>`, params.mode)
     } else {
-      regx = new RegExp(
-        `<wpml:${params.name}>${params.findRegx}<\\/wpml:${params.name}>`,
-      )
+      regx = new RegExp(`<wpml:${params.name}>${params.findRegx}<\\/wpml:${params.name}>`)
     }
   } else {
     if (params.mode) {
-      regx = new RegExp(
-        `<${params.name}>${params.findRegx}<\\/${params.name}>`,
-        params.mode,
-      )
+      regx = new RegExp(`<${params.name}>${params.findRegx}<\\/${params.name}>`, params.mode)
     } else {
-      regx = new RegExp(
-        `<${params.name}>${params.findRegx}<\\/${params.name}>`,
-      )
+      regx = new RegExp(`<${params.name}>${params.findRegx}<\\/${params.name}>`)
     }
   }
   return source?.match(regx)
 }
+
+export const generateKmlFormat = (settingParmas: any) => {
+  let paramGroup = ''
+  Object.keys(settingParmas).forEach((key: string) => {
+    if (Object.prototype.toString.call(settingParmas[key]) === '[object Object]') {
+      let parmaStr = ''
+      Object.keys(settingParmas[key]).forEach((v) => {
+        parmaStr += `<wpml:${v}>${settingParmas[key][v]}</wpml:${v}>`
+      })
+      paramGroup += `<wpml:${key}>${parmaStr}</wpml:${key}>`
+    } else {
+      paramGroup += `<wpml:${key}>${settingParmas[key]}</wpml:${key}>`
+    }
+  })
+  return paramGroup
+}
+
+export const insertChar = (str: string, index: number, char: string) => {
+  if (index > str.length) {
+    return str + char
+  } else if (index < 0) {
+    return char + str
+  } else {
+    return str.slice(0, index) + char + str.slice(index)
+  }
+}
diff --git a/src/utils/cesium/types/kml.ts b/src/utils/cesium/types/kml.ts
new file mode 100644
index 0000000..d66a8a4
--- /dev/null
+++ b/src/utils/cesium/types/kml.ts
@@ -0,0 +1,129 @@
+export interface droneInfo {
+  // 飞行器机型主类型
+  droneEnumValue: string | number
+  // 飞行器机型子类型
+  droneSubEnumValue: string | number
+}
+
+export interface payloadInfo {
+  payloadEnumValue: string | number
+  payloadSubEnumValue: string | number
+  payloadPositionIndex: string | number
+}
+
+export interface missionConfig {
+  // 飞向首航点模式
+  flyToWaylineMode: string
+  // 航线结束动作
+  finishAction: string
+  // 失控是否继续执行航线
+  exitOnRCLost: string
+  // 失控动作类型
+  executeRCLostAction?: string
+  // 安全起飞高度
+  takeOffSecurityHeight: string | number
+  // 全局航线过渡速度
+  globalTransitionalSpeed: string | number
+  // 全局返航高度
+  globalRTHHeight: string | number
+  // 参考起飞点
+  takeOffRefPoint?: string
+  // 参考起飞点海拔高度
+  takeOffRefPointAGLHeight?: string | number
+  // 飞行器机型信息
+  droneInfo: droneInfo
+  // 负载机型信息
+  payloadInfo: payloadInfo
+}
+
+export interface Placemark {
+  // 是否开启标定飞行
+  caliFlightEnable?: boolean | number
+  // 是否开启高程优化
+  elevationOptimizeEnable: boolean | number
+  // 是否开启智能摆拍
+  smartObliqueEnable: boolean | number
+  // 智能摆拍拍摄俯仰角
+  smartObliqueGimbalPitch: number
+  // 拍照模式(定时或定距
+  shootType: string
+  // 航线方向
+  direction: string | number
+  // 测区外扩距离
+  margin?: number
+  //   重叠率参数
+  overlap?: any
+  // 全局航线高度(椭球高)
+  ellipsoidHeight: number
+  // 全局航线高度
+  height: number
+  // 测区多边形
+  Polygon?: any
+  // 建图航拍飞行器朝向参数
+  mappingHeadingParam?: any
+  // 云台俯仰角模式
+  gimbalPitchMode?: string
+  // 云台俯仰角度
+  gimbalPitchAngle?: any
+}
+
+export interface payloadParam {
+  // 负载挂载位置
+  payloadPositionIndex: number
+  // 负载对焦模式
+  focusMode?: string
+  // 负载测光模式
+  meteringMode?: string
+  // 是否开启畸变矫正
+  dewarpingEnable?: boolean | number
+  // 激光雷达回波模式
+  returnMode?: string
+  // 负载采样率
+  samplingRate?: number
+  // 负载扫描模式
+  scanningMode?: number
+  // 真彩上色
+  modelColoringEnable?: boolean | number
+  // 图片格式列表
+  imageFormat: string
+}
+
+export interface waylineCoordinateSysParam {
+  // 经纬度坐标系
+  coordinateMode?: string
+  // 航点高程参考平面
+  heightMode?: string
+  // 经纬度与高度数据源
+  positioningType?: string
+  // 飞行器离被摄面高度(相对地面高)
+  globalShootHeight?: string
+  // 是否开启仿地飞行
+  surfaceFollowModeEnable?: boolean | number
+  // 仿地飞行离地高度(相对地面高)
+  surfaceRelativeHeight?: number
+}
+
+export interface Folder {
+  // 预定义模板类型
+  templateType: string
+  //   模板ID
+  templateId: number
+  //   全局航线飞行速度
+  autoFlightSpeed: number
+  //   坐标系参数
+  waylineCoordinateSysParam?: waylineCoordinateSysParam
+  //   负载设置
+  payloadParam?: payloadParam
+  //   全局航点类型(全局航点转弯模式)
+  globalWaypointTurnMode?: string
+  //   全局航段轨迹是否尽量贴合直线
+  globalUseStraightLine?: boolean | number
+  //   云台俯仰角控制模式
+  gimbalPitchMode?: string
+  //   全局航线高度(相对起飞点高度)
+  globalHeight?: number
+  //   全局偏航角模式参数
+  globalWaypointHeadingParam?: number
+  //   航点信息(包括航点经纬度和高度等)
+  Placemark?: Placemark
+}
diff --git a/src/utils/cesium/use-kmz-tsa.ts b/src/utils/cesium/use-kmz-tsa.ts
index a7543de..a37e16e 100644
--- a/src/utils/cesium/use-kmz-tsa.ts
+++ b/src/utils/cesium/use-kmz-tsa.ts
@@ -1,16 +1,17 @@
 import { ref } from 'vue'
-import { analyzeKmzFile, getKmlParams } from '/@/utils/cesium/kmz'
+import { analyzeKmzFile, getKmlParams, generateKmlFormat } from '/@/utils/cesium/kmz'
 
-const useKMLTsa = () => {
-  const kmzStr = ref('')
+const kmlStr = ref('')
 
-  const init = async (fileUrl: string, fileContent ?: string) => {
+const useKmzTsa = () => {
+  const init = async (fileUrl: string, fileContent?: string) => {
     const kmzRes: string = await analyzeKmzFile(fileUrl)
     if (fileContent) {
-      kmzStr.value = fileContent
+      kmlStr.value = fileContent
       return false
     }
-    kmzStr.value = kmzRes
+    kmlStr.value = kmzRes
+    return kmzRes
   }
 
   const create = () => {
@@ -29,22 +30,54 @@
       </Document>
     </kml>
     `
-    kmzStr.value = str
+    kmlStr.value = str
   }
 
-  const write = () => {}
+  const write = (settingParmas: any = {}, name?: string, isWpml?: boolean = false) => {}
 
-  const del = () => {}
+  const del = () => {
+  }
 
-  const edit = () => {}
+  const edit = (settingParmas: any = {}, keyName?: string, isKeyWpml: boolean = false) => {
+    Object.keys(settingParmas).forEach((key: string) => {
+      const regxVal: any = getKmlParams(kmlStr.value, true, {
+        name: key,
+        findRegx: '([\\s\\S]*?)',
+      })
+      const str = regxVal[1]
+      if (str) {
+        if (key === 'globalHeight') {
+          const regxVal: any = getKmlParams(kmlStr.value, true, {
+            name: 'height',
+            findRegx: '([\\s\\S]*?)',
+            mode: 'g'
+          })
+          regxVal.forEach((heightStr: string) => {
+            const rstr = generateKmlFormat({ height: settingParmas[key] })
+            kmlStr.value = kmlStr.value.replace(heightStr, rstr)
+          })
+        }
+        const replaceStr = generateKmlFormat({ [key]: settingParmas[key] })
+        kmlStr.value = kmlStr.value.replace(regxVal[0], replaceStr)
+      } else {
+        console.warn('没有找到对应的属性')
+      }
+    })
+  }
 
-  const save = () => {}
+  const save = () => {
+    console.log(kmlStr.value)
+  }
 
   return {
+    init,
     create,
     write,
     del,
     edit,
-    save
+    save,
   }
 }
+
+export { kmlStr }
+export default useKmzTsa
diff --git a/src/utils/cesium/use-map-draw.ts b/src/utils/cesium/use-map-draw.ts
index 3bba15f..3734bd9 100644
--- a/src/utils/cesium/use-map-draw.ts
+++ b/src/utils/cesium/use-map-draw.ts
@@ -86,6 +86,29 @@
   },
 ]
 
+const waylinePointsEvent = ref<tragetPoint[]>([])
+// 路线详情
+const waylineDetails = reactive<waylineDetails[]>([
+  {
+    title: '航线长度',
+    value: '0',
+  },
+  {
+    title: '预计执行时间',
+    value: '0',
+  },
+  {
+    title: '航点',
+    value: 0,
+  },
+  {
+    title: '照片',
+    value: 0,
+  },
+])
+// kml中的全部实体
+const kmlEntities = ref<Cesium.Entity[]>([])
+
 const useMapDraw = (
   dataSource: Cesium.DataSource | any,
   entitiesList: Cesium.Entity[] | any,
@@ -93,43 +116,29 @@
   global: any,
 ) => {
   const ellipsoid = global.$viewer.scene.globe.ellipsoid
-  const waylinePointsEvent = ref<tragetPoint[]>([])
-  // 路线详情
-  const waylineDetails = reactive<waylineDetails[]>([
-    {
-      title: '航线长度',
-      value: '0',
-    },
-    {
-      title: '预计执行时间',
-      value: '0',
-    },
-    {
-      title: '航点',
-      value: 0,
-    },
-    {
-      title: '照片',
-      value: 0,
-    },
-  ])
-  // kml中的全部实体
-  const kmlEntities = ref<Cesium.Entity[]>([])
+
   //   kml文件中点位string
   let kmlPoints: string[] | any = []
-  //   记录点位信息
-  const cartesianArr: Cesium.Cartesian3[] = []
+  //  记录点位信息
+  let cartesianArr: Cesium.Cartesian3[] = []
 
   //   绘制路线
-  const drawWayline = async () => {
-    dataSource.show = false
-    let kmlEntityArr = [...entitiesList]
+  const drawWayline = async (entities: Cesium.Entity[], kmlStr: string) => {
+    if (!entities && !kmlStr) {
+      dataSource.show = false
+    }
+    let kmlEntityArr = entities || [...entitiesList]
     if (dataSource) {
       kmlEntityArr = dataSource.entities.values[0]._children
       kmlEntities.value = kmlEntityArr
     }
     // 获取所有点位
-    const kmlRes = await analyzeKmzFile(fileUrl)
+    let kmlRes = ''
+    if (kmlStr) {
+      kmlRes = kmlStr
+    } else {
+      kmlRes = await analyzeKmzFile(fileUrl)
+    }
     // 所有航点
     kmlPoints = getKmlParams(kmlRes, false, {
       name: 'Placemark',
@@ -138,6 +147,11 @@
     })
     // 起飞点
     let btmStartPoint = null
+    // 判断是否存在实体集
+    if (entities) {
+      cartesianArr = []
+      waylinePointsEvent.value = []
+    }
     // 修改点位样式
     for (let i = 0; i < kmlEntityArr.length; i++) {
       const entity: any = kmlEntityArr[i]
@@ -148,21 +162,17 @@
       const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
       // 获取当前航点中的值
       const point = kmlPoints[i]
-      const getPointHeight: any = getKmlParams(point, true, {
+      const getHaeHeight: any = getKmlParams(point, true, {
         name: 'ellipsoidHeight',
         findRegx: '([\\s\\S]*?)',
       })
-      const getHaeHeight: any = getKmlParams(point, true, {
+      const getPointHeight: 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,
-      )
+      entity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude, AslHeight)
       if (i === 0) {
         btmStartPoint = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
       }
@@ -191,6 +201,9 @@
         color: Cesium.Color.GHOSTWHITE,
         outlineColor: Cesium.Color.BLACK,
       })
+      if (entities) {
+        global.$viewer.entities.add(entity)
+      }
       // 创建虚线
       addPolyline({
         id: 'dashLine' + i,
@@ -244,7 +257,9 @@
     })
     // 获取航线详情
     getWaylineDetails(kmlRes)
-    dataSource.show = true
+    if (!entities && !kmlStr) {
+      dataSource.show = true
+    }
     global.$viewer.flyTo(getEntityById('entityLine'), {
       offset: new Cesium.HeadingPitchRange(0, -90, 600),
     })
@@ -267,15 +282,19 @@
     const sportTime = polylineLength / speed
     // 判断有没有超过一分钟
     const time = sportTime / 60
-    waylineDetails[1].value =
-      Math.trunc(time) + ' m ' + Math.round((time % 1) * 60) + ' s'
+    waylineDetails[1].value = Math.trunc(time) + ' m ' + Math.round((time % 1) * 60) + ' s'
 
     // 获取事件
-    getPointEvent()
+    getPointEvent(kmlStr || null)
   }
   // 获取航线点位事件
-  const getPointEvent = async () => {
-    const kmlRes = await analyzeKmzFile(fileUrl)
+  const getPointEvent = async (kmlStr: string | null) => {
+    let kmlRes = ''
+    if (kmlStr) {
+      kmlRes = kmlStr
+    } else {
+      await analyzeKmzFile(fileUrl)
+    }
     // 所有航点
     const points = getKmlParams(kmlRes, false, {
       name: 'Placemark',
@@ -347,6 +366,10 @@
       }
     })
   }
+  const clearWaylineData = () => {
+    kmlEntities.value = []
+    waylinePointsEvent.value = []
+  }
 
   return {
     waylinePointsEvent,
@@ -354,6 +377,9 @@
     kmlEntities,
     drawWayline,
     getWaylineDetails,
+    clearWaylineData,
   }
 }
+
+export { waylinePointsEvent, waylineDetails, kmlEntities }
 export default useMapDraw

--
Gitblit v1.9.3