324 lines
11 KiB
Vue
324 lines
11 KiB
Vue
<template>
|
|
<div class="devive-map">
|
|
<div class="map-search-box">
|
|
<a-select
|
|
v-model:value="intValue"
|
|
allow-clear
|
|
show-search
|
|
label-in-value
|
|
placeholder="请输入地点"
|
|
style="width: 400px"
|
|
:default-active-first-option="false"
|
|
:show-arrow="true"
|
|
:filter-option="false"
|
|
:not-found-content="null"
|
|
@search="onSearch"
|
|
:options="panelList"
|
|
@change="handleChange"
|
|
/>
|
|
<!-- <a-button type="primary" @click="onButtonSearch"> 搜索 </a-button>-->
|
|
</div>
|
|
<div id="panel" style="display: none"></div>
|
|
<div class="list" id="list"> </div>
|
|
<div class="map" id="container"></div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup name="aed-map" lang="ts">
|
|
import { onMounted, reactive, ref } from 'vue';
|
|
import AMapLoader from '@amap/amap-jsapi-loader';
|
|
import { debounce } from 'lodash-es';
|
|
import positionIcon from '/@/assets/images/position.png';
|
|
import MarkersIcon from '/@/assets/images/markerCricle.png';
|
|
import { list } from './DeviceMap.api';
|
|
import { message } from 'ant-design-vue';
|
|
import {mapCenter} from "/@/utils/mapInfo";
|
|
|
|
let SelfMap = null;
|
|
let BasicMap = null;
|
|
let overlayGroup = null;
|
|
const intValue = ref('');
|
|
let placeSearch = ref();
|
|
let panelList = ref([]);
|
|
let pointerArray = ref([]);
|
|
let positionRef = ref({
|
|
lng: '',
|
|
lat: '',
|
|
handleItem: {
|
|
pname: '',
|
|
},
|
|
});
|
|
let mapState = [];
|
|
let defaultMarker = null;
|
|
onMounted(() => {
|
|
initMap();
|
|
});
|
|
function initMap() {
|
|
AMapLoader.load({
|
|
key: '4bbcb216b889f2d612cbed05ae6979c8',
|
|
version: '2.0',
|
|
plugins: ['AMap.Geocoder'], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
|
|
})
|
|
.then((AMap) => {
|
|
SelfMap = AMap;
|
|
//设置地图容器id
|
|
BasicMap = new AMap.Map('container', {
|
|
viewMode: '3D', //是否为3D地图模式
|
|
// zoom: 11, //初始化地图级别
|
|
center: mapCenter, //初始化地图中心点位置
|
|
resizeEnable: true,
|
|
});
|
|
// 注册搜索插件
|
|
bindSearch(AMap);
|
|
handleMarker({});
|
|
})
|
|
.catch((e) => {
|
|
console.log(e);
|
|
});
|
|
}
|
|
/*
|
|
** 获取区域对角线的两点坐标,即这个区域内的最小坐标值和最大坐标值
|
|
* @param pointerArray [[a,b],[c,d]]* @return Array {min:number[a,b], max:number[c,d]}
|
|
* */
|
|
function getMaxBoundsPointer(pointerArray) {
|
|
let lngArray = pointerArray.map((item) => item[0]);
|
|
let latArray = pointerArray.map((item) => item[1]);
|
|
return { min: [Math.min(...lngArray), Math.min(...latArray)], max: [Math.max(...lngArray), Math.max(...latArray)] };
|
|
}
|
|
/**
|
|
* @Description:输入框查询位置
|
|
* @date 2023/7/8
|
|
*/
|
|
function onSearch(value: string) {
|
|
//关键字查询
|
|
if (value) {
|
|
intValue.value = value;
|
|
searchRes(value);
|
|
}
|
|
}
|
|
const searchRes = debounce((value) => {
|
|
placeSearch.value.search(value, (status: string, result: any) => {
|
|
if (status === 'complete') {
|
|
panelList.value = result.poiList.pois.map((item) => ({ label: item.name, value: item.name, ...item }));
|
|
}
|
|
});
|
|
}, 500);
|
|
function onButtonSearch() {
|
|
onSearch(intValue.value);
|
|
}
|
|
/**
|
|
* @Description下拉框选择事件
|
|
* @date 2023/8/30
|
|
*/
|
|
function handleChange(value: any, option: any) {
|
|
if (option) {
|
|
setMapZoom(16);
|
|
let params = {
|
|
longitude: option.location.lng, // 经度
|
|
latitude: option.location.lat, // 纬度
|
|
radiusRange: '50', // 半径范围
|
|
};
|
|
addDefault(option.location.lng, option.location.lat);
|
|
handleMarker(params);
|
|
} else {
|
|
handleMarker({});
|
|
setMapZoom(12);
|
|
removeDefault();
|
|
}
|
|
}
|
|
function handleMarker(params) {
|
|
list(params).then((res) => {
|
|
if (res.length > 0) {
|
|
pointerArray.value = res;
|
|
let maxLocations = getMaxBoundsPointer(res.map((item) => [item.longitude, item.latitude]));
|
|
hanleBounds(maxLocations);
|
|
addMarker(res);
|
|
} else {
|
|
removeMarker();
|
|
// message.warn('该位置附近暂无设备!');
|
|
}
|
|
});
|
|
}
|
|
function hanleBounds(maxLocations) {
|
|
let lngGap = (maxLocations.max[0] - maxLocations.min[0]) / 4;
|
|
let latGap = (maxLocations.max[1] - maxLocations.min[1]) / 4;
|
|
let min = new SelfMap.LngLat(maxLocations.min[0] - lngGap, maxLocations.min[1] - latGap);
|
|
let max = new SelfMap.LngLat(maxLocations.max[0] + lngGap, maxLocations.max[1] + latGap);
|
|
if (pointerArray.value.length > 1) {
|
|
let bounds = new SelfMap.Bounds(min, max);
|
|
BasicMap.setBounds(bounds);
|
|
}
|
|
// 2. 一个点时,将其作为中心点
|
|
else if (pointerArray.value.length === 1) {
|
|
let pointValue = pointerArray.value;
|
|
let centerLngLat = new SelfMap.LngLat(pointValue[0].longitude, pointValue[0].latitude);
|
|
BasicMap.setCenter(centerLngLat); // 设置地图中心点坐标
|
|
}
|
|
}
|
|
// 加载默认图标
|
|
function addDefault(longitude, latitude) {
|
|
removeDefault();
|
|
let defaultIcon = new SelfMap.Icon({
|
|
image: MarkersIcon,
|
|
size: new SelfMap.Size(50, 58), //图标大小
|
|
imageSize: new SelfMap.Size(50, 58),
|
|
});
|
|
|
|
defaultMarker = new SelfMap.Marker({
|
|
icon: defaultIcon,
|
|
position: [longitude, latitude],
|
|
offset: [-18, -32],
|
|
maxZoom: 14,
|
|
});
|
|
defaultMarker.setMap(BasicMap);
|
|
BasicMap.setCenter([longitude, latitude], true);
|
|
}
|
|
function addMarker(position) {
|
|
removeMarker();
|
|
if (position.length === 0) {
|
|
return;
|
|
}
|
|
overlayGroup = new SelfMap.OverlayGroup();
|
|
position.map((item) => {
|
|
let marker = new SelfMap.Marker({
|
|
icon: positionIcon,
|
|
position: [item.longitude, item.latitude],
|
|
offset: [-18, -32],
|
|
maxZoom: 14,
|
|
});
|
|
marker.on('click', () => {
|
|
infoWindow(item);
|
|
});
|
|
overlayGroup.setMap(BasicMap);
|
|
overlayGroup.addOverlay(marker);
|
|
});
|
|
}
|
|
function removeDefault() {
|
|
defaultMarker && BasicMap.remove(defaultMarker);
|
|
}
|
|
function removeMarker() {
|
|
if (overlayGroup) {
|
|
BasicMap.remove(overlayGroup);
|
|
overlayGroup.setMap(null);
|
|
overlayGroup = null;
|
|
}
|
|
}
|
|
function infoWindow(position) {
|
|
let startDiv = `<div class="dialog-conMap">
|
|
<div class="item">
|
|
<span> 设备型号:</span>
|
|
<span>${position.hostModel}</span>
|
|
</div>
|
|
<div class="item">
|
|
<span>设备编号:</span>
|
|
<span>${position.hostSerialNum}</span>
|
|
</div>
|
|
`;
|
|
if (position.installAddress) {
|
|
startDiv += `<div class="item">
|
|
<span>布点位置:</span>
|
|
<span>${position.installAddress}</span>
|
|
</div>`;
|
|
}
|
|
if (position.mfrsMobile) {
|
|
startDiv += ` <div class="item">
|
|
<span>售后电话:</span>
|
|
<span>${position.mfrsMobile}</span>
|
|
</div>`;
|
|
}
|
|
if (position.manageUserMobile) {
|
|
startDiv += ` <div class="item">
|
|
<span>管理人电话:</span>
|
|
<span>${position.manageUserMobile}</span>
|
|
</div>`;
|
|
}
|
|
if (position?.chargeFirstMobile) {
|
|
startDiv += ` <div class="item">
|
|
<span>负责人1电话:</span>
|
|
<span>${position?.chargeFirstMobile}</span>
|
|
</div>`;
|
|
}
|
|
if (position.chargeSecondMobile) {
|
|
startDiv += ` <div class="item">
|
|
<span>负责人2电话:</span>
|
|
<span>${position?.chargeSecondMobile}</span>
|
|
</div>`;
|
|
}
|
|
let endDiv = `</div>`;
|
|
let infoWindow = new SelfMap.InfoWindow({
|
|
position: [position.longitude, position.latitude],
|
|
offset: new SelfMap.Pixel(0, -30),
|
|
content: startDiv + endDiv,
|
|
});
|
|
infoWindow.open(BasicMap);
|
|
}
|
|
function setMapZoom(zoom: number) {
|
|
if (zoom) BasicMap && (BasicMap as any).setZoom(zoom);
|
|
}
|
|
// 搜索插件
|
|
function bindSearch(AMap) {
|
|
AMap.plugin(['AMap.PlaceSearch'], function () {
|
|
//构造地点查询类
|
|
placeSearch.value = new AMap.PlaceSearch({
|
|
pageSize: 20, // 单页显示结果条数
|
|
pageIndex: 1, // 页码
|
|
panel: 'panel', // 结果列表将在此容器中进行展示。
|
|
autoFitView: false, // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
|
|
});
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.devive-map {
|
|
width: 100%;
|
|
height: calc(100vh - 130px);
|
|
.map {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
.map-search-box {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
z-index: 10;
|
|
box-shadow: 1px 2px 1px rgba(0, 0, 0, 0.15);
|
|
}
|
|
.panel-list {
|
|
position: absolute;
|
|
background-color: white;
|
|
max-height: 90%;
|
|
overflow-y: auto;
|
|
top: 70px;
|
|
left: 13px;
|
|
width: 280px;
|
|
z-index: 9;
|
|
.panel-item {
|
|
padding: 10px 5px;
|
|
color: #999;
|
|
line-height: 20px;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
<style lang="less">
|
|
.dialog-conMap {
|
|
padding: 10px;
|
|
width: 380px;
|
|
.item {
|
|
padding: 8px 0;
|
|
display: flex;
|
|
span:nth-child(1) {
|
|
display: inline-block;
|
|
width: 30%;
|
|
text-align: right;
|
|
}
|
|
span:nth-child(2) {
|
|
display: inline-block;
|
|
width: 70%;
|
|
text-align: left;
|
|
}
|
|
}
|
|
}
|
|
</style>
|