diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue index 2ecbbee..5fa818d 100644 --- a/src/views/AiEmotion.vue +++ b/src/views/AiEmotion.vue @@ -108,16 +108,16 @@
-

🔍 情绪监控-金融宇宙的【量子检测网络】 +

情绪监控-金融宇宙的【量子检测网络】 核心任务:构建全市场情绪引力场雷达,实时监测资金流向和情绪波动

-

🧠 情绪解码-主力思维的【神经破译矩阵】 +

情绪解码-主力思维的【神经破译矩阵】 核心任务:解构资金行为的量子密码,破译主力操盘意图和策略布局

-

🔮 情绪推演-未来战争的【时空推演舱】 +

情绪推演-未来战争的【时空推演舱】 核心任务:基于情绪数据推演未来走势,预测市场转折点和机会窗口

-

💰 情绪套利-财富裂变的【粒子对撞机】 +

情绪套利-财富裂变的【粒子对撞机】 核心任务:将情绪差转化为收益粒子流,实现情绪能量的价值转换

@@ -409,7 +409,7 @@ watch(currentStock, (newStock) => { four: !!conclusion.four, disclaimer: true }; - + // 提取音频URL但不自动播放,等待用户手动点击 let voiceUrl = null; if (conclusion.url) { @@ -423,7 +423,7 @@ watch(currentStock, (newStock) => { } 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; @@ -458,7 +458,7 @@ watch(currentStock, (newStock) => { four: false, disclaimer: false }; - + // 即使没有显示过,也需要设置音频URL以便用户手动播放 if (newStock.conclusionData) { try { @@ -475,7 +475,7 @@ watch(currentStock, (newStock) => { } 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; @@ -494,75 +494,75 @@ watch(currentStock, (newStock) => { renderCharts(newStock.apiData); console.log('图表数据已准备完成,开始渲染:', newStock.apiData) // 检查场景应用部分是否已经在视口中,如果是则立即触发效果 - setTimeout(() => { - if (scenarioApplicationRef.value && parsedConclusion.value) { - const stockCode = newStock.stockInfo?.code || newStock.stockInfo?.symbol; - - // 如果该股票已经显示过,不需要再处理 - if (stockCode && stockTypewriterShown.value.has(stockCode)) { - return; - } + setTimeout(() => { + if (scenarioApplicationRef.value && parsedConclusion.value) { + const stockCode = newStock.stockInfo?.code || newStock.stockInfo?.symbol; - const rect = scenarioApplicationRef.value.getBoundingClientRect(); - const isInViewport = rect.top < window.innerHeight && rect.bottom > 0; - - if (isInViewport) { - console.log('股票切换后检测到场景应用部分在视口中'); - - if (stockCode) { - // 检查该股票是否是第一次触发 - if (!stockTypewriterShown.value.has(stockCode)) { - // 该股票第一次:播放音频和打字机效果 - if (audioUrl.value) { - console.log('该股票第一次进入场景应用,开始打字机效果和音频播放'); - hasTriggeredTypewriter.value = true; - hasTriggeredAudio.value = true; - - startTypewriterEffect(parsedConclusion.value); + // 如果该股票已经显示过,不需要再处理 + if (stockCode && stockTypewriterShown.value.has(stockCode)) { + return; + } - if (!stockAudioPlayed.value.has(stockCode)) { - console.log('开始音频播放'); - stockAudioPlayed.value.set(stockCode, true); - playAudio(audioUrl.value); + const rect = scenarioApplicationRef.value.getBoundingClientRect(); + const isInViewport = rect.top < window.innerHeight && rect.bottom > 0; + + if (isInViewport) { + console.log('股票切换后检测到场景应用部分在视口中'); + + if (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); + } + + stockTypewriterShown.value.set(stockCode, true); + } else { + console.log('音频尚未准备好,等待音频加载完成后再触发效果(股票切换后)'); + return; } - - stockTypewriterShown.value.set(stockCode, true); } else { - console.log('音频尚未准备好,等待音频加载完成后再触发效果(股票切换后)'); - return; + // 非第一次或已经触发过:直接显示完整内容,不播放音频和打字机效果 + 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 + }; } - } else { - // 非第一次或已经触发过:直接显示完整内容,不播放音频和打字机效果 - 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 - }; } } } - } - }, 500); // 延迟500ms确保数据完全加载 + }, 500); // 延迟500ms确保数据完全加载 }); } else { console.log('页面尚未加载完成,等待数据加载完成后再渲染图表'); @@ -969,11 +969,11 @@ async function handleSendMessage(input) { conclusionData.value = conclusionResponse.data; // 将结论数据存储到store中的当前激活股票 emotionStore.updateActiveStockConclusion(conclusionResponse.data); - + // 所有数据加载完成,关闭加载状态,显示页面 isLoading.value = false; isPageLoaded.value = true; - + // 数据获取成功后,重新获取用户次数以实现实时更新 try { await chatStore.getUserCount(); @@ -981,22 +981,22 @@ async function handleSendMessage(input) { } catch (error) { console.error('更新用户次数失败:', error); } - + console.log('所有数据加载完成,开始渲染页面'); - + // 确保页面状态更新后触发图表渲染和音频文本 nextTick(() => { if (currentStock.value && currentStock.value.apiData) { renderCharts(currentStock.value.apiData); console.log('数据加载完成后开始渲染图表'); - + // 只有在用户主动搜索时才自动触发音频和文本 if (isUserInitiated.value && parsedConclusion.value && audioUrl.value) { const stockCode = currentStock.value.stockInfo?.code || currentStock.value.stockInfo?.symbol; if (stockCode && !stockTypewriterShown.value.has(stockCode)) { console.log('用户主动搜索,立即触发音频和打字机效果'); startTypewriterEffect(parsedConclusion.value); - + if (!stockAudioPlayed.value.has(stockCode)) { stockAudioPlayed.value.set(stockCode, true); playAudio(audioUrl.value); @@ -1004,7 +1004,7 @@ async function handleSendMessage(input) { stockTypewriterShown.value.set(stockCode, true); } } - + // 重置用户主动搜索标志 isUserInitiated.value = false; } @@ -1210,7 +1210,7 @@ function setupIntersectionObserver() { if (!stockTypewriterShown.value.has(stockCode)) { // 该股票第一次进入视口:只显示文本,不自动播放音频和打字机效果 console.log('该股票第一次进入场景应用,直接显示完整内容,不自动播放'); - + // 直接显示完整内容,不使用打字机效果 const conclusion = parsedConclusion.value; displayedTexts.value = { @@ -1294,15 +1294,15 @@ onMounted(async () => { // 确保获取用户次数 try { await chatStore.getUserCount(); - console.log('情绪大模型页面:用户次数获取成功'); + console.log('情绪大模型页面:用户次数获取成功'); } catch (error) { console.error('情绪大模型页面:获取用户次数失败', error); } - + // 添加全局resize监听器,确保所有图表和容器响应页面宽度变化 const globalResizeHandler = debounce(() => { console.log('AiEmotion页面:窗口大小变化,触发容器和图表resize'); - + // 强制重新计算容器布局 const mainContainer = document.querySelector('.class01'); if (mainContainer) { @@ -1311,7 +1311,7 @@ onMounted(async () => { mainContainer.offsetHeight; // 强制重排 mainContainer.style.display = ''; } - + // 触发所有图表组件的resize const resizeHandlers = [ window.emoEnergyConverterResizeHandler, @@ -1319,7 +1319,7 @@ onMounted(async () => { window.emotionalBottomRadarResizeHandler, window.emotionDecodResizeHandler ]; - + resizeHandlers.forEach(handler => { if (typeof handler === 'function') { try { @@ -1329,7 +1329,7 @@ onMounted(async () => { } } }); - + // 延迟再次触发图表resize,确保容器尺寸稳定后图表能正确适配 setTimeout(() => { resizeHandlers.forEach(handler => { @@ -1343,16 +1343,16 @@ onMounted(async () => { }); }, 100); }, 150); // 150ms防抖延迟 - + // 移除之前的监听器(如果存在) if (window.aiEmotionGlobalResizeHandler) { window.removeEventListener('resize', window.aiEmotionGlobalResizeHandler); } - + // 添加新的监听器 window.addEventListener('resize', globalResizeHandler); window.aiEmotionGlobalResizeHandler = globalResizeHandler; - + // 防抖函数定义 function debounce(func, wait) { let timeout; @@ -1371,17 +1371,17 @@ onMounted(async () => { // 检查是否有已保存的股票数据需要恢复 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; @@ -1393,7 +1393,7 @@ onMounted(async () => { } } } - + setupIntersectionObserver(); }); } else { @@ -1418,7 +1418,7 @@ onUnmounted(() => { intersectionObserver.value.disconnect(); intersectionObserver.value = null; } - + // 清理全局resize监听器 if (window.aiEmotionGlobalResizeHandler) { window.removeEventListener('resize', window.aiEmotionGlobalResizeHandler); @@ -1552,16 +1552,12 @@ defineExpose({ margin: 20px; background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(0, 100, 200, 0.15) 100%); border: 2px solid rgba(0, 212, 255, 0.4); - box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); .conclusion-item { margin-bottom: 20px; padding: 20px; border-radius: 12px; - background: linear-gradient(135deg, rgba(0, 212, 255, 0.2) 0%, rgba(0, 150, 255, 0.1) 100%); border: 1px solid rgba(0, 212, 255, 0.5); - border-left: 5px solid #00d4ff; - box-shadow: 0 4px 15px rgba(0, 212, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1); transition: all 0.3s ease; position: relative; overflow: hidden; @@ -1589,9 +1585,7 @@ defineExpose({ font-weight: bold; margin: 0 0 15px 0; text-align: center; - text-shadow: 0 2px 8px rgba(0, 212, 255, 0.5), 0 0 20px rgba(0, 212, 255, 0.3); letter-spacing: 2px; - position: relative; &::after { content: ''; @@ -1612,19 +1606,10 @@ defineExpose({ margin: 0 0 12px 0; text-align: left; word-wrap: break-word; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7); padding-left: 15px; position: relative; - &::before { - content: '▶'; - position: absolute; - left: 0; - top: 0; - color: #00d4ff; - font-size: 12px; - opacity: 0.7; - } + &:last-child { margin-bottom: 0; @@ -1659,7 +1644,6 @@ defineExpose({ margin: 20px; background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(0, 100, 200, 0.15) 100%); border: 2px solid rgba(0, 212, 255, 0.4); - box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); } .text-container p { @@ -1668,15 +1652,11 @@ defineExpose({ margin-left: 0%; padding: 20px; border-radius: 12px; - background: linear-gradient(135deg, rgba(0, 212, 255, 0.2) 0%, rgba(0, 150, 255, 0.1) 100%); - border: 1px solid rgba(0, 212, 255, 0.5); - border-left: 5px solid #00d4ff; - box-shadow: 0 4px 15px rgba(0, 212, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1); transition: all 0.3s ease; position: relative; overflow: hidden; - text-shadow: 0 2px 8px rgba(0, 212, 255, 0.5), 0 0 20px rgba(0, 212, 255, 0.3); letter-spacing: 2px; + border: 1px solid rgba(0, 212, 255, 0.5); } .text-container p::before { @@ -2168,41 +2148,41 @@ defineExpose({ width: 95%; padding: 0.8rem; } - + .span01 { width: 40%; font-size: 1.3rem; } - + .span02 { font-size: 1.3rem; } - + /* 调整图表容器高度 */ .class00 { min-height: 45rem; } - + .class03 { min-height: 60rem; } - + .class04 { min-height: 65rem; } - + .class05 { min-height: 75rem; } - + .class06 { min-height: 58rem; } - + .class08 { min-height: 42rem; } - + .scaled-img { height: 350px; min-height: 30rem; @@ -2214,49 +2194,49 @@ defineExpose({ width: 98%; padding: 0.6rem; } - + .class003 { padding-top: 6%; padding-left: 5%; } - + .div00 { gap: 1%; justify-content: center; } - + .class003 .div01, .class003 .div02 { width: 45%; min-width: 180px; font-size: 20px; } - + /* 调整图表容器高度 */ .class00 { min-height: 40rem; } - + .class03 { min-height: 55rem; } - + .class04 { min-height: 55rem; } - + .class05 { min-height: 65rem; } - + .class06 { min-height: 50rem; } - + .class08 { min-height: 35rem; } - + .scaled-img { height: 300px; min-height: 25rem; @@ -2270,7 +2250,7 @@ defineExpose({ padding: 0.5rem; margin-bottom: 5rem; } - + .container { padding-top: 2%; } @@ -2406,20 +2386,20 @@ defineExpose({ /* margin-left: -39px; */ /* min-height: 38rem; */ } - + /* 调整其他图表容器高度 */ .class00 { min-height: 35rem; } - + .class03 { min-height: 45rem; } - + .class05 { min-height: 48rem; } - + .class06 { min-height: 35rem; } @@ -2536,7 +2516,6 @@ defineExpose({ background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(0, 100, 200, 0.15) 100%); border: 2px solid rgba(0, 212, 255, 0.4); box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); - backdrop-filter: blur(15px); .conclusion-item { margin-bottom: 20px; @@ -2573,9 +2552,7 @@ defineExpose({ font-weight: bold; margin: 0 0 15px 0; text-align: center; - text-shadow: 0 2px 8px rgba(0, 212, 255, 0.5), 0 0 20px rgba(0, 212, 255, 0.3); letter-spacing: 2px; - position: relative; &::after { content: ''; @@ -2596,7 +2573,6 @@ defineExpose({ margin: 0 0 12px 0; text-align: left; word-wrap: break-word; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7); padding-left: 15px; position: relative; @@ -2734,18 +2710,18 @@ defineExpose({ .class0601 { padding-top: 10%; } - + .class003 { padding-top: 4%; padding-left: 2%; } - + .div00 { flex-direction: column; gap: 1rem; align-items: center; } - + .class003 .div01, .class003 .div02 { width: 80%; @@ -2753,19 +2729,22 @@ defineExpose({ font-size: 16px; min-height: 35px; } - + .span01 { width: 60%; font-size: 1.2rem; padding: 8px; } - + .span02 { font-size: 1.2rem; margin-top: -3%; } - - .title1, .title2, .title3, .title4 { + + .title1, + .title2, + .title3, + .title4 { font-size: 18px; margin-left: 0; } @@ -2778,13 +2757,13 @@ defineExpose({ padding: 0.3rem; margin-bottom: 3rem; } - + .div00 { flex-direction: column; gap: 0.8rem; align-items: center; } - + .class003 .div01, .class003 .div02 { width: 90%; @@ -2792,46 +2771,46 @@ defineExpose({ font-size: 14px; min-height: 30px; } - + .span01 { width: 70%; font-size: 1rem; padding: 6px; } - + .span02 { font-size: 1rem; } - + .golden-wheel-img { width: 80%; } - + /* 调整图表容器高度适配超小屏幕 */ .class00 { min-height: 25rem; } - + .class03 { min-height: 35rem; } - + .class04 { min-height: 30rem; } - + .class05 { min-height: 35rem; } - + .class06 { min-height: 25rem; } - + .class08 { min-height: 15rem; } - + .scaled-img { height: 150px; min-height: 150px;