| | |
| | | <template> |
| | | <div class="flex flex-col h-full"> |
| | | <div class="h-full flex flex-col items-center overflow-y-auto"> |
| | | <div ref="chatListDom" class="h-full" :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" |
| | | > |
| | | <img |
| | | class="rounded-full size-12 flex-0" |
| | | :class="{ 'mr-4': item.role === RoleEnum.assistant, 'ml-4': item.role === RoleEnum.user }" |
| | | :src="roleImageMap[item.role]" |
| | | alt="" |
| | | srcset="" |
| | | /> |
| | | <div class="flex-auto flex" :class="{ 'justify-end': item.role === RoleEnum.user }"> |
| | | <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }"> |
| | | <div class="w-full" v-if="item.content?.values"> |
| | | <div |
| | | class="text-sm rounded-[6px] p-4 leading-relaxed" |
| | | :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }" |
| | | > |
| | | <div v-if="item.content.errCode === ErrorCode.Message" class="text-red-500 w-full">{{ item.content.msg }}</div> |
| | | <component v-else :is="answerTypeMapCom[item.content.type]" :data="item.content.values" :originData="item" /> |
| | | </div> |
| | | |
| | | <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 mr-4 mt-2 space-x-2"> |
| | | <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 |
| | | 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" |
| | | > |
| | | <img |
| | | class="rounded-full size-12 flex-0" |
| | | :class="{ 'mr-4': item.role === RoleEnum.assistant, 'ml-4': item.role === RoleEnum.user }" |
| | | :src="roleImageMap[item.role]" |
| | | alt="" |
| | | srcset="" |
| | | /> |
| | | <div class="flex-auto flex" :class="{ 'justify-end': item.role === RoleEnum.user }"> |
| | | <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }"> |
| | | <div class="w-full" v-if="item.content?.values"> |
| | | <div |
| | | class="flex items-center justify-center size-[15px]" |
| | | v-if="item.content?.type === AnswerType.Text || item.content?.type === AnswerType.Knowledge" |
| | | class="text-sm rounded-[6px] p-4 leading-relaxed" |
| | | :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }" |
| | | > |
| | | <i class="p-2 ywicon icon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]" @click="copyClick(item)" /> |
| | | <div v-if="item.content.errCode === ErrorCode.Message" class="text-red-500 w-full">{{ item.content.msg }}</div> |
| | | <component v-else :is="answerTypeMapCom[item.content.type]" :data="item.content.values" :originData="item" /> |
| | | </div> |
| | | <template v-if="item.content.errCode !== ErrorCode.Message"> |
| | | <div class="flex items-center justify-center size-[15px]"> |
| | | <i |
| | | :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }" |
| | | class="p-2 ywicon icon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]" |
| | | @click="likeClick(item)" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center justify-center size-[15px]"> |
| | | <i |
| | | :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }" |
| | | class="p-2 ywicon icon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]" |
| | | @click="unLikeClick(item)" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <div class="flex items-center justify-center size-[15px] relative"> |
| | | <i |
| | | class="p-2 ywicon icon-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 v-if="item.role === RoleEnum.assistant" 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 ywicon icon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]" |
| | | @click="copyClick(item)" |
| | | /> |
| | | </div> |
| | | <template v-if="item.content.errCode !== ErrorCode.Message"> |
| | | <div class="flex items-center justify-center size-[15px]"> |
| | | <i |
| | | :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }" |
| | | class="p-2 ywicon icon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]" |
| | | @click="likeClick(item)" |
| | | /> |
| | | </div> |
| | | <div class="flex items-center justify-center size-[15px]"> |
| | | <i |
| | | :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }" |
| | | class="p-2 ywicon icon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]" |
| | | @click="unLikeClick(item)" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <div class="flex items-center justify-center size-[15px] relative"> |
| | | <i |
| | | class="p-2 ywicon icon-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> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <Loding v-else class="w-fit" :process="process" /> |
| | | <Loding v-else class="w-fit" :process="process" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-if="showAskMore" class="ml-4 mt-5 text-sm"> |
| | | <div class="text-gray-600 mb-5">你可以继续问我:</div> |
| | | <div class="space-y-2 inline-flex flex-col"> |
| | | <div |
| | | v-for="item in computedMessageList.at(-1).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 v-if="showAskMore" class="ml-4 mt-5 text-sm"> |
| | | <div class="text-gray-600 mb-5">你可以继续问我:</div> |
| | | <div class="space-y-2 inline-flex flex-col"> |
| | | <div |
| | | v-for="item in computedMessageList.at(-1).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> |
| | | |
| | | <div class="sticky bottom-0 w-full p-6 pb-8 bg-[rgb(247,248,250)] flex justify-center"> |
| | | <PlayBar |
| | | :isTalking="isTalking" |
| | | v-model="messageContent.values" |
| | | @sendClick="sendChatMessage" |
| | | :style="{ width: chatWidth }" |
| | | ></PlayBar> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="sticky bottom-0 w-full p-6 pb-8 bg-[rgb(247,248,250)] flex justify-center"> |
| | | <PlayBar |
| | | :isTalking="isTalking" |
| | | v-model="messageContent.values" |
| | | @sendClick="sendChatMessage" |
| | | :style="{ width: chatWidth }" |
| | | ></PlayBar> |
| | | </div> |
| | | <CustomDrawer v-model:isShow="drawerIsShow" @updateChatInput="updateChatInput" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { ErrorCode } from '/@/utils/request'; |
| | | import FeedbackPanel from './components/FeedbackPanel.vue'; |
| | | import { useClickOther } from '/@/hooks/useClickOther'; |
| | | import CustomDrawer from '/@/components/drawer/CustomDrawer.vue'; |
| | | |
| | | const chatWidth = '75%'; |
| | | |
| | |
| | | } |
| | | ); |
| | | //#endregion |
| | | |
| | | //#region ====================== 侧边栏drawer ====================== |
| | | const drawerIsShow = ref(false); |
| | | |
| | | const updateChatInput = (content) => { |
| | | messageContent.value.values = content; |
| | | }; |
| | | //#endregion |
| | | </script> |
| | | |
| | | <style scoped> |