consumer-app/pages/detail/mapDetail.vue

493 lines
12 KiB
Vue
Raw Normal View History

2025-12-19 12:27:55 +00:00
<template>
<view class="map-detail-page">
<!-- 顶部导航栏 -->
<NavHeader title="店铺位置" />
<!-- 地图区域 -->
<view class="map-container" v-if="mapInitialized">
<map
id="storeMap"
class="map"
:latitude="mapCenter.latitude"
:longitude="mapCenter.longitude"
:markers="markers"
:scale="16"
:show-location="false"
:enable-zoom="false"
:enable-scroll="false"
:enable-rotate="false"
:enable-poi="true"
></map>
</view>
<view class="map-container" v-else>
<view class="map-placeholder">
<text>加载地图中...</text>
</view>
</view>
<!-- 店铺信息卡片悬浮在下方 -->
<view class="store-card" v-if="storeInfo.id">
<view class="store-card-content">
<!-- 左侧店铺图片 -->
<view class="store-image-wrapper">
<image
class="store-image"
2026-01-14 10:55:42 +00:00
:src="storeInfo.coverUrl"
2025-12-19 12:27:55 +00:00
mode="aspectFill"
></image>
</view>
<!-- 右侧店铺信息 -->
<view class="store-info">
<view class="store-title-row">
<text class="store-name">{{ storeInfo.name }}</text>
<view class="distance-info">
<image
class="location-icon"
src="/static/service/location-icon.png"
mode="aspectFill"
></image>
<text class="distance-text">{{ storeInfo.distance || "0" }}km</text>
</view>
</view>
<view class="store-detail">
<text class="detail-label">门店地址:</text>
<text class="detail-value">{{
storeInfo.address || "暂无地址"
}}</text>
</view>
<view class="store-detail">
<text class="detail-label">联系电话:</text>
<text class="detail-value">{{
storeInfo.phone || "暂无电话"
}}</text>
</view>
<view class="store-tags-row">
<view class="store-tags">
<view class="tag-item tag-pink">会员特惠</view>
<view class="tag-item tag-orange" v-if="storeInfo.typeName">{{
storeInfo.typeName
}}</view>
</view>
</view>
<!-- <view class="enter-store-btn" @click="handleEnterStore"> </view> -->
</view>
</view>
</view>
<!-- 加载中提示 -->
<view class="loading-mask" v-if="loading">
<text class="loading-text">加载中...</text>
</view>
</view>
</template>
<script>
import { getGuildStoreDetail } from "@/api/service";
import NavHeader from "@/components/NavHeader/NavHeader.vue";
export default {
components: {
NavHeader
},
data() {
return {
shopId: null,
storeInfo: {},
loading: false,
// 地图中心点(初始值,加载数据后会更新)
mapCenter: {
latitude: 39.908823,
longitude: 116.39747,
},
// 地图标记点
markers: [],
// 用户当前位置
userLocation: null,
// 地图是否已初始化(避免重复移动)
mapInitialized: false,
};
},
computed: {
// // 计算距离文本
// distanceText() {
// if (
// !this.userLocation ||
// !this.storeInfo.latitude ||
// !this.storeInfo.longitude
// ) {
// return "计算中...";
// }
// const distance = this.calculateDistance(
// this.userLocation.latitude,
// this.userLocation.longitude,
// this.storeInfo.latitude,
// this.storeInfo.longitude
// );
// return distance < 1
// ? `${(distance * 1000).toFixed(0)}m`
// : `${distance.toFixed(1)}km`;
// },
},
onLoad(options) {
this.shopId = options.id;
if (this.shopId) {
// 从存储中读取用户位置信息
this.loadUserLocation();
this.loadStoreDetail();
} else {
uni.showToast({
title: "店铺信息错误",
icon: "none",
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
},
methods: {
// 获取系统信息
// 从存储中加载用户位置信息
loadUserLocation() {
const savedLocation = uni.getStorageSync("userLocation");
if (savedLocation && savedLocation.latitude && savedLocation.longitude) {
this.userLocation = savedLocation;
}
},
// 验证经纬度是否有效
isValidCoordinate(lat, lng) {
const latitude = parseFloat(lat);
const longitude = parseFloat(lng);
// 纬度范围:-90 到 90经度范围-180 到 180
return (
!isNaN(latitude) &&
!isNaN(longitude) &&
latitude >= -90 &&
latitude <= 90 &&
longitude >= -180 &&
longitude <= 180
);
},
// 加载店铺详情
async loadStoreDetail() {
if (!this.shopId) return;
this.loading = true;
try {
const res = await getGuildStoreDetail(this.shopId);
if (res) {
this.storeInfo = res;
// 设置地图中心点和标记
if (res.latitude && res.longitude) {
// 验证经纬度是否有效
if (this.isValidCoordinate(res.latitude, res.longitude)) {
// 直接设置地图中心点,避免从默认位置移动
this.mapCenter = {
latitude: parseFloat(res.latitude),
longitude: parseFloat(res.longitude),
};
this.setMapMarkers();
// 标记地图已初始化,此时再显示地图,避免移动动画
this.$nextTick(() => {
this.mapInitialized = true;
});
} else {
console.warn("店铺经纬度无效:", res.latitude, res.longitude);
uni.showToast({
title: "店铺位置信息无效",
icon: "none",
});
// 即使经纬度无效,也显示地图(使用默认位置)
this.mapInitialized = true;
}
} else {
// 如果没有经纬度,也显示地图(使用默认位置)
this.mapInitialized = true;
}
}
} catch (error) {
console.error("加载店铺详情失败:", error);
uni.showToast({
title: "加载店铺信息失败",
icon: "none",
});
// 即使加载失败,也显示地图
this.mapInitialized = true;
} finally {
this.loading = false;
}
},
// 设置地图标记点
setMapMarkers() {
if (!this.storeInfo.latitude || !this.storeInfo.longitude) return;
const lat = parseFloat(this.storeInfo.latitude);
const lng = parseFloat(this.storeInfo.longitude);
// 再次验证经纬度有效性
if (!this.isValidCoordinate(lat, lng)) {
console.warn("标记点经纬度无效:", lat, lng);
return;
}
this.markers = [
{
id: 1,
latitude: lat,
longitude: lng,
title: this.storeInfo.name || "店铺位置",
width: 30,
height: 30,
callout: {
content: this.storeInfo.name || "店铺位置",
color: "#333333",
fontSize: 14,
borderRadius: 4,
bgColor: "#ffffff",
padding: 8,
display: "BYCLICK", // 点击时显示
},
},
];
},
// 计算两点之间的距离单位km
calculateDistance(lat1, lng1, lat2, lng2) {
// 验证坐标有效性
if (
!this.isValidCoordinate(lat1, lng1) ||
!this.isValidCoordinate(lat2, lng2)
) {
return 0;
}
const R = 6371; // 地球半径km
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLng = ((lng2 - lng1) * Math.PI) / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos((lat1 * Math.PI) / 180) *
Math.cos((lat2 * Math.PI) / 180) *
Math.sin(dLng / 2) *
Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
},
// // 进店按钮点击
// handleEnterStore() {
// uni.navigateTo({
// url: `/pages/detail/serviceDetail?id=${this.shopId}`,
// });
// },
},
};
</script>
<style lang="scss" scoped>
.map-detail-page {
height: 100vh;
background-color: #f5f5f5;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 地图容器 */
.map-container {
width: 100%;
flex: 1;
position: relative;
overflow: hidden;
.map {
width: 100%;
height: 100%;
}
.map-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 28rpx;
color: #999999;
}
}
}
/* 店铺信息卡片 */
.store-card {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
// height: 40vh;
background-color: #ffffff;
border-radius: 24rpx 24rpx 0 0;
.store-card-content {
display: flex;
padding: 30rpx;
gap: 24rpx;
}
.store-image-wrapper {
width: 186rpx;
height: 200rpx;
flex-shrink: 0;
border-radius: 12rpx;
overflow: hidden;
.store-image {
width: 100%;
height: 100%;
}
}
.store-info {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
.store-title-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
.store-name {
flex: 1;
font-family: PingFang-SC, PingFang-SC;
font-weight: bold;
font-size: 30rpx;
color: #1a1819;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 16rpx;
}
.distance-info {
display: flex;
align-items: center;
flex-shrink: 0;
.location-icon {
width: 17rpx;
height: 20rpx;
margin-right: 8rpx;
}
.distance-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: bold;
font-size: 22rpx;
color: #004294;
}
}
}
.store-detail {
display: flex;
align-items: flex-start;
margin-bottom: 12rpx;
line-height: 1.5;
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 22rpx;
color: #888888;
.detail-label {
margin-right: 8rpx;
flex-shrink: 0;
}
.detail-value {
flex: 1;
word-break: break-all;
}
}
.store-tags-row {
display: flex;
align-items: center;
margin-bottom: 16rpx;
.store-tags {
display: flex;
align-items: center;
gap: 12rpx;
flex: 1;
.tag-item {
padding: 7rpx 12rpx;
font-size: 20rpx;
border-radius: 4rpx;
&.tag-pink {
background-color: rgba(213, 28, 60, 0.1);
color: #d51c3c;
border: 1rpx solid #d51c3c;
}
&.tag-orange {
background-color: rgba(255, 107, 0, 0.1);
color: #ff6b00;
border: 1rpx solid #ff6b00;
}
}
}
}
.enter-store-btn {
align-self: flex-end;
padding: 12rpx 40rpx;
background: #004294;
border-radius: 25rpx;
font-family: PingFang-SC, PingFang-SC;
font-weight: bold;
font-size: 26rpx;
color: #ffffff;
margin-top: auto;
}
}
}
/* 加载中遮罩 */
.loading-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
.loading-text {
font-family: PingFang-SC, PingFang-SC;
font-weight: 500;
font-size: 28rpx;
color: #ffffff;
}
}
</style>