<template> 
 | 
  <div :style="{ height: heightrg }"> 
 | 
    <div style="padding: 10px"> 
 | 
      <a-avatar :style="{ backgroundColor: '#3370ff' }"> 
 | 
        <img 
 | 
          :style="{ width: '100%' }" 
 | 
          alt="dessert" 
 | 
          src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a20012a2d4d5b9db43dfc6a01fe508c0.png~tplv-uwbnlip3yd-webp.webp" 
 | 
        /> 
 | 
      </a-avatar> 
 | 
      调试预览 
 | 
    </div> 
 | 
    <a-divider style="margin: 0; margin-left: 10px" /> 
 | 
    <a-scrollbar 
 | 
      ref="scrollbar" 
 | 
      id="home" 
 | 
      class="chat-list" 
 | 
      style="width: 90%; overflow: auto; height: 70vh; 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' }" style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none;padding: 16px;">{{ 
 | 
                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: var(--color-bg-2);color: var(--color-text-3);border: none" 
 | 
            > 
 | 
              <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: var(--color-bg-2);color: var(--color-text-3);border: none" 
 | 
            > 
 | 
            </a-textarea> 
 | 
          </template> 
 | 
        </a-comment> 
 | 
      </div> 
 | 
    </a-scrollbar> 
 | 
    <div class="bottom"> 
 | 
      <div class="input"> 
 | 
        <a-input 
 | 
          v-model="inputMsg" 
 | 
          @keydown.enter="sendMessage" 
 | 
          placeholder="输入您想了解的内容,按Enter发送" 
 | 
        > 
 | 
          <template #suffix> 
 | 
            <icon-send style="cursor: pointer" @click="sendMessage" /> 
 | 
          </template> </a-input 
 | 
        ></div> 
 | 
      <div class="text">内容由AI生成,仅供参考</div> 
 | 
    </div> 
 | 
  </div> 
 | 
</template> 
 | 
  
 | 
<script setup lang="ts"> 
 | 
import { 
 | 
  IconMoreVertical, 
 | 
  IconQuestionCircleFill, 
 | 
  IconPoweroff, 
 | 
  IconCommon, 
 | 
  IconSend, 
 | 
} from '@arco-design/web-vue/es/icon'; 
 | 
import img1 from '@/assets/images/u64.png'; 
 | 
import img2 from '@/assets/images/u69.png'; 
 | 
import img3 from '@/assets/images/u74.png'; 
 | 
import { ref, onMounted, computed, reactive, nextTick, watch } from 'vue'; 
 | 
import { useUserStore, useAppStore } from '@/store'; 
 | 
import { 
 | 
  sessionListApi, 
 | 
  deleteSessionApi, 
 | 
  getSessionDetailsApi, 
 | 
  chatApi, 
 | 
} from '@/api/session'; 
 | 
import { Message } from '@arco-design/web-vue'; 
 | 
const userStore = useUserStore(); 
 | 
const appStore = useAppStore(); 
 | 
const theme = computed(() => { 
 | 
  return appStore.theme; 
 | 
}); 
 | 
const heightrg = ref('calc(100vh - 100px)'); 
 | 
const sessionList = ref([]); //会话列表 
 | 
const sessionDetailList = ref([]); //根据会话id出来的会话详情 
 | 
const activeSessionId = ref(''); 
 | 
const inputMsg = ref(''); 
 | 
const scrollbar = ref(null); 
 | 
  
 | 
const currIndex = ref(0); 
 | 
const displayedText = ref(''); // 正在显示的文字 
 | 
let timer: number | null = null; 
 | 
const streamStr = ref(''); 
 | 
const modalObj = reactive({ add: false }); 
 | 
//查询会话列表 
 | 
