场地信息地图定点展示

pull/853/head
wersd 2025-06-22 16:27:11 +08:00
parent 7ef6ad19ff
commit 3f527669ed
3 changed files with 186 additions and 46 deletions

View File

@ -0,0 +1,116 @@
<template>
<!-- 地图容器 -->
<div id="map-container" ref="mapContainer"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
// props
const props = defineProps({
center: {
type: Object,
default: () => ({ lat: 39.984104, lng: 116.307503 })
},
zoom: {
type: Number,
default: 11
},
markers: {
type: Array,
default: () => []
}
})
//
const map = ref(null)
const mapContainer = ref(null)
const emit = defineEmits(['map-click'])
let markerLayer = null
const API_KEY = import.meta.env.VITE_APP_TENCENT_MAP_KEY
onMounted(() => {
const script = document.createElement('script')
script.src = `https://map.qq.com/api/gljs?v=1.exp&key=${API_KEY}`
script.onload = initMap
document.head.appendChild(script)
})
function initMap() {
if (!window.TMap) {
console.error('腾讯地图API加载失败')
return
}
map.value = new TMap.Map(mapContainer.value, {
center: new TMap.LatLng(props.center.lat, props.center.lng),
zoom: props.zoom,
viewMode: '2D'
})
map.value.on('click', (evt) => {
//
emit('map-click', evt)
})
if (props.markers && props.markers.length > 0) {
addMarkers()
}
}
function addMarkers() {
if (!window.TMap || !map.value) return
removeMarker()
markerLayer = new TMap.MultiMarker({
map: map.value,
styles: {
"marker": new TMap.MarkerStyle({
width: 25,
height: 35,
anchor: { x: 12.5, y: 35 }
})
},
geometries: props.markers.map(m => ({
position: new TMap.LatLng(m.position.lat, m.position.lng),
id: m.id,
styleId: 'marker'
}))
})
}
function removeMarker() {
if (markerLayer) {
markerLayer.setMap(null)
markerLayer = null
}
}
// props
watch(() => props.center, (val) => {
if (map.value && val) {
map.value.setCenter(new TMap.LatLng(val.lat, val.lng))
}
}, { deep: true })
watch(() => props.zoom, (val) => {
if (map.value && val) {
map.value.setZoom(val)
}
})
watch(() => props.markers, () => {
addMarkers()
}, { deep: true })
onUnmounted(() => {
if (map.value) {
map.value.destroy()
}
})
</script>
<style scoped>
#map-container {
width: 100%;
height: 100%;
}
</style>

View File

