From c319e76c7470e3be05413bec77c30e8f8ef32e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 30 May 2026 09:16:08 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20UI=20=E2=80=94=20edit=20modal,=20admin-?= =?UTF-8?q?=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C=20=D0=B2=D1=8B=D0=B1=D0=BE?= =?UTF-8?q?=D1=80=D0=B0=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=B0=D0=BD=D0=B8=D0=B8?= =?UTF-8?q?,=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20=D0=90=D1=83=D0=B4?= =?UTF-8?q?=D0=B8=D1=82/=D0=9B=D0=B8=D0=BC=D0=B8=D1=82=D1=8B;=20views/audi?= =?UTF-8?q?t.ejs,=20views/admin.ejs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- views/admin.ejs | 204 ++++++++++++++++++++++++++++++++++++++++++++++++ views/audit.ejs | 173 ++++++++++++++++++++++++++++++++++++++++ views/index.ejs | 162 +++++++++++++++++++++++++++++++++++++- 3 files changed, 535 insertions(+), 4 deletions(-) create mode 100644 views/admin.ejs create mode 100644 views/audit.ejs diff --git a/views/admin.ejs b/views/admin.ejs new file mode 100644 index 0000000..05f42be --- /dev/null +++ b/views/admin.ejs @@ -0,0 +1,204 @@ + + + + + Управление лимитами — IP WhiteList + + + + + +
+ + + + + + + + + + | + Управление лимитами + + ← Список адресов + Журнал аудита + Выйти (<%= user.email %>) + +
+ +
+ + <% if (message) { %>
<%= message %>
<% } %> + <% if (error) { %>
<%= error %>
<% } %> + +
+
+ Компании и лимиты + + Глобальный дефолт: <%= defaultLimit %> записей. + Пустое поле = сброс на дефолт. + +
+ + <% if (companies.length === 0) { %> +
Нет компаний в системе
+ <% } else { %> +
+ + + + + + + + + + + + <% companies.forEach(c => { %> + <% + // Вычисляем эффективный лимит (кастомный или дефолтный) + const effectiveLimit = c.custom_limit != null ? c.custom_limit : defaultLimit; + const pct = effectiveLimit > 0 ? Math.min(c.active_count / effectiveLimit, 1) : 1; + const barClass = pct >= 1 ? 'full' : pct >= 0.8 ? 'warn' : ''; + %> + + + + + + + + + + + <% }) %> + +
КомпанияClientIDИспользованоЛимитДействие
<%= c.name %><%= c.client_id %> +
+
+
+
+ + <%= c.active_count %> / <%= effectiveLimit %> + <% if (c.custom_limit != null) { %> + + <% } %> + +
+
+ <% if (c.custom_limit != null) { %> + <%= c.custom_limit %> + (индивидуальный) + <% } else { %> + дефолт (<%= defaultLimit %>) + <% } %> + +
+ + + <% if (c.custom_limit != null) { %> + + + <% } %> +
+
+
+ <% } %> +
+ +
+ + + + diff --git a/views/audit.ejs b/views/audit.ejs new file mode 100644 index 0000000..9e4ccb2 --- /dev/null +++ b/views/audit.ejs @@ -0,0 +1,173 @@ + + + + + Журнал аудита — IP WhiteList + + + + + + +
+ + + + + + + + + + | + Журнал аудита + + ← Список адресов + Управление лимитами + Выйти (<%= user.email %>) + +
+ +
+ + <% if (error) { %>
<%= error %>
<% } %> + + +
+
+ Фильтр +
+
+
+ + + <% if (selectedCompanyId) { %> + Сбросить + <% } %> + + Показано: <%= rows.length %> записей (макс 500) + +
+
+
+ + +
+
Записи журнала
+ <% if (rows.length === 0) { %> +
Нет записей в журнале аудита
+ <% } else { %> +
+ + + + + + + + + + + + <% rows.forEach(r => { %> + + + + + + + + + + + + <% }) %> + +
КогдаКтоКомпанияДействиеЗначение
+ <%= new Date(r.created_at).toLocaleString('ru', { + day: '2-digit', month: '2-digit', year: 'numeric', + hour: '2-digit', minute: '2-digit' + }) %> + <%= r.user_email %> + <%= r.company_name %>
+ <%= r.client_id %> +
+ <%= r.action %> + + <% if (r.old_value && r.new_value) { %> + <%= r.old_value %> + + <%= r.new_value %> + <% } else if (r.new_value) { %> + <%= r.new_value %> + <% } else if (r.old_value) { %> + <%= r.old_value %> + <% } else { %> + + <% } %> +
+
+ <% } %> +
+ +
+ + diff --git a/views/index.ejs b/views/index.ejs index f7f3b7c..be4d8e1 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -157,6 +157,14 @@ | Белые списки IP + + + <% if (isAdmin) { %> + Аудит + Лимиты + <% } %> + Выйти (<%= user.email %>) +
@@ -164,6 +172,40 @@ <% if (message) { %>
<%= message %>
<% } %> <% if (error) { %>
<%= error %>
<% } %> + <% + // Для admin: selectedCompany — выбранная компания (объект из getAllCompanies). + // Для обычного пользователя: selectedCompany — их компания (из getOrCreateCompany). + // company_id — числовой PK для передачи в скрытые поля форм. + const companyPk = selectedCompany ? selectedCompany.id : null; + %> + + + <% if (isAdmin && companies) { %> +
+
+
+ Компания: + + + → Аудит этой компании + → Лимиты + + Режим: Администратор + +
+
+
+ <% } %> +
@@ -173,7 +215,8 @@
записей
-
<%= user.clientId %>
+ +
<%= selectedCompany ? selectedCompany.client_id : user.clientId %>
компания
@@ -189,6 +232,13 @@
Добавить адрес
+ <% + // Передаём числовой PK компании в скрытом поле. + // Для admin: server.js возьмёт его из req.body.company_id. + // Для обычного пользователя: server.js игнорирует это поле + // и использует clientId из токена — защита от подмены. + %> +
@@ -220,7 +270,8 @@ Комментарий Добавил Дата - Действие + Изменён + Действия @@ -230,8 +281,33 @@ <%= e.comment || '—' %> <%= e.created_by %> <%= new Date(e.created_at).toLocaleDateString('ru', {day:'numeric',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'}) %> - - + + + <%= e.updated_at + ? new Date(e.updated_at).toLocaleDateString('ru', {day:'numeric',month:'short',hour:'2-digit',minute:'2-digit'}) + : '—' %> + + + <% + // data-* атрибуты для JS-заполнения modal без inline-onclick с параметрами. + // Так как комментарий может содержать кавычки — EJS экранирует их в HTML. + // Но в data-атрибуте JSON::stringify безопаснее. + %> + + + + + @@ -244,5 +320,83 @@
+ + + + + + +