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:
2026-05-13 16:01:15 +08:00
parent 39245dfcac
commit 69466f410c
4 changed files with 53 additions and 73 deletions

View File

@@ -68,7 +68,7 @@ export default {
}
return result;
} 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] store 状态:', {

View File

@@ -119,9 +119,9 @@ export class CustomerService {
}
/**
* 跳转到 AI智能客服页面(Dify)
* 跳转到 AI智能客服页面(AiChat)
*/
openDifyService() {
openAiChatService() {
try {
// 清除未读数(如果存在)
if (typeof this.vm.setAiUnreadCount === 'function') {
@@ -177,7 +177,7 @@ export class CustomerService {
// 核心路由:根据 type 决定行为
switch (config.type) {
case 'aikefu':
this.openDifyService();
this.openAiChatService();
break;
case 'wxwork':
this.openWxworkService(false, config, options);
@@ -364,7 +364,7 @@ export class CustomerService {
openAliappService(config) {
if (config.type === 'aikefu') {
this.openDifyService();
this.openAiChatService();
} else if (config.type === 'third') {
this.openThirdService(config);
} else {

View File

@@ -1,5 +1,5 @@
<template>
<view class="ai-chat-container">
<view class="ai-chat-container" :style="aiChatContainerStyle">
<!-- 聊天消息列表 - 统一使用 scroll-into-view -->
<scroll-view
class="chat-messages"
@@ -197,7 +197,7 @@
</scroll-view>
<!-- 输入区域 -->
<view class="input-area" :style="inputAreaStyle" >
<view class="input-area" :style="inputAreaStyle">
<view class="input-tools">
<button class="tool-btn" @click="showMoreTools" style="display: none;">
<text class="iconfont icon-plus">...</text>
@@ -215,7 +215,7 @@
:maxlength="500"
:auto-height="true"
:show-confirm-bar="false"
:adjust-position="true"
:adjust-position="false"
:cursor-spacing="150"
@confirm="sendMessage"
@input="onInput"
@@ -329,6 +329,9 @@
</view>
</view>
<!-- 键盘垫高层:键盘弹出时撑开空间将输入框上推 -->
<view v-if="keyboardHeight > 0" :style="{ height: keyboardHeight + 'px', flexShrink: 0 }"></view>
<!-- 语音输入面板 -->
<view v-if="enalbeVoicePanelShow" class="voice-popup">
<view class="voice-mask" @click="hideVoicePanel"></view>
@@ -499,7 +502,7 @@ export default {
// AI头像错误状态
avatarError: false,
// Dify API相关
// AiChat API相关
currentConversationId: null,
isAIServiceAvailable: true,
aiServiceError: null,
@@ -523,16 +526,17 @@ export default {
return this.$util.img(IMAGE_CONFIG.aiAvatar);
},
chatMessagesStyle() {
// 输入框在 flex 流中,scroll-view 仅在键盘弹出时需要底部padding
// 键盘收起时:padding = 0(scroll-view 底部自然紧贴输入框顶部)
// 键盘弹出时:padding = 键盘高度(避免最后消息被键盘遮挡)
// 键盘弹出时增加底部padding,避免消息内容被键盘遮挡
return {
'padding-bottom': this.keyboardHeight > 0 ? this.keyboardHeight + 'px' : '0px'
};
},
aiChatContainerStyle() {
// 键盘高度由末尾垫高 view 处理,容器无需额外样式
return {};
},
inputAreaStyle() {
// 输入框在 flex 流中自然定位到容器底部,无需额外样式
// 键盘弹出时由 <textarea adjust-position> 自动处理页面偏移
// 输入框在 flex 流中自然定位,无需额外样式
return {};
},
canSendMessage() {
@@ -2212,9 +2216,14 @@ $radius-lg: 36rpx;
/* 页面样式 */
.ai-chat-container {
height: 100vh;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
background: #f8f8f8; /* 微信聊天页面背景色 */
overflow: hidden;
box-sizing: border-box;
@@ -2892,8 +2901,6 @@ $radius-lg: 36rpx;
border-top: 1rpx solid #e5e5e5;
padding: 16rpx 24rpx;
flex-shrink: 0;
/* 微信小程序安全区域适配 */
padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
.input-tools {

View File

@@ -1,23 +1,19 @@
<template>
<view class="container" :style="wrapperPageStyle">
<!--自定义导航头部 - 只在微信小程序显示,H5端隐藏 -->
<view class="wrapper">
<!--自定义导航头部 - 绝对定位在顶部,不随键盘上移 -->
<!-- #ifdef MP-WEIXIN -->
<view class="custom-navbar" ref="pageHeader" v-if="showCustomNavbar">
<view class="header-left">
<button class="back-btn" v-show="showBackButton" @click="goBack">
<text class="iconfont icon-back"></text>
</button>
<!-- 占位元素,确保布局平衡 -->
<view v-show="!showMenuButton" class="placeholder"></view>
</view>
</view>
<!-- #endif -->
<!-- 聊天内容区域 -->
<view class="chat-content"
:style="wrapperChatContentStyle"
>
<!-- AI聊天组件 -->
<!-- 聊天内容区域:从导航栏下方到容器底部 -->
<view class="chat-content">
<ai-chat-message
ref="chat"
:initial-messages="initialMessages"
@@ -131,37 +127,6 @@ export default {
return this.globalAIKefuConfig?.aiAvatar || this.$util.img(IMAGE_CONFIG.aiAvatar)
},
/// ---- 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) {
@@ -574,20 +539,22 @@ export default {
@import url('/common/css/iconfont.css');
/* 页面样式 */
.container {
display: flex;
flex-direction: column;
background-color: white; /* 白色 */
overflow: hidden;
position: fixed;
top: 48px;
left: 0;
right: 0;
bottom: 0;
}
.wrapper {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
/* 自定义导航头部 */
/* 自定义导航头部:固定在wrapper顶部,不随键盘上移 */
.custom-navbar {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
@@ -667,12 +634,18 @@ export default {
}
}
/* 聊天内容区域 */
/* 聊天内容区域:从导航栏下方到容器底部 */
.chat-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
position: absolute;
/* #ifdef MP-WEIXIN */
top: 0;
/* #endif */
/* #ifndef MP-WEIXIN */
top: 44px;
/* #endif */
left: 0;
right: 0;
bottom: 0;
}
/* 底部tabBar占位样式 */