refactor: remove unused monitoring and system info features

This commit is contained in:
2026-05-05 15:05:26 +08:00
parent 4c6e8294bb
commit 1323da55a6
6 changed files with 1 additions and 548 deletions

View File

@@ -9,8 +9,6 @@ Frontend application for Super-frpc - a frpc instance integrated management syst
- User management (create, edit, delete users)
- Session management (view and delete active sessions)
- System logs viewing with filtering capabilities
- Real-time system monitoring (CPU, memory, disk, network)
- System information display
- Role-based access control (superuser, admin, visitor)
- Responsive design with modern UI
@@ -49,8 +47,7 @@ frontend/
│ ├── Users.vue # User management
│ ├── Sessions.vue # Session management
│ ├── Logs.vue # System logs
── Monitor.vue # System monitoring
│ └── SystemInfo.vue # System information
── Settings.vue # Settings
├── logger.js # Logging utility
├── api-backend.md # Backend API documentation
└── README.md # This file

View File

@@ -112,13 +112,4 @@ export const logApi = {
getLogs: (level) => api.post('/logMgr/list', { level })
};
export const monitorApi = {
getSystemStats: () => api.get('/monitor/stats')
};
export default api;
export const TODO_API_NOTES = {
monitorStats: 'TODO: /monitor/stats - 获取系统监控数据 API 未在 api-backend.md 中定义',
systemInfo: 'TODO: /system/info - 获取系统信息 API 未在 api-backend.md 中定义'
};

View File

@@ -53,8 +53,6 @@ export default {
{ path: '/users', title: 'User Management', icon: 'fas fa-users', permission: ['superuser'] },
{ 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: '/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'] }
];

View File

@@ -43,18 +43,6 @@ const routes = [
component: () => import('../views/Logs.vue'),
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',
name: 'Settings',

View File

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

View File

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