<template>
|
<div class="h-[60vh] relative">
|
<!-- 原始地图容器 -->
|
<div v-show="!isFullscreen" ref="containerRef" class="h-full"></div>
|
|
<!-- 全屏按钮 -->
|
<div class="absolute right-2 top-2 cursor-pointer" @click="toggleFullScreen">
|
<el-tooltip :content="isFullscreen ? '退出全屏' : '全屏展开'" placement="top">
|
<div class="ywifont text-[20px] text-black rounded-lg ywicon-fullscreen"></div>
|
</el-tooltip>
|
</div>
|
|
<!-- Teleport 全屏地图 -->
|
<Teleport to=".layout-parent">
|
<Transition name="fullscreen">
|
<div v-if="isFullscreen" class="absolute inset-0 z-50 w-full h-full">
|
<div ref="fullscreenContainerRef" class="w-full h-full"></div>
|
<div class="absolute right-2 top-2 cursor-pointer" @click="toggleFullScreen">
|
<el-tooltip content="退出全屏" placement="top">
|
<div class="ywifont text-[20px] text-black rounded-lg ywicon-tuichuquanping"></div>
|
</el-tooltip>
|
</div>
|
<div class="absolute bottom-0 w-full">
|
<EquipCurve
|
v-model:isShow="chartDlgIsShow"
|
class=" opacity-90"
|
:data="equipCurveMapRow"
|
:quotaChartCol="data?.quota_chart?.col"
|
height="15rem"
|
:tableHeight="240"
|
/>
|
</div>
|
</div>
|
</Transition>
|
</Teleport>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { onMounted, ref, nextTick, onDeactivated } from 'vue';
|
|
import equipPic from './img/equip.svg';
|
import equipSelectPic from './img/equip-select.svg';
|
|
import type { GaoDePosition, LabelMarkerData } from '/@/model/map/GaoDeMap';
|
import { GaoDeMap } from '/@/model/map/GaoDeMap';
|
import EquipCurve from '../components/EquipCurve.vue';
|
let gaoDeMap = new GaoDeMap();
|
const containerRef = ref<HTMLDivElement>(null);
|
const fullscreenContainerRef = ref<HTMLDivElement>(null);
|
const isFullscreen = ref(false);
|
const props = defineProps(['data']);
|
|
const emit = defineEmits(['equipClick', 'closeInfoWindow']);
|
const createInfoWindow = () => {
|
// title
|
// <div class="title flex-center bg-[#ca0dab] text-white py-0.5 mb-2 w-full over-ellipsis">
|
// 罗汉鱼
|
// </div>
|
const dom = `<div class="rounded-md text-nowrap flex flex-col w-fit border border-solid border-blue-600 relative" style="padding: 12px">
|
<span class="guanbi absolute ywifont ywicon-guanbi right-[4px] top-[-2px] font-bold text-[#c3c3c3] cursor-pointer" ></span>
|
|
<div class="space-x-4 flex w-full">
|
<div class="flex flex-col w-1/2 key-list">
|
|
</div>
|
|
<div class="flex flex-col w-1/2 value-list">
|
|
</div>
|
</div>
|
</div>`;
|
|
return dom;
|
};
|
|
const updateInfoWindow = (item) => {
|
const cellHeight = '20px';
|
const keyListDom = infoWindow.dom.querySelector('.key-list');
|
const valueListDom = infoWindow.dom.querySelector('.value-list');
|
|
const colsArray = props.data.cols ?? [];
|
const keyItemHtml = colsArray
|
.map((col) => {
|
return `<span class="flex-items-center justify-start text-gray-600" style="height:${cellHeight}">${col.title ?? ''}</span>`;
|
})
|
.join('');
|
|
const valueItemHtml = colsArray
|
.map((col, index) => {
|
return `<span class="flex-items-center justify-end text-black" style="height:${cellHeight}">${item[index] ?? ''}</span>`;
|
})
|
.join('');
|
|
keyListDom.innerHTML = keyItemHtml;
|
valueListDom.innerHTML = valueItemHtml;
|
};
|
let curMarkerLabel: AMap.LabelMarker;
|
const addMarkerLayer = () => {
|
const map = props.data.map;
|
if (map.pos_x == null && map.pos_y == null) return;
|
|
const dataList = (props.data?.values ?? []).map((item) => {
|
const x = item[map.pos_x];
|
const y = item[map.pos_y];
|
|
return {
|
position: [x, y],
|
// textColor: item.color,
|
extData: item,
|
title: item.title,
|
};
|
});
|
gaoDeMap.addMarkerLayer(dataList, {
|
markerOpt: {
|
icon: {
|
url: equipPic,
|
size: 30,
|
selectUrl: equipSelectPic,
|
},
|
click(e, label) {
|
curMarkerLabel && curMarkerLabel !== label && restoreLabel();
|
curMarkerLabel = label;
|
infoWindow.open(gaoDeMap.map, label.getPosition() as any);
|
const extData = label.getExtData();
|
if (isFullscreen.value) {
|
showCurve(extData);
|
} else {
|
emit('equipClick', extData);
|
}
|
label.setRank(999);
|
|
updateInfoWindow(extData);
|
},
|
},
|
layerOpt: {
|
// allowCollision:false
|
},
|
});
|
};
|
|
const bottomBarIsShow = ref(false);
|
const chartIsShow = ref(true);
|
const toggleShowChart = () => {
|
chartIsShow.value = !chartIsShow.value;
|
};
|
|
let infoWindow: AMap.InfoWindow;
|
const restoreLabel = () => {
|
// 关闭恢复图片
|
curMarkerLabel?.setIcon({
|
image: equipPic,
|
});
|
curMarkerLabel?.setRank(1);
|
};
|
|
// 初始化信息窗口
|
const initInfoWindow = () => {
|
infoWindow = new AMap.InfoWindow({
|
content: createInfoWindow(),
|
anchor: 'top-left',
|
closeWhenClickMap: true,
|
});
|
|
(infoWindow as any).on('close', () => {
|
restoreLabel();
|
curMarkerLabel = null;
|
if (isFullscreen.value) {
|
closeChartDlg();
|
} else {
|
emit('closeInfoWindow');
|
}
|
});
|
|
// 自带关闭去掉,自带关闭监听 close 会多次触发 close 事件
|
const closeBtnDom = infoWindow.dom.querySelector('.amap-info-close');
|
closeBtnDom.remove();
|
const myCloseBtn = infoWindow.dom.querySelector('.guanbi');
|
myCloseBtn.addEventListener('click', () => {
|
infoWindow.close();
|
});
|
};
|
|
// 切换全屏
|
const toggleFullScreen = async () => {
|
isFullscreen.value = !isFullscreen.value;
|
|
// 等待 DOM 更新完成
|
await nextTick();
|
// 重新初始化地图
|
if (isFullscreen.value) {
|
await initMap(fullscreenContainerRef.value);
|
} else {
|
// await initMap(containerRef.value);
|
}
|
};
|
|
// 初始化地图
|
const initMap = async (container: HTMLDivElement) => {
|
// 销毁旧实例
|
// gaoDeMap.map?.destroy();
|
gaoDeMap = new GaoDeMap();
|
|
// 初始化新实例
|
await gaoDeMap.init({
|
container,
|
aMapOption: {
|
resizeEnable: true,
|
},
|
});
|
|
gaoDeMap.applyBasicPlugins();
|
addMarkerLayer();
|
gaoDeMap.map.setFitView();
|
|
// 初始化信息窗口
|
initInfoWindow();
|
};
|
//#region ====================== 设备曲线 ======================
|
const chartDlgIsShow = ref(false);
|
const equipCurveMapRow = ref(null);
|
const showCurve = (row) => {
|
equipCurveMapRow.value = row;
|
chartDlgIsShow.value = true;
|
};
|
|
const closeChartDlg = () => {
|
chartDlgIsShow.value = false;
|
equipCurveMapRow.value = null;
|
};
|
//#endregion
|
onMounted(async () => {
|
await initMap(containerRef.value);
|
});
|
|
onDeactivated(async () => {
|
if (isFullscreen.value) {
|
await toggleFullScreen();
|
}
|
});
|
</script>
|
<style scoped lang="scss">
|
:deep(.amap-info-content) {
|
padding: 0;
|
}
|
|
// 全屏过渡动画
|
.fullscreen-enter-active,
|
.fullscreen-leave-active {
|
transition: all 0.3s ease;
|
}
|
|
.fullscreen-enter-from,
|
.fullscreen-leave-to {
|
opacity: 0;
|
transform: scale(0.95);
|
}
|
</style>
|