From 6f7617b174da8af4034c9a4828401d45b6a71094 Mon Sep 17 00:00:00 2001 From: Maxim Date: Thu, 18 Jun 2026 15:14:37 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=81=D0=B8=D1=82=D1=83=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?,=20=D0=BA=D0=BE=D0=B3=D0=B4=D0=B0=20=D0=BD=D0=B5=D1=82=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=B5,=20=D0=B8=D0=BB=D0=B8=20=D0=BE=D1=88=D0=B8?= =?UTF-8?q?=D0=B1=D0=BA=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0=D0=B3?= =?UTF-8?q?=D1=80=D1=83=D0=B7=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server/main.go | 27 ++++++++++++++++-- cmd/server/web/css/logs.css | 55 +++++++++++++++++++++++++++++++++++++ cmd/server/web/js/camera.ts | 4 +-- cmd/server/web/js/logs.ts | 36 ++++++++++++++++++++++-- 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 4ce1382..70a6a8d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -307,6 +307,29 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) { } total := len(allSamples) + + if total == 0 { + writeJSON(w, map[string]any{ + "filename": filename, + "total": 0, + "page": 1, + "page_size": pageSize, + "total_pages": 1, + "has_previous": false, + "has_next": false, + "start_index": 0, + "end_index": 0, + "samples": []Sample{}, + "stats": map[string]any{ + "total_points": 0, + "amplitude_over_0": 0, + "signal_over_10": 0, + }, + "order": "newest_first", + }) + return + } + totalPages := (total + pageSize - 1) / pageSize if totalPages == 0 { totalPages = 1 @@ -320,8 +343,6 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) { page = 1 } - // Страница 1 = самые новые записи (с конца файла) - // Новые записи в конце файла, поэтому начинаем с конца start := total - page*pageSize if start < 0 { start = 0 @@ -346,7 +367,7 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) { reversedSamples = append(reversedSamples, pageSamples[i]) } - // Считаем статистику (без суммы объектов) + // Считаем статистику amplitudeOver0 := 0 signalOver10 := 0 for _, s := range allSamples { diff --git a/cmd/server/web/css/logs.css b/cmd/server/web/css/logs.css index 9d4bb05..af373e8 100644 --- a/cmd/server/web/css/logs.css +++ b/cmd/server/web/css/logs.css @@ -562,4 +562,59 @@ font-size: var(--font-size-xs); color: #666; min-width: 30px; +} + +/* ===== ПУСТОЕ СОСТОЯНИЕ ===== */ +.empty-state { + text-align: center; + padding: 60px 20px; + color: #88ffbb; +} + +.empty-icon { + font-size: 48px; + margin-bottom: 16px; + opacity: 0.5; +} + +.empty-message { + font-size: var(--font-size-xl); + font-family: var(--font-display); + letter-spacing: 0.05em; + margin-bottom: 8px; + color: #00ff88; +} + +.empty-hint { + font-size: var(--font-size-base); + font-family: var(--font-mono); + opacity: 0.5; + color: #88ffbb; +} + +/* ===== ЗАГРУЗКА ===== */ +.loading-indicator { + text-align: center; + padding: 60px 20px; + color: #88ffbb; + font-family: var(--font-mono); + font-size: var(--font-size-lg); + opacity: 0.7; +} + +.loading-indicator::after { + content: ''; + display: inline-block; + width: 20px; + height: 20px; + margin-left: 12px; + border: 2px solid #00ff88; + border-top-color: transparent; + border-radius: 50%; + animation: spin 0.8s linear infinite; + vertical-align: middle; +} + +@keyframes spin { + to { transform: rotate(360deg); } } \ No newline at end of file diff --git a/cmd/server/web/js/camera.ts b/cmd/server/web/js/camera.ts index 2d9ae6f..ce137b6 100644 --- a/cmd/server/web/js/camera.ts +++ b/cmd/server/web/js/camera.ts @@ -41,7 +41,7 @@ export function initCamera(): void { if (textSpan) { textSpan.textContent = 'Скрыть'; } else { - btn.innerHTML = '📷 Скрыть'; + btn.innerHTML = 'Скрыть'; } } @@ -74,7 +74,7 @@ export function initCamera(): void { if (textSpan) { textSpan.textContent = 'Камера'; } else { - btn.innerHTML = '📷 Камера'; + btn.innerHTML = 'Камера'; } } diff --git a/cmd/server/web/js/logs.ts b/cmd/server/web/js/logs.ts index ea01a53..9446d4c 100644 --- a/cmd/server/web/js/logs.ts +++ b/cmd/server/web/js/logs.ts @@ -205,6 +205,12 @@ async function loadFileData(filename: string, page: number = 1): Promise { console.log(`[Logs] Загрузка данных: страница ${page} для ${filename}`); const response = await fetch(url); + + // Проверяем статус ответа + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + const data: LogDataResponse = await response.json(); state.currentData = data; state.dataTotalPages = data.total_pages; @@ -216,8 +222,22 @@ async function loadFileData(filename: string, page: number = 1): Promise { } catch (error) { console.error('[Logs] Ошибка загрузки данных:', error); if (DOM.dataTableContainer) { - DOM.dataTableContainer.innerHTML = '
❌ Ошибка загрузки данных
'; + // Показываем информативное сообщение, а не красную ошибку + DOM.dataTableContainer.innerHTML = ` +
+
Нет данных для отображения
+
Файл пуст или данные ещё не поступили
+
+ `; } + // Сбрасываем пагинацию + if (DOM.dataPageInfo) { + DOM.dataPageInfo.textContent = 'Нет записей'; + } + if (DOM.dataFirstPageBtn) DOM.dataFirstPageBtn.disabled = true; + if (DOM.dataPrevPageBtn) DOM.dataPrevPageBtn.disabled = true; + if (DOM.dataNextPageBtn) DOM.dataNextPageBtn.disabled = true; + if (DOM.dataLastPageBtn) DOM.dataLastPageBtn.disabled = true; } finally { state.isLoadingData = false; } @@ -234,13 +254,18 @@ async function loadEvents(page: number = 1): Promise { state.currentPage = page; if (DOM.eventsContent) { - DOM.eventsContent.innerHTML = '
⏳ Загрузка событий...
'; + DOM.eventsContent.innerHTML = '
Загрузка событий...
'; } const url = `/api/log/events?page=${page}&page_size=${PAGE_SIZE}&order=newest_first`; console.log(`[Logs] Загрузка событий: страница ${page}`); const response = await fetch(url); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + const data: EventsResponse = await response.json(); state.totalPages = data.total_pages; @@ -253,7 +278,12 @@ async function loadEvents(page: number = 1): Promise { } catch (error) { console.error('[Logs] Ошибка загрузки событий:', error); if (DOM.eventsContent) { - DOM.eventsContent.innerHTML = '
❌ Ошибка загрузки событий
'; + DOM.eventsContent.innerHTML = ` +
+
Нет событий
+
Журнал событий пуст
+
+ `; } } finally { state.isLoading = false;