Browse Source

功能和样式调整

gr 1 month ago
parent
commit
da5ecabf9d

+ 162 - 157
src/assets/styles/index.scss

@@ -10,205 +10,210 @@
 
 /* 自定义字体引入 */
 @font-face {
-  font-family: 'PingFang';
-  src: url('../fonts/PingFangSC-Regular.woff2') format('woff2');
+	font-family: 'PingFang';
+	src: url('../fonts/PingFangSC-Regular.woff2') format('woff2');
 }
 @font-face {
-  font-family: 'ShuHei';
-  src: url('../fonts/AlimamaShuHeiTi-Bold.woff2') format('woff2');
+	font-family: 'ShuHei';
+	src: url('../fonts/AlimamaShuHeiTi-Bold.woff2') format('woff2');
 }
 @font-face {
-  font-family: 'SF-Regular';
-  src: url('../fonts/SF-Pro-Display-Regular.otf') format("opentype");
+	font-family: 'SF-Regular';
+	src: url('../fonts/SF-Pro-Display-Regular.otf') format('opentype');
 }
 @font-face {
-  font-family: 'SF-Light';
-  src: url('../fonts/SF-Pro-Display-Light.otf') format("opentype");
+	font-family: 'SF-Light';
+	src: url('../fonts/SF-Pro-Display-Light.otf') format('opentype');
 }
 @font-face {
-  font-family: 'SF-Bold';
-  src: url('../fonts/SF-Pro-Display-Bold.otf') format("opentype");
+	font-family: 'SF-Bold';
+	src: url('../fonts/SF-Pro-Display-Bold.otf') format('opentype');
 }
 @font-face {
-  font-family: 'BarlowMedium';
-  src: url('../fonts/Barlow-Medium.ttf') format("truetype");
+	font-family: 'BarlowMedium';
+	src: url('../fonts/Barlow-Medium.ttf') format('truetype');
 }
 
-
 /* 滚动条样式 */
 ::-webkit-scrollbar {
-  width : 4px;
-  height: 4px;
+	width: 4px;
+	height: 4px;
 }
 ::-webkit-scrollbar-thumb {
-  border-radius: 12px;
-  background   : #1d63b3;
+	border-radius: 12px;
+	background: #1d63b3;
 }
 ::-webkit-scrollbar-track {
-  border-radius: 12px;
-  background   : #20466a;
+	border-radius: 12px;
+	background: #20466a;
 }
 
 .text-ellipsis {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
 }
 
 .title-main {
-  position: relative;
-  height: 40px;
-  padding: 0 0 10px 55px;
-  font-size: 22px;
-  color: rgba(238,245,255,0.96);
-  text-shadow: 8px -6px 10px rgba(106,175,255,0.42), 0px 3px 0px rgba(0,2,3,0.22);
-  line-height: 22px;
-  
-  &::after {
-    content: '';
-    display: block;
-    position: absolute;
-    left: 0;
-    top: 0;
-    width: 100%;
-    height: 100%;
-    background: url('../images/page/bg-title.png');
-    background-size: cover;
-    z-index: -1;
-  }
-
-  &.rtl {
-    padding: 0 55px 10px 0;
-    text-align: right;
-    &::after {
-      transform: rotateY(180deg);
-    }
-  }
+	position: relative;
+	height: 40px;
+	padding: 0 0 10px 55px;
+	font-size: 22px;
+	color: rgba(238, 245, 255, 0.96);
+	text-shadow:
+		8px -6px 10px rgba(106, 175, 255, 0.42),
+		0px 3px 0px rgba(0, 2, 3, 0.22);
+	line-height: 22px;
+
+	&::after {
+		content: '';
+		display: block;
+		position: absolute;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		background: url('../images/page/bg-title.png');
+		background-size: cover;
+		z-index: -1;
+	}
+
+	&.rtl {
+		padding: 0 55px 10px 0;
+		text-align: right;
+		&::after {
+			transform: rotateY(180deg);
+		}
+	}
 }
 
 .title-sub {
-  display: flex;
-  align-items: center;
-  font-size: 16px;
-  text-shadow: 0px 5px 5px rgba(127,191,255,0.32);
-  &::before {
-    content: '';
-    display: block;
-    width: 38px;
-    height: 38px;
-    margin-right: 4px;
-    background: url('../images/page/bg-title-2.png');
-    background-size: 100%;
-    background-position: center 2px;
-  }
+	display: flex;
+	align-items: center;
+	font-size: 16px;
+	text-shadow: 0px 5px 5px rgba(127, 191, 255, 0.32);
+	&::before {
+		content: '';
+		display: block;
+		width: 38px;
+		height: 38px;
+		margin-right: 4px;
+		background: url('../images/page/bg-title-2.png');
+		background-size: 100%;
+		background-position: center 2px;
+	}
 }
 
 // 左侧面板内部容器样式
 .aside-left-inner {
-  position: absolute;
-  left: 20px;
-  top: 15px;
-  height: calc(100% - 35px);
-  width: calc(100% - 40px);
+	position: absolute;
+	left: 20px;
+	top: 15px;
+	height: calc(100% - 35px);
+	width: calc(100% - 40px);
 }
 
 // 默认表格样式
 .table-default {
-  width: 100%;
-  border-collapse: collapse;
-
-  tr {
-    width: 100%;
-    height: 50px;
-    background: url('../../assets/images/page/bg-table-row.png') no-repeat;
-    background-size: contain;
-    background-position: bottom;
-    table-layout: fixed;
-    display: table;
-  }
-  th, td {
-    border: none;
-    line-height: 43px;
-    padding: 7px 5px 0;
-    font-size: 16px;
-    &:first-child {
-      padding-left: 15px;
-    }
-  }
-  thead {
-    th {
-      text-align: left;
-      color: #FFFFFF;
-    }
-  }
-  tbody {
-    display: block;
-    overflow-y: auto;
-    tr {
-      td {
-        color: #ccc;
-        color: #A6D2FF;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-      }
-    }
-  }
-
-  &.stripe {
-    tr {
-      background: rgba(95,103,131,0.1);
-    }
-    thead tr,
-    tbody tr:nth-child(2n) {
-      background: rgba(169,180,218,0.15);
-      box-shadow: 0 1px 2px 0 rgba(120, 147, 236, 0.5);
-    }
-    th, td {
-      padding-top: 0;
-    }
-  }
+	width: 100%;
+	border-collapse: collapse;
+
+	tr {
+		width: 100%;
+		height: 50px;
+		background: url('../../assets/images/page/bg-table-row.png') no-repeat;
+		background-size: contain;
+		background-position: bottom;
+		table-layout: fixed;
+		display: table;
+	}
+	th,
+	td {
+		border: none;
+		line-height: 43px;
+		padding: 7px 5px 0;
+		font-size: 16px;
+		&:first-child {
+			padding-left: 15px;
+		}
+	}
+	thead {
+		th {
+			text-align: left;
+			color: #ffffff;
+		}
+	}
+	tbody {
+		display: block;
+		overflow-y: auto;
+		tr {
+			td {
+				color: #deefff;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+			}
+		}
+	}
+
+	&.stripe {
+		tr {
+			background: rgba(95, 103, 131, 0.1);
+		}
+		thead tr,
+		tbody tr:nth-child(2n) {
+			background: rgba(169, 180, 218, 0.15);
+			box-shadow: 0 1px 2px 0 rgba(120, 147, 236, 0.5);
+		}
+		th,
+		td {
+			padding-top: 0;
+		}
+	}
 }
 
 .btn-main {
-  font-size: 20px;
-  width: 123px;
-  height: 40px;
-  text-align: center;
-  background: url('../images/buttons/btn-main.png') !important;
-  background-size: 100%;
-  border: none;
-  .is-disabled {
-    opacity: 0.4;
-  }
+	font-size: 20px;
+	width: 123px;
+	height: 40px;
+	text-align: center;
+	background: url('../images/buttons/btn-main.png') !important;
+	background-size: 100%;
+	border: none;
+	.is-disabled {
+		opacity: 0.4;
+	}
 }
 
 .btn-secondary {
-  font-size: 18px;
-  min-width: 80px;
-  height: 40px;
-  padding: 0 15px 4px;
-  background: url('../images/buttons/btn-secondary.png') no-repeat !important;
-  background-size: 100% 100% !important;
-  border: none;
-  .is-disabled {
-    opacity: 0.4;
-  }
-  &.small {
-    font-size: 16px;
-    height: 34px;
-  }
+	font-size: 18px;
+	min-width: 80px;
+	height: 40px;
+	padding: 0 15px 4px;
+	background: url('../images/buttons/btn-secondary.png') no-repeat !important;
+	background-size: 100% 100% !important;
+	border: none;
+	.is-disabled {
+		opacity: 0.4;
+	}
+	&.small {
+		font-size: 16px;
+		height: 34px;
+	}
 }
 
 // 左上浮动面板通用样式
 .f-panel-left {
-  position: absolute;
-  left: var(--panel-left);
-  top: var(--panel-gap);
-  visibility: visible;
-  transition: opacity 0.3s ease, transform 0.3s ease-out, left 0.5s ease-out;
-  
-  &.collapse {
-    left: var(--panel-gap);
-  }
-}
+	position: absolute;
+	left: var(--panel-left);
+	top: var(--panel-gap);
+	visibility: visible;
+	transition:
+		opacity 0.3s ease,
+		transform 0.3s ease-out,
+		left 0.5s ease-out;
+
+	&.collapse {
+		left: var(--panel-gap);
+	}
+}

+ 16 - 6
src/store/layout.js

@@ -1,12 +1,13 @@
 import { defineStore } from 'pinia'
 
 const floatPanelsConflict = {
-	uav: ['fcky', 'cube', 'kysg', 'tsjs_gis', 'layers_legend'],
+	uav: ['fcky', 'cube', 'kysg', 'layers_legend', 'air_space'],
 	kysg: ['uav', 'tsjs_gis', 'layers_legend'],
-	fcky: ['uav', 'cube'],
-	cube: ['uav', 'fcky'],
-	tsjs_gis: ['uav', 'kysg', 'layers_legend'],
-	layers_legend: ['kysg', 'uav', 'tsjs_gis'],
+	fcky: ['uav', 'cube', 'air_space'],
+	cube: ['uav', 'fcky', 'air_space'],
+	air_space: ['uav', 'fcky', 'cube'],
+	tsjs_gis: ['kysg'],
+	layers_legend: ['kysg', 'uav'],
 }
 
 let lastAsideCollapse = {}
@@ -28,6 +29,7 @@ const useLayoutStore = defineStore('layout', {
 			cube: false, // 网格点查询
 			tsjs_gis: false, // gis态势监视,按钮面板
 			layers_legend: false, // 空域图层的图例
+			air_space: false, // 空域点查询
 		},
 		uavMonitorOn: false, // 是否在ue场景中打开态势监视
 		toolsActive: {}, // 工具栏的激活状态
@@ -65,7 +67,15 @@ const useLayoutStore = defineStore('layout', {
 			this.floatPanels[target] = value
 			if (value) {
 				floatPanelsConflict[target].forEach((t) => {
-					this.floatPanels[t] = false
+					if (this.floatPanels[t]) {
+						this.floatPanels[t] = 0
+					}
+				})
+			} else {
+				floatPanelsConflict[target].forEach((t) => {
+					if (this.floatPanels[t] === 0) {
+						this.floatPanels[t] = true
+					}
 				})
 			}
 		},

+ 13 - 0
src/utils/map/addLayer.js

@@ -521,3 +521,16 @@ export function toggleMoveCube(stauts) {
 		token: '',
 	})
 }
+
+// 空域点查询
+export function toggleFeaturesClickEvent(status) {
+	invokeParams('AccessFeaturesWithPointEvents', {
+		status: status ? 'show' : 'hide',
+		type: 'pointer-move',
+		mouse_time: 500,
+		popup_title: '悬浮结果',
+		mouse_handle_id: 'mouse_handle_id',
+		highlight_handle_id: 'highlight_handle_id',
+		token: '',
+	})
+}

+ 8 - 8
src/views/home/Home.vue

@@ -147,7 +147,7 @@
 		</Transition>
 
 		<!-- gis 态势监视-选项面板 -->
-		<Transition name="emerge-left">
+		<Transition name="emerge-right">
 			<FloatPanelTsjsGis v-if="layoutStore.floatPanels.tsjs_gis" />
 		</Transition>
 
@@ -231,7 +231,7 @@ onMounted(() => {})
 		width: var(--aside-width);
 		padding: 15px 20px 20px;
 		transition: all 0.5s ease;
-		background: linear-gradient(to bottom, rgba(0, 10, 30, 0.1) 0%, rgba(0, 10, 30, 0.3) 5%);
+		background: linear-gradient(to bottom, rgba(0, 10, 30, 0.1) 0%, rgba(0, 10, 30, 0.4) 5%);
 		border-radius: 0px 0px 12px 12px;
 		z-index: 3;
 	}
