Compare commits

...

2 Commits

@ -9,4 +9,5 @@ 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 Report } from './src/Report.vue';
export { default as Map } from '../workplan/components/map.vue';

@ -72,17 +72,18 @@
@loadLiveStreaming="livePreviewVisible = false"
@changeCameraType="changeCameraType"
/>
<div class="intelligent-patrol">
<!-- <div class="intelligent-patrol">
<div @click="patrolVisible = true">
<span> <RadarChartOutlined /> </span>
<span>智能巡检</span>
</div>
<div @click="reportedBtn">
<div @click="reportVisible = true">
<span> <AlertOutlined /></span>
<span>上报事件</span>
</div>
</div>
<Patrol v-if="patrolVisible" @changePatrol="patrolVisible = false" />
<Report @changeReport="reportVisible = false" v-if="reportVisible" /> -->
</div>
</template>
<script setup lang="ts">
@ -100,6 +101,7 @@
TakeOffForm,
FlyToForm,
Patrol,
Report,
} from './index';
import { useMessage } from '@/hooks/web/useMessage';
import { getClient, createConnection, clientSubscribe, destroyConnection } from '@/utils/mqtt';
@ -198,6 +200,8 @@
const uavLive = ref(false);
//
const patrolVisible = ref(false);
//
const reportVisible = ref(false);
const changeAirportLive = () => {
airportLiveVisible.value = !airportLiveVisible.value;
zIndex.value++;
@ -271,7 +275,6 @@
//
clientSubscribe(topicUAVUrl, { qos: 1 });
};
const reportedBtn = () => {};
</script>
<style lang="less" scoped>
.map-container {

@ -1,68 +1,71 @@
<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>
<div class="shade-container" v-if="drawarea"></div>
<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>
<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 class="content-edit space">
<span>空间约束范围</span>
<div class="space-content">
<span>导入KML</span>
<span @click="drawarea = true"><PlusOutlined />新增</span>
</div>
</div>
</div>
<div class="content-edit space">
<span>空间约束范围</span>
<div class="space-content">
<span>导入KML</span>
<span @click="drawarea = true">新增</span>
<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" style="border: none">
<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="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">
@ -89,7 +92,7 @@
<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 { InfoCircleOutlined, DownOutlined, UpOutlined ,PlusOutlined} from '@ant-design/icons-vue';
import { Map } from '../index';
const { createMessage } = useMessage();
@ -142,11 +145,43 @@
onMounted(() => {});
</script>
<style lang="less" scoped>
.shade-container {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
left: 0;
z-index: 1000;
}
.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;
align-items: center;
span {
color: #f2762d;
font-size: 12px;
border-radius: 10px;
border: 1px solid #f2762d;
display: inline-block;
padding: 4px 6px;
}
}
.content-button {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.airport-information {
position: absolute;
top: 100px;
right: 140px;
width: 260px;
width: 290px;
padding: 10px;
background: #0d0e15;
margin: 10px 0 0 10px;
@ -156,18 +191,6 @@
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;
@ -182,12 +205,7 @@
}
}
}
.content-button {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.content-edit {
display: flex;
align-items: center;
@ -261,16 +279,16 @@
padding: 10px 4px;
font-size: 14px;
.space-content {
span {
> span {
color: #f2762d;
border: 1px solid #f2762d;
padding: 4px 6px;
padding: 4px 8px;
border-radius: 18px;
font-size: 12px;
cursor: pointer;
}
span:last-child {
> span:last-child {
margin-left: 10px;
color: #0377f6;
border: 1px solid #0377f6;
@ -310,8 +328,8 @@
}
.patrol-map {
position: absolute;
top: 10px;
right: 140px;
top: 80px;
right: calc(50% - 400px);
width: 800px;
height: 600px;
padding: 10px;
@ -323,7 +341,8 @@
border-radius: 6px;
backdrop-filter: blur(3px);
color: #fff;
z-index: 3;
z-index: 1001;
.map-container {
width: 100%;
height: calc(100% - 80px);

@ -0,0 +1,400 @@
<template>
<div>
<div class="shade-container"></div>
<div class="patrol-map" v-if="step == 1">
<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="emits('changeReport')"
>取消</a-button
>
<a-button type="primary" style="background: #0a99eb; margin-left: 20px" @click="nextStep"
>下一步</a-button
>
</div>
</div>
<div class="airport-information" v-else>
<div class="title">关联事件</div>
<div class="content">
<div class="content-edit">
<span class="edit-title">发生时间</span>
<a-input v-model:value="data.time" placeholder="异常提示" readonly />
</div>
<div class="content-edit instantiate">
<span class="edit-title">关联事件</span>
<div class="input-container" @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>
<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">
<span class="edit-title">描述</span>
<a-input v-model:value="data.desc" />
</div>
<div class="content-edit">
<span class="edit-title">发生位置</span>
<a-input v-model:value="data.location" readonly />
</div>
<div class="clearfix"></div>
<div class="map-view">
<div class="map-view-container">
<div class="map-view-container-content">
<Map :polygonArea="data.area" />
</div>
</div>
</div>
<div class="content-button">
<a-button type="primary" style="background: #3a57e8" @click="lastStep"></a-button>
<a-button
type="primary"
style="background: #0a99eb; margin-left: 20px"
@click="reportConfirm"
>提交关联</a-button
>
<a-button
type="primary"
style="background: #0a99eb; margin-left: 20px"
@click="reportConfirm"
>上报新事件</a-button
>
</div>
</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 step = ref(1);
const { createMessage } = useMessage();
const emits = defineEmits(['changeReport']);
const props = defineProps({});
const data = reactive({
location: null,
instantiate: '',
desc: '',
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 instantiateItem = ref({});
const instantiateSelect = (val) => {
data.instantiate = val.value;
instantiateItem.value = val;
instantiateVisible.value = false;
};
const drawarea = ref(true);
const getAreaData = (val) => {
console.log(val);
data.area = val;
const center = getPointsCalculateCenter(val);
data.location = center[1] + '°E,' + center[0] + '°N';
};
const nextStep = () => {
if (!data.area) {
createMessage.warning('请绘制区域');
return;
}
step.value = 2;
};
const lastStep = () => {
step.value = 1;
};
const reportConfirm = () => {};
const getPointsCalculateCenter = (points) => {
let point_num = points.length; //
let X = 0,
Y = 0,
Z = 0;
for (let i = 0; i < points.length; i++) {
if (points[i] == '') {
continue;
}
let point = points[i];
let lat, lng, x, y, z;
lat = (parseFloat(point[1]) * Math.PI) / 180;
lng = (parseFloat(point[0]) * Math.PI) / 180;
x = Math.cos(lat) * Math.cos(lng);
y = Math.cos(lat) * Math.sin(lng);
z = Math.sin(lat);
X += x;
Y += y;
Z += z;
}
X = X / point_num;
Y = Y / point_num;
Z = Z / point_num;
let tmp_lng = Math.atan2(Y, X);
let tmp_lat = Math.atan2(Z, Math.sqrt(X * X + Y * Y));
return [(tmp_lat * 180) / Math.PI, (tmp_lng * 180) / Math.PI];
};
onMounted(() => {});
</script>
<style lang="less" scoped>
.shade-container {
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
left: 0;
z-index: 1000;
}
.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-button {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.airport-information {
position: absolute;
top: 100px;
right: calc(50% - 360px);
width: 700px;
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: 1001;
.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-edit {
display: flex;
flex-direction: column;
margin-top: 14px;
padding: 2px 10px;
border-radius: 4px;
font-size: 12px;
width: 49%;
float: left;
.edit-title {
display: block;
width: 100px;
margin: 10px 0;
}
input {
background: none;
border: 1px solid #4e5778;
color: #fff;
font-size: 12px;
}
textarea {
background: none;
color: #fff;
border: none;
}
::v-deep .ant-select-selector {
background: none;
width: 220px;
border: 1px solid #4e5778;
text-align: center;
color: #fff;
font-size: 12px;
}
}
.instantiate {
cursor: pointer;
position: relative;
div {
span {
margin-right: 6px;
}
}
.input-container {
width: 100%;
border: 1px solid #4e5778;
display: flex;
border-radius: 6px;
padding: 2px 6px;
}
.input-result {
width: 92%;
height: 26px;
span {
padding: 6px;
border-radius: 6px;
display: inline-block;
}
}
.select-result {
position: absolute;
top: 70px;
left: 0;
width: 100%;
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: 80px;
right: calc(50% - 400px);
width: 900px;
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: 1001;
.map-container {
width: 100%;
height: calc(100% - 80px);
}
.map-container-content {
height: calc(100% - 10px);
}
}
.map-view {
margin-top: 20px;
.map-view-container {
width: 100%;
height: calc(100% - 80px);
}
.map-view-container-content {
height: calc(100% - 10px);
}
}
.clearfix {
clear: both;
}
</style>

@ -157,6 +157,7 @@
<a-switch v-model:checked="submitForm.aiInspection"
checked-color="#3A57E8"
un-checked-color="#cccccc"
@change="changeAiInspection"
/>
</div>
</div>
@ -489,7 +490,7 @@ watch(
}
)
const emit = defineEmits(['selectAriLine','cancleCraete',"selectAircraft","successCreatePlan"]);
const emit = defineEmits(['selectAriLine','cancleCraete',"selectAircraft","successCreatePlan","intelligentPatrol"]);
const removeAirLine = ()=>{
props.checkedAriLine.value = {};
@ -719,7 +720,11 @@ const handleRepeatTypeChange = ()=>{
submitForm.value.periodicFormula = cronTime;
}
const changeAiInspection = (val)=>{
if(val){
emit('intelligentPatrol')
}
}
</script>
<style scoped>

@ -226,7 +226,10 @@
"drawArea":{
type:Boolean,
default:false
}
},
"polygonArea":{
type:Object
},
})
@ -240,7 +243,14 @@
}
}
)
watch(
() => props.polygonArea,
(newVal,oldVal)=>{
if(newVal ){
handlerReportPolygonAirLine();
}
}
)
watch(
@ -759,6 +769,10 @@ const initMap = () => {
if(props.editMode == 'edit' ){
handlerEditPolygonAirLine();
}
//
if(props.polygonArea){
handlerReportPolygonAirLine();
}
emits('mapOnLoad',map)
@ -1554,6 +1568,37 @@ const handlerEditPolygonAirLine =async () => {
// handlerDrawPolygonLine(line);
}
//
const handlerReportPolygonAirLine = ()=>{
let geometry = {
"type": "Polygon",
"coordinates": [props.polygonArea]
}
let geojsonData = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": geometry
}
]
}
patrolPolygonGraphicLayer ? patrolPolygonGraphicLayer.clear() : null;
patrolPolygonGraphicLayer.loadGeoJSON(geojsonData,{
type: 'polygon',
flyTo:true,
style: {
color: '#408eff',
opacity: 0.3,
outline: true,
outlineColor: '#408eff',
outlineWidth: 3.0,
clampToGround: true,
},
})
}
///////////////////////////////线////////////////////////////////////////////

@ -16,7 +16,11 @@
<!-- 创建计划 -->
<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"></createWorkPlan>
<createWorkPlan :workPlanStatus="workPlanStatus" :formData="formData" @successCreatePlan="successCreatePlan" @cancleCraete="cancleCraete" @selectAircraft="selectAircraft" @selectAriLine="selectAriLine" :checkedAriLine="checkedAriLine" :checkedDronePort="checkedDronePort" @intelligentPatrol="changePatrolShow"></createWorkPlan>
</div>
<!-- 智能巡检 -->
<div v-if="patrolShow" class="patrol-box">
<Patrol @changePatrol="patrolShow = false"/>
</div>
<!-- 航线库 -->
@ -64,7 +68,7 @@ import createAirLine from './components/createAirLine.vue'
import Map from './components/map.vue'
import AirPolygon from './components/airPolygon.vue';
import {getAirLine} from '@/api/sys/workplan';
import { Patrol } from '../flightoperation/index';
import JSZip from 'jszip';
import axios from 'axios';
@ -114,7 +118,7 @@ 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;
@ -123,6 +127,9 @@ const selectAriLine = ()=> {
ariLineShow.value = true;
aircraftShow.value = false;
}
const changePatrolShow = ()=>{
patrolShow.value = true;
}
// 线
const closeAirLine = ()=>{
@ -311,4 +318,16 @@ onMounted(()=>{
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>

Loading…
Cancel
Save