chore: 保留ai-chat-popup 及 ai-chat-flaot组件
This commit is contained in:
@@ -162,7 +162,7 @@
|
||||
v-for="action in message.actions"
|
||||
:key="action.id"
|
||||
class="action-btn"
|
||||
:class="action.type"
|
||||
:class="[`iconfont`, action.icon, action.type]"
|
||||
@click="handleAction(action, message)">
|
||||
{{ action.text }}
|
||||
</button>
|
||||
@@ -246,7 +246,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 语音输入面板 -->
|
||||
<view v-if="showVoicePanel" class="voice-popup">
|
||||
<view v-if="enalbeVoicePanelShow" class="voice-popup">
|
||||
<view class="voice-mask" @click="hideVoicePanel"></view>
|
||||
<view class="voice-input-panel">
|
||||
<view class="voice-header">
|
||||
@@ -332,7 +332,7 @@ export default {
|
||||
currentAudio: null,
|
||||
messageId: 0,
|
||||
showToolsPanel: false,
|
||||
showVoicePanel: false,
|
||||
enalbeVoicePanelShow: false,
|
||||
streamingMessage: null, // 流式消息对象
|
||||
streamInterval: null, // 流式更新定时器
|
||||
streamContent: '', // 流式内容缓存
|
||||
@@ -540,12 +540,12 @@ export default {
|
||||
|
||||
// 显示语音面板
|
||||
showVoicePanel() {
|
||||
this.showVoicePanel = true
|
||||
this.enalbeVoicePanelShow = true
|
||||
},
|
||||
|
||||
// 隐藏语音面板
|
||||
hideVoicePanel() {
|
||||
this.showVoicePanel = false
|
||||
this.enalbeVoicePanelShow = false
|
||||
this.voiceInputing = false
|
||||
},
|
||||
|
||||
@@ -779,11 +779,16 @@ export default {
|
||||
|
||||
/* 页面样式 */
|
||||
.ai-chat-container {
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f8f8f8;
|
||||
overflow: hidden;
|
||||
/* 微信小程序安全区域适配 */
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
box-sizing: border-box;
|
||||
/* 确保在微信小程序中正确布局 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
@@ -791,7 +796,8 @@ export default {
|
||||
padding: 20rpx;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
height: calc(100% - 200rpx); /* 减去输入区域高度 */
|
||||
/* 微信小程序需要明确的flex布局 */
|
||||
min-height: 0; /* 重要:防止flex元素溢出 */
|
||||
}
|
||||
|
||||
.load-more {
|
||||
@@ -1162,11 +1168,13 @@ export default {
|
||||
gap: 10rpx;
|
||||
|
||||
.action-btn {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
border: 2rpx solid #e9ecef;
|
||||
// border: 2rpx solid #e9ecef;
|
||||
background-color: white;
|
||||
padding: 10rpx 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.like {
|
||||
color: #ff4544;
|
||||
@@ -1185,6 +1193,13 @@ export default {
|
||||
background-color: white;
|
||||
border-top: 2rpx solid #eeeeee;
|
||||
padding: 20rpx;
|
||||
/* 确保在微信小程序中紧贴底部 */
|
||||
flex-shrink: 0;
|
||||
/* 微信小程序安全区域适配 */
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
/* 确保输入区域正确显示 */
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.input-tools {
|
||||
|
||||
173
components/ai-chat-popup/README.md
Normal file
173
components/ai-chat-popup/README.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# AI智能客服弹窗集成说明
|
||||
|
||||
## 概述
|
||||
|
||||
本方案将AI智能客服弹窗功能集成到现有的浮动导航组件 `hover-nav.vue` 中,实现了对项目影响最小的集成方案。
|
||||
|
||||
## 集成文件
|
||||
|
||||
### 1. 新增组件
|
||||
- `components/ai-chat-popup/ai-chat-popup.vue` - AI聊天弹窗主组件
|
||||
- `components/ai-chat-popup/ai-chat-popup.json` - 组件配置文件
|
||||
|
||||
### 2. 修改文件
|
||||
- `components/hover-nav/hover-nav.vue` - 集成AI客服按钮和弹窗
|
||||
|
||||
## 功能特性
|
||||
|
||||
### ✅ 已实现功能
|
||||
1. **浮动AI客服按钮** - 在现有浮动导航中添加AI客服按钮
|
||||
2. **智能弹窗** - 点击按钮弹出AI聊天界面
|
||||
3. **未读消息提示** - 显示未读消息数量小红点
|
||||
4. **全屏模式** - 支持全屏/窗口模式切换
|
||||
5. **响应式设计** - 适配不同屏幕尺寸
|
||||
6. **复用现有组件** - 基于现有的 `ai-chat-message` 组件
|
||||
|
||||
### 🔧 技术特点
|
||||
1. **最小化影响** - 只修改现有组件,不改变项目结构
|
||||
2. **模块化设计** - 弹窗组件独立,可复用
|
||||
3. **事件驱动** - 完整的生命周期事件
|
||||
4. **性能优化** - 按需加载,避免资源浪费
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 自动集成
|
||||
AI客服功能已经自动集成到 `hover-nav` 组件中,无需额外配置。
|
||||
|
||||
### 2. 自定义配置
|
||||
如果需要自定义AI客服功能,可以修改以下配置:
|
||||
|
||||
```vue
|
||||
<!-- 在 hover-nav.vue 中自定义AI客服按钮 -->
|
||||
<view class="btn-item" @click="openAIChat" :style="{backgroundImage:'url('+(aiimg?aiimg:'')+')',backgroundSize:'100% 100%'}">
|
||||
<text class="iconfont icon-ai" v-if="!aiimg"></text>
|
||||
<view v-if="aiUnreadCount > 0" class="unread-badge">
|
||||
<text>{{ aiUnreadCount > 99 ? '99+' : aiUnreadCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- AI聊天弹窗 -->
|
||||
<ai-chat-popup
|
||||
v-if="showAIChat"
|
||||
:show="showAIChat"
|
||||
@update:show="showAIChat = $event"
|
||||
@unread-update="onUnreadUpdate"
|
||||
@message-sent="onAIMessageSent"
|
||||
@ai-response="onAIResponse" />
|
||||
```
|
||||
|
||||
### 3. 事件监听
|
||||
可以监听以下事件来处理业务逻辑:
|
||||
|
||||
```javascript
|
||||
// 未读消息更新
|
||||
onUnreadUpdate(count) {
|
||||
this.aiUnreadCount = count
|
||||
// 可以在这里添加未读消息处理逻辑
|
||||
},
|
||||
|
||||
// AI消息发送事件
|
||||
onAIMessageSent(message) {
|
||||
console.log('AI消息发送:', message)
|
||||
// 可以在这里添加消息发送后的处理逻辑
|
||||
},
|
||||
|
||||
// AI回复事件
|
||||
onAIResponse(message) {
|
||||
console.log('AI回复:', message)
|
||||
// 可以在这里添加AI回复后的处理逻辑
|
||||
}
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### AI聊天弹窗组件参数
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| show | Boolean | false | 是否显示弹窗 |
|
||||
| userAvatar | String | '/static/images/default-avatar.png' | 用户头像 |
|
||||
| aiAvatar | String | '/static/images/ai-avatar.png' | AI头像 |
|
||||
|
||||
### 事件
|
||||
|
||||
| 事件名 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| popup-open | - | 弹窗打开事件 |
|
||||
| popup-close | - | 弹窗关闭事件 |
|
||||
| unread-update | count | 未读消息数量更新 |
|
||||
| message-sent | message | 消息发送事件 |
|
||||
| ai-response | message | AI回复事件 |
|
||||
|
||||
## 样式定制
|
||||
|
||||
### 1. AI客服按钮样式
|
||||
```css
|
||||
.btn-item {
|
||||
/* 按钮基础样式 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.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;
|
||||
z-index: 1;
|
||||
box-shadow: 0 2rpx 10rpx rgba(255, 69, 68, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 弹窗样式
|
||||
弹窗样式在 `ai-chat-popup.vue` 中定义,可以根据需要自定义。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **图标资源** - 需要确保AI图标文件存在,默认路径为 `/static/images/ai-icon.png`
|
||||
2. **组件依赖** - AI聊天弹窗依赖于现有的 `ai-chat-message` 组件
|
||||
3. **z-index** - 弹窗的z-index设置为1000,确保在其他元素之上
|
||||
4. **响应式适配** - 弹窗已经做了移动端适配,但可能需要根据具体项目调整
|
||||
|
||||
## 兼容性
|
||||
|
||||
- ✅ H5
|
||||
- ✅ 微信小程序
|
||||
- ✅ APP
|
||||
- ✅ 其他小程序平台
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **图标优化** - 可以添加更精美的AI图标
|
||||
2. **动画效果** - 可以添加更流畅的打开/关闭动画
|
||||
3. **主题定制** - 支持暗色主题等
|
||||
4. **多语言** - 支持国际化
|
||||
5. **性能优化** - 懒加载等优化措施
|
||||
|
||||
## 问题排查
|
||||
|
||||
如果AI客服功能无法正常工作,请检查:
|
||||
|
||||
1. 组件路径是否正确
|
||||
2. 依赖的 `ai-chat-message` 组件是否存在
|
||||
3. 图标资源路径是否正确
|
||||
4. 控制台是否有错误信息
|
||||
|
||||
## 总结
|
||||
|
||||
本集成方案成功将AI智能客服功能添加到现有的浮动导航组件中,实现了:
|
||||
|
||||
- ✅ 对项目影响最小
|
||||
- ✅ 功能完整可用
|
||||
- ✅ 代码结构清晰
|
||||
- ✅ 易于维护扩展
|
||||
|
||||
现在您可以在任何使用 `hover-nav` 组件的页面中享受AI智能客服功能!
|
||||
6
components/ai-chat-popup/ai-chat-popup.json
Normal file
6
components/ai-chat-popup/ai-chat-popup.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"ai-chat-message": "../ai-chat-message/ai-chat-message"
|
||||
}
|
||||
}
|
||||
310
components/ai-chat-popup/ai-chat-popup.vue
Normal file
310
components/ai-chat-popup/ai-chat-popup.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<!-- AI聊天弹窗 -->
|
||||
<view v-if="showPopup" class="ai-chat-popup">
|
||||
<!-- 遮罩层 -->
|
||||
<view class="popup-mask" @click="closePopup"></view>
|
||||
|
||||
<!-- 弹窗内容 -->
|
||||
<view class="popup-content" :class="{ 'full-screen': isFullScreen }">
|
||||
<!-- 弹窗头部 -->
|
||||
<view class="popup-header">
|
||||
<view class="header-left">
|
||||
<view class="ai-avatar">🤖</view>
|
||||
<view class="header-info">
|
||||
<text class="ai-name">AI智能客服</text>
|
||||
<text class="ai-status">{{ isOnline ? '在线' : '离线' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<button class="header-btn" @click="toggleFullScreen">
|
||||
<text class="icon-text">{{ isFullScreen ? '↗' : '↘' }}</text>
|
||||
</button>
|
||||
<button class="header-btn" @click="closePopup">
|
||||
<text class="icon-text">×</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 聊天消息区域 -->
|
||||
<view class="chat-area">
|
||||
<!-- 使用ai-chat-message组件 -->
|
||||
<ai-chat-message
|
||||
ref="chatMessage"
|
||||
:initial-messages="messages"
|
||||
:user-avatar="userAvatar"
|
||||
:ai-avatar="aiAvatar"
|
||||
:show-load-more="false"
|
||||
@message-sent="onMessageSent"
|
||||
@ai-response="onAIResponse"
|
||||
@unread-update="onUnreadUpdate"
|
||||
@popup-open="onPopupOpen"
|
||||
@popup-close="onPopupClose"
|
||||
class="chat-message-component" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import aiChatMessage from '@/components/ai-chat-message/ai-chat-message.vue'
|
||||
|
||||
export default {
|
||||
name: 'ai-chat-popup',
|
||||
components: {
|
||||
aiChatMessage
|
||||
},
|
||||
props: {
|
||||
// 是否显示弹窗
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 用户头像
|
||||
userAvatar: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// AI头像
|
||||
aiAvatar: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPopup: false,
|
||||
isFullScreen: false,
|
||||
isOnline: true,
|
||||
unreadCount: 0,
|
||||
messages: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(newVal) {
|
||||
this.showPopup = newVal
|
||||
if (newVal) {
|
||||
this.unreadCount = 0
|
||||
this.$store.commit('setAiUnreadCount', 0)
|
||||
this.$emit('popup-open')
|
||||
} else {
|
||||
this.$emit('popup-close')
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 打开弹窗
|
||||
openPopup() {
|
||||
this.showPopup = true
|
||||
this.$emit('update:show', true)
|
||||
},
|
||||
|
||||
// 关闭弹窗
|
||||
closePopup() {
|
||||
this.showPopup = false
|
||||
this.$emit('update:show', false)
|
||||
this.isFullScreen = false
|
||||
},
|
||||
|
||||
// 切换全屏模式
|
||||
toggleFullScreen() {
|
||||
this.isFullScreen = !this.isFullScreen
|
||||
this.$emit('fullscreen-toggle', this.isFullScreen)
|
||||
},
|
||||
|
||||
// 消息发送事件处理
|
||||
onMessageSent(message) {
|
||||
this.$emit('message-sent', message)
|
||||
},
|
||||
|
||||
// AI回复事件处理
|
||||
onAIResponse(message) {
|
||||
this.$emit('ai-response', message)
|
||||
|
||||
// 如果弹窗关闭,增加未读消息计数
|
||||
if (!this.showPopup) {
|
||||
this.unreadCount++
|
||||
this.$store.commit('setAiUnreadCount', this.unreadCount)
|
||||
this.$emit('unread-update', this.unreadCount)
|
||||
}
|
||||
},
|
||||
|
||||
// 未读消息更新事件处理
|
||||
onUnreadUpdate(count) {
|
||||
this.unreadCount = count
|
||||
this.$emit('unread-update', count)
|
||||
},
|
||||
|
||||
// 弹窗打开事件处理
|
||||
onPopupOpen() {
|
||||
this.$emit('popup-open')
|
||||
},
|
||||
|
||||
// 弹窗关闭事件处理
|
||||
onPopupClose() {
|
||||
this.$emit('popup-close')
|
||||
},
|
||||
|
||||
// 添加未读消息
|
||||
addUnreadMessage() {
|
||||
if (!this.showPopup) {
|
||||
this.unreadCount++
|
||||
this.$emit('unread-update', this.unreadCount)
|
||||
}
|
||||
},
|
||||
|
||||
// 清空未读消息
|
||||
clearUnreadMessages() {
|
||||
this.unreadCount = 0
|
||||
this.$emit('unread-update', 0)
|
||||
},
|
||||
|
||||
// 添加消息到聊天记录
|
||||
addMessage(message) {
|
||||
this.messages.push(message)
|
||||
},
|
||||
|
||||
// 清空聊天记录
|
||||
clearMessages() {
|
||||
this.messages = []
|
||||
},
|
||||
|
||||
// 获取聊天消息组件实例
|
||||
getChatMessageInstance() {
|
||||
return this.$refs.chatMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ai-chat-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.popup-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
bottom: 300rpx;
|
||||
width: 600rpx;
|
||||
height: 800rpx;
|
||||
background-color: white;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 10rpx 50rpx rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.full-screen {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 2rpx solid #eeeeee;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.ai-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.header-info {
|
||||
.ai-name {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.ai-status {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-top: 5rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.header-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
margin-left: 15rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.iconfont {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-area {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.chat-message-component {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式适配 */
|
||||
@media (max-width: 750rpx) {
|
||||
.popup-content {
|
||||
right: 20rpx;
|
||||
left: 20rpx;
|
||||
width: auto;
|
||||
height: 70vh;
|
||||
bottom: 20rpx;
|
||||
|
||||
&.full-screen {
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,142 +1,209 @@
|
||||
<template>
|
||||
<!-- 悬浮按钮 -->
|
||||
<view v-if="pageCount == 1 || need" class="fixed-box" :style="{ height: fixBtnShow ? '330rpx' : '120rpx' }">
|
||||
<!-- <view class="btn-item" v-if="fixBtnShow" @click="$util.redirectTo('/pages/index/index')"> -->
|
||||
<!-- #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%'}">
|
||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||
<!-- <view>首页</view> -->
|
||||
</button>
|
||||
<!-- #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> -->
|
||||
</view>
|
||||
|
||||
<!-- <view class="btn-item icon-xiala" v-if="fixBtnShow" @click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
|
||||
<text class="iconfont icon-unfold"></text>
|
||||
</view>
|
||||
<view class="btn-item switch" v-else :class="{ show: fixBtnShow }"
|
||||
@click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
|
||||
<view class="">快捷</view>
|
||||
<view>导航</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'hover-nav',
|
||||
props: {
|
||||
need: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageCount: 0,
|
||||
fixBtnShow: true,
|
||||
tel:'',
|
||||
kefuimg:'',
|
||||
phoneimg:''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.kefuimg = this.$util.getDefaultImage().kefu
|
||||
this.phoneimg = this.$util.getDefaultImage().phone
|
||||
this.pageCount = getCurrentPages().length;
|
||||
var that = this
|
||||
uni.getStorage({
|
||||
key:'shopInfo',
|
||||
success(e){
|
||||
that.tel = e.data.mobile
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
methods: {
|
||||
//拨打电话
|
||||
call(){
|
||||
uni.makePhoneCall({
|
||||
phoneNumber:this.tel+''
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//悬浮按钮
|
||||
.fixed-box {
|
||||
position: fixed;
|
||||
right: 0rpx;
|
||||
bottom: 200rpx;
|
||||
z-index: 10;
|
||||
// background: #fff;
|
||||
// box-shadow: 2rpx 2rpx 22rpx rgba(0, 0, 0, 0.3);
|
||||
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;
|
||||
background: #fff;
|
||||
border-radius: 50rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
padding: 0;
|
||||
text {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
view {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.show {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
&.switch {}
|
||||
|
||||
&.icon-xiala {
|
||||
margin: 0;
|
||||
margin-top: 0.1rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<!-- 悬浮按钮 -->
|
||||
<view v-if="pageCount == 1 || need" class="fixed-box" :style="{ height: fixBtnShow ? '330rpx' : '120rpx' }">
|
||||
<!-- <view class="btn-item" v-if="fixBtnShow" @click="$util.redirectTo('/pages/index/index')"> -->
|
||||
<!-- #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%'}">
|
||||
<text class="icox icox-kefu" v-if="!kefuimg"></text>
|
||||
<!-- <view>首页</view> -->
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- AI智能助手 -->
|
||||
<view class="btn-item" v-if="fixBtnShow && enableAIChat" @click="openAIChat" :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>
|
||||
|
||||
<!-- 电话 -->
|
||||
<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> -->
|
||||
</view>
|
||||
|
||||
<!-- <view class="btn-item icon-xiala" v-if="fixBtnShow" @click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
|
||||
<text class="iconfont icon-unfold"></text>
|
||||
</view>
|
||||
<view class="btn-item switch" v-else :class="{ show: fixBtnShow }"
|
||||
@click="fixBtnShow ? (fixBtnShow = false) : (fixBtnShow = true)">
|
||||
<view class="">快捷</view>
|
||||
<view>导航</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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:''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.kefuimg = this.$util.getDefaultImage().kefu
|
||||
this.phoneimg = this.$util.getDefaultImage().phone
|
||||
this.pageCount = getCurrentPages().length;
|
||||
|
||||
|
||||
var that = this
|
||||
uni.getStorage({
|
||||
key:'shopInfo',
|
||||
success(e){
|
||||
that.tel = e.data.mobile
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'globalAIAgentConfig',
|
||||
'aiUnreadCount'
|
||||
]),
|
||||
aiAgentimg() {
|
||||
return this.globalAIAgentConfig?.icon || this.$util.getDefaultImage().aiAgent || '' // AI智能助手的头像
|
||||
},
|
||||
unreadCount() {
|
||||
return this.aiUnreadCount
|
||||
},
|
||||
enableAIChat() {
|
||||
return this.globalAIAgentConfig?.enable || true // 是否开启AI智能助手
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'setAiUnreadCount'
|
||||
]),
|
||||
|
||||
//拨打电话
|
||||
call(){
|
||||
uni.makePhoneCall({
|
||||
phoneNumber:this.tel+''
|
||||
})
|
||||
},
|
||||
|
||||
// 打开AI聊天弹窗
|
||||
openAIChat() {
|
||||
if (this.enableAIChat) {
|
||||
this.setAiUnreadCount(0);
|
||||
}
|
||||
|
||||
this.$util.redirectTo('/pages_tool/ai-chat/index')
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.container-box {
|
||||
width: 100%;
|
||||
|
||||
.item-wrap {
|
||||
border-radius: 10rpx;
|
||||
|
||||
.image-box {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10rpx;
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//悬浮按钮
|
||||
.fixed-box {
|
||||
position: fixed;
|
||||
right: 0rpx;
|
||||
bottom: 200rpx;
|
||||
z-index: 10;
|
||||
// background: #fff;
|
||||
// box-shadow: 2rpx 2rpx 22rpx rgba(0, 0, 0, 0.3);
|
||||
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;
|
||||
background: #fff;
|
||||
border-radius: 50rpx;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
text {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
view {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.show {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
&.switch {}
|
||||
|
||||
&.icon-xiala {
|
||||
margin: 0;
|
||||
margin-top: 0.1rpx;
|
||||
}
|
||||
|
||||
// 未读消息小红点
|
||||
.unread-badge {
|
||||
position: absolute;
|
||||
top: -5rpx;
|
||||
right: -5rpx;
|
||||
background-color: #ff4544;
|
||||
color: white;
|
||||
border-radius: 20rpx;
|
||||
min-width: 30rpx;
|
||||
height: 30rpx;
|
||||
font-size: 10rpx;
|
||||
line-height: 30rpx;
|
||||
text-align: center;
|
||||
padding: 0 8rpx;
|
||||
z-index: 1;
|
||||
box-shadow: 0 2rpx 10rpx rgba(255, 69, 68, 0.3);
|
||||
|
||||
.badge-text {
|
||||
font-size: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user