Files
YG_FT/frontend/src/views/system/HardwareView.vue

284 lines
7.6 KiB
Vue
Raw Normal View History

<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>