Browse Source

每个K线图单独显示

hxl
hongxilin 2 months ago
parent
commit
ac8c28b017
  1. 2
      .env.development
  2. 5
      .env.production
  3. 27
      src/views/AIchat.vue
  4. 157
      src/views/Echarts/KLine.vue
  5. 48
      src/views/homePage.vue

2
.env.development

@ -2,7 +2,7 @@
VITE_ENV = 'development' VITE_ENV = 'development'
VITE_OUTPUT_DIR = 'dev' VITE_OUTPUT_DIR = 'dev'
# public path # public path
VITE_PUBLIC_PATH = /AIxiaocaishen
VITE_PUBLIC_PATH = /
#新数据接口 #新数据接口
VITE_APP_API_BASE_URL = "http://39.101.133.168:8828/link" VITE_APP_API_BASE_URL = "http://39.101.133.168:8828/link"

5
.env.production

@ -2,13 +2,14 @@
VITE_ENV = 'production' VITE_ENV = 'production'
VITE_OUTPUT_DIR = 'dist' VITE_OUTPUT_DIR = 'dist'
# public path # public path
VITE_PUBLIC_PATH = /AIxiaocaishen
VITE_PUBLIC_PATH = /aixiaocaishen
# Whether to open mock # Whether to open mock
VITE_USE_MOCK = true VITE_USE_MOCK = true
#新数据接口 #新数据接口
VITE_APP_API_BASE_URL = https://api.homilychart.com/link
# VITE_APP_API_BASE_URL = https://api.homilychart.com/link
VITE_APP_API_BASE_URL = "http://39.101.133.168:8828/link"
#MJ API #MJ API
VITE_APP_MJ_API_BASE_URL = "http://192.168.9.19:8080/api" VITE_APP_MJ_API_BASE_URL = "http://192.168.9.19:8080/api"

27
src/views/AIchat.vue

