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;