|
|
@@ -1,7 +1,7 @@
|
|
|
<template>
|
|
|
- <div class="container">
|
|
|
<el-card class="map-card">
|
|
|
<div class="title">
|
|
|
+ <div class="section-icon">🗺️</div>
|
|
|
<p class="map-title">乐昌市土地酸化预测</p>
|
|
|
</div>
|
|
|
|
|
|
@@ -25,8 +25,9 @@
|
|
|
ref="popupElement"
|
|
|
class="feature-popup fixed-center"
|
|
|
:style="{
|
|
|
- left: popupPosition.x + 'px',
|
|
|
- top: popupPosition.y + 'px'
|
|
|
+ left: popupPosition.x + '%',
|
|
|
+ top: popupPosition.y + '%',
|
|
|
+ translate:'none'
|
|
|
}">
|
|
|
<div class="popup-content">
|
|
|
<div class="popup-header" @mousedown="startDrag">
|
|
|
@@ -204,7 +205,7 @@
|
|
|
<div v-else-if="predictionResult" class="prediction-result">
|
|
|
<!--降酸结果-->
|
|
|
<div class="result-item" v-if="currentPredictionType === 'reduction' && predictionResult.prediction_reduce !== undefined">
|
|
|
- <span class="prediction-value reduction">每亩地土壤表层20cm撒{{ formatPredictionValue(predictionResult.prediction_reduce/10)}} 吨</span>
|
|
|
+ <span class="prediction-value reduction">每亩地土壤表层20cm撒{{ formatPredictionValue(predictionResult.prediction_reduce)}} 吨</span>
|
|
|
</div>
|
|
|
<!-- 反酸预测结果 -->
|
|
|
<div class="result-item" v-if="currentPredictionType === 'inversion' && predictionResult.prediction_reflux !== undefined">
|
|
|
@@ -225,14 +226,12 @@
|
|
|
:style="connectionLine.style">
|
|
|
</div>
|
|
|
</el-card>
|
|
|
- </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
import { reactive, ref, nextTick, onMounted, onUnmounted, computed } from "vue";
|
|
|
import { ElMessage } from "element-plus";
|
|
|
import type { FormInstance } from "element-plus";
|
|
|
-import { api5000, api8000, api8080 } from '@/utils/request'; // 导入封装好的API实例
|
|
|
|
|
|
// 新增:反酸预测相关状态(区分降酸/反酸的显示)
|
|
|
const showInversionPrediction = ref(false); // 控制反酸预测区域显示
|
|
|
@@ -404,20 +403,20 @@ const acidReductionRules = reactive({
|
|
|
// 格式化预测值
|
|
|
const formatPredictionValue = (value: any): string => {
|
|
|
console.log('预测值原始数据:', value, '类型:', typeof value);
|
|
|
-
|
|
|
+
|
|
|
if (value === null || value === undefined) return '无数据';
|
|
|
-
|
|
|
+
|
|
|
if (Array.isArray(value)) {
|
|
|
if (value.length === 0) return '无数据';
|
|
|
const num = Number(value[0]);
|
|
|
return isNaN(num) ? '无效数据' : num.toFixed(4);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (typeof value === 'object') {
|
|
|
console.warn('预测值是对象类型:', value);
|
|
|
return '数据格式错误';
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const num = Number(value);
|
|
|
return isNaN(num) ? '无效数据' : num.toFixed(4);
|
|
|
};
|
|
|
@@ -472,13 +471,13 @@ const drawHighlightFeature = (geoJsonFeature: any) => {
|
|
|
return scaledFeature;
|
|
|
};
|
|
|
|
|
|
- // 创建放大1.3倍的地块
|
|
|
- const scaledFeature = scaleFeatureCoordinates(geoJsonFeature, 1.3);
|
|
|
+ // 创建放大1倍的地块
|
|
|
+ const scaledFeature = scaleFeatureCoordinates(geoJsonFeature, 1);
|
|
|
|
|
|
// 使用放大后的GeoJSON创建高亮图层
|
|
|
highlightLayer.value = L.geoJSON(scaledFeature, {
|
|
|
style: {
|
|
|
- color: '#ff4d4f',
|
|
|
+ color: '#000',
|
|
|
weight: 4,
|
|
|
fillColor: '#ff4d4f',
|
|
|
fillOpacity: 1,
|
|
|
@@ -513,7 +512,7 @@ const drawHighlightFeature = (geoJsonFeature: any) => {
|
|
|
// 获取地块信息
|
|
|
const getFeatureInfo = async (latlng: any, point: any): Promise<boolean> => {
|
|
|
if (!map.value) return false;
|
|
|
-
|
|
|
+
|
|
|
featureInfo.loading = true;
|
|
|
featureInfo.error = false;
|
|
|
featureInfo.data = null;
|
|
|
@@ -525,7 +524,7 @@ const getFeatureInfo = async (latlng: any, point: any): Promise<boolean> => {
|
|
|
layerGroup: "mapwithboundary",
|
|
|
};
|
|
|
|
|
|
- const bounds = map.value.getBounds();
|
|
|
+ const bounds = map.value.getBounds();
|
|
|
const size = map.value.getSize();
|
|
|
|
|
|
const params = new URLSearchParams();
|
|
|
@@ -544,30 +543,24 @@ const getFeatureInfo = async (latlng: any, point: any): Promise<boolean> => {
|
|
|
params.append('bbox', `${bounds.getWest()},${bounds.getSouth()},${bounds.getEast()},${bounds.getNorth()}`);
|
|
|
|
|
|
const url = `${GEOSERVER_CONFIG.url}?${params.toString()}`;
|
|
|
- console.log('GetFeatureInfo URL:', url); // 添加日志
|
|
|
|
|
|
- // 修改:使用 apiMain 代替 fetch
|
|
|
- const response = await api8080.get(url);
|
|
|
+ const response = await fetch(url);
|
|
|
|
|
|
- if (response.status !== 200) {
|
|
|
+ if (!response.ok) {
|
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
}
|
|
|
|
|
|
- const data = response.data;
|
|
|
- console.log('GeoServer返回数据:', data); // 添加日志
|
|
|
+ const data = await response.json();
|
|
|
|
|
|
if (data.features && data.features.length > 0) {
|
|
|
-
|
|
|
const feature = data.features[0]; // 保存完整的要素(包含几何信息)
|
|
|
const properties = feature.properties;
|
|
|
const hasValidData = properties.QSDWMC || properties.DLMC;
|
|
|
- const village = properties.QSDWMC || properties.village || properties.VILLAGE || properties.name || '未知';
|
|
|
- const landType = properties.DLMC || properties.landType || properties.LANDTYPE || properties.type || '未知';
|
|
|
|
|
|
if (hasValidData) {
|
|
|
featureInfo.data = {
|
|
|
- village: village,
|
|
|
- landType: landType,
|
|
|
+ village: properties.QSDWMC,
|
|
|
+ landType: properties.DLMC,
|
|
|
};
|
|
|
// 绘制高亮地块
|
|
|
drawHighlightFeature(feature);
|
|
|
@@ -575,21 +568,11 @@ const getFeatureInfo = async (latlng: any, point: any): Promise<boolean> => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 如果没有数据,显示默认信息
|
|
|
- featureInfo.data = {
|
|
|
- village: '无数据',
|
|
|
- landType: '无数据',
|
|
|
- };
|
|
|
return false;
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('获取地块信息失败:', error);
|
|
|
featureInfo.error = true;
|
|
|
- // 错误时也显示默认信息
|
|
|
- featureInfo.data = {
|
|
|
- village: '获取失败',
|
|
|
- landType: '获取失败',
|
|
|
- };
|
|
|
return false;
|
|
|
} finally {
|
|
|
featureInfo.loading = false;
|
|
|
@@ -603,18 +586,22 @@ const fetchCurrentPH = async () => {
|
|
|
|
|
|
phLoading.value = true;
|
|
|
try {
|
|
|
- const params = {
|
|
|
- target_lon: currentClickCoords.lng.toString(),
|
|
|
- target_lat: currentClickCoords.lat.toString(),
|
|
|
- NO3: defaultParams.NO3.toString(),
|
|
|
- NH4: defaultParams.NH4.toString()
|
|
|
- };
|
|
|
-
|
|
|
- // 修改:使用 api8000 代替 fetch
|
|
|
- const response = await api8000.get('/api/vector/nearest-with-predictions', { params });
|
|
|
+ const urlParams = new URLSearchParams();
|
|
|
+ urlParams.append('target_lon', currentClickCoords.lng.toString());
|
|
|
+ urlParams.append('target_lat', currentClickCoords.lat.toString());
|
|
|
+ urlParams.append('NO3', defaultParams.NO3.toString());
|
|
|
+ urlParams.append('NH4', defaultParams.NH4.toString());
|
|
|
+
|
|
|
+ // 调用接口获取当前pH(接口会返回nearest_point.ph)
|
|
|
+ const response = await fetch(
|
|
|
+ `http://localhost:8000/api/vector/nearest-with-predictions?${urlParams.toString()}`
|
|
|
+ );
|
|
|
|
|
|
- // 从接口提取当前pH(根据你的接口结构:data.nearest_point.ph)
|
|
|
- currentPH.value = response.data.nearest_point?.ph !== undefined ? Number(response.data.nearest_point.ph) : null;
|
|
|
+ if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
+ const data = await response.json();
|
|
|
+
|
|
|
+ // 从接口提取当前pH(根据你的接口结构:data.nearest_point.ph)
|
|
|
+ currentPH.value = data.nearest_point?.ph !== undefined ? Number(data.nearest_point.ph) : null;
|
|
|
return currentPH.value !== null; // 返回是否获取成功
|
|
|
} catch (error) {
|
|
|
console.error('获取当前pH失败:', error);
|
|
|
@@ -730,37 +717,42 @@ const callPredictionAPI = async (
|
|
|
predictionResult.value = null;
|
|
|
|
|
|
try {
|
|
|
- const requestParams: any = {
|
|
|
- target_lon: lng.toString(),
|
|
|
- target_lat: lat.toString()
|
|
|
- };
|
|
|
+ const urlParams = new URLSearchParams();
|
|
|
+ urlParams.append('target_lon', lng.toString());
|
|
|
+ urlParams.append('target_lat', lat.toString());
|
|
|
|
|
|
// 明确传递 prediction_type
|
|
|
if (currentPredictionType.value === 'reduction') {
|
|
|
- requestParams.prediction_type = 'reduce';
|
|
|
+ urlParams.append('prediction_type', 'reduce');
|
|
|
} else if (currentPredictionType.value === 'inversion') {
|
|
|
- requestParams.prediction_type = 'reflux';
|
|
|
+ urlParams.append('prediction_type', 'reflux');
|
|
|
}
|
|
|
|
|
|
if (params) {
|
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
|
if (value !== undefined && value !== null) {
|
|
|
- requestParams[key] = value.toString();
|
|
|
+ urlParams.append(key, value.toString());
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- console.log('调用预测接口,参数:', requestParams);
|
|
|
+ console.log('调用预测接口,参数:', urlParams.toString());
|
|
|
|
|
|
- // 修改:使用 api8000 代替 fetch
|
|
|
- const response = await api8000.get('/api/vector/nearest-with-predictions', {
|
|
|
- params: requestParams
|
|
|
- });
|
|
|
+ const response = await fetch(
|
|
|
+ `http://localhost:8000/api/vector/nearest-with-predictions?${urlParams.toString()}`
|
|
|
+ );
|
|
|
|
|
|
- predictionResult.value = response.data;
|
|
|
- console.log('预测结果:', response.data);
|
|
|
+ if (!response.ok) {
|
|
|
+ const errorData = await response.json();
|
|
|
+ console.error('预测接口返回错误:', errorData);
|
|
|
+ throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
+ }
|
|
|
|
|
|
- currentPH.value = response.data.nearest_point?.ph !== undefined ? Number(response.data.nearest_point.ph) : null;
|
|
|
+ const data = await response.json();
|
|
|
+ predictionResult.value = data;
|
|
|
+ console.log('预测结果:', data);
|
|
|
+
|
|
|
+ currentPH.value = data.nearest_point?.ph !== undefined ? Number(data.nearest_point.ph) : null;
|
|
|
|
|
|
// 显示预测结果
|
|
|
showPredictionResult.value = true;
|
|
|
@@ -791,9 +783,7 @@ const resetPrediction = () => {
|
|
|
const handleMapClick = async (e: any) => {
|
|
|
const lng = e.latlng.lng;
|
|
|
const lat = e.latlng.lat;
|
|
|
-
|
|
|
- console.log('地图点击坐标:', { lng, lat }); // 添加日志
|
|
|
-
|
|
|
+
|
|
|
// 更新当前坐标
|
|
|
currentClickCoords.lng = lng;
|
|
|
currentClickCoords.lat = lat;
|
|
|
@@ -811,8 +801,8 @@ const handleMapClick = async (e: any) => {
|
|
|
clickPoint.y = mapRect.top + containerPoint.y;
|
|
|
|
|
|
// 设置弹窗初始位置(在点击点右侧)
|
|
|
- popupPosition.x = clickPoint.x + 20;
|
|
|
- popupPosition.y = clickPoint.y - 100; // 居中显示
|
|
|
+ popupPosition.x = 35;
|
|
|
+ popupPosition.y = 35; // 居中显示
|
|
|
|
|
|
showPopup.value = true;
|
|
|
showConnectionLine.value=false;
|
|
|
@@ -879,8 +869,8 @@ const closePopup = () => {
|
|
|
// 新增:弹窗拖动相关状态
|
|
|
const popupElement = ref<HTMLElement>();
|
|
|
const popupPosition = reactive({
|
|
|
- x: 0,
|
|
|
- y: 0
|
|
|
+ x: 35,
|
|
|
+ y: 35
|
|
|
});
|
|
|
|
|
|
// 新增:连接线相关状态
|
|
|
@@ -903,8 +893,14 @@ const startDrag = (event: MouseEvent) => {
|
|
|
if (!popupElement.value) return;
|
|
|
|
|
|
isDragging.value = true;
|
|
|
- dragStartPos.x = event.clientX - popupPosition.x;
|
|
|
- dragStartPos.y = event.clientY - popupPosition.y;
|
|
|
+ // 初始值:百分比转像素
|
|
|
+ const viewportWidth = window.innerWidth;
|
|
|
+ const viewportHeight = window.innerHeight;
|
|
|
+ const popupLeft = (popupPosition.x / 100) * viewportWidth;
|
|
|
+ const popupTop = (popupPosition.y / 100) * viewportHeight;
|
|
|
+
|
|
|
+ dragStartPos.x = event.clientX - popupLeft;
|
|
|
+ dragStartPos.y = event.clientY - popupTop;
|
|
|
|
|
|
document.addEventListener('mousemove', onDrag);
|
|
|
document.addEventListener('mouseup', stopDrag);
|
|
|
@@ -914,8 +910,15 @@ const startDrag = (event: MouseEvent) => {
|
|
|
const onDrag = (event: MouseEvent) => {
|
|
|
if (!isDragging.value) return;
|
|
|
|
|
|
- popupPosition.x = event.clientX - dragStartPos.x;
|
|
|
- popupPosition.y = event.clientY - dragStartPos.y;
|
|
|
+ // 拖拽后转成百分比
|
|
|
+ const viewportWidth = window.innerWidth;
|
|
|
+ const viewportHeight = window.innerHeight;
|
|
|
+ // 计算拖拽后的像素位置
|
|
|
+ const newX = event.clientX - dragStartPos.x;
|
|
|
+ const newY = event.clientY - dragStartPos.y;
|
|
|
+ // 转成百分比(限制0-95,避免弹窗超出可视区)
|
|
|
+ popupPosition.x = Math.max(0, Math.min(95, (newX / viewportWidth) * 100));
|
|
|
+ popupPosition.y = Math.max(0, Math.min(95, (newY / viewportHeight) * 100));
|
|
|
updateConnectionLine();
|
|
|
};
|
|
|
|
|
|
@@ -923,6 +926,9 @@ const stopDrag = () => {
|
|
|
isDragging.value = false;
|
|
|
document.removeEventListener('mousemove', onDrag);
|
|
|
document.removeEventListener('mouseup', stopDrag);
|
|
|
+ nextTick(() => {
|
|
|
+ updateConnectionLine();
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
// 修改更新连接线方法,使用经纬度坐标
|
|
|
@@ -939,8 +945,15 @@ const updateConnectionLine = () => {
|
|
|
|
|
|
// 获取弹窗中心点
|
|
|
const popupRect = popupElement.value.getBoundingClientRect();
|
|
|
- const endX = popupPosition.x + popupRect.width / 2;
|
|
|
- const endY = popupPosition.y + popupRect.height / 2;
|
|
|
+ // 视口总宽度/高度
|
|
|
+ const viewportWidth = window.innerWidth;
|
|
|
+ const viewportHeight = window.innerHeight;
|
|
|
+ // 弹窗左上角像素坐标(百分比转像素)
|
|
|
+ const popupLeft = (popupPosition.x / 100) * viewportWidth;
|
|
|
+ const popupTop = (popupPosition.y / 100) * viewportHeight;
|
|
|
+ // 弹窗中心点像素坐标
|
|
|
+ const endX = popupLeft + popupRect.width / 2;
|
|
|
+ const endY = popupTop + popupRect.height / 2;
|
|
|
|
|
|
// 计算线的长度和角度
|
|
|
const length = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2));
|
|
|
@@ -951,7 +964,8 @@ const updateConnectionLine = () => {
|
|
|
top: startY + 'px',
|
|
|
width: length + 'px',
|
|
|
transform: `rotate(${angle}deg)`,
|
|
|
- transformOrigin: '0 0'
|
|
|
+ transformOrigin: '0 0',
|
|
|
+ '--arrow-angle':`${angle}deg`
|
|
|
};
|
|
|
};
|
|
|
|
|
|
@@ -960,21 +974,11 @@ const initMap = async () => {
|
|
|
mapError.value = false;
|
|
|
|
|
|
try {
|
|
|
- console.log('开始初始化地图...');
|
|
|
-
|
|
|
- // 检查地图容器是否存在
|
|
|
- const mapContainer = document.getElementById('map-container');
|
|
|
- if (!mapContainer) {
|
|
|
- throw new Error('地图容器未找到');
|
|
|
- }
|
|
|
- console.log('地图容器尺寸:', mapContainer.offsetWidth, 'x', mapContainer.offsetHeight);
|
|
|
-
|
|
|
// 动态导入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',
|
|
|
@@ -986,6 +990,7 @@ const initMap = async () => {
|
|
|
// 清除现有地图
|
|
|
if (map.value) {
|
|
|
map.value.remove();
|
|
|
+ map.value = null;
|
|
|
}
|
|
|
|
|
|
// 创建地图实例
|
|
|
@@ -996,34 +1001,48 @@ const initMap = async () => {
|
|
|
zoom: 10
|
|
|
});
|
|
|
|
|
|
- console.log('地图实例创建成功');
|
|
|
-
|
|
|
- // 然后尝试添加WMS图层
|
|
|
+ // WMS配置
|
|
|
const GEOSERVER_CONFIG = {
|
|
|
url: "/geoserver/wms",
|
|
|
workspace: "acidmap",
|
|
|
layerGroup: "mapwithboundary",
|
|
|
};
|
|
|
|
|
|
- try {
|
|
|
- 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"
|
|
|
- }).addTo(map.value);
|
|
|
- console.log('WMS图层添加成功');
|
|
|
- } catch (wmsError) {
|
|
|
- console.warn('WMS图层加载失败,使用OSM底图:', wmsError);
|
|
|
- }
|
|
|
+ // 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);
|
|
|
|
|
|
// 绑定点击事件
|
|
|
map.value.on('click', handleMapClick);
|
|
|
|
|
|
+ // 添加地图移动和缩放事件监听,实时更新连接线
|
|
|
+ map.value.on('moveend zoomend', () => {
|
|
|
+ if (showPopup.value && showConnectionLine.value) {
|
|
|
+ updateConnectionLine();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 监听地图飞行动画完成事件
|
|
|
+ map.value.on('moveend', () => {
|
|
|
+ // 地图动画完成后显示连接线
|
|
|
+ if (showPopup.value && !showConnectionLine.value && featureCenter.lng && featureCenter.lat) {
|
|
|
+ showConnectionLine.value = true;
|
|
|
+ nextTick(() => {
|
|
|
+ updateConnectionLine();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
mapLoading.value = false;
|
|
|
- console.log('地图初始化完成');
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('地图初始化失败:', error);
|
|
|
@@ -1055,21 +1074,31 @@ onUnmounted(() => {
|
|
|
// 移除拖拽事件监听
|
|
|
document.removeEventListener('mousemove', onDrag);
|
|
|
document.removeEventListener('mouseup', stopDrag);
|
|
|
+
|
|
|
+ window.removeEventListener('resize', handleWindowResize);
|
|
|
});
|
|
|
|
|
|
onMounted(() => {
|
|
|
nextTick(() => {
|
|
|
initMap();
|
|
|
});
|
|
|
+ // 监听窗口缩放
|
|
|
+ window.addEventListener('resize', handleWindowResize);
|
|
|
});
|
|
|
+
|
|
|
+// 窗口缩放时重新计算连接线
|
|
|
+const handleWindowResize = () => {
|
|
|
+ if (showPopup.value && showConnectionLine.value) {
|
|
|
+ nextTick(() => {
|
|
|
+ updateConnectionLine();
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.feature-popup {
|
|
|
position: fixed;
|
|
|
- top: 45%;
|
|
|
- left: 40%;
|
|
|
- transform: translate(-50%,-50%);
|
|
|
z-index: 1000;
|
|
|
background: white;
|
|
|
border-radius: 8px;
|
|
|
@@ -1260,13 +1289,10 @@ onMounted(() => {
|
|
|
}
|
|
|
|
|
|
.map-card {
|
|
|
- background-color: rgba(255, 255, 255, 0.8);
|
|
|
- border-radius: 8px;
|
|
|
- padding: 15px;
|
|
|
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
- position: relative;
|
|
|
- backdrop-filter: blur(5px);
|
|
|
- overflow: visible !important;
|
|
|
+ width: 850px;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 600px;
|
|
|
+ margin: 0 auto;
|
|
|
}
|
|
|
|
|
|
.map-container {
|
|
|
@@ -1457,15 +1483,6 @@ onMounted(() => {
|
|
|
color: #48bb78; /* 反酸结果用绿色 */
|
|
|
}
|
|
|
|
|
|
-.container {
|
|
|
- padding: 20px;
|
|
|
- background: linear-gradient(
|
|
|
- 135deg,
|
|
|
- rgba(230, 247, 255, 0.7) 0%,
|
|
|
- rgba(240, 248, 255, 0.7) 100%
|
|
|
- );
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
/* 新增:高亮图层的z-index确保在最上层 */
|
|
|
:deep(.leaflet-geojson) {
|
|
|
z-index: 999 !important;
|
|
|
@@ -1481,28 +1498,24 @@ onMounted(() => {
|
|
|
border: none;
|
|
|
z-index: 999;
|
|
|
pointer-events: none;
|
|
|
+ --arrow-angle: 0deg;
|
|
|
}
|
|
|
|
|
|
.connection-line::before {
|
|
|
content: '';
|
|
|
position: absolute;
|
|
|
- width: 6px;
|
|
|
- height: 6px;
|
|
|
- background: #409eff;
|
|
|
- border-radius: 50%;
|
|
|
- top: -2.5px;
|
|
|
- left: -3px;
|
|
|
-}
|
|
|
-
|
|
|
-.connection-line::after {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- width: 6px;
|
|
|
- height: 6px;
|
|
|
- background: #409eff;
|
|
|
- border-radius: 50%;
|
|
|
- top: -2.5px;
|
|
|
- right: -3px;
|
|
|
+ left: -5px; /* 箭头在连接线起点左侧,对准地块 */
|
|
|
+ top: 50%;
|
|
|
+ /* 跟随连接线角度旋转,保持垂直居中 */
|
|
|
+ transform: translateY(-50%) rotate(var(--arrow-angle));
|
|
|
+ /* 三角形箭头:右向箭头(指向地块) */
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border-style: solid;
|
|
|
+ border-width: 4px 8px 4px 0; /* 箭头尺寸:高4px*2,长8px */
|
|
|
+ border-color: transparent #409eff transparent transparent; /* 箭头颜色与连接线一致 */
|
|
|
+ transform-origin: center center;
|
|
|
+ z-index: 1;
|
|
|
}
|
|
|
|
|
|
</style>
|