feat:新增地图视图效果,接口待对接

This commit is contained in:
2025-08-08 14:51:45 +08:00
parent 67eb4e5516
commit c5b8026fba
49 changed files with 2811 additions and 884 deletions
+198
View File
@@ -0,0 +1,198 @@
"use strict";
const common_vendor = require("../common/vendor.js");
const common_assets = require("../common/assets.js");
const _sfc_main = {
__name: "MapComponent",
props: {
userLocation: {
type: Object,
default: null
},
positionList: {
type: Array,
default: () => []
},
filteredPositions: {
type: Array,
default: () => []
},
searchKeyword: {
type: String,
default: ""
}
},
emits: [
"relocate",
"scan",
"showList",
"markerTap",
"mapCenterChange"
],
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emit = __emit;
const mapKey = common_vendor.ref(0);
const mapZoom = common_vendor.ref(16);
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]
});
}
});
}
}, 200);
});
};
const handleRelocate = () => {
emit("relocate");
};
const handleScan = () => {
emit("scan");
};
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"
}
});
}
});
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);
}
});
__expose({
mapCenter: common_vendor.computed(() => mapCenter.value)
});
return (_ctx, _cache) => {
return common_vendor.e({
a: mapKey.value,
b: mapCenter.value.longitude,
c: mapCenter.value.latitude,
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),
m: common_assets._imports_0,
n: common_vendor.o(handleShowList)
});
};
}
};
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-651a9dc3"]]);
wx.createComponent(Component);
//# sourceMappingURL=../../.sourcemap/mp-weixin/components/MapComponent.js.map
@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}
@@ -0,0 +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>
@@ -0,0 +1,159 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
/* 文字基本颜色 */
/* 背景颜色 */
/* 边框颜色 */
/* 尺寸变量 */
/* 文字尺寸 */
/* 图片尺寸 */
/* Border Radius */
/* 水平间距 */
/* 垂直间距 */
/* 透明度 */
/* 文章场景相关 */
/* 地图容器 */
.map-container.data-v-651a9dc3 {
flex: 1;
position: relative;
height: 100vh;
width: 100%;
}
.map-container .map.data-v-651a9dc3 {
width: 100%;
height: 100%;
}
.map-container .map-loading.data-v-651a9dc3 {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
}
.map-container .map-loading .loading-content.data-v-651a9dc3 {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.map-container .map-loading .loading-content .loading-spinner.data-v-651a9dc3 {
width: 60rpx;
height: 60rpx;
border: 8rpx solid #f3f3f3;
border-top: 8rpx solid #3498db;
border-radius: 50%;
animation: spin-651a9dc3 1s linear infinite;
margin-bottom: 20rpx;
}
.map-container .map-loading .loading-content text.data-v-651a9dc3 {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
.map-container .map-controls.data-v-651a9dc3 {
position: absolute;
right: 30rpx;
bottom: 20rpx;
left: 30rpx;
display: flex;
justify-content: center;
align-items: center;
gap: 30rpx;
}
.map-container .map-controls .control-btn.data-v-651a9dc3 {
min-width: 140rpx;
height: 80rpx;
background: #ffffff;
border-radius: 40rpx;
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;
}
.map-container .map-controls .control-btn.data-v-651a9dc3:active {
transform: scale(0.95);
}
.map-container .map-controls .control-btn .control-icon.data-v-651a9dc3 {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
}
.map-container .map-controls .control-btn text.data-v-651a9dc3 {
font-size: 26rpx;
color: #333;
white-space: nowrap;
font-weight: 500;
}
.map-container .map-controls .control-btn.main-btn.data-v-651a9dc3 {
min-width: 160rpx;
height: 90rpx;
box-shadow: 0 6rpx 20rpx rgba(33, 150, 243, 0.4);
transform: translateY(-5rpx);
}
.map-container .map-controls .control-btn.main-btn .control-icon.data-v-651a9dc3 {
width: 36rpx;
height: 36rpx;
margin-right: 16rpx;
}
.map-container .map-controls .control-btn.main-btn text.data-v-651a9dc3 {
font-size: 28rpx;
font-weight: 600;
}
.map-container .map-controls .control-btn.main-btn.data-v-651a9dc3:active {
transform: translateY(-5rpx) scale(0.95);
}
.map-container .map-controls .scan-control.data-v-651a9dc3 {
background: #2196F3;
}
.map-container .map-controls .scan-control .control-icon.data-v-651a9dc3 {
filter: brightness(0) invert(1);
}
.map-container .map-controls .scan-control text.data-v-651a9dc3 {
color: #ffffff;
}
.map-container .map-controls .list-control.data-v-651a9dc3 {
background: #4CAF50;
}
.map-container .map-controls .list-control .control-icon.data-v-651a9dc3 {
filter: brightness(0) invert(1);
}
.map-container .map-controls .list-control text.data-v-651a9dc3 {
color: #ffffff;
}
.map-container .map-controls .location-control.data-v-651a9dc3 {
background: #ffffff;
border: 2rpx solid #e0e0e0;
}
.map-container .map-controls .location-control .control-icon.data-v-651a9dc3 {
filter: none;
}
.map-container .map-controls .location-control text.data-v-651a9dc3 {
color: #333;
}
@keyframes spin-651a9dc3 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}