| | |
| | | <script setup lang="ts"> |
| | | import { IconSearch,IconTiktokColor ,IconSend,IconClose} from '@arco-design/web-vue/es/icon'; |
| | | import { useAppStore} from '@/store'; |
| | | import {computed,ref,onMounted,reactive} from 'vue'; |
| | | import {sessionListApi}from '@/api/session'; |
| | | import { computed, ref, onMounted, reactive, nextTick } from 'vue'; |
| | | import { Message } from '@arco-design/web-vue'; |
| | | import moment from 'moment'; |
| | | import AddSession from '@/views/session/sessionManager/components/addSession.vue'; |
| | | import { sessionListApi, deleteSessionApi,getSessionDetailsApi,chatApi }from '@/api/session'; |
| | | const sessionDetailList=ref([]);//根据会话id出来的会话详情 |
| | | const sessionList=ref([]);//会话列表 |
| | | const modalObj=reactive({add:false}); |
| | | //查询会话列表 |
| | | const modalObj=reactive({ add:false }); |
| | | |
| | | const currIndex = ref(0) |
| | | const displayedText = ref('');// 正在显示的文字 |
| | | let timer: number|null = null; |
| | | const streamStr=ref(''); |
| | | const inputMsg=ref(''); |
| | | const activeSessionId=ref(''); |
| | | |
| | | const sendMessage= async (event)=>{ |
| | | event.preventDefault(); |
| | | if(!activeSessionId.value){ |
| | | Message.warning('请选择会话'); |
| | | return; |
| | | } |
| | | if(inputMsg.value){ |
| | | const {code,data} =await chatApi({conversation_id:activeSessionId.value,messages:inputMsg.value}); |
| | | const res= await getSessionDetailsApi(activeSessionId.value); |
| | | if(res.code===200){ |
| | | sessionDetailList.value=res.data.message.map((item,index)=>{ |
| | | if(index===res.data.message.length-1){ |
| | | item.role='last'; |
| | | displayedText.value=''; |
| | | currIndex.value=0; |
| | | streamStr.value=item.content; |
| | | startDisplayStr(); |
| | | } |
| | | return item; |
| | | }); |
| | | refreshScroll(); |
| | | } |
| | | inputMsg.value=''; |
| | | }else{ |
| | | Message.warning('消息不能为空'); |
| | | } |
| | | }; |
| | | const querySessionDetail=async (session)=>{ |
| | | activeSessionId.value=session.id; |
| | | const {code,data}= await getSessionDetailsApi(session.id); |
| | | if(code===200){ |
| | | sessionDetailList.value=data.message; |
| | | refreshScroll();//刷新滚动条位置 |
| | | } |
| | | }; |
| | | const scrollbar = ref(null); |
| | | const refreshScroll=()=>{ |
| | | nextTick(()=>{ |
| | | const container = document.getElementById('home'); |
| | | scrollbar.value.scrollTop(container.scrollHeight); |
| | | }); |
| | | }; |
| | | // 查询会话列表 |
| | | const querySessionList=async ()=>{ |
| | | const {code,data} =await sessionListApi(); |
| | | if(code===200){ |
| | |
| | | const theme = computed(() => { |
| | | return appStore.theme; |
| | | }); |
| | | //文字动态输出 |
| | | const startDisplayStr = () => { |
| | | if (timer) { |
| | | clearTimeout(timer!); |
| | | } |
| | | const res = streamStr.value; |
| | | // 将数组中的字符串拼接起来 |
| | | if (currIndex.value < res.length) { |
| | | displayedText.value += res[currIndex.value]; |
| | | currIndex.value++; |
| | | setTimeout(startDisplayStr, 100); |
| | | } else { |
| | | clearTimeout(timer!); |
| | | timer = null |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | </a-card> |
| | | <a-card class="left"> |
| | | <a-scrollbar class="left-list" style="height: calc(100vh - 160px);overflow-y: auto;overflow-x: hidden;"> |
| | | <div class="item" v-for="session in sessionList"> |
| | | <div class="item" v-for="session in sessionList" @click="querySessionDetail(session)" :class="{ isLeftActive:activeSessionId===session.id }"> |
| | | <div class="text" :class="{light:theme==='dark'}">{{session.name}}</div> |
| | | <div class="time">{{moment(new Date(session.create_time)).format('YYYY-MM-DD HH:mm:ss')}}</div> |
| | | </div> |
| | |
| | | </a-col> |
| | | <a-col :span="15"> |
| | | <a-card class="center"> |
| | | <div class="center-title">智能问答</div> |
| | | <div class="center-content"> |
| | | 我可以理解和学习人类的语言,具备多轮对话的能力,现在和我开始交流吧~ |
| | | </div> |
| | | <div class="center-question"> |
| | | <div class="center-question-left">试一试这样问我</div> |
| | | <div class="center-question-right"> |
| | | <a-button type="primary">换一换</a-button> |
| | | <div v-if="sessionDetailList.length===0"> |
| | | <div class="center-title">智能问答</div> |
| | | <div class="center-content"> |
| | | 我可以理解和学习人类的语言,具备多轮对话的能力,现在和我开始交流吧~ |
| | | </div> |
| | | <div class="center-question"> |
| | | <div class="center-question-left">试一试这样问我</div> |
| | | <div class="center-question-right"> |
| | | <a-button type="primary">换一换</a-button> |
| | | </div> |
| | | </div> |
| | | <a-row justify="space-around" class="center-list"> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | </a-row> |
| | | </div> |
| | | <a-row justify="space-around" class="center-list"> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | <a-col :span="7" class="item"> |
| | | <div class="item-title"> |
| | | <IconTiktokColor></IconTiktokColor>抖音带货脚本 |
| | | </div> |
| | | <div class="item-content" :class="{dark:theme==='dark'}"> |
| | | 编写引人注目且具有说服力的、适用于产品的... |
| | | </div> |
| | | </a-col> |
| | | </a-row> |
| | | <a-scrollbar ref="scrollbar" id="home" v-else class="chat-list" style="width:90%;overflow:auto;height: 60vh;margin: 0px auto"> |
| | | <div class="chat-item" v-for="sessionDetail in sessionDetailList"> |
| | | <a-comment |
| | | v-if="sessionDetail.role==='user'" |
| | | avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp" |
| | | > |
| | | <template #content> |
| | | <div :class="{light:theme==='light'}">{{sessionDetail.content}}</div> |
| | | </template> |
| | | </a-comment> |
| | | <a-comment |
| | | v-else-if="sessionDetail.role==='assistant'" |
| | | avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp" |
| | | > |
| | | <template #content> |
| | | <a-card class="chat-item-answer" style="background-color: rgba(63, 64, 79, 1);"> |
| | | <div :class="{light:theme==='light'}">{{sessionDetail.content}}</div> |
| | | </a-card> |
| | | </template> |
| | | </a-comment> |
| | | <a-comment |
| | | v-else-if="sessionDetail.role==='last'" |
| | | avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp" |
| | | > |
| | | <template #content> |
| | | <a-textarea readonly auto-size v-model="displayedText" class="chat-item-answer" style="background-color: rgba(63, 64, 79, 1);"> |
| | | </a-textarea> |
| | | </template> |
| | | </a-comment> |
| | | </div> |
| | | </a-scrollbar> |
| | | |
| | | <div class="center-bottom"> |
| | | <a-textarea style="height: 180px" placeholder="输入您想了解的内容,Shift+Enter换行" :max-length="500" allow-clear show-word-limit> |
| | | <a-textarea v-model="inputMsg" @keydown.shift.enter="sendMessage" style="height: 180px" placeholder="输入您想了解的内容,Shift+Enter发送" :max-length="500" allow-clear show-word-limit> |
| | | </a-textarea> |
| | | </div> |
| | | </a-card> |
| | |
| | | </template> |
| | | |
| | | <style scoped lang="scss"> |
| | | .isLeftActive{ |
| | | background-color:lightgrey; |
| | | } |
| | | .light{ |
| | | color: white !important; |
| | | } |
| | |
| | | } |
| | | .text{ |
| | | color: black; |
| | | padding-left: 10px; |
| | | } |
| | | .time{ |
| | | color: gray; |
| | | font-size: 12px; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | } |
| | |
| | | .center-bottom{ |
| | | position: absolute; |
| | | width: 90%; |
| | | bottom: 70px; |
| | | bottom: 20px; |
| | | left:5%; |
| | | } |
| | | } |