Files
oci-portal-dash/src/components/instance/InstanceTrafficPanel.vue
T

141 lines
4.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { LineChart } from 'echarts/charts'
import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { NSelect, NSpin } from 'naive-ui'
import { computed, ref, watch } from 'vue'
import VChart from 'vue-echarts'
import { getInstanceTraffic } from '@/api/analytics'
import EmptyCard from '@/components/EmptyCard.vue'
import FootNote from '@/components/FootNote.vue'
import { fmtBytes } from '@/composables/useFormat'
import { useAsync } from '@/composables/useAsync'
import { useAppStore } from '@/stores/app'
import { darkTokens, tokens } from '@/theme/tokens'
use([LineChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer])
/** echarts 不认 CSS 变量,色板按明暗主题从 tokens 取 */
const app = useAppStore()
const t = computed(() => (app.dark ? darkTokens : tokens))
const props = defineProps<{ cfgId: number; instanceId: string; region?: string }>()
const days = ref(7)
const traffic = useAsync(() =>
getInstanceTraffic(props.cfgId, props.instanceId, days.value, props.region),
)
watch(days, () => void traffic.run())
const daysOptions = [
{ label: '近 7 天', value: 7 },
{ label: '近 30 天', value: 30 },
]
const series = computed(() => {
const vnic = traffic.data.value?.vnics[0]
if (!vnic) return null
const labels = vnic.outbound.map((p) => p.timestamp.slice(5, 10))
return {
labels,
outbound: vnic.outbound.map((p) => +(p.bytes / 1024 ** 3).toFixed(2)),
inbound: vnic.inbound.map((p) => +(p.bytes / 1024 ** 3).toFixed(2)),
}
})
const option = computed(() => ({
grid: { left: 44, right: 16, top: 36, bottom: 26 },
legend: { top: 4, left: 8, textStyle: { color: t.value.ink2, fontSize: 12 }, itemWidth: 14 },
tooltip: {
trigger: 'axis',
backgroundColor: t.value.ink,
borderWidth: 0,
textStyle: { color: t.value.bg, fontSize: 12 },
valueFormatter: (v: number) => `${v} GB`,
},
xAxis: {
type: 'category',
data: series.value?.labels ?? [],
boundaryGap: false,
axisLine: { lineStyle: { color: t.value.line } },
axisTick: { show: false },
axisLabel: { color: t.value.ink3, fontSize: 10.5 },
},
yAxis: {
type: 'value',
splitLine: { lineStyle: { color: t.value.lineSoft } },
axisLabel: { color: t.value.ink3, fontSize: 10.5, formatter: '{value}G' },
},
series: [
{
name: '流出',
type: 'line',
data: series.value?.outbound ?? [],
lineStyle: { color: t.value.chart, width: 2 },
itemStyle: { color: t.value.chart },
symbol: 'circle',
symbolSize: 5,
},
{
name: '流入',
type: 'line',
data: series.value?.inbound ?? [],
lineStyle: { color: t.value.info, width: 2 },
itemStyle: { color: t.value.info },
symbol: 'circle',
symbolSize: 5,
},
],
}))
</script>
<template>
<div class="panel">
<div class="flex flex-wrap items-center gap-2.5 border-b border-line-soft px-4.5 py-3.5">
<div class="text-sm font-semibold">流量</div>
<div class="flex-1" />
<div class="w-28">
<NSelect
v-model:value="days"
size="small"
:options="daysOptions"
:loading="traffic.loading.value"
/>
</div>
</div>
<div
v-if="traffic.loading.value && !traffic.data.value"
class="flex items-center justify-center py-14"
>
<NSpin size="small" />
</div>
<template v-else-if="traffic.data.value">
<div class="flex flex-wrap gap-5 px-4.5 pt-3 text-[12.5px] text-ink-2">
<span>
<span class="mr-1.5 inline-block h-2 w-2 rounded-full" style="background: var(--color-chart)" />
流出 · 合计 {{ fmtBytes(traffic.data.value.outboundBytes) }}
</span>
<span>
<span class="mr-1.5 inline-block h-2 w-2 rounded-full" style="background: var(--color-info)" />
流入 · 合计 {{ fmtBytes(traffic.data.value.inboundBytes) }}
</span>
</div>
<div class="px-3 pb-2">
<VChart class="w-full" style="height: 210px" :option="option" autoresize />
</div>
</template>
<EmptyCard
v-else
title="暂无流量数据"
note="该实例暂无 Monitoring 数据点(新建实例有数分钟延迟,终止实例不再产生数据)"
/>
<FootNote>
数据来自 Monitoring 指标VnicToNetworkBytes 发送 / VnicFromNetworkBytes 接收),按日聚合
</FootNote>
</div>
</template>