284 lines
7.6 KiB
Vue
284 lines
7.6 KiB
Vue
|
|
<script setup lang="ts">
|
|||
|
|
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
|||
|
|
import PageCard from '@/components/PageCard.vue'
|
|||
|
|
import { getSystemInfo } from '@/api/modules/system'
|
|||
|
|
import type { SystemInfo } from '@/types'
|
|||
|
|
|
|||
|
|
const refreshInterval = ref(5000)
|
|||
|
|
let timer: ReturnType<typeof setInterval> | null = null
|
|||
|
|
|
|||
|
|
const info = ref<SystemInfo>({})
|
|||
|
|
|
|||
|
|
async function fetchInfo() {
|
|||
|
|
try {
|
|||
|
|
info.value = await getSystemInfo()
|
|||
|
|
} catch {
|
|||
|
|
// ignore
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function startTimer() {
|
|||
|
|
stopTimer()
|
|||
|
|
timer = setInterval(fetchInfo, refreshInterval.value)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function stopTimer() {
|
|||
|
|
if (timer) {
|
|||
|
|
clearInterval(timer)
|
|||
|
|
timer = null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function changeInterval(val: number) {
|
|||
|
|
refreshInterval.value = val
|
|||
|
|
startTimer()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 温度颜色 */
|
|||
|
|
function tempColor(t?: number) {
|
|||
|
|
if (t == null) return ''
|
|||
|
|
if (t >= 80) return '#f56c6c'
|
|||
|
|
if (t >= 70) return '#e6a23c'
|
|||
|
|
return '#303133'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
fetchInfo()
|
|||
|
|
startTimer()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
onUnmounted(stopTimer)
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<template>
|
|||
|
|
<PageCard title="平台性能">
|
|||
|
|
<template #extra>
|
|||
|
|
<span style="font-size: 13px; color: #909399">刷新频率:</span>
|
|||
|
|
<el-select v-model="refreshInterval" size="small" style="width: 90px" @change="changeInterval">
|
|||
|
|
<el-option :value="1000" label="1秒" />
|
|||
|
|
<el-option :value="3000" label="3秒" />
|
|||
|
|
<el-option :value="5000" label="5秒" />
|
|||
|
|
</el-select>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<!-- CPU / 内存 / 磁盘 -->
|
|||
|
|
<el-row :gutter="16" style="margin-bottom: 16px">
|
|||
|
|
<!-- CPU -->
|
|||
|
|
<el-col :span="8">
|
|||
|
|
<el-card shadow="never">
|
|||
|
|
<div class="metric-header">
|
|||
|
|
<div>
|
|||
|
|
<i class="fa fa-microchip metric-icon cpu-icon" />
|
|||
|
|
<div class="metric-info">
|
|||
|
|
<div class="metric-title">CPU 使用率</div>
|
|||
|
|
<div class="metric-sub">{{ info.cpu?.cores || 0 }} 核心</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="metric-value">{{ info.cpu?.percent || 0 }}%</div>
|
|||
|
|
</div>
|
|||
|
|
<el-progress :percentage="info.cpu?.percent || 0" :stroke-width="10" :show-text="false" color="#1890ff" />
|
|||
|
|
</el-card>
|
|||
|
|
</el-col>
|
|||
|
|
|
|||
|
|
<!-- 内存 -->
|
|||
|
|
<el-col :span="8">
|
|||
|
|
<el-card shadow="never">
|
|||
|
|
<div class="metric-header">
|
|||
|
|
<div>
|
|||
|
|
<i class="fa fa-database metric-icon mem-icon" />
|
|||
|
|
<div class="metric-info">
|
|||
|
|
<div class="metric-title">内存使用</div>
|
|||
|
|
<div class="metric-sub">总计: {{ info.memory?.total_gb || 0 }} GB</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="metric-value">{{ info.memory?.percent || 0 }}%</div>
|
|||
|
|
</div>
|
|||
|
|
<el-progress :percentage="info.memory?.percent || 0" :stroke-width="10" :show-text="false" color="#e6a23c" />
|
|||
|
|
<div class="metric-detail">
|
|||
|
|
<span>已用 {{ info.memory?.used_gb || 0 }} GB</span>
|
|||
|
|
<span>可用 {{ info.memory?.available_gb || 0 }} GB</span>
|
|||
|
|
<span>缓存 {{ info.memory?.cached_gb || 0 }} GB</span>
|
|||
|
|
</div>
|
|||
|
|
</el-card>
|
|||
|
|
</el-col>
|
|||
|
|
|
|||
|
|
<!-- 磁盘 -->
|
|||
|
|
<el-col :span="8">
|
|||
|
|
<el-card shadow="never">
|
|||
|
|
<div class="metric-header">
|
|||
|
|
<div>
|
|||
|
|
<i class="fa fa-hdd-o metric-icon disk-icon" />
|
|||
|
|
<div class="metric-info">
|
|||
|
|
<div class="metric-title">磁盘使用</div>
|
|||
|
|
<div class="metric-sub">总计: {{ info.disk?.total_gb || 0 }} GB</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="metric-value">{{ info.disk?.percent || 0 }}%</div>
|
|||
|
|
</div>
|
|||
|
|
<el-progress :percentage="info.disk?.percent || 0" :stroke-width="10" :show-text="false" color="#67c23a" />
|
|||
|
|
<div class="metric-detail">
|
|||
|
|
<span>已用 {{ info.disk?.used_gb || 0 }} GB</span>
|
|||
|
|
<span>可用 {{ (info.disk?.total_gb || 0) - (info.disk?.used_gb || 0) }} GB</span>
|
|||
|
|
</div>
|
|||
|
|
</el-card>
|
|||
|
|
</el-col>
|
|||
|
|
</el-row>
|
|||
|
|
|
|||
|
|
<!-- GPU -->
|
|||
|
|
<el-card shadow="never" style="margin-bottom: 16px">
|
|||
|
|
<template #header>
|
|||
|
|
<div class="section-header">
|
|||
|
|
<i class="fa fa-microchip" style="color: #f56c6c" />
|
|||
|
|
<span>GPU 监控({{ info.gpu?.length || 0 }} 块)</span>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
<el-row :gutter="12">
|
|||
|
|
<el-col v-for="(gpu, idx) in info.gpu" :key="idx" :span="6">
|
|||
|
|
<el-card shadow="never" class="gpu-card">
|
|||
|
|
<div class="gpu-name">{{ gpu.name }}</div>
|
|||
|
|
<div class="gpu-usage">{{ gpu.gpu_percent }}%</div>
|
|||
|
|
<el-progress :percentage="gpu.gpu_percent" :stroke-width="8" :show-text="false" />
|
|||
|
|
<div class="gpu-meta">
|
|||
|
|
<div>显存: {{ gpu.memory_used_gb }}/{{ gpu.memory_total_gb }} GB</div>
|
|||
|
|
<div>温度: <span :style="{ color: tempColor(gpu.temperature) }">{{ gpu.temperature }}°C</span></div>
|
|||
|
|
<div>功耗: {{ gpu.power_w }} W</div>
|
|||
|
|
<div>风扇: {{ gpu.fan_speed || 0 }}%</div>
|
|||
|
|
</div>
|
|||
|
|
</el-card>
|
|||
|
|
</el-col>
|
|||
|
|
</el-row>
|
|||
|
|
</el-card>
|
|||
|
|
|
|||
|
|
<!-- 系统信息 -->
|
|||
|
|
<el-row :gutter="16">
|
|||
|
|
<el-col :span="12">
|
|||
|
|
<el-card shadow="never">
|
|||
|
|
<template #header>
|
|||
|
|
<div class="section-header">
|
|||
|
|
<i class="fa fa-globe" style="color: #909399" />
|
|||
|
|
<span>网络流量</span>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
<div class="metric-detail">
|
|||
|
|
<span>总流入: {{ info.network?.download_mb || 0 }} GB</span>
|
|||
|
|
<span>总流出: {{ info.network?.upload_mb || 0 }} GB</span>
|
|||
|
|
</div>
|
|||
|
|
</el-card>
|
|||
|
|
</el-col>
|
|||
|
|
<el-col :span="12">
|
|||
|
|
<el-card shadow="never">
|
|||
|
|
<template #header>
|
|||
|
|
<div class="section-header">
|
|||
|
|
<i class="fa fa-info-circle" style="color: #909399" />
|
|||
|
|
<span>系统信息</span>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
<div class="sys-info">
|
|||
|
|
<div class="sys-row"><span>操作系统</span><span>{{ info.system?.os || '-' }}</span></div>
|
|||
|
|
<div class="sys-row"><span>进程数</span><span>{{ info.system?.process_count || 0 }}</span></div>
|
|||
|
|
</div>
|
|||
|
|
</el-card>
|
|||
|
|
</el-col>
|
|||
|
|
</el-row>
|
|||
|
|
</PageCard>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<style scoped lang="scss">
|
|||
|
|
.metric-header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
|
|||
|
|
> div:first-child {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 10px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.metric-icon {
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
.cpu-icon {
|
|||
|
|
color: #1890ff;
|
|||
|
|
}
|
|||
|
|
.mem-icon {
|
|||
|
|
color: #e6a23c;
|
|||
|
|
}
|
|||
|
|
.disk-icon {
|
|||
|
|
color: #67c23a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.metric-title {
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #303133;
|
|||
|
|
}
|
|||
|
|
.metric-sub {
|
|||
|
|
font-size: 12px;
|
|||
|
|
color: #909399;
|
|||
|
|
}
|
|||
|
|
.metric-value {
|
|||
|
|
font-size: 24px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #303133;
|
|||
|
|
}
|
|||
|
|
.metric-detail {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
margin-top: 12px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: #606266;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 8px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #303133;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gpu-card {
|
|||
|
|
.gpu-name {
|
|||
|
|
font-size: 13px;
|
|||
|
|
font-weight: 500;
|
|||
|
|
margin-bottom: 4px;
|
|||
|
|
overflow: hidden;
|
|||
|
|
text-overflow: ellipsis;
|
|||
|
|
white-space: nowrap;
|
|||
|
|
}
|
|||
|
|
.gpu-usage {
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #f56c6c;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
.gpu-meta {
|
|||
|
|
margin-top: 8px;
|
|||
|
|
font-size: 11px;
|
|||
|
|
color: #909399;
|
|||
|
|
line-height: 1.8;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sys-info {
|
|||
|
|
.sys-row {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 8px 0;
|
|||
|
|
border-bottom: 1px solid #ebeef5;
|
|||
|
|
font-size: 13px;
|
|||
|
|
|
|||
|
|
&:last-child {
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
span:first-child {
|
|||
|
|
color: #909399;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|