2026-03-31 18:10:34 +08:00
|
|
|
|
<template>
|
2026-04-21 15:34:43 +08:00
|
|
|
|
<!-- 检查URL参数中是否有Map=dev,如果有,则使用本地地图数据,否则使用阿里云地图数据 -->
|
2026-03-31 18:10:34 +08:00
|
|
|
|
<div class="chongqing-map-container">
|
|
|
|
|
|
<div ref="mapContainer" class="map-container"></div>
|
|
|
|
|
|
<div v-if="loading" class="loading-overlay">
|
|
|
|
|
|
<div class="loading-spinner"></div>
|
|
|
|
|
|
<span class="loading-text">地图加载中...</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-if="error" class="error-overlay">
|
|
|
|
|
|
<span class="error-text">{{ error }}</span>
|
|
|
|
|
|
<button class="retry-btn" @click="loadMapData">重试</button>
|
|
|
|
|
|
</div>
|
2026-04-08 18:47:57 +08:00
|
|
|
|
<mapInfoDialog
|
|
|
|
|
|
v-model:visible="mapInfoDialogVisible"
|
|
|
|
|
|
:type="mapInfoDialogType"
|
|
|
|
|
|
:data="mapInfoDialogData"
|
|
|
|
|
|
/>
|
2026-04-13 11:38:11 +08:00
|
|
|
|
<centerInfoCard
|
|
|
|
|
|
:visible="centerCardVisible"
|
|
|
|
|
|
:title="centerCardTitle"
|
|
|
|
|
|
:dataList="centerCardDataList"
|
|
|
|
|
|
@close="closeCenterCard"
|
|
|
|
|
|
@itemClick="handleCenterCardItemClick"
|
|
|
|
|
|
@click="handleCenterCardClick"
|
|
|
|
|
|
/>
|
2026-04-17 14:50:25 +08:00
|
|
|
|
|
|
|
|
|
|
<hazardPointSituationDialog
|
|
|
|
|
|
v-model:visible="hazardPointSituationDialogVisible"
|
|
|
|
|
|
:data="{}"
|
|
|
|
|
|
@close="closeHazardPointSituationDialog"
|
|
|
|
|
|
/>
|
2026-03-31 18:10:34 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-04-17 14:50:25 +08:00
|
|
|
|
import { ref, onMounted, onUnmounted, watch, defineExpose, h, render } from 'vue';
|
|
|
|
|
|
import axios from 'axios';
|
|
|
|
|
|
import { request } from '@/utils/request';
|
|
|
|
|
|
|
|
|
|
|
|
import projectIcon from '../../../assets/MaMap_img/项目@2x.png';
|
|
|
|
|
|
import bridgeIcon from '../../../assets/MaMap_img/桥梁icon@2x.png';
|
|
|
|
|
|
import tunnelIcon from '../../../assets/MaMap_img/蓝色@2x1.png';
|
|
|
|
|
|
import tunnelIcon2 from '../../../assets/MaMap_img/隧洞icon@2x.png';
|
|
|
|
|
|
import rescueTeamIcon from '../../../assets/MaMap_img/队伍icon@2x.png';
|
2026-04-28 09:20:54 +08:00
|
|
|
|
import engineeringIconIcon from '../../../assets/MaMap_img/危大工程icon@2x.png';
|
2026-04-17 14:50:25 +08:00
|
|
|
|
|
|
|
|
|
|
import hazardIconIcon1 from '../../../assets/MaMap_img/一般路内隐患点@2x.png';
|
|
|
|
|
|
import hazardIconIcon2 from '../../../assets/MaMap_img/一般路外隐患点@2x.png';
|
|
|
|
|
|
import hazardIconIcon3 from '../../../assets/MaMap_img/较大路内隐患点@2x.png';
|
|
|
|
|
|
import hazardIconIcon4 from '../../../assets/MaMap_img/较大路外隐患点@2x.png';
|
|
|
|
|
|
import hazardIconIcon5 from '../../../assets/MaMap_img/重大路内隐患点@2x.png';
|
|
|
|
|
|
import hazardIconIcon6 from '../../../assets/MaMap_img/重大路外隐患点@2x.png';
|
|
|
|
|
|
|
|
|
|
|
|
import tunnelLineIcon3 from '../../../assets/MaMap_img/高风险路段@2x.png';
|
|
|
|
|
|
import tunnelLineIcon2 from '../../../assets/MaMap_img/较高风险路段@2x.png';
|
|
|
|
|
|
import tunnelLineIcon1 from '../../../assets/MaMap_img/中风险路段@2x.png';
|
|
|
|
|
|
import tunnelLineIcon from '../../../assets/MaMap_img/线路icon定位@2x.png';
|
|
|
|
|
|
|
|
|
|
|
|
import mapInfoDialog from '../Dialog/mapInfoDialog.vue';
|
|
|
|
|
|
import centerInfoCard from '../Dialog/centerInfoCard.vue';
|
|
|
|
|
|
import hazardPointSituationDialog from '../Dialog/hazardPointSituationDialog.vue';
|
2026-04-21 15:34:43 +08:00
|
|
|
|
import I from '../../../../dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain';
|
2026-04-08 18:47:57 +08:00
|
|
|
|
|
2026-04-02 16:35:45 +08:00
|
|
|
|
const mapContainer = ref(null);
|
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
|
const error = ref(null);
|
|
|
|
|
|
let mapInstance = null;
|
|
|
|
|
|
let geoJsonLayer = null;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const props = defineProps({
|
2026-04-15 16:40:35 +08:00
|
|
|
|
activeitem: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: () => {},
|
2026-04-08 18:47:57 +08:00
|
|
|
|
},
|
2026-04-09 14:53:44 +08:00
|
|
|
|
dateRange: {
|
|
|
|
|
|
type: Array,
|
|
|
|
|
|
default: () => [],
|
|
|
|
|
|
},
|
2026-04-15 16:40:35 +08:00
|
|
|
|
roadItem: {
|
|
|
|
|
|
// 路段项 数据 主要是选中的路段等级
|
|
|
|
|
|
type: Object,
|
2026-04-17 14:50:25 +08:00
|
|
|
|
default: () => {
|
|
|
|
|
|
return {
|
|
|
|
|
|
label: '高风险',
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
2026-04-15 16:40:35 +08:00
|
|
|
|
},
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
watch(
|
|
|
|
|
|
() => props.roadItem,
|
|
|
|
|
|
async (newVal, oldVal) => {
|
2026-04-28 09:20:54 +08:00
|
|
|
|
getAffectedRoadSectionData(false);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
},
|
2026-04-28 09:20:54 +08:00
|
|
|
|
{ immediate: false }
|
2026-04-17 14:50:25 +08:00
|
|
|
|
);
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 定义 emits
|
2026-04-13 11:38:11 +08:00
|
|
|
|
const emit = defineEmits([
|
2026-04-17 14:50:25 +08:00
|
|
|
|
'districtClick',
|
|
|
|
|
|
'openTongnanTeam',
|
|
|
|
|
|
'openResponseSituation',
|
|
|
|
|
|
'openTongnanResponsible',
|
|
|
|
|
|
'riskPointStatsChange',
|
|
|
|
|
|
'update:roadvalArr',
|
|
|
|
|
|
'openHazardPointSituation',
|
2026-04-29 10:33:26 +08:00
|
|
|
|
'openRoadSectionSituation',
|
2026-04-13 11:38:11 +08:00
|
|
|
|
]);
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 当前选中的区县
|
|
|
|
|
|
const selectedDistrict = ref(null);
|
|
|
|
|
|
let selectedLayer = null;
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 地图信息弹窗
|
|
|
|
|
|
const mapInfoDialogVisible = ref(false);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const mapInfoDialogType = ref('project');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const mapInfoDialogData = ref({});
|
|
|
|
|
|
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 中心信息卡片弹窗
|
|
|
|
|
|
const centerCardVisible = ref(false);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const centerCardTitle = ref('调度统计');
|
2026-04-13 11:38:11 +08:00
|
|
|
|
const centerCardDataList = ref([]);
|
|
|
|
|
|
|
|
|
|
|
|
// 地图上显示的区县卡片标记
|
|
|
|
|
|
let countyCardMarkers = [];
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 打开地图信息弹窗
|
|
|
|
|
|
const openMapInfoDialog = (type, data) => {
|
|
|
|
|
|
mapInfoDialogType.value = type;
|
|
|
|
|
|
mapInfoDialogData.value = data;
|
|
|
|
|
|
mapInfoDialogVisible.value = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 清除地图上的区县卡片标记
|
|
|
|
|
|
const clearCountyCardMarkers = () => {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
countyCardMarkers.forEach(marker => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 清理 Vue 组件
|
|
|
|
|
|
if (marker._vueContainer) {
|
|
|
|
|
|
render(null, marker._vueContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (mapInstance) {
|
|
|
|
|
|
mapInstance.removeLayer(marker);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
countyCardMarkers = [];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 在地图上显示区县卡片
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const showCountyCardsOnMap = dataList => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
if (!mapInstance || !geoJsonLayer) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('地图未初始化,无法显示区县卡片');
|
2026-04-13 11:38:11 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清除之前的卡片标记
|
|
|
|
|
|
clearCountyCardMarkers();
|
|
|
|
|
|
|
|
|
|
|
|
if (!dataList || dataList.length === 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 简化区县名称
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const simplifyName = name => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
return name
|
2026-04-17 14:50:25 +08:00
|
|
|
|
.replace('土家族苗族自治县', '')
|
|
|
|
|
|
.replace('苗族土家族自治县', '')
|
|
|
|
|
|
.replace('自治县', '')
|
|
|
|
|
|
.replace('区', '')
|
|
|
|
|
|
.replace('县', '');
|
2026-04-13 11:38:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历数据列表,为每个区县创建卡片
|
2026-04-17 14:50:25 +08:00
|
|
|
|
dataList.forEach(item => {
|
2026-04-21 15:34:43 +08:00
|
|
|
|
// if (j.countyName === item.countyName) {
|
|
|
|
|
|
// item = j;
|
|
|
|
|
|
// }
|
2026-04-13 11:38:11 +08:00
|
|
|
|
const countyName = item.countyName || item.name;
|
|
|
|
|
|
if (!countyName) return;
|
|
|
|
|
|
|
|
|
|
|
|
const targetName = simplifyName(countyName);
|
|
|
|
|
|
|
|
|
|
|
|
// 查找对应的区县图层
|
|
|
|
|
|
let targetLayer = null;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
geoJsonLayer.eachLayer(layer => {
|
|
|
|
|
|
const layerName = layer.feature?.properties?.name || '';
|
2026-04-13 11:38:11 +08:00
|
|
|
|
if (simplifyName(layerName) === targetName) {
|
|
|
|
|
|
targetLayer = layer;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (targetLayer) {
|
|
|
|
|
|
// 获取区县的中心点
|
|
|
|
|
|
const bounds = targetLayer.getBounds();
|
|
|
|
|
|
const center = bounds.getCenter();
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个容器元素用于挂载 Vue 组件
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const container = document.createElement('div');
|
|
|
|
|
|
container.className = 'county-card-wrapper';
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 使用 Vue 的 h 函数创建组件虚拟节点
|
|
|
|
|
|
const vnode = h(centerInfoCard, {
|
|
|
|
|
|
visible: true,
|
|
|
|
|
|
title: countyName,
|
|
|
|
|
|
dataList: [item],
|
|
|
|
|
|
item: item,
|
|
|
|
|
|
onClose: () => {
|
|
|
|
|
|
closeCenterCard();
|
|
|
|
|
|
},
|
2026-04-17 14:50:25 +08:00
|
|
|
|
onItemClick: clickedItem => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
handleCenterCardItemClick(clickedItem);
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染组件到容器
|
|
|
|
|
|
render(vnode, container);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建自定义图标,使用渲染后的 HTML
|
|
|
|
|
|
const customIcon = window.L.divIcon({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
className: 'county-card-icon',
|
2026-04-13 11:38:11 +08:00
|
|
|
|
html: container.innerHTML,
|
2026-04-15 16:40:35 +08:00
|
|
|
|
iconSize: [140, 40],
|
2026-04-13 11:38:11 +08:00
|
|
|
|
iconAnchor: [110, 60],
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 创建标记
|
|
|
|
|
|
const marker = window.L.marker(center, {
|
|
|
|
|
|
icon: customIcon,
|
|
|
|
|
|
interactive: true,
|
2026-04-21 15:34:43 +08:00
|
|
|
|
zIndexOffset: 2000, // 提升区县卡片层级,确保在最上层
|
2026-04-13 11:38:11 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 添加点击事件到 marker
|
2026-04-17 14:50:25 +08:00
|
|
|
|
marker.on('click', () => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 调用处理函数
|
|
|
|
|
|
handleCenterCardItemClick(item);
|
|
|
|
|
|
// 移动地图到该位置
|
2026-04-16 14:03:39 +08:00
|
|
|
|
// mapInstance.setView(center, 10);
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 触发点击事件
|
2026-04-17 14:50:25 +08:00
|
|
|
|
emit('districtClick', {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
name: countyName,
|
|
|
|
|
|
data: item,
|
2026-04-13 14:54:48 +08:00
|
|
|
|
type: item.type,
|
2026-04-13 11:38:11 +08:00
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
marker.addTo(mapInstance);
|
|
|
|
|
|
countyCardMarkers.push(marker);
|
|
|
|
|
|
|
|
|
|
|
|
// 保存容器引用以便后续清理
|
|
|
|
|
|
marker._vueContainer = container;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 调整地图视角以显示所有卡片
|
2026-04-16 14:03:39 +08:00
|
|
|
|
// if (countyCardMarkers.length > 0) {
|
|
|
|
|
|
// const group = new window.L.featureGroup(countyCardMarkers);
|
|
|
|
|
|
// mapInstance.fitBounds(group.getBounds().pad(0.2));
|
|
|
|
|
|
// }
|
2026-04-13 11:38:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取公路类型文本
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const getRoadTypeText = roadType => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
const roadTypeMap = {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
national: '国省道',
|
|
|
|
|
|
rural: '农村公路',
|
2026-04-13 11:38:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
return roadTypeMap[roadType] || roadType;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 打开中心信息卡片弹窗
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const openCenterCard = data => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
centerCardDataList.value = data.dataList || [];
|
2026-04-17 14:50:25 +08:00
|
|
|
|
centerCardTitle.value = data.title || '调度统计';
|
2026-04-13 11:38:11 +08:00
|
|
|
|
centerCardVisible.value = true;
|
2026-04-21 15:34:43 +08:00
|
|
|
|
let affectedItems = [];
|
|
|
|
|
|
// 遍历数据列表,只有影响区域的区县才添加到受影响列表中
|
|
|
|
|
|
data.dataList.forEach(item => {
|
|
|
|
|
|
if (item.countyName && (item.countyName.includes('渝北') || item.countyName.includes('江北'))) {
|
|
|
|
|
|
item.countyName = '两江新区';
|
|
|
|
|
|
}
|
|
|
|
|
|
affectedCountyData.value.sortedList.forEach(j => {
|
|
|
|
|
|
if (item.countyName.includes(j.name)) {
|
|
|
|
|
|
affectedItems.push(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2026-04-13 11:38:11 +08:00
|
|
|
|
|
|
|
|
|
|
// 在地图上显示区县卡片
|
2026-04-21 15:34:43 +08:00
|
|
|
|
showCountyCardsOnMap(affectedItems);
|
2026-04-13 11:38:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭中心信息卡片弹窗
|
|
|
|
|
|
const closeCenterCard = () => {
|
|
|
|
|
|
centerCardVisible.value = false;
|
|
|
|
|
|
clearCountyCardMarkers();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理中心卡片项点击
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const handleCenterCardItemClick = item => {
|
|
|
|
|
|
console.log('点击了卡片项:', item);
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 根据区县名称定位地图
|
|
|
|
|
|
if (item.countyName || item.name) {
|
|
|
|
|
|
const countyName = item.countyName || item.name;
|
|
|
|
|
|
locateToDistrict(countyName);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 打开隧道信息弹窗(兼容旧代码)
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const openTunnelDialog = data => {
|
|
|
|
|
|
openMapInfoDialog('tunnel', data);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-09 14:53:44 +08:00
|
|
|
|
// 格式化日期时间为接口所需格式
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const formatDateTime = date => {
|
|
|
|
|
|
if (!date) return '';
|
2026-04-09 14:53:44 +08:00
|
|
|
|
const d = new Date(date);
|
|
|
|
|
|
const year = d.getFullYear();
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
|
const day = String(d.getDate()).padStart(2, '0');
|
|
|
|
|
|
const hours = String(d.getHours()).padStart(2, '0');
|
|
|
|
|
|
const minutes = String(d.getMinutes()).padStart(2, '0');
|
|
|
|
|
|
const seconds = String(d.getSeconds()).padStart(2, '0');
|
2026-04-09 14:53:44 +08:00
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取时间参数
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const getTimeParams = type => {
|
|
|
|
|
|
let start = '';
|
|
|
|
|
|
let end = '';
|
2026-04-09 14:53:44 +08:00
|
|
|
|
if (props.dateRange && props.dateRange.length === 2) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
start = formatDateTime(props.dateRange[0]) || '';
|
|
|
|
|
|
end = formatDateTime(props.dateRange[1]) || '';
|
2026-04-15 16:40:35 +08:00
|
|
|
|
}
|
2026-04-09 14:53:44 +08:00
|
|
|
|
return {
|
2026-04-15 16:40:35 +08:00
|
|
|
|
start: start,
|
|
|
|
|
|
end: end,
|
2026-04-09 14:53:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 受影响对象数据
|
|
|
|
|
|
const affectedCountyData = ref({
|
|
|
|
|
|
byName: {},
|
|
|
|
|
|
sortedList: [],
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 获取受影响对象数据
|
|
|
|
|
|
const getAffectedCountyData = async () => {
|
|
|
|
|
|
try {
|
2026-04-09 14:53:44 +08:00
|
|
|
|
const timeParams = getTimeParams();
|
2026-04-08 15:34:49 +08:00
|
|
|
|
const res = await request({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
url: '/snow-ops-platform/weather-warning/affected-county',
|
|
|
|
|
|
method: 'GET',
|
2026-04-09 14:53:44 +08:00
|
|
|
|
params: timeParams,
|
2026-04-08 15:34:49 +08:00
|
|
|
|
});
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('受影响对象数据:', res);
|
2026-04-28 09:20:54 +08:00
|
|
|
|
clearProjectMarkers();
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (res.code === '00000' && res.data) {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 统计各区县预警数量
|
|
|
|
|
|
const warningStats = countWarningsByCounty(res.data);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('区县预警统计:', warningStats);
|
2026-04-08 15:34:49 +08:00
|
|
|
|
affectedCountyData.value = warningStats;
|
2026-04-09 14:53:44 +08:00
|
|
|
|
|
2026-04-28 09:20:54 +08:00
|
|
|
|
getAffectedProjectData(true); // 获取受影响项目数据
|
|
|
|
|
|
getAffectedTunnelData(true); // 获取受影响隧道数据
|
|
|
|
|
|
getAffectedBridgeData(true); // 获取受影响桥梁数据
|
|
|
|
|
|
getDangerProjectData(true); // 获取危大工程数据
|
|
|
|
|
|
// 获取受影响路段数据
|
2026-04-21 15:34:43 +08:00
|
|
|
|
for (let index = 0; index < 5; index++) {
|
|
|
|
|
|
console.log(index);
|
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
|
props.roadItem.label = '高风险路段';
|
|
|
|
|
|
} else if (index == 1) {
|
|
|
|
|
|
props.roadItem.label = '较高风险路段';
|
|
|
|
|
|
} else if (index == 2) {
|
|
|
|
|
|
props.roadItem.label = '中风险路段';
|
|
|
|
|
|
} else if (index == 3) {
|
|
|
|
|
|
props.roadItem.label = '低风险路段';
|
|
|
|
|
|
} else if (index == 4) {
|
|
|
|
|
|
props.roadItem.label = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (props.roadItem.label) {
|
|
|
|
|
|
getAffectedRoadSectionData(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-17 14:50:25 +08:00
|
|
|
|
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// getEmergencyForceData();
|
2026-04-09 14:53:44 +08:00
|
|
|
|
|
2026-04-28 09:20:54 +08:00
|
|
|
|
loadMapData(); // 加载地图数据
|
2026-04-08 15:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('获取受影响对象数据失败:', error);
|
2026-04-08 15:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-28 09:20:54 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 通用数据过滤方法 - 根据区县筛选数据并设置坐标
|
|
|
|
|
|
* @param {Array} dataList - 原始数据列表
|
|
|
|
|
|
* @param {boolean} flag - 是否只筛选受影响区县的数据
|
|
|
|
|
|
* @param {Object} options - 配置选项
|
|
|
|
|
|
* @param {string} options.countyField - 区县字段名
|
|
|
|
|
|
* @param {string} options.countyMatchField - 匹配区县时使用的字段名(如与countyField不同)
|
|
|
|
|
|
* @param {Function} options.coordinateParser - 坐标解析函数,接收item返回[lng, lat]
|
|
|
|
|
|
* @returns {Array} 过滤后的数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
const filterDataByCounty = (dataList, flag, options) => {
|
|
|
|
|
|
const { countyField = 'COUNTY', countyMatchField, coordinateParser } = options;
|
|
|
|
|
|
const matchField = countyMatchField || countyField;
|
|
|
|
|
|
const filteredData = [];
|
|
|
|
|
|
|
|
|
|
|
|
dataList.forEach(item => {
|
|
|
|
|
|
// 区县名称处理:江北/渝北 -> 两江新区
|
|
|
|
|
|
const countyValue = item[countyField];
|
|
|
|
|
|
if (countyValue && (countyValue.includes('江北') || countyValue.includes('渝北'))) {
|
|
|
|
|
|
item[countyField] = '两江新区';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
const matchValue = item[matchField];
|
|
|
|
|
|
|
|
|
|
|
|
if (!flag) {
|
|
|
|
|
|
// 不过滤,直接添加所有数据
|
|
|
|
|
|
item.COORDINATE_POINT = coordinateParser(item);
|
|
|
|
|
|
filteredData.push(item);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 根据受影响区县列表进行过滤
|
|
|
|
|
|
const isMatched = affectedCountyData.value.sortedList.some(j => {
|
|
|
|
|
|
return matchValue && j.name && matchValue.includes(j.name);
|
|
|
|
|
|
});
|
|
|
|
|
|
if (isMatched) {
|
2026-04-28 09:20:54 +08:00
|
|
|
|
item.COORDINATE_POINT = coordinateParser(item);
|
|
|
|
|
|
filteredData.push(item);
|
|
|
|
|
|
}
|
2026-04-29 15:55:12 +08:00
|
|
|
|
}
|
2026-04-28 09:20:54 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return filteredData;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const affectedBridgeData = ref([]);
|
|
|
|
|
|
// 获取受影响桥梁数据
|
2026-04-21 15:34:43 +08:00
|
|
|
|
const getAffectedBridgeData = async flag => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
try {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 检查桥梁标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
if (hasProjectMarkersByType('bridge')) {
|
|
|
|
|
|
console.log('类型为 bridge 的标记已存在,跳过接口调用');
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-09 14:53:44 +08:00
|
|
|
|
const timeParams = getTimeParams();
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const res = await request({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
url: '/snow-ops-platform/map/bridge',
|
|
|
|
|
|
method: 'GET',
|
2026-04-09 14:53:44 +08:00
|
|
|
|
params: timeParams,
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-16 14:03:39 +08:00
|
|
|
|
if (res.data) {
|
2026-04-28 09:20:54 +08:00
|
|
|
|
// 使用通用过滤方法处理数据
|
|
|
|
|
|
const filteredData = filterDataByCounty(res.data, flag, {
|
|
|
|
|
|
countyField: 'COUNTY',
|
|
|
|
|
|
countyMatchField: 'GL1_QXMC',
|
|
|
|
|
|
coordinateParser: item => [item.GL1_QLJD, item.GL1_QLWD],
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-28 09:20:54 +08:00
|
|
|
|
affectedBridgeData.value = filteredData;
|
|
|
|
|
|
console.log('受影响桥梁数据:', affectedBridgeData.value);
|
|
|
|
|
|
addProjectMarkers(affectedBridgeData.value, bridgeIcon, 'bridge');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('获取受影响桥梁数据失败:', error);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const tunnelInfoDialogRef = ref([]);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 获取受影响隧道数据
|
2026-04-21 15:34:43 +08:00
|
|
|
|
const getAffectedTunnelData = async flag => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
try {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 检查隧道标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
if (hasProjectMarkersByType('tunnel')) {
|
|
|
|
|
|
console.log('类型为 tunnel 的标记已存在,跳过接口调用');
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-09 14:53:44 +08:00
|
|
|
|
const timeParams = getTimeParams();
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const res = await request({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
url: '/snow-ops-platform/map/tunnel',
|
|
|
|
|
|
method: 'GET',
|
2026-04-09 14:53:44 +08:00
|
|
|
|
params: timeParams,
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (res.code === '00000' && res.data) {
|
2026-04-28 09:20:54 +08:00
|
|
|
|
// 使用通用过滤方法处理数据
|
|
|
|
|
|
const filteredData = filterDataByCounty(res.data, flag, {
|
|
|
|
|
|
countyField: 'COUNTY',
|
|
|
|
|
|
countyMatchField: 'GL1_QXMC',
|
|
|
|
|
|
coordinateParser: item => [Number(item.GL1_SDJD2), Number(item.GL1_SDWD2)],
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-28 09:20:54 +08:00
|
|
|
|
tunnelInfoDialogRef.value = filteredData;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('受影响隧道数据:', tunnelInfoDialogRef.value);
|
|
|
|
|
|
addProjectMarkers(tunnelInfoDialogRef.value, tunnelIcon2, 'tunnel');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
return [];
|
|
|
|
|
|
} catch (error) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('获取受影响隧道数据失败:', error);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取受影响项目数据
|
2026-04-16 14:03:39 +08:00
|
|
|
|
const affectedProjectData = ref([]);
|
2026-04-21 15:34:43 +08:00
|
|
|
|
const getAffectedProjectData = async flag => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
try {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 检查项目标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
if (hasProjectMarkersByType('project')) {
|
|
|
|
|
|
console.log('类型为 project 的标记已存在,跳过接口调用');
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-09 14:53:44 +08:00
|
|
|
|
const timeParams = getTimeParams();
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const res = await request({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
url: '/snow-ops-platform/weather-warning/affected-object/project',
|
|
|
|
|
|
method: 'GET',
|
2026-04-09 14:53:44 +08:00
|
|
|
|
params: timeParams,
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('受影响项目数据:', res);
|
|
|
|
|
|
if (res.code === '00000' && res.data) {
|
|
|
|
|
|
console.log('项目数据条数:', res.data.length);
|
2026-04-28 09:20:54 +08:00
|
|
|
|
// 预处理:解析坐标格式
|
|
|
|
|
|
const preprocessedData = res.data.map(item => {
|
|
|
|
|
|
const newItem = { ...item };
|
|
|
|
|
|
if (item.COORDINATE_POINT) {
|
|
|
|
|
|
console.log('原始坐标:', item.COORDINATE_POINT);
|
|
|
|
|
|
newItem.COORDINATE_POINT_PARSED = item.COORDINATE_POINT.substring(
|
|
|
|
|
|
6,
|
|
|
|
|
|
item.COORDINATE_POINT.length - 1
|
|
|
|
|
|
)
|
|
|
|
|
|
.split(' ')
|
|
|
|
|
|
.reverse();
|
|
|
|
|
|
console.log('解析后坐标:', newItem.COORDINATE_POINT_PARSED);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
2026-04-28 09:20:54 +08:00
|
|
|
|
return newItem;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-28 09:20:54 +08:00
|
|
|
|
// 使用通用过滤方法处理数据
|
|
|
|
|
|
const filteredData = filterDataByCounty(preprocessedData, flag, {
|
|
|
|
|
|
countyField: 'COUNTY',
|
|
|
|
|
|
coordinateParser: item => item.COORDINATE_POINT_PARSED || [],
|
|
|
|
|
|
});
|
|
|
|
|
|
affectedProjectData.value = filteredData;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 在地图上添加项目标记
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('开始添加项目标记...');
|
2026-04-28 09:20:54 +08:00
|
|
|
|
addProjectMarkers(filteredData, projectIcon, 'project');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
} else {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('没有获取到项目数据或返回码错误:', res);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
return res.data || [];
|
|
|
|
|
|
} catch (error) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('获取受影响项目数据失败:', error);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取受影响路段数据
|
2026-04-16 14:03:39 +08:00
|
|
|
|
const affectedRoadSectionData = ref([]);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const roadvalArr = ref([
|
|
|
|
|
|
{ label: '高风险', value: 0, show: false },
|
|
|
|
|
|
{ label: '较高风险', value: 0, show: false },
|
|
|
|
|
|
{ label: '中风险', value: 0, show: false },
|
|
|
|
|
|
{ label: '低风险', value: 0, show: false },
|
|
|
|
|
|
]);
|
2026-04-21 15:34:43 +08:00
|
|
|
|
const getAffectedRoadSectionData = async flag => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
try {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('受影响路段数据:', props.roadItem);
|
|
|
|
|
|
const { start, end } = getTimeParams();
|
|
|
|
|
|
let riskLevel = '';
|
|
|
|
|
|
if (props.roadItem.label == '高风险路段') {
|
|
|
|
|
|
riskLevel = '高风险';
|
|
|
|
|
|
} else if (props.roadItem.label == '较高风险路段') {
|
|
|
|
|
|
riskLevel = '较高风险';
|
|
|
|
|
|
} else if (props.roadItem.label == '中风险路段') {
|
|
|
|
|
|
riskLevel = '中风险';
|
|
|
|
|
|
} else if (props.roadItem.label == '低风险路段') {
|
|
|
|
|
|
riskLevel = '低风险';
|
|
|
|
|
|
}
|
2026-04-29 15:55:12 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查该等级的路段标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
const typeKey = `road-${riskLevel}`;
|
|
|
|
|
|
if (hasProjectMarkersByType(typeKey)) {
|
|
|
|
|
|
console.log(`类型为 ${typeKey} 的标记已存在,跳过接口调用`);
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const res = await request({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
// url: '/snow-ops-platform/weather-warning/affected-object/road-section',
|
|
|
|
|
|
url: '/snow-ops-platform/risk-point/road-section',
|
|
|
|
|
|
method: 'GET',
|
|
|
|
|
|
params: {
|
|
|
|
|
|
riskLevel: riskLevel,
|
|
|
|
|
|
isWithinRedLine: '是',
|
|
|
|
|
|
start: start,
|
|
|
|
|
|
end: end,
|
|
|
|
|
|
},
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('受影响路段数据:', res);
|
2026-04-28 09:20:54 +08:00
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (res.code === '00000' && res.data) {
|
2026-04-28 09:20:54 +08:00
|
|
|
|
// 使用通用过滤方法处理数据
|
|
|
|
|
|
const filteredData = filterDataByCounty(res.data, flag, {
|
|
|
|
|
|
countyField: 'COUNTY',
|
|
|
|
|
|
countyMatchField: 'GL1_QXMC',
|
|
|
|
|
|
coordinateParser: item => [item.GL1_LON, item.GL1_LAT],
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-28 09:20:54 +08:00
|
|
|
|
affectedRoadSectionData.value = filteredData;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 在地图上添加项目标记
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('受影响路段数据:', affectedRoadSectionData.value);
|
|
|
|
|
|
|
|
|
|
|
|
let img = tunnelLineIcon;
|
|
|
|
|
|
if (riskLevel == '高风险') {
|
|
|
|
|
|
img = tunnelLineIcon3;
|
|
|
|
|
|
roadvalArr.value[0] = {
|
|
|
|
|
|
label: '高风险',
|
|
|
|
|
|
value: affectedRoadSectionData.value.length,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
};
|
|
|
|
|
|
} else if (riskLevel == '较高风险') {
|
|
|
|
|
|
img = tunnelLineIcon2;
|
|
|
|
|
|
roadvalArr.value[1] = {
|
|
|
|
|
|
label: '较高风险',
|
|
|
|
|
|
value: affectedRoadSectionData.value.length,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
};
|
|
|
|
|
|
} else if (riskLevel == '中风险') {
|
|
|
|
|
|
img = tunnelLineIcon1;
|
|
|
|
|
|
roadvalArr.value[2] = {
|
|
|
|
|
|
label: '中风险',
|
|
|
|
|
|
value: affectedRoadSectionData.value.length,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
};
|
|
|
|
|
|
} else if (riskLevel == '低风险') {
|
|
|
|
|
|
img = tunnelLineIcon;
|
|
|
|
|
|
roadvalArr.value[3] = {
|
|
|
|
|
|
label: '低风险',
|
|
|
|
|
|
value: affectedRoadSectionData.value.length,
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
emit('update:roadvalArr ==== 风险点总数', roadvalArr.value);
|
|
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 给数据添加风险等级字段,确保 addProjectMarkers 能正确识别类型键
|
|
|
|
|
|
const dataWithRiskLevel = affectedRoadSectionData.value.map(item => ({
|
|
|
|
|
|
...item,
|
|
|
|
|
|
riskLevel: riskLevel
|
|
|
|
|
|
}));
|
|
|
|
|
|
addProjectMarkers(dataWithRiskLevel, img, 'road');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
return [];
|
|
|
|
|
|
} catch (error) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('获取受影响路段数据失败:', error);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const emergencyForceData = ref([]);
|
|
|
|
|
|
// 获取应急力量数据
|
|
|
|
|
|
const getEmergencyForceData = async () => {
|
|
|
|
|
|
try {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 检查应急力量标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
if (hasProjectMarkersByType('emergency')) {
|
|
|
|
|
|
console.log('类型为 emergency 的标记已存在,跳过接口调用');
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-09 14:53:44 +08:00
|
|
|
|
const timeParams = getTimeParams();
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const res = await request({
|
2026-04-20 10:22:34 +08:00
|
|
|
|
url: '/snow-ops-platform/yhYjll/listForcesAndMaterials',
|
2026-04-17 14:50:25 +08:00
|
|
|
|
method: 'GET',
|
2026-04-09 14:53:44 +08:00
|
|
|
|
params: timeParams,
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('应急力量数据:', res);
|
|
|
|
|
|
if (res.code === '00000' && res.data) {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 解析坐标数据
|
2026-04-17 14:50:25 +08:00
|
|
|
|
res.data.forEach(item => {
|
2026-04-21 15:34:43 +08:00
|
|
|
|
item.COORDINATE_POINT = [item.lng, item.lat];
|
|
|
|
|
|
console.log('解析后坐标:', item.COORDINATE_POINT);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-09 14:53:44 +08:00
|
|
|
|
emergencyForceData.value = res.data;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
|
|
|
|
|
|
// 在地图上添加应急力量标记
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('开始添加应急力量标记...', res.data);
|
|
|
|
|
|
addProjectMarkers(res.data, rescueTeamIcon, 'emergency');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
} else {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('没有获取到应急力量数据或返回码错误:', res);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
return res.data || [];
|
|
|
|
|
|
} catch (error) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('获取应急力量数据失败:', error);
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-28 09:20:54 +08:00
|
|
|
|
const dangerProjectData = ref([]);
|
|
|
|
|
|
// 获取危大工程数据
|
|
|
|
|
|
const getDangerProjectData = async flag => {
|
|
|
|
|
|
try {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 检查危大工程标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
if (hasProjectMarkersByType('engineering')) {
|
|
|
|
|
|
console.log('类型为 engineering 的标记已存在,跳过接口调用');
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-28 09:20:54 +08:00
|
|
|
|
const res = await request({
|
|
|
|
|
|
url: '/snow-ops-platform/dangerProjectInfo/listAll',
|
|
|
|
|
|
method: 'GET',
|
|
|
|
|
|
});
|
|
|
|
|
|
console.log('危大工程数据:', res);
|
|
|
|
|
|
if (res.code === '00000' && res.data) {
|
|
|
|
|
|
// 使用通用过滤方法处理数据
|
|
|
|
|
|
const filteredData = filterDataByCounty(res.data, flag, {
|
|
|
|
|
|
countyField: 'districtName',
|
|
|
|
|
|
coordinateParser: item => [item.longitude, item.latitude],
|
|
|
|
|
|
});
|
|
|
|
|
|
dangerProjectData.value = filteredData;
|
|
|
|
|
|
console.log('过滤后危大工程数据:', filteredData);
|
|
|
|
|
|
|
|
|
|
|
|
// 在地图上添加危大工程标记
|
|
|
|
|
|
console.log('开始添加危大工程标记...', filteredData);
|
|
|
|
|
|
addProjectMarkers(filteredData, engineeringIconIcon, 'engineering');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.warn('没有获取到危大工程数据或返回码错误:', res);
|
|
|
|
|
|
}
|
|
|
|
|
|
return res.data || [];
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取危大工程数据失败:', error);
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
// 风险点数据
|
|
|
|
|
|
const riskPointData = ref([]);
|
|
|
|
|
|
// 风险点统计数据
|
|
|
|
|
|
const riskPointStats = ref({
|
|
|
|
|
|
重大路外隐患点: 0,
|
|
|
|
|
|
重大路内隐患点: 0,
|
|
|
|
|
|
较大路外隐患点: 0,
|
|
|
|
|
|
较大路内隐患点: 0,
|
|
|
|
|
|
一般路内隐患点: 0,
|
|
|
|
|
|
一般路外隐患点: 0,
|
|
|
|
|
|
风险点总数: 0,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 获取风险点数据
|
|
|
|
|
|
const getRiskPointData = async (riskLevel, item) => {
|
|
|
|
|
|
try {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 根据风险等级和在红线内外确定类型键
|
|
|
|
|
|
let riskTypeKey = 'riskPoint';
|
|
|
|
|
|
if (riskLevel) {
|
|
|
|
|
|
if (riskLevel.includes('重大') && item.isWithinRedLine === '是') {
|
|
|
|
|
|
riskTypeKey = 'riskPoint-重大路内';
|
|
|
|
|
|
} else if (riskLevel.includes('重大') && item.isWithinRedLine === '否') {
|
|
|
|
|
|
riskTypeKey = 'riskPoint-重大路外';
|
|
|
|
|
|
} else if (riskLevel.includes('较大') && item.isWithinRedLine === '是') {
|
|
|
|
|
|
riskTypeKey = 'riskPoint-较大路内';
|
|
|
|
|
|
} else if (riskLevel.includes('较大') && item.isWithinRedLine === '否') {
|
|
|
|
|
|
riskTypeKey = 'riskPoint-较大路外';
|
|
|
|
|
|
} else if (riskLevel.includes('一般') && item.isWithinRedLine === '是') {
|
|
|
|
|
|
riskTypeKey = 'riskPoint-一般路内';
|
|
|
|
|
|
} else if (riskLevel.includes('一般') && item.isWithinRedLine === '否') {
|
|
|
|
|
|
riskTypeKey = 'riskPoint-一般路外';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查该类型的风险点标记是否已存在,如果存在则不加载接口
|
|
|
|
|
|
if (hasProjectMarkersByType(riskTypeKey)) {
|
|
|
|
|
|
console.log(`类型为 ${riskTypeKey} 的标记已存在,跳过接口调用`);
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const res = await request({
|
|
|
|
|
|
url: '/snow-ops-platform/risk-point',
|
|
|
|
|
|
method: 'GET',
|
|
|
|
|
|
params: {
|
|
|
|
|
|
riskLevel: riskLevel || '',
|
|
|
|
|
|
isWithinRedLine: item.isWithinRedLine,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
console.log('风险点数据:', res);
|
|
|
|
|
|
if (res.code === '00000' && res.data) {
|
|
|
|
|
|
// 解析坐标数据
|
|
|
|
|
|
res.data.forEach(item => {
|
|
|
|
|
|
item.COORDINATE_POINT = [item.GL1_LON, item.GL1_LAT];
|
|
|
|
|
|
});
|
|
|
|
|
|
riskPointData.value = res.data;
|
|
|
|
|
|
// 在地图上添加风险点标记
|
|
|
|
|
|
console.log('开始添加风险点标记...', res.data);
|
|
|
|
|
|
// 根据风险等级选择不同的图标
|
|
|
|
|
|
let iconUrl = hazardIconIcon1; // 默认使用一般路内隐患点图标
|
|
|
|
|
|
if (riskLevel) {
|
|
|
|
|
|
if (riskLevel.includes('重大') && item.isWithinRedLine === '是') {
|
|
|
|
|
|
iconUrl = hazardIconIcon5; // 重大路内隐患点
|
|
|
|
|
|
} else if (riskLevel.includes('重大') && item.isWithinRedLine === '否') {
|
|
|
|
|
|
iconUrl = hazardIconIcon6; // 重大路外隐患点
|
|
|
|
|
|
} else if (riskLevel.includes('较大') && item.isWithinRedLine === '是') {
|
|
|
|
|
|
iconUrl = hazardIconIcon3; // 较大路内隐患点
|
|
|
|
|
|
} else if (riskLevel.includes('较大') && item.isWithinRedLine === '否') {
|
|
|
|
|
|
iconUrl = hazardIconIcon4; // 较大路外隐患点
|
|
|
|
|
|
} else if (riskLevel.includes('一般') && item.isWithinRedLine === '是') {
|
|
|
|
|
|
iconUrl = hazardIconIcon1; // 一般路内隐患点
|
|
|
|
|
|
} else if (riskLevel.includes('一般') && item.isWithinRedLine === '否') {
|
|
|
|
|
|
iconUrl = hazardIconIcon2; // 一般路外隐患点
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
emit('riskPointStatsChange', {
|
|
|
|
|
|
riskLevel: riskLevel.substring(0, 2),
|
|
|
|
|
|
isWithinRedLine: item.isWithinRedLine,
|
|
|
|
|
|
value: riskPointData.value.length,
|
|
|
|
|
|
});
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 给数据添加风险等级和在红线内外字段,确保 addProjectMarkers 能正确识别类型键
|
|
|
|
|
|
const dataWithRiskInfo = riskPointData.value.map(riskItem => ({
|
|
|
|
|
|
...riskItem,
|
|
|
|
|
|
riskLevel: riskLevel,
|
|
|
|
|
|
isWithinRedLine: item.isWithinRedLine
|
|
|
|
|
|
}));
|
|
|
|
|
|
addProjectMarkers(dataWithRiskInfo, iconUrl, 'riskPoint');
|
2026-04-17 14:50:25 +08:00
|
|
|
|
// 获取风险点统计数据
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.warn('没有获取到风险点数据或返回码错误:', res);
|
|
|
|
|
|
}
|
|
|
|
|
|
return res.data || [];
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取风险点数据失败:', error);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 按类型存储项目标记,避免同类型重复刷新
|
|
|
|
|
|
// 格式: { 'road-高风险': [...], 'road-较高风险': [...], 'riskPoint-高风险': [...], ... }
|
|
|
|
|
|
let projectMarkersMap = new Map();
|
2026-04-08 18:47:57 +08:00
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 清除所有项目标记
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const clearProjectMarkers = () => {
|
2026-04-29 15:55:12 +08:00
|
|
|
|
projectMarkersMap.forEach((markers, type) => {
|
|
|
|
|
|
markers.forEach(marker => {
|
|
|
|
|
|
if (mapInstance) {
|
|
|
|
|
|
mapInstance.removeLayer(marker);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-04-29 15:55:12 +08:00
|
|
|
|
projectMarkersMap.clear();
|
2026-04-13 11:38:11 +08:00
|
|
|
|
clearCountyCardMarkers();
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭所有弹窗
|
|
|
|
|
|
mapInfoDialogVisible.value = false;
|
|
|
|
|
|
centerCardVisible.value = false;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 清除指定类型的项目标记
|
|
|
|
|
|
const clearProjectMarkersByType = (typeKey) => {
|
|
|
|
|
|
const markers = projectMarkersMap.get(typeKey);
|
|
|
|
|
|
if (markers) {
|
|
|
|
|
|
markers.forEach(marker => {
|
|
|
|
|
|
if (mapInstance) {
|
|
|
|
|
|
mapInstance.removeLayer(marker);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
projectMarkersMap.delete(typeKey);
|
|
|
|
|
|
console.log(`已清除类型为 ${typeKey} 的标记,共 ${markers.length} 个`);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 检查指定类型的项目标记是否已存在
|
|
|
|
|
|
const hasProjectMarkersByType = (typeKey) => {
|
|
|
|
|
|
const markers = projectMarkersMap.get(typeKey);
|
|
|
|
|
|
return markers && markers.length > 0;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
// 根据数据类型获取对应的图标
|
|
|
|
|
|
const getIconByType = (item, type) => {
|
|
|
|
|
|
// 如果是风险点类型,根据风险等级和是否在红线内返回对应图标
|
|
|
|
|
|
if (type === 'riskPoint' || item.riskLevel) {
|
|
|
|
|
|
const riskLevel = item.riskLevel || '';
|
|
|
|
|
|
const isWithinRedLine = item.isWithinRedLine || item.iswithinredline || '';
|
|
|
|
|
|
|
|
|
|
|
|
if (riskLevel.includes('重大')) {
|
|
|
|
|
|
return isWithinRedLine === '是' ? hazardIconIcon5 : hazardIconIcon6;
|
|
|
|
|
|
} else if (riskLevel.includes('较大')) {
|
|
|
|
|
|
return isWithinRedLine === '是' ? hazardIconIcon3 : hazardIconIcon4;
|
|
|
|
|
|
} else if (riskLevel.includes('一般')) {
|
|
|
|
|
|
return isWithinRedLine === '是' ? hazardIconIcon1 : hazardIconIcon2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是路段类型,根据风险等级返回对应图标
|
|
|
|
|
|
if (type === 'road' || item.riskLevel) {
|
|
|
|
|
|
const riskLevel = item.riskLevel || '';
|
|
|
|
|
|
if (riskLevel.includes('高风险')) {
|
|
|
|
|
|
return tunnelLineIcon3;
|
|
|
|
|
|
} else if (riskLevel.includes('较高风险')) {
|
|
|
|
|
|
return tunnelLineIcon2;
|
|
|
|
|
|
} else if (riskLevel.includes('中风险')) {
|
|
|
|
|
|
return tunnelLineIcon1;
|
|
|
|
|
|
} else if (riskLevel.includes('低风险')) {
|
|
|
|
|
|
return tunnelLineIcon;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 默认返回传入的图标或项目图标
|
|
|
|
|
|
return projectIcon;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 在地图上添加项目标记
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const addProjectMarkers = (data, iconUrl, type = 'project') => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
if (!mapInstance) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('mapInstance 未初始化,无法添加标记');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!data || data.length === 0) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('没有数据,无法添加标记');
|
2026-04-08 18:47:57 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 根据类型和等级生成类型键,用于区分不同类型的标记
|
|
|
|
|
|
// 例如: 'road-高风险', 'road-较高风险', 'riskPoint-高风险', 'project', 'tunnel', 'bridge'
|
|
|
|
|
|
let typeKey = type;
|
|
|
|
|
|
|
|
|
|
|
|
// 对于路段类型,从数据中解析风险等级
|
|
|
|
|
|
if (type === 'road' && data.length > 0) {
|
|
|
|
|
|
const riskLevel = data[0].GL1_FXDJ || data[0].riskLevel || '';
|
|
|
|
|
|
if (riskLevel) {
|
|
|
|
|
|
typeKey = `road-${riskLevel}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 对于风险点类型,从数据中解析风险等级和在红线内外
|
|
|
|
|
|
if (type === 'riskPoint' && data.length > 0) {
|
|
|
|
|
|
const riskLevel = data[0].GL1_FXDJ || data[0].riskLevel || '';
|
|
|
|
|
|
const isWithinRedLine = data[0].GL1_SFHXN || data[0].isWithinRedLine || '';
|
|
|
|
|
|
if (riskLevel) {
|
|
|
|
|
|
// 根据风险等级和在红线内外确定类型键
|
|
|
|
|
|
if (riskLevel.includes('重大') && isWithinRedLine === '是') {
|
|
|
|
|
|
typeKey = 'riskPoint-重大路内';
|
|
|
|
|
|
} else if (riskLevel.includes('重大') && isWithinRedLine === '否') {
|
|
|
|
|
|
typeKey = 'riskPoint-重大路外';
|
|
|
|
|
|
} else if (riskLevel.includes('较大') && isWithinRedLine === '是') {
|
|
|
|
|
|
typeKey = 'riskPoint-较大路内';
|
|
|
|
|
|
} else if (riskLevel.includes('较大') && isWithinRedLine === '否') {
|
|
|
|
|
|
typeKey = 'riskPoint-较大路外';
|
|
|
|
|
|
} else if (riskLevel.includes('一般') && isWithinRedLine === '是') {
|
|
|
|
|
|
typeKey = 'riskPoint-一般路内';
|
|
|
|
|
|
} else if (riskLevel.includes('一般') && isWithinRedLine === '否') {
|
|
|
|
|
|
typeKey = 'riskPoint-一般路外';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
typeKey = `riskPoint-${riskLevel}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果该类型的标记已存在,直接返回,避免重复渲染
|
|
|
|
|
|
if (hasProjectMarkersByType(typeKey)) {
|
|
|
|
|
|
console.log(`类型为 ${typeKey} 的标记已存在,跳过添加`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 存储新添加的标记
|
|
|
|
|
|
const newMarkers = [];
|
2026-04-08 18:47:57 +08:00
|
|
|
|
|
|
|
|
|
|
// 遍历数据添加标记
|
2026-04-17 14:50:25 +08:00
|
|
|
|
data.forEach(item => {
|
2026-04-21 15:34:43 +08:00
|
|
|
|
if (item && item.COORDINATE_POINT && item.COORDINATE_POINT.length == 2) {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// COORDINATE_POINT 格式: [经度, 纬度]
|
|
|
|
|
|
// Leaflet 需要: [纬度, 经度]
|
|
|
|
|
|
const lng = item.COORDINATE_POINT[0];
|
|
|
|
|
|
const lat = item.COORDINATE_POINT[1];
|
|
|
|
|
|
|
|
|
|
|
|
const latNum = parseFloat(lat);
|
|
|
|
|
|
const lngNum = parseFloat(lng);
|
|
|
|
|
|
|
|
|
|
|
|
if (!isNaN(latNum) && !isNaN(lngNum)) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
// 根据数据类型获取对应的图标
|
|
|
|
|
|
const currentIconUrl = iconUrl || getIconByType(item, type);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建自定义图标
|
|
|
|
|
|
const projectIconObj = window.L.icon({
|
|
|
|
|
|
iconUrl: currentIconUrl,
|
|
|
|
|
|
iconSize: [35, 35],
|
|
|
|
|
|
iconAnchor: [10, 10],
|
|
|
|
|
|
popupAnchor: [0, -10],
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const marker = window.L.marker([latNum, lngNum], {
|
|
|
|
|
|
icon: projectIconObj,
|
2026-04-21 15:34:43 +08:00
|
|
|
|
zIndexOffset: 1000, // 提升图标层级,确保在地图其他元素之上
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 点击 marker 打开对应类型的信息弹窗
|
2026-04-17 14:50:25 +08:00
|
|
|
|
marker.on('click', () => {
|
|
|
|
|
|
if (type === 'riskPoint') {
|
|
|
|
|
|
// 风险点类型,触发父组件打开涉灾隐患点情况弹窗
|
|
|
|
|
|
emit('openHazardPointSituation', item);
|
2026-04-29 10:33:26 +08:00
|
|
|
|
} else if (type === 'road') {
|
|
|
|
|
|
// 路段类型,触发父组件打开路段情况弹窗
|
|
|
|
|
|
emit('openRoadSectionSituation', item);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
openMapInfoDialog(type, item);
|
|
|
|
|
|
}
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
marker.addTo(mapInstance);
|
2026-04-29 15:55:12 +08:00
|
|
|
|
newMarkers.push(marker);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
} else {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('无效的坐标:', item.COORDINATE_POINT, item);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('缺少坐标数据:', item);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-04-29 15:55:12 +08:00
|
|
|
|
// 将新标记存储到对应类型中
|
|
|
|
|
|
projectMarkersMap.set(typeKey, newMarkers);
|
|
|
|
|
|
console.log(`已添加 ${newMarkers.length} 个类型为 ${typeKey} 的标记`);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 确定主要预警颜色(出现最多的预警等级)
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const getMainWarningColor = levels => {
|
|
|
|
|
|
if (!levels || Object.keys(levels).length === 0) return '#1890ff'; // 默认蓝色
|
2026-04-08 15:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 预警等级优先级:红色 > 橙色 > 黄色 > 蓝色
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const priority = ['红色', '橙色', '黄色', '蓝色'];
|
2026-04-08 15:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 按数量排序
|
|
|
|
|
|
const sortedLevels = Object.entries(levels)
|
|
|
|
|
|
.map(([level, count]) => ({ level, count }))
|
|
|
|
|
|
.sort((a, b) => b.count - a.count);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有多个等级数量相同,按优先级排序
|
|
|
|
|
|
const maxCount = sortedLevels[0].count;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const maxLevels = sortedLevels.filter(item => item.count === maxCount);
|
2026-04-08 15:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
if (maxLevels.length === 1) {
|
|
|
|
|
|
return getColorByLevel(maxLevels[0].level);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 按优先级选择
|
|
|
|
|
|
for (const level of priority) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (maxLevels.some(item => item.level === level)) {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
return getColorByLevel(level);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return getColorByLevel(maxLevels[0].level);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 统计各区县的预警数量(按预警等级区分)
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const countWarningsByCounty = data => {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
if (!data || !Array.isArray(data)) return {};
|
|
|
|
|
|
|
|
|
|
|
|
const stats = {};
|
2026-04-17 14:50:25 +08:00
|
|
|
|
data.forEach(item => {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 根据实际数据结构调整字段名
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const rawCountyName = item.countyName || item.name || item.qxmc || item.gl1Qxmc;
|
|
|
|
|
|
const riskLevel = item.riskLevel || item.level || item.warningLevel || item.gl1Yjdj;
|
2026-04-08 15:34:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 简化区县名称
|
|
|
|
|
|
const countyName = simplifyDistrictName(rawCountyName);
|
|
|
|
|
|
|
|
|
|
|
|
if (countyName) {
|
|
|
|
|
|
if (!stats[countyName]) {
|
|
|
|
|
|
stats[countyName] = {
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
levels: {},
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统计总数
|
|
|
|
|
|
stats[countyName].total += 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 按预警等级统计
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const level = riskLevel || '未知';
|
2026-04-08 15:34:49 +08:00
|
|
|
|
if (stats[countyName].levels[level]) {
|
|
|
|
|
|
stats[countyName].levels[level] += 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
stats[countyName].levels[level] = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 合并渝北区和江北区为两江新区
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (stats['渝北区'] || stats['江北区']) {
|
|
|
|
|
|
const yubeiData = stats['渝北区'] || {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
total: 0,
|
|
|
|
|
|
levels: {},
|
|
|
|
|
|
};
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const jiangbeiData = stats['江北区'] || {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
total: 0,
|
|
|
|
|
|
levels: {},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 合并总数
|
|
|
|
|
|
const total = yubeiData.total + jiangbeiData.total;
|
|
|
|
|
|
|
|
|
|
|
|
// 合并各等级预警数量
|
|
|
|
|
|
const levels = { ...yubeiData.levels };
|
|
|
|
|
|
Object.entries(jiangbeiData.levels).forEach(([level, count]) => {
|
|
|
|
|
|
if (levels[level]) {
|
|
|
|
|
|
levels[level] += count;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
levels[level] = count;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 创建两江新区数据
|
2026-04-17 14:50:25 +08:00
|
|
|
|
stats['两江新区'] = {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
total,
|
|
|
|
|
|
levels,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 删除渝北区和江北区
|
2026-04-17 14:50:25 +08:00
|
|
|
|
delete stats['渝北区'];
|
|
|
|
|
|
delete stats['江北区'];
|
2026-04-08 15:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为数组格式并按总数排序(数量从大到小)
|
|
|
|
|
|
const sortedList = Object.entries(stats)
|
|
|
|
|
|
.map(([name, data]) => ({
|
2026-04-21 15:34:43 +08:00
|
|
|
|
name: name.substring(0, 2),
|
2026-04-08 15:34:49 +08:00
|
|
|
|
total: data.total,
|
|
|
|
|
|
levels: data.levels,
|
|
|
|
|
|
}))
|
|
|
|
|
|
.sort((a, b) => b.total - a.total);
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
byName: stats, // 对象格式:{ 区县名: { total: 总数, levels: { 等级: 数量 } } }
|
|
|
|
|
|
sortedList: sortedList, // 数组格式:[{ name: 区县名, total: 总数, levels: { 等级: 数量 } }]
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 重庆地图 GeoJSON API 地址 - 使用最新版本
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const GEOJSON_URL = 'https://geo.datav.aliyun.com/areas_v3/bound/500000_full.json';
|
2026-03-31 18:10:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载地图数据
|
|
|
|
|
|
const loadMapData = async () => {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
loading.value = true;
|
|
|
|
|
|
error.value = null;
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
try {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 初始化地图
|
|
|
|
|
|
|
2026-04-03 18:08:42 +08:00
|
|
|
|
// 检查URL参数中是否有Map=dev
|
|
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const isDev = urlParams.get('Map') === 'dev';
|
2026-04-08 15:34:49 +08:00
|
|
|
|
|
2026-04-03 18:08:42 +08:00
|
|
|
|
let geoJsonData;
|
2026-04-08 15:34:49 +08:00
|
|
|
|
|
2026-04-03 18:08:42 +08:00
|
|
|
|
if (isDev) {
|
|
|
|
|
|
// 本地测试用
|
2026-04-08 15:34:49 +08:00
|
|
|
|
const response = await fetch(GEOJSON_URL);
|
2026-04-03 18:08:42 +08:00
|
|
|
|
if (!response.ok) {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
2026-04-03 18:08:42 +08:00
|
|
|
|
}
|
2026-04-08 15:34:49 +08:00
|
|
|
|
geoJsonData = await response.json();
|
2026-04-03 18:08:42 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 部署用
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const response = await axios.get('/aliyun-geo/bound/500000_full.json');
|
2026-04-03 18:08:42 +08:00
|
|
|
|
geoJsonData = response.data;
|
|
|
|
|
|
if (!geoJsonData) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
throw new Error('地图数据为空');
|
2026-04-03 18:08:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
|
|
|
|
|
// // 处理行政区划变更:渝北区和江北区合并为两江新区
|
|
|
|
|
|
processDistrictMerge(geoJsonData);
|
2026-04-08 15:34:49 +08:00
|
|
|
|
initMap(geoJsonData);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
} catch (err) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('加载地图数据失败:', err);
|
|
|
|
|
|
error.value = '地图数据加载失败,请检查网络连接';
|
2026-03-31 18:10:34 +08:00
|
|
|
|
} finally {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
loading.value = false;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理行政区划合并
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const processDistrictMerge = geoJsonData => {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
if (!geoJsonData || !geoJsonData.features) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 查找渝北区和江北区的特征
|
|
|
|
|
|
const yubeiIndex = geoJsonData.features.findIndex(
|
2026-04-17 14:50:25 +08:00
|
|
|
|
f => f.properties && f.properties.name === '渝北区'
|
2026-04-02 16:35:45 +08:00
|
|
|
|
);
|
|
|
|
|
|
const jiangbeiIndex = geoJsonData.features.findIndex(
|
2026-04-17 14:50:25 +08:00
|
|
|
|
f => f.properties && f.properties.name === '江北区'
|
2026-04-02 16:35:45 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果两个区都存在,合并为两江新区
|
|
|
|
|
|
if (yubeiIndex !== -1 && jiangbeiIndex !== -1) {
|
|
|
|
|
|
const yubeiFeature = geoJsonData.features[yubeiIndex];
|
|
|
|
|
|
const jiangbeiFeature = geoJsonData.features[jiangbeiIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// 创建两江新区的特征
|
|
|
|
|
|
const liangjiangFeature = JSON.parse(JSON.stringify(yubeiFeature));
|
2026-04-17 14:50:25 +08:00
|
|
|
|
liangjiangFeature.properties.name = '两江新区';
|
|
|
|
|
|
liangjiangFeature.properties.adcode = '500006'; // 使用新的行政区划代码
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 如果是 MultiPolygon,合并两个区的坐标
|
|
|
|
|
|
if (
|
2026-04-17 14:50:25 +08:00
|
|
|
|
yubeiFeature.geometry.type === 'MultiPolygon' &&
|
|
|
|
|
|
jiangbeiFeature.geometry.type === 'MultiPolygon'
|
2026-04-02 16:35:45 +08:00
|
|
|
|
) {
|
|
|
|
|
|
liangjiangFeature.geometry.coordinates = [
|
|
|
|
|
|
...yubeiFeature.geometry.coordinates,
|
|
|
|
|
|
...jiangbeiFeature.geometry.coordinates,
|
|
|
|
|
|
];
|
|
|
|
|
|
} else if (
|
2026-04-17 14:50:25 +08:00
|
|
|
|
yubeiFeature.geometry.type === 'Polygon' &&
|
|
|
|
|
|
jiangbeiFeature.geometry.type === 'Polygon'
|
2026-04-02 16:35:45 +08:00
|
|
|
|
) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
liangjiangFeature.geometry.type = 'MultiPolygon';
|
2026-04-02 16:35:45 +08:00
|
|
|
|
liangjiangFeature.geometry.coordinates = [
|
|
|
|
|
|
[yubeiFeature.geometry.coordinates],
|
|
|
|
|
|
[jiangbeiFeature.geometry.coordinates],
|
|
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除原来的两个区
|
|
|
|
|
|
geoJsonData.features.splice(Math.max(yubeiIndex, jiangbeiIndex), 1);
|
|
|
|
|
|
geoJsonData.features.splice(Math.min(yubeiIndex, jiangbeiIndex), 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加合并后的两江新区
|
|
|
|
|
|
geoJsonData.features.push(liangjiangFeature);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 计算区县中心点
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const getCentroid = coordinates => {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
let sumLat = 0;
|
|
|
|
|
|
let sumLng = 0;
|
|
|
|
|
|
let count = 0;
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const processCoordinates = coords => {
|
|
|
|
|
|
if (typeof coords[0] === 'number') {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 单个坐标点 [lng, lat]
|
|
|
|
|
|
sumLng += coords[0];
|
|
|
|
|
|
sumLat += coords[1];
|
|
|
|
|
|
count++;
|
|
|
|
|
|
} else if (Array.isArray(coords[0])) {
|
|
|
|
|
|
// 坐标数组
|
|
|
|
|
|
coords.forEach(processCoordinates);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
processCoordinates(coordinates);
|
|
|
|
|
|
|
|
|
|
|
|
return count > 0 ? [sumLat / count, sumLng / count] : null;
|
|
|
|
|
|
};
|
2026-03-31 18:10:34 +08:00
|
|
|
|
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 简化区县名称
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const simplifyDistrictName = name => {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
const nameMap = {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
酉阳土家族苗族自治县: '酉阳县',
|
|
|
|
|
|
秀山土家族苗族自治县: '秀山县',
|
|
|
|
|
|
彭水苗族土家族自治县: '彭水县',
|
|
|
|
|
|
石柱土家族自治县: '石柱县',
|
2026-04-08 15:34:49 +08:00
|
|
|
|
};
|
|
|
|
|
|
return nameMap[name] || name;
|
|
|
|
|
|
};
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 根据预警等级获取颜色
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const getColorByLevel = level => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
const colorMap = {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
红色预警: '#912210',
|
|
|
|
|
|
橙色预警: '#BA6527',
|
|
|
|
|
|
黄色预警: '#A47109',
|
|
|
|
|
|
蓝色预警: '#185A91',
|
|
|
|
|
|
未知: '#1890ff',
|
2026-04-08 18:47:57 +08:00
|
|
|
|
};
|
2026-04-17 14:50:25 +08:00
|
|
|
|
return colorMap[level] || '#1890ff';
|
2026-04-08 18:47:57 +08:00
|
|
|
|
};
|
2026-03-31 18:10:34 +08:00
|
|
|
|
// 初始化地图
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const initMap = geoJsonData => {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
if (!mapContainer.value) return;
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 清除旧地图实例
|
|
|
|
|
|
if (mapInstance) {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
mapInstance.remove();
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
// 创建地图实例
|
|
|
|
|
|
mapInstance = new window.L.Map(mapContainer.value, {
|
|
|
|
|
|
center: [29.563, 106.551], // 重庆中心坐标
|
2026-04-09 14:53:44 +08:00
|
|
|
|
zoom: 8,
|
2026-04-02 16:35:45 +08:00
|
|
|
|
minZoom: 6,
|
2026-03-31 18:10:34 +08:00
|
|
|
|
maxZoom: 18,
|
|
|
|
|
|
zoomControl: false,
|
2026-04-02 16:35:45 +08:00
|
|
|
|
attributionControl: false,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 添加瓦片图层 - 使用深色样式
|
2026-04-03 18:08:42 +08:00
|
|
|
|
// const tileLayer = new window.L.TileLayer(
|
|
|
|
|
|
// "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
|
|
|
|
|
|
// {
|
|
|
|
|
|
// attribution:
|
|
|
|
|
|
// '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
|
|
|
|
|
// subdomains: "abcd",
|
|
|
|
|
|
// maxZoom: 19,
|
|
|
|
|
|
// },
|
|
|
|
|
|
// );
|
|
|
|
|
|
// mapInstance.addLayer(tileLayer);
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加 GeoJSON 图层
|
|
|
|
|
|
geoJsonLayer = new window.L.GeoJSON(geoJsonData, {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
style: feature => {
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// const districtName = feature.properties.name;
|
|
|
|
|
|
const districtName = simplifyDistrictName(feature.properties.name);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
let fillColor = '#132C44'; // 默认深蓝色背景
|
2026-04-09 14:53:44 +08:00
|
|
|
|
let fillOpacity = 0.4; // 默认透明度更高(更透明)
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 如果有预警统计数据,应用主要预警颜色
|
|
|
|
|
|
if (
|
|
|
|
|
|
affectedCountyData.value &&
|
|
|
|
|
|
affectedCountyData.value.byName &&
|
|
|
|
|
|
affectedCountyData.value.byName[districtName]
|
|
|
|
|
|
) {
|
|
|
|
|
|
const districtData = affectedCountyData.value.byName[districtName];
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// console.log(districtData.levels);
|
2026-04-08 15:34:49 +08:00
|
|
|
|
fillColor = getMainWarningColor(districtData.levels);
|
2026-04-09 14:53:44 +08:00
|
|
|
|
fillOpacity = 1; // 有预警时稍微不透明一些
|
2026-04-08 15:34:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
fillColor: fillColor,
|
2026-04-09 14:53:44 +08:00
|
|
|
|
weight: 0.5,
|
|
|
|
|
|
opacity: 0.6,
|
2026-04-17 14:50:25 +08:00
|
|
|
|
color: '#00d4ff',
|
2026-04-09 14:53:44 +08:00
|
|
|
|
fillOpacity: fillOpacity,
|
2026-04-08 15:34:49 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
2026-03-31 18:10:34 +08:00
|
|
|
|
onEachFeature: (feature, layer) => {
|
|
|
|
|
|
if (feature.properties && feature.properties.name) {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 区县点击事件
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// layer.on("click", (e) => {
|
|
|
|
|
|
// // 清除之前选中的样式
|
|
|
|
|
|
// if (selectedLayer) {
|
|
|
|
|
|
// selectedLayer.setStyle({
|
|
|
|
|
|
// fillColor: "#1890ff",
|
|
|
|
|
|
// fillOpacity: 0.15,
|
|
|
|
|
|
// weight: 1.5,
|
|
|
|
|
|
// color: "#40a9ff",
|
|
|
|
|
|
// });
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // 设置当前选中样式
|
|
|
|
|
|
// layer.setStyle({
|
|
|
|
|
|
// fillColor: "#ff4d4f",
|
|
|
|
|
|
// fillOpacity: 0.6,
|
|
|
|
|
|
// weight: 2.5,
|
|
|
|
|
|
// color: "#ff7875",
|
|
|
|
|
|
// });
|
|
|
|
|
|
// selectedLayer = layer;
|
|
|
|
|
|
// selectedDistrict.value = feature.properties.name;
|
|
|
|
|
|
// // 触发事件
|
|
|
|
|
|
// emit("districtClick", {
|
|
|
|
|
|
// name: feature.properties.name,
|
|
|
|
|
|
// feature: feature,
|
|
|
|
|
|
// latlng: e.latlng,
|
|
|
|
|
|
// });
|
|
|
|
|
|
// // 平滑移动到点击位置
|
|
|
|
|
|
// mapInstance.panTo(e.latlng, { animate: true, duration: 0.5 });
|
|
|
|
|
|
// });
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 鼠标悬停效果
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// layer.on("mouseover", () => {
|
|
|
|
|
|
// layer.setStyle({
|
|
|
|
|
|
// fillColor: "#1890ff",
|
|
|
|
|
|
// fillOpacity: 0.4,
|
|
|
|
|
|
// weight: 2,
|
|
|
|
|
|
// color: "#69c0ff",
|
|
|
|
|
|
// });
|
|
|
|
|
|
// });
|
|
|
|
|
|
// layer.on("mouseout", () => {
|
|
|
|
|
|
// layer.setStyle({
|
|
|
|
|
|
// fillColor: "#1890ff",
|
|
|
|
|
|
// fillOpacity: 0.15,
|
|
|
|
|
|
// weight: 1.5,
|
|
|
|
|
|
// color: "#40a9ff",
|
|
|
|
|
|
// });
|
|
|
|
|
|
// });
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 添加 popup
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// layer.bindPopup(`<div class="map-popup">
|
|
|
|
|
|
// <strong>${feature.properties.name}</strong>
|
|
|
|
|
|
// </div>`);
|
2026-04-02 16:35:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
mapInstance.addLayer(geoJsonLayer);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加区县标签
|
2026-04-17 14:50:25 +08:00
|
|
|
|
geoJsonData.features.forEach(feature => {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
if (feature.properties && feature.properties.name) {
|
|
|
|
|
|
let centroid;
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (feature.geometry.type === 'Polygon') {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
centroid = getCentroid(feature.geometry.coordinates);
|
2026-04-17 14:50:25 +08:00
|
|
|
|
} else if (feature.geometry.type === 'MultiPolygon') {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 取第一个多边形的中心
|
|
|
|
|
|
centroid = getCentroid(feature.geometry.coordinates[0]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (centroid) {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
const displayName = simplifyDistrictName(feature.properties.name);
|
2026-04-02 16:35:45 +08:00
|
|
|
|
const label = window.L.divIcon({
|
2026-04-17 14:50:25 +08:00
|
|
|
|
className: 'district-label',
|
2026-04-08 15:34:49 +08:00
|
|
|
|
html: `<div class="label-content">${displayName}</div>`,
|
2026-04-02 16:35:45 +08:00
|
|
|
|
iconSize: [80, 30],
|
|
|
|
|
|
iconAnchor: [40, 15],
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-04-28 09:20:54 +08:00
|
|
|
|
const marker = window.L.marker(centroid, {
|
2026-04-21 15:34:43 +08:00
|
|
|
|
icon: label,
|
|
|
|
|
|
zIndexOffset: 500, // 提升标签层级
|
|
|
|
|
|
});
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// marker.on("click", (e) => {
|
|
|
|
|
|
// // 清除之前选中的样式
|
|
|
|
|
|
// if (selectedLayer) {
|
|
|
|
|
|
// selectedLayer.setStyle({
|
|
|
|
|
|
// fillColor: "#1E3A8A",
|
|
|
|
|
|
// fillOpacity: 0.3,
|
|
|
|
|
|
// weight: 2,
|
|
|
|
|
|
// });
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// // 找到对应的区县图层并设置样式
|
|
|
|
|
|
// geoJsonLayer.eachLayer((layer) => {
|
|
|
|
|
|
// if (
|
|
|
|
|
|
// layer.feature &&
|
|
|
|
|
|
// layer.feature.properties.name === feature.properties.name
|
|
|
|
|
|
// ) {
|
|
|
|
|
|
// layer.setStyle({
|
|
|
|
|
|
// fillColor: "#ff4d4f",
|
|
|
|
|
|
// fillOpacity: 0.6,
|
|
|
|
|
|
// weight: 2.5,
|
|
|
|
|
|
// color: "#ff7875",
|
|
|
|
|
|
// });
|
|
|
|
|
|
// selectedLayer = layer;
|
|
|
|
|
|
// selectedDistrict.value = feature.properties.name;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
|
|
// // 触发事件
|
|
|
|
|
|
// emit("districtClick", {
|
|
|
|
|
|
// name: feature.properties.name,
|
|
|
|
|
|
// feature: feature,
|
|
|
|
|
|
// latlng: e.latlng,
|
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
|
|
// // 平滑移动到点击位置
|
|
|
|
|
|
// mapInstance.panTo(e.latlng, { animate: true, duration: 0.5 });
|
|
|
|
|
|
// });
|
2026-04-02 16:35:45 +08:00
|
|
|
|
mapInstance.addLayer(marker);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
// 调整视图以适应重庆边界
|
2026-04-02 16:35:45 +08:00
|
|
|
|
mapInstance.fitBounds(geoJsonLayer.getBounds());
|
2026-03-31 18:10:34 +08:00
|
|
|
|
} catch (err) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.error('初始化地图失败:', err);
|
|
|
|
|
|
error.value = '地图初始化失败';
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
};
|
2026-03-31 18:10:34 +08:00
|
|
|
|
|
2026-04-15 16:40:35 +08:00
|
|
|
|
// 监听 activeitem 变化
|
2026-04-08 18:47:57 +08:00
|
|
|
|
watch(
|
2026-04-15 16:40:35 +08:00
|
|
|
|
() => props.activeitem,
|
2026-04-17 14:50:25 +08:00
|
|
|
|
async newVal => {
|
|
|
|
|
|
console.log('activeitem 变化:', newVal);
|
2026-04-15 16:40:35 +08:00
|
|
|
|
switch (newVal.label) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '涉灾隐患点':
|
|
|
|
|
|
// 点击涉灾隐患点时,获取所有风险点数据
|
|
|
|
|
|
await getRiskPointData();
|
2026-04-15 16:40:35 +08:00
|
|
|
|
break;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '项目':
|
2026-04-21 15:34:43 +08:00
|
|
|
|
await getAffectedProjectData(false);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
break;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '隧道':
|
2026-04-21 15:34:43 +08:00
|
|
|
|
await getAffectedTunnelData(false);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
break;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '边坡':
|
2026-04-15 16:40:35 +08:00
|
|
|
|
break;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '桥梁':
|
2026-04-21 15:34:43 +08:00
|
|
|
|
await getAffectedBridgeData(false);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
break;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '路段':
|
2026-04-21 15:34:43 +08:00
|
|
|
|
await getAffectedRoadSectionData(false);
|
2026-04-08 18:47:57 +08:00
|
|
|
|
break;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
case '队伍':
|
2026-04-09 14:53:44 +08:00
|
|
|
|
await getEmergencyForceData();
|
|
|
|
|
|
break;
|
2026-04-28 09:20:54 +08:00
|
|
|
|
case '危大工程':
|
|
|
|
|
|
await getDangerProjectData(false);
|
|
|
|
|
|
break;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-04-17 14:50:25 +08:00
|
|
|
|
{ immediate: false }
|
2026-04-08 18:47:57 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
// 处理隐患点点击事件
|
|
|
|
|
|
const handleHazardItemClick = async item => {
|
|
|
|
|
|
console.log('处理隐患点点击:', item);
|
|
|
|
|
|
// 根据隐患点类型映射风险等级
|
|
|
|
|
|
const riskLevelMap = {
|
|
|
|
|
|
重大路内隐患点: '重大隐患',
|
|
|
|
|
|
重大路外隐患点: '重大隐患',
|
|
|
|
|
|
较大路内隐患点: '较大隐患',
|
|
|
|
|
|
较大路外隐患点: '较大隐患',
|
|
|
|
|
|
一般路内隐患点: '一般隐患',
|
|
|
|
|
|
一般路外隐患点: '一般隐患',
|
|
|
|
|
|
};
|
|
|
|
|
|
const riskLevel = riskLevelMap[item.label] || '';
|
|
|
|
|
|
await getRiskPointData(riskLevel, item);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-09 14:53:44 +08:00
|
|
|
|
// 监听 dateRange 变化,重新加载数据
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => props.dateRange,
|
2026-04-13 16:38:07 +08:00
|
|
|
|
async (newVal, oldVal) => {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.log('dateRange 变化:', newVal, oldVal);
|
2026-04-13 16:38:07 +08:00
|
|
|
|
// 先重新加载受影响区县数据
|
2026-04-28 09:20:54 +08:00
|
|
|
|
clearProjectMarkers(); // 清除项目标记
|
|
|
|
|
|
|
2026-04-13 16:38:07 +08:00
|
|
|
|
await getAffectedCountyData();
|
2026-04-09 14:53:44 +08:00
|
|
|
|
},
|
2026-04-17 14:50:25 +08:00
|
|
|
|
{ deep: true }
|
2026-04-09 14:53:44 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
// 组件挂载时加载地图
|
|
|
|
|
|
onMounted(() => {
|
2026-04-08 15:34:49 +08:00
|
|
|
|
// 获取受影响对象数据
|
|
|
|
|
|
getAffectedCountyData();
|
|
|
|
|
|
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 检查 Leaflet 是否已加载
|
2026-04-17 14:50:25 +08:00
|
|
|
|
if (typeof window.L === 'undefined') {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 动态加载 Leaflet CSS 和 JS
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const link = document.createElement('link');
|
|
|
|
|
|
link.rel = 'stylesheet';
|
|
|
|
|
|
link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
|
|
|
|
|
|
link.integrity = 'sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=';
|
|
|
|
|
|
link.crossOrigin = '';
|
2026-04-02 16:35:45 +08:00
|
|
|
|
document.head.appendChild(link);
|
|
|
|
|
|
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const script = document.createElement('script');
|
|
|
|
|
|
script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
|
|
|
|
|
|
script.integrity = 'sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=';
|
|
|
|
|
|
script.crossOrigin = '';
|
2026-04-02 16:35:45 +08:00
|
|
|
|
script.onload = loadMapData;
|
|
|
|
|
|
document.head.appendChild(script);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
} else {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
loadMapData();
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
});
|
2026-03-31 18:10:34 +08:00
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理资源
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
if (mapInstance) {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
mapInstance.remove();
|
|
|
|
|
|
mapInstance = null;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
});
|
2026-04-08 18:47:57 +08:00
|
|
|
|
|
2026-04-13 11:38:11 +08:00
|
|
|
|
// 根据区县名称定位地图
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const locateToDistrict = countyName => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
if (!mapInstance || !geoJsonLayer) {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('地图未初始化,无法定位');
|
2026-04-13 11:38:11 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 简化区县名称
|
2026-04-17 14:50:25 +08:00
|
|
|
|
const simplifyName = name => {
|
2026-04-13 11:38:11 +08:00
|
|
|
|
return name
|
2026-04-17 14:50:25 +08:00
|
|
|
|
.replace('土家族苗族自治县', '')
|
|
|
|
|
|
.replace('苗族土家族自治县', '')
|
|
|
|
|
|
.replace('自治县', '')
|
|
|
|
|
|
.replace('区', '')
|
|
|
|
|
|
.replace('县', '');
|
2026-04-13 11:38:11 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const targetName = simplifyName(countyName);
|
|
|
|
|
|
|
|
|
|
|
|
// 查找对应的区县图层
|
|
|
|
|
|
let targetLayer = null;
|
2026-04-17 14:50:25 +08:00
|
|
|
|
geoJsonLayer.eachLayer(layer => {
|
|
|
|
|
|
const layerName = layer.feature?.properties?.name || '';
|
2026-04-13 11:38:11 +08:00
|
|
|
|
if (simplifyName(layerName) === targetName) {
|
|
|
|
|
|
targetLayer = layer;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (targetLayer) {
|
|
|
|
|
|
// 获取区县的中心点
|
|
|
|
|
|
const bounds = targetLayer.getBounds();
|
|
|
|
|
|
const center = bounds.getCenter();
|
|
|
|
|
|
|
|
|
|
|
|
// 移动地图到该中心点并放大
|
2026-04-16 14:03:39 +08:00
|
|
|
|
// mapInstance.setView(center, 10);
|
2026-04-13 11:38:11 +08:00
|
|
|
|
|
|
|
|
|
|
// 高亮显示该区县
|
|
|
|
|
|
if (selectedLayer) {
|
|
|
|
|
|
geoJsonLayer.resetStyle(selectedLayer);
|
|
|
|
|
|
}
|
2026-04-13 14:54:48 +08:00
|
|
|
|
// targetLayer.setStyle({
|
|
|
|
|
|
// fillColor: "#ff7a00",
|
|
|
|
|
|
// fillOpacity: 0.6,
|
|
|
|
|
|
// weight: 3,
|
|
|
|
|
|
// color: "#ff4d4f",
|
|
|
|
|
|
// });
|
2026-04-13 11:38:11 +08:00
|
|
|
|
selectedLayer = targetLayer;
|
|
|
|
|
|
} else {
|
2026-04-17 14:50:25 +08:00
|
|
|
|
console.warn('未找到区县:', countyName);
|
2026-04-13 11:38:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-04-08 18:47:57 +08:00
|
|
|
|
// 暴露方法给父组件调用
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
getEmergencyForceData,
|
|
|
|
|
|
clearProjectMarkers,
|
2026-04-13 11:38:11 +08:00
|
|
|
|
openCenterCard,
|
|
|
|
|
|
locateToDistrict,
|
2026-04-17 14:50:25 +08:00
|
|
|
|
handleHazardItemClick,
|
|
|
|
|
|
getRiskPointData,
|
2026-04-08 18:47:57 +08:00
|
|
|
|
});
|
2026-03-31 18:10:34 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
2026-04-02 16:35:45 +08:00
|
|
|
|
<style lang="scss">
|
|
|
|
|
|
// 区县标签样式(需要全局样式,因为 Leaflet 动态添加元素)
|
|
|
|
|
|
.district-label {
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
border: none !important;
|
|
|
|
|
|
|
|
|
|
|
|
.label-content {
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
padding: vw(4) vw(8);
|
|
|
|
|
|
border-radius: vw(2);
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
text-shadow:
|
|
|
|
|
|
0 1px 3px rgba(0, 0, 0, 0.8),
|
|
|
|
|
|
0 0 2px rgba(0, 0, 0, 0.5);
|
|
|
|
|
|
letter-spacing: 0.5px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
width: fit-content;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
color: #40a9ff;
|
|
|
|
|
|
text-shadow: 0 0 10px rgba(64, 169, 255, 0.8);
|
|
|
|
|
|
transform: scale(1.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
<style lang="scss" scoped>
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// 视频屏幕自适应 - 基于视口宽度动态调整
|
|
|
|
|
|
@function vw($px) {
|
|
|
|
|
|
@return calc($px / 1920 * 100vw);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
.chongqing-map-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.map-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading-overlay,
|
|
|
|
|
|
.error-overlay {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
background: rgba(0, 0, 0, 0.7);
|
|
|
|
|
|
z-index: 1000;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading-spinner {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
width: vw(40);
|
|
|
|
|
|
height: vw(40);
|
|
|
|
|
|
border: vw(4) solid #3b82f6;
|
|
|
|
|
|
border-top: vw(4) solid transparent;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
animation: spin 1s linear infinite;
|
2026-04-02 16:35:45 +08:00
|
|
|
|
margin-bottom: vw(10);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading-text {
|
|
|
|
|
|
color: #fff;
|
2026-04-02 16:35:45 +08:00
|
|
|
|
font-size: vw(14);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.error-text {
|
|
|
|
|
|
color: #ff6b6b;
|
2026-04-02 16:35:45 +08:00
|
|
|
|
font-size: vw(14);
|
|
|
|
|
|
margin-bottom: vw(10);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.retry-btn {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
background: #3b82f6;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
color: white;
|
|
|
|
|
|
border: none;
|
2026-04-02 16:35:45 +08:00
|
|
|
|
padding: vw(8) vw(16);
|
|
|
|
|
|
border-radius: vw(4);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
cursor: pointer;
|
2026-04-02 16:35:45 +08:00
|
|
|
|
font-size: vw(12);
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
&:hover {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
background: #2563eb;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@keyframes spin {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
0% {
|
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
100% {
|
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
|
}
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 16:35:45 +08:00
|
|
|
|
// Leaflet 地图样式覆盖
|
2026-03-31 18:10:34 +08:00
|
|
|
|
:deep(.leaflet-container) {
|
|
|
|
|
|
background: #0f1c2e !important;
|
2026-04-08 18:47:57 +08:00
|
|
|
|
.leaflet-popup {
|
|
|
|
|
|
left: -20px !important;
|
|
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
.leaflet-popup-content-wrapper {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
background: rgba(24, 144, 255, 0.95);
|
|
|
|
|
|
border-radius: vw(4);
|
|
|
|
|
|
padding: vw(6) vw(12);
|
|
|
|
|
|
min-width: vw(80);
|
|
|
|
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
|
|
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
.map-popup {
|
|
|
|
|
|
color: #fff;
|
2026-04-02 16:35:45 +08:00
|
|
|
|
font-size: vw(12);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
font-weight: 500;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
2026-03-31 18:10:34 +08:00
|
|
|
|
.leaflet-popup-tip {
|
2026-04-02 16:35:45 +08:00
|
|
|
|
background: rgba(24, 144, 255, 0.95);
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
|
|
|
|
|
|
.leaflet-popup-content {
|
|
|
|
|
|
width: max-content !important;
|
|
|
|
|
|
margin: vw(10) 10px vw(10) 0;
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 区县高亮样式
|
|
|
|
|
|
:deep(.leaflet-interactive) {
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
cursor: pointer;
|
2026-03-31 18:10:34 +08:00
|
|
|
|
}
|
2026-04-08 18:47:57 +08:00
|
|
|
|
|
|
|
|
|
|
.project-popup {
|
|
|
|
|
|
width: vw(120);
|
|
|
|
|
|
height: vw(20);
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
font-size: vw(12);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 15px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
2026-04-13 11:38:11 +08:00
|
|
|
|
|
|
|
|
|
|
// 区县卡片样式
|
|
|
|
|
|
:deep(.county-card-icon) {
|
|
|
|
|
|
background: transparent !important;
|
|
|
|
|
|
border: none !important;
|
|
|
|
|
|
|
2026-04-15 16:40:35 +08:00
|
|
|
|
// .center-info-card-container {
|
|
|
|
|
|
// width: 100%;
|
|
|
|
|
|
// min-width: 120px;
|
|
|
|
|
|
// }
|
2026-04-13 11:38:11 +08:00
|
|
|
|
|
|
|
|
|
|
.center-info-card {
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
box-shadow: 0 6px 20px rgba(24, 144, 255, 0.5);
|
|
|
|
|
|
filter: brightness(1.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-04-02 16:35:45 +08:00
|
|
|
|
</style>
|