From bd639f00fe39d981c27203e7c4cdd0f3b92cb7d2 Mon Sep 17 00:00:00 2001
From: yangyin <1850366751@qq.com>
Date: 星期四, 31 十月 2024 15:06:35 +0800
Subject: [PATCH] 添加对话时间

---
 src/components/chat/Chat.vue |  149 ++++++++++++++++++++++++-------------------------
 1 files changed, 73 insertions(+), 76 deletions(-)

diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue
index 943c8cd..f881ca4 100644
--- a/src/components/chat/Chat.vue
+++ b/src/components/chat/Chat.vue
@@ -1,14 +1,19 @@
 <template>
 	<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="relative h-full flex flex-col items-center overflow-y-auto">
+				<span
+					class="more-loading absolute text-blue-400 left-[50%] translate-x-[-50%] cursor-pointer w-10"
+					v-loading="moreIsLoading"
+				></span>
+				<div class="h-full relative" 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 }"
 						v-for="(item, index) of computedMessageList"
-						:key="index"
+						:key="`${item.historyId}_${item.role}`"
 					>
+						<div class="absolute top-0 left-[72px] text-[#1c86ff]">{{ item?.createTime?.slice(5, 19) }}</div>
 						<img
 							class="rounded-full size-12 flex-0"
 							:class="{ 'mr-4': item.role === RoleEnum.assistant, 'ml-4': item.role === RoleEnum.user }"
@@ -123,7 +128,7 @@
 							</div>
 						</div>
 					</div>
-					<div v-if="showAskMore" class="ml-4 mt-5 text-sm">
+					<div v-if="showAskMore" class="ml-4 mt-5 text-sm pb-10">
 						<div class="text-gray-600 mb-5">浣犲彲浠ョ户缁棶鎴戯細</div>
 						<div class="space-y-2 inline-flex flex-col">
 							<div
@@ -139,7 +144,7 @@
 				</div>
 			</div>
 
-			<div class="sticky bottom-0 w-full p-6 pb-8 bg-[rgb(247,248,250)] flex justify-center">
+			<div class="sticky bottom-0 w-full p-6 bg-[rgb(247,248,250)] flex justify-center">
 				<PlayBar
 					v-model:voicePageIsShow="voicePageIsShow"
 					:isTalking="isTalking"
@@ -156,7 +161,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';
@@ -164,14 +168,24 @@
 import Loding from './components/Loding.vue';
 import { useAssistantContentOpt } from './hooks/useAssistantContentOpt';
 import { useQueryProcess } from './hooks/useQueryProcess';
+import { useScrollLoad } from './hooks/useScrollLoad';
 import { useScrollToBottom } from './hooks/useScrollToBottom';
 import type { ChatContent } from './model/types';
 import { AnswerState, AnswerType, RoleEnum, answerTypeMapCom, roleImageMap, type ChatMessage } from './model/types';
-import { GetHistoryAnswer, QueryHistoryDetail, QuestionAi, extCallQuery } from '/@/api/ai/chat';
+import { QuestionAi, extCallQuery } from '/@/api/ai/chat';
 import PlayBar from '/@/components/chat/components/playBar/PlayBar.vue';
 import CustomDrawer from '/@/components/drawer/CustomDrawer.vue';
 import router from '/@/router';
-import { activeChatRoom, activeLLMId, activeSampleId, activeSectionAId, getRoomConfig, roomConfig } from '/@/stores/chatRoom';
+import {
+	activeChatRoom,
+	activeGroupType,
+	activeLLMId,
+	activeRoomId,
+	activeSampleId,
+	activeSectionAId,
+	getRoomConfig,
+	roomConfig,
+} from '/@/stores/chatRoom';
 import { ErrorCode } from '/@/utils/request';
 
 const chatWidth = '75%';
@@ -183,12 +197,12 @@
 });
 const currentRoute = router.currentRoute;
 const currentRouteId = currentRoute.value.query.id as string;
+activeRoomId.value = currentRouteId;
 const chatListDom = ref<HTMLDivElement>();
 const messageList = ref<ChatMessage[]>([]);
 const computedMessageList = computed(() => {
 	return messageList.value.filter((v) => !!v);
 });
-
 const parseContent = (res) => {
 	if (!res) return null;
 	let content: ChatContent = {
@@ -248,10 +262,8 @@
 	content.origin = res;
 	return content;
 };
-
 const { clearQueryProcess, process, processId, queryProcess } = useQueryProcess();
 const DEFAULT_SECTION_A_ID = 'knowledge_base';
-
 let questionRes = null;
 
 let finalCalcSectionAId = null;
@@ -290,11 +302,15 @@
 		process_id: processId.value,
 		question: text,
 		// FIXME: 鏆傛椂杩欐牱
-		section_a_id: currentSectionAId,
+		// section_a_id: currentSectionAId,
 		history_group_id: currentRouteId,
 		raw_mode: roomConfig.value?.[currentRouteId]?.isAnswerByLLM ?? false,
 		...judgeParams,
 	} as any;
