Browse Source

修复刷新页面音频重复播放和打字机效果;token为0时不能使用。

songjie/feature-20250628160649-上线前优化
宋杰 5 days ago
parent
commit
e0c0bc1086
  1. 50
      src/store/emotionAudio.js
  2. 178
      src/views/AiEmotion.vue

50
src/store/emotionAudio.js

@ -1,4 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { Howl } from 'howler'
export const useEmotionAudioStore = defineStore('emotionAudio', { export const useEmotionAudioStore = defineStore('emotionAudio', {
state: () => ({ state: () => ({
@ -21,6 +22,11 @@ export const useEmotionAudioStore = defineStore('emotionAudio', {
}, },
// 播放控制 // 播放控制
play() { play() {
// 如果没有音频实例但有音频URL,先创建实例
if (!this.soundInstance && this.currentAudioUrl) {
this.createAudioInstance(this.currentAudioUrl)
}
if (this.soundInstance) { if (this.soundInstance) {
if (this.isPaused && this.playbackPosition > 0) { if (this.isPaused && this.playbackPosition > 0) {
// 从暂停位置继续播放 // 从暂停位置继续播放
@ -83,6 +89,50 @@ export const useEmotionAudioStore = defineStore('emotionAudio', {
this.ttsUrl = '' this.ttsUrl = ''
this.soundInstance = null this.soundInstance = null
this.nowSound = '' this.nowSound = ''
},
// 创建音频实例
createAudioInstance(url) {
// 停止之前的音频
if (this.soundInstance) {
this.soundInstance.stop()
}
// 创建新的音频实例
const newSound = new Howl({
src: [url],
html5: true,
format: ['mp3', 'wav'],
onplay: () => {
this.isPlaying = true
console.log('音频开始播放')
},
onend: () => {
this.isPlaying = false
this.isPaused = false
this.playbackPosition = 0
console.log('音频播放结束')
},
onstop: () => {
this.isPlaying = false
console.log('音频播放停止')
},
onpause: () => {
this.isPlaying = false
console.log('音频播放暂停')
},
onerror: (error) => {
this.isPlaying = false
console.error('音频播放错误:', error)
},
onload: () => {
this.duration = newSound.duration()
console.log('音频加载完成,时长:', this.duration)
}
})
// 保存音频实例
this.soundInstance = newSound
this.nowSound = newSound
} }
} }
}) })

178
src/views/AiEmotion.vue

@ -247,6 +247,7 @@ const scenarioApplicationRef = ref(null); // 场景应用部分的引用
const hasTriggeredAudio = ref(false); // const hasTriggeredAudio = ref(false); //
const hasTriggeredTypewriter = ref(false); // const hasTriggeredTypewriter = ref(false); //
const intersectionObserver = ref(null); // observer const intersectionObserver = ref(null); // observer
const isUserInitiated = ref(false); //
// //
const displayedTexts = ref({ const displayedTexts = ref({
@ -325,8 +326,8 @@ watch(currentStock, (newStock) => {
stopAudio(); stopAudio();
// URL // URL
audioUrl.value = ''; audioUrl.value = '';
// currentAudioUrl
emotionAudioStore.stop();
// storeURL
emotionAudioStore.resetAudioState();
// //
clearTypewriterTimers(); clearTypewriterTimers();
// //
@ -365,8 +366,7 @@ watch(currentStock, (newStock) => {
disclaimer: true disclaimer: true
}; };
// 使
// URL
// URL
let voiceUrl = null; let voiceUrl = null;
if (conclusion.url) { if (conclusion.url) {
voiceUrl = conclusion.url.toString().trim().replace(/[`\s]/g, ''); voiceUrl = conclusion.url.toString().trim().replace(/[`\s]/g, '');
@ -381,10 +381,11 @@ watch(currentStock, (newStock) => {
} }
if (voiceUrl && voiceUrl.startsWith('http')) { if (voiceUrl && voiceUrl.startsWith('http')) {
console.log('切换到已显示股票,播放对应音频:', voiceUrl);
console.log('切换到已显示股票,准备音频URL但不自动播放:', voiceUrl);
audioUrl.value = voiceUrl; audioUrl.value = voiceUrl;
//
playAudio(voiceUrl);
// storeURL
emotionAudioStore.setCurrentAudioUrl(voiceUrl);
//
} }
} catch (error) { } catch (error) {
console.error('解析结论数据失败:', error); console.error('解析结论数据失败:', error);
@ -413,6 +414,34 @@ watch(currentStock, (newStock) => {
four: false, four: false,
disclaimer: false disclaimer: false
}; };
// 使URL便
if (newStock.conclusionData) {
try {
const conclusion = JSON.parse(newStock.conclusionData);
let voiceUrl = null;
if (conclusion.url) {
voiceUrl = conclusion.url.toString().trim().replace(/[`\s]/g, '');
} else if (conclusion.audioUrl) {
voiceUrl = conclusion.audioUrl.toString().trim().replace(/[`\s]/g, '');
} else if (conclusion.voice_url) {
voiceUrl = conclusion.voice_url.toString().trim().replace(/[`\s]/g, '');
} else if (conclusion.audio) {
voiceUrl = conclusion.audio.toString().trim().replace(/[`\s]/g, '');
} else if (conclusion.tts_url) {
voiceUrl = conclusion.tts_url.toString().trim().replace(/[`\s]/g, '');
}
if (voiceUrl && voiceUrl.startsWith('http')) {
console.log('切换到未显示股票,准备音频URL:', voiceUrl);
audioUrl.value = voiceUrl;
// storeURL
emotionAudioStore.setCurrentAudioUrl(voiceUrl);
}
} catch (error) {
console.error('解析结论数据失败:', error);
}
}
} }
// //
@ -523,37 +552,13 @@ watch(parsedConclusion, (newConclusion) => {
if (voiceUrl && voiceUrl.startsWith('http')) { if (voiceUrl && voiceUrl.startsWith('http')) {
console.log('找到并清理后的语音URL:', voiceUrl); console.log('找到并清理后的语音URL:', voiceUrl);
audioUrl.value = voiceUrl; audioUrl.value = voiceUrl;
// storeURL
emotionAudioStore.setCurrentAudioUrl(voiceUrl);
console.log('音频URL已准备,检查是否需要立即触发效果'); console.log('音频URL已准备,检查是否需要立即触发效果');
//
nextTick(() => {
setTimeout(() => {
if (currentStock.value?.stockInfo && isPageLoaded.value) {
const stockCode = currentStock.value.stockInfo.code || currentStock.value.stockInfo.symbol;
if (parsedConclusion.value && stockCode) {
//
if (stockTypewriterShown.value.has(stockCode)) {
return;
}
//
console.log('音频准备完成且页面已加载,立即触发效果');
hasTriggeredTypewriter.value = true;
hasTriggeredAudio.value = true;
startTypewriterEffect(parsedConclusion.value);
if (!stockAudioPlayed.value.has(stockCode)) {
console.log('立即开始音频播放');
stockAudioPlayed.value.set(stockCode, true);
playAudio(audioUrl.value);
}
stockTypewriterShown.value.set(stockCode, true);
}
}
}, 100); // DOM
});
//
//
console.log('音频URL已准备完成,等待用户手动触发播放');
} else { } else {
console.log('未找到有效的语音URL,原始URL:', newConclusion.url); console.log('未找到有效的语音URL,原始URL:', newConclusion.url);
console.log('结论数据中的所有字段:', Object.keys(newConclusion)); console.log('结论数据中的所有字段:', Object.keys(newConclusion));
@ -806,6 +811,8 @@ function startImageRotation() {
// //
async function handleSendMessage(input) { async function handleSendMessage(input) {
console.log("发送内容:", input); console.log("发送内容:", input);
//
isUserInitiated.value = true;
// //
if (!input || !input.trim()) { if (!input || !input.trim()) {
@ -931,11 +938,11 @@ async function handleSendMessage(input) {
renderCharts(currentStock.value.apiData); renderCharts(currentStock.value.apiData);
console.log('数据加载完成后开始渲染图表'); console.log('数据加载完成后开始渲染图表');
//
if (parsedConclusion.value && audioUrl.value) {
//
if (isUserInitiated.value && parsedConclusion.value && audioUrl.value) {
const stockCode = currentStock.value.stockInfo?.code || currentStock.value.stockInfo?.symbol; const stockCode = currentStock.value.stockInfo?.code || currentStock.value.stockInfo?.symbol;
if (stockCode && !stockTypewriterShown.value.has(stockCode)) { if (stockCode && !stockTypewriterShown.value.has(stockCode)) {
console.log('数据加载完成,立即触发音频和打字机效果');
console.log('用户主动搜索,立即触发音频和打字机效果');
startTypewriterEffect(parsedConclusion.value); startTypewriterEffect(parsedConclusion.value);
if (!stockAudioPlayed.value.has(stockCode)) { if (!stockAudioPlayed.value.has(stockCode)) {
@ -945,6 +952,9 @@ async function handleSendMessage(input) {
stockTypewriterShown.value.set(stockCode, true); stockTypewriterShown.value.set(stockCode, true);
} }
} }
//
isUserInitiated.value = false;
} }
}); });
} else { } else {
@ -1189,28 +1199,37 @@ function setupIntersectionObserver() {
if (parsedConclusion.value && stockCode) { if (parsedConclusion.value && stockCode) {
// //
if (!stockTypewriterShown.value.has(stockCode)) { if (!stockTypewriterShown.value.has(stockCode)) {
//
if (audioUrl.value) {
console.log('该股票第一次进入场景应用,开始打字机效果和音频播放');
hasTriggeredTypewriter.value = true;
hasTriggeredAudio.value = true;
//
startTypewriterEffect(parsedConclusion.value);
//
if (!stockAudioPlayed.value.has(stockCode)) {
console.log('开始音频播放');
stockAudioPlayed.value.set(stockCode, true);
playAudio(audioUrl.value);
}
//
console.log('该股票第一次进入场景应用,直接显示完整内容,不自动播放');
// 使
const conclusion = parsedConclusion.value;
displayedTexts.value = {
one1: conclusion.one1 || '',
one2: conclusion.one2 || '',
two: conclusion.two || '',
three: conclusion.three || '',
four: conclusion.four || '',
disclaimer: '该内容由AI生成,请注意甄别'
};
displayedTitles.value = {
one: 'L1: 情绪监控',
two: 'L2: 情绪解码',
three: 'L3: 情绪推演',
four: 'L4: 情绪套利'
};
//
moduleVisibility.value = {
one: !!(conclusion.one1 || conclusion.one2),
two: !!conclusion.two,
three: !!conclusion.three,
four: !!conclusion.four,
disclaimer: true
};
//
stockTypewriterShown.value.set(stockCode, true);
} else {
console.log('音频尚未准备好,等待音频加载完成后再触发效果');
return;
}
//
stockTypewriterShown.value.set(stockCode, true);
stockAudioPlayed.value.set(stockCode, true); //
} else { } else {
// //
console.log('非第一次进入场景应用或已触发过,直接显示完整内容'); console.log('非第一次进入场景应用或已触发过,直接显示完整内容');
@ -1285,11 +1304,40 @@ onMounted(async () => {
startImageRotation(); startImageRotation();
// DOM
nextTick(() => {
setupIntersectionObserver();
//
});
//
if (emotionStore.stockList.length > 0 && emotionStore.activeStock) {
console.log('检测到已保存的股票数据,开始恢复页面状态(不自动播放音频)');
//
isPageLoaded.value = true;
// DOM
nextTick(() => {
const currentStockData = emotionStore.activeStock;
if (currentStockData && currentStockData.apiData) {
console.log('恢复图表数据:', currentStockData.stockInfo.name);
renderCharts(currentStockData.apiData);
//
if (currentStockData.conclusionData) {
conclusionData.value = currentStockData.conclusionData;
//
const stockCode = currentStockData.stockInfo?.code || currentStockData.stockInfo?.symbol;
if (stockCode) {
stockTypewriterShown.value.set(stockCode, true);
stockAudioPlayed.value.set(stockCode, true);
}
}
}
setupIntersectionObserver();
});
} else {
//
nextTick(() => {
setupIntersectionObserver();
});
}
}); });
// observer // observer

Loading…
Cancel
Save