|
|
@@ -0,0 +1,260 @@
|
|
|
+<template>
|
|
|
+ <div class="total-introduction">
|
|
|
+ <!-- 背景层 -->
|
|
|
+ <div class="background-layer"></div>
|
|
|
+
|
|
|
+ <!-- 顶部标题 -->
|
|
|
+ <!-- <div class="header-title">
|
|
|
+ <h1>数据看板</h1>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- 主要内容区域 -->
|
|
|
+ <div class="main-content">
|
|
|
+ <!-- 左侧区域 -->
|
|
|
+ <div class="left-section">
|
|
|
+ <CropcdStatictics/>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 中间区域 -->
|
|
|
+ <div class="center-section">
|
|
|
+ <!-- 地图区域 -->
|
|
|
+
|
|
|
+ <div id="map-container" class="map-containter" ref="mapContainer">
|
|
|
+ <div v-if="mapLoading" class="map-loading">
|
|
|
+ <div class="spinner"></div>
|
|
|
+ <p>地图加载中...</p>
|
|
|
+ </div>
|
|
|
+ <div v-if="mapError" class="map-error">
|
|
|
+ <p>地图加载失败,请刷新重试</p>
|
|
|
+ <button @click="reloadMap" class="reload-btn">重新加载</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <FluxcdStatictics/>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧区域 -->
|
|
|
+ <div class="right-section">
|
|
|
+ <EffcdStatistics/>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted, nextTick } from 'vue';
|
|
|
+import FluxcdStatictics from "@/components/soilcdStatistics/fluxcdStatictics.vue";
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+import { useI18n } from 'vue-i18n';
|
|
|
+import CropcdStatictics from '@/components/soilcdStatistics/cropcdStatictics.vue';
|
|
|
+
|
|
|
+const { t } = useI18n();
|
|
|
+
|
|
|
+// 地图相关
|
|
|
+let L = null;
|
|
|
+const map = ref(null);
|
|
|
+const mapContainer = ref(null);
|
|
|
+const mapLoading = ref(false);
|
|
|
+const mapError = ref(false);
|
|
|
+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)._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',
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除现有地图
|
|
|
+ const container = document.getElementById('map-container');
|
|
|
+
|
|
|
+ // 创建地图实例
|
|
|
+ map.value = L.map(container, {
|
|
|
+ zoomControl: true,
|
|
|
+ attributionControl: false,
|
|
|
+ center: [25.202903, 113.25383],
|
|
|
+ zoom: 10
|
|
|
+ });
|
|
|
+
|
|
|
+ // WMS 配置
|
|
|
+ const GEOSERVER_CONFIG = {
|
|
|
+ url: "/geoserver/wms",
|
|
|
+ workspace: "acidmap",
|
|
|
+ layerGroup: "mapwithboundary",
|
|
|
+ };
|
|
|
+
|
|
|
+ // 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);
|
|
|
+ // 等待地图渲染完成后调整大小
|
|
|
+ setTimeout(() => {
|
|
|
+ if (map.value) {
|
|
|
+ map.value.invalidateSize();
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+
|
|
|
+ mapLoading.value = false;
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('地图初始化失败:', error);
|
|
|
+ mapError.value = true;
|
|
|
+ mapLoading.value = false;
|
|
|
+
|
|
|
+ let errorMessage = t('AcidModelMap.mapInitError');
|
|
|
+ if (error instanceof Error) {
|
|
|
+ errorMessage += ': ' + error.message;
|
|
|
+ }
|
|
|
+ ElMessage.error(errorMessage);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const reloadMap = () => {
|
|
|
+ initMap();
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ // 等待地图渲染完成后调整大小
|
|
|
+ setTimeout(() => {
|
|
|
+ initMap()
|
|
|
+ }, 200);
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.total-introduction {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #0a0a2a;
|
|
|
+ color: white;
|
|
|
+ font-family: 'Arial', sans-serif;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.background-layer {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-image: url('https://via.placeholder.com/1920x1080/0a0a2a/0a0a2a');
|
|
|
+ background-size: cover;
|
|
|
+ z-index: -1;
|
|
|
+}
|
|
|
+
|
|
|
+.header-title {
|
|
|
+ text-align: center;
|
|
|
+ padding: 20px 20px 0 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.header-title h1 {
|
|
|
+ font-size: 32px;
|
|
|
+ color: #00bfff;
|
|
|
+ text-shadow: 0 0 10px rgba(0, 187, 255, 0.8);
|
|
|
+ border-bottom: 2px solid #00bfff;
|
|
|
+ padding-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.main-content {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+ padding: 20px;
|
|
|
+ overflow-x: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.left-section,
|
|
|
+
|
|
|
+.right-section {
|
|
|
+ flex: 1;
|
|
|
+ width: 200px;
|
|
|
+}
|
|
|
+.center-section {
|
|
|
+ flex: 2;
|
|
|
+ width: 500px;
|
|
|
+}
|
|
|
+
|
|
|
+.map-containter {
|
|
|
+ width: 100%;
|
|
|
+ height: 600px;
|
|
|
+ border: 2px solid #00bfff;
|
|
|
+ border-radius: 10px;
|
|
|
+ overflow: hidden;
|
|
|
+ position: relative;
|
|
|
+ background-color: rgba(10, 10, 42, 0.8);
|
|
|
+}
|
|
|
+
|
|
|
+.map-loading,
|
|
|
+.map-error {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: rgba(0, 0, 0, 0.7);
|
|
|
+ z-index: 1000;
|
|
|
+ color: white;
|
|
|
+}
|
|
|
+
|
|
|
+.spinner {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border: 4px solid rgba(0, 187, 255, 0.3);
|
|
|
+ border-radius: 50%;
|
|
|
+ border-top-color: #00bfff;
|
|
|
+ animation: spin 1s linear infinite;
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes spin {
|
|
|
+ to { transform: rotate(360deg); }
|
|
|
+}
|
|
|
+
|
|
|
+.map-error p {
|
|
|
+ color: #ff6b6b;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.reload-btn {
|
|
|
+ padding: 10px 20px;
|
|
|
+ background-color: #00bfff;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ transition: all 0.3s;
|
|
|
+}
|
|
|
+
|
|
|
+.reload-btn:hover {
|
|
|
+ background-color: #009acd;
|
|
|
+ transform: translateY(-2px);
|
|
|
+}
|
|
|
+
|
|
|
+</style>
|