From fc42a3c9fb49ecf6c72d22738757c5cda8c06130 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期四, 10 十月 2024 16:10:18 +0800 Subject: [PATCH] 主动 scrollToBottom --- src/components/chat/Chat.vue | 69 ++++++++++++++--------- src/components/chat/hooks/useScrollToBottom.ts | 45 +++++--------- src/components/chat/hooks/useAssistantContentOpt.ts | 13 +--- 3 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue index 943c8cd..2143389 100644 --- a/src/components/chat/Chat.vue +++ b/src/components/chat/Chat.vue @@ -2,7 +2,7 @@ <div class="flex h-full"> <div class="flex flex-col h-full flex-auto"> <div class="h-full flex flex-col items-center overflow-y-auto"> - <div ref="chatListDom" class="h-full" :style="{ width: chatWidth }"> + <div ref="chatListDom" class="h-full" v-loading="chatListLoading" :style="{ width: chatWidth }"> <div class="group flex px-4 py-6 hover:bg-slate-100 rounded-lg relative" :class="{ 'flex-row-reverse': item.role === RoleEnum.user }" @@ -156,7 +156,6 @@ </template> <script setup lang="ts"> -import { ElMessage } from 'element-plus'; import _ from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { computed, onMounted, ref } from 'vue'; @@ -331,7 +330,7 @@ }; const sendChatMessage = async (content: ChatContent = messageContent.value, cb?: any, isCallExtParams?: any) => { - if (!content?.values || isTalking.value) return; + if (!content?.values || isTalking.value ||chatListLoading.value) return; const isNewChat = messageList.value.length === 0; if (isNewChat) { if (activeSampleId.value) { @@ -355,6 +354,9 @@ // 鍑虹幇鍥炲锛岀疆绌哄嚭鐜扮瓑寰呭姩鐢� messageList.value.push(assistantItem); + // 婊氬姩鑷冲綋鍓嶅彂閫佹秷鎭� + scrollToBottom(); + if (isCallExtParams) { const extRes = await extCallQuery(isCallExtParams); questionRes = extRes; @@ -374,6 +376,8 @@ assistantItem.historyId = questionRes.history_id; assistantItem.sectionAId = finalCalcSectionAId; appendLastMessageContent(resMsgContent); + // 鏀跺埌鎭㈠锛岀户缁粴 + scrollToBottom(); } catch (error: any) { // appendLastMessageContent({ // type: AnswerType.Text, @@ -400,7 +404,7 @@ let userMsgHistory = []; // 涓嬫鍔犺浇鐢ㄦ埛鎻愰棶绱㈠紩浣嶇疆 let nextUserMsgEndIndex = 0; - +const chatListLoading = ref(false); onMounted(async () => { const res = await QueryHistoryDetail({ history_group_id: currentRouteId, @@ -409,7 +413,8 @@ nextUserMsgEndIndex = userMsgHistory.length; // 鎴彇鍊掓暟 LOAD_CHAT_LIMIT 鏉$敤鎴锋秷鎭� const currentUserMsgList = userMsgHistory.slice(nextUserMsgEndIndex - LOAD_CHAT_LIMIT, nextUserMsgEndIndex); - messageList.value = currentUserMsgList.map((item) => { + + const tmpMessageList = currentUserMsgList.map((item) => { return { historyId: item.history_id, role: RoleEnum.user, @@ -421,44 +426,55 @@ }); const sectionAIdMap = new Map(); - // 鑾峰彇缁撴灉鎻掑叆鍒扮敤鎴锋彁闂箣鍚� - currentUserMsgList.map((item) => { - sectionAIdMap.set(item.history_id, item.section_a_id); - getAnswerById(item.history_id).then((aiRobot) => { - // 鐢ㄦ埛鎻愰棶绱㈠紩 - const userMsgIndex = messageList.value.findIndex((subItem) => subItem?.historyId === item.history_id); - const userMsg = messageList.value[userMsgIndex]; - // values 鍙栧洖绛斾箣鍚庢渶缁堢殑 question - userMsg.content.values = aiRobot.answer?.question ?? userMsg.content.values; - messageList.value.splice( - userMsgIndex + 1, + try { + chatListLoading.value = true; + const resList = await Promise.all( + (currentUserMsgList ?? []).map((item) => { + sectionAIdMap.set(item.history_id, item.section_a_id); + return getAnswerById(item.history_id); + }) + ); + let i = 0; + resList.map((item, index) => { + const insertIndex = index + 1 + i; + const userMsg = tmpMessageList[insertIndex - 1]; + userMsg.content.values = item?.answer?.question ?? userMsg.content.values; + tmpMessageList.splice( + insertIndex, 0, - aiRobot.answer === null + item.answer === null ? null : { - historyId: aiRobot.answer?.history_id, + historyId: item.answer?.history_id, role: RoleEnum.assistant, - content: parseContent(aiRobot.answer), - state: aiRobot.answer_state, - sectionAId: sectionAIdMap.get(aiRobot.answer.history_id), + content: parseContent(item.answer), + state: item.answer_state, + sectionAId: sectionAIdMap.get(item.answer.history_id), } ); + i++; }); - }); - - if (messageList.value.length === 0) { + } finally { + chatListLoading.value = false; + } + messageList.value = tmpMessageList; + if (tmpMessageList.length === 0) { messageContent.value = { type: AnswerType.Text, values: activeChatRoom.value.title, }; sendChatMessage(); + } else { + setTimeout(() => { + // 鍒濆鐘舵�佹粴涓�涓� + scrollToBottom(); + }, 300); } }); -const { forbidScroll } = useScrollToBottom({ +const { scrollToBottom } = useScrollToBottom({ chatListDom: chatListDom, - displayMessageList: computedMessageList, }); //#region ====================== 鍏宠仈鏌ヨ ====================== @@ -495,7 +511,6 @@ showFixQuestion, showAskMore, } = useAssistantContentOpt({ - forbidScroll, sendChatMessage, displayMessageList: computedMessageList, }); diff --git a/src/components/chat/hooks/useAssistantContentOpt.ts b/src/components/chat/hooks/useAssistantContentOpt.ts index a691603..843bc1c 100644 --- a/src/components/chat/hooks/useAssistantContentOpt.ts +++ b/src/components/chat/hooks/useAssistantContentOpt.ts @@ -9,13 +9,12 @@ import { onClickOutside } from '@vueuse/core'; export type AssistantContentOptOption = { - forbidScroll: Ref<boolean>; sendChatMessage: any; displayMessageList: ComputedRef<ChatMessage[]>; }; export const useAssistantContentOpt = (option: AssistantContentOptOption) => { - const { forbidScroll, sendChatMessage, displayMessageList } = option; + const { sendChatMessage, displayMessageList } = option; const { toClipboard } = useClipboard(); const preQuestion = ref(null); @@ -38,10 +37,7 @@ answer_state: toSetState, }); item.state = toSetState; - forbidScroll.value = true; - nextTick(() => { - forbidScroll.value = false; - }); + }; const unLikeClick = async (item) => { @@ -52,10 +48,7 @@ }); item.state = toSetState; - forbidScroll.value = true; - nextTick(() => { - forbidScroll.value = false; - }); + }; const feedbackPosition = ref({ x: 0, diff --git a/src/components/chat/hooks/useScrollToBottom.ts b/src/components/chat/hooks/useScrollToBottom.ts index 3272653..f7484b2 100644 --- a/src/components/chat/hooks/useScrollToBottom.ts +++ b/src/components/chat/hooks/useScrollToBottom.ts @@ -6,49 +6,36 @@ export type UseScrollToBottomOption = { chatListDom: Ref<HTMLDivElement>; - displayMessageList: ComputedRef<ChatMessage[]>; }; export const useScrollToBottom = (option: UseScrollToBottomOption) => { - const { chatListDom, displayMessageList } = option; + const { chatListDom } = option; const scrollToBottom = () => { - if (!chatListDom.value) return; - const parent = chatListDom.value.parentElement; - if (!parent) return; - if (parent.scrollHeight > parent.clientHeight) { - parent.scrollTop = parent.scrollHeight - parent.clientHeight; - } + nextTick(() => { + if (!chatListDom.value) return; + const parent = chatListDom.value.parentElement; + if (!parent) return; + if (parent.scrollHeight > parent.clientHeight) { + parent.scrollTop = parent.scrollHeight - parent.clientHeight; + } + }); }; const debounceAmisScroll = debounce(({ instance }) => { - nextTick(() => { - scrollToBottom(); - }); + scrollToBottom(); }, 500); - emitter.on('amis.page.ready', debounceAmisScroll); + // emitter.on('amis.page.ready', debounceAmisScroll); - onUnmounted(()=>{ - emitter.off('amis.page.ready'); - }) - const forbidScroll = ref(false); - watch( - displayMessageList, - () => { - if (forbidScroll.value) return; - nextTick(() => scrollToBottom()); - }, - { - deep: true, - } - ); + // onUnmounted(() => { + // emitter.off('amis.page.ready'); + // }); onActivated(() => { - if (forbidScroll.value) return; - nextTick(() => scrollToBottom()); + scrollToBottom(); }); return { - forbidScroll, + scrollToBottom, }; }; -- Gitblit v1.9.3