From b9197ca47e32405b5a9b17fbd274d80ab541d3a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E6=9D=B0?= Date: Wed, 18 Jun 2025 19:57:05 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=AD=E9=9F=B3=E6=92=AD=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/AiEmotion.vue | 233 +++++++++++++++++++++++++++++++++---- src/views/components/StockTabs.vue | 8 +- 2 files changed, 212 insertions(+), 29 deletions(-) diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue index ad34834..53eb003 100644 --- a/src/views/AiEmotion.vue +++ b/src/views/AiEmotion.vue @@ -5,6 +5,7 @@ 金轮图标 +
@@ -118,7 +119,7 @@
-
+
场景应用标题
@@ -167,7 +168,7 @@ import { ElMessage } from 'element-plus'; import { useEmotionStore } from '@/store/emotion'; // 导入Pinia store import { useAudioStore } from '@/store/audio.js'; // 导入音频store import { Howl, Howler } from 'howler'; // 导入音频播放库 - +import { reactive } from 'vue'; // 使用Pinia store const emotionStore = useEmotionStore(); const audioStore = useAudioStore(); @@ -186,6 +187,15 @@ const isRotating = ref(false);//控制旋转 const version1 = ref(2); // 版本号 const conclusionData = ref(''); // 存储第二个工作流接口返回的结论数据 +// 自动滚动相关数据 +const isAutoScrolling = ref(false); +const currentSection = ref(0); +const sectionRefs = ref([]); +const scenarioApplicationRef = ref(null); // 场景应用部分的引用 +const hasTriggeredAudio = ref(false); // 是否已触发音频播放 +const hasTriggeredTypewriter = ref(false); // 是否已触发打字机效果 +const intersectionObserver = ref(null); // 存储observer实例 + // 打字机效果相关数据 const displayedTexts = ref({ one1: '', @@ -232,10 +242,24 @@ const parsedConclusion = computed(() => { } }); + + // 监听当前股票变化,重新渲染图表 watch(currentStock, (newStock) => { if (newStock && newStock.apiData) { isPageLoaded.value = true; + // 重置触发状态,允许新股票重新触发效果 + hasTriggeredAudio.value = false; + hasTriggeredTypewriter.value = false; + // 清空之前的显示文本 + displayedTexts.value = { + one1: '', + one2: '', + two: '', + three: '', + four: '', + disclaimer: '' + }; nextTick(() => { renderCharts(newStock.apiData); }); @@ -244,11 +268,11 @@ watch(currentStock, (newStock) => { } }, { immediate: true }); -// 监听parsedConclusion变化,触发打字机效果 +// 监听parsedConclusion变化,准备数据但不立即触发打字机效果 watch(parsedConclusion, (newConclusion) => { if (newConclusion) { console.log('场景应用结论数据:', newConclusion); - startTypewriterEffect(newConclusion); + // 不再立即开始打字机效果,等待滚动到场景应用部分时触发 // 尝试多种可能的语音URL字段名 let voiceUrl = null; @@ -266,13 +290,13 @@ watch(parsedConclusion, (newConclusion) => { } if (voiceUrl && voiceUrl.startsWith('http')) { - console.log('找到并清理后的语音URL:', voiceUrl); - audioUrl.value = voiceUrl; - playAudio(voiceUrl); - } else { - console.log('未找到有效的语音URL,原始URL:', newConclusion.url); - console.log('结论数据中的所有字段:', Object.keys(newConclusion)); - } + console.log('找到并清理后的语音URL:', voiceUrl); + audioUrl.value = voiceUrl; + console.log('音频URL已准备,等待滚动触发播放'); + } else { + console.log('未找到有效的语音URL,原始URL:', newConclusion.url); + console.log('结论数据中的所有字段:', Object.keys(newConclusion)); + } } }, { immediate: true }); @@ -293,7 +317,7 @@ function startTypewriterEffect(conclusion) { }; // 定义打字速度(毫秒) - const typeSpeed = 50; + const typeSpeed = 300; let totalDelay = 0; // 为每个文本创建打字机效果 @@ -404,8 +428,6 @@ function stopAudio() { } isAudioPlaying.value = false; } -//导出方法供外部使用 -defineExpose({ handleSendMessage }) // 触发图片旋转的方法 function startImageRotation() { isRotating.value = true; @@ -620,16 +642,175 @@ const scrollToBottom = async () => { }; -// 页面挂载完成后触发图片旋转 -onMounted(() => { - startImageRotation(); -}); +// 检查数据是否已加载完成 +function isDataLoaded() { + // 检查页面是否已加载 + if (!isPageLoaded.value) { + console.log('页面数据尚未加载完成'); + return false; + } + + // 检查当前股票数据是否存在 + if (!currentStock.value || !currentStock.value.apiData) { + console.log('股票数据尚未加载完成'); + return false; + } + + // 检查图表组件是否已渲染 + const requiredRefs = [ + marketTemperatureRef.value, + emotionDecodRef.value, + emotionalBottomRadarRef.value, + emoEnergyConverterRef.value + ]; + + const allRefsLoaded = requiredRefs.every(ref => ref !== null); + if (!allRefsLoaded) { + console.log('图表组件尚未完全加载'); + return false; + } + + console.log('所有数据和组件已加载完成,可以开始滚动'); + return true; +} -// 组件卸载时清理定时器和音频 -onUnmounted(() => { - clearTypewriterTimers(); - stopAudio(); -}); +// 自动滚动函数 +function startAutoScroll() { + if (isAutoScrolling.value) return; + + // 检查数据是否已加载完成 + if (!isDataLoaded()) { + console.log('数据尚未加载完成,延迟1秒后重试'); + setTimeout(() => { + startAutoScroll(); + }, 1000); + return; + } + + isAutoScrolling.value = true; + const sections = document.querySelectorAll('.class02, .class03, .class04, .class05, .class06, .class08, .class09'); + + let currentIndex = 0; + + function scrollToNextSection() { + if (currentIndex < sections.length) { + const section = sections[currentIndex]; + + // 使用更平滑的滚动配置 + section.scrollIntoView({ + behavior: 'smooth', + block: 'center', // 改为居中显示,视觉效果更好 + inline: 'nearest' + }); + + console.log(`滚动到第${currentIndex + 1}个部分`); + currentSection.value = currentIndex; + currentIndex++; + + // 增加滚动间隔时间,让用户有更多时间观看内容 + setTimeout(scrollToNextSection, 4000); // 从2秒增加到4秒 + } else { + console.log('自动滚动完成'); + isAutoScrolling.value = false; + } + } + + // 开始滚动前等待2秒,给用户准备时间 + console.log('自动滚动将在2秒后开始'); + setTimeout(scrollToNextSection, 2000); +} + +// 设置Intersection Observer监听场景应用部分 + function setupIntersectionObserver() { + if (!scenarioApplicationRef.value) return; + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting && (!hasTriggeredAudio.value || !hasTriggeredTypewriter.value)) { + console.log('场景应用部分进入视口,开始打字机效果和音频播放'); + + // 触发打字机效果 + if (!hasTriggeredTypewriter.value && parsedConclusion.value) { + console.log('开始场景应用打字机效果'); + hasTriggeredTypewriter.value = true; + startTypewriterEffect(parsedConclusion.value); + } + + // 触发音频播放 + if (!hasTriggeredAudio.value && audioUrl.value && parsedConclusion.value) { + console.log('自动触发场景应用音频播放'); + hasTriggeredAudio.value = true; + playAudio(audioUrl.value); + } + } + }); + }, + { + threshold: 0.3, // 当30%的元素进入视口时触发 + rootMargin: '0px 0px -100px 0px' // 提前100px触发 + } + ); + + observer.observe(scenarioApplicationRef.value); + intersectionObserver.value = observer; + } + + // 手动触发自动滚动 + function triggerAutoScroll() { + // 检查是否正在滚动 + if (isAutoScrolling.value) { + console.log('自动滚动正在进行中,请稍候'); + return; + } + + // 检查数据是否已准备好 + if (!isDataLoaded()) { + console.log('数据尚未准备完成,请等待数据加载后再试'); + // 可以显示提示信息给用户 + return; + } + + console.log('手动触发自动滚动'); + startAutoScroll(); + } + +// 页面挂载完成后触发图片旋转和设置滚动监听 + onMounted(() => { + startImageRotation(); + + // 等待DOM完全渲染后设置监听器 + nextTick(() => { + setupIntersectionObserver(); + + // 页面加载完成后自动开始滚动 + setTimeout(() => { + triggerAutoScroll(); + }, 1000); // 延迟1秒开始滚动,确保页面完全渲染 + }); + }); + + // 组件卸载时清理定时器、音频和observer + onUnmounted(() => { + clearTypewriterTimers(); + stopAudio(); + + // 重置触发状态 + hasTriggeredAudio.value = false; + hasTriggeredTypewriter.value = false; + + // 清理Intersection Observer + if (intersectionObserver.value) { + intersectionObserver.value.disconnect(); + intersectionObserver.value = null; + } + }); + + // 导出方法供外部使用 + defineExpose({ + handleSendMessage, + triggerAutoScroll + });