WholeProcessPlatform/frontend/src/components/gis/GisView.vue

479 lines
13 KiB
Vue
Raw Normal View History

2026-03-27 15:52:43 +08:00
<template>
<!-- 1. 切换菜单的时候图层没有切换 是因为接口的原因现在没有接口
2. 切换菜单的时候图例现在是不对的默认选中的数据他们没有做处理
1. 图层切换显示
2. 鼠标悬停点击完成
3. 文字重叠
4. 搜索
5. 公共弹框基础信息是eng的时候才显示电站专题
-->
2026-03-31 14:17:30 +08:00
<div class="gis-view">
<div id="mapContainer" />
<div ref="popupRef" class="map-popup-container" style="display: none"></div>
2026-03-31 14:17:30 +08:00
<!-- 地图图例 -->
<MapLegend
:setLegendDataMap="updateLegendDataMap"
:legendData="mapStore.legendData"
:legendDataMap="mapStore.legendDataMap"
:pointData="mapStore.pointData"
/>
2026-03-31 14:17:30 +08:00
<!-- 地图筛选器 -->
<MapFilter v-if="showMapFilter" :map="mapClass" />
2026-03-31 14:17:30 +08:00
<!-- 地图控制器 -->
2026-04-22 17:53:20 +08:00
<MapController :map="mapClass" :onClick="handleMapController" />
2026-03-31 14:17:30 +08:00
<!-- 基础图层切换器 -->
2026-04-22 17:53:20 +08:00
<BaseLayerSwitcher :map="mapClass" />
2026-03-31 14:17:30 +08:00
</div>
2026-03-27 15:52:43 +08:00
</template>
2026-03-31 14:17:30 +08:00
<script setup lang="ts">
import _ from 'lodash';
import { ref, onMounted, watch, onUnmounted, computed } from 'vue';
import MapLegend from '@/components/mapLegend/index.vue';
import MapFilter from '@/components/mapFilter/index.vue';
import MapController from '@/components/mapController/index.vue';
import BaseLayerSwitcher from '@/components/BaseLayerSwitcher/index.vue';
import { useRoute } from 'vue-router';
import { useMapStore } from '@/store/modules/map';
import { MapClass } from './map.class';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { getMapList, getModuleMapLegendList } from '@/api/map';
// Store 实例
const mapStore = useMapStore();
const JidiSelectEventStore = useJidiSelectEventStore();
// 路由
2026-04-22 17:53:20 +08:00
const route = useRoute();
// 地图实例
2026-04-22 17:53:20 +08:00
const mapClass = MapClass.getInstance();
// 响应式状态
const mapIsInited = ref(false);
2026-04-22 17:53:20 +08:00
const tlyLayerVisible = ref(false);
const popupRef = ref<HTMLDivElement>(null);
const loading = ref(false);
// 从路由获取 pageKey
const pageKey = computed(() => {
const path = route.path;
const parts = path.split('/');
if (parts.length >= 3) {
return parts[1] + '_' + parts[2];
2026-04-22 17:53:20 +08:00
}
return '';
});
2026-04-22 17:53:20 +08:00
// 判断是否显示 MapFilter 组件
const showMapFilter = computed(() => {
const path = route.path;
// 当路径为 dianZhanZhuanTi/dianZhanZhuanTi 时隐藏
if (path.includes('dianZhanZhuanTi/dianZhanZhuanTi')) {
return false;
2026-04-22 17:53:20 +08:00
}
return true;
});
// 判断当前菜单是否为水电开发状况
const isShuiDianKaiFaMenu = computed(() => {
const path = route.path;
return path.includes('home/shuiDianKaiFaZhuangKuang');
});
// 地图缩放级别状态
const currentZoomLevel = ref(4.5);
// 动态添加的图层 keys
const dynamicLayerKeys = [
'dw_point',
'stinfo_video_point',
'stinfo_gjllz_point'
];
// 监听地图缩放级别变化
let zoomListenerKey: any = null;
const setupZoomListener = () => {
if (mapClass.view) {
console.log('设置缩放监听器mapClass.view:', mapClass.view);
// OpenLayers 使用 map 的 change:resolution 事件
const view = mapClass.view.getView
? mapClass.view.getView()
: mapClass.view;
console.log('view 对象:', view);
if (view && view.on) {
zoomListenerKey = view.on('change:resolution', () => {
const zoom = view.getZoom ? view.getZoom() : mapClass.view.getZoom();
console.log('缩放事件触发,当前缩放级别:', zoom);
2026-04-22 17:53:20 +08:00
if (zoom !== undefined) {
const oldZoomLevel = Math.floor(currentZoomLevel.value);
const newZoomLevel = Math.floor(zoom);
currentZoomLevel.value = zoom;
// 只在水电开发状况菜单下触发
if (isShuiDianKaiFaMenu.value) {
console.log('当前是水电开发菜单,检查层级变化');
// 从小于12缩放到12或以上时添加动态图层
if (oldZoomLevel < 12 && newZoomLevel >= 12) {
console.log('层级从小于12变为>=12添加动态图层');
addDynamicLayers();
}
// 从12或以上缩放到小于12时移除动态图层
else if (oldZoomLevel >= 12 && newZoomLevel < 12) {
console.log('层级从>=12变为小于12移除动态图层');
removeDynamicLayers();
}
}
}
});
console.log('缩放监听器设置完成key:', zoomListenerKey);
} else {
console.error('view 对象没有 on 方法');
}
} else {
console.error('mapClass.view 未初始化');
}
2026-04-22 17:53:20 +08:00
};
// 添加动态图层
const addDynamicLayers = async () => {
console.log('地图层级>=12添加动态图层:', dynamicLayerKeys);
2026-04-22 17:53:20 +08:00
// 获取当前选中的图层 keys
const currentCheckedKeys = mapStore.getCheckedKeys();
2026-04-22 17:53:20 +08:00
// 检查哪些动态图层还未被勾选
const layersToAdd = dynamicLayerKeys.filter(
key => !currentCheckedKeys.includes(key)
);
2026-04-22 17:53:20 +08:00
if (layersToAdd.length === 0) {
console.log('动态图层已全部添加,跳过');
return;
}
2026-04-22 17:53:20 +08:00
// 查找对应的图层配置
const layersToLoad = layersToAdd
.map(key => mapStore.findLayerByKey(mapStore.layerData, key))
.filter(Boolean);
2026-04-22 17:53:20 +08:00
// 加载图层数据
for (const layer of layersToLoad) {
if (layer && layer.url) {
await mapStore.loadLayerData(layer);
}
}
2026-04-22 17:53:20 +08:00
// 更新选中的图层 keys
const newCheckedKeys = [...currentCheckedKeys, ...layersToAdd];
await mapStore.updateLayerData(newCheckedKeys, true);
2026-04-22 17:53:20 +08:00
console.log('动态图层添加完成');
};
2026-04-22 17:53:20 +08:00
// 移除动态图层
const removeDynamicLayers = async () => {
console.log('地图层级<12移除动态图层:', dynamicLayerKeys);
// 获取当前选中的图层 keys
const currentCheckedKeys = mapStore.getCheckedKeys();
// 移除动态图层 keys
const newCheckedKeys = currentCheckedKeys.filter(
key => !dynamicLayerKeys.includes(key)
);
// 如果没有变化,跳过
if (newCheckedKeys.length === currentCheckedKeys.length) {
console.log('动态图层已移除,跳过');
return;
}
await mapStore.updateLayerData(newCheckedKeys, true);
console.log('动态图层移除完成');
};
// 获取 moduleId从路由或 sessionStorage
const getModuleId = () => {
const menuList: any = JSON.parse(sessionStorage.getItem('menuList') || '[]');
const pathParts = route.path.split('/');
if (pathParts.length >= 3) {
const page = pathParts[2];
const menuItem = menuList.find((item: any) => item.actionCode === page);
return menuItem?.id || '';
}
return '';
};
/** 更新图例关系数据,同时更新缓存 */
const updateLegendDataMap = (data: any) => {
mapStore.legendDataMap = data;
};
// 地图初始化
2026-04-22 17:53:20 +08:00
const init = async () => {
const container = document.getElementById('mapContainer') as HTMLElement;
if (!container) return;
mapClass.init(container).then(() => {
if (popupRef.value) {
mapClass?.initPopupOverlay(popupRef.value);
}
2026-04-22 17:53:20 +08:00
mapIsInited.value = true;
// 地图初始化完成后设置缩放监听
setupZoomListener();
console.log('缩放监听器已设置');
// 初始化图层数据和图例数据
fetchMapConfigs();
2026-04-22 17:53:20 +08:00
});
};
/** 请求地图配置数据:图层、图例 */
const fetchMapConfigs = _.debounce(async () => {
loading.value = true;
mapStore.loading = true;
try {
// 并行获取图层配置和图例数据,减少等待时间
const [layerRes, legendAllRes, legendSelectedRes] = await Promise.all([
getMapList({
systemId: '974975A6-47FD-4C04-9ACD-68938D2992BD',
moduleId: '2157c1a1-e909-4c9f-af94-b4ccebe05808',
description: 'true'
}),
getModuleMapLegendList(),
getModuleMapLegendList({ moduleId: pageKey.value })
]);
// 设置图例数据(优先显示)- 这会初始化 legendDataMap
if (legendAllRes.data) {
mapStore.setLegendData(legendAllRes.data, legendSelectedRes.data || []);
}
// 处理图层数据
if (layerRes.data && layerRes.data.mapLayerVos) {
// TODO: 临时只取前三个图层进行测试,测试完成后删除以下两行
const limitedLayers = layerRes.data.mapLayerVos;
console.log('临时限制只处理前3个图层');
// 1. 先设置图层数据(会提取初始选中的图层 keys
mapStore.setLayerData(limitedLayers);
// 2. 收集所有选中的图层 keys包括子级
const checkedKeys = collectCheckedKeys(limitedLayers);
console.log('初始选中的图层 keys:', checkedKeys);
// 3. 加载所有锚点数据(并行加载,缓存数据)- 传入 checkedKeys 优先加载选中的图层
// loadAllLayerData 内部会调用 updateLayerData 显示选中图层的锚点
await mapStore.loadAllLayerData(limitedLayers, checkedKeys);
}
// 所有图层加载完成后才关闭 loading
mapStore.loading = false;
} catch (error) {
console.error('获取地图配置失败:', error);
} finally {
loading.value = false;
}
}, 400);
/**
* 递归收集所有选中的图层 keys包括子级
*/
const collectCheckedKeys = (layers: any[]): string[] => {
const keys: string[] = [];
const collect = (items: any[]) => {
items.forEach(item => {
if (item.checked === 1 && item.key) {
keys.push(item.key);
}
if (item.children && item.children.length > 0) {
collect(item.children);
}
});
};
collect(layers);
return keys;
};
// 右侧 menu 点击处理
const handleMapController = async (e: any, mapType: any) => {
2026-04-22 17:53:20 +08:00
switch (e) {
case 'dim':
await mapClass.switchView(mapType);
fetchPointData();
break;
2026-04-22 17:53:20 +08:00
case 4: // 梯级流域显示
tlyLayerVisible.value = !tlyLayerVisible.value;
if (tlyLayerVisible.value) {
// 添加梯级流域图层
2026-04-22 17:53:20 +08:00
} else {
// 移除梯级流域图层
2026-04-22 17:53:20 +08:00
}
break;
2026-04-22 17:53:20 +08:00
default:
break;
}
};
// 监听地图初始化完成
2026-04-22 17:53:20 +08:00
watch(
() => mapIsInited.value,
newVal => {
if (newVal === true) {
console.log('地图初始化完成');
}
}
);
// 监听 pageKey 变化,重新获取地图配置
watch(
() => pageKey.value,
newVal => {
console.log('pageKey:', newVal);
console.log('当前菜单是否为水电开发:', isShuiDianKaiFaMenu.value);
if (newVal && mapIsInited.value) {
// 切换菜单时,如果新菜单不是水电开发状况,移除动态图层
if (!isShuiDianKaiFaMenu.value) {
removeDynamicLayers();
}
// 先获取地图配置
2026-04-22 17:53:20 +08:00
fetchMapConfigs();
// 配置加载完成后,如果新菜单是水电开发状况且层级>=12添加动态图层
if (isShuiDianKaiFaMenu.value) {
// 正确获取 view 对象
const view = mapClass.view?.getView
? mapClass.view.getView()
: mapClass.view;
const currentZoom = view?.getZoom?.();
console.log('当前地图层级:', currentZoom);
console.log('view 对象:', view);
if (currentZoom !== undefined && currentZoom >= 12) {
console.log('切换到水电开发菜单,当前层级已>=12添加动态图层');
// 延迟足够时间确保图层配置已完全加载
setTimeout(() => {
console.log('延迟后调用 addDynamicLayers');
addDynamicLayers();
}, 1000);
}
}
2026-04-22 17:53:20 +08:00
}
}
);
// 监听水电基地点击
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal) {
if (newVal.wbsCode == 'all') {
mapClass.jdPanelControlShowAndHidden(newVal.wbsCode, false);
} else {
mapClass.jdPanelControlShowAndHidden(newVal.wbsCode, true);
}
}
},
{ deep: true }
);
2026-04-03 16:04:16 +08:00
// 监听图例数据变化,更新描点显示
watch(
() => mapStore.legendDataSelected,
newVal => {
if (newVal && newVal.length > 0) {
newVal.forEach((legend: any) => {
if (legend.checked === 1) {
// mapClass.mdLayerTreeShowOrHidden(legend.layerCode, true);
} else {
// mapClass.mdLayerTreeShowOrHidden(legend.layerCode, false);
}
});
}
},
{ deep: true }
);
2026-04-03 16:04:16 +08:00
onMounted(() => {
2026-04-22 17:53:20 +08:00
init();
// @ts-ignore
2026-04-22 17:53:20 +08:00
window.mapClass = mapClass;
});
2026-04-22 17:53:20 +08:00
onUnmounted(() => {
// 移除缩放监听
if (zoomListenerKey && mapClass.view) {
const view = mapClass.view.getView
? mapClass.view.getView()
: mapClass.view;
if (view && view.unByKey) {
view.unByKey(zoomListenerKey);
console.log('缩放监听器已移除');
}
}
2026-04-22 17:53:20 +08:00
mapClass.destroy();
});
2026-03-31 14:17:30 +08:00
</script>
2026-03-27 15:52:43 +08:00
<style lang="scss" scoped>
.gis-view {
2026-03-31 14:17:30 +08:00
width: 100%;
height: 100%;
position: absolute;
visibility: visible;
2026-03-27 15:52:43 +08:00
}
#mapContainer {
2026-03-31 14:17:30 +08:00
width: 100%;
height: 100%;
2026-04-03 16:04:16 +08:00
position: absolute;
background-color: #fff;
cursor: grab;
2026-04-22 17:53:20 +08:00
z-index: 1;
}
/* 消除瓦片之间的缝隙和默认边框 */
.leaflet-tile {
border: none !important;
margin: 0 !important;
padding: 0 !important;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
/* 确保地图容器背景色与瓦片一致,避免透出底色 */
.leaflet-container {
background-color: #fff;
2026-04-22 17:53:20 +08:00
}
/* 如果使用 Canvas 模式,确保 Canvas 没有边框 */
.leaflet-pane canvas {
border: none;
2026-03-27 15:52:43 +08:00
}
.map-popup-container {
z-index: 1000;
pointer-events: auto;
}
.custom-popup {
padding: 10px;
}
.custom-popup h4 {
margin: 0 0 5px 0;
color: #333;
}
.custom-popup p {
margin: 2px 0;
font-size: 12px;
color: #666;
}
2026-03-27 15:52:43 +08:00
</style>