飞行作业智能巡检

main
刘妍 4 weeks ago
parent f16c74f139
commit dcfbb07dc9

@ -8,4 +8,5 @@ export { default as LoadControl } from './src/LoadControl.vue';
export { default as FlightControl } from './src/FlightControl.vue';
export { default as TakeOffForm } from './src/TakeOffForm.vue';
export { default as FlyToForm } from './src/FlyToForm.vue';
export { default as Patrol } from './src/Patrol.vue';
export { default as Map } from '../workplan/components/map.vue';

@ -2,14 +2,10 @@
<div>
<div class="map-container">
<div class="map-container-content">
<Map
:airRoute="airRoute"
@flyToThere="flyToThere"
:airPort="airPort"
:uavTrack="uavTrack"
/>
<Map @flyToThere="flyToThere" :airPort="airPort" :uavTrack="uavTrack" />
</div>
</div>
<SelectComponent @selectChange="changeSelect" />
<AirportInformation
@changeLive="changeAirportLive"
@ -76,6 +72,17 @@
@loadLiveStreaming="livePreviewVisible = false"
@changeCameraType="changeCameraType"
/>
<div class="intelligent-patrol">
<div @click="patrolVisible = true">
<span> <RadarChartOutlined /> </span>
<span>智能巡检</span>
</div>
<div @click="reportedBtn">
<span> <AlertOutlined /></span>
<span>上报事件</span>
</div>
</div>
<Patrol v-if="patrolVisible" @changePatrol="patrolVisible = false" />
</div>
</template>
<script setup lang="ts">
@ -92,6 +99,7 @@
FlightControl,
TakeOffForm,
FlyToForm,
Patrol,
} from './index';
import { useMessage } from '@/hooks/web/useMessage';
import { getClient, createConnection, clientSubscribe, destroyConnection } from '@/utils/mqtt';
@ -100,18 +108,13 @@
import { EventBus } from '@/utils/eventBus';
import { drcUpTopic, setTopic } from '@/utils/debugging/remote';
import { airPortStore } from '@/store/modules/airport';
import { AlertOutlined, RadarChartOutlined } from '@ant-design/icons-vue';
const zIndex = ref(0);
const airPortStoreVal = airPortStore();
const airPortInfo = airPortStoreVal.getAirport;
const UAVinfo = airPortStoreVal.getUAV;
const { createMessage } = useMessage();
const airRoute = ref({
airLineType: null,
airType: null,
airModel: null,
name: null,
});
const locationVal: any = ref({});
const flyToThere = (e) => {
locationVal.value.lat = e._lat;
@ -193,6 +196,8 @@
const flyToFormVisible = ref(false);
//
const uavLive = ref(false);
//
const patrolVisible = ref(false);
const changeAirportLive = () => {
airportLiveVisible.value = !airportLiveVisible.value;
zIndex.value++;
@ -266,6 +271,7 @@
//
clientSubscribe(topicUAVUrl, { qos: 1 });
};
const reportedBtn = () => {};
</script>
<style lang="less" scoped>
.map-container {
@ -331,4 +337,38 @@
right: 10px;
bottom: 20px;
}
.intelligent-patrol {
position: absolute;
right: 40px;
top: 100px;
display: flex;
flex-direction: column;
div {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 30px;
cursor: pointer;
}
span {
color: #fff;
}
span:first-child {
margin-bottom: 6px;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
color: #fff;
background: linear-gradient(180deg, rgba(13, 25, 45, 0.87) 0%, #25436c 100%);
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
border-image: linear-gradient(180deg, rgba(54, 97, 164, 1), rgba(61, 109, 171, 0.68)) 1 1;
}
::v-deep .anticon svg {
width: 20px;
height: 20px;
}
}
</style>

@ -0,0 +1,335 @@
<template>
<div class="airport-information">
<div class="title">选择AI算法实例<span> 航飞要求 </span></div>
<div class="content">
<div class="content-edit instantiate" @click="instantiateVisible = !instantiateVisible">
<div class="input-result">
<span :style="{ backgroundColor: instantiateItem.bgColor }">
{{ instantiateItem.type }}</span
>
{{ instantiateItem.label }}
</div>
<DownOutlined v-if="instantiateVisible" />
<UpOutlined v-else />
<div class="select-result" v-if="instantiateVisible">
<div
v-for="(item, index) in instantiateOptions"
:key="index"
@click="instantiateSelect(item)"
>
<span :style="{ backgroundColor: item.bgColor }">{{ item.type }}</span>
{{ item.label }}
</div>
</div>
</div>
<div class="content-edit space">
<span>空间约束范围</span>
<div class="space-content">
<span>导入KML</span>
<span @click="drawarea = true">新增</span>
</div>
</div>
<div class="content-title">
<span>识别时间范围</span>
</div>
<div class="content-edit">
<a-select v-model:value="data.time" :options="timeOptions" />
</div>
<div class="content-title">
<span>触发动作</span>
</div>
<div class="content-edit">
<a-radio-group v-model:value="data.action" button-style="solid">
<a-radio-button value="1">关闭</a-radio-button>
<a-radio-button value="2">等待接管</a-radio-button>
</a-radio-group>
</div>
<div class="content-title">
<span>警告提示</span>
</div>
<div class="content-edit">
<a-input v-model:value="data.code" placeholder="异常提示" />
</div>
<div class="content-edit">
<a-textarea v-model:value="data.desc" placeholder="识别到异常目标" />
</div>
<div class="content-button">
<a-button type="primary" style="background: #3a57e8" @click="emits('changePatrol')"
>取消</a-button
>
<a-button
type="primary"
style="background: #0a99eb; margin-left: 20px"
@click="emits('changeLoadControl')"
>确定</a-button
>
</div>
</div>
<div class="patrol-map" v-if="drawarea">
<div class="title">绘制范围</div>
<div class="map-container">
<div class="map-container-content">
<Map :drawArea="drawarea" @areaData="getAreaData" />
</div>
</div>
<div class="content-button">
<a-button type="primary" style="background: #3a57e8" @click="drawarea = false"
>取消</a-button
>
<a-button
type="primary"
style="background: #0a99eb; margin-left: 20px"
@click="patrolMapConfirm"
>确定</a-button
>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, watch, onMounted } from 'vue';
import { useMessage } from '@/hooks/web/useMessage';
import { InfoCircleOutlined, DownOutlined, UpOutlined } from '@ant-design/icons-vue';
import { Map } from '../index';
const { createMessage } = useMessage();
const emits = defineEmits(['changePatrol']);
const props = defineProps({});
const data = reactive({
instantiate: null,
code: '',
desc: '',
action: '1',
time: null,
area: null,
});
const bgOptions = ref(['#6909B2', '#09B284', '#B2AA09', '#E240BD', '#E24040']);
const instantiateVisible = ref(false);
const instantiateOptions = ref([
{
label: '疑似违停车辆识别',
type: '违停车辆',
value: '1',
bgColor: bgOptions.value[0],
},
{
label: '疑似违停车辆识别',
type: '违停车辆',
value: '1',
bgColor: bgOptions.value[2],
},
]);
const timeOptions = ref([
{
label: '全天',
value: 'day',
},
]);
const instantiateItem = ref({});
const instantiateSelect = (val) => {
data.instantiate = val.value;
instantiateItem.value = val;
};
const drawarea = ref(false);
const getAreaData = (val) => {
console.log(val);
};
const patrolMapConfirm = () => {
if (!data.area) {
createMessage.warning('请绘制区域');
}
};
onMounted(() => {});
</script>
<style lang="less" scoped>
.airport-information {
position: absolute;
top: 100px;
right: 140px;
width: 260px;
padding: 10px;
background: #0d0e15;
margin: 10px 0 0 10px;
box-shadow:
0px 10px 30px 0px rgba(0, 0, 6, 0.15),
inset 0px 0px 36px 0px rgba(58, 87, 232, 0.73);
border-radius: 6px;
backdrop-filter: blur(3px);
color: #fff;
.title {
width: 100%;
padding: 10px 0;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-bottom: 1px solid #4e5778;
display: flex;
justify-content: space-between;
span {
color: #f2762d;
font-size: 12px;
}
}
.content-item {
display: flex;
align-items: center;
border-bottom: 1px solid #4e5778;
padding: 10px 0;
.item-div {
width: 49%;
cursor: pointer;
img {
width: 20px;
}
}
}
.content-button {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.content-edit {
display: flex;
align-items: center;
justify-content: space-between;
border: 1px solid #4e5778;
margin-top: 10px;
padding: 2px 10px;
border-radius: 4px;
font-size: 12px;
input {
background: none;
border: none;
color: #fff;
font-size: 12px;
}
textarea {
background: none;
color: #fff;
border: none;
}
::v-deep .ant-select-selector {
background: none;
width: 220px;
border: none;
text-align: center;
color: #fff;
font-size: 12px;
}
}
.instantiate {
padding: 10px 6px;
cursor: pointer;
position: relative;
div {
span {
margin-right: 6px;
}
}
.input-result {
span {
padding: 6px;
border-radius: 6px;
display: inline-block;
}
}
.select-result {
position: absolute;
top: 40px;
left: -2%;
width: 104%;
background: #0d0e15;
box-shadow:
0px 5px 15px 0px rgba(0, 0, 6, 0.15),
inset 0px 0px 18px 0px rgba(58, 87, 232, 0.73);
height: 300px;
overflow: auto;
z-index: 2;
border: 1px solid #4e5778;
div {
padding: 10px 6px;
border-bottom: 1px solid #1c1c1c;
span {
padding: 6px;
border-radius: 6px;
display: inline-block;
}
}
}
}
.space {
padding: 10px 4px;
font-size: 14px;
.space-content {
span {
color: #f2762d;
border: 1px solid #f2762d;
padding: 4px 6px;
border-radius: 18px;
font-size: 12px;
cursor: pointer;
}
span:last-child {
margin-left: 10px;
color: #0377f6;
border: 1px solid #0377f6;
}
}
}
.content-title {
padding-top: 10px;
.anticon {
margin-left: 4px;
cursor: pointer;
}
}
::v-deep .ant-radio-group {
width: 100%;
margin: 2px;
}
::v-deep .ant-radio-button-wrapper {
border: none;
width: 50%;
text-align: center;
background: #0b234d;
color: #fff;
box-shadow:
0px 10px 30px 0px rgba(0, 0, 6, 0.15),
0px 10px 30px 0px rgba(0, 0, 6, 0.15),
inset 0px -1px 5px 0px rgba(213, 220, 255, 0.73);
border-radius: 4px;
}
::v-deep .ant-radio-button-wrapper-checked {
background: #0377f6;
box-shadow:
0px 10px 30px 0px rgba(0, 0, 6, 0.15),
0px 10px 30px 0px rgba(0, 0, 6, 0.15),
inset 0px -1px 5px 0px rgba(213, 220, 255, 0.73);
}
}
.patrol-map {
position: absolute;
top: 10px;
right: 140px;
width: 800px;
height: 600px;
padding: 10px;
background: #0d0e15;
margin: 10px 0 0 10px;
box-shadow:
0px 10px 30px 0px rgba(0, 0, 6, 0.15),
inset 0px 0px 36px 0px rgba(58, 87, 232, 0.73);
border-radius: 6px;
backdrop-filter: blur(3px);
color: #fff;
z-index: 3;
.map-container {
width: 100%;
height: calc(100% - 80px);
}
.map-container-content {
height: calc(100% - 10px);
}
}
</style>

@ -222,6 +222,10 @@
},
"waylineWpmlConfig":{
type:Object
},
"drawArea":{
type:Boolean,
default:false
}
})
@ -347,7 +351,7 @@ const generatePreviewPoint = (placemark)=>{
}
};
const emits = defineEmits(['exitDraw', 'flyToThere', 'mapOnLoad', 'clickAirPort', 'changeAirportLive', 'changeUAVLive']);
const emits = defineEmits(['exitDraw', 'flyToThere', 'mapOnLoad', 'clickAirPort', 'changeAirportLive', 'changeUAVLive','areaData']);
const airPoints = ref([]);
const currentAirPoint = ref({});
@ -401,6 +405,8 @@ const generatePreviewPoint = (placemark)=>{
//
let polygonGraphicLayer: mars3d.layer.GraphicLayer;
//
let patrolPolygonGraphicLayer: mars3d.layer.GraphicLayer;
// 线
let polygonLineGraphicLayer: mars3d.layer.GeoJsonLayer;
@ -436,6 +442,8 @@ const generatePreviewPoint = (placemark)=>{
polygonGraphicLayer ? polygonGraphicLayer.clear() : null;
patrolPolygonGraphicLayer ? patrolPolygonGraphicLayer.clear() : null;
polygonLineGraphicLayer ? polygonLineGraphicLayer.clear() : null;
airPoints.value = [];
@ -699,6 +707,10 @@ const initMap = () => {
polygonGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: true, //
});
//
patrolPolygonGraphicLayer = new mars3d.layer.GraphicLayer({
isAutoEditing: true, //
})
polygonGraphicLayer.bindContextMenu([
{
@ -709,12 +721,26 @@ const initMap = () => {
},
},
]);
patrolPolygonGraphicLayer.bindContextMenu([
{
text: '删除测区',
icon: 'fa fa-camera-retro', // font-class
callback: (e) => {
handlerClearPolygonGraphicLayer(e);
},
},
]);
polygonGraphicLayer.on(mars3d.EventType.editMovePoint,(event)=>{
onPolygonGraphicLayerEdit(event);
})
patrolPolygonGraphicLayer.on(mars3d.EventType.editMovePoint,(event)=>{
console.log(event)
onPatrolPolygonGraphicLayerEdit(event);
})
map.addLayer(polygonGraphicLayer);
map.addLayer(patrolPolygonGraphicLayer);
//
@ -799,6 +825,17 @@ const handlerBindMapMenus = () => {
},
];
}
if(props.drawArea){
mapContextmenuItems = [
{
text: '添加面区域',
icon: 'fa fa-camera-retro', // font-class
callback: (e) => {
handlerDrawPolygonPatrol();
},
},
];
}
map.bindContextMenu(mapContextmenuItems);
};
@ -962,6 +999,26 @@ const handlerDrawPolygon = async () => {
//
handlerGetPolygonBorderInfo(polygonGeoJson.value);
};
//
const handlerDrawPolygonPatrol= async () => {
const graphic = await patrolPolygonGraphicLayer.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]);
polygonGeoJson.value = coordinates;
emits('areaData',polygonGeoJson.value);
};
// 线
const onPolygonGraphicLayerEdit = (e)=>{
@ -991,6 +1048,15 @@ const onPolygonGraphicLayerEdit = (e)=>{
}
//
const onPatrolPolygonGraphicLayerEdit = (e)=>{
let coordinates = e.graphic.toJSON().positions;
if(props.editMode == 'add'){
coordinates.push(coordinates[0]);
}
polygonGeoJson.value = coordinates;
emits('areaData',polygonGeoJson.value);
}
// 线
const handlerDrawPolygonLine = (lines) => {
//
@ -1254,6 +1320,8 @@ const handlerClearPolygonGraphicLayer = () => {
polygonLineGraphicLayer ? polygonLineGraphicLayer.clear() : null;
patrolPolygonGraphicLayer ? patrolPolygonGraphicLayer.clear() : null;
textLabelGraphicLayer ? textLabelGraphicLayer.clear() : null;
polygonGeoJson.value = null;
@ -2487,12 +2555,14 @@ const setUAVPosition = () => {
const airPortStoreVal = airPortStore();
const uav = airPortStoreVal.getUAV;
const type_subtype_gimbalindex = props.uavTrack[uav.camera_index];
const rectSensor = graphicLayer.getGraphicById("uav-route-rectSensor")
rectSensor.heading = type_subtype_gimbalindex.gimbal_yaw //0360
rectSensor.pitch = type_subtype_gimbalindex.gimbal_pitch //0360
rectSensor.roll = type_subtype_gimbalindex.gimbal_roll + 90 //0360
rectSensor.angle1 = 10 //1 0.1-89.9
rectSensor.angle2 = 10 //2 0.1-89.9
if(type_subtype_gimbalindex){
const rectSensor = graphicLayer.getGraphicById("uav-route-rectSensor")
rectSensor.heading = type_subtype_gimbalindex.gimbal_yaw //0360
rectSensor.pitch = type_subtype_gimbalindex.gimbal_pitch //0360
rectSensor.roll = type_subtype_gimbalindex.gimbal_roll + 90 //0360
rectSensor.angle1 = 10 //1 0.1-89.9
rectSensor.angle2 = 10 //2 0.1-89.9
}
}
};
// 线

Loading…
Cancel
Save