Обработка ситуации, когда нет данных в файле, или ошибка при загрузке
This commit is contained in:
@@ -307,6 +307,29 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
total := len(allSamples)
|
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
|
totalPages := (total + pageSize - 1) / pageSize
|
||||||
if totalPages == 0 {
|
if totalPages == 0 {
|
||||||
totalPages = 1
|
totalPages = 1
|
||||||
@@ -320,8 +343,6 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) {
|
|||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Страница 1 = самые новые записи (с конца файла)
|
|
||||||
// Новые записи в конце файла, поэтому начинаем с конца
|
|
||||||
start := total - page*pageSize
|
start := total - page*pageSize
|
||||||
if start < 0 {
|
if start < 0 {
|
||||||
start = 0
|
start = 0
|
||||||
@@ -346,7 +367,7 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) {
|
|||||||
reversedSamples = append(reversedSamples, pageSamples[i])
|
reversedSamples = append(reversedSamples, pageSamples[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Считаем статистику (без суммы объектов)
|
// Считаем статистику
|
||||||
amplitudeOver0 := 0
|
amplitudeOver0 := 0
|
||||||
signalOver10 := 0
|
signalOver10 := 0
|
||||||
for _, s := range allSamples {
|
for _, s := range allSamples {
|
||||||
|
|||||||
@@ -562,4 +562,59 @@
|
|||||||
font-size: var(--font-size-xs);
|
font-size: var(--font-size-xs);
|
||||||
color: #666;
|
color: #666;
|
||||||
min-width: 30px;
|
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); }
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ export function initCamera(): void {
|
|||||||
if (textSpan) {
|
if (textSpan) {
|
||||||
textSpan.textContent = 'Скрыть';
|
textSpan.textContent = 'Скрыть';
|
||||||
} else {
|
} else {
|
||||||
btn.innerHTML = '📷 Скрыть';
|
btn.innerHTML = 'Скрыть';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ export function initCamera(): void {
|
|||||||
if (textSpan) {
|
if (textSpan) {
|
||||||
textSpan.textContent = 'Камера';
|
textSpan.textContent = 'Камера';
|
||||||
} else {
|
} else {
|
||||||
btn.innerHTML = '📷 Камера';
|
btn.innerHTML = 'Камера';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,12 @@ async function loadFileData(filename: string, page: number = 1): Promise<void> {
|
|||||||
console.log(`[Logs] Загрузка данных: страница ${page} для ${filename}`);
|
console.log(`[Logs] Загрузка данных: страница ${page} для ${filename}`);
|
||||||
|
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
// Проверяем статус ответа
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
const data: LogDataResponse = await response.json();
|
const data: LogDataResponse = await response.json();
|
||||||
state.currentData = data;
|
state.currentData = data;
|
||||||
state.dataTotalPages = data.total_pages;
|
state.dataTotalPages = data.total_pages;
|
||||||
@@ -216,8 +222,22 @@ async function loadFileData(filename: string, page: number = 1): Promise<void> {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Logs] Ошибка загрузки данных:', error);
|
console.error('[Logs] Ошибка загрузки данных:', error);
|
||||||
if (DOM.dataTableContainer) {
|
if (DOM.dataTableContainer) {
|
||||||
DOM.dataTableContainer.innerHTML = '<div style="color:#ff4444;">❌ Ошибка загрузки данных</div>';
|
// Показываем информативное сообщение, а не красную ошибку
|
||||||
|
DOM.dataTableContainer.innerHTML = `
|
||||||
|
<div class="empty-state">
|
||||||
|
<div class="empty-message">Нет данных для отображения</div>
|
||||||
|
<div class="empty-hint">Файл пуст или данные ещё не поступили</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
// Сбрасываем пагинацию
|
||||||
|
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 {
|
} finally {
|
||||||
state.isLoadingData = false;
|
state.isLoadingData = false;
|
||||||
}
|
}
|
||||||
@@ -234,13 +254,18 @@ async function loadEvents(page: number = 1): Promise<void> {
|
|||||||
state.currentPage = page;
|
state.currentPage = page;
|
||||||
|
|
||||||
if (DOM.eventsContent) {
|
if (DOM.eventsContent) {
|
||||||
DOM.eventsContent.innerHTML = '<div class="loading-indicator">⏳ Загрузка событий...</div>';
|
DOM.eventsContent.innerHTML = '<div class="loading-indicator">Загрузка событий...</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `/api/log/events?page=${page}&page_size=${PAGE_SIZE}&order=newest_first`;
|
const url = `/api/log/events?page=${page}&page_size=${PAGE_SIZE}&order=newest_first`;
|
||||||
console.log(`[Logs] Загрузка событий: страница ${page}`);
|
console.log(`[Logs] Загрузка событий: страница ${page}`);
|
||||||
|
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
const data: EventsResponse = await response.json();
|
const data: EventsResponse = await response.json();
|
||||||
|
|
||||||
state.totalPages = data.total_pages;
|
state.totalPages = data.total_pages;
|
||||||
@@ -253,7 +278,12 @@ async function loadEvents(page: number = 1): Promise<void> {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Logs] Ошибка загрузки событий:', error);
|
console.error('[Logs] Ошибка загрузки событий:', error);
|
||||||
if (DOM.eventsContent) {
|
if (DOM.eventsContent) {
|
||||||
DOM.eventsContent.innerHTML = '<div style="color:#ff4444;">❌ Ошибка загрузки событий</div>';
|
DOM.eventsContent.innerHTML = `
|
||||||
|
<div class="empty-state">
|
||||||
|
<div class="empty-message">Нет событий</div>
|
||||||
|
<div class="empty-hint">Журнал событий пуст</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
state.isLoading = false;
|
state.isLoading = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user