You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
15 KiB
Vue

<template>
<div>
<div class="map-out-container">
<div class="map-inner-container">
<Map
:workPlanFormShow="workPlanFormShow"
:editMode="editMode"
:airLineForm="airLineForm"
@exitDraw="exitDraw"
@flyToThere="flyToThere"
:wayline="wayline"
:waylineInfo="waylineInfo"
:templateKmlConfig="templateKmlConfig"
:waylineWpmlConfig="waylineWpmlConfig"
></Map>
</div>
</div>
<div style="position:absolute;top:20px;left:20px;z-index:1;display:flex;gap:15px;">
<!-- 工作计划列表 -->
<div v-if="planListShow" style="width:360px;height: calc( 100vh - 144px);flex:1;">
<planList ref="planListRef"
:planListShow="planListShow"
@planDetail="planDetail"
@createWorkPlan="toCreateWorkPlan"
></planList>
</div>
<!-- 创建计划 -->
<div v-if="workPlanFormShow" style="width:360px;height: calc( 100vh - 144px);flex:1;">
<createWorkPlan
:workPlanStatus="workPlanStatus"
:formData="formData"
@successCreatePlan="successCreatePlan"
@cancleCraete="cancleCraete"
@selectAircraft="selectAircraft"
@selectAriLine="selectAriLine"
:checkedAriLine="checkedAriLine"
:checkedDronePort="checkedDronePort"
@intelligentPatrol="changePatrolShow"
@startEditAirLine="startEditAirLine"
@loadResultImageList="loadResultImageList"
></createWorkPlan>
</div>
<!-- 智能巡检 -->
<div v-if="patrolShow" class="patrol-box">
<Patrol type="plan" @changePatrol="patrolShow = false"/>
</div>
<!-- 航线库 -->
<div v-if="ariLineShow" style="width:566px;height: calc( 100vh - 144px);flex:1;">
<airLineList :title="'选择航线'" @startEditAirLine="startEditAirLine" @checkAriLine="checkAriLine" @previewAirLine="previewAirLine" @createAirLine="handlerCreateAirLine" @closeAirLine="closeAirLine"></airLineList>
</div>
<!-- 设备 -->
<div v-if="aircraftShow" style="width:340px;height: calc( 100vh - 144px);flex:1;">
<aircraft @checkAriLine="checkDronePort" @closeAirCraft="closeAirCraft" ></aircraft>
</div>
</div>
<!-- 创建计划弹窗 -->
<!-- <div v-if="workPlanFormShow" style="width:380px;position:absolute;top:30px;left:30px;z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
<createWorkPlan :formData="formData" @successCreatePlan="successCreatePlan" @cancleCraete="cancleCraete" @selectAircraft="selectAircraft" @selectAriLine="selectAriLine" :checkedAriLine="checkedAriLine" :checkedDronePort="checkedDronePort"></createWorkPlan>
</div> -->
<!-- 航线库 -->
<!-- <div v-if="ariLineShow" style="width:566px;position:absolute;top:30px;left:440px;z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
<airLineList :title="'选择航线'" @checkAriLine="checkAriLine" @previewAirLine="previewAirLine" @createAirLine="handlerCreateAirLine"></airLineList>
</div> -->
<!-- 飞行器 -->
<!-- <div v-if="aircraftShow" style="width:340px;background:#0d0e15c1 ;position:absolute;top:30px;left:440px;z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
<aircraft @checkAriLine="checkDronePort" ></aircraft>
</div> -->
<!-- 新建航线 -->
<div v-if="createAirLineShow" style="width:566px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
<createAirLine @createAirLine="handlerCreateairLineForm" @cancle="cancleCreateAirLine"></createAirLine>
</div>
</div>
</template>
<script lang="ts" setup>
import {onMounted, ref,watch} from 'vue';
import planList from './components/planList.vue';
import airLineList from './components/airLineList.vue';
import aircraft from './components/aircraft.vue';
import createWorkPlan from './components/createWorkPlan.vue';
import createAirLine from './components/createAirLine.vue'
import Map from './components/map.vue'
import AirPolygon from './components/airPolygon.vue';
import Patrol from './components/Patrol.vue';
import {getAirLine,uploadXmlFile,addAirLine,editAirLine} from '@/api/sys/workplan';
import JSZip from 'jszip';
import axios from 'axios';
import { GeojsonToWkt, WktToGeojson } from '@/components/MapboxMaps/src/WktGeojsonTransform';
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
import { message } from 'ant-design-vue';
import { useRoute } from 'vue-router'
const router = useRoute()
const paramValue = router.query.taskid
// 导入航线计算类
import Mapping2d from './lib/generateMapping2d';
const formData = ref({
"id": null,
"taskName": "",
"taskType": 0,
"taskAirLineName": null,
"taskDronePortName": null,
"taskDronePort": null,
"taskAirLine": null,
"returnAltitude": 90,
"lossOfControlAction": 1,
"continuationMode": 0,
"aiInspection": null,
"status": 0,
"periodicFormula": null,
"airLineId": null,
"createId": 0,
"createTime": "",
"waylinePrecisionType": 0,
"scheduledStartTime": "",
"scheduledEndTime": "",
"executeTime": "",
"completedTime": "",
"planExecuteDuration": 0,
"actualExecuteDuration": 0,
"workspaceId": null,
"expectedFileCount": 0,
"uploadedFileCount": 0,
"flightId": null,
"reason": null,
"externalTaskId": ""
});
const airLineForm = ref({
"id": null,
"airLineName": null,
"airLineType": null,
"uavId": null,
"flyToFirstPointMode": null,
"safeTakeoffAltitude": 0,
"safeTakeoffSpeed": 0,
"globalRouteSpeed": 0,
"taskCompletionAction": null,
"outOfControlOption": null,
"typeOfOutOfControlAction": null,
"globalWayPointType": null,
"ptzControlMode": null,
"aircraftYawAngleMode": null,
"createTime": null,
"wpml": null,
"taskOffLng": 0,
"taskOffLat": 0,
"folder": null
});
const flyToTherePosition = ref({
lng:null,
lat:null,
alt:null,
})
const flyToThere = (e)=>{
}
const planListShow = ref(true);
const workPlanFormShow = ref(false);
const ariLineShow = ref(false);
const aircraftShow = ref(false);
const createAirLineShow = ref(false);
const importAirLineShow = ref(true);
const patrolShow = ref(false);
if(paramValue){
planListShow.value = false;
workPlanFormShow.value = true;
}
const selectAriLine = ()=> {
ariLineShow.value = true;
aircraftShow.value = false;
}
const changePatrolShow = ()=>{
patrolShow.value = true;
}
// 关闭航线库弹窗
const closeAirLine = ()=>{
ariLineShow.value = false;
}
// 关闭选择设备弹窗
const closeAirCraft = ()=>{
aircraftShow.value = false;
}
const selectAircraft = ()=>{
aircraftShow.value = true;
ariLineShow.value = false;
}
const cancleCraete = ()=>{
workPlanFormShow.value = false;
ariLineShow.value = false;
aircraftShow.value = false;
planListShow.value = true;
}
const checkedAriLine = ref({});
const checkAriLine = (item)=>{
if(item){
ariLineShow.value = false;
checkedAriLine.value = item;
}
}
const checkedDronePort = ref({});
const checkDronePort = (item)=>{
if(item){
aircraftShow.value = false;
checkedDronePort.value = item;
}
}
const toCreateWorkPlan = (data)=> {
formData.value = data;
workPlanFormShow.value = true;
if(data){
workPlanStatus.value = "edit"
}else{
workPlanStatus.value = "create"
}
}
const loadResultImageList = (imageLists) => {
console.log("loadResultImageList",imageLists)
}
// 创建航线
const handlerCreateAirLine = ()=>{
createAirLineShow.value = true;
}
const cancleCreateAirLine = ()=>{
createAirLineShow.value = false;
}
const handlerCreateairLineForm = (info)=>{
console.log("info",info);
workPlanFormShow.value = false;
ariLineShow.value = false;
aircraftShow.value = false;
planListShow.value = false;
createAirLineShow.value = false;
airLineForm.value = info
}
const planListRef = ref(null);
const successCreatePlan = ()=>{
workPlanFormShow.value = false;
ariLineShow.value = false;
aircraftShow.value = false;
planListShow.value = true;
planListRef.value.getTaskList();
}
// 保存航线后退出
const exitDraw = ()=>{
planListShow.value = false;
workPlanFormShow.value = true;
ariLineShow.value = true;
}
// 预览航线
const wayline = ref({});
const waylineInfo = ref(null)
const previewAirLine =async (line,type) => {
let info =await getAirLine({airLineId:type.value?.id});
if(info){
wayline.value = line;
waylineInfo.value = info;
}
}
// 航线模式 add edit detail
const editMode = ref("add");
// 航线template.kml
const templateKmlConfig = ref({})
// 航线wayline.wpml
const waylineWpmlConfig = ref({})
// 编辑航线
const startEditAirLine = (data,form,type) => {
// 航线文件template.kml配置信息
templateKmlConfig.value = data.template.kml.Document
// 航线wayline.wpml配置信息
waylineWpmlConfig.value = data.wayline.kml.Document;
// 航线表信息
waylineInfo.value = form;
// 航线表单
airLineForm.value = form;
// 设置模式为编辑模式
editMode.value = type;
}
const workPlanStatus = ref("");
// 查看航线详情
const planDetail =async (item) => {
formData.value = item;
let info =await getAirLine({airLineId : formData.value?.airLineId});
if(info){
waylineInfo.value = info;
wayline.value = await airLineDetail(info);
}
workPlanFormShow.value = true;
workPlanStatus.value = "detail"
}
// 获取wpml文件
const currentPreviewWayLine = ref(null);
const airLineDetail =async (item) => {
currentPreviewWayLine.value = item;
try{
let response = await axios.get(item.wpml,{responseType: 'arraybuffer'});
// 解压kmz文件
let xmlStr =await extractKmz(response.data);
let xmlData = xmlStr.replace(/wpml:/g,"");
const parser = new XMLParser();
const jsonObj = parser.parse(xmlData);
return jsonObj.kml.Document;
}catch(e){
console.error(e);
}
}
// 解压航线文件
const extractKmz = async (kmzBlob)=>{
const zip = new JSZip();
const contents = await zip.loadAsync(kmzBlob);
// 查找.wmpl文件
for (const [filename, file] of Object.entries(contents.files)) {
if (filename.toLowerCase().endsWith('.wpml')) {
return await file.async('text');
}
}
throw new Error('KMZ文件中未找到WMPL文件');
}
// 加载默认航线文件
const loadDefaultAirlineParams = async (info) => {
// 获取范围坐标并处理
let coordinatesString = "";
if(info.geometry){
let geojson = WktToGeojson(info.geometry)
geojson.coordinates[0].pop();
let coordinatesArray = geojson.coordinates[0];
coordinatesArray?.forEach((item,index)=>{
if(index != coordinatesArray.length-1){
coordinatesString += item.join(",")+",70"+"\n"
}else{
coordinatesString += item.join(",")+",70"
}
})
}else{
message.warning("处理图斑数据失败!");
return null;
}
const {templateKml,waylineWpml} = await import("./waylineConfig/autoPlanMapping2dConfig.ts");
templateKmlConfig.value = templateKml;
templateKmlConfig.value.Folder.Placemark.Polygon.outerBoundaryIs.LinearRing.coordinates = coordinatesString;
waylineWpmlConfig.value = waylineWpml;
let mapping2d = new Mapping2d(templateKmlConfig.value,waylineWpmlConfig.value);
let blob = mapping2d.generateAirLine();
blob.then((blobData)=>{
workPlanStatus.value = "create"
let airLineForm = {
"id": null,
"airLineName": info.nember+"地块规划航线",
"airLineType": "mapping2d",
"uavId": null,
"flyToFirstPointMode": null,
"safeTakeoffAltitude": 0,
"safeTakeoffSpeed": 0,
"globalRouteSpeed": 0,
"taskCompletionAction": null,
"outOfControlOption": null,
"typeOfOutOfControlAction": null,
"globalWayPointType": null,
"ptzControlMode": null,
"aircraftYawAngleMode": null,
"createTime": null,
"wpml": null,
"taskOffLng": 0,
"taskOffLat": 0,
"folder": ""
}
// 创建FormData对象用于上传
const fileFormData = new FormData();
fileFormData.append('xmlFile', blobData,"面状航线.kmz");
let res = uploadXmlFile(airLineForm.folder,fileFormData);
res.then(fileRes=>{
if(fileRes){
airLineForm.wpml = fileRes.path;
let addAirLineResult = addAirLine(airLineForm);
addAirLineResult.then(addAirLineRes=>{
formData.value.taskName = info.nember+"地块飞行任务"
formData.value.externalTaskId = info.taskid
formData.value.airLineId = addAirLineRes.id
formData.value.airLineId = addAirLineRes;
formData.value.taskAirLineName = info.nember+"地块规划航线"
})
}
})
})
}
onMounted(()=>{
let element = window.document.getElementsByClassName("mars3d-locationbar")[0] as HTMLElement;
element.style.bottom = '40px';
// 如果有任务id等信息
if(router.query.taskid){
let autoPlanAirLienInfo = {
taskid:router.query.taskid,
nember:router.query.nember,
geometry:router.query.geometry,
}
// editMode.value = "autoAdd";
loadDefaultAirlineParams(autoPlanAirLienInfo);
}
})
</script>
<style scoped>
.map-out-container{
width: 100%;
height: calc( 100vh - 80px);
overflow: hidden;
}
.map-inner-container{
width: calc( 100% + 80px);
height: calc( 100% + 80px);
position: relative;
top:-40px;
left:-40px;
}
.patrol-box{
width:360px;
height: calc( 100vh - 144px);
flex:1;
position: relative;
}
.patrol-box ::v-deep .airport-information{
right: 0;
left: 0;
top: 200px;
}
</style>