徐景良 2 months ago
commit 0ec3d35163

@ -8,6 +8,7 @@ enum Api {
DeleteUav = '/api/Manage/DeleteUav',
GetGateway = '/api/AirportMaintenance/GetGateway',
GetManageDeviceHmsList = '/api/AirportMaintenance/GetManageDeviceHmsList',
ExportDevice = '/api/Manage/ExportDevice'
}
export function GetDataList(params) {
@ -54,4 +55,11 @@ export function GetManageDeviceHmsList(params) {
url: Api.GetManageDeviceHmsList,
params
});
}
export function ExportDevice(params?) {
return defHttp.get({
url: Api.ExportDevice,
params,
responseType: 'blob',
});
}

@ -1,7 +1,7 @@
<template>
<BasicTable class="w-4/4 xl:w-5/5" @register="registerTable">
<template #toolbar>
<a-button type="primary">导出飞行器信息</a-button>
<a-button type="primary" @click="exportDevice"></a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key == 'workSpaceId'">
@ -37,8 +37,8 @@
import { h, watch, onMounted, ref, nextTick } from "vue"
import { EditOutlined } from '@ant-design/icons-vue'
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { columns, dataSource, searchFormSchema } from './utils'
import { GetUavPageList, DeleteUav } from '@/api/demo/device'
import { columns, searchFormSchema } from './utils'
import { GetUavPageList, DeleteUav, ExportDevice } from '@/api/demo/device'
import { getClient, clientSubscribe } from '@/utils/mqtt'
import dayjs from "dayjs";
import { message, Modal } from "ant-design-vue";
@ -48,7 +48,7 @@ const props = defineProps(['projectList','connected'])
const editDeviceDate = ref({})
const editDeviceModal = ref(false)
onMounted(() => {
const targetField = searchFormSchema.find(item => item.field === 'project');
const targetField = searchFormSchema.find(item => item.field === 'workspaceid');
if (targetField) {
targetField.componentProps = {
...(targetField.componentProps || {}),
@ -131,6 +131,18 @@ const delDate = (record) => {
},
});
}
const exportDevice = () => {
ExportDevice().then(res => {
const elink = document.createElement('a');
elink.download = '飞行器信息.xlsx';
elink.style.display = 'none';
elink.href = URL.createObjectURL(res);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
})
}
</script>
<style lang="scss" scoped></style>

@ -28,32 +28,11 @@ export const columns = [
title: '加入组织时间',
dataIndex: 'updateTime',
},
{
title: '在线时间',
dataIndex: 'online_time',
},
];
export const dataSource = [
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
{ model: 111, sn:222, name: 333, version: 444, status: 555, project: 666, join_time: 777, online_time: 888 },
]
export const searchFormSchema: FormSchema[] = [
{
field: 'project',
field: 'workspaceid',
label: '项目',
component: 'Select',
componentProps: {
@ -63,25 +42,9 @@ export const searchFormSchema: FormSchema[] = [
colProps: { span: 4 },
},
{
field: 'status',
label: '当前状态',
component: 'Select',
componentProps: {
options: [
{ label: '在线', value: '在线' },
{ label: '离线', value: '离线' },
],
},
colProps: { span: 4 },
},
{
field: 'model',
field: 'type',
label: '设备型号',
component: 'Select',
componentProps: {
options: [
],
},
component: 'Input',
colProps: { span: 4 },
},
{

@ -88,7 +88,7 @@ import { cloneDeep } from 'lodash-es';
const props = defineProps(['projectList','connected'])
watch(() => props.projectList, () => {
const targetField = searchFormSchema.find(item => item.field === 'project');
const targetField = searchFormSchema.find(item => item.field === 'workspaceid');
if (targetField) {
targetField.componentProps = {
...(targetField.componentProps || {}),

@ -14,16 +14,16 @@ export const columns = [
},
{
title: '固件版本',
dataIndex: 'version',
},
{
title: '固件升级',
dataIndex: 'compatible_status',
},
{
title: '飞行安全数据库',
dataIndex: 'database',
dataIndex: 'firmwareVersion',
},
// {
// title: '固件升级',
// dataIndex: 'compatible_status',
// },
// {
// title: '飞行安全数据库',
// dataIndex: 'database',
// },
{
title: '工作状态',
dataIndex: 'flighttask_step_code',
@ -35,47 +35,43 @@ export const columns = [
{
title: '加入组织时间',
dataIndex: 'createTime',
},
{
title: '在线时间',
dataIndex: 'first_power_on',
},
}
];
export const searchFormSchema: FormSchema[] = [
// {
// field: 'upgrade_status',
// label: '升级状态',
// component: 'Select',
// componentProps: {
// options: [
// { label: '固件待升级', value: '固件待升级' },
// { label: '固件一致性升级', value: '固件一致性升级' },
// { label: '飞行安全数据库待升级', value: '飞行安全数据库待升级' },
// ],
// },
// colProps: { span: 4 },
// },
// {
// field: 'work_status',
// label: '工作状态',
// component: 'Select',
// componentProps: {
// options: [
// { label: '全部工作状态', value: '全部工作状态' },
// { label: '设备空闲中', value: '设备空闲中' },
// { label: '现场调试中', value: '现场调试中' },
// { label: '远程调试中', value: '远程调试中' },
// { label: '设备作业中', value: '设备作业中' },
// { label: '设备升级中', value: '设备升级中' },
// { label: '设备已离线', value: '设备已离线' },
// { label: '未标定', value: '未标定' },
// ],
// },
// colProps: { span: 4 },
// },
{
field: 'upgrade_status',
label: '升级状态',
component: 'Select',
componentProps: {
options: [
{ label: '固件待升级', value: '固件待升级' },
{ label: '固件一致性升级', value: '固件一致性升级' },
{ label: '飞行安全数据库待升级', value: '飞行安全数据库待升级' },
],
},
colProps: { span: 4 },
},
{
field: 'work_status',
label: '工作状态',
component: 'Select',
componentProps: {
options: [
{ label: '全部工作状态', value: '全部工作状态' },
{ label: '设备空闲中', value: '设备空闲中' },
{ label: '现场调试中', value: '现场调试中' },
{ label: '远程调试中', value: '远程调试中' },
{ label: '设备作业中', value: '设备作业中' },
{ label: '设备升级中', value: '设备升级中' },
{ label: '设备已离线', value: '设备已离线' },
{ label: '未标定', value: '未标定' },
],
},
colProps: { span: 4 },
},
{
field: 'project',
field: 'workspaceid',
label: '项目',
component: 'Select',
componentProps: {
@ -87,15 +83,11 @@ export const searchFormSchema: FormSchema[] = [
{
field: 'model',
label: '设备型号',
component: 'Select',
componentProps: {
options: [
],
},
component: 'Input',
colProps: { span: 4 },
},
{
field: 'key',
field: 'sn',
label: '设备SN',
component: 'Input',
colProps: { span: 6 },

@ -0,0 +1,375 @@
<template>
<div class="pathModal">
<!-- 左侧目录 -->
<div
class="leftMenuDiv"
:style="{
width: leftMenuShow ? '275px' : '0px',
}"
>
<PathLeftMenu
ref="pathLeftMenuRef"
:pathRecord="props.pathRecord"
:leftMenuShow="leftMenuShow"
:allAnnotationDataList="allAnnotationDataList"
:nowShowAnnotationData="nowShowAnnotationData"
:allAreaDataList="allAreaDataList"
:nowShowAreaData="nowShowAreaData"
:allImageDataList="allImageDataList"
:nowShowImageData="nowShowImageData"
@changeLeftMenuShow="changeLeftMenuShow"
@handlerLocation="handlerLocation"
@closePathModal="closePathModal"
@changeAnnotationInfoShow="changeAnnotationInfoShow"
@setNowShowAnnotationData="setNowShowAnnotationData"
@setNowShowImageData="setNowShowImageData"
@setNowShowAreaData="setNowShowAreaData"
@setAllAnnotationData="setAllAnnotationData"
@setAllAreaData="setAllAreaData"
@deleteAnnotation="deleteAnnotation"
@deleteArea="deleteArea"
/>
</div>
<!-- 地图 -->
<div class="mapDiv" :style="{ width: dynamicWidth }">
<PathMap
ref="pathMapRef"
:allAnnotationDataList="allAnnotationDataList"
:nowShowAnnotationData="nowShowAnnotationData"
:allAreaDataList="allAreaDataList"
:nowShowAreaData="nowShowAreaData"
:allImageDataList="allImageDataList"
:nowShowImageData="nowShowImageData"
@setNowShowAnnotationData="setNowShowAnnotationData"
@setNowShowImageData="setNowShowImageData"
@setNowShowAreaData="setNowShowAreaData"
@setAllAnnotationData="setAllAnnotationData"
@setAllImageData="setAllImageData"
@setAllAreaData="setAllAreaData"
@closePathImageInfo="closePathImageInfo"
/>
</div>
<!-- 地图标注 -->
<div class="annotationInfoDiv" v-if="annotationInfoShow">
<PathAnnotationInfo
:allAnnotationDataList="allAnnotationDataList"
:nowShowAnnotationData="nowShowAnnotationData"
@setNowShowAnnotationData="setNowShowAnnotationData"
@closePathAnnotationInfo="closePathAnnotationInfo"
@handlerLocation="handlerLocation"
@deleteAnnotation="deleteAnnotation"
/>
</div>
<!-- 地图作业区域 -->
<!-- <div class="areaInfoDiv" v-if="areaInfoShow">
<PathAreaInfo
:allAreaDataList="allAreaDataList"
:nowShowAreaData="nowShowAreaData"
@setNowShowAreaData="setNowShowAreaData"
@closePathAreaInfo="closePathAreaInfo"
@handlerLocation="handlerLocation"
@deleteArea="deleteArea"
/>
</div> -->
<!-- 地图照片 -->
<!-- <div class="imageInfoDiv" v-if="imageInfoShow">
<PathImageInfo
:allImageDataList="allImageDataList"
:nowShowImageData="nowShowImageData"
@setNowShowImageData="setNowShowImageData"
@closePathImageInfo="closePathImageInfo"
@handlerLocation="handlerLocation"
/>
</div> -->
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue';
import { PathLeftMenu, PathMap, PathAnnotationInfo, PathAreaInfo, PathImageInfo } from './path';
import { cloneDeep } from 'lodash-es';
import imageJson from './json/image.json';
import {
GetAnnotationList,
DeleteAnnotation,
GetWorkAreaList,
DeleteWorkArea,
} from '@/api/demo/mediaLibrary';
import { WktToGeojson, GeojsonToWkt } from '@/components/MapboxMaps/src/WktGeojsonTransform';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage, createConfirm } = useMessage();
const props = defineProps(['pathRecord']);
const emits = defineEmits(['closePathModal']);
//
const dynamicWidth = computed(() => {
let width = 0;
//
if (leftMenuShow.value) {
width += 275;
} else {
width += 0;
}
//
if (annotationInfoShow.value) {
width += 320;
}
// //
// if (areaInfoShow.value) {
// width += 320;
// }
// //
// if (imageInfoShow.value) {
// width += 720;
// }
return 'calc(100% - ' + width + 'px)';
});
// ref
const pathMapRef = ref();
// ----------------------------------------------------
const pathLeftMenuRef = ref();
const leftMenuShow = ref(true);
function changeLeftMenuShow() {
leftMenuShow.value = !leftMenuShow.value;
}
// ----------------------------------------------------
const annotationInfoShow = ref(false);
function changeAnnotationInfoShow() {
annotationInfoShow.value = !annotationInfoShow.value;
}
//
function closePathAnnotationInfo() {
annotationInfoShow.value = false;
nowShowAnnotationData.value = {};
pathMapRef.value.annotationRestoreDefault();
}
//
const nowShowAnnotationData = ref();
const allAnnotationDataList: any = ref([]);
//
function setNowShowAnnotationData(value, restore = true) {
if (value.id) {
annotationInfoShow.value = true;
} else {
annotationInfoShow.value = false;
}
if (restore) {
pathMapRef.value.annotationRestoreDefault();
}
nowShowAnnotationData.value = value;
}
//
function setAllAnnotationData() {
//
getAnnotationList();
}
//
async function getAnnotationList(showThis = true) {
allAnnotationDataList.value = await GetAnnotationList({ workspaceid: 1 });
if (allAnnotationDataList.value.length > 0) {
allAnnotationDataList.value.forEach((annotation, index) => {
let geomjson = WktToGeojson(annotation.geom);
annotation = {
...annotation,
properties: JSON.parse(annotation.properties),
geomtype: getGeomType(annotation),
coordinates: geomjson.coordinates,
};
allAnnotationDataList.value[index] = annotation;
});
}
if (showThis) {
setTimeout(() => {
pathLeftMenuRef.value.updateShowMenuInfoList('地图标注');
}, 50);
}
}
//
function deleteAnnotation(value) {
if (nowShowAnnotationData.value && nowShowAnnotationData.value.id == value.id) {
annotationInfoShow.value = false;
nowShowAnnotationData.value = {};
}
DeleteAnnotation({
id: value.id,
}).then((result) => {
if (result) {
//
getAnnotationList();
createMessage.success('删除成功');
}
});
}
// ----------------------------------------------------
const areaInfoShow = ref(false);
function changeAreaInfoShow() {
areaInfoShow.value = !areaInfoShow.value;
}
//
function closePathAreaInfo() {
areaInfoShow.value = false;
nowShowAreaData.value = {};
pathMapRef.value.areaRestoreDefault();
}
//
const nowShowAreaData = ref();
const allAreaDataList: any = ref([]);
//
function setNowShowAreaData(value, restore = true) {
if (value.id) {
areaInfoShow.value = true;
} else {
areaInfoShow.value = false;
}
if (restore) {
pathMapRef.value.areaRestoreDefault();
}
nowShowAreaData.value = value;
}
//
function setAllAreaData() {
//
getWorkAreaList();
}
//
async function getWorkAreaList(showThis = true) {
allAreaDataList.value = await GetWorkAreaList({ workspaceid: 1 });
if (allAreaDataList.value.length > 0) {
allAreaDataList.value.forEach((area, index) => {
let geomjson = WktToGeojson(area.geom);
area = {
...area,
properties: JSON.parse(area.properties),
geomtype: getGeomType(area),
coordinates: geomjson.coordinates,
};
allAreaDataList.value[index] = area;
});
}
if (showThis) {
setTimeout(() => {
pathLeftMenuRef.value.updateShowMenuInfoList('地图作业区域');
}, 50);
}
}
//
async function deleteArea(value) {
if (nowShowAreaData.value && nowShowAreaData.value.id == value.id) {
areaInfoShow.value = false;
nowShowAreaData.value = {};
}
DeleteWorkArea({
id: value.id,
}).then((result) => {
if (result) {
//
getWorkAreaList();
createMessage.success('删除成功');
}
});
}
// ----------------------------------------------------
const imageInfoShow = ref(false);
//
function closePathImageInfo() {
imageInfoShow.value = false;
}
//
const nowShowImageData = ref();
const allImageDataList = ref(imageJson);
//
function setNowShowImageData(value) {
if (value.id) {
imageInfoShow.value = true;
} else {
imageInfoShow.value = false;
}
nowShowImageData.value = value;
pathMapRef.value.setNowShowImageByRight();
}
// -----------------------------------------------------------------
//
function closePathModal() {
emits('closePathModal');
}
//
function handlerLocation(position) {
pathMapRef.value.handlerLocation([position.lng, position.lat]);
}
// WKT
function getGeomType(area) {
let geom = area.geom;
let radiusFlag = area.properties.indexOf('radius') > -1 ? true : false;
//
if (geom.indexOf('POINT') > -1 && !radiusFlag) {
return 'Point';
}
// 线
if (geom.indexOf('LINESTRING') > -1 && !radiusFlag) {
return 'Polyline';
}
//
if (geom.indexOf('POLYGON') > -1 && !radiusFlag) {
return 'Polygon';
}
//
if (geom.indexOf('POLYGON') > -1 && radiusFlag) {
return 'Circle';
}
}
onMounted(() => {
//
getWorkAreaList(false);
getAnnotationList();
});
</script>
<style lang="less" scoped>
.pathModal {
position: relative;
display: flex;
width: 100%;
height: 100%;
.leftMenuDiv {
position: relative;
height: 100%;
}
.mapDiv {
position: relative;
height: 100%;
// width: auto;
}
.annotationInfoDiv {
position: relative;
height: 100%;
width: 320px;
}
.areaInfoDiv {
position: relative;
height: 100%;
width: 320px;
}
.imageInfoDiv {
position: relative;
height: 100%;
// width: 37%;
width: 720px;
// min-width: 720px;
}
}
</style>

@ -0,0 +1,5 @@
export { default as PathLeftMenu } from './pathLeftMenu.vue';
export { default as PathMap } from './pathMap.vue';
export { default as PathImageInfo } from './pathImageInfo.vue';
export { default as PathAnnotationInfo } from './pathAnnotationInfo.vue';
export { default as PathAreaInfo } from './pathAreaInfo.vue';

@ -0,0 +1,750 @@
<template>
<div class="annotationInfo">
<!-- 关闭按钮 -->
<div class="closeButton">
<CloseOutlined @click="closePathAnnotationInfo" style="font-size: 20px; color: white" />
</div>
<div class="annotationInfo_biaozhu_1">
<a-row>
<a-col :span="24">
<div class="annotationTitle">标注信息</div>
</a-col>
<!-- 标题名线 -->
<a-col :span="24">
<div class="annotationTitle">
<div class="annotationTitleButton_right">
<AntDesignOutlined
v-if="nowAnnotationData.type == 0"
:style="{ color: nowAnnotationData.properties.color }"
/>
<ExpandAltOutlined
v-if="nowAnnotationData.type == 1"
:style="{ color: nowAnnotationData.properties.color }"
/>
<BorderOutlined
v-if="nowAnnotationData.type == 2"
:style="{ color: nowAnnotationData.properties.color }"
/>
<LogoutOutlined
v-if="nowAnnotationData.type == 3"
:style="{ color: nowAnnotationData.properties.color }"
/>
</div>
<a-input
v-model:value="nowAnnotationData.name"
style="width: 60%"
size="small"
></a-input>
<div class="annotationTitleButton" @click="handlerLocation">
<AimOutlined />
</div>
<div class="annotationTitleButton" @click="deleteAnnotation">
<DeleteOutlined />
</div>
</div>
</a-col>
<!-- 颜色线 -->
<a-col :span="6">
<div class="annotationTitle">颜色</div>
</a-col>
<a-col :span="18">
<div class="annotationContent">
<div
class="popoverClass"
v-for="color in ['#2D8CF0', '#19BE6B', '#FF9900', '#E23C39', '#B620E0']"
:key="color"
:style="{ background: color }"
@click="nowAnnotationData.properties.color = color"
>
<CheckOutlined
v-if="nowAnnotationData.properties.color == color"
style="color: white"
/>
</div>
</div>
</a-col>
<!-- 形态线 -->
<a-col :span="6" v-if="nowAnnotationData.type == 1">
<div class="annotationTitle">形态</div>
</a-col>
<a-col :span="18" v-if="nowAnnotationData.type == 1">
<div class="annotationContent" style="gap: 5%">
<a-tooltip placement="top">
<template #title> 线宽度 </template>
<a-input
v-model:value="nowAnnotationData.properties.line_width"
style="width: 30%"
@change="
nowAnnotationData.properties.line_width = parseFloat(
nowAnnotationData.properties.line_width.toString().replace(/[^-0-9]/g, ''),
)
"
>
<template #prefix><AlignLeftOutlined /></template>
</a-input>
</a-tooltip>
<a-tooltip placement="top">
<template #title> 线头部样式 </template>
<a-select
v-model:value="nowAnnotationData.properties.line_start_cap"
style="width: 30%"
option-label-prop="children"
>
<a-select-option :value="0">
<div class="svg-container" v-html="line_start_cap_0"></div>
</a-select-option>
<a-select-option :value="1">
<div class="svg-container" v-html="line_start_cap_1"></div>
</a-select-option>
<a-select-option :value="2">
<div class="svg-container" v-html="line_start_cap_2"></div>
</a-select-option>
<a-select-option :value="3">
<div class="svg-container" v-html="line_start_cap_3"></div>
</a-select-option>
</a-select>
</a-tooltip>
<a-tooltip placement="top">
<template #title> 线尾部样式 </template>
<a-select
v-model:value="nowAnnotationData.properties.line_end_cap"
style="width: 30%"
option-label-prop="children"
>
<a-select-option :value="0">
<div class="svg-container" v-html="line_end_cap_0"></div>
</a-select-option>
<a-select-option :value="1">
<div class="svg-container" v-html="line_end_cap_1"></div>
</a-select-option>
<a-select-option :value="2">
<div class="svg-container" v-html="line_end_cap_2"></div>
</a-select-option>
<a-select-option :value="3">
<div class="svg-container" v-html="line_end_cap_3"></div>
</a-select-option>
</a-select>
</a-tooltip>
</div>
</a-col>
<!-- 图标 -->
<a-col :span="6" v-if="nowAnnotationData.type == 0">
<div class="annotationTitle">图标</div>
</a-col>
<a-col :span="18" v-if="nowAnnotationData.type == 0">
<div class="annotationContent">
<div
class="annotationContentButton"
:style="
nowAnnotationData.properties.iconname == iconname
? 'outline: 2px solid #5cadff'
: ''
"
v-for="iconname in [
'defaultIcon',
'fireIcon',
'peopleIcon',
'warnIcon',
'carIcon',
'checkIcon',
'closeIcon',
]"
:key="iconname"
>
<div
class="svg-container"
v-html="getIcon(iconname)"
@click="nowAnnotationData.properties.iconname = iconname"
/>
</div>
</div>
</a-col>
<!-- 字体线 -->
<a-col :span="6">
<div class="annotationTitle">字体</div>
</a-col>
<a-col :span="18">
<div class="annotationContent">
<a-radio-group
v-model:value="nowAnnotationData.properties.font_size"
button-style="solid"
size="small"
>
<a-radio-button :value="16"></a-radio-button>
<a-radio-button :value="24"></a-radio-button>
<a-radio-button :value="32"></a-radio-button>
</a-radio-group>
</div>
</a-col>
</a-row>
</div>
<div style="border-bottom: 1px solid #ffffff55; margin-left: 15px; margin-right: 15px"></div>
<div class="annotationInfo_biaozhu_2">
<a-row>
<a-col :span="24">
<div class="annotationTitle">
测量数据
<a-tooltip placement="top">
<template #title> 只能测量出当前视窗范围内的数据 </template>
<InfoCircleOutlined style="margin-left: 10px" />
</a-tooltip>
</div>
</a-col>
<!-- 经纬模式 -->
<a-col :span="6" v-if="[0, 3].includes(nowAnnotationData.type)">
<div class="annotationTitle">经纬模式</div>
</a-col>
<a-col :span="18" v-if="[0, 3].includes(nowAnnotationData.type)">
<div class="annotationContent">
<a-radio-group v-model:value="modalType">
<a-radio :value="0"><span style="color: white">十进制</span></a-radio>
<a-radio :value="1"><span style="color: white">度分秒</span></a-radio>
</a-radio-group>
</div>
</a-col>
<!-- 经度 -->
<a-col :span="6" v-if="[0].includes(nowAnnotationData.type)">
<div class="annotationTitle">经度</div>
</a-col>
<a-col :span="18" v-if="[0].includes(nowAnnotationData.type)">
<div class="annotationContent">
<!-- 十进制 -->
<a-input v-if="modalType == 0" v-model:value="nowAnnotationData.coordinates[0]">
<template #addonAfter>
<span style="color: white">°</span>
</template>
</a-input>
<!-- 度分秒 -->
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_0.degrees"
style="max-width: 32px"
@change="
decimalToDMS_0.degrees = parseFloat(
decimalToDMS_0.degrees.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white">°</span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_0.minutes"
style="max-width: 30px"
@change="
decimalToDMS_0.minutes = parseFloat(
decimalToDMS_0.minutes.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_0.seconds"
style="width: 120px"
@change="
decimalToDMS_0.seconds = parseFloat(
decimalToDMS_0.seconds.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
</div>
</a-col>
<!-- 纬度 -->
<a-col :span="6" v-if="[0].includes(nowAnnotationData.type)">
<div class="annotationTitle">纬度</div>
</a-col>
<a-col :span="18" v-if="[0].includes(nowAnnotationData.type)">
<div class="annotationContent">
<!-- 十进制 -->
<a-input v-if="modalType == 0" v-model:value="nowAnnotationData.coordinates[1]">
<template #addonAfter>
<span style="color: white">°</span>
</template>
</a-input>
<!-- 度分秒 -->
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_1.degrees"
style="max-width: 32px"
@change="
decimalToDMS_1.degrees = parseFloat(
decimalToDMS_1.degrees.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white">°</span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_1.minutes"
style="max-width: 30px"
@change="
decimalToDMS_1.minutes = parseFloat(
decimalToDMS_1.minutes.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
<a-input
v-if="modalType == 1"
v-model:value="decimalToDMS_1.seconds"
style="width: 120px"
@change="
decimalToDMS_1.seconds = parseFloat(
decimalToDMS_1.seconds.toString().replace(/[^-0-9]/g, ''),
)
"
/>
<span v-if="modalType == 1" style="margin: 2px; color: white"></span>
</div>
</a-col>
<!-- 高度 -->
<a-col :span="6" v-if="[0].includes(nowAnnotationData.type)">
<div class="annotationTitle">高度</div>
</a-col>
<a-col :span="18" v-if="[0].includes(nowAnnotationData.type)">
<div class="annotationContent">
<a-input v-model:value="nowAnnotationData.coordinates[2]">
<template #addonAfter> <span style="color: white">m</span> </template>
</a-input>
</div>
</a-col>
<!-- 圆心经度 -->
<a-col :span="6" v-if="[3].includes(nowAnnotationData.type)">
<div class="annotationTitle">圆心经度</div>
</a-col>
<a-col :span="18" v-if="[3].includes(nowAnnotationData.type)">
<div class="annotationContent">
<a-input v-model:value="nowAnnotationData.properties.centerPoint[0]">
<template #addonAfter> <span style="color: white">°</span> </template>
</a-input>
</div>
</a-col>
<!-- 圆心纬度 -->
<a-col :span="6" v-if="[3].includes(nowAnnotationData.type)">
<div class="annotationTitle">圆心纬度</div>
</a-col>
<a-col :span="18" v-if="[3].includes(nowAnnotationData.type)">
<div class="annotationContent">
<a-input v-model:value="nowAnnotationData.properties.centerPoint[1]">
<template #addonAfter> <span style="color: white">°</span> </template>
</a-input>
</div>
</a-col>
<!-- 水平半径 -->
<a-col :span="6" v-if="[3].includes(nowAnnotationData.type)">
<div class="annotationTitle">水平半径</div>
</a-col>
<a-col :span="18" v-if="[3].includes(nowAnnotationData.type)">
<div class="annotationContent">
<a-input v-model:value="nowAnnotationData.properties.radius">
<template #addonAfter> <span style="color: white">m</span> </template>
</a-input>
</div>
</a-col>
<!-- 水平面积形状 -->
<a-col :span="6" v-if="[2, 3].includes(nowAnnotationData.type)">
<div class="annotationTitle">水平面积</div>
</a-col>
<a-col :span="18" v-if="[2, 3].includes(nowAnnotationData.type)">
<div class="annotationContent">
<span style="color: white; gap: 10px" v-if="[2].includes(nowAnnotationData.type)">
{{ horizontalArea }}
</span>
<span style="color: white; gap: 10px" v-if="[3].includes(nowAnnotationData.type)">
{{
(
Math.PI *
nowAnnotationData.properties.radius *
nowAnnotationData.properties.radius
).toFixed(2)
}}
</span>
</div>
</a-col>
<!-- 水平周长形状 -->
<a-col :span="6" v-if="[2, 3].includes(nowAnnotationData.type)">
<div class="annotationTitle">水平周长</div>
</a-col>
<a-col :span="18" v-if="[2, 3].includes(nowAnnotationData.type)">
<div class="annotationContent">
<span style="color: white; gap: 10px" v-if="[2].includes(nowAnnotationData.type)">
{{ horizontalPerimeter }}m
</span>
<span style="color: white; gap: 10px" v-if="[3].includes(nowAnnotationData.type)">
{{ (2 * Math.PI * nowAnnotationData.properties.radius).toFixed(1) }}
m
</span>
</div>
</a-col>
<!-- 水平距离线 -->
<a-col :span="6" v-if="[1].includes(nowAnnotationData.type)">
<div class="annotationTitle">水平距离</div>
</a-col>
<a-col :span="18" v-if="[1].includes(nowAnnotationData.type)">
<div class="annotationContent">
<span style="color: white; gap: 10px"> {{ horizontalDistance }}m </span>
</div>
</a-col>
<!-- 直线距离线 -->
<a-col :span="6" v-if="[1].includes(nowAnnotationData.type)">
<div class="annotationTitle">直线距离</div>
</a-col>
<a-col :span="18" v-if="[1].includes(nowAnnotationData.type)">
<div class="annotationContent">
<span style="color: white; gap: 10px"> {{ linearDistance }}m </span>
</div>
</a-col>
<!-- 高度差线 -->
<a-col :span="6" v-if="[1, 2].includes(nowAnnotationData.type)">
<div class="annotationTitle">高度差</div>
</a-col>
<a-col :span="18" v-if="[1, 2].includes(nowAnnotationData.type)">
<div class="annotationContent">
<span style="color: white; gap: 10px" v-if="[1, 2].includes(nowAnnotationData.type)">
{{ heightDiff }}m
</span>
</div>
</a-col>
<!-- 简介线 -->
<a-col :span="6">
<div class="annotationTitle">简介</div>
</a-col>
<a-col :span="18">
<div class="annotationContent">
<a-textarea
v-model:value="nowAnnotationData.remark"
:rows="4"
:maxlength="10"
placeholder="请输入"
allow-clear
/>
</div>
</a-col>
<!-- 绘制者线 -->
<a-col :span="6">
<div class="annotationTitle">绘制者</div>
</a-col>
<a-col :span="18">
<div class="annotationContent">
<span style="color: white">{{ nowAnnotationData.createUserName }}</span>
</div>
</a-col>
</a-row>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, computed, onMounted } from 'vue';
import * as mars3d from 'mars3d';
import * as Cesium from 'mars3d-cesium';
import {
line_start_cap_0,
line_start_cap_1,
line_start_cap_2,
line_start_cap_3,
line_end_cap_0,
line_end_cap_1,
line_end_cap_2,
line_end_cap_3,
defaultIcon,
fireIcon,
peopleIcon,
warnIcon,
carIcon,
checkIcon,
closeIcon,
} from './svg';
import {
CloseOutlined,
DeleteOutlined,
CheckOutlined,
AimOutlined,
AlignLeftOutlined,
InfoCircleOutlined,
AntDesignOutlined,
ExpandAltOutlined,
BorderOutlined,
LogoutOutlined,
} from '@ant-design/icons-vue';
import { cloneDeep } from 'lodash-es';
let map: mars3d.Map;
const props = defineProps(['allAnnotationDataList', 'nowShowAnnotationData']);
const emits = defineEmits([
'setNowShowAnnotationData',
'closePathAnnotationInfo',
'handlerLocation',
'deleteAnnotation',
]);
const nowAnnotationData: any = ref(props.nowShowAnnotationData);
function getIcon(iconname) {
let returnIcon: any = null;
switch (iconname) {
case 'defaultIcon':
returnIcon = defaultIcon;
break;
case 'fireIcon':
returnIcon = fireIcon;
break;
case 'peopleIcon':
returnIcon = peopleIcon;
break;
case 'warnIcon':
returnIcon = warnIcon;
break;
case 'carIcon':
returnIcon = carIcon;
break;
case 'checkIcon':
returnIcon = checkIcon;
break;
case 'closeIcon':
returnIcon = closeIcon;
break;
}
return returnIcon.replaceAll('currentColor', '#ffffff');
}
//
const modalType = ref<number>(0);
// -
const decimalToDMS_0 = ref({
degrees: 0,
minutes: 0,
seconds: 0,
});
// -
const decimalToDMS_1 = ref({
degrees: 0,
minutes: 0,
seconds: 0,
});
watch(
() => modalType.value,
(newValue) => {
if (newValue == 0) {
// - -
let { degrees, minutes, seconds } = decimalToDMS_0.value;
let decimal = Math.abs(degrees) + minutes / 60 + seconds / 3600;
nowAnnotationData.value.coordinates[0] = decimal;
// - -
degrees = decimalToDMS_1.value.degrees;
minutes = decimalToDMS_1.value.minutes;
seconds = decimalToDMS_1.value.seconds;
decimal = Math.abs(degrees) + minutes / 60 + seconds / 3600;
nowAnnotationData.value.coordinates[1] = decimal;
}
if (newValue == 1) {
// - -
const decimal1 = nowAnnotationData.value.coordinates[0];
const degrees1 = Math.floor(decimal1);
const minutesFull1 = (decimal1 - degrees1) * 60;
const minutes1 = Math.floor(minutesFull1);
const seconds1 = parseFloat((minutesFull1 - minutes1) * 60);
decimalToDMS_0.value = {
degrees: degrees1,
minutes: minutes1,
seconds: seconds1,
};
// - -
const decimal2 = nowAnnotationData.value.coordinates[1];
const degrees2 = Math.floor(decimal2);
const minutesFull2 = (decimal2 - degrees2) * 60;
const minutes2 = Math.floor(minutesFull2);
const seconds2 = parseFloat((minutesFull2 - minutes2) * 60);
decimalToDMS_1.value = {
degrees: degrees2,
minutes: minutes2,
seconds: seconds2,
};
}
},
);
//
function closePathAnnotationInfo() {
emits('closePathAnnotationInfo');
}
//
function handlerLocation() {
emits('handlerLocation', {
lng: props.nowShowAnnotationData.properties.centerPoint[0],
lat: props.nowShowAnnotationData.properties.centerPoint[1],
});
}
//
function deleteAnnotation() {
emits('deleteAnnotation', props.nowShowAnnotationData);
}
// 线-线
const linearDistance: any = ref();
// 线-
const horizontalDistance: any = ref();
// -
const horizontalArea: any = ref();
// -
const horizontalPerimeter: any = ref();
//
const heightDiff: any = ref();
watch(
() => nowAnnotationData.value,
() => {
emits('setNowShowAnnotationData', nowAnnotationData.value, false);
},
{
deep: true,
},
);
watch(
() => props.nowShowAnnotationData,
() => {
nowAnnotationData.value = props.nowShowAnnotationData;
// 线
if (nowAnnotationData.value.type == 1) {
// 线
linearDistance.value = mars3d.MeasureUtil.getDistance(
nowAnnotationData.value.coordinates,
).toFixed(2);
//
horizontalDistance.value = mars3d.MeasureUtil.getSurfaceDistance(
nowAnnotationData.value.coordinates,
).toFixed(2);
//
let heightlist: any = [];
nowAnnotationData.value.coordinates.forEach((item) => {
heightlist.push(item[2]);
});
heightDiff.value = (Math.max(...heightlist) - Math.min(...heightlist)).toFixed(2);
}
//
if (nowAnnotationData.value.type == 2) {
//
horizontalArea.value = mars3d.MeasureUtil.getSurfaceArea(
nowAnnotationData.value.coordinates[0],
).toFixed(2);
//
horizontalPerimeter.value = mars3d.MeasureUtil.getSurfaceDistance(
nowAnnotationData.value.coordinates[0],
).toFixed(2);
//
let heightlist: any = [];
nowAnnotationData.value.coordinates[0].forEach((item) => {
heightlist.push(item[2]);
});
heightDiff.value = (Math.max(...heightlist) - Math.min(...heightlist)).toFixed(2);
}
},
{
deep: true,
immediate: true,
},
);
onMounted(() => {});
</script>
<style lang="less" scoped>
.annotationInfo {
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none;
position: relative;
width: 100%;
height: 100%;
background: #232323;
.annotationInfo_biaozhu_1 {
padding: 15px;
}
.annotationInfo_biaozhu_2 {
padding: 15px;
overflow-y: auto;
height: 650px;
}
}
//
.closeButton {
position: absolute;
top: 30px;
right: 20px;
z-index: 200;
}
.annotationTitle {
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
font-size: 14px;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
.annotationTitleButton_right {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
font-size: 18px;
}
.annotationTitleButton {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 12px;
font-size: 18px;
}
}
.annotationContent {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
gap: 5px;
}
.popoverClass {
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 3px;
margin-right: 5px;
}
.svg-container {
display: block;
}
::v-deep .annotationContent .ant-input {
padding: 0px !important;
}
::v-deep .annotationContent .ant-select-selection-item {
height: 20px !important;
}
.annotationContentButton {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
}
</style>

@ -0,0 +1,373 @@
<template>
<div class="areaInfo">
<a-row>
<a-col :span="24">
<div class="annotationTitle"> 自定义飞行区 </div>
</a-col>
<a-col :span="24">
<div class="annotationTitle">
<!-- 自定义禁降区 -->
<div
v-if="props.nowShowAreaData.type == 'noland'"
:style="{
width: '15px',
height: '15px',
outline: `2px solid #FF9900`,
'margin-left': '2px',
'margin-right': '12px',
}"
/>
<!-- 自定义作业区 -->
<div
v-if="props.nowShowAreaData.type == 'dfence'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid #00FF00`,
'margin-left': '2px',
'margin-right': '12px',
'border-radius': props.nowShowAreaData.geomtype == 'Circle' ? '6.5px' : '0px',
}"
/>
<!-- 自定义限飞区 -->
<div
v-if="props.nowShowAreaData.type == 'nfz'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid #FF0000`,
background: `#FF000055`,
'margin-left': '2px',
'margin-right': '12px',
'border-radius': props.nowShowAreaData.geomtype == 'Circle' ? '6.5px' : '0px',
}"
/>
<a-input v-model:value="nowAreaData.name" style="width: 65%" size="small"></a-input>
<div class="annotationTitleButton" @click="handlerLocation">
<AimOutlined />
</div>
<div class="annotationTitleButton" @click="deleteArea">
<DeleteOutlined />
</div>
</div>
</a-col>
<a-col :span="24">
<div class="annotationPrompt" v-if="props.nowShowAreaData.type == 'noland'">
自定义作业区绘制后飞行器只能在该区域内飞行
</div>
<div class="annotationPrompt" v-if="props.nowShowAreaData.type == 'dfence'">
自定义禁降区绘制后飞行器不能在绘制区域内自动降落
</div>
<div class="annotationPrompt" v-if="props.nowShowAreaData.type == 'nfz'">
自定义作业区绘制后飞行器只能在该区域内飞行
</div>
</a-col>
<a-col :span="24">
<div class="annotationTitle"> 更多信息 </div>
</a-col>
<!-- 启用状态 -->
<a-col :span="6">
<div class="annotationTitle">启用状态</div>
</a-col>
<a-col :span="18">
<div class="annotationContent">
{{ props.nowShowAreaData.state == 0 ? '已启用' : '已禁用' }}
</div>
</a-col>
<!-- 水平周长 -->
<a-col :span="6">
<div class="annotationTitle">水平周长</div>
</a-col>
<a-col :span="18">
<div class="annotationContent"> {{ length.toFixed(2) }}m</div>
</a-col>
<!-- 水平面积 -->
<a-col :span="6">
<div class="annotationTitle">水平面积</div>
</a-col>
<a-col :span="18">
<div class="annotationContent"> {{ area.toFixed(2) }}</div>
</a-col>
<!-- 半径 -->
<a-col :span="6" v-if="props.nowShowAreaData.geomtype == 'Circle'">
<div class="annotationTitle">半径</div>
</a-col>
<a-col :span="18" v-if="props.nowShowAreaData.geomtype == 'Circle'">
<div class="annotationContent">
<a-input v-model:value="nowAreaData.properties.radius" style="width: 100%" size="small">
<template #addonAfter> <span style="color: white">m</span> </template>
</a-input>
</div>
</a-col>
<!-- 绘制者 -->
<a-col :span="6">
<div class="annotationTitle">绘制者</div>
</a-col>
<a-col :span="18">
<div class="annotationContent"> {{ props.nowShowAreaData.createdUser }}</div>
</a-col>
<a-col :span="24">
<div class="area_buttons">
<div class="cancelDiv" @click="closePathAreaInfo"></div>
<div class="startDiv" :class="{ disabled: props.nowShowAreaData }">确认</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick } from 'vue';
import * as mars3d from 'mars3d';
import * as Cesium from 'mars3d-cesium';
import {
CloseOutlined,
DeleteOutlined,
CheckOutlined,
AimOutlined,
AlignLeftOutlined,
InfoCircleOutlined,
AntDesignOutlined,
ExpandAltOutlined,
BorderOutlined,
LogoutOutlined,
MinusOutlined,
PlusOutlined,
} from '@ant-design/icons-vue';
import {
GetWorkAreaList,
AddWorkArea,
UpdateWorkArea,
DeleteWorkArea,
} from '@/api/demo/mediaLibrary';
import { cloneDeep } from 'lodash-es';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage, createConfirm } = useMessage();
const props = defineProps(['allAreaDataList', 'nowShowAreaData']);
const emits = defineEmits([
'setNowShowAreaData',
'closePathAreaInfo',
'handlerLocation',
'deleteArea',
]);
const nowAreaData: any = ref(props.nowShowAreaData);
//
function closePathAreaInfo() {
emits('closePathAreaInfo');
}
//
function handlerLocation() {
emits('handlerLocation', {
lng: props.nowShowAreaData.properties.centerPoint[0],
lat: props.nowShowAreaData.properties.centerPoint[1],
});
}
//
function deleteArea() {
createConfirm({
iconType: 'info',
title: '提示',
content: '将会影响到项目内设备的作业范围,是否删除该区域?',
onOk: async () => {
emits('deleteArea', props.nowShowAreaData);
},
});
}
//
const length: any = ref();
const area: any = ref();
watch(
() => nowAreaData.value,
() => {
emits('setNowShowAreaData', nowAreaData.value, false);
},
{
deep: true,
},
);
watch(
() => props.nowShowAreaData,
() => {
nowAreaData.value = props.nowShowAreaData;
if (props.nowShowAreaData.geomtype == 'Polygon') {
//
length.value = mars3d.MeasureUtil.getDistance(nowAreaData.value.coordinates[0]);
//
area.value = mars3d.MeasureUtil.getArea(nowAreaData.value.coordinates[0]);
}
if (props.nowShowAreaData.geomtype == 'Circle') {
//
length.value = 2 * Math.PI * parseFloat(nowAreaData.value.properties.radius);
//
area.value =
Math.PI *
parseFloat(nowAreaData.value.properties.radius) *
parseFloat(nowAreaData.value.properties.radius);
}
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
.areaInfo {
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none;
position: relative;
width: 100%;
height: 100%;
background: #232323;
padding: 15px;
}
.annotationTitle {
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
font-size: 14px;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
.annotationTitleButton_right {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
font-size: 18px;
}
.annotationTitleButton {
height: 20px;
width: 20px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 12px;
font-size: 18px;
}
}
.annotationContent {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
color: #ffffff;
}
.annotationButton {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
}
.annotationPrompt {
display: flex;
align-items: center;
justify-content: flex-start;
min-height: 45px;
height: auto;
width: 100%;
flex-wrap: wrap;
color: #ffffff55;
}
.button {
display: flex;
align-items: center;
justify-content: center;
width: 35px;
height: 35px;
background: #3c3c3c;
border-radius: 2px;
&:hover {
background: #5d5f61;
}
}
.button.disabled {
cursor: not-allowed;
opacity: 0.5;
background-color: #ccc;
}
.numDiv {
width: calc(80% - 70px);
display: flex;
align-items: center;
justify-content: center;
.numSpan {
color: #2d8cf0;
font-size: 26px;
font-weight: bold;
&:hover {
text-decoration: underline;
text-decoration-color: #2d8cf0;
}
}
}
//
.area_buttons {
display: flex;
align-items: center;
justify-content: center;
border-top: 1px solid #ffffff55;
width: 100%;
height: 68px;
gap: 20px;
.cancelDiv {
display: flex;
align-items: center;
justify-content: center;
background: #3c3c3c;
color: #ffffff;
width: 40%;
height: 32px;
border-radius: 5px;
&:hover {
background: #5d5f61;
}
}
.startDiv {
display: flex;
align-items: center;
justify-content: center;
background: #0960bd;
color: #ffffff;
width: 40%;
height: 32px;
border-radius: 5px;
&:hover {
background: #2a7dc9;
}
}
}
</style>

@ -0,0 +1,891 @@
<template>
<div class="leftMenu">
<div class="leftMenuContent">
<!-- <div class="leftMenuContent_1">
<div class="leftMenu_closeButton">
<a-tooltip placement="right">
<template #title> 关闭弹窗 </template>
<CloseOutlined
style="font-size: 24px; margin: 8px; color: white"
@click="closePathModal"
/>
</a-tooltip>
</div>
<div class="leftMenu_buttonList">
<div
class="leftMenu_buttonList_annotation"
:style="{
background: showMenuInfoName == '地图标注' ? '#2D8CF0' : '#1a375a',
}"
@click="
showMenuInfoName = '地图标注';
updateShowMenuInfoList(showMenuInfoName);
showMenuInfoList = filterAfterAnnotationDataList;
"
>
<a-tooltip placement="right">
<template #title> 地图标注 </template>
<AntDesignOutlined style="font-size: 24px; margin: 8px; color: white" />
</a-tooltip>
</div>
<div
class="leftMenu_buttonList_image"
:style="{
background: showMenuInfoName == '地图照片' ? '#2D8CF0' : '#1a375a',
}"
@click="
showMenuInfoName = '地图照片';
updateShowMenuInfoList(showMenuInfoName);
"
>
<a-tooltip placement="right">
<template #title> 地图照片 </template>
<EnvironmentOutlined style="font-size: 24px; margin: 8px; color: white" />
</a-tooltip>
</div>
<div
class="leftMenu_buttonList_area"
:style="{
background: showMenuInfoName == '地图作业区域' ? '#2D8CF0' : '#1a375a',
}"
@click="
showMenuInfoName = '地图作业区域';
updateShowMenuInfoList(showMenuInfoName);
showMenuInfoList = filterAfterAreaDataList;
"
>
<a-tooltip placement="right">
<template #title> 地图作业区域 </template>
<CodeSandboxOutlined style="font-size: 24px; margin: 8px; color: white" />
</a-tooltip>
</div>
</div>
</div> -->
<div class="leftMenuContent_2" v-if="leftMenuShow">
<div class="leftMenuContent_title">
{{ showMenuInfoName }}
</div>
<div class="leftMenuContent_list">
<!-- 地图作业区域 -->
<!-- <div v-if="showMenuInfoName == '地图作业区域'" style="margin: 10px">
<a-select
v-model:value="areatype"
style="width: 120px; margin-right: 15px"
@change="handleChangeAreaSelect"
>
<a-select-option value="all">全部类型</a-select-option>
<a-select-option value="dfence">全部作业区</a-select-option>
<a-select-option value="nfz">全部限飞区</a-select-option>
<a-select-option value="noland">全部禁降区</a-select-option>
</a-select>
<a-select
v-model:value="areastate"
style="width: 120px"
@change="handleChangeAreaSelect"
>
<a-select-option value="all">全部状态</a-select-option>
<a-select-option value="0">已启用</a-select-option>
<a-select-option value="1">已禁用</a-select-option>
</a-select>
</div> -->
<!-- 列表 -->
<div v-for="show in showMenuInfoList" :key="show.id">
<!-- 地图标注 -->
<div
v-if="showMenuInfoName == '地图标注'"
class="showMenuInfo_annotation"
:style="{
background:
props.nowShowAnnotationData && props.nowShowAnnotationData.id == show.id
? '#274D75'
: show.mouse
? '#393939'
: '',
}"
@mouseenter="
show.mouse = true;
show.deleteClickNum = 0;
"
@mouseleave="
show.mouse = false;
show.deleteClickNum = 0;
"
>
<div @click="setNowShowAnnotationData(show)">
<AntDesignOutlined v-if="show.type == 0" />
<ExpandAltOutlined v-if="show.type == 1" />
<BorderOutlined v-if="show.type == 2" />
<LogoutOutlined v-if="show.type == 3" />
</div>
<div
class="eye"
@click="show.state == 0 ? hideThisAnnotation(show) : showThisAnnotation(show)"
:style="{ background: show.state == 0 ? '#2d8cf0' : '#000000' }"
>
<EyeOutlined v-if="show.state == 0" style="color: #ffffff; font-size: 16px" />
<EyeInvisibleOutlined
v-if="show.state == 1"
style="color: #ffffff; font-size: 16px"
/>
</div>
<div @click="setNowShowAnnotationData(show)">{{ show.name }}</div>
<div class="buttonRight2" v-if="show.mouse">
<a-tooltip placement="top">
<template #title>
<span>回中</span>
</template>
<AimOutlined @click="handlerLocation(show)" />
</a-tooltip>
</div>
<div
class="buttonRight1"
v-if="show.mouse"
:style="{ background: show.deleteClickNum == 1 ? '#FF0000' : '' }"
>
<a-tooltip placement="top">
<template #title>
<span>删除</span>
</template>
<DeleteOutlined
@click="
show.deleteClickNum == 1 ? deleteAnnotation(show) : show.deleteClickNum++
"
/>
</a-tooltip>
</div>
</div>
<!-- 地图照片 -->
<!-- <div
class="showMenuInfo_image"
v-if="showMenuInfoName == '地图照片'"
:style="{
background:
props.nowShowImageData && props.nowShowImageData.id == show.id
? '#274D75'
: show.mouse
? '#393939'
: '',
}"
>
<FileImageOutlined />
<div
class="eye"
@click="show.is_displayed = !show.is_displayed"
:style="{ background: show.is_displayed ? '#2d8cf0' : '#000000' }"
>
<EyeOutlined v-if="show.is_displayed" style="color: #ffffff; font-size: 16px" />
<EyeInvisibleOutlined
v-if="!show.is_displayed"
style="color: #ffffff; font-size: 16px"
/>
</div>
<a-tooltip placement="top">
<template #title>
<span> {{ show.name }}</span>
</template>
<div
:style="{
width: show.mouse ? '160px' : '210px',
'white-space': 'nowrap',
overflow: 'hidden',
'text-overflow': 'ellipsis',
}"
@click="setNowShowImageData(show)"
>
{{ show.name }}
</div>
</a-tooltip>
<div class="buttonRight2" v-if="show.mouse">
<a-tooltip placement="top">
<template #title>
<span>回中</span>
</template>
<AimOutlined @click="handlerLocation(show)" />
</a-tooltip>
</div>
<div class="buttonRight1" v-if="show.mouse">
<a-tooltip placement="top">
<template #title>
<span>
{{ show.show_on_map ? '在地图上取消加载' : '在地图上加载' }}
</span>
</template>
<div style="display: flex; align-items: center">
<svg
v-if="show.show_on_map"
@click="funAddOrRemoveToMap(show)"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
width="18"
height="18"
>
<path
d="M19 5v11.17l2 2V5c0-1.1-.9-2-2-2H5.83l2 2H19zM2.81 2.81L1.39 4.22L3 5.83V19c0 1.1.9 2 2 2h13.17l1.61 1.61l1.41-1.41L2.81 2.81zM5 19V7.83l7.07 7.07l-.82 1.1L9 13l-3 4h8.17l2 2H5z"
fill="#ffffff"
></path>
</svg>
<svg
v-if="!show.show_on_map"
@click="funAddOrRemoveToMap(show)"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
width="18"
height="18"
>
<path
d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86l-3 3.87L9 13.14L6 17h12l-3.86-5.14z"
fill="#ffffff"
></path>
</svg>
</div>
</a-tooltip>
</div>
</div> -->
<!-- 地图作业区域 -->
<!-- <div
v-if="showMenuInfoName == '地图作业区域'"
class="showMenuInfo_area"
:style="{
outline:
props.nowShowAreaData && props.nowShowAreaData.id == show.id
? '2px solid #2D8CF0'
: '',
background: props.nowShowAreaData && show.state == 0 ? '#3c3c3c' : '#3c3c3c55',
}"
>
<a-tooltip placement="right">
<template #title> {{ show.name }} </template>
<div
class="name"
@click="setNowShowAreaData(show)"
:style="{
color: show.state == 0 ? '#ffffff' : '#ffffff55',
}"
>
{{ show.name }}
</div>
</a-tooltip>
<div
class="type"
@click="setNowShowAreaData(show)"
:style="{
color: show.state == 0 ? '#ffffff' : '#ffffff55',
}"
>
<div
v-if="show.type == 'noland'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid #FF9900`,
'margin-right': '6px',
}"
/>
<div
v-if="show.type == 'dfence'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid #00FF00`,
'margin-right': '6px',
'border-radius': show.geomtype == 'Circle' ? '6.5px' : '0px',
}"
/>
<div
v-if="show.type == 'nfz'"
:style="{
width: '13px',
height: '13px',
outline: `2px solid #FF0000`,
background: `#FF000055`,
'margin-right': '6px',
'border-radius': show.geomtype == 'Circle' ? '6.5px' : '0px',
}"
/>
<span>{{ getType(show.type) }}</span>
</div>
<div class="buttonlist">
<div class="button" v-if="show.state == 1">
<a-popconfirm
title="将会影响到项目内设备的作业范围,是否启用该区域?"
ok-text="启用"
cancel-text="取消"
placement="right"
@confirm="enableThisArea(show)"
>
<a-tooltip placement="top">
<template #title>
<span>可点击启用该区域</span>
</template>
<CheckCircleOutlined />
</a-tooltip>
</a-popconfirm>
</div>
<div class="button" v-if="show.state == 0">
<a-popconfirm
title="将会影响到项目内设备的作业范围,是否禁用该区域?"
ok-text="禁用"
cancel-text="取消"
placement="right"
@confirm="disableThisArea(show)"
>
<a-tooltip placement="top">
<template #title>
<span>可点击禁用该区域</span>
</template>
<StopOutlined />
</a-tooltip>
</a-popconfirm>
</div>
<div class="button">
<a-tooltip placement="top">
<template #title>
<span>回中</span>
</template>
<AimOutlined @click="handlerLocation(show)" />
</a-tooltip>
</div>
<div class="button">
<a-popconfirm
title="将会影响到项目内设备的作业范围,是否删除该区域?"
ok-text="删除"
cancel-text="取消"
placement="right"
@confirm="deleteArea(show)"
>
<a-tooltip placement="top">
<template #title>
<span>删除</span>
</template>
<DeleteOutlined />
</a-tooltip>
</a-popconfirm>
</div>
</div>
</div> -->
</div>
</div>
</div>
</div>
<div class="suojinButton" @click="changeLeftMenuShow">
<DoubleLeftOutlined v-if="leftMenuShow" style="font-size: 16px" />
<DoubleRightOutlined v-if="!leftMenuShow" style="font-size: 16px" />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import {
CloseOutlined,
AntDesignOutlined,
DoubleLeftOutlined,
DoubleRightOutlined,
EnvironmentOutlined,
CodeSandboxOutlined,
ExpandAltOutlined,
BorderOutlined,
LogoutOutlined,
EyeOutlined,
EyeInvisibleOutlined,
AimOutlined,
DeleteOutlined,
FileImageOutlined,
CheckCircleOutlined,
StopOutlined,
} from '@ant-design/icons-vue';
import { UpdateWorkArea, UpdateAnnotation } from '@/api/demo/mediaLibrary';
import { cloneDeep } from 'lodash-es';
import { useMessage } from '@/hooks/web/useMessage';
const { createMessage, createConfirm } = useMessage();
const props = defineProps([
'pathRecord',
'leftMenuShow',
'allAnnotationDataList',
'nowShowAnnotationData',
'allImageDataList',
'nowShowImageData',
'allAreaDataList',
'nowShowAreaData',
]);
const emits = defineEmits([
'changeLeftMenuShow',
'handlerLocation',
'closePathModal',
'changeAnnotationInfoShow',
'setNowShowAnnotationData',
'setNowShowImageData',
'setNowShowAreaData',
'setAllAreaData',
'setAllAnnotationData',
'deleteAnnotation',
'deleteArea',
]);
const showMenuInfoList = ref(props.allAnnotationDataList);
const showMenuInfoName = ref('地图标注');
function updateShowMenuInfoList(type) {
if (type == '地图标注') {
handleChangeAnnotationSearch();
}
if (type == '地图照片') {
showMenuInfoList.value = props.allImageDataList;
}
if (type == '地图作业区域') {
handleChangeAreaSelect();
}
}
// -
function changeLeftMenuShow() {
emits('changeLeftMenuShow');
}
// -
function closePathModal() {
emits('closePathModal');
}
// -
function funAddOrRemoveToMap(show) {
show.show_on_map = !show.show_on_map;
if (show.show_on_map) {
createMessage.success('在地图上加载成功');
} else {
createMessage.success('在地图上取消加载成功');
}
}
// -
const filterAfterAnnotationDataList = ref(props.allAnnotationDataList);
function handleChangeAnnotationSearch() {
let filterAnnotationData = props.allAnnotationDataList;
// if (areatype.value !== 'all') {
// filterAnnotationData = filterAnnotationData.filter((item) => item.type == areatype.value);
// }
// if (areastate.value !== 'all') {
// filterAnnotationData = filterAnnotationData.filter((item) => item.state == areastate.value);
// }
filterAfterAnnotationDataList.value = filterAnnotationData;
showMenuInfoList.value = filterAfterAnnotationDataList.value;
}
// -
function deleteAnnotation(show) {
show.deleteClickNum = 0;
emits('deleteAnnotation', show);
}
// -
function showThisAnnotation(value) {
setNowShowAnnotationData({
...value,
state: 0,
});
UpdateAnnotation({
...value,
properties: JSON.stringify(value.properties),
state: 0,
}).then((res) => {
emits('setAllAnnotationData');
});
}
// -
function hideThisAnnotation(value) {
setNowShowAnnotationData({
...value,
state: 1,
});
UpdateAnnotation({
...value,
properties: JSON.stringify(value.properties),
state: 1,
}).then((res) => {
emits('setAllAnnotationData');
});
}
// -------------------------------------------------
// -
const areatype = ref('all');
const areastate = ref('all');
// -
function getType(type) {
let name = '';
switch (type) {
case 'nfz':
name = '自定义限飞区';
break;
case 'dfence':
name = '自定义作业区';
break;
case 'noland':
name = '自定义禁降区';
break;
}
return name;
}
// -
const filterAfterAreaDataList = ref(props.allAreaDataList);
function handleChangeAreaSelect() {
let filterAreaData = props.allAreaDataList;
if (areatype.value !== 'all') {
filterAreaData = filterAreaData.filter((item) => item.type == areatype.value);
}
if (areastate.value !== 'all') {
filterAreaData = filterAreaData.filter((item) => item.state == areastate.value);
}
filterAfterAreaDataList.value = filterAreaData;
showMenuInfoList.value = filterAfterAreaDataList.value;
}
// -
function enableThisArea(value) {
setNowShowAreaData({
...value,
state: 0,
});
UpdateWorkArea({
...value,
properties: JSON.stringify(value.properties),
state: 0,
}).then((res) => {
emits('setAllAreaData');
});
}
// -
function disableThisArea(value) {
setNowShowAreaData({
...value,
state: 1,
});
UpdateWorkArea({
...value,
properties: JSON.stringify(value.properties),
state: 1,
}).then((res) => {
emits('setAllAreaData');
});
}
// -
function deleteArea(show) {
emits('deleteArea', show);
}
//
function setNowShowAnnotationData(value) {
emits('setNowShowAnnotationData', value);
}
//
function setNowShowImageData(value) {
emits('setNowShowImageData', value);
}
//
function setNowShowAreaData(value) {
emits('setNowShowAreaData', value);
}
// ------------------------------------------------------------------
//
function handlerLocation(position) {
// if (showMenuInfoName.value == '') {
// let coordinates = position.coordinates;
// switch (position.type) {
// case 0:
// emits('handlerLocation', {
// lng: coordinates[0],
// lat: coordinates[1],
// });
// break;
// case 1:
// emits('handlerLocation', {
// lng: coordinates[0][0],
// lat: coordinates[0][1],
// });
// break;
// case 2:
// emits('handlerLocation', {
// lng: coordinates[0][0][0],
// lat: coordinates[0][0][1],
// });
// break;
// case 3:
// emits('handlerLocation', {
// lng: coordinates[0],
// lat: coordinates[1],
// });
// break;
// }
// }
// if (showMenuInfoName.value == '') {
// emits('handlerLocation', {
// lng: position.photo_position.lng,
// lat: position.photo_position.lat,
// });
// }
if (showMenuInfoName.value == '地图作业区域') {
if (position.geomtype == 'Circle') {
emits('handlerLocation', {
lng: position.properties.centerPoint[0],
lat: position.properties.centerPoint[1],
});
} else {
emits('handlerLocation', {
lng: position.properties.centerPoint[0],
lat: position.properties.centerPoint[1],
});
}
}
}
defineExpose({
updateShowMenuInfoList,
});
</script>
<style lang="less" scoped>
.leftMenu {
position: relative;
width: 100%;
height: 100%;
background: #232323;
.leftMenuTitle {
position: relative;
width: 100%;
height: 50px;
padding: 10px;
border-bottom: 1px solid #ffffff55;
.title {
display: flex;
align-items: center;
justify-content: flex-start;
font-size: 20px;
color: #ffffff;
width: 100%;
/* 关键属性 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.leftMenuContent {
position: relative;
display: flex;
width: 100%;
height: calc(100%-50px);
// height: 800px;
.leftMenuContent_1 {
position: relative;
width: 64px;
height: 100%;
border-right: 1px solid #ffffff55;
// padding-top: 10px;
// padding-bottom: 10px;
.leftMenu_closeButton {
position: relative;
padding-top: 7px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
.leftMenu_buttonList {
position: relative;
width: 50px;
height: 100%;
border-radius: 10px;
background: #1a375a;
margin-top: 15px;
margin-left: 7px;
margin-right: 7px;
padding-top: 5px;
padding-bottom: 5px;
gap: 10px;
.leftMenu_buttonList_annotation {
position: relative;
border-radius: 5px;
height: 40px;
width: 40px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.leftMenu_buttonList_image {
position: relative;
border-radius: 5px;
height: 40px;
width: 40px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.leftMenu_buttonList_area {
position: relative;
border-radius: 5px;
height: 40px;
width: 40px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.leftMenuContent_2 {
position: relative;
width: 275px;
height: 100%;
.leftMenuContent_title {
margin-top: 10px;
margin-left: 10px;
color: #ffffff;
font-size: 16px;
}
.leftMenuContent_list {
overflow-y: auto;
max-height: 800px;
//
.showMenuInfo_annotation {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
height: 30px;
padding-left: 15px;
gap: 10px;
.eye {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
}
.buttonRight2 {
position: absolute;
right: 30px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.buttonRight1 {
position: absolute;
right: 5px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
}
//
.showMenuInfo_image {
display: flex;
align-items: center;
justify-content: flex-start;
color: #ffffff;
height: 30px;
padding-left: 15px;
gap: 10px;
.eye {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
}
.buttonRight2 {
position: absolute;
right: 35px;
}
.buttonRight1 {
position: absolute;
right: 10px;
}
}
//
.showMenuInfo_area {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
height: 70px;
margin: 10px 15px;
.name {
position: absolute;
top: 6px;
left: 6px;
color: #ffffff;
font-size: 15px;
width: 90%;
height: 30px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.type {
position: absolute;
display: inline-flex;
align-items: center;
justify-content: flex-start;
bottom: 6px;
left: 8px;
color: #ffffff;
font-size: 15px;
width: 165px;
}
.buttonlist {
position: absolute;
bottom: 6px;
right: 6px;
width: 75px;
height: 25px;
display: flex;
gap: 1px;
.button {
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 16px;
width: 25px;
height: 25px;
}
}
}
}
}
}
}
.suojinButton {
position: absolute;
top: 45%;
right: -18px;
height: 90px;
width: 18px;
background: #ffffff;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
}
</style>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,271 @@
export const line_start_cap_0 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_start_cap_1 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M14.0459,2.2L4,8L14.0459,13.8L14.0459,9L44,9L44,7L14.0459,7L14.0459,2.2Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_start_cap_2 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<rect
x="4"
y="4"
width="2"
height="8"
rx="0"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</g>
</svg>`;
export const line_start_cap_3 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M44,9L5.5,9L5.5,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<ellipse cx="7" cy="8" rx="3" ry="3" fill="#000000" fill-opacity="1" />
</g>
</g>
</g>
</svg>`;
export const line_end_cap_0 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_end_cap_1 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<path
d="M33.9541,13.8L44,8L33.9541,2.2L33.9541,7L4,7L4,9L33.9541,9L33.9541,13.8Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</svg>`;
export const line_end_cap_2 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M44,9L4,9L4,7L44,7L44,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<rect
x="42"
y="4"
width="2"
height="8"
rx="0"
fill="#000000"
fill-opacity="1"
/>
</g>
</g>
</g>
</svg>`;
export const line_end_cap_3 = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="36"
height="12"
viewBox="0 0 48 16"
>
<g>
<g>
<g>
<path
d="M43.5,9L4,9L4,7L43.5,7L43.5,9Z"
fill-rule="evenodd"
fill="#000000"
fill-opacity="1"
/>
</g>
<g>
<ellipse cx="41" cy="8" rx="3" ry="3" fill="#000000" fill-opacity="1" />
</g>
</g>
</g>
</svg>`;
export const circle = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="48"
height="48"
viewBox="0 0 512 512"
>
<path d="M256 8C119 8 8 119 8 256s111 248 248 248s248-111 248-248S393 8 256 8z" fill="#000000">
</path>
</svg>`;
export const rect = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="48"
height="48"
viewBox="0 0 512 512">
<path d="M2 4h20v16H2z" fill="#000000">
</path>
</svg>`;
export const triangle = `<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="48"
height="48"
viewBox="0 0 512 512">
<path d="M464 464H48a16 16 0 0 1-14.07-23.62l208-384a16 16 0 0 1 28.14 0l208 384A16 16 0 0 1 464 464z" fill="#000000">
</path>
</svg>`;
export const defaultIcon = `<svg width="15px" height="21.25px" viewBox="0 0 20 29" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="监测平台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="林业防火-智览-物资点图层-2.0" transform="translate(-880, -469)" fill="currentColor">
<g id="菱形" transform="translate(880, 469)">
<path d="M9.90588766,0 L20,13.1685517 L12.4843534,23.5505302 L12.4843534,28.0455285 L7.51106516,28.0455285 L7.51106516,23.5505302 L0,13.1685517 L9.90588766,0 Z M9.90588766,6 L5,13.1685517 L9.90588766,20.3166169 L15,13.1685517 L9.90588766,6 Z" id="形状结合"></path>
</g>
</g>
</g>
</svg>`;
export const locateBack = `<svg width="24px" height="28px" viewBox="0 0 24 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="监测平台" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linejoin="round">
<g id="林业防火-智览-物资点图层-2.0" transform="translate(-914, -469)" fill-rule="nonzero" stroke-width="2.75">
<g id="定位" transform="translate(916, 471)">
<path d="M10,23.8461538 C10,23.8461538 20,17.3107692 20,9.75523077 C20,4.36756923 15.5228462,0 10,0 C4.47715385,0 0,4.36756923 0,9.75523077 C0,17.3107692 10,23.8461538 10,23.8461538 Z" id="路径" stroke="currentColor" fill="currentColor"></path>
<path d="M10,16 C13.31368,16 16,13.31368 16,10 C16,6.68632 13.31368,4 10,4 C6.68632,4 4,6.68632 4,10 C4,13.31368 6.68632,16 10,16 Z" id="路径" stroke="#ffffff" fill="#ffffff"></path>
</g>
</g>
</g>
</svg>`;
export const fireIcon = `<svg width="24px" height="24px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M19.48 12.35c-1.57-4.08-7.16-4.3-5.81-10.23c.1-.44-.37-.78-.75-.55C9.29 3.71 6.68 8 8.87 13.62c.18.46-.36.89-.75.59c-1.81-1.37-2-3.34-1.84-4.75c.06-.52-.62-.77-.91-.34C4.69 10.16 4 11.84 4 14.37c.38 5.6 5.11 7.32 6.81 7.54c2.43.31 5.06-.14 6.95-1.87c2.08-1.93 2.84-5.01 1.72-7.69zm-9.28 5.03c1.44-.35 2.18-1.39 2.38-2.31c.33-1.43-.96-2.83-.09-5.09c.33 1.87 3.27 3.04 3.27 5.08c.08 2.53-2.66 4.7-5.56 2.32z" fill="currentColor">
</path></svg>`;
export const peopleIcon = `<svg width="24px" height="24px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<circle cx="12" cy="4" r="2" fill="currentColor"></circle><path d="M15.89 8.11C15.5 7.72 14.83 7 13.53 7h-2.54C8.24 6.99 6 4.75 6 2H4c0 3.16 2.11 5.84 5 6.71V22h2v-6h2v6h2V10.05L18.95 14l1.41-1.41l-4.47-4.48z" fill="currentColor">
</path></svg>`;
export const warnIcon = `<svg width="24px" height="24px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 12 12"><g fill="none"><path d="M5.214 1.459a.903.903 0 0 1 1.572 0l4.092 7.169c.348.61-.089 1.372-.787 1.372H1.91c-.698 0-1.135-.762-.787-1.372l4.092-7.17zM5.5 4.5v1a.5.5 0 0 0 1 0v-1a.5.5 0 0 0-1 0zM6 6.75a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5z" fill="currentColor">
</path></g></svg>`;
export const carIcon = `<svg width="24px" height="24px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512">
<path d="M447.68 220.78a16 16 0 0 0-1-3.08l-37.78-88.16C400.19 109.17 379 96 354.89 96H157.11c-24.09 0-45.3 13.17-54 33.54L65.29 217.7A15.72 15.72 0 0 0 64 224v176a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16v-16h256v16a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16V224a16.15 16.15 0 0 0-.32-3.22zM144 320a32 32 0 1 1 32-32a32 32 0 0 1-32 32zm224 0a32 32 0 1 1 32-32a32 32 0 0 1-32 32zM104.26 208l28.23-65.85C136.11 133.69 146 128 157.11 128h197.78c11.1 0 21 5.69 24.62 14.15L407.74 208z" fill="currentColor">
</path></svg>`;
export const checkIcon = `<svg width="24px" height="24px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<path d="M5 12l5 5L20 7" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
</path></svg>`;
export const closeIcon = `<svg width="24px" height="24px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><path d="M24 9.4L22.6 8L16 14.6L9.4 8L8 9.4l6.6 6.6L8 22.6L9.4 24l6.6-6.6l6.6 6.6l1.4-1.4l-6.6-6.6L24 9.4z" fill="currentColor">
</path></svg>`;

@ -34,7 +34,6 @@
v-if="loadControlVisible"
@changeLoadControl="changeLoadControl"
:msgData="msgData"
:uavStatus="uavStatus"
:cameraType="cameraType"
/>
<!-- 飞行控制 -->
@ -42,7 +41,6 @@
@changeFlightControl="changeFlightControl"
@clickTakeOff="clickTakeOff"
@clickFlyTo="clickFlyTo"
:uavStatus="uavStatus"
v-if="flightControlVisible"
/>
<!-- 一键起飞表单 -->
@ -75,7 +73,7 @@
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, onBeforeUnmount, reactive, watch } from 'vue';
import { onMounted, ref, onBeforeUnmount, reactive, watch, computed } from 'vue';
import {
SelectComponent,
AirportInformation,
@ -124,12 +122,41 @@
const connectCallback = () => {
connected.value = true;
};
const topicUrl = computed(() => {
return 'thing/product/' + airPortInfo.sn + '/osd'
})
const topicUAVUrl = computed(() => {
return 'thing/product/' + UAVinfo.sn + '/osd'
})
onMounted(() => {
destroyConnection();
createConnection(connectCallback);
// setTimeout(() => {
// changeSelect();
// }, 1000);
setTimeout(() => {
//
getClient().on('message', (topic, message) => {
const rs = JSON.parse(message);
if (rs) {
msgData.value = {
topic: topic,
message: rs,
};
if (topic == topicUAVUrl.value) {
if (rs.data.latitude && rs.data.longitude) {
uavTrack.value = rs.data;
}
} else if (topic == topicUrl.value) {
if (rs.data.latitude && rs.data.longitude) {
airPort.value.latitude = rs.data.latitude;
airPort.value.longitude = rs.data.longitude;
}
if (rs.data.sub_device) {
uavStatus.value = rs.data.sub_device.device_online_status;
}
}
}
});
}, 1000);
});
watch(
() => connected.value,
@ -197,12 +224,11 @@
};
const cameraType = ref('wide');
const changeCameraType = (value: any) => {
console.log(value);
cameraType.value = value;
};
const msgData = ref({});
const changeSelect = async (value?: any) => {
createConnection(connectCallback);
// createConnection(connectCallback);
//
//
airportLiveVisible.value = false;
@ -227,33 +253,6 @@
const topicUAVUrl = 'thing/product/' + UAVinfo.sn + '/osd';
//
clientSubscribe(topicUAVUrl, { qos: 0 });
if (!value) {
//
getClient().on('message', (topic, message) => {
const rs = JSON.parse(message);
if (rs) {
msgData.value = {
topic: topic,
message: rs,
};
if (topic == topicUAVUrl) {
if (rs.data.latitude && rs.data.longitude) {
uavTrack.value = rs.data;
}
} else if (topic == topicUrl) {
if (rs.data.latitude && rs.data.longitude) {
airPort.value.latitude = rs.data.latitude;
airPort.value.longitude = rs.data.longitude;
}
if (rs.data.sub_device) {
uavStatus.value = rs.data.sub_device.device_online_status;
}
}
}
});
}
};
</script>
<style lang="less" scoped>

@ -194,10 +194,7 @@
import { airPortStore } from '@/store/modules/airport';
import { EventBus } from '@/utils/eventBus';
const props = defineProps({
uavStatus: Number,
});
console.log(props.uavStatus);
const uavStatus = ref();
const airPortStoreVal = airPortStore();
const uav = airPortStoreVal.getUAV;
const isTakeOff = ref(false);
@ -255,10 +252,7 @@
};
//
const flyTo = () => {
console.log('飞行器状态', props.uavStatus);
console.log('是否一键起飞', !isTakeOff.value);
console.log(props.uavStatus == 0 && !isTakeOff.value);
if (!props.uavStatus && !isTakeOff.value) {
if (uavStatus.value == 0) {
createMessage.warning('飞行器未开机');
return;
}
@ -273,7 +267,7 @@
createMessage.warning('当前有用户正在操作,请稍后再试');
return;
}
if (props.uavStatus == 0 && !isTakeOff.value) {
if (uavStatus.value == 0) {
createMessage.warning('飞行器未开机');
return;
}
@ -306,7 +300,7 @@
//
const returnBtn = ref(false);
const returnVoyage = () => {
if (props.uavStatus == 0 && !isTakeOff.value) {
if (uavStatus.value == 0) {
createMessage.warning('飞行器未开机');
return;
}
@ -400,7 +394,7 @@
let drc_mode_enter_timer;
const drc_mode_enter_val = ref(1);
const enterDRC = () => {
if (props.uavStatus == 0 && !isTakeOff.value) {
if (uavStatus.value == 0) {
createMessage.warning('飞行器未开机');
return;
}
@ -469,7 +463,7 @@
eventsTopicSubscribe();
};
const exitDRC = () => {
if (props.uavStatus == 0 && !isTakeOff.value) {
if (uavStatus.value == 0) {
createMessage.warning('飞行器未开机');
return;
}
@ -497,6 +491,9 @@
if (rs.data.mode_code || rs.data.mode_code == 0) {
airportVal.value.mode_code = rs.data.mode_code;
}
if (rs.data.sub_device) {
uavStatus.value = rs.data.sub_device.device_online_status;
}
if (rs.method == 'flight_authority_grab' && rs.bid == bid) {
if (rs.data.result == 0) {
flightGrab.value = true;

@ -141,8 +141,8 @@
const props = defineProps({
msgData: Object,
cameraType: String,
uavStatus: Number,
});
const uavStatus = ref();
const monitorDRC = ref(false);
//
const flightGrab = ref(false);
@ -226,7 +226,6 @@
// redis
const lockedClient = () => {
getLockedClients().then((res) => {
console.log(res);
if (res.length > 0) {
res.forEach((item, index) => {
if (item.userId != userInfo.id) {
@ -245,7 +244,7 @@
createMessage.warning('当前有用户正在操作,请稍后再试');
return;
}
if (!props.uavStatus) {
if (uavStatus.value == 0) {
createMessage.warning('飞行器未开机');
return;
}
@ -371,6 +370,9 @@
// //
getClient().on('message', (topic, message) => {
const rs = JSON.parse(message);
if (rs.data.sub_device) {
uavStatus.value = rs.data.sub_device.device_online_status;
}
if (rs.method == 'camera_photo_take') {
if (rs.data.result == 0) {
createMessage.success('拍照成功');

@ -103,7 +103,7 @@
<div class="arrow-icon"></div>
</div>
</div>
<div class="setting-item">
<!-- <div class="setting-item">
<div class="setting-label-div">
<div class="setting-label">设备直传</div>
<div class="hint"></div>
@ -120,7 +120,7 @@
<div class="setting-value-div">
<a-switch class="setting-switch" v-model:checked="project.isDeicePlaneTrans" />
</div>
</div>
</div> -->
<div class="setting-list-item" style="margin-bottom: 15px;">
<div class="setting-list-title-div">
<div class="setting-list-title">项目成员</div>

Loading…
Cancel
Save