|
@@ -0,0 +1,363 @@
|
|
|
+<template>
|
|
|
+ <van-dialog v-model:show="showPositionSelect" title="请选择地点" show-cancel-button @close="handleClose" @confirm="submit">
|
|
|
+ <div class="position-container">
|
|
|
+ <div style="position: relative">
|
|
|
+ <div class="box">
|
|
|
+ <van-search
|
|
|
+ v-model="form.address"
|
|
|
+ show-action
|
|
|
+ label="详细地址"
|
|
|
+ left-icon="none"
|
|
|
+ placeholder="请输入"
|
|
|
+ @search="handleInput"
|
|
|
+ >
|
|
|
+ <template #action>
|
|
|
+ <div @click="handleInput">搜索</div>
|
|
|
+ </template>
|
|
|
+ </van-search>
|
|
|
+ </div>
|
|
|
+ <div v-if="searchPop" class="scroll_box">
|
|
|
+ <div class="scroll-header">
|
|
|
+ <span>搜索结果列表</span>
|
|
|
+ <i class="close-icon" @click="closeSearchList()" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="scroll">
|
|
|
+ <div v-for="(item, index) in searchList" v-show="searchList.length" :key="index" class="item" @click="handlePanTo(index)">
|
|
|
+ <van-image width="50" height="50" fit="fill" :src="item.img" style="flex-shrink: 0; margin-right: 8px;" />
|
|
|
+ <div>
|
|
|
+ <div class="text">{{ item.name }}</div>
|
|
|
+ <div>{{ item.address }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-show="!searchList.length" class="empty" style="text-align: center">没有搜索到内容</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <van-field v-model="form.longitude" label="经度" placeholder="请输入" />
|
|
|
+ <van-field v-model="form.latitude" label="纬度" placeholder="请输入" />
|
|
|
+ <div id="map" class="map" />
|
|
|
+ </div>
|
|
|
+ </van-dialog>
|
|
|
+
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup name="PositionSelect">
|
|
|
+import AMapLoader from '@amap/amap-jsapi-loader';
|
|
|
+import { useRouter } from 'vue-router';
|
|
|
+import { addEvent } from '@/api/emergencyCommandMap/JointDuty';
|
|
|
+import {nextTick, onUnmounted, reactive, ref, watch} from "vue";
|
|
|
+import {showFailToast} from "vant";
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ address: {//公司地址
|
|
|
+ type: String,
|
|
|
+ default: () => {
|
|
|
+ return '';
|
|
|
+ },
|
|
|
+ },
|
|
|
+ lnglat: {//经纬度
|
|
|
+ type: Array,
|
|
|
+ default: () => {
|
|
|
+ return [];
|
|
|
+ },
|
|
|
+ },
|
|
|
+ visible: {
|
|
|
+ type: Boolean,
|
|
|
+ default: () => {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+const emits = defineEmits(['update:visible', 'confirm']);
|
|
|
+let showPositionSelect = ref(false);
|
|
|
+// 地图对象
|
|
|
+let map = null;
|
|
|
+let amap = {};
|
|
|
+let marker = null; //地图上的点标记
|
|
|
+let contextMenu = null;
|
|
|
+let lnglatPosition = ref([]); //选中的新坐标
|
|
|
+let pageNum = ref(1);
|
|
|
+let pageSize = ref(10);
|
|
|
+let total = ref(0);
|
|
|
+
|
|
|
+let searchList = ref([]);
|
|
|
+let searchPop = ref(false);
|
|
|
+let placeSearch;
|
|
|
+let form = reactive({
|
|
|
+ address: '',
|
|
|
+ longitude: '',
|
|
|
+ latitude: ''
|
|
|
+});
|
|
|
+let geocoder = {};
|
|
|
+watch(
|
|
|
+ () => props.visible,
|
|
|
+ (n) => {
|
|
|
+ if (n) {
|
|
|
+ showPositionSelect.value = n;
|
|
|
+ nextTick(() => {
|
|
|
+ initMap();
|
|
|
+ form.address = props.address;
|
|
|
+ handleInput(0)
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
+);
|
|
|
+onUnmounted(() => {
|
|
|
+ if (!!map) {
|
|
|
+ map.off('rightclick');
|
|
|
+ map.destroy();
|
|
|
+ map = null;
|
|
|
+ }
|
|
|
+});
|
|
|
+function handleInput(flag?: any) {
|
|
|
+ if (!form.address) return;
|
|
|
+
|
|
|
+ if (!flag) {
|
|
|
+ //搜索
|
|
|
+ total.value = 0;
|
|
|
+ pageNum.value = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!placeSearch) {
|
|
|
+ placeSearch = new amap.PlaceSearch({
|
|
|
+ pageSize: pageSize.value, // 每页条数,默认10,范围1-50
|
|
|
+ pageIndex: pageNum.value, // 页码
|
|
|
+ extensions: 'all' // 默认base,返回基本地址信息;all:返回详细信息
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ searchPop.value = true;
|
|
|
+ placeSearch.setPageIndex(pageNum.value);
|
|
|
+ placeSearch.search(form.address, (status, result) => {
|
|
|
+ // console.log(result.poiList.pois, 'result')
|
|
|
+ if (!!result.poiList && result.poiList.pois && result.poiList.pois.length > 0) {
|
|
|
+ let arr = [];
|
|
|
+ const pois = result.poiList.pois;
|
|
|
+ total.value = result.poiList ? result.poiList.count : 0;
|
|
|
+ arr = pois.map((item) => {
|
|
|
+ return {
|
|
|
+ name: item.name,
|
|
|
+ address: item.address,
|
|
|
+ img: item.photos[0]?.url,
|
|
|
+ lnglat: [item.location.lng, item.location.lat]
|
|
|
+ };
|
|
|
+ });
|
|
|
+ searchList.value = arr;
|
|
|
+ } else {
|
|
|
+ total.value = 0;
|
|
|
+ searchList.value = [];
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+function handleChangePage(newNum) {
|
|
|
+ if (!searchPop.value) return;
|
|
|
+ pageNum.value = newNum;
|
|
|
+ handleInput(1);
|
|
|
+}
|
|
|
+function closeSearchList() {
|
|
|
+ searchPop.value = false;
|
|
|
+ searchList.value = [];
|
|
|
+ total.value = 0;
|
|
|
+ pageNum.value = 1;
|
|
|
+}
|
|
|
+// 地图中心的平移至指定点位置
|
|
|
+function handlePanTo(index) {
|
|
|
+ let lnglat = searchList.value[index].lnglat;
|
|
|
+ form.address = searchList.value[index].name + '(' + searchList.value[index].address + ')';
|
|
|
+ form.longitude = lnglat[0];
|
|
|
+ form.latitude = lnglat[1];
|
|
|
+
|
|
|
+ map.panTo(lnglat);
|
|
|
+ setMarks(lnglat);
|
|
|
+ closeSearchList();
|
|
|
+}
|
|
|
+const updateForm = (position) => {
|
|
|
+ form.longitude = position[0];
|
|
|
+ form.latitude = position[1];
|
|
|
+ geocoder.getAddress(position, (status, result) => {
|
|
|
+ if (status === 'complete' && result.info === 'OK') {
|
|
|
+ form.address = result.regeocode.formattedAddress;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+const initMap = async () => {
|
|
|
+ window._AMapSecurityConfig = {
|
|
|
+ securityJsCode: '4868bc1b8fac7d9e54e7279ed556879a'
|
|
|
+ };
|
|
|
+ const AMap = await AMapLoader.load({
|
|
|
+ key: '9c5041381e5e824f9ee324d8f7a40150', // 申请好的Web端开发者Key,首次调用 load 时必填
|
|
|
+ version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
|
|
|
+ plugins: ['AMap.PlaceSearch', 'AMap.ContextMenu', 'AMap.PolygonEditor', 'AMap.Geocoder'] // 插件列表
|
|
|
+ });
|
|
|
+ let position = [110.925175, 21.678955];
|
|
|
+ if (props.lnglat && props.lnglat.length > 0) {
|
|
|
+ position = props.lnglat
|
|
|
+ } else {
|
|
|
+ AMap.plugin('AMap.Geolocation', function() {
|
|
|
+ var geolocation = new AMap.Geolocation({
|
|
|
+ enableHighAccuracy: true, // 是否使用高精度定位,默认:true
|
|
|
+ timeout: 10000, // 设置定位超时时间,默认:无穷大
|
|
|
+ offset: [10, 20], // 定位按钮的停靠位置的偏移量
|
|
|
+ zoomToAccuracy: true, // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
|
|
|
+ position: 'RB' // 定位按钮的排放位置, RB表示右下
|
|
|
+ })
|
|
|
+
|
|
|
+ geolocation.getCurrentPosition(function(status,result){
|
|
|
+ if(status=='complete'){
|
|
|
+ updateForm(position);
|
|
|
+ setMarks(position);
|
|
|
+ } else{
|
|
|
+ showFailToast('获取定位失败,请手动拖拽选点');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ })
|
|
|
+ }
|
|
|
+ map = new AMap.Map('map', {
|
|
|
+ viewMode: '3D', //是否为3D地图模式
|
|
|
+ center: position,
|
|
|
+ zoom: 15
|
|
|
+ });
|
|
|
+ amap = AMap;
|
|
|
+ geocoder = new AMap.Geocoder({
|
|
|
+ // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
|
|
|
+ city: '010'
|
|
|
+ });
|
|
|
+ // 创建右键菜单
|
|
|
+ ContextMenu();
|
|
|
+ map.on('rightclick', handleRightclick);
|
|
|
+ map.on('complete', () => {
|
|
|
+ if (!props.address) {
|
|
|
+ updateForm(position);
|
|
|
+ } else {
|
|
|
+ form.longitude = position[0];
|
|
|
+ form.latitude = position[1];
|
|
|
+ }
|
|
|
+ setMarks(position);
|
|
|
+ });
|
|
|
+};
|
|
|
+function ContextMenu() {
|
|
|
+ contextMenu = new AMap.ContextMenu();
|
|
|
+ contextMenu.addItem(
|
|
|
+ '选择标点',
|
|
|
+ () => {
|
|
|
+ form.longitude = lnglatPosition.value[0];
|
|
|
+ form.latitude = lnglatPosition.value[1];
|
|
|
+ contextMenu.close();
|
|
|
+ let lnglat = [form.longitude, form.latitude];
|
|
|
+ geocoder.getAddress(lnglat, (status, result) => {
|
|
|
+ if (status === 'complete' && result.info === 'OK') {
|
|
|
+ form.address = result.regeocode.formattedAddress;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ updateForm(lnglat);
|
|
|
+ setMarks(lnglat);
|
|
|
+ },
|
|
|
+ 1
|
|
|
+ );
|
|
|
+}
|
|
|
+// 右键事件
|
|
|
+function handleRightclick(e) {
|
|
|
+ let lnglat = [e.lnglat.getLng(), e.lnglat.getLat()];
|
|
|
+ contextMenu.open(map, e.lnglat);
|
|
|
+ lnglatPosition.value = lnglat;
|
|
|
+}
|
|
|
+function setMarks(lnglat) {
|
|
|
+ //添加标记
|
|
|
+ if (marker) map.remove(marker);
|
|
|
+ marker = new AMap.Marker({
|
|
|
+ position: lnglat,
|
|
|
+ icon: new AMap.Icon({
|
|
|
+ size: new AMap.Size(22, 28), //图标所处区域大小
|
|
|
+ imageSize: new AMap.Size(22, 28), //图标大小
|
|
|
+ image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png'
|
|
|
+ }),
|
|
|
+ draggable: true,
|
|
|
+ anchor: 'bottom-center',
|
|
|
+ offset: new AMap.Pixel(0, 0)
|
|
|
+ });
|
|
|
+ marker.on('dragend', (e) => {
|
|
|
+ updateForm([e.lnglat.lng, e.lnglat.lat]);
|
|
|
+ });
|
|
|
+ marker.setMap(map);
|
|
|
+}
|
|
|
+function handleClose() {
|
|
|
+ emits('update:visible', false);
|
|
|
+}
|
|
|
+let queryFormRef = ref();
|
|
|
+
|
|
|
+function submit() {
|
|
|
+ emits('confirm', { lnglat: [form.longitude, form.latitude], address: form.address });
|
|
|
+ handleClose();
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss"scoped>
|
|
|
+.position-container {
|
|
|
+ height: calc(100vh - 250px);
|
|
|
+ min-height: 60%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ .position-header {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ height: 45px;
|
|
|
+ line-height: 45px;
|
|
|
+ border-bottom: 1px solid #eeeeee;
|
|
|
+ padding: 0 10px;
|
|
|
+ color: #445267;
|
|
|
+ }
|
|
|
+ #map {
|
|
|
+ width: 100%;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+.scroll_box {
|
|
|
+ width: 100%;
|
|
|
+ background-color: #fff;
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 45px;
|
|
|
+ z-index: 9;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 3px;
|
|
|
+ .scroll-header {
|
|
|
+ height: 45px;
|
|
|
+ line-height: 45px;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+ .close-icon {
|
|
|
+ position: absolute;
|
|
|
+ right: 10px;
|
|
|
+ top: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 20px;
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ background: url('@/assets/images/close.png') no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+.scroll {
|
|
|
+ width: 100%;
|
|
|
+ height: 380px;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .item {
|
|
|
+ display: flex;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 8px;
|
|
|
+ .text {
|
|
|
+ color: #3385ff;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.box {
|
|
|
+ border-bottom: 1px solid #eeeeee;
|
|
|
+}
|
|
|
+</style>
|