Browse Source

feat(地图组件): 新增地图卡片组件并集成到详情页

添加可交互的地图卡片组件,支持显示位置标记和地址信息
在工作和租房详情页中集成地图组件,当有经纬度时显示地图
优化callPhone组件,增加悬浮窗模式并添加动画效果
将createBrowseRecordParams参数从orderId改为formId以保持一致性
master
前端-胡立永 2 days ago
parent
commit
65125a6465
6 changed files with 362 additions and 46 deletions
  1. +168
    -0
      components/base/mapCard.vue
  2. +116
    -5
      components/user/callPhone.vue
  3. +2
    -2
      config/browseConfig.js
  4. +45
    -29
      pages_order/renting/rentingDetail.vue
  5. +27
    -10
      pages_order/work/workDetail.vue
  6. +4
    -0
      static/image/location-marker.svg

+ 168
- 0
components/base/mapCard.vue View File

@ -0,0 +1,168 @@
<template>
<view class="map-card">
<!-- 地图区域 -->
<view class="map-container">
<map
:latitude="latitude"
:longitude="longitude"
:markers="markers"
:show-location="false"
:enable-zoom="false"
:enable-scroll="false"
:enable-rotate="false"
:enable-overlooking="false"
:enable-traffic="false"
class="map"
@tap="onMapTap"
></map>
</view>
<!-- 地址信息区域 -->
<view class="address-container">
<view class="address-name">{{ addressName }}</view>
<view class="address-detail" v-if="addressDetail">{{ addressDetail }}</view>
</view>
</view>
</template>
<script>
export default {
name: 'MapCard',
props: {
//
latitude: {
type: [Number, String],
required: true,
default: 39.908823
},
//
longitude: {
type: [Number, String],
required: true,
default: 116.397470
},
//
addressName: {
type: String,
required: true,
default: '位置信息'
},
//
addressDetail: {
type: String,
default: ''
},
//
mapHeight: {
type: [Number, String],
default: 300
},
//
clickable: {
type: Boolean,
default: true
}
},
computed: {
//
markers() {
return [{
id: 1,
latitude: Number(this.latitude),
longitude: Number(this.longitude),
iconPath: '/static/image/location-marker.svg',
width: 30,
height: 30,
callout: {
content: this.addressName,
color: '#333333',
fontSize: 12,
borderRadius: 4,
bgColor: '#ffffff',
padding: 8,
display: 'ALWAYS'
}
}]
}
},
methods: {
//
onMapTap() {
if (this.clickable) {
this.$emit('mapClick', {
latitude: this.latitude,
longitude: this.longitude,
addressName: this.addressName
});
//
this.openLocation();
}
},
//
openLocation() {
uni.openLocation({
latitude: Number(this.latitude),
longitude: Number(this.longitude),
name: this.addressName,
address: this.addressDetail || this.addressName,
success: () => {
console.log('打开地图成功');
},
fail: (err) => {
console.error('打开地图失败:', err);
uni.showToast({
title: '打开地图失败',
icon: 'none'
});
}
});
}
}
}
</script>
<style lang="scss" scoped>
.map-card {
background: $uni-bg-color;
border-radius: $uni-border-radius-lg;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin: $uni-spacing-row-base;
}
.map-container {
position: relative;
height: 300rpx;
.map {
width: 100%;
height: 100%;
}
}
.address-container {
padding: $uni-spacing-row-lg $uni-spacing-row-base;
background: $uni-bg-color;
.address-name {
font-size: $uni-font-size-lg;
color: $uni-text-color;
font-weight: 500;
margin-bottom: $uni-spacing-col-sm;
line-height: 1.4;
}
.address-detail {
font-size: $uni-font-size-sm;
color: $uni-text-color-grey;
line-height: 1.4;
}
}
//
.map-card:active {
background: $uni-bg-color-hover;
}
</style>

+ 116
- 5
components/user/callPhone.vue View File

