From 02409bfbe15f22fc3b5dccadabfd860a660a49d9 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Sat, 11 Oct 2025 10:37:14 +0800
Subject: [PATCH] feat: 名称修改
---
src/views/airspace/components/AirspaceMap.vue | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 273 insertions(+), 26 deletions(-)
diff --git a/src/views/airspace/components/AirspaceMap.vue b/src/views/airspace/components/AirspaceMap.vue
index cd2d1aa..4c14cac 100644
--- a/src/views/airspace/components/AirspaceMap.vue
+++ b/src/views/airspace/components/AirspaceMap.vue
@@ -5,35 +5,78 @@
<div class="form-container">
<avue-form ref="formEle" :option="option" v-model="form"></avue-form>
</div>
- <div class="map-container">
+
+ <div class="map-container" v-loading="mapLoading" element-loading-text="地形初始化中,请稍后..."
+ element-loading-background="rgba(0, 0, 0, 0.7)">
+ <div class="tool-tip warning" v-show="isShowWaringTip">
+ <span class="icon">
+ <el-icon>
+ <WarningFilled />
+ </el-icon>
+ </span>
+ <span>空域不支持交叉面,无法生成空域</span>
+ </div>
<div id="AirspaceMap" class="ztzf-cesium"></div>
+ </div>
+
+ <div class="btn-container">
+ <el-button icon="el-icon-check" type="primary" @click="handleSubmit">确定</el-button>
+ <el-button icon="el-icon-close" @click="dialogShow = false">取消</el-button>
</div>
</div>
</el-dialog>
</template>
<script setup>
+import _, { cloneDeep, throttle } from 'lodash'
+
import * as Cesium from 'cesium'
+import * as turf from '@turf/turf'
+
+import { getPointPositionsHeight } from '@/utils/cesium/mapUtil'
+import { DrawPolygon } from '@/utils/drawPolygon/drawPolygon'
import { PublicCesium } from '@/utils/cesium/publicCesium'
+import { ElMessageBox, ElMessage } from 'element-plus'
+
+import {
+ airspaceEnteringAdd,
+ airspaceEnteringUpdate
+} from '@/api/airspace/airspace'
+
const props = defineProps({
title: {
type: String,
default: '新增空域',
},
+
+ type: {
+ type: String,
+ default: 'add',
+ },
+
+ curEditRow: {
+ type: Object,
+ default: () => { },
+ }
})
+
+const emit = defineEmits(['submitClick'])
const dialogShow = defineModel('show')
const formEle = ref(null)
-const form = ref({})
+const form = ref({
+ height: 120,
+})
const option = ref({
submitBtn: false,
emptyBtn: false,
+ menuBtn: false,
column: [
{
label: '名称',
- prop: 'input',
+ prop: 'name',
type: 'input',
rules: [
{
@@ -46,31 +89,41 @@
{
label: '高度',
- prop: 'input',
+ prop: 'height',
type: 'input',
+ value: 120,
+ min: 5,
+ max: 500,
+ type: 'number',
+ change ({ column, value }) {
+ drawPolygonExample?.setPolygonHeight?.(value)
+ },
rules: [
{
required: true,
message: '请输入高度',
trigger: 'blur'
+ },
+ {
+ pattern: /^(?:[5-9]|[1-9]\d|[1-4]\d{2}|500)$/, // 5-500
+ message: '高度需在5-500之间',
+ trigger: ['blur', 'change']
}
]
},
{
label: '类型',
- prop: 'select',
+ prop: 'flight_type',
type: 'select',
- dicData: [
- {
- label: '字典1',
- value: 0,
- },
- {
- label: '字典2',
- value: 1,
- },
- ],
+ dicUrl: `/drone-device-core/airspace/page?current=1&size=10000`,
+ props: {
+ label: 'type_name',
+ value: 'id',
+ },
+ dicFormatter (res) {
+ return res.data.records
+ },
rules: [
{
required: true,
@@ -81,7 +134,7 @@
},
{
label: '管控时段',
- prop: 'daterange',
+ prop: 'time_period',
type: 'daterange',
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
@@ -97,22 +150,29 @@
},
{
- label: '备注',
- prop: 'input',
+ label: '管控原因',
+ prop: 'remark',
type: 'textarea',
span: 24,
rows: 1,
minRows: 1,
maxRows: 1,
- placeholder: '请输入备注',
+ placeholder: '请输入管控原因',
},
],
})
+let drawPolygonExample = null
let publicCesiumInstance = null
let viewer = null
// 地图
-const initMap = () => {
+const mapLoading = ref(true)
+
+const isShowWaringTip = ref(false)
+
+const curDrawPolygonData = ref([])
+
+const initMap = async () => {
if (!document.getElementById('AirspaceMap')) {
return
}
@@ -121,37 +181,224 @@
flatMode: false,
terrain: true,
layerMode: 4,
- contour: false,
+ contour: true,
+ flyToContour: true,
+ terrainInit () {
+ setTimeout(async () => {
+ initDrawPolygon()
+ mapLoading.value = false
+ }, 1500)
+ }
})
+
viewer = publicCesiumInstance.getViewer()
+
+ drawPolygonExample = new DrawPolygon()
+
+ drawPolygonExample.initHandler(viewer)
+
+ drawPolygonExample.subscribe('getShowWaringTip', data => {
+ isShowWaringTip.value = data
+ })
+
+ drawPolygonExample.subscribe('getPolygonPositions', data => {
+ curDrawPolygonData.value = data.map(item => {
+ let cartographic = Cesium.Cartographic.fromCartesian(item)
+
+ let lng = Cesium.Math.toDegrees(cartographic.longitude) // 经度
+ let lat = Cesium.Math.toDegrees(cartographic.latitude) // 纬度
+ let height = cartographic.height
+
+ return {
+ lng: _.round(lng, 6),
+ lat: _.round(lat, 6),
+ height
+ }
+ })
+ })
}
watch(dialogShow, async (show) => {
if (show) {
+ if (props.type === 'edit') {
+ form.value = { ...props.curEditRow }
+ }
+
+ initDrawPolygon()
+
+ if (viewer) return
+
await nextTick()
+ cesiumContextMenu()
initMap()
}
})
+const initDrawPolygon = async () => {
+ if (props.type === 'edit' && drawPolygonExample) {
+ drawPolygonExample?.setPolygonHeight?.(props.curEditRow.height)
+
+ let polygon = JSON.parse(props.curEditRow.flight_range)
+
+ if (polygon.length > 0) {
+ const aslData = await getPointPositionsHeight(polygon, viewer)
+ drawPolygonExample?.initPolygon(viewer, aslData.map(item => ({ ...item, height: item.ASL })))
+ }
+ }
+}
+
+const handleSubmit = () => {
+ if (ElMessage.value) {
+ ElMessage.warning('空域不支持交叉,请重新绘制或调整')
+ return
+ }
+
+ if (curDrawPolygonData.value.length === 0) {
+ ElMessage.warning('请绘制空域区域')
+ return
+ }
+
+ if (formEle.value) {
+ formEle.value.validate((valid, done, msg) => {
+ if (valid) {
+ let disposePolygon = curDrawPolygonData.value.map(i => [i.lng, i.lat])
+
+ let polygon = turf.polygon([
+ [
+ ...disposePolygon,
+ disposePolygon[0]
+ ]
+ ])
+
+ let area = turf.area(polygon)
+
+ if (props.type === 'edit') {
+ airspaceEnteringUpdate({
+ id: props.curEditRow.id,
+ name: form.value.name,
+ flight_range: JSON.stringify(curDrawPolygonData.value),
+ height: form.value.height,
+ time_period: form.value.time_period.join('~'),
+ flight_type: form.value.flight_type,
+ remark: form.value.remark,
+ area: area
+ }).then(res => {
+ ElMessage.success('更新成功')
+ dialogShow.value = false
+ emit('submitClick')
+ done()
+ })
+ } else {
+ airspaceEnteringAdd({
+ name: form.value.name,
+ flight_range: JSON.stringify(curDrawPolygonData.value),
+ height: form.value.height,
+ time_period: form.value.time_period.join('~'),
+ flight_type: form.value.flight_type,
+ remark: form.value.remark,
+ area: area
+ }).then(res => {
+ ElMessage.success('新增成功')
+ dialogShow.value = false
+ emit('submitClick')
+ done()
+ })
+ }
+ } else {
+ return false
+ }
+ })
+ }
+}
+
const handleClose = () => {
- publicCesiumInstance?.viewerDestroy()
- publicCesiumInstance = null
- viewer = null
- form.value = {}
+ drawPolygonExample?.delPolygon()
+ isShowWaringTip.value = false
+ curDrawPolygonData.value = []
+ form.value = {
+ height: 120
+ }
formEle.value.resetForm()
dialogShow.value = false
}
+
+// 阻止右键默认行为
+const preventDefault = event => {
+ event.preventDefault()
+ return
+}
+
+const cesiumContextMenu = (isAdd = true) => {
+ let cesium = document.getElementById('AirspaceMap')
+ if (!cesium) return
+ if (isAdd) {
+ cesium.addEventListener('contextmenu', preventDefault)
+ } else {
+ cesium.removeEventListener('contextmenu', preventDefault)
+ }
+}
+
+onBeforeUnmount(() => {
+ drawPolygonExample?.destroy()
+ drawPolygonExample = null
+ cesiumContextMenu(false)
+ publicCesiumInstance?.viewerDestroy()
+ publicCesiumInstance = null
+ viewer = null
+})
</script>
<style scoped lang="scss">
.custom-container {
.map-container {
- height: 440px;
+ height: 620px;
#AirspaceMap {
+ position: relative;
width: 100%;
height: 100%;
+ overflow: hidden;
}
}
+
+ .btn-container {
+ margin-top: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+.tool-tip {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ width: 800px;
+ height: 64px;
+ font-family: Source Han Sans CN, Source Han Sans CN;
+ font-size: 18px;
+ color: #ffffff;
+
+ background: rgba(11, 31, 58, 0.7);
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ z-index: 9;
+}
+
+.warning {
+ top: 234px;
+ left: 50%;
+ transform: translateX(-50%);
+ color: #fff;
+ background: rgba(140, 0, 0, 0.4);
+
+ .icon {
+ display: flex;
+ align-items: center;
+ color: #ff1f1f;
+ }
}
</style>
--
Gitblit v1.9.3