feat(dashboard): бесшовное обновление данных без перезагрузки страницы

- Добавлен API endpoint /api/dashboard/stats
- Реализована замена location.reload() на fetch() каждые 30 секунд
- Добавлены ID к элементам метрик для точечного обновления
- Убрано мерцание страницы при обновлении
This commit is contained in:
mirivlad 2026-04-14 00:38:43 +08:00
parent e985bb2c34
commit 8d4a789e00
3 changed files with 49 additions and 7 deletions

View File

@ -141,6 +141,9 @@ $dashboardGroup = $app->group('', function ($group) use ($twig) {
return $twig->render($response, 'dashboard.twig', $templateData);
});
})->add($csrfMiddleware)->add(AuthMiddleware::class);
n// API для дашборда
= new DashboardController();
->get('/api/dashboard/stats', [, 'getDashboardData']);
// Create controllers BEFORE routes
$groupController = new GroupController($twig);

View File

@ -42,4 +42,43 @@ class DashboardController
return $this->twig->render($response, 'dashboard.twig', $templateData);
}
public function getDashboardData(Request $request, Response $response, $args)
{
$servers = $this->serverModel->getServersWithStatus();
$result = [];
foreach ($servers as $server) {
$serverData = [
'id' => $server['id'],
'status' => $server['status'],
'updated_at' => $server['last_metrics_at'] ? date('d.m.Y H:i:s', strtotime($server['last_metrics_at'])) : 'Нет данных',
'metrics' => []
];
if (isset($server['latest_metrics']['cpu_load'])) {
$serverData['metrics']['cpu_load'] = [
'value' => $server['latest_metrics']['cpu_load']['value'],
'unit' => $server['latest_metrics']['cpu_load']['unit'] ?? '%'
];
}
if (isset($server['latest_metrics']['ram_used'])) {
$serverData['metrics']['ram_used'] = [
'value' => $server['latest_metrics']['ram_used']['value'],
'unit' => $server['latest_metrics']['ram_used']['unit'] ?? '%'
];
}
$diskMetric = $server['latest_metrics']['disk_used_root'] ?? $server['latest_metrics']['disk_used'] ?? null;
if ($diskMetric) {
$serverData['metrics']['disk'] = [
'value' => $diskMetric['value'],
'unit' => $diskMetric['unit'] ?? '%'
];
}
$result[] = $serverData;
}
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
}
}

View File

@ -107,7 +107,7 @@
<div class="col-6 mb-2">
<div class="d-flex justify-content-between">
<small class="text-muted"><i class="fas fa-microchip"></i> CPU</small>
<strong>{{ server.latest_metrics['cpu_load'].value }}{{ server.latest_metrics['cpu_load'].unit }}</strong>
<strong><span id='cpu-val-{{ server.id }}'>{{ server.latest_metrics['cpu_load'].value }}{{ server.latest_metrics['cpu_load'].unit }}</span></strong>
</div>
{% set cpu_t = server.thresholds['cpu_load']|default(null) %}
{% if cpu_t and server.latest_metrics['cpu_load'].value >= cpu_t.critical %}
@ -123,7 +123,7 @@
{% endif %}
<div class="progress" style="height: 6px;">
<div class="progress-bar {{ cpu_color }}"
role="progressbar"
role="progressbar" id="cpu-bar-{{ server.id }}"
style="width: {{ server.latest_metrics['cpu_load'].value }}%"></div>
</div>
</div>
@ -133,7 +133,7 @@
<div class="col-6 mb-2">
<div class="d-flex justify-content-between">
<small class="text-muted"><i class="fas fa-memory"></i> RAM</small>
<strong>{{ server.latest_metrics['ram_used'].value }}{{ server.latest_metrics['ram_used'].unit }}</strong>
<strong><span id='ram-val-{{ server.id }}'>{{ server.latest_metrics['ram_used'].value }}{{ server.latest_metrics['ram_used'].unit }}</span></strong>
</div>
{% set ram_t = server.thresholds['ram_used']|default(null) %}
{% if ram_t and server.latest_metrics['ram_used'].value >= ram_t.critical %}
@ -149,7 +149,7 @@
{% endif %}
<div class="progress" style="height: 6px;">
<div class="progress-bar {{ ram_color }}"
role="progressbar"
role="progressbar" id="ram-bar-{{ server.id }}"
style="width: {{ server.latest_metrics['ram_used'].value }}%"></div>
</div>
</div>
@ -160,7 +160,7 @@
<div class="col-6 mb-2">
<div class="d-flex justify-content-between">
<small class="text-muted"><i class="fas fa-hdd"></i> Диск (/)</small>
<strong>{{ diskMetric.value }}{{ diskMetric.unit|default('%') }}</strong>
<strong><span id='disk-val-{{ server.id }}'>{{ diskMetric.value }}{{ diskMetric.unit|default('%') }}</span></strong>
</div>
{% set disk_t = server.thresholds['disk_used_root'] is defined ? server.thresholds['disk_used_root'] : null %}
{% if disk_t and diskMetric.value >= disk_t.critical %}
@ -176,7 +176,7 @@
{% endif %}
<div class="progress" style="height: 6px;">
<div class="progress-bar {{ disk_color }}"
role="progressbar"
role="progressbar" id="disk-bar-{{ server.id }}"
style="width: {{ diskMetric.value }}%"></div>
</div>
</div>
@ -196,7 +196,7 @@
<div class="text-muted small mt-2">
<i class="fas fa-clock"></i>
{% if server.last_metrics_at %}
Обновлено: {{ server.last_metrics_at|date('d.m.Y H:i:s') }}
Обновлено: <span id="updated-at-{{ server.id }}">{{ server.last_metrics_at|date('d.m.Y H:i:s') }}</span>
{% else %}
Метрики не получены
{% endif %}