From fba92618406ce7f5ba8b53831268d3aabbadbf72 Mon Sep 17 00:00:00 2001
From: ISFP_T <68358856@qq.com>
Date: Fri, 24 Oct 2025 17:08:33 +0800
Subject: [PATCH] =?UTF-8?q?feat:=E9=A6=96=E9=A1=B5=E5=9C=B0=E5=9B=BE?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=BE=E5=A4=87=E6=A0=87=E8=AE=B0=E7=82=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/MapComponent.vue | 234 ++++++++++++++++++++----------------
pages/index/index.vue | 117 +++++++++++++-----
static/markes_fdz.png | Bin 0 -> 1027 bytes
3 files changed, 218 insertions(+), 133 deletions(-)
create mode 100644 static/markes_fdz.png
diff --git a/components/MapComponent.vue b/components/MapComponent.vue
index 58151f0..f41247b 100644
--- a/components/MapComponent.vue
+++ b/components/MapComponent.vue
@@ -4,12 +4,18 @@
@@ -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
-
- try {
- mapContext.value.includePoints({
- points: [{
- 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)
+ if (!location || !location.longitude || !location.latitude) {
+ console.warn('moveToLocation: 无效的位置参数', location)
+ return
}
+
+ const newCenter = {
+ longitude: Number(location.longitude),
+ latitude: Number(location.latitude)
+ }
+
+ console.log('移动地图到:', newCenter)
+
+ // 直接更新地图中心,触发地图组件的视图更新
+ mapCenter.value = newCenter
+
+ // 更新标记点
+ updateMapMarkers()
}
// 监听用户位置变化
- watch(() => props.userLocation, (newLocation) => {
+ watch(() => props.userLocation, (newLocation, oldLocation) => {
if (newLocation && newLocation.longitude && newLocation.latitude) {
- mapCenter.value = {
- longitude: newLocation.longitude,
- latitude: 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()
}
- updateMapMarkers()
- moveToLocation(newLocation)
}
}, {
immediate: true,
@@ -252,25 +241,75 @@
isLoading.value = false
}
- // 地图区域变化事件
+ // 地图区域变化事件(带防抖优化)
const onMapRegionChange = (e) => {
- // 在手势或缩放结束时更新中心坐标
- if (e && e.type === 'end') {
- if (mapContext.value) {
- mapContext.value.getCenterLocation({
- success: (res) => {
- if (res && res.longitude && res.latitude) {
- mapCenter.value = {
- longitude: res.longitude,
- latitude: res.latitude
- }
- // 更新中心 marker 位置
- updateMapMarkers()
- emit('mapCenterChange', mapCenter.value)
- }
- }
- })
+ 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) {
+ const newCenter = {
+ longitude: res.longitude,
+ latitude: res.latitude
+ }
+ 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 {
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 6c71e29..e793243 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -6,11 +6,12 @@
icon="volume">
-
-
+
+
@@ -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)
@@ -447,6 +456,8 @@
filteredPositions.value = positionList.value.filter(item => {
return !item.distanceInMeters || item.distanceInMeters <= maxDistanceInMeters
})
+
+ console.log('过滤后场地数量:', filteredPositions.value.length)
} else {
console.error('根据地图中心加载场地失败:', res.data.msg)
@@ -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)
- } catch (e) {
+
+ // 保存到本地缓存
+ 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)
}
- loadPositionsByCenter(center)
}
const selectPosition = (position) => {
diff --git a/static/markes_fdz.png b/static/markes_fdz.png
new file mode 100644
index 0000000000000000000000000000000000000000..aae661902cfc50cf8e5fee0ddf31285e89d7ca54
GIT binary patch
literal 1027
zcmV+e1pNDnP)Px#1am@3R0s$N2z&@+hyVZstw}^dR9J1RZP>EFw
zXk2juA-f#7H3$BJR)PzcBGfz19i$!**X95c=SIDOVv8Fnm`ar;he)l0tdO`#6FY8V
z$KK)K^=5Xv>t8ru$?~o}dhfIE&CGkVf*~ZO%mCjgKV_8bocWyxazcn4i699$+z+AQejha65U+&E&EW!WG69LQ1)YlJ7#L
z#7c41=Cq&gB$wP^azcokeIc9xE5%hF6dw-kd;pkNKr{zHcANkJ4~h@1^qI;y=ZF;v
z=NuRZfGU@W-0Uu66+)gDfCq?`7R?06s)Nr1z{ReWmhPOerQtkvH~+1An+DKiXDhaJ
zUQy`EvCK14%8Z6%HH=l#{5Vu_fM}Q@8Q5;y;I!5N>0;d)B#~`{YH5eP^(|z}u>I|L
z*tFh*&{C`3VB?41IN7Z+`Bs!xy}^}FuQ9#w27BvUL~q3Lg#*Zz!O3oo;&;EW@MRi_
zq_JN|_&lov06I!Kytd_PX_uGf1Fn7j3HyKkgKxqQ5=!6asc!DFlmDA{zW4~?(>N$@
zW1Jd1{pok6=A*rB1<8bZ^kZC0pl
zR%joe^5Sus(4}egaDdQUqyyYX8fVQ2i)Iy6B@KzDYs|cRna1-vlk-s;&yNVlXYqvs
zT)YuS(=~+dWAe?592U2!ZtU=K`;hS544U897ovA0q@;b^Wc$|=uYY_MZNg7&vqE4t
z%+=371PSFwPdY=}ZR%Su2u3IIh5R%RjtS4rxSDl5Y_2DS(K2}U^E$quP9%AW+4rsx
zUwWUTXL~&T@elN=AjjncBFW46f_|bO%oB)&Fq$p=Ghy^_z}0Tb4v`n;X0-;L)$x^m
zM>|{RjtMSX2FL$a(JurEOiy$M2=DQ#95rOw7KxP0obWOxbdB&_t
zW;xBNlmknMft;#x*w4XP0b5on-B!uC9)%MPcMk;Wn-j1V=