consumer-app/pages/detail/mapDetail.vue

493 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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"
:src="storeInfo.coverUrl"
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>