|
@@ -0,0 +1,434 @@
|
|
|
+<template>
|
|
|
+ <div ref="containerRef" class="map-container">
|
|
|
+ <div id="aMap" class="map-container2"></div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts" name="Map">
|
|
|
+import { iconList } from '@/views/globalMap/data/mapData';
|
|
|
+import { useAMap } from '@/hooks/AMap/useAMap';
|
|
|
+import { useDrawTool } from '@/hooks/AMap/useDrawTool';
|
|
|
+import { getPointInfo, getPointInfoList } from '@/api/globalMap';
|
|
|
+import { getDictLabel } from '@/utils/dict';
|
|
|
+import { PointType } from '@/api/globalMap/type';
|
|
|
+import { getEmergencyExpertDetails } from '@/api/globalMap/spatialAnalysis';
|
|
|
+import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
|
|
|
+import useAppStore from '@/store/modules/app';
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ activeMap: string;
|
|
|
+ pointType: PointType[];
|
|
|
+}
|
|
|
+
|
|
|
+const props = withDefaults(defineProps<Props>(), {});
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
+const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
|
|
|
+const appStore = useAppStore();
|
|
|
+
|
|
|
+const emits = defineEmits([
|
|
|
+ 'update:drawing',
|
|
|
+ 'selectGraphics',
|
|
|
+ 'unSelectGraphics',
|
|
|
+ 'showTextEditBox',
|
|
|
+ 'onDrawCompleted',
|
|
|
+ 'handleShowVideo',
|
|
|
+ 'handleShowWarehouse'
|
|
|
+]);
|
|
|
+const containerRef = ref();
|
|
|
+
|
|
|
+const mapState = reactive({
|
|
|
+ center: [110.925175, 22],
|
|
|
+ zoom: 9,
|
|
|
+ minZoom: 6,
|
|
|
+ maxZoom: 20,
|
|
|
+ isThreeDimensional: false,
|
|
|
+ // 是否显示比例尺
|
|
|
+ showScale: true
|
|
|
+});
|
|
|
+
|
|
|
+let AMap, map, scale;
|
|
|
+
|
|
|
+// 鼠标绘制工具
|
|
|
+const drawTool = useDrawTool();
|
|
|
+// 初始化地图
|
|
|
+const mapUtils = useAMap({
|
|
|
+ key: '30d3d8448efd68cb0b284549fd41adcf', // 申请好的Web端开发者Key,首次调用 load 时必填
|
|
|
+ version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
|
|
|
+ pitch: mapState.isThreeDimensional ? 45 : 0,
|
|
|
+ zoom: mapState.zoom,
|
|
|
+ center: mapState.center,
|
|
|
+ dragEnable: true,
|
|
|
+ scrollWheel: true,
|
|
|
+ showScale: false,
|
|
|
+ enableMouseTool: true,
|
|
|
+ // 加载完成事件
|
|
|
+ onLoadCompleted: () => {
|
|
|
+ AMap = getAMap();
|
|
|
+ map = getMap();
|
|
|
+ scale = getScale();
|
|
|
+ if (!['logical', 'vectorgraph'].includes(props.activeMap)) {
|
|
|
+ switchMap(props.activeMap);
|
|
|
+ } else {
|
|
|
+ map.removeLayer();
|
|
|
+ }
|
|
|
+ map.on('zoomchange', zoomChangeHandler);
|
|
|
+ creatMask([{ strokeWeight: 2 }]);
|
|
|
+ drawTool.initMouseTool({ container: 'aMap', map, AMap });
|
|
|
+ handleResize();
|
|
|
+ getPointInfo('1').then((res) => {
|
|
|
+ const data = res.data && res.data.list ? res.data?.list : [];
|
|
|
+ data.forEach((item2) => {
|
|
|
+ // 获取图标
|
|
|
+ if (iconList[item2.dataType]) {
|
|
|
+ item2.icon = iconList[item2.dataType].image;
|
|
|
+ item2.image = iconList[item2.dataType].image;
|
|
|
+ item2.imageHover = iconList[item2.dataType].imageHover;
|
|
|
+ item2.size = iconList[item2.dataType].size;
|
|
|
+ }
|
|
|
+ item2.parentId = '1';
|
|
|
+ item2.dataType = '1';
|
|
|
+ if (item2.materia_name) {
|
|
|
+ item2.name = item2.materia_name;
|
|
|
+ }
|
|
|
+ item2.lnglat = [item2.longitude, item2.latitude];
|
|
|
+ });
|
|
|
+ mapUtils.addMarker(data);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onMarkerClick: (data) => {
|
|
|
+ // 多点位
|
|
|
+ if (data.type === '1') {
|
|
|
+ getPointInfoList({
|
|
|
+ option: '1',
|
|
|
+ longitude: data.longitude.toString(),
|
|
|
+ latitude: data.latitude.toString()
|
|
|
+ }).then((res) => {
|
|
|
+ const data2 = res.data.list;
|
|
|
+ let content = document.createElement('div');
|
|
|
+ content.className = 'point-info';
|
|
|
+ let content2 = '';
|
|
|
+ content2 += '<div class="title-box"><div class="gradient-text">多点位信息</div></div>';
|
|
|
+ content2 += '<div class="icon1"></div>';
|
|
|
+ content2 += '<div class="icon2"></div>';
|
|
|
+ content2 += '<div class="icon3"></div>';
|
|
|
+ content2 += '<div class="icon4"></div>';
|
|
|
+ content.innerHTML = content2;
|
|
|
+ let tableBox = document.createElement('div');
|
|
|
+ tableBox.className = 'table-box';
|
|
|
+ let table = document.createElement('div');
|
|
|
+ table.className = 'table';
|
|
|
+ table.innerHTML = '<div class="point-item"><div class="td3">主题</div><div class="td3">名称</div></div>';
|
|
|
+ data2.forEach((item) => {
|
|
|
+ item.longitude = data.longitude;
|
|
|
+ item.latitude = data.latitude;
|
|
|
+ const div = document.createElement('div');
|
|
|
+ div.className = 'point-item point-item-hover';
|
|
|
+ div.innerHTML =
|
|
|
+ '<div class="td4">' + getDictLabel(point_type.value, item.dataType.toString()) + '</div><div class="td4">' + item.name + '</div>';
|
|
|
+ div.addEventListener('click', () => {
|
|
|
+ handlePointDetails(item);
|
|
|
+ });
|
|
|
+ table.appendChild(div);
|
|
|
+ });
|
|
|
+ tableBox.appendChild(table);
|
|
|
+ content.appendChild(tableBox);
|
|
|
+ let closeBtn = document.createElement('div');
|
|
|
+ closeBtn.className = 'close';
|
|
|
+ closeBtn.onclick = hideInfo;
|
|
|
+ content.appendChild(closeBtn);
|
|
|
+ showInfo(content, [data.longitude, data.latitude], true);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ handlePointDetails(data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+const {
|
|
|
+ getAMap,
|
|
|
+ getMap,
|
|
|
+ switchMap,
|
|
|
+ addMarker,
|
|
|
+ addSearchMarker,
|
|
|
+ clearMarker,
|
|
|
+ getMarkers,
|
|
|
+ getScale,
|
|
|
+ showInfo,
|
|
|
+ hideInfo,
|
|
|
+ handleHover,
|
|
|
+ creatMask,
|
|
|
+ trackPlayback
|
|
|
+} = { ...mapUtils };
|
|
|
+const handlePointDetails = (data) => {
|
|
|
+ let methodList = {
|
|
|
+ '1': getEmergencyExpertDetails
|
|
|
+ };
|
|
|
+ let titleList = {
|
|
|
+ '1': '专家信息'
|
|
|
+ };
|
|
|
+ let method = methodList[data.dataType];
|
|
|
+ let title = !!titleList[data.dataType] ? titleList[data.dataType] : '信息';
|
|
|
+ if (!method) return;
|
|
|
+ method(data.id).then((res) => {
|
|
|
+ if (!!pointDetailTemplate[data.dataType]) {
|
|
|
+ let div = document.createElement('div');
|
|
|
+ div.className = 'point-info';
|
|
|
+ let titleDom = document.createElement('div');
|
|
|
+ titleDom.className = 'title-box';
|
|
|
+ titleDom.innerHTML = '<div class="gradient-text">' + title + '</div></div>';
|
|
|
+ div.appendChild(titleDom);
|
|
|
+ if (data.dataType === 2) {
|
|
|
+ let btnBox = document.createElement('div');
|
|
|
+ let btn = document.createElement('div');
|
|
|
+ btnBox.className = 'flex';
|
|
|
+ btn.className = 'btn';
|
|
|
+ btn.innerHTML = '<div class="video-icon"></div><div>物资详情</div>';
|
|
|
+ btn.onclick = () => {
|
|
|
+ emits('handleShowWarehouse', data);
|
|
|
+ };
|
|
|
+ btnBox.appendChild(btn);
|
|
|
+ div.appendChild(btnBox);
|
|
|
+ } else if (data.dataType === 4) {
|
|
|
+ let btnBox = document.createElement('div');
|
|
|
+ let btn = document.createElement('div');
|
|
|
+ btnBox.className = 'flex';
|
|
|
+ btn.className = 'btn';
|
|
|
+ btn.innerHTML = '<div class="video-icon"></div><div>附近视频</div>';
|
|
|
+ btn.onclick = () => {
|
|
|
+ emits('handleShowVideo', data);
|
|
|
+ };
|
|
|
+ btnBox.appendChild(btn);
|
|
|
+ div.appendChild(btnBox);
|
|
|
+ }
|
|
|
+ let icon1 = document.createElement('div');
|
|
|
+ icon1.className = 'icon1';
|
|
|
+ let icon2 = document.createElement('div');
|
|
|
+ icon2.className = 'icon2';
|
|
|
+ let icon3 = document.createElement('div');
|
|
|
+ icon3.className = 'icon3';
|
|
|
+ let icon4 = document.createElement('div');
|
|
|
+ icon4.className = 'icon4';
|
|
|
+ div.appendChild(icon1);
|
|
|
+ div.appendChild(icon2);
|
|
|
+ div.appendChild(icon3);
|
|
|
+ div.appendChild(icon4);
|
|
|
+ let table = document.createElement('div');
|
|
|
+ table.className = 'table-box';
|
|
|
+ let content = '';
|
|
|
+ content += '<div class="table">';
|
|
|
+ const newData = filterTd(res.rows[0], data.dataType);
|
|
|
+ newData.forEach((item) => {
|
|
|
+ if (item.type === 'shortText') {
|
|
|
+ content += '<div class="tr">';
|
|
|
+ item.data.forEach((item2) => {
|
|
|
+ content += '<div class="point-item">';
|
|
|
+ content += '<div class="td1">' + item2.label + '</div><div class="td2">' + item2.value + '</div>';
|
|
|
+ content += '</div>';
|
|
|
+ });
|
|
|
+ content += '</div>';
|
|
|
+ } else {
|
|
|
+ content += '<div class="point-item2">';
|
|
|
+ content += '<div class="td1">' + item.data[0].label + '</div><div class="td2">' + item.data[0].value + '</div>';
|
|
|
+ content += '</div>';
|
|
|
+ }
|
|
|
+ });
|
|
|
+ content += '</div>';
|
|
|
+ table.innerHTML = content;
|
|
|
+ div.appendChild(table);
|
|
|
+ let closeBtn = document.createElement('div');
|
|
|
+ closeBtn.className = 'close';
|
|
|
+ closeBtn.onclick = hideInfo;
|
|
|
+ div.appendChild(closeBtn);
|
|
|
+ showInfo(div, [data.longitude, data.latitude], true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+const filterTd = (obj, dataType) => {
|
|
|
+ let data = [];
|
|
|
+ let tempData = {};
|
|
|
+ let i = 0;
|
|
|
+ for (let key in obj) {
|
|
|
+ let keyLabel = pointDetailTemplate[dataType][key];
|
|
|
+ if (!!keyLabel) {
|
|
|
+ if (i === 2) {
|
|
|
+ i = 0;
|
|
|
+ }
|
|
|
+ const value = !!obj[key] ? obj[key] : '';
|
|
|
+ if (value && value.length > 8) {
|
|
|
+ if (i === 0) {
|
|
|
+ data.push({ type: 'longText', data: [{ label: keyLabel, value: value }] });
|
|
|
+ i = 0;
|
|
|
+ } else {
|
|
|
+ tempData = { type: 'longText', data: [{ label: keyLabel, value: value }] };
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (i === 0) {
|
|
|
+ data.push({ type: 'shortText', data: [{ label: keyLabel, value: value }] });
|
|
|
+ } else {
|
|
|
+ data[data.length - 1].data.push({ label: keyLabel, value: value });
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ if (!!tempData && JSON.stringify(tempData) !== '{}') {
|
|
|
+ data.push(tempData);
|
|
|
+ tempData = {};
|
|
|
+ i = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!!tempData && JSON.stringify(tempData) !== '{}') {
|
|
|
+ data.push(tempData);
|
|
|
+ }
|
|
|
+ if (data[data.length - 1].data && data[data.length - 1].data.length === 1 && data[data.length - 1].type === 'shortText') {
|
|
|
+ data[data.length - 1].data[1] = { label: '', value: '' };
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+};
|
|
|
+// 监听地图类型变化
|
|
|
+watch(
|
|
|
+ () => props.activeMap,
|
|
|
+ (value, oldValue) => {
|
|
|
+ switchMap(props.activeMap);
|
|
|
+ }
|
|
|
+);
|
|
|
+// 缩放级别变化
|
|
|
+const zoomChangeHandler = () => {
|
|
|
+ mapState.zoom = map.getZoom();
|
|
|
+};
|
|
|
+
|
|
|
+const setCenter = (item) => {
|
|
|
+ map.setCenter([item.longitude, item.latitude]);
|
|
|
+};
|
|
|
+
|
|
|
+defineExpose({ addMarker, addSearchMarker, setCenter, getMarkers, clearMarker, getMap, drawTool, handleHover, trackPlayback });
|
|
|
+const handleResize = () => {
|
|
|
+ map.resize();
|
|
|
+};
|
|
|
+watch(
|
|
|
+ () => appStore.showLeftSection,
|
|
|
+ () => {
|
|
|
+ nextTick(() => {
|
|
|
+ handleResize();
|
|
|
+ });
|
|
|
+ }
|
|
|
+);
|
|
|
+watch(
|
|
|
+ () => appStore.showRightSection,
|
|
|
+ () => {
|
|
|
+ nextTick(() => {
|
|
|
+ handleResize();
|
|
|
+ });
|
|
|
+ }
|
|
|
+);
|
|
|
+onMounted(() => {
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
+});
|
|
|
+// 卸载事件
|
|
|
+onUnmounted(() => {
|
|
|
+ if (map) {
|
|
|
+ map.off('zoomchange', zoomChangeHandler);
|
|
|
+ }
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import '@/components/Map/map.scss';
|
|
|
+.map-container2 {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.map-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ .zoom-text {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 52px;
|
|
|
+ right: 80px;
|
|
|
+ color: #eaf3fc;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ .right-tool {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 90px;
|
|
|
+ right: 0px;
|
|
|
+ z-index: 2;
|
|
|
+ }
|
|
|
+ .model-btn {
|
|
|
+ background-color: #04327c;
|
|
|
+ font-size: 12px;
|
|
|
+ font-family: 'SourceHanSansCN';
|
|
|
+ border: 1px solid #91cfff;
|
|
|
+ color: #eaf3fc;
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 3px 3px;
|
|
|
+ border-radius: 5px;
|
|
|
+ }
|
|
|
+ .ruler-icon {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ background: url('@/assets/images/map/ruler.png') no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ :deep(.amap-scalecontrol) {
|
|
|
+ left: unset !important;
|
|
|
+ background-color: unset !important;
|
|
|
+ right: 62px;
|
|
|
+ bottom: 55px !important;
|
|
|
+ }
|
|
|
+ :deep(.amap-scale-text) {
|
|
|
+ text-align: left !important;
|
|
|
+ padding-left: 20px;
|
|
|
+ color: #eaf3fc;
|
|
|
+ font-size: vw(32);
|
|
|
+ font-family: 'SourceHanSansCN';
|
|
|
+ }
|
|
|
+ :deep(.amap-scale-edgeleft),
|
|
|
+ :deep(.amap-scale-middle),
|
|
|
+ :deep(.amap-scale-edgeright) {
|
|
|
+ border: 1px solid #bfe1fc !important;
|
|
|
+ background: transparent !important;
|
|
|
+ }
|
|
|
+ :deep(.amap-logo),
|
|
|
+ :deep(.amap-copyright) {
|
|
|
+ display: none !important;
|
|
|
+ }
|
|
|
+ /* 自定义测距工具样式 */
|
|
|
+ :deep(.amap-ranger) {
|
|
|
+ background-color: #ffffff;
|
|
|
+ border: 1px solid #888888;
|
|
|
+ border-radius: 5px;
|
|
|
+ padding: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.amap-ranger .amap-toolbar) {
|
|
|
+ color: #333;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.amap-ranger .amap-toolbar button) {
|
|
|
+ background-color: #022577;
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 5px;
|
|
|
+ margin-right: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.amap-ranger .amap-toolbar button:hover) {
|
|
|
+ background-color: #1a3c75;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.amap-ranger .amap-toolbar .amap-toolbar-text) {
|
|
|
+ color: #444;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ :deep(.amap-marker) {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|