Files
YG_FT/frontend/src/views/system/HardwareView.vue
caoxiaozhu 6f6609dae5 feat: 实现业务视图页面
登录、模型调优、评测、推理、对比、模型管理、数据集、数据处理、工具、系统(硬件/日志/训练日志)等全部业务页面视图。
2026-07-10 16:45:55 +08:00

284 lines
7.6 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 { 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>