330 lines
8.3 KiB
Vue
330 lines
8.3 KiB
Vue
<template>
|
||
<view v-if="pageCount == 1 || need" class="fixed-box"
|
||
:style="[customContainerStyle, {
|
||
height: containerHeight,
|
||
backgroundImage: bgUrl ? `url(${bgUrl})` : '',
|
||
backgroundSize: 'cover'
|
||
}]">
|
||
|
||
<!-- ✅ 统一客服入口(根据后台配置自动适配 AI / 企业微信 / 第三方等) -->
|
||
<!-- 微信官方客服需要使用 button open-type="contact" -->
|
||
<button
|
||
v-if="fixBtnShow && isWeappOfficialKefu"
|
||
class="btn-item common-bg"
|
||
open-type="contact"
|
||
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||
>
|
||
<text class="ai-icon" v-if="!currentKefuImg">🤖</text>
|
||
</button>
|
||
<!-- 其他类型客服使用普通 view -->
|
||
<view
|
||
v-else-if="fixBtnShow"
|
||
class="btn-item common-bg"
|
||
@click="handleUnifiedKefuClick"
|
||
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||
>
|
||
<text class="ai-icon" v-if="!currentKefuImg">🤖</text>
|
||
</view>
|
||
|
||
<!-- ✅ 新增:小程序系统客服按钮(当附加设置开启时显示) -->
|
||
<button
|
||
v-if="fixBtnShow && showWeappSystemKefu"
|
||
class="btn-item common-bg"
|
||
open-type="contact"
|
||
:style="{ backgroundImage: currentKefuImg ? `url(${currentKefuImg})` : '', backgroundSize: '100% 100%' }"
|
||
>
|
||
<text class="ai-icon" v-if="!currentKefuImg">💬</text>
|
||
</button>
|
||
|
||
<!-- 中英文切换按钮 -->
|
||
<view
|
||
v-if="isLanguageSwitchEnabled && fixBtnShow"
|
||
class="btn-item common-bg"
|
||
@click="toggleLanguage"
|
||
>
|
||
<text>{{ currentLangDisplayName }}</text>
|
||
</view>
|
||
|
||
<!-- 电话按钮(始终显示) -->
|
||
<view
|
||
v-if="fixBtnShow"
|
||
class="btn-item common-bg"
|
||
@click="call()"
|
||
:style="[{ backgroundImage: phoneimg ? `url(${phoneimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]"
|
||
>
|
||
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
|
||
</view>
|
||
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { createCustomerService } from '@/common/js/customer-service.js';
|
||
|
||
export default {
|
||
name: 'hover-nav',
|
||
props: {
|
||
need: { type: Boolean, default: false }
|
||
},
|
||
data() {
|
||
return {
|
||
pageCount: 0,
|
||
fixBtnShow: true,
|
||
shopInfo: null,
|
||
currentLangIndex: 0,
|
||
langIndexMap: {},
|
||
kefuList: [
|
||
{ id: 'weixin-official', name: '微信官方客服', isOfficial: true, type: 'weapp' },
|
||
{ id: 'custom-kefu', name: '自定义在线客服', isOfficial: false, type: 'custom' },
|
||
{ id: 'qyweixin-kefu', name: '企业微信客服', isOfficial: false, type: 'qyweixin' }
|
||
],
|
||
selectedKefu: null,
|
||
};
|
||
},
|
||
computed: {
|
||
bgUrl() {
|
||
return this.shopInfo?.bgUrl || '';
|
||
},
|
||
aiAgentimg() {
|
||
return this.shopInfo?.aiAgentimg || '';
|
||
},
|
||
kefuimg() {
|
||
return this.shopInfo?.kefuimg || this. $util.getDefaultImage().kefu;
|
||
},
|
||
phoneimg() {
|
||
return this.shopInfo?.phoneimg || this. $util.getDefaultImage().phone;
|
||
},
|
||
tel() {
|
||
return this.shopInfo?.mobile || '';
|
||
},
|
||
isLanguageSwitchEnabled() {
|
||
return !!this.shopInfo?.ischina;
|
||
},
|
||
currentLangDisplayName() {
|
||
const lang = this.langIndexMap[this.currentLangIndex];
|
||
return lang === 'zh-cn' ? 'EN' : 'CN';
|
||
},
|
||
customContainerStyle() {
|
||
return this.shopInfo?.floatingButton?.container || {};
|
||
},
|
||
customButtonStyle() {
|
||
return this.shopInfo?.floatingButton?.button || {};
|
||
},
|
||
unreadCount() {
|
||
const customerService = createCustomerService(this);
|
||
return customerService.getUnreadCount();
|
||
},
|
||
|
||
currentKefuImg() {
|
||
const customerService = createCustomerService(this);
|
||
return customerService.getKefuButtonIcon();
|
||
},
|
||
|
||
isWeappOfficialKefu() {
|
||
const customerService = createCustomerService(this);
|
||
return customerService.isWeappOfficialKefu();
|
||
},
|
||
|
||
showWeappSystemKefu() {
|
||
const customerService = createCustomerService(this);
|
||
return customerService.shouldShowExtraWeappSystemKefu();
|
||
},
|
||
|
||
//根据显示的按钮数量动态计算容器高度
|
||
containerHeight() {
|
||
if (!this.fixBtnShow) return '320rpx';
|
||
|
||
let buttonCount = 1;
|
||
if (this.isLanguageSwitchEnabled) buttonCount++;
|
||
if (this.showWeappSystemKefu) buttonCount++;
|
||
buttonCount++;
|
||
const totalRpx = 94 * buttonCount - 14;
|
||
const pxValue = Math.round(totalRpx * 0.5);
|
||
|
||
return ` $ {pxValue}px`;
|
||
}
|
||
},
|
||
watch: {
|
||
shopInfo: {
|
||
handler(newVal) {
|
||
// 可在此添加额外逻辑(如埋点、通知等),当前无需操作
|
||
},
|
||
immediate: true
|
||
}
|
||
},
|
||
created() {
|
||
this.initLanguage();
|
||
this.pageCount = getCurrentPages().length;
|
||
|
||
uni.getStorage({
|
||
key: 'shopInfo',
|
||
success: (e) => {
|
||
console.log('【调试】当前 shopInfo:', e.data);
|
||
this.shopInfo = e.data;
|
||
},
|
||
fail: () => {
|
||
console.warn('未获取到 shopInfo,使用默认设置');
|
||
}
|
||
});
|
||
},
|
||
methods: {
|
||
|
||
/**
|
||
* 初始化多语言配置
|
||
*/
|
||
initLanguage() {
|
||
this.langList = this.$langConfig.list();
|
||
this.langIndexMap = {};
|
||
for (let i = 0; i < this.langList.length; i++) {
|
||
this.langIndexMap[i] = this.langList[i].value;
|
||
}
|
||
const savedLang = this.$langConfig.getCurrentLocale();
|
||
if (savedLang) {
|
||
for (let i = 0; i < this.langList.length; i++) {
|
||
if (this.langList[i].value === savedLang) {
|
||
this.currentLangIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
this.currentLangIndex = 0;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 电话联系客服
|
||
*/
|
||
call() {
|
||
const customerService = createCustomerService(this);
|
||
customerService.makePhoneCallByNumber(this.tel);
|
||
},
|
||
|
||
/**
|
||
* 切换中英文语言,并刷新当前页面(保留所有参数)
|
||
*/
|
||
toggleLanguage() {
|
||
this.currentLangIndex = this.currentLangIndex === 0 ? 1 : 0;
|
||
const targetLang = this.langIndexMap[this.currentLangIndex];
|
||
|
||
// 调用语言切换逻辑(设置 storage + 清空缓存)
|
||
this.$langConfig.change(targetLang);
|
||
},
|
||
|
||
/**
|
||
* 打开 AI 智能助手
|
||
*/
|
||
openAIChat() {
|
||
const customerService = createCustomerService(this);
|
||
customerService.openAIChat();
|
||
},
|
||
|
||
/**
|
||
* 打开客服选择对话框
|
||
*/
|
||
openCustomerSelectPopup() {
|
||
const customerService = createCustomerService(this);
|
||
customerService.openCustomerSelectPopupDialog();
|
||
},
|
||
|
||
/**
|
||
* 核心方法:统一客服入口
|
||
*/
|
||
handleUnifiedKefuClick() {
|
||
const customerService = createCustomerService(this);
|
||
customerService.handleUnifiedKefuClick({
|
||
sendMessageTitle: '来自悬浮按钮的咨询',
|
||
sendMessagePath: '/pages/index/index'
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 打开客服选择弹出层(ActionSheet)
|
||
*/
|
||
openKefuSelectPopup() {
|
||
const customerService = createCustomerService(this);
|
||
customerService.openKefuSelectPopup(this.kefuList);
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.fixed-box {
|
||
position: fixed;
|
||
right: 0rpx;
|
||
bottom: 240rpx;
|
||
/* #ifdef H5 */
|
||
bottom: 320rpx;
|
||
/* #endif */
|
||
z-index: 10;
|
||
border-radius: 120rpx;
|
||
padding: 20rpx 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
width: 100rpx;
|
||
box-sizing: border-box;
|
||
transition: 0.3s;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.btn-item {
|
||
display: flex;
|
||
justify-content: center;
|
||
text-align: center;
|
||
flex-direction: column;
|
||
line-height: 1;
|
||
margin: 14rpx 0;
|
||
transition: 0.1s;
|
||
color: var(--hover-nav-text-color);
|
||
border-radius: 50%;
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
padding: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 定义共同的背景颜色 */
|
||
.common-bg {
|
||
background-color: var(--hover-nav-bg-color);
|
||
/* 使用变量以保持一致性 */
|
||
}
|
||
|
||
.btn-item text {
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.iconfont,
|
||
.icox {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin: 14rpx 0;
|
||
border-radius: 50rpx;
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
padding: 0;
|
||
position: relative;
|
||
}
|
||
|
||
.iconfont text,
|
||
.icox text {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
|
||
|
||
.ai-icon {
|
||
font-size: 40rpx;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
</style> |