mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
5.1 KiB
Vue
217 lines
5.1 KiB
Vue
<!--
|
|
* tschart.vue
|
|
* Copyright (C) 2023 veypi <i@veypi.com>
|
|
* 2023-10-20 22:50
|
|
* Distributed under terms of the MIT license.
|
|
-->
|
|
<template>
|
|
<div class="w-full h-full">
|
|
<div v-if="enable_mode" class="h-16 flex justify-start items-center">
|
|
<div :color="enable_sync ? 'primary' : ''" @click="enable_sync = !enable_sync">{{ enable_sync ? '关闭同步'
|
|
:
|
|
'开启同步' }}</div>
|
|
<div :color="mode === k ? 'primary' : ''" v-for="(v, k) in mode_label" :key="k" @click="change_mode(k)">{{
|
|
v }}</div>
|
|
</div>
|
|
<div class="v-chart w-full" :style="{
|
|
height:
|
|
enable_mode ? 'calc(100% - 4rem)' : '100%'
|
|
}" ref="chartdom"></div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import * as echart from 'echarts'
|
|
import use_params from './params'
|
|
import { onMounted, onUnmounted, computed, ref, watch, markRaw } from 'vue';
|
|
|
|
let { params, mode, change_mode, mode_label } = use_params()
|
|
interface Item {
|
|
name: string
|
|
query: string | string[]
|
|
valueFormatter?: (s: number) => string
|
|
label?: string | string[] | ((s: any) => string)
|
|
}
|
|
let props = withDefaults(defineProps<{
|
|
item: Item,
|
|
sync?: boolean,
|
|
enable_zoom?: boolean,
|
|
time_mode?: number,
|
|
enable_mode?: boolean,
|
|
}>(),
|
|
{
|
|
}
|
|
)
|
|
let count = 0
|
|
let timer = ref<any[]>([])
|
|
let enable_sync = ref(false)
|
|
let chartdom = ref()
|
|
let options = ref<{ [key: string]: any }>({})
|
|
let chart: echart.ECharts = {} as any
|
|
let tooltip = {
|
|
trigger: 'axis',
|
|
axisPointer: {
|
|
type: 'cross',
|
|
label: {},
|
|
},
|
|
valueFormatter: (value: number) => value.toFixed(2),
|
|
className: 'v-echarts-tooltip',
|
|
}
|
|
|
|
const init_chart = () => {
|
|
count++
|
|
if (chart.clear) {
|
|
chart.clear()
|
|
}
|
|
timer.value.forEach(e => {
|
|
clearInterval(e)
|
|
})
|
|
options.value = {
|
|
title: { text: props.item.name, x: 'center' },
|
|
animationThreshold: 200,
|
|
tooltip: Object.assign({}, tooltip),
|
|
axisPointer: {
|
|
link: { xAxisIndex: 'all' },
|
|
label: {
|
|
backgroundColor: '#777'
|
|
}
|
|
},
|
|
xAxis: {
|
|
type: 'time',
|
|
},
|
|
yAxis: {},
|
|
series: []
|
|
}
|
|
if (props.enable_zoom) {
|
|
options.value.dataZoom = [
|
|
{
|
|
type: 'slider',
|
|
xAxisIndex: [0],
|
|
filterMode: 'filter'
|
|
},
|
|
]
|
|
}
|
|
if (props.item.valueFormatter) {
|
|
options.value.tooltip.valueFormatter = props.item.valueFormatter
|
|
}
|
|
let tmp = {
|
|
start: params.value.start.toISOString(),
|
|
step: params.value.step,
|
|
}
|
|
let querys: string[] = Array.isArray(props.item.query) ? props.item.query :
|
|
[props.item.query]
|
|
let labels = Array.isArray(props.item.label) ? props.item.label :
|
|
[props.item.label]
|
|
for (let q = 0; q < querys.length; q++) {
|
|
let query = querys[q]
|
|
api.tsdb.range(query, tmp).then(e => {
|
|
if (e.status == 'success') {
|
|
let data = e.data.result as any[]
|
|
if (data.length == 0) {
|
|
console.warn('not get data')
|
|
return
|
|
}
|
|
let idx = options.value.series.length || 0
|
|
data.forEach(d => {
|
|
let name = props.item.name
|
|
let label = labels[q]
|
|
if (typeof label === 'string') {
|
|
name = label
|
|
} else if (typeof label === 'function') {
|
|
name = label(d.metric)
|
|
}
|
|
options.value.series.push({
|
|
name: name,
|
|
data: d.values.map((e: any) =>
|
|
[e[0] * 1000, Number(e[1])]),
|
|
metric: d.metric,
|
|
metric_str: JSON.stringify(d.metric),
|
|
origin: query,
|
|
symbol: 'none',
|
|
smooth: true,
|
|
type: 'line',
|
|
})
|
|
})
|
|
chart.setOption(options.value)
|
|
let t = setInterval(() => {
|
|
sync_chart(idx, query, count)
|
|
}, 1000)
|
|
timer.value.push(t)
|
|
}
|
|
})
|
|
}
|
|
// let query = props.query
|
|
}
|
|
const sync_chart = (idx: number, query: string, c: number) => {
|
|
if (!enable_sync.value) {
|
|
return
|
|
}
|
|
api.tsdb.query(query).then(e => {
|
|
if (e.status == 'success') {
|
|
let data = e.data.result as any[]
|
|
if (data.length == 0) {
|
|
console.warn('not get data')
|
|
timer.value.forEach(e => {
|
|
clearInterval(e)
|
|
})
|
|
return
|
|
}
|
|
if (count === c) {
|
|
data.forEach((d, i) => {
|
|
let sidx = idx + i
|
|
if (d.metric) {
|
|
let ti = options.value.series.findIndex((s: any) =>
|
|
query === s.origin && JSON.stringify(d.metric) === s.metric_str)
|
|
if (ti >= 0) {
|
|
sidx = ti
|
|
}
|
|
}
|
|
options.value.series[sidx].data.push([d.value[0] * 1000,
|
|
Number(d.value[1])])
|
|
})
|
|
chart.setOption(options.value)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
|
|
watch(computed(() => props.item), q => {
|
|
if (q) {
|
|
init_chart()
|
|
}
|
|
})
|
|
|
|
watch(mode, q => {
|
|
init_chart()
|
|
})
|
|
|
|
onMounted(() => {
|
|
enable_sync.value = props.sync
|
|
if (props.time_mode) {
|
|
change_mode(props.time_mode)
|
|
}
|
|
chart = markRaw(echart.init(chartdom.value, null, { renderer: 'svg' }))
|
|
init_chart()
|
|
})
|
|
onUnmounted(() => {
|
|
timer.value.forEach(e => {
|
|
clearInterval(e)
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
.v-chart {
|
|
min-width: 20rem;
|
|
min-height: 15rem;
|
|
}
|
|
|
|
.v-echarts-tooltip {
|
|
/* height: 5rem; */
|
|
/* width: 10rem; */
|
|
}
|
|
</style>
|
|
|