|
|
<template> <div class="ai-emotion-container"> <!-- 金轮 --> <div class="golden-wheel"> <img src="@/assets/img/AiEmotion/金轮.png" alt="金轮图标" :class="{ 'rotating-image': isRotating }"> </div> <!-- 消息显示区域 --> <div class="user-input-display" ref="userInputDisplayRef"> <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> <!-- 输入框和发送按钮 --> <!-- <footer class="input-container fixed-bottom"> <input type="text" v-model="userInput" placeholder="请输入内容..." class="input-box" /> <button @click="handleSendMessage(userInput)" class="send-button">发送</button> </footer> --> <!-- <div class="input-container fixed-bottom"> <input type="text" v-model="userInput" placeholder="请输入内容..." class="input-box" /> <button @click="sendMessage" class="send-button">发送</button> </div> --> </div>
<!-- 渲染整个页面 --> <div v-if="isPageLoaded" class="class01"> <div class="class00"> <!-- 四维矩阵图 --> <div class="class02"> <div class="span01"> {{ stockName }}{{ stockName ? '量子四维矩阵图' : '' }} </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" style="padding-top: 7rem;padding-left: 12rem;"> <img src="@/assets/img/AiEmotion/温度计.png" alt="温度计图标" style="float: left;padding-left: 5rem;"> <div class="div00"> <div class="div01">galg</div> <div class="div02">hkjkl</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 src='@/assets/img/AiEmotion/emotionDecod.png' alt="情绪解码器图标"> </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 src="@/assets/img/AiEmotion/探底雷达.png" alt="探底雷达图表"> </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 src="@/assets/img/AiEmotion/能量转化器.png" alt="能量转化器图标"> </div> <emoEnergyConverter ref="emoEnergyConverterRef"></emoEnergyConverter> </div> <!-- 核心看点 --> <div class="class0702"> <img src="@/assets/img/AiEmotion/核心看点.png" alt="核心看点字样"> </div> <div class="bk-image"> <div class="text-container"> <p>情绪监控-金融宇宙的【量子检测网络】核心任务:构建全市场情绪引力场雷达</p> <p>情绪解码-主力思维的【神经破译矩阵】核心任务:解构资金行为的量子密码</p> <p>情绪推演-未来战争的【时空推演舱】核心任务:情绪推演</p> <p>情绪套利-财富裂变的【粒子对撞机】核心任务:将情绪差转化为a收益粒子流</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.png" alt="树图片"> </div> </div> <!-- 场景应用 --> <div class="class09"> <img src="@/assets/img/AiEmotion/场景应用.png" alt="场景应用标题"> <div class="bk-image"> <!-- <div class="text-container"> <p>情绪监控-金融宇宙的【量子检测网络】核心任务:构建全市场情绪引力场雷达</p> <p>情绪解码-主力思维的【神经破译矩阵】核心任务:解构资金行为的量子密码</p> <p>情绪推演-未来战争的【时空推演舱】核心任务:情绪推演</p> <p>情绪套利-财富裂变的【粒子对撞机】核心任务:将情绪差转化为a收益粒子流</p> </div> --> </div> </div> </div> <!-- <div v-else class="loading"> <p>数据加载中,请稍候...</p> </div> --> </template>
<script setup> import { ref, reactive } from 'vue'; import { getReplyAPI } from '@/api/AiEmotionApi.js'; // 导入工作流接口方法
import axios from 'axios'; 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 blueBorderImg from '@/assets/img/AiEmotion/blueBorder.png' //导入蓝色背景框图片
const stockName = ref(''); // 存储股票名称
const marketTemperatureRef = ref(null); // 引用市场温度计组件
const emoEnergyConverterRef = ref(null) const emotionDecodRef = ref(null) const emotionalBottomRadarRef = ref(null) const userInput = ref(''); const messages = ref([]); const displayDate = ref(''); // 用于存储显示的日期
const isPageLoaded = ref(false); // 控制页面是否显示
const isRotating = ref(false);//控制旋转
const userInputDisplayRef = ref(null);//消息区域的引用
//导出方法供外部使用
defineExpose({handleSendMessage})
// 从本地存储中加载对话历史的方法
const loadMessagesFromLocalStorage = () => { const storedMessages = localStorage.getItem('chatMessages'); if (storedMessages) { messages.value = JSON.parse(storedMessages); } };
// 将对话历史保存到本地存储的方法
const saveMessagesToLocalStorage = () => { localStorage.setItem('chatMessages', JSON.stringify(messages.value)); };
// 触发图片旋转的方法
function startImageRotation() { isRotating.value = true; // 如果你想在一段时间后停止旋转,可以添加以下代码
setTimeout(() => { isRotating.value = false; }, 5000); // 5 秒后停止旋转
} // 更新 span01 中股票名字的方法
function updateSpan01() { nextTick(() => { const span01 = document.querySelector('.span01'); if (span01) { span01.textContent = `${stockName.value}量子四维矩阵图`; } }); }
// 发送消息方法
async function handleSendMessage(input) { console.log('发送内容:', input);
// 检查用户输入内容是否为空
if (input.trim()) { const userMessage = reactive({ sender: 'user', text: input }); messages.value.push(userMessage); userInput.value = ''; // 清空输入框
// 添加等待提示信息
messages.value.push({ sender: 'ai', text: '数据加载中,请稍候...' });
// 滚动到最新消息
nextTick(() => { if (userInputDisplayRef.value) { userInputDisplayRef.value.scrollTop = userInputDisplayRef.value.scrollHeight; } });
// 触发图片旋转
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);
// 更新股票名称
stockName.value = parsedData.name || '未知股票'; // 请求数据接口
fetchData(parsedData.code, parsedData.market);
// 更新 span01 的内容
updateSpan01(); } else { console.error('工作流接口返回非股票信息:', parsedData.refuse); messages.value.push({ sender: 'ai', text: `工作流接口返回信息: ${parsedData.refuse || '未知错误'}`, }); } } catch (error) { console.error('请求工作流接口失败:', error); messages.value.push({ sender: 'ai', text: '工作流接口请求失败,请稍后再试。', }); } finally { // 停止图片旋转
isRotating.value = false;
// 保存对话历史到本地存储
saveMessagesToLocalStorage(); } } else { messages.value.push({ sender: 'ai', text: '请输入内容后再发送。', });
// 滚动到最新消息
nextTick(() => { if (userInputDisplayRef.value) { userInputDisplayRef.value.scrollTop = userInputDisplayRef.value.scrollHeight; } }); } } const version1 = ref(2); // 版本号
// 请求数据接口
async function fetchData(code, market) { try { const stockDataParams = { // token: '+XgqsgdW0RLIbIG2pxnnbZi0+fEeMx8pywnIlrmTxtkSaPZ9xjSOWrxq+s0rL3RrfNhXPvGtz9srFfjwu8A',
token: '9ior41AF0xTIbIG2pRnnbZi0+fEeMx8pywnIlrmTwo5FbqJ9lWrSWOxp9MkpKiNtedtUafqvzIwpFKrwuMs', market: 'usa', code: 'TSLA', 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) { messages.value.push({ sender: 'ai', text: `股票数据已成功获取`, });
// 滚动到最新消息
nextTick(() => { if (userInputDisplayRef.value) { userInputDisplayRef.value.scrollTop = userInputDisplayRef.value.scrollHeight; } }); console.log('1111111111111111111111') // 调用渲染图表的方法
renderCharts(stockDataResponse.data); console.log('2222222222222222222222') // 设置当天日期
const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, '0'); const day = String(today.getDate()).padStart(2, '0'); displayDate.value = `${year}/${month}/${day}`;
// 数据和图表加载完成,显示页面
isPageLoaded.value = true; } else { messages.value.push({ sender: 'ai', text: '图表数据接口返回数据不完整,请稍后再试。', }); // 滚动到最新消息
nextTick(() => { if (userInputDisplayRef.value) { userInputDisplayRef.value.scrollTop = userInputDisplayRef.value.scrollHeight; } }); } } catch (error) { messages.value.push({ sender: 'ai', text: '图表数据接口请求失败,请稍后再试。', }); } }
// 渲染组件图表的方法
function renderCharts(data) { nextTick(() => { // 渲染股市温度计图表
if (marketTemperatureRef.value && data.GSWDJ) { console.log('开始渲染股市温度计图表'); console.log('股市温度计数据', data.GSWDJ) marketTemperatureRef.value.initChart(data.GSWDJ, data.KLine20, data.WDRL); console.log('股市温度计图表已渲染'); } // 渲染情绪解码器图表
if (emotionDecodRef.value && data.QXJMQ) { console.log('开始渲染情绪解码器图表'); console.log('情绪解码器数据', data.QXJMQ) emotionDecodRef.value.initQXNLZHEcharts(data.KLine20, data.QXJMQ); console.log('情绪解码器图表已渲染'); } // 渲染情绪探底雷达图表
if (emotionalBottomRadarRef.value && data.QXTDLD) { console.log('开始渲染情绪探底雷达图表'); console.log('数据', data.QXTDLD) emotionalBottomRadarRef.value.initEmotionalBottomRadar(data.KLine20, data.QXTDLD); console.log('情绪探底雷达图表已渲染'); } // 渲染情绪能量转化器图表
if (emoEnergyConverterRef.value && data.QXNLZHQ) { console.log('开始渲染情绪能量转化器图表'); console.log('KLine20:', data.KLine20); console.log('QXNLZHQ:', data.QXNLZHQ); emoEnergyConverterRef.value.initQXNLZHEcharts(data.KLine20, data.QXNLZHQ); console.log('情绪能量转化器图表已渲染'); }
}); }
// 页面挂载完成后触发图片旋转
onMounted(() => { startImageRotation(); loadMessagesFromLocalStorage();//加载历史对话
});
</script>
<style scoped>
.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: 100px; margin-top: 30px; text-align: center; font-size: 24px; color: white; } .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: 100px; text-align: center; margin-top: 10px; font-size: 24px; color: white; } /* 定义旋转动画 */ @keyframes rotate { from { transform: rotate(0deg); }
to { transform: rotate(360deg); } }
/* 应用动画到图片 */ .rotating-image { animation: rotate 5s linear; /* 5 秒完成一次旋转,线性速度*/ }
.bk-image { background-image: url('@/assets/img/AiEmotion/bk03.png'); background-size: 100% 100%; /* background-position: center; */ background-repeat: no-repeat; width: 95%; height: 30rem; margin: 0 auto; margin-top: 20px; }
/* 最后文字的颜色 */ .text-container { position: relative; top: 40%; left: 50%; transform: translate(-50%, -50%); color: white; /* 设置文字颜色 */ text-align: left; /* 文字居中对齐 */ padding: 20px; }
.text-container p { margin: 10px 0; /* 设置段落间距 */ font-size: 40px; /* 设置字体大小 */ margin-left: 50px; }
.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; }
.class0702 { margin: 0 auto; width: fit-content; }
.class0503 { width: 80%; margin: 0 auto;
}
.class0402 { width: 80%; margin: 0 auto; }
.class0601 { padding-top: 10rem; text-align: center; }
.class0502 { padding-top: 10rem; text-align: center; }
.class0701 { margin: 0 auto; width: fit-content; }
.class0501 { margin: 0 auto; width: fit-content; }
.class0403 { margin: 0 auto; width: fit-content; }
.class0301 { margin: 0 auto; width: fit-content; }
.class0201 { margin: 0 auto; width: fit-content; }
.class0401 { padding-top: 10rem; text-align: center; }
.class09 { text-align: center; }
/* 为需要放大的图片添加样式 */ .scaled-img { transform: scale(2.5); text-align: center; }
.lz-img { margin-bottom: 10rem; 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: 70rem; /* 设置最小高度,确保图片显示 */ 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: 70rem; /* 设置最小高度,确保图片显示 */ 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: 55rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; }
.class03 { background-image: url('@/assets/img/AiEmotion/bk03.png'); /* 使用导入的背景图片 */ background-size: 100% 100%; /* 确保背景图片完整显示 */ background-repeat: no-repeat; /* 防止背景图片重复 */ width: 95%; /* 设置容器宽度 */ height: auto; /* 高度根据内容动态变化 */ min-height: 70rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; } .class00{ background-size: 100% 100%; /* 确保背景图片完整显示 */ background-repeat: no-repeat; /* 防止背景图片重复 */ width: 95%; /* 设置容器宽度 */ height: auto; /* 高度根据内容动态变化 */ min-height: 55rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; }
.span02 { font-size: 1.5rem; color: white; float: right; }
.span01 { background-image: url('@/assets/img/AiEmotion/bk01.png'); /* 使用导入的背景图片 */ background-size: cover; /* 背景图片覆盖整个容器 */ background-repeat: no-repeat; /* 防止背景图片重复 */ display: inline-block; /* 确保容器是块级元素 */ padding: 10px; /* 添加内边距以显示内容 */ color: #fff; /* 设置文字颜色以确保可读性 */ border-radius: 5px; /* 添加圆角 */ min-height: 3rem; min-width: 30rem; font-size: 1.5rem; /* 增加字体大小以便更清晰显示股票名称 */ text-align: center; /* 文字居中 */ }
.class01 { width: 90%; /* 固定容器宽度 */ min-height: 100px; /* 设置最小高度,确保初始显示 */ height: auto; /* 高度根据内容动态变化 */ padding: 40px; /* 添加内边距,确保内容与边界有间距 */ box-sizing: border-box; /* 包括内边距在宽度和高度计算中 */ background-color: #5e81a7; 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; } </style>
|