263 lines
6.7 KiB
Vue
263 lines
6.7 KiB
Vue
<template>
|
||
<div class="mapLegendView">
|
||
<div class="legendTitle">
|
||
图例
|
||
<span class="legendBtn" @click="isOpen = !isOpen">
|
||
<i
|
||
class="icon iconfont"
|
||
:class="isOpen ? 'icon-fold' : 'icon-unFold'"
|
||
></i>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="legendContent" v-show="isOpen">
|
||
<a-spin :spinning="loadLegendData" tip="加载中...">
|
||
<div class="legendContainer">
|
||
<div
|
||
class="legendGroup"
|
||
v-for="i in legendData"
|
||
:key="i.name"
|
||
:class="{ envFac: i.name == '环保设施' }"
|
||
>
|
||
<div
|
||
class="groupTitle"
|
||
v-if="i.name != '环保设施'"
|
||
:class="{ gray: isGroupAllUnchecked(i) }"
|
||
@click="toggleGroup(i)"
|
||
>
|
||
{{ i.name }}
|
||
</div>
|
||
<div
|
||
class="groupContent"
|
||
:class="{ envFacBottom: hasEnvFac && i.name != '环保设施' }"
|
||
>
|
||
<template v-for="j in i.childrenList" :key="j.name">
|
||
<LegendItem
|
||
v-if="j.layerCode"
|
||
:item="j"
|
||
@click="legendItemClick(j)"
|
||
/>
|
||
<div
|
||
v-else-if="j.childrenList && j.childrenList.length > 0"
|
||
class="legendGroup"
|
||
>
|
||
<div
|
||
class="groupTitle"
|
||
:class="{ gray: isGroupAllUnchecked(j) }"
|
||
@click="toggleGroup(j)"
|
||
>
|
||
{{ j.name }}
|
||
</div>
|
||
<div class="groupContent">
|
||
<LegendItem
|
||
v-for="item in j.childrenList"
|
||
:key="item.layerCode"
|
||
:item="item"
|
||
@click="legendItemClick(item)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</a-spin>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { ref, computed } from 'vue';
|
||
import { useMapOrchestrator } from '@/modules/map/application/map-orchestrator';
|
||
import { useMapConfigStore } from '@/modules/map/stores/map-config.store';
|
||
import { useMapStore } from '@/store/modules/map';
|
||
import LegendItem from '@/components/mapLegend/LegendItem.vue';
|
||
|
||
const mapStore = useMapStore();
|
||
const mapConfigStore = useMapConfigStore();
|
||
const mapOrchestrator = useMapOrchestrator();
|
||
const isOpen = ref(true);
|
||
|
||
// 备注:图例组件直接渲染当前已派生好的图例运行态,不再维护本地同步副本。
|
||
const legendData = computed(() => mapStore.legendDataSelected || []);
|
||
// 备注:图例转圈只跟图例配置接口绑定,不再等待全部锚点接口加载完成。
|
||
const loadLegendData = computed(() => mapConfigStore.legendLoading);
|
||
// 备注:环保设施分组展示状态直接从当前图例数据派生,保持组件只负责渲染。
|
||
const hasEnvFac = computed(() =>
|
||
legendData.value.some((item: any) => item.name === '环保设施')
|
||
);
|
||
|
||
const legendItemClick = (item: any) => {
|
||
if (item.parentName == '环保设施') return;
|
||
if (item.canBeChecked == 0) {
|
||
return;
|
||
}
|
||
if (item.nameEn) {
|
||
mapOrchestrator.toggleLegend(item.nameEn, item.checked == 0 ? 1 : 0);
|
||
}
|
||
};
|
||
|
||
const getAllLeafItems = (group: any): any[] => {
|
||
const items: any[] = [];
|
||
if (!group.childrenList) return items;
|
||
|
||
group.childrenList.forEach((child: any) => {
|
||
if (child.layerCode) {
|
||
items.push(child);
|
||
} else if (child.childrenList && child.childrenList.length > 0) {
|
||
items.push(...getAllLeafItems(child));
|
||
}
|
||
});
|
||
return items;
|
||
};
|
||
|
||
const isGroupAllUnchecked = (group: any): boolean => {
|
||
const leafItems = getAllLeafItems(group);
|
||
if (leafItems.length === 0) return false;
|
||
return leafItems.every((item: any) => item.checked === 0);
|
||
};
|
||
|
||
const toggleGroup = (group: any) => {
|
||
const leafItems = getAllLeafItems(group);
|
||
if (leafItems.length === 0) return;
|
||
|
||
const hasAnyChecked = leafItems.some((item: any) => item.checked === 1);
|
||
|
||
const targetChecked = hasAnyChecked ? 0 : 1;
|
||
const targetNameEns = leafItems
|
||
.filter(
|
||
(item: any) => item.parentName !== '环保设施' && item.canBeChecked !== 0
|
||
)
|
||
.filter((item: any) => item.checked !== targetChecked)
|
||
.map((item: any) => item.nameEn)
|
||
.filter(Boolean);
|
||
|
||
mapOrchestrator.toggleLegendBatch(targetNameEns, targetChecked);
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.mapLegendView {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
min-width: 72px;
|
||
margin: 24px 0 16px 16px;
|
||
border: 1px solid #ccdae7;
|
||
padding: 6px;
|
||
z-index: 9;
|
||
background-color: #ffffff;
|
||
}
|
||
.legendTitle {
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
cursor: pointer;
|
||
.legendBtn {
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
.envFac {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
background-color: #ffffff;
|
||
border-top: 1px solid #eeeeee;
|
||
.groupContent {
|
||
padding: 0 !important;
|
||
:deep(.legendItem) {
|
||
cursor: none;
|
||
.legendIconTitle {
|
||
span {
|
||
white-space: nowrap !important;
|
||
}
|
||
}
|
||
&:hover {
|
||
.legendIconTitle {
|
||
cursor: auto;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.envFacBottom {
|
||
padding-bottom: 80px !important;
|
||
}
|
||
.legendContent {
|
||
white-space: nowrap;
|
||
max-width: 450px;
|
||
max-height: 450px;
|
||
overflow-x: scroll;
|
||
overflow-y: scroll;
|
||
border-top: 1px solid #eeeeee;
|
||
:deep(.ant-spin-nested-loading) {
|
||
min-height: 50px;
|
||
}
|
||
&::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
.legendContainer {
|
||
position: relative;
|
||
min-height: 20px;
|
||
min-width: 30px;
|
||
overflow: auto;
|
||
padding-bottom: 8px;
|
||
}
|
||
.legendGroup {
|
||
display: inline-block;
|
||
vertical-align: top;
|
||
padding: 0 4px;
|
||
.groupTitle {
|
||
text-align: left;
|
||
font-weight: 700;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
.groupContent {
|
||
font-size: 14px;
|
||
padding: 10px 0;
|
||
margin-bottom: 0;
|
||
.gray {
|
||
filter: grayscale(100%);
|
||
color: #00000073;
|
||
}
|
||
.disabled {
|
||
cursor: not-allowed !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.legendItem {
|
||
cursor: pointer;
|
||
margin-right: 10px;
|
||
padding: 4px 0;
|
||
min-height: 30px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
.legendIcon {
|
||
width: 25px !important;
|
||
height: 25px !important;
|
||
text-align: center;
|
||
img {
|
||
max-width: 80%;
|
||
max-height: 80%;
|
||
vertical-align: middle;
|
||
display: inline-block;
|
||
}
|
||
}
|
||
.smallIcon {
|
||
width: 22px !important;
|
||
height: 22px !important;
|
||
text-align: center;
|
||
}
|
||
.legendIconTitle {
|
||
cursor: pointer;
|
||
flex: 1 1;
|
||
}
|
||
&:hover {
|
||
color: #2f6b98;
|
||
}
|
||
}
|
||
</style>
|