feat:首页地图新增设备标记点
This commit is contained in:
+111
-87
@@ -4,12 +4,18 @@
|
||||
<view class="map-wrapper">
|
||||
<!-- 使用小程序原生地图组件 -->
|
||||
<map id="map" class="native-map" :longitude="mapCenter.longitude" :latitude="mapCenter.latitude"
|
||||
:markers="mapMarkers" :scale="mapZoom" :show-location="true" @regionchange="onMapRegionChange"
|
||||
:markers="mapMarkers" :scale="mapZoom" :show-location="false" @regionchange="onMapRegionChange"
|
||||
@markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError">
|
||||
<!-- 覆盖在地图上的可点击控件(使用 cover-view 以兼容小程序原生组件层级) -->
|
||||
<cover-view class="index-swiper" v-if="!props.hideControls" @tap="handleJoinTap">
|
||||
<cover-image src="/static/index_swiper.png" class="index-swiper-img" mode="aspectFit"></cover-image>
|
||||
</cover-view>
|
||||
|
||||
<!-- 地图中心固定定位图标 -->
|
||||
<cover-view class="center-location-marker">
|
||||
<cover-image src="/static/location-icon.png" class="center-marker-icon"></cover-image>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-controls" v-if="!props.hideControls">
|
||||
<cover-view class="side-btn service" @tap="handleService">
|
||||
<cover-image class="side-icon" src="/static/customer-service.png"></cover-image>
|
||||
@@ -24,7 +30,6 @@
|
||||
<!-- <cover-view class="side-text">定位</cover-view> -->
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
<!-- 使用原生 marker 方案渲染中心指示,随 regionchange 同步到地图中心 -->
|
||||
</map>
|
||||
|
||||
<!-- 地图加载状态 -->
|
||||
@@ -144,28 +149,14 @@
|
||||
!(latitude === 0 && longitude === 0) // 排除 0,0 这种无效坐标
|
||||
}
|
||||
|
||||
// 防抖定时器
|
||||
let regionChangeTimer = null
|
||||
|
||||
// 方法
|
||||
const updateMapMarkers = () => {
|
||||
const markers = []
|
||||
// 中心 marker(始终存在,使用传入中心坐标或 userLocation)
|
||||
const centerLng = Number(mapCenter.value.longitude || (props.userLocation && props.userLocation.longitude))
|
||||
const centerLat = Number(mapCenter.value.latitude || (props.userLocation && props.userLocation.latitude))
|
||||
if (!isNaN(centerLng) && !isNaN(centerLat) && isValidCoordinate(centerLat, centerLng)) {
|
||||
markers.push({
|
||||
id: 999999, // 固定 id 作为中心点
|
||||
latitude: centerLat,
|
||||
longitude: centerLng,
|
||||
iconPath: '/static/location-icon.png',
|
||||
width: 30,
|
||||
height: 40,
|
||||
anchor: {
|
||||
x: 0.5,
|
||||
y: 1
|
||||
} // 图钉尖端对准坐标
|
||||
})
|
||||
}
|
||||
|
||||
// 可选:周边位置点
|
||||
// 只添加周边场地位置点,中心定位图标改用固定的cover-view显示
|
||||
if (props.enableMarkers && props.filteredPositions && props.filteredPositions.length > 0) {
|
||||
props.filteredPositions.forEach((pos, index) => {
|
||||
if (pos.longitude && pos.latitude && isValidCoordinate(pos.latitude, pos.longitude)) {
|
||||
@@ -175,9 +166,9 @@
|
||||
id: index + 1,
|
||||
latitude: lat,
|
||||
longitude: lng,
|
||||
iconPath: '/static/map.png',
|
||||
width: 30,
|
||||
height: 30,
|
||||
iconPath: '/static/markes_fdz.png',
|
||||
width: 40,
|
||||
height: 40,
|
||||
callout: {
|
||||
content: pos.name,
|
||||
fontSize: 12,
|
||||
@@ -195,45 +186,43 @@
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
// 移动地图到指定位置(使用 includePoints 以避免 mapid 错误,并兼容不同基础库)
|
||||
// 移动地图到指定位置(直接更新地图中心坐标)
|
||||
const moveToLocation = (location) => {
|
||||
if (!location || !location.longitude || !location.latitude) return
|
||||
if (!mapContext.value) return
|
||||
if (!location || !location.longitude || !location.latitude) {
|
||||
console.warn('moveToLocation: 无效的位置参数', location)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
mapContext.value.includePoints({
|
||||
points: [{
|
||||
const newCenter = {
|
||||
longitude: Number(location.longitude),
|
||||
latitude: Number(location.latitude)
|
||||
}],
|
||||
padding: [60, 60, 60, 60],
|
||||
success: () => {
|
||||
console.log('地图已移动到指定位置(includePoints)')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('includePoints 失败,尝试 moveToLocation():', err)
|
||||
// 回退尝试(不传参,部分基础库仅支持移动到用户当前位置)
|
||||
try {
|
||||
mapContext.value.moveToLocation()
|
||||
} catch (e) {
|
||||
console.error('moveToLocation 回退失败:', e)
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('移动地图异常:', e)
|
||||
}
|
||||
|
||||
console.log('移动地图到:', newCenter)
|
||||
|
||||
// 直接更新地图中心,触发地图组件的视图更新
|
||||
mapCenter.value = newCenter
|
||||
|
||||
// 更新标记点
|
||||
updateMapMarkers()
|
||||
}
|
||||
|
||||
// 监听用户位置变化
|
||||
watch(() => props.userLocation, (newLocation) => {
|
||||
watch(() => props.userLocation, (newLocation, oldLocation) => {
|
||||
if (newLocation && newLocation.longitude && newLocation.latitude) {
|
||||
// 检查位置是否真的变化了(避免重复更新)
|
||||
const isChanged = !oldLocation ||
|
||||
oldLocation.longitude !== newLocation.longitude ||
|
||||
oldLocation.latitude !== newLocation.latitude
|
||||
|
||||
if (isChanged) {
|
||||
console.log('用户位置变化:', newLocation)
|
||||
mapCenter.value = {
|
||||
longitude: newLocation.longitude,
|
||||
latitude: newLocation.latitude
|
||||
}
|
||||
updateMapMarkers()
|
||||
moveToLocation(newLocation)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
immediate: true,
|
||||
@@ -252,25 +241,75 @@
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
// 地图区域变化事件
|
||||
// 地图区域变化事件(带防抖优化)
|
||||
const onMapRegionChange = (e) => {
|
||||
// 在手势或缩放结束时更新中心坐标
|
||||
if (e && e.type === 'end') {
|
||||
console.log('regionchange事件:', e)
|
||||
|
||||
// 只处理结束事件
|
||||
if (!e || e.type !== 'end') {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取事件原因
|
||||
// 微信小程序:e.causedBy 可能的值:
|
||||
// - 'gesture': 手势拖动
|
||||
// - 'scale': 缩放
|
||||
// - 'update': 调用更新接口(如 setCenterOffset 等)
|
||||
const causedBy = e.causedBy || e.detail?.causedBy
|
||||
|
||||
console.log('地图变化原因:', causedBy, '完整事件:', e)
|
||||
|
||||
// 只在用户手动操作(拖动或缩放)结束时触发查询
|
||||
// 排除程序调用(update)导致的变化,避免定位按钮触发多余查询
|
||||
if (causedBy === 'gesture' || causedBy === 'scale' || causedBy === 'drag') {
|
||||
// 清除之前的定时器
|
||||
if (regionChangeTimer) {
|
||||
clearTimeout(regionChangeTimer)
|
||||
}
|
||||
|
||||
// 直接从事件对象中获取最新的中心点位置
|
||||
const centerLocation = e.detail?.centerLocation || e.centerLocation
|
||||
|
||||
if (centerLocation && centerLocation.longitude && centerLocation.latitude) {
|
||||
// 防抖:500ms后执行查询
|
||||
regionChangeTimer = setTimeout(() => {
|
||||
const newCenter = {
|
||||
longitude: Number(centerLocation.longitude),
|
||||
latitude: Number(centerLocation.latitude)
|
||||
}
|
||||
|
||||
mapCenter.value = newCenter
|
||||
console.log('地图中心变化,触发查询:', newCenter, '原因:', causedBy)
|
||||
|
||||
// 触发父组件查询新位置的场地
|
||||
emit('mapCenterChange', newCenter)
|
||||
}, 500)
|
||||
} else {
|
||||
console.warn('未能从事件中获取中心点位置,尝试使用API获取')
|
||||
// 兜底方案:如果事件中没有centerLocation,才使用API获取
|
||||
regionChangeTimer = setTimeout(() => {
|
||||
if (mapContext.value) {
|
||||
mapContext.value.getCenterLocation({
|
||||
success: (res) => {
|
||||
if (res && res.longitude && res.latitude) {
|
||||
mapCenter.value = {
|
||||
const newCenter = {
|
||||
longitude: res.longitude,
|
||||
latitude: res.latitude
|
||||
}
|
||||
// 更新中心 marker 位置
|
||||
updateMapMarkers()
|
||||
emit('mapCenterChange', mapCenter.value)
|
||||
mapCenter.value = newCenter
|
||||
console.log('地图中心变化(API获取):', newCenter, '原因:', causedBy)
|
||||
emit('mapCenterChange', newCenter)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('获取地图中心失败:', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
} else {
|
||||
console.log('跳过查询,原因:', causedBy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,16 +317,7 @@
|
||||
const onMapMarkerTap = (e) => {
|
||||
const markerId = e.detail?.markerId || e.markerId
|
||||
|
||||
// 中心点标记
|
||||
if (markerId === 999999) {
|
||||
uni.showToast({
|
||||
title: '这是您的当前位置',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 查找对应的位置信息
|
||||
// 查找对应的场地位置信息
|
||||
if (props.filteredPositions && props.filteredPositions.length > 0) {
|
||||
const position = props.filteredPositions[markerId - 1]
|
||||
if (position) {
|
||||
@@ -369,6 +399,10 @@ const handleSearch = () => {
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清理工作
|
||||
if (regionChangeTimer) {
|
||||
clearTimeout(regionChangeTimer)
|
||||
regionChangeTimer = null
|
||||
}
|
||||
mapContext.value = null
|
||||
})
|
||||
|
||||
@@ -464,33 +498,23 @@ const handleSearch = () => {
|
||||
}
|
||||
}
|
||||
|
||||
/* 地图中心图钉(cover-view,避免使用 transform 以兼容小程序) */
|
||||
.center-pin {
|
||||
/* 地图中心定位图标(固定在屏幕中心) */
|
||||
.center-location-marker {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 16;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: 100;
|
||||
width: 60rpx;
|
||||
height: 80rpx;
|
||||
margin-left: -30rpx;
|
||||
margin-top: -80rpx;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.center-pin .pin-img {
|
||||
position: absolute;
|
||||
width: 48rpx;
|
||||
height: 64rpx;
|
||||
/* 使图钉尖端对准中心点:X 向左偏半宽,Y 向上偏高度-阴影间距 */
|
||||
margin-left: -24rpx;
|
||||
margin-top: -68rpx;
|
||||
}
|
||||
|
||||
.center-pin .pin-shadow {
|
||||
position: absolute;
|
||||
width: 28rpx;
|
||||
height: 8rpx;
|
||||
border-radius: 10rpx;
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
margin-left: -14rpx;
|
||||
margin-top: -8rpx;
|
||||
.center-marker-icon {
|
||||
width: 60rpx;
|
||||
height: 80rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.map-side-controls {
|
||||
|
||||
+83
-22
@@ -9,6 +9,7 @@
|
||||
<!-- 全屏地图组件 -->
|
||||
<MapComponent v-if="!isLoading && userLocation" ref="mapRef" :userLocation="userLocation"
|
||||
:positionList="positionList" :filteredPositions="filteredPositions" :searchKeyword="searchKeyword"
|
||||
:enableMarkers="true"
|
||||
@relocate="handleRelocate" @scan="handleScan" @showList="showLocationList" @markerTap="selectPosition"
|
||||
@mapCenterChange="onMapCenterChange" />
|
||||
|
||||
@@ -175,6 +176,7 @@
|
||||
const showPhoneAuthPopup = ref(false)
|
||||
const isLocationInitialized = ref(false)
|
||||
const showLocationPopup = ref(false)
|
||||
const isRelocating = ref(false) // 防抖标志:是否正在重新定位
|
||||
|
||||
// 使用指南步骤
|
||||
const guideSteps = ref([
|
||||
@@ -184,13 +186,6 @@
|
||||
{ title: '归还设备', desc: '使用完毕后,按照设备规格要求将风扇还入即可结束订单' }
|
||||
])
|
||||
|
||||
// 使用指南步骤
|
||||
// 使用指南已取消
|
||||
|
||||
// 滚动通知内容
|
||||
// const noticeText = ref('消费规则:每小时5元,不足1小时按1小时计费,最高24小时封顶,请爱护设备,使用后请及时归还')
|
||||
|
||||
|
||||
const redirectToLogin = () => {
|
||||
try {
|
||||
const pages = getCurrentPages()
|
||||
@@ -423,14 +418,25 @@
|
||||
}
|
||||
|
||||
const loadPositionsByCenter = async (center) => {
|
||||
if (!center || !center.longitude || !center.latitude) {
|
||||
console.warn('loadPositionsByCenter: 无效的中心点', center)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('根据地图中心加载场地:', center)
|
||||
|
||||
try {
|
||||
// 使用原有接口获取所有场地
|
||||
// 使用原有接口获取所有场地,传入中心点经纬度
|
||||
const res = await uni.request({
|
||||
url: `${URL}/device/position/app/list`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
||||
'Clientid': uni.getStorageSync('client_id')
|
||||
},
|
||||
data: {
|
||||
latitude: center.latitude,
|
||||
longitude: center.longitude
|
||||
}
|
||||
})
|
||||
|
||||
@@ -438,7 +444,10 @@
|
||||
redirectToLogin()
|
||||
return
|
||||
} else if (res.statusCode === 200 && res.data.code === 200) {
|
||||
positionList.value = res.data.rows || []
|
||||
const rows = res.data.rows || []
|
||||
console.log('加载到场地数量:', rows.length)
|
||||
|
||||
positionList.value = rows
|
||||
// 基于地图中心计算距离
|
||||
calculateDistances(center)
|
||||
|
||||
@@ -448,6 +457,8 @@
|
||||
return !item.distanceInMeters || item.distanceInMeters <= maxDistanceInMeters
|
||||
})
|
||||
|
||||
console.log('过滤后场地数量:', filteredPositions.value.length)
|
||||
|
||||
} else {
|
||||
console.error('根据地图中心加载场地失败:', res.data.msg)
|
||||
positionList.value = []
|
||||
@@ -460,34 +471,80 @@
|
||||
}
|
||||
|
||||
const handleRelocate = async () => {
|
||||
// 防抖:如果正在定位中,直接返回
|
||||
if (isRelocating.value) {
|
||||
console.log('正在定位中,请勿重复点击')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
isRelocating.value = true
|
||||
|
||||
uni.showLoading({
|
||||
title: '定位中...'
|
||||
title: '重新定位中...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
// 重新获取用户真实位置(不使用缓存)
|
||||
const loc = await getUserLocation()
|
||||
const center = {
|
||||
const newLocation = {
|
||||
longitude: Number(loc.longitude),
|
||||
latitude: Number(loc.latitude)
|
||||
}
|
||||
userLocation.value = center
|
||||
try {
|
||||
uni.setStorageSync('userLocation', center)
|
||||
} catch (_) {}
|
||||
if (mapRef.value && typeof mapRef.value.moveToLocation === 'function') {
|
||||
mapRef.value.moveToLocation(center)
|
||||
|
||||
console.log('重新定位成功,新位置:', newLocation)
|
||||
console.log('当前位置:', userLocation.value)
|
||||
|
||||
// 更新用户位置(触发地图组件的watch,自动移动地图)
|
||||
userLocation.value = {
|
||||
...newLocation
|
||||
}
|
||||
await loadPositionsByCenter(center)
|
||||
|
||||
// 保存到本地缓存
|
||||
try {
|
||||
uni.setStorageSync('userLocation', newLocation)
|
||||
} catch (e) {
|
||||
console.warn('缓存位置失败:', e)
|
||||
}
|
||||
|
||||
// 确保地图移动到新位置
|
||||
if (mapRef.value && typeof mapRef.value.moveToLocation === 'function') {
|
||||
mapRef.value.moveToLocation(newLocation)
|
||||
}
|
||||
|
||||
// 延迟一下,等待地图移动完成后再查询场地
|
||||
await new Promise(resolve => setTimeout(resolve, 300))
|
||||
|
||||
// 加载新位置的场地
|
||||
await loadPositionsByCenter(newLocation)
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: '定位失败',
|
||||
icon: 'none'
|
||||
title: '定位成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('定位失败:', e)
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: e.errMsg || '定位失败,请检查定位权限',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
} finally {
|
||||
uni.hideLoading()
|
||||
// 1秒后解除防抖锁定
|
||||
setTimeout(() => {
|
||||
isRelocating.value = false
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
const onMapCenterChange = (center) => {
|
||||
console.log('onMapCenterChange 被调用,中心点:', center)
|
||||
|
||||
if (center && typeof center.longitude !== 'undefined' && typeof center.latitude !== 'undefined') {
|
||||
userLocation.value = {
|
||||
longitude: Number(center.longitude),
|
||||
@@ -496,8 +553,12 @@
|
||||
try {
|
||||
uni.setStorageSync('userLocation', userLocation.value)
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// 调用加载场地方法
|
||||
loadPositionsByCenter(center)
|
||||
} else {
|
||||
console.warn('onMapCenterChange: 无效的中心点', center)
|
||||
}
|
||||
}
|
||||
|
||||
const selectPosition = (position) => {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Reference in New Issue
Block a user