diff --git a/README.md b/README.md index 9570926..1d221de 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,4 @@ npm install html-to-text npm install echarts npm install lodash 安装 lodash 组件,解决数据处理问题 npm install vue-device-detect 安装 vue-device-detect 组件,解决移动端适配问题 -npm install moment 安装 moment 组件,解决时间处理问题 \ No newline at end of file +npm install moment 安装 moment 组件,解决时间处理问题 diff --git a/src/assets/img/AIchat/PCbackPic.png b/src/assets/img/AIchat/PCbackPic.png new file mode 100644 index 0000000..45d7b41 Binary files /dev/null and b/src/assets/img/AIchat/PCbackPic.png differ diff --git a/src/assets/img/AIchat/new-app-bgc.png b/src/assets/img/AIchat/new-app-bgc.png new file mode 100644 index 0000000..e583cc0 Binary files /dev/null and b/src/assets/img/AIchat/new-app-bgc.png differ diff --git a/src/store/dataList.js b/src/store/dataList.js index 739761e..193dd0c 100644 --- a/src/store/dataList.js +++ b/src/store/dataList.js @@ -1,196 +1,218 @@ - -import { defineStore } from 'pinia' -import { ref, watch } from 'vue' -import { useUserStore } from './userPessionCode' -import { useLanguage } from '@/utils/languageService' -import { dataListAPI } from '@/api/AIxiaocaishen' +import { defineStore } from "pinia"; +import { ref, watch } from "vue"; +import { useUserStore } from "./userPessionCode"; +import { useLanguage } from "@/utils/languageService"; +import { dataListAPI } from "@/api/AIxiaocaishen"; // import { useSkeletonStore } from '@/utils/skeletonLoader' -import { useRoute } from 'vue-router' +import { useRoute } from "vue-router"; // const skeletonStore = useSkeletonStore() // const { t } = useLanguage() -export const useDataStore = defineStore('data', () => { - const route = useRoute() - console.log(route, '地址栏携带的参数。。。。。。') - const userStore = useUserStore() - const brainDataList = ref(null) - const swordDataList = ref(null) - const priceDataList = ref(null) - const timeDataList = ref(null) - const showALLData = ref(null) - const HomePage = ref(null) - const AIBull = ref(null) - const AIGoldBull = ref(null) - const AIRadar = ref(null) - const loading = ref(false) - const klineData = ref(null) - const activeTabIndex = ref(null) - const isFeedback = ref(false) // 用于控制是否显示反馈页面的标志 - const setKlineData = (data) => { - klineData.value = data - } +export const useDataStore = defineStore("data", () => { + const route = useRoute(); + console.log(route, "地址栏携带的参数。。。。。。"); + const userStore = useUserStore(); + const brainDataList = ref(null); + const swordDataList = ref(null); + const priceDataList = ref(null); + const timeDataList = ref(null); + const showALLData = ref(null); + const HomePage = ref(null); + const AIBull = ref(null); + const AIGoldBull = ref(null); + const AIRadar = ref(null); + const loading = ref(false); + const klineData = ref(null); + const activeTabIndex = ref(null); + const isFeedback = ref(false); // 用于控制是否显示反馈页面的标志 + const setKlineData = (data) => { + klineData.value = data; + }; - const setActiveTabIndex = (index) => { - activeTabIndex.value = index - } + const setActiveTabIndex = (index) => { + activeTabIndex.value = index; + }; - const getQueryVariable = (variable) => { - const query = window.location.search.substring(1) - // console.log(query,'query') - const vars = query.split('&') - // console.log(vars,'vars') - for (let i = 0; i < vars.length; i++) { - const pair = vars[i].split('=') - if (pair[0] === variable) { - return pair[1] - } - } - return '' + const getQueryVariable = (variable) => { + const query = window.location.search.substring(1); + // console.log(query,'query') + const vars = query.split("&"); + // console.log(vars,'vars') + for (let i = 0; i < vars.length; i++) { + const pair = vars[i].split("="); + if (pair[0] === variable) { + return pair[1]; + } } + return ""; + }; - // const getAnswer = (result) => { - // const data = result.data; - // const vars = query.split('&') - // for (let i = 0; i < vars.length; i++) { - // const pair = vars[i].split('=') - // if (pair[0] === variable) { - // return pair[1] - // } - // } - // return '' - // } + // const getAnswer = (result) => { + // const data = result.data; + // const vars = query.split('&') + // for (let i = 0; i < vars.length; i++) { + // const pair = vars[i].split('=') + // if (pair[0] === variable) { + // return pair[1] + // } + // } + // return '' + // } - // 使用示例,获取地址栏参数 - // const token = ref(getQueryVariable('token')) - // const market = ref(getQueryVariable('market')) - // const code = ref(getQueryVariable('code')) - // console.log(token.value) // 输出 token 的值,例如 "111" - // const fetchChartData = async () => { - // const getTokenString = String(localStorage.getItem('localToken')) - // const getMarketString = String(localStorage.getItem('localMarket')) - // const getCodeString = String(localStorage.getItem('localCode')) - // // const getMarket = String() - // try { - // const res = await dataListAPI({ - // token: getTokenString || '', - // market: getMarket() || getMarketString || 'gb', - // code: getQueryVariable('code') || getCodeString || 'NDX', - // language: 'cn', //t.value.suoxie, - // brainPrivilegeState: userStore.brainPerssion, - // swordPrivilegeState: userStore.swordPerssion, - // stockForecastPrivilegeState: userStore.pricePerssion, - // spaceForecastPrivilegeState: userStore.timePerssion, - // aibullPrivilegeState: userStore.aibullPerssion, - // aigoldBullPrivilegeState: userStore.aiGnbullPerssion, - // airadarPrivilegeState: userStore.airadarPerssion, - // marketList: userStore.aiGoldMarketList - // }) + // 使用示例,获取地址栏参数 + const token = ref(getQueryVariable("token")); + const market = ref(getQueryVariable("market")); + const code = ref(getQueryVariable("code")); + console.log(token.value); // 输出 token 的值,例如 "111" + const fetchChartData = async (market,code) => { + const getTokenString = String(localStorage.getItem("localToken")); + // const getMarketString = String(localStorage.getItem("localMarket")); + // const getCodeString = String(localStorage.getItem("localCode")); + // const getMarket = String() + try { + const res = await dataListAPI({ + token: getTokenString || "", + market: market || "gb", + code: code || "NDX", + language: "cn", //t.value.suoxie, + brainPrivilegeState: userStore.brainPerssion, + swordPrivilegeState: userStore.swordPerssion, + stockForecastPrivilegeState: userStore.pricePerssion, + spaceForecastPrivilegeState: userStore.timePerssion, + aibullPrivilegeState: userStore.aibullPerssion, + aigoldBullPrivilegeState: userStore.aiGnbullPerssion, + airadarPrivilegeState: userStore.airadarPerssion, + marketList: userStore.aiGoldMarketList, + }); - // brainDataList.value = res.data.Brain - // swordDataList.value = res.data.Sword - // priceDataList.value = res.data.StockForecast - // timeDataList.value = res.data.SpaceForecast - // showALLData.value = res.data.ShowAll - // HomePage.value = res.data.HomePage - // AIBull.value = res.data.AIBull - // AIGoldBull.value = res.data.AIGoldBull - // AIRadar.value = res.data.AIRadar - // } catch (error) { - // console.error('获取图表数据出错:', error) - // } finally { - // loading.value = false - // console.log('数据获取过程结束') - // } - // } + brainDataList.value = res.data.Brain; + swordDataList.value = res.data.Sword; + priceDataList.value = res.data.StockForecast; + timeDataList.value = res.data.SpaceForecast; + showALLData.value = res.data.ShowAll; + HomePage.value = res.data.HomePage; + AIBull.value = res.data.AIBull; + AIGoldBull.value = res.data.AIGoldBull; + AIRadar.value = res.data.AIRadar; + } catch (error) { + console.error("获取图表数据出错:", error); + } finally { + loading.value = false; + console.log("数据获取过程结束"); + } + }; - // 获取路径上market的值 - const getMarket = () => { - let market = '' - const queryMarket = getQueryVariable('market') - if (queryMarket) { - if ( - ['sg', 'my', 'in', 'hk', 'th', 'vi', 'usa', 'can', 'gb', 'cn'].includes(queryMarket) - ) { - return queryMarket - } else { - switch (queryMarket) { - case 'SGX': return 'sg' - case 'BMB': return 'my' - case 'IDX': return 'in' - case 'HKEX': return 'hk' - case 'SET': return 'th' - case 'HN': return 'vi' - case 'HONSE': return 'vi' - case 'AMERA': return 'usa' - case 'NYSE': return 'usa' - case 'NASDAQ': return 'usa' - case 'DLD': return 'can' - case 'DLDCY': return 'can' - case 'GINDEX': return 'gb' - case 'BZ': return 'cn' - case 'SH': return 'cn' - case 'SZ': return 'cn' - default: return '无市场数据' - } - } + // 获取路径上market的值 + const getMarket = () => { + let market = ""; + const queryMarket = getQueryVariable("market"); + if (queryMarket) { + if ( + ["sg", "my", "in", "hk", "th", "vi", "usa", "can", "gb", "cn"].includes( + queryMarket + ) + ) { + return queryMarket; + } else { + switch (queryMarket) { + case "SGX": + return "sg"; + case "BMB": + return "my"; + case "IDX": + return "in"; + case "HKEX": + return "hk"; + case "SET": + return "th"; + case "HN": + return "vi"; + case "HONSE": + return "vi"; + case "AMERA": + return "usa"; + case "NYSE": + return "usa"; + case "NASDAQ": + return "usa"; + case "DLD": + return "can"; + case "DLDCY": + return "can"; + case "GINDEX": + return "gb"; + case "BZ": + return "cn"; + case "SH": + return "cn"; + case "SZ": + return "cn"; + default: + return "无市场数据"; } - return '' + } } + return ""; + }; - const isLoading = ref(true) - const initData = async () => { - isLoading.value = true - try { - // 初始化逻辑 - } catch (error) { - console.error('Error loading data:', error) - } finally { - isLoading.value = false - } + const isLoading = ref(true); + const initData = async () => { + isLoading.value = true; + try { + // 初始化逻辑 + } catch (error) { + console.error("Error loading data:", error); + } finally { + isLoading.value = false; } + }; - // watch( - // () => [userStore.isReady, t.value?.suoxie], - // ([isReady]) => { - // console.log('isReady 或 language 变化:', isReady) - // if (isReady) { - // setTimeout(() => fetchChartData(), 500) - // } - // }, - // { immediate: true, deep: true } - // ) + // watch( + // () => [userStore.isReady, t.value?.suoxie], + // ([isReady]) => { + // console.log('isReady 或 language 变化:', isReady) + // if (isReady) { + // setTimeout(() => fetchChartData(), 500) + // } + // }, + // { immediate: true, deep: true } + // ) - // watch(() => route.query, () => { - // if (route.query.market || route.query.code) { - // fetchChartData() - // } - // }) + watch( + () => window.location.ancestorOrigins, + (newQuery, oldQuery) => { + console.log("newQuery", newQuery); + // if () { + // fetchChartData(); + // } + } + ); - // watch(() => userStore.aibullPerssion, (newValue) => { - // if (newValue === 1) fetchChartData() - // }) + // watch(() => userStore.aibullPerssion, (newValue) => { + // if (newValue === 1) fetchChartData() + // }) - initData() + initData(); - return { - // brainDataList, - // swordDataList, - // priceDataList, - // timeDataList, - // showALLData, - // HomePage, - // AIBull, - // AIGoldBull, - // loading, - // AIRadar, - // fetchChartData, - activeTabIndex, - klineData, - setKlineData, - initData, - getMarket, - getQueryVariable, - setActiveTabIndex, - isFeedback - } -}) + return { + // brainDataList, + // swordDataList, + // priceDataList, + // timeDataList, + // showALLData, + HomePage, + // AIBull, + AIGoldBull, + // loading, + // AIRadar, + fetchChartData, + activeTabIndex, + klineData, + setKlineData, + initData, + getMarket, + getQueryVariable, + setActiveTabIndex, + isFeedback, + }; +}); diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue index 44a9343..5644f3b 100644 --- a/src/views/AIchat.vue +++ b/src/views/AIchat.vue @@ -11,6 +11,7 @@ import { dbqbSecondTwoAPI, dbqbSecondThreeAPI, dbqbSecondFourAPI, + dataListAPI, } from "../api/AIxiaocaishen"; import { useUserStore } from "../store/userPessionCode"; import { useChatStore } from "../store/chat"; @@ -21,6 +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 moment from "moment"; import AIgif1 from "@/assets/img/AIchat/AIgif1.gif"; @@ -42,6 +44,14 @@ const dataStore = useDataStore(); // 随机GIF const currentGif = ref(""); +const renderer = new marked.Renderer(); +// 重写 del 方法,让删除线不生效 +renderer.del = function (text) { + // 处理各种数据类型 + console.log("text", text); + return "~" + text.tokens[0].raw + "
" + text.tokens[2].raw + "~"; +}; + // 定义自定义事件 const emit = defineEmits(["updateMessage", "sendMessage"]); @@ -174,6 +184,34 @@ const typeWriter = (text, callback) => { }, 50); // 调整速度(毫秒) }; +const fnGetData = (data) => { + const YaLiZhiChengLuoPan = data.YaLiZhiChengLuoPan; + let sz = ref(5.5); // 进行判断 + const yl = YaLiZhiChengLuoPan.Yali; // 压力位 + const zc = YaLiZhiChengLuoPan.ZhiCheng; // 支撑位 + console.log("yl", yl, "zc", zc); + if (yl == "较大" && zc == "较弱") { + sz.value = 0.5; // 极高风险 + } else if (yl == "一般" && zc == "较弱") { + sz.value = 1.5; // 弱撑中压区 + } else if (yl == "较弱" && zc == "较弱") { + sz.value = 2.5; // 弱撑弱压区 + } else if (yl == "较大" && zc == "较大") { + sz.value = 3.5; // 强撑强压区 + } else if (yl == "一般" && zc == "较大") { + sz.value = 4.5; // 强撑中压 + } else if (yl == "较弱" && zc == "较大") { + sz.value = 5.5; // 强撑弱压区 + } else if (yl == "较大" && zc == "一般") { + sz.value = 0.2; + } else if (yl == "一般" && zc == "一般") { + sz.value = 3; + } else if (yl == "较弱" && zc == "一般") { + sz.value = 5.8; + } + return sz.value; +}; + const hasValidData = ref(false); // 创建一个非响应式的对象来存储图表实例 @@ -205,18 +243,13 @@ watch( const userStore = useUserStore(); const params1 = { - workflow_id: "7514939889071718438", - parameters: { - content: newVal[newVal.length - 1].content, - userData: { - language: "cn", - marketList: "hk,cn,usa,my,sg,vi,in,gb", - token: localStorage.getItem("localToken"), - // language: "cn", - // marketList: "hk,cn,usa,my,sg,vi,in,gb" - // token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", - }, - }, + content: newVal[newVal.length - 1].content, + language: "cn", + marketList: "hk,cn,usa,my,sg,vi,in,gb", + token: localStorage.getItem("localToken"), + // language: "cn", + // marketList: "hk,cn,usa,my,sg,vi,in,gb" + // token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", }; // 标志 let flag = true; @@ -272,51 +305,49 @@ watch( if (flag) { const params2 = { content: newVal[newVal.length - 1].content, - userData: { - aibullPrivilegeState: 1, - aigoldBullPrivilegeS: 1, - airadarPrivilegeStat: 1, - brainPrivilegeState: 1, - spaceForecastPrivile: 1, - stockForecastPrivile: 1, - swordPrivilegeState: 1, - language: "cn", - marketList: "hk,cn,usa,my,sg,vi,in,gb", - token: localStorage.getItem("localToken"), - // aibullPrivilegeState: userStore.aibullPrivilegeState, - // aigoldBullPrivilegeState: userStore.aigoldBullPrivilegeState, - // airadarPrivilegeState: userStore.airadarPrivilegeState, - // brainPrivilegeState: userStore.brainPrivilegeState, - // spaceForecastPrivilegeState: userStore.spaceForecastPrivilegeState, - // stockForecastPrivilegeState: userStore.stockForecastPrivilegeState, - // swordPrivilegeState: userStore.swordPrivilegeState, - // language: "cn", - // marketList: "hk,cn,usa,my,sg,vi,in,gb" - // token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", - }, + language: "cn", + marketList: "hk,cn,usa,my,sg,vi,in,gb", + token: localStorage.getItem("localToken"), + // language: "cn", + // marketList: "hk,cn,usa,my,sg,vi,in,gb" + // token: "+SsksARQgUHIbIG3rRnnbZi0+fEeMx8pywnIlrmTxo5EOPR/wjWDV7w7+ZUseiBtf9kFa/atmNx6QfSpv5w", name: codeData.value.name, code: codeData.value.code, market: codeData.value.market, }; try { - const result21 = await dbqbSecondOneAPI({ - workflow_id: "7514945685688025127", - parameters: params2, - }); - const result22 = await dbqbSecondTwoAPI({ - workflow_id: "7514945728733888575", - parameters: params2, - }); - const result23 = await dbqbSecondThreeAPI({ - workflow_id: "7514945758421811254", - parameters: params2, - }); - const result24 = await dbqbSecondFourAPI({ - workflow_id: "7514945791469223955", - parameters: params2, + const result20 = await dataListAPI({ + token: localStorage.getItem("localToken"), + market: codeData.value.market, + code: codeData.value.code, + language: "cn", //t.value.suoxie, + // brainPrivilegeState: 1, + // swordPrivilegeState: 1, + // stockForecastPrivilegeState: 1, + // spaceForecastPrivilegeState: 1, + // aibullPrivilegeState: 1, + // aigoldBullPrivilegeState: 1, + // airadarPrivilegeState: 1, + // marketList: 1, + brainPrivilegeState: userStore.brainPerssion, + swordPrivilegeState: userStore.swordPerssion, + stockForecastPrivilegeState: userStore.pricePerssion, + spaceForecastPrivilegeState: userStore.timePerssion, + aibullPrivilegeState: userStore.aibullPerssion, + aigoldBullPrivilegeState: userStore.aiGnbullPerssion, + airadarPrivilegeState: userStore.airadarPerssion, + marketList: userStore.aiGoldMarketList, }); + const HomePage = result20.data.HomePage; + const AIGoldBull = result20.data.AIGoldBull; + + const result21 = await dbqbSecondOneAPI(params2); + const result22 = await dbqbSecondTwoAPI(params2); + const result23 = await dbqbSecondThreeAPI(params2); + const result24 = await dbqbSecondFourAPI(params2); + const katexRegex = /\$\$(.*?)\$\$/g; // 删除正在为您生成信息 chatStore.messages.pop(); @@ -335,7 +366,7 @@ watch( "\n" + result21.data.price + "\n" + - result21.data.data + result21.data.date ); const ac1 = pc1.replace(katexRegex, (match, formula) => { try { @@ -346,20 +377,157 @@ watch( } }); - chatStore.messages.push({ + // 先推送初始消息 + const aiMessage1 = reactive({ sender: "ai", class: "content1", type: "content1", - content: ac1, + content: "", + isTyping: true, }); + 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/字符 + + // chatStore.messages.push({ + // sender: "ai", + // class: "content1", + // type: "content1", + // content: ac1, + // }); // 添加六色罗盘 + const LiuSeData = JSON.parse(JSON.stringify(toRaw(HomePage))); + const sz = fnGetData(LiuSeData); + if (sz) { + hasValidData.value = true; + console.log("hasValidData设置为:", hasValidData.value); + } + // 先推送K线图消息 + 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, + }); + + 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 === klineMessageId1) { + 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线消息"); + } + }); + + // 度牛尺K线图 + const AIGoldBullData = JSON.parse(JSON.stringify(toRaw(AIGoldBull))); + const HomePageData = JSON.parse(JSON.stringify(toRaw(HomePage))); + console.log("处理 K 线数据 - 开始"); + console.log("AIGoldBullData", AIGoldBullData); + console.log("HomePageData", HomePageData); + + const Kline20 = { + name: HomePageData.StockInformation.Name, + Kline: AIGoldBullData, + }; + + // 打印K线数据结构 + console.log("K线数据结构:", Kline20); + console.log("K线数据名称:", Kline20.name); + console.log("K线数据:", Kline20.Kline ? Kline20.Kline : null); + + // 设置数据有效标志 + hasValidData.value = true; + console.log("hasValidData设置为:", hasValidData.value); + + // chatStore.messages.pop(); + + // 先推送K线图消息 + const klineMessageId2 = `kline-${Date.now() + 1}`; + console.log("生成K线消息ID:", klineMessageId2); + chatStore.messages.push({ sender: "ai", class: "content2", type: "content2", - content: "K线图", + kline: true, + chartData: Kline20, + messageId: klineMessageId2, + hasValidData: true, // 添加hasValidData标志 + klineType: 2, }); - // 度牛尺K线图 + + 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 === klineMessageId2) { + 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线消息"); + } + }); + // 添加标题2 chatStore.messages.push({ sender: "ai", @@ -378,12 +546,34 @@ watch( return match; } }); - chatStore.messages.push({ + + // 先推送初始消息 + const aiMessage2 = reactive({ sender: "ai", class: "content3", type: "content3", - content: ac2, + 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({ + // sender: "ai", + // class: "content3", + // type: "content3", + // content: ac2, + // }); // 添加标题3-2 chatStore.messages.push({ sender: "ai", @@ -405,12 +595,51 @@ watch( // } // ); const ac3 = `

