|
@ -46,18 +46,17 @@ |
|
|
<div class="loading-text">AI情绪大模型正在努力为您加载,请稍候...</div> |
|
|
<div class="loading-text">AI情绪大模型正在努力为您加载,请稍候...</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<!-- 股票标签页 --> |
|
|
|
|
|
<StockTabs /> |
|
|
|
|
|
<!-- 渲染整个页面 --> |
|
|
|
|
|
<div v-if="isPageLoaded" class="main"> |
|
|
|
|
|
|
|
|
<!-- 移除股票标签页,改为对话形式展示 --> |
|
|
|
|
|
<!-- 渲染整个页面 - 遍历stockList显示所有股票 --> |
|
|
|
|
|
<div v-for="(stock, stockIndex) in emotionStore.stockList" :key="`stock-${stockIndex}-${stock.timestamp}`" v-if="isPageLoaded" class="main"> |
|
|
<div class="main-content-wrapper"> |
|
|
<div class="main-content-wrapper"> |
|
|
<!-- 四维矩阵图 --> |
|
|
<!-- 四维矩阵图 --> |
|
|
<div class="matrix-header"> |
|
|
<div class="matrix-header"> |
|
|
<!-- <img class="item" :src="item" alt="思维矩阵图片" /> --> |
|
|
<!-- <img class="item" :src="item" alt="思维矩阵图片" /> --> |
|
|
<div class="market-temperature-label"> |
|
|
<div class="market-temperature-label"> |
|
|
{{ stockName }}{{ stockName ? '量子四维矩阵图' : '' }} |
|
|
|
|
|
|
|
|
{{ stock.stockInfo.name }}{{ stock.stockInfo.name ? '量子四维矩阵图' : '' }} |
|
|
</div> |
|
|
</div> |
|
|
<div class="market-temperature-value">{{ displayDate }}</div> |
|
|
|
|
|
|
|
|
<div class="market-temperature-value">{{ getDisplayDate(stock) }}</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="market-temperature-icon" v-if="chartVisibility.marketTemperature"> |
|
|
<div class="market-temperature-icon" v-if="chartVisibility.marketTemperature"> |
|
|
<img src="@/assets/img/AiEmotion/L1.png" alt="情绪监控图标"> |
|
|
<img src="@/assets/img/AiEmotion/L1.png" alt="情绪监控图标"> |
|
@ -70,11 +69,11 @@ |
|
|
<span class="matrix-main-title">股市温度计</span> |
|
|
<span class="matrix-main-title">股市温度计</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="temperature-display"> |
|
|
<div class="temperature-display"> |
|
|
<div class="temperature-cold">股票温度:{{ data2 ?? "NA" }}</div> |
|
|
|
|
|
<div class="temperature-hot">市场温度:{{ data1 }}</div> |
|
|
|
|
|
|
|
|
<div class="temperature-cold">股票温度:{{ getStockData2(stock) ?? "NA" }}</div> |
|
|
|
|
|
<div class="temperature-hot">市场温度:{{ getStockData1(stock) }}</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<marketTemperature ref="marketTemperatureRef" :companyName="stockName" :stockCode="stockCode" /> |
|
|
|
|
|
|
|
|
<marketTemperature :ref="el => marketTemperatureRef[stockIndex] = el" :companyName="stock.stockInfo.name" :stockCode="stock.stockInfo.code" /> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="emotion-decoder-icon" v-if="chartVisibility.emotionDecod"> |
|
|
<div class="emotion-decoder-icon" v-if="chartVisibility.emotionDecod"> |
|
@ -87,7 +86,7 @@ |
|
|
<span class="emotion-decoder-text">情绪解码器</span> |
|
|
<span class="emotion-decoder-text">情绪解码器</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="emotion-decoder-content"> |
|
|
<div class="emotion-decoder-content"> |
|
|
<emotionDecod ref="emotionDecodRef"></emotionDecod> |
|
|
|
|
|
|
|
|
<emotionDecod :ref="el => emotionDecodRef[stockIndex] = el"></emotionDecod> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bottom-radar-icon" v-if="chartVisibility.emotionalBottomRadar"> |
|
|
<div class="bottom-radar-icon" v-if="chartVisibility.emotionalBottomRadar"> |
|
@ -100,7 +99,7 @@ |
|
|
<span class="bottom-radar-text">情绪探底雷达</span> |
|
|
<span class="bottom-radar-text">情绪探底雷达</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bottom-radar-content"> |
|
|
<div class="bottom-radar-content"> |
|
|
<emotionalBottomRadar ref="emotionalBottomRadarRef"></emotionalBottomRadar> |
|
|
|
|
|
|
|
|
<emotionalBottomRadar :ref="el => emotionalBottomRadarRef[stockIndex] = el"></emotionalBottomRadar> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="energy-converter-icon" v-if="chartVisibility.emoEnergyConverter"> |
|
|
<div class="energy-converter-icon" v-if="chartVisibility.emoEnergyConverter"> |
|
@ -113,7 +112,7 @@ |
|
|
<span class="energy-converter-text">情绪能量转化器</span> |
|
|
<span class="energy-converter-text">情绪能量转化器</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="energy-converter-content"> |
|
|
<div class="energy-converter-content"> |
|
|
<emoEnergyConverter ref="emoEnergyConverterRef"></emoEnergyConverter> |
|
|
|
|
|
|
|
|
<emoEnergyConverter :ref="el => emoEnergyConverterRef[stockIndex] = el"></emoEnergyConverter> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<!-- 核心看点 --> |
|
|
<!-- 核心看点 --> |
|
@ -152,27 +151,27 @@ |
|
|
<div class="scenario-application-section" ref="scenarioApplicationRef"> |
|
|
<div class="scenario-application-section" ref="scenarioApplicationRef"> |
|
|
<img src="@/assets/img/AiEmotion/场景应用.png" alt="场景应用标题"> |
|
|
<img src="@/assets/img/AiEmotion/场景应用.png" alt="场景应用标题"> |
|
|
<div class="bk-image"> |
|
|
<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 class="conclusion-container" v-if="getStockConclusion(stock)"> |
|
|
|
|
|
<div class="conclusion-item" v-if="(getStockConclusion(stock).one1 || getStockConclusion(stock).one2)"> |
|
|
|
|
|
<h4 class="conclusion-title">L1: 情绪监控</h4> |
|
|
|
|
|
<p class="conclusion-text" v-if="getStockConclusion(stock).one1">{{ getStockConclusion(stock).one1 }}</p> |
|
|
|
|
|
<p class="conclusion-text" v-if="getStockConclusion(stock).one2">{{ getStockConclusion(stock).one2 }}</p> |
|
|
</div> |
|
|
</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 class="conclusion-item" v-if="getStockConclusion(stock).two"> |
|
|
|
|
|
<h4 class="conclusion-title">L2: 情绪解码</h4> |
|
|
|
|
|
<p class="conclusion-text">{{ getStockConclusion(stock).two }}</p> |
|
|
</div> |
|
|
</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 class="conclusion-item" v-if="getStockConclusion(stock).three"> |
|
|
|
|
|
<h4 class="conclusion-title">L3: 情绪推演</h4> |
|
|
|
|
|
<p class="conclusion-text">{{ getStockConclusion(stock).three }}</p> |
|
|
</div> |
|
|
</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 class="conclusion-item" v-if="getStockConclusion(stock).four"> |
|
|
|
|
|
<h4 class="conclusion-title">L4: 情绪套利</h4> |
|
|
|
|
|
<p class="conclusion-text">{{ getStockConclusion(stock).four }}</p> |
|
|
</div> |
|
|
</div> |
|
|
<!-- AI生成内容免责声明 --> |
|
|
<!-- AI生成内容免责声明 --> |
|
|
<div class="disclaimer-item" v-if="parsedConclusion && moduleVisibility.disclaimer"> |
|
|
|
|
|
<p class="disclaimer-text">{{ displayedTexts.disclaimer }}</p> |
|
|
|
|
|
|
|
|
<div class="disclaimer-item" v-if="getStockConclusion(stock)"> |
|
|
|
|
|
<p class="disclaimer-text">该内容由AI生成,请注意甄别</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="conclusion-placeholder" v-else> |
|
|
<div class="conclusion-placeholder" v-else> |
|
@ -271,11 +270,11 @@ function processRefuseMessage(refuseData) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 组件引用 |
|
|
|
|
|
const marketTemperatureRef = ref(null); // 引用市场温度计组件 |
|
|
|
|
|
const emoEnergyConverterRef = ref(null) |
|
|
|
|
|
const emotionDecodRef = ref(null) |
|
|
|
|
|
const emotionalBottomRadarRef = ref(null) |
|
|
|
|
|
|
|
|
// 组件引用 - 修改为数组形式支持多个股票 |
|
|
|
|
|
const marketTemperatureRef = ref([]); // 引用市场温度计组件数组 |
|
|
|
|
|
const emoEnergyConverterRef = ref([]) |
|
|
|
|
|
const emotionDecodRef = ref([]) |
|
|
|
|
|
const emotionalBottomRadarRef = ref([]) |
|
|
const userInputDisplayRef = ref(null);//消息区域的引用 |
|
|
const userInputDisplayRef = ref(null);//消息区域的引用 |
|
|
|
|
|
|
|
|
// 响应式数据 |
|
|
// 响应式数据 |
|
@ -290,10 +289,53 @@ const loadConversationsFromStore = () => { |
|
|
})); |
|
|
})); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 记录已经添加到对话中的股票,避免重复添加 |
|
|
|
|
|
const addedStocks = ref(new Set()); |
|
|
|
|
|
|
|
|
|
|
|
// 从stockList生成对话历史 |
|
|
|
|
|
const loadConversationsFromStockList = () => { |
|
|
|
|
|
// 检查是否有新的股票需要添加到对话中 |
|
|
|
|
|
emotionStore.stockList.forEach(stock => { |
|
|
|
|
|
const stockKey = `${stock.stockInfo.code}_${stock.timestamp}`; |
|
|
|
|
|
|
|
|
|
|
|
// 如果这个股票还没有添加到对话中 |
|
|
|
|
|
if (!addedStocks.value.has(stockKey)) { |
|
|
|
|
|
// 检查messages中是否已经存在相同的用户消息 |
|
|
|
|
|
const existingMessage = messages.value.find(msg => |
|
|
|
|
|
msg.sender === 'user' && msg.text === stock.queryText |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 只有当messages中不存在相同消息时才添加 |
|
|
|
|
|
if (!existingMessage) { |
|
|
|
|
|
// 只添加用户输入消息,不添加AI回复 |
|
|
|
|
|
const userMessage = { |
|
|
|
|
|
sender: 'user', |
|
|
|
|
|
text: stock.queryText |
|
|
|
|
|
}; |
|
|
|
|
|
messages.value.push(userMessage); |
|
|
|
|
|
|
|
|
|
|
|
// 只将用户消息添加到emotion store中(如果store中也不存在) |
|
|
|
|
|
const storeConversations = emotionStore.getConversations(); |
|
|
|
|
|
const existingInStore = storeConversations.find(conv => |
|
|
|
|
|
conv.sender === 'user' && conv.text === stock.queryText |
|
|
|
|
|
); |
|
|
|
|
|
if (!existingInStore) { |
|
|
|
|
|
emotionStore.addConversation(userMessage); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 将这个股票标记为已添加 |
|
|
|
|
|
addedStocks.value.add(stockKey); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// 清空对话记录 |
|
|
// 清空对话记录 |
|
|
const clearConversations = () => { |
|
|
const clearConversations = () => { |
|
|
messages.value = []; |
|
|
messages.value = []; |
|
|
emotionStore.clearConversations(); |
|
|
emotionStore.clearConversations(); |
|
|
|
|
|
// 清空已添加股票的记录 |
|
|
|
|
|
addedStocks.value.clear(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// 暴露清空对话记录的方法给父组件 |
|
|
// 暴露清空对话记录的方法给父组件 |
|
@ -346,10 +388,10 @@ const moduleVisibility = ref({ |
|
|
|
|
|
|
|
|
// 图表组件显示状态 |
|
|
// 图表组件显示状态 |
|
|
const chartVisibility = ref({ |
|
|
const chartVisibility = ref({ |
|
|
marketTemperature: false, |
|
|
|
|
|
emotionDecod: false, |
|
|
|
|
|
emotionalBottomRadar: false, |
|
|
|
|
|
emoEnergyConverter: false |
|
|
|
|
|
|
|
|
marketTemperature: true, |
|
|
|
|
|
emotionDecod: true, |
|
|
|
|
|
emotionalBottomRadar: true, |
|
|
|
|
|
emoEnergyConverter: true |
|
|
}); |
|
|
}); |
|
|
const typewriterTimers = ref([]); |
|
|
const typewriterTimers = ref([]); |
|
|
// 记录每个股票是否已经显示过打字机效果 |
|
|
// 记录每个股票是否已经显示过打字机效果 |
|
@ -410,6 +452,50 @@ const parsedConclusion = computed(() => { |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:获取股票的显示日期 |
|
|
|
|
|
const getDisplayDate = (stock) => { |
|
|
|
|
|
if (!stock?.apiData) return ""; |
|
|
|
|
|
const lastData = stock.apiData.GSWDJ?.at(-1); |
|
|
|
|
|
if (!lastData || !lastData[0]) return ""; |
|
|
|
|
|
|
|
|
|
|
|
const dateStr = lastData[0]; |
|
|
|
|
|
// 假设原格式为 YYYY-MM-DD 或 YYYY/MM/DD |
|
|
|
|
|
const dateMatch = dateStr.match(/(\d{4})[\-\/](\d{1,2})[\-\/](\d{1,2})/); |
|
|
|
|
|
if (dateMatch) { |
|
|
|
|
|
const [, year, month, day] = dateMatch; |
|
|
|
|
|
// 转换为 DD/MM/YYYY 格式 |
|
|
|
|
|
return `更新时间:${day.padStart(2, '0')}/${month.padStart(2, '0')}/${year}`; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果不匹配预期格式,返回原始值 |
|
|
|
|
|
return dateStr; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:获取股票的市场温度数据 |
|
|
|
|
|
const getStockData1 = (stock) => { |
|
|
|
|
|
if (!stock?.apiData) return null; |
|
|
|
|
|
const lastData = stock.apiData.GSWDJ?.at(-1); |
|
|
|
|
|
return lastData ? Math.round(lastData[1]) : null; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:获取股票的股票温度数据 |
|
|
|
|
|
const getStockData2 = (stock) => { |
|
|
|
|
|
if (!stock?.apiData) return null; |
|
|
|
|
|
const lastData = stock.apiData.GSWDJ?.at(-1); |
|
|
|
|
|
return lastData ? Math.round(lastData[2]) : null; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:获取股票的结论数据 |
|
|
|
|
|
const getStockConclusion = (stock) => { |
|
|
|
|
|
if (!stock?.conclusionData) return null; |
|
|
|
|
|
try { |
|
|
|
|
|
return JSON.parse(stock.conclusionData); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('解析股票结论数据失败:', error); |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 监听股票列表变化,当列表为空时隐藏页面数据 |
|
|
// 监听股票列表变化,当列表为空时隐藏页面数据 |
|
@ -429,6 +515,8 @@ watch(() => emotionStore.stockList, (newStockList) => { |
|
|
hasTriggeredTypewriter.value = false; |
|
|
hasTriggeredTypewriter.value = false; |
|
|
stockTypewriterShown.value.clear(); |
|
|
stockTypewriterShown.value.clear(); |
|
|
stockAudioPlayed.value.clear(); |
|
|
stockAudioPlayed.value.clear(); |
|
|
|
|
|
// 清理已添加股票的记录 |
|
|
|
|
|
addedStocks.value.clear(); |
|
|
// 清理显示的文本和标题 |
|
|
// 清理显示的文本和标题 |
|
|
displayedTexts.value = { |
|
|
displayedTexts.value = { |
|
|
one1: '', |
|
|
one1: '', |
|
@ -460,6 +548,9 @@ watch(() => emotionStore.stockList, (newStockList) => { |
|
|
emoEnergyConverter: false |
|
|
emoEnergyConverter: false |
|
|
}; |
|
|
}; |
|
|
console.log('股票列表已清空,页面数据已隐藏'); |
|
|
console.log('股票列表已清空,页面数据已隐藏'); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 当stockList有数据时,更新对话记录 |
|
|
|
|
|
loadConversationsFromStockList(); |
|
|
} |
|
|
} |
|
|
}, { deep: true }); |
|
|
}, { deep: true }); |
|
|
|
|
|
|
|
@ -1089,11 +1180,20 @@ async function handleSendMessage(input, onComplete) { |
|
|
const previousMessages = [...messages.value]; // 保存历史消息 |
|
|
const previousMessages = [...messages.value]; // 保存历史消息 |
|
|
messages.value = []; // 清空历史数据 |
|
|
messages.value = []; // 清空历史数据 |
|
|
|
|
|
|
|
|
|
|
|
// 添加用户消息(只添加一次) |
|
|
|
|
|
const userMessage = reactive({ sender: 'user', text: input }); |
|
|
|
|
|
messages.value.push(userMessage); |
|
|
|
|
|
|
|
|
|
|
|
// 将用户消息添加到emotion store中 |
|
|
|
|
|
emotionStore.addConversation({ |
|
|
|
|
|
sender: 'user', |
|
|
|
|
|
text: input, |
|
|
|
|
|
timestamp: new Date().toISOString() |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 检查用户剩余次数 |
|
|
// 检查用户剩余次数 |
|
|
await chatStore.getUserCount(); // 获取最新的用户次数 |
|
|
await chatStore.getUserCount(); // 获取最新的用户次数 |
|
|
if (chatStore.UserCount <= 0) { |
|
|
if (chatStore.UserCount <= 0) { |
|
|
const userMessage = reactive({ sender: 'user', text: input }); |
|
|
|
|
|
messages.value.push(userMessage); |
|
|
|
|
|
const aiMessage = reactive({ sender: 'ai', text: '您的剩余次数为0,无法使用情绪大模型,请联系客服或购买服务包。' }); |
|
|
const aiMessage = reactive({ sender: 'ai', text: '您的剩余次数为0,无法使用情绪大模型,请联系客服或购买服务包。' }); |
|
|
messages.value.push(aiMessage); |
|
|
messages.value.push(aiMessage); |
|
|
|
|
|
|
|
@ -1115,39 +1215,6 @@ async function handleSendMessage(input, onComplete) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 检查用户是否有使用次数(检查是否有任何权限) |
|
|
|
|
|
// const hasPermission = userStore.brainPerssion || userStore.swordPerssion || |
|
|
|
|
|
// userStore.pricePerssion || userStore.timePerssion || |
|
|
|
|
|
// userStore.aibullPerssion || userStore.aiGnbullPerssion || |
|
|
|
|
|
// userStore.airadarPerssion; |
|
|
|
|
|
|
|
|
|
|
|
// if (!hasPermission) { |
|
|
|
|
|
// const userMessage = reactive({ sender: 'user', text: input }); |
|
|
|
|
|
// messages.value.push(userMessage); |
|
|
|
|
|
// const aiMessage = reactive({ sender: 'ai', text: '您当前没有可用权限,请联系客服或购买服务包。' }); |
|
|
|
|
|
// messages.value.push(aiMessage); |
|
|
|
|
|
// // 停止图片旋转,恢复历史数据 |
|
|
|
|
|
// isRotating.value = false; |
|
|
|
|
|
// messages.value = [...previousMessages, ...messages.value]; |
|
|
|
|
|
// // 调用完成回调,重新启用输入框 |
|
|
|
|
|
// if (onComplete && typeof onComplete === 'function') { |
|
|
|
|
|
// onComplete(); |
|
|
|
|
|
// // 清除保存的回调函数 |
|
|
|
|
|
// currentOnCompleteCallback.value = null; |
|
|
|
|
|
// } |
|
|
|
|
|
// return; |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
const userMessage = reactive({ sender: 'user', text: input }); |
|
|
|
|
|
messages.value.push(userMessage); |
|
|
|
|
|
|
|
|
|
|
|
// 将用户消息添加到emotion store中 |
|
|
|
|
|
emotionStore.addConversation({ |
|
|
|
|
|
sender: 'user', |
|
|
|
|
|
text: input, |
|
|
|
|
|
timestamp: new Date().toISOString() |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 开始思考过程(不带股票名称) |
|
|
// 开始思考过程(不带股票名称) |
|
|
const thinkingMessageRef = await showThinkingProcess(); |
|
|
const thinkingMessageRef = await showThinkingProcess(); |
|
|
|
|
|
|
|
@ -1602,36 +1669,36 @@ function hasValidData(obj) { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 依次渲染图表的方法 |
|
|
|
|
|
async function renderChartsSequentially(clonedData) { |
|
|
|
|
|
console.log('开始依次渲染图表'); |
|
|
|
|
|
|
|
|
// 依次渲染图表的方法 - 支持多个股票 |
|
|
|
|
|
async function renderChartsSequentially(clonedData, stockIndex = 0) { |
|
|
|
|
|
console.log(`开始渲染第${stockIndex}个股票的图表`); |
|
|
|
|
|
|
|
|
// 定义图表渲染顺序和配置 |
|
|
// 定义图表渲染顺序和配置 |
|
|
const chartConfigs = [ |
|
|
const chartConfigs = [ |
|
|
{ |
|
|
{ |
|
|
name: '股市温度计', |
|
|
name: '股市温度计', |
|
|
ref: marketTemperatureRef, |
|
|
|
|
|
|
|
|
ref: marketTemperatureRef.value[stockIndex], |
|
|
visibility: chartVisibility.value.marketTemperature, |
|
|
visibility: chartVisibility.value.marketTemperature, |
|
|
method: 'initChart', |
|
|
method: 'initChart', |
|
|
params: [clonedData.GSWDJ, clonedData.KLine20, clonedData.WDRL] |
|
|
params: [clonedData.GSWDJ, clonedData.KLine20, clonedData.WDRL] |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
name: '情绪解码器', |
|
|
name: '情绪解码器', |
|
|
ref: emotionDecodRef, |
|
|
|
|
|
|
|
|
ref: emotionDecodRef.value[stockIndex], |
|
|
visibility: chartVisibility.value.emotionDecod, |
|
|
visibility: chartVisibility.value.emotionDecod, |
|
|
method: 'initQXNLZHEcharts', |
|
|
method: 'initQXNLZHEcharts', |
|
|
params: [clonedData.KLine20, clonedData.QXJMQ] |
|
|
params: [clonedData.KLine20, clonedData.QXJMQ] |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
name: '情绪探底雷达', |
|
|
name: '情绪探底雷达', |
|
|
ref: emotionalBottomRadarRef, |
|
|
|
|
|
|
|
|
ref: emotionalBottomRadarRef.value[stockIndex], |
|
|
visibility: chartVisibility.value.emotionalBottomRadar, |
|
|
visibility: chartVisibility.value.emotionalBottomRadar, |
|
|
method: 'initEmotionalBottomRadar', |
|
|
method: 'initEmotionalBottomRadar', |
|
|
params: [clonedData.KLine20, clonedData.QXTDLD] |
|
|
params: [clonedData.KLine20, clonedData.QXTDLD] |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
name: '情绪能量转化器', |
|
|
name: '情绪能量转化器', |
|
|
ref: emoEnergyConverterRef, |
|
|
|
|
|
|
|
|
ref: emoEnergyConverterRef.value[stockIndex], |
|
|
visibility: chartVisibility.value.emoEnergyConverter, |
|
|
visibility: chartVisibility.value.emoEnergyConverter, |
|
|
method: 'initQXNLZHEcharts', |
|
|
method: 'initQXNLZHEcharts', |
|
|
params: [clonedData.KLine20, clonedData.QXNLZHQ] |
|
|
params: [clonedData.KLine20, clonedData.QXNLZHQ] |
|
@ -1640,29 +1707,29 @@ async function renderChartsSequentially(clonedData) { |
|
|
|
|
|
|
|
|
// 依次渲染每个图表 |
|
|
// 依次渲染每个图表 |
|
|
for (const config of chartConfigs) { |
|
|
for (const config of chartConfigs) { |
|
|
if (config.ref.value && config.visibility) { |
|
|
|
|
|
console.log(`开始渲染${config.name}图表`); |
|
|
|
|
|
console.log(`${config.name}Ref方法:`, typeof config.ref.value[config.method]); |
|
|
|
|
|
|
|
|
if (config.ref && config.visibility) { |
|
|
|
|
|
console.log(`开始渲染第${stockIndex}个股票的${config.name}图表`); |
|
|
|
|
|
console.log(`${config.name}Ref方法:`, typeof config.ref[config.method]); |
|
|
|
|
|
|
|
|
if (typeof config.ref.value[config.method] === 'function') { |
|
|
|
|
|
|
|
|
if (typeof config.ref[config.method] === 'function') { |
|
|
try { |
|
|
try { |
|
|
config.ref.value[config.method](...config.params); |
|
|
|
|
|
console.log(`${config.name}图表渲染成功`); |
|
|
|
|
|
|
|
|
config.ref[config.method](...config.params); |
|
|
|
|
|
console.log(`第${stockIndex}个股票的${config.name}图表渲染成功`); |
|
|
|
|
|
|
|
|
// 每个图表渲染完成后等待一段时间再渲染下一个 |
|
|
// 每个图表渲染完成后等待一段时间再渲染下一个 |
|
|
await new Promise(resolve => setTimeout(resolve, 800)); |
|
|
await new Promise(resolve => setTimeout(resolve, 800)); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error(`${config.name}图表渲染失败:`, error); |
|
|
|
|
|
|
|
|
console.error(`第${stockIndex}个股票的${config.name}图表渲染失败:`, error); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.error(`${config.name}Ref.${config.method} 方法不存在`); |
|
|
|
|
|
|
|
|
console.error(`第${stockIndex}个股票的${config.name}Ref.${config.method} 方法不存在`); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.log(`${config.name}图表未渲染,ref存在:`, !!config.ref.value, '数据存在:', config.visibility); |
|
|
|
|
|
|
|
|
console.log(`第${stockIndex}个股票的${config.name}图表未渲染,ref存在:`, !!config.ref, '数据存在:', config.visibility); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
console.log('所有图表依次渲染完成'); |
|
|
|
|
|
|
|
|
console.log(`第${stockIndex}个股票的所有图表依次渲染完成`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 渲染组件图表的方法 |
|
|
// 渲染组件图表的方法 |
|
@ -1746,8 +1813,12 @@ function renderCharts(data) { |
|
|
} |
|
|
} |
|
|
}, 1000); |
|
|
}, 1000); |
|
|
|
|
|
|
|
|
// 开始依次渲染图表 |
|
|
|
|
|
renderChartsSequentially(clonedData); |
|
|
|
|
|
|
|
|
// 开始依次渲染图表 - 为每个股票渲染 |
|
|
|
|
|
emotionStore.stockList.forEach((stock, index) => { |
|
|
|
|
|
if (stock.apiData) { |
|
|
|
|
|
renderChartsSequentially(stock.apiData, index); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
console.log('图表渲染完成'); |
|
|
console.log('图表渲染完成'); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
@ -1798,19 +1869,28 @@ function isDataLoaded() { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 检查图表组件是否已渲染 |
|
|
|
|
|
|
|
|
// 检查图表组件是否已渲染 - 检查所有股票的组件 |
|
|
|
|
|
const stockCount = emotionStore.stockList.length; |
|
|
|
|
|
if (stockCount === 0) { |
|
|
|
|
|
console.log('没有股票数据'); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 检查每个股票的图表组件是否都已加载 |
|
|
|
|
|
for (let i = 0; i < stockCount; i++) { |
|
|
const requiredRefs = [ |
|
|
const requiredRefs = [ |
|
|
marketTemperatureRef.value, |
|
|
|
|
|
emotionDecodRef.value, |
|
|
|
|
|
emotionalBottomRadarRef.value, |
|
|
|
|
|
emoEnergyConverterRef.value |
|
|
|
|
|
|
|
|
marketTemperatureRef.value[i], |
|
|
|
|
|
emotionDecodRef.value[i], |
|
|
|
|
|
emotionalBottomRadarRef.value[i], |
|
|
|
|
|
emoEnergyConverterRef.value[i] |
|
|
]; |
|
|
]; |
|
|
|
|
|
|
|
|
const allRefsLoaded = requiredRefs.every(ref => ref !== null); |
|
|
const allRefsLoaded = requiredRefs.every(ref => ref !== null); |
|
|
if (!allRefsLoaded) { |
|
|
if (!allRefsLoaded) { |
|
|
console.log('图表组件尚未完全加载'); |
|
|
|
|
|
|
|
|
console.log(`第${i}个股票的图表组件尚未完全加载`); |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
console.log('所有数据和组件已加载完成'); |
|
|
console.log('所有数据和组件已加载完成'); |
|
|
return true; |
|
|
return true; |
|
@ -1954,6 +2034,8 @@ const handleContainerScroll = () => { |
|
|
onMounted(async () => { |
|
|
onMounted(async () => { |
|
|
// 恢复对话记录 |
|
|
// 恢复对话记录 |
|
|
loadConversationsFromStore(); |
|
|
loadConversationsFromStore(); |
|
|
|
|
|
// 从stockList加载对话记录 |
|
|
|
|
|
loadConversationsFromStockList(); |
|
|
|
|
|
|
|
|
// 确保获取用户次数 |
|
|
// 确保获取用户次数 |
|
|
// try { |
|
|
// try { |
|
|