253 lines
5.7 KiB
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>
|