@ -247,35 +247,24 @@ watch(
Kline: data.data.AIBull.KLine20 Kline: data.data.AIBull.KLine20
} }
dataStore.setKlineData(Kline20);
// chatStore.chartData.push({
// data: Kline20.Kline
// });
// for (let i = 0; i < chatStore.chartData.length; i++) {
// console.log(chatStore.chartData[i], "chatStore.chartData[i]")
// }
chatStore.messages.pop(); chatStore.messages.pop();
// K线
chatStore.messages.push({ chatStore.messages.push({
sender: "ai", sender: "ai",
type: "kline", type: "kline",
chartRef: Kline20.name, //
chartData: Kline20.Kline, //
chartData: Kline20, //
messageId: `kline-${Date.now()}` // ID
}); });
//
chatStore.messages.push({ chatStore.messages.push({
sender: "ai", sender: "ai",
content: "AI正在思考中..." content: "AI正在思考中..."
}); });
console.log(Kline20, "Kline20");
console.log(code, "code");
console.log(market, "market");
console.log(data, "data");
// K线dataStore使
dataStore.setKlineData(Kline20);
} else if (ans.value.answerN !== "") { } else if (ans.value.answerN !== "") {
AIcontent.value = ans.value.answerN; AIcontent.value = ans.value.answerN;
@ -499,9 +488,7 @@ onMounted(() => {
<div v-for="(msg, index) in chatMsg" :key="index" :class="['message-bubble', msg.sender]"> <div v-for="(msg, index) in chatMsg" :key="index" :class="['message-bubble', msg.sender]">
<div v-if="msg.type === 'kline'" class="kline-container"> <div v-if="msg.type === 'kline'" class="kline-container">
<KLine />
<!-- <KLine :key="msg.timestamp" /> -->
<!-- <div class="kLineChart"></div> -->
<KLine :chartData="msg.chartData" />
</div> </div>
<div v-else v-html="msg.content"></div> <div v-else v-html="msg.content"></div>
</div> </div>

157
src/views/Echarts/KLine.vue

@ -1,109 +1,46 @@
<template> <template>
<!-- <div ref="KlineCanvs" class="KlineClass"></div> -->
<div ref="chartContainer" class="KlineClass"></div> <div ref="chartContainer" class="KlineClass"></div>
</template> </template>
<script setup> <script setup>
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { useDataStore } from '@/store/dataList' import { useDataStore } from '@/store/dataList'
// import { useLanguage } from '@/utils/languageService'
// const { translate, t } = useLanguage()
const KlineCanvs = ref() // Echarts
const dataStore = useDataStore()
const klineData = computed(() => dataStore.klineData)
const chartContainer = ref() //
const chartInstances = ref([]) //
//
// watch(
// klineData,
// (newValue) => {
// console.log('K线', newValue) //
// const currentData = newValue //
// if (currentData) {
// nextTick(() => {
// //
// const newChartDiv = document.createElement('div')
// newChartDiv.className = 'dynamic-chart'
// chartContainer.value.appendChild(newChartDiv)
// //
// requestAnimationFrame(() => {
// //
// if (newChartDiv.offsetHeight === 0) {
// console.warn('')
// newChartDiv.style.height = '500px'
// }
import { onMounted, watch, ref, computed, nextTick, onUnmounted } from 'vue'
// const newInstance = echarts.init(newChartDiv)
// chartInstances.value.push(newInstance)
// KlineCanvsEcharts(currentData, newInstance)
// })
// // KlineCanvsEcharts(currentData)
//
const props = defineProps({
chartData: {
type: Object,
default: null
}
})
// console.log(':', newChartDiv.offsetWidth, 'x', newChartDiv.offsetHeight)
// })
// }
// },
// { immediate: true, deep: true }
// )
const chartContainer = ref() //
const chartInstance = ref(null) //
//
watch( watch(
klineData,
() => props.chartData,
(newValue) => { (newValue) => {
console.log('收到K线数据:', newValue)
const currentData = newValue
if (currentData) {
console.log('KLine组件收到数据:', newValue)
if (newValue) {
nextTick(() => { nextTick(() => {
//
const chartId = `chart-${Date.now()}`
const newChartDiv = document.createElement('div')
newChartDiv.className = 'dynamic-chart'
newChartDiv.id = chartId
chartContainer.value.appendChild(newChartDiv)
requestAnimationFrame(() => {
if (newChartDiv.offsetHeight === 0) {
newChartDiv.style.height = '500px'
}
//
const newInstance = echarts.init(newChartDiv)
const instanceData = JSON.parse(JSON.stringify(currentData))
//
chartInstances.value.push({
id: chartId,
instance: newInstance,
data: instanceData,
container: newChartDiv //
})
// 使
KlineCanvsEcharts(instanceData, newInstance)
})
//
if (chartContainer.value && !chartInstance.value) {
chartInstance.value = echarts.init(chartContainer.value)
// 使
const instanceData = JSON.parse(JSON.stringify(newValue))
KlineCanvsEcharts(instanceData, chartInstance.value)
}
}) })
} }
}, },
{ immediate: true, deep: true }
{ immediate: true }
) )
//
// watch(
// () => t.value,
// (newLang) => {
// // textEcharts
// if (klineData.value) {
// const currentData = klineData
// nextTick(() => {
// KlineCanvsEcharts(currentData)
// })
// }
// },
// { immediate: true, deep: true }
// )
function KlineCanvsEcharts(datatok, instance) { function KlineCanvsEcharts(datatok, instance) {
// const textEcahrts = t.value //
const data = datatok.Kline
// //
const data = datatok.Kline
const spliteDate = (a) => { const spliteDate = (a) => {
const categoryData = [] const categoryData = []
let value = [] let value = []
@ -124,8 +61,6 @@ function KlineCanvsEcharts(datatok, instance) {
// //
const KlineOption = { const KlineOption = {
title: { title: {
// text: k_name,
// Canvs
text: datatok.name, text: datatok.name,
top: 20, top: 20,
left: 20 left: 20
@ -265,54 +200,36 @@ function KlineCanvsEcharts(datatok, instance) {
} }
] ]
} }
// echarts
// const KlineCanvsChart = echarts.init(KlineCanvs.value)
// KlineCanvsChart.setOption(KlineOption)
//
//
instance.setOption(KlineOption) instance.setOption(KlineOption)
//
// window.addEventListener('resize', () => {
// KlineCanvsChart.resize()
// })
// resize // resize
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
instance.resize() instance.resize()
}) })
} }
onMounted(() => {
// fnGetData()
//
onUnmounted(() => {
if (chartInstance.value) {
chartInstance.value.dispose()
chartInstance.value = null
}
// resize
window.removeEventListener('resize', () => {})
}) })
onMounted(() => {
console.log('KLine组件挂载完成')
})
</script> </script>
<style scoped> <style scoped>
.KlineClass { .KlineClass {
position: relative; position: relative;
width: 100%; width: 100%;
min-height: 600px;
/* 改为最小高度 */
display: flex;
flex-direction: column;
gap: 20px;
/* 添加间距 */
}
.chart-container {
position: relative;
width: 100%;
min-height: 400px;
height: 100%; height: 100%;
} }
.dynamic-chart {
width: 100%;
height: 500px !important;
/* 强制高度 */
flex-shrink: 0;
/* 禁止高度压缩 */
}
</style> </style>

48
src/views/homePage.vue

@ -3,6 +3,7 @@
import { ref, computed, onMounted, watch, nextTick } from "vue"; import { ref, computed, onMounted, watch, nextTick } from "vue";
import { setHeight } from "../utils/setHeight"; import { setHeight } from "../utils/setHeight";
import { getUserCountAPI } from "../api/AIxiaocaishen"; import { getUserCountAPI } from "../api/AIxiaocaishen";
import { ElMessage } from 'element-plus'
import AIchat from "./AIchat.vue"; import AIchat from "./AIchat.vue";
import AIfind from "./AIfind.vue"; import AIfind from "./AIfind.vue";
import { useAppBridge } from '../assets/js/useAppBridge.js' import { useAppBridge } from '../assets/js/useAppBridge.js'
@ -10,9 +11,25 @@ import { useDataStore } from '@/store/dataList.js'
import { useChatStore } from '../store/chat' import { useChatStore } from '../store/chat'
import { useAudioStore } from '../store/audio' import { useAudioStore } from '../store/audio'
import _ from "lodash"; import _ from "lodash";
import logo from "../assets/img/homePage/logo.png";
import madeInHL from "../assets/img/homePage/madeInHL.png";
import getCountAll from "../assets/img/homePage/get-count-all.png";
import announcementBtn from "../assets/img/homePage/announcement.png";
import thinkActive from "../assets/img/homePage/tail/think-active.png";
import thinkNoActive from "../assets/img/homePage/tail/think-no-active.png";
import languageBtn from "../assets/img/homePage/tail/language.png";
import voice from "../assets/img/homePage/tail/voice.png";
import voiceNoActive from "../assets/img/homePage/tail/voice-no-active.png";
import sendBtn from "../assets/img/homePage/tail/send.png";
import msgBtn from "../assets/img/homePage/tail/msg.png";
// import { useUserStore } from "../store/userPessionCode.js"; // import { useUserStore } from "../store/userPessionCode.js";
const { getQueryVariable } = useDataStore() const { getQueryVariable } = useDataStore()
// //
// //
const audioStore = useAudioStore() const audioStore = useAudioStore()
@ -101,6 +118,10 @@ const updateMessage = (title) => {
// console.log("updateMessage :", title); // console.log("updateMessage :", title);
}; };
const sendMessage = async () => { const sendMessage = async () => {
if (localStorage.getItem('localToken') == null||localStorage.getItem('localToken') == '') {
ElMessage.error('请先登录');
return ;
}
isScrolling.value = false; isScrolling.value = false;
// ensureAIchat AIchat // ensureAIchat AIchat
ensureAIchat(); ensureAIchat();
@ -318,17 +339,16 @@ onMounted(async () => {
<el-header class="homepage-head"> <el-header class="homepage-head">
<!-- logo --> <!-- logo -->
<div class="homepage-logo"> <div class="homepage-logo">
<img src="src\assets\img\homePage\logo.png" alt="图片加载失败" class="logo1" />
<img src="src\assets\img\homePage\madeInHL.png" alt="图片加载失败" class="logo2" />
<img :src="logo" alt="图片加载失败" class="logo1" />
<img :src="madeInHL" alt="图片加载失败" class="logo2" />
</div> </div>
<div class="homepage-right-group"> <div class="homepage-right-group">
<div class="count-badge" @click="showCount"> <div class="count-badge" @click="showCount">
<img src="src\assets\img\homePage\get-count-all.png" class="action-btn" />
<img :src="getCountAll" class="action-btn" />
<div class="count-number">{{ UserCount }}</div> <div class="count-number">{{ UserCount }}</div>
</div> </div>
<img src="src\assets\img\homePage\announcement.png" class="announcement-btn action-btn"
@click="showAnnouncement" />
<img :src="announcementBtn" class="announcement-btn action-btn" @click="showAnnouncement" />
</div> </div>
</el-header> </el-header>
<!-- 主体部分小人 问题轮询图 对话内容 --> <!-- 主体部分小人 问题轮询图 对话内容 -->
@ -353,17 +373,13 @@ onMounted(async () => {
<!-- 第一行按钮 --> <!-- 第一行按钮 -->
<div class="footer-first-line"> <div class="footer-first-line">
<div class="left-group"> <div class="left-group">
<img v-if="isThinking" src="src\assets\img\homePage\tail\think-active.png" @click="toggleThink"
class="action-btn" />
<img v-else src="src\assets\img\homePage\tail\think-no-active.png" @click="toggleThink"
class="action-btn" />
<img src="src\assets\img\homePage\tail\language.png" @click="changeLanguage" class="action-btn" />
<img v-if="isVoice" src="src\assets\img\homePage\tail\voice.png" @click="toggleVoice" class="action-btn" />
<img v-else src="src\assets\img\homePage\tail\voice-no-active.png" @click="toggleVoice"
class="action-btn" />
<img v-if="isThinking" :src="thinkActive" @click="toggleThink" class="action-btn" />
<img v-else :src="thinkNoActive" @click="toggleThink" class="action-btn" />
<img :src="languageBtn" @click="changeLanguage" class="action-btn" />
<img v-if="isVoice" :src="voice" @click="toggleVoice" class="action-btn" />
<img v-else :src="voiceNoActive" @click="toggleVoice" class="action-btn" />
</div> </div>
<img v-if="!chatStore.isLoading" src="src\assets\img\homePage\tail\send.png" @click="sendMessage"
class="action-btn send-btn" />
<img v-if="!chatStore.isLoading" :src="sendBtn" @click="sendMessage" class="action-btn send-btn" />
<div v-else> <div v-else>
<el-icon class="is-loading"> <el-icon class="is-loading">
<Loading /> <Loading />
@ -373,7 +389,7 @@ onMounted(async () => {
<!-- 第二行输入框 --> <!-- 第二行输入框 -->
<div class="footer-second-line"> <div class="footer-second-line">
<img src="src\assets\img\homePage\tail\msg.png" class="msg-icon" />
<img :src="msgBtn" class="msg-icon" />
<el-input type="textarea" v-model="message" :autosize="{ minRows: 1, maxRows: 4 }" placeholder="给AI小财神发消息..." <el-input type="textarea" v-model="message" :autosize="{ minRows: 1, maxRows: 4 }" placeholder="给AI小财神发消息..."
class="msg-input" @keydown.enter.exact.prevent="isLoading ? null : sendMessage()" resize="none"> class="msg-input" @keydown.enter.exact.prevent="isLoading ? null : sendMessage()" resize="none">
</el-input> </el-input>

Loading…
Cancel
Save