You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2309 lines
62 KiB
2309 lines
62 KiB
<template>
|
|
<div class="ai-emotion-container" ref="userInputDisplayRef">
|
|
<!-- 金轮 -->
|
|
<div class="golden-wheel">
|
|
<img src="@/assets/img/AiEmotion/金轮.png" class="golden-wheel-img" alt="金轮图标"
|
|
:class="{ 'rotating-image': isRotating }" />
|
|
</div>
|
|
|
|
<!-- 消息显示区域 -->
|
|
<div class="user-input-display">
|
|
<div v-for="(message, index) in messages" :key="index" class="message-container">
|
|
<!-- 用户输入内容 -->
|
|
<div v-if="message.sender === 'user'" class="message-bubble user-message">
|
|
{{ message.text }}
|
|
</div>
|
|
<!-- AI返回结果 -->
|
|
<div v-if="message.sender === 'ai'" class="message-bubble ai-message">
|
|
{{ message.text }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 股票标签页 -->
|
|
<StockTabs />
|
|
|
|
<!-- 加载提示 -->
|
|
<div v-if="isLoading" class="loading-container">
|
|
<div class="loading-content">
|
|
<div class="loading-spinner"></div>
|
|
<div class="loading-text">AI小财神正在分析中,请稍候...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 渲染整个页面 -->
|
|
<div v-if="isPageLoaded" class="class01">
|
|
<div class="class00">
|
|
<!-- 四维矩阵图 -->
|
|
<div class="class02">
|
|
<div class="container">
|
|
<!-- <img class="item" :src="item" alt="思维矩阵图片" /> -->
|
|
<div class="span01">
|
|
{{ stockName }}{{ stockName ? '量子四维矩阵图' : '' }}
|
|
</div>
|
|
</div>
|
|
<span class="span02">{{ displayDate }}</span>
|
|
</div>
|
|
<div class="class0201">
|
|
<img src="@/assets/img/AiEmotion/L1.png" alt="情绪监控图标">
|
|
</div>
|
|
<!-- 温度计图表 -->
|
|
<div class="class03">
|
|
<div class="class003">
|
|
<div class="content1">
|
|
<img class="img01" src="@/assets/img/AiEmotion/温度计.png" alt="温度计图标">
|
|
<span class="title1">股票温度计</span>
|
|
</div>
|
|
<div class="div00">
|
|
<div class="div01">股票温度:{{ data2 ?? "NA" }}</div>
|
|
<div class="div02">市场温度:{{ data1 }}</div>
|
|
</div>
|
|
</div>
|
|
<marketTemperature ref="marketTemperatureRef" />
|
|
</div>
|
|
</div>
|
|
<div class="class0301">
|
|
<img src="@/assets/img/AiEmotion/L2.png" alt="情绪解码图标">
|
|
</div>
|
|
<!-- 情绪解码器图表 -->
|
|
<div class="class04">
|
|
<div class="class0401">
|
|
<img class="img02" src='@/assets/img/AiEmotion/emotionDecod.png' alt="情绪解码器图标">
|
|
<span class="title2">情绪解码器</span>
|
|
</div>
|
|
<div class="class0402">
|
|
<emotionDecod ref="emotionDecodRef"></emotionDecod>
|
|
</div>
|
|
</div>
|
|
<div class="class0403">
|
|
<img src="@/assets/img/AiEmotion/L3.png" alt="情绪推演图标">
|
|
</div>
|
|
<!-- 情绪探底雷达图表 -->
|
|
<div class="class05">
|
|
<div class="class0502">
|
|
<img class="img03" src="@/assets/img/AiEmotion/探底雷达.png" alt="探底雷达图表">
|
|
<span class="title3">情绪探底雷达</span>
|
|
</div>
|
|
<div class="class0503">
|
|
<emotionalBottomRadar ref="emotionalBottomRadarRef"></emotionalBottomRadar>
|
|
</div>
|
|
</div>
|
|
<div class="class0501">
|
|
<img src="@/assets/img/AiEmotion/L4.png" alt="情绪套利">
|
|
</div>
|
|
<!-- 情绪能量转化器图表 -->
|
|
<div class="class06">
|
|
<div class="class0601">
|
|
<img class="img04" src="@/assets/img/AiEmotion/能量转化器.png" alt="能量转化器图标">
|
|
<span class="title4">情绪能量转化器</span>
|
|
</div>
|
|
<div class="class0603">
|
|
<emoEnergyConverter ref="emoEnergyConverterRef"></emoEnergyConverter>
|
|
</div>
|
|
</div>
|
|
<!-- 核心看点 -->
|
|
<div class="class0702">
|
|
<img src="@/assets/img/AiEmotion/核心看点.png" alt="核心看点字样">
|
|
</div>
|
|
<div class="bk-image">
|
|
<div class="text-container">
|
|
<p><span class="title">🔍 情绪监控-金融宇宙的【量子检测网络】</span>
|
|
<span class="content">核心任务:构建全市场情绪引力场雷达,实时监测资金流向和情绪波动</span>
|
|
</p>
|
|
<p><span class="title">🧠 情绪解码-主力思维的【神经破译矩阵】</span>
|
|
<span class="content">核心任务:解构资金行为的量子密码,破译主力操盘意图和策略布局</span>
|
|
</p>
|
|
<p><span class="title">🔮 情绪推演-未来战争的【时空推演舱】</span>
|
|
<span class="content">核心任务:基于情绪数据推演未来走势,预测市场转折点和机会窗口</span>
|
|
</p>
|
|
<p><span class="title">💰 情绪套利-财富裂变的【粒子对撞机】</span>
|
|
<span class="content">核心任务:将情绪差转化为收益粒子流,实现情绪能量的价值转换</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<!-- 核心逻辑 -->
|
|
<div class="class0700">
|
|
<img src="@/assets/img/AiEmotion/核心逻辑.png" alt="核心逻辑字样">
|
|
</div>
|
|
<div class="class08">
|
|
<div class="lz-img">
|
|
<img src="@/assets/img/AiEmotion/量子神经决策树.png" alt="树标题">
|
|
</div>
|
|
<div class="scaled-img">
|
|
<!-- <img src="@/assets/img/AiEmotion/tree02.jpg" alt="树图片"> -->
|
|
</div>
|
|
</div>
|
|
<!-- 场景应用 -->
|
|
<div class="class09" ref="scenarioApplicationRef">
|
|
<img src="@/assets/img/AiEmotion/场景应用.png" alt="场景应用标题">
|
|
<div class="bk-image">
|
|
<div class="conclusion-container" v-if="parsedConclusion">
|
|
<div class="conclusion-item" v-if="(parsedConclusion.one1 || parsedConclusion.one2) && moduleVisibility.one">
|
|
<h4 class="conclusion-title">{{ displayedTitles.one }}</h4>
|
|
<p class="conclusion-text" v-if="parsedConclusion.one1">{{ displayedTexts.one1 }}</p>
|
|
<p class="conclusion-text" v-if="parsedConclusion.one2">{{ displayedTexts.one2 }}</p>
|
|
</div>
|
|
<div class="conclusion-item" v-if="parsedConclusion.two && moduleVisibility.two">
|
|
<h4 class="conclusion-title">{{ displayedTitles.two }}</h4>
|
|
<p class="conclusion-text">{{ displayedTexts.two }}</p>
|
|
</div>
|
|
<div class="conclusion-item" v-if="parsedConclusion.three && moduleVisibility.three">
|
|
<h4 class="conclusion-title">{{ displayedTitles.three }}</h4>
|
|
<p class="conclusion-text">{{ displayedTexts.three }}</p>
|
|
</div>
|
|
<div class="conclusion-item" v-if="parsedConclusion.four && moduleVisibility.four">
|
|
<h4 class="conclusion-title">{{ displayedTitles.four }}</h4>
|
|
<p class="conclusion-text">{{ displayedTexts.four }}</p>
|
|
</div>
|
|
<!-- AI生成内容免责声明 -->
|
|
<div class="disclaimer-item" v-if="parsedConclusion && moduleVisibility.disclaimer">
|
|
<p class="disclaimer-text">{{ displayedTexts.disclaimer }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="conclusion-placeholder" v-else>
|
|
<p>等待股票分析结论...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue';
|
|
import { getReplyAPI, getConclusionAPI } from '@/api/AiEmotionApi.js'; // 导入工作流接口方法
|
|
import axios from 'axios';
|
|
import item from '@/assets/img/AiEmotion/bk01.png'; // 导入思维矩阵图片
|
|
import emotionDecod from '@/views/components/emotionDecod.vue'; // 导入情绪解码组件
|
|
import emotionalBottomRadar from '@/views/components/emotionalBottomRadar.vue'; // 导入情绪探底雷达图组件
|
|
import emoEnergyConverter from '@/views/components/emoEnergyConverter.vue'; // 导入情绪能量转化器组件
|
|
import marketTemperature from '@/views/components/marketTemperature.vue';
|
|
import StockTabs from '@/views/components/StockTabs.vue'; // 导入股票标签页组件
|
|
import blueBorderImg from '@/assets/img/AiEmotion/blueBorder.png' //导入蓝色背景框图片
|
|
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();
|
|
|
|
// 组件引用
|
|
const marketTemperatureRef = ref(null); // 引用市场温度计组件
|
|
const emoEnergyConverterRef = ref(null)
|
|
const emotionDecodRef = ref(null)
|
|
const emotionalBottomRadarRef = ref(null)
|
|
const userInputDisplayRef = ref(null);//消息区域的引用
|
|
|
|
// 响应式数据
|
|
const messages = ref([]);
|
|
const isPageLoaded = ref(false); // 控制页面是否显示
|
|
const isLoading = ref(false); // 控制加载状态
|
|
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: '',
|
|
one2: '',
|
|
two: '',
|
|
three: '',
|
|
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('');
|
|
const isAudioPlaying = ref(false);
|
|
|
|
// 计算属性 - 从store获取当前股票数据
|
|
const currentStock = computed(() => emotionStore.activeStock);
|
|
const stockName = computed(() => currentStock.value?.stockInfo.name || "");
|
|
const displayDate = computed(() => {
|
|
if (!currentStock.value?.apiData) return "";
|
|
const lastData = currentStock.value.apiData.GSWDJ?.at(-1);
|
|
return lastData ? lastData[0] : "";
|
|
});
|
|
const data1 = computed(() => {
|
|
if (!currentStock.value?.apiData) return null;
|
|
const lastData = currentStock.value.apiData.GSWDJ?.at(-1);
|
|
return lastData ? Math.round(lastData[1]) : null;
|
|
});
|
|
const data2 = computed(() => {
|
|
if (!currentStock.value?.apiData) return null;
|
|
const lastData = currentStock.value.apiData.GSWDJ?.at(-1);
|
|
return lastData ? Math.round(lastData[2]) : null;
|
|
});
|
|
const currentConclusion = computed(() => {
|
|
return currentStock.value?.conclusionData || '';
|
|
});
|
|
const parsedConclusion = computed(() => {
|
|
if (!currentConclusion.value) return null;
|
|
try {
|
|
return JSON.parse(currentConclusion.value);
|
|
} catch (error) {
|
|
console.error('解析结论数据失败:', error);
|
|
return null;
|
|
}
|
|
});
|
|
|
|
|
|
|
|
// 监听当前股票变化,重新渲染图表
|
|
watch(currentStock, (newStock) => {
|
|
if (newStock && newStock.apiData) {
|
|
isPageLoaded.value = true;
|
|
isLoading.value = false; // 数据加载完成,关闭加载状态
|
|
// 停止当前播放的音频
|
|
stopAudio();
|
|
// 清理正在进行的打字机效果定时器
|
|
clearTypewriterTimers();
|
|
// 重置触发状态,让每个股票都能独立触发效果
|
|
hasTriggeredAudio.value = false;
|
|
hasTriggeredTypewriter.value = false;
|
|
|
|
// 获取股票代码作为唯一标识
|
|
const stockCode = newStock.stockInfo?.code || newStock.stockInfo?.symbol;
|
|
|
|
// 检查该股票是否已经显示过打字机效果
|
|
if (stockCode && stockTypewriterShown.value.has(stockCode)) {
|
|
// 如果已经显示过,直接显示完整文本和标题
|
|
if (newStock.conclusionData) {
|
|
try {
|
|
const conclusion = JSON.parse(newStock.conclusionData);
|
|
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
|
|
};
|
|
} catch (error) {
|
|
console.error('解析结论数据失败:', error);
|
|
}
|
|
}
|
|
} else {
|
|
// 如果没有显示过,清空显示文本,等待打字机效果
|
|
displayedTexts.value = {
|
|
one1: '',
|
|
one2: '',
|
|
two: '',
|
|
three: '',
|
|
four: '',
|
|
disclaimer: ''
|
|
};
|
|
displayedTitles.value = {
|
|
one: '',
|
|
two: '',
|
|
three: '',
|
|
four: ''
|
|
};
|
|
moduleVisibility.value = {
|
|
one: false,
|
|
two: false,
|
|
three: false,
|
|
four: false,
|
|
disclaimer: false
|
|
};
|
|
}
|
|
|
|
nextTick(() => {
|
|
renderCharts(newStock.apiData);
|
|
console.log('0000000000000000000000000',newStock.apiData)
|
|
// 检查场景应用部分是否已经在视口中,如果是则立即触发效果
|
|
setTimeout(() => {
|
|
if (scenarioApplicationRef.value && parsedConclusion.value) {
|
|
const stockCode = newStock.stockInfo?.code || newStock.stockInfo?.symbol;
|
|
|
|
// 如果该股票已经显示过,不需要再处理
|
|
if (stockCode && stockTypewriterShown.value.has(stockCode)) {
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
} 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确保数据完全加载
|
|
});
|
|
} else {
|
|
isPageLoaded.value = false;
|
|
}
|
|
}, { immediate: true });
|
|
|
|
// 监听parsedConclusion变化,准备数据但不立即触发打字机效果
|
|
watch(parsedConclusion, (newConclusion) => {
|
|
if (newConclusion) {
|
|
console.log('场景应用结论数据:', newConclusion);
|
|
// 不再立即开始打字机效果,等待滚动到场景应用部分时触发
|
|
|
|
// 尝试多种可能的语音URL字段名
|
|
let voiceUrl = null;
|
|
if (newConclusion.url) {
|
|
// 清理URL字符串,去除空格、反引号等特殊字符
|
|
voiceUrl = newConclusion.url.toString().trim().replace(/[`\s]/g, '');
|
|
} else if (newConclusion.audioUrl) {
|
|
voiceUrl = newConclusion.audioUrl.toString().trim().replace(/[`\s]/g, '');
|
|
} else if (newConclusion.voice_url) {
|
|
voiceUrl = newConclusion.voice_url.toString().trim().replace(/[`\s]/g, '');
|
|
} else if (newConclusion.audio) {
|
|
voiceUrl = newConclusion.audio.toString().trim().replace(/[`\s]/g, '');
|
|
} else if (newConclusion.tts_url) {
|
|
voiceUrl = newConclusion.tts_url.toString().trim().replace(/[`\s]/g, '');
|
|
}
|
|
|
|
if (voiceUrl && voiceUrl.startsWith('http')) {
|
|
console.log('找到并清理后的语音URL:', voiceUrl);
|
|
audioUrl.value = voiceUrl;
|
|
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 && parsedConclusion.value && stockCode) {
|
|
// 如果该股票已经显示过,不需要再处理
|
|
if (stockTypewriterShown.value.has(stockCode)) {
|
|
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);
|
|
}
|
|
}
|
|
}, 100); // 短暂延迟确保DOM更新完成
|
|
});
|
|
} else {
|
|
console.log('未找到有效的语音URL,原始URL:', newConclusion.url);
|
|
console.log('结论数据中的所有字段:', Object.keys(newConclusion));
|
|
}
|
|
}
|
|
}, { immediate: true });
|
|
|
|
// 打字机效果函数
|
|
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: '',
|
|
two: '',
|
|
three: '',
|
|
four: '',
|
|
disclaimer: ''
|
|
};
|
|
|
|
displayedTitles.value = {
|
|
one: '',
|
|
two: '',
|
|
three: '',
|
|
four: ''
|
|
};
|
|
|
|
moduleVisibility.value = {
|
|
one: false,
|
|
two: false,
|
|
three: false,
|
|
four: false,
|
|
disclaimer: false
|
|
};
|
|
|
|
// 定义打字速度(毫秒)
|
|
const typeSpeed = 200;
|
|
let totalDelay = 0;
|
|
|
|
// 定义模块配置
|
|
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 }
|
|
]
|
|
}
|
|
];
|
|
|
|
// 按模块顺序处理
|
|
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 += 800; // 模块间间隔
|
|
});
|
|
|
|
// 添加免责声明的打字机效果(在所有模块显示完成后)
|
|
const disclaimerText = '该内容由AI内容生成,请注意甄别';
|
|
|
|
// 显示免责声明模块
|
|
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);
|
|
}, totalDelay + i * typeSpeed);
|
|
typewriterTimers.value.push(timer);
|
|
}
|
|
}
|
|
|
|
// 清理定时器的函数
|
|
function clearTypewriterTimers() {
|
|
typewriterTimers.value.forEach(timer => clearTimeout(timer));
|
|
typewriterTimers.value = [];
|
|
}
|
|
|
|
// 音频播放函数
|
|
function playAudio(url) {
|
|
console.log('尝试播放音频:', url);
|
|
|
|
if (!url) {
|
|
console.warn('音频URL为空,跳过播放');
|
|
isAudioPlaying.value = false;
|
|
return;
|
|
}
|
|
|
|
// 检查是否启用了语音功能
|
|
console.log('语音功能状态:', audioStore.isVoiceEnabled);
|
|
if (!audioStore.isVoiceEnabled) {
|
|
console.log('语音功能已关闭,跳过播放');
|
|
return;
|
|
}
|
|
|
|
console.log('开始创建音频实例...');
|
|
|
|
try {
|
|
// 停止之前的音频
|
|
if (audioStore.nowSound) {
|
|
audioStore.nowSound.stop();
|
|
}
|
|
|
|
// 创建新的音频实例
|
|
const newSound = new Howl({
|
|
src: [url],
|
|
html5: true,
|
|
format: ['mp3', 'wav'],
|
|
onplay: () => {
|
|
isAudioPlaying.value = true;
|
|
console.log('开始播放场景应用语音');
|
|
},
|
|
onend: () => {
|
|
isAudioPlaying.value = false;
|
|
console.log('场景应用语音播放结束');
|
|
},
|
|
onstop: () => {
|
|
isAudioPlaying.value = false;
|
|
console.log('场景应用语音播放停止');
|
|
},
|
|
onerror: (error) => {
|
|
isAudioPlaying.value = false;
|
|
console.error('音频播放错误:', error);
|
|
}
|
|
});
|
|
|
|
// 保存音频实例到store
|
|
audioStore.nowSound = newSound;
|
|
audioStore.setAudioInstance(newSound);
|
|
|
|
// 播放音频
|
|
newSound.play();
|
|
|
|
} catch (error) {
|
|
console.error('创建音频实例失败:', error);
|
|
isAudioPlaying.value = false;
|
|
}
|
|
}
|
|
|
|
// 停止音频播放
|
|
function stopAudio() {
|
|
if (audioStore.nowSound) {
|
|
audioStore.nowSound.stop();
|
|
}
|
|
isAudioPlaying.value = false;
|
|
}
|
|
// 触发图片旋转的方法
|
|
function startImageRotation() {
|
|
isRotating.value = true;
|
|
// 如果你想在一段时间后停止旋转,可以添加以下代码
|
|
setTimeout(() => {
|
|
isRotating.value = false;
|
|
}, 5000); // 5 秒后停止旋转
|
|
}
|
|
|
|
|
|
// 发送消息方法
|
|
async function handleSendMessage(input) {
|
|
console.log("发送内容:", input);
|
|
|
|
// 检查用户输入内容是否为空
|
|
if (input.trim()) {
|
|
const userMessage = reactive({ sender: 'user', text: input });
|
|
messages.value.push(userMessage);
|
|
// 设置加载状态,隐藏图表页面
|
|
isLoading.value = true;
|
|
isPageLoaded.value = false;
|
|
// 触发图片旋转
|
|
isRotating.value = true;
|
|
|
|
try {
|
|
// 用来调用工作流接口的参数
|
|
const params = {
|
|
content: userMessage.text,
|
|
userData: {
|
|
token:
|
|
"9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs",
|
|
language: "cn",
|
|
brainPrivilegeState: "1",
|
|
swordPrivilegeState: "1",
|
|
stockForecastPrivile: "1",
|
|
spaceForecastPrivile: "1",
|
|
aibullPrivilegeState: "1",
|
|
aigoldBullPrivilegeS: "1",
|
|
airadarPrivilegeStat: "1",
|
|
marketList: "hk,cn,usa,my,sg,vi,in,gb",
|
|
},
|
|
};
|
|
|
|
const result = await getReplyAPI(params);
|
|
const response = await result.json(); // 解析返回的 JSON 数据
|
|
console.log("工作流接口返回数据:", response);
|
|
|
|
// 解析 data 字段
|
|
const parsedData = JSON.parse(response.data); // 将字符串形式的 JSON 转换为对象
|
|
console.log("解析后的数据:", parsedData);
|
|
|
|
if (parsedData && parsedData.market && parsedData.code) {
|
|
console.log("工作流接口返回股票信息:", parsedData);
|
|
// 调用第二个工作流接口
|
|
const conclusionParams = {
|
|
content: input.trim(),
|
|
userData: {
|
|
token:
|
|
"9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs",
|
|
language: "cn",
|
|
marketList: "hk,cn,usa,my,sg,vi,in,gb",
|
|
},
|
|
code: parsedData.code,
|
|
market: parsedData.market,
|
|
};
|
|
console.log('======================================')
|
|
|
|
// 取消自动滚动效果
|
|
// console.log('第二个工作流接口开始调用,立即开始缓慢滚动');
|
|
// startAutoScroll();
|
|
|
|
// 同时调用第二个数据流接口和fetchData方法
|
|
const [conclusionResult, fetchDataResult] = await Promise.all([
|
|
getConclusionAPI(conclusionParams),
|
|
fetchData(parsedData.code, parsedData.market, parsedData.name || "未知股票", input.trim())
|
|
]);
|
|
|
|
// 处理结论接口返回的数据
|
|
const conclusionResponse = await conclusionResult.json();
|
|
console.log("第二个工作流接口返回数据:", conclusionResponse);
|
|
|
|
// 将结论数据存储到响应式变量和store中
|
|
if (conclusionResponse && conclusionResponse.data) {
|
|
conclusionData.value = conclusionResponse.data;
|
|
// 将结论数据存储到store中的当前激活股票
|
|
emotionStore.updateActiveStockConclusion(conclusionResponse.data);
|
|
console.log("结论数据已存储到响应式变量和store中:", conclusionData.value);
|
|
}
|
|
|
|
console.log('------------------------------------')
|
|
|
|
} else {
|
|
ElMessage.error('工作流接口未返回非股票信息');
|
|
}
|
|
} catch (error) {
|
|
ElMessage.error('请求工作流接口失败,请检查网络连接');
|
|
} finally {
|
|
// 停止图片旋转
|
|
isRotating.value = false;
|
|
}
|
|
} else {
|
|
ElMessage.error('消息发送失败,请检查网络连接');
|
|
}
|
|
}
|
|
|
|
// 请求数据接口
|
|
async function fetchData(code, market, stockName, queryText) {
|
|
try {
|
|
const stockDataParams = {
|
|
// token: '+XgqsgdW0RLIbIG2pxnnbZi0+fEeMx8pywnIlrmTxtkSaPZ9xjSOWrxq+s0rL3RrfNhXPvGtz9srFfjwu8A',
|
|
token: '9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs',
|
|
market: market,
|
|
code: code,
|
|
language: 'cn',
|
|
version: version1.value
|
|
};
|
|
|
|
const stockDataResult = await axios.post(
|
|
// "http://39.101.133.168:8828/link/api/aiEmotion/client/getAiEmotionData",
|
|
'https://api.homilychart.com/link/api/aiEmotion/client/getAiEmotionData',
|
|
stockDataParams,
|
|
{
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
}
|
|
);
|
|
|
|
const stockDataResponse = stockDataResult.data; // 获取返回所有的数据
|
|
console.log('图表数据接口返回数据:', stockDataResponse.data);
|
|
|
|
if (stockDataResponse.code === 200 && stockDataResponse.data) {
|
|
console.log(stockDataResponse.code)
|
|
|
|
// 创建股票数据对象
|
|
const stockData = {
|
|
queryText: queryText,
|
|
stockInfo: {
|
|
name: stockName,
|
|
code: code,
|
|
market: market
|
|
},
|
|
apiData: stockDataResponse.data,
|
|
conclusionData: conclusionData.value, // 包含结论数据
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
// 将股票数据添加到store中
|
|
emotionStore.addStock(stockData);
|
|
|
|
console.log('股票数据已添加到store');
|
|
|
|
} else {
|
|
ElMessage.error('获取接口数据失败');
|
|
}
|
|
} catch (error) {
|
|
ElMessage.error('获取接口数据失败。。。');
|
|
}
|
|
}
|
|
|
|
// 渲染组件图表的方法
|
|
function renderCharts(data) {
|
|
nextTick(() => {
|
|
// 添加小延迟确保DOM完全更新
|
|
setTimeout(() => {
|
|
try {
|
|
// 深拷贝数据避免污染原始数据
|
|
const clonedData = JSON.parse(JSON.stringify(data));
|
|
console.log('已深拷贝数据,避免污染原始数据');
|
|
console.log('所有数据1111111111111:', clonedData)
|
|
// 渲染股市温度计图表
|
|
if (marketTemperatureRef.value && clonedData.GSWDJ) {
|
|
console.log("开始渲染股市温度计图表");
|
|
console.log("股市温度计数据", clonedData.GSWDJ);
|
|
marketTemperatureRef.value.initChart(clonedData.GSWDJ, clonedData.KLine20, clonedData.WDRL);
|
|
console.log("股市温度计图表已渲染");
|
|
}
|
|
// 渲染情绪解码器图表
|
|
if (emotionDecodRef.value && clonedData.QXJMQ) {
|
|
console.log("开始渲染情绪解码器图表");
|
|
console.log("情绪解码器数据", clonedData.QXJMQ);
|
|
emotionDecodRef.value.initQXNLZHEcharts(clonedData.KLine20, clonedData.QXJMQ);
|
|
console.log("情绪解码器图表已渲染");
|
|
}
|
|
// 渲染情绪探底雷达图表
|
|
if (emotionalBottomRadarRef.value && clonedData.QXTDLD) {
|
|
console.log("开始渲染情绪探底雷达图表");
|
|
console.log("探底雷达数据", clonedData.QXTDLD);
|
|
emotionalBottomRadarRef.value.initEmotionalBottomRadar(
|
|
clonedData.KLine20,
|
|
clonedData.QXTDLD
|
|
);
|
|
console.log("情绪探底雷达图表已渲染");
|
|
}
|
|
// 渲染情绪能量转化器图表
|
|
if (emoEnergyConverterRef.value && clonedData.QXNLZHQ) {
|
|
console.log("开始渲染情绪能量转化器图表");
|
|
console.log("KLine20:", clonedData.KLine20);
|
|
console.log("QXNLZHQ:", clonedData.QXNLZHQ);
|
|
emoEnergyConverterRef.value.initQXNLZHEcharts(clonedData.KLine20, clonedData.QXNLZHQ);
|
|
console.log("情绪能量转化器图表已渲染");
|
|
}
|
|
} catch (error) {
|
|
console.error('图表渲染过程中发生错误:', error);
|
|
ElMessage.error('图表渲染失败,请重试');
|
|
}
|
|
}, 100); // 100ms延迟确保DOM稳定
|
|
});
|
|
}
|
|
|
|
const scrollToBottom = async () => {
|
|
const container = userInputDisplayRef.value;
|
|
if (!container) return;
|
|
await nextTick();
|
|
console.log(container.scrollHeight, "container.scrollHeight");
|
|
console.log(container.scrollTop, "container.scrollTop");
|
|
console.log(container.offsetHeight, "container.offsetHeight");
|
|
container.scrollTop = container.scrollHeight - container.offsetHeight;
|
|
};
|
|
|
|
|
|
// 检查数据是否已加载完成
|
|
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;
|
|
}
|
|
|
|
// 自动滚动函数
|
|
function startAutoScroll() {
|
|
if (isAutoScrolling.value) return;
|
|
|
|
// 检查数据是否已加载完成
|
|
if (!isDataLoaded()) {
|
|
console.log('数据尚未加载完成,延迟1秒后重试');
|
|
setTimeout(() => {
|
|
startAutoScroll();
|
|
}, 1000);
|
|
return;
|
|
}
|
|
|
|
isAutoScrolling.value = true;
|
|
console.log('开始流畅自动滚动');
|
|
|
|
// 获取页面总高度
|
|
const documentHeight = document.documentElement.scrollHeight;
|
|
const windowHeight = window.innerHeight;
|
|
const maxScrollTop = documentHeight - windowHeight;
|
|
|
|
// 滚动参数
|
|
const scrollDuration = 15000; // 总滚动时间15秒
|
|
const scrollStep = maxScrollTop / (scrollDuration / 50); // 每50ms滚动的距离
|
|
let currentScrollTop = 0;
|
|
|
|
function smoothScroll() {
|
|
if (currentScrollTop < maxScrollTop) {
|
|
currentScrollTop += scrollStep;
|
|
if (currentScrollTop > maxScrollTop) {
|
|
currentScrollTop = maxScrollTop;
|
|
}
|
|
|
|
window.scrollTo({
|
|
top: currentScrollTop,
|
|
behavior: 'auto' // 使用auto而不是smooth,因为我们自己控制滚动
|
|
});
|
|
|
|
// 继续滚动
|
|
setTimeout(smoothScroll, 50);
|
|
} else {
|
|
console.log('流畅自动滚动完成');
|
|
isAutoScrolling.value = false;
|
|
}
|
|
}
|
|
|
|
// 延迟1秒开始滚动
|
|
setTimeout(smoothScroll, 1000);
|
|
}
|
|
|
|
// 设置Intersection Observer监听场景应用部分
|
|
function setupIntersectionObserver() {
|
|
if (!scenarioApplicationRef.value) return;
|
|
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
console.log('场景应用部分进入视口');
|
|
|
|
// 获取当前股票代码
|
|
const stockCode = currentStock.value?.stockInfo?.code || currentStock.value?.stockInfo?.symbol;
|
|
|
|
if (parsedConclusion.value && 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;
|
|
}
|
|
} 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
|
|
};
|
|
}
|
|
}
|
|
}
|
|
});
|
|
},
|
|
{
|
|
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();
|
|
// 移除自动滚动触发,改为在第二个工作流接口调用时触发
|
|
});
|
|
});
|
|
|
|
// 组件卸载时清理定时器、音频和observer
|
|
onUnmounted(() => {
|
|
clearTypewriterTimers();
|
|
stopAudio();
|
|
|
|
// 重置触发状态
|
|
hasTriggeredAudio.value = false;
|
|
hasTriggeredTypewriter.value = false;
|
|
|
|
// 清理Intersection Observer
|
|
if (intersectionObserver.value) {
|
|
intersectionObserver.value.disconnect();
|
|
intersectionObserver.value = null;
|
|
}
|
|
});
|
|
|
|
// 导出方法供外部使用
|
|
defineExpose({
|
|
handleSendMessage,
|
|
triggerAutoScroll
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.container {
|
|
padding-top: 2%;
|
|
}
|
|
|
|
.class003 {
|
|
padding-top: 8%;
|
|
padding-left: 10%;
|
|
}
|
|
|
|
.class003 .div02 {
|
|
background-image: url('@/assets/img/AiEmotion/redBorder.png');
|
|
background-repeat: no-repeat;
|
|
background-size: 100% 100%;
|
|
width: 35%;
|
|
min-height: 40px;
|
|
float: left;
|
|
margin-left: 9%;
|
|
margin-top: 2%;
|
|
text-align: center;
|
|
font-size: 24px;
|
|
color: white;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.class003 .div01 {
|
|
background-image: url('@/assets/img/AiEmotion/blueBorder.png');
|
|
background-repeat: no-repeat;
|
|
background-size: 100% 100%;
|
|
width: 35%;
|
|
min-height: 40px;
|
|
float: left;
|
|
margin-left: 9%;
|
|
text-align: center;
|
|
font-size: 24px;
|
|
color: white;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.golden-wheel {
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.golden-wheel-img {
|
|
width: 60%;
|
|
max-width: 500px;
|
|
height: auto;
|
|
}
|
|
|
|
|
|
|
|
/* 定义旋转动画 */
|
|
@keyframes rotate {
|
|
from {
|
|
transform: rotate(0deg);
|
|
}
|
|
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
/* 应用动画到图片 */
|
|
.rotating-image {
|
|
animation: rotate 5s linear;
|
|
/* 5 秒完成一次旋转,线性速度*/
|
|
will-change: transform;
|
|
/* 优化动画性能 */
|
|
}
|
|
|
|
.bk-image {
|
|
background-image: url("@/assets/img/AiEmotion/bk03.png");
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 95%;
|
|
height: auto;
|
|
margin: 0 auto;
|
|
margin-top: 20px;
|
|
|
|
.conclusion-container {
|
|
padding: 20px;
|
|
border-radius: 15px;
|
|
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);
|
|
backdrop-filter: blur(15px);
|
|
|
|
.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;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, #00d4ff, #0099ff, #00d4ff);
|
|
opacity: 0.8;
|
|
}
|
|
|
|
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.conclusion-title {
|
|
color: #FFD700;
|
|
font-size: 22px;
|
|
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: '';
|
|
position: absolute;
|
|
bottom: -5px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 60px;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, transparent, #00d4ff, transparent);
|
|
}
|
|
}
|
|
|
|
.conclusion-text {
|
|
color: #ffffff;
|
|
font-size: 20px;
|
|
line-height: 1.8;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.conclusion-placeholder {
|
|
padding: 30px;
|
|
text-align: center;
|
|
border-radius: 12px;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border: 1px dashed rgba(153, 153, 153, 0.3);
|
|
|
|
p {
|
|
color: #999999;
|
|
font-size: 16px;
|
|
margin: 0;
|
|
font-style: italic;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 最后文字的颜色 */
|
|
.text-container {
|
|
position: relative;
|
|
color: white;
|
|
text-align: left;
|
|
padding: 20px;
|
|
border-radius: 15px;
|
|
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);
|
|
backdrop-filter: blur(15px);
|
|
}
|
|
|
|
.text-container p {
|
|
margin: 0 auto;
|
|
font-size: 40px;
|
|
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;
|
|
}
|
|
|
|
.text-container p::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, #00d4ff, #0099ff, #00d4ff);
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.text-container .title {
|
|
display: block;
|
|
color: #FFD700;
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
font-size: 22px;
|
|
}
|
|
|
|
.text-container .content {
|
|
display: block;
|
|
color: white;
|
|
font-size: 20px;
|
|
}
|
|
|
|
|
|
|
|
.class07 {
|
|
background-image: url("@/assets/img/AiEmotion/bk03.png");
|
|
/* 使用导入的背景图片 */
|
|
background-size: cover;
|
|
/* 确保背景图片完整显示 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
width: 95%;
|
|
/* 设置容器宽度 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
min-height: 70rem;
|
|
/* 设置最小高度,确保图片显示 */
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.class0700 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
margin-top: 2%;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
.class0702 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
margin-top: 2%;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
.class0402 {
|
|
width: 80%;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
|
|
.class0603 {
|
|
min-width: 100%;
|
|
margin-top: 3%;
|
|
}
|
|
|
|
.class0502 {
|
|
padding-top: 7%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 竖向排列元素 */
|
|
gap: 1rem;
|
|
margin-left: 2rem;
|
|
}
|
|
|
|
.class0601 {
|
|
padding-top: 5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 竖向排列元素 */
|
|
gap: 1rem;
|
|
margin-left: 2rem;
|
|
}
|
|
|
|
.img03 {
|
|
width: 10%;
|
|
height: auto;
|
|
margin-left: 43%;
|
|
}
|
|
|
|
.img04 {
|
|
width: 10%;
|
|
height: auto;
|
|
margin-left: 43%;
|
|
}
|
|
|
|
.class0701 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
}
|
|
|
|
.class0501 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
margin-top: 2%;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
.class0403 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
margin-top: 2%;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
.class0301 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
margin-top: 2%;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
.class0201 {
|
|
margin: 0 auto;
|
|
width: fit-content;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
.class0401 {
|
|
padding-top: 5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 竖向排列元素 */
|
|
gap: 1rem;
|
|
margin-left: 2rem;
|
|
}
|
|
|
|
.img02 {
|
|
width: 10%;
|
|
height: auto;
|
|
margin-left: 43%;
|
|
}
|
|
|
|
.title2 {
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-left: 44%;
|
|
}
|
|
|
|
.title3 {
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-left: 43%;
|
|
}
|
|
|
|
.title4 {
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-left: 41.5%;
|
|
}
|
|
|
|
.class09 {
|
|
text-align: center;
|
|
margin-top: 2%;
|
|
margin-bottom: 1%;
|
|
}
|
|
|
|
/* 为需要放大的图片添加样式 */
|
|
.scaled-img {
|
|
background-image: url('@/assets/img/AiEmotion/tree02.jpg');
|
|
background-size: 100% 100%;
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
width: 70%;
|
|
height: 400px;
|
|
min-height: 400px;
|
|
text-align: center;
|
|
margin: 0 auto;
|
|
margin-top: 3%;
|
|
}
|
|
|
|
.lz-img {
|
|
text-align: center;
|
|
padding-top: 70px;
|
|
}
|
|
|
|
.class08 {
|
|
background-image: url("@/assets/img/AiEmotion/bk03.png");
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 95%;
|
|
height: auto;
|
|
min-height: 40rem;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.class06 {
|
|
background-image: url('@/assets/img/AiEmotion/bk03.png');
|
|
/* 使用导入的背景图片 */
|
|
background-size: 100% 100%;
|
|
/* 确保背景图片完整显示 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
width: 95%;
|
|
/* 设置容器宽度 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
min-height: 66rem;
|
|
/* 设置最小高度,确保图片显示 */
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.class05 {
|
|
background-image: url("@/assets/img/AiEmotion/bk03.png");
|
|
/* 使用导入的背景图片 */
|
|
background-size: 100% 100%;
|
|
/* 确保背景图片完整显示 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
width: 95%;
|
|
/* 设置容器宽度 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
min-height: 86rem;
|
|
/* 设置最小高度,确保图片显示 */
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.class04 {
|
|
background-image: url('@/assets/img/AiEmotion/bk03.png');
|
|
/* 使用导入的背景图片 */
|
|
background-size: 100% 100%;
|
|
/* 确保背景图片完整显示 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
width: 95%;
|
|
/* 设置容器宽度 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
min-height: 75rem;
|
|
/* 设置最小高度,确保图片显示 */
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.class03 {
|
|
background-image: url('@/assets/img/AiEmotion/bk03.png');
|
|
/* 使用导入的背景图片 */
|
|
background-size: 100% 100%;
|
|
/* 确保背景图片完整显示 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
width: 100%;
|
|
/* 设置容器宽度 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
min-height: 70rem;
|
|
/* 设置最小高度,确保图片显示 */
|
|
margin: 0 auto;
|
|
/* display: flex;
|
|
flex-direction:row;
|
|
align-items: center;
|
|
padding: 1rem;
|
|
gap: 1rem; */
|
|
}
|
|
|
|
.class00 {
|
|
background-size: 100% 100%;
|
|
/* 确保背景图片完整显示 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
width: 95%;
|
|
/* 设置容器宽度 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
min-height: 55rem;
|
|
/* 设置最小高度,确保图片显示 */
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.content1 {
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 竖向排列元素 */
|
|
gap: 1rem;
|
|
margin-left: 10%;
|
|
}
|
|
|
|
.title1 {
|
|
color: white;
|
|
font-size: 30px;
|
|
font-weight: bold;
|
|
margin-left: 0%;
|
|
|
|
}
|
|
|
|
.img01 {
|
|
width: 10%;
|
|
height: auto;
|
|
}
|
|
|
|
.div00 {
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 竖向排列元素 */
|
|
margin-left: 37%;
|
|
gap: 1rem;
|
|
margin-top: -12%;
|
|
width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
.span02 {
|
|
font-size: 1.5rem;
|
|
color: white;
|
|
float: right;
|
|
margin-top: -2%;
|
|
}
|
|
|
|
.span01 {
|
|
background-image: url('@/assets/img/AiEmotion/bk01.png');
|
|
/* 使用导入的背景图片 */
|
|
background-size: 100% 100%;
|
|
/* 背景图片覆盖整个容器 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
/* display: inline-block; */
|
|
/* 确保容器是块级元素 */
|
|
padding: 10px;
|
|
/* 添加内边距以显示内容 */
|
|
color: #fff;
|
|
/* 设置文字颜色以确保可读性 */
|
|
font-size: 1.5rem;
|
|
/* 增加字体大小以便更清晰显示股票名称 */
|
|
text-align: center;
|
|
/* transform: translate(-50%, -50%); */
|
|
margin-left: 0;
|
|
width: 30%;
|
|
height: auto;
|
|
}
|
|
|
|
.class01 {
|
|
width: 100%;
|
|
/* 固定容器宽度 */
|
|
min-height: 100px;
|
|
/* 设置最小高度,确保初始显示 */
|
|
height: auto;
|
|
/* 高度根据内容动态变化 */
|
|
/* 添加内边距,确保内容与边界有间距 */
|
|
box-sizing: border-box;
|
|
/* 包括内边距在宽度和高度计算中 */
|
|
background-color: #02107d;
|
|
margin: 0 auto;
|
|
/* 居中容器 */
|
|
margin-bottom: 10rem;
|
|
}
|
|
|
|
.ai-emotion-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 20px;
|
|
position: relative;
|
|
}
|
|
|
|
.user-input-display {
|
|
margin-top: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
}
|
|
|
|
.message-container {
|
|
display: flex;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.user-message {
|
|
background-color: #007bff;
|
|
color: #fff;
|
|
padding: 10px 15px;
|
|
border-radius: 15px;
|
|
max-width: 60%;
|
|
text-align: left;
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
align-self: flex-end;
|
|
}
|
|
|
|
.ai-message {
|
|
background-color: #f1f1f1;
|
|
color: #333;
|
|
padding: 10px 15px;
|
|
border-radius: 15px;
|
|
max-width: 60%;
|
|
text-align: left;
|
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
align-self: flex-start;
|
|
}
|
|
|
|
.input-container {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.fixed-bottom {
|
|
position: fixed;
|
|
bottom: 100px;
|
|
left: 0;
|
|
width: 100%;
|
|
background-color: #f8f9fa;
|
|
padding: 10px 20px;
|
|
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.input-box {
|
|
padding: 10px;
|
|
font-size: 16px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 5px;
|
|
width: calc(100% - 120px);
|
|
}
|
|
|
|
.send-button {
|
|
padding: 10px 20px;
|
|
font-size: 16px;
|
|
color: #fff;
|
|
background-color: #007bff;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.send-button:hover {
|
|
background-color: #0056b3;
|
|
}
|
|
|
|
/* 手机端适配样式 */
|
|
@media only screen and (max-width: 768px) {
|
|
.container {
|
|
padding-top: 2%;
|
|
}
|
|
|
|
.title4 {
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-left: 28%;
|
|
}
|
|
|
|
.class0603 {
|
|
min-width: 100%;
|
|
margin-top: 25%;
|
|
}
|
|
|
|
.scaled-img {
|
|
background-image: url('@/assets/img/AiEmotion/tree02.jpg');
|
|
background-size: 100% 100%;
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
text-align: center;
|
|
width: 95%;
|
|
margin-top: 6%;
|
|
height: 200px;
|
|
min-height: 200px;
|
|
}
|
|
|
|
.title3 {
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-left: 30%;
|
|
}
|
|
|
|
.title2 {
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-left: 30%;
|
|
}
|
|
|
|
/* 图片样式 */
|
|
.golden-wheel img {
|
|
width: 100%;
|
|
}
|
|
|
|
.class0201 img {
|
|
width: 100%;
|
|
}
|
|
|
|
.class0301 img {
|
|
width: 100%;
|
|
margin: 10px 10px;
|
|
}
|
|
|
|
.class0403 img {
|
|
width: 100%;
|
|
margin: 10px 10px;
|
|
}
|
|
|
|
.class0501 img {
|
|
width: 100%;
|
|
margin: 10px 10px;
|
|
}
|
|
|
|
.class0702 img {
|
|
width: 100%;
|
|
margin: 10px 10px;
|
|
}
|
|
|
|
.class0700 img {
|
|
width: 100%;
|
|
margin: 10px 10px;
|
|
}
|
|
|
|
.scaled-img img {
|
|
width: 30%;
|
|
height: auto;
|
|
}
|
|
|
|
.class09 img {
|
|
width: 100%;
|
|
margin: 10px 10px;
|
|
}
|
|
|
|
.img01 {
|
|
height: auto;
|
|
margin-left: 7%;
|
|
width: 25%;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.title1 {
|
|
font-size: 20px;
|
|
margin-left: 5%;
|
|
}
|
|
|
|
.class02 .span02 {
|
|
font-size: 14px;
|
|
color: white;
|
|
float: right;
|
|
margin-top: -6%;
|
|
}
|
|
|
|
.class03 {
|
|
background-image: url('@/assets/img/AiEmotion/bk03.png');
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 100%;
|
|
/* margin-left: -45px; */
|
|
height: auto;
|
|
}
|
|
|
|
.class03 .class003 {
|
|
padding-top: 3rem;
|
|
padding-left: 0rem;
|
|
}
|
|
|
|
.class01 {
|
|
min-height: 100px;
|
|
height: auto;
|
|
box-sizing: border-box;
|
|
background-color: #02107d;
|
|
margin-bottom: 10rem;
|
|
}
|
|
|
|
.class04 {
|
|
width: 100%;
|
|
height: auto;
|
|
min-height: 38rem;
|
|
/* min-height: 51rem; */
|
|
/* margin-left: -39px; */
|
|
/* min-height: 38rem; */
|
|
}
|
|
|
|
.class02 .container img {
|
|
width: 68%;
|
|
height: auto;
|
|
/* margin-top: 5%; */
|
|
margin-left: 0%;
|
|
}
|
|
|
|
.img02 {
|
|
width: 25%;
|
|
height: auto;
|
|
margin-left: 32%;
|
|
}
|
|
|
|
.class0401 {
|
|
padding-top: 3rem;
|
|
}
|
|
|
|
.img03,
|
|
.img04 {
|
|
width: 25%;
|
|
height: auto;
|
|
margin-left: 33%;
|
|
}
|
|
|
|
.text-container p {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.lz-img {
|
|
margin-bottom: 0;
|
|
padding-top: 0;
|
|
|
|
img {
|
|
width: 30%;
|
|
height: auto;
|
|
margin-top: 5%;
|
|
}
|
|
}
|
|
|
|
.class08 {
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 100%;
|
|
height: auto;
|
|
min-height: 20rem;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.bk-image {
|
|
.conclusion-container {
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
margin: 8px;
|
|
|
|
.conclusion-item {
|
|
margin-bottom: 15px;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.conclusion-title {
|
|
color: #FFD700;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
margin: 0 0 8px 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.conclusion-text {
|
|
color: #ffffff;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
margin: 0 0 6px 0;
|
|
text-align: left;
|
|
word-wrap: break-word;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.conclusion-placeholder {
|
|
padding: 15px;
|
|
text-align: center;
|
|
|
|
p {
|
|
color: #999999;
|
|
font-size: 12px;
|
|
margin: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
.bk-image {
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 100%;
|
|
height: auto;
|
|
margin: 0 auto;
|
|
margin-top: 0px;
|
|
margin-left: 0;
|
|
|
|
.conclusion-container {
|
|
padding: 20px;
|
|
border-radius: 15px;
|
|
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);
|
|
backdrop-filter: blur(15px);
|
|
|
|
.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;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, #00d4ff, #0099ff, #00d4ff);
|
|
opacity: 0.8;
|
|
}
|
|
|
|
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.conclusion-title {
|
|
color: #FFD700;
|
|
font-size: 22px;
|
|
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: '';
|
|
position: absolute;
|
|
bottom: -5px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 60px;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, transparent, #00d4ff, transparent);
|
|
}
|
|
}
|
|
|
|
.conclusion-text {
|
|
color: #ffffff;
|
|
font-size: 20px;
|
|
line-height: 1.8;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.conclusion-placeholder {
|
|
padding: 30px;
|
|
text-align: center;
|
|
border-radius: 12px;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border: 1px dashed rgba(153, 153, 153, 0.3);
|
|
|
|
p {
|
|
color: #999999;
|
|
font-size: 16px;
|
|
margin: 0;
|
|
font-style: italic;
|
|
}
|
|
}
|
|
|
|
.disclaimer-item {
|
|
margin-top: 30px;
|
|
padding: 20px;
|
|
border-top: 1px solid rgba(153, 153, 153, 0.2);
|
|
text-align: center;
|
|
|
|
.disclaimer-text {
|
|
color: #999999;
|
|
font-size: 14px;
|
|
margin: 0;
|
|
font-style: italic;
|
|
opacity: 0.8;
|
|
letter-spacing: 1px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.class05 {
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 100%;
|
|
height: auto;
|
|
min-height: 48rem;
|
|
}
|
|
|
|
.class06 {
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: 100%;
|
|
height: auto;
|
|
min-height: 35rem;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.text-container {
|
|
position: relative;
|
|
top: 0;
|
|
left: 0;
|
|
color: white;
|
|
text-align: left;
|
|
padding: 5%;
|
|
}
|
|
|
|
.div00 {
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-left: 5rem;
|
|
gap: 0;
|
|
margin-top: -6rem;
|
|
width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
.class003 .div01 {
|
|
background-repeat: no-repeat;
|
|
background-size: 100% 100%;
|
|
width: 35%;
|
|
min-height: 25px;
|
|
float: left;
|
|
margin-left: 100px;
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
font-size: 10px;
|
|
color: white;
|
|
}
|
|
|
|
.class003 .div02 {
|
|
background-repeat: no-repeat;
|
|
background-size: 100% 100%;
|
|
width: 35%;
|
|
min-height: 25px;
|
|
float: left;
|
|
margin-left: 100px;
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
font-size: 10px;
|
|
color: white;
|
|
}
|
|
|
|
.span01 {
|
|
/* 使用导入的背景图片 */
|
|
background-image: url('@/assets/img/AiEmotion/bk01.png');
|
|
background-size: 100% 100%;
|
|
/* 背景图片覆盖整个容器 */
|
|
background-repeat: no-repeat;
|
|
/* 防止背景图片重复 */
|
|
display: inline-block;
|
|
/* 确保容器是块级元素 */
|
|
padding: 10px;
|
|
/* 添加内边距以显示内容 */
|
|
color: #fff;
|
|
/* 设置文字颜色以确保可读性 */
|
|
font-size: 14px;
|
|
/* 增加字体大小以便更清晰显示股票名称 */
|
|
text-align: center;
|
|
width: 50%;
|
|
}
|
|
|
|
.class0502,
|
|
.class0601 {
|
|
padding-top: 10%;
|
|
}
|
|
}
|
|
|
|
/* 加载提示样式 */
|
|
.loading-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
min-height: 60vh;
|
|
padding: 40px 20px;
|
|
}
|
|
|
|
.loading-content {
|
|
text-align: center;
|
|
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);
|
|
border-radius: 20px;
|
|
padding: 40px;
|
|
backdrop-filter: blur(15px);
|
|
box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3);
|
|
}
|
|
|
|
.loading-spinner {
|
|
width: 60px;
|
|
height: 60px;
|
|
border: 4px solid rgba(0, 212, 255, 0.3);
|
|
border-top: 4px solid #00d4ff;
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin: 0 auto 20px;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% {
|
|
transform: rotate(0deg);
|
|
}
|
|
|
|
100% {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
.loading-text {
|
|
color: #00d4ff;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
text-shadow: 0 2px 8px rgba(0, 212, 255, 0.5);
|
|
letter-spacing: 1px;
|
|
}
|
|
</style>
|