diff --git a/HISTORY.md b/HISTORY.md
index b9eea32..cf0df62 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,17 @@
# История изменений
+## 2026-04-06 09:37 UTC – Загрузка из БД при пустой таблице
+
+**Проблема:** При открытии главной страницы данные из PostgreSQL подставлялись только если `GET /api/incidents` возвращал непустой `rows`; при пустой базе `processData` не вызывался, дашборд оставался скрытым до первой загрузки файла.
+
+**Решение:** После успешного ответа API всегда вызывается `processData(rows)` (в том числе для пустого массива); показ индикатора «Загрузка данных из базы…», отдельные сообщения для непустой и пустой выборки, вывод ошибки при недоступности API.
+
+**Изменения:** `index.html` (`tryLoadFromDb`).
+
+**Проверка:** Открытие главной при пустой БД — видны KPI/диаграммы в нулевом состоянии и сообщение о пустой базе; при наличии записей — прежнее поведение.
+
+---
+
## 2026-04-06 18:00 UTC – Многостраничный UI: загрузка на data.html
**Проблема:** Источник данных и кнопка загрузки должны быть на отдельной странице; на ней же — сводка по числу объектов в БД и по последней загрузке.
diff --git a/index.html b/index.html
index 176c2fc..22f7cc4 100644
--- a/index.html
+++ b/index.html
@@ -8,8 +8,927 @@
-
+
+
+
@@ -21,10 +940,6 @@
OMC · Ситуационный центр
-
Статус АКТИВЕН
@@ -50,10 +965,17 @@
ПодсистемаМониторинг инцидентов
- Данные из PostgreSQL · загрузка файла: раздел «Источник данных»
+ Файл: CSV · JSON · Excel · сохранение в PostgreSQL по ключу «Название»
+
+ Источник данных
+
+ Файл не выбран — CSV, JSON или Excel (.xlsx, .xls) с теми же колонками, что в экспорте ServiceDesk
+
+
+
@@ -1101,18 +2023,31 @@
}
function tryLoadFromDb() {
+ el("error").classList.remove("show");
+ el("success").classList.remove("show");
+ el("loading").classList.add("show");
+ el("loading").textContent = "Загрузка данных из базы…";
fetch("/api/incidents")
.then(function (r) {
- if (!r.ok) return null;
+ if (!r.ok) throw new Error("HTTP " + r.status);
return r.json();
})
.then(function (j) {
- if (!j || !j.rows || !j.rows.length) return;
- processData(j.rows);
+ el("loading").classList.remove("show");
+ const rows = j && Array.isArray(j.rows) ? j.rows : [];
+ processData(rows);
el("success").classList.add("show");
- el("success").textContent = "✓ Загружено из базы: " + j.rows.length + " записей";
+ if (rows.length) {
+ el("success").textContent = "✓ Загружено из базы: " + rows.length + " записей";
+ } else {
+ el("success").textContent = "✓ База пуста — загрузите выгрузку через «Источник данных»";
+ }
})
- .catch(function () { /* API недоступен */ });
+ .catch(function () {
+ el("loading").classList.remove("show");
+ el("error").classList.add("show");
+ el("error").textContent = "✗ Не удалось загрузить данные из базы (API недоступен или ошибка сети).";
+ });
}
el("btn-today").addEventListener("click", function () {