【主力行为】

${result23.data.zhuli1}

${result23.data.zhuli2}

${result23.data.zhuli3}

`; - chatStore.messages.push({ + + // 先推送初始消息 + const aiMessage3 = reactive({ sender: "ai", class: "content3", type: "content3", - content: ac3, + content: "", + isTyping: true, }); + 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/字符 + + // chatStore.messages.push({ + // sender: "ai", + // class: "content3", + // type: "content3", + // content: ac3, + // }); // 添加标题3-3 chatStore.messages.push({ sender: "ai", @@ -440,12 +669,51 @@ watch( // return match; // } // }); - chatStore.messages.push({ + + // 先推送初始消息 + const aiMessage4 = reactive({ sender: "ai", class: "content3", type: "content3", - content: ac4, + content: "", + isTyping: true, }); + 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/字符 + + // chatStore.messages.push({ + // sender: "ai", + // class: "content3", + // type: "content3", + // content: ac4, + // }); // 添加标题3-4 chatStore.messages.push({ sender: "ai", @@ -467,191 +735,184 @@ watch( // return match; // } // }); - chatStore.messages.push({ + + // 先推送初始消息 + const aiMessage5 = reactive({ sender: "ai", class: "content3", type: "content3", - content: ac5, + content: "", + isTyping: true, }); + chatStore.messages.push(aiMessage5); - chatStore.messages.push({ + 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/字符 + + // chatStore.messages.push({ + // sender: "ai", + // class: "content3", + // type: "content3", + // content: ac5, + // }); + + const ac6 = "内容由AI生成,请注意甄别"; + // 先推送初始消息 + const aiMessage6 = reactive({ sender: "ai", class: "mianze", type: "mianze", - content: "内容由AI生成,请注意甄别", - }); - - // 调用工作流获取回复 - const result = await getReplyAPI(params1); - // 获取结果 - const ans = ref(); - await result.then((res) => { - // 解析 data 字段中的 JSON - ans.value = JSON.parse(res.data); + content: "", + isTyping: true, }); - const AIcontent = ref(""); - // 处理不同的 answer 字段 - - if (ans.value.resp !== "" && ans.value.resp !== null) { - } else { - // 判断是否是股票问题 - if (ans.value.answer !== "") { - AIcontent.value = ans.value.answer; - const type = ans.value.type; - const data = JSON.parse(ans.value.data); - - console.log("处理 K 线数据 - 开始"); - console.log(data, "data"); - - const Kline20 = { - name: data.data.HomePage.StockInformation.Name, - Kline: data.data, - type: type, - }; - - // 打印K线数据结构 - console.log("K线数据结构:", Kline20); - console.log("K线数据名称:", Kline20.name); - console.log("K线数据类型:", Kline20.type); - console.log("K线数据:", Kline20.Kline ? Kline20.Kline : null); - - // 设置数据有效标志 - hasValidData.value = true; - console.log("hasValidData设置为:", hasValidData.value); - - // chatStore.messages.pop(); - - // 先推送K线图消息 - const klineMessageId = `kline-${Date.now()}`; - console.log("生成K线消息ID:", klineMessageId); - - chatStore.messages.push({ - sender: "ai", - type: "kline", - chartData: Kline20, - messageId: klineMessageId, - hasValidData: true, // 添加hasValidData标志 - }); + chatStore.messages.push(aiMessage6); - console.log("K线消息已添加到聊天列表"); + 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(() => { - 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 === klineMessageId) { - klineIndex = i; - break; + aiMessage6.content = aiMessage6.content.replace( + katexRegex, + (match, formula) => { + try { + return katex.renderToString(formula, { + throwOnError: false, + }); + } catch (error) { + console.error("KaTeX 渲染错误:", error); + return match; + } } - } - - 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线消息"); - } + ); }); } + }, 50); // 调整速度为50ms/字符 - // 修改后的消息处理逻辑 - const processedContent = marked(AIcontent.value); - const katexRegex = /\$\$(.*?)\$\$/g; - const plainTextContent = htmlToText(processedContent); - - // 获取音频数据 - const TTSResult = ( - await TTSAPI({ - language: "cn", - content: plainTextContent, - }) - ).json(); - - const tts = ref(); - await TTSResult.then((res) => { - tts.value = JSON.parse(res.data); - }); - - const ttsUrl = ref(); - if (tts.value.tts_cn !== null) { - audioStore.ttsUrl = tts.value.tts_cn.url; - ttsUrl.value = tts.value.tts_cn.url; - audioStore.isNewInstance = true; - } else if (tts.value.tts_en !== null) { - audioStore.ttsUrl = tts.value.tts_en.url; - ttsUrl.value = tts.value.tts_en.url; - audioStore.isNewInstance = true; - } + // chatStore.messages.push({ + // sender: "ai", + // class: "mianze", + // type: "mianze", + // content: "内容由AI生成,请注意甄别", + // }); - if (ttsUrl.value) { - nextTick(() => { - if (audioStore.isVoiceEnabled) { - console.log("ttsUrl.value", ttsUrl.value); - // 播放音频 - playAudio(ttsUrl.value); - } - }); - } + // // 修改后的消息处理逻辑 + // const processedContent = marked(AIcontent.value); + // const katexRegex = /\$\$(.*?)\$\$/g; + // const plainTextContent = htmlToText(processedContent); + + // // 获取音频数据 + // const TTSResult = ( + // await TTSAPI({ + // language: "cn", + // content: plainTextContent, + // }) + // ).json(); + + // const tts = ref(); + // await TTSResult.then((res) => { + // tts.value = JSON.parse(res.data); + // }); + + // const ttsUrl = ref(); + // if (tts.value.tts_cn !== null) { + // audioStore.ttsUrl = tts.value.tts_cn.url; + // ttsUrl.value = tts.value.tts_cn.url; + // audioStore.isNewInstance = true; + // } else if (tts.value.tts_en !== null) { + // audioStore.ttsUrl = tts.value.tts_en.url; + // ttsUrl.value = tts.value.tts_en.url; + // audioStore.isNewInstance = true; + // } - // chatStore.messages.pop(); - // 先推送初始消息 - const aiMessage = reactive({ - sender: "ai", - content: "", - isTyping: true, - }); - chatStore.messages.push(aiMessage); - - let index = 0; - const typingInterval = setInterval(() => { - if (index < processedContent.length) { - aiMessage.content += processedContent.charAt(index); - index++; - } else { - clearInterval(typingInterval); - aiMessage.isTyping = false; - - // 延迟处理KaTeX确保DOM已更新 - nextTick(() => { - aiMessage.content = aiMessage.content.replace( - katexRegex, - (match, formula) => { - try { - return katex.renderToString(formula, { - throwOnError: false, - }); - } catch (error) { - console.error("KaTeX 渲染错误:", error); - return match; - } - } - ); - chatStore.setLoading(false); - }); - } - }, 50); // 调整速度为50ms/字符 - // } else { - // chatStore.messages.pop(); - // chatStore.messages.push({ - // sender: "ai", - // content: status.msg - // }); - - // chatStore.setLoading(false); - // } - } + // if (ttsUrl.value) { + // nextTick(() => { + // if (audioStore.isVoiceEnabled) { + // console.log("ttsUrl.value", ttsUrl.value); + // // 播放音频 + // playAudio(ttsUrl.value); + // } + // }); + // } + + // // chatStore.messages.pop(); + // // 先推送初始消息 + // const aiMessage = reactive({ + // sender: "ai", + // content: "", + // isTyping: true, + // }); + // chatStore.messages.push(aiMessage); + + // let index = 0; + // const typingInterval = setInterval(() => { + // if (index < processedContent.length) { + // aiMessage.content += processedContent.charAt(index); + // index++; + // } else { + // clearInterval(typingInterval); + // aiMessage.isTyping = false; + + // // 延迟处理KaTeX确保DOM已更新 + // nextTick(() => { + // aiMessage.content = aiMessage.content.replace( + // katexRegex, + // (match, formula) => { + // try { + // return katex.renderToString(formula, { + // throwOnError: false, + // }); + // } catch (error) { + // console.error("KaTeX 渲染错误:", error); + // return match; + // } + // } + // ); + // chatStore.setLoading(false); + // }); + // } + // }, 50); // 调整速度为50ms/字符 + // // } else { + // // chatStore.messages.pop(); + // // chatStore.messages.push({ + // // sender: "ai", + // // content: status.msg + // // }); + + // // chatStore.setLoading(false); + // // } + // } } catch (e) { console.error("请求失败:", e); hasValidData.value = false; // 请求失败时设置数据无效 @@ -698,59 +959,12 @@ function KlineCanvsEcharts(containerId) { klineMessageIndex = containerId.split("-")[2]; console.log("KLine渲染: 找到K线消息索引:", klineMessageIndex); if ( - messages[klineMessageIndex].type === "kline" && + messages[klineMessageIndex].kline && messages[klineMessageIndex].chartData ) { klineData = messages[klineMessageIndex].chartData; } - if (!klineData || !klineData.Kline) { - console.warn("KLine渲染: 数据无效 - 在chatStore中找不到有效的K线数据"); - return; - } - - // 获取容器元素 - const container = document.getElementById(containerId); - if (!container) { - console.error("KLine渲染: 找不到容器元素:", containerId); - return; - } - - // 创建图表实例 - console.log("KLine渲染: 创建图表实例"); - try { - // 如果已有实例,先销毁 - if (chartInstancesMap[containerId]) { - console.log("KLine渲染: 销毁已有图表实例"); - chartInstancesMap[containerId].dispose(); - delete chartInstancesMap[containerId]; - } - - // 使用普通变量存储实例 - chartInstancesMap[containerId] = echarts.init(container); - console.log("KLine渲染: 图表实例创建成功"); - } catch (error) { - console.error("KLine渲染: 图表实例创建失败:", error); - return; - } - - const data = klineData.Kline.AIGoldBull; - console.log("KLine渲染: Kline数据", data); - - // 切割数据方法 - const splitData = (a) => { - console.log("KLine渲染: 开始数据切割"); - const categoryData = []; - let values = []; - for (let i = 0; i < a.length; i++) { - categoryData.push(a[i][0]); - values.push([a[i][1], a[i][2], a[i][3], a[i][4]]); - } - console.log("KLine渲染: 日期数据点数量", categoryData.length); - console.log("KLine渲染: 值数据点数量", values.length); - return { categoryData, values }; - }; - var KlineOption = {}; // 检测设备类型 @@ -761,18 +975,190 @@ function KlineCanvsEcharts(containerId) { isMobile ? "移动设备" : isTablet ? "平板设备" : "桌面设备" ); - // 给配置项 - console.log("KLine渲染: 开始配置图表选项"); + if (messages[klineMessageIndex].klineType == 1) { + if (!klineData) { + console.warn("六色罗盘渲染: 数据无效 - 在chatStore中找不到有效的K线数据"); + return; + } + + // 获取容器元素 + const container = document.getElementById(containerId); + if (!container) { + console.error("六色罗盘渲染: 找不到容器元素:", containerId); + return; + } + + // 创建图表实例 + console.log("六色罗盘渲染: 创建图表实例"); + + try { + // 如果已有实例,先销毁 + if (chartInstancesMap[containerId]) { + console.log("六色罗盘渲染: 销毁已有图表实例"); + chartInstancesMap[containerId].dispose(); + delete chartInstancesMap[containerId]; + } + + // 使用普通变量存储实例 + chartInstancesMap[containerId] = echarts.init(container); + console.log("六色罗盘渲染: 图表实例创建成功"); + } catch (error) { + console.error("六色罗盘渲染: 图表实例创建失败:", error); + return; + } + + const name = ref("六色罗盘"); + const size = ref(16); + // PC版字体大小 + if (window.innerWidth > 768) { + size.value = 25; + } + + KlineOption = { + tooltip: { + show: !1, + }, + series: [ + { + name: "\u4eea\u8868\u76d8", + type: "gauge", + center: ["50%", "50%"], + radius: "90%", + startAngle: 140, + endAngle: -140, + min: 0, + max: 6, + precision: 0, + splitNumber: 30, // 分成30份 + axisLine: { + show: !0, + lineStyle: { + color: [ + [0.17, "#FC4407"], + [0.33, "#FDC404"], + [0.5, "#2D8FFD"], + [0.67, "#87CCE7"], + [0.83, "#C1F478"], + [1, "#8FEB8D"], + ], + width: 20, + }, + }, + axisTick: { + show: !0, + splitNumber: 9, + length: 8, + lineStyle: { + color: "#eee", + width: 1, + type: "solid", + }, + }, + axisLabel: { + show: true, + formatter: function (v) {}, + textStyle: { + color: "auto", + }, + }, + // 中途切割 + splitLine: { + show: !0, + length: 20, + lineStyle: { + color: "#eee", + width: 2, + type: "solid", + }, + }, + pointer: { + length: "80%", + width: 8, + color: "auto", + }, + title: { + show: !0, + offsetCenter: ["-65%", -10], + textStyle: { + color: "#333", + fontSize: 15, + }, + }, + detail: { + show: !0, + backgroundColor: "rgba(0,0,0,0)", + borderWidth: 0, + borderColor: "#ccc", + width: 100, + height: 40, + offsetCenter: ["-90%", 0], // name位置 + formatter: function () { + return name.value; + }, + textStyle: { + color: "auto", + fontSize: size.value, // 字体尺寸 + }, + }, + data: [{ value: klineData }], + }, + ], + }; + } else if (messages[klineMessageIndex].klineType == 2) { + if (!klineData || !klineData.Kline) { + console.warn("KLine渲染: 数据无效 - 在chatStore中找不到有效的K线数据"); + return; + } + + // 获取容器元素 + const container = document.getElementById(containerId); + if (!container) { + console.error("KLine渲染: 找不到容器元素:", containerId); + return; + } + + // 创建图表实例 + console.log("KLine渲染: 创建图表实例"); + try { + // 如果已有实例,先销毁 + if (chartInstancesMap[containerId]) { + console.log("KLine渲染: 销毁已有图表实例"); + chartInstancesMap[containerId].dispose(); + delete chartInstancesMap[containerId]; + } + + // 使用普通变量存储实例 + chartInstancesMap[containerId] = echarts.init(container); + console.log("KLine渲染: 图表实例创建成功"); + } catch (error) { + console.error("KLine渲染: 图表实例创建失败:", error); + return; + } + + const data = klineData.Kline; + console.log("KLine渲染: Kline数据", data); + + // 切割数据方法 + const splitData = (a) => { + console.log("KLine渲染: 开始数据切割"); + const categoryData = []; + let values = []; + for (let i = 0; i < a.length; i++) { + categoryData.push(a[i][0]); + values.push([a[i][1], a[i][2], a[i][3], a[i][4]]); + } + console.log("KLine渲染: 日期数据点数量", categoryData.length); + console.log("KLine渲染: 值数据点数量", values.length); + return { categoryData, values }; + }; - if (klineData.type === 1) { - console.log("进入第一分类"); + // 给配置项 + console.log("KLine渲染: 开始配置图表选项"); const arr1 = []; const arr2 = []; const arr3 = []; const arr4 = []; - - // 动态K线 const changeColorKline = (QSXH, KLine20) => { if (QSXH) { QSXH.map((item) => { @@ -913,25 +1299,16 @@ function KlineCanvsEcharts(containerId) { }); } }; + console.log(arr1, arr2, arr3, arr4); changeColorKline(data.QSXH, data.KLine20); var dealData = splitData(data.KLine20); var dealData1 = splitData(arr1); var dealData2 = splitData(arr2); var dealData3 = splitData(arr3); var dealData4 = splitData(arr4); - - console.log("dealData", dealData); - console.log("dealData1", dealData1); - console.log("dealData2", dealData2); - console.log("dealData3", dealData3); - console.log("dealData4", dealData4); - - var dealGnBullData = data.JN; //金牛版成交量数据 - // 处理MA数据,创建两段重叠的数据 + var dealGnBullData = data.JN; function processMAData(data) { let processedData = []; - - // 初始化处理后的数据结构 data.forEach((item, idx) => { processedData.push({ date: item[0], @@ -943,7 +1320,6 @@ function KlineCanvsEcharts(containerId) { let singleTypeRed = [{ min: 0, max: 0, color: "#000" }]; let singleTypeYellow = [{ min: 0, max: 0, color: "#000" }]; let singleTypeGreen = [{ min: 0, max: 0, color: "#000" }]; - // 在类型切换点添加过渡点 for (let i = 1; i < processedData.length; i++) { if (processedData[i].type !== processedData[i - 1].type) { if ( @@ -984,7 +1360,6 @@ function KlineCanvsEcharts(containerId) { // processedData[i - 1].isTransition = true } } - // 分离红绿数据,包含过渡点 let greenData = []; let redData = []; let yellowData = []; @@ -998,11 +1373,9 @@ function KlineCanvsEcharts(containerId) { yellowData.push([item.date, "-"]); // if (item.isTransition) { - // // 添加过渡点到红色线 - // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] - // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] + // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] + // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] // } - if (item.isTransitionGreen) { greenData[greenData.length - 1] = [ processedData[idx].date, @@ -1025,11 +1398,9 @@ function KlineCanvsEcharts(containerId) { yellowData.push([item.date, "-"]); // if (item.isTransition) { - // // 添加过渡点到绿色线 - // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] - // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] + // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] + // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] // } - if (item.isTransitionGreen) { greenData[greenData.length - 1] = [ processedData[idx].date, @@ -1052,11 +1423,9 @@ function KlineCanvsEcharts(containerId) { yellowData.push(point); // if (item.isTransition) { - // // 添加过渡点到绿色线 - // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] - // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] + // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] + // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] // } - if (item.isTransitionGreen) { greenData[greenData.length - 1] = [ processedData[idx].date, @@ -1086,84 +1455,77 @@ function KlineCanvsEcharts(containerId) { }; } const maData = processMAData(data.FCX); - console.log("maData", maData); - // 牵牛绳的数据 - - // 如果第一个字段的第一个数据为-1的话,不展示牵牛绳 + const maDuchiData = processMAData(data.DNC); if (data.FCX[0][1] == "-1") { maData.greenData = []; maData.redData = []; maData.yellowData = []; } - // 生成文字标注 const processBarData = (data) => { const barData = []; const markPointData = []; data.forEach((item) => { let color; - // 根据 item[4] 设置不同的颜色 switch (item[4]) { case 1: - color = "#13E113"; // 绿色 + color = "#13E113"; break; case 2: - color = "#FF0E00"; // 红色 + color = "#FF0E00"; break; case 3: - color = "#0000FE"; // 深蓝色(倍量阳) + color = "#0000FE"; break; case 4: - color = "#1397FF"; // 浅蓝色(倍量阴) + color = "#1397FF"; break; } barData.push({ value: item[5], itemStyle: { normal: { - color: color, // 动态设置颜色 + color: color, }, }, }); - // 小牛 + if (item[1] === 1) { markPointData.push({ coord: [item[0], item[5]], symbol: "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujb101000d5si3v3hr7w2vg0h43z1u.png", - symbolSize: [30, 30], // 图片大小 + symbolSize: [30, 30], label: { normal: { - color: "rgba(0, 0, 0, 0)", //字体颜色 + color: "rgba(0, 0, 0, 0)", }, }, }); } - // 大牛 - // 中部标记(红色牛) + if (item[2] === 1) { markPointData.push({ coord: [item[0], item[5] / 2], symbol: "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujaz01000d5si016bxdf6vh0377d2h.png", - symbolSize: [30, 30], // 图片大小 + symbolSize: [30, 30], label: { normal: { - color: "rgba(0, 0, 0, 0)", //字体颜色 + color: "rgba(0, 0, 0, 0)", }, }, }); } - // 金牛 - // 底部标记(金牛) + if (item[3] === 1) { markPointData.push({ coord: [item[0], 0], symbol: "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujb001000d5shzls0tmd4vs0e5tdrw.png", - symbolSize: [30, 30], // 图片大小 + symbolSize: [30, 30], label: { normal: { - color: "rgba(0, 0, 0, 0)", //字体颜色 + color: "rgba(0, 0, 0, 0)", }, }, }); @@ -1172,23 +1534,19 @@ function KlineCanvsEcharts(containerId) { return { barData, markPointData }; }; const { barData, markPointData } = processBarData(dealGnBullData); - // 配置项 KlineOption = { - // 底部选项 - // animation: false, - // 手放上去显示的内容 legend: [ { - //图例文字的样式 textStyle: { - color: "black", //图例文字颜色 - fontSize: window.innerWidth > 768 ? 15 : vwToPx(2.8), // 响应式字体大小 + color: "black", + fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), }, - width: "100%", // 确保有足够的宽度容纳图例 + width: "100%", + top: window.innerWidth > 768 ? "0%" : "-1%", left: "center", - itemGap: window.innerWidth > 768 ? 20 : 10, // 控制图例项之间的间距 - itemWidth: 10, // 调整颜色块的宽度 - itemHeight: 10, // 调整颜色块的高度 + itemGap: window.innerWidth > 768 ? 20 : 10, + itemWidth: 10, + itemHeight: 10, data: [ { name: "进攻K线", @@ -1217,21 +1575,19 @@ function KlineCanvsEcharts(containerId) { ], }, { - //图例文字的样式 textStyle: { - color: "black", //图例文字颜色 - fontSize: window.innerWidth > 768 ? 15 : vwToPx(2.8), // 响应式字体大小 + color: "black", + fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), }, - orient: "horizontal", // 设置图例水平布局 - top: "5%", - width: "100%", // 确保有足够的宽度容纳图例 + orient: "horizontal", + top: window.innerWidth > 768 ? "3%" : "2%", + width: "100%", left: "center", - itemGap: 15, // 控制图例项之间的间距 + itemGap: 15, data: [ - // 牵牛绳 { - name: "{green|━}{red|━} " + "牵牛绳", // 将牵牛绳样式应用到文本前缀 - icon: "none", // 去掉默认图例图标 + name: "{green|━}{red|━} " + "牵牛绳", + icon: "none", textStyle: { rich: { green: { @@ -1253,20 +1609,46 @@ function KlineCanvsEcharts(containerId) { }, ], }, + { + textStyle: { + color: "black", + fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), + }, + orient: "horizontal", + top: window.innerWidth > 768 ? "72%" : "64%", + width: "100%", + left: "center", + itemGap: 15, + data: [ + { + name: "{green|━}{red|━} " + "度牛尺", + icon: "none", + textStyle: { + rich: { + green: { + color: "green", + fontSize: window.innerWidth > 768 ? 20 : 10, + }, + red: { + color: "red", + fontSize: window.innerWidth > 768 ? 20 : 10, + }, + }, + }, + }, + ], + }, ], tooltip: { - // 调用接口之后方法 formatter: function (a, b, d) { if (a[0].seriesIndex == 0) { - const KlineTag = ref([]); // 判断几根K线 + const KlineTag = ref([]); const AIBullTag = ref([]); - - // 找到第一个满足条件的数据 KlineTag.value = a.find((item) => item.data[1])?.data || []; - - // 找到第一个满足条件的非 '-' 数据 AIBullTag.value = a.slice(4).find((item) => item.data[1] !== "-")?.data || []; + // console.log(AIBullTag.value) + return ( a[0].name + "
" + @@ -1290,8 +1672,8 @@ function KlineCanvsEcharts(containerId) { ":" + AIBullTag.value[1] ); - } else { - // 格式化成交量显示 + } + if (a[0].seriesIndex == 4) { let formattedVolume; if (a[0].data.value >= 10000) { formattedVolume = (a[0].data.value / 10000).toFixed(2) + "w"; @@ -1300,30 +1682,35 @@ function KlineCanvsEcharts(containerId) { } return a[0].name + "
" + "成交量" + ":" + formattedVolume; } + if ([10, 11, 12].includes(a[0].seriesIndex)) { + const duchiData = a.find( + (item) => item.data && item.data[1] !== "-" + ); + return duchiData + ? a[0].axisValue + "
" + "度牛尺" + ":" + duchiData.data[1] + : null; + } }, trigger: "axis", axisPointer: { - //坐标轴指示器配置项 - type: "cross", //‘line’直线指示器,‘cross’十字准星指示器,‘shadow’阴影指示器 + type: "cross", }, - backgroundColor: "rgba(119, 120, 125, 0.6)", // 提示框浮层的边框颜色。 - borderWidth: 1, // 提示框浮层的边框宽。 - borderColor: "#77787D", // 提示框浮层的边框颜色。 - padding: 10, // 提示框浮层内边距, + backgroundColor: "rgba(119, 120, 125, 0.6)", + borderWidth: 1, + borderColor: "#77787D", + padding: 10, textStyle: { - //提示框浮层上的文字样式 color: "#fff", }, }, - // 手放上去时拉的框 axisPointer: { link: [ { - xAxisIndex: "all", // 同时触发所有图形的 x 坐标轴指示器 + xAxisIndex: "all", }, ], label: { - backgroundColor: "#77787D", // 文本标签的背景颜色 + backgroundColor: "#77787D", }, }, toolbox: { @@ -1331,18 +1718,24 @@ function KlineCanvsEcharts(containerId) { }, grid: [ { - left: window.innerWidth > 768 ? "18%" : "15%", + // left: window.innerWidth > 768 ? '8%' : '15%', + // right: window.innerWidth > 768 ? '4%' : '2.5%', + top: window.innerWidth > 768 ? "10%" : "5%", + height: window.innerWidth > 768 ? "36%" : "34%", + containLabel: false, + }, + { + // left: window.innerWidth > 768 ? '8%' : '15%', // right: window.innerWidth > 768 ? '4%' : '2.5%', - height: window.innerWidth > 768 ? "60%" : "57%", - top: window.innerWidth > 768 ? "8%" : "12%", - // height: '33%', + top: window.innerWidth > 768 ? "50%" : "42%", + height: window.innerWidth > 768 ? "20%" : "22%", containLabel: false, }, { - left: window.innerWidth > 768 ? "18%" : "15%", + // left: window.innerWidth > 768 ? '8%' : '15%', // right: window.innerWidth > 768 ? '4%' : '2.5%', - top: window.innerWidth > 768 ? "72%" : "73%", - height: "20%", + top: window.innerWidth > 768 ? "78%" : "70%", + height: window.innerWidth > 768 ? "20%" : "22%", containLabel: false, }, ], @@ -1350,23 +1743,22 @@ function KlineCanvsEcharts(containerId) { { type: "category", data: dealData.categoryData, - boundaryGap: true, // 坐标轴两边是否留空,false表示不留空(通常用于K线图) - axisLine: { onZero: false }, // 设置坐标轴是否通过零点,onZero:false表示不强制穿过零点 - splitLine: { show: false }, // 是否显示分隔线,false表示不显示 - min: "dataMin", // 坐标轴最小值,'dataMin'表示从数据的最小值开始 - max: "dataMax", // 坐标轴最大值,'dataMax'表示从数据的最大值开始 + boundaryGap: true, + axisLine: { onZero: false }, + splitLine: { show: false }, + min: "dataMin", + max: "dataMax", axisPointer: { - z: 100, // 坐标轴指示器的层级,较大的值会让它显示在其他元素上方 + z: 100, }, axisLine: { lineStyle: { - color: "black", // 坐标轴线的颜色 + color: "black", }, }, // - axisLabel: { show: false }, // 隐藏刻度标签 - axisTick: { show: false }, // 隐藏刻度线 + axisLabel: { show: false }, + axisTick: { show: false }, }, - // 下方成交量图的X轴 { type: "category", gridIndex: 1, @@ -1374,14 +1766,22 @@ function KlineCanvsEcharts(containerId) { boundaryGap: true, axisLine: { lineStyle: { color: "black" } }, axisLabel: { + show: false, + interval: "auto", + }, + }, + { + type: "category", + gridIndex: 2, + data: dealData.categoryData, + boundaryGap: true, + axisLine: { lineStyle: { color: "black" } }, + axisLabel: { show: true, - // fontSize: window.innerWidth > 768 ? 10 : 8, interval: "auto", }, - axisTick: { show: false }, // 隐藏刻度线 }, ], - // 控制纵坐标展示数据 yAxis: [ { scale: true, @@ -1402,16 +1802,16 @@ function KlineCanvsEcharts(containerId) { axisTick: { show: false }, splitLine: { show: false }, }, - // 下方成交量图的Y轴 { scale: true, gridIndex: 1, - splitNumber: 4, // 增加分割数以获得更好的间距 - minInterval: 1, // 确保标签之间的最小间隔 + splitNumber: 4, + min: 0, + minInterval: 1, axisLabel: { show: true, fontSize: window.innerWidth > 768 ? 15 : 10, - margin: 8, // 添加边距以获得更好的间距 + margin: 8, formatter: (value) => { if (value >= 1000000000) { return (value / 1000000000).toFixed(1) + "B"; @@ -1425,25 +1825,58 @@ function KlineCanvsEcharts(containerId) { }, axisLine: { show: true, lineStyle: { color: "black" } }, axisTick: { show: false }, - splitLine: { show: true, lineStyle: { type: "dashed" } }, // 添加分割线以提高可读性 - boundaryGap: ["20%", "20%"], // 为坐标轴边界添加内边距 + splitLine: { show: true, lineStyle: { type: "dashed" } }, + boundaryGap: ["20%", "20%"], + }, + { + type: "value", + gridIndex: 2, + min: 0, + max: 100, + axisLabel: { + show: true, + fontSize: window.innerWidth > 768 ? 15 : 10, + formatter: function (value) { + var customValues = [0, 20, 50, 80, 100]; + return customValues.indexOf(value) > -1 ? value : ""; + }, + }, + axisLine: { + show: true, + lineStyle: { + color: "black", + }, + }, + axisTick: { + show: false, + }, + splitNumber: 10, + splitLine: { + show: true, + lineStyle: { + type: "dashed", + color: "#fff", + width: 1, + }, + interval: function (index, value) { + return [20, 50, 80, 100].indexOf(value) > -1; + }, + }, }, ], - // 下拉条 dataZoom: [ { type: "inside", - xAxisIndex: [0, 1], + xAxisIndex: [0, 1, 2], start: 55, end: 100, }, { show: true, - xAxisIndex: [0, 1], + xAxisIndex: [0, 1, 2], type: "slider", - top: window.innerWidth > 768 ? "95%" : "91%", - left: window.innerWidth > 768 ? "18%" : "15%", - // left: window.innerWidth > 768 ? '10%' : '8%', + top: window.innerWidth > 768 ? "95%" : "96%", + left: window.innerWidth > 768 ? "10%" : "8%", start: 98, end: 100, }, @@ -1457,7 +1890,7 @@ function KlineCanvsEcharts(containerId) { color: "green", }, dimension: 0, - seriesIndex: 6, + seriesIndex: 7, }, { type: "piecewise", @@ -1467,7 +1900,7 @@ function KlineCanvsEcharts(containerId) { color: "red", }, dimension: 0, - seriesIndex: 7, + seriesIndex: 8, }, { type: "piecewise", @@ -1477,21 +1910,20 @@ function KlineCanvsEcharts(containerId) { color: "yellow", }, dimension: 0, - seriesIndex: 8, + seriesIndex: 9, }, ], series: [ - // 第一条K线 { name: "进攻K线", type: "candlestick", - barWidth: "50%", // 设置和上方图表一致的柱子宽度 + barWidth: "50%", data: dealData1.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 + xAxisIndex: 0, + yAxisIndex: 0, itemStyle: { normal: { - color: "rgb(255,0,0)", // 默认颜色 + color: "rgb(255,0,0)", color0: "rgb(255,0,0)", borderColor: "rgb(255,0,0)", borderColor0: "rgb(255,0,0)", @@ -1503,13 +1935,13 @@ function KlineCanvsEcharts(containerId) { { name: "推进K线", type: "candlestick", - barWidth: "50%", // 设置和上方图表一致的柱子宽度 + barWidth: "50%", data: dealData2.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 + xAxisIndex: 0, + yAxisIndex: 0, itemStyle: { normal: { - color: "rgb(0,0,252)", // 默认颜色 + color: "rgb(0,0,252)", color0: "rgb(0,0,252)", borderColor: "rgb(0,0,252)", borderColor0: "rgb(0,0,252)", @@ -1520,13 +1952,13 @@ function KlineCanvsEcharts(containerId) { { name: "防守K线", type: "candlestick", - barWidth: "50%", // 设置和上方图表一致的柱子宽度 + barWidth: "50%", data: dealData3.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 + xAxisIndex: 0, + yAxisIndex: 0, itemStyle: { normal: { - color: "orange", // 默认颜色 + color: "orange", color0: "orange", borderColor: "orange", borderColor0: "orange", @@ -1537,13 +1969,13 @@ function KlineCanvsEcharts(containerId) { { name: "撤退K线", type: "candlestick", - barWidth: "50%", // 设置和上方图表一致的柱子宽度 + barWidth: "50%", data: dealData4.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 + xAxisIndex: 0, + yAxisIndex: 0, itemStyle: { normal: { - color: "rgb(84,252,252)", // 默认颜色 + color: "rgb(84,252,252)", color0: "rgb(84,252,252)", borderColor: "rgb(84,252,252)", borderColor0: "rgb(84,252,252)", @@ -1551,39 +1983,57 @@ function KlineCanvsEcharts(containerId) { }, gridIndex: 0, }, - //成交量柱状图 { name: "成交量", type: "bar", - barWidth: "70%", // 设置和上方图表一致的柱子宽度 + barWidth: "70%", xAxisIndex: 1, yAxisIndex: 1, data: barData, markPoint: { data: markPointData, label: { - show: false, // 确保隐藏标记的值 + show: false, + }, + }, + }, + { + name: "{green|━}{red|━} " + "牵牛绳", + type: "line", + data: [], + smooth: true, + symbol: "none", + xAxisIndex: 0, + yAxisIndex: 0, + showSymbol: false, + lineStyle: { + opacity: 0, + }, + itemStyle: { + normal: { + color: "green", }, }, + gridIndex: 0, }, { - name: "{green|━}{red|━} " + "牵牛绳", // 将牵牛绳样式应用到文本前缀 + name: "{green|━}{red|━} " + "度牛尺", type: "line", - data: [], // 设置为空数组,不显示数据点 + data: [], smooth: true, symbol: "none", - xAxisIndex: 0, // 线图与第一个 K 线图共享 X 轴 - yAxisIndex: 0, // 线图与第一个 K 线图共享 Y 轴 - showSymbol: false, // 隐藏符号 + xAxisIndex: 0, + yAxisIndex: 0, + showSymbol: false, lineStyle: { - opacity: 0, // 使线条透明 + opacity: 0, }, itemStyle: { normal: { color: "green", }, }, - gridIndex: 0, // 确保线图与第一个K线图共享网格 + gridIndex: 0, }, { name: "虫线", @@ -1591,19 +2041,18 @@ function KlineCanvsEcharts(containerId) { data: maData.greenData, smooth: true, symbol: "none", - xAxisIndex: 0, // 线图与第一个 K 线图共享 X 轴 - yAxisIndex: 0, // 线图与第一个 K 线图共享 Y 轴 + xAxisIndex: 0, + yAxisIndex: 0, itemStyle: { normal: { color: "green", lineStyle: { - // color: 'orange', // 线的颜色 - width: 2, // 线宽 - type: "solid", // 线类型 + width: 2, + type: "solid", }, }, }, - gridIndex: 0, // 确保线图与第一个K线图共享网格 + gridIndex: 0, }, { name: "龙线", @@ -1611,19 +2060,18 @@ function KlineCanvsEcharts(containerId) { data: maData.redData, smooth: true, symbol: "none", - xAxisIndex: 0, // 线图与第一个 K 线图共享 X 轴 - yAxisIndex: 0, // 线图与第一个 K 线图共享 Y 轴 + xAxisIndex: 0, + yAxisIndex: 0, itemStyle: { normal: { color: "red", lineStyle: { - // color: 'orange', // 线的颜色 - width: 2, // 线宽 - type: "solid", // 线类型 + width: 2, + type: "solid", }, }, }, - gridIndex: 0, // 确保线图与第一个K线图共享网格 + gridIndex: 0, }, { name: "黄色", @@ -1644,3453 +2092,281 @@ function KlineCanvsEcharts(containerId) { }, gridIndex: 0, }, - ], - // graphic: { - // markPointData : generateGraphicmarkPointData(data11111) - // } - }; - } else if (klineData.type === 2) { - console.log("进入第二分类"); - - const arr1 = []; - const arr2 = []; - const arr3 = []; - const arr4 = []; - const changeColorKline = (QSXH, KLine20) => { - if (QSXH) { - QSXH.map((item) => { - KLine20.map((kline_item) => { - if (item[1] == 1 && item[0] == kline_item[0]) { - arr1.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 2 && item[0] == kline_item[0]) { - arr2.push(kline_item); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 3 && item[0] == kline_item[0]) { - arr3.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 4 && item[0] == kline_item[0]) { - arr4.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - }); - }); - } - }; - console.log(arr1, arr2, arr3, arr4); - changeColorKline(data.QSXH, data.KLine20); - var dealData = splitData(data.KLine20); - var dealData1 = splitData(arr1); - var dealData2 = splitData(arr2); - var dealData3 = splitData(arr3); - var dealData4 = splitData(arr4); - var dealGnBullData = data.JN; - function processMAData(data) { - let processedData = []; - data.forEach((item, idx) => { - processedData.push({ - date: item[0], - value: item[1], - type: item[2], - }); - }); - // 当某一种type只存在一天,设置另一种type透明 - let singleTypeRed = [{ min: 0, max: 0, color: "#000" }]; - let singleTypeYellow = [{ min: 0, max: 0, color: "#000" }]; - let singleTypeGreen = [{ min: 0, max: 0, color: "#000" }]; - for (let i = 1; i < processedData.length; i++) { - if (processedData[i].type !== processedData[i - 1].type) { - if ( - i == processedData.length - 1 || - (processedData[i].type !== processedData[i + 1].type && - processedData[i - 1].type === processedData[i + 1].type) - ) { - if (processedData[i - 1].type === 0) { - singleTypeGreen.push({ - min: i - 1, - max: i, - color: "rgba(0,0,0,0)", - }); - } else if (processedData[i - 1].type === 1) { - singleTypeRed.push({ - min: i - 1, - max: i, - color: "rgba(0,0,0,0)", - }); - } else if (processedData[i - 1].type === 2) { - singleTypeYellow.push({ - min: i - 1, - max: i, - color: "rgba(0,0,0,0)", - }); - } - } - } - if (processedData[i].type !== processedData[i - 1].type) { - if (processedData[i].type == 0) { - processedData[i - 1].isTransitionGreen = 1; - } else if (processedData[i].type == 1) { - processedData[i - 1].isTransitionRed = 1; - } else if (processedData[i].type == 2) { - processedData[i - 1].isTransitionYellow = 1; - } - // // 创建过渡点,使用前一个点的值 - // processedData[i - 1].isTransition = true - } - } - let greenData = []; - let redData = []; - let yellowData = []; - - processedData.forEach((item, idx) => { - const point = [item.date, item.value]; - - if (item.type === 0) { - greenData.push(point); - redData.push([item.date, "-"]); - yellowData.push([item.date, "-"]); - - // if (item.isTransition) { - // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] - // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] - // } - if (item.isTransitionGreen) { - greenData[greenData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionRed) { - redData[redData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionYellow) { - yellowData[yellowData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } - } else if (item.type === 1) { - redData.push(point); - greenData.push([item.date, "-"]); - yellowData.push([item.date, "-"]); - - // if (item.isTransition) { - // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] - // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] - // } - if (item.isTransitionGreen) { - greenData[greenData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionRed) { - redData[redData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionYellow) { - yellowData[yellowData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } - } else if (item.type === 2) { - redData.push([item.date, "-"]); - greenData.push([item.date, "-"]); - yellowData.push(point); - - // if (item.isTransition) { - // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] - // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] - // } - if (item.isTransitionGreen) { - greenData[greenData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionRed) { - redData[redData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionYellow) { - yellowData[yellowData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } - } - }); - - return { - greenData: greenData, - redData: redData, - yellowData: yellowData, - singleTypeGreen: singleTypeGreen, - singleTypeRed: singleTypeRed, - singleTypeYellow: singleTypeYellow, - }; - } - const maData = processMAData(data.FCX); - const maDuchiData = processMAData(data.DNC); - if (data.FCX[0][1] == "-1") { - maData.greenData = []; - maData.redData = []; - maData.yellowData = []; - } - const processBarData = (data) => { - const barData = []; - const markPointData = []; - data.forEach((item) => { - let color; - switch (item[4]) { - case 1: - color = "#13E113"; - break; - case 2: - color = "#FF0E00"; - break; - case 3: - color = "#0000FE"; - break; - case 4: - color = "#1397FF"; - break; - } - barData.push({ - value: item[5], - itemStyle: { - normal: { - color: color, - }, - }, - }); - - if (item[1] === 1) { - markPointData.push({ - coord: [item[0], item[5]], - symbol: - "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujb101000d5si3v3hr7w2vg0h43z1u.png", - symbolSize: [30, 30], - label: { - normal: { - color: "rgba(0, 0, 0, 0)", - }, - }, - }); - } - - if (item[2] === 1) { - markPointData.push({ - coord: [item[0], item[5] / 2], - symbol: - "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujaz01000d5si016bxdf6vh0377d2h.png", - symbolSize: [30, 30], - label: { - normal: { - color: "rgba(0, 0, 0, 0)", - }, - }, - }); - } - - if (item[3] === 1) { - markPointData.push({ - coord: [item[0], 0], - symbol: - "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujb001000d5shzls0tmd4vs0e5tdrw.png", - symbolSize: [30, 30], - label: { - normal: { - color: "rgba(0, 0, 0, 0)", - }, - }, - }); - } - }); - return { barData, markPointData }; - }; - const { barData, markPointData } = processBarData(dealGnBullData); - KlineOption = { - legend: [ - { - textStyle: { - color: "black", - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), - }, - width: "100%", - top: window.innerWidth > 768 ? "0%" : "-1%", - left: "center", - itemGap: window.innerWidth > 768 ? 20 : 10, - itemWidth: 10, - itemHeight: 10, - data: [ - { - name: "进攻K线", - itemStyle: { - color: "rgb(255,0,0)", - }, - }, - { - name: "防守K线", - itemStyle: { - color: "red", - }, - }, - { - name: "推进K线", - itemStyle: { - color: "orange", - }, - }, - { - name: "撤退K线", - itemStyle: { - color: "rgb(84,252,252)", - }, - }, - ], - }, - { - textStyle: { - color: "black", - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), - }, - orient: "horizontal", - top: window.innerWidth > 768 ? "3%" : "2%", - width: "100%", - left: "center", - itemGap: 15, - data: [ - { - name: "{green|━}{red|━} " + "牵牛绳", - icon: "none", - textStyle: { - rich: { - green: { - color: "green", - fontSize: window.innerWidth > 768 ? 20 : 10, - }, - red: { - color: "red", - fontSize: window.innerWidth > 768 ? 20 : 10, - }, - }, - }, - }, - { - name: "龙线", - }, - { - name: "虫线", - }, - ], - }, - { - textStyle: { - color: "black", - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), - }, - orient: "horizontal", - top: window.innerWidth > 768 ? "72%" : "64%", - width: "100%", - left: "center", - itemGap: 15, - data: [ - { - name: "{green|━}{red|━} " + "度牛尺", - icon: "none", - textStyle: { - rich: { - green: { - color: "green", - fontSize: window.innerWidth > 768 ? 20 : 10, - }, - red: { - color: "red", - fontSize: window.innerWidth > 768 ? 20 : 10, - }, - }, - }, - }, - ], - }, - ], - tooltip: { - formatter: function (a, b, d) { - if (a[0].seriesIndex == 0) { - const KlineTag = ref([]); - const AIBullTag = ref([]); - KlineTag.value = a.find((item) => item.data[1])?.data || []; - AIBullTag.value = - a.slice(4).find((item) => item.data[1] !== "-")?.data || []; - // console.log(AIBullTag.value) - - return ( - a[0].name + - "
" + - "开盘价" + - ":" + - KlineTag.value[1] + - "
" + - "收盘价" + - ":" + - KlineTag.value[2] + - "
" + - "最低价" + - ":" + - KlineTag.value[3] + - "
" + - "最高价" + - ":" + - KlineTag.value[4] + - "
" + - "牵牛绳" + - ":" + - AIBullTag.value[1] - ); - } - if (a[0].seriesIndex == 4) { - let formattedVolume; - if (a[0].data.value >= 10000) { - formattedVolume = (a[0].data.value / 10000).toFixed(2) + "w"; - } else { - formattedVolume = a[0].data.value; - } - return a[0].name + "
" + "成交量" + ":" + formattedVolume; - } - if ([10, 11, 12].includes(a[0].seriesIndex)) { - const duchiData = a.find( - (item) => item.data && item.data[1] !== "-" - ); - return duchiData - ? a[0].axisValue + "
" + "度牛尺" + ":" + duchiData.data[1] - : null; - } - }, - trigger: "axis", - axisPointer: { - type: "cross", - }, - backgroundColor: "rgba(119, 120, 125, 0.6)", - borderWidth: 1, - borderColor: "#77787D", - padding: 10, - textStyle: { - color: "#fff", - }, - }, - axisPointer: { - link: [ - { - xAxisIndex: "all", - }, - ], - label: { - backgroundColor: "#77787D", - }, - }, - toolbox: { - show: false, - }, - grid: [ - { - // left: window.innerWidth > 768 ? '8%' : '15%', - // right: window.innerWidth > 768 ? '4%' : '2.5%', - top: window.innerWidth > 768 ? "10%" : "5%", - height: window.innerWidth > 768 ? "36%" : "34%", - containLabel: false, - }, - { - // left: window.innerWidth > 768 ? '8%' : '15%', - // right: window.innerWidth > 768 ? '4%' : '2.5%', - top: window.innerWidth > 768 ? "50%" : "42%", - height: window.innerWidth > 768 ? "20%" : "22%", - containLabel: false, - }, - { - // left: window.innerWidth > 768 ? '8%' : '15%', - // right: window.innerWidth > 768 ? '4%' : '2.5%', - top: window.innerWidth > 768 ? "78%" : "70%", - height: window.innerWidth > 768 ? "20%" : "22%", - containLabel: false, - }, - ], - xAxis: [ - { - type: "category", - data: dealData.categoryData, - boundaryGap: true, - axisLine: { onZero: false }, - splitLine: { show: false }, - min: "dataMin", - max: "dataMax", - axisPointer: { - z: 100, - }, - axisLine: { - lineStyle: { - color: "black", - }, - }, // - axisLabel: { show: false }, - axisTick: { show: false }, - }, - { - type: "category", - gridIndex: 1, - data: dealData.categoryData, - boundaryGap: true, - axisLine: { lineStyle: { color: "black" } }, - axisLabel: { - show: false, - interval: "auto", - }, - }, - { - type: "category", - gridIndex: 2, - data: dealData.categoryData, - boundaryGap: true, - axisLine: { lineStyle: { color: "black" } }, - axisLabel: { - show: true, - interval: "auto", - }, - }, - ], - yAxis: [ - { - scale: true, - gridIndex: 0, - position: "left", - axisLabel: { - inside: false, - align: "right", - fontSize: window.innerWidth > 768 ? 15 : 10, - }, - axisLine: { - show: true, - lineStyle: { - fontSize: "", - color: "black", - }, - }, - axisTick: { show: false }, - splitLine: { show: false }, - }, - { - scale: true, - gridIndex: 1, - splitNumber: 4, - min: 0, - minInterval: 1, - axisLabel: { - show: true, - fontSize: window.innerWidth > 768 ? 15 : 10, - margin: 8, - formatter: (value) => { - if (value >= 1000000000) { - return (value / 1000000000).toFixed(1) + "B"; - } else if (value >= 1000000) { - return (value / 1000000).toFixed(1) + "M"; - } else if (value >= 10000) { - return (value / 10000).toFixed(1) + "W"; - } - return value.toFixed(0); - }, - }, - axisLine: { show: true, lineStyle: { color: "black" } }, - axisTick: { show: false }, - splitLine: { show: true, lineStyle: { type: "dashed" } }, - boundaryGap: ["20%", "20%"], - }, - { - type: "value", - gridIndex: 2, - min: 0, - max: 100, - axisLabel: { - show: true, - fontSize: window.innerWidth > 768 ? 15 : 10, - formatter: function (value) { - var customValues = [0, 20, 50, 80, 100]; - return customValues.indexOf(value) > -1 ? value : ""; - }, - }, - axisLine: { - show: true, - lineStyle: { - color: "black", - }, - }, - axisTick: { - show: false, - }, - splitNumber: 10, - splitLine: { - show: true, - lineStyle: { - type: "dashed", - color: "#fff", - width: 1, - }, - interval: function (index, value) { - return [20, 50, 80, 100].indexOf(value) > -1; - }, - }, - }, - ], - dataZoom: [ - { - type: "inside", - xAxisIndex: [0, 1, 2], - start: 55, - end: 100, - }, - { - show: true, - xAxisIndex: [0, 1, 2], - type: "slider", - top: window.innerWidth > 768 ? "95%" : "96%", - left: window.innerWidth > 768 ? "10%" : "8%", - start: 98, - end: 100, - }, - ], - visualMap: [ - { - type: "piecewise", - show: false, - pieces: maData.singleTypeGreen, - outOfRange: { - color: "green", - }, - dimension: 0, - seriesIndex: 7, - }, - { - type: "piecewise", - show: false, - pieces: maData.singleTypeRed, - outOfRange: { - color: "red", - }, - dimension: 0, - seriesIndex: 8, - }, - { - type: "piecewise", - show: false, - pieces: maData.singleTypeYellow, - outOfRange: { - color: "yellow", - }, - dimension: 0, - seriesIndex: 9, - }, - ], - series: [ - { - name: "进攻K线", - type: "candlestick", - barWidth: "50%", - data: dealData1.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "rgb(255,0,0)", - color0: "rgb(255,0,0)", - borderColor: "rgb(255,0,0)", - borderColor0: "rgb(255,0,0)", - }, - }, - gridIndex: 0, - }, - // - { - name: "推进K线", - type: "candlestick", - barWidth: "50%", - data: dealData2.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "rgb(0,0,252)", - color0: "rgb(0,0,252)", - borderColor: "rgb(0,0,252)", - borderColor0: "rgb(0,0,252)", - }, - }, - gridIndex: 0, - }, - { - name: "防守K线", - type: "candlestick", - barWidth: "50%", - data: dealData3.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "orange", - color0: "orange", - borderColor: "orange", - borderColor0: "orange", - }, - }, - gridIndex: 0, - }, - { - name: "撤退K线", - type: "candlestick", - barWidth: "50%", - data: dealData4.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "rgb(84,252,252)", - color0: "rgb(84,252,252)", - borderColor: "rgb(84,252,252)", - borderColor0: "rgb(84,252,252)", - }, - }, - gridIndex: 0, - }, - { - name: "成交量", - type: "bar", - barWidth: "70%", - xAxisIndex: 1, - yAxisIndex: 1, - data: barData, - markPoint: { - data: markPointData, - label: { - show: false, - }, - }, - }, - { - name: "{green|━}{red|━} " + "牵牛绳", - type: "line", - data: [], - smooth: true, - symbol: "none", - xAxisIndex: 0, - yAxisIndex: 0, - showSymbol: false, - lineStyle: { - opacity: 0, - }, - itemStyle: { - normal: { - color: "green", - }, - }, - gridIndex: 0, - }, - { - name: "{green|━}{red|━} " + "度牛尺", - type: "line", - data: [], - smooth: true, - symbol: "none", - xAxisIndex: 0, - yAxisIndex: 0, - showSymbol: false, - lineStyle: { - opacity: 0, - }, - itemStyle: { - normal: { - color: "green", - }, - }, - gridIndex: 0, - }, - { - name: "虫线", - type: "line", - data: maData.greenData, - smooth: true, - symbol: "none", - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "green", - lineStyle: { - width: 2, - type: "solid", - }, - }, - }, - gridIndex: 0, - }, - { - name: "龙线", - type: "line", - data: maData.redData, - smooth: true, - symbol: "none", - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "red", - lineStyle: { - width: 2, - type: "solid", - }, - }, - }, - gridIndex: 0, - }, - { - name: "黄色", - type: "line", - data: maData.yellowData, - smooth: true, - symbol: "none", - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "yellow", - lineStyle: { - width: 2, - type: "solid", - }, - }, - }, - gridIndex: 0, - }, - { - name: "背景区域", - type: "line", - data: [], - xAxisIndex: 2, - yAxisIndex: 2, - markArea: { - silent: true, - itemStyle: { - normal: { - opacity: 1, - }, - }, - label: { - normal: { - show: true, - position: "insideRight", - fontSize: window.innerWidth > 768 ? 16 : 12, - fontWeight: "bold", - color: "#13E113", - distance: 10, - }, - }, - data: [ - [ - { - yAxis: 0, - itemStyle: { - normal: { - color: "#CFFFCF", - }, - }, - label: { - normal: { - formatter: "度牛区", - }, - }, - }, - { - yAxis: 20, - }, - ], - [ - { - yAxis: 20, - itemStyle: { - normal: { - color: "#A6FFFF", - }, - }, - }, - { - yAxis: 40, - }, - ], - [ - { - yAxis: 40, - itemStyle: { - normal: { - color: "#FFF686", - }, - }, - }, - { - yAxis: 60, - }, - ], - [ - { - yAxis: 60, - itemStyle: { - normal: { color: "#FFD2B3" }, - }, - }, - { - yAxis: 80, - }, - ], - [ - { - yAxis: 80, - itemStyle: { - normal: { color: "#FFB8B8" }, - }, - label: { - normal: { - formatter: "度牛区", - color: "#FF0000", - position: "insideLeft", - distance: 10, - }, - }, - }, - { - yAxis: 100, - }, - ], - ], - }, - }, - { - name: "度牛尺", - type: "line", - data: maDuchiData.greenData, - symbol: "none", - xAxisIndex: 2, - yAxisIndex: 2, - itemStyle: { - normal: { - color: "green", - lineStyle: { - width: 2, - type: "solid", - }, - }, - }, - gridIndex: 2, - markPoint: { - symbol: "rect", - symbolSize: (value, params) => { - const width = window.innerWidth; - const baseHeight = 36; - if (width <= 375) { - return [2, 16]; - } else if (width <= 768) { - return [2, 24]; - } - return [2, baseHeight]; - }, - itemStyle: { - normal: { - label: { - show: false, - }, - }, - }, - data: [ - ...maDuchiData.greenData - .map((item) => { - if (item[1] === 0) { - return { - coord: [item[0], 20], - symbolOffset: window.innerWidth > 768 ? [0, 20] : [0, 12], - itemStyle: { - color: "#00ff00", - }, - }; - } - }) - .filter(Boolean), - ], - }, - }, - { - type: "line", - data: maDuchiData.redData, - // smooth: true, - symbol: "none", - xAxisIndex: 2, - yAxisIndex: 2, - itemStyle: { - normal: { - color: "red", - lineStyle: { - width: 2, - type: "solid", - }, - }, - }, - gridIndex: 2, - markPoint: { - symbol: "rect", - symbolSize: (value, params) => { - const width = window.innerWidth; - const baseHeight = 36; - if (width <= 375) { - return [2, 16]; - } else if (width <= 768) { - return [2, 24]; - } - return [2, baseHeight]; - }, - itemStyle: { - normal: { - label: { - show: false, - }, - }, - }, - data: [ - ...maDuchiData.redData - .map((item) => { - if (item[1] === 100) { - return { - coord: [item[0], 80], - symbolOffset: - window.innerWidth > 768 ? [0, -20] : [0, -12], - itemStyle: { - color: "#ff0000", - }, - }; - } - }) - .filter(Boolean), - ], - }, - }, - { - name: "辅助线", - type: "line", - data: [], - xAxisIndex: 2, - yAxisIndex: 2, - markLine: { - silent: true, - symbol: "none", - lineStyle: { - color: "#000000", - width: 3, - type: "solid", - }, - data: [{ yAxis: 20 }], - }, - }, - { - name: "辅助线", - type: "line", - data: [], - xAxisIndex: 2, - yAxisIndex: 2, - markLine: { - silent: true, - symbol: "none", - lineStyle: { - color: "#000000", - width: 3, - type: "solid", - }, - data: [{ yAxis: 50 }], - }, - }, - { - name: "辅助线", - type: "line", - data: [], - xAxisIndex: 2, - yAxisIndex: 2, - markLine: { - silent: true, - symbol: "none", - lineStyle: { - color: "#000000", - width: 3, - type: "solid", - }, - data: [{ yAxis: 80 }], - }, - }, - { - name: "辅助线", - type: "line", - data: [], - xAxisIndex: 2, - yAxisIndex: 2, - markLine: { - silent: true, - symbol: "none", - lineStyle: { - color: "#000000", - width: 3, - - type: "solid", - }, - data: [{ yAxis: 100 }], - }, - }, - ], - }; - } else if ( - klineData.type === 3 || - klineData.type === 4 || - klineData.type === 8 || - klineData.type === 9 || - klineData.type === 10 - ) { - console.log("进入3,4,8,9,10分类"); - - const arr1 = []; - const arr2 = []; - const arr3 = []; - const arr4 = []; - // k线的数据 - // 动态K线 - const changeColorKline = (QSXH, KLine20) => { - console.log(QSXH, KLine20); - if (QSXH) { - QSXH.map((item) => { - KLine20.map((kline_item) => { - if (item[1] == 1 && item[0] == kline_item[0]) { - arr1.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 2 && item[0] == kline_item[0]) { - arr2.push(kline_item); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 3 && item[0] == kline_item[0]) { - arr3.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 4 && item[0] == kline_item[0]) { - arr4.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - }); - }); - } - }; - changeColorKline(data.QSXH, data.KLine20); - var dealData = splitData(data.KLine20); - var dealData1 = splitData(arr1); - var dealData2 = splitData(arr2); - var dealData3 = splitData(arr3); - var dealData4 = splitData(arr4); - // 处理MA数据,创建两段重叠的数据 - function processMAData(data) { - let processedData = []; - // 初始化处理后的数据结构 - data.forEach((item, idx) => { - processedData.push({ - date: item[0], - value: item[1], - type: item[2], - }); - }); - // 当某一种type只存在一天,设置另一种type透明 - let singleTypeRed = [{ min: 0, max: 0, color: "#000" }]; - let singleTypeYellow = [{ min: 0, max: 0, color: "#000" }]; - let singleTypeGreen = [{ min: 0, max: 0, color: "#000" }]; - // 在类型切换点添加过渡点 - for (let i = 1; i < processedData.length; i++) { - if (processedData[i].type !== processedData[i - 1].type) { - if ( - i == processedData.length - 1 || - (processedData[i].type !== processedData[i + 1].type && - processedData[i - 1].type === processedData[i + 1].type) - ) { - if (processedData[i - 1].type === 0) { - singleTypeGreen.push({ - min: i - 1, - max: i, - color: "rgba(0,0,0,0)", - }); - } else if (processedData[i - 1].type === 1) { - singleTypeRed.push({ - min: i - 1, - max: i, - color: "rgba(0,0,0,0)", - }); - } else if (processedData[i - 1].type === 2) { - singleTypeYellow.push({ - min: i - 1, - max: i, - color: "rgba(0,0,0,0)", - }); - } - } - } - if (processedData[i].type !== processedData[i - 1].type) { - if (processedData[i].type == 0) { - processedData[i - 1].isTransitionGreen = 1; - } else if (processedData[i].type == 1) { - processedData[i - 1].isTransitionRed = 1; - } else if (processedData[i].type == 2) { - processedData[i - 1].isTransitionYellow = 1; - } - // // 创建过渡点,使用前一个点的值 - // processedData[i - 1].isTransition = true - } - } - // 分离红绿数据,包含过渡点 - let greenData = []; - let redData = []; - let yellowData = []; - - processedData.forEach((item, idx) => { - const point = [item.date, item.value]; - - if (item.type === 0) { - greenData.push(point); - redData.push([item.date, "-"]); - yellowData.push([item.date, "-"]); - - // if (item.isTransition) { - // // 添加过渡点到红色线 - // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] - // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] - // } - if (item.isTransitionGreen) { - greenData[greenData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionRed) { - redData[redData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionYellow) { - yellowData[yellowData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } - } else if (item.type === 1) { - redData.push(point); - greenData.push([item.date, "-"]); - yellowData.push([item.date, "-"]); - - // if (item.isTransition) { - // // 添加过渡点到绿色线 - // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] - // yellowData[yellowData.length - 1] = [processedData[idx].date, processedData[idx].value] - // } - if (item.isTransitionGreen) { - greenData[greenData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionRed) { - redData[redData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionYellow) { - yellowData[yellowData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } - } else if (item.type === 2) { - redData.push([item.date, "-"]); - greenData.push([item.date, "-"]); - yellowData.push(point); - - // if (item.isTransition) { - // // 添加过渡点到绿色线 - // greenData[greenData.length - 1] = [processedData[idx].date, processedData[idx].value] - // redData[redData.length - 1] = [processedData[idx].date, processedData[idx].value] - // } - if (item.isTransitionGreen) { - greenData[greenData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionRed) { - redData[redData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } else if (item.isTransitionYellow) { - yellowData[yellowData.length - 1] = [ - processedData[idx].date, - processedData[idx].value, - ]; - } - } - }); - // console.log('greenData', greenData) - // console.log('redData', redData) - // console.log('yellowData', yellowData) - // console.log('green', singleTypeGreen) - // console.log('red', singleTypeRed) - // console.log('yellow', singleTypeYellow) - return { - greenData: greenData, - redData: redData, - yellowData: yellowData, - singleTypeGreen: singleTypeGreen, - singleTypeRed: singleTypeRed, - singleTypeYellow: singleTypeYellow, - }; - } - const maData = processMAData(data.FCX); - // 牵牛绳的数据 - - // 如果第一个字段的第一个数据为-1的话,不展示牵牛绳 - if (data.FCX[0][1] == "-1") { - maData.greenData = []; - maData.redData = []; - maData.yellowData = []; - } - // K线图距离顶部的距离 - // 配置项 - KlineOption = { - // 底部选项 - // animation: false, - // 手放上去显示的内容 - legend: [ - { - //图例文字的样式 - textStyle: { - color: "black", //图例文字颜色 - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), // 响应式字体大小 - }, - width: "100%", // 确保有足够的宽度容纳图例 - left: "center", - itemGap: window.innerWidth > 768 ? 20 : 10, // 控制图例项之间的间距 - itemWidth: 10, // 调整颜色块的宽度 - itemHeight: 10, // 调整颜色块的高度 - data: [ - { - name: "进攻K线", - itemStyle: { - color: "rgb(255,0,0)", - }, - }, - { - name: "防守K线", - itemStyle: { - color: "red", - }, - }, - { - name: "推进K线", - itemStyle: { - color: "orange", - }, - }, - { - name: "撤退K线", - itemStyle: { - color: "rgb(84,252,252", - }, - }, - ], - }, - { - //图例文字的样式 - textStyle: { - color: "black", //图例文字颜色 - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), // 响应式字体大小 - }, - orient: "horizontal", // 设置图例水平布局 - top: window.innerWidth > 768 ? "8%" : "8%", - width: "100%", // 确保有足够的宽度容纳图例 - left: "center", - itemGap: 15, // 控制图例项之间的间距 - data: [ - // 牵牛绳 - { - name: "{green|━}{red|━} " + "牵牛绳", // 将牵牛绳样式应用到文本前缀 - icon: "none", // 去掉默认图例图标 - textStyle: { - rich: { - green: { - color: "green", - fontSize: window.innerWidth > 768 ? 20 : 10, - }, - red: { - color: "red", - fontSize: window.innerWidth > 768 ? 20 : 10, - }, - }, - }, - }, - { - name: "龙线", - }, - { - name: "虫线", - }, - ], - }, - ], - tooltip: { - // 调用接口之后方法 - formatter: function (a, b, d) { - if (a[0].seriesIndex == 0) { - const KlineTag = ref([]); // 判断几根K线 - const AIBullTag = ref([]); - - // 找到第一个满足条件的数据 - KlineTag.value = a.find((item) => item.data[1])?.data || []; - - // 找到第一个满足条件的非 '-' 数据 - AIBullTag.value = - a.slice(4).find((item) => item.data[1] !== "-")?.data || []; - return ( - a[0].name + - "
" + - "开盘价" + - ":" + - KlineTag.value[1] + - "
" + - "收盘价" + - ":" + - KlineTag.value[2] + - "
" + - "最低价" + - ":" + - KlineTag.value[3] + - "
" + - "最高价" + - ":" + - KlineTag.value[4] + - "
" + - "牵牛绳" + - ":" + - AIBullTag.value[1] - ); - // }else if(a[0].seriesIndex == 5){ - // return a[0].name+ "
" + a[0].seriesName + ":" + a[0].value + "
" + a[1].seriesName + ":" + a[1].value + "
" + a[2].seriesName + ":" + a[2].value + "
" + a[3].seriesName + ":" + a[3].value + "
" + a[4].seriesName + ":" + a[4].value + "
" + a[5].seriesName + ":" + a[5].value - } else { - return ( - a[0].name + - "
" + - "开盘价" + - ":" + - a[0].data[1] + - "
" + - "收盘价" + - ":" + - a[0].data[2] + - "
" + - "最低价" + - ":" + - a[0].data[3] + - "
" + - "最高价" + - ":" + - a[0].data[4] + - "
" - ); - } - }, - trigger: "axis", - axisPointer: { - //坐标轴指示器配置项 - type: "cross", //‘line’直线指示器,‘cross’十字准星指示器,‘shadow’阴影指示器 - }, - backgroundColor: "rgba(119, 120, 125, 0.6)", // 提示框浮层的边框颜色。 - borderWidth: 1, // 提示框浮层的边框宽。 - borderColor: "#77787D", // 提示框浮层的边框颜色。 - padding: 10, // 提示框浮层内边距, - textStyle: { - //提示框浮层上的文字样式 - color: "#fff", - }, - }, - // 手放上去时拉的框 - axisPointer: { - link: [ - { - xAxisIndex: "all", // 同时触发所有图形的 x 坐标轴指示器 - }, - ], - label: { - backgroundColor: "#77787D", // 文本标签的背景颜色 - }, - }, - toolbox: { - show: false, - }, - grid: [ - { - // left: window.innerWidth > 768 ? '8%' : '15%', - // right: window.innerWidth > 768 ? '7%' : '2.5%', - height: window.innerWidth > 768 ? "40%" : "37%", - top: window.innerWidth > 768 ? "10%" : "12%", - containLabel: false, - }, - { - // left: window.innerWidth > 768 ? '8%' : '15%', - // right: window.innerWidth > 768 ? '7%' : '2.5%', - top: window.innerWidth > 768 ? "53%" : "52%", - height: window.innerWidth > 768 ? "40%" : "37%", - containLabel: false, - }, - ], - xAxis: [ - { - type: "category", - data: dealData.categoryData, - boundaryGap: true, // 坐标轴两边是否留空,false表示不留空(通常用于K线图) - axisLine: { onZero: false }, // 设置坐标轴是否通过零点,onZero:false表示不强制穿过零点 - splitLine: { show: false }, // 是否显示分隔线,false表示不显示 - min: "dataMin", // 坐标轴最小值,'dataMin'表示从数据的最小值开始 - max: "dataMax", // 坐标轴最大值,'dataMax'表示从数据的最大值开始 - axisPointer: { - z: 100, // 坐标轴指示器的层级,较大的值会让它显示在其他元素上方 - }, - axisLine: { - lineStyle: { - color: "black", // 坐标轴线的颜色 - }, - }, // - axisLabel: { show: false }, // 隐藏刻度标签 - axisTick: { show: false }, // 隐藏刻度线 - }, - { - type: "category", - gridIndex: 1, - data: dealData.categoryData, - boundaryGap: true, - axisLine: { - show: false, - }, - axisTick: { show: false }, // 隐藏刻度线 // 只保留一个 axisLine 定义 - // 对于第二个类别轴,通常也不需要设置 min 和 max - }, - ], - // 控制纵坐标展示数据 - yAxis: [ - { - scale: true, - gridIndex: 0, - axisLabel: { - show: true, - fontSize: window.innerWidth > 768 ? 15 : 10, - }, - axisLine: { - lineStyle: { - fontSize: "", - color: "black", - }, - }, - axisTick: { show: false }, - splitLine: { show: false }, - }, - { - scale: true, - gridIndex: 1, - splitNumber: 2, - axisLabel: { - show: true, - fontSize: window.innerWidth > 768 ? 15 : 10, - }, - axisLine: { - lineStyle: { - color: "black", - }, - }, - axisTick: { show: false }, - splitLine: { show: false }, - }, - ], - // 下拉条 - dataZoom: [ - { - type: "inside", - xAxisIndex: [0, 1], - start: 55, - end: 100, - }, - { - show: true, - xAxisIndex: [0, 1], - type: "slider", - top: window.innerWidth > 768 ? "92%" : "91%", - left: window.innerWidth > 768 ? "10%" : "8%", - start: 98, - end: 100, - }, - ], - visualMap: [ - { - type: "piecewise", - show: false, - pieces: maData.singleTypeGreen, - outOfRange: { - color: "green", - }, - dimension: 0, - seriesIndex: 6, - }, - { - type: "piecewise", - show: false, - pieces: maData.singleTypeRed, - outOfRange: { - color: "red", - }, - dimension: 0, - seriesIndex: 7, - }, - { - type: "piecewise", - show: false, - pieces: maData.singleTypeYellow, - outOfRange: { - color: "yellow", - }, - dimension: 0, - seriesIndex: 8, - }, - ], - series: [ - // 第一条K线 - { - name: "进攻K线", - type: "candlestick", - data: dealData1.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 - itemStyle: { - normal: { - color: "rgb(255,0,0)", // 默认颜色 - color0: "rgb(255,0,0)", - borderColor: "rgb(255,0,0)", - borderColor0: "rgb(255,0,0)", - }, - }, - gridIndex: 0, - }, - // - { - name: "推进K线", - type: "candlestick", - data: dealData2.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 - itemStyle: { - normal: { - color: "rgb(0,0,252)", // 默认颜色 - color0: "rgb(0,0,252)", - borderColor: "rgb(0,0,252)", - borderColor0: "rgb(0,0,252)", - }, - }, - gridIndex: 0, - }, - { - name: "防守K线", - type: "candlestick", - data: dealData3.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 - itemStyle: { - normal: { - color: "orange", // 默认颜色 - color0: "orange", - borderColor: "orange", - borderColor0: "orange", - }, - }, - gridIndex: 0, - }, - { - name: "撤退K线", - type: "candlestick", - data: dealData4.values, - xAxisIndex: 0, // 使用第一个 X 轴 - yAxisIndex: 0, // 使用第一个 Y 轴 - itemStyle: { - normal: { - color: "rgb(84,252,252)", // 默认颜色 - color0: "rgb(84,252,252)", - borderColor: "rgb(84,252,252)", - borderColor0: "rgb(84,252,252)", - }, - }, - gridIndex: 0, - }, - // 第二条K线 - { - type: "candlestick", - name: "日K", - xAxisIndex: 1, // 使用第二个 X 轴 - yAxisIndex: 1, // 使用第二个 Y 轴 - data: dealData.values, - itemStyle: { - normal: { - color0: "red", - color: "green", - borderColor0: "red", - borderColor: "green", - }, - }, - gridIndex: 1, - }, - { - name: "{green|━}{red|━} " + "牵牛绳", // 将牵牛绳样式应用到文本前缀 - type: "line", - data: [], // 设置为空数组,不显示数据点 - smooth: true, - symbol: "none", - xAxisIndex: 0, // 线图与第一个 K 线图共享 X 轴 - yAxisIndex: 0, // 线图与第一个 K 线图共享 Y 轴 - showSymbol: false, // 隐藏符号 - lineStyle: { - opacity: 0, // 使线条透明 - }, - itemStyle: { - normal: { - color: "green", - }, - }, - gridIndex: 0, // 确保线图与第一个K线图共享网格 - }, - { - name: "虫线", - type: "line", - data: maData.greenData, - smooth: true, - symbol: "none", - xAxisIndex: 0, // 线图与第一个 K 线图共享 X 轴 - yAxisIndex: 0, // 线图与第一个 K 线图共享 Y 轴 - itemStyle: { - normal: { - color: "green", - lineStyle: { - // color: 'orange', // 线的颜色 - width: 2, // 线宽 - type: "solid", // 线类型 - }, - }, - }, - gridIndex: 0, // 确保线图与第一个K线图共享网格 - }, - { - name: "龙线", - type: "line", - data: maData.redData, - smooth: true, - symbol: "none", - xAxisIndex: 0, // 线图与第一个 K 线图共享 X 轴 - yAxisIndex: 0, // 线图与第一个 K 线图共享 Y 轴 - itemStyle: { - normal: { - color: "red", - lineStyle: { - // color: 'orange', // 线的颜色 - width: 2, // 线宽 - type: "solid", // 线类型 - }, - }, - }, - gridIndex: 0, // 确保线图与第一个K线图共享网格 - }, - { - name: "黄色", - type: "line", - data: maData.yellowData, - smooth: true, - symbol: "none", - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "yellow", - lineStyle: { - width: 2, - type: "solid", - }, - }, - }, - gridIndex: 0, - }, - ], - }; - } else if (klineData.type === 5 || klineData.type === 7) { - console.log("进入第7分类"); - - const upColor = "#00da3c"; - const downColor = "#ec0000"; - function calculateMA(index, data) { - let result = []; - if (data.FTLINE) { - data.FTLINE.forEach((item) => { - result.push(item[index]); - }); - } - return result; - } - var dealData = splitData(data.KLine20); - var bodongliang = splitData(data.WAVEVOL); - function bodongliangData(values, i) { - return values.map((subArray) => subArray[i]); - } - KlineOption = { - animation: false, - legend: { - textStyle: { - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), - }, - left: "center", - data: [ - { - name: "天线", - }, - { - name: "飞线", - itemStyle: { - color: "#000", - }, - }, - { - name: "中线", - }, - { - name: "流线", - }, - ], - }, - tooltip: [ - { - trigger: "axis", - formatter: function (a, b, d) { - if (a[0].seriesIndex == 0) { - return ( - a[0].name + - "
" + - "开盘价" + - ":" + - a[0].data[1] + - "
" + - "收盘价" + - ":" + - a[0].data[2] + - "
" + - "最低价" + - ":" + - a[0].data[3] + - "
" + - "最高价" + - ":" + - a[0].data[4] + - "
" + - a[3].marker + - a[3].seriesName + - ":" + - a[3].value + - "
" + - a[1].marker + - a[1].seriesName + - ":" + - a[1].value + - "
" + - a[2].marker + - a[2].seriesName + - ":" + - a[2].value + - "
" + - a[4].marker + - a[4].seriesName + - ":" + - a[4].value - ); - // }else if(a[0].seriesIndex == 5){ - // console.log(a[0].seriesIndex,'a[0].seriesIndex') - // return a[0].name+ "
" + a[0].seriesName + ":" + a[0].value + "
" + a[1].seriesName + ":" + a[1].value + "
" + a[2].seriesName + ":" + a[2].value + "
" + a[3].seriesName + ":" + a[3].value + "
" + a[4].seriesName + ":" + a[4].value + "
" + a[5].seriesName + ":" + a[5].value - } else { - return ( - a[0].name + - "
" + - a[0].marker + - a[0].seriesName + - ":" + - a[0].value + - "
" + - a[1].marker + - a[1].seriesName + - ":" + - a[1].value + - "
" + - a[2].marker + - a[2].seriesName + - ":" + - a[2].value + - "
" + - a[3].marker + - a[3].seriesName + - ":" + - a[3].value + - "
" + - a[4].marker + - a[4].seriesName + - ":" + - a[4].value + - "
" - ); - } - }, - axisPointer: { - type: "cross", - }, - backgroundColor: "#fff", - borderWidth: 1, - borderColor: "#ccc", - padding: 10, - textStyle: { - color: "#000", - }, - }, - ], - axisPointer: { - link: [ - { - xAxisIndex: "all", - }, - ], - label: { - backgroundColor: "#777", - }, - }, - toolbox: { - show: false, - }, - - visualMap: { - show: false, - seriesIndex: 5, - dimension: 2, - pieces: [ - { - value: 1, - color: downColor, - }, - { - value: -1, - color: upColor, - }, - ], - }, - grid: [ - { - top: "8%", - // left: window.innerWidth > 768 ? '10%' : '17%', - right: "8%", - height: "40%", - containLabel: false, - }, - { - // left: window.innerWidth > 768 ? '10%' : '17%', - right: "8%", - top: "10%", - height: "1%", - containLabel: false, - }, - { - // left: window.innerWidth > 768 ? '10%' : '17%', - right: "8%", - top: window.innerWidth > 768 ? "60%" : "63%", - height: "30%", - containLabel: false, - }, - ], - xAxis: [ - { - type: "category", - data: dealData.categoryData, - boundaryGap: true, - axisLine: { onZero: false }, - splitLine: { show: false }, - min: "dataMin", - max: "dataMax", - axisPointer: { - z: 100, - }, - axisLine: { - lineStyle: { - color: "#8392A5", - }, - }, - }, - { - type: "category", - gridIndex: 1, - data: [], - boundaryGap: true, - axisLine: { onZero: false }, - axisTick: { show: false }, - splitLine: { show: false }, - axisLabel: { show: false }, - min: "dataMin", - max: "dataMax", - show: false, - }, - { - type: "category", - gridIndex: 2, - data: dealData.categoryData, - boundaryGap: true, - axisLine: { - onZero: true, - lineStyle: { - color: "#8392A5", - }, - }, - axisTick: { show: false }, - splitLine: { show: false }, - axisLabel: { show: false }, - min: "dataMin", - max: "dataMax", - }, - ], - yAxis: [ - { - scale: true, - splitArea: { - show: false, - }, - splitLine: { - show: !1, - }, - axisLine: { - lineStyle: { - color: "#8392A5", - }, - }, - }, - { - scale: true, - gridIndex: 1, - splitNumber: 2, - min: "0", - max: "100", - axisLabel: { show: false }, - - axisLine: { show: false }, - axisTick: { show: false }, - splitLine: { show: false }, - }, - { - scale: true, - gridIndex: 2, - splitNumber: 2, - axisLabel: { show: true }, - axisLine: { onZero: true }, - axisLine: { - show: true, - onZero: false, - lineStyle: { - color: "#8392A5", - }, - }, - axisTick: { show: true }, - splitLine: { show: false }, - }, - ], - dataZoom: [ - { - type: "inside", - xAxisIndex: [0, 1, 2], - start: 50, - end: 100, - textStyle: { - color: "#8392A5", - }, - }, - { - show: true, - xAxisIndex: [0, 1, 2], - type: "slider", - top: "85%", - start: 50, - end: 100, - textStyle: { - color: "#8392A5", - }, - }, - ], - series: [ - { - name: "Dow-Jones index", - type: "candlestick", - data: dealData.values, - itemStyle: { - normal: { - color0: "#ec0000", - color: "#00da3c", - borderColor0: "#ec0000", - borderColor: "#00da3c", - }, - }, - }, - { - name: "飞线", - type: "line", - data: calculateMA(1, data), - smooth: true, - symbol: "none", - itemStyle: { - normal: { - color: "#00a32e", - lineStyle: { - color: "#00a32e", - width: 2, - type: "solid", - }, - }, - }, - }, - { - name: "中线", - type: "line", - data: calculateMA(2, data), - smooth: true, - symbol: "none", - itemStyle: { - normal: { - color: "#de0000", - lineStyle: { - color: "#de0000", - width: 2, - type: "solid", - }, - }, - }, - }, - { - name: "天线", - type: "line", - data: calculateMA(3, data), - smooth: true, - symbol: "none", - itemStyle: { - normal: { - color: "#ffb300", - lineStyle: { - color: "#ffb300", - width: 2, - type: "solid", - }, - }, - }, - }, - { - name: "流线", - type: "line", - data: calculateMA(4, data), - smooth: true, - symbol: "none", - itemStyle: { - normal: { - color: "#00c8ff", - lineStyle: { - color: "#00c8ff", - width: 2, - type: "solid", - }, - }, - }, - }, - { - name: "买盘", - data: bodongliangData(bodongliang.values, 1), - xAxisIndex: 2, - yAxisIndex: 2, - type: "bar", - stack: "1", - itemStyle: { - normal: { - color: "#ec0000", - }, - }, - }, - { - name: "卖盘", - data: bodongliangData(bodongliang.values, 0), - xAxisIndex: 2, - yAxisIndex: 2, - type: "bar", - stack: "1", - itemStyle: { - normal: { - color: "#00ffff", - }, - }, - }, - - { - name: "CJ", - data: bodongliangData(bodongliang.values, 2), - xAxisIndex: 2, - yAxisIndex: 2, - type: "line", - smooth: !0, - showSymbol: false, - itemStyle: { - normal: { - color: "#B0B0B0", - }, - }, - lineStyle: { - width: 2, - }, - }, - { - name: "CD", - data: bodongliangData(bodongliang.values, 3), - xAxisIndex: 2, - yAxisIndex: 2, - type: "line", - smooth: !0, - showSymbol: false, - itemStyle: { - normal: { - color: "#ffb300", - }, - }, - lineStyle: { - width: 2, - }, - }, - { - name: "CK", - data: bodongliangData(bodongliang.values, 4), - xAxisIndex: 2, - yAxisIndex: 2, - type: "line", - smooth: !0, - showSymbol: false, - itemStyle: { - normal: { - color: "#ff00ff", - }, - }, - lineStyle: { - width: 2, - }, - }, - ], - }; - } else if (klineData.type === 6) { - console.log("进入第6分类"); - - var bodongliang = splitData(data.WAVEVOL); - function bodongliangData(values, i) { - return values.map((subArray) => subArray[i]); - } - function calculateMA(index, data) { - let result = []; - if (data.FTLINE) { - data.FTLINE.forEach((item) => { - result.push(item[index]); - }); - } - return result; - } - function vwToPx(vw) { - return (window.innerWidth * vw) / 100; - } - const arr1 = []; - const arr2 = []; - const arr3 = []; - const arr4 = []; - const changeColorKline = (QSXH, KLine20) => { - if (QSXH) { - QSXH.map((item) => { - KLine20.map((kline_item) => { - if (item[1] == 1 && item[0] == kline_item[0]) { - arr1.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 2 && item[0] == kline_item[0]) { - arr2.push(kline_item); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 3 && item[0] == kline_item[0]) { - arr3.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr4.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - if (item[1] == 4 && item[0] == kline_item[0]) { - arr4.push(kline_item); - arr2.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr3.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - arr1.push([ - kline_item[0], - null, - null, - null, - null, - null, - null, - null, - ]); - } - }); - }); - } - }; - changeColorKline(data.QSXH, data.KLine20); - var dealData = splitData(data.KLine20); - var dealData1 = splitData(arr1); - var dealData2 = splitData(arr2); - var dealData3 = splitData(arr3); - var dealData4 = splitData(arr4); - var dealGnBullData = data.JN; - const processBarData = (data) => { - const barData = []; - const markPointData = []; - data.forEach((item) => { - let color; - switch (item[4]) { - case 1: - color = "#13E113"; - break; - case 2: - color = "#FF0E00"; - break; - case 3: - color = "#0000FE"; - break; - case 4: - color = "#1397FF"; - break; - } - barData.push({ - value: item[5], - itemStyle: { - normal: { - color: color, - }, - }, - }); - if (item[1] === 1) { - markPointData.push({ - coord: [item[0], item[5]], - symbol: - "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujb101000d5si3v3hr7w2vg0h43z1u.png", - symbolSize: [30, 30], - label: { - normal: { - color: "rgba(0, 0, 0, 0)", - }, - }, - }); - } - if (item[2] === 1) { - markPointData.push({ - coord: [item[0], item[5] / 2], - symbol: - "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujaz01000d5si016bxdf6vh0377d2h.png", - symbolSize: [30, 30], - label: { - normal: { - color: "rgba(0, 0, 0, 0)", - }, - }, - }); - } - if (item[3] === 1) { - markPointData.push({ - coord: [item[0], 0], - symbol: - "image://https://d31zlh4on95l9h.cloudfront.net/images/5iujb001000d5shzls0tmd4vs0e5tdrw.png", - symbolSize: [30, 30], - label: { - normal: { - color: "rgba(0, 0, 0, 0)", - }, - }, - }); - } - }); - return { barData, markPointData }; - }; - const { barData, markPointData } = processBarData(dealGnBullData); - KlineOption = { - legend: [ - { - textStyle: { - color: "black", - fontSize: window.innerWidth > 768 ? 15 : vwToPx(1.8), - }, - width: "100%", - // top: , - left: "center", - itemGap: window.innerWidth > 768 ? 20 : 10, - itemWidth: 10, - itemHeight: 10, - data: [ - { - name: "进攻K线", - itemStyle: { - color: "rgb(255,0,0)", - }, - }, - { - name: "防守K线", - itemStyle: { - color: "red", - }, - }, - { - name: "推进K线", - itemStyle: { - color: "orange", - }, - }, - { - name: "撤退K线", - itemStyle: { - color: "rgb(84,252,252)", - }, - }, - ], - }, - { - textStyle: { - color: "black", - fontSize: window.innerWidth > 768 ? 15 : vwToPx(2.8), - }, - width: "100%", - top: "5%", - left: "center", - itemGap: window.innerWidth > 768 ? 20 : 10, - itemWidth: 10, - itemHeight: 10, - data: [ - { - name: "天线", - }, - { - name: "飞线", - itemStyle: { - color: "#fff", - }, - }, - { - name: "中线", - }, - { - name: "流线", - }, - ], - }, - { - textStyle: { - color: "black", - fontSize: window.innerWidth > 768 ? 15 : vwToPx(2.8), - }, - orient: "horizontal", - top: window.innerWidth > 768 ? "8%" : "8%", - width: "100%", - left: "center", - itemGap: 15, - data: [ - { - name: "龙线", - }, - { - name: "虫线", - }, - ], - }, - ], - tooltip: { - formatter: function (a, b, d) { - if (a[0].seriesIndex == 0) { - const KlineTag = ref([]); - const AIBullTag = ref([]); - KlineTag.value = a.find((item) => item.data[1])?.data || []; - AIBullTag.value = - a.slice(4).find((item) => item.data[1] !== "-")?.data || []; - return ( - a[0].name + - "
" + - "开盘价" + - ":" + - KlineTag.value[1] + - "
" + - "收盘价" + - ":" + - KlineTag.value[2] + - "
" + - "最低价" + - ":" + - KlineTag.value[3] + - "
" + - "最高价" + - ":" + - KlineTag.value[4] + - "
" + - a[4].seriesName + - ":" + - a[4].value + - "
" + - a[5].seriesName + - ":" + - a[5].value + - "
" + - a[6].seriesName + - ":" + - a[6].value + - "
" + - a[7].seriesName + - ":" + - a[7].value - ); - } - if (a[0].seriesIndex == 4) { - let formattedVolume; - if (a[0].data.value >= 10000) { - formattedVolume = (a[0].data.value / 10000).toFixed(2) + "w"; - } else { - formattedVolume = a[0].data.value; - } - return a[0].name + "
" + "成交量" + ":" + formattedVolume; - } - if (a[0].seriesIndex == 9) { - return ( - a[0].name + - "
" + - a[0].marker + - a[0].seriesName + - ":" + - a[0].value + - "
" + - a[1].marker + - a[1].seriesName + - ":" + - a[1].value + - "
" + - a[2].marker + - a[2].seriesName + - ":" + - a[2].value + - "
" + - a[3].marker + - a[3].seriesName + - ":" + - a[3].value + - "
" + - a[4].marker + - a[4].seriesName + - ":" + - a[4].value + - "
" - ); - } - }, - trigger: "axis", - axisPointer: { - type: "cross", - }, - backgroundColor: "rgba(119, 120, 125, 0.6)", - borderWidth: 1, - borderColor: "#77787D", - padding: 10, - textStyle: { - color: "#fff", - }, - }, - axisPointer: { - link: [ - { - xAxisIndex: "all", - }, - ], - label: { - backgroundColor: "#77787D", - }, - }, - toolbox: { - show: false, - }, - grid: [ - { - left: window.innerWidth > 768 ? "14%" : "15%", - right: window.innerWidth > 768 ? "4%" : "5%", - top: window.innerWidth > 768 ? "10%" : "12%", - height: window.innerWidth > 768 ? "36%" : "34%", - containLabel: false, - }, - { - left: window.innerWidth > 768 ? "14%" : "15%", - right: window.innerWidth > 768 ? "4%" : "5%", - top: window.innerWidth > 768 ? "50%" : "50%", - height: window.innerWidth > 768 ? "20%" : "22%", - containLabel: false, - }, - { - left: window.innerWidth > 768 ? "14%" : "15%", - right: window.innerWidth > 768 ? "4%" : "5%", - top: window.innerWidth > 768 ? "74%" : "75%", - height: window.innerWidth > 768 ? "20%" : "20%", - containLabel: false, - }, - ], - xAxis: [ - { - type: "category", - data: dealData.categoryData, - boundaryGap: true, - axisLine: { onZero: false }, - splitLine: { show: false }, - min: "dataMin", - max: "dataMax", - axisPointer: { - z: 100, - }, - axisLine: { - lineStyle: { - color: "black", - }, - }, // - axisLabel: { show: false }, - axisTick: { show: false }, - }, - { - type: "category", - gridIndex: 1, - data: dealData.categoryData, - boundaryGap: true, - axisLine: { lineStyle: { color: "black" } }, - axisLabel: { - show: false, - // fontSize: window.innerWidth > 768 ? 10 : 8, - interval: "auto", - }, - axisTick: { show: false }, - }, - { - type: "category", - gridIndex: 2, - data: dealData.categoryData, - boundaryGap: true, - axisLine: { lineStyle: { color: "black" } }, - axisLabel: { - show: true, - interval: "auto", - }, - axisTick: { show: false }, - }, - ], - yAxis: [ - { - scale: true, - gridIndex: 0, - position: "left", - axisLabel: { - inside: false, - align: "right", - fontSize: window.innerWidth > 768 ? 15 : 10, - }, - axisLine: { - show: true, - lineStyle: { - fontSize: "", - color: "black", - }, - }, - axisTick: { show: false }, - splitLine: { show: false }, - }, - { - scale: true, - gridIndex: 1, - splitNumber: 4, - min: 0, - minInterval: 1, - axisLabel: { - show: true, - fontSize: window.innerWidth > 768 ? 15 : 10, - margin: 8, - formatter: (value) => { - if (value >= 1000000000) { - return (value / 1000000000).toFixed(1) + "B"; - } else if (value >= 1000000) { - return (value / 1000000).toFixed(1) + "M"; - } else if (value >= 10000) { - return (value / 10000).toFixed(1) + "W"; - } - return value.toFixed(0); - }, - }, - axisLine: { show: true, lineStyle: { color: "black" } }, - axisTick: { show: false }, - splitLine: { show: true, lineStyle: { type: "dashed" } }, - boundaryGap: ["20%", "20%"], - }, - { - scale: true, - gridIndex: 2, - splitNumber: 2, - axisLabel: { - show: true, - fontSize: window.innerWidth > 768 ? 15 : 10, - }, - axisLine: { show: true, lineStyle: { color: "black" } }, - axisTick: { show: false }, - splitLine: { show: false }, - }, - ], - dataZoom: [ - { - type: "inside", - xAxisIndex: [0, 1, 2], - start: 55, - end: 100, - }, - { - show: true, - xAxisIndex: [0, 1, 2], - type: "slider", - top: window.innerWidth > 768 ? "95%" : "95%", - left: window.innerWidth > 768 ? "14%" : "14%", - start: 98, - end: 100, - }, - ], - series: [ - { - name: "进攻K线", - type: "candlestick", - barWidth: "50%", - data: dealData1.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "rgb(255,0,0)", - color0: "rgb(255,0,0)", - borderColor: "rgb(255,0,0)", - borderColor0: "rgb(255,0,0)", - }, - }, - gridIndex: 0, - }, - // - { - name: "推进K线", - type: "candlestick", - barWidth: "50%", - data: dealData2.values, - // markPoint: { data: dealMarkPointData }, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "rgb(0,0,252)", - color0: "rgb(0,0,252)", - borderColor: "rgb(0,0,252)", - borderColor0: "rgb(0,0,252)", - }, - }, - gridIndex: 0, - }, - { - name: "防守K线", - type: "candlestick", - barWidth: "50%", - data: dealData3.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "orange", - color0: "orange", - borderColor: "orange", - borderColor0: "orange", - }, - }, - gridIndex: 0, - }, { - name: "撤退K线", - type: "candlestick", - barWidth: "50%", - data: dealData4.values, - xAxisIndex: 0, - yAxisIndex: 0, - itemStyle: { - normal: { - color: "rgb(84,252,252)", - color0: "rgb(84,252,252)", - borderColor: "rgb(84,252,252)", - borderColor0: "rgb(84,252,252)", + name: "背景区域", + type: "line", + data: [], + xAxisIndex: 2, + yAxisIndex: 2, + markArea: { + silent: true, + itemStyle: { + normal: { + opacity: 1, + }, }, - }, - gridIndex: 0, - }, - { - name: "成交量", - type: "bar", - barWidth: "70%", - xAxisIndex: 1, - yAxisIndex: 1, - data: barData, - markPoint: { - data: markPointData, label: { - show: false, - }, - }, - }, - { - name: "飞线", - type: "line", - data: calculateMA(1, data), - smooth: true, - symbol: "none", - itemStyle: { - normal: { - color: "#00a32e", - lineStyle: { - color: "#00a32e", - width: 2, - type: "solid", + normal: { + show: true, + position: "insideRight", + fontSize: window.innerWidth > 768 ? 16 : 12, + fontWeight: "bold", + color: "#13E113", + distance: 10, }, }, + data: [ + [ + { + yAxis: 0, + itemStyle: { + normal: { + color: "#CFFFCF", + }, + }, + label: { + normal: { + formatter: "度牛区", + }, + }, + }, + { + yAxis: 20, + }, + ], + [ + { + yAxis: 20, + itemStyle: { + normal: { + color: "#A6FFFF", + }, + }, + }, + { + yAxis: 40, + }, + ], + [ + { + yAxis: 40, + itemStyle: { + normal: { + color: "#FFF686", + }, + }, + }, + { + yAxis: 60, + }, + ], + [ + { + yAxis: 60, + itemStyle: { + normal: { color: "#FFD2B3" }, + }, + }, + { + yAxis: 80, + }, + ], + [ + { + yAxis: 80, + itemStyle: { + normal: { color: "#FFB8B8" }, + }, + label: { + normal: { + formatter: "度牛区", + color: "#FF0000", + position: "insideLeft", + distance: 10, + }, + }, + }, + { + yAxis: 100, + }, + ], + ], }, }, { - name: "中线", + name: "度牛尺", type: "line", - data: calculateMA(2, data), - smooth: true, + data: maDuchiData.greenData, symbol: "none", + xAxisIndex: 2, + yAxisIndex: 2, itemStyle: { normal: { - color: "#de0000", + color: "green", lineStyle: { - color: "#de0000", width: 2, type: "solid", }, }, }, - }, - { - name: "天线", - type: "line", - data: calculateMA(3, data), - smooth: true, - symbol: "none", - itemStyle: { - normal: { - color: "#ffb300", - lineStyle: { - color: "#ffb300", - width: 2, - type: "solid", + gridIndex: 2, + markPoint: { + symbol: "rect", + symbolSize: (value, params) => { + const width = window.innerWidth; + const baseHeight = 36; + if (width <= 375) { + return [2, 16]; + } else if (width <= 768) { + return [2, 24]; + } + return [2, baseHeight]; + }, + itemStyle: { + normal: { + label: { + show: false, + }, }, }, + data: [ + ...maDuchiData.greenData + .map((item) => { + if (item[1] === 0) { + return { + coord: [item[0], 20], + symbolOffset: window.innerWidth > 768 ? [0, 20] : [0, 12], + itemStyle: { + color: "#00ff00", + }, + }; + } + }) + .filter(Boolean), + ], }, }, { - name: "流线", type: "line", - data: calculateMA(4, data), - smooth: true, + data: maDuchiData.redData, + // smooth: true, symbol: "none", + xAxisIndex: 2, + yAxisIndex: 2, itemStyle: { normal: { - color: "#00c8ff", + color: "red", lineStyle: { - color: "#00c8ff", width: 2, type: "solid", }, }, }, - }, - { - name: "买盘", - data: bodongliangData(bodongliang.values, 1), - barWidth: "70%", - xAxisIndex: 2, - yAxisIndex: 2, - type: "bar", - stack: "1", - itemStyle: { - normal: { - color: "#ec0000", + gridIndex: 2, + markPoint: { + symbol: "rect", + symbolSize: (value, params) => { + const width = window.innerWidth; + const baseHeight = 36; + if (width <= 375) { + return [2, 16]; + } else if (width <= 768) { + return [2, 24]; + } + return [2, baseHeight]; + }, + itemStyle: { + normal: { + label: { + show: false, + }, + }, }, + data: [ + ...maDuchiData.redData + .map((item) => { + if (item[1] === 100) { + return { + coord: [item[0], 80], + symbolOffset: + window.innerWidth > 768 ? [0, -20] : [0, -12], + itemStyle: { + color: "#ff0000", + }, + }; + } + }) + .filter(Boolean), + ], }, }, { - name: "卖盘", - data: bodongliangData(bodongliang.values, 0), - barWidth: "70%", + name: "辅助线", + type: "line", + data: [], xAxisIndex: 2, yAxisIndex: 2, - type: "bar", - stack: "1", - itemStyle: { - normal: { - color: "#00ffff", + markLine: { + silent: true, + symbol: "none", + lineStyle: { + color: "#000000", + width: 3, + type: "solid", }, + data: [{ yAxis: 20 }], }, }, { - name: "CJ", - data: bodongliangData(bodongliang.values, 2), + name: "辅助线", + type: "line", + data: [], xAxisIndex: 2, yAxisIndex: 2, - type: "line", - smooth: !0, - showSymbol: false, - itemStyle: { - normal: { - color: "#000", + markLine: { + silent: true, + symbol: "none", + lineStyle: { + color: "#000000", + width: 3, + type: "solid", }, - }, - lineStyle: { - width: 2, + data: [{ yAxis: 50 }], }, }, { - name: "CD", - data: bodongliangData(bodongliang.values, 3), + name: "辅助线", + type: "line", + data: [], xAxisIndex: 2, yAxisIndex: 2, - type: "line", - smooth: !0, - showSymbol: false, - itemStyle: { - normal: { - color: "#ffb300", + markLine: { + silent: true, + symbol: "none", + lineStyle: { + color: "#000000", + width: 3, + type: "solid", }, - }, - lineStyle: { - width: 2, + data: [{ yAxis: 80 }], }, }, { - name: "CK", - data: bodongliangData(bodongliang.values, 4), + name: "辅助线", + type: "line", + data: [], xAxisIndex: 2, yAxisIndex: 2, - type: "line", - smooth: !0, - showSymbol: false, - itemStyle: { - normal: { - color: "#ff00ff", - }, - }, - lineStyle: { - width: 2, - }, - }, - ], - // graphic: { - // markPointData : generateGraphicmarkPointData(data11111) - // } - }; - } else { - console.log("其他分类"); - - var dealData = splitData(data.KLine20); - console.log("dealData", dealData); - - KlineOption = { - title: { - text: klineData.name, - left: 50, - }, - tooltip: { - trigger: "axis", - formatter: function (a, b, d) { - let def = - a[0].name + - "
" + - "开盘价" + - a[0].data[1] + - "
" + - "收盘价" + - a[0].data[2] + - "
" + - "最低价" + - a[0].data[3] + - "
" + - "最高价" + - a[0].data[4]; - - if (a[1] && a[1].seriesName) { - def += "
" + a[1].seriesName + ":" + a[1].value; - } - return def; - }, - axisPointer: { - animation: false, - type: "line", - lineStyle: { - color: "#376df4", - width: 2, - opacity: 1, - }, - }, - confine: true, // 确保提示框不超出画布 - }, - //控制坐标轴 - grid: { - left: "12%", - right: "10%", - bottom: "10%", - top: "18%", - }, - xAxis: { - type: "category", - data: dealData.categoryData, - axisLine: { lineStyle: { color: "#8392A5" } }, - }, - yAxis: { - scale: !0, //true - // 自定义纵坐标现实的数据 - axisLabel: { - formatter: function (value) { - return value; // 返回原始值 - }, - }, - axisLine: { lineStyle: { color: "#8392A5" } }, - splitLine: { - show: !1, - }, - }, - dataZoom: [ - { - textStyle: { - color: "#8392A5", - }, - handleIcon: - "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", - handleSize: "80%", - dataBackground: { - areaStyle: { - color: "#8392A5", - }, + markLine: { + silent: true, + symbol: "none", lineStyle: { - opacity: 0.8, - color: "#8392A5", - }, - }, - handleStyle: { - color: "#fff", - shadowBlur: 3, - shadowColor: "rgba(0, 0, 0, 0.6)", - shadowOffsetX: 2, - shadowOffsetY: 2, - }, - }, - { - type: "inside", - start: 1, - end: 100, - zoomOnMouseWheel: true, - moveOnMouseMove: true, - }, - ], - animation: false, - series: [ - { - type: "candlestick", - name: "\u65e5K", - data: dealData.values, - itemStyle: { - normal: { - color0: "#FD1050", - color: "#0CF49B", - borderColor0: "#FD1050", - borderColor: "#0CF49B", + color: "#000000", + width: 3, + + type: "solid", }, - }, - // barWidth: isMobile ? 6 : isTablet ? 8 : 10 - }, - { - name: "MA5", - type: "line", - data: (function (a) { - for (var MA5 = [], d = 0, g = dealData.values.length; d < g; d++) { - if (d < a) { - MA5.push("-"); - } else { - for (var f = 0, e = 0; e < a; e++) { - f += dealData.values[d - e][1]; - } - MA5.push((f / a).toFixed(2)); - } - } - return MA5; - })(5), - smooth: true, - lineStyle: { - width: isMobile ? 1 : 2, - opacity: 0.8, + data: [{ yAxis: 100 }], }, }, ], @@ -5106,26 +2382,30 @@ function KlineCanvsEcharts(containerId) { console.log("KLine渲染: 图表选项设置成功"); // 窗口大小变化时重新渲染图表 - const resizeFunc = function () { - console.log("窗口大小改变,调整图表大小"); - if ( - chartInstancesMap[containerId] && - !chartInstancesMap[containerId].isDisposed() - ) { - // 如果设备类型发生变化,重新渲染 - const newIsMobile = window.innerWidth < 768; - const newIsTablet = - window.innerWidth >= 768 && window.innerWidth < 1024; - - if (newIsMobile !== isMobile || newIsTablet !== isTablet) { - console.log("设备类型变化,重新渲染图表"); - KlineCanvsEcharts(containerId); - return; - } + const resizeFunc = _.throttle( + function () { + console.log("窗口大小改变,调整图表大小"); + if ( + chartInstancesMap[containerId] && + !chartInstancesMap[containerId].isDisposed() + ) { + // 如果设备类型发生变化,重新渲染 + const newIsMobile = window.innerWidth < 768; + const newIsTablet = + window.innerWidth >= 768 && window.innerWidth < 1024; + + if (newIsMobile !== isMobile || newIsTablet !== isTablet) { + console.log("设备类型变化,重新渲染图表"); + KlineCanvsEcharts(containerId); + return; + } - chartInstancesMap[containerId].resize(); - } - }; + chartInstancesMap[containerId].resize(); + } + }, + 1000, + { trailing: false } + ); // 给resize事件绑定一个特定的函数名,便于后续移除 window[`resize_${containerId}`] = resizeFunc; @@ -5200,7 +2480,7 @@ function renderAllKlineCharts() { // 查找所有K线消息 const messages = chatStore.messages; for (let i = 0; i < messages.length; i++) { - if (messages[i].type === "kline" && messages[i].chartData) { + if (messages[i].kline && messages[i].chartData) { const containerId = `kline-container-${i}`; console.log(`尝试渲染K线图: ${containerId}`); @@ -5226,6 +2506,7 @@ onMounted(() => { smartLists: true, // 智能列表 smartypants: true, // 智能标点符号 xhtml: false, // 不使用 XHTML 输出 + renderer: renderer, }); const random = Math.floor(Math.random() * 6) + 1; @@ -5323,7 +2604,7 @@ onUnmounted(() => { 出错了
-
+

暂无数据

@@ -5335,7 +2616,7 @@ onUnmounted(() => {
-
+

暂无数据

@@ -5600,6 +2881,17 @@ onUnmounted(() => { align-items: center; } +.content1chart { + background-image: url("@/assets/img/AIchat/罗盘边框.png"); + background-repeat: no-repeat; + background-size: 100% 100%; + width: 50vw; + min-width: 350px; + display: flex; + justify-content: center; + align-items: center; +} + .content1Text { background-image: url("@/assets/img/AIchat/框.png"); background-repeat: no-repeat; @@ -5621,6 +2913,20 @@ onUnmounted(() => { .message-bubble.ai.content2 { width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.content2chart { + background-image: url("@/assets/img/AIchat/PCbackPic.png"); + background-repeat: no-repeat; + background-size: 100% 100%; + width: 50vw; + min-width: 350px; + display: flex; + justify-content: center; + align-items: center; } .message-bubble.ai.content3 { @@ -5663,7 +2969,7 @@ onUnmounted(() => { min-height: 320px; /* 视口高度单位 */ height: 40vh; - min-width: 50vw; + width: 50vw; } @media (max-width: 768px) { @@ -5682,6 +2988,11 @@ onUnmounted(() => { font-size: 20px; } + .content2chart { + background-image: url("@/assets/img/AIchat/new-app-bgc.png") !important; + height: 100vw; + } + .content3Text { width: 77vw; min-width: 0px; @@ -5699,7 +3010,10 @@ onUnmounted(() => { } .kline-container .chart-mount-point { - height: 100%; - width: 100%; + display: flex; + justify-content: center; + align-items: center; + height: 80%; + width: 90%; } diff --git a/src/views/Announcement.vue b/src/views/Announcement.vue index b8e413b..359cd10 100644 --- a/src/views/Announcement.vue +++ b/src/views/Announcement.vue @@ -26,18 +26,18 @@ const codeList = ref([ const getMarketAndCode = async () => { const result = await getMarketAndCodeAPI() - console.log(result.data, "MarketAndCode"); + // console.log(result.data, "MarketAndCode"); for (let i = 0; i < result.data.length; i++) { const item = result.data[i]; const market = marketList.value[item.market]; const codeLists=item.code.split(',') - console.log(codeLists, "codeLists",market,'market'); + // console.log(codeLists, "codeLists",market,'market'); const targetMarket=codeList.value.find(item=>item.market==market) if(targetMarket){ targetMarket.code=codeLists - console.log(targetMarket, "targetMarket"); + // console.log(targetMarket, "targetMarket"); }else{ console.log("未找到对应的市场") } @@ -50,7 +50,7 @@ const getMarketAndCode = async () => { const announcementVideo = ref({}); const getAnnouncement = async () => { const result = await getAnnouncementAPI() - console.log(result.data, "result.data"); + // console.log(result.data, "result.data"); announcementVideo.value.url = result.data[0].url; announcementVideo.value.img = result.data[0].img; @@ -58,9 +58,9 @@ const getAnnouncement = async () => { token: localStorage.getItem('localToken'), id: result.data[0].id }) - console.log(click); + // console.log(click); - console.log(announcementVideo.value, "announcementVideo"); + // console.log(announcementVideo.value, "announcementVideo"); } const handleVideoPlay = () => { diff --git a/src/views/Feedback.vue b/src/views/Feedback.vue index f147f5e..7a10c33 100644 --- a/src/views/Feedback.vue +++ b/src/views/Feedback.vue @@ -12,7 +12,6 @@ import failure from "../assets/img/Feedback/failure.png"; import save from "../assets/img/Feedback/save.png"; import back from "../assets/img/Feedback/back.png"; import purpleDot from "../assets/img/Feedback/purpleDot.png"; - import moment from 'moment'; const dataStore = useDataStore()