const querySessionList = async () => { 
 | 
  const { code, data } = await sessionListApi(); 
 | 
  if (code === 200) { 
 | 
    sessionList.value = data; 
 | 
    if (Array.isArray(data) && data.length > 0) { 
 | 
      activeSessionId.value = data[1].id; 
 | 
      const res = await getSessionDetailsApi(data[0].id); 
 | 
      if (res.code === 200) { 
 | 
        sessionDetailList.value = res.data.message; 
 | 
        refreshScroll(); 
 | 
      } 
 | 
    } 
 | 
  } else { 
 | 
    Message.warning('查询失败'); 
 | 
  } 
 | 
}; 
 | 
//根据会话id删除会话 
 | 
const deleteSession = async (session) => { 
 | 
  const { code } = await deleteSessionApi([session.id]); 
 | 
  if (code === 200) { 
 | 
    Message.success('删除成功'); 
 | 
    querySessionList(); 
 | 
  } 
 | 
}; 
 | 
// eslint-disable-next-line prettier/prettier 
 | 
// 新增会话之后刷新会话列表 
 | 
const addSession = () => { 
 | 
  querySessionList(); 
 | 
}; 
 | 
// 初始化数据 
 | 
const initData = () => { 
 | 
  querySessionList(); 
 | 
}; 
 | 
// 获取登录信息 
 | 
const userName = computed(() => { 
 | 
  return userStore.name; 
 | 
}); 
 | 
const avatar = computed(() => { 
 | 
  return userStore.avatar; 
 | 
}); 
 | 
const refreshScroll = () => { 
 | 
  nextTick(() => { 
 | 
    const container = document.getElementById('home'); 
 | 
    scrollbar.value.scrollTop(container.scrollHeight); 
 | 
  }); 
 | 
}; 
 | 
// 根据会话id 查询会话详情 
 | 
const querySessionDetail = async (session) => { 
 | 
  activeSessionId.value = session.id; 
 | 
  const { code, data } = await getSessionDetailsApi(session.id); 
 | 
  if (code === 200) { 
 | 
    sessionDetailList.value = data.message; 
 | 
    refreshScroll(); //刷新滚动条位置 
 | 
  } 
 | 
}; 
 | 
const sendMessage = async () => { 
 | 
  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('消息不能为空'); 
 | 
  } 
 | 
}; 
 | 
onMounted(() => { 
 | 
  initData(); 
 | 
}); 
 | 
//文字动态输出 
 | 
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; 
 | 
  } 
 | 
}; 
 | 
watch( 
 | 
  () => scrollbar.value, 
 | 
  (newScroll, oldScroll) => { 
 | 
    if (newScroll) { 
 | 
      // 获取a-scroll的高度 
 | 
      const height = newScroll.$el.offsetHeight; 
 | 
      console.log('a-scroll height changed to:', height); 
 | 
    } 
 | 
  }, 
 | 
  { deep: true } 
 | 
); 
 | 
</script> 
 | 
  
 | 
<style scoped lang="less"> 
 | 
.container { 
 | 
  width: 100%; 
 | 
  display: flex; 
 | 
} 
 | 
//.light { 
 | 
//  color: white !important; 
 | 
//} 
 | 
.bottom { 
 | 
  width: 100%; 
 | 
  position: absolute; 
 | 
  bottom: 40px; 
 | 
  left: 0; 
 | 
  
 | 
  .input { 
 | 
    margin-left: 20%; 
 | 
    width: 60%; 
 | 
  } 
 | 
  
 | 
  .text { 
 | 
    margin-left: 40%; 
 | 
    font-size: 12px; 
 | 
    color: lightgrey; 
 | 
    line-height: 40px; 
 | 
  } 
 | 
} 
 | 
.chat-list { 
 | 
  width: 90%; 
 | 
  margin: 0px auto; 
 | 
  .chat-item { 
 | 
    margin-top: 20px; 
 | 
    .chat-item-answer { 
 | 
      color: white; 
 | 
    } 
 | 
  } 
 | 
} 
 | 
</style> 
 |