diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue index d1af1ba..29dbfd8 100644 --- a/src/views/AiEmotion.vue +++ b/src/views/AiEmotion.vue @@ -123,25 +123,25 @@ 场景应用标题
-
-

L1: 情绪监控

+
+

{{ displayedTitles.one }}

{{ displayedTexts.one1 }}

{{ displayedTexts.one2 }}

-
-

L2: 情绪解码

+
+

{{ displayedTitles.two }}

{{ displayedTexts.two }}

-
-

L3: 情绪推演

+
+

{{ displayedTitles.three }}

{{ displayedTexts.three }}

-
-

L4: 情绪套利

+
+

{{ displayedTitles.four }}

{{ displayedTexts.four }}

-
+

{{ displayedTexts.disclaimer }}

@@ -196,7 +196,7 @@ const hasTriggeredAudio = ref(false); // 是否已触发音频播放 const hasTriggeredTypewriter = ref(false); // 是否已触发打字机效果 const intersectionObserver = ref(null); // 存储observer实例 -// 打字机效果相关数据 +// 显示的文本内容(用于打字机效果) const displayedTexts = ref({ one1: '', one2: '', @@ -205,9 +205,28 @@ const displayedTexts = ref({ four: '', disclaimer: '' }); + +// 显示的标题内容(用于打字机效果) +const displayedTitles = ref({ + one: '', + two: '', + three: '', + four: '' +}); + +// 模块显示状态 +const moduleVisibility = ref({ + one: false, + two: false, + three: false, + four: false, + disclaimer: false +}); const typewriterTimers = ref([]); // 记录每个股票是否已经显示过打字机效果 const stockTypewriterShown = ref(new Map()); +// 记录每个股票是否已经播放过音频 +const stockAudioPlayed = ref(new Map()); // 音频播放相关数据 const audioUrl = ref(''); @@ -261,7 +280,7 @@ watch(currentStock, (newStock) => { // 检查该股票是否已经显示过打字机效果 if (stockCode && stockTypewriterShown.value.has(stockCode)) { - // 如果已经显示过,直接显示完整文本 + // 如果已经显示过,直接显示完整文本和标题 if (newStock.conclusionData) { try { const conclusion = JSON.parse(newStock.conclusionData); @@ -273,6 +292,20 @@ watch(currentStock, (newStock) => { 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 + }; } catch (error) { console.error('解析结论数据失败:', error); } @@ -287,10 +320,88 @@ watch(currentStock, (newStock) => { four: '', disclaimer: '' }; + displayedTitles.value = { + one: '', + two: '', + three: '', + four: '' + }; + moduleVisibility.value = { + one: false, + two: false, + three: false, + four: false, + disclaimer: false + }; } nextTick(() => { renderCharts(newStock.apiData); + + // 检查场景应用部分是否已经在视口中,如果是则立即触发效果 + setTimeout(() => { + if (scenarioApplicationRef.value && parsedConclusion.value) { + const rect = scenarioApplicationRef.value.getBoundingClientRect(); + const isInViewport = rect.top < window.innerHeight && rect.bottom > 0; + + if (isInViewport && !hasTriggeredTypewriter.value) { + console.log('股票切换后检测到场景应用部分在视口中,立即触发效果'); + const stockCode = newStock.stockInfo?.code || newStock.stockInfo?.symbol; + + if (stockCode) { + if (!stockTypewriterShown.value.has(stockCode)) { + // 检查音频是否准备好,如果没有准备好则不触发效果 + if (!audioUrl.value) { + console.log('音频尚未准备好,等待音频加载完成后再触发效果(股票切换后)'); + 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); + } else { + console.log('该股票已显示过,直接显示完整内容(股票切换后)'); + hasTriggeredTypewriter.value = true; + hasTriggeredAudio.value = true; + + // 直接显示完整内容 + 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 + }; + } + } + } + } + }, 500); // 延迟500ms确保数据完全加载 }); } else { isPageLoaded.value = false; @@ -321,7 +432,36 @@ watch(parsedConclusion, (newConclusion) => { if (voiceUrl && voiceUrl.startsWith('http')) { console.log('找到并清理后的语音URL:', voiceUrl); audioUrl.value = voiceUrl; - console.log('音频URL已准备,等待滚动触发播放'); + console.log('音频URL已准备,检查是否需要立即触发效果'); + + // 音频准备好后,检查场景应用部分是否已经在视口中 + nextTick(() => { + setTimeout(() => { + if (scenarioApplicationRef.value && currentStock.value?.stockInfo) { + const stockCode = currentStock.value.stockInfo.code || currentStock.value.stockInfo.symbol; + const rect = scenarioApplicationRef.value.getBoundingClientRect(); + const isInViewport = rect.top < window.innerHeight && rect.bottom > 0; + + if (isInViewport && !hasTriggeredTypewriter.value && parsedConclusion.value && stockCode) { + if (!stockTypewriterShown.value.has(stockCode)) { + 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更新完成 + }); } else { console.log('未找到有效的语音URL,原始URL:', newConclusion.url); console.log('结论数据中的所有字段:', Object.keys(newConclusion)); @@ -331,11 +471,20 @@ watch(parsedConclusion, (newConclusion) => { // 打字机效果函数 function startTypewriterEffect(conclusion) { + console.log('开始打字机效果,结论数据:', conclusion); + + // 详细调试各个字段 + console.log('L1字段 - one1:', conclusion.one1); + console.log('L1字段 - one2:', conclusion.one2); + console.log('L2字段 - two:', conclusion.two); + console.log('L3字段 - three:', conclusion.three); + console.log('L4字段 - four:', conclusion.four); + // 清除之前的定时器 typewriterTimers.value.forEach(timer => clearTimeout(timer)); typewriterTimers.value = []; - // 清空之前的显示文本 + // 重置显示文本和状态 displayedTexts.value = { one1: '', one2: '', @@ -344,41 +493,117 @@ function startTypewriterEffect(conclusion) { four: '', disclaimer: '' }; + + displayedTitles.value = { + one: '', + two: '', + three: '', + four: '' + }; + + moduleVisibility.value = { + one: false, + two: false, + three: false, + four: false, + disclaimer: false + }; // 定义打字速度(毫秒) - const typeSpeed = 250; + const typeSpeed = 200; let totalDelay = 0; - // 为每个文本创建打字机效果 - const textKeys = ['one1', 'one2', 'two', 'three', 'four']; - - textKeys.forEach((key) => { - if (conclusion[key]) { - const text = conclusion[key]; - const startDelay = totalDelay; - - for (let i = 0; i <= text.length; i++) { - const timer = setTimeout(() => { - displayedTexts.value[key] = text.substring(0, i); - }, startDelay + i * typeSpeed); + // 定义模块配置 + const modules = [ + { + key: 'one', + title: 'L1: 情绪监控', + contents: [ + { key: 'one1', text: conclusion.one1 }, + { key: 'one2', text: conclusion.one2 } + ] + }, + { + key: 'two', + title: 'L2: 情绪解码', + contents: [ + { key: 'two', text: conclusion.two } + ] + }, + { + key: 'three', + title: 'L3: 情绪推演', + contents: [ + { key: 'three', text: conclusion.three } + ] + }, + { + key: 'four', + title: 'L4: 情绪套利', + contents: [ + { key: 'four', text: conclusion.four } + ] + } + ]; - typewriterTimers.value.push(timer); + // 按模块顺序处理 + modules.forEach((module) => { + // 检查模块是否有内容 + const hasContent = module.contents.some(content => content.text && content.text.trim()); + console.log(`模块 ${module.key} 是否有内容:`, hasContent, '内容:', module.contents.map(c => c.text)); + if (!hasContent) return; + + console.log(`开始显示模块 ${module.key}`); + // 显示模块 + const showModuleTimer = setTimeout(() => { + moduleVisibility.value[module.key] = true; + console.log(`模块 ${module.key} 已设置为可见`); + }, totalDelay); + typewriterTimers.value.push(showModuleTimer); + totalDelay += 100; + + // 打字机效果显示标题 + const title = module.title; + for (let i = 0; i <= title.length; i++) { + const timer = setTimeout(() => { + displayedTitles.value[module.key] = title.substring(0, i); + }, totalDelay + i * typeSpeed); + typewriterTimers.value.push(timer); + } + totalDelay += title.length * typeSpeed + 300; // 标题完成后间隔 + + // 打字机效果显示内容 + module.contents.forEach((content) => { + if (content.text && content.text.trim()) { + const text = content.text; + for (let i = 0; i <= text.length; i++) { + const timer = setTimeout(() => { + displayedTexts.value[content.key] = text.substring(0, i); + }, totalDelay + i * typeSpeed); + typewriterTimers.value.push(timer); + } + totalDelay += text.length * typeSpeed + 500; // 内容完成后间隔 } + }); - // 更新总延迟,为下一个文本留出时间 - totalDelay += text.length * typeSpeed + 300; // 额外300ms间隔 - } + totalDelay += 800; // 模块间间隔 }); - // 添加免责声明的打字机效果(在所有内容显示完成后) + // 添加免责声明的打字机效果(在所有模块显示完成后) const disclaimerText = '该内容由AI内容生成,请注意甄别'; - const disclaimerStartDelay = totalDelay + 500; // 额外500ms间隔 - + + // 显示免责声明模块 + const showDisclaimerTimer = setTimeout(() => { + moduleVisibility.value.disclaimer = true; + }, totalDelay); + typewriterTimers.value.push(showDisclaimerTimer); + totalDelay += 100; + + // 打字机效果显示免责声明 for (let i = 0; i <= disclaimerText.length; i++) { const timer = setTimeout(() => { displayedTexts.value.disclaimer = disclaimerText.substring(0, i); - }, disclaimerStartDelay + i * typeSpeed); - + }, totalDelay + i * typeSpeed); typewriterTimers.value.push(timer); } } @@ -521,6 +746,10 @@ async function handleSendMessage(input) { }; console.log('======================================') + // 在调用第二个工作流接口前立即开始缓慢滚动 + console.log('第二个工作流接口开始调用,立即开始缓慢滚动'); + startAutoScroll(); + // 同时调用第二个数据流接口和fetchData方法 const [conclusionResult, fetchDataResult] = await Promise.all([ getConclusionAPI(conclusionParams), @@ -766,27 +995,63 @@ function setupIntersectionObserver() { // 获取当前股票代码 const stockCode = currentStock.value?.stockInfo?.code || currentStock.value?.stockInfo?.symbol; - // 触发打字机效果 + // 同时触发打字机效果和音频播放 if (!hasTriggeredTypewriter.value && parsedConclusion.value && stockCode) { // 检查该股票是否已经显示过打字机效果 if (!stockTypewriterShown.value.has(stockCode)) { - console.log('开始场景应用打字机效果'); + // 检查音频是否准备好,如果没有准备好则不触发效果 + if (!audioUrl.value) { + console.log('音频尚未准备好,等待音频加载完成后再触发效果'); + 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); } else { - console.log('该股票已显示过打字机效果,跳过'); + console.log('该股票已显示过打字机效果,直接显示完整内容'); hasTriggeredTypewriter.value = true; + hasTriggeredAudio.value = true; + + // 直接显示完整内容,不使用打字机效果 + 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 + }; } } - - // 触发音频播放 - if (!hasTriggeredAudio.value && audioUrl.value && parsedConclusion.value) { - console.log('自动触发场景应用音频播放'); - hasTriggeredAudio.value = true; - playAudio(audioUrl.value); - } } }); }, @@ -826,11 +1091,7 @@ onMounted(() => { // 等待DOM完全渲染后设置监听器 nextTick(() => { setupIntersectionObserver(); - - // 页面加载完成后自动开始滚动 - setTimeout(() => { - triggerAutoScroll(); - }, 1000); // 延迟1秒开始滚动,确保页面完全渲染 + // 移除自动滚动触发,改为在第二个工作流接口调用时触发 }); });