Parcourir la source

1、课程中的小智问答加入消息列表自动保持最底端
2、课程小智问答加入回答语音

liyanbo il y a 8 mois
Parent
commit
92dae4b823
2 fichiers modifiés avec 56 ajouts et 20 suppressions
  1. 55 19
      src/components/videopage/DialogComponents.vue
  2. 1 1
      src/views/AIQuestions.vue

+ 55 - 19
src/components/videopage/DialogComponents.vue

@@ -76,7 +76,7 @@
           >
         </div>
         <div class="ai-dialog-content">
-          <div class="ai-message-history">
+          <div class="ai-message-history" ref="messageContainer">
             <div
               v-for="(message, index) in messageList"
               :key="index"
@@ -124,7 +124,7 @@
 </template>
 
 <script setup>
-import { ref, defineProps, defineEmits, onMounted,watch } from 'vue'
+import {ref, defineProps, defineEmits, onMounted, watch, nextTick} from 'vue'
 import { ElMessage } from 'element-plus'
 import { CreateDialogue, sendChatMessageStream } from '@/api/questions.js'
 import { teacherList } from '@/api/teachers.js'
@@ -152,6 +152,7 @@ const showAIDialog = ref(false)
 const selectedOption = ref(null)
 const messageList = ref([])
 const prompt = ref('')
+const messageContainer = ref(null)
 const aiQuestionCount = ref(0)
 const xZAiData = ref({})
 const activeConversationId = ref(null)
@@ -162,6 +163,10 @@ const isComposing = ref(false)
 const inputTimeout = ref()
 const enableContext = ref(true)
 
+//tts
+import { useAudioPlayer } from '@/components/TTS/useAudioPlayer';
+const { playAudioChunk } = useAudioPlayer();
+
 // 处理选择的默认消息
 const handleSelectMessage = message => {
   prompt.value = message
@@ -380,25 +385,39 @@ const doSendMessageStream = async userMessage => {
           console.log(`对话异常! ${msg}`)
           return
         }
-        receiveMessageFullText.value = receiveMessageFullText.value + data.receive.content
-        // 首次返回需要添加一个 message 到页面,后面的都是更新
-        if (isFirstChunk) {
-          isFirstChunk = false
-          // 弹出两个假数据
-          messageList.value.pop()
-          messageList.value.pop()
-          // 更新返回的数据
-          messageList.value.push(data.send)
-          messageList.value.push(data.receive)
-        } else {
-          // 更新最后一条消息
-          if (messageList.value.length > 0) {
-            const lastMessage = messageList.value[messageList.value.length - 1]
-            if (lastMessage.id === data.receive.id) {
-              lastMessage.content = receiveMessageFullText.value
+
+        if (data.eventType === 'TEXT') {
+
+          // 如果内容为空,就不处理。
+          if (data.receive?.content === '') {
+            return
+          }
+          receiveMessageFullText.value += data.receive.content
+          // 首次返回需要添加一个 message 到页面,后面的都是更新
+          if (isFirstChunk) {
+            isFirstChunk = false
+            // 弹出两个假数据
+            messageList.value.pop()
+            messageList.value.pop()
+            // 更新返回的数据
+            messageList.value.push(data.send)
+            messageList.value.push(data.receive)
+          } else {
+            //更新最后一条消息
+            if (messageList.value.length > 0) {
+              const lastMessage = messageList.value[messageList.value.length - 1]
+              if (lastMessage.id === data.receive.id) {
+                lastMessage.content = receiveMessageFullText.value
+              }
             }
           }
+        } else if (data.eventType === 'AUDIO') {
+          // 处理音频消息
+          await playAudioChunk(data.audioData);
         }
+
+        // 添加此行确保触发滚动
+        scrollToBottom()
       },
       error => {
         console.log(`对话异常! ${error}`)
@@ -463,7 +482,24 @@ watch(() => props.questionDialogVisible, (newVal) => {
     selectedOption.value = null
   }
 })
-
+// 监听消息列表变化,自动滚动到底部
+watch(messageList, () => {
+  scrollToBottom()
+}, { deep: true })
+
+// 单独的滚动到底部函数
+const scrollToBottom = () => {
+  nextTick(() => {
+    if (messageContainer.value) {
+      // 强制重排以确保获取最新高度
+      messageContainer.value.scrollTop = messageContainer.value.scrollHeight
+      // 双重保险:使用requestAnimationFrame确保在浏览器重绘后执行
+      requestAnimationFrame(() => {
+        messageContainer.value.scrollTop = messageContainer.value.scrollHeight
+      })
+    }
+  })
+}
 onMounted(() => {
   // 初始化
 })

+ 1 - 1
src/views/AIQuestions.vue

@@ -435,7 +435,7 @@ const doSendMessageStream = async (userMessage) => {
       createTime: new Date(),
     });
 
-    // 1.3 开始滚动
+    // 1.2 开始滚动
     textRoll();
 
     // 2. 发送 event stream