123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- <template>
- <div class="panel-sjwg flex flex-col aside-left-inner">
- <div class="title-main shrink-0">低空数字地图</div>
- <div class="title-sub my-4 shrink-0">
- 底板数据
- <i @click="toggleContentShow('b1')" class="drop-down" :class="{ reverse: contentShow.b1 }"></i>
- </div>
- <Transition>
- <div v-if="contentShow.b1" v-collapse="'scroll'" class="pr-1" style="flex: 1">
- <template v-for="item in basicList">
- <div class="title-shade">
- <span>{{ item.label }}</span>
- <i
- v-if="'active' in item"
- class="btn-selectall"
- :class="{ active: item.active }"
- @click="basicCheckAll(item)"></i>
- <i class="drop-down" @click="toggleB1Show(item)" :class="{ reverse: item.show }"></i>
- </div>
- <Transition>
- <ul v-if="item.show" v-collapse>
- <li v-for="child in item.children" class="list-item" :class="{ disabled: child.disabled }">
- <img :src="getAssetsFile(`resources/${child.icon}.png`)" alt="" />
- <span>{{ child.label }}</span>
- <i title="查看" @click="handleBaseClick(child)" :class="{ active: child.active }"></i>
- </li>
- </ul>
- </Transition>
- </template>
- </div>
- </Transition>
- <div class="title-sub my-4 shrink-0">
- 低空要素数据<i @click="toggleContentShow('b2')" class="drop-down" :class="{ reverse: contentShow.b2 }"></i>
- </div>
- <Transition>
- <div v-if="contentShow.b2" v-collapse="'scroll'" class="pr-1" style="flex: 1">
- <template v-for="item in featureLists">
- <div class="title-shade">
- <span @click="handleCheckShiFei(item.label)">{{ item.label }}</span>
- <i class="btn-selectall" :class="{ active: item.check }" @click="handleCheckAll(item)"></i>
- <i class="drop-down" @click="toggleB2Show(item)" :class="{ reverse: item.show }"></i>
- </div>
- <Transition>
- <ul v-if="item.show" v-collapse>
- <li v-for="child in item.children" class="list-item">
- <img :src="getAssetsFile(`resources/${item.icon}.png`)" alt="" />
- <span>{{ child.name }}</span>
- <i title="查看" @click="handleCheck(child, item.type)" :class="{ active: child.check }"></i>
- <i title="网格" @click="handleMesh(child, item.type)" :class="{ active: child.mesh }"></i>
- <el-popconfirm title="确定删除?" @confirm="handleDelete(child, item.type)">
- <template #reference>
- <i title="删除"></i>
- </template>
- </el-popconfirm>
- </li>
- <li v-if="!item.children.length" class="no-data">无数据</li>
- </ul>
- </Transition>
- </template>
- </div>
- </Transition>
- <Transition name="emerge-left">
- <div class="feature-legend" v-if="layoutStore.floatPanels.layers_legend">
- <div class="title-sub">图例</div>
- <ul>
- <template v-for="item in featureLists">
- <li>
- <i v-if="item.color" :style="{ background: item.color }"></i>
- <span :class="{ bold: item.colors }">{{ item.label }}</span>
- </li>
- <template v-if="item.colors">
- <div v-for="(childColor, childLabel) in item.colors">
- <i :style="{ background: childColor }"></i>
- <span>{{ childLabel }}</span>
- </div>
- </template>
- </template>
- </ul>
- </div>
- </Transition>
- <!-- 空域点查询 -->
- <Transition name="emerge-left">
- <FloatPanelAirSpace v-if="layoutStore.floatPanels.air_space" />
- </Transition>
- </div>
- </template>
- <script setup>
- 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, 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 FloatPanelAirSpace from './FloatPanelAirSpace.vue'
- const panelStore = usePanelStore()
- const layoutStore = useLayoutStore()
- const mapStore = useMapStore()
- let shifeiStatus = false
- onBeforeMount(() => {
- getLists()
- addAreaColors()
- if (layoutStore.sceneType === 'ue') {
- contentShow.b1 = false
- }
- toggleFeaturesClickEvent(true)
- })
- function addAreaColors() {
- featureLists.value.forEach((i) => {
- if (!i.color && !i.colors) {
- i.color = airSpaceTypes.find((t) => t.label === i.label).color
- }
- })
- layoutStore.toggleFloatPanel('layers_legend', true)
- }
- function showWarning(message) {
- ElMessage({ offset: 90, type: 'warning', message })
- }
- function getLists() {
- Promise.all([
- GetAreaList()
- .then((res) => {
- if (!Array.isArray(res.data.data)) {
- showWarning('空域列表查询失败')
- return
- }
- const resList = res.data.data.map((row) => ({
- ...row,
- check: false,
- mesh: false,
- }))
- featureLists.value[0].children = resList.filter((r) => r.spaceType === '1')
- featureLists.value[1].children = resList.filter((r) => r.spaceType === '2')
- featureLists.value[2].children = resList.filter((r) => r.spaceType === '3')
- featureLists.value[3].children = resList.filter((r) => r.spaceType === '6')
- featureLists.value[0].show = true
- })
- .catch(() => {
- showWarning('空域列表查询失败')
- }),
- GetPlotList()
- .then((res) => {
- if (!Array.isArray(res.data.data)) {
- showWarning('起降场列表查询失败')
- return
- }
- featureLists.value[6].children = res.data.data.map((row) => ({
- ...row,
- check: false,
- mesh: false,
- }))
- })
- .catch(() => {
- showWarning('起降场列表查询失败')
- }),
- GetRouteList()
- .then((res) => {
- if (!Array.isArray(res.data.data)) {
- showWarning('航线列表查询失败')
- return
- }
- featureLists.value[4].children = res.data.data.map((row) => ({
- ...row,
- check: false,
- mesh: false,
- }))
- })
- .catch(() => {
- showWarning('航线列表查询失败')
- }),
- ]).finally(() => {
- // 恢复选中状态
- handleRestoreChecked()
- })
- }
- function basicCheckAll(item) {
- item.active = !item.active
- item.children.forEach((c) => {
- c.active = !item.active
- handleBaseClick(c)
- })
- }
- const basicList = ref([
- {
- label: '地形',
- show: true,
- children: [
- { label: '影像', alias: '影像底图', icon: 'dxing', active: false },
- { label: '政务底图', alias: '政务底图', icon: 'dxing', active: false },
- { label: '暗色底图', alias: '暗色底图', icon: 'dxing', active: false },
- ],
- },
- {
- label: '低空障碍物',
- show: false,
- active: false,
- children: [
- { label: '全市建筑物', alias: '全市白模', icon: 'qsjzwu', active: false },
- { label: '高精度模型', alias: '五角场精模', icon: 'gjdmxing', active: false },
- ],
- },
- {
- label: '电磁干扰场域',
- show: false,
- active: false,
- children: [
- { label: '无线通信基站', active: false, icon: 'wxtxjzhan', disabled: true },
- { label: '电磁干扰', active: false, icon: 'dcgrao', disabled: true },
- ],
- },
- {
- label: '其它社会信息',
- show: false,
- active: false,
- children: [
- { label: '道路', alias: ['快速路', '高速公路', '地面道路'], icon: 'dlu', active: false },
- { label: '河流', alias: '全市河流', icon: 'hliu', active: false },
- { label: '轨道交通', icon: 'gdjtong', active: false },
- { label: '铁路', icon: 'tlu', active: false },
- { label: '绿化', alias: '公园绿地', icon: 'lhua', active: false },
- { label: '学校', icon: 'xxiao', active: false },
- { label: '医院', alias: '医院', icon: 'yyuan', active: false },
- { label: '人口', alias: '人口', icon: 'rkou', active: false },
- { label: '政府部门', icon: 'zfbmen', active: false },
- ],
- },
- ])
- const featureLists = ref([
- { label: '禁飞区', type: 'area', show: false, check: false, icon: 'jfqu', children: [] },
- { label: '净空区', type: 'area', show: false, check: false, icon: 'jkqu', children: [] },
- { label: '适飞区', type: 'area', show: false, check: false, icon: 'sfqu', children: [] },
- {
- label: '已批复空域',
- type: 'area',
- show: false,
- check: false,
- icon: 'ypfkyu',
- children: [],
- colors: { '120米以下': '#ccff66', '300米以下': '#ffcc66', '600米以下': '#feb2b2' },
- },
- {
- label: '航线',
- type: 'route',
- show: false,
- check: false,
- icon: 'hxian',
- children: [],
- colors: { 已批复: '#6eff25', 未批复: '#ffff00' },
- },
- { label: '航路', type: 'hanglu', show: false, check: false, icon: 'hxian', children: [], color: '#c195ff' },
- { label: '起降场', type: 'plot', show: false, check: false, icon: 'qjchang', children: [], color: '#45dcb5' },
- ])
- let resources
- async function handleBaseClick(layer) {
- layer.active = !layer.active
- if (layer.alias) {
- const aliasArr = Array.isArray(layer.alias) ? layer.alias : [layer.alias]
- if (!resources) {
- resources = await getData('resources.json')
- }
- const targetServices = resources.filter((r) => aliasArr.some((i) => i === r.title))
- if (targetServices.length === 0) return
- targetServices.forEach((service) => {
- if (service.type == 'feature') {
- heatMap({
- ...service,
- visible: layer.active,
- })
- } else {
- AddSingleLayer({
- ...service,
- visible: layer.active,
- opacity: 1,
- })
- }
- })
- }
- }
- function toggleB1Show(item) {
- const target = basicList.value.find((i) => i.label === item.label)
- target.show = !target.show
- basicList.value.forEach((i) => {
- if (i.show && i.label !== item.label) {
- i.show = false
- }
- })
- }
- function toggleB2Show(item) {
- const target = featureLists.value.find((i) => i.label === item.label)
- target.show = !target.show
- featureLists.value.forEach((i) => {
- if (i.show && i.label !== item.label) {
- i.show = false
- }
- })
- }
- function handleCheck(item, type) {
- // console.log(item)
- item.check = !item.check
- let color
- const shapeObj = JSON.parse(item.shape)
- let additional = {}
- switch (type) {
- case 'area':
- additional = {
- attributes: {
- id: item.id,
- name: item.name,
- height: shapeObj.height,
- },
- }
- if (item.spaceType !== '6') {
- color = hexToRgb(airSpaceTypes.find((i) => i.value === item.spaceType).color, 0.5)
- } else {
- const colorArr = Object.values(featureLists.value.find((i) => i.label === '已批复空域').colors)
- color = +shapeObj.height < 120 ? colorArr[0] : +shapeObj.height < 300 ? colorArr[1] : colorArr[2]
- color = hexToRgb(color, 0.5)
- // 已批复空域添加属性
- additional.attributes = {
- lb: item.category,
- rwxz: item.taskProperties,
- ssdw: item.affiliatedUnit,
- jx_js: item.modelAndAmount,
- ...additional.attributes,
- }
- }
- break
- case 'plot':
- color = hexToRgb(featureLists.value.find((i) => i.type === 'plot').color, 0.7)
- const { height, coneHeight, cylinderHeight } = shapeObj
- additional = {
- attributes: {
- id: item.id,
- name: item.name,
- height: height || coneHeight + cylinderHeight,
- },
- }
- break
- case 'route':
- const colors = featureLists.value.find((i) => i.type === 'route').colors
- color = hexToRgb(
- ['复旦第三教学楼', '互联宝地', '黄兴公园', '国正中心'].some((i) => item.name.includes(i))
- ? colors['已批复']
- : colors['未批复'],
- 0.5
- )
- }
- const data = [
- {
- ...additional,
- type: type === 'route' ? item.type : item.geoType,
- shape: {
- ...shapeObj,
- color,
- },
- },
- ]
- if (layoutStore.sceneType === 'gis') {
- showShapes({
- id: item.id,
- data: item.check ? data : null,
- })
- } else {
- renderShapes({
- id: item.id,
- data: item.check ? data[0] : null,
- })
- }
- }
- function handleCheckShiFei(label) {
- if (label !== '适飞区') return
- shifeiStatus = !shifeiStatus
- if (shifeiStatus) {
- shifei.forEach((item) => {
- showShapes({
- id: item.attributes.FID,
- data: [
- {
- type: 'polygon',
- shape: {
- color: [0, 255, 0, 0.5],
- height: 120,
- rings: item.geometry.rings,
- },
- },
- ],
- })
- })
- } else {
- shifei.forEach((item) => {
- showShapes({
- id: item.attributes.FID,
- })
- })
- }
- }
- function handleDelete(item, type) {
- switch (type) {
- case 'area':
- DeleteArea(item.id).then((res) => {
- if (res.data.code === 200) {
- ElMessage.success('删除成功')
- getLists()
- }
- })
- break
- case 'plot':
- DeletePlot(item.id).then((res) => {
- if (res.data.code === 200) {
- ElMessage.success('删除成功')
- getLists()
- }
- })
- break
- case 'route':
- DeleteRoute(item.id).then((res) => {
- if (res.data.code === 200) {
- ElMessage.success('删除成功')
- getLists()
- }
- })
- }
- }
- function handleMesh(item, type) {
- item.mesh = !item.mesh
- if (item.mesh) {
- layoutStore.toggleGlobalLoading(true)
- }
- InspectCube({
- id: item.id,
- show: item.mesh,
- type: item.geoType || item.type,
- shape: JSON.parse(item.shape),
- })
- }
- const contentShow = reactive({
- b1: true,
- b2: true,
- })
- function toggleContentShow(id) {
- contentShow[id] = !contentShow[id]
- }
- function handleCheckAll(item) {
- item.check = !item.check
- item.children.forEach((c) => {
- if (item.check && !c.check) {
- handleCheck(c, item.type)
- } else if (!item.check && c.check) {
- handleCheck(c, item.type)
- }
- })
- }
- function handleStoreChecked() {
- panelStore.setSjwg({
- basicList: basicList.value,
- featureLists: featureLists.value.map((t) => ({
- label: t.label,
- show: t.show,
- check: t.check,
- children: t.children.map((c) => ({
- id: c.id,
- check: c.check,
- mesh: c.mesh,
- })),
- })),
- })
- }
- function handleRestoreChecked() {
- if (!Object.keys(panelStore.sjwg).length) return
- const temp = panelStore.sjwg
- basicList.value = temp.basicList
- featureLists.value.forEach((row) => {
- const tar_row = temp.featureLists.find((t) => t.label === row.label)
- row.check = tar_row.check
- row.show = tar_row.show
- row.children.forEach((c) => {
- const tar_c = tar_row.children.find((tc) => tc.id === c.id)
- c.check = tar_c.check
- c.mesh = tar_c.mesh
- })
- })
- }
- onBeforeUnmount(() => {
- handleStoreChecked()
- layoutStore.toggleFloatPanel('layers_legend', false)
- layoutStore.toggleFloatPanel('air_space', false)
- toggleFeaturesClickEvent(false)
- })
- const vCollapse = {
- beforeMount(el, binding) {
- el.style.height = '0'
- el.style.overflow = binding.value === 'scroll' ? 'auto' : 'hidden'
- el.style.transition = 'height 0.5s ease'
- },
- mounted(el) {
- const naturalHeight = el.scrollHeight
- el.style.height = `${naturalHeight}px`
- },
- beforeUnmount(el) {
- el.style.height = '0'
- },
- }
- watch(
- () => mapStore.cubeResult,
- (val) => {
- if (val.data == 'error') {
- ElMessage({ type: 'error', message: '核查结果为空' })
- }
- layoutStore.toggleGlobalLoading(false)
- },
- { deep: true }
- )
- watch(
- () => mapStore.clickResult,
- (val) => {
- const isShow = val && val.id && val.name && val.height
- layoutStore.toggleFloatPanel('air_space', isShow)
- },
- { deep: true }
- )
- </script>
- <style lang="scss" scoped>
- .list-base {
- li {
- span {
- width: 75px;
- }
- img {
- width: 75px;
- height: 77px;
- }
- }
- }
- .drop-down {
- display: block;
- width: 20px;
- height: 20px;
- margin-left: 10px;
- background: url('../../../assets/images/buttons/btn-dropdown.png') no-repeat;
- background-size: 10px 7px;
- background-position: center;
- transition: transform 0.3s ease;
- cursor: pointer;
- &.reverse {
- transform: rotateZ(180deg);
- }
- }
- .title-shade {
- position: relative;
- height: 32px;
- background: linear-gradient(to right, rgba(101, 131, 190, 1) 0%, rgba(101, 131, 190, 0) 100%);
- display: flex;
- align-items: center;
- padding: 0 16px;
- margin-bottom: 10px;
- &::before {
- content: '';
- position: absolute;
- left: 0;
- top: 0;
- width: 4px;
- height: 32px;
- background: #c0d5ff;
- }
- span {
- text-shadow: 0px 4px 4px rgba(21, 41, 91, 0.45);
- margin-right: 10px;
- }
- .btn-selectall {
- display: block;
- width: 26px;
- height: 26px;
- background: url('../../../assets/images/buttons/btn-selectall.png');
- background-size: 100%;
- background-position: center 1px;
- cursor: pointer;
- filter: opacity(0.6);
- &.active {
- filter: opacity(1) drop-shadow(0 0 5px #379bff);
- transform: scale(1.1);
- }
- }
- .drop-down {
- margin-left: auto;
- }
- }
- .list-item {
- position: relative;
- height: 40px;
- padding: 0 15px;
- margin: 9px 0;
- display: flex;
- align-items: center;
- background: #4352704d;
- &.disabled {
- pointer-events: none;
- opacity: 0.5;
- }
- &::before {
- content: '';
- position: absolute;
- left: 0;
- top: 0;
- width: 1px;
- height: 40px;
- background: #808dc9;
- }
- &:last-child {
- margin-bottom: 15px;
- }
- img {
- width: 24px;
- height: 24px;
- margin-right: 10px;
- }
- span {
- flex: 1;
- }
- i {
- display: block;
- width: 34px;
- height: 34px;
- margin-left: 5px;
- cursor: pointer;
- filter: grayscale(1);
- &.active {
- filter: grayscale(0);
- }
- }
- i:nth-child(3) {
- background: url('../../../assets/images/buttons/btn-check.png');
- background-size: cover;
- }
- i:nth-child(4) {
- background: url('../../../assets/images/buttons/btn-mesh.png');
- background-size: cover;
- }
- i:nth-child(5) {
- background: url('../../../assets/images/buttons/btn-delete.png');
- background-size: 40px 40px;
- background-position: center;
- }
- }
- .no-data {
- display: block;
- width: 100%;
- text-align: center;
- margin: 5px 0 10px;
- color: #999;
- }
- .feature-legend {
- position: absolute;
- bottom: var(--panel-gap);
- left: calc(var(--panel-left) - var(--panel-gap));
- width: 140px;
- padding: 10px 15px 15px;
- background-color: rgba(0, 17, 50, 0.5);
- border: 1px solid #055f8d;
- border-radius: 5px;
- .title-sub {
- margin-left: -7px;
- }
- ul {
- margin-top: 5px;
- li,
- div {
- display: flex;
- align-items: center;
- i {
- display: block;
- width: 10px;
- height: 10px;
- margin-right: 10px;
- opacity: 0.6;
- }
- span {
- font-size: 14px;
- color: #ccc;
- }
- }
- li {
- &:not(:last-child) {
- margin: 5px 0;
- }
- span.bold {
- font-size: 15px;
- }
- }
- div {
- padding-left: 15px;
- }
- }
- }
- </style>
|