|
@@ -1,20 +1,34 @@
|
|
|
<template>
|
|
|
<div class="menu-content">
|
|
|
- <div class="gradient-text common-dialog-title2">定点分析</div>
|
|
|
+ <div class="gradient-text title">定点分析</div>
|
|
|
<div class="scroll-box">
|
|
|
- <div v-if="!tempState.address" class="search-box">
|
|
|
- <div class="text-box">
|
|
|
+ <div class="search-box">
|
|
|
+ <di class="text-box">
|
|
|
<i class="icon-position2" />
|
|
|
- <div class="text1" :title="selectData.event_title">{{ selectData.event_title }}</div>
|
|
|
- </div>
|
|
|
- <div class="common-btn-primary3" @click="toSelect">定点选取</div>
|
|
|
+ <div class="text1" :title="tempState.address ? tempState.address : selectData.event_title">
|
|
|
+ {{ tempState.address ? tempState.address : selectData.event_title }}
|
|
|
+ </div>
|
|
|
+ </di>
|
|
|
+ <div v-if="tempState.address" class="common-btn-primary4" @click="confirmSelect">确定定位</div>
|
|
|
</div>
|
|
|
- <div v-else class="search-box">
|
|
|
- <div class="text-box">
|
|
|
- <i class="icon-position2" />
|
|
|
- <div class="text1" :title="tempState.address">{{ tempState.address }}</div>
|
|
|
+ <div ref="inputRef" class="search-item" style="position: relative">
|
|
|
+ <el-input v-model="inputText" class="custom-input2" placeholder="请输入地址或经纬度后回车搜索" @keyup.enter="handleSearch" />
|
|
|
+ <div v-if="searchPop" class="scroll_box">
|
|
|
+ <div style="height: 60px; line-height: 60px">
|
|
|
+ <span style="font-weight: bold">搜索结果列表</span>
|
|
|
+ <i class="el-icon-close" style="float: right; font-size: 20px; cursor: pointer" @click="closeSearchList()" />
|
|
|
+ </div>
|
|
|
+ <el-scrollbar class="scroll" style="height: 350px">
|
|
|
+ <div v-for="(item, index) in searchList" v-show="searchList.length" :key="index" class="item" @click="handleSearchSelect(item)">
|
|
|
+ <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>
|
|
|
+ </el-scrollbar>
|
|
|
</div>
|
|
|
- <div class="common-btn-primary4" @click="confirmSelect">确定定位</div>
|
|
|
+ <div class="common-btn-primary4" @click="toSelect">地图选取</div>
|
|
|
</div>
|
|
|
<div class="search-item">
|
|
|
<div class="text1">选择救灾资源:</div>
|
|
@@ -45,12 +59,12 @@
|
|
|
个
|
|
|
</div>
|
|
|
<div class="list-content">
|
|
|
- <div v-for="(item, index) in dataList" :key="index" class="list-item">
|
|
|
+ <div v-for="(item, index) in dataList" :key="index" class="list-item" @click="handleRoutes(item)">
|
|
|
<div class="text-box2">
|
|
|
<div class="text2">{{ item.name }}</div>
|
|
|
<div class="text3">{{ item.address }}</div>
|
|
|
</div>
|
|
|
- <div class="operate" @click="handleRoutes(item)">
|
|
|
+ <div class="operate">
|
|
|
<i class="icon2" />
|
|
|
路线
|
|
|
</div>
|
|
@@ -73,7 +87,7 @@
|
|
|
>
|
|
|
<div class="text-box1">
|
|
|
<div :class="'tag tag' + index">{{ getTag(index) }}</div>
|
|
|
-<!-- <div class="text1">{{ item.strategy }}</div>-->
|
|
|
+ <!-- <div class="text1">{{ item.strategy }}</div>-->
|
|
|
</div>
|
|
|
<div class="route-info">
|
|
|
<div class="text-box2">
|
|
@@ -111,6 +125,7 @@ import useMapStore from '@/store/modules/map';
|
|
|
import markImg from '@/assets/images/map/mark.png';
|
|
|
import startImg from '@/assets/images/map/start.png';
|
|
|
import endImg from '@/assets/images/map/end.png';
|
|
|
+import { onClickOutside } from '@vueuse/core';
|
|
|
|
|
|
interface Props {
|
|
|
location?: string | number[];
|
|
@@ -122,6 +137,7 @@ const getMap = inject('getMap');
|
|
|
const getMapUtils = inject('getMapUtils');
|
|
|
const mapStore = useMapStore();
|
|
|
const amapKey = 'e45d4caa2bef3c84714a2ed9b1e27d98';
|
|
|
+let inputRef = ref();
|
|
|
let showAddress = ref(true);
|
|
|
let routeData = ref([]);
|
|
|
let routeLine, startMarker, endMarker;
|
|
@@ -145,8 +161,11 @@ let queryParams = reactive({
|
|
|
keyword: '',
|
|
|
dataType: '2'
|
|
|
});
|
|
|
+let inputText = ref('');
|
|
|
let total = ref(0);
|
|
|
let dataList = ref([]);
|
|
|
+let searchList = ref([]);
|
|
|
+let searchPop = ref(false);
|
|
|
watch(
|
|
|
() => mapStore.mapLoaded,
|
|
|
(loaded) => {
|
|
@@ -159,6 +178,10 @@ watch(
|
|
|
immediate: true
|
|
|
}
|
|
|
);
|
|
|
+onClickOutside(inputRef, (event) => {
|
|
|
+ searchPop.value = false;
|
|
|
+ searchList.value = [];
|
|
|
+});
|
|
|
const toSelect = () => {
|
|
|
map.on('click', handleClickMap);
|
|
|
mapStore.setIsMapSelect(true);
|
|
@@ -463,6 +486,61 @@ const clearLine = () => {
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
+// 搜索地址或者经纬度
|
|
|
+const handleSearch = () => {
|
|
|
+ const value = inputText.value.trim();
|
|
|
+ // 1. 检测是否为经纬度格式
|
|
|
+ const isCoordinate = /^\s*[-+]?\d{1,3}(\.\d+)?\s*[,,]\s*[-+]?\d{1,3}(\.\d+)?\s*$/.test(value);
|
|
|
+
|
|
|
+ if (isCoordinate) {
|
|
|
+ // 2. 分割并验证经纬度范围
|
|
|
+ const parts = value.split(/[,,]/);
|
|
|
+ if (parts.length !== 2) {
|
|
|
+ handleAddress(value);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const lng = parseFloat(parts[0]);
|
|
|
+ const lat = parseFloat(parts[1]);
|
|
|
+
|
|
|
+ if (lng < -180 || lng > 180 || lat < -90 || lat > 90) {
|
|
|
+ proxy.$modal.msgError('请输入合法的坐标');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ handleCoordinate([lng, lat]); // 处理经纬度逻辑
|
|
|
+ } else {
|
|
|
+ handleAddress(value); // 处理地址逻辑
|
|
|
+ }
|
|
|
+};
|
|
|
+const handleCoordinate = (lnglat) => {
|
|
|
+ const newMap = mapStore.isAMap ? map : map.getView();
|
|
|
+ newMap.setCenter(lnglat);
|
|
|
+ getAddress(lnglat);
|
|
|
+};
|
|
|
+
|
|
|
+const handleAddress = async (value) => {
|
|
|
+ const url = `https://restapi.amap.com/v5/place/text?key=${amapKey}&keywords=${value}`;
|
|
|
+ const response = await fetch(url);
|
|
|
+ const result = await response.json();
|
|
|
+ searchList.value = result.pois;
|
|
|
+ searchPop.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+const handleSearchSelect = (item) => {
|
|
|
+ const newMap = mapStore.isAMap ? map : map.getView();
|
|
|
+ const location = item.location.split(',');
|
|
|
+ newMap.setCenter(location);
|
|
|
+ const gcj02Coord = gcoord.transform(location, gcoord.WGS84, gcoord.GCJ02);
|
|
|
+ createMarks({ longitude: gcj02Coord[0], latitude: gcj02Coord[1] }, true);
|
|
|
+ tempState.address = item.address;
|
|
|
+};
|
|
|
+
|
|
|
+const closeSearchList = () => {
|
|
|
+ searchPop.value = false;
|
|
|
+ searchList.value = [];
|
|
|
+};
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
if (mapStore.isAMap) {
|
|
|
AMap = mapUtils.getAMap();
|
|
@@ -489,7 +567,7 @@ onMounted(() => {
|
|
|
}
|
|
|
.search-box {
|
|
|
width: 100%;
|
|
|
- height: 150px;
|
|
|
+ height: 75px;
|
|
|
background: url('@/assets/images/electronicDisasterMapManage/box6.png') no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
padding: 0 10px 0 30px;
|
|
@@ -576,7 +654,7 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
.list-content {
|
|
|
- height: 210px;
|
|
|
+ height: 350px;
|
|
|
overflow-y: auto;
|
|
|
.list-item {
|
|
|
display: flex;
|
|
@@ -736,4 +814,38 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+.scroll_box {
|
|
|
+ width: calc(100% - 105px);
|
|
|
+ background: #0a2c5c;
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 45px;
|
|
|
+ z-index: 9;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 3px;
|
|
|
+ .close {
|
|
|
+ position: absolute;
|
|
|
+ right: 10px;
|
|
|
+ top: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.scroll {
|
|
|
+ width: 100%;
|
|
|
+ .item {
|
|
|
+ display: flex;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 8px;
|
|
|
+ border-bottom: 1px solid #4574d5;
|
|
|
+ &:hover {
|
|
|
+ background-color: #102e76;
|
|
|
+ }
|
|
|
+ .text {
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|