-
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秒开始滚动,确保页面完全渲染
+ // 移除自动滚动触发,改为在第二个工作流接口调用时触发
});
});