LoongPanel-Asp/web/components/Charts/LineChart.vue

217 lines
5.1 KiB
Vue
Executable File

<script lang="ts" setup>
import {useDataStore} from "~/strores/DataStore";
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
import type {PropType} from "vue";
import {ref} from 'vue';
import dayjs from "dayjs";
import VChart from 'vue-echarts';
import _ from "lodash";
const dataStore = useDataStore()
const mainLayoutStore = useMainLayoutStore()
type ArbitraryKeyValuePairs = {
[key: string]: (number | string)[];
};
const values = ref<ArbitraryKeyValuePairs>({});
const chartRet = ref<any>(null)
const isLoading = ref<boolean>(true)
const props = defineProps({
valueIds: {
type: Array as PropType<string[]>,
required: true,
},
valueNames: {
type: Array as PropType<string[]>,
required: true,
},
rangeNum: {
type: Number,
default: 6,
},
})
const option = computed(() => {
return {
backgroundColor:'',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
grid: {
left: '2%',
right: '50',
bottom: '10%',
containLabel: true
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: []
}
],
yAxis: [
{
type: 'value',
}
],
dataZoom: [
{
type: 'inside',
start: 90,
end: 100,
},
{
type: 'slider',
throttle: 500,
},
{
type: 'slider',
yAxisIndex: 0,
startValue: 0,
endValue: 100,
},
],
legend: {
data: props.valueNames,
right:"5",
top:"1",
textStyle: {
fontSize: 16,
},
},
series: props.valueNames?.map((id) => {
return {
name: id,
type: 'line',
large: true,
smooth: true,
emphasis: {
focus: 'series'
},
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' }
]
},
markLine: {
data: [{ type: 'average', name: 'Avg' }]
},
data: [],
}
}) ?? []
}
});
let interval: NodeJS.Timeout;
onUnmounted(() => {
clearInterval(interval);
})
onMounted(() => {
let history = dataStore.dataHistory
setTimeout(() => {
isLoading.value = false;
}, 5000)
nextTick(() => {
props.valueIds?.forEach((id, index) => {
chartRet.value.appendData({
seriesIndex: index,
data: history.data[id]
})
})
const currentOption = chartRet.value.getOption();
currentOption.xAxis[0].data = history.times
chartRet.value.setOption(currentOption)
isLoading.value = false
interval = setInterval(() => {
const data = dataStore.data
props.valueIds?.forEach((id, index) => {
const newData = data[id] ?? 0
if (!values.value[id]) {
values.value[id] = []
}
chartRet.value.appendData({
seriesIndex: index,
data: [newData]
})
})
const currentOption = chartRet.value.getOption();
currentOption.xAxis[0].data.push(dayjs().format('MM-DD HH:mm:ss'))
chartRet.value.setOption(currentOption)
}, 4000 + 1000 * Math.random())
})
})
let endIndex = dataStore.dataHistory.times ? dataStore.dataHistory.times.length : 0
let startTemp = 0;
let done = false;
type Data = {
times: string[]; // 时间轴
data: { [key: string]: string[] }; // 数据,键是字符串,值是字符串数组的数组
endIndex: number; // 结束索引
done: boolean; // 是否完成加载
};
const zoom = _.throttle((e: any) => {
console.log(e)
let start = e.start ?? e.batch[0].start
if (done) return
if (start <= 50 && start !== startTemp) {
startTemp = e.start
isLoading.value = true
setTimeout(() => {
isLoading.value = false
}, 5000)
$fetch('/Api/Server/GetServerHistoryDate', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + useCookie('token').value
},
params: {
ServerId: mainLayoutStore.SelectServer.value,
DataTypes: props.valueIds,
StartIndex: endIndex,
},
baseURL: useRuntimeConfig().public.baseUrl,
}).then((res) => {
const data = res as Data;
if (data.done) {
isLoading.value = false
done = true
return
}
endIndex = data.endIndex
//获得图表data
const currentOption = chartRet.value.getOption();
currentOption.series.map((series: any, index: number) => {
series.data = [...data.data[props.valueIds[index]], ...series.data]
})
currentOption.xAxis[0].data = [...data.times, ...currentOption.xAxis[0].data]
//start 为5
currentOption.dataZoom[0].start = 55
chartRet.value.setOption(currentOption)
setTimeout(() => {
isLoading.value = false
}, 1000)
})
}
}, 1000)
</script>
<template>
<v-chart ref="chartRet" :loading="isLoading" :manual-update="true" :option="option"
autoresize
:theme="$colorMode.value"
class="chart"
@datazoom="zoom"/>
</template>
<style>
.chart {
will-change: contents, scroll-position;
}
</style>