From 1d0eec6da86e3e9bcbf002d1a22142586fe023a3 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期二, 31 十二月 2024 11:34:15 +0800 Subject: [PATCH] 拆分组件 assistantMsg.vue --- src/components/chat/Chat.vue | 335 ++++--------------------------------------------------- 1 files changed, 25 insertions(+), 310 deletions(-) diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue index 4cad518..ff4ec3f 100644 --- a/src/components/chat/Chat.vue +++ b/src/components/chat/Chat.vue @@ -12,267 +12,20 @@ <div v-for="(item, msgIndex) of computedMessageList" :key="`${item.historyId}_${item.role}`"> <UserMsg :msg="item" - @copyMsg="copyClick" @shareClick="shareClick" @setCommonQuestion="setCommonQuestionClick" v-if="item.role === RoleEnum.user" ></UserMsg> - <div v-else class="flex px-4 py-6 rounded-lg relative" :class="{ 'px-10': isShareCheck }"> - <div class="absolute top-0 left-[72px] text-[#8d8e99]">{{ item?.createTime }}</div> - - <img - class="rounded-full size-12 flex-0" - :class="{ 'mr-4': item.role === RoleEnum.assistant }" - :src="roleImageMap[item.role]" - alt="" - srcset="" - /> - <div class="flex-auto flex"> - <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }"> - <div class="w-full"> - <div class="rounded-[6px] p-4 leading-relaxed bg-white"> - <!-- #region ====================== 娑堟伅鍐呭 ======================--> - <!-- <template v-if="item.content?.values"> --> - <!-- #region ====================== 鎶ラ敊淇℃伅 ======================--> - <div v-if="item.content?.errCode === ErrorCode.Message" class="flex-column w-full"> - <p class="text-danger"> - {{ item.content.errMsg }} - </p> - <div class="mt-3 flex" v-if="showFixQuestion(item)"> - <div class="text-gray-600 flex-0 mb-auto py-3"> - {{ '鐚滀綘鎯抽棶锛�' }} - </div> - <div class="flex-auto space-x-2 space-y-1 inline-flex flex-wrap items-center"> - <div - v-for="fixItem in item.content.origin?.sample_question" - :key="fixItem" - class="bg-gray-200 p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg first-of-type:ml-2 first-of-type:mt-1" - @click="fixQuestionClick(fixItem, item.content.origin)" - > - {{ fixItem }} - </div> - </div> - </div> - </div> - <!-- #endregion --> - <!-- #region ====================== 鍥炵瓟缁勪欢 ======================--> - <template v-else> - <template v-if="item.content.type === AnswerType.Report"> - <template v-if="item?.stepGroup?.length > 0"> - <div v-for="(num, index) in item?.stepGroup?.length" :key="index"> - <!-- #region ====================== 鎰忓浘鍒嗘瀽 ======================--> - <div class="flex flex-col" v-if="item?.stepGroup?.[index]?.value?.length > 0"> - <!-- #region ====================== 鎰忓浘鍒嗘瀽 ======================--> - <div class="flex items-center"> - <span class="mr-2">鎰忓浘鍒嗘瀽锛�</span> - <div - @click="toggleStepList(item?.stepGroup?.[index])" - class="cursor-pointer border border-gray-300 border-solid w-fit px-2 flex items-center space-x-2 rounded-lg hover:bg-gray-100 active:bg-gray-200" - > - <span> - {{ toggleStepLabel(item?.stepGroup?.[index]) }} - </span> - <span - class="ywifont" - :class="{ - 'ywicon-unfold': !item?.stepGroup?.[index].isShow, - 'ywicon-fold': item?.stepGroup?.[index].isShow, - }" - ></span> - </div> - </div> - <!-- #endregion --> - - <!-- #region ====================== 杩囩▼杈撳嚭 ======================--> - <el-steps - v-show="item?.stepGroup?.[index].isShow" - class="mt-3" - direction="vertical" - :active="activeStep" - > - <el-step - :key="`template-${stepIndex}`" - v-for="(subItem, stepIndex) in item?.stepGroup?.[index].value" - :title="subItem.title" - :status="stepEnumMap[subItem.status]" - > - <template - #icon - v-if=" - stepIndex + 1 === item?.stepGroup?.[index].value.length && - isTalking && - msgIndex === computedMessageList.length - 1 - " - > - <span class="ywifont ywicon-loading1 animate-spin !text-[24px]"></span> - </template> - <template #title> - <span class=""> - {{ subItem.title }} - - <span v-if="subItem.ms" class="text-green-600">{{ `锛�${subItem.ms}锛塦 }}</span></span - > - </template> - - <template #description v-if="subItem?.subStep?.length > 0"> - <div class="my-1 flex flex-col gap-1 text-[14px]"> - <div - :key="`${item.historyId}-${stepIndex + 1}-${multiChatIndex + 1}`" - v-for="(multiChatItem, multiChatIndex) in subItem.subStep" - > - <component - v-if="multiChatItem.type === MultiChatType.Select" - :order="`${stepIndex + 1}-${multiChatIndex + 1}`" - :item="multiChatItem" - :is="multiChatTypeMapCom[multiChatItem.type]" - :disabled=" - !( - stepIndex + 1 === item?.stepGroup?.[index].value.length && - isTalking && - msgIndex === computedMessageList.length - 1 - ) - " - /> - <component - v-else-if="multiChatItem.type === MultiChatType.Result" - :is="answerTypeMapCom['summary']" - :data="multiChatItem.data.content.values" - :originData="multiChatItem.data" - /> - <div v-else-if="multiChatItem.type === MultiChatType.Summary" class="ml-4 mt-5 pb-10"> - <div class="text-gray-600 mb-5">浣犲彲浠ョ户缁棶鎴戯細</div> - <div class="space-y-2 inline-flex flex-col"> - <div - v-for="item in multiChatItem.data.content.askMoreList" - :key="item.history_id" - class="bg-white p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg" - @click="askMoreClick(item)" - > - {{ item.question }} - </div> - </div> - </div> - </div> - </div> - </template> - </el-step> - </el-steps> - <!-- #endregion --> - </div> - <!-- #endregion --> - - <component - v-if="item.content?.values?.[index]" - :reportIndex="index" - :conclusion="item.content.values[index].conclusion" - :is="answerTypeMapCom[item.content.values[index].content.type]" - :data="item.content.values[index].content.values" - :originData="item.content.values[index]" - :historyId="item.historyId" - :isTalking="isTalking && msgIndex === computedMessageList.length - 1" - /> - </div> - </template> - <p v-else class="text-info">鏆傛棤鍐呭锛岃閲嶈瘯</p> - </template> - <component - v-else - :historyId="item.historyId" - :conclusion="item.conclusion" - :is="answerTypeMapCom[item.content.type]" - :data="item.content.values" - :originData="item" - :isTalking="isTalking && msgIndex === computedMessageList.length - 1" - /> - </template> - <!-- #endregion --> - <!-- </template> --> - - <!-- #endregion --> - <!-- #region ====================== 闄勫姞鍐呭 ======================--> - <!-- #region ====================== 鍋滄 ======================--> - <span v-if="item.isStopMsg && item?.role === RoleEnum.assistant" class="text-gray-400 text-[12px]" - >锛堝凡鍋滄锛�</span - > - <!-- parseContent 杩斿洖涓� null --> - <p v-if="!item.content && !isTalking && !item.isStopMsg" class="text-red-500">鏆傛棤鏁版嵁</p> - <!-- #endregion --> - <!-- #endregion --> - </div> - <!-- #region ====================== ai 娑堟伅鎿嶄綔 ======================--> - <div - v-if="item.role === RoleEnum.assistant && item.content?.values && !isSharePage && !isShareCheck" - class="absolute flex items-center right-0 mr-4 mt-2 space-x-2" - > - <div - class="flex items-center justify-center size-[15px]" - v-if="item.content?.type === AnswerType.Text || item.content?.type === AnswerType.Knowledge" - > - <i - class="p-2 ywifont ywicon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]" - @click="copyClick(item)" - /> - </div> - <template v-if="item.content.errCode !== ErrorCode.Message"> - <el-tooltip effect="dark" content="鐐硅禐" placement="top"> - <div class="flex items-center justify-center size-[15px]"> - <i - :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }" - class="p-2 ywifont ywicon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]" - @click="likeClick(item)" - /> - </div> - </el-tooltip> - <el-tooltip effect="dark" content="鐐硅俯" placement="top"> - <div class="flex items-center justify-center size-[15px]"> - <i - :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }" - class="p-2 ywifont ywicon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]" - @click="unLikeClick(item)" - /> - </div> - </el-tooltip> - </template> - <el-tooltip effect="dark" content="鍒嗕韩" placement="top"> - <div class="flex items-center justify-center size-[15px]"> - <i - class="p-2 ywifont ywicon-fenxiang cursor-pointer hover:text-[#0284ff] !text-[15px] hover:!text-[18px]" - @click="shareClick(item)" - /> - </div> - </el-tooltip> - <el-tooltip effect="dark" content="鍙嶉" placement="top"> - <div class="flex items-center justify-center size-[15px] relative"> - <i - class="p-2 ywifont ywicon-wentifankui cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]" - @click=" - ($event) => - feedbackClick( - $event, - item, - computedMessageList - .filter((v) => v.role === RoleEnum.assistant) - .findIndex((v) => v.historyId === item.historyId) - ) - " - /> - <FeedbackPanel - v-show="feedbackIsShow && currentFeedbackMapItem === item" - ref="feedbackPanelRef" - v-model:isShow="feedbackIsShow" - v-model:content="feedbackContent" - :chatItem="currentFeedbackMapItem" - :position="feedbackPosition" - /> - </div> - </el-tooltip> - </div> - <!-- #endregion --> - </div> - </div> - </div> - </div> + <AssistantMsg + v-else + :msg="item" + :msgList="computedMessageList" + :isLast="msgIndex === computedMessageList.length - 1" + @sendChatMessage="sendChatMessage" + @shareMsg="shareClick" + :isTalking="isTalking" + /> </div> <div v-if="showAskMore" class="ml-4 mt-5 pb-10"> <div class="text-gray-600 mb-5">浣犲彲浠ョ户缁棶鎴戯細</div> @@ -322,35 +75,23 @@ <script setup lang="ts"> import type { CancelTokenSource } from 'axios'; import axios from 'axios'; -import { findLast, orderBy } from 'lodash-es'; +import { orderBy } from 'lodash-es'; import moment from 'moment'; import { computed, onActivated, onMounted, ref } from 'vue'; -import useClipboard from 'vue-clipboard3'; import { loadAmisSource } from '../amis/load'; -import FeedbackPanel from './components/FeedbackPanel.vue'; -import { useAssistantContentOpt } from './hooks/useAssistantContentOpt'; import { convertProcessItem, convertProcessToStep, formatShowTimeYear, useScrollLoad } from './hooks/useScrollLoad'; import type { ChatContent } from './model/types'; -import { - AnswerState, - AnswerType, - MultiChatType, - RoleEnum, - answerTypeMapCom, - roleImageMap, - stepEnumMap, - type ChatMessage, -} from './model/types'; -import { extCallQuery, getShareChatJsonByPost, questionStreamByPost } from '/@/api/ai/chat'; +import { AnswerState, AnswerType, RoleEnum, type ChatMessage } from './model/types'; +import { getShareChatJsonByPost, questionStreamByPost } from '/@/api/ai/chat'; import PlayBar from '/@/components/chat/components/playBar/PlayBar.vue'; import CustomDrawer from '/@/components/drawer/CustomDrawer.vue'; import { Logger } from '/@/model/logger/Logger'; import { ElMessage } from 'element-plus'; +import AssistantMsg from './assistant/index.vue'; import ChatContainer from './components/ChatContainer.vue'; import ShareLinkDlg from './components/shareLink/index.vue'; import UserMsg from './user/index.vue'; -import { multiChatTypeMapCom } from '/@/components/chat/chatComponents/multiChat'; import router from '/@/router'; import { activeChatRoom, @@ -362,7 +103,6 @@ roomConfig, } from '/@/stores/chatRoom'; import emitter from '/@/utils/mitt'; -import { ErrorCode } from '/@/utils/request'; import { useCompRef } from '/@/utils/types'; import { toMyFixed } from '/@/utils/util'; const containerRef = useCompRef(ChatContainer); @@ -488,22 +228,9 @@ return content; }; -//#region ====================== 姝ラ step ====================== -const activeStep = ref(-1); - -const resetStep = () => { - activeStep.value = -1; -}; - -const toggleStepLabel = (item: any) => (item.isShow ? '鏀惰捣' : '灞曞紑'); -const toggleStepList = (item: any) => { - item.isShow = !item.isShow; -}; - -//#endregion - let questionRes = null; let position = null; +const preQuestion = ref(null); let lastAxiosSource: CancelTokenSource = null; const questionAi = async (text) => { @@ -538,7 +265,6 @@ currentSampleId = ''; } - resetStep(); let lastTimestamp = new Date().getTime(); questionRes = {}; let lastIsResult = false; @@ -706,8 +432,6 @@ computedMessageList.value.at(-1).stepGroup.forEach((item) => { item.isShow = false; }); - - resetStep(); }); }); @@ -730,7 +454,7 @@ lastAxiosSource?.cancel(); isTalking.value = false; chatListLoading.value = false; - resetStep(); + computedMessageList.value.at(-1).isStopMsg = true; }; @@ -942,25 +666,17 @@ messageContent.value.values = history_data.value[currentIndex.value].content.values; }; //#endregion -const { - copyClick, - likeClick, - unLikeClick, - feedbackPosition, - feedbackIsShow, - feedbackContent, - feedbackPanelRef, - currentFeedbackMapItem, - feedbackClick, - askMoreClick, - fixQuestionClick, - preQuestion, - showFixQuestion, - showAskMore, -} = useAssistantContentOpt({ - sendChatMessage, - displayMessageList: computedMessageList, +const showAskMore = computed(() => { + if (!computedMessageList.value || computedMessageList.value.length === 0) return false; + const last = computedMessageList.value.at(-1); + const isShow = last?.role === RoleEnum.assistant && last?.content?.values && last.content?.askMoreList?.length > 0; + const result = isShow && !isSharePage.value; + return result; }); +const askMoreClick = (item) => { + if (!item.question) return; + sendChatMessage({ type: AnswerType.Text, values: item.question }); +}; //#region ====================== 渚ц竟鏍廳rawer ====================== const drawerIsShow = ref(false); @@ -981,7 +697,6 @@ //#region ====================== 鍒嗕韩 ====================== const shareLinkDlgRef = useCompRef(ShareLinkDlg); -const isShareCheck = ref(false); const shareClick = async (item: ChatMessage) => { shareLinkDlgRef.value.openShare(item); -- Gitblit v1.9.3