fix(ai-chat): 修复聊天页面键盘弹出时导航栏上移、输入框不可见、间距问题
- 自定义导航栏 position:absolute 固定在顶部,不随键盘上移 - textarea 设置 adjust-position=false,阻止系统上推页面 - 输入框后方加 spacer 垫高层,键盘弹出时将输入框推至键盘上方 - chat-content 根据平台设置不同 top 值(MP:0 / H5:44px) - 去掉输入框多余的安全区域内边距 - scroll-view 底部 padding 随键盘高度动态调整
This commit is contained in:
@@ -68,7 +68,7 @@ export default {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AI Service] Dify API请求失败,详细错误:', error);
|
console.error('[AI Service] AiChat API请求失败,详细错误:', error);
|
||||||
console.error('[AI Service] 错误堆栈:', error.stack);
|
console.error('[AI Service] 错误堆栈:', error.stack);
|
||||||
// 打印更多信息帮助调试
|
// 打印更多信息帮助调试
|
||||||
console.error('[AI Service] store 状态:', {
|
console.error('[AI Service] store 状态:', {
|
||||||
|
|||||||
@@ -119,9 +119,9 @@ export class CustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳转到 AI智能客服页面(Dify)
|
* 跳转到 AI智能客服页面(AiChat)
|
||||||
*/
|
*/
|
||||||
openDifyService() {
|
openAiChatService() {
|
||||||
try {
|
try {
|
||||||
// 清除未读数(如果存在)
|
// 清除未读数(如果存在)
|
||||||
if (typeof this.vm.setAiUnreadCount === 'function') {
|
if (typeof this.vm.setAiUnreadCount === 'function') {
|
||||||
@@ -177,7 +177,7 @@ export class CustomerService {
|
|||||||
// 核心路由:根据 type 决定行为
|
// 核心路由:根据 type 决定行为
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case 'aikefu':
|
case 'aikefu':
|
||||||
this.openDifyService();
|
this.openAiChatService();
|
||||||
break;
|
break;
|
||||||
case 'wxwork':
|
case 'wxwork':
|
||||||
this.openWxworkService(false, config, options);
|
this.openWxworkService(false, config, options);
|
||||||
@@ -364,7 +364,7 @@ export class CustomerService {
|
|||||||
|
|
||||||
openAliappService(config) {
|
openAliappService(config) {
|
||||||
if (config.type === 'aikefu') {
|
if (config.type === 'aikefu') {
|
||||||
this.openDifyService();
|
this.openAiChatService();
|
||||||
} else if (config.type === 'third') {
|
} else if (config.type === 'third') {
|
||||||
this.openThirdService(config);
|
this.openThirdService(config);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="ai-chat-container">
|
<view class="ai-chat-container" :style="aiChatContainerStyle">
|
||||||
<!-- 聊天消息列表 - 统一使用 scroll-into-view -->
|
<!-- 聊天消息列表 - 统一使用 scroll-into-view -->
|
||||||
<scroll-view
|
<scroll-view
|
||||||
class="chat-messages"
|
class="chat-messages"
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 输入区域 -->
|
<!-- 输入区域 -->
|
||||||
<view class="input-area" :style="inputAreaStyle" >
|
<view class="input-area" :style="inputAreaStyle">
|
||||||
<view class="input-tools">
|
<view class="input-tools">
|
||||||
<button class="tool-btn" @click="showMoreTools" style="display: none;">
|
<button class="tool-btn" @click="showMoreTools" style="display: none;">
|
||||||
<text class="iconfont icon-plus">...</text>
|
<text class="iconfont icon-plus">...</text>
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
:maxlength="500"
|
:maxlength="500"
|
||||||
:auto-height="true"
|
:auto-height="true"
|
||||||
:show-confirm-bar="false"
|
:show-confirm-bar="false"
|
||||||
:adjust-position="true"
|
:adjust-position="false"
|
||||||
:cursor-spacing="150"
|
:cursor-spacing="150"
|
||||||
@confirm="sendMessage"
|
@confirm="sendMessage"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
@@ -329,6 +329,9 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 键盘垫高层:键盘弹出时撑开空间将输入框上推 -->
|
||||||
|
<view v-if="keyboardHeight > 0" :style="{ height: keyboardHeight + 'px', flexShrink: 0 }"></view>
|
||||||
|
|
||||||
<!-- 语音输入面板 -->
|
<!-- 语音输入面板 -->
|
||||||
<view v-if="enalbeVoicePanelShow" class="voice-popup">
|
<view v-if="enalbeVoicePanelShow" class="voice-popup">
|
||||||
<view class="voice-mask" @click="hideVoicePanel"></view>
|
<view class="voice-mask" @click="hideVoicePanel"></view>
|
||||||
@@ -499,7 +502,7 @@ export default {
|
|||||||
// AI头像错误状态
|
// AI头像错误状态
|
||||||
avatarError: false,
|
avatarError: false,
|
||||||
|
|
||||||
// Dify API相关
|
// AiChat API相关
|
||||||
currentConversationId: null,
|
currentConversationId: null,
|
||||||
isAIServiceAvailable: true,
|
isAIServiceAvailable: true,
|
||||||
aiServiceError: null,
|
aiServiceError: null,
|
||||||
@@ -523,16 +526,17 @@ export default {
|
|||||||
return this.$util.img(IMAGE_CONFIG.aiAvatar);
|
return this.$util.img(IMAGE_CONFIG.aiAvatar);
|
||||||
},
|
},
|
||||||
chatMessagesStyle() {
|
chatMessagesStyle() {
|
||||||
// 输入框在 flex 流中,scroll-view 仅在键盘弹出时需要底部padding
|
// 键盘弹出时增加底部padding,避免消息内容被键盘遮挡
|
||||||
// 键盘收起时:padding = 0(scroll-view 底部自然紧贴输入框顶部)
|
|
||||||
// 键盘弹出时:padding = 键盘高度(避免最后消息被键盘遮挡)
|
|
||||||
return {
|
return {
|
||||||
'padding-bottom': this.keyboardHeight > 0 ? this.keyboardHeight + 'px' : '0px'
|
'padding-bottom': this.keyboardHeight > 0 ? this.keyboardHeight + 'px' : '0px'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
aiChatContainerStyle() {
|
||||||
|
// 键盘高度由末尾垫高 view 处理,容器无需额外样式
|
||||||
|
return {};
|
||||||
|
},
|
||||||
inputAreaStyle() {
|
inputAreaStyle() {
|
||||||
// 输入框在 flex 流中自然定位到容器底部,无需额外样式
|
// 输入框在 flex 流中自然定位,无需额外样式
|
||||||
// 键盘弹出时由 <textarea adjust-position> 自动处理页面偏移
|
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
canSendMessage() {
|
canSendMessage() {
|
||||||
@@ -2212,9 +2216,14 @@ $radius-lg: 36rpx;
|
|||||||
|
|
||||||
/* 页面样式 */
|
/* 页面样式 */
|
||||||
.ai-chat-container {
|
.ai-chat-container {
|
||||||
height: 100vh;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
background: #f8f8f8; /* 微信聊天页面背景色 */
|
background: #f8f8f8; /* 微信聊天页面背景色 */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -2892,8 +2901,6 @@ $radius-lg: 36rpx;
|
|||||||
border-top: 1rpx solid #e5e5e5;
|
border-top: 1rpx solid #e5e5e5;
|
||||||
padding: 16rpx 24rpx;
|
padding: 16rpx 24rpx;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
/* 微信小程序安全区域适配 */
|
|
||||||
padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
.input-tools {
|
.input-tools {
|
||||||
|
|||||||
@@ -1,23 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="container" :style="wrapperPageStyle">
|
<view class="wrapper">
|
||||||
<!--自定义导航头部 - 只在微信小程序显示,H5端隐藏 -->
|
<!--自定义导航头部 - 绝对定位在顶部,不随键盘上移 -->
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<view class="custom-navbar" ref="pageHeader" v-if="showCustomNavbar">
|
<view class="custom-navbar" ref="pageHeader" v-if="showCustomNavbar">
|
||||||
<view class="header-left">
|
<view class="header-left">
|
||||||
<button class="back-btn" v-show="showBackButton" @click="goBack">
|
<button class="back-btn" v-show="showBackButton" @click="goBack">
|
||||||
<text class="iconfont icon-back"></text>
|
<text class="iconfont icon-back"></text>
|
||||||
</button>
|
</button>
|
||||||
<!-- 占位元素,确保布局平衡 -->
|
|
||||||
<view v-show="!showMenuButton" class="placeholder"></view>
|
<view v-show="!showMenuButton" class="placeholder"></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
|
|
||||||
<!-- 聊天内容区域 -->
|
<!-- 聊天内容区域:从导航栏下方到容器底部 -->
|
||||||
<view class="chat-content"
|
<view class="chat-content">
|
||||||
:style="wrapperChatContentStyle"
|
|
||||||
>
|
|
||||||
<!-- AI聊天组件 -->
|
|
||||||
<ai-chat-message
|
<ai-chat-message
|
||||||
ref="chat"
|
ref="chat"
|
||||||
:initial-messages="initialMessages"
|
:initial-messages="initialMessages"
|
||||||
@@ -131,37 +127,6 @@ export default {
|
|||||||
return this.globalAIKefuConfig?.aiAvatar || this.$util.img(IMAGE_CONFIG.aiAvatar)
|
return this.globalAIKefuConfig?.aiAvatar || this.$util.img(IMAGE_CONFIG.aiAvatar)
|
||||||
},
|
},
|
||||||
/// ---- others ----
|
/// ---- others ----
|
||||||
containerHeight() {
|
|
||||||
return `calc(100vh - ${this.navBarHeight + this.statusBarHeight}px)`
|
|
||||||
},
|
|
||||||
wrapperPageStyle() {
|
|
||||||
// #ifdef H5
|
|
||||||
return `top: $ {this.navBarHeight + 'px'};`
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
return `top: -1px;` // 微信小程序需要上移1px, 否则与系统导航栏出现1px的空隙
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
return ``
|
|
||||||
},
|
|
||||||
wrapperChatContentStyle() {
|
|
||||||
// #ifdef H5
|
|
||||||
// H5端没有自定义导航栏,不需要paddingTop
|
|
||||||
return {
|
|
||||||
height: this.containerHeight,
|
|
||||||
paddingTop: '0'
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
// 微信小程序端根据导航栏显示情况决定
|
|
||||||
return {
|
|
||||||
height: this.containerHeight,
|
|
||||||
paddingTop: this.showCustomNavbar ? '0' : (this.navBarHeight + 'px')
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async onLoad(options) {
|
async onLoad(options) {
|
||||||
@@ -574,20 +539,22 @@ export default {
|
|||||||
@import url('/common/css/iconfont.css');
|
@import url('/common/css/iconfont.css');
|
||||||
|
|
||||||
/* 页面样式 */
|
/* 页面样式 */
|
||||||
.container {
|
.wrapper {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: white; /* 白色 */
|
|
||||||
overflow: hidden;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 48px;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* 自定义导航头部 */
|
/* 自定义导航头部:固定在wrapper顶部,不随键盘上移 */
|
||||||
.custom-navbar {
|
.custom-navbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 88rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -667,12 +634,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 聊天内容区域 */
|
/* 聊天内容区域:从导航栏下方到容器底部 */
|
||||||
.chat-content {
|
.chat-content {
|
||||||
flex: 1;
|
position: absolute;
|
||||||
display: flex;
|
/* #ifdef MP-WEIXIN */
|
||||||
flex-direction: column;
|
top: 0;
|
||||||
overflow: hidden;
|
/* #endif */
|
||||||
|
/* #ifndef MP-WEIXIN */
|
||||||
|
top: 44px;
|
||||||
|
/* #endif */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 底部tabBar占位样式 */
|
/* 底部tabBar占位样式 */
|
||||||
|
|||||||
Reference in New Issue
Block a user