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