You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
11 KiB

7 months ago
<!-- @format -->
<template>
<div style="display: flex; width: 100%">
<a-form-item-rest>
<div class="rightBox">
<div class="inputArea">
<div style="margin-right: 10px">经度</div>
<div class="longitude">
<ns-input
v-model:value="longLatTudeobj.longitude"
type="number"
class="input"
placeholder="请输入经度"
:disabled="viewOnly"
@change="inputChange('longitude', $event)" /> </div
><div style="margin: 0 10px">纬度</div>
<div class="latitude">
<ns-input
v-model:value="longLatTudeobj.latitude"
type="number"
class="input"
placeholder="请输入纬度"
:disabled="viewOnly"
@change="inputChange('latitude', $event)" />
</div>
</div>
<div class="inputSearch" style="margin: 15px 0 15px 0">
<label style="margin-right: 10px">地址</label>
<ns-input
v-model:value="longLatTudeobj.address"
class="inputAdress"
:disabled="viewOnly"
placeholder="请输入地址" />
<ns-button type="primary" @click="onSearch" :disabled="viewOnly">查询</ns-button>
</div>
<div class="mapArea">
<div id="map-container"></div>
<div v-if="isShowResult" id="map-result" style="overflow: auto"></div>
</div>
</div>
</a-form-item-rest>
</div>
</template>
<script lang="ts">
import { defineComponent, watch, ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue';
import AMapLoader from '@amap/amap-jsapi-loader';
import { shallowRef } from 'vue';
import { isArray, isEqual, isEmpty } from 'lodash-es';
export default defineComponent({
name: 'NsMapV2',
props: {
defaultValue: {
type: Array,
default: () => {
return [];
},
},
viewOnly: {
type: Boolean,
default: false,
},
value: {
type: Array,
default: () => {
return [];
},
},
fieldMap: {
type: Object || Array,
default: () => {
return [];
},
},
formModel: {
type: Object || Array,
},
//兼容v1写法
longitude: {
type: String,
default: '',
},
latitude: {
type: String,
default: '',
},
defaultAddress: {
type: String,
default: '',
},
//兼容v1写法end
},
emits: ['change', 'updata:longLat'],
setup(props, { emit }) {
let map: Recordable;
let geoc: any, localSearch: any, Amap: any;
const isShowResult = ref(false);
const hasload = ref(false);
const longLatTudeobj = ref({
longitude: '',
latitude: '',
address: '',
});
const delay = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(map);
}, time);
});
};
const circleDelay = async () => {
let res = await delay(100);
if (res) {
return res;
} else {
return circleDelay();
}
};
//更新值
const updateValue = async (event) => {
if (!map) {
//循环等待map初始化
await circleDelay();
}
if (isArray(event)) {
if (!event.length) return;
longLatTudeobj.value['latitude'] = event[0] || '';
longLatTudeobj.value['longitude'] = event[1] || '';
longLatTudeobj.value['address'] = event[2] || '';
if (longLatTudeobj.value['latitude'] && longLatTudeobj.value['longitude']) {
map.clearMap();
getAddressBylnglat(longLatTudeobj.value, (res) => {
longLatTudeobj.value.address = res;
});
addMark({ position: [event[1], event[0]] });
map.setFitView();
}
}
};
const resultPanelClick = (data: { [x: string]: string }) => {
if (data && data['location']) {
if (data['location']) {
const location = data['location']; // 当前marker的经纬度信息
longLatTudeobj.value.longitude = location['lng'].toFixed(6);
longLatTudeobj.value.latitude = location['lat'].toFixed(6);
}
if (data['address']) {
longLatTudeobj.value.address = data['address'];
}
}
};
//搜索
const onSearch = () => {
isShowResult.value = true;
map.clearMap();
if (!localSearch) return;
localSearch.search(longLatTudeobj.value.address, (status: string, result: Recordable) => {
if (status == 'complete' && result.info == 'OK') {
const resultPoi = result['poiList']['pois'];
if (resultPoi && resultPoi instanceof Array && resultPoi.length > 0) {
const pois = result.poiList.pois;
for (let i = 0; i < pois.length; i++) {
const poi = pois[i];
const marker = [];
marker[i] = addMark({
position: poi.location, // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
title: poi.name,
});
}
map.setFitView();
}
} else {
}
});
};
//初始化
const initMap = async () => {
AMapLoader.load({
key: '2694972059c3b978de5d7e073efdfc64', // 申请好的Web端开发者Key,首次调用 load 时必填
version: '1.4.15',
plugins: ['AMap.Geocoder', 'AMap.PlaceSearch'],
})
.then((AMap) => {
Amap = AMap;
// 需要传入AMap ,否则方法无法调用
map = new AMap.Map('map-container', {
// center: [117.000923, 36.675807],
resizeEnable: true,
zoom: 12,
});
//精准搜索插件
geoc = new AMap.Geocoder({
city: '021',
});
//模糊匹配插件
AMap.service('AMap.PlaceSearch', function () {
// 回调函数
// 实例化PlaceSearch
localSearch = new AMap.PlaceSearch({
pageSize: 5, // 每页显示多少行
pageIndex: 1, // 显示的下标从那个开始
type: '', // 类别,可以以|后面加其他类
city: '021',
panel: 'map-result', // 服务显示 的面板
autoFitView: true,
});
});
if (AMap.event) {
// 搜索结果列表的点标记
AMap.event.addListener(localSearch, 'listElementClick', (e) => {
resultPanelClick(e['data']);
});
// 标记物点击
AMap.event.addListener(localSearch, 'markerClick', (e) => {
// console.log('搜索结果标记物点击');
resultPanelClick(e['data']);
});
}
//不可编辑状态
if (!props.viewOnly) {
map.on('click', (e) => {
map.clearMap();
getAddressByaddress(e, (res) => {
longLatTudeobj.value.address = res;
longLatTudeobj.value.latitude = e.lnglat['lat'].toFixed(6);
longLatTudeobj.value.longitude = e.lnglat['lng'].toFixed(6);
});
addMark({
position: e.lnglat,
});
map.setFitView();
});
}
})
.catch((e) => {});
};
//根据经纬度搜索
const getAddressBylnglat = (event, callBack) => {
geoc.getAddress(event.lnglat, (status, result) => {
if (status == 'complete' && result.info == 'OK') {
const addComp = result['regeocode']['addressComponent'];
let address =
addComp.province +
addComp.city +
addComp.district +
addComp.street +
addComp.streetNumber;
callBack(address, result);
}
});
};
//根据关键字搜索
const getAddressByaddress = (event, callBack) => {
geoc.getAddress(event.lnglat, function (status, result) {
if (status == 'complete' && result.info == 'OK') {
const addComp = result['regeocode']['addressComponent'];
let address =
addComp.province +
addComp.city +
addComp.district +
addComp.street +
addComp.streetNumber;
callBack(address, result);
}
});
};
//添加点标记
const addMark = (data: Recordable) => {
let marker = new Amap.Marker(data);
map.add(marker);
};
onMounted(async () => {
await initMap();
if (props.value.length) {
updateValue(props.value);
}
if (props.defaultValue.length) {
updateValue(props.defaultValue);
}
});
onBeforeUnmount(() => {
map.destroy();
// localSearch.render.markerList.clear();
isShowResult.value = false;
});
watch(
() => props.value,
(newv, oldv) => {
if (!isEqual(newv, oldv) && !isEqual(newv, longLatTudeobj.value)) {
updateValue(newv);
}
},
{
immediate: true,
},
);
watch(
() => longLatTudeobj.value,
(newv, oldv) => {
if (newv) {
emit('change', [newv['latitude'], newv['longitude'], newv['address']]);
}
},
{
deep: true,
},
);
watch(
() => props.formModel,
(newv, oldv) => {
if (!isEmpty(newv) && props.fieldMap.length && !hasload.value) {
if (isArray(props.value) && !isEmpty(props.value)) {
return;
}
let longitude = [];
props.fieldMap.forEach((el, i) => {
longitude[i] = newv[el];
});
updateValue(longitude);
hasload.value = true;
}
},
{
immediate: true,
},
);
//兼容老的处理方法
watch(
//
() => [props.latitude, props.longitude, props.defaultAddress],
//
([latitude, longitude, defaultAddress]) => {
console.log(latitude, longitude, defaultAddress);
if (latitude && longitude) {
updateValue([latitude, longitude, defaultAddress]);
}
},
{
deep: true,
immediate: true,
},
);
return {
map,
isShowResult,
longLatTudeobj,
onSearch,
};
},
});
</script>
<style lang="less" scoped>
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
#map-container {
height: 400px;
}
.leftBox,
.rightBox {
flex: 1;
}
.inputArea {
display: flex;
line-height: 30px;
}
.inputSearch {
.inputAdress {
width: 344px;
margin-right: 10px;
}
}
</style>