@ -81,15 +81,21 @@
</el-form-item>
</el-col>
</el-row>
<el-dialog v-model="mapDialogVisible" title="获取经纬度" width="800px" append-to-body>
<iframe
v-if="mapDialogVisible"
:src="tencentLbsUrl"
width="100%"
height="600"
frameborder="0"
></iframe>
</el-dialog>
<!-- 地图选点弹窗 -->
<Dialog v-model="mapDialogVisible" title="地图选点" width="800px" append-to-body >
<TencentMap
ref="tencentMapRef"
:center="{ lat: tempLocation.lat, lng: tempLocation.lng }"
:zoom="16"
:markers="tempLocation.lat && tempLocation.lng ? [{ id: 'selected', content: formData, position: { lat: tempLocation.lat, lng: tempLocation.lng } }] : []"
@map-click="handleMapClick"
/>
<div style="margin-top: 10px; text-align: right;">
<el-button @click="mapDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmMapSelection"></el-button>
</div>
</Dialog>
<el-row>
<el-col :span="12">
<el-form-item label="业主方" prop="ownerId">
@ -212,6 +218,7 @@ import { defaultProps } from '@/utils/tree'
import * as AreaApi from '@/api/system/area'
import { useUserStore } from '@/store/modules/user'
import * as CustomerApi from '@/api/crm/customer'
import TencentMap from '@/components/TencentMap/index.vue'
/** 场地信息 表单 */
defineOptions({ name: 'StationSiteForm' })
@ -223,6 +230,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const tencentMapRef = ref()
const formData = ref({
id: undefined,
name: undefined,
@ -230,6 +238,8 @@ const formData = ref({
detailAddress: undefined,
locationLng: 0,
locationLat: 0,
mapCenterLat: 0,
mapCenterLng: 0,
estimatedPiles: 0,
parkingSpace: 0,
siteStatus: undefined,
@ -268,7 +278,6 @@ const formRules = reactive({
const formRef = ref() // Ref
const mapDialogVisible = ref(false)
const tencentLbsUrl = ref('')
const TENCENT_MAP_KEY = import.meta.env.VITE_APP_TENCENT_MAP_KEY // key
const ownerDialogVisible = ref(false)
const managementDialogVisible = ref(false)
const selectedOwner = ref()
@ -277,6 +286,7 @@ const ownerFlag = ref(false)
const managementFlag = ref(false)
const ownerInputDisabled = computed(() => !!formData.value.ownerId)
const managementInputDisabled = computed(() => !!formData.value.managementId)
const tempLocation = ref({ lat: 39.984104, lng: 116.307503 })
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
@ -349,6 +359,8 @@ const resetForm = () => {
detailAddress: undefined,
locationLng: 0,
locationLat: 0,
mapCenterLat: 0,
mapCenterLng: 0,
estimatedPiles: 0,
parkingSpace: 0,
siteStatus: undefined,
@ -390,51 +402,67 @@ const filteredManagementList = computed(() =>
: customerList.value
);
/** 初始化 **/
const openMapDialog = () => {
// url
let url = `https://apis.map.qq.com/tools/locpicker?type=1&key=${TENCENT_MAP_KEY}&referer=myapp`
if (formData.value.locationLat && formData.value.locationLng) {
url += `&coord=${formData.value.locationLat},${formData.value.locationLng}`
}
tencentLbsUrl.value = url
mapDialogVisible.value = true
// //
// async function getLocationNameByLatLng(lat, lng) {
// const key = import.meta.env.VITE_APP_TENCENT_MAP_KEY
// const url = `https://apis.map.qq.com/ws/geocoder/v1/?location=${lat},${lng}&key=${key}`
// try {
// const res = await fetch(url)
// const data = await res.json()
// if (data.status === 0) {
// return data.result.address
// }
// return `(${lat}, ${lng})`
// } catch {
// return `(${lat}, ${lng})`
// }
// }
//
function handleMapClick(e) {
// API
console.log('地图点击事件:', e)
const lat = e.latLng.getLat()
const lng = e.latLng.getLng()
tempLocation.value = { lat, lng }
// getLocationNameByLatLng(lat, lng).then(name => {
// formData.value.locationName = name
// })
}
function selectAddress(loc: any): void {
if (loc.poiname) {
formData.value.locationName = loc.poiname
} else {
formData.value.locationName = ''
//
async function confirmMapSelection() {
if (!tempLocation.value.lat || !tempLocation.value.lng) {
message.error('请在地图上选择位置')
return
}
if (loc.latlng && loc.latlng.lat) {
formData.value.locationLat = Number(loc.latlng.lat)
formData.value.locationLng = Number(loc.latlng.lng)
//
let center = { lat: 0, lng: 0 }
if (tencentMapRef.value && tencentMapRef.value.getCenter) {
center = tencentMapRef.value.getCenter()
}
formData.value.locationLat = tempLocation.value.lat
formData.value.locationLng = tempLocation.value.lng
formData.value.mapCenterLat = center.lat
formData.value.mapCenterLng = center.lng
//
formData.value.locationName = `(${tempLocation.value.lat}, ${tempLocation.value.lng})`
mapDialogVisible.value = false
}
const initTencentLbsMap = () => {
// @ts-ignore
window.selectAddress = selectAddress
window.addEventListener(
'message',
function (event) {
let loc = event.data
if (loc && loc.module === 'locationPicker') {
// @ts-ignore
window.selectAddress(loc)
}
},
false
)
const openMapDialog = () => {
//
const lat = formData.value.locationLat || 39.984104
const lng = formData.value.locationLng || 116.307503
tempLocation.value = { lat, lng }
mapDialogVisible.value = true
}
onMounted(() => {
AreaApi.getAreaTree().then(res => {
areaList.value = res
})
initTencentLbsMap()
})
watch(mapDialogVisible, (val) => {

View File

@ -152,10 +152,6 @@
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<!-- 地图弹窗 -->
<el-dialog v-model="mapDialogVisible" title="获取经纬度" append-to-body>
<IFrame class="h-609px" :src="tencentLbsUrl" />
</el-dialog>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->