forked from drone/command-center-dashboard

罗广辉
2025-04-21 2800fa4f32f3900509cb4d6eefaf2bfaf54efdd7
src/utils/cesium/use-kmz-tsa.js
@@ -1,685 +1,675 @@
import _ from 'lodash';
import JSZIP from 'jszip';
import { JSONToXML } from './kmz';
import { getDateFromTimestamp } from '@/utils/date';
import _ from 'lodash'
import JSZIP from 'jszip'
import { JSONToXML } from './kmz'
import { getDateFromTimestamp } from '@/utils/date'
export default function kmzFile() {
  // 云台信息
  const droneModel = {
    52: '0',
    53: '1',
    66: '0',
    67: '1',
    80: '0',
    81: '1',
  };
  // 创建图斑航线
  const create = async (waylineBasicInfo, lnglats, spotList) => {
    try {
      const date = new Date();
      const username = window.localStorage.getItem('bs_username');
      const updateTime = date.getTime();
      const fileName = '图斑航线规划_' + date.getTime();
      // 无人机机型、云台型号、航线高度
      const { droneEnumValue, payloadEnumValue, height } = waylineBasicInfo;
      const defaultHeight = height || 100;
      // 起始点位 (参考点位-具体以机场为准)
      const startPoint = lnglats[0];
      const takeOffPoint = [startPoint[1], startPoint[0], 0].join(',');
      // template.xml对象模版
      const fileTemplate = {
        author: { '#text': username },
        createTime: { '#text': updateTime },
        updateTime: { '#text': updateTime },
        missionConfig: {
          // 飞向首航点模式
          flyToWaylineMode: { '#text': 'safely' },
          // 航线结束动作
          finishAction: { '#text': 'goHome' },
          // 失控是否继续执行航线
          exitOnRCLost: { '#text': 'goContinue' },
          // 失控动作类型
          executeRCLostAction: { '#text': 'goBack' },
          // 安全起飞高度
          takeOffSecurityHeight: { '#text': 20 },
          // 参考起飞点
          takeOffRefPoint: { '#text': takeOffPoint },
          // 参考起飞点海拔高度
          takeOffRefPointAGLHeight: { '#text': 0 },
          // 全局航线过渡速度
          globalTransitionalSpeed: { '#text': 10 },
          // 全局返航高度
          globalRTHHeight: { '#text': defaultHeight },
          // 无人机参数
          droneInfo: {
            droneEnumValue: { '#text': droneEnumValue },
            droneSubEnumValue: {
              '#text': droneModel[payloadEnumValue],
            },
          },
          // 云台参数
          payloadInfo: {
            payloadEnumValue: { '#text': payloadEnumValue },
            payloadSubEnumValue: {
              '#text': droneModel[payloadEnumValue],
            },
            payloadPositionIndex: { '#text': 0 },
          },
        },
        Folder: {
          // 预定义模板类型 - 航点飞行
          templateType: { '#text': 'waypoint' },
          // 是否使用全局航线过渡速度
          useGlobalTransitionalSpeed: { '#text': 0 },
          templateId: { '#text': 0 },
          // 坐标系参数信息
          waylineCoordinateSysParam: {
            // 经纬度坐标系 - 固定值
            coordinateMode: { '#text': 'WGS84' },
            // 航点高程参考平面   - 相对高度
            heightMode: { '#text': 'relativeToStartPoint' },
          },
          // 全局航线飞行速度
          autoFlightSpeed: { '#text': 10 },
          // 云台俯仰角控制模式
          gimbalPitchMode: { '#text': 'usePointSetting' },
          // 全局高度
          globalHeight: { '#text': '100' },
          // 全局偏航角模式参数 - 可使用当前默认值
          globalWaypointHeadingParam: {
            waypointHeadingMode: { '#text': 'followWayline' },
            waypointHeadingAngle: { '#text': 0 },
            waypointPoiPoint: {
              '#text': '0.000000,0.000000,0.000000',
            },
            waypointHeadingPathMode: { '#text': 'followBadArc' },
            waypointHeadingPoiIndex: { '#text': 0 },
          },
          // 全局航点类型 - 直线飞行,飞行器到点停
          globalWaypointTurnMode: {
            '#text': 'toPointAndStopWithDiscontinuityCurvature',
          },
          // 全局航段轨迹是否尽量贴合直线
          globalUseStraightLine: { '#text': 1 },
          // 航点点位信息 - 位置、事件等
          Placemark: [],
          // payloadParam: {
          //   payloadPositionIndex: { '#text': 0 },
          //   focusMode: { '#text': 'firstPoint' },
          //   meteringMode: { '#text': 'average' },
          //   returnMode: { '#text': 'singleReturnFirst' },
          //   samplingRate: { '#text': '240000' },
          //   scanningMode: { '#text': 'repetitive' },
          //   imageFormat: { '#text': 'wide,zoom' },
          // },
        },
      };
      // 航点创建
      const polygonNo = {
        no: '',
        index: 0,
      };
      lnglats.forEach((lnglat, index) => {
        const obj = spotList.find((spot) =>
          spot.dkfw.find((item) => _.isEqual(item, lnglat)),
        );
        let fileSuffix = '';
        if (obj) {
          if (polygonNo.no === obj.dkbh) {
            polygonNo.index++;
          } else {
            polygonNo.no = obj.dkbh;
            polygonNo.index = 1;
          }
          fileSuffix = `图斑航线拍摄(${obj.dkbh}-${polygonNo.index})`;
        } else {
          fileSuffix = '图斑航线拍摄(起点)';
        }
        const placemark = {
          Point: {
            // 航点经纬度
            coordinates: { '#text': `${lnglat[0]},${lnglat[1]}` },
          },
          // 航点index
          index: { '#text': index },
          // 全局航线高度(椭球高)
          ellipsoidHeight: { '#text': defaultHeight },
          // 全局航线高度 (EGM96海拔高/相对起飞点高度/AGL相对地面高度)
          height: { '#text': defaultHeight },
          // 航点飞行速度
          waypointSpeed: { '#text': 10 },
          // 沿航线方向 - 可使用当前默认值
          waypointHeadingParam: {
            waypointHeadingMode: { '#text': 'followWayline' },
            waypointHeadingAngle: { '#text': 0 },
            waypointPoiPoint: {
              '#text': '0.000000,0.000000,0.000000',
            },
            waypointHeadingPathMode: { '#text': 'followBadArc' },
            waypointHeadingPoiIndex: { '#text': 0 },
          },
          // 航点类型
          waypointTurnParam: {
            waypointTurnMode: {
              '#text': 'toPointAndStopWithDiscontinuityCurvature',
            },
            waypointTurnDampingDist: { '#text': 0.2 },
          },
          // 是否全局参数
          useGlobalHeight: { '#text': 1 },
          useGlobalSpeed: { '#text': 1 },
          useGlobalHeadingParam: { '#text': 1 },
          useGlobalTurnParam: { '#text': 1 },
          useStraightLine: { '#text': 1 },
          // 事件组
          actionGroup: {
            actionGroupId: { '#text': index },
            actionGroupStartIndex: { '#text': index },
            actionGroupEndIndex: { '#text': index },
            actionGroupMode: { '#text': 'sequence' },
            actionTrigger: {
              actionTriggerType: { '#text': 'reachPoint' },
            },
            // 单个事件 - 如果是多个事件action可改成数组 action: [{}]
            action: {
              actionId: { '#text': 0 },
              actionActuatorFunc: { '#text': 'takePhoto' },
              actionActuatorFuncParam: {
                fileSuffix: { '#text': fileSuffix },
                payloadPositionIndex: { '#text': '0' },
                useGlobalPayloadLensIndex: { '#text': '1' },
              },
            },
          },
        };
        fileTemplate.Folder.Placemark.push(placemark);
      });
      const fileWaylines = waylinesContext(fileTemplate);
   // 云台信息
   const droneModel = {
      52: '0',
      53: '1',
      66: '0',
      67: '1',
      80: '0',
      81: '1',
   }
   // 创建图斑航线
   const create = async (waylineBasicInfo, lnglats, spotList) => {
      try {
         const date = new Date()
         const username = window.localStorage.getItem('bs_username')
         const updateTime = date.getTime()
         const fileName = '图斑航线规划_' + date.getTime()
         // 无人机机型、云台型号、航线高度
         const { droneEnumValue, payloadEnumValue, height } = waylineBasicInfo
         const defaultHeight = height || 100
         // 起始点位 (参考点位-具体以机场为准)
         const startPoint = lnglats[0]
         const takeOffPoint = [startPoint[1], startPoint[0], 0].join(',')
         // template.xml对象模版
         const fileTemplate = {
            author: { '#text': username },
            createTime: { '#text': updateTime },
            updateTime: { '#text': updateTime },
            missionConfig: {
               // 飞向首航点模式
               flyToWaylineMode: { '#text': 'safely' },
               // 航线结束动作
               finishAction: { '#text': 'goHome' },
               // 失控是否继续执行航线
               exitOnRCLost: { '#text': 'goContinue' },
               // 失控动作类型
               executeRCLostAction: { '#text': 'goBack' },
               // 安全起飞高度
               takeOffSecurityHeight: { '#text': 20 },
               // 参考起飞点
               takeOffRefPoint: { '#text': takeOffPoint },
               // 参考起飞点海拔高度
               takeOffRefPointAGLHeight: { '#text': 0 },
               // 全局航线过渡速度
               globalTransitionalSpeed: { '#text': 10 },
               // 全局返航高度
               globalRTHHeight: { '#text': defaultHeight },
               // 无人机参数
               droneInfo: {
                  droneEnumValue: { '#text': droneEnumValue },
                  droneSubEnumValue: {
                     '#text': droneModel[payloadEnumValue],
                  },
               },
               // 云台参数
               payloadInfo: {
                  payloadEnumValue: { '#text': payloadEnumValue },
                  payloadSubEnumValue: {
                     '#text': droneModel[payloadEnumValue],
                  },
                  payloadPositionIndex: { '#text': 0 },
               },
            },
            Folder: {
               // 预定义模板类型 - 航点飞行
               templateType: { '#text': 'waypoint' },
               // 是否使用全局航线过渡速度
               useGlobalTransitionalSpeed: { '#text': 0 },
               templateId: { '#text': 0 },
               // 坐标系参数信息
               waylineCoordinateSysParam: {
                  // 经纬度坐标系 - 固定值
                  coordinateMode: { '#text': 'WGS84' },
                  // 航点高程参考平面   - 相对高度
                  heightMode: { '#text': 'relativeToStartPoint' },
               },
               // 全局航线飞行速度
               autoFlightSpeed: { '#text': 10 },
               // 云台俯仰角控制模式
               gimbalPitchMode: { '#text': 'usePointSetting' },
               // 全局高度
               globalHeight: { '#text': '100' },
               // 全局偏航角模式参数 - 可使用当前默认值
               globalWaypointHeadingParam: {
                  waypointHeadingMode: { '#text': 'followWayline' },
                  waypointHeadingAngle: { '#text': 0 },
                  waypointPoiPoint: {
                     '#text': '0.000000,0.000000,0.000000',
                  },
                  waypointHeadingPathMode: { '#text': 'followBadArc' },
                  waypointHeadingPoiIndex: { '#text': 0 },
               },
               // 全局航点类型 - 直线飞行,飞行器到点停
               globalWaypointTurnMode: {
                  '#text': 'toPointAndStopWithDiscontinuityCurvature',
               },
               // 全局航段轨迹是否尽量贴合直线
               globalUseStraightLine: { '#text': 1 },
               // 航点点位信息 - 位置、事件等
               Placemark: [],
               // payloadParam: {
               //   payloadPositionIndex: { '#text': 0 },
               //   focusMode: { '#text': 'firstPoint' },
               //   meteringMode: { '#text': 'average' },
               //   returnMode: { '#text': 'singleReturnFirst' },
               //   samplingRate: { '#text': '240000' },
               //   scanningMode: { '#text': 'repetitive' },
               //   imageFormat: { '#text': 'wide,zoom' },
               // },
            },
         }
         // 航点创建
         const polygonNo = {
            no: '',
            index: 0,
         }
         lnglats.forEach((lnglat, index) => {
            const obj = spotList.find(spot => spot.dkfw.find(item => _.isEqual(item, lnglat)))
            let fileSuffix = ''
            if (obj) {
               if (polygonNo.no === obj.dkbh) {
                  polygonNo.index++
               } else {
                  polygonNo.no = obj.dkbh
                  polygonNo.index = 1
               }
               fileSuffix = `图斑航线拍摄(${obj.dkbh}-${polygonNo.index})`
            } else {
               fileSuffix = '图斑航线拍摄(起点)'
            }
            const placemark = {
               Point: {
                  // 航点经纬度
                  coordinates: { '#text': `${lnglat[0]},${lnglat[1]}` },
               },
               // 航点index
               index: { '#text': index },
               // 全局航线高度(椭球高)
               ellipsoidHeight: { '#text': defaultHeight },
               // 全局航线高度 (EGM96海拔高/相对起飞点高度/AGL相对地面高度)
               height: { '#text': defaultHeight },
               // 航点飞行速度
               waypointSpeed: { '#text': 10 },
               // 沿航线方向 - 可使用当前默认值
               waypointHeadingParam: {
                  waypointHeadingMode: { '#text': 'followWayline' },
                  waypointHeadingAngle: { '#text': 0 },
                  waypointPoiPoint: {
                     '#text': '0.000000,0.000000,0.000000',
                  },
                  waypointHeadingPathMode: { '#text': 'followBadArc' },
                  waypointHeadingPoiIndex: { '#text': 0 },
               },
               // 航点类型
               waypointTurnParam: {
                  waypointTurnMode: {
                     '#text': 'toPointAndStopWithDiscontinuityCurvature',
                  },
                  waypointTurnDampingDist: { '#text': 0.2 },
               },
               // 是否全局参数
               useGlobalHeight: { '#text': 1 },
               useGlobalSpeed: { '#text': 1 },
               useGlobalHeadingParam: { '#text': 1 },
               useGlobalTurnParam: { '#text': 1 },
               useStraightLine: { '#text': 1 },
               // 事件组
               actionGroup: {
                  actionGroupId: { '#text': index },
                  actionGroupStartIndex: { '#text': index },
                  actionGroupEndIndex: { '#text': index },
                  actionGroupMode: { '#text': 'sequence' },
                  actionTrigger: {
                     actionTriggerType: { '#text': 'reachPoint' },
                  },
                  // 单个事件 - 如果是多个事件action可改成数组 action: [{}]
                  action: {
                     actionId: { '#text': 0 },
                     actionActuatorFunc: { '#text': 'takePhoto' },
                     actionActuatorFuncParam: {
                        fileSuffix: { '#text': fileSuffix },
                        payloadPositionIndex: { '#text': '0' },
                        useGlobalPayloadLensIndex: { '#text': '1' },
                     },
                  },
               },
            }
            fileTemplate.Folder.Placemark.push(placemark)
         })
         const fileWaylines = waylinesContext(fileTemplate)
      return {
        fileName,
        template: fileTemplate,
        waylines: fileWaylines,
      };
    } catch (error) {
      console.log(error);
      return false;
    }
  };
         return {
            fileName,
            template: fileTemplate,
            waylines: fileWaylines,
         }
      } catch (error) {
         console.log(error)
         return false
      }
   }
  // 创建正常航线
  const createNoramlWaylines = (waylineBasicInfo, lnglats) => {
    try {
      const date = new Date();
      const username = window.localStorage.getItem('bs_username');
      const updateTime = date.getTime();
      const { year, month, day, hours, minutes } =
        getDateFromTimestamp(updateTime);
      const fileName = '新建航线_' + year + month + day + hours + minutes;
      // 无人机机型、云台型号、航线高度
      const { droneEnumValue, payloadEnumValue, height, waylineName } =
        waylineBasicInfo;
      const defaultHeight = height || 100;
      // 起始点位 (参考点位-具体以机场为准)
      const startPoint = lnglats[0];
      const takeOffPoint = [startPoint.latitude, startPoint.longitude, 0].join(
        ',',
      );
      // template.xml对象模版
      const fileTemplate = {
        author: { '#text': username },
        createTime: { '#text': updateTime },
        updateTime: { '#text': updateTime },
        missionConfig: {
          // 飞向首航点模式
          flyToWaylineMode: { '#text': 'safely' },
          // 航线结束动作
          finishAction: { '#text': 'goHome' },
          // 失控是否继续执行航线
          exitOnRCLost: { '#text': 'goContinue' },
          // 失控动作类型
          executeRCLostAction: { '#text': 'goBack' },
          // 安全起飞高度
          takeOffSecurityHeight: { '#text': 20 },
          // 参考起飞点
          takeOffRefPoint: { '#text': takeOffPoint },
          // 参考起飞点海拔高度
          takeOffRefPointAGLHeight: { '#text': 0 },
          // 全局航线过渡速度
          globalTransitionalSpeed: { '#text': 10 },
          // 全局返航高度
          globalRTHHeight: { '#text': defaultHeight },
          // 无人机参数
          droneInfo: {
            droneEnumValue: { '#text': droneEnumValue },
            droneSubEnumValue: {
              '#text': droneModel[payloadEnumValue],
            },
          },
          // 是否自动绕行(暂未验证M30T机型使用此参数后会不会无法起飞)
          autoRerouteInfo: {
            missionAutoRerouteMode: { '#text': 1 },
            transitionalAutoRerouteMode: { '#text': 1 },
          },
          // 云台参数
          payloadInfo: {
            payloadEnumValue: { '#text': payloadEnumValue },
            payloadSubEnumValue: {
              '#text': droneModel[payloadEnumValue],
            },
            payloadPositionIndex: { '#text': 0 },
          },
        },
        Folder: {
          // 预定义模板类型 - 航点飞行
          templateType: { '#text': 'waypoint' },
          // 是否使用全局航线过渡速度
          useGlobalTransitionalSpeed: { '#text': 0 },
          templateId: { '#text': 0 },
          // 坐标系参数信息
          waylineCoordinateSysParam: {
            // 经纬度坐标系 - 固定值
            coordinateMode: { '#text': 'WGS84' },
            // 航点高程参考平面   - 相对高度
            heightMode: { '#text': 'relativeToStartPoint' },
          },
          // 全局航线飞行速度
          autoFlightSpeed: { '#text': 10 },
          // 云台俯仰角控制模式
          gimbalPitchMode: { '#text': 'usePointSetting' },
          // 全局高度
          globalHeight: { '#text': '100' },
          // 全局偏航角模式参数 - 可使用当前默认值
          globalWaypointHeadingParam: {
            waypointHeadingMode: { '#text': 'followWayline' },
            waypointHeadingAngle: { '#text': 0 },
            waypointPoiPoint: {
              '#text': '0.000000,0.000000,0.000000',
            },
            waypointHeadingPathMode: { '#text': 'followBadArc' },
            waypointHeadingPoiIndex: { '#text': 0 },
          },
          // 全局航点类型 - 直线飞行,飞行器到点停
          globalWaypointTurnMode: {
            '#text': 'toPointAndStopWithDiscontinuityCurvature',
          },
          // 全局航段轨迹是否尽量贴合直线
          globalUseStraightLine: { '#text': 1 },
          // 航点点位信息 - 位置、事件等
          Placemark: [],
          payloadParam: {
            payloadPositionIndex: { '#text': 0 },
            focusMode: { '#text': 'firstPoint' },
            meteringMode: { '#text': 'average' },
            returnMode: { '#text': 'singleReturnFirst' },
            samplingRate: { '#text': '240000' },
            scanningMode: { '#text': 'repetitive' },
            imageFormat: { '#text': 'wide,zoom' },
          },
        },
      };
      lnglats.forEach((lnglat, index) => {
        const placemark = {
          Point: {
            // 航点经纬度
            coordinates: {
              '#text': `${lnglat.longitude},${lnglat.latitude}`,
            },
          },
          // 航点index
          index: { '#text': index },
          // 全局航线高度(椭球高)
          ellipsoidHeight: { '#text': lnglat.height },
          // 全局航线高度 (EGM96海拔高/相对起飞点高度/AGL相对地面高度)
          height: { '#text': lnglat.height },
          // 航点飞行速度
          waypointSpeed: { '#text': lnglat?.speed || 10 },
          // 沿航线方向 - 可使用当前默认值
          waypointHeadingParam: {
            waypointHeadingMode: { '#text': 'followWayline' },
            waypointHeadingAngle: { '#text': 0 },
            waypointPoiPoint: {
              '#text': '0.000000,0.000000,0.000000',
            },
            waypointHeadingPathMode: { '#text': 'followBadArc' },
            waypointHeadingPoiIndex: { '#text': 0 },
          },
          // 航点类型
          waypointTurnParam: {
            waypointTurnMode: {
              '#text': 'toPointAndStopWithDiscontinuityCurvature',
            },
            waypointTurnDampingDist: { '#text': 0.2 },
          },
          // 是否全局参数
          useGlobalHeight: { '#text': 1 },
          useGlobalSpeed: { '#text': 0 },
          useGlobalHeadingParam: { '#text': 1 },
          useGlobalTurnParam: { '#text': 1 },
          useStraightLine: { '#text': 1 },
        };
        if (lnglat?.actions) {
          const actionGroup = {
            actionGroupId: { '#text': index },
            actionGroupStartIndex: { '#text': index },
            actionGroupEndIndex: { '#text': index },
            actionGroupMode: { '#text': 'sequence' },
            actionTrigger: {
              actionTriggerType: { '#text': 'reachPoint' },
            },
            // 单个事件 - 如果是多个事件action可改成数组 action: [{}]
            // action: [{
            //   actionId: { '#text': 0 },
            //   actionActuatorFunc: { '#text': '' },
            //   actionActuatorFuncParam: {},
            // }],
            action: [],
          };
          lnglat?.actions.forEach((action, index) => {
            const singleAction = {
              actionId: { '#text': index },
              actionActuatorFunc: { '#text': '' },
              actionActuatorFuncParam: {},
            };
            // actionGroup.action['actionActuatorFunc'] = { '#text': action.key }
            // action.params.forEach(p => {
            //   if (p.value || p.value !== '') {
            //     actionGroup.action['actionActuatorFuncParam'][p.key] = { '#text': p.value }
            //   }
            // })
            singleAction['actionActuatorFunc'] = {
              '#text': action.key,
            };
            action.params.forEach((p) => {
              if (p.value || p.value !== '') {
                singleAction['actionActuatorFuncParam'][p.key] = {
                  '#text': p.value,
                };
              }
            });
            if (lnglat?.actions.length > 1) {
              actionGroup.action.push(singleAction);
            } else {
              actionGroup.action = singleAction;
            }
          });
          placemark.actionGroup = actionGroup;
        }
        fileTemplate.Folder.Placemark.push(placemark);
      });
      const fileWaylines = waylinesContext(fileTemplate);
      return {
        fileName: waylineName || fileName,
        template: fileTemplate,
        waylines: fileWaylines,
      };
    } catch (error) {
      console.log(error);
      return error;
    }
  };
   // 创建正常航线
   const createNoramlWaylines = (waylineBasicInfo, lnglats) => {
      try {
         const date = new Date()
         const username = window.localStorage.getItem('bs_username')
         const updateTime = date.getTime()
         const { year, month, day, hours, minutes } = getDateFromTimestamp(updateTime)
         const fileName = '新建航线_' + year + month + day + hours + minutes
         // 无人机机型、云台型号、航线高度
         const { droneEnumValue, payloadEnumValue, height, waylineName } = waylineBasicInfo
         const defaultHeight = height || 100
         // 起始点位 (参考点位-具体以机场为准)
         const startPoint = lnglats[0]
         const takeOffPoint = [startPoint.latitude, startPoint.longitude, 0].join(',')
         // template.xml对象模版
         const fileTemplate = {
            author: { '#text': username },
            createTime: { '#text': updateTime },
            updateTime: { '#text': updateTime },
            missionConfig: {
               // 飞向首航点模式
               flyToWaylineMode: { '#text': 'safely' },
               // 航线结束动作
               finishAction: { '#text': 'goHome' },
               // 失控是否继续执行航线
               exitOnRCLost: { '#text': 'goContinue' },
               // 失控动作类型
               executeRCLostAction: { '#text': 'goBack' },
               // 安全起飞高度
               takeOffSecurityHeight: { '#text': 20 },
               // 参考起飞点
               takeOffRefPoint: { '#text': takeOffPoint },
               // 参考起飞点海拔高度
               takeOffRefPointAGLHeight: { '#text': 0 },
               // 全局航线过渡速度
               globalTransitionalSpeed: { '#text': 10 },
               // 全局返航高度
               globalRTHHeight: { '#text': defaultHeight },
               // 无人机参数
               droneInfo: {
                  droneEnumValue: { '#text': droneEnumValue },
                  droneSubEnumValue: {
                     '#text': droneModel[payloadEnumValue],
                  },
               },
               // 是否自动绕行(暂未验证M30T机型使用此参数后会不会无法起飞)
               autoRerouteInfo: {
                  missionAutoRerouteMode: { '#text': 1 },
                  transitionalAutoRerouteMode: { '#text': 1 },
               },
               // 云台参数
               payloadInfo: {
                  payloadEnumValue: { '#text': payloadEnumValue },
                  payloadSubEnumValue: {
                     '#text': droneModel[payloadEnumValue],
                  },
                  payloadPositionIndex: { '#text': 0 },
               },
            },
            Folder: {
               // 预定义模板类型 - 航点飞行
               templateType: { '#text': 'waypoint' },
               // 是否使用全局航线过渡速度
               useGlobalTransitionalSpeed: { '#text': 0 },
               templateId: { '#text': 0 },
               // 坐标系参数信息
               waylineCoordinateSysParam: {
                  // 经纬度坐标系 - 固定值
                  coordinateMode: { '#text': 'WGS84' },
                  // 航点高程参考平面   - 相对高度
                  heightMode: { '#text': 'relativeToStartPoint' },
               },
               // 全局航线飞行速度
               autoFlightSpeed: { '#text': 10 },
               // 云台俯仰角控制模式
               gimbalPitchMode: { '#text': 'usePointSetting' },
               // 全局高度
               globalHeight: { '#text': '100' },
               // 全局偏航角模式参数 - 可使用当前默认值
               globalWaypointHeadingParam: {
                  waypointHeadingMode: { '#text': 'followWayline' },
                  waypointHeadingAngle: { '#text': 0 },
                  waypointPoiPoint: {
                     '#text': '0.000000,0.000000,0.000000',
                  },
                  waypointHeadingPathMode: { '#text': 'followBadArc' },
                  waypointHeadingPoiIndex: { '#text': 0 },
               },
               // 全局航点类型 - 直线飞行,飞行器到点停
               globalWaypointTurnMode: {
                  '#text': 'toPointAndStopWithDiscontinuityCurvature',
               },
               // 全局航段轨迹是否尽量贴合直线
               globalUseStraightLine: { '#text': 1 },
               // 航点点位信息 - 位置、事件等
               Placemark: [],
               payloadParam: {
                  payloadPositionIndex: { '#text': 0 },
                  focusMode: { '#text': 'firstPoint' },
                  meteringMode: { '#text': 'average' },
                  returnMode: { '#text': 'singleReturnFirst' },
                  samplingRate: { '#text': '240000' },
                  scanningMode: { '#text': 'repetitive' },
                  imageFormat: { '#text': 'wide,zoom' },
               },
            },
         }
         lnglats.forEach((lnglat, index) => {
            const placemark = {
               Point: {
                  // 航点经纬度
                  coordinates: {
                     '#text': `${lnglat.longitude},${lnglat.latitude}`,
                  },
               },
               // 航点index
               index: { '#text': index },
               // 全局航线高度(椭球高)
               ellipsoidHeight: { '#text': lnglat.height },
               // 全局航线高度 (EGM96海拔高/相对起飞点高度/AGL相对地面高度)
               height: { '#text': lnglat.height },
               // 航点飞行速度
               waypointSpeed: { '#text': lnglat?.speed || 10 },
               // 沿航线方向 - 可使用当前默认值
               waypointHeadingParam: {
                  waypointHeadingMode: { '#text': 'followWayline' },
                  waypointHeadingAngle: { '#text': 0 },
                  waypointPoiPoint: {
                     '#text': '0.000000,0.000000,0.000000',
                  },
                  waypointHeadingPathMode: { '#text': 'followBadArc' },
                  waypointHeadingPoiIndex: { '#text': 0 },
               },
               // 航点类型
               waypointTurnParam: {
                  waypointTurnMode: {
                     '#text': 'toPointAndStopWithDiscontinuityCurvature',
                  },
                  waypointTurnDampingDist: { '#text': 0.2 },
               },
               // 是否全局参数
               useGlobalHeight: { '#text': 1 },
               useGlobalSpeed: { '#text': 0 },
               useGlobalHeadingParam: { '#text': 1 },
               useGlobalTurnParam: { '#text': 1 },
               useStraightLine: { '#text': 1 },
            }
            if (lnglat?.actions) {
               const actionGroup = {
                  actionGroupId: { '#text': index },
                  actionGroupStartIndex: { '#text': index },
                  actionGroupEndIndex: { '#text': index },
                  actionGroupMode: { '#text': 'sequence' },
                  actionTrigger: {
                     actionTriggerType: { '#text': 'reachPoint' },
                  },
                  // 单个事件 - 如果是多个事件action可改成数组 action: [{}]
                  // action: [{
                  //   actionId: { '#text': 0 },
                  //   actionActuatorFunc: { '#text': '' },
                  //   actionActuatorFuncParam: {},
                  // }],
                  action: [],
               }
               lnglat?.actions.forEach((action, index) => {
                  const singleAction = {
                     actionId: { '#text': index },
                     actionActuatorFunc: { '#text': '' },
                     actionActuatorFuncParam: {},
                  }
                  // actionGroup.action['actionActuatorFunc'] = { '#text': action.key }
                  // action.params.forEach(p => {
                  //   if (p.value || p.value !== '') {
                  //     actionGroup.action['actionActuatorFuncParam'][p.key] = { '#text': p.value }
                  //   }
                  // })
                  singleAction['actionActuatorFunc'] = {
                     '#text': action.key,
                  }
                  action.params.forEach(p => {
                     if (p.value || p.value !== '') {
                        singleAction['actionActuatorFuncParam'][p.key] = {
                           '#text': p.value,
                        }
                     }
                  })
                  if (lnglat?.actions.length > 1) {
                     actionGroup.action.push(singleAction)
                  } else {
                     actionGroup.action = singleAction
                  }
               })
               placemark.actionGroup = actionGroup
            }
            fileTemplate.Folder.Placemark.push(placemark)
         })
         const fileWaylines = waylinesContext(fileTemplate)
         return {
            fileName: waylineName || fileName,
            template: fileTemplate,
            waylines: fileWaylines,
         }
      } catch (error) {
         console.log(error)
         return error
      }
   }
  // 创建面状航线
  const createPlanarWayline = (waylineBasicInfo, lnglats) => {};
   // 创建面状航线
   const createPlanarWayline = (waylineBasicInfo, lnglats) => {}
  // 创建点状航线
  const createPointWayLines = (
    waylineBasicInfo,
    points,
    settingInfo,
    dockPosition,
  ) => {
    try {
      const { droneEnumValue, payloadEnumValue, waylineName } =
        waylineBasicInfo;
   // 创建点状航线
   const createPointWayLines = (waylineBasicInfo, points, settingInfo, dockPosition) => {
      try {
         const { droneEnumValue, payloadEnumValue, waylineName } = waylineBasicInfo
      const { imageFormat, heightMode, globalHeight, autoFlightSpeed,gimbalPitchMode,
        waypointTurnMode,waypointHeadingMode,finishAction,globalTransitionalSpeed  } =
        settingInfo;
         const {
            imageFormat,
            heightMode,
            globalHeight,
            autoFlightSpeed,
            gimbalPitchMode,
            waypointTurnMode,
            waypointHeadingMode,
            finishAction,
            globalTransitionalSpeed,
         } = settingInfo
      const date = new Date();
      const username = window.localStorage.getItem('bs_username');
      const updateTime = date.getTime();
      const { year, month, day, hours, minutes } =
        getDateFromTimestamp(updateTime);
      const fileName = '新建航线_' + year + month + day + hours + minutes;
      // 无人机机型、云台型号、航线高度
         const date = new Date()
         const username = window.localStorage.getItem('bs_username')
         const updateTime = date.getTime()
         const { year, month, day, hours, minutes } = getDateFromTimestamp(updateTime)
         const fileName = '新建航线_' + year + month + day + hours + minutes
         // 无人机机型、云台型号、航线高度
      const defaultHeight = 100;
      // 起始点位 (参考点位-具体以机场为准)
      const takeOffPoint = [
        dockPosition.latitude,
        dockPosition.longitude,
        0,
      ].join(',');
         const defaultHeight = 100
         // 起始点位 (参考点位-具体以机场为准)
         const takeOffPoint = [dockPosition.latitude, dockPosition.longitude, 0].join(',')
      // template.xml对象模版
      const fileTemplate = {
        author: { '#text': username },
        createTime: { '#text': updateTime },
        updateTime: { '#text': updateTime },
        missionConfig: {
          // 飞向首航点模式
          flyToWaylineMode: { '#text': 'safely' },
          // 航线结束动作
          finishAction: { '#text': finishAction || 'goHome' },
          // 失控是否继续执行航线
          exitOnRCLost: { '#text': 'executeLostAction' },
          // 失控动作类型
          executeRCLostAction: { '#text': 'goBack' },
          // 安全起飞高度
          takeOffSecurityHeight: { '#text': 120 },
          // 参考起飞点
          takeOffRefPoint: { '#text': takeOffPoint },
          // 参考起飞点海拔高度
          takeOffRefPointAGLHeight: { '#text': 0 },
          // 全局航线过渡速度
          globalTransitionalSpeed: { '#text': globalTransitionalSpeed || 10 },
          // 全局返航高度
          globalRTHHeight: { '#text': defaultHeight },
          // 无人机参数
          droneInfo: {
            droneEnumValue: { '#text': droneEnumValue },
            droneSubEnumValue: {
              '#text': droneModel[payloadEnumValue],
            },
          },
          // 是否自动绕行(暂未验证M30T机型使用此参数后会不会无法起飞)
          autoRerouteInfo: {
            missionAutoRerouteMode: { '#text': 1 },
            transitionalAutoRerouteMode: { '#text': 1 },
          },
          // 云台参数
          payloadInfo: {
            payloadEnumValue: { '#text': payloadEnumValue },
            payloadSubEnumValue: {
              '#text': droneModel[payloadEnumValue],
            },
            payloadPositionIndex: { '#text': 0 },
          },
        },
        Folder: {
          // 预定义模板类型 - 航点飞行
          templateType: { '#text': 'waypoint' },
          // 是否使用全局航线过渡速度
          useGlobalTransitionalSpeed: { '#text': 0 },
          templateId: { '#text': 0 },
          // 坐标系参数信息
          waylineCoordinateSysParam: {
            // 经纬度坐标系 - 固定值
            coordinateMode: { '#text': 'WGS84' },
            // 航点高程参考平面   - 相对高度
            heightMode: heightMode,
          },
          // 全局航线飞行速度
          autoFlightSpeed: { '#text': autoFlightSpeed || 10 },
          // 云台俯仰角控制模式
          gimbalPitchMode: { '#text': gimbalPitchMode || 'manual' },
          // 全局高度
          globalHeight: { '#text': globalHeight || '100' },
          // 全局偏航角模式参数 - 可使用当前默认值
          globalWaypointHeadingParam: {
            waypointHeadingMode: { '#text': waypointHeadingMode || 'followWayline' },
            waypointHeadingAngle: { '#text': 0 },
            waypointPoiPoint: {
              '#text': '0.000000,0.000000,0.000000',
            },
            waypointHeadingPathMode: { '#text': 'followBadArc' },
            waypointHeadingPoiIndex: { '#text': 0 },
          },
          // 全局航点类型 - 直线飞行,飞行器到点停
          globalWaypointTurnMode: {
            '#text': waypointTurnMode || 'toPointAndStopWithDiscontinuityCurvature',
          },
          // 全局航段轨迹是否尽量贴合直线
          globalUseStraightLine: { '#text': 1 },
          // 航点点位信息 - 位置、事件等
          Placemark: [],
          payloadParam: {
            payloadPositionIndex: { '#text': 0 },
            focusMode: { '#text': 'firstPoint' },
            meteringMode: { '#text': 'average' },
            returnMode: { '#text': 'singleReturnFirst' },
            samplingRate: { '#text': '240000' },
            scanningMode: { '#text': 'repetitive' },
            imageFormat: imageFormat,
          },
        },
      };
      points.length &&
        points.forEach((detail, ind) => {
          const { Point, index, height, ellipsoidHeight, actionGroup,waypointSpeed } = detail;
         // template.xml对象模版
         const fileTemplate = {
            author: { '#text': username },
            createTime: { '#text': updateTime },
            updateTime: { '#text': updateTime },
            missionConfig: {
               // 飞向首航点模式
               flyToWaylineMode: { '#text': 'safely' },
               // 航线结束动作
               finishAction: { '#text': finishAction || 'goHome' },
               // 失控是否继续执行航线
               exitOnRCLost: { '#text': 'executeLostAction' },
               // 失控动作类型
               executeRCLostAction: { '#text': 'goBack' },
               // 安全起飞高度
               takeOffSecurityHeight: { '#text': 120 },
               // 参考起飞点
               takeOffRefPoint: { '#text': takeOffPoint },
               // 参考起飞点海拔高度
               takeOffRefPointAGLHeight: { '#text': 0 },
               // 全局航线过渡速度
               globalTransitionalSpeed: { '#text': globalTransitionalSpeed || 10 },
               // 全局返航高度
               globalRTHHeight: { '#text': defaultHeight },
               // 无人机参数
               droneInfo: {
                  droneEnumValue: { '#text': droneEnumValue },
                  droneSubEnumValue: {
                     '#text': droneModel[payloadEnumValue],
                  },
               },
               // 是否自动绕行(暂未验证M30T机型使用此参数后会不会无法起飞)
               autoRerouteInfo: {
                  missionAutoRerouteMode: { '#text': 1 },
                  transitionalAutoRerouteMode: { '#text': 1 },
               },
               // 云台参数
               payloadInfo: {
                  payloadEnumValue: { '#text': payloadEnumValue },
                  payloadSubEnumValue: {
                     '#text': droneModel[payloadEnumValue],
                  },
                  payloadPositionIndex: { '#text': 0 },
               },
            },
            Folder: {
               // 预定义模板类型 - 航点飞行
               templateType: { '#text': 'waypoint' },
               // 是否使用全局航线过渡速度
               useGlobalTransitionalSpeed: { '#text': 0 },
               templateId: { '#text': 0 },
               // 坐标系参数信息
               waylineCoordinateSysParam: {
                  // 经纬度坐标系 - 固定值
                  coordinateMode: { '#text': 'WGS84' },
                  // 航点高程参考平面   - 相对高度
                  heightMode: heightMode,
               },
               // 全局航线飞行速度
               autoFlightSpeed: { '#text': autoFlightSpeed || 10 },
               // 云台俯仰角控制模式
               gimbalPitchMode: { '#text': gimbalPitchMode || 'manual' },
               // 全局高度
               globalHeight: { '#text': globalHeight || '100' },
               // 全局偏航角模式参数 - 可使用当前默认值
               globalWaypointHeadingParam: {
                  waypointHeadingMode: { '#text': waypointHeadingMode || 'followWayline' },
                  waypointHeadingAngle: { '#text': 0 },
                  waypointPoiPoint: {
                     '#text': '0.000000,0.000000,0.000000',
                  },
                  waypointHeadingPathMode: { '#text': 'followBadArc' },
                  waypointHeadingPoiIndex: { '#text': 0 },
               },
               // 全局航点类型 - 直线飞行,飞行器到点停
               globalWaypointTurnMode: {
                  '#text': waypointTurnMode || 'toPointAndStopWithDiscontinuityCurvature',
               },
               // 全局航段轨迹是否尽量贴合直线
               globalUseStraightLine: { '#text': 1 },
               // 航点点位信息 - 位置、事件等
               Placemark: [],
               payloadParam: {
                  payloadPositionIndex: { '#text': 0 },
                  focusMode: { '#text': 'firstPoint' },
                  meteringMode: { '#text': 'average' },
                  returnMode: { '#text': 'singleReturnFirst' },
                  samplingRate: { '#text': '240000' },
                  scanningMode: { '#text': 'repetitive' },
                  imageFormat: imageFormat,
               },
            },
         }
         points.length &&
            points.forEach((detail, ind) => {
               const { Point, index, height, ellipsoidHeight, actionGroup, waypointSpeed } = detail
          const placemark = {
            Point,
            // 航点index
            index,
            // 全局航线高度(椭球高)
            ellipsoidHeight,
            // 全局航线高度 (EGM96海拔高/相对起飞点高度/AGL相对地面高度)
            height,
            // 航点飞行速度
            waypointSpeed: { '#text': waypointSpeed ||  10 },
            // 沿航线方向 - 可使用当前默认值
            waypointHeadingParam: {
              waypointHeadingMode: { '#text': waypointHeadingMode || 'followWayline' },
              waypointHeadingAngle: { '#text': 0 },
              waypointPoiPoint: {
                '#text': '0.000000,0.000000,0.000000',
              },
              waypointHeadingPathMode: { '#text': 'followBadArc' },
              waypointHeadingPoiIndex: { '#text': 0 },
            },
            // 航点类型
            waypointTurnParam: {
              waypointTurnMode: {
                '#text': waypointTurnMode || 'toPointAndStopWithDiscontinuityCurvature',
              },
              waypointTurnDampingDist: { '#text': 0.2 },
            },
            // 是否全局参数
            useGlobalHeight: { '#text': 1 },
            useGlobalSpeed: { '#text': 0 },
            useGlobalHeadingParam: { '#text': 1 },
            useGlobalTurnParam: { '#text': 1 },
            useStraightLine: { '#text': 1 },
          };
          if (actionGroup) {
            placemark.actionGroup = actionGroup;
          }
               const placemark = {
                  Point,
                  // 航点index
                  index,
                  // 全局航线高度(椭球高)
                  ellipsoidHeight,
                  // 全局航线高度 (EGM96海拔高/相对起飞点高度/AGL相对地面高度)
                  height,
                  // 航点飞行速度
                  waypointSpeed: { '#text': waypointSpeed || 10 },
                  // 沿航线方向 - 可使用当前默认值
                  waypointHeadingParam: {
                     waypointHeadingMode: {
                        '#text': waypointHeadingMode || 'followWayline',
                     },
                     waypointHeadingAngle: { '#text': 0 },
                     waypointPoiPoint: {
                        '#text': '0.000000,0.000000,0.000000',
                     },
                     waypointHeadingPathMode: { '#text': 'followBadArc' },
                     waypointHeadingPoiIndex: { '#text': 0 },
                  },
                  // 航点类型
                  waypointTurnParam: {
                     waypointTurnMode: {
                        '#text': waypointTurnMode || 'toPointAndStopWithDiscontinuityCurvature',
                     },
                     waypointTurnDampingDist: { '#text': 0.2 },
                  },
                  // 是否全局参数
                  useGlobalHeight: { '#text': 1 },
                  useGlobalSpeed: { '#text': 0 },
                  useGlobalHeadingParam: { '#text': 1 },
                  useGlobalTurnParam: { '#text': 1 },
                  useStraightLine: { '#text': 1 },
               }
               if (actionGroup) {
                  placemark.actionGroup = actionGroup
               }
          fileTemplate.Folder.Placemark.push(placemark);
        });
               fileTemplate.Folder.Placemark.push(placemark)
            })
      const fileWaylines = waylinesContext(fileTemplate);
      return {
        fileName: waylineName || fileName,
        template: fileTemplate,
        waylines: fileWaylines,
      };
    } catch (error) {
      console.log(error);
      return error;
    }
  };
         const fileWaylines = waylinesContext(fileTemplate)
         return {
            fileName: waylineName || fileName,
            template: fileTemplate,
            waylines: fileWaylines,
         }
      } catch (error) {
         console.log(error)
         return error
      }
   }
  const save = async (fileInfo) => {
    const JsZip = new JSZIP();
    const { fileName, template, waylines } = fileInfo;
    const templateXml = JSONToXML(template, '', true);
    const waylinesWpml = JSONToXML(waylines, '', true);
    JsZip.file('wpmz/template.kml', templateXml);
    JsZip.file('wpmz/waylines.wpml', waylinesWpml);
    const fileBlob = await JsZip.generateAsync({ type: 'blob' });
    // saveAs(kmzFile, `${fileName}.kmz`)
    return fileBlob;
  };
   const save = async fileInfo => {
      const JsZip = new JSZIP()
      const { fileName, template, waylines } = fileInfo
      const templateXml = JSONToXML(template, '', true)
      const waylinesWpml = JSONToXML(waylines, '', true)
      JsZip.file('wpmz/template.kml', templateXml)
      JsZip.file('wpmz/waylines.wpml', waylinesWpml)
      const fileBlob = await JsZip.generateAsync({ type: 'blob' })
      // saveAs(kmzFile, `${fileName}.kmz`)
      return fileBlob
   }
  const waylinesContext = (templateJson) => {
    const waylinesObj = {
      // 标准模版
      missionConfig: {
        flyToWaylineMode: null,
        finishAction: null,
        exitOnRCLost: null,
        executeRCLostAction: null,
        takeOffSecurityHeight: null,
        globalTransitionalSpeed: null,
        globalRTHHeight: null,
        droneInfo: null,
        payloadInfo: null,
      },
      Folder: {
        templateId: null,
        executeHeightMode: null,
        waylineId: null,
        autoFlightSpeed: null,
        /*
   const waylinesContext = templateJson => {
      const waylinesObj = {
         // 标准模版
         missionConfig: {
            flyToWaylineMode: null,
            finishAction: null,
            exitOnRCLost: null,
            executeRCLostAction: null,
            takeOffSecurityHeight: null,
            globalTransitionalSpeed: null,
            globalRTHHeight: null,
            droneInfo: null,
            payloadInfo: null,
         },
         Folder: {
            templateId: null,
            executeHeightMode: null,
            waylineId: null,
            autoFlightSpeed: null,
            /*
          waylines.wpml和template.xml的Placemark通用
          不同点:
            waylineId = templateId
            ellipsoidHeight、 height 替换成 executeHeight
        */
        Placemark: null,
      },
    };
    Object.keys(waylinesObj).forEach((key) => {
      if (
        Object.prototype.toString.call(waylinesObj[key]) === '[object Object]'
      ) {
        Object.keys(waylinesObj[key]).forEach((item) => {
          waylinesObj[key][item] = templateJson[key][item];
          if (item === 'executeHeightMode') {
            waylinesObj[key][item] =
              templateJson[key].waylineCoordinateSysParam.heightMode;
          }
          if (item === 'waylineId') {
            waylinesObj[key][item] = templateJson[key].templateId;
          }
          if (item === 'Placemark') {
            const placemarks = _.cloneDeep(templateJson[key][item]);
            placemarks.forEach((placemark) => {
              placemark.executeHeight = {
                '#text': placemark.ellipsoidHeight?.['#text'] || '',
              };
              delete placemark.ellipsoidHeight;
              delete placemark.height;
            });
            waylinesObj[key][item] = placemarks;
          }
        });
      } else {
        waylinesObj[key] = templateJson[key];
      }
    });
    return waylinesObj;
  };
            Placemark: null,
         },
      }
      Object.keys(waylinesObj).forEach(key => {
         if (Object.prototype.toString.call(waylinesObj[key]) === '[object Object]') {
            Object.keys(waylinesObj[key]).forEach(item => {
               waylinesObj[key][item] = templateJson[key][item]
               if (item === 'executeHeightMode') {
                  waylinesObj[key][item] = templateJson[key].waylineCoordinateSysParam.heightMode
               }
               if (item === 'waylineId') {
                  waylinesObj[key][item] = templateJson[key].templateId
               }
               if (item === 'Placemark') {
                  const placemarks = _.cloneDeep(templateJson[key][item])
                  placemarks.forEach(placemark => {
                     placemark.executeHeight = {
                        '#text': placemark.ellipsoidHeight?.['#text'] || '',
                     }
                     delete placemark.ellipsoidHeight
                     delete placemark.height
                  })
                  waylinesObj[key][item] = placemarks
               }
            })
         } else {
            waylinesObj[key] = templateJson[key]
         }
      })
      return waylinesObj
   }
  return {
    create,
    createNoramlWaylines,
    createPlanarWayline,
    createPointWayLines,
    save,
  };
   return {
      create,
      createNoramlWaylines,
      createPlanarWayline,
      createPointWayLines,
      save,
   }
}