|
@@ -151,7 +151,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import {ref, defineProps, defineEmits, onMounted, watch, nextTick} from 'vue'
|
|
|
|
|
|
|
+import {ref,onUnmounted, defineProps, defineEmits, onMounted, watch, nextTick} from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
import { ElMessage } from 'element-plus'
|
|
|
import { CreateDialogue, sendChatMessageStream } from '@/api/questions.js'
|
|
import { CreateDialogue, sendChatMessageStream } from '@/api/questions.js'
|
|
|
import { teacherList } from '@/api/teachers.js'
|
|
import { teacherList } from '@/api/teachers.js'
|
|
@@ -199,7 +199,7 @@ const enableContext = ref(true)
|
|
|
|
|
|
|
|
// tts
|
|
// tts
|
|
|
import { useAudioPlayer } from '@/api/tts/useAudioPlayer';
|
|
import { useAudioPlayer } from '@/api/tts/useAudioPlayer';
|
|
|
-const { playAudioChunk } = useAudioPlayer();
|
|
|
|
|
|
|
+const { playAudioChunk , stopPlayback } = useAudioPlayer();
|
|
|
|
|
|
|
|
// 语音输入响应式变量
|
|
// 语音输入响应式变量
|
|
|
const isRecording = ref(false) // 录音状态
|
|
const isRecording = ref(false) // 录音状态
|
|
@@ -214,6 +214,7 @@ const handleSelectMessage = message => {
|
|
|
|
|
|
|
|
// 关闭试题弹框
|
|
// 关闭试题弹框
|
|
|
const handleCloseQuestionDialog = () => {
|
|
const handleCloseQuestionDialog = () => {
|
|
|
|
|
+ stopPlayback(); // 销毁语音读取
|
|
|
emits('closeQuestionDialog')
|
|
emits('closeQuestionDialog')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -223,7 +224,6 @@ const handleSubmitAnswer = () => {
|
|
|
ElMessage.warning('请选择一个选项')
|
|
ElMessage.warning('请选择一个选项')
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
emits('submitAnswer', { selectedOption: selectedOption.value })
|
|
emits('submitAnswer', { selectedOption: selectedOption.value })
|
|
|
selectedOption.value = null
|
|
selectedOption.value = null
|
|
|
}
|
|
}
|
|
@@ -239,7 +239,7 @@ const handleAIClick = async () => {
|
|
|
|
|
|
|
|
if (props.currentQuestion.ccQuestContent) {
|
|
if (props.currentQuestion.ccQuestContent) {
|
|
|
// prompt.value = props.currentQuestion.ccQuestContent
|
|
// prompt.value = props.currentQuestion.ccQuestContent
|
|
|
- // sendMessage()
|
|
|
|
|
|
|
+ sendMessage()
|
|
|
|
|
|
|
|
prompt.value = ''
|
|
prompt.value = ''
|
|
|
// 执行发送
|
|
// 执行发送
|
|
@@ -255,7 +255,6 @@ const handleAIClick = async () => {
|
|
|
const getXzAi = async () => {
|
|
const getXzAi = async () => {
|
|
|
try {
|
|
try {
|
|
|
const grade = localStorage.getItem('selectedGrade') || ''
|
|
const grade = localStorage.getItem('selectedGrade') || ''
|
|
|
-
|
|
|
|
|
// 获取AI数据
|
|
// 获取AI数据
|
|
|
const juniorAIRes = await teacherList({ category: grade + 'AI' })
|
|
const juniorAIRes = await teacherList({ category: grade + 'AI' })
|
|
|
const aiPerson = juniorAIRes.data.list.find(
|
|
const aiPerson = juniorAIRes.data.list.find(
|
|
@@ -303,7 +302,7 @@ const sendMessage = async () => {
|
|
|
|
|
|
|
|
// 增加问答次数
|
|
// 增加问答次数
|
|
|
aiQuestionCount.value++
|
|
aiQuestionCount.value++
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 保存AI问答次数
|
|
// 保存AI问答次数
|
|
|
try {
|
|
try {
|
|
|
await saveRecord({
|
|
await saveRecord({
|
|
@@ -347,7 +346,7 @@ const initSpeechRecognition = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 新增:识别器结束时清除定时器
|
|
|
|
|
|
|
+ // 识别器结束时清除定时器
|
|
|
instance.onend = () => {
|
|
instance.onend = () => {
|
|
|
clearInterval(countdownTimer.value)
|
|
clearInterval(countdownTimer.value)
|
|
|
isRecording.value = false
|
|
isRecording.value = false
|
|
@@ -574,6 +573,8 @@ const stopStream = async () => {
|
|
|
if (conversationInAbortController.value) {
|
|
if (conversationInAbortController.value) {
|
|
|
conversationInAbortController.value.abort()
|
|
conversationInAbortController.value.abort()
|
|
|
}
|
|
}
|
|
|
|
|
+ // 销毁语音读取
|
|
|
|
|
+ stopPlayback();
|
|
|
// 设置为 false
|
|
// 设置为 false
|
|
|
conversationInProgress.value = false
|
|
conversationInProgress.value = false
|
|
|
}
|
|
}
|
|
@@ -615,6 +616,12 @@ watch(() => props.questionDialogVisible, (newVal) => {
|
|
|
selectedOption.value = null
|
|
selectedOption.value = null
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
+// 监听showAIDialog变化,在关闭时销毁语音读取
|
|
|
|
|
+watch(() => showAIDialog.value, (newVal) => {
|
|
|
|
|
+ if (!newVal) {
|
|
|
|
|
+ stopPlayback();
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
// 监听消息列表变化,自动滚动到底部
|
|
// 监听消息列表变化,自动滚动到底部
|
|
|
watch(messageList, () => {
|
|
watch(messageList, () => {
|
|
|
scrollToBottom()
|
|
scrollToBottom()
|
|
@@ -648,6 +655,10 @@ const scrollToBottom = () => {
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
// 初始化
|
|
// 初始化
|
|
|
})
|
|
})
|
|
|
|
|
+// 组件卸载时清理语音资源
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ stopPlayback();
|
|
|
|
|
+});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
@@ -790,8 +801,8 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
|
|
|
|
|
|
|
|
// 底部按钮样式
|
|
// 底部按钮样式
|
|
|
.child-button {
|
|
.child-button {
|
|
|
- min-width: rpx(80);
|
|
|
|
|
- height: rpx(30);
|
|
|
|
|
|
|
+ min-width: rpx(70);
|
|
|
|
|
+ height: rpx(25);
|
|
|
border-radius: rpx(8);
|
|
border-radius: rpx(8);
|
|
|
font-size: rpx(12);
|
|
font-size: rpx(12);
|
|
|
font-weight: 500;
|
|
font-weight: 500;
|
|
@@ -833,7 +844,7 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
|
|
|
width: rpx(30);
|
|
width: rpx(30);
|
|
|
height: rpx(30);
|
|
height: rpx(30);
|
|
|
margin-bottom: rpx(0);
|
|
margin-bottom: rpx(0);
|
|
|
- filter: drop-shadow(0 rpx(2) rpx(4) rgba($primary-color, 0.3));
|
|
|
|
|
|
|
+ // filter: drop-shadow(0 rpx(2) rpx(4) rgba($primary-color, 0.3));
|
|
|
// 添加过渡动画
|
|
// 添加过渡动画
|
|
|
transition: transform 0.3s ease;
|
|
transition: transform 0.3s ease;
|
|
|
}
|
|
}
|