Merge remote-tracking branch 'origin/dev-wdb' into dev-hjf

This commit is contained in:
Jafeng 2026-02-12 14:21:20 +08:00
commit 150c6072d7
6 changed files with 112 additions and 52 deletions

View File

@ -6,13 +6,15 @@ $text-color-sub: #999;
$primary-color: #0877F1;
.chat-page {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
overflow: hidden;
position: relative;
width: 100%;
}
/* 患者信息栏样式 - 固定在顶部 */
@ -24,10 +26,8 @@ $primary-color: #0877F1;
background: #fff;
border-bottom: 1rpx solid #f0f0f0;
padding: 20rpx 32rpx;
z-index: 100;
flex-shrink: 0; /* 防止被压缩 */
width: 100%;
box-sizing: border-box;
z-index: 10;
flex-shrink: 0;
}
.patient-info-content {
@ -91,15 +91,14 @@ $primary-color: #0877F1;
}
.chat-content {
flex: 1;
position: fixed;
top: 100rpx; /* 患者信息栏高度,根据实际调整 */
left: 0;
right: 0;
bottom: 200rpx; /* 输入框高度,根据实际调整 */
box-sizing: border-box;
overflow-x: hidden;
overflow-y: auto;
min-height: 0;
margin-top: 120rpx;
margin-bottom: 0;
position: relative;
z-index: 1;
}
.chat-content-compressed {
@ -364,19 +363,31 @@ $primary-color: #0877F1;
}
.input-section {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
border-top: 1rpx solid #e0e0e0;
position: relative;
z-index: 200;
padding-bottom: env(safe-area-inset-bottom);
flex-shrink: 0;
transform: translateZ(0); /* 开启硬件加速,提升性能 */
display: flex;
flex-direction: column;
}
.ai-assistant-slot {
width: 100%;
background: #fff;
}
.input-toolbar {
display: flex;
align-items: center;
padding: 16rpx 20rpx;
padding: 12rpx 20rpx;
padding-bottom: env(safe-area-inset-bottom);
gap: 12rpx;
border-top: 1rpx solid #e0e0e0;
background: #fff;
}
.voice-toggle-btn {
@ -499,7 +510,8 @@ $primary-color: #0877F1;
justify-content: flex-start;
background: #fff;
border-top: 1rpx solid #eee;
padding: 20rpx 0 40rpx 60rpx;
padding: 20rpx 0 20rpx 60rpx;
padding-bottom: env(safe-area-inset-bottom);
gap: 40rpx 50rpx;
flex-wrap: wrap;
background-color: #f5f5f5;

View File

@ -383,7 +383,6 @@ defineExpose({
gap: 16rpx;
padding: 16rpx 24rpx;
background-color: #f8f9fa;
border-bottom: 1rpx solid #e5e5e5;
.ai-button {
display: flex;

View File

@ -1,5 +1,10 @@
<template>
<view class="input-section">
<!-- AI助手按钮组 -->
<view class="ai-assistant-slot">
<slot name="ai-assistant"></slot>
</view>
<view class="input-toolbar">
<view @click="toggleVoiceInput" class="voice-toggle-btn">
<image v-if="showVoiceInput" src="/static/jianpan.png" class="voice-toggle-icon" mode="aspectFit"></image>
@ -8,7 +13,8 @@
<view class="input-area">
<textarea v-if="!showVoiceInput" class="text-input" v-model="inputText" placeholder="我来说两句..."
@confirm="sendTextMessage" @focus="handleInputFocus" @input="handleInput"
:auto-height="true" :show-confirm-bar="false" :adjust-position="true" :cursor-spacing="30"
:auto-height="true" :show-confirm-bar="false" :hold-keyboard="true"
ref="textareaRef"
/>
<input v-else class="voice-input-btn" :class="{ recording: isRecording }" @touchstart="startRecord"
@touchmove="onRecordTouchMove" @touchend="stopRecord" @touchcancel="cancelRecord" :placeholder="isRecording ? '松开发送' : '按住说话'" disabled>
@ -100,6 +106,7 @@ const showVoiceInput = ref(false);
const showMorePanel = ref(false);
const isRecording = ref(false);
const recordingText = ref("录音中...");
const textareaRef = ref(null);
const cloudCustomData = computed(() => {
const arr = [
props.chatRoomBusiness.businessType,
@ -167,8 +174,19 @@ const initRecorderManager = () => {
const sendTextMessage = async () => {
if (!inputText.value.trim()) return;
await sendMessage("text", inputText.value);
const textToSend = inputText.value;
inputText.value = "";
await sendMessage("text", textToSend);
//
nextTick(() => {
// focus
//
setTimeout(() => {
// hold-keyboard
}, 50);
});
};
//

View File

@ -133,23 +133,6 @@
@cancel="handleRejectReasonCancel"
/>
<!-- AI助手按钮组 -->
<AIAssistantButtons
v-if="
!isEvaluationPopupOpen &&
!showConsultAccept &&
orderStatus === 'processing'
"
ref="aiAssistantRef"
:groupId="groupId"
:patientAccountId="chatInfo.userID || ''"
:patientId="patientId"
:corpId="corpId"
@streamText="handleStreamText"
@clearInput="handleClearInput"
@generatingStateChange="handleGeneratingStateChange"
/>
<!-- 聊天输入组件 -->
<ChatInput
v-if="!isEvaluationPopupOpen && !showConsultAccept"
@ -172,7 +155,22 @@
@messageSent="() => scrollToBottom(true)"
@endConsult="handleEndConsult"
@openConsult="handleOpenConsult"
/>
>
<!-- AI助手按钮组插槽 -->
<template #ai-assistant>
<AIAssistantButtons
v-if="orderStatus === 'processing'"
ref="aiAssistantRef"
:groupId="groupId"
:patientAccountId="chatInfo.userID || ''"
:patientId="patientId"
:corpId="corpId"
@streamText="handleStreamText"
@clearInput="handleClearInput"
@generatingStateChange="handleGeneratingStateChange"
/>
</template>
</ChatInput>
</view>
</template>
@ -214,6 +212,7 @@ const timChatManager = globalTimChatManager;
const PENDING_FOLLOWUP_SEND_STORAGE_KEY = "ykt_followup_pending_send";
const pendingFollowUpSendConsumed = ref(false);
const initialMessageListLoaded = ref(false);
const isCallbacksInitialized = ref(false); //
function normalizeGroupId(v) {
const s = String(v || "").trim();
@ -302,6 +301,7 @@ const chatInfo = ref({
userID: "",
avatar: "/static/home/avatar.svg",
});
//
const isEvaluationPopupOpen = ref(false);
@ -492,6 +492,9 @@ const checkLoginAndInitTIM = async () => {
// IM
const initTIMCallbacks = async () => {
//
isCallbacksInitialized.value = true;
timChatManager.setCallback("onSDKReady", () => {
if (messageList.value.length === 0 && !isLoading.value) {
loadMessageList();
@ -878,26 +881,49 @@ onShow(() => {
if (!isIMInitialized.value) {
checkLoginAndInitTIM();
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
timChatManager.ensureIMConnection();
// IM
timChatManager.ensureIMConnection().then(() => {
//
if (timChatManager.isLoggedIn && chatInfo.value.conversationID) {
console.log("✓ 重连成功,重新注册消息监听回调");
initTIMCallbacks();
timChatManager.setConversationID(chatInfo.value.conversationID);
}
});
} else if (
timChatManager.tim &&
timChatManager.isLoggedIn &&
chatInfo.value.conversationID
)
) {
// IMID
console.log("✓ 页面显示重新设置当前会话ID");
timChatManager.setConversationID(chatInfo.value.conversationID);
//
if (!isCallbacksInitialized.value) {
console.log("✓ 回调未初始化,进行初始化");
initTIMCallbacks();
}
//
if (timChatManager.tim && timChatManager.isLoggedIn) {
timChatManager.tim
.setMessageRead({
conversationID: chatInfo.value.conversationID,
})
.then(() => {
console.log("✓ 页面显示时已标记会话为已读");
})
.catch((error) => {
console.error("✗ 标记会话已读失败:", error);
});
}
startIMMonitoring(30000);
}
// 访
uni.$on("send-followup-message", handleSendFollowUpMessage);
//
uni.onKeyboardHeightChange((res) => {
if (res.height > 0) {
//
setTimeout(() => {
scrollToBottom(true);
}, 100);
}
});
});
// 访

View File

@ -96,4 +96,8 @@ onLoad((opt) => {
width: 40rpx;
height: 40rpx;
}
.pt-12 {
padding-top: 24rpx;
}
</style>

View File

@ -192,6 +192,7 @@ export async function sendArticleMessage(article, options = {}) {
userId: options.userId,
customerId: options.customerId,
corpId: options.corpId,
uniqueRecord: 'YES'
};
if (options.teamId) {
params.teamId = options.teamId;