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 @@ + + + + + + @@ -24,7 +30,6 @@ - @@ -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=