diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue index 5644f3b..c67dfe4 100644 --- a/src/views/AIchat.vue +++ b/src/views/AIchat.vue @@ -22,7 +22,7 @@ import katex from "katex"; // 引入 KaTeX 库 import { htmlToText } from "html-to-text"; import { Howl, Howler } from "howler"; import * as echarts from "echarts"; -import _ from "lodash"; +import _, { add } from "lodash"; import moment from "moment"; import AIgif1 from "@/assets/img/AIchat/AIgif1.gif"; @@ -212,6 +212,150 @@ const fnGetData = (data) => { return sz.value; }; +const typingQueue = ref([]); +const isTypingInProgress = ref(false); + +// 创建打字机效果的Promise函数 +const createTypingEffect = (message, content, speed) => { + return new Promise((resolve) => { + chatStore.messages.push(message); + if (content != "") { + let index = 0; + message.content = ""; + message.isTyping = true; + + const typingInterval = setInterval(() => { + if (index < content.length) { + message.content += content.charAt(index); + index++; + } else { + clearInterval(typingInterval); + message.isTyping = false; + + // 处理KaTeX渲染(如果需要) + nextTick(() => { + if (message.content.includes("$$")) { + message.content = message.content.replace( + katexRegex, + (match, formula) => { + try { + return katex.renderToString(formula, { + throwOnError: false, + }); + } catch (error) { + console.error("KaTeX 渲染错误:", error); + return match; + } + } + ); + } + resolve(); // 完成后resolve + }); + } + }, speed); + } else { + if (message.kline) { + if (message.klineType == 1) { + console.log("六色罗盘消息已添加到聊天列表"); + + // 在渲染完成后初始化图表 + nextTick(() => { + console.log("nextTick开始 - 准备渲染图表"); + console.log("消息列表:", chatStore.messages); + + // 寻找最新添加的K线消息索引 + let klineIndex = -1; + for (let i = 0; i < chatStore.messages.length; i++) { + if (chatStore.messages[i].messageId === message.messageId) { + klineIndex = i; + break; + } + } + + console.log("找到的K线消息索引:", klineIndex); + + if (klineIndex !== -1) { + const containerId = `kline-container-${klineIndex}`; + console.log("图表容器ID:", containerId); + + // 确保DOM已经渲染完成 + setTimeout(() => { + console.log("延时执行,确保DOM已渲染"); + KlineCanvsEcharts(containerId); + }, 100); // 短暂延时确保DOM已渲染 + } else { + console.warn("未找到K线消息"); + } + }); + } else { + console.log("K线消息已添加到聊天列表"); + + // 在渲染完成后初始化图表 + nextTick(() => { + console.log("nextTick开始 - 准备渲染图表"); + console.log("消息列表:", chatStore.messages); + + // 寻找最新添加的K线消息索引 + let klineIndex = -1; + for (let i = 0; i < chatStore.messages.length; i++) { + if (chatStore.messages[i].messageId === message.messageId) { + klineIndex = i; + break; + } + } + + console.log("找到的K线消息索引:", klineIndex); + + if (klineIndex !== -1) { + const containerId = `kline-container-${klineIndex}`; + console.log("图表容器ID:", containerId); + + // 确保DOM已经渲染完成 + setTimeout(() => { + console.log("延时执行,确保DOM已渲染"); + KlineCanvsEcharts(containerId); + }, 100); // 短暂延时确保DOM已渲染 + } else { + console.warn("未找到K线消息"); + } + }); + } + // 延时1秒后resolve + setTimeout(() => { + resolve(); + }, 1000); + } else { + // 延时1秒后resolve + setTimeout(() => { + resolve(); + }, 1000); + } + } + }); +}; + +// 队列处理函数 +const processTypingQueue = async () => { + if (isTypingInProgress.value || typingQueue.value.length === 0) { + return; + } + + isTypingInProgress.value = true; + + while (typingQueue.value.length > 0) { + const task = typingQueue.value.shift(); + await createTypingEffect(task.message, task.content, task.speed); + } + + isTypingInProgress.value = false; +}; + +// 添加打字机任务到队列 +const addTypingTask = (message, content, speed = 50) => { + typingQueue.value.push({ message, content, speed }); + processTypingQueue(); +}; + const hasValidData = ref(false); // 创建一个非响应式的对象来存储图表实例 @@ -352,13 +496,24 @@ watch( // 删除正在为您生成信息 chatStore.messages.pop(); // 添加报告头和时间 - chatStore.messages.push({ - sender: "ai", - class: "title1", - type: "title1", - content: codeData.value.name + "全景作战报告", - date: moment().format("MM/DD/YYYY"), - }); + addTypingTask( + { + sender: "ai", + class: "title1", + type: "title1", + content: codeData.value.name + "全景作战报告", + date: moment().format("MM/DD/YYYY"), + }, + "", + 50 + ); + // chatStore.messages.push({ + // sender: "ai", + // class: "title1", + // type: "title1", + // content: codeData.value.name + "全景作战报告", + // date: moment().format("MM/DD/YYYY"), + // }); // 添加股票信息框 const pc1 = marked( @@ -385,18 +540,20 @@ watch( content: "", isTyping: true, }); - chatStore.messages.push(aiMessage1); + // chatStore.messages.push(aiMessage1); + + // let index1 = 0; + // const typingInterval1 = setInterval(() => { + // if (index1 < ac1.length) { + // aiMessage1.content += ac1.charAt(index1); + // index1++; + // } else { + // clearInterval(typingInterval1); + // aiMessage1.isTyping = false; + // } + // }, 50); // 调整速度为50ms/字符 - let index1 = 0; - const typingInterval1 = setInterval(() => { - if (index1 < ac1.length) { - aiMessage1.content += ac1.charAt(index1); - index1++; - } else { - clearInterval(typingInterval1); - aiMessage1.isTyping = false; - } - }, 50); // 调整速度为50ms/字符 + addTypingTask(aiMessage1, ac1, 50); // chatStore.messages.push({ // sender: "ai", @@ -415,48 +572,62 @@ watch( const klineMessageId1 = `kline-${Date.now()}`; console.log("生成K线消息ID:", klineMessageId1); - chatStore.messages.push({ - sender: "ai", - class: "content1", - type: "content1", - kline: true, - chartData: sz, - messageId: klineMessageId1, - hasValidData: true, - klineType: 1, - }); + addTypingTask( + { + sender: "ai", + class: "content1", + type: "content1", + kline: true, + chartData: sz, + messageId: klineMessageId1, + hasValidData: true, + klineType: 1, + }, + "", + 50 + ); + // chatStore.messages.push({ + // sender: "ai", + // class: "content1", + // type: "content1", + // kline: true, + // chartData: sz, + // messageId: klineMessageId1, + // hasValidData: true, + // klineType: 1, + // }); - console.log("六色罗盘消息已添加到聊天列表"); + // console.log("六色罗盘消息已添加到聊天列表"); - // 在渲染完成后初始化图表 - nextTick(() => { - console.log("nextTick开始 - 准备渲染图表"); - console.log("消息列表:", chatStore.messages); + // // 在渲染完成后初始化图表 + // nextTick(() => { + // console.log("nextTick开始 - 准备渲染图表"); + // console.log("消息列表:", chatStore.messages); - // 寻找最新添加的K线消息索引 - let klineIndex = -1; - for (let i = 0; i < chatStore.messages.length; i++) { - if (chatStore.messages[i].messageId === klineMessageId1) { - klineIndex = i; - break; - } - } + // // 寻找最新添加的K线消息索引 + // let klineIndex = -1; + // for (let i = 0; i < chatStore.messages.length; i++) { + // if (chatStore.messages[i].messageId === klineMessageId1) { + // klineIndex = i; + // break; + // } + // } - console.log("找到的K线消息索引:", klineIndex); + // console.log("找到的K线消息索引:", klineIndex); - if (klineIndex !== -1) { - const containerId = `kline-container-${klineIndex}`; - console.log("图表容器ID:", containerId); + // if (klineIndex !== -1) { + // const containerId = `kline-container-${klineIndex}`; + // console.log("图表容器ID:", containerId); - // 确保DOM已经渲染完成 - setTimeout(() => { - console.log("延时执行,确保DOM已渲染"); - KlineCanvsEcharts(containerId); - }, 100); // 短暂延时确保DOM已渲染 - } else { - console.warn("未找到K线消息"); - } - }); + // // 确保DOM已经渲染完成 + // setTimeout(() => { + // console.log("延时执行,确保DOM已渲染"); + // KlineCanvsEcharts(containerId); + // }, 100); // 短暂延时确保DOM已渲染 + // } else { + // console.warn("未找到K线消息"); + // } + // }); // 度牛尺K线图 const AIGoldBullData = JSON.parse(JSON.stringify(toRaw(AIGoldBull))); @@ -485,56 +656,81 @@ watch( const klineMessageId2 = `kline-${Date.now() + 1}`; console.log("生成K线消息ID:", klineMessageId2); - chatStore.messages.push({ - sender: "ai", - class: "content2", - type: "content2", - kline: true, - chartData: Kline20, - messageId: klineMessageId2, - hasValidData: true, // 添加hasValidData标志 - klineType: 2, - }); + // chatStore.messages.push({ + // sender: "ai", + // class: "content2", + // type: "content2", + // kline: true, + // chartData: Kline20, + // messageId: klineMessageId2, + // hasValidData: true, // 添加hasValidData标志 + // klineType: 2, + // }); - console.log("K线消息已添加到聊天列表"); + addTypingTask( + { + sender: "ai", + class: "content2", + type: "content2", + kline: true, + chartData: Kline20, + messageId: klineMessageId2, + hasValidData: true, // 添加hasValidData标志 + klineType: 2, + }, + "", + 50 + ); - // 在渲染完成后初始化图表 - nextTick(() => { - console.log("nextTick开始 - 准备渲染图表"); - console.log("消息列表:", chatStore.messages); + // console.log("K线消息已添加到聊天列表"); - // 寻找最新添加的K线消息索引 - let klineIndex = -1; - for (let i = 0; i < chatStore.messages.length; i++) { - if (chatStore.messages[i].messageId === klineMessageId2) { - klineIndex = i; - break; - } - } + // // 在渲染完成后初始化图表 + // nextTick(() => { + // console.log("nextTick开始 - 准备渲染图表"); + // console.log("消息列表:", chatStore.messages); - console.log("找到的K线消息索引:", klineIndex); + // // 寻找最新添加的K线消息索引 + // let klineIndex = -1; + // for (let i = 0; i < chatStore.messages.length; i++) { + // if (chatStore.messages[i].messageId === klineMessageId2) { + // klineIndex = i; + // break; + // } + // } - if (klineIndex !== -1) { - const containerId = `kline-container-${klineIndex}`; - console.log("图表容器ID:", containerId); + // console.log("找到的K线消息索引:", klineIndex); - // 确保DOM已经渲染完成 - setTimeout(() => { - console.log("延时执行,确保DOM已渲染"); - KlineCanvsEcharts(containerId); - }, 100); // 短暂延时确保DOM已渲染 - } else { - console.warn("未找到K线消息"); - } - }); + // if (klineIndex !== -1) { + // const containerId = `kline-container-${klineIndex}`; + // console.log("图表容器ID:", containerId); + + // // 确保DOM已经渲染完成 + // setTimeout(() => { + // console.log("延时执行,确保DOM已渲染"); + // KlineCanvsEcharts(containerId); + // }, 100); // 短暂延时确保DOM已渲染 + // } else { + // console.warn("未找到K线消息"); + // } + // }); // 添加标题2 - chatStore.messages.push({ - sender: "ai", - class: "title2", - type: "title2", - content: "", - }); + addTypingTask( + { + sender: "ai", + class: "title2", + type: "title2", + content: "", + }, + "", + 50 + ); + // chatStore.messages.push({ + // sender: "ai", + // class: "title2", + // type: "title2", + // content: "", + // }); // 添加内容框1 const pc2 = marked(result22.data.hxjzpg); console.log(pc2, "pc2"); @@ -555,18 +751,19 @@ watch( content: "", isTyping: true, }); - chatStore.messages.push(aiMessage2); - - let index2 = 0; - const typingInterval2 = setInterval(() => { - if (index2 < ac2.length) { - aiMessage2.content += ac2.charAt(index2); - index2++; - } else { - clearInterval(typingInterval2); - aiMessage2.isTyping = false; - } - }, 50); // 调整速度为50ms/字符 + // chatStore.messages.push(aiMessage2); + + // let index2 = 0; + // const typingInterval2 = setInterval(() => { + // if (index2 < ac2.length) { + // aiMessage2.content += ac2.charAt(index2); + // index2++; + // } else { + // clearInterval(typingInterval2); + // aiMessage2.isTyping = false; + // } + // }, 50); // 调整速度为50ms/字符 + addTypingTask(aiMessage2, ac2, 50); // chatStore.messages.push({ // sender: "ai", @@ -575,12 +772,22 @@ watch( // content: ac2, // }); // 添加标题3-2 - chatStore.messages.push({ - sender: "ai", - class: "title3", - type: "title3", - content: title2, - }); + addTypingTask( + { + sender: "ai", + class: "title3", + type: "title3", + content: title2, + }, + "", + 50 + ); + // chatStore.messages.push({ + // sender: "ai", + // class: "title3", + // type: "title3", + // content: title2, + // }); // 添加内容框2 // const pc3 = marked(result23.data.zhuli1+'\n'+result23.data.zhuli2+'\n'+result23.data.zhuli3); // const ac3 = pc3.replace( @@ -604,35 +811,20 @@ watch( content: "", isTyping: true, }); - chatStore.messages.push(aiMessage3); + // chatStore.messages.push(aiMessage3); - let index3 = 0; - const typingInterval3 = setInterval(() => { - if (index3 < ac3.length) { - aiMessage3.content += ac3.charAt(index3); - index3++; - } else { - clearInterval(typingInterval3); - aiMessage3.isTyping = false; - - // 延迟处理KaTeX确保DOM已更新 - nextTick(() => { - aiMessage3.content = aiMessage3.content.replace( - katexRegex, - (match, formula) => { - try { - return katex.renderToString(formula, { - throwOnError: false, - }); - } catch (error) { - console.error("KaTeX 渲染错误:", error); - return match; - } - } - ); - }); - } - }, 50); // 调整速度为50ms/字符 + // let index3 = 0; + // const typingInterval3 = setInterval(() => { + // if (index3 < ac3.length) { + // aiMessage3.content += ac3.charAt(index3); + // index3++; + // } else { + // clearInterval(typingInterval3); + // aiMessage3.isTyping = false; + + // } + // }, 50); // 调整速度为50ms/字符 + addTypingTask(aiMessage3, ac3, 50); // chatStore.messages.push({ // sender: "ai", @@ -641,12 +833,22 @@ watch( // content: ac3, // }); // 添加标题3-3 - chatStore.messages.push({ - sender: "ai", - class: "title3", - type: "title3", - content: title3, - }); + addTypingTask( + { + sender: "ai", + class: "title3", + type: "title3", + content: title3, + }, + "", + 50 + ); + // chatStore.messages.push({ + // sender: "ai", + // class: "title3", + // type: "title3", + // content: title3, + // }); // 添加内容框3 const arr = result23.data.kongjian.split(","); const kongjian = `
【空间维度】
${arr[0]},${arr[1]}
${arr[2]},${arr[3]}
`; @@ -678,35 +880,20 @@ watch( content: "", isTyping: true, }); - chatStore.messages.push(aiMessage4); + // chatStore.messages.push(aiMessage4); - let index4 = 0; - const typingInterval4 = setInterval(() => { - if (index4 < ac4.length) { - aiMessage4.content += ac4.charAt(index4); - index4++; - } else { - clearInterval(typingInterval4); - aiMessage4.isTyping = false; - - // 延迟处理KaTeX确保DOM已更新 - nextTick(() => { - aiMessage4.content = aiMessage4.content.replace( - katexRegex, - (match, formula) => { - try { - return katex.renderToString(formula, { - throwOnError: false, - }); - } catch (error) { - console.error("KaTeX 渲染错误:", error); - return match; - } - } - ); - }); - } - }, 50); // 调整速度为50ms/字符 + // let index4 = 0; + // const typingInterval4 = setInterval(() => { + // if (index4 < ac4.length) { + // aiMessage4.content += ac4.charAt(index4); + // index4++; + // } else { + // clearInterval(typingInterval4); + // aiMessage4.isTyping = false; + + // } + // }, 50); // 调整速度为50ms/字符 + addTypingTask(aiMessage4, ac4, 50); // chatStore.messages.push({ // sender: "ai", @@ -715,6 +902,16 @@ watch( // content: ac4, // }); // 添加标题3-4 + addTypingTask( + { + sender: "ai", + class: "title3", + type: "title3", + content: title4, + }, + "", + 50 + ); chatStore.messages.push({ sender: "ai", class: "title3", @@ -744,35 +941,20 @@ watch( content: "", isTyping: true, }); - chatStore.messages.push(aiMessage5); + // chatStore.messages.push(aiMessage5); - let index5 = 0; - const typingInterval5 = setInterval(() => { - if (index5 < ac5.length) { - aiMessage5.content += ac5.charAt(index5); - index5++; - } else { - clearInterval(typingInterval5); - aiMessage5.isTyping = false; - - // 延迟处理KaTeX确保DOM已更新 - nextTick(() => { - aiMessage5.content = aiMessage5.content.replace( - katexRegex, - (match, formula) => { - try { - return katex.renderToString(formula, { - throwOnError: false, - }); - } catch (error) { - console.error("KaTeX 渲染错误:", error); - return match; - } - } - ); - }); - } - }, 50); // 调整速度为50ms/字符 + // let index5 = 0; + // const typingInterval5 = setInterval(() => { + // if (index5 < ac5.length) { + // aiMessage5.content += ac5.charAt(index5); + // index5++; + // } else { + // clearInterval(typingInterval5); + // aiMessage5.isTyping = false; + + // } + // }, 50); // 调整速度为50ms/字符 + addTypingTask(aiMessage5, ac5, 50); // chatStore.messages.push({ // sender: "ai", @@ -790,35 +972,20 @@ watch( content: "", isTyping: true, }); - chatStore.messages.push(aiMessage6); + // chatStore.messages.push(aiMessage6); - let index6 = 0; - const typingInterval6 = setInterval(() => { - if (index6 < ac6.length) { - aiMessage6.content += ac6.charAt(index6); - index6++; - } else { - clearInterval(typingInterval6); - aiMessage6.isTyping = false; - - // 延迟处理KaTeX确保DOM已更新 - nextTick(() => { - aiMessage6.content = aiMessage6.content.replace( - katexRegex, - (match, formula) => { - try { - return katex.renderToString(formula, { - throwOnError: false, - }); - } catch (error) { - console.error("KaTeX 渲染错误:", error); - return match; - } - } - ); - }); - } - }, 50); // 调整速度为50ms/字符 + // let index6 = 0; + // const typingInterval6 = setInterval(() => { + // if (index6 < ac6.length) { + // aiMessage6.content += ac6.charAt(index6); + // index6++; + // } else { + // clearInterval(typingInterval6); + // aiMessage6.isTyping = false; + + // } + // }, 50); // 调整速度为50ms/字符 + addTypingTask(aiMessage6, ac6, 100); // chatStore.messages.push({ // sender: "ai", @@ -921,8 +1088,9 @@ watch( // sender: "ai", // content: "AI思考失败,请稍后再试... ", // }); - chatStore.setLoading(false); + // chatStore.setLoading(false); } finally { + chatStore.setLoading(false); await chatStore.getUserCount(); } } diff --git a/src/views/homePage.vue b/src/views/homePage.vue index e8e034c..1b540e7 100644 --- a/src/views/homePage.vue +++ b/src/views/homePage.vue @@ -238,7 +238,7 @@ const smoothScrollToBottom = async () => { } }; -const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 500, { +const throttledSmoothScrollToBottom = _.throttle(smoothScrollToBottom, 300, { trailing: false, }); @@ -306,7 +306,7 @@ const fnGetToken = () => { }; // console.log('出来了') // 触发App桥接 - useAppBridge().packageFun("JWwebReady", () => { }, 5, {}); + useAppBridge().packageFun("JWwebReady", () => {}, 5, {}); }; // 在setTimeout中延迟执行 @@ -323,7 +323,7 @@ const heightListener = () => { // 新增底部判断逻辑 const isBottom = - aftertop + tabContainer.offsetHeight + 50 >= tabContainer.scrollHeight; + aftertop + tabContainer.offsetHeight + 70 >= tabContainer.scrollHeight; if (activeTab.value === "AIchat") { if (aftertop - befortop > 0) { @@ -526,8 +526,16 @@ onMounted(async () => {