123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- <script setup lang="ts">
- import AreaChart from '@/components/Chart/AreaChart.vue'
- import RadialBarChart from '@/components/Chart/RadialBarChart.vue'
- import {useGettext} from 'vue3-gettext'
- import {onMounted, onUnmounted, reactive, ref} from 'vue'
- import analytic from '@/api/analytic'
- import ws from '@/lib/websocket'
- import {bytesToSize} from '@/lib/helper'
- import ReconnectingWebSocket from 'reconnecting-websocket'
- const {$gettext} = useGettext()
- let websocket: ReconnectingWebSocket | WebSocket
- const host = reactive({})
- const cpu = ref('0.0')
- const cpu_info = reactive([])
- const cpu_analytic_series = reactive([{name: 'User', data: <any>[]}, {name: 'Total', data: <any>[]}])
- const net_analytic = reactive([{name: $gettext('Receive'), data: <any>[]},
- {name: $gettext('Send'), data: <any>[]}])
- const disk_io_analytic = reactive([{name: $gettext('Writes'), data: <any>[]},
- {name: $gettext('Reads'), data: <any>[]}])
- const memory = reactive({})
- const disk = reactive({})
- const disk_io = reactive({writes: 0, reads: 0})
- const uptime = ref('')
- const loadavg = reactive({})
- const net = reactive({recv: 0, sent: 0, last_recv: 0, last_sent: 0})
- const net_formatter = (bytes: number) => {
- return bytesToSize(bytes) + '/s'
- }
- interface Usage {
- x: number
- y: number
- }
- onMounted(() => {
- analytic.init().then(r => {
- Object.assign(host, r.host)
- Object.assign(cpu_info, r.cpu.info)
- Object.assign(memory, r.memory)
- Object.assign(disk, r.disk)
- // uptime
- handle_uptime(r.host?.uptime)
- // load_avg
- Object.assign(loadavg, r.loadavg)
- net.last_recv = r.network.init.bytesRecv
- net.last_sent = r.network.init.bytesSent
- r.cpu.user.forEach((u: Usage) => {
- cpu_analytic_series[0].data.push([u.x, u.y.toFixed(2)])
- })
- r.cpu.total.forEach((u: Usage) => {
- cpu_analytic_series[1].data.push([u.x, u.y.toFixed(2)])
- })
- r.network.bytesRecv.forEach((u: Usage) => {
- net_analytic[0].data.push([u.x, u.y.toFixed(2)])
- })
- r.network.bytesSent.forEach((u: Usage) => {
- net_analytic[1].data.push([u.x, u.y.toFixed(2)])
- })
- disk_io_analytic[0].data = disk_io_analytic[0].data.concat(r.disk_io.writes)
- disk_io_analytic[1].data = disk_io_analytic[1].data.concat(r.disk_io.reads)
- websocket = ws('/api/analytic')
- websocket.onmessage = wsOnMessage
- })
- })
- onUnmounted(() => {
- websocket.close()
- })
- function handle_uptime(t: number) {
- // uptime
- let _uptime = Math.floor(t)
- let uptime_days = Math.floor(_uptime / 86400)
- _uptime -= uptime_days * 86400
- let uptime_hours = Math.floor(_uptime / 3600)
- _uptime -= uptime_hours * 3600
- uptime.value = uptime_days + 'd ' + uptime_hours + 'h ' + Math.floor(_uptime / 60) + 'm'
- }
- function wsOnMessage(m: { data: any }) {
- const r = JSON.parse(m.data)
- const cpu_usage = r.cpu.system + r.cpu.user
- cpu.value = cpu_usage.toFixed(2)
- const time = new Date().getTime()
- cpu_analytic_series[0].data.push([time, r.cpu.user.toFixed(2)])
- cpu_analytic_series[1].data.push([time, cpu.value])
- if (cpu_analytic_series[0].data.length > 100) {
- cpu_analytic_series[0].data.shift()
- cpu_analytic_series[1].data.shift()
- }
- // mem
- Object.assign(memory, r.memory)
- // disk
- Object.assign(disk, r.disk)
- disk_io.writes = r.disk.writes.y
- disk_io.reads = r.disk.reads.y
- // uptime
- handle_uptime(r.uptime)
- // loadavg
- Object.assign(loadavg, r.loadavg)
- // network
- Object.assign(net, r.network)
- net.recv = r.network.bytesRecv - net.last_recv
- net.sent = r.network.bytesSent - net.last_sent
- net.last_recv = r.network.bytesRecv
- net.last_sent = r.network.bytesSent
- net_analytic[0].data.push([time, net.recv])
- net_analytic[1].data.push([time, net.sent])
- if (net_analytic[0].data.length > 100) {
- net_analytic[0].data.shift()
- net_analytic[1].data.shift()
- }
- disk_io_analytic[0].data.push(r.disk.writes)
- disk_io_analytic[1].data.push(r.disk.reads)
- if (disk_io_analytic[0].data.length > 100) {
- disk_io_analytic[0].data.shift()
- disk_io_analytic[1].data.shift()
- }
- }
- </script>
- <template>
- <div>
- <a-row :gutter="[{xs: 0, sm: 16}, 16]" class="first-row">
- <a-col :xl="7" :lg="24" :md="24" :xs="24">
- <a-card :title="$gettext('Server Info')" :bordered="false">
- <p>
- <translate>Uptime:</translate>
- {{ uptime }}
- </p>
- <p>
- <translate>Load Averages:</translate>
- <span class="load-avg-describe"> 1min:</span>{{ ' ' + loadavg?.load1?.toFixed(2) }}
- <span class="load-avg-describe"> | 5min:</span>{{ loadavg?.load5?.toFixed(2) }}
- <span class="load-avg-describe"> | 15min:</span>{{ loadavg?.load15?.toFixed(2) }}
- </p>
- <p>
- <translate>OS:</translate>
- <span class="os-platform">{{ ' ' + host.platform }}</span> {{ host.platformVersion }}
- <span class="os-info">({{ host.os }} {{ host.kernelVersion }}
- {{ host.kernelArch }})</span>
- </p>
- <p v-if="cpu_info">
- {{ $gettext('CPU:') + ' ' }}
- <span class="cpu-model">{{ cpu_info[0]?.modelName || 'core' }}</span>
- <span class="cpu-mhz">{{ (cpu_info[0]?.mhz / 1000).toFixed(2) + 'GHz' }}</span>
- * {{ cpu_info.length }}
- </p>
- </a-card>
- </a-col>
- <a-col :xl="10" :lg="16" :md="24" :xs="24" class="chart_dashboard">
- <a-card :title="$gettext('Memory and Storage')" :bordered="false">
- <a-row :gutter="[0,16]">
- <a-col :xs="24" :sm="24" :md="8">
- <radial-bar-chart :name="$gettext('Memory')" :series="[memory.pressure]"
- :centerText="memory.used" :bottom-text="memory.total" colors="#36a3eb"/>
- </a-col>
- <a-col :xs="24" :sm="12" :md="8">
- <radial-bar-chart :name="$gettext('Swap')" :series="[memory.swap_percent]"
- :centerText="memory.swap_used"
- :bottom-text="memory.swap_total" colors="#ff6385"/>
- </a-col>
- <a-col :xs="24" :sm="12" :md="8">
- <radial-bar-chart :name="$gettext('Storage')" :series="[disk.percentage]"
- :centerText="disk.used" :bottom-text="disk.total" colors="#87d068"/>
- </a-col>
- </a-row>
- </a-card>
- </a-col>
- <a-col :xl="7" :lg="8" :sm="24" :xs="24" class="chart_dashboard network-total">
- <a-card :title="$gettext('Network Statistics')" :bordered="false">
- <a-row :gutter="16">
- <a-col :span="12">
- <a-statistic :value="bytesToSize(net.last_recv)"
- :title="$gettext('Network Total Receive')"/>
- </a-col>
- <a-col :span="12">
- <a-statistic :value="bytesToSize(net.last_sent)"
- :title="$gettext('Network Total Send')"/>
- </a-col>
- </a-row>
- </a-card>
- </a-col>
- </a-row>
- <a-row :gutter="[{xs: 0, sm: 16}, 16]" class="row-two">
- <a-col :xl="8" :lg="24" :md="24" :sm="24" :xs="24">
- <a-card :title="$gettext('CPU Status')" :bordered="false">
- <a-statistic :value="cpu" title="CPU">
- <template v-slot:suffix>
- <span>%</span>
- </template>
- </a-statistic>
- <area-chart :series="cpu_analytic_series" :max="100"/>
- </a-card>
- </a-col>
- <a-col :xl="8" :lg="12" :md="24" :sm="24" :xs="24">
- <a-card :title="$gettext('Network')" :bordered="false">
- <a-row :gutter="16">
- <a-col :span="12">
- <a-statistic :value="bytesToSize(net.recv)"
- :title="$gettext('Receive')">
- <template v-slot:suffix>
- <span>/s</span>
- </template>
- </a-statistic>
- </a-col>
- <a-col :span="12">
- <a-statistic :value="bytesToSize(net.sent)" :title="$gettext('Send')">
- <template v-slot:suffix>
- <span>/s</span>
- </template>
- </a-statistic>
- </a-col>
- </a-row>
- <area-chart :series="net_analytic" :y_formatter="net_formatter"/>
- </a-card>
- </a-col>
- <a-col :xl="8" :lg="12" :md="24" :sm="24" :xs="24">
- <a-card :title="$gettext('Disk IO')" :bordered="false">
- <a-row :gutter="16">
- <a-col :span="12">
- <a-statistic :value="disk_io.writes"
- :title="$gettext('Writes')">
- <template v-slot:suffix>
- <span>/s</span>
- </template>
- </a-statistic>
- </a-col>
- <a-col :span="12">
- <a-statistic :value="disk_io.reads" :title="$gettext('Reads')">
- <template v-slot:suffix>
- <span>/s</span>
- </template>
- </a-statistic>
- </a-col>
- </a-row>
- <area-chart :series="disk_io_analytic"/>
- </a-card>
- </a-col>
- </a-row>
- </div>
- </template>
- <style lang="less" scoped>
- .first-row {
- .ant-card {
- min-height: 227px;
- p {
- margin-bottom: 8px;
- }
- }
- margin-bottom: 20px;
- }
- .ant-card {
- .ant-statistic {
- margin: 0 0 10px 10px
- }
- .chart {
- max-width: 800px;
- max-height: 350px;
- }
- .chart_dashboard {
- padding: 60px;
- .description {
- width: 120px;
- text-align: center
- }
- }
- @media (max-width: 512px) {
- margin: 10px 0;
- .chart_dashboard {
- padding: 20px;
- }
- }
- }
- .load-avg-describe {
- @media (max-width: 1600px) and (min-width: 1200px) {
- display: none;
- }
- }
- .os-info {
- @media (max-width: 1600px) and (min-width: 1200px) {
- display: none;
- }
- }
- .cpu-model {
- @media (max-width: 1790px) and (min-width: 1200px) {
- display: none;
- }
- }
- .cpu-mhz {
- @media (min-width: 1790px) or (max-width: 1200px) {
- display: none;
- }
- }
- </style>
|