| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- <template>
- <div ref="mapContainer" class="map-container"></div>
- <div v-if="!isTopLevel" class="map-reset-btn">
- <Button type="primary" @click="reset">重置</Button>
- </div>
- </template>
- <script lang="ts" setup>
- import { ref, onMounted, onUnmounted, computed } from 'vue';
- import L from 'leaflet';
- import 'leaflet/dist/leaflet.css';
- import { Button } from 'ant-design-vue';
- import { getMarkers } from '/@/api/sys/map';
- import { DEFAULT_LAYER_ID, regionColorMap, tileLayerConfigs, generatePopupContent, getRootMarkerIcon, GEOJSON_LAYER_ID } from './simpleMap.data';
- import { useAppStore } from '/@/store/modules/app';
- import { isEmpty } from '/@/utils/is';
- import { useRoute } from 'vue-router';
- import { PageEnum } from '/@/enums/pageEnum';
- const appStore = useAppStore();
- const route = useRoute();
- const mapContainer = ref(null);
- const isTopLevel = computed(() => {
- return isEmpty(appStore.getSimpleMapParams);
- });
- let map: L.Map | null = null;
- // 图层组 Map(基于所有区域编码初始化)
- const layerMap = new Map<string, L.LayerGroup>([
- [DEFAULT_LAYER_ID, L.featureGroup()],
- [GEOJSON_LAYER_ID, L.featureGroup()],
- // // 西安
- // ['1566101', L.featureGroup()],
- // // 铜川
- // ['1566102', L.featureGroup()],
- // // 宝鸡
- // ['1566103', L.featureGroup()],
- // // 咸阳
- // ['1566104', L.featureGroup()],
- // // 渭南
- // ['1566105', L.featureGroup()],
- // // 延安
- // ['1566106', L.featureGroup()],
- // // 汉中
- // ['1566107', L.featureGroup()],
- // // 榆林
- // ['1566108', L.featureGroup()],
- // // 安康
- // ['1566109', L.featureGroup()],
- // // 商洛
- // ['1566111', L.featureGroup()],
- ]);
- onMounted(async () => {
- if (!mapContainer.value) return;
- reset();
- map = L.map(mapContainer.value, {
- center: [35.841, 108.94],
- zoom: 7,
- zoomControl: false,
- attributionControl: false,
- });
- initTileLayers();
- if (route.path === PageEnum.BASE_HOME) {
- await initMarkers();
- await initGeoJSON();
- }
- layerMap.get(DEFAULT_LAYER_ID)?.addTo(map);
- });
- onUnmounted(() => {
- map?.remove();
- });
- /** 初始化瓦片图层 */
- function initTileLayers() {
- tileLayerConfigs.forEach((config) => {
- const layer = L.tileLayer(config.url, config.options);
- if (config.addByDefault) {
- layer.addTo(map!);
- }
- });
- }
- /** 加载 GeoJSON 并添加到对应图层组 */
- async function initGeoJSON() {
- const response = await fetch('/js/shanxi.geo.json');
- const ShanXiGeoJSON = await response.json();
- const geoJsonLayer = L.geoJSON(ShanXiGeoJSON, {
- style(feature) {
- const gb = feature.properties.gb.slice(0, -2);
- return {
- fillColor: regionColorMap[gb] || '#14baff',
- fillOpacity: 0.2,
- weight: 2,
- opacity: 1,
- color: '#ff9100',
- };
- },
- onEachFeature(_, layer) {
- layer.on({
- mouseover: (e) => {
- e.target.setStyle({ weight: 2, fillOpacity: 0.6 });
- e.target.bringToFront();
- },
- mouseout: (e) => {
- geoJsonLayer.resetStyle(e.target);
- },
- });
- },
- });
- map.addLayer(geoJsonLayer);
- // geoJsonLayer.addTo(layerMap.get(GEOJSON_LAYER_ID));
- // layerMap.forEach((group, code) => {
- // const features = ShanXiGeoJSON.features.filter((feature: any) => {
- // if (code === DEFAULT_LAYER_ID) return true;
- // return feature.properties.gb.startsWith(code);
- // });
- // });
- }
- /** 初始化所有标记点 */
- async function initMarkers() {
- const records = await getMarkers({ pageNo: 0, pageSize: 9999 });
- records.forEach((item, index) => {
- if (!layerMap.has(item.id)) {
- layerMap.set(item.id, L.featureGroup());
- }
- // 创建根标记点
- const iconConfig = getRootMarkerIcon(40, item.children.length, Object.values(regionColorMap)[index]);
- const marker = L.marker([item.lat, item.lng], {
- icon: L.divIcon(iconConfig),
- riseOnHover: true,
- }).on('click', () => {
- layerMap.forEach((group, code) => {
- map?.removeLayer(group);
- if (code === item.id) {
- // map?.addLayer(group);
- // map?.flyToBounds(group.getBounds());
- map?.flyToBounds(layerMap.get(item.id).getBounds());
- }
- });
- appStore.setSimpleMapParams({ mineCode: item.mineCode });
- });
- marker.addTo(layerMap.get(DEFAULT_LAYER_ID)!);
- // 创建子标记点
- if (!item.children.length) return;
- item.children.forEach((child: any) => {
- const popupContent = generatePopupContent(child);
- const childMarker = L.marker([child.lat, child.lng]).bindPopup(popupContent);
- if (layerMap.has(child.rootId)) {
- childMarker.addTo(layerMap.get(child.rootId)!);
- }
- });
- });
- }
- /** 重置视图到默认图层 */
- function reset() {
- layerMap.forEach((group, code) => {
- map?.removeLayer(group);
- if (code === DEFAULT_LAYER_ID) {
- map?.addLayer(group);
- map?.flyToBounds(group.getBounds());
- }
- });
- appStore.setSimpleMapParams({});
- }
- </script>
- <style lang="less">
- .map-container {
- flex: 1;
- height: 100%;
- width: 100%;
- position: fixed;
- top: 0;
- left: 0;
- z-index: @simple-map-z-index;
- // filter: grayscale(80%) invert(0%) sepia(10%) hue-rotate(150deg) saturate(200%) brightness(100%) contrast(100%);
- }
- .light-blue-theme {
- filter: invert(0.1) hue-rotate(190deg) saturate(2);
- // filter: sepia(0.3) hue-rotate(180deg) saturate(1.8);
- }
- .leaflet-popup {
- color: @white;
- &-content-wrapper {
- background-color: @map-popup-bg;
- }
- &-tip {
- background-color: @map-popup-bg;
- }
- .leaflet-popup-content {
- margin: 13px 20px;
- min-width: 280px;
- // &__popup {
- // }
- &__divider {
- height: 1px;
- background-color: @white;
- margin: 10px 5px;
- }
- &__title {
- color: @white;
- text-align: center;
- }
- &__board {
- padding: 10px;
- border-radius: 5px;
- background-color: @map-popup-board-bg;
- display: flex;
- justify-content: space-between;
- }
- &__table {
- color: @white;
- text-align: center;
- thead {
- height: 20px;
- }
- tbody {
- tr {
- background-color: @map-popup-table-th-bg;
- }
- tr:nth-child(even) {
- background-color: @map-popup-table-theven-bg;
- }
- td {
- padding: 5px;
- }
- }
- }
- }
- }
- .map-reset-btn {
- position: absolute;
- right: 30%; /* 距离右边 20px */
- z-index: 2; /* 确保在地图控件之上 */
- top: @header-height;
- // padding: 10px 15px;
- margin: 10px 0;
- }
- </style>
|