diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue
index d5f50fe..63d9de4 100644
--- a/src/views/AIchat.vue
+++ b/src/views/AIchat.vue
@@ -682,6 +682,104 @@ const addTypingTask = (message, content, speed) => {
processTypingQueue();
};
+// 显示思考过程
+async function showThinkingProcess(stockName = null) {
+ // 第一步:正在思考
+ const thinkingMessage1 = reactive({
+ sender: 'ai',
+ class: 'ing',
+ type: 'ing',
+ flag: true,
+ content: '正在思考......'
+ });
+ chatStore.messages.push(thinkingMessage1);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ chatStore.messages.pop();
+
+ // 第二步:正在解析关键数据(持续显示直到获取到股票名称)
+ const thinkingMessage2 = reactive({
+ sender: 'ai',
+ class: 'ing',
+ type: 'ing',
+ flag: true,
+ content: '正在解析关键数据......'
+ });
+ chatStore.messages.push(thinkingMessage2);
+
+ // 如果没有股票名称,保持第二步显示
+ if (!stockName) {
+ return thinkingMessage2; // 返回消息引用,以便后续更新
+ }
+
+ // 有股票名称后,继续后续步骤
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ chatStore.messages.pop();
+
+ // 第三步:生成具体股票的全景作战报告
+ const thinkingMessage3 = reactive({
+ sender: 'ai',
+ class: 'ing',
+ type: 'ing',
+ flag: true,
+ content: `正在生成${stockName}全景作战报告......`
+ });
+ chatStore.messages.push(thinkingMessage3);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ chatStore.messages.pop();
+
+ // 第四步:报告已生成
+ const thinkingMessage4 = reactive({
+ sender: 'ai',
+ class: 'ing',
+ type: 'ing',
+ flag: true,
+ content: '报告已生成!'
+ });
+ chatStore.messages.push(thinkingMessage4);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ chatStore.messages.pop();
+
+ return null;
+}
+
+// 继续思考过程(当获取到股票名称后调用)
+async function continueThinkingProcess(thinkingMessageRef, stockName) {
+ if (!thinkingMessageRef || !stockName) return;
+
+ // 等待一段时间后继续
+ await new Promise(resolve => setTimeout(resolve, 1500));
+
+ // 移除第二步消息
+ const index = chatStore.messages.indexOf(thinkingMessageRef);
+ if (index > -1) {
+ chatStore.messages.splice(index, 1);
+ }
+
+ // 第三步:生成具体股票的全景作战报告
+ const thinkingMessage3 = reactive({
+ sender: 'ai',
+ class: 'ing',
+ type: 'ing',
+ flag: true,
+ content: `正在生成${stockName}全景作战报告......`
+ });
+ chatStore.messages.push(thinkingMessage3);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ chatStore.messages.pop();
+
+ // 第四步:报告已生成
+ const thinkingMessage4 = reactive({
+ sender: 'ai',
+ class: 'ing',
+ type: 'ing',
+ flag: true,
+ content: '报告已生成!'
+ });
+ chatStore.messages.push(thinkingMessage4);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ chatStore.messages.pop();
+}
+
const hasValidData = ref(false);
// 创建一个非响应式的对象来存储图表实例
@@ -724,6 +822,9 @@ watch(
// 标志
let flag = true;
const codeData = ref();
+ // 开始思考过程(不带股票名称)
+ const thinkingMessageRef = await showThinkingProcess();
+
// 第一阶段,意图识别
try {
// 调用工作流获取回复
@@ -732,6 +833,11 @@ watch(
console.log(codeData.value, "codeData");
// 根据意图识别结果判断
if (result.code == 200) {
+ // 获取到股票名称后,继续思考过程
+ if (thinkingMessageRef && codeData.value.name) {
+ await continueThinkingProcess(thinkingMessageRef, codeData.value.name);
+ }
+
chatStore.messages.push({
class: "ing",
type: "ing",
@@ -739,6 +845,14 @@ watch(
content: result.data.kaishi,
});
} else {
+ // 意图识别失败,先清理思考过程消息
+ if (thinkingMessageRef) {
+ const index = chatStore.messages.indexOf(thinkingMessageRef);
+ if (index > -1) {
+ chatStore.messages.splice(index, 1);
+ }
+ }
+
flag = false;
console.log("执行回绝话术");
const AIcontent = ref(result.msg);
@@ -770,6 +884,14 @@ watch(
emit('enableInput');
}
} catch (e) {
+ // 意图识别异常,先清理思考过程消息
+ if (thinkingMessageRef) {
+ const index = chatStore.messages.indexOf(thinkingMessageRef);
+ if (index > -1) {
+ chatStore.messages.splice(index, 1);
+ }
+ }
+
console.log(e, "意图识别失败");
chatStore.messages.push({
class: "ing",
diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue
index 3123a91..b4354a2 100644
--- a/src/views/AiEmotion.vue
+++ b/src/views/AiEmotion.vue
@@ -42,9 +42,6 @@
-
-
-
@@ -299,7 +296,7 @@ defineExpose({
clearConversations
});
const isPageLoaded = ref(false); // 控制页面是否显示
-const isLoading = ref(false); // 控制加载状态
+// const isLoading = ref(false); // 控制加载状态
const isRotating = ref(false);//控制旋转
const version1 = ref(1); // 版本号
const conclusionData = ref(''); // 存储第二个工作流接口返回的结论数据
@@ -970,6 +967,83 @@ function startImageRotation() {
}
+// 显示思考过程
+async function showThinkingProcess(stockName = null) {
+ // 第一步:正在思考
+ const thinkingMessage1 = reactive({ sender: 'ai', text: '正在思考......' });
+ messages.value.push(thinkingMessage1);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ messages.value.pop();
+
+ // 第二步:正在解析关键数据(持续显示直到获取到股票名称)
+ const thinkingMessage2 = reactive({ sender: 'ai', text: '正在解析关键数据......' });
+ messages.value.push(thinkingMessage2);
+
+ // 如果没有股票名称,保持第二步显示
+ if (!stockName) {
+ return thinkingMessage2; // 返回消息引用,以便后续更新
+ }
+
+ // 有股票名称后,继续后续步骤
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ messages.value.pop();
+
+ // 第三步:生成具体股票的量子四维矩阵图
+ const thinkingMessage3 = reactive({ sender: 'ai', text: `正在生成${stockName}量子四维矩阵图......` });
+ messages.value.push(thinkingMessage3);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ messages.value.pop();
+
+ // 第四步:报告已生成
+ const thinkingMessage4 = reactive({ sender: 'ai', text: '报告已生成!' });
+ messages.value.push(thinkingMessage4);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ messages.value.pop();
+
+ return null;
+}
+
+// 继续思考过程(当获取到股票名称后调用)
+async function continueThinkingProcess(thinkingMessageRef, stockName) {
+ if (!thinkingMessageRef || !stockName) return;
+
+ // 等待一段时间后继续
+ await new Promise(resolve => setTimeout(resolve, 1500));
+
+ // 移除第二步消息
+ const index = messages.value.indexOf(thinkingMessageRef);
+ if (index > -1) {
+ messages.value.splice(index, 1);
+ }
+
+ // 第三步:生成具体股票的量子四维矩阵图
+ const thinkingMessage3 = reactive({ sender: 'ai', text: `正在生成${stockName}量子四维矩阵图......` });
+ messages.value.push(thinkingMessage3);
+
+ // 返回第三步消息的引用,以便后续处理
+ return thinkingMessage3;
+}
+
+// 完成思考过程(当第二个工作流接口成功后调用)
+async function finishThinkingProcess(thinkingMessage3Ref) {
+ if (!thinkingMessage3Ref) return;
+
+ // 等待一段时间
+ await new Promise(resolve => setTimeout(resolve, 1500));
+
+ // 移除第三步消息
+ const index = messages.value.indexOf(thinkingMessage3Ref);
+ if (index > -1) {
+ messages.value.splice(index, 1);
+ }
+
+ // 第四步:报告已生成
+ const thinkingMessage4 = reactive({ sender: 'ai', text: '报告已生成!' });
+ messages.value.push(thinkingMessage4);
+ await new Promise(resolve => setTimeout(resolve, 1500));
+ messages.value.pop();
+}
+
// 发送消息方法
async function handleSendMessage(input, onComplete) {
console.log("发送内容:", input);
@@ -1052,6 +1126,9 @@ async function handleSendMessage(input, onComplete) {
timestamp: new Date().toISOString()
});
+ // 开始思考过程(不带股票名称)
+ const thinkingMessageRef = await showThinkingProcess();
+
try {
// 第一步:调用第一个接口验证用户输入内容是否合法
const params = {
@@ -1084,8 +1161,16 @@ async function handleSendMessage(input, onComplete) {
// 检查用户输入是否合法
if (!parsedData || !parsedData.market || !parsedData.code) {
- // 输入不合法,关闭加载状态和等待提示,返回refuse信息,停止图片旋转,恢复历史数据
- isLoading.value = false;
+ // 输入不合法,先清理思考过程消息
+ if (thinkingMessageRef) {
+ const index = messages.value.indexOf(thinkingMessageRef);
+ if (index > -1) {
+ messages.value.splice(index, 1);
+ }
+ }
+
+ // 关闭加载状态和等待提示,返回refuse信息,停止图片旋转,恢复历史数据
+ // isLoading.value = false;
isPageLoaded.value = false;
const aiMessage = reactive({ sender: 'ai', text: processRefuseMessage(parsedData.refuse) });
messages.value.push(aiMessage);
@@ -1108,8 +1193,14 @@ async function handleSendMessage(input, onComplete) {
}
// 输入合法,继续执行后续处理
+ // 获取到股票名称后,继续思考过程
+ let thinkingMessage3Ref = null;
+ if (thinkingMessageRef && parsedData.name) {
+ thinkingMessage3Ref = await continueThinkingProcess(thinkingMessageRef, parsedData.name);
+ }
+
// 设置加载状态,隐藏图表页面
- isLoading.value = true;
+ // isLoading.value = true;
isPageLoaded.value = false;
@@ -1135,13 +1226,18 @@ async function handleSendMessage(input, onComplete) {
// 检查所有数据是否都加载成功
if (conclusionResponse && conclusionResponse.data && fetchDataResult) {
+ // 第二个工作流接口成功,完成思考过程
+ if (thinkingMessage3Ref) {
+ await finishThinkingProcess(thinkingMessage3Ref);
+ }
+
// 将结论数据存储到响应式变量和store中
conclusionData.value = conclusionResponse.data;
// 将结论数据存储到store中的当前激活股票
emotionStore.updateActiveStockConclusion(conclusionResponse.data);
// 所有数据加载完成,关闭加载状态,显示页面
- isLoading.value = false;
+ // isLoading.value = false;
isPageLoaded.value = true;
// 数据获取成功后,重新获取用户次数以实现实时更新
@@ -1184,8 +1280,16 @@ async function handleSendMessage(input, onComplete) {
}
});
} else {
+ // 数据加载失败,清理第三步思考过程消息
+ if (thinkingMessage3Ref) {
+ const index = messages.value.indexOf(thinkingMessage3Ref);
+ if (index > -1) {
+ messages.value.splice(index, 1);
+ }
+ }
+
// 数据加载失败,停止图片旋转,恢复历史数据
- isLoading.value = false;
+ // isLoading.value = false;
// 如果 fetchDataResult 为 false,说明数据不完整的错误信息已经在 fetchData 中添加到 messages
// 只有在 conclusionResponse 有问题时才添加通用错误信息
if (!conclusionResponse || !conclusionResponse.data) {
@@ -1212,8 +1316,16 @@ async function handleSendMessage(input, onComplete) {
return;
}
} catch (error) {
+ // 请求失败,清理第三步思考过程消息
+ if (thinkingMessage3Ref) {
+ const index = messages.value.indexOf(thinkingMessage3Ref);
+ if (index > -1) {
+ messages.value.splice(index, 1);
+ }
+ }
+
// 请求失败时关闭加载状态
- isLoading.value = false;
+ // isLoading.value = false;
// 如果有之前的股票数据,恢复显示状态;否则设置为false
if (emotionStore.stockList.length > 0 && emotionStore.activeStock) {
@@ -1298,7 +1410,7 @@ async function fetchData(code, market, stockName, queryText) {
if (!validation.isValid) {
console.log('API返回数据不完整,缺失字段:', validation.missingFields);
// 关闭加载状态
- isLoading.value = false;
+ // isLoading.value = false;
// 如果有之前的股票数据,恢复显示状态;否则设置为false
if (emotionStore.stockList.length > 0 && emotionStore.activeStock) {
@@ -1345,7 +1457,7 @@ async function fetchData(code, market, stockName, queryText) {
return true; // 返回成功标识
} else {
// 关闭加载状态
- isLoading.value = false;
+ // isLoading.value = false;
// 如果有之前的股票数据,恢复显示状态;否则设置为false
if (emotionStore.stockList.length > 0 && emotionStore.activeStock) {
@@ -1373,7 +1485,7 @@ async function fetchData(code, market, stockName, queryText) {
}
} catch (error) {
// 关闭加载状态
- isLoading.value = false;
+ // isLoading.value = false;
// 如果有之前的股票数据,恢复显示状态;否则设置为false
if (emotionStore.stockList.length > 0 && emotionStore.activeStock) {
@@ -1468,6 +1580,69 @@ function hasValidData(obj) {
return false;
}
+// 依次渲染图表的方法
+async function renderChartsSequentially(clonedData) {
+ console.log('开始依次渲染图表');
+
+ // 定义图表渲染顺序和配置
+ const chartConfigs = [
+ {
+ name: '股市温度计',
+ ref: marketTemperatureRef,
+ visibility: chartVisibility.value.marketTemperature,
+ method: 'initChart',
+ params: [clonedData.GSWDJ, clonedData.KLine20, clonedData.WDRL]
+ },
+ {
+ name: '情绪解码器',
+ ref: emotionDecodRef,
+ visibility: chartVisibility.value.emotionDecod,
+ method: 'initQXNLZHEcharts',
+ params: [clonedData.KLine20, clonedData.QXJMQ]
+ },
+ {
+ name: '情绪探底雷达',
+ ref: emotionalBottomRadarRef,
+ visibility: chartVisibility.value.emotionalBottomRadar,
+ method: 'initEmotionalBottomRadar',
+ params: [clonedData.KLine20, clonedData.QXTDLD]
+ },
+ {
+ name: '情绪能量转化器',
+ ref: emoEnergyConverterRef,
+ visibility: chartVisibility.value.emoEnergyConverter,
+ method: 'initQXNLZHEcharts',
+ params: [clonedData.KLine20, clonedData.QXNLZHQ]
+ }
+ ];
+
+ // 依次渲染每个图表
+ 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 (typeof config.ref.value[config.method] === 'function') {
+ try {
+ config.ref.value[config.method](...config.params);
+ console.log(`${config.name}图表渲染成功`);
+
+ // 每个图表渲染完成后等待一段时间再渲染下一个
+ await new Promise(resolve => setTimeout(resolve, 800));
+ } catch (error) {
+ console.error(`${config.name}图表渲染失败:`, error);
+ }
+ } else {
+ console.error(`${config.name}Ref.${config.method} 方法不存在`);
+ }
+ } else {
+ console.log(`${config.name}图表未渲染,ref存在:`, !!config.ref.value, '数据存在:', config.visibility);
+ }
+ }
+
+ console.log('所有图表依次渲染完成');
+}
+
// 渲染组件图表的方法
function renderCharts(data) {
console.log('开始渲染图表,数据:', data);
@@ -1496,7 +1671,7 @@ function renderCharts(data) {
// 隐藏页面内容
isPageLoaded.value = false;
- isLoading.value = false;
+ // isLoading.value = false;
return; // 直接返回,不进行后续渲染
}
@@ -1549,80 +1724,8 @@ function renderCharts(data) {
}
}, 1000);
- // 渲染股市温度计图表
- if (marketTemperatureRef.value && chartVisibility.value.marketTemperature) {
- console.log('开始渲染股市温度计图表');
- console.log('marketTemperatureRef方法:', typeof marketTemperatureRef.value.initChart);
- if (typeof marketTemperatureRef.value.initChart === 'function') {
- try {
- marketTemperatureRef.value.initChart(clonedData.GSWDJ, clonedData.KLine20, clonedData.WDRL);
- console.log('股市温度计图表渲染成功');
- } catch (error) {
- console.error('股市温度计图表渲染失败:', error);
- }
- } else {
- console.error('marketTemperatureRef.initChart 方法不存在');
- }
- } else {
- console.log('股市温度计图表未渲染,ref存在:', !!marketTemperatureRef.value, '数据存在:', chartVisibility.value.marketTemperature);
- }
-
- // 渲染情绪解码器图表
- if (emotionDecodRef.value && chartVisibility.value.emotionDecod) {
- console.log('开始渲染情绪解码器图表');
- console.log('emotionDecodRef方法:', typeof emotionDecodRef.value.initQXNLZHEcharts);
- if (typeof emotionDecodRef.value.initQXNLZHEcharts === 'function') {
- try {
- emotionDecodRef.value.initQXNLZHEcharts(clonedData.KLine20, clonedData.QXJMQ);
- console.log('情绪解码器图表渲染成功');
- } catch (error) {
- console.error('情绪解码器图表渲染失败:', error);
- }
- } else {
- console.error('emotionDecodRef.initQXNLZHEcharts 方法不存在');
- }
- } else {
- console.log('情绪解码器图表未渲染,ref存在:', !!emotionDecodRef.value, '数据存在:', chartVisibility.value.emotionDecod);
- }
-
- // 渲染情绪探底雷达图表
- if (emotionalBottomRadarRef.value && chartVisibility.value.emotionalBottomRadar) {
- console.log('开始渲染情绪探底雷达图表');
- console.log('emotionalBottomRadarRef方法:', typeof emotionalBottomRadarRef.value.initEmotionalBottomRadar);
- if (typeof emotionalBottomRadarRef.value.initEmotionalBottomRadar === 'function') {
- try {
- emotionalBottomRadarRef.value.initEmotionalBottomRadar(
- clonedData.KLine20,
- clonedData.QXTDLD
- );
- console.log('情绪探底雷达图表渲染成功');
- } catch (error) {
- console.error('情绪探底雷达图表渲染失败:', error);
- }
- } else {
- console.error('emotionalBottomRadarRef.initEmotionalBottomRadar 方法不存在');
- }
- } else {
- console.log('情绪探底雷达图表未渲染,ref存在:', !!emotionalBottomRadarRef.value, '数据存在:', chartVisibility.value.emotionalBottomRadar);
- }
-
- // 渲染情绪能量转化器图表
- if (emoEnergyConverterRef.value && chartVisibility.value.emoEnergyConverter) {
- console.log('开始渲染情绪能量转化器图表');
- console.log('emoEnergyConverterRef方法:', typeof emoEnergyConverterRef.value.initQXNLZHEcharts);
- if (typeof emoEnergyConverterRef.value.initQXNLZHEcharts === 'function') {
- try {
- emoEnergyConverterRef.value.initQXNLZHEcharts(clonedData.KLine20, clonedData.QXNLZHQ);
- console.log('情绪能量转化器图表渲染成功');
- } catch (error) {
- console.error('情绪能量转化器图表渲染失败:', error);
- }
- } else {
- console.error('emoEnergyConverterRef.initQXNLZHEcharts 方法不存在');
- }
- } else {
- console.log('情绪能量转化器图表未渲染,ref存在:', !!emoEnergyConverterRef.value, '数据存在:', chartVisibility.value.emoEnergyConverter);
- }
+ // 开始依次渲染图表
+ renderChartsSequentially(clonedData);
console.log('图表渲染完成');
} catch (error) {
@@ -3212,24 +3315,24 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']);
}
/* 加载提示样式 */
-.loading-container {
+/* .loading-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 20vh;
padding: 20px 10px;
-}
+} */
-.loading-content {
+/* .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;
box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3);
-}
+} */
-.loading-spinner {
+/* .loading-spinner {
width: 60px;
height: 60px;
border: 4px solid rgba(0, 212, 255, 0.3);
@@ -3237,7 +3340,7 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
-}
+} */
@keyframes spin {
0% {
@@ -3249,13 +3352,13 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']);
}
}
-.loading-text {
+/* .loading-text {
color: #00d4ff;
font-size: 18px;
font-weight: bold;
text-shadow: 0 2px 8px rgba(0, 212, 255, 0.5);
letter-spacing: 1px;
-}
+} */
/* 顶部锚点样式 */
.top-anchor {
@@ -3283,7 +3386,6 @@ const emit = defineEmits(['updateMessage', 'sendMessage', 'ensureAIchat']);
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
- box-shadow: 0 4px 15px rgba(0, 212, 255, 0.3) !important;
transition: all 0.3s ease !important;
z-index: 100 !important;
color: white !important;
diff --git a/src/views/components/emotionDecod.vue b/src/views/components/emotionDecod.vue
index ddbc56f..e23347d 100644
--- a/src/views/components/emotionDecod.vue
+++ b/src/views/components/emotionDecod.vue
@@ -93,8 +93,10 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
top: "5%",
height: window.innerWidth <= 768 ? "30%" : "40%"
},
- { top: "45%", height: "35%" },
- { top: "80%", height: "2%" },
+ { top: window.innerWidth <= 768 ? "35%" :"45%",
+ height: "35%" },
+ { top: window.innerWidth <= 768 ? "70%" : "80%",
+ height: "2%" },
],
visualMap: [
@@ -278,7 +280,7 @@ function initQXNLZHEcharts(kline, qxnlzhqData) {
shadowOffsetX: 2,
shadowOffsetY: 2,
},
- bottom: window.innerWidth > 768 ? "8%" : "5%", // 下移数据缩放滑块
+ bottom: "8%", // 下移数据缩放滑块
},
{
show: !1,