Files
lucky_shop/components/hover-nav/hover-nav.vue

307 lines
7.9 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view v-if="pageCount == 1 || need" class="fixed-box" :style="{ height: fixBtnShow ? (isH5 ? '180rpx' : '330rpx') : '120rpx' }">
<!-- #ifdef MP-WEIXIN -->
<!-- 微信小程序根据配置自动选择官方客服/自定义客服 -->
<button
class="btn-item"
v-if="fixBtnShow"
hoverClass="none"
:open-type="weappOfficialService ? 'contact' : ''"
@click="weappOfficialService ? '' : handleWeappCustomerService"
:style="{ backgroundImage: 'url(' + (kefuimg ? kefuimg : '') + ')', backgroundSize: '100% 100%' }"
>
<text class="icox icox-kefu" v-if="!kefuimg"></text>
</button>
<!-- #endif -->
<!-- #ifdef H5 -->
<!-- H5逻辑保持不变 -->
<button
class="btn-item"
v-if="fixBtnShow"
hoverClass="none"
@click="handleCustomerService"
:style="{ backgroundImage: 'url(' + (kefuimg ? kefuimg : '') + ')', backgroundSize: '100% 100%' }"
>
<text class="icox icox-kefu" v-if="!kefuimg"></text>
<view v-if="unreadCount > 0 && isDifyService" class="unread-badge">
<text class="badge-text">{{ unreadCount > 99 ? '99+' : unreadCount }}</text>
</view>
</button>
<!-- #endif -->
<!-- #ifndef H5 -->
<view
class="btn-item"
v-if="fixBtnShow && isDifyService"
@click="handleCustomerService"
:style="{ backgroundImage: 'url(' + (aiAgentimg ? aiAgentimg : '') + ')', backgroundSize: '100% 100%' }"
>
<text class="ai-icon" v-if="!aiAgentimg">🤖</text>
<view v-if="unreadCount > 0" class="unread-badge">
<text class="badge-text">{{ unreadCount > 99 ? '99+' : unreadCount }}</text>
</view>
</view>
<!-- #endif -->
<view
class="btn-item"
v-if="fixBtnShow"
@click="call()"
:style="{ backgroundImage: 'url(' + (phoneimg ? phoneimg : '') + ')', backgroundSize: '100% 100%' }"
>
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
</view>
</view>
</template>
<script>
import { createCustomerService } from '@/common/js/customer-service.js';
import { mapGetters, mapMutations } from 'vuex';
export default {
name: 'hover-nav',
props: {
need: {
type: Boolean,
default: false
}
},
data() {
return {
pageCount: 0,
fixBtnShow: true,
tel: '',
kefuimg: '',
phoneimg: '',
customerService: null,
buttonConfig: null,
isH5: false,
platformConfig: null,
latestConfig: null,
weappOfficialService: false // 微信小程序是否使用官方客服
};
},
created() {
// 1. 判断平台类型
// #ifdef H5
this.isH5 = true;
// #endif
// #ifdef MP-WEIXIN
this.isH5 = false;
// #endif
// 2. 初始化资源
this.kefuimg = this.$util.getDefaultImage().kefu;
this.phoneimg = this.$util.getDefaultImage().phone;
this.pageCount = getCurrentPages().length;
// 3. 获取店铺电话
this.getShopTel();
// 4. 首次加载获取最新配置
this.getLatestConfig().then(config => {
this.latestConfig = config;
this.initCustomerService(config);
// 微信小程序:判断是否使用官方客服
this.initWeappServiceType();
});
},
computed: {
...mapGetters([
'globalAIKefuConfig',
'aiUnreadCount'
]),
isDifyService() {
const serviceType = this.platformConfig?.type || '';
return serviceType === 'aikefu';
},
aiAgentimg() {
return this.globalAIKefuConfig?.icon || this.$util.getDefaultImage().aiAgent || '';
},
unreadCount() {
return this.aiUnreadCount;
}
},
methods: {
...mapMutations([
'setAiUnreadCount'
]),
/**
* 获取最新配置H5禁用缓存小程序保留默认
*/
async getLatestConfig() {
return new Promise((resolve) => {
// H5强制请求最新配置小程序优先用vuex缓存
if (this.isH5) {
this.$api.sendRequest({
url: '/api/site/getServicerConfig',
header: {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0'
},
data: { t: new Date().getTime() },
success: (res) => {
const config = res.code === 0 ? res.data : this.$store.state.servicerConfig || {};
this.$store.commit('setServicerConfig', config);
resolve(config);
},
fail: () => resolve(this.$store.state.servicerConfig || {})
});
} else {
// 小程序直接用vuex缓存后台修改后需重启开发者工具
resolve(this.$store.state.servicerConfig || {});
}
});
},
/**
* 初始化客服服务
*/
initCustomerService(config = null) {
this.customerService = createCustomerService(this, config || this.latestConfig);
this.platformConfig = this.customerService.refreshConfig(config || this.latestConfig);
this.buttonConfig = this.customerService.getButtonConfig();
},
/**
* 微信小程序:初始化服务类型(官方/自定义)
*/
initWeappServiceType() {
// #ifdef MP-WEIXIN
// 从buttonConfig中获取官方客服标识
this.weappOfficialService = this.buttonConfig?.openType === 'contact';
// #endif
},
/**
* 获取店铺电话
*/
getShopTel() {
uni.getStorage({
key: 'shopInfo',
success: (e) => {
if (e.data && e.data.mobile && /^1[3-9]\d{9}$/.test(e.data.mobile)) {
this.tel = e.data.mobile;
}
}
});
},
/**
* 拨打电话
*/
call() {
if (!this.tel || !/^1[3-9]\d{9}$/.test(this.tel)) {
uni.showToast({ title: '暂无有效联系电话', icon: 'none' });
return;
}
uni.makePhoneCall({
phoneNumber: this.tel,
fail: (err) => {
if (err.errMsg !== 'makePhoneCall:fail cancel') {
uni.showToast({ title: '拨号失败,请稍后重试', icon: 'none' });
}
}
});
},
/**
* H5客服点击逻辑保持不变
*/
async handleCustomerService() {
if (this.isH5) {
uni.showLoading({ title: '加载中...', mask: true });
try {
const newConfig = await this.getLatestConfig();
this.latestConfig = newConfig;
this.initCustomerService(newConfig);
this.customerService.handleCustomerClick();
} catch (e) {
uni.showToast({ title: '操作失败', icon: 'none' });
} finally {
uni.hideLoading();
}
} else {
// 小程序:直接调用客服逻辑
this.customerService.handleCustomerClick();
}
},
/**
* 微信小程序自定义客服点击逻辑
*/
handleWeappCustomerService() {
// #ifdef MP-WEIXIN
this.customerService.handleCustomerClick();
// #endif
}
}
};
</script>
<style scoped>
/* 父容器:不限制高度,避免挤压按钮 */
.fixed-box {
position: fixed;
right: 20rpx; /* 增加右侧边距,避免贴边 */
bottom: 200rpx;
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
gap: 14rpx; /* 替代margin更稳定 */
}
/* 核心:强制按钮为正方形+正圆 */
.btn-item {
/* 宽高强制相等,必须是正方形 */
width: 88rpx !important;
height: 88rpx !important;
/* 强制正圆(优先级最高) */
border-radius: 50% !important;
/* 白色背景(确保是圆) */
background-color: #ffffff !important;
/* 背景图居中显示,不拉伸 */
background-size: 60% 60% !important;
background-position: center !important;
background-repeat: no-repeat !important;
/* 清除默认样式 */
border: none !important;
padding: 0 !important;
margin: 0 !important;
/* 居中内容 */
display: flex !important;
justify-content: center !important;
align-items: center !important;
/* 阴影增强视觉(可选) */
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.1);
}
/* 清除button标签的默认点击样式微信小程序/浏览器) */
.btn-item::after {
border: none !important;
}
.unread-badge {
position: absolute;
top: -5rpx;
right: -5rpx;
background: #ff4544;
color: #fff;
border-radius: 20rpx;
min-width: 30rpx;
height: 30rpx;
line-height: 30rpx;
text-align: center;
font-size: 10rpx;
padding: 0 8rpx;
box-shadow: 0 2rpx 10rpx rgba(255, 73, 72, 0.3);
z-index: 1;
}
/* 微信小程序字体适配 */
/* #ifdef MP-WEIXIN */
.unread-badge {
font-size: 20rpx;
}
/* #endif */
.ai-icon {
font-size: 40rpx;
}
</style>