This commit is contained in:
2026-04-02 11:09:27 +08:00
parent 6414902057
commit 982e78d21e
3 changed files with 285 additions and 24 deletions

View File

@ -0,0 +1,274 @@
<template>
<view class="contact-select-modal" v-if="visible">
<view class="modal-mask" @click="handleClose"></view>
<view class="modal-content">
<view class="service-time">
<text>客服时间{{ serviceTime }}</text>
</view>
<view class="option-list">
<!-- 在线咨询商家 - 根据是否有自定义回调决定使用哪种方式 -->
<button
v-if="!hasCustomCallback"
class="option-item im-btn"
open-type="im"
:data-im-id="imId"
@im="imCallback"
@error="onimError"
>
<view class="option-icon online-icon">
<text class="icon-text">💬</text>
</view>
<view class="option-info">
<text class="option-title">在线咨询商家</text>
<text class="option-desc">在线客服实时与您沟通</text>
</view>
</button>
<view
v-else
class="option-item"
@click="handleOnlineConsult"
>
<view class="option-icon online-icon">
<text class="icon-text">💬</text>
</view>
<view class="option-info">
<text class="option-title">在线咨询商家</text>
<text class="option-desc">在线客服实时与您沟通</text>
</view>
</view>
<!-- 商家客服电话 -->
<view class="option-item" @click="handlePhoneCall">
<view class="option-icon phone-icon">
<text class="icon-text">📞</text>
</view>
<view class="option-info">
<text class="option-title">商家客服电话</text>
<text class="option-desc">下单咨询服务投诉等反馈</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ContactSelectModal',
props: {
visible: {
type: Boolean,
default: false
},
serviceTime: {
type: String,
default: '9:00——18:30'
},
servicePhone: {
type: String,
default: '13641827576'
},
imId: {
type: String,
default: '42747510730'
},
hasCustomCallback: {
type: Boolean,
default: false
}
},
emits: ['close', 'phoneCall', 'imSuccess', 'imError', 'onlineConsult'],
methods: {
handleClose() {
this.$emit('close')
},
handleOnlineConsult() {
this.$emit('onlineConsult')
this.$emit('close')
},
imCallback(e) {
console.log('跳转IM客服成功', e.detail)
this.$emit('imSuccess', e)
this.$emit('close')
},
onimError(e) {
console.log('拉起IM客服失败', e.detail)
this.$emit('imError', e)
uni.showToast({
title: '客服功能暂不可用',
icon: 'none'
})
},
handlePhoneCall() {
this.$emit('phoneCall', this.servicePhone)
this.$emit('close')
if (this.servicePhone) {
// 抖音小程序拨打电话
uni.makePhoneCall({
phoneNumber: this.servicePhone,
success: () => {
console.log('拨打电话成功')
},
fail: (err) => {
console.error('拨打电话失败', err)
// 失败时显示客服电话供用户手动拨打
uni.showModal({
title: '客服电话',
content: this.servicePhone,
confirmText: '复制',
cancelText: '知道了',
success: (res) => {
if (res.confirm) {
uni.setClipboardData({
data: this.servicePhone,
success: () => {
uni.showToast({
title: '电话已复制',
icon: 'success'
})
}
})
}
}
})
}
})
} else {
uni.showToast({
title: '客服电话暂未设置',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.contact-select-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
.modal-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
position: relative;
width: 600rpx;
background-color: #fff;
border-radius: 24rpx;
overflow: hidden;
animation: modalFadeIn 0.3s ease-out;
padding-bottom: 20rpx;
@keyframes modalFadeIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.service-time {
padding: 40rpx 32rpx 20rpx;
text-align: center;
font-size: 28rpx;
color: #666;
}
.option-list {
padding: 0 32rpx 20rpx;
.option-item {
display: flex;
align-items: center;
padding: 30rpx 0;
border-bottom: 1rpx solid #f0f0f0;
background: none;
border-left: none;
border-right: none;
border-top: none;
outline: none;
line-height: normal;
text-align: left;
width: 100%;
margin: 0;
&:last-child {
border-bottom: none;
}
&:active {
background-color: #f5f5f5;
}
&::after {
border: none;
}
.option-icon {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
&.online-icon {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
&.phone-icon {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.icon-text {
font-size: 36rpx;
}
}
.option-info {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
.option-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
margin-bottom: 8rpx;
text-align: left;
}
.option-desc {
font-size: 24rpx;
color: #999;
text-align: left;
}
}
}
}
}
}
</style>

View File

@ -1,14 +1,9 @@
<template> <template>
<view> <view>
<button <view
class="draggable-contact" class="draggable-contact"
:style="{ right: right + 'rpx', bottom: bottom + 'rpx' }" :style="{ right: right + 'rpx', bottom: bottom + 'rpx' }"
:hover-class="'draggable-contact-hover'" @click="handleClick"
:hover-stay-time="150"
open-type="im"
:data-im-id="imId"
@im="imCallback"
@error="onimError"
> >
<view class="click-area"> <view class="click-area">
<image class="contact-icon" :src="iconSrc" mode="aspectFill" /> <image class="contact-icon" :src="iconSrc" mode="aspectFill" />
@ -16,26 +11,23 @@
{{ text }} {{ text }}
</view> </view>
</view> </view>
</button> </view>
<!-- 联系客服弹窗 --> <!-- 联系客服弹窗 -->
<ContactPopupModal <ContactSelectModal
:visible="showContactModalFlag" :visible="showContactModalFlag"
@cancel="closeContactModal"
@confirm="closeContactModal"
@close="closeContactModal" @close="closeContactModal"
/> />
</view> </view>
</template> </template>
<script> <script>
import { jumpToWeChat } from '@/utils/common' import ContactSelectModal from './ContactSelectModal.vue'
import ContactPopupModal from './ContactPopupModal.vue'
export default { export default {
name: 'DraggableContact', name: 'DraggableContact',
components: { components: {
ContactPopupModal ContactSelectModal
}, },
props: { props: {
// 图标 URL // 图标 URL
@ -79,16 +71,6 @@ export default {
} }
}, },
methods: { methods: {
imCallback(e) {
console.log("跳转IM客服成功", e.detail)
},
onimError(e) {
console.log("拉起IM客服失败", e.detail)
uni.showToast({
title: "客服功能暂不可用",
icon: "none"
})
},
// 初始化位置 // 初始化位置
initPosition() { initPosition() {
const systemInfo = uni.getSystemInfoSync() const systemInfo = uni.getSystemInfoSync()

View File

@ -91,6 +91,11 @@
"minifyWXML" : true, "minifyWXML" : true,
"minifyWXSS" : true "minifyWXSS" : true
}, },
"privacy": {
"usePrivacyCheck": true,
"requiredPrivateInfos": ["makePhoneCall"]
},
"plugins" : { "plugins" : {
"myTradePlugin" : { "myTradePlugin" : {
"version" : "*", "version" : "*",