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

253 lines
5.7 KiB
Vue

<script lang="ts" setup>
import VChart from 'vue-echarts';
import {useDataStore} from "~/strores/DataStore";
import _ from "lodash";
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
import type {PropType} from "vue";
import dayjs from "dayjs";
const mainLayoutStore = useMainLayoutStore()
const dataStore = useDataStore()
const isLoading = ref(false)
const chartRef = ref<any>(null);
const isSwitch= ref(false)
const props = defineProps({
valueIds: {
type: Array as PropType<string[]>,
required: true,
},
valueNames: {
type: Array as PropType<string[]>,
required: true,
},
colors: {
type: Array as PropType<string[]>,
required: true,
},
bgColor: {
type: String,
required: true,
},
configs: {
type: Array as PropType<Array<object>>,
default: () => {
return []
}
},
min: {
type: [Number, null],
default: () => {
return 0
}
},
max: {
type: [Number, null],
default: () => {
return 100
}
},
unit: {
type: String,
default: () => {
return ''
}
},
xAxis: {
type: Array as PropType<string[]>,
default: () => {
return []
}
},
yAxis: {
type: Array as PropType<string[]>,
default: () => {
return []
}
},
})
const option = computed(() => {
return {
backgroundColor:'',
grid: {
left: '0',
right: '0',
bottom: '0',
top: '30',
show: true,
},
dataZoom: [
{
type: 'inside',
start: 90,
end: 100,
throttle: 50, // 设置触发视图刷新的频率
minValueSpan: 10, // 设置最小值跨度,用于控制坐标轴标签的显示
},
],
legend: {
//嵌入式左上角
orient: 'vertical',
right: '30',
//向下30px
top: '50',
},
xAxis: {
type: 'category',
data: [],
position: 'top',
boundaryGap: false,
splitLine: {
show: true,
lineStyle: {
color: [props.bgColor],
width: 2,
type: 'solid'
}
}
},
yAxis: {
type: 'value',
splitNumber: 10,
min: props.min,
max: props.max,
splitLine: {
show: true,
lineStyle: {
color: [props.bgColor],
width: 2,
type: 'solid'
}
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
},
},
series: props.valueNames?.map((id, index) => {
return {
name: id,
type: 'line',
large: true,
smooth: true,
color: [props.colors[index] ?? props.colors[0]],
emphasis: {
focus: 'series'
},
...props.configs[index],
data: [],
}
}) ?? []
}
})
let interval: NodeJS.Timeout;
onUnmounted(() => {
clearInterval(interval);
})
onMounted(() => {
let history = dataStore.dataHistory;
nextTick(() => {
props.valueIds?.forEach((id, index) => {
chartRef.value.appendData({
seriesIndex: index,
data: history.data[id]
})
})
const currentOption = chartRef.value.getOption();
currentOption.xAxis[0].data = history.times
chartRef.value.setOption(currentOption)
isLoading.value = false
})
interval = setInterval(() => {
const data = dataStore.data
props.valueIds?.forEach((id, index) => {
const newData = data[id] ?? 0
chartRef.value.appendData({
seriesIndex: index,
data: [newData]
})
})
const currentOption = chartRef.value.getOption();
currentOption.xAxis[0].data.push(dayjs().format('MM-DD HH:mm:ss'))
chartRef.value.setOption(currentOption)
}, 1000)
})
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) => {
let start = e.start ?? e.batch[0].start
if (start <= 50 && start !== startTemp) {
if (done) return
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) => {
console.log(res)
const data = res as Data;
if (data.done) {
done = true
return
}
endIndex = data.endIndex
//获得图表data
const currentOption = chartRef.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
chartRef.value.setOption(currentOption)
setTimeout(() => {
isLoading.value = false
}, 1000)
})
}
}, 1000)
watch(()=>useColorMode().value,()=>{
isSwitch.value=true
nextTick(()=>{
isSwitch.value=false
})
})
</script>
<template>
<v-chart ref="chartRef" :loading="isLoading" :manual-update="true"
:option="option"
autoresize
v-if="!isSwitch"
:theme="$colorMode.value"
class="chart"
@datazoom="zoom"
/>
</template>
<style>
.chart {
will-change: contents, scroll-position;
}
</style>