style:根据UI设计图跳转页面样式

This commit is contained in:
2025-10-15 01:35:23 +08:00
parent 4408673438
commit 46179c5d3f
30 changed files with 4632 additions and 2459 deletions
+169 -215
View File
@@ -3,11 +3,13 @@
<!-- 地图容器 -->
<view class="map-wrapper">
<!-- 使用小程序原生地图组件 -->
<map id="map" class="native-map" :longitude="mapCenter.longitude" :latitude="mapCenter.latitude"
<map id="map" class="native-map" :longitude="mapCenter.longitude" :latitude="mapCenter.latitude"
:markers="mapMarkers" :scale="mapZoom" :show-location="true" @regionchange="onMapRegionChange"
@markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated"
@error="onMapError">
@markertap="onMapMarkerTap" @callouttap="onCalloutTap" @updated="onMapUpdated" @error="onMapError">
<!-- 覆盖在地图上的可点击控件使用 cover-view 以兼容小程序原生组件层级 -->
<cover-view class="index-swiper">
<image src="/static/index_swiper.png" class="index-swiper" mode="aspectFit"></image>
</cover-view>
<cover-view class="map-side-controls">
<cover-view class="side-btn service" @tap="handleService">
<cover-image class="side-icon" src="/static/customer-service.png"></cover-image>
@@ -22,11 +24,9 @@
<!-- <cover-view class="side-text">定位</cover-view> -->
</cover-view>
</cover-view>
<!-- 使用原生 marker 方案渲染中心指示 regionchange 同步到地图中心 -->
<!-- 使用原生 marker 方案渲染中心指示 regionchange 同步到地图中心 -->
</map>
<!-- 地图加载状态 -->
<view class="map-loading" v-if="isLoading">
<view class="loading-content">
@@ -39,15 +39,15 @@
</template>
<script setup>
import {
ref,
computed,
watch,
onMounted,
onUnmounted,
nextTick,
getCurrentInstance
} from 'vue'
import {
ref,
computed,
watch,
onMounted,
onUnmounted,
nextTick,
getCurrentInstance
} from 'vue'
// 导入地图工具函数
import {
calculateDistanceSync
@@ -76,7 +76,7 @@ import {
])
// Props
const props = defineProps({
const props = defineProps({
userLocation: {
type: Object,
default: null
@@ -92,15 +92,15 @@ import {
searchKeyword: {
type: String,
default: ''
},
noticeText: {
type: String,
default: ''
},
enableMarkers: {
type: Boolean,
default: false
}
},
noticeText: {
type: String,
default: ''
},
enableMarkers: {
type: Boolean,
default: false
}
})
// Emits
@@ -123,73 +123,79 @@ import {
const mapContext = ref(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)) {
markers.push({
id: 999999, // 固定 id 作为中心点
latitude: centerLat,
longitude: centerLng,
iconPath: '/static/location-icon.png',
width: 30,
height: 40,
anchor: { x: 0.5, y: 1 } // 图钉尖端对准坐标
})
}
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)) {
markers.push({
id: 999999, // 固定 id 作为中心点
latitude: centerLat,
longitude: centerLng,
iconPath: '/static/location-icon.png',
width: 30,
height: 40,
anchor: {
x: 0.5,
y: 1
} // 图钉尖端对准坐标
})
}
// 可选:周边位置点
if (props.enableMarkers && 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) {
markers.push({
id: index + 1,
latitude: lat,
longitude: lng,
width: 24,
height: 24,
title: pos.name
})
}
}
})
}
// 可选:周边位置点
if (props.enableMarkers && 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) {
markers.push({
id: index + 1,
latitude: lat,
longitude: lng,
width: 24,
height: 24,
title: pos.name
})
}
}
})
}
mapMarkers.value = markers
isLoading.value = false
}
mapMarkers.value = markers
isLoading.value = false
}
// 移动地图到指定位置(使用 includePoints 以避免 mapid 错误,并兼容不同基础库)
const moveToLocation = (location) => {
if (!location || !location.longitude || !location.latitude) return
if (!mapContext.value) return
// 移动地图到指定位置(使用 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)
}
}
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)
}
}
// 监听用户位置变化
watch(() => props.userLocation, (newLocation) => {
@@ -219,26 +225,26 @@ const moveToLocation = (location) => {
}
// 地图区域变化事件
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)
}
}
})
}
}
}
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)
}
}
})
}
}
}
// 标记点点击事件
const onMapMarkerTap = (e) => {
@@ -276,55 +282,23 @@ const moveToLocation = (location) => {
isLoading.value = false
}
const handleRelocate = () => {
// 直接委托父级处理定位并移动地图,避免内部重复弹 loading
try {
emit('relocate')
} catch (e) {}
}
const handleSearch = () => {
// 选择位置后移动地图并通知父组件刷新附近列表(增强容错与平台兼容)
const onSuccess = (res) => {
try {
const lng = Number(res.longitude)
const lat = Number(res.latitude)
if (!isNaN(lng) && !isNaN(lat)) {
const center = { longitude: lng, latitude: lat }
moveToLocation(center)
emit('mapCenterChange', center)
} else {
uni.showToast({ title: '无效的坐标', icon: 'none' })
}
} catch (e) {
console.error('处理选择位置结果异常:', e)
}
}
const onFail = (err) => {
console.error('chooseLocation 失败:', err)
// 授权被拒时引导开启
if (err && (String(err.errMsg || '').includes('auth') || String(err.errMsg || '').includes('deny'))) {
// #ifdef MP-WEIXIN
wx.openSetting && wx.openSetting({})
// #endif
}
// uni.showToast({ title: '无法打开选择位置', icon: 'none' })
}
// #ifdef MP-WEIXIN
if (typeof wx !== 'undefined' && wx.chooseLocation) {
wx.chooseLocation({ success: onSuccess, fail: onFail })
return
}
// #endif
if (uni && typeof uni.chooseLocation === 'function') {
uni.chooseLocation({ success: onSuccess, fail: onFail })
} else {
uni.showToast({ title: '当前环境不支持选择位置', icon: 'none' })
}
const handleRelocate = () => {
// 直接委托父级处理定位并移动地图,避免内部重复弹 loading
try {
emit('relocate')
} catch (e) {}
}
const handleSearch = () => {
try {
uni.navigateTo({ url: '/pages/search/index' })
} catch (e) {}
}
const handleService = () => {
uni.navigateTo({ url: '/pages/help/index' })
uni.navigateTo({
url: '/pages/help/index'
})
}
const handleScan = () => {
@@ -336,26 +310,26 @@ const handleRelocate = () => {
}
// 生命周期钩子
onMounted(() => {
// 初始化地图上下文
nextTick(() => {
// 需要使用nextTick确保地图组件已经渲染
const inst = getCurrentInstance()
const vm = (inst && (inst.proxy || inst)) || undefined
try {
mapContext.value = uni.createMapContext('map', vm)
} catch (e) {
// 兼容:如果第二参不被支持,退回单参
mapContext.value = uni.createMapContext('map')
}
updateMapMarkers()
onMounted(() => {
// 初始化地图上下文
nextTick(() => {
// 需要使用nextTick确保地图组件已经渲染
const inst = getCurrentInstance()
const vm = (inst && (inst.proxy || inst)) || undefined
try {
mapContext.value = uni.createMapContext('map', vm)
} catch (e) {
// 兼容:如果第二参不被支持,退回单参
mapContext.value = uni.createMapContext('map')
}
updateMapMarkers()
// 初始化折叠面板
if (collapseRef.value) {
collapseRef.value.init()
}
})
})
// 初始化折叠面板
if (collapseRef.value) {
collapseRef.value.init()
}
})
})
onUnmounted(() => {
// 清理工作
@@ -447,7 +421,7 @@ onMounted(() => {
}
}
}
/* 地图中心图钉(cover-view,避免使用 transform 以兼容小程序) */
.center-pin {
position: absolute;
@@ -479,7 +453,7 @@ onMounted(() => {
.map-side-controls {
position: absolute;
left: 20rpx;
right: 20rpx;
bottom: 20rpx;
display: flex;
flex-direction: column;
@@ -492,7 +466,7 @@ onMounted(() => {
.side-btn {
// min-width: 160rpx;
margin: auto;
height: 72rpx;
// height: 72rpx;
background: rgba(255, 255, 255, 0.96);
border-radius: 36rpx;
display: inline-flex;
@@ -500,7 +474,7 @@ onMounted(() => {
align-items: center;
justify-content: center;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.12);
padding: 0 18rpx;
padding: 20rpx;
border: 2rpx solid #e0e0e0;
&:active {
@@ -514,40 +488,9 @@ onMounted(() => {
font-weight: 500;
}
&.search {
border-color: #07c160;
}
}
}
/* 展示用图标列(与 cover-view 对齐) */
.map-side-icons {
position: absolute;
left: 20rpx;
bottom: 20rpx;
display: flex;
flex-direction: column;
gap: 12rpx;
.side-btn {
min-width: 160rpx;
height: 72rpx;
background: rgba(255, 255, 255, 0.96);
border-radius: 36rpx;
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.12);
padding: 0 18rpx;
border: 2rpx solid #e0e0e0;
.label {
margin-left: 8rpx;
font-size: 26rpx;
color: #333;
font-weight: 500;
}
// &.search {
// border-color: #07c160;
// }
}
}
}
@@ -562,9 +505,20 @@ onMounted(() => {
}
}
.side-icon{
width: 32rpx;
height: 32rpx;
.side-icon {
width: 44rpx;
height: 44rpx;
}
.index-swiper {
width: 92vw;
height: 180rpx;
border-radius: 20rpx;
z-index: 1000;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
right: 0;
}
</style>