@@ -310,11 +310,11 @@ onMounted(() => {})
 		width: fit-content;
 		padding: 0 10px;
 		border-radius: 10px;
-		border: 1px solid #98cda4;
+		border: 1px solid #7ed893;
 		font-weight: bold;
 		font-size: 14px;
 		line-height: 18px;
-		color: #98cda4;
+		color: #7ed893;
 		text-align: center;
 
 		&.red {
@@ -323,13 +323,13 @@ onMounted(() => {})
 		}
 
 		&.orange {
-			color: #dfa9a9;
-			border-color: #dfa9a9;
+			color: #e08d8d;
+			border-color: #e08d8d;
 		}
 
 		&.yellow {
-			color: #ced09d;
-			border-color: #ced09d;
+			color: #cdd072;
+			border-color: #cdd072;
 		}
 	}
 

+ 98 - 0
src/views/home/cpns/FloatPanelAirSpace.vue

@@ -0,0 +1,98 @@
+<template>
+	<Transition name="fade">
+		<div class="f-panel-left panel-airspace" :class="{ collapse: layoutStore.leftCollapse }">
+			<i @click="handleClose" class="absolute right-4 top-4 text-white size-5 cursor-pointer hover:scale-110">
+				<img src="@/assets/images/svg/close.svg" alt="" />
+			</i>
+
+			<h2 class="c-title">空域信息</h2>
+
+			<ul class="des-list">
+				<li v-for="item in list">
+					<div class="flex-1 flex">
+						<span>{{ item.label }}:</span><span class="value">{{ item.value }}</span>
+					</div>
+				</li>
+			</ul>
+		</div>
+	</Transition>
+</template>
+
+<script setup>
+import useLayoutStore from '@/store/layout'
+import { useMapStore } from '@/store/map.js'
+import { ref, watch } from 'vue'
+
+const mapStore = useMapStore()
+const layoutStore = useLayoutStore()
+
+const list = ref([
+	{ label: 'ID', value: '', id: 'id', unit: '' },
+	{ label: '名称', value: '', id: 'name', unit: '' },
+	{ label: '高度', value: '', id: 'height', unit: '米' },
+])
+
+function handleClose() {
+	layoutStore.toggleFloatPanel('air_space', false)
+}
+
+watch(
+	() => mapStore.clickResult,
+	(val) => {
+		list.value.forEach((row) => {
+			row.value = val[row.id] + row.unit
+		})
+	},
+	{ deep: true, immediate: true }
+)
+</script>
+
+<style lang="scss" scoped>
+.panel-airspace {
+	width: 302px;
+	height: fit-content;
+	padding: 20px 20px 35px;
+	display: flex;
+	flex-direction: column;
+	background: url('../../../assets/images/page/bg-dialog-s.png');
+	background-size: 100% 100% !important;
+	left: calc(var(--panel-left) - var(--panel-gap));
+}
+
+.c-title {
+	width: 90%;
+	overflow: hidden;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+	margin-bottom: 5px;
+	font-size: 22px;
+	background: linear-gradient(186deg, rgba(128, 155, 237, 1) 0%, rgba(255, 255, 255, 1) 100%);
+	-webkit-background-clip: text;
+	-webkit-text-fill-color: transparent;
+}
+
+.des-list {
+	li {
+		height: 35px;
+		display: flex;
+		padding: 0 10px;
+		background: rgba(41, 104, 207, 0.45);
+		line-height: 35px;
+		font-size: 16px;
+
+		&:nth-child(2n) {
+			background: rgba(41, 104, 207, 0.2);
+		}
+
+		.value {
+			flex: 1;
+			width: 0;
+			font-size: 16px;
+			color: #eef1ff;
+			overflow: hidden;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+		}
+	}
+}
+</style>