@ -1,8 +1,19 @@
<template> <template>
<view class="phone" v-if="phone" @click.stop="callPhone">
<image src="/static/image/home/phone.png" mode="widthFix"></image>
{{ title || '联系' + ta[sexName] }}
</view>
<view>
<!-- 普通模式 -->
<view v-if="!showModel" class="phone" v-show="phone" @click.stop="callPhone">
<image src="/static/image/home/phone.png" mode="widthFix"></image>
{{ title || '联系' + ta[sexName] }}
</view>
<!-- 悬浮窗模式 -->
<view v-else v-show="phone" class="phone-modal" @click.stop="callPhone">
<view class="phone-modal-content">
<image src="/static/image/home/phone.png" mode="widthFix"></image>
<text class="phone-modal-text">{{ title || '联系' + ta[sexName] }}</text>
</view>
</view>
</view>
</template> </template>
<script> <script>
@ -11,7 +22,37 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
mixins: [mixinsSex, rewardedVideoAdMixin], mixins: [mixinsSex, rewardedVideoAdMixin],
props: ['phone', 'title', 'sexName', 'type', 'phoneTitle', 'pid'],
props: {
phone: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
sexName: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
phoneTitle: {
type: String,
default: ''
},
pid: {
type: [String, Number],
default: ''
},
// false-true-
showModel: {
type: Boolean,
default: false
}
},
data() { data() {
return { return {
// 广 // 广
@ -117,6 +158,7 @@
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
//
.phone { .phone {
background-color: rgba($uni-color, 0.2); background-color: rgba($uni-color, 0.2);
color: $uni-color; color: $uni-color;
@ -130,4 +172,73 @@
height: 20rpx; height: 20rpx;
} }
} }
//
.phone-modal {
position: fixed;
bottom: calc(140rpx + env(safe-area-inset-bottom));
right: 30rpx;
z-index: 999;
.phone-modal-content {
background: linear-gradient(135deg, $uni-color 0%, rgba($uni-color, 0.8) 100%);
color: #ffffff;
padding: 20rpx 30rpx;
border-radius: 50rpx;
box-shadow: 0 8rpx 24rpx rgba($uni-color, 0.3);
display: flex;
align-items: center;
justify-content: center;
min-width: 160rpx;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
box-shadow: 0 4rpx 12rpx rgba($uni-color, 0.4);
}
image {
width: 28rpx;
height: 28rpx;
margin-right: 12rpx;
filter: brightness(0) invert(1); //
}
.phone-modal-text {
font-size: 28rpx;
font-weight: 500;
white-space: nowrap;
}
}
//
&::before {
content: '';
position: absolute;
top: -10rpx;
left: -10rpx;
right: -10rpx;
bottom: -10rpx;
background: rgba($uni-color, 0.2);
border-radius: 60rpx;
animation: pulse 2s infinite;
z-index: -1;
}
}
//
@keyframes pulse {
0% {
transform: scale(1);
opacity: 0.7;
}
50% {
transform: scale(1.1);
opacity: 0.3;
}
100% {
transform: scale(1);
opacity: 0.7;
}
}
</style> </style>

+ 2
- 2
config/browseConfig.js View File

@ -117,11 +117,11 @@ export function getBrowseRecordConfig(itemType) {
} }
// 创建浏览记录参数的工具函数 // 创建浏览记录参数的工具函数
export function createBrowseRecordParams(orderId, itemType = 'dynamic') {
export function createBrowseRecordParams(formId, itemType = 'dynamic') {
const config = getBrowseRecordConfig(itemType) const config = getBrowseRecordConfig(itemType)
return { return {
orderId: orderId,
formId: formId,
type: config.type, type: config.type,
category: config.category category: config.category
} }

+ 45
- 29
pages_order/renting/rentingDetail.vue View File

@ -83,38 +83,48 @@
</span> </span>
</view> </view>
</view> --> </view> -->
<view class="flex-sb">
<view>
<span class="font-b">小区</span>
<span class="font-c">
<uni-icons type="paperplane" size="12" />
{{ detail.address }}
</span>
</view>
</view>
<!-- <view
style="margin-left: auto;"
class="d-btn" @click="clickService">
<span>打电话</span>
</view> -->
<view style="width: 160rpx;font-size: 26rpx;
margin-left: auto;
height: 50rpx;">
<callPhone
:phone="detail.phone"
type="1"
:phoneTitle="detail.title"
:pid="detail.id"
title="联系房东"/>
<!-- <view class="flex-sb">
<view>
<span class="font-b">小区</span>
<span class="font-c">
<uni-icons type="paperplane" size="12" />
{{ detail.address }}
</span>
</view> </view>
</view>
</view> -->
<!-- <view
style="margin-left: auto;"
class="d-btn" @click="clickService">
<span>打电话</span>
</view> -->
<callPhone
:phone="detail.phone"
type="1"
:phoneTitle="detail.title"
:pid="detail.id"
title="联系房东"
:showModel="true"/>
</view> </view>
</view>
<!-- 地图位置信息 -->
<view style="padding: 20rpx;background-color: #FFF;">
<mapCard
v-if="detail.latitude && detail.longitude"
:address-name="detail.address"
:latitude="detail.latitude"
:longitude="detail.longitude"
:address-detail="detail.title"
@mapClick="onMapClick"
/>
</view>
<!-- <view class="b-fiexd flex" style="height: 98rpx; z-index: 2;"> <!-- <view class="b-fiexd flex" style="height: 98rpx; z-index: 2;">
<view style="padding-left: 20rpx;"> <view style="padding-left: 20rpx;">
<image src="/static/logo.png" class="radius80 test" /> <image src="/static/logo.png" class="radius80 test" />
@ -143,10 +153,12 @@
<script> <script>
import mixinsList from '@/mixins/list.js' import mixinsList from '@/mixins/list.js'
import commentList from '../components/list/comment/commentList.vue' import commentList from '../components/list/comment/commentList.vue'
import mapCard from '@/components/base/mapCard.vue'
export default { export default {
mixins: [mixinsList], mixins: [mixinsList],
components : { components : {
commentList, commentList,
mapCard,
}, },
data() { data() {
return { return {
@ -180,6 +192,10 @@
this.getDetail() this.getDetail()
}, },
methods: { methods: {
//
onMapClick(data) {
console.log('地图点击事件:', data);
},
clickShare() { clickShare() {
uni.share({ uni.share({
provider: 'weixin', provider: 'weixin',


+ 27
- 10
pages_order/work/workDetail.vue View File

@ -50,13 +50,25 @@
</view> </view>
</view> </view>
<view class="address">
<!-- 工作地址地图卡片 -->
<view class="address-section" v-if="detail.latitude && detail.longitude">
<view class="title2">
工作地址
</view>
<mapCard
:latitude="detail.latitude"
:longitude="detail.longitude"
:address-name="detail.address"
:address-detail="detail.addressDetail"
@mapClick="onMapClick"
/>
</view>
<!-- 备用地址显示当没有经纬度时 -->
<view class="address" v-else>
<view class="title2"> <view class="title2">
工作地址 工作地址
</view> </view>
<!--
深圳罗湖区深圳市百货广场大厦罗湖区百货广场大厦东深圳罗湖区深圳市百货广场大厦罗湖区百货广场大厦东
-->
<view class="line" <view class="line"
style="justify-content: space-between;"> style="justify-content: space-between;">
{{ detail.address }} {{ detail.address }}
@ -66,12 +78,6 @@
name="arrow-right" name="arrow-right"
></uv-icon> ></uv-icon>
</view> </view>
<!-- <view class="tag-list">
<view>
距您14.6千米
</view>
</view> -->
</view> </view>
<view class="info"> <view class="info">
@ -117,10 +123,12 @@
<script> <script>
import mixinsList from '@/mixins/list.js' import mixinsList from '@/mixins/list.js'
import commentList from '../components/list/comment/commentList.vue' import commentList from '../components/list/comment/commentList.vue'
import mapCard from '@/components/base/mapCard.vue'
export default { export default {
mixins: [mixinsList], mixins: [mixinsList],
components : { components : {
commentList, commentList,
mapCard,
}, },
data() { data() {
return { return {
@ -175,6 +183,11 @@
} }
}) })
}, },
//
onMapClick(mapData) {
console.log('工作地址地图点击:', mapData);
}
} }
} }
</script> </script>
@ -236,6 +249,10 @@
} }
} }
.address-section{
padding: 30rpx 0;
}
.info{ .info{
margin: 20rpx 0; margin: 20rpx 0;
.text{ .text{


+ 4
- 0
static/image/location-marker.svg View File

@ -0,0 +1,4 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 2C10.0294 2 6 6.02944 6 11C6 18.25 15 28 15 28C15 28 24 18.25 24 11C24 6.02944 19.9706 2 15 2Z" fill="#5baaff" stroke="#ffffff" stroke-width="2"/>
<circle cx="15" cy="11" r="4" fill="#ffffff"/>
</svg>

Loading…
Cancel
Save