Compare commits
2 Commits
19cb5395db
...
9f28e09454
| Author | SHA1 | Date |
|---|---|---|
|
|
9f28e09454 | |
|
|
cd0f957d5c |
|
|
@ -118,6 +118,7 @@
|
|||
"mapbox-gl-utils": "^0.44.0",
|
||||
"mars3d": "^3.7.0",
|
||||
"mars3d-cesium": "^1.113.0",
|
||||
"mars3d-space": "^3.7.0",
|
||||
"min-dash": "^4.2.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"mqtt": "^5.13.1",
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 723 B |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
|
|
@ -0,0 +1,36 @@
|
|||
import { defHttp } from '@/utils/http/axios';
|
||||
|
||||
enum Api{
|
||||
GetTaskPageList = '/api/Manage/GetTaskPageList',
|
||||
AddTask = '/api/Manage/AddTask',
|
||||
EditTask = '/api/Manage/EditTask',
|
||||
DeleteTask = '/api/Manage/DeleteTask',
|
||||
GetUavPageList = '/api/Manage/GetUavPageList',
|
||||
GetAirLineList = '/api/Manage/GetAirLineList'
|
||||
}
|
||||
|
||||
export function getTaskPageList(params) {
|
||||
return defHttp.get({ url: Api.GetTaskPageList, params });
|
||||
}
|
||||
|
||||
export function addTask(params){
|
||||
return defHttp.post({ url: Api.AddTask, params });
|
||||
}
|
||||
|
||||
export function editTask(params){
|
||||
return defHttp.post({ url: Api.EditTask, params });
|
||||
}
|
||||
|
||||
export function deleteTask(params){
|
||||
return defHttp.post({ url: Api.DeleteTask+"?id="+params.id, params });
|
||||
}
|
||||
|
||||
export function getUavPageList(params) {
|
||||
return defHttp.get({ url: Api.GetUavPageList, params });
|
||||
}
|
||||
|
||||
|
||||
export function getAirLineList(params) {
|
||||
return defHttp.get({ url: Api.GetAirLineList, params });
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
<div class="search-container">
|
||||
<a-input-search
|
||||
v-model:value="pageQuery.key"
|
||||
placeholder="输入路线名称"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -72,13 +73,13 @@
|
|||
<div>
|
||||
<ImportOutlined />
|
||||
|
||||
<PlusOutlined />
|
||||
<PlusOutlined @click="createAirLine" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ari-line" v-for="(item,index) in ariLineList" :key="index" @click="checkAriLine(item)">
|
||||
<div class="title">
|
||||
<div style="flex:1;">
|
||||
{{item.name}}
|
||||
{{item.airLineName}}
|
||||
</div>
|
||||
<div style="">
|
||||
<EditOutlined />
|
||||
|
|
@ -88,9 +89,9 @@
|
|||
</div>
|
||||
<div class="type" >
|
||||
<img src="/public/iocn/uav.png" alt="">
|
||||
{{item.uav}}
|
||||
{{item.uavId}}
|
||||
</div>
|
||||
<div class="time">更新时间:{{item.updateTime}}</div>
|
||||
<div class="time">更新时间:{{item.createTime}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -99,28 +100,33 @@
|
|||
<script lang="ts" setup>
|
||||
import { PlusOutlined,FileAddOutlined,LeftOutlined,ImportOutlined,MoreOutlined,EditOutlined } from '@ant-design/icons-vue';
|
||||
import {ref,defineEmits} from 'vue'
|
||||
|
||||
import { getAirLineList } from '@/api/sys/workplan';
|
||||
|
||||
const emit = defineEmits(["checkAriLine"])
|
||||
const emit = defineEmits(["checkAriLine","createAirLine"])
|
||||
|
||||
const createAirLine = () => {
|
||||
emit("createAirLine");
|
||||
}
|
||||
const checkAriLine = (item)=> {
|
||||
emit("checkAriLine",item);
|
||||
}
|
||||
|
||||
const expandedKeys = ref<string[]>(['0-0', '0-1']);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const treeData = ref(
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const treeData = ref(
|
||||
[
|
||||
{
|
||||
title: '默认文件夹',
|
||||
key: '1',
|
||||
children: [
|
||||
{
|
||||
title: '文件夹1',
|
||||
title: '面状航线',
|
||||
key: '2',
|
||||
isLeaf: true,
|
||||
},
|
||||
{
|
||||
title: '文件夹2',
|
||||
title: '航点航线',
|
||||
key: '3',
|
||||
isLeaf: true,
|
||||
},
|
||||
|
|
@ -129,29 +135,24 @@ const treeData = ref(
|
|||
]
|
||||
)
|
||||
|
||||
const ariLineList = ref([
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
}
|
||||
|
||||
])
|
||||
const ariLineList = ref([])
|
||||
|
||||
const pageQuery = ref({
|
||||
page:1,
|
||||
limit:10,
|
||||
key:null,
|
||||
})
|
||||
|
||||
const getAirList = async ()=>{
|
||||
|
||||
let res = await getAirLineList(pageQuery.value);
|
||||
|
||||
ariLineList.value = res.items;
|
||||
|
||||
}
|
||||
|
||||
getAirList();
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.container{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,315 @@
|
|||
<template>
|
||||
<div class="containner">
|
||||
<div class="title">
|
||||
<LeftOutlined />
|
||||
<div>航点航线</div>
|
||||
<SaveOutlined/>
|
||||
|
||||
<div style="flex:1;">
|
||||
<a-input size="middle" placeholder="航线名称" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="area-info">
|
||||
<div class="item">
|
||||
<div>航点数量</div>
|
||||
<div>1</div>
|
||||
</div>
|
||||
<div class="bar"></div>
|
||||
<div class="item">
|
||||
<div>航线长度</div>
|
||||
<div>{{props.airInfo.length}} km</div>
|
||||
</div>
|
||||
<div class="bar"></div>
|
||||
<div class="item">
|
||||
<div>预计用时</div>
|
||||
<div>{{props.airInfo.time}} mins</div>
|
||||
</div>
|
||||
<div class="bar"></div>
|
||||
<div class="item">
|
||||
<div>照片数量</div>
|
||||
<div>{{props.airInfo.picture}} </div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="air-point-list">
|
||||
|
||||
<div class="air-point-item">
|
||||
<!-- <div class="cel">经度</div>
|
||||
<div class="cel">纬度</div> -->
|
||||
<div class="cel">航点</div>
|
||||
<div class="cel">高度</div>
|
||||
<div class="cel">偏航角</div>
|
||||
<div class="cel">水平角</div>
|
||||
<div class="cel">俯仰角</div>
|
||||
<div class="cel">照片</div>
|
||||
</div>
|
||||
|
||||
<div class="air-point-item" v-for="(item,index) in props.airPoints" :key="index">
|
||||
<!-- <div class="cel">{{item.lng}}</div>
|
||||
<div class="cel">{{item.lat}}</div> -->
|
||||
<div class="cel">
|
||||
<img src="/map/air-point.png" width="18" alt="">
|
||||
{{index+1}}
|
||||
</div>
|
||||
<div class="cel">{{item.alt}}</div>
|
||||
<div class="cel">{{item.aircraftHorizontalAngle}}</div>
|
||||
<div class="cel">{{item.cameraHorizontalAngle}}</div>
|
||||
<div class="cel">{{item.cameraVerticalAngle}}</div>
|
||||
<div class="cel">{{item.focalLength}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="area-options" v-if="false">
|
||||
<div class="item">
|
||||
<div class="label">参考起飞点</div>
|
||||
<div class="content">
|
||||
<a-button type="link" style="color:#408eff" @click="setFlyPoint()">
|
||||
<img src="./start-fly.png" style="width:24px;height:24px;position:relative;left:-2px;top:-2px;" alt="">
|
||||
设置起飞点
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item flex-column">
|
||||
<div class="label">选择镜头</div>
|
||||
<div class="content">
|
||||
<a-radio-group button-style="solid" v-model:value="props.polygonAirForm.lensMode">
|
||||
<a-radio-button :value="1">红外</a-radio-button>
|
||||
<a-radio-button :value="2">可见光</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item flex-column">
|
||||
<div class="label">采集方式</div>
|
||||
<div class="content">
|
||||
<a-radio-group button-style="solid" v-model:value="props.polygonAirForm.gatherMode">
|
||||
<a-radio-button :value="1">正射采集</a-radio-button>
|
||||
<a-radio-button :value="2">倾斜采集</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label">智能摆动拍摄</div>
|
||||
</div>
|
||||
<div class="item flex-column">
|
||||
<div class="label">航线高度模式</div>
|
||||
<div class="content">
|
||||
<a-radio-group button-style="solid" v-model:value="props.polygonAirForm.heightMode">
|
||||
<a-radio-button :value="1">海拔高度</a-radio-button>
|
||||
<a-radio-button :value="2">相对起点高度</a-radio-button>
|
||||
<a-radio-button :value="3">相对地形高度</a-radio-button>
|
||||
</a-radio-group>
|
||||
|
||||
<div style="margin-top:12px;">
|
||||
<a-input-number v-model:value="props.polygonAirForm.height" :min="1" :max="100000" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label">全局航线速度</div>
|
||||
<div class="content">
|
||||
<a-input-number style="width:160px" v-model:value="props.polygonAirForm.speed" :min="1" :max="20" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 主航线角度</div>
|
||||
<div class="content">
|
||||
<a-input-number width="160px" v-model:value="props.polygonAirForm.angle" :min="0" :max="180" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 高程优化</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 完成动作</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<a-select
|
||||
ref="select"
|
||||
style="width:160px;"
|
||||
v-model:value="props.polygonAirForm.complete"
|
||||
>
|
||||
<a-select-option :value="1">自动返航</a-select-option>
|
||||
<a-select-option :value="2">返回航线起始点悬停</a-select-option>
|
||||
<a-select-option :value="3">退出航线模式</a-select-option>
|
||||
<a-select-option :value="4">原地降落</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {ref,defineEmits,defineProps} from 'vue'
|
||||
import { SaveOutlined,LeftOutlined } from '@ant-design/icons-vue';
|
||||
const emits = defineEmits(["setFlyPoint"])
|
||||
|
||||
const props = defineProps(["airPoints","airInfo","polygonAirForm"])
|
||||
|
||||
const airInfo = ref({
|
||||
area:0.0,
|
||||
length:0.0,
|
||||
time:'4m 11s',
|
||||
picture:23
|
||||
})
|
||||
|
||||
const setFlyPoint = ()=>{
|
||||
emits("setFlyPoint");
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.container{
|
||||
width:100%;
|
||||
height:100%;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.title{
|
||||
padding:20px;
|
||||
font-size:16px;
|
||||
color:#ffffff;
|
||||
display:flex;
|
||||
gap:12px;
|
||||
line-height:24px;
|
||||
}
|
||||
|
||||
.area-info{
|
||||
width:100%;
|
||||
border-top:1px solid rgba(255,255,255,0.2);
|
||||
border-bottom:1px solid rgba(255,255,255,0.2);
|
||||
display:flex;
|
||||
padding:20px 0px;
|
||||
}
|
||||
.area-info .item{
|
||||
flex:1;
|
||||
color:#fff;
|
||||
text-align: center;
|
||||
display:flex;
|
||||
gap:12px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.area-options{
|
||||
width:100%;
|
||||
height: calc( 100vh - 260px);
|
||||
padding:10px;
|
||||
overflow-y:auto;
|
||||
line-height:32px;
|
||||
}
|
||||
|
||||
.area-options .item{
|
||||
padding:10px;
|
||||
margin:15px 0px;
|
||||
background:#232323;
|
||||
color:#fff;
|
||||
display:flex;
|
||||
}
|
||||
.area-options .item .label{
|
||||
flex:1;
|
||||
}
|
||||
.area-options .item .content{
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.flex-column{
|
||||
flex-direction: column;
|
||||
gap:10px;
|
||||
}
|
||||
|
||||
.air-point-list{
|
||||
width:100%;
|
||||
height: calc( 100vh - 260px);
|
||||
padding:10px;
|
||||
overflow-y:auto;
|
||||
line-height:32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.air-point-item{
|
||||
display:flex;
|
||||
gap:15px;
|
||||
border-bottom:1px solid rgba(255,255,255,0.2);
|
||||
padding:6px 0px;
|
||||
}
|
||||
.air-point-item .cel{
|
||||
flex:1;
|
||||
color:#fff;
|
||||
}
|
||||
::v-deep .ant-radio-group {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
::v-deep .ant-select-selector{
|
||||
border:none!important;
|
||||
color:#fff!important;
|
||||
background:#3F4150!important ;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-select-selection-placeholder {
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
::v-deep .ant-select-arrow {
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
::v-deep .ant-select-selection-search-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.933)!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-tree {
|
||||
background:none!important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected{
|
||||
background:#3a57e877!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected::before{
|
||||
background:none!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected::after{
|
||||
content:"";
|
||||
height:28px;
|
||||
width:4px;
|
||||
background:#3A57E8;
|
||||
position:absolute;
|
||||
top:0px;
|
||||
left:0px;
|
||||
}
|
||||
|
||||
::v-deep .ant-input{
|
||||
background:#3c3c3c!important ;
|
||||
border:none!important;
|
||||
border-top-left-radius: 3px !important;
|
||||
border-bottom-left-radius: 3px !important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-btn-default{
|
||||
background:none!important;
|
||||
border:none!important;
|
||||
outline:none!important;
|
||||
color:#fff!important;
|
||||
height:30px !important;
|
||||
background:#3F4150!important ;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
航点经度
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-input-number
|
||||
v-model:value="config.lng"
|
||||
:min="-180"
|
||||
:max="180"
|
||||
:step="0.00000001"
|
||||
string-mode
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
航点纬度
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-input-number
|
||||
v-model:value="config.lat"
|
||||
:min="-90"
|
||||
:max="90"
|
||||
:step="0.00000001"
|
||||
string-mode
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
航点高度
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-input-number
|
||||
v-model:value="config.alt"
|
||||
:min="0"
|
||||
:step="0.01"
|
||||
string-mode
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
<div class="label">
|
||||
飞行器偏航角
|
||||
</div>
|
||||
<div>
|
||||
{{ config.aircraftHorizontalAngle }} °
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-slider v-model:value="config.aircraftHorizontalAngle" :min="-180" :max="180" :step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
<div class="label">
|
||||
云台偏航角
|
||||
</div>
|
||||
<div>
|
||||
{{ config.cameraHorizontalAngle }} °
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-slider v-model:value="config.cameraHorizontalAngle" :min="-180" :max="180" :step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
<div class="label">
|
||||
云台俯仰角
|
||||
</div>
|
||||
<div class="">
|
||||
{{ config.cameraVerticalAngle }} °
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-slider v-model:value="config.cameraVerticalAngle" :min="-180" :max="180" :step="0.01" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<div class="item-title">
|
||||
<div class="label">
|
||||
相机焦距
|
||||
</div>
|
||||
<div class="">
|
||||
× {{ config.cameraFocalLength }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-content">
|
||||
<a-slider v-model:value="config.cameraFocalLength" :min="1" :max="56" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {ref} from 'vue';
|
||||
|
||||
const config = ref({
|
||||
id:"1",
|
||||
name:"航点",
|
||||
lng:118.023154,
|
||||
lat:35.21458,
|
||||
alt:167.23,
|
||||
aircraftHorizontalAngle:0,
|
||||
cameraHorizontalAngle:0,
|
||||
cameraVerticalAngle:0,
|
||||
cameraFocalLength:2,
|
||||
focalLength:2
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container{
|
||||
width:100%;
|
||||
height:100%;
|
||||
padding:15px;
|
||||
color:#fff;
|
||||
overflow-y:auto;
|
||||
}
|
||||
|
||||
.config-item {
|
||||
color:#fff;
|
||||
background:#232323;
|
||||
padding:15px 10px;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
.config-item .item-content{
|
||||
margin-top:12px;
|
||||
}
|
||||
.config-item .item-title{
|
||||
display:flex;
|
||||
}
|
||||
.config-item .item-title .label{
|
||||
flex:1;
|
||||
}
|
||||
::v-deep .ant-slider .ant-slider-rail{
|
||||
background:#fff!important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
<template>
|
||||
<div class="containner">
|
||||
<div class="title">
|
||||
<LeftOutlined />
|
||||
<div>面状航线</div>
|
||||
<SaveOutlined/>
|
||||
|
||||
<div style="flex:1;">
|
||||
<a-input size="small" placeholder="航线名称" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="area-info">
|
||||
<div class="item">
|
||||
<div>测区面积</div>
|
||||
<div>{{props.airInfo.area}} m²</div>
|
||||
</div>
|
||||
<div class="bar"></div>
|
||||
<div class="item">
|
||||
<div>航线长度</div>
|
||||
<div>{{props.airInfo.length}} km</div>
|
||||
</div>
|
||||
<div class="bar"></div>
|
||||
<div class="item">
|
||||
<div>预计用时</div>
|
||||
<div>{{props.airInfo.time}} mins</div>
|
||||
</div>
|
||||
<div class="bar"></div>
|
||||
<div class="item">
|
||||
<div>照片数量</div>
|
||||
<div>{{props.airInfo.picture}} </div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="area-options">
|
||||
<div class="item">
|
||||
<div class="label">参考起飞点</div>
|
||||
<div class="content">
|
||||
<a-button type="link" style="color:#408eff" @click="setFlyPoint()">
|
||||
<img src="./start-fly.png" style="width:24px;height:24px;position:relative;left:-2px;top:-2px;" alt="">
|
||||
设置起飞点
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item flex-column">
|
||||
<div class="label">选择镜头</div>
|
||||
<div class="content">
|
||||
<a-radio-group button-style="solid" v-model:value="props.polygonAirForm.lensMode">
|
||||
<a-radio-button :value="1">红外</a-radio-button>
|
||||
<a-radio-button :value="2">可见光</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item flex-column">
|
||||
<div class="label">采集方式</div>
|
||||
<div class="content">
|
||||
<a-radio-group button-style="solid" v-model:value="props.polygonAirForm.gatherMode">
|
||||
<a-radio-button :value="1">正射采集</a-radio-button>
|
||||
<a-radio-button :value="2">倾斜采集</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label">智能摆动拍摄</div>
|
||||
</div>
|
||||
<div class="item flex-column">
|
||||
<div class="label">航线高度模式</div>
|
||||
<div class="content">
|
||||
<a-radio-group button-style="solid" v-model:value="props.polygonAirForm.heightMode">
|
||||
<a-radio-button :value="1">海拔高度</a-radio-button>
|
||||
<a-radio-button :value="2">相对起点高度</a-radio-button>
|
||||
<a-radio-button :value="3">相对地形高度</a-radio-button>
|
||||
</a-radio-group>
|
||||
|
||||
<div style="margin-top:12px;">
|
||||
<a-input-number v-model:value="props.polygonAirForm.height" :min="1" :max="100000" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label">全局航线速度</div>
|
||||
<div class="content">
|
||||
<a-input-number style="width:160px" v-model:value="props.polygonAirForm.speed" :min="1" :max="20" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 主航线角度</div>
|
||||
<div class="content">
|
||||
<a-input-number width="160px" v-model:value="props.polygonAirForm.angle" :min="0" :max="180" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 高程优化</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label"> 完成动作</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<a-select
|
||||
ref="select"
|
||||
style="width:160px;"
|
||||
v-model:value="props.polygonAirForm.complete"
|
||||
>
|
||||
<a-select-option :value="1">自动返航</a-select-option>
|
||||
<a-select-option :value="2">返回航线起始点悬停</a-select-option>
|
||||
<a-select-option :value="3">退出航线模式</a-select-option>
|
||||
<a-select-option :value="4">原地降落</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {ref,defineEmits,defineProps} from 'vue'
|
||||
import { SaveOutlined,LeftOutlined } from '@ant-design/icons-vue';
|
||||
const emits = defineEmits(["setFlyPoint"])
|
||||
|
||||
const props = defineProps(["airInfo","polygonAirForm"])
|
||||
|
||||
const airInfo = ref({
|
||||
area:0.0,
|
||||
length:0.0,
|
||||
time:'4m 11s',
|
||||
picture:23
|
||||
})
|
||||
|
||||
const setFlyPoint = ()=>{
|
||||
emits("setFlyPoint");
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.container{
|
||||
width:100%;
|
||||
height:100%;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.title{
|
||||
padding:20px;
|
||||
font-size:16px;
|
||||
color:#ffffff;
|
||||
display:flex;
|
||||
gap:12px;
|
||||
line-height:24px;
|
||||
}
|
||||
|
||||
.area-info{
|
||||
width:100%;
|
||||
border-top:1px solid rgba(255,255,255,0.2);
|
||||
border-bottom:1px solid rgba(255,255,255,0.2);
|
||||
display:flex;
|
||||
padding:20px 0px;
|
||||
}
|
||||
.area-info .item{
|
||||
flex:1;
|
||||
color:#fff;
|
||||
text-align: center;
|
||||
display:flex;
|
||||
gap:12px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.area-options{
|
||||
width:100%;
|
||||
height: calc( 100vh - 260px);
|
||||
padding:10px;
|
||||
overflow-y:auto;
|
||||
line-height:32px;
|
||||
}
|
||||
|
||||
.area-options .item{
|
||||
padding:10px;
|
||||
margin:15px 0px;
|
||||
background:#232323;
|
||||
color:#fff;
|
||||
display:flex;
|
||||
}
|
||||
.area-options .item .label{
|
||||
flex:1;
|
||||
}
|
||||
.area-options .item .content{
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.flex-column{
|
||||
flex-direction: column;
|
||||
gap:10px;
|
||||
}
|
||||
|
||||
::v-deep .ant-radio-group {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
::v-deep .ant-select-selector{
|
||||
border:none!important;
|
||||
color:#fff!important;
|
||||
background:#3F4150!important ;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-select-selection-placeholder {
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
::v-deep .ant-select-arrow {
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
::v-deep .ant-select-selection-search-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.933)!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-tree {
|
||||
background:none!important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected{
|
||||
background:#3a57e877!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected::before{
|
||||
background:none!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected::after{
|
||||
content:"";
|
||||
height:28px;
|
||||
width:4px;
|
||||
background:#3A57E8;
|
||||
position:absolute;
|
||||
top:0px;
|
||||
left:0px;
|
||||
}
|
||||
|
||||
::v-deep .ant-input{
|
||||
background:#3c3c3c!important ;
|
||||
border:none!important;
|
||||
border-top-left-radius: 3px !important;
|
||||
border-bottom-left-radius: 3px !important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-btn-default{
|
||||
background:none!important;
|
||||
border:none!important;
|
||||
outline:none!important;
|
||||
color:#fff!important;
|
||||
height:30px !important;
|
||||
background:#3F4150!important ;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,10 +4,6 @@
|
|||
<div style="flex:1;">
|
||||
<LeftOutlined @click="checkAriLine(null);"/> 选择飞行器
|
||||
</div>
|
||||
<div>
|
||||
<PlusOutlined @click="createWorkPlan" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="filter-container">
|
||||
<div>
|
||||
|
|
@ -26,6 +22,8 @@
|
|||
|
||||
<div class="filter-buttons">
|
||||
<a-input-search
|
||||
v-model:value="pageQuery.key"
|
||||
@keyup.enter="getList()"
|
||||
placeholder="输入飞行器名称"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -36,82 +34,43 @@
|
|||
|
||||
<div class="routers-list">
|
||||
<div class="ari-line" v-for="(item,index) in ariLineList" :key="index" @click="checkAriLine(item)">
|
||||
<div class="title">
|
||||
<div style="flex:1;">
|
||||
{{item.name}}
|
||||
</div>
|
||||
<div style="">
|
||||
<EditOutlined />
|
||||
|
||||
<MoreOutlined />
|
||||
</div>
|
||||
</div>
|
||||
<div class="type" >
|
||||
<img src="/public/iocn/uav.png" alt="">
|
||||
{{item.uav}}
|
||||
{{item.name}}
|
||||
</div>
|
||||
<div class="time">更新时间:{{item.updateTime}}</div>
|
||||
<div class="time">无人机型号:{{item.firmwareVersion}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { PlusOutlined,FileAddOutlined,LeftOutlined,ImportOutlined,MoreOutlined,EditOutlined } from '@ant-design/icons-vue';
|
||||
import {ref,defineEmits} from 'vue'
|
||||
|
||||
import { getUavPageList } from '@/api/sys/workplan';
|
||||
|
||||
const emit = defineEmits(["checkAriLine"])
|
||||
|
||||
const checkAriLine = (item)=> {
|
||||
emit("checkAriLine",item);
|
||||
}
|
||||
|
||||
const expandedKeys = ref<string[]>(['0-0', '0-1']);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const treeData = ref(
|
||||
[
|
||||
{
|
||||
title: '默认文件夹',
|
||||
key: '1',
|
||||
children: [
|
||||
{
|
||||
title: '文件夹1',
|
||||
key: '2',
|
||||
isLeaf: true,
|
||||
},
|
||||
{
|
||||
title: '文件夹2',
|
||||
key: '3',
|
||||
isLeaf: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
)
|
||||
const ariLineList = ref([])
|
||||
|
||||
const pageQuery = ref({
|
||||
page:1,
|
||||
limit:10,
|
||||
key:null,
|
||||
})
|
||||
|
||||
const getList = async ()=>{
|
||||
let res = await getUavPageList(pageQuery.value);
|
||||
ariLineList.value = res.items;
|
||||
}
|
||||
|
||||
getList();
|
||||
|
||||
const ariLineList = ref([
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"航线1",
|
||||
uav:"Matrice 3TD",
|
||||
updateTime:"2025-06-03 17:01:47"
|
||||
}
|
||||
|
||||
])
|
||||
</script>
|
||||
<style scoped>
|
||||
.title{
|
||||
|
|
@ -285,4 +244,17 @@ const treeData = ref(
|
|||
height:30px !important;
|
||||
background:#3F4150!important ;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-input{
|
||||
background:#3c3c3c!important ;
|
||||
border:none!important;
|
||||
border-top-left-radius: 3px !important;
|
||||
border-bottom-left-radius: 3px !important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="title">
|
||||
<div style="flex:1;">
|
||||
<LeftOutlined @click="checkAriLine(null);"/> 新建航线
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="item-label">航线类型</div>
|
||||
|
||||
<div class="draw-type">
|
||||
<div v-for="(item,index) in airLineType"
|
||||
:class="item.checked ? 'air-line-type-active':'air-line-type'"
|
||||
@click="checkType('airLine',index)"
|
||||
>
|
||||
<div v-html="item.icon"></div>
|
||||
<div>{{item.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-label">选择飞行器</div>
|
||||
|
||||
<div class="draw-type">
|
||||
<div class="air-line-type" v-for="(item,index) in airType"
|
||||
:class="item.checked ? 'air-line-type-active':'air-line-type'"
|
||||
@click="checkType('airType',index)"
|
||||
>
|
||||
<div>{{item.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-label">选择型号</div>
|
||||
|
||||
<div class="draw-type">
|
||||
<div class="air-line-type" v-for="(item,index) in airModel"
|
||||
:class="item.checked ? 'air-line-type-active':'air-line-type'"
|
||||
@click="checkType('airModel',index)"
|
||||
>
|
||||
<div>{{item.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-label">航线名称</div>
|
||||
<a-input v-model:value="airLineInfo.name" placeholder="航线名称" />
|
||||
|
||||
<div class="item-label"></div>
|
||||
<div class="operate-button">
|
||||
|
||||
<a-button style="width:44%;" @click="cancle">取消</a-button>
|
||||
<a-button style="margin-left: 10px;width:54%;" type="primary" @click="createAirLine">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { PlusOutlined,FileAddOutlined,LeftOutlined,ImportOutlined,MoreOutlined,EditOutlined } from '@ant-design/icons-vue';
|
||||
import {ref,defineEmits} from 'vue'
|
||||
|
||||
const emit = defineEmits(["checkAriLine","cancle","createAirLine"])
|
||||
|
||||
const checkAriLine = (item)=> {
|
||||
emit("checkAriLine",item);
|
||||
}
|
||||
|
||||
const cancle = () => {
|
||||
emit("cancle");
|
||||
}
|
||||
|
||||
const airLineInfo = ref({
|
||||
airLineType:null,
|
||||
airType:null,
|
||||
airModel:null,
|
||||
name:null,
|
||||
})
|
||||
|
||||
const createAirLine = () => {
|
||||
getCheckedData();
|
||||
emit("createAirLine",airLineInfo.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const airLineType = ref([
|
||||
{
|
||||
name:"航点航线",
|
||||
checked:false,
|
||||
icon:'<svg t="1749104723424" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7226" width="40" height="40"><path d="M784 454.4c-28.8 0-54.4 12.8-70.4 35.2L326.4 352l188.8-134.4c12.8 6.4 25.6 12.8 41.6 12.8 48 0 86.4-38.4 86.4-86.4S608 64 560 64s-86.4 38.4-86.4 86.4c0 9.6 3.2 16 3.2 25.6l-179.2 128c-12.8-19.2-35.2-28.8-57.6-28.8-48 0-86.4 38.4-86.4 86.4S192 448 240 448c25.6 0 51.2-12.8 67.2-32l352 124.8L320 608c-12.8-32-41.6-57.6-80-57.6-48 0-86.4 38.4-86.4 86.4s38.4 86.4 86.4 86.4c35.2 0 64-19.2 76.8-51.2l396.8-83.2c16 22.4 41.6 38.4 70.4 38.4 48 0 86.4-38.4 86.4-86.4 0-48-38.4-86.4-86.4-86.4z m-224-342.4c19.2 0 35.2 16 35.2 35.2s-16 35.2-35.2 35.2c-19.2 0-35.2-16-35.2-35.2s16-35.2 35.2-35.2z m-320 284.8c-19.2 0-35.2-16-35.2-35.2s16-35.2 35.2-35.2 35.2 16 35.2 35.2-16 35.2-35.2 35.2z m0 275.2c-19.2 0-35.2-16-35.2-35.2s16-35.2 35.2-35.2 35.2 16 35.2 35.2S259.2 672 240 672z m544-92.8c-19.2 0-35.2-16-35.2-35.2 0-19.2 16-35.2 35.2-35.2 19.2 0 35.2 16 35.2 35.2 0 16-16 35.2-35.2 35.2z m-246.4 182.4l-150.4-51.2c-35.2-12.8-67.2 22.4-57.6 57.6l51.2 150.4c12.8 38.4 67.2 41.6 83.2 3.2l25.6-54.4 54.4-25.6c35.2-16 35.2-67.2-6.4-80z m-76.8 57.6c-9.6 3.2-19.2 12.8-22.4 22.4l-12.8 32-35.2-102.4 102.4 35.2-32 12.8z" p-id="7227" fill="#ffffff"></path></svg>',
|
||||
},{
|
||||
name:"面状航线",
|
||||
checked:false,
|
||||
icon:'<svg t="1749104746320" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7498" width="40" height="40"><path d="M918.485333 261.930667L857.813333 208.64a20.992 20.992 0 0 0-27.008 0L770.133333 261.973333a15.36 15.36 0 0 0 0 23.68 20.48 20.48 0 0 0 13.482667 4.906667 20.48 20.48 0 0 0 13.525333-4.906667l15.36-13.482666v141.994666c0 15.402667 14.250667 27.904 31.786667 27.904 17.578667 0 31.829333-12.501333 31.829333-27.904V272.128l15.36 13.482667a20.48 20.48 0 0 0 13.482667 4.906666 20.48 20.48 0 0 0 13.525333-4.906666 15.36 15.36 0 0 0 0-23.68z m-277.461333 159.146666c0 15.445333 14.250667 27.946667 31.829333 27.946667s31.829333-12.501333 31.829334-27.946667V346.325333c0-31.786667-11.349333-61.952-31.914667-84.906666a115.328 115.328 0 0 0-85.632-38.698667c-32.426667 0-63.573333 14.08-85.632 38.698667a126.848 126.848 0 0 0-31.914667 84.906666v335.530667c0 36.693333-24.704 67.754667-53.888 67.754667-29.226667 0-53.930667-31.061333-53.930666-67.754667V355.498667l0.469333-7.68 0.042667-1.493334c0-31.786667-11.306667-61.952-31.914667-84.906666a115.328 115.328 0 0 0-85.632-38.698667c-32.384 0-63.573333 14.08-85.632 38.698667a126.848 126.848 0 0 0-31.914667 84.906666v138.496c0 15.402667 14.250667 27.904 31.829334 27.904s31.829333-12.501333 31.829333-27.904V346.325333c0-36.693333 24.704-67.754667 53.888-67.754666 29.013333 0 53.589333 30.634667 53.930667 67.072l-0.512 8.405333v327.808c0 31.786667 11.306667 61.952 31.914666 84.906667a115.328 115.328 0 0 0 85.632 38.698666c32.384 0 63.573333-14.08 85.632-38.698666a126.848 126.848 0 0 0 31.914667-84.906667V346.325333c0-36.693333 24.661333-67.754667 53.888-67.754666 29.226667 0 53.888 31.018667 53.888 67.754666V421.12z" p-id="7499" fill="#ffffff"></path><path d="M858.453333 786.432l72.106667-122.624a27.861333 27.861333 0 0 0 0-28.288l-72.106667-122.624a28.928 28.928 0 0 0-24.96-14.165333h-144.128a28.928 28.928 0 0 0-24.96 14.165333l-72.106666 122.624a27.861333 27.861333 0 0 0 0 28.288l72.106666 122.624c5.12 8.746667 14.634667 14.165333 24.96 14.165333h144.128a28.928 28.928 0 0 0 24.96-14.165333z m-152.32-231.04h110.805334l55.466666 94.293333-55.466666 94.293334H706.133333l-55.424-94.293334 55.466667-94.293333z" p-id="7500" fill="#ffffff"></path><path d="M703.786667 650.410667a57.173333 57.173333 0 0 0 57.642666 56.618666 57.173333 57.173333 0 0 0 57.642667-56.618666 57.173333 57.173333 0 0 0-57.642667-56.618667 57.173333 57.173333 0 0 0-57.642666 56.618667z m57.6 14.165333q1.408 0 2.816-0.298667 1.408-0.256 2.688-0.810666 1.322667-0.512 2.517333-1.28 1.194667-0.768 2.176-1.749334 1.024-1.024 1.792-2.133333 0.810667-1.194667 1.322667-2.474667 0.554667-1.28 0.853333-2.645333 0.256-1.365333 0.256-2.773333t-0.256-2.773334q-0.298667-1.365333-0.853333-2.645333-0.512-1.28-1.28-2.432-0.853333-1.194667-1.834667-2.133333-0.981333-1.024-2.176-1.792-1.194667-0.768-2.517333-1.28-1.28-0.554667-2.688-0.853334-1.408-0.256-2.816-0.256t-2.816 0.256q-1.365333 0.298667-2.688 0.853334-1.28 0.512-2.517334 1.28-1.152 0.768-2.133333 1.749333-1.024 0.981333-1.834667 2.133333-0.768 1.194667-1.322666 2.474667-0.554667 1.28-0.853334 2.645333-0.256 1.365333-0.256 2.773334t0.298667 2.773333q0.256 1.365333 0.810667 2.645333t1.322666 2.432q0.810667 1.152 1.792 2.133334 1.024 1.024 2.176 1.792 1.194667 0.768 2.517334 1.28 1.28 0.554667 2.688 0.853333 1.408 0.256 2.816 0.256z" p-id="7501" fill="#ffffff"></path><path d="M162.389333 510.464a43.690667 43.690667 0 1 1 0 87.381333 43.690667 43.690667 0 0 1 0-87.381333z m0-37.632c-44.8 0-81.322667 36.48-81.322666 81.322667 0 44.8 36.48 81.322667 81.322666 81.322666s81.322667-36.48 81.322667-81.322666-36.48-81.322667-81.322667-81.322667z" p-id="7502" fill="#ffffff"></path><path d="M234.112 554.154667q0-29.653333-21.034667-50.688t-50.688-21.034667q-29.653333 0-50.688 21.034667-20.992 21.034667-20.992 50.688t20.992 50.645333q21.034667 21.034667 50.688 21.034667t50.688-21.034667q21.034667-20.992 21.034667-50.645333z m19.2 0q0 37.589333-26.666667 64.256-26.624 26.666667-64.256 26.666666-37.589333 0-64.256-26.666666t-26.666666-64.256q0-37.632 26.666666-64.256 26.666667-26.666667 64.256-26.666667 37.632 0 64.256 26.666667 26.666667 26.624 26.666667 64.256z m-144.213333 0q0-22.101333 15.616-37.717334t37.674666-15.616q22.101333 0 37.717334 15.616t15.616 37.717334q0 22.058667-15.616 37.674666t-37.717334 15.616q-22.058667 0-37.674666-15.616t-15.616-37.674666z m19.2 0q0 14.08 9.984 24.106666 9.984 9.984 24.106666 9.984 14.122667 0 24.106667-9.984 9.984-9.984 9.984-24.106666 0-14.122667-9.984-24.106667-9.984-9.984-24.106667-9.984-14.08 0-24.106666 9.984-9.984 9.984-9.984 24.106667z" p-id="7503" fill="#ffffff"></path></svg>',
|
||||
},{
|
||||
name:"带状航线",
|
||||
checked:false,
|
||||
icon:'<svg t="1749104685102" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6766" width="40" height="40"><path d="M712.313523 0.469118v51.176544c-208.544417 0-446.600641 148.795802-446.600641 279.040107 0 41.197118 9.552955 70.367748 31.68681 107.342801l7.25001 11.600017 17.314731 27.422098 3.497064 5.714714c31.729457 53.820666 34.075049 100.007497-2.004415 164.959061-51.38978 92.458956-145.682562 173.914956-282.281288 244.965057l-18.039731 9.211778L0.234559 856.098288c137.920786-68.960393 230.507684-146.919329 278.485694-233.237099 26.867686-48.404481 25.502978-75.314814 2.644122-114.123694l-21.579443-34.20299-6.22648-10.107367c-26.611803-44.438299-39.022115-81.882471-39.022114-133.741369 0-162.059056 255.669485-324.629878 485.878638-330.088709L712.313523 0.469118z m49.470659 185.514973l22.901504 45.717712-18.892674 9.638249-16.845613 9.083837c-68.661863 38.126525-82.053059 63.288326-72.329516 121.757528 3.539711 21.110324 17.442672 42.775061 44.566241 71.092749l8.316188 8.529424 9.595602 9.425014 31.089751 29.852984c59.876557 57.744201 90.3266 98.514847 104.058973 153.231102 20.129441 80.645704 21.408854 148.326684 2.857357 203.000292l-3.966182 10.747074-47.508892-19.020616c18.039732-45.120653 18.039732-105.850152-1.066178-182.316438-10.022073-40.088293-33.307401-72.926575-80.219233-119.411936l-42.34859-40.813294-12.282371-12.154429a601.06851 601.06851 0 0 1-5.458831-5.62942c-33.648578-35.141227-52.498605-64.525093-58.128025-98.131023-14.926492-89.644246 14.07355-130.628129 114.592812-183.809088l21.067677-10.832368zM574.904502 797.970264v50.579484h-29.852984v-50.622131h29.852984z m0-136.513432v85.29424h-29.852984v-85.29424h29.852984z m-25.161801-139.882554c14.627962 30.492691 23.072092 58.767731 24.863271 87.511891l-29.852984 1.833826c-1.450002-24.479447-8.827954-49.172129-21.92062-76.466286z m-68.278039-119.028112l7.505893 14.286786 35.269168 58.213318-25.588272 15.352964-31.302986-51.517721a446.856524 446.856524 0 0 1-12.538253-22.858857l26.65445-13.47649zM458.264629 268.719504l25.75886 15.09708a192.082629 192.082629 0 0 0-15.99267 34.927991c-4.264712 12.836783-5.117654 24.820624-2.985298 37.955937l-29.426513 4.861772a106.191329 106.191329 0 0 1 4.136771-52.370663c4.776477-14.07355 11.002957-27.55004 18.50885-40.472117z m104.186914-99.282496l15.011786 25.844155a284.712174 284.712174 0 0 0-64.013327 49.641248l-21.707384-20.513265a314.351922 314.351922 0 0 1 70.708925-54.972138z m131.011953-51.261838l7.25001 29.000041a533.515472 533.515472 0 0 0-78.811878 26.014744l-11.642663-27.507393c25.588272-10.875016 53.436841-20.044146 83.161884-27.507392z" fill="#ffffff" p-id="6767"></path></svg>',
|
||||
}
|
||||
])
|
||||
|
||||
const airType = ref([
|
||||
{
|
||||
name:"经纬 M30 系列",
|
||||
checked:false,
|
||||
},{
|
||||
name:"Mavic 3 行业系列",
|
||||
checked:false,
|
||||
},{
|
||||
name:"Matrice 3D 系列",
|
||||
checked:false,
|
||||
},{
|
||||
name:"Matrice 4 行业系列",
|
||||
checked:false,
|
||||
},{
|
||||
name:"Matrice 4D 系列",
|
||||
checked:false,
|
||||
}
|
||||
])
|
||||
|
||||
const airModel = ref([
|
||||
{
|
||||
name:"Matrice 4D",
|
||||
checked:false,
|
||||
},{
|
||||
name:"Matrice 4TD",
|
||||
checked:false,
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
const checkType = (type,index)=>{
|
||||
|
||||
if(type == 'airLine'){
|
||||
airLineType.value?.forEach((item,idx)=>{
|
||||
if(idx == index){
|
||||
airLineType.value[idx].checked = true;
|
||||
}else{
|
||||
airLineType.value[idx].checked = false;
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
if(type == 'airType'){
|
||||
airType.value?.forEach((item,idx)=>{
|
||||
if(idx == index){
|
||||
airType.value[idx].checked = true;
|
||||
}else{
|
||||
airType.value[idx].checked = false;
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
if(type == 'airModel'){
|
||||
airModel.value?.forEach((item,idx)=>{
|
||||
if(idx == index){
|
||||
airModel.value[idx].checked = true;
|
||||
}else{
|
||||
airModel.value[idx].checked = false;
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const getCheckedData = () => {
|
||||
airLineType.value?.forEach((item,idx)=>{
|
||||
if(item.checked){
|
||||
airLineInfo.value.airLineType = item.name;
|
||||
}
|
||||
})
|
||||
|
||||
console.log("airLineInfo.value.airLineType",airLineInfo.value);
|
||||
}
|
||||
|
||||
|
||||
const form = {
|
||||
"id": "",
|
||||
"airLineName": "测试航线01", // 航线名称
|
||||
"airLineType": "waypoint", // 航线类型 : templateType 【waypoint、mapping2d、mappingStrip】
|
||||
"uavId": "1",
|
||||
"flyToFirstPointMode": "safely", // 飞向首航点模式:flyToWaylineMode 【safely、pointToPoint】
|
||||
"safeTakeoffAltitude": 0, // 安全起飞高度 : takeOffSecurityHeight
|
||||
"safeTakeoffSpeed": 0, // 飞行到首航点速度
|
||||
"globalRouteSpeed": 0, // 全局航线速度 autoFlightSpeed
|
||||
"taskCompletionAction": "string", // 任务完成动作 finishAction 【goHome、autoLand、gotoFirstWaypoint】
|
||||
"outOfControlOption": "string", // 失控选项 exitOnRCLost 【goContinue、executeLostAction】
|
||||
"typeOfOutOfControlAction": "string", // 失控动作类型 executeRCLostAction 【goBack、landing、hover】
|
||||
"globalWayPointType": "string", // 全局航点类型 globalWaypointTurnMode 【toPointAndStopWithDiscontinuityCurvature】
|
||||
"ptzControlMode": "string", // 云台控制模式
|
||||
"aircraftYawAngleMode": "string", // 飞行器偏航角模式
|
||||
"createTime": "2025-06-16T08:23:11.740Z",
|
||||
"createId": 0,
|
||||
"wpml": "string" // 航线文件
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container{
|
||||
padding:20px;
|
||||
color:#fff;
|
||||
}
|
||||
.title{
|
||||
padding:15px;
|
||||
color:#fff;
|
||||
font-size:14px;
|
||||
display:flex;
|
||||
}
|
||||
.item-label{
|
||||
padding:10px 0px;
|
||||
color:#999;
|
||||
}
|
||||
.draw-type{
|
||||
display:grid;
|
||||
grid-template-columns: repeat(3, 1fr); /* 创建 3 列,每列等宽 */
|
||||
gap: 16px; /* 设置网格间隙 */
|
||||
}
|
||||
|
||||
.air-line-type{
|
||||
text-align: center;
|
||||
background:#3c3c3c;
|
||||
padding:20px;
|
||||
border: 1px solid #3c3c3c;
|
||||
border-radius: 4px;
|
||||
line-height:20px;
|
||||
}
|
||||
|
||||
.air-line-type-active{
|
||||
text-align: center;
|
||||
background:rgba(45, 139, 240, 0.478);
|
||||
padding:20px;
|
||||
border: 1px solid#2d8cf0;
|
||||
border-radius: 4px;
|
||||
line-height:20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.air-line-type svg{
|
||||
width:50px;
|
||||
}
|
||||
|
||||
.air-line-type:hover{
|
||||
background:rgba(45, 139, 240, 0.478);
|
||||
border: 1px solid#2d8cf0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.operate-button{
|
||||
padding:20px 0px;
|
||||
}
|
||||
::v-deep .ant-select-selector{
|
||||
border:none!important;
|
||||
color:#fff!important;
|
||||
background:#3F4150!important ;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-select-selection-placeholder {
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
::v-deep .ant-select-arrow {
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
::v-deep .ant-select-selection-search-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.933)!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-tree {
|
||||
background:none!important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected{
|
||||
background:#3a57e877!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected::before{
|
||||
background:none!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-tree-treenode-selected::after{
|
||||
content:"";
|
||||
height:28px;
|
||||
width:4px;
|
||||
background:#3A57E8;
|
||||
position:absolute;
|
||||
top:0px;
|
||||
left:0px;
|
||||
}
|
||||
|
||||
::v-deep .ant-input{
|
||||
background:#3c3c3c!important ;
|
||||
border:none!important;
|
||||
border-top-left-radius: 3px !important;
|
||||
border-bottom-left-radius: 3px !important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
|
||||
|
||||
::v-deep .ant-btn-default{
|
||||
background:none!important;
|
||||
border:none!important;
|
||||
outline:none!important;
|
||||
color:#fff!important;
|
||||
height:30px !important;
|
||||
background:#3F4150!important ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
:size="'middle'"
|
||||
>
|
||||
<a-form-item ref="name" label="计划名称" name="name">
|
||||
<a-input v-model:value="submitForm.name" />
|
||||
<a-input v-model:value="submitForm.name" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item ref="name" label="任务类型" name="name">
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,13 +1,76 @@
|
|||
<template>
|
||||
<div ref="vChartRef" id="mars3d-container" class="mars3d-container"></div>
|
||||
<div ref="vChartRef" id="mars3d-container" class="mars3d-container">
|
||||
|
||||
<!-- 航点航线 -->
|
||||
<div v-if="props.airRoute.airLineType == '航点航线'" class="air-container">
|
||||
<airPoint :airPoints="airPoints" @setFlyPoint="setFlyPoint" :airInfo="airInfo" :polygonAirForm="polygonAirForm"></airPoint>
|
||||
</div>
|
||||
|
||||
<!-- 航面航线 -->
|
||||
<div v-if="props.airRoute.airLineType == '面状航线'" class="airpolygon-container">
|
||||
<airPolygon @setFlyPoint="setFlyPoint" :airInfo="airInfo" :polygonAirForm="polygonAirForm"></airPolygon>
|
||||
</div>
|
||||
|
||||
<!-- 航点航线配置 -->
|
||||
<div class="airpoint-config-container">
|
||||
<airPointConfig></airPointConfig>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {ref,onMounted} from 'vue'
|
||||
import {ref,onMounted,defineProps,watch} from 'vue'
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
import {buildUUID} from '@/utils/uuid'
|
||||
import airPoint from './airPoint.vue'
|
||||
import * as mars3d from "mars3d";
|
||||
import "mars3d-space";
|
||||
|
||||
import * as Cesium from 'mars3d-cesium'
|
||||
import * as turf from '@turf/turf'
|
||||
import airPolygon from './airPolygon.vue'
|
||||
import airPointConfig from './airPointConfig.vue'
|
||||
|
||||
const props = defineProps(["airRoute"]);
|
||||
|
||||
watch(
|
||||
()=> props.airRoute,
|
||||
(newVal,oldVal)=>{
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
const airPoints = ref([])
|
||||
|
||||
let map: mars3d.Map; // 地图对象
|
||||
let graphicLayer = null;
|
||||
let graphicLayer:mars3d.layer.GraphicLayer;
|
||||
|
||||
// 面航线图层
|
||||
let polygonGraphicLayer:mars3d.layer.GraphicLayer;
|
||||
|
||||
let polygonLineGraphicLayer:mars3d.layer.GeoJsonLayer;
|
||||
|
||||
let graphic = null;
|
||||
|
||||
const airInfo = ref({
|
||||
area:0,
|
||||
length:0,
|
||||
time:0,
|
||||
picture:'- -'
|
||||
})
|
||||
|
||||
const polygonAirForm = ref({
|
||||
startingPoint:null,
|
||||
lensMode:1,
|
||||
gatherMode:1,
|
||||
heightMode:2,
|
||||
height:120,
|
||||
speed:15,
|
||||
angle:0,
|
||||
complete:1
|
||||
})
|
||||
|
||||
const vChartRef = ref<HTMLElement>()
|
||||
|
||||
|
|
@ -22,13 +85,7 @@ const initMap = ()=>{
|
|||
map = new mars3d.Map(vChartRef.value,
|
||||
{
|
||||
"scene": {
|
||||
"center": {
|
||||
"lat": 35.362625,
|
||||
"lng": 118.033886,
|
||||
"alt": 8306.3,
|
||||
"heading": 360,
|
||||
"pitch": -45
|
||||
},
|
||||
"center": {"lat":35.134762,"lng":118.295245,"alt":953.2,"heading":360,"pitch":-90},
|
||||
"scene3DOnly": false,
|
||||
"shadows": false,
|
||||
"removeDblClick": true,
|
||||
|
|
@ -49,8 +106,9 @@ const initMap = ()=>{
|
|||
"powerPreference": "high-performance"
|
||||
}
|
||||
},
|
||||
|
||||
"globe": {
|
||||
"depthTestAgainstTerrain": false,
|
||||
"depthTestAgainstTerrain": true,
|
||||
"baseColor": "#546a53",
|
||||
"showGroundAtmosphere": true,
|
||||
"enableLighting": false
|
||||
|
|
@ -246,105 +304,479 @@ const initMap = ()=>{
|
|||
|
||||
map.on(mars3d.EventType.load, function (event) {
|
||||
|
||||
// 地图右键菜单
|
||||
handlerBindMapMenus();
|
||||
|
||||
graphicLayer = new mars3d.layer.GraphicLayer({
|
||||
isAutoEditing: true // 是否自动激活编辑
|
||||
isAutoEditing: false // 是否自动激活编辑
|
||||
})
|
||||
map.addLayer(graphicLayer);
|
||||
|
||||
graphicLayer.on(mars3d.EventType.editStop, function (e) {
|
||||
console.log("停止编辑", e.graphic.options.position)
|
||||
})
|
||||
|
||||
graphicLayer.on(mars3d.EventType.editMovePoint, function (e) {
|
||||
console.log("编辑修改了点", e.graphic.options.position)
|
||||
})
|
||||
|
||||
bindLayerContextMenu();
|
||||
|
||||
drawPint();
|
||||
|
||||
// 绘制起点
|
||||
// handlerDrawStartPoint();
|
||||
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 绑定地图右键菜单
|
||||
const handlerBindMapMenus = ()=>{
|
||||
const mapContextmenuItems = [
|
||||
{
|
||||
text: "添加航点",
|
||||
icon: "fa fa-camera-retro", // 支持 font-class 的字体方式图标
|
||||
callback: (e) => {
|
||||
handlerDrawPoint(e);
|
||||
}
|
||||
},{
|
||||
text: "添加面区域",
|
||||
icon: "fa fa-camera-retro", // 支持 font-class 的字体方式图标
|
||||
callback: (e) => {
|
||||
|
||||
if(!polygonAirForm.value.startingPoint){
|
||||
message.warning("请先设置起飞点");
|
||||
return null;
|
||||
}
|
||||
handlerDrawPolygon();
|
||||
}
|
||||
}
|
||||
]
|
||||
map.bindContextMenu(mapContextmenuItems)
|
||||
}
|
||||
|
||||
const uavPoints = ref([]);
|
||||
|
||||
|
||||
// 绘制航点
|
||||
const handlerDrawPoint = (e) => {
|
||||
|
||||
let position = mars3d.LngLatPoint.fromCartesian(e.position);
|
||||
|
||||
|
||||
position._alt = position._alt + 100;
|
||||
|
||||
let uuid = buildUUID();
|
||||
|
||||
|
||||
const graphic = new mars3d.graphic.BillboardEntity({
|
||||
id:uuid,
|
||||
name: "航点",
|
||||
position: [position._lng,position._lat,position._alt+180],
|
||||
style: {
|
||||
image: "/map/node.png",
|
||||
scale: 1,
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
label: {
|
||||
text: "航点",
|
||||
font_size: 14,
|
||||
color: "#ffffff",
|
||||
outline: true,
|
||||
outlineColor: "#000000",
|
||||
pixelOffsetY: -35
|
||||
}
|
||||
},
|
||||
})
|
||||
uavPoints.value.push(graphic);
|
||||
|
||||
|
||||
const rectSensor = new mars3d.graphic.RectSensor({
|
||||
id: "-rectSensor",
|
||||
position: [position._lng,position._lat,position._alt+180],
|
||||
style: {
|
||||
angle1: 30, // 椎体夹角1
|
||||
angle2: 30, // 椎体夹角2
|
||||
length: 100, // 椎体长度
|
||||
rayEllipsoid: true,
|
||||
color: "rgba(0,255,255,0.3)",
|
||||
outline: true,
|
||||
topShow: true,
|
||||
topSteps: 2,
|
||||
flat: true,
|
||||
cameraHpr: true,
|
||||
heading: 0,
|
||||
pitch: 180,
|
||||
roll: 30, //
|
||||
clippingPlanes: [{
|
||||
distance: 0, // 设置裁剪平面在地表(0高度)
|
||||
normal: new Cesium.Cartesian3(0, 0, -1) // 法向量向下(隐藏地表以下部分)
|
||||
}]
|
||||
}
|
||||
})
|
||||
graphicLayer.addGraphic(rectSensor)
|
||||
|
||||
|
||||
let airPointInfo = {
|
||||
id:uuid,
|
||||
name:"航点",
|
||||
lng:position._lng,
|
||||
lat:position._lat,
|
||||
alt:position._alt,
|
||||
aircraftHorizontalAngle:0,
|
||||
cameraHorizontalAngle:0,
|
||||
cameraVerticalAngle:0,
|
||||
focalLength:2,
|
||||
}
|
||||
|
||||
airPoints.value?.push(airPointInfo);
|
||||
|
||||
graphicLayer.addGraphic(graphic)
|
||||
|
||||
handlerDrawLine();
|
||||
}
|
||||
|
||||
|
||||
// 绘制航线
|
||||
const handlerDrawLine = () => {
|
||||
console.log("uavPoints",uavPoints.value);
|
||||
|
||||
let positions = [];
|
||||
uavPoints.value?.forEach((item,index)=>{
|
||||
positions.push(item._position);
|
||||
})
|
||||
|
||||
|
||||
console.log("positions",positions);
|
||||
|
||||
if(positions.length>1){
|
||||
const graphic = new mars3d.graphic.PolylineEntity({
|
||||
positions: positions,
|
||||
style: {
|
||||
width: 2,
|
||||
color: "#3388ff",
|
||||
},
|
||||
})
|
||||
graphicLayer.addGraphic(graphic)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const startPosition = ref(null);
|
||||
|
||||
// 设置起飞点
|
||||
const setFlyPoint = async ()=>{
|
||||
|
||||
const graphic = await graphicLayer.startDraw({
|
||||
type: "billboardP",
|
||||
style: {
|
||||
image: "/map/start.png",
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
label: {
|
||||
text: "参考起飞点",
|
||||
font_size: 16,
|
||||
color: "#ffffff",
|
||||
outline: true,
|
||||
outlineColor: "#000000",
|
||||
pixelOffsetY: -50
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
startPosition.value = graphic.toJSON().position
|
||||
|
||||
polygonAirForm.value.startingPoint = graphic.toJSON().position;
|
||||
|
||||
}
|
||||
|
||||
// 绘制面状
|
||||
const handlerDrawPolygon = async () => {
|
||||
|
||||
if(polygonGraphicLayer==null){
|
||||
polygonGraphicLayer = new mars3d.layer.GraphicLayer({
|
||||
isAutoEditing: false // 是否自动激活编辑
|
||||
})
|
||||
|
||||
polygonGraphicLayer.bindContextMenu([
|
||||
{
|
||||
text: "删除测区",
|
||||
icon: "fa fa-camera-retro", // 支持 font-class 的字体方式图标
|
||||
callback: (e) => {
|
||||
handlerRemovePolygonArea(e);
|
||||
}
|
||||
}
|
||||
])
|
||||
map.addLayer(polygonGraphicLayer);
|
||||
}
|
||||
|
||||
const graphic = await polygonGraphicLayer.startDraw({
|
||||
type: "polygon",
|
||||
style: {
|
||||
color: "#408eff",
|
||||
opacity: 0.3,
|
||||
outline: true,
|
||||
outlineColor: "#408eff",
|
||||
outlineWidth: 3.0,
|
||||
clampToGround:true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let coordinates = graphic.toJSON().positions;
|
||||
|
||||
coordinates.push(coordinates[0])
|
||||
|
||||
let polygon = turf.polygon([coordinates])
|
||||
let lines = generateScanLines(polygon,0.003,0);
|
||||
|
||||
CalculateAreaInfo(polygon,lines);
|
||||
|
||||
|
||||
// 绘制面航线
|
||||
handlerDrawPolygonLine(lines);
|
||||
}
|
||||
|
||||
// 绘制面航线
|
||||
const handlerDrawPolygonLine = (lines) => {
|
||||
|
||||
|
||||
const graphic = new mars3d.graphic.BillboardEntity({
|
||||
id:"节点",
|
||||
name: "航点",
|
||||
position:lines.geometry.coordinates[0],
|
||||
style: {
|
||||
image: "/map/node.png",
|
||||
scale: 1,
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
label: {
|
||||
text: "",
|
||||
font_size: 14,
|
||||
color: "#ffffff",
|
||||
outline: true,
|
||||
outlineColor: "#000000",
|
||||
pixelOffsetY: -35
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
polygonGraphicLayer.addGraphic(graphic);
|
||||
|
||||
|
||||
// 添加起飞点
|
||||
lines.geometry.coordinates.unshift([polygonAirForm.value.startingPoint[0],polygonAirForm.value.startingPoint[1],polygonAirForm.value.startingPoint[2]+20]);
|
||||
|
||||
lines.geometry.coordinates.unshift(polygonAirForm.value.startingPoint);
|
||||
|
||||
|
||||
|
||||
|
||||
if(polygonLineGraphicLayer){
|
||||
polygonLineGraphicLayer.clear();
|
||||
polygonLineGraphicLayer.loadGeoJSON(lines);
|
||||
}else{
|
||||
polygonLineGraphicLayer = new mars3d.layer.GeoJsonLayer({
|
||||
name: "面航线",
|
||||
data:lines,
|
||||
symbol: {
|
||||
type: "polylineP",
|
||||
styleOptions: {
|
||||
width: 2.0,
|
||||
color:"#0aed8b",
|
||||
// clampToGround: true,
|
||||
}
|
||||
},
|
||||
flyTo: true
|
||||
})
|
||||
map.addLayer(polygonLineGraphicLayer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 删除面 和 面航线
|
||||
const handlerRemovePolygonArea = () => {
|
||||
if(polygonGraphicLayer){
|
||||
polygonGraphicLayer.clear();
|
||||
}
|
||||
if(polygonLineGraphicLayer){
|
||||
polygonLineGraphicLayer.clear();
|
||||
}
|
||||
|
||||
airInfo.value = {
|
||||
area:0,
|
||||
length:0,
|
||||
time:0,
|
||||
picture:'- -'
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// 计算面航线
|
||||
function generateScanLines(polygon, spacing, angle = 0) {
|
||||
|
||||
const bindLayerContextMenu =()=> {
|
||||
graphicLayer.bindContextMenu([
|
||||
{
|
||||
text: "删除对象",
|
||||
icon: "fa fa-trash-o",
|
||||
show: (event) => {
|
||||
const graphic = event.graphic
|
||||
if (!graphic || graphic.isDestroy || graphic.isPrivate || graphic.graphicIds) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
callback: (e) => {
|
||||
const graphic = e.graphic
|
||||
if (!graphic) {
|
||||
return
|
||||
}
|
||||
const parent = graphic.parent // 右击是编辑点时
|
||||
graphicLayer.removeGraphic(graphic)
|
||||
if (parent) {
|
||||
graphicLayer.removeGraphic(parent)
|
||||
if (!turf.booleanValid(polygon)) throw new Error('无效的多边形');
|
||||
spacing = Math.abs(spacing);
|
||||
|
||||
// 获取多边形的旋转边界框
|
||||
const bbox = turf.bbox(polygon);
|
||||
const center = turf.center(polygon).geometry.coordinates;
|
||||
|
||||
// 计算需要生成的线数量(加缓冲确保完全覆盖)
|
||||
const diagLength = turf.distance(turf.point([bbox[0], bbox[1]]),turf.point([bbox[2], bbox[3]]));
|
||||
const lineCount = Math.ceil(diagLength / spacing) + 2;
|
||||
|
||||
// 生成基础水平线
|
||||
const lines = [];
|
||||
|
||||
for (let i = -1; i <= lineCount; i++) {
|
||||
const y = bbox[1] + (i * spacing*0.1) - spacing*0.1;
|
||||
lines.push(
|
||||
turf.lineString([[bbox[0] - spacing, y],[bbox[2] + spacing, y]])
|
||||
);
|
||||
}
|
||||
|
||||
// 旋转线条到指定角度
|
||||
const rotatedLines = lines.map(line =>
|
||||
turf.transformRotate(line, angle, { pivot: center })
|
||||
);
|
||||
|
||||
// 裁剪线条到多边形内并处理结果
|
||||
const coverageLines = [];
|
||||
|
||||
rotatedLines.forEach(line => {
|
||||
try {
|
||||
const intersection = turf.lineIntersect(line, polygon);
|
||||
|
||||
|
||||
if (intersection.features.length >= 2) {
|
||||
// 按与线起点距离排序交点
|
||||
const sortedPoints = intersection.features.map(f => f.geometry.coordinates).sort((a, b) => turf.distance(line.geometry.coordinates[0], turf.point(a)) -
|
||||
turf.distance(line.geometry.coordinates[0], turf.point(b)));
|
||||
|
||||
// 创建连接最远两个交点的线段
|
||||
coverageLines.push(turf.lineString([sortedPoints[0],sortedPoints[sortedPoints.length - 1]]));
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('处理线段时出错:', e);
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "停止编辑对象",
|
||||
icon: "fa fa-edit",
|
||||
show: function (e) {
|
||||
const graphic = e.graphic
|
||||
if (!graphic || !graphic.hasEdit) {
|
||||
return false
|
||||
}
|
||||
return graphic.isEditing
|
||||
},
|
||||
callback: (e) => {
|
||||
const graphic = e.graphic
|
||||
if (!graphic) {
|
||||
return false
|
||||
}
|
||||
if (graphic) {
|
||||
graphic.stopEditing()
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
});
|
||||
|
||||
|
||||
let connectedLine = connectLinesManual(turf.featureCollection(coverageLines));
|
||||
console.log("connectedLine",connectedLine)
|
||||
return connectedLine;
|
||||
}
|
||||
|
||||
const drawPint = async ()=>{
|
||||
const graphic = await graphicLayer.startDraw({
|
||||
type: "polylineP",
|
||||
style: {
|
||||
pixelSize: 12,
|
||||
color: "#3388ff",
|
||||
label: {
|
||||
// 不需要文字时,去掉label配置即可
|
||||
text: "可以同时支持文字",
|
||||
font_size: 20,
|
||||
color: "#ffffff",
|
||||
outline: true,
|
||||
outlineColor: "#000000",
|
||||
pixelOffsetY: -20
|
||||
}
|
||||
}
|
||||
// 连接线段
|
||||
const connectLinesManual= (lines) => {
|
||||
// 确保输入是FeatureCollection
|
||||
if (lines.type !== 'FeatureCollection') {
|
||||
lines = turf.featureCollection([lines]);
|
||||
}
|
||||
|
||||
// 收集所有坐标点
|
||||
let allCoords = [];
|
||||
lines.features.forEach((line,index) => {
|
||||
console.log("line.geometry.coordinates",line.geometry.coordinates);
|
||||
line.geometry.coordinates?.forEach((item,idx)=>{
|
||||
line.geometry.coordinates[idx].push(180);
|
||||
})
|
||||
|
||||
console.log("标绘完成", graphic.toJSON())
|
||||
if (line.geometry.type === 'LineString' && index % 2 == 0) {
|
||||
allCoords = allCoords.concat(line.geometry.coordinates.reverse());
|
||||
}else{
|
||||
allCoords = allCoords.concat(line.geometry.coordinates);
|
||||
}
|
||||
});
|
||||
|
||||
console.log("allCoords",allCoords);
|
||||
// 移除连续重复的点
|
||||
const cleanedCoords = [];
|
||||
if (allCoords.length > 0) {
|
||||
cleanedCoords.push(allCoords[0]);
|
||||
for (let i = 1; i < allCoords.length; i++) {
|
||||
const prev = cleanedCoords[cleanedCoords.length - 1];
|
||||
if (prev[0] !== allCoords[i][0] || prev[1] !== allCoords[i][1]) {
|
||||
cleanedCoords.push(allCoords[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return turf.lineString(cleanedCoords);
|
||||
}
|
||||
|
||||
// 标绘起点
|
||||
const handlerDrawStartPoint = async ()=>{
|
||||
graphic = await graphicLayer.startDraw({
|
||||
type: "billboard",
|
||||
style: {
|
||||
image: "/map/start.png",
|
||||
scale:0.7,
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
label: {
|
||||
text: "无人机起始位置",
|
||||
font_size: 16,
|
||||
color: "#ffffff",
|
||||
outline: true,
|
||||
outlineColor: "#000000",
|
||||
pixelOffsetY: -60
|
||||
}
|
||||
}
|
||||
})
|
||||
// 设置贴地点 和 连接线
|
||||
}
|
||||
|
||||
// 计算面状测区信息
|
||||
const CalculateAreaInfo = (polygon,lines)=>{
|
||||
// 测区面积
|
||||
airInfo.value.area = turf.area(polygon).toFixed(2);
|
||||
|
||||
// 航线长度
|
||||
airInfo.value.length = turf.length(lines).toFixed(2);
|
||||
|
||||
// 预计用时
|
||||
airInfo.value.time = (airInfo.value.length * 1000 / polygonAirForm.value.speed / 60).toFixed(2);
|
||||
|
||||
// 照片数量
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.mars3d-container{
|
||||
width:100%;
|
||||
height:100%;
|
||||
background:red;
|
||||
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.air-container{
|
||||
width:400px;
|
||||
background:#0d0e15c1 ;
|
||||
overflow-y:hidden;
|
||||
position:absolute;
|
||||
height: calc( 100vh - 80px);
|
||||
top:0px;
|
||||
left:0px;
|
||||
z-index:999;
|
||||
}
|
||||
|
||||
.airpolygon-container{
|
||||
width:400px;
|
||||
background:#0d0e15c1 ;
|
||||
overflow-y:hidden;
|
||||
position:absolute;
|
||||
height: calc( 100vh - 80px);
|
||||
top:0px;
|
||||
left:0px;
|
||||
z-index:999;
|
||||
}
|
||||
|
||||
.airpoint-config-container{
|
||||
width:400px;
|
||||
background:#0d0e15c1 ;
|
||||
overflow-y:hidden;
|
||||
position:absolute;
|
||||
height: calc( 100vh - 80px);
|
||||
top:0px;
|
||||
right:0px;
|
||||
z-index:999;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="container">
|
||||
<div class="title">
|
||||
<div style="flex:1;">
|
||||
工作计划
|
||||
|
|
@ -22,7 +22,8 @@
|
|||
</div>
|
||||
|
||||
<div class="filter-buttons">
|
||||
<a-input-search
|
||||
<a-input-search v-model:value="pageQuery.key"
|
||||
@keyup.enter="getTaskList"
|
||||
placeholder="输入计划名称"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -34,11 +35,11 @@
|
|||
<div class="routers-list">
|
||||
<div class="ari-line" v-for="(item,index) in ariLineList" :key="index" @click="checkAriLine(item)">
|
||||
<div class="title">
|
||||
<div class="state">
|
||||
进行中
|
||||
<div :class="item.status == 0 ? 'state-no' : 'state' ">
|
||||
{{item.status == 0 ? '未开始' : '进行中'}}
|
||||
</div>
|
||||
<div style="flex:1;">
|
||||
{{item.name}}
|
||||
{{item.taskName}}
|
||||
</div>
|
||||
<div>
|
||||
<a-dropdown>
|
||||
|
|
@ -48,7 +49,7 @@
|
|||
<a-menu-item>
|
||||
<a href="javascript:;">编辑</a>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-menu-item @click="deletePlan(item.id)">
|
||||
<a href="javascript:;">删除</a>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
|
|
@ -61,82 +62,107 @@
|
|||
{{item.description}}
|
||||
</div>
|
||||
<div class="time">更新时间:{{item.createTime}}</div>
|
||||
<div class="username"><UserOutlined /> {{item.createUserName}}</div>
|
||||
<div class="username"><UserOutlined /> {{item.createId}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pagenation">
|
||||
<a-pagination v-model:current="pageQuery.page" :total="lineListTotal" @change="onPageChange" show-less-items />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { UserOutlined,PlusOutlined,FileAddOutlined,LeftOutlined,ImportOutlined,MoreOutlined,EditOutlined } from '@ant-design/icons-vue';
|
||||
import {ref,defineEmits} from 'vue'
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import {ref,defineEmits,createVNode} from 'vue'
|
||||
import { Modal, message } from 'ant-design-vue';
|
||||
import { getTaskPageList, deleteTask } from '@/api/sys/workplan';
|
||||
|
||||
const emit = defineEmits(["checkAriLine","createWorkPlan"])
|
||||
|
||||
|
||||
const createWorkPlan = () => {
|
||||
emit("createWorkPlan");
|
||||
}
|
||||
|
||||
const ariLineList = ref([]);
|
||||
const lineListTotal = ref(0);
|
||||
|
||||
const pageQuery = ref({
|
||||
page:0,
|
||||
limit:10,
|
||||
key:null
|
||||
})
|
||||
|
||||
const getTaskList = async ()=>{
|
||||
|
||||
let res = await getTaskPageList(pageQuery.value);
|
||||
ariLineList.value = res.items;
|
||||
lineListTotal.value = res.total;
|
||||
}
|
||||
|
||||
getTaskList();
|
||||
|
||||
const deletePlan = async (id) => {
|
||||
Modal.confirm({
|
||||
title: '是否确认删除?',
|
||||
icon: createVNode(ExclamationCircleOutlined),
|
||||
onCancel() {},
|
||||
async onOk() {
|
||||
let res = await deleteTask({id:id});
|
||||
if(res){
|
||||
message.success("操作成功!");
|
||||
getTaskList();
|
||||
}else{
|
||||
message.error("操作失败!");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
const checkAriLine = (item)=> {
|
||||
emit("checkAriLine",item);
|
||||
}
|
||||
|
||||
const expandedKeys = ref<string[]>(['0-0', '0-1']);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const treeData = ref(
|
||||
[
|
||||
{
|
||||
title: '默认文件夹',
|
||||
key: '1',
|
||||
children: [
|
||||
{
|
||||
title: '文件夹1',
|
||||
key: '2',
|
||||
isLeaf: true,
|
||||
},
|
||||
{
|
||||
title: '文件夹2',
|
||||
key: '3',
|
||||
isLeaf: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
)
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const treeData = ref(
|
||||
[
|
||||
{
|
||||
title: '默认文件夹',
|
||||
key: '1',
|
||||
children: [
|
||||
{
|
||||
title: '文件夹1',
|
||||
key: '2',
|
||||
isLeaf: true,
|
||||
},
|
||||
{
|
||||
title: '文件夹2',
|
||||
key: '3',
|
||||
isLeaf: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
const onPageChange = (e)=>{
|
||||
pageQuery.value.page = e;
|
||||
getTaskList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ariLineList = ref([
|
||||
{
|
||||
name:"工作计划1",
|
||||
state:"进行中",
|
||||
description:" 预置航线、照片、模型和地图标注等,辅助了解司空2 功能。",
|
||||
createUserName:"17861857725",
|
||||
createTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"工作计划1",
|
||||
state:"进行中",
|
||||
description:" 预置航线、照片、模型和地图标注等,辅助了解司空2 功能。",
|
||||
createUserName:"17861857725",
|
||||
createTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"工作计划1",
|
||||
state:"进行中",
|
||||
description:" 预置航线、照片、模型和地图标注等,辅助了解司空2 功能。",
|
||||
createUserName:"17861857725",
|
||||
createTime:"2025-06-03 17:01:47"
|
||||
},
|
||||
{
|
||||
name:"工作计划1",
|
||||
state:"进行中",
|
||||
description:" 预置航线、照片、模型和地图标注等,辅助了解司空2 功能。",
|
||||
createUserName:"17861857725",
|
||||
createTime:"2025-06-03 17:01:47"
|
||||
}
|
||||
])
|
||||
</script>
|
||||
<style scoped>
|
||||
.container{
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
.title{
|
||||
padding:30px 15px;
|
||||
color:#fff;
|
||||
|
|
@ -169,6 +195,8 @@ const treeData = ref(
|
|||
cursor:pointer;
|
||||
}
|
||||
.routers-container{
|
||||
height: calc( 100% - 160px);
|
||||
overflow-y:auto;
|
||||
display:flex;
|
||||
gap:10px;
|
||||
font-size:14px;
|
||||
|
|
@ -232,6 +260,17 @@ const treeData = ref(
|
|||
top:2px;
|
||||
}
|
||||
|
||||
.ari-line .state-no{
|
||||
border:1px solid rgb(246, 18, 18);
|
||||
color:rgb(246, 18, 18);;
|
||||
font-size:12px;
|
||||
height:24px;
|
||||
line-height:20px;
|
||||
padding:0px 4px;
|
||||
position:relative;
|
||||
top:2px;
|
||||
}
|
||||
|
||||
.ari-line .type{
|
||||
padding:12px 0px;
|
||||
|
||||
|
|
@ -253,6 +292,10 @@ const treeData = ref(
|
|||
color:#ccc;
|
||||
}
|
||||
|
||||
.pagenation{
|
||||
padding:10px 15px;
|
||||
}
|
||||
|
||||
::v-deep .ant-select-selector{
|
||||
border:none!important;
|
||||
color:#fff!important;
|
||||
|
|
@ -316,6 +359,26 @@ const treeData = ref(
|
|||
background:#3F4150!important ;
|
||||
}
|
||||
|
||||
::v-deep .ant-pagination-item-link{
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-pagination .ant-pagination-item a {
|
||||
color:#fff!important;
|
||||
}
|
||||
::v-deep .ant-pagination .ant-pagination-item-active a{
|
||||
color:#408eff;
|
||||
}
|
||||
|
||||
::v-deep .ant-input{
|
||||
background:#3c3c3c!important ;
|
||||
border:none!important;
|
||||
border-top-left-radius: 3px !important;
|
||||
border-bottom-left-radius: 3px !important;
|
||||
color:#fff!important;
|
||||
}
|
||||
|
||||
::v-deep .ant-input::placeholder{
|
||||
color:rgba(255, 255, 255, 0.533)!important;
|
||||
}
|
||||
</style>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,22 +1,22 @@
|
|||
<template>
|
||||
<div>
|
||||
<div style="width:100%;height: calc( 100vh - 80px);" >
|
||||
<Map></Map>
|
||||
<Map :airRoute="airRoute"></Map>
|
||||
</div>
|
||||
|
||||
<!-- 工作计划列表 -->
|
||||
<div v-if="planListShow" style="width:360px;background:#0d0e15c1 ;position:absolute;top:0px;left:0px;z-index:1;height: calc( 100vh - 104px);overflow-y:hidden;">
|
||||
<planList @createWorkPlan="createWorkPlan" ></planList>
|
||||
<div v-show="planListShow" style="width:360px;background:#0d0e15c1 ;position:absolute;top:0px;left:0px;z-index:1;height: calc( 100vh - 104px);overflow-y:hidden;">
|
||||
<planList @createWorkPlan="toCreateWorkPlan" ></planList>
|
||||
</div>
|
||||
|
||||
<!-- 创建计划弹窗 -->
|
||||
<div v-if="workPlanFormShow" style="width:380px;background:#0d0e15ce ;position:absolute;top:30px;left:30px;z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
|
||||
<WorkPlanForm @cancleCraete="cancleCraete" @selectAircraft="selectAircraft" @selectAriLine="selectAriLine"></WorkPlanForm>
|
||||
<createWorkPlan @cancleCraete="cancleCraete" @selectAircraft="selectAircraft" @selectAriLine="selectAriLine"></createWorkPlan>
|
||||
</div>
|
||||
|
||||
<!-- 航线库 -->
|
||||
<div v-if="ariLineShow" style="width:566px;background:#0d0e15c1 ;position:absolute;top:30px;left:440px;z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
|
||||
<airLineList @checkAriLine="checkAriLine" ></airLineList>
|
||||
<airLineList @checkAriLine="checkAriLine" @createAirLine="handlerCreateAirLine"></airLineList>
|
||||
</div>
|
||||
|
||||
<!-- 飞行器 -->
|
||||
|
|
@ -24,6 +24,13 @@
|
|||
<aircraft @checkAriLine="checkAriLine" ></aircraft>
|
||||
</div>
|
||||
|
||||
<!-- 新建航线 -->
|
||||
<div v-if="createAirLineShow" style="width:566px;background:#0d0e15c1 ;position:absolute;top:30px;left:440px;z-index:1;height: calc( 100vh - 164px);overflow-y:hidden;">
|
||||
<createAirLine @createAirLine="handlerCreateAirRoute" @cancle="cancleCreateAirLine"></createAirLine>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
|
@ -31,13 +38,19 @@ import {ref} from 'vue';
|
|||
import planList from './components/planList.vue';
|
||||
import airLineList from './components/airLineList.vue';
|
||||
import aircraft from './components/aircraft.vue';
|
||||
import WorkPlanForm from './components/workPlanForm.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';
|
||||
|
||||
const airRoute = ref({})
|
||||
|
||||
const planListShow = ref(true);
|
||||
const workPlanFormShow = ref(false);
|
||||
const ariLineShow = ref(false);
|
||||
const aircraftShow = ref(false);
|
||||
const createAirLineShow = ref(false);
|
||||
|
||||
const selectAriLine = ()=> {
|
||||
ariLineShow.value = true;
|
||||
aircraftShow.value = false;
|
||||
|
|
@ -57,12 +70,30 @@ const cancleCraete = ()=>{
|
|||
const checkAriLine = (item)=>{
|
||||
if(item){
|
||||
ariLineShow.value = false;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const createWorkPlan = ()=> {
|
||||
const toCreateWorkPlan = ()=> {
|
||||
planListShow.value = false;
|
||||
workPlanFormShow.value = true;
|
||||
}
|
||||
|
||||
// 创建航线
|
||||
const handlerCreateAirLine = ()=>{
|
||||
createAirLineShow.value = true;
|
||||
}
|
||||
|
||||
const cancleCreateAirLine = ()=>{
|
||||
createAirLineShow.value = false;
|
||||
}
|
||||
|
||||
const handlerCreateAirRoute = (info)=>{
|
||||
workPlanFormShow.value = false;
|
||||
ariLineShow.value = false;
|
||||
aircraftShow.value = false;
|
||||
planListShow.value = false;
|
||||
createAirLineShow.value = false;
|
||||
airRoute.value = info
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue