From c16e8870fae2047bf888c02aee6be36b308b6ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E6=9D=B0?= Date: Mon, 23 Jun 2025 11:59:36 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=A1=86=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=AF=AD=E4=BF=AE=E6=94=B9=EF=BC=9B=E4=BF=AE=E6=94=B9=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E9=9D=9E=E6=B3=95=E5=86=85=E5=AE=B9=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=9B=E4=BF=AE=E6=94=B9=E4=BA=86=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E5=AD=98=E5=82=A8=E6=96=87=E4=BB=B6=EF=BC=8C=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E5=8A=A0=E5=85=A5=E9=9F=B3=E9=A2=91=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/audio.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++-- src/views/AiEmotion.vue | 43 +++++++++++++++++++++++++++++--------- src/views/homePage.vue | 32 +++++++++++++++++++++++++--- 3 files changed, 115 insertions(+), 15 deletions(-) diff --git a/src/store/audio.js b/src/store/audio.js index a33154c..7f5d82a 100644 --- a/src/store/audio.js +++ b/src/store/audio.js @@ -9,7 +9,10 @@ export const useAudioStore = defineStore('audio', { lastVoiceState: null, ttsUrl:'', isNewInstance: false, // 新增是否是新实例的标志 - nowSound:'' + nowSound:'', + currentAudioUrl: '', // 当前音频URL + isPaused: false, // 是否处于暂停状态 + duration: 0 // 音频总时长 }), actions: { // 设置音频实例 @@ -19,19 +22,67 @@ export const useAudioStore = defineStore('audio', { // 播放控制 play() { if (this.soundInstance) { + if (this.isPaused && this.playbackPosition > 0) { + // 从暂停位置继续播放 + this.soundInstance.seek(this.playbackPosition) + } this.soundInstance.play() this.isPlaying = true + this.isPaused = false } }, // 暂停控制 pause() { - if (this.soundInstance) { + if (this.soundInstance && this.isPlaying) { + // 保存当前播放位置 + this.playbackPosition = this.soundInstance.seek() || 0 this.soundInstance.pause() this.isPlaying = false + this.isPaused = true + } + }, + // 停止播放 + stop() { + if (this.soundInstance) { + this.soundInstance.stop() + this.isPlaying = false + this.isPaused = false + this.playbackPosition = 0 } }, + // 切换播放/暂停 + togglePlayPause() { + if (this.isPlaying) { + this.pause() + } else { + this.play() + } + }, + // 设置当前音频URL + setCurrentAudioUrl(url) { + if (this.currentAudioUrl !== url) { + // 如果是新的音频,重置播放状态 + this.stop() + this.currentAudioUrl = url + this.playbackPosition = 0 + this.isPaused = false + } + }, + // 语音开关控制 toggleVoice() { this.isVoiceEnabled = !this.isVoiceEnabled + if (!this.isVoiceEnabled) { + // 关闭语音时停止当前播放 + this.stop() + } + }, + // 重置音频状态 + resetAudioState() { + this.stop() + this.currentAudioUrl = '' + this.ttsUrl = '' + this.soundInstance = null + this.nowSound = '' } } }) diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue index 803f7d0..8defdbc 100644 --- a/src/views/AiEmotion.vue +++ b/src/views/AiEmotion.vue @@ -693,8 +693,11 @@ function playAudio(url) { console.log('开始创建音频实例...'); try { + // 设置当前音频URL + audioStore.setCurrentAudioUrl(url); + // 停止之前的音频 - if (audioStore.nowSound) { + if (audioStore.nowSound && audioStore.nowSound.playing()) { audioStore.nowSound.stop(); } @@ -705,19 +708,35 @@ function playAudio(url) { format: ['mp3', 'wav'], onplay: () => { isAudioPlaying.value = true; + audioStore.isPlaying = true; console.log('开始播放场景应用语音'); }, onend: () => { isAudioPlaying.value = false; + audioStore.isPlaying = false; + audioStore.isPaused = false; + audioStore.playbackPosition = 0; console.log('场景应用语音播放结束'); }, onstop: () => { isAudioPlaying.value = false; + audioStore.isPlaying = false; console.log('场景应用语音播放停止'); }, + onpause: () => { + isAudioPlaying.value = false; + audioStore.isPlaying = false; + console.log('场景应用语音播放暂停'); + }, onerror: (error) => { isAudioPlaying.value = false; + audioStore.isPlaying = false; console.error('音频播放错误:', error); + }, + onload: () => { + // 音频加载完成,获取时长 + audioStore.duration = newSound.duration(); + console.log('音频加载完成,时长:', audioStore.duration); } }); @@ -764,11 +783,6 @@ async function handleSendMessage(input) { if (input.trim()) { const userMessage = reactive({ sender: 'user', text: input }); messages.value.push(userMessage); - // 设置加载状态,隐藏图表页面 - isLoading.value = true; - isPageLoaded.value = false; - // 触发图片旋转 - isRotating.value = true; try { // 用来调用工作流接口的参数 @@ -797,6 +811,12 @@ async function handleSendMessage(input) { if (parsedData && parsedData.market && parsedData.code) { console.log("工作流接口返回股票信息:", parsedData); + // 设置加载状态,隐藏图表页面 + isLoading.value = true; + isPageLoaded.value = false; + // 触发图片旋转 + isRotating.value = true; + // 调用第二个工作流接口 const conclusionParams = { content: input.trim(), @@ -826,16 +846,19 @@ async function handleSendMessage(input) { emotionStore.updateActiveStockConclusion(conclusionResponse.data); } } else { + // 不是股票信息,显示refuse信息,但不隐藏页面数据 ElMessage.error(processRefuseMessage(parsedData.refuse)); + return; // 直接返回,不进行后续处理 } } catch (error) { ElMessage.error('请求工作流接口失败,请检查网络连接'); + return; // 请求失败时直接返回 } finally { - // 停止图片旋转 - isRotating.value = false; + // 停止图片旋转(只有在设置了旋转状态时才需要停止) + if (isRotating.value) { + isRotating.value = false; + } } - } else { - ElMessage.error(processRefuseMessage(parsedData.refuse)); } } diff --git a/src/views/homePage.vue b/src/views/homePage.vue index babee2d..4ba233d 100644 --- a/src/views/homePage.vue +++ b/src/views/homePage.vue @@ -46,7 +46,19 @@ const chatStore = useChatStore(); const audioStore = useAudioStore(); const isVoice = computed(() => audioStore.isVoiceEnabled); const toggleVoice = () => { - audioStore.toggleVoice(); + if (!audioStore.isVoiceEnabled) { + // 如果语音功能关闭,先开启语音功能 + audioStore.toggleVoice(); + } else { + // 如果语音功能开启,则切换播放/暂停状态 + if (audioStore.currentAudioUrl || audioStore.ttsUrl) { + // 有音频时切换播放/暂停 + audioStore.togglePlayPause(); + } else { + // 没有音频时关闭语音功能 + audioStore.toggleVoice(); + } + } }; // 将默认值改为从 sessionStorage 中获取,如果没有则使用默认值 'aifindCow'为第一个默认tab const activeTab = ref(sessionStorage.getItem("activeTabAI") || "AIchat"); @@ -570,7 +582,8 @@ onMounted(async () => { AI情绪大模型 - + + @@ -585,7 +598,7 @@ onMounted(async () => { @@ -949,6 +962,19 @@ body { margin-right: 5px; } +/* 音频播放动画 */ +@keyframes pulse { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + } +} + .footer-second-line { position: relative; display: flex;