|
|
@ -30,7 +30,18 @@ |
|
|
|
<div class="ai-message-container"> |
|
|
|
<img v-if="message.gif" :src="message.gif" alt="思考过程" class="thinking-gif" /> |
|
|
|
<div class="message-bubble ai-message"> |
|
|
|
{{ message.text }} |
|
|
|
<div v-if="message.flag"> |
|
|
|
<span>{{ message.text }}</span> |
|
|
|
<span class="loading-dots"> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
<span class="dot">.</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<div v-else>{{ message.text }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -49,8 +60,9 @@ |
|
|
|
|
|
|
|
<!-- main容器区域 --> |
|
|
|
<!-- 移除股票标签页,改为对话形式展示 --> |
|
|
|
<!-- 渲染整个页面 - 遍历stockList显示所有股票 --> |
|
|
|
<div class="master" v-for="(stock, stockIndex) in emotionStore.stockList" :key="`stock-${stockIndex}-${stock.timestamp}`" v-if="isPageLoaded"> |
|
|
|
|
|
|
|
<!-- 渲染整个页面 - 遍历过滤后的股票列表显示所有股票 --> |
|
|
|
<div class="master" v-for="(stock, stockIndex) in filteredStockList" :key="`stock-${stockIndex}-${stock.timestamp}`" v-if="isPageLoaded"> |
|
|
|
<!-- 对应股票的消息显示区域 --> |
|
|
|
<div class="user-input-display"> |
|
|
|
<div class="message-container"> |
|
|
@ -675,6 +687,20 @@ const parsedConclusion = computed(() => { |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 多股票数据显示的计算属性 |
|
|
|
// 过滤和排序后的股票列表 |
|
|
|
const filteredStockList = computed(() => { |
|
|
|
return emotionStore.stockList |
|
|
|
.filter(stock => { |
|
|
|
// 过滤掉数据不完整的股票 |
|
|
|
return stock.stockInfo?.name && stock.apiData && stock.queryText; |
|
|
|
}) |
|
|
|
.sort((a, b) => { |
|
|
|
// 按时间戳降序排序,最新的在前 |
|
|
|
return new Date(a.timestamp) - new Date(b.timestamp); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
// 辅助函数:获取股票的显示日期 |
|
|
|
const getDisplayDate = (stock) => { |
|
|
|
if (!stock?.apiData) return ""; |
|
|
@ -1630,8 +1656,9 @@ async function showThinkingProcess(stockName = null) { |
|
|
|
// 第一步:正在思考 |
|
|
|
const thinkingMessage1 = reactive({ |
|
|
|
sender: 'ai', |
|
|
|
text: 'AI情绪大模型正在思考......', |
|
|
|
gif: thinkingGif |
|
|
|
text: 'AI情绪大模型正在思考', |
|
|
|
gif: thinkingGif, |
|
|
|
flag: true // 添加flag属性以显示动态加载点 |
|
|
|
}); |
|
|
|
messages.value.push(thinkingMessage1); |
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500)); |
|
|
@ -1640,8 +1667,9 @@ async function showThinkingProcess(stockName = null) { |
|
|
|
// 第二步:正在解析关键数据(持续显示直到获取到股票名称) |
|
|
|
const thinkingMessage2 = reactive({ |
|
|
|
sender: 'ai', |
|
|
|
text: 'AI情绪大模型正在解析关键数据......', |
|
|
|
gif: analyzeGif |
|
|
|
text: '正在解析关键数据', |
|
|
|
gif: analyzeGif, |
|
|
|
flag: true // 添加flag属性以显示动态加载点 |
|
|
|
}); |
|
|
|
messages.value.push(thinkingMessage2); |
|
|
|
|
|
|
@ -1657,8 +1685,9 @@ async function showThinkingProcess(stockName = null) { |
|
|
|
// 第三步:生成具体股票的量子四维矩阵图 |
|
|
|
const thinkingMessage3 = reactive({ |
|
|
|
sender: 'ai', |
|
|
|
text: `AI情绪大模型正在生成${stockName}量子四维矩阵图......`, |
|
|
|
gif: generateGif |
|
|
|
text: `正在生成${stockName}量子四维矩阵图`, |
|
|
|
gif: generateGif, |
|
|
|
flag: true // 添加flag属性以显示动态加载点 |
|
|
|
}); |
|
|
|
messages.value.push(thinkingMessage3); |
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500)); |
|
|
@ -1689,8 +1718,9 @@ async function continueThinkingProcess(thinkingMessageRef, stockName) { |
|
|
|
// 第三步:生成具体股票的量子四维矩阵图 |
|
|
|
const thinkingMessage3 = reactive({ |
|
|
|
sender: 'ai', |
|
|
|
text: `正在生成${stockName}量子四维矩阵图......`, |
|
|
|
gif: generateGif |
|
|
|
text: `正在生成${stockName}量子四维矩阵图`, |
|
|
|
gif: generateGif, |
|
|
|
flag: true // 添加flag属性以显示动态加载点 |
|
|
|
}); |
|
|
|
messages.value.push(thinkingMessage3); |
|
|
|
|
|
|
@ -3007,6 +3037,129 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']); |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
|
/* 股票统计概览样式 */ |
|
|
|
.stock-statistics-overview { |
|
|
|
background: rgba(255, 255, 255, 0.95); |
|
|
|
border-radius: 15px; |
|
|
|
padding: 20px; |
|
|
|
margin-bottom: 20px; |
|
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); |
|
|
|
backdrop-filter: blur(10px); |
|
|
|
border: 1px solid rgba(255, 255, 255, 0.2); |
|
|
|
} |
|
|
|
|
|
|
|
.statistics-header { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 15px; |
|
|
|
padding-bottom: 10px; |
|
|
|
border-bottom: 2px solid #f0f0f0; |
|
|
|
} |
|
|
|
|
|
|
|
.statistics-header h3 { |
|
|
|
margin: 0; |
|
|
|
color: #333; |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.stock-count { |
|
|
|
background: linear-gradient(45deg, #667eea, #764ba2); |
|
|
|
color: white; |
|
|
|
padding: 5px 12px; |
|
|
|
border-radius: 20px; |
|
|
|
font-size: 12px; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.statistics-content { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
|
|
gap: 15px; |
|
|
|
margin-bottom: 20px; |
|
|
|
} |
|
|
|
|
|
|
|
.stat-item { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding: 10px 15px; |
|
|
|
background: rgba(102, 126, 234, 0.1); |
|
|
|
border-radius: 8px; |
|
|
|
border-left: 4px solid #667eea; |
|
|
|
} |
|
|
|
|
|
|
|
.stat-label { |
|
|
|
color: #666; |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.stat-value { |
|
|
|
color: #333; |
|
|
|
font-size: 16px; |
|
|
|
font-weight: 600; |
|
|
|
} |
|
|
|
|
|
|
|
.stat-value.hot-temp { |
|
|
|
color: #ff4757; |
|
|
|
} |
|
|
|
|
|
|
|
.stat-value.cold-temp { |
|
|
|
color: #3742fa; |
|
|
|
} |
|
|
|
|
|
|
|
.temperature-distribution { |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
gap: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.distribution-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 8px; |
|
|
|
padding: 8px 12px; |
|
|
|
background: rgba(255, 255, 255, 0.8); |
|
|
|
border-radius: 20px; |
|
|
|
border: 1px solid #e0e0e0; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-level { |
|
|
|
font-size: 12px; |
|
|
|
font-weight: 500; |
|
|
|
padding: 2px 8px; |
|
|
|
border-radius: 10px; |
|
|
|
color: white; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-level.hot { |
|
|
|
background: #ff4757; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-level.warm { |
|
|
|
background: #ff6b35; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-level.normal { |
|
|
|
background: #26de81; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-level.cool { |
|
|
|
background: #45aaf2; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-level.cold { |
|
|
|
background: #3742fa; |
|
|
|
} |
|
|
|
|
|
|
|
.temp-count { |
|
|
|
color: #666; |
|
|
|
font-size: 12px; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.matrix-header { |
|
|
|
width: 100%; |
|
|
|
display: flex; |
|
|
@ -3624,7 +3777,7 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']); |
|
|
|
align-items: flex-start; |
|
|
|
gap: 10px; |
|
|
|
margin-right: auto; |
|
|
|
max-width: 80%; |
|
|
|
/* max-width: 80%; */ |
|
|
|
white-space: normal; |
|
|
|
width: fit-content; |
|
|
|
overflow: visible; |
|
|
@ -3654,18 +3807,62 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 动态加载点样式 */ |
|
|
|
.loading-dots { |
|
|
|
display: inline-block; |
|
|
|
} |
|
|
|
|
|
|
|
.dot { |
|
|
|
opacity: 0.4; |
|
|
|
animation: loading 1.4s infinite; |
|
|
|
} |
|
|
|
|
|
|
|
.dot:nth-child(1) { |
|
|
|
animation-delay: 0s; |
|
|
|
} |
|
|
|
|
|
|
|
.dot:nth-child(2) { |
|
|
|
animation-delay: 0.2s; |
|
|
|
} |
|
|
|
|
|
|
|
.dot:nth-child(3) { |
|
|
|
animation-delay: 0.4s; |
|
|
|
} |
|
|
|
|
|
|
|
.dot:nth-child(4) { |
|
|
|
animation-delay: 0.6s; |
|
|
|
} |
|
|
|
|
|
|
|
.dot:nth-child(5) { |
|
|
|
animation-delay: 0.8s; |
|
|
|
} |
|
|
|
|
|
|
|
.dot:nth-child(6) { |
|
|
|
animation-delay: 1s; |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes loading { |
|
|
|
0%, |
|
|
|
60%, |
|
|
|
100% { |
|
|
|
opacity: 0.4; |
|
|
|
} |
|
|
|
|
|
|
|
30% { |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.ai-message { |
|
|
|
/* background-color: #f1f1f1; */ |
|
|
|
color: #333; |
|
|
|
color: #000000; |
|
|
|
font-weight: bold; |
|
|
|
padding: 20px 30px; |
|
|
|
border-radius: 15px; |
|
|
|
text-align: left; |
|
|
|
margin-right: auto; |
|
|
|
/* 将AI消息保持在左边 */ |
|
|
|
white-space: normal; |
|
|
|
word-wrap: break-word; |
|
|
|
word-break: break-word; |
|
|
|
white-space: nowrap; |
|
|
|
width: fit-content; |
|
|
|
overflow: visible; |
|
|
|
align-items: center; |
|
|
|