+ 6 - 2
src/views/home/cpns/FloatPanelKysg.vue

@@ -15,7 +15,7 @@
 			</el-form-item>
 			<el-form-item label="范围:" prop="meshRange">
 				<el-radio-group v-model="form.meshRange">
-					<el-radio label="自适应" value="自适应" />
+					<el-radio label="自适应" value="自适应" @click="handleTest" />
 					<el-radio label="自定义" value="自定义" />
 					<el-radio label="行政区划" value="行政区划" />
 				</el-radio-group>
@@ -180,7 +180,11 @@ watch(
 watch(
 	() => mapStore.currentCubeLevel,
 	(val) => {
-		if (val) form.value.meshLevel = val
+		if (val) {
+			form.value.meshLevel = val
+			const maxHeight = Number(DenseData.find((d) => d.level == val).des.slice(1, -2))
+			form.value.meshHeights = [0, Math.min(600, maxHeight)]
+		}
 	}
 )
 

+ 11 - 1
src/views/home/cpns/FloatPanelTsjs.vue

@@ -23,7 +23,13 @@
 		</div>
 
 		<Transition name="emerge-left">
-			<FloatPanelUav class="uav-demo" v-if="uavInfoShow" :alert="alertInfo" :base="baseInfo" @close="handleCloseInfo" />
+			<FloatPanelUav
+				class="uav-demo"
+				v-if="uavInfoShow"
+				:alert="alertInfo"
+				:base="baseInfo"
+				@close="handleCloseInfo"
+				@showLine="handleToggleSingleLine" />
 		</Transition>
 	</div>
 </template>
@@ -189,6 +195,10 @@ function handleCloseInfo() {
 	}
 }
 
+function handleToggleSingleLine(val) {
+	console.log('handleToggleSingleLine', val)
+}
+
 onBeforeMount(() => {
 	getData()
 	proxy.$bus.on('ueReceived_DemoScene', (msg) => {

+ 45 - 23
src/views/home/cpns/FloatPanelTsjsGis.vue

@@ -1,42 +1,58 @@
 <template>
 	<div class="panel-tsjs-gis" :class="{ collapse: layoutStore.leftCollapse }">
 		<div class="options">
-			<div class="switch" @click="toggleOption('airLine')">
-				<span>航线</span>
-				<i :class="{ on: options.airLine }"></i>
-			</div>
-			<div class="switch" @click="toggleOption('mesh')">
-				<span>网格</span>
-				<i :class="{ on: options.mesh }"></i>
+			<div class="switch" v-for="item in optionList" @click="toggleOption(item)">
+				<span>{{ item.label }}</span>
+				<i :class="{ on: item.status }"></i>
 			</div>
 		</div>
 	</div>
 </template>
 
 <script setup>
-import { reactive, onBeforeUnmount } from 'vue'
-import { toggleMovePath, toggleMoveCube } from '@/utils/map/addLayer'
 import useLayoutStore from '@/store/layout'
+import { AddSingleLayer, toggleMoveCube, toggleMovePath } from '@/utils/map/addLayer'
+import { onBeforeUnmount, ref } from 'vue'
 
 const layoutStore = useLayoutStore()
 
-const options = reactive({
-	airLine: false,
-	mesh: false,
-})
+const optionList = ref([
+	{ label: '航线', id: 'airLine', status: false },
+	{ label: '网格', id: 'mesh', status: false },
+	{ label: '建筑物', id: 'buildings', status: false },
+])
+
+function toggleBuildings(status) {
+	AddSingleLayer({
+		title: '全市白模',
+		D_CODE: 'D85030103202409',
+		id: 'D8503010320240901',
+		url: 'https://cimweb.zjw.sh.cegn.cn:2008/MapProxyApi/getSceneServer/ptgl/05195418',
+		visible: status,
+		opacity: 1,
+		type: 'scene',
+	})
+}
+
+function toggleOption(item) {
+	item.status = !item.status
 
-function toggleOption(target) {
-	options[target] = !options[target]
-	if (target === 'airLine') {
-		toggleMovePath(options[target])
-	} else {
-		toggleMoveCube(options[target])
+	switch (item.id) {
+		case 'airLine':
+			toggleMovePath(item.status)
+			break
+		case 'mesh':
+			toggleMoveCube(item.status)
+			break
+		case 'buildings':
+			toggleBuildings(item.status)
 	}
 }
 
 function clearStatus() {
 	toggleMovePath(false)
 	toggleMoveCube(false)
+	toggleBuildings(false)
 }
 
 onBeforeUnmount(() => {
@@ -47,16 +63,19 @@ onBeforeUnmount(() => {
 <style lang="scss" scoped>
 .panel-tsjs-gis {
 	position: absolute;
-	left: var(--panel-left);
+	right: var(--panel-left);
 	bottom: calc(var(--footer-height) - var(--aside-height));
 	background-color: rgba(0, 17, 50, 0.5);
 	border: 1px solid #055f8d;
 	border-radius: 5px;
 	visibility: visible;
-	transition: left 0.5s ease;
+	transition:
+		right 0.5s ease,
+		opacity 0.3s ease,
+		transform 0.3s ease-out;
 
 	&.collapse {
-		left: var(--panel-gap);
+		right: var(--panel-gap);
 	}
 }
 
@@ -68,11 +87,14 @@ onBeforeUnmount(() => {
 		width: fit-content;
 		cursor: pointer;
 		&:not(:last-child) {
-			margin-bottom: 15px;
+			margin-bottom: 7px;
 		}
 		span {
+			display: block;
+			width: 55px;
 			margin-right: 15px;
 			font-size: 18px;
+			text-align: right;
 		}
 		i {
 			display: block;

+ 26 - 17
src/views/home/cpns/FloatPanelUav.vue

@@ -28,7 +28,10 @@
 				</li>
 			</ul>
 
-			<div class="title-sub my-2">飞行动态</div>
+			<div class="title-sub my-2">
+				飞行动态
+				<el-checkbox class="ml-auto" v-model="showLine" @change="handleToggleLine">航线</el-checkbox>
+			</div>
 			<ul class="des-list">
 				<li>
 					<div class="flex-1 flex">
@@ -186,30 +189,30 @@ const props = defineProps({
 		type: Object,
 		default: {
 			collision: {
-				show: true,
-				distance: 20,
+				show: false,
+				distance: 0,
 			},
 			offCourse: {
-				show: true,
-				distance: 20,
-				lineCode: 'MG22100WRJ',
+				show: false,
+				distance: 0,
+				lineCode: '',
 			},
 			power: {
-				show: true,
-				battery: 27,
-				distance: 310,
-				estimation: 720,
+				show: false,
+				battery: 0,
+				distance: 0,
+				estimation: 0,
 			},
 			area: {
-				show: true,
-				type: '禁飞区',
-				name: '禁飞区11',
+				show: false,
+				type: '',
+				name: '',
 			},
 			weather: {
-				show: true,
+				show: false,
 				// type: '大风',
 				// type: '大雨',
-				type: '雾霾',
+				// type: '雾霾',
 			},
 		},
 	},
@@ -241,7 +244,7 @@ function genWeatherDes(type) {
 	}
 }
 
-const emit = defineEmits(['close'])
+const emit = defineEmits(['close', 'showLine'])
 
 function handleClose() {
 	emit('close')
@@ -259,6 +262,12 @@ watch(
 	},
 	{ deep: true, immediate: true }
 )
+
+const showLine = ref(false)
+
+function handleToggleLine(val) {
+	emit('showLine', val)
+}
 </script>
 
 <style lang="scss" scoped>
@@ -301,7 +310,7 @@ watch(
 			flex: 1;
 			width: 0;
 			font-size: 16px;
-			color: #d2ddff;
+			color: #eef1ff;
 			overflow: hidden;
 			text-overflow: ellipsis;
 			white-space: nowrap;

+ 406 - 406
src/views/home/cpns/PanelLeft.vue

@@ -1,431 +1,431 @@
 <template>
-  <div class="panel-left aside-left-inner">
-    <div class="title-main">服务概览</div>
-    <ul class="b-fwgl">
-      <li v-for="item in panelData.serviceOverview">
-        <img :src="item.icon" alt="">
-        <div>
-          <div>
-            <!-- <span>{{ item.count }}</span> -->
-            <NumberScroll :value="item.count" />
-            <span>{{ item.unit }}</span>
-          </div>
-          <span>{{ item.label }}</span>
-        </div>
-      </li>
-    </ul>
-
-    <div class="title-main">今日飞行</div>
-    <div class="b-jrfx">
-      <ul class="bj-left">
-        <li v-for="item in panelData.flightSta">
-          <img :src="item.icon" alt="">
-          <div>
-            <span>{{ item.label }}</span>
-            <div>
-              <!-- <span>{{ item.count.toLocaleString() }}</span> -->
-              <NumberScroll :value="item.count" />
-              <span>{{ item.unit }}</span>
-            </div>
-          </div>
-        </li>
-      </ul>
-      <div class="bj-right">
-        <span class="chart-title">各类无人机</span>
-        <div id="chart-jrfx"></div>
-      </div>
-    </div>
-
-    <div class="title-main">空域申请计划</div>
-    <div class="b-kysq">
-
-      <template v-if="layoutStore.sceneType==='gis'">
-        <div class="title-sub">任务类型</div>
-        <ul class="row-rwlx">
-          <li v-for="(item, index) in panelData.taskApply" :style="{ marginTop: item.offsetTop }">
-            <!-- <span>{{ item.count }}</span> -->
-            <NumberScroll :value="item.count" />
-            <span>{{ item.label }}</span>
-            <img :src="getAssetsFile('page/stick-' + (index + 1) + '.png')" alt="">
-          </li>
-        </ul>
-      </template>
-
-      <div class="title-sub">审批状态</div>
-      <ul class="row-spzt">
-        <li v-for="(item, index) in panelData.taskAudit" :class="{'active': pickedTaskStatus===item.label}" @click="handlePickType(item)">
-          <!-- <span>{{ item.count }}</span> -->
-          <NumberScroll :value="item.count" />
-          <span>{{ item.label }}</span>
-        </li>
-      </ul>
-
-      <table class="table-default my-2" v-if="layoutStore.sceneType==='ue'">
-        <thead>
-          <tr>
-            <th>申请时间</th>
-            <th>起降场</th>
-            <th>飞行单位/人</th>
-            <th>任务类型</th>
-          </tr>
-        </thead>
-        <tbody class="h-36">
-          <tr v-for="item in deliveryListFiltered">
-            <td>{{ item.time }}</td>
-            <td>{{ item.port }}</td>
-            <td>{{ item.unit }}</td>
-            <td>{{ item.type }}</td>
-          </tr>
-        </tbody>
-      </table>
-
-    </div>
-
-  </div>
+	<div class="panel-left aside-left-inner">
+		<div class="title-main">服务概览</div>
+		<ul class="b-fwgl">
+			<li v-for="item in panelData.serviceOverview">
+				<img :src="item.icon" alt="" />
+				<div>
+					<div>
+						<!-- <span>{{ item.count }}</span> -->
+						<NumberScroll :value="item.count" />
+						<span>{{ item.unit }}</span>
+					</div>
+					<span>{{ item.label }}</span>
+				</div>
+			</li>
+		</ul>
+
+		<div class="title-main">今日飞行</div>
+		<div class="b-jrfx">
+			<ul class="bj-left">
+				<li v-for="item in panelData.flightSta">
+					<img :src="item.icon" alt="" />
+					<div>
+						<span>{{ item.label }}</span>
+						<div>
+							<!-- <span>{{ item.count.toLocaleString() }}</span> -->
+							<NumberScroll :value="item.count" />
+							<span>{{ item.unit }}</span>
+						</div>
+					</div>
+				</li>
+			</ul>
+			<div class="bj-right">
+				<span class="chart-title">各类无人机</span>
+				<div id="chart-jrfx"></div>
+			</div>
+		</div>
+
+		<div class="title-main">空域申请计划</div>
+		<div class="b-kysq">
+			<template v-if="layoutStore.sceneType === 'gis'">
+				<div class="title-sub">任务类型</div>
+				<ul class="row-rwlx">
+					<li v-for="(item, index) in panelData.taskApply" :style="{ marginTop: item.offsetTop }">
+						<!-- <span>{{ item.count }}</span> -->
+						<NumberScroll :value="item.count" />
+						<span>{{ item.label }}</span>
+						<img :src="getAssetsFile('page/stick-' + (index + 1) + '.png')" alt="" />
+					</li>
+				</ul>
+			</template>
+
+			<div class="title-sub">审批状态</div>
+			<ul class="row-spzt">
+				<li
+					v-for="(item, index) in panelData.taskAudit"
+					:class="{ active: pickedTaskStatus === item.label }"
+					@click="handlePickType(item)">
+					<!-- <span>{{ item.count }}</span> -->
+					<NumberScroll :value="item.count" />
+					<span>{{ item.label }}</span>
+				</li>
+			</ul>
+
+			<table class="table-default my-2" v-if="layoutStore.sceneType === 'ue'">
+				<thead>
+					<tr>
+						<th>申请时间</th>
+						<th>起降场</th>
+						<th>飞行单位/人</th>
+						<th>任务类型</th>
+					</tr>
+				</thead>
+				<tbody class="h-36">
+					<tr v-for="item in deliveryListFiltered">
+						<td>{{ item.time }}</td>
+						<td>{{ item.port }}</td>
+						<td>{{ item.unit }}</td>
+						<td>{{ item.type }}</td>
+					</tr>
+				</tbody>
+			</table>
+		</div>
+	</div>
 </template>
 
 <script setup>
-import { computed, onMounted, reactive, ref } from 'vue';
-import { getAssetsFile } from '@/utils/require';
-import { setJrfx } from '@/echarts/options';
-import useLayoutStore from '@/store/layout';
-import NumberScroll from '@/components/NumberScroll.vue';
+import { computed, onMounted, reactive, ref } from 'vue'
+import { getAssetsFile } from '@/utils/require'
+import { setJrfx } from '@/echarts/options'
+import useLayoutStore from '@/store/layout'
+import NumberScroll from '@/components/NumberScroll.vue'
 
 const layoutStore = useLayoutStore()
 
 const panelData = reactive({
-  serviceOverview: [
-    { label: '航线数量', count: 8, unit: '条', icon: getAssetsFile('page/icon-sta-hx.png') },
-    { label: '空域数量', count: 25, unit: '块', icon: getAssetsFile('page/icon-sta-ky.png') },
-    { label: '起降点数量', count: 9, unit: '个', icon: getAssetsFile('page/icon-sta-qjd.png') },
-    { label: '航空器数量', count: 50, unit: '个', icon: getAssetsFile('page/icon-sta-hkq.png') },
-    { label: '企业数量', count: 1, unit: '家', icon: getAssetsFile('page/icon-sta-qy.png') },
-    { label: '操控员数', count: 10, unit: '人', icon: getAssetsFile('page/icon-sta-cky.png') },
-  ],
-  taskApply: [
-    { label: '城配物流', count: 2313, offsetTop: '90px' },
-    { label: '飞行表演', count: 1425, offsetTop: '37px' },
-    { label: '医疗救护', count: 1462, offsetTop: '65px' },
-    { label: '空中巡查', count: 2562, offsetTop: '0px' },
-    { label: '空中浏览', count: 1638, offsetTop: '78px' },
-  ],
-  taskAudit: [
-    { count: 9, label: '待审批' },
-    { count: 5, label: '审核通过' },
-    { count: 2, label: '审核不通过' },
-  ],
-  flightSta: [
-    { label: '飞行架次', count: 1334, unit: '次', icon: getAssetsFile('page/icon-plane.png') },
-    { label: '航时', count: 5448, unit: 'H', icon: getAssetsFile('page/icon-clock.png') },
-    { label: '距离', count: 8720, unit: 'km', icon: getAssetsFile('page/icon-distance.png') },
-  ],
-  flightStaChart: [
-    { type: '微型', count: 560 },
-    { type: '轻型', count: 1460 },
-    { type: '小型', count: 280 },
-    { type: '中型', count: 460 },
-    { type: '大型', count: 980 },
-  ],
-  deliveryList: [
-    { time: '2025-02-21', port: '合生汇-黄兴公园', unit: '美团无人机', type: '城配物流', status: '待审批' },
-    { time: '2025-02-21', port: '合生汇-黄兴公园', unit: '美团无人机', type: '医疗救护', status: '审核通过' },
-    { time: '2025-02-21', port: '合生汇-黄兴公园', unit: '美团无人机', type: '城配物流', status: '审核不通过' },
-  ]
+	serviceOverview: [
+		{ label: '航线数量', count: 8, unit: '条', icon: getAssetsFile('page/icon-sta-hx.png') },
+		{ label: '空域数量', count: 25, unit: '块', icon: getAssetsFile('page/icon-sta-ky.png') },
+		{ label: '起降点数量', count: 9, unit: '个', icon: getAssetsFile('page/icon-sta-qjd.png') },
+		{ label: '航空器数量', count: 50, unit: '个', icon: getAssetsFile('page/icon-sta-hkq.png') },
+		{ label: '企业数量', count: 1, unit: '家', icon: getAssetsFile('page/icon-sta-qy.png') },
+		{ label: '操控员数', count: 10, unit: '人', icon: getAssetsFile('page/icon-sta-cky.png') },
+	],
+	taskApply: [
+		{ label: '城配物流', count: 2313, offsetTop: '90px' },
+		{ label: '飞行表演', count: 1425, offsetTop: '37px' },
+		{ label: '医疗救护', count: 1462, offsetTop: '65px' },
+		{ label: '空中巡查', count: 2562, offsetTop: '0px' },
+		{ label: '空中浏览', count: 1638, offsetTop: '78px' },
+	],
+	taskAudit: [
+		{ count: 9, label: '待审批' },
+		{ count: 5, label: '审核通过' },
+		{ count: 2, label: '审核不通过' },
+	],
+	flightSta: [
+		{ label: '飞行架次', count: 1334, unit: '次', icon: getAssetsFile('page/icon-plane.png') },
+		{ label: '航时', count: 5448, unit: 'H', icon: getAssetsFile('page/icon-clock.png') },
+		{ label: '距离', count: 8720, unit: 'km', icon: getAssetsFile('page/icon-distance.png') },
+	],
+	flightStaChart: [
+		{ type: '微型', count: 560 },
+		{ type: '轻型', count: 1460 },
+		{ type: '小型', count: 280 },
+		{ type: '中型', count: 460 },
+		{ type: '大型', count: 980 },
+	],
+	deliveryList: [
+		{ time: '2025-02-21', port: '合生汇-黄兴公园', unit: '美团无人机', type: '城配物流', status: '待审批' },
+		{ time: '2025-02-21', port: '合生汇-黄兴公园', unit: '美团无人机', type: '医疗救护', status: '审核通过' },
+		{ time: '2025-02-21', port: '合生汇-黄兴公园', unit: '美团无人机', type: '城配物流', status: '审核不通过' },
+	],
 })
 
 const pickedTaskStatus = ref('')
 
 function handlePickType(item) {
-  pickedTaskStatus.value = item.label === pickedTaskStatus.value? '': item.label
+	pickedTaskStatus.value = item.label === pickedTaskStatus.value ? '' : item.label
 }
 
 const deliveryListFiltered = computed(() => {
-  return pickedTaskStatus.value? panelData.deliveryList.filter(i => i.status === pickedTaskStatus.value): panelData.deliveryList
+	return pickedTaskStatus.value
+		? panelData.deliveryList.filter((i) => i.status === pickedTaskStatus.value)
+		: panelData.deliveryList
 })
 
 onMounted(() => {
-  setJrfx(document.getElementById('chart-jrfx'), panelData.flightStaChart)
+	setJrfx(document.getElementById('chart-jrfx'), panelData.flightStaChart)
 })
 </script>
 
 <style lang="scss" scoped>
 .panel-left {
-  display: flex;
-  flex-direction: column;
-  justify-content: space-between;
-
-  .b-fwgl {
-    display: flex;
-    justify-content: space-between;
-    flex-wrap: wrap;
-    height: 140px;
-    align-content: space-between;
-
-    li {
-      display: flex;
-      align-items: center;
-      width: 32%;
-
-      img {
-        width: 51px;
-        height: 51px;
-        margin-right: 7px;
-      }
-
-      &>div {
-        &>div {
-          margin-bottom: 7px;
-          display: flex;
-          align-items: end;
-
-          &>span:first-child {
-            margin-right: 5px;
-            font-size: 24px;
-            line-height: 20px;
-            background: linear-gradient(0deg, #FFFFFF 0%, #8BBBFF 79%);
-            -webkit-background-clip: text;
-            -webkit-text-fill-color: transparent;
-          }
-
-          &>span:last-child {
-            font-family: PingFang;
-            font-size: 14px;
-            line-height: 14px;
-          }
-        }
-
-        &>span {
-          display: block;
-          font-size: 16px;
-          text-shadow: -7px 7px 10px #001121;
-          background: url();
-        }
-      }
-    }
-  }
-
-  .b-kysq {
-    margin: 0 10px;
-
-    .row-rwlx {
-      margin: -30px 0 30px;
-      position: relative;
-      display: flex;
-      justify-content: space-between;
-      height: 180px;
-      padding: 0 10px;
-      overflow: visible;
-
-      &::after {
-        content: '';
-        display: block;
-        position: absolute;
-        height: 106px;
-        width: 100%;
-        bottom: -70px;
-        left: 0;
-        background: url('../../../assets/images/page/bg-plate.png') no-repeat;
-        background-size: 100%;
-        z-index: -1;
-      }
-
-      li {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-
-        span:first-child {
-          font-size: 17px;
-          font-size: 500;
-          color: #A5BCFF;
-          line-height: 22px;
-        }
-
-        span:nth-child(2) {
-          font-size: 14px;
-          color: #BEDFFF;
-          line-height: 18px;
-        }
-
-        &:nth-child(4) {
-          span:first-child {
-            background: linear-gradient(0deg, #D7B669 0%, #FFFFFF 100%);
-            -webkit-background-clip: text;
-            -webkit-text-fill-color: transparent;
-          }
-
-          span:nth-child(2) {
-            color: #D3BF83;
-          }
-        }
-      }
-    }
-
-    .row-spzt {
-      display: flex;
-      justify-content: space-between;
-      margin-top: 10px;
-
-      @mixin active {
-        content: '';
-        position: absolute;
-        left: 0;
-        top: 0;
-        width: 100%;
-        height: 100%;
-        clip-path: polygon(0% 0%, 100% 0%, 99% 60%, 50% 90%, 0% 60%);
-        z-index: -1;
-      }
-
-      li {
-        position: relative;
-        width: 117px;
-        height: 110px;
-        background: url('../../../assets/images/page/bg-rank-1.png');
-        background-size: 100% !important;
-        padding: 12px 0 20px;
-        text-align: center;
-        cursor: pointer;
-
-        &.active {
-          &::after {
-            @include active();
-            background: linear-gradient(to top, rgba(170, 160, 112, 0.8) 0%, rgba(170, 160, 112, 0) 80%);
-          }
-        }
-
-        span {
-          display: block;
-
-          &:first-child {
-            font-size: 30px;
-            line-height: 30px;
-            background: linear-gradient(0deg, #FFFFFF 0%, #F8FFA6 100%);
-            -webkit-background-clip: text !important;
-            -webkit-text-fill-color: transparent;
-          }
-
-          &:last-child {
-            margin-top: 7px;
-            font-size: 18px;
-            color: #E9EBCF;
-            line-height: 18px;
-          }
-        }
-
-        &:nth-child(2) {
-          background: url('../../../assets/images/page/bg-rank-2.png');
-
-          span:first-child {
-            background: linear-gradient(0deg, #FFFFFF 0%, #78B0FF 100%);
-          }
-
-          span:last-child {
-            color: #AECCDF;
-          }
-
-          &.active {
-            &::after {
-              @include active();
-              background: linear-gradient(to top, rgba(112, 157, 222, 0.8) 0%, rgba(112, 157, 222, 0) 80%);
-            }
-          }
-        }
-
-        &:nth-child(3) {
-          background: url('../../../assets/images/page/bg-rank-3.png');
-
-          span:first-child {
-            background: linear-gradient(0deg, #FFFFFF 0%, #7B7FE1 100%);
-          }
-
-          span:last-child {
-            color: #ABBBE6;
-          }
-
-          &.active {
-            &::after {
-              @include active();
-              background: linear-gradient(to top, rgba(173, 126, 190, 0.8) 0%, rgba(173, 126, 190, 0) 80%);
-            }
-          }
-        }
-      }
-    }
-  }
-
-  .b-jrfx {
-    display: flex;
-    height: 180px;
-
-    .bj-left {
-      width: 130px;
-      display: flex;
-      flex-direction: column;
-      justify-content: space-between;
-      padding-bottom: 15px;
-
-      li {
-        display: flex;
-        align-items: center;
-
-        img {
-          width: 49px;
-          height: 49px;
-          margin-right: 4px;
-        }
-
-        &>div {
-          &>span {
-            font-size: 14px;
-          }
-
-          &>div {
-            display: flex;
-            align-items: end;
-
-            &>span:first-child {
-              margin-right: 5px;
-              font-size: 24px;
-              line-height: 22px;
-              background: linear-gradient(180deg, #95CDFF 0%, #D8EDFF 100%);
-              -webkit-background-clip: text;
-              -webkit-text-fill-color: transparent;
-            }
-
-            &>span:last-child {
-              font-family: PingFang;
-              font-size: 14px;
-              line-height: 12px;
-            }
-          }
-        }
-      }
-    }
-
-    .bj-right {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-
-      .chart-title {
-        display: block;
-        width: 108px;
-        height: 37px;
-        background: url('../../../assets/images/page/bg-chart-title.png');
-        background-size: cover;
-        font-size: 16px;
-        line-height: 44px;
-        text-align: center;
-      }
-      #chart-jrfx {
-        width: 100%;
-        flex: 1;
-      }
-    }
-
-
-  }
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+
+	.b-fwgl {
+		display: flex;
+		justify-content: space-between;
+		flex-wrap: wrap;
+		height: 140px;
+		align-content: space-between;
+
+		li {
+			display: flex;
+			align-items: center;
+			width: 32%;
+
+			img {
+				width: 51px;
+				height: 51px;
+				margin-right: 7px;
+			}
+
+			& > div {
+				& > div {
+					margin-bottom: 7px;
+					display: flex;
+					align-items: end;
+
+					& > span:first-child {
+						margin-right: 5px;
+						font-size: 24px;
+						line-height: 20px;
+						background: linear-gradient(0deg, #ffffff 0%, #8bbbff 79%);
+						-webkit-background-clip: text;
+						-webkit-text-fill-color: transparent;
+					}
+
+					& > span:last-child {
+						font-family: PingFang;
+						font-size: 14px;
+						line-height: 14px;
+					}
+				}
+
+				& > span {
+					display: block;
+					font-size: 16px;
+					text-shadow: -7px 7px 10px #001121;
+					background: url();
+				}
+			}
+		}
+	}
+
+	.b-kysq {
+		margin: 0 10px;
+
+		.row-rwlx {
+			margin: -30px 0 30px;
+			position: relative;
+			display: flex;
+			justify-content: space-between;
+			height: 180px;
+			padding: 0 10px;
+			overflow: visible;
+
+			&::after {
+				content: '';
+				display: block;
+				position: absolute;
+				height: 106px;
+				width: 100%;
+				bottom: -70px;
+				left: 0;
+				background: url('../../../assets/images/page/bg-plate.png') no-repeat;
+				background-size: 100%;
+				z-index: -1;
+			}
+
+			li {
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+
+				span:first-child {
+					font-size: 19px;
+					font-size: 500;
+					color: #b7c9ff;
+					line-height: 22px;
+				}
+
+				span:nth-child(2) {
+					font-size: 16px;
+					color: #d0e8ff;
+					line-height: 24px;
+				}
+
+				&:nth-child(4) {
+					span:first-child {
+						background: linear-gradient(0deg, #f4d998 0%, #ffffff 100%);
+						-webkit-background-clip: text;
+						-webkit-text-fill-color: transparent;
+					}
+
+					span:nth-child(2) {
+						color: #ebd9a2;
+					}
+				}
+			}
+		}
+
+		.row-spzt {
+			display: flex;
+			justify-content: space-between;
+			margin-top: 10px;
+
+			@mixin active {
+				content: '';
+				position: absolute;
+				left: 0;
+				top: 0;
+				width: 100%;
+				height: 100%;
+				clip-path: polygon(0% 0%, 100% 0%, 99% 60%, 50% 90%, 0% 60%);
+				z-index: -1;
+			}
+
+			li {
+				position: relative;
+				width: 117px;
+				height: 110px;
+				background: url('../../../assets/images/page/bg-rank-1.png');
+				background-size: 100% !important;
+				padding: 12px 0 20px;
+				text-align: center;
+				cursor: pointer;
+
+				&.active {
+					&::after {
+						@include active();
+						background: linear-gradient(to top, rgba(170, 160, 112, 0.8) 0%, rgba(170, 160, 112, 0) 80%);
+					}
+				}
+
+				span {
+					display: block;
+
+					&:first-child {
+						font-size: 30px;
+						line-height: 30px;
+						background: linear-gradient(0deg, #ffffff 0%, #f8ffa6 100%);
+						-webkit-background-clip: text !important;
+						-webkit-text-fill-color: transparent;
+					}
+
+					&:last-child {
+						margin-top: 7px;
+						font-size: 18px;
+						color: #e9ebcf;
+						line-height: 18px;
+					}
+				}
+
+				&:nth-child(2) {
+					background: url('../../../assets/images/page/bg-rank-2.png');
+
+					span:first-child {
+						background: linear-gradient(0deg, #ffffff 0%, #78b0ff 100%);
+					}
+
+					span:last-child {
+						color: #aeccdf;
+					}
+
+					&.active {
+						&::after {
+							@include active();
+							background: linear-gradient(to top, rgba(112, 157, 222, 0.8) 0%, rgba(112, 157, 222, 0) 80%);
+						}
+					}
+				}
+
+				&:nth-child(3) {
+					background: url('../../../assets/images/page/bg-rank-3.png');
+
+					span:first-child {
+						background: linear-gradient(0deg, #ffffff 0%, #7b7fe1 100%);
+					}
+
+					span:last-child {
+						color: #abbbe6;
+					}
+
+					&.active {
+						&::after {
+							@include active();
+							background: linear-gradient(to top, rgba(173, 126, 190, 0.8) 0%, rgba(173, 126, 190, 0) 80%);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	.b-jrfx {
+		display: flex;
+		height: 180px;
+
+		.bj-left {
+			width: 130px;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+			padding-bottom: 15px;
+
+			li {
+				display: flex;
+				align-items: center;
+
+				img {
+					width: 49px;
+					height: 49px;
+					margin-right: 4px;
+				}
+
+				& > div {
+					& > span {
+						font-size: 14px;
+					}
+
+					& > div {
+						display: flex;
+						align-items: end;
+
+						& > span:first-child {
+							margin-right: 5px;
+							font-size: 24px;
+							line-height: 22px;
+							background: linear-gradient(180deg, #95cdff 0%, #d8edff 100%);
+							-webkit-background-clip: text;
+							-webkit-text-fill-color: transparent;
+						}
+
+						& > span:last-child {
+							font-family: PingFang;
+							font-size: 14px;
+							line-height: 12px;
+						}
+					}
+				}
+			}
+		}
+
+		.bj-right {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+
+			.chart-title {
+				display: block;
+				width: 108px;
+				height: 37px;
+				background: url('../../../assets/images/page/bg-chart-title.png');
+				background-size: cover;
+				font-size: 16px;
+				line-height: 44px;
+				text-align: center;
+			}
+			#chart-jrfx {
+				width: 100%;
+				flex: 1;
+			}
+		}
+	}
 }
-</style>
+</style>

+ 30 - 3
src/views/home/cpns/PanelSjwg.vue

@@ -83,6 +83,11 @@
 				</ul>
 			</div>
 		</Transition>
+
+		<!-- 空域点查询 -->
+		<Transition name="emerge-left">
+			<FloatPanelAirSpace v-if="layoutStore.floatPanels.air_space" />
+		</Transition>
 	</div>
 </template>
 
@@ -90,14 +95,15 @@
 import shifei from '@/data/shifei.json'
 import { DeleteArea, DeletePlot, DeleteRoute, GetAreaList, GetPlotList, GetRouteList } from '@/service/http'
 import useLayoutStore from '@/store/layout'
+import { useMapStore } from '@/store/map.js'
 import usePanelStore from '@/store/panel'
-import { AddSingleLayer, heatMap, InspectCube, showShapes } from '@/utils/map/addLayer'
+import { AddSingleLayer, heatMap, InspectCube, showShapes, toggleFeaturesClickEvent } from '@/utils/map/addLayer'
 import { airSpaceTypes } from '@/utils/options'
 import { getAssetsFile, getData } from '@/utils/require'
 import { hexToRgb } from '@/utils/tools'
 import { renderShapes } from '@/utils/ueActions'
 import { onBeforeMount, onBeforeUnmount, reactive, ref, watch } from 'vue'
-import { useMapStore } from '@/store/map.js'
+import FloatPanelAirSpace from './FloatPanelAirSpace.vue'
 
 const panelStore = usePanelStore()
 const layoutStore = useLayoutStore()
@@ -110,6 +116,7 @@ onBeforeMount(() => {
 	if (layoutStore.sceneType === 'ue') {
 		contentShow.b1 = false
 	}
+	toggleFeaturesClickEvent(true)
 })
 
 function addAreaColors() {
@@ -307,6 +314,7 @@ function handleCheck(item, type) {
 	item.check = !item.check
 	let color
 	const shapeObj = JSON.parse(item.shape)
+	let additional = {}
 	switch (type) {
 		case 'area':
 			if (item.spaceType !== '6') {
@@ -316,6 +324,13 @@ function handleCheck(item, type) {
 				color = +shapeObj.height < 120 ? colorArr[0] : +shapeObj.height < 300 ? colorArr[1] : colorArr[2]
 				color = hexToRgb(color, 0.5)
 			}
+			additional = {
+				attributes: {
+					id: item.id,
+					name: item.name,
+					height: shapeObj.height,
+				},
+			}
 			break
 		case 'plot':
 			color = hexToRgb(featureLists.value.find((i) => i.type === 'plot').color, 0.7)
@@ -325,6 +340,7 @@ function handleCheck(item, type) {
 	}
 	const data = [
 		{
+			...additional,
 			type: type === 'route' ? item.type : item.geoType,
 			shape: {
 				...shapeObj,
@@ -469,7 +485,8 @@ function handleRestoreChecked() {
 onBeforeUnmount(() => {
 	handleStoreChecked()
 	layoutStore.toggleFloatPanel('layers_legend', false)
-	// clearAllFeatures()
+	layoutStore.toggleFloatPanel('air_space', false)
+	toggleFeaturesClickEvent(false)
 })
 
 const vCollapse = {
@@ -497,6 +514,16 @@ watch(
 	},
 	{ deep: true }
 )
+
+watch(
+	() => mapStore.clickResult,
+	(val) => {
+		if (!layoutStore.floatPanels.air_space) {
+			layoutStore.toggleFloatPanel('air_space', true)
+		}
+	},
+	{ deep: true }
+)
 </script>
 
 <style lang="scss" scoped>

+ 2 - 2
src/views/home/cpns/ToolList.vue

@@ -183,7 +183,7 @@ function handleToolClick(tool, childIndex) {
 }
 
 // 浮动面板被关闭时,取消按钮选中
-watch(
+/* watch(
 	layoutStore.floatPanels,
 	(val) => {
 		for (let [k, v] of Object.entries(val)) {
@@ -196,7 +196,7 @@ watch(
 		}
 	},
 	{ deep: true }
-)
+) */
 
 function handleToolHover(tool) {
 	if (!(tool.children && tool.children.some((i) => i.active))) return

+ 151 - 153
src/views/layout/cpns/Footer.vue

@@ -1,179 +1,177 @@
 <template>
-  <div class="footer flex justify-center" :class="{'collapse': footerCollapse }">
-    <div class="footer-deco footer-deco-left"></div>
-    <div class="footer-main flex items-end justify-center">
-      <div class="btn-switch switch-left" :class="{ 'active': sceneType === 'ue' }" @click="handleToggleScene">
-        <i></i>
-        <span>城市配送</span>
-      </div>
-      <i class="btn-collapse" @click="handleToggleFooter(true)"></i>
-      <Transition name="fade">
-        <i v-if="footerCollapse" class="btn-collapse bc-up" @click="handleToggleFooter(false)"></i>
-      </Transition>
-      <div class="btn-switch switch-right">
-        <i></i>
-        <span>编队表演</span>
-      </div>
-    </div>
-    <div class="footer-deco footer-deco-right"></div>
-  </div>
+	<div class="footer flex justify-center" :class="{ collapse: footerCollapse }">
+		<div class="footer-deco footer-deco-left"></div>
+		<div class="footer-main flex items-end justify-center">
+			<div class="btn-switch switch-left" :class="{ active: sceneType === 'ue' }" @click="handleToggleScene">
+				<i></i>
+				<span>城市配送</span>
+			</div>
+			<i class="btn-collapse" @click="handleToggleFooter(true)"></i>
+			<Transition name="fade">
+				<i v-if="footerCollapse" class="btn-collapse bc-up" @click="handleToggleFooter(false)"></i>
+			</Transition>
+			<div class="btn-switch switch-right">
+				<i></i>
+				<span>编队表演</span>
+			</div>
+		</div>
+		<div class="footer-deco footer-deco-right"></div>
+	</div>
 </template>
 
 <script setup>
-import { computed } from 'vue';
-import useLayoutStore from '@/store/layout';
+import { computed } from 'vue'
+import useLayoutStore from '@/store/layout'
 
 const layoutStore = useLayoutStore()
 
 const footerCollapse = computed(() => {
-  return layoutStore.footerCollapse
+	return layoutStore.footerCollapse
 })
 
 const sceneType = computed(() => {
-  return layoutStore.sceneType
+	return layoutStore.sceneType
 })
 
 function handleToggleScene() {
-  layoutStore.toggleScene()
-  const isUeScene = layoutStore.sceneType === 'ue'
-  if(layoutStore.toolsActive.tsjs) {
-    layoutStore.toggleUavMonitor(isUeScene)
-  }
+	layoutStore.toggleScene()
+	const isUeScene = layoutStore.sceneType === 'ue'
+	if (layoutStore.toolsActive.tsjs) {
+		layoutStore.toggleUavMonitor(isUeScene)
+	}
 }
 
 function handleToggleFooter(val) {
-  layoutStore.toggleFooter(val)
+	layoutStore.toggleFooter(val)
 }
-
 </script>
 
 <style lang="scss" scoped>
 .footer {
-  position: absolute;
-  bottom: 0;
-  width: calc(100% - 40px);
-  margin: 0 20px;
-  height: var(--footer-height);
-  text-align: center;
-  background: url('../../../assets/images/layout/bg-footer-deco.png') no-repeat;
-  background-size: contain;
-  background-position: bottom;
-  transition: bottom 0.5s ease;
-
-  &.collapse {
-    bottom: calc(0px - var(--footer-height));
-    visibility: visible;
-  }
-
-  .footer-main {
-    height: 100%;
-    width: 725px;
-    padding-bottom: 2px;
-    background: url('../../../assets/images/layout/bg-footer.png');
-    background-size: cover;
-    background-position: bottom;
-  }
-
-  .btn-switch {
-    display: flex;
-    align-items: center;
-    margin-bottom: 3px;
-    cursor: pointer;
-    i {
-      display: block;
-      width: 36px;
-      height: 36px;
-      background-size: 100% !important;
-      background-position: center 5px !important;
-    }
-    span {
-      padding-right: 5px;
-      font-size: 23px;
-      font-style: italic;
-      background: linear-gradient(45deg, rgba(169, 176, 184, 1) 0%, RGBA(138, 162, 189, 1) 100%);
-      -webkit-background-clip: text;
-      -webkit-text-fill-color: transparent;
-    }
-
-    &.active span {
-      background: linear-gradient(180deg, #BFD6FF 0%, #fff 100%);
-      -webkit-background-clip: text;
-      -webkit-text-fill-color: transparent;
-    }
-  }
-
-  .switch-left {
-    i {
-      background: url('../../../assets/images/layout/icon-csps.png');
-    }
-    &.active {
-      i {
-        background: url('../../../assets/images/layout/icon-csps-h.png');
-      }
-    }
-  }
-  .switch-right {
-    i {
-      background: url('../../../assets/images/layout/icon-bdby.png');
-    }
-    &.active {
-      i {
-        background: url('../../../assets/images/layout/icon-bdby-h.png');
-      }
-    }
-  }
-
-  .btn-collapse {
-    display: block;
-    width: 33px;
-    height: 25px;
-    margin: 0 20px 10px;
-    background: url('../../../assets/images/layout/arrow-down.png');
-    background-size: 100%;
-    cursor: pointer;
-
-    &.bc-up {
-      position: absolute;
-      top: -40px;
-      margin: 0;
-      background: url('../../../assets/images/layout/arrow-up.png');
-    }
-  }
-
-  .footer-deco {
-    display: none;
-  }
-
+	position: absolute;
+	bottom: 0;
+	width: calc(100% - 40px);
+	margin: 0 20px;
+	height: var(--footer-height);
+	text-align: center;
+	background: url('../../../assets/images/layout/bg-footer-deco.png') no-repeat;
+	background-size: contain;
+	background-position: bottom;
+	transition: bottom 0.5s ease;
+
+	&.collapse {
+		bottom: calc(0px - var(--footer-height));
+		visibility: visible;
+	}
+
+	.footer-main {
+		height: 100%;
+		width: 725px;
+		padding-bottom: 3px;
+		background: url('../../../assets/images/layout/bg-footer.png') no-repeat;
+		background-size: cover;
+		background-position: bottom;
+	}
+
+	.btn-switch {
+		display: flex;
+		align-items: center;
+		margin-bottom: 3px;
+		cursor: pointer;
+		i {
+			display: block;
+			width: 36px;
+			height: 36px;
+			background-size: 100% !important;
+			background-position: center 5px !important;
+		}
+		span {
+			padding-right: 5px;
+			font-size: 23px;
+			font-style: italic;
+			background: linear-gradient(45deg, rgba(169, 176, 184, 1) 0%, RGBA(138, 162, 189, 1) 100%);
+			-webkit-background-clip: text;
+			-webkit-text-fill-color: transparent;
+		}
+
+		&.active span {
+			background: linear-gradient(180deg, #bfd6ff 0%, #fff 100%);
+			-webkit-background-clip: text;
+			-webkit-text-fill-color: transparent;
+		}
+	}
+
+	.switch-left {
+		i {
+			background: url('../../../assets/images/layout/icon-csps.png');
+		}
+		&.active {
+			i {
+				background: url('../../../assets/images/layout/icon-csps-h.png');
+			}
+		}
+	}
+	.switch-right {
+		i {
+			background: url('../../../assets/images/layout/icon-bdby.png');
+		}
+		&.active {
+			i {
+				background: url('../../../assets/images/layout/icon-bdby-h.png');
+			}
+		}
+	}
+
+	.btn-collapse {
+		display: block;
+		width: 33px;
+		height: 25px;
+		margin: 0 20px 10px;
+		background: url('../../../assets/images/layout/arrow-down.png');
+		background-size: 100%;
+		cursor: pointer;
+
+		&.bc-up {
+			position: absolute;
+			top: -40px;
+			margin: 0;
+			background: url('../../../assets/images/layout/arrow-up.png');
+		}
+	}
+
+	.footer-deco {
+		display: none;
+	}
 }
 
 @media screen and (min-aspect-ratio: 21/9) {
-  .footer {
-    .footer-main {
-      width: 1100px;
-      background: url('../../../assets/images/layout/bg-footer_large.png');
-      background-size: 100% 115px;
-      background-position: bottom;
-      .btn-switch {
-        margin-bottom: 7px;
-      }
-      .btn-collapse {
-        margin-bottom: 14px;
-      }
-    }
-    background: none;
-    .footer-deco {
-      display: block;
-      flex: 1;
-      background-size: contain !important;
-      background-position: bottom !important;
-      pointer-events: none;
-      &.footer-deco-left {
-        background: url('../../../assets/images/layout/bg-footer-deco-left.png') no-repeat;
-      }
-      &.footer-deco-right {
-        background: url('../../../assets/images/layout/bg-footer-deco-right.png') no-repeat;
-      }
-    }
-  }
+	.footer {
+		.footer-main {
+			width: 1100px;
+			background: url('../../../assets/images/layout/bg-footer_large.png');
+			background-size: 100% 115px;
+			background-position: bottom;
+			.btn-switch {
+				margin-bottom: 7px;
+			}
+			.btn-collapse {
+				margin-bottom: 14px;
+			}
+		}
+		background: none;
+		.footer-deco {
+			display: block;
+			flex: 1;
+			background-size: contain !important;
+			background-position: bottom !important;
+			pointer-events: none;
+			&.footer-deco-left {
+				background: url('../../../assets/images/layout/bg-footer-deco-left.png') no-repeat;
+			}
+			&.footer-deco-right {
+				background: url('../../../assets/images/layout/bg-footer-deco-right.png') no-repeat;
+			}
+		}
+	}
 }
-</style>
+</style>

+ 1 - 1
src/views/layout/cpns/Header.vue

@@ -141,7 +141,7 @@ function handleReset() {
 			font-size: 30px;
 			line-height: 30px;
 			letter-spacing: 2px;
-			background-image: linear-gradient(0deg, #a5bae3 0%, #e8e9ee 100%);
+			background-image: linear-gradient(0deg, #cedeff 0%, #ffffff 100%);
 			-webkit-background-clip: text;
 			-webkit-text-fill-color: transparent;
 			z-index: 1;