Merge branch 'main' of http://114.55.169.15:3000/qiushanhe/ss-crm-manage-web into salary
commit
f2064d99ad
@ -0,0 +1,269 @@ |
||||
<template> |
||||
<div class="relative w-full h-full"> |
||||
<div id="mapClue" style="height: 100%"></div> |
||||
<el-autocomplete |
||||
v-model="areaValue" |
||||
clearable |
||||
style="position: absolute; top: 20px; left: 20px; width: 400px" |
||||
placeholder="输入并搜索位置" |
||||
:fetch-suggestions="remoteMethod" |
||||
@select="currentSelect" |
||||
/> |
||||
<el-collapse v-model="collaspeKey" class="box-card"> |
||||
<el-collapse-item name="nearbySchool"> |
||||
<template #title> |
||||
<span class="ml-10px font-bold" style="font-size: 16px">附近驾校</span> |
||||
</template> |
||||
<div style="padding: 0 10px"> |
||||
<div v-if="nearbySchoolSearching">正在搜索中...</div> |
||||
<template v-else> |
||||
<div v-for="p in nearbySchoolList" :key="p.index"> |
||||
<div class="hover-pointer" style="font-size: 14px; color: blue"> |
||||
<i v-if="p.recommend" class="el-icon-star-off"></i> |
||||
驾校: {{ p.deptName }}-{{ p.name }} |
||||
</div> |
||||
<div class="mt5">地址:{{ p.address }}</div> |
||||
<div class="mt5"> |
||||
直线距离: {{ p.distance }} 公里; |
||||
<span class="ml0">步行距离:{{ p.walkdistance }}</span> |
||||
</div> |
||||
<el-divider style="margin: 3px 0 !important" /> |
||||
</div> |
||||
</template> |
||||
</div> |
||||
</el-collapse-item> |
||||
</el-collapse> |
||||
<DialogSchoolInfo ref="placeInfoDialog" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup name="ClueMap"> |
||||
import { getPlaceList } from '@/api/school/place' |
||||
|
||||
import ImgPostion from '@/assets/imgs/flag/position_black.png' |
||||
import FlagRed from '@/assets/imgs/flag/flag_red.png' |
||||
import FlagYellow from '@/assets/imgs/flag/flag_yellow.png' |
||||
import FlagPurple from '@/assets/imgs/flag/flag_purple.png' |
||||
import FlagGreen from '@/assets/imgs/flag/flag_green.png' |
||||
import FlagBlue from '@/assets/imgs/flag/flag_blue.png' |
||||
import FlagBlack from '@/assets/imgs/flag/flag_black.png' |
||||
import AMapLoader from '@amap/amap-jsapi-loader' |
||||
|
||||
import DialogSchoolInfo from './DialogSchoolInfo.vue' |
||||
|
||||
// 地图相关 |
||||
const clueMap = ref(null) |
||||
const aMap = ref(null) |
||||
const areaValue = ref('') |
||||
|
||||
const flagMap = { |
||||
red: FlagRed, |
||||
yellow: FlagYellow, |
||||
purple: FlagPurple, |
||||
green: FlagGreen, |
||||
blue: FlagBlue, |
||||
black: FlagBlack |
||||
} |
||||
|
||||
const defaultLatLng = ref({ |
||||
lat: 31.86119, |
||||
lng: 117.283042 |
||||
}) |
||||
|
||||
let AutoComplete = ref(null) |
||||
function initMap() { |
||||
AMapLoader.load({ |
||||
key: '713d839ff505943b0f18e6df45f3b0dc', //设置您的key |
||||
version: '2.0', |
||||
plugins: ['AMap.AutoComplete'] |
||||
}).then((AMap) => { |
||||
aMap.value = AMap |
||||
AutoComplete.value = new AMap.AutoComplete({ |
||||
city: '合肥' |
||||
}) |
||||
clueMap.value = new AMap.Map('mapClue', { |
||||
zoom: 14, |
||||
zooms: [2, 22], |
||||
center: [defaultLatLng.value.lng, defaultLatLng.value.lat] |
||||
}) |
||||
getPageData() |
||||
}) |
||||
} |
||||
|
||||
const placeList = ref([]) |
||||
|
||||
async function getPageData() { |
||||
placeList.value = [] |
||||
const data = await getPlaceList({ |
||||
placeStatus: 0 |
||||
}) |
||||
if (data.placeList) { |
||||
placeList.value = data.placeList |
||||
createMarkersInMap() |
||||
getNearbySchool(defaultLatLng.value) |
||||
} |
||||
} |
||||
|
||||
// 生成markers |
||||
function createMarkersInMap() { |
||||
for (let i = 0; i < placeList.value.length; i++) { |
||||
const element = placeList.value[i] |
||||
const markerIcon = flagMap[element.flagColor || 'red'] |
||||
const tmpMarker = new aMap.value.Marker({ |
||||
map: clueMap.value, |
||||
position: [element.lng, element.lat], |
||||
icon: markerIcon, |
||||
label: { |
||||
content: element.name, |
||||
direction: 'right' |
||||
}, |
||||
extData: element |
||||
}) |
||||
tmpMarker.on('click', handleClickMarker) |
||||
} |
||||
} |
||||
|
||||
const placeInfoDialog = ref() |
||||
function handleClickMarker(ev) { |
||||
placeInfoDialog.value.open(ev.target.getExtData()) |
||||
} |
||||
|
||||
function remoteMethod(searchValue, cb) { |
||||
if (searchValue) { |
||||
AutoComplete.value?.search(searchValue, (status, result) => { |
||||
if (result.tips?.length) { |
||||
// areaList.value = result?.tips |
||||
const list = result.tips.map((it) => ({ |
||||
...it, |
||||
value: it.name |
||||
})) |
||||
cb(list) |
||||
} else { |
||||
cb([]) |
||||
} |
||||
}) |
||||
} else { |
||||
cb([]) |
||||
} |
||||
} |
||||
|
||||
function currentSelect(val) { |
||||
if (val) { |
||||
defaultLatLng.value = { |
||||
lng: val.location?.lng, |
||||
lat: val.location?.lat |
||||
} |
||||
addmark(val.location?.lng, val.location?.lat, aMap.value) |
||||
} |
||||
} |
||||
|
||||
const marker = ref(null) |
||||
function addmark(lat, lng, AMap) { |
||||
marker.value && removeMarker() |
||||
marker.value = new AMap.Marker({ |
||||
position: new AMap.LngLat(lat, lng), |
||||
zoom: 14, |
||||
icon: ImgPostion, |
||||
offset: [-16, -32] |
||||
}) |
||||
clueMap.value.add(marker.value) |
||||
clueMap.value.setCenter([lat, lng], true) |
||||
getNearbySchool({ lat: lng, lng: lat }) |
||||
} |
||||
|
||||
const nearbySchoolList = ref([]) |
||||
const nearbySchoolSearching = ref(false) |
||||
const collaspeKey = ref('nearbySchool') |
||||
|
||||
function getNearbySchool(info) { |
||||
if (info.lng && info.lat) { |
||||
nearbySchoolList.value = [] |
||||
nearbySchoolSearching.value = true |
||||
// 推荐的场地 |
||||
let places1 = [] |
||||
// 普通的场地 |
||||
let places2 = [] |
||||
|
||||
const p2 = [info.lng, info.lat] |
||||
for (let i = 0; i < placeList.value.length; i++) { |
||||
const element = placeList.value[i] |
||||
const p1 = [element.lng, element.lat] |
||||
// 计算直线距离 |
||||
element.distance = (aMap.value.GeometryUtil.distance(p1, p2) / 1000).toFixed(2) |
||||
element.recommend ? places1.push(element) : places2.push(element) |
||||
} |
||||
// 按直线距离排序 |
||||
// 排序 |
||||
if (places1.length > 1) { |
||||
places1 = places1.sort((a, b) => a.distance - b.distance) |
||||
} |
||||
// 排序 |
||||
if (places2.length > 1) { |
||||
places2 = places2.sort((a, b) => a.distance - b.distance) |
||||
} |
||||
// 取普通场地和推荐场地,组合, 取四个 |
||||
nearbySchoolList.value = [] |
||||
for (let i = 0; i < 4; i++) { |
||||
places1.length > i && nearbySchoolList.value.push(places1[i]) |
||||
places2.length > i && nearbySchoolList.value.push(places2[i]) |
||||
if (nearbySchoolList.value.length === 4) { |
||||
break |
||||
} |
||||
} |
||||
// 计算步行距离 |
||||
nearbySchoolList.value.map(async (item) => { |
||||
const p1 = [item.lng, item.lat] |
||||
const resp = await getWalkingDistance(p1, p2) |
||||
item.walkdistance = resp |
||||
}) |
||||
nearbySchoolSearching.value = false |
||||
} |
||||
} |
||||
|
||||
// 获取两点之间的步行距离 |
||||
async function getWalkingDistance(start, end) { |
||||
return new Promise((resolve) => { |
||||
aMap.value.plugin('AMap.Walking', () => { |
||||
const walking = new aMap.value.Walking() |
||||
let num = 0 |
||||
walking.search(start, end, (status, result) => { |
||||
if (status === 'complete') { |
||||
result.routes.forEach((item) => { |
||||
num += item.distance |
||||
}) |
||||
resolve(num > 1000 ? `${(num / 1000).toFixed(2)} 公里` : `${num} 米`) |
||||
} else { |
||||
resolve('步行数据无法确定') |
||||
} |
||||
}) |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
function removeMarker() { |
||||
clueMap.value.remove(marker.value) |
||||
} |
||||
|
||||
function destroyMap() { |
||||
areaValue.value = undefined |
||||
clueMap.value = null |
||||
aMap.value = null |
||||
} |
||||
|
||||
defineExpose({ destroyMap }) |
||||
|
||||
onMounted(() => { |
||||
nextTick(() => { |
||||
initMap() |
||||
}) |
||||
}) |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.box-card { |
||||
position: absolute; |
||||
right: 10px; |
||||
bottom: 10px; |
||||
width: 40%; |
||||
} |
||||
</style> |
Loading…
Reference in new issue