feat:新增地图模块,用于查找附近设备场地

This commit is contained in:
2025-08-18 14:52:39 +08:00
parent c5b8026fba
commit 38eb05fefd
122 changed files with 8317 additions and 1768 deletions
+207 -132
View File
@@ -1,6 +1,14 @@
"use strict";
const common_vendor = require("../common/vendor.js");
const common_assets = require("../common/assets.js");
if (!Array) {
const _easycom_uv_icon2 = common_vendor.resolveComponent("uv-icon");
_easycom_uv_icon2();
}
const _easycom_uv_icon = () => "../node-modules/@climblee/uv-ui/components/uv-icon/uv-icon.js";
if (!Math) {
_easycom_uv_icon();
}
const _sfc_main = {
__name: "MapComponent",
props: {
@@ -29,41 +37,179 @@ const _sfc_main = {
"mapCenterChange"
],
setup(__props, { expose: __expose, emit: __emit }) {
const collapseRef = common_vendor.ref(null);
common_vendor.ref([
{
title: "扫码使用",
desc: "找到附近设备,扫描设备上的二维码"
},
{
title: "免押金支付",
desc: "无需支付押金,使用支付分免押即可完成租借"
},
{
title: "开始使用",
desc: "设备自动解锁,风扇弹出后取出即可开始使用"
},
{
title: "归还设备",
desc: "使用完毕后,按照设备规格要求将风扇还入即可结束订单"
}
]);
const props = __props;
const emit = __emit;
const mapKey = common_vendor.ref(0);
const mapZoom = common_vendor.ref(16);
const isLoading = common_vendor.ref(true);
const mapCenter = common_vendor.ref({
longitude: 116.397128,
latitude: 39.916527
});
const loadPositionsTimer = common_vendor.ref(null);
const isMapInitialized = common_vendor.ref(false);
const updateMapCenter = (longitude, latitude) => {
if (mapCenter.value.longitude === longitude && mapCenter.value.latitude === latitude) {
return;
}
mapCenter.value = { longitude, latitude };
mapZoom.value = 16;
common_vendor.nextTick$1(() => {
setTimeout(() => {
const mapContext = common_vendor.index.createMapContext("mainMap");
if (mapContext) {
mapContext.setCenterOffset({
longitude,
latitude,
success: () => {
},
fail: () => {
mapContext.includePoints({
points: [{ longitude, latitude }],
padding: [0, 0, 0, 0]
});
}
});
const mapZoom = common_vendor.ref(17);
const mapMarkers = common_vendor.ref([]);
const mapContext = common_vendor.ref(null);
const updateMapMarkers = () => {
mapMarkers.value = [];
if (props.userLocation) {
mapMarkers.value.push({
id: 0,
// ID必须是数字
// iconPath: '/static/scan-icon.png',
width: 32,
height: 32,
latitude: props.userLocation.latitude,
longitude: props.userLocation.longitude,
title: "我的位置",
callout: {
content: "我的位置",
color: "#ffffff",
fontSize: 12,
borderRadius: 4,
bgColor: "#2196F3",
padding: 6,
display: "BYCLICK"
// 点击时显示
},
customCallout: {
anchorX: 0,
anchorY: 0
}
}, 200);
});
});
}
if (props.filteredPositions && props.filteredPositions.length > 0) {
props.filteredPositions.forEach((pos, index) => {
if (pos.longitude && pos.latitude) {
const lat = parseFloat(pos.latitude);
const lng = parseFloat(pos.longitude);
if (lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
mapMarkers.value.push({
id: index + 1,
// ID必须是数字,避免和用户位置的ID冲突
// iconPath: '/static/scan-icon.png',
width: 30,
height: 30,
latitude: lat,
longitude: lng,
title: pos.name,
position: pos,
// 存储原始位置数据,用于事件处理
callout: {
content: pos.name,
color: "#333333",
fontSize: 12,
borderRadius: 4,
bgColor: "#ffffff",
padding: 6,
display: "BYCLICK"
// 点击时显示
}
});
} else {
common_vendor.index.__f__("warn", "at components/MapComponent.vue:176", `忽略无效坐标: ${pos.name}, 纬度=${lat}, 经度=${lng}`);
}
}
});
}
isLoading.value = false;
};
const moveToLocation = (location) => {
if (!location || !location.longitude || !location.latitude)
return;
if (mapContext.value) {
mapContext.value.moveToLocation({
longitude: location.longitude,
latitude: location.latitude,
success: () => {
common_vendor.index.__f__("log", "at components/MapComponent.vue:194", "地图已移动到指定位置");
},
fail: (error) => {
common_vendor.index.__f__("error", "at components/MapComponent.vue:197", "移动地图失败:", error);
}
});
}
};
common_vendor.watch(() => props.userLocation, (newLocation) => {
if (newLocation && newLocation.longitude && newLocation.latitude) {
mapCenter.value = {
longitude: newLocation.longitude,
latitude: newLocation.latitude
};
updateMapMarkers();
moveToLocation(newLocation);
}
}, {
immediate: true,
deep: true
});
common_vendor.watch(() => props.filteredPositions, (newPositions) => {
updateMapMarkers();
}, {
deep: true
});
const onMapUpdated = () => {
isLoading.value = false;
};
const onMapRegionChange = (e) => {
if (e.type === "end" && e.causedBy === "drag") {
if (mapContext.value) {
mapContext.value.getCenterLocation({
success: (res) => {
if (res.longitude && res.latitude) {
mapCenter.value = {
longitude: res.longitude,
latitude: res.latitude
};
emit("mapCenterChange", mapCenter.value);
}
}
});
}
}
};
const onMapMarkerTap = (e) => {
const markerId = e.markerId;
const marker = mapMarkers.value.find((item) => item.id === markerId);
if (marker) {
if (markerId === 0) {
common_vendor.index.showToast({
title: "这是您的位置",
icon: "none"
});
return;
}
if (marker.position) {
emit("markerTap", marker.position);
}
}
};
const onCalloutTap = (e) => {
const markerId = e.markerId;
const marker = mapMarkers.value.find((item) => item.id === markerId);
if (marker && marker.position) {
emit("markerTap", marker.position);
}
};
const onMapError = (error) => {
common_vendor.index.__f__("error", "at components/MapComponent.vue:283", "地图加载失败:", error);
isLoading.value = false;
};
const handleRelocate = () => {
emit("relocate");
@@ -74,121 +220,50 @@ const _sfc_main = {
const handleShowList = () => {
emit("showList");
};
const handleMarkerTap = (e) => {
if (!e.detail || typeof e.detail.markerId === "undefined") {
return;
}
const markerId = e.detail.markerId;
if (markerId === 9999) {
common_vendor.index.showToast({
title: "这是您的位置",
icon: "none"
});
return;
}
const position = props.filteredPositions[markerId];
if (position) {
emit("markerTap", position);
}
};
const handleRegionChange = (e) => {
if (e.detail.type === "end") {
const { center } = e.detail;
if (!center || typeof center.longitude === "undefined" || typeof center.latitude === "undefined") {
return;
}
mapCenter.value = {
longitude: center.longitude,
latitude: center.latitude
};
mapZoom.value = 16;
if (loadPositionsTimer.value) {
clearTimeout(loadPositionsTimer.value);
}
loadPositionsTimer.value = setTimeout(() => {
emit("mapCenterChange", mapCenter.value);
}, 500);
}
};
const mapMarkers = common_vendor.computed(() => {
const markers = [];
props.filteredPositions.forEach((item, index) => {
if (item.longitude && item.latitude) {
markers.push({
id: index,
longitude: parseFloat(item.longitude),
latitude: parseFloat(item.latitude),
title: item.name,
iconPath: "/static/scan-icon.png",
width: 30,
height: 30,
callout: {
content: item.name,
fontSize: 14,
borderRadius: 8,
bgColor: "#ffffff",
padding: 10,
display: "BYCLICK"
}
});
common_vendor.onMounted(() => {
common_vendor.nextTick$1(() => {
mapContext.value = common_vendor.index.createMapContext("map");
updateMapMarkers();
if (collapseRef.value) {
collapseRef.value.init();
}
});
if (props.userLocation) {
markers.push({
id: 9999,
// 特殊ID标识用户位置
longitude: props.userLocation.longitude,
latitude: props.userLocation.latitude,
title: "我的位置",
iconPath: "/static/scan-icon.png",
width: 32,
height: 32,
callout: {
content: "我的位置",
fontSize: 14,
borderRadius: 8,
bgColor: "#2196F3",
color: "#ffffff",
padding: 10,
display: "BYCLICK"
}
});
}
return markers;
});
common_vendor.watch(() => props.userLocation, (newLocation) => {
if (newLocation && newLocation.longitude && newLocation.latitude && !isMapInitialized.value) {
updateMapCenter(newLocation.longitude, newLocation.latitude);
isMapInitialized.value = true;
}
}, { immediate: true, deep: true });
common_vendor.onMounted(() => {
});
common_vendor.onUnmounted(() => {
if (loadPositionsTimer.value) {
clearTimeout(loadPositionsTimer.value);
}
mapContext.value = null;
});
__expose({
mapCenter: common_vendor.computed(() => mapCenter.value)
mapCenter: common_vendor.computed(() => mapCenter.value),
moveToLocation,
updateMapMarkers,
initCollapse: () => {
if (collapseRef.value) {
collapseRef.value.init();
}
}
});
return (_ctx, _cache) => {
return common_vendor.e({
a: mapKey.value,
b: mapCenter.value.longitude,
c: mapCenter.value.latitude,
a: mapCenter.value.longitude,
b: mapCenter.value.latitude,
c: mapMarkers.value,
d: mapZoom.value,
e: mapMarkers.value,
f: common_vendor.o(handleMarkerTap),
g: common_vendor.o(handleRegionChange),
h: !mapCenter.value.longitude
}, !mapCenter.value.longitude ? {} : {}, {
i: common_assets._imports_0,
j: common_vendor.o(handleRelocate),
k: common_assets._imports_0,
l: common_vendor.o(handleScan),
e: common_vendor.o(onMapRegionChange),
f: common_vendor.o(onMapMarkerTap),
g: common_vendor.o(onCalloutTap),
h: common_vendor.o(onMapUpdated),
i: common_vendor.o(onMapError),
j: isLoading.value
}, isLoading.value ? {} : {}, {
k: common_vendor.p({
name: "map-fill",
size: "18"
}),
l: common_vendor.o(handleRelocate),
m: common_assets._imports_0,
n: common_vendor.o(handleShowList)
n: common_vendor.o(handleScan),
o: common_assets._imports_1$1,
p: common_vendor.o(handleShowList)
});
};
}
+3 -1
View File
@@ -1,4 +1,6 @@
{
"component": true,
"usingComponents": {}
"usingComponents": {
"uv-icon": "../node-modules/@climblee/uv-ui/components/uv-icon/uv-icon"
}
}
+1 -1
View File
@@ -1 +1 @@
<view class="map-container data-v-651a9dc3"><map id="mainMap" class="map data-v-651a9dc3" key="{{a}}" longitude="{{b}}" latitude="{{c}}" scale="{{d}}" markers="{{e}}" show-location="{{false}}" enable-scroll="{{true}}" enable-zoom="{{true}}" enable-rotate="{{false}}" show-compass="{{false}}" bindmarkertap="{{f}}" bindregionchange="{{g}}"></map><view wx:if="{{h}}" class="map-loading data-v-651a9dc3"><view class="loading-content data-v-651a9dc3"><view class="loading-spinner data-v-651a9dc3"></view><text class="data-v-651a9dc3">地图加载中...</text></view></view><view class="map-controls data-v-651a9dc3"><view class="control-btn location-control data-v-651a9dc3" bindtap="{{j}}"><image class="control-icon data-v-651a9dc3" src="{{i}}" mode="aspectFit"/><text class="data-v-651a9dc3">我的位置</text></view><view class="control-btn scan-control main-btn data-v-651a9dc3" bindtap="{{l}}"><image class="control-icon data-v-651a9dc3" src="{{k}}" mode="aspectFit"/><text class="data-v-651a9dc3">扫码使用</text></view><view class="control-btn list-control data-v-651a9dc3" bindtap="{{n}}"><image class="control-icon data-v-651a9dc3" src="{{m}}" mode="aspectFit"/><text class="data-v-651a9dc3">附近场地</text></view></view></view>
<view class="map-container data-v-651a9dc3"><view class="map-wrapper data-v-651a9dc3"><map id="map" class="native-map data-v-651a9dc3" longitude="{{a}}" latitude="{{b}}" markers="{{c}}" scale="{{d}}" show-location="{{true}}" bindregionchange="{{e}}" bindmarkertap="{{f}}" bindcallouttap="{{g}}" bindupdated="{{h}}" binderror="{{i}}"></map><view wx:if="{{j}}" class="map-loading data-v-651a9dc3"><view class="loading-content data-v-651a9dc3"><view class="loading-spinner data-v-651a9dc3"></view><text class="data-v-651a9dc3">地图加载中...</text></view></view></view><view class="map-controls data-v-651a9dc3"><view class="control-btn location-control data-v-651a9dc3" bindtap="{{l}}"><uv-icon wx:if="{{k}}" class="data-v-651a9dc3" u-i="651a9dc3-0" bind:__l="__l" u-p="{{k}}"></uv-icon><text class="data-v-651a9dc3" style="margin-left:8rpx">我的位置</text></view><view class="control-btn scan-control main-btn data-v-651a9dc3" bindtap="{{n}}"><image class="control-icon data-v-651a9dc3" src="{{m}}" mode="aspectFit"/><text class="data-v-651a9dc3">扫码使用</text></view><view class="control-btn list-control data-v-651a9dc3" bindtap="{{p}}"><image class="control-icon data-v-651a9dc3" src="{{o}}" mode="aspectFit"/><text class="data-v-651a9dc3">附近设备</text></view></view></view>
+37 -12
View File
@@ -27,12 +27,33 @@
.map-container.data-v-651a9dc3 {
flex: 1;
position: relative;
height: 100vh;
width: 100%;
height: 60vh;
/* 增加高度 */
width: 92%;
/* 略微增加宽度 */
margin: 10rpx auto 30rpx;
/* 调整上下间距,左右自动居中 */
border-radius: 24rpx;
/* 添加圆角 */
overflow: hidden;
/* 确保圆角生效 */
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
/* 添加阴影效果 */
}
.map-container .map.data-v-651a9dc3 {
.map-container .map-wrapper.data-v-651a9dc3 {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
border-radius: 24rpx;
/* 内层也添加圆角 */
}
.map-container .map-wrapper .native-map.data-v-651a9dc3 {
width: 100%;
height: 100%;
display: block;
border-radius: 24rpx;
/* 地图也添加圆角 */
}
.map-container .map-loading.data-v-651a9dc3 {
position: absolute;
@@ -68,26 +89,28 @@
}
.map-container .map-controls.data-v-651a9dc3 {
position: absolute;
right: 30rpx;
right: 20rpx;
bottom: 20rpx;
left: 30rpx;
left: 20rpx;
display: flex;
justify-content: center;
align-items: center;
gap: 30rpx;
gap: 20rpx;
}
.map-container .map-controls .control-btn.data-v-651a9dc3 {
min-width: 140rpx;
height: 80rpx;
min-width: 120rpx;
/* 减小按钮宽度 */
height: 70rpx;
/* 减小按钮高度 */
background: #ffffff;
border-radius: 40rpx;
border-radius: 35rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
padding: 0 20rpx;
padding: 0 16rpx;
}
.map-container .map-controls .control-btn.data-v-651a9dc3:active {
transform: scale(0.95);
@@ -104,8 +127,10 @@
font-weight: 500;
}
.map-container .map-controls .control-btn.main-btn.data-v-651a9dc3 {
min-width: 160rpx;
height: 90rpx;
min-width: 140rpx;
/* 减小主按钮宽度 */
height: 80rpx;
/* 减小主按钮高度 */
box-shadow: 0 6rpx 20rpx rgba(33, 150, 243, 0.4);
transform: translateY(-5rpx);
}