Merge branch 'feat-ai-agent-kefu' into xindeznkf

chore:合并了提交
This commit is contained in:
2026-01-13 15:57:35 +08:00
21 changed files with 3453 additions and 229 deletions

View File

@@ -2,25 +2,60 @@
<!-- 悬浮按钮 -->
<view v-if="pageCount == 1 || need" class="fixed-box"
:style="[{ height: fixBtnShow ? '400rpx' : '320rpx' }, customContainerStyle]">
<!-- <view class="btn-item" v-if="fixBtnShow" @click="$util.redirectTo('/pages/index/index')"> -->
<!-- 切换语言按钮 -->
<button class="btn-item" v-if="fixBtnShow && isLanguageSwitchEnabled" @click="toggleLanguage()"
:style="[{ backgroundSize: '100% 100%' }, customButtonStyle]">
<text :style="customTextStyle">{{ currentLangDisplayName }}</text>
</button>
<!-- 客服按钮 -->
<!-- #ifdef MP-WEIXIN -->
<button class="btn-item" v-if="fixBtnShow" hoverClass="none" openType="contact" sessionFrom="weapp"
showMessageCard="true"
:style="[{ backgroundImage: 'url(' + (kefuimg ? kefuimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
<button
class="btn-item"
v-if="fixBtnShow && isLanguageSwitchEnabled"
@click="toggleLanguage()"
:style="[{ backgroundSize: '100% 100%' }, customButtonStyle]"
>
<text :style="customTextStyle">{{ currentLangDisplayName }}</text>
</button>
<!-- AI 智能助手 客服按钮根据 enableAIChat 决定 -->
<template v-if="fixBtnShow">
<!-- 优先显示 AI 助手如果启用 -->
<view
v-if="enableAIChat"
class="btn-item"
@click="openAIChat"
:style="{ backgroundImage: aiAgentimg ? `url(${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>
<!-- 否则显示客服按钮 -->
<template v-else>
<!-- #ifdef MP-WEIXIN -->
<button
class="btn-item"
hoverClass="none"
openType="contact"
sessionFrom="weapp"
showMessageCard="true"
:style="[{ backgroundImage: kefuimg ? `url(${kefuimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]"
>
<text class="icox icox-kefu" v-if="!kefuimg"></text>
</button>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<button
class="btn-item"
hoverClass="none"
@click="openKefuSelectPopup"
:style="[{ backgroundImage: kefuimg ? `url(${kefuimg})` : '', backgroundSize: '100% 100%' }, customButtonStyle]"
>
<text class="icox icox-kefu" v-if="!kefuimg"></text>
<!-- <view>首页</view> -->
<!-- <view>首页</view> -->
</button>
<!-- #endif -->
<view class="btn-item" v-if="fixBtnShow" @click="call()"
:style="[{ backgroundImage: 'url(' + (phoneimg ? phoneimg : '') + ')', backgroundSize: '100% 100%' }, customButtonStyle]">
<text class="iconfont icon-dianhua" v-if="!phoneimg"></text>
<!-- <view>我的</view> -->
</view>
<!-- <view class="btn-item icon-xiala" v-if="fixBtnShow" @click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
@@ -35,6 +70,8 @@
</template>
<script>
import { mapGetters } from 'vuex' // 去掉mapMutations直接用$store.commit
import { createCustomerService } from '@/common/js/customer-service.js';
export default {
name: 'hover-nav',
props: {
@@ -89,12 +126,27 @@ export default {
const lang = this.langIndexMap[this.currentLangIndex];
return lang == 'zh-cn' ? 'EN' : 'CN';
},
};
// 获取容器的自定义样式
customContainerStyle() {
// 只返回非空的样式属性,确保不覆盖原有的默认样式
return this.shopInfo?.floatingButton?.container || {};
},
data() {
return {
pageCount: 0,
fixBtnShow: true,
tel: '',
kefuimg: '',
phoneimg: '',
customerService: null,
buttonConfig: null,
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
}; },
// 获取按钮的自定义样式
customButtonStyle() {
@@ -152,24 +204,51 @@ export default {
};
</script>
<style lang="scss">
.container-box {
width: 100%;
// 打开客服选择弹窗
openKefuSelectPopup() {
const kefuNames = this.kefuList.map(item => item.name);
wx.showActionSheet({
itemList: kefuNames,
success: (res) => {
this.selectedKefu = this.kefuList[res.tapIndex];
this.reinitCustomerService(this.selectedKefu);
this.handleSelectedKefu();
}
});
},
.item-wrap {
border-radius: 10rpx;
.image-box {
border-radius: 10rpx;
// 重新初始化客服实例
reinitCustomerService(kefu) {
this.customerService = createCustomerService(this, kefu);
this.buttonConfig = this.customerService.getButtonConfig();
},
}
image {
width: 100%;
height: auto;
border-radius: 10rpx;
will-change: transform;
// 执行选中的客服逻辑
handleSelectedKefu() {
const kefu = this.selectedKefu;
if (!kefu) return;
if (kefu.isOfficial) {
wx.openCustomerServiceConversation({ sessionFrom: 'weapp', showMessageCard: true });
} else if (kefu.id === 'custom-kefu') {
this.customerService.handleCustomerClick();
} else if (kefu.id === 'qyweixin-kefu') {
this.customerService.handleQyWeixinKefuClick();
}
},
// 打开AI聊天修复setAiUnreadCount的核心
openAIChat() {
if (this.enableAIChat) {
// 直接用$store.commit调用Vuex mutation绕过映射问题
this.$store.commit('setAiUnreadCount', 0);
}
this.$util.redirectTo('/pages_tool/ai-chat/index')
}
}
}
};
</script>
}
//悬浮按钮
@@ -219,24 +298,43 @@ export default {
display: flex;
justify-content: center;
align-items: center;
border-radius: 40rpx;
/* 确保图标本身也是圆形 */
}
margin: 14rpx 0;
background: #fff;
border-radius: 50rpx;
width: 80rpx;
height: 80rpx;
padding: 0;
position: relative;
view {
font-size: 26rpx;
font-weight: bold;
}
text {
font-size: 36rpx;
font-weight: bold;
}
&.show {
transform: rotate(180deg);
}
.unread-badge {
position: absolute;
top: -5rpx;
right: -5rpx;
background-color: #ff4544;
color: white;
border-radius: 20rpx;
min-width: 30rpx;
height: 30rpx;
font-size: 20rpx;
line-height: 30rpx;
text-align: center;
padding: 0 8rpx;
box-shadow: 0 2rpx 10rpx rgba(255, 69, 68, 0.3);
}
&.switch {}
&.icon-xiala {
margin: 0;
margin-top: 0.1rpx;
.ai-icon {
font-size: 40rpx;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}