+
+	if (activeGroupType.value) {
+		params.group_type = activeGroupType.value;
+	}
 
 	if (currentSampleId) {
 		params.sample_id = currentSampleId;
@@ -324,14 +340,8 @@
 
 let currentLLMId = null;
 
-const getAnswerById = async (historyId: string) => {
-	return await GetHistoryAnswer({
-		history_id: historyId,
-	});
-};
-
 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 +365,9 @@
 
 		// 鍑虹幇鍥炲锛岀疆绌哄嚭鐜扮瓑寰呭姩鐢�
 		messageList.value.push(assistantItem);
+		// 婊氬姩鑷冲綋鍓嶅彂閫佹秷鎭�
+		scrollToBottom();
+
 		if (isCallExtParams) {
 			const extRes = await extCallQuery(isCallExtParams);
 			questionRes = extRes;
@@ -362,7 +375,7 @@
 		} else {
 			resMsgContent = await questionAi(content.values);
 		}
-
+		nextUserMsgEndIndex.value++;
 		if (isNewChat) {
 			const firstResCb = getRoomConfig(currentRouteId, 'firstResCb');
 			firstResCb?.(resMsgContent);
@@ -374,6 +387,10 @@
 		assistantItem.historyId = questionRes.history_id;
 		assistantItem.sectionAId = finalCalcSectionAId;
 		appendLastMessageContent(resMsgContent);
+		setTimeout(() => {
+			// 鏀跺埌鍥炲锛岀户缁粴
+			scrollToBottom();
+		}, 300);
 	} catch (error: any) {
 		// appendLastMessageContent({
 		// 	type: AnswerType.Text,
@@ -392,60 +409,27 @@
 		messageList.value.at(-1).content = content;
 	}
 };
+const { loadRangeData, onChatListScroll, moreIsLoading, nextUserMsgEndIndex } = useScrollLoad({
+	container: chatListDom,
+	historyGroupId: currentRouteId,
+	messageList,
+	parseAnswerContent: parseContent,
+});
 
-// 涓�娆℃�у姞杞芥渶杩戞潯鏁伴檺鍒�
-const LOAD_CHAT_LIMIT = 10;
+const chatListLoading = ref(false);
 
-// 鎵�鏈夌敤鎴锋彁闂巻鍙茶褰�
-let userMsgHistory = [];
-// 涓嬫鍔犺浇鐢ㄦ埛鎻愰棶绱㈠紩浣嶇疆
-let nextUserMsgEndIndex = 0;
+const { scrollToBottom } = useScrollToBottom({
+	chatListDom: chatListDom,
+});
 
 onMounted(async () => {
-	const res = await QueryHistoryDetail({
-		history_group_id: currentRouteId,
-	});
-	userMsgHistory = res.details ?? [];
-	nextUserMsgEndIndex = userMsgHistory.length;
-	// 鎴彇鍊掓暟 LOAD_CHAT_LIMIT 鏉$敤鎴锋秷鎭�
-	const currentUserMsgList = userMsgHistory.slice(nextUserMsgEndIndex - LOAD_CHAT_LIMIT, nextUserMsgEndIndex);
-	messageList.value = currentUserMsgList.map((item) => {
-		return {
-			historyId: item.history_id,
-			role: RoleEnum.user,
-			content: {
-				type: AnswerType.Text,
-				values: item.question,
-			},
-		} as ChatMessage;
-	});
-	const sectionAIdMap = new Map();
+	messageList.value = [];
+	// 鍔犺浇鍒濆鏁版嵁
+	chatListLoading.value = true;
 
-	// 鑾峰彇缁撴灉鎻掑叆鍒扮敤鎴锋彁闂箣鍚�
-	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,
-				0,
-				aiRobot.answer === null
-					? null
-					: {
-							historyId: aiRobot.answer?.history_id,
-							role: RoleEnum.assistant,
-							content: parseContent(aiRobot.answer),
-							state: aiRobot.answer_state,
-							sectionAId: sectionAIdMap.get(aiRobot.answer.history_id),
-					  }
-			);
-		});
+	await loadRangeData().finally(() => {
+		chatListLoading.value = false;
 	});
-
 	if (messageList.value.length === 0) {
 		messageContent.value = {
 			type: AnswerType.Text,
@@ -453,14 +437,17 @@
 		};
 
 		sendChatMessage();
+	} else {
+		setTimeout(() => {
+			// 鍒濆鐘舵�佹粴涓�涓�
+			scrollToBottom();
+
+			setTimeout(() => {
+				chatListDom.value.addEventListener('scroll', onChatListScroll);
+			}, 300);
+		}, 300);
 	}
 });
-
-const { forbidScroll } = useScrollToBottom({
-	chatListDom: chatListDom,
-	displayMessageList: computedMessageList,
-});
-
 //#region ====================== 鍏宠仈鏌ヨ ======================
 const relativeQueryClick = async (val) => {
 	sendChatMessage(
@@ -495,7 +482,6 @@
 	showFixQuestion,
 	showAskMore,
 } = useAssistantContentOpt({
-	forbidScroll,
 	sendChatMessage,
 	displayMessageList: computedMessageList,
 });
@@ -509,10 +495,21 @@
 //#endregion
 </script>
 
-<style scoped>
+<style scoped lang="scss">
 pre {
 	font-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica, 'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC',
 		'Hiragino Sans GB', 'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN', 'Microsoft YaHei', 'Wenquanyi Micro Hei',
 		'WenQuanYi Zen Hei', 'ST Heiti', SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
 }
+
+.more-loading {
+	:deep(.el-loading-spinner) {
+		--loading-size: 35px;
+		margin-top: 0;
+		.circular {
+			width: var(--loading-size);
+			height: var(--loading-size);
+		}
+	}
+}
 </style>

--
Gitblit v1.9.3