|
|
@@ -0,0 +1,190 @@
|
|
|
+<template>
|
|
|
+ <el-card class="map-card">
|
|
|
+ <div class="title">
|
|
|
+ <div class="section-icon">🗺️</div>
|
|
|
+ <p class="map-title">南雄市细粒度地块级酸化预测</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div id="map-container" class="map-container">
|
|
|
+ <div v-if="mapLoading" class="loading">
|
|
|
+ <div class="loading-spinner"></div>
|
|
|
+ <span>地图加载中...</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="mapError" class="error-tip">
|
|
|
+ <el-alert title="地图加载失败" type="error" show-icon>
|
|
|
+ <template #description>
|
|
|
+ <p>请检查GeoServer服务和配置</p>
|
|
|
+ <el-button @click="reloadMap" type="primary">重试加载</el-button>
|
|
|
+ </template>
|
|
|
+ </el-alert>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, nextTick, onMounted, onUnmounted } from "vue";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+//import { api8000 } from "@/utils/request";
|
|
|
+//import { api5000 } from "../../../utils/request";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// 地图状态
|
|
|
+const mapLoading = ref(true);
|
|
|
+const mapError = ref(false);
|
|
|
+const map = ref<any>(null);
|
|
|
+
|
|
|
+
|
|
|
+let L: any = null;
|
|
|
+
|
|
|
+
|
|
|
+const initMap = async () => {
|
|
|
+ mapLoading.value = true;
|
|
|
+ mapError.value = false;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 动态导入Leaflet
|
|
|
+ if (!L) {
|
|
|
+ L = await import('leaflet');
|
|
|
+ await import('leaflet/dist/leaflet.css');
|
|
|
+
|
|
|
+ delete (L.Icon.Default.prototype as any)._getIconUrl;
|
|
|
+ L.Icon.Default.mergeOptions({
|
|
|
+ iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png',
|
|
|
+ iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
|
|
|
+ shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除现有地图
|
|
|
+ if (map.value) {
|
|
|
+ map.value.remove();
|
|
|
+ map.value = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建地图实例
|
|
|
+ map.value = L.map('map-container', {
|
|
|
+ zoomControl: true,
|
|
|
+ attributionControl: false,
|
|
|
+ center: [25.24280, 114.39770],
|
|
|
+ zoom: 15
|
|
|
+ });
|
|
|
+
|
|
|
+ // WMS配置
|
|
|
+ const GEOSERVER_CONFIG = {
|
|
|
+ url: "/geoserver/wms",
|
|
|
+ workspace: "acidmap",
|
|
|
+ layerGroup: "xiafencun",
|
|
|
+ };
|
|
|
+
|
|
|
+ // WMS图层配置
|
|
|
+ const wmsLayer = L.tileLayer.wms(GEOSERVER_CONFIG.url, {
|
|
|
+ layers: `${GEOSERVER_CONFIG.workspace}:${GEOSERVER_CONFIG.layerGroup}`,
|
|
|
+ format: "image/png",
|
|
|
+ transparent: true,
|
|
|
+ version: "1.1.1",
|
|
|
+ crs: L.CRS.EPSG4326,
|
|
|
+ attribution: "Data from GeoServer"
|
|
|
+ });
|
|
|
+
|
|
|
+ // 添加图层到地图
|
|
|
+ wmsLayer.addTo(map.value);
|
|
|
+ mapLoading.value = false;
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('地图初始化失败:', error);
|
|
|
+ mapError.value = true;
|
|
|
+ mapLoading.value = false;
|
|
|
+
|
|
|
+ let errorMessage = '地图初始化失败';
|
|
|
+ if (error instanceof Error) {
|
|
|
+ errorMessage += ': ' + error.message;
|
|
|
+ }
|
|
|
+ ElMessage.error(errorMessage);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const reloadMap = () => {
|
|
|
+ initMap();
|
|
|
+};
|
|
|
+
|
|
|
+// 组件卸载时清理(新增:清除高亮图层)
|
|
|
+onUnmounted(() => {
|
|
|
+ if (map.value) {
|
|
|
+ map.value.remove();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ nextTick(() => {
|
|
|
+ initMap();
|
|
|
+ });
|
|
|
+
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+.map-card {
|
|
|
+ width: 850px;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 600px;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+
|
|
|
+.title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-icon {
|
|
|
+ font-size: 2.2rem;
|
|
|
+ color: #3a9fd3;
|
|
|
+}
|
|
|
+.map-title {
|
|
|
+ color: #1a365d;
|
|
|
+ font-size: 1.6rem;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+
|
|
|
+.map-container {
|
|
|
+ height: 550px;
|
|
|
+ width: 100%;
|
|
|
+ position: relative;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: hidden;
|
|
|
+ background: #f0f2f5;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+}
|
|
|
+
|
|
|
+.loading {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ text-align: center;
|
|
|
+ z-index: 1000;
|
|
|
+ background: rgba(255, 255, 255, 0.95);
|
|
|
+ padding: 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.loading span {
|
|
|
+ margin-left: 8px;
|
|
|
+ color: #606266;
|
|
|
+}
|
|
|
+
|
|
|
+.error-tip {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ width: 80%;
|
|
|
+ z-index: 1000;
|
|
|
+}
|
|
|
+</style>
|