refactor: remove unused monitoring and system info features
This commit is contained in:
@@ -9,8 +9,6 @@ Frontend application for Super-frpc - a frpc instance integrated management syst
|
|||||||
- User management (create, edit, delete users)
|
- User management (create, edit, delete users)
|
||||||
- Session management (view and delete active sessions)
|
- Session management (view and delete active sessions)
|
||||||
- System logs viewing with filtering capabilities
|
- System logs viewing with filtering capabilities
|
||||||
- Real-time system monitoring (CPU, memory, disk, network)
|
|
||||||
- System information display
|
|
||||||
- Role-based access control (superuser, admin, visitor)
|
- Role-based access control (superuser, admin, visitor)
|
||||||
- Responsive design with modern UI
|
- Responsive design with modern UI
|
||||||
|
|
||||||
@@ -49,8 +47,7 @@ frontend/
|
|||||||
│ ├── Users.vue # User management
|
│ ├── Users.vue # User management
|
||||||
│ ├── Sessions.vue # Session management
|
│ ├── Sessions.vue # Session management
|
||||||
│ ├── Logs.vue # System logs
|
│ ├── Logs.vue # System logs
|
||||||
│ ├── Monitor.vue # System monitoring
|
│ └── Settings.vue # Settings
|
||||||
│ └── SystemInfo.vue # System information
|
|
||||||
├── logger.js # Logging utility
|
├── logger.js # Logging utility
|
||||||
├── api-backend.md # Backend API documentation
|
├── api-backend.md # Backend API documentation
|
||||||
└── README.md # This file
|
└── README.md # This file
|
||||||
|
|||||||
@@ -112,13 +112,4 @@ export const logApi = {
|
|||||||
getLogs: (level) => api.post('/logMgr/list', { level })
|
getLogs: (level) => api.post('/logMgr/list', { level })
|
||||||
};
|
};
|
||||||
|
|
||||||
export const monitorApi = {
|
|
||||||
getSystemStats: () => api.get('/monitor/stats')
|
|
||||||
};
|
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|
||||||
export const TODO_API_NOTES = {
|
|
||||||
monitorStats: 'TODO: /monitor/stats - 获取系统监控数据 API 未在 api-backend.md 中定义',
|
|
||||||
systemInfo: 'TODO: /system/info - 获取系统信息 API 未在 api-backend.md 中定义'
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ export default {
|
|||||||
{ path: '/users', title: 'User Management', icon: 'fas fa-users', permission: ['superuser'] },
|
{ path: '/users', title: 'User Management', icon: 'fas fa-users', permission: ['superuser'] },
|
||||||
{ path: '/sessions', title: 'Session Management', icon: 'fas fa-key', permission: ['superuser', 'admin'] },
|
{ path: '/sessions', title: 'Session Management', icon: 'fas fa-key', permission: ['superuser', 'admin'] },
|
||||||
{ path: '/logs', title: 'System Logs', icon: 'fas fa-file-alt', permission: ['superuser', 'admin'] },
|
{ path: '/logs', title: 'System Logs', icon: 'fas fa-file-alt', permission: ['superuser', 'admin'] },
|
||||||
{ path: '/monitor', title: 'System Monitoring', icon: 'fas fa-chart-bar', permission: ['superuser', 'admin', 'visitor'] },
|
|
||||||
{ path: '/system-info', title: 'System Information', icon: 'fas fa-info-circle', permission: ['superuser', 'admin', 'visitor'] },
|
|
||||||
{ path: '/settings', title: 'Settings', icon: 'fas fa-cog', permission: ['superuser', 'admin'] }
|
{ path: '/settings', title: 'Settings', icon: 'fas fa-cog', permission: ['superuser', 'admin'] }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -43,18 +43,6 @@ const routes = [
|
|||||||
component: () => import('../views/Logs.vue'),
|
component: () => import('../views/Logs.vue'),
|
||||||
meta: { requiresAuth: true, permission: ['superuser', 'admin'] }
|
meta: { requiresAuth: true, permission: ['superuser', 'admin'] }
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'monitor',
|
|
||||||
name: 'Monitor',
|
|
||||||
component: () => import('../views/Monitor.vue'),
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'system-info',
|
|
||||||
name: 'SystemInfo',
|
|
||||||
component: () => import('../views/SystemInfo.vue'),
|
|
||||||
meta: { requiresAuth: true }
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
name: 'Settings',
|
name: 'Settings',
|
||||||
|
|||||||
@@ -1,317 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="monitor-page">
|
|
||||||
<div class="page-header">
|
|
||||||
<h2>System Monitoring</h2>
|
|
||||||
</div>
|
|
||||||
<div class="monitor-grid">
|
|
||||||
<div class="monitor-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>CPU Usage</h3>
|
|
||||||
<span class="card-value">{{ cpuUsage }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="chart-container">
|
|
||||||
<canvas ref="cpuChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="monitor-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>Memory Usage</h3>
|
|
||||||
<span class="card-value">{{ memoryUsage }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="chart-container">
|
|
||||||
<canvas ref="memoryChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="monitor-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>Disk Usage</h3>
|
|
||||||
<span class="card-value">{{ diskUsage }}%</span>
|
|
||||||
</div>
|
|
||||||
<div class="chart-container">
|
|
||||||
<canvas ref="diskChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="monitor-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>Network Traffic</h3>
|
|
||||||
</div>
|
|
||||||
<div class="network-stats">
|
|
||||||
<div class="network-item">
|
|
||||||
<span class="network-label">Upload:</span>
|
|
||||||
<span class="network-value">{{ formatBytes(networkUpload) }}/s</span>
|
|
||||||
</div>
|
|
||||||
<div class="network-item">
|
|
||||||
<span class="network-label">Download:</span>
|
|
||||||
<span class="network-value">{{ formatBytes(networkDownload) }}/s</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart-container">
|
|
||||||
<canvas ref="networkChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
|
||||||
import { Chart, registerables } from 'chart.js';
|
|
||||||
import { monitorApi } from '../api/index.js';
|
|
||||||
import { showNotification, formatBytes } from '../utils/functions.js';
|
|
||||||
|
|
||||||
Chart.register(...registerables);
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Monitor',
|
|
||||||
setup() {
|
|
||||||
const cpuUsage = ref(0);
|
|
||||||
const memoryUsage = ref(0);
|
|
||||||
const diskUsage = ref(0);
|
|
||||||
const networkUpload = ref(0);
|
|
||||||
const networkDownload = ref(0);
|
|
||||||
|
|
||||||
const cpuChart = ref(null);
|
|
||||||
const memoryChart = ref(null);
|
|
||||||
const diskChart = ref(null);
|
|
||||||
const networkChart = ref(null);
|
|
||||||
|
|
||||||
let cpuChartInstance = null;
|
|
||||||
let memoryChartInstance = null;
|
|
||||||
let diskChartInstance = null;
|
|
||||||
let networkChartInstance = null;
|
|
||||||
let updateInterval = null;
|
|
||||||
|
|
||||||
const createChart = (canvas, data, label, color) => {
|
|
||||||
return new Chart(canvas, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: Array(20).fill(''),
|
|
||||||
datasets: [{
|
|
||||||
label: label,
|
|
||||||
data: data,
|
|
||||||
borderColor: color,
|
|
||||||
backgroundColor: color + '20',
|
|
||||||
fill: true,
|
|
||||||
tension: 0.4,
|
|
||||||
pointRadius: 0,
|
|
||||||
borderWidth: 2
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true,
|
|
||||||
max: 100,
|
|
||||||
ticks: {
|
|
||||||
callback: (value) => value + '%'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
x: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
animation: {
|
|
||||||
duration: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const createNetworkChart = (canvas, uploadData, downloadData) => {
|
|
||||||
return new Chart(canvas, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: Array(20).fill(''),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: '上传',
|
|
||||||
data: uploadData,
|
|
||||||
borderColor: '#52c41a',
|
|
||||||
backgroundColor: '#52c41a20',
|
|
||||||
fill: true,
|
|
||||||
tension: 0.4,
|
|
||||||
pointRadius: 0,
|
|
||||||
borderWidth: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '下载',
|
|
||||||
data: downloadData,
|
|
||||||
borderColor: '#1890ff',
|
|
||||||
backgroundColor: '#1890ff20',
|
|
||||||
fill: true,
|
|
||||||
tension: 0.4,
|
|
||||||
pointRadius: 0,
|
|
||||||
borderWidth: 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
display: true,
|
|
||||||
position: 'top'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true,
|
|
||||||
ticks: {
|
|
||||||
callback: (value) => formatBytes(value) + '/s'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
x: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
animation: {
|
|
||||||
duration: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateStats = async () => {
|
|
||||||
try {
|
|
||||||
const result = await monitorApi.getSystemStats();
|
|
||||||
const stats = result.data;
|
|
||||||
|
|
||||||
cpuUsage.value = stats.cpuUsage || 0;
|
|
||||||
memoryUsage.value = stats.memoryUsage || 0;
|
|
||||||
diskUsage.value = stats.diskUsage || 0;
|
|
||||||
networkUpload.value = stats.networkUpload || 0;
|
|
||||||
networkDownload.value = stats.networkDownload || 0;
|
|
||||||
|
|
||||||
if (cpuChartInstance) {
|
|
||||||
cpuChartInstance.data.datasets[0].data.push(cpuUsage.value);
|
|
||||||
cpuChartInstance.data.datasets[0].data.shift();
|
|
||||||
cpuChartInstance.update('none');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (memoryChartInstance) {
|
|
||||||
memoryChartInstance.data.datasets[0].data.push(memoryUsage.value);
|
|
||||||
memoryChartInstance.data.datasets[0].data.shift();
|
|
||||||
memoryChartInstance.update('none');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diskChartInstance) {
|
|
||||||
diskChartInstance.data.datasets[0].data.push(diskUsage.value);
|
|
||||||
diskChartInstance.data.datasets[0].data.shift();
|
|
||||||
diskChartInstance.update('none');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (networkChartInstance) {
|
|
||||||
networkChartInstance.data.datasets[0].data.push(networkUpload.value);
|
|
||||||
networkChartInstance.data.datasets[0].data.shift();
|
|
||||||
networkChartInstance.data.datasets[1].data.push(networkDownload.value);
|
|
||||||
networkChartInstance.data.datasets[1].data.shift();
|
|
||||||
networkChartInstance.update('none');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to update stats:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const initialData = Array(20).fill(0);
|
|
||||||
|
|
||||||
cpuChartInstance = createChart(cpuChart.value, [...initialData], 'CPU', '#ff4d4f');
|
|
||||||
memoryChartInstance = createChart(memoryChart.value, [...initialData], '内存', '#1890ff');
|
|
||||||
diskChartInstance = createChart(diskChart.value, [...initialData], '磁盘', '#faad14');
|
|
||||||
networkChartInstance = createNetworkChart(networkChart.value, [...initialData], [...initialData]);
|
|
||||||
|
|
||||||
updateStats();
|
|
||||||
updateInterval = setInterval(updateStats, 2000);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (updateInterval) {
|
|
||||||
clearInterval(updateInterval);
|
|
||||||
}
|
|
||||||
if (cpuChartInstance) cpuChartInstance.destroy();
|
|
||||||
if (memoryChartInstance) memoryChartInstance.destroy();
|
|
||||||
if (diskChartInstance) diskChartInstance.destroy();
|
|
||||||
if (networkChartInstance) networkChartInstance.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
cpuUsage,
|
|
||||||
memoryUsage,
|
|
||||||
diskUsage,
|
|
||||||
networkUpload,
|
|
||||||
networkDownload,
|
|
||||||
cpuChart,
|
|
||||||
memoryChart,
|
|
||||||
diskChart,
|
|
||||||
networkChart,
|
|
||||||
formatBytes
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
@import '../styles/common.css';
|
|
||||||
|
|
||||||
.monitor-page {
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monitor-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monitor-card {
|
|
||||||
transition: background-color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-value {
|
|
||||||
font-family: 'SF Pro Display', 'SF Pro Icons', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.14;
|
|
||||||
letter-spacing: 0.196px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-container {
|
|
||||||
height: 200px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-stats {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-family: 'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.29;
|
|
||||||
letter-spacing: -0.224px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-label {
|
|
||||||
color: var(--text-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-value {
|
|
||||||
color: var(--text-color);
|
|
||||||
font-weight: 500;
|
|
||||||
transition: color 0.3s;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="system-info-page">
|
|
||||||
<div class="page-header">
|
|
||||||
<h2>System Information</h2>
|
|
||||||
</div>
|
|
||||||
<div class="info-grid">
|
|
||||||
<div class="info-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-icon"><i class="fas fa-laptop" aria-hidden="true"></i></span>
|
|
||||||
<h3>Operating System</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Operating System:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.os || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Hostname:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.hostname || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Kernel Version:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.kernel || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-icon"><i class="fas fa-tools" aria-hidden="true"></i></span>
|
|
||||||
<h3>Processor</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Processor Model:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.cpuModel || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">CPU Cores:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.cpuCores || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">CPU Frequency:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.cpuFrequency || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-icon"><i class="fas fa-memory" aria-hidden="true"></i></span>
|
|
||||||
<h3>Memory</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Total Memory:</span>
|
|
||||||
<span class="info-value">{{ formatBytes(systemInfo.totalMemory || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Available Memory:</span>
|
|
||||||
<span class="info-value">{{ formatBytes(systemInfo.availableMemory || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Used Memory:</span>
|
|
||||||
<span class="info-value">{{ formatBytes(systemInfo.usedMemory || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-icon"><i class="fas fa-hdd" aria-hidden="true"></i></span>
|
|
||||||
<h3>Disk</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Total Disk Space:</span>
|
|
||||||
<span class="info-value">{{ formatBytes(systemInfo.totalDisk || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Available Disk Space:</span>
|
|
||||||
<span class="info-value">{{ formatBytes(systemInfo.availableDisk || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Used Disk Space:</span>
|
|
||||||
<span class="info-value">{{ formatBytes(systemInfo.usedDisk || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-icon"><i class="fas fa-globe" aria-hidden="true"></i></span>
|
|
||||||
<h3>Network</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">IP Address:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.ipAddress || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">MAC Address:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.macAddress || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Network Interface:</span>
|
|
||||||
<span class="info-value">{{ systemInfo.networkInterface || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<span class="card-icon"><i class="fas fa-clock" aria-hidden="true"></i></span>
|
|
||||||
<h3>Uptime</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">System Uptime:</span>
|
|
||||||
<span class="info-value">{{ formatUptime(systemInfo.uptime || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Boot Time:</span>
|
|
||||||
<span class="info-value">{{ formatDate(systemInfo.bootTime || 0) }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { ref, onMounted } from 'vue';
|
|
||||||
import { systemInfoApi } from '../api/index.js';
|
|
||||||
import { showNotification, formatBytes, formatDate } from '../utils/functions.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'SystemInfo',
|
|
||||||
setup() {
|
|
||||||
const systemInfo = ref({});
|
|
||||||
|
|
||||||
const loadSystemInfo = async () => {
|
|
||||||
try {
|
|
||||||
const result = await systemInfoApi.getSystemInfo();
|
|
||||||
systemInfo.value = result.data;
|
|
||||||
} catch (error) {
|
|
||||||
showNotification('Load System Info Failed', 'error');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatUptime = (seconds) => {
|
|
||||||
const days = Math.floor(seconds / 86400);
|
|
||||||
const hours = Math.floor((seconds % 86400) / 3600);
|
|
||||||
const minutes = Math.floor((seconds % 3600) / 60);
|
|
||||||
|
|
||||||
const parts = [];
|
|
||||||
if (days > 0) parts.push(`${days} day${days > 1 ? 's' : ''}`);
|
|
||||||
if (hours > 0) parts.push(`${hours} hour${hours > 1 ? 's' : ''}`);
|
|
||||||
if (minutes > 0) parts.push(`${minutes} minute${minutes > 1 ? 's' : ''}`);
|
|
||||||
|
|
||||||
return parts.length > 0 ? parts.join(' ') : '0 minute';
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
loadSystemInfo();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
systemInfo,
|
|
||||||
formatBytes,
|
|
||||||
formatDate,
|
|
||||||
formatUptime
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
@import '../styles/common.css';
|
|
||||||
|
|
||||||
.system-info-page {
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
padding-bottom: 12px;
|
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-icon {
|
|
||||||
font-size: 24px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user