ui: заменить оставшиеся боковые панели на центрированные popup.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-13 13:12:21 +03:00
parent 31dd3b4ffc
commit 4e1d5f221e
12 changed files with 107 additions and 52 deletions
+12
View File
@@ -152,6 +152,18 @@ class ItManagerEquipmentTests(TestCase):
self.assertContains(r, 'role="dialog"') self.assertContains(r, 'role="dialog"')
self.assertNotContains(r, 'id="it-equipment-panel-overlay"') self.assertNotContains(r, 'id="it-equipment-panel-overlay"')
def test_remaining_it_forms_are_popups(self):
r = self.client.get('/it-manager/')
for panel_id in (
'it-consumable-panel',
'it-provider-panel',
'it-contract-panel',
'it-servicecall-panel',
):
self.assertContains(r, f'id="{panel_id}"')
self.assertNotContains(r, f'id="{panel_id}-overlay"')
self.assertNotContains(r, 'translateX(100%)')
def test_models_catalog_is_popup(self): def test_models_catalog_is_popup(self):
r = self.client.get('/it-manager/') r = self.client.get('/it-manager/')
self.assertContains(r, 'id="it-equipment-models-panel"') self.assertContains(r, 'id="it-equipment-models-panel"')
+13
View File
@@ -874,6 +874,19 @@ class DislocationVendorsTabTests(TestCase):
self.assertContains(r, 'ТестСервис') self.assertContains(r, 'ТестСервис')
self.assertNotContains(r, 'Добавить') self.assertNotContains(r, 'Добавить')
def test_vendor_form_is_popup(self):
from django.test import Client
from core.test_utils import login_2fa
client = Client()
login_2fa(client, self.it_user)
r = client.get('/dislocation/', {'tab': 'vendors'}, HTTP_HX_REQUEST='true')
self.assertEqual(r.status_code, 200)
self.assertContains(r, 'id="dislo-vendor-panel"')
self.assertContains(r, 'role="dialog"')
self.assertNotContains(r, 'id="dislo-vendor-panel-overlay"')
self.assertNotContains(r, 'translateX(100%)')
def test_it_can_create_vendor(self): def test_it_can_create_vendor(self):
from django.test import Client from django.test import Client
from apps.locations.models.base import Location from apps.locations.models.base import Location
+3
View File
@@ -51,6 +51,9 @@ class PowerAssetsTests(TestCase):
self.assertEqual(r.context['accounting_active_tab'], 'power') self.assertEqual(r.context['accounting_active_tab'], 'power')
tab_keys = [t[0] for t in r.context['accounting_tabs']] tab_keys = [t[0] for t in r.context['accounting_tabs']]
self.assertIn('power', tab_keys) self.assertIn('power', tab_keys)
self.assertContains(r, 'id="power-create-panel"')
self.assertContains(r, 'role="dialog"')
self.assertNotContains(r, 'id="power-create-overlay"')
def test_create_inverter_on_location(self): def test_create_inverter_on_location(self):
r = self.client.post('/power-assets/create/', { r = self.client.post('/power-assets/create/', {
+4
View File
@@ -152,6 +152,10 @@ class CashRegisterPortalTests(TestCase):
resp = self.client.get('/rro/', HTTP_HX_REQUEST='true') resp = self.client.get('/rro/', HTTP_HX_REQUEST='true')
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
self.assertContains(resp, 'FN-PORTAL-1') self.assertContains(resp, 'FN-PORTAL-1')
self.assertContains(resp, 'id="rro-form-panel"')
self.assertContains(resp, 'role="dialog"')
self.assertNotContains(resp, 'id="rro-form-overlay"')
self.assertNotContains(resp, 'translateX(100%)')
def test_pharmacy_detail_rro_tab(self): def test_pharmacy_detail_rro_tab(self):
self._login() self._login()
+2 -6
View File
@@ -78,17 +78,13 @@ function chatToggleArchived(show) {
function chatPanelOpen(id) { function chatPanelOpen(id) {
var panel = document.getElementById(id); var panel = document.getElementById(id);
var overlay = document.getElementById(id + '-overlay'); if (panel) panel.style.display = 'flex';
if (overlay) overlay.style.display = 'block';
if (panel) panel.style.transform = 'translateX(0)';
document.body.style.overflow = 'hidden'; document.body.style.overflow = 'hidden';
} }
function chatPanelClose(id) { function chatPanelClose(id) {
var panel = document.getElementById(id); var panel = document.getElementById(id);
var overlay = document.getElementById(id + '-overlay'); if (panel) panel.style.display = 'none';
if (overlay) overlay.style.display = 'none';
if (panel) panel.style.transform = 'translateX(100%)';
document.body.style.overflow = ''; document.body.style.overflow = '';
} }
+3 -3
View File
@@ -530,9 +530,9 @@ document.addEventListener('keydown', function (ev) {
itModelsDismiss(); itModelsDismiss();
return; return;
} }
['it-equipment-panel', 'it-worklog-panel'].forEach(function (id) { document.querySelectorAll('[id^="it-"][role="dialog"]').forEach(function (el) {
var el = document.getElementById(id); if (el.id === 'it-equipment-models-panel' || el.id === 'it-report-preview-modal') return;
if (el && el.style.display === 'flex') itPanelClose(id); if (el.style.display === 'flex') itPanelClose(el.id);
}); });
}); });
+3 -3
View File
@@ -218,14 +218,14 @@ function ttShowDetail(empId) {
'</table>' + '</table>' +
'</div>'; '</div>';
overlay.style.display = 'block'; if (overlay) overlay.style.display = 'none';
panel.style.transform = 'translateX(0)'; panel.style.display = 'flex';
} }
function ttCloseDetail() { function ttCloseDetail() {
var panel = document.getElementById('tt-detail'); var panel = document.getElementById('tt-detail');
var overlay = document.getElementById('tt-detail-overlay'); var overlay = document.getElementById('tt-detail-overlay');
if (panel) panel.style.transform = 'translateX(100%)'; if (panel) panel.style.display = 'none';
if (overlay) overlay.style.display = 'none'; if (overlay) overlay.style.display = 'none';
} }
+12 -6
View File
@@ -80,9 +80,11 @@
</div> </div>
</div> </div>
<!-- Выездная панель: обсуждение --> <!-- Попап: обсуждение -->
<div id="chat-thread-panel-overlay" onclick="chatPanelClose('chat-thread-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="chat-thread-panel" role="dialog" aria-modal="true"
<div id="chat-thread-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto; display:flex; flex-direction:column;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:center; justify-content:center; padding:1.5rem 1rem;"
onclick="if(event.target===this) chatPanelClose('chat-thread-panel')">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; height:min(36rem, 90vh); margin:auto; display:flex; flex-direction:column; overflow:hidden;">
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">{% trans "Обсуждение" %}</span> <span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">{% trans "Обсуждение" %}</span>
<button type="button" onclick="chatPanelClose('chat-thread-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}"> <button type="button" onclick="chatPanelClose('chat-thread-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
@@ -102,11 +104,14 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/></svg>
</button> </button>
</div> </div>
</div>
</div> </div>
<!-- Выездная панель: новое личное/групповое сообщение --> <!-- Попап: новое личное/групповое сообщение -->
<div id="chat-dm-picker-panel-overlay" onclick="chatPanelClose('chat-dm-picker-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="chat-dm-picker-panel" role="dialog" aria-modal="true"
<div id="chat-dm-picker-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto; display:flex; flex-direction:column;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:center; justify-content:center; padding:1.5rem 1rem;"
onclick="if(event.target===this) chatPanelClose('chat-dm-picker-panel')">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; height:min(32rem, 90vh); margin:auto; display:flex; flex-direction:column; overflow:hidden;">
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">{% trans "Новое сообщение" %}</span> <span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">{% trans "Новое сообщение" %}</span>
<button type="button" onclick="chatPanelClose('chat-dm-picker-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}"> <button type="button" onclick="chatPanelClose('chat-dm-picker-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
@@ -118,6 +123,7 @@
<div id="chat-dm-picker-list" style="display:flex; flex-direction:column; gap:0.25rem; overflow-y:auto; flex:1;"></div> <div id="chat-dm-picker-list" style="display:flex; flex-direction:column; gap:0.25rem; overflow-y:auto; flex:1;"></div>
<button type="button" class="btn btn-primary" style="width:100%; justify-content:center;" onclick="chatStartNewDm()">{% trans "Начать разговор" %}</button> <button type="button" class="btn btn-primary" style="width:100%; justify-content:center;" onclick="chatStartNewDm()">{% trans "Начать разговор" %}</button>
</div> </div>
</div>
</div> </div>
<script>chatInit();</script> <script>chatInit();</script>
+17 -11
View File
@@ -515,8 +515,10 @@
</div> </div>
{% if can_manage_vendors and vendor_form %} {% if can_manage_vendors and vendor_form %}
<div id="dislo-vendor-panel-overlay" onclick="disloVendorPanelClose()" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="dislo-vendor-panel" role="dialog" aria-modal="true"
<div id="dislo-vendor-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this) disloVendorPanelClose()">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<form id="dislo-vendor-form" <form id="dislo-vendor-form"
hx-post="{% if vendor_form.instance.pk %}/dislocation/vendors/{{ vendor_form.instance.pk }}/update/{% else %}/dislocation/vendors/create/{% endif %}" hx-post="{% if vendor_form.instance.pk %}/dislocation/vendors/{{ vendor_form.instance.pk }}/update/{% else %}/dislocation/vendors/create/{% endif %}"
hx-target="#main-content" hx-indicator="#loader" hx-disabled-elt="find button[type=submit]"> hx-target="#main-content" hx-indicator="#loader" hx-disabled-elt="find button[type=submit]">
@@ -571,6 +573,7 @@
<button type="submit" class="btn btn-primary" style="width:100%; margin-top:0.5rem;">{% trans "Сохранить" %}</button> <button type="submit" class="btn btn-primary" style="width:100%; margin-top:0.5rem;">{% trans "Сохранить" %}</button>
</div> </div>
</form> </form>
</div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
@@ -667,15 +670,20 @@ function disloVendorPanelOpen() {
}); });
const activeEl = form.querySelector('[name="is_active"]'); const activeEl = form.querySelector('[name="is_active"]');
if (activeEl) activeEl.checked = true; if (activeEl) activeEl.checked = true;
document.getElementById('dislo-vendor-panel-overlay').style.display = 'block'; disloVendorPanelShow();
document.getElementById('dislo-vendor-panel').style.transform = 'translateX(0)'; }
function disloVendorPanelShow() {
const panel = document.getElementById('dislo-vendor-panel');
if (!panel) return;
panel.style.display = 'flex';
document.body.style.overflow = 'hidden';
} }
function disloVendorPanelClose() { function disloVendorPanelClose() {
const overlay = document.getElementById('dislo-vendor-panel-overlay');
const panel = document.getElementById('dislo-vendor-panel'); const panel = document.getElementById('dislo-vendor-panel');
if (overlay) overlay.style.display = 'none'; if (panel) panel.style.display = 'none';
if (panel) panel.style.transform = 'translateX(100%)'; document.body.style.overflow = '';
} }
function disloVendorEdit(pk) { function disloVendorEdit(pk) {
@@ -701,13 +709,11 @@ function disloVendorEdit(pk) {
set('comments', btn.dataset.comments); set('comments', btn.dataset.comments);
const activeEl = form.querySelector('[name="is_active"]'); const activeEl = form.querySelector('[name="is_active"]');
if (activeEl) activeEl.checked = btn.dataset.active === '1'; if (activeEl) activeEl.checked = btn.dataset.active === '1';
document.getElementById('dislo-vendor-panel-overlay').style.display = 'block'; disloVendorPanelShow();
document.getElementById('dislo-vendor-panel').style.transform = 'translateX(0)';
} }
{% if vendor_form_error and can_manage_vendors %} {% if vendor_form_error and can_manage_vendors %}
document.getElementById('dislo-vendor-panel-overlay').style.display = 'block'; disloVendorPanelShow();
document.getElementById('dislo-vendor-panel').style.transform = 'translateX(0)';
{% endif %} {% endif %}
disloVendorFilter(); disloVendorFilter();
+20 -8
View File
@@ -1059,8 +1059,10 @@
</div> </div>
<!-- Виїзна панель: новий витратний матеріал --> <!-- Виїзна панель: новий витратний матеріал -->
<div id="it-consumable-panel-overlay" onclick="itPanelClose('it-consumable-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="it-consumable-panel" role="dialog" aria-modal="true"
<div id="it-consumable-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this) itPanelClose('it-consumable-panel')">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<form hx-post="/it-manager/consumables/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"> <form hx-post="/it-manager/consumables/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %} {% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
@@ -1136,6 +1138,7 @@
</div> </div>
</div> </div>
</form> </form>
</div>
</div> </div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;"> <div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
@@ -1260,8 +1263,10 @@
</div> </div>
<!-- Виїзна панель: новий провайдер --> <!-- Виїзна панель: новий провайдер -->
<div id="it-provider-panel-overlay" onclick="itPanelClose('it-provider-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="it-provider-panel" role="dialog" aria-modal="true"
<div id="it-provider-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this) itPanelClose('it-provider-panel')">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<form hx-post="/it-manager/providers/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"> <form hx-post="/it-manager/providers/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %} {% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
@@ -1307,11 +1312,14 @@
</div> </div>
</div> </div>
</form> </form>
</div>
</div> </div>
<!-- Виїзна панель: новий договір --> <!-- Виїзна панель: новий договір -->
<div id="it-contract-panel-overlay" onclick="itPanelClose('it-contract-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="it-contract-panel" role="dialog" aria-modal="true"
<div id="it-contract-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this) itPanelClose('it-contract-panel')">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<form hx-post="/it-manager/contracts/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"> <form hx-post="/it-manager/contracts/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %} {% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
@@ -1430,6 +1438,7 @@
</div> </div>
</div> </div>
</form> </form>
</div>
</div> </div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;"> <div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
@@ -1522,8 +1531,10 @@
</div> </div>
<!-- Виїзна панель: нове звернення --> <!-- Виїзна панель: нове звернення -->
<div id="it-servicecall-panel-overlay" onclick="itPanelClose('it-servicecall-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="it-servicecall-panel" role="dialog" aria-modal="true"
<div id="it-servicecall-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this) itPanelClose('it-servicecall-panel')">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<form hx-post="/it-manager/servicecalls/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"> <form hx-post="/it-manager/servicecalls/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %} {% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
@@ -1571,6 +1582,7 @@
</div> </div>
</div> </div>
</form> </form>
</div>
</div> </div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;"> <div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
+7 -4
View File
@@ -8,7 +8,7 @@
{% trans "Инверторы и генераторы: объекты, обслуживание и плановое ТО" %} {% trans "Инверторы и генераторы: объекты, обслуживание и плановое ТО" %}
</p> </p>
</div> </div>
<button type="button" class="btn btn-primary" onclick="document.getElementById('power-create-panel').style.display='block'; document.getElementById('power-create-overlay').style.display='block';"> <button type="button" class="btn btn-primary" onclick="var p=document.getElementById('power-create-panel'); p.style.display='flex'; document.body.style.overflow='hidden'; if(typeof initSearchableSelects==='function') initSearchableSelects(p);">
{% trans "Добавить" %} {% trans "Добавить" %}
</button> </button>
</div> </div>
@@ -265,11 +265,13 @@
{% include "partials/pagination.html" with page=power_assets_page base_url="/accounting/?tab=power" page_param="power_page" size_param="power_per_page" item_label="единиц" %} {% include "partials/pagination.html" with page=power_assets_page base_url="/accounting/?tab=power" page_param="power_page" size_param="power_per_page" item_label="единиц" %}
</div> </div>
<div id="power-create-overlay" onclick="this.style.display='none'; document.getElementById('power-create-panel').style.display='none';" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="power-create-panel" role="dialog" aria-modal="true"
<div id="power-create-panel" style="display:none; position:fixed; top:0; right:0; height:100vh; width:28rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this){this.style.display='none'; document.body.style.overflow='';}">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; justify-content:space-between; align-items:center; position:sticky; top:0; background:var(--color-card);"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; justify-content:space-between; align-items:center; position:sticky; top:0; background:var(--color-card);">
<span style="font-weight:600;">{% trans "Новое энергооборудование" %}</span> <span style="font-weight:600;">{% trans "Новое энергооборудование" %}</span>
<button type="button" class="btn btn-ghost btn-icon" onclick="document.getElementById('power-create-panel').style.display='none'; document.getElementById('power-create-overlay').style.display='none';" aria-label="{% trans 'Закрыть' %}">×</button> <button type="button" class="btn btn-ghost btn-icon" onclick="document.getElementById('power-create-panel').style.display='none'; document.body.style.overflow='';" aria-label="{% trans 'Закрыть' %}">×</button>
</div> </div>
<form hx-post="/power-assets/create/" hx-target="#main-content" hx-indicator="#loader" <form hx-post="/power-assets/create/" hx-target="#main-content" hx-indicator="#loader"
style="padding:1.25rem; display:flex; flex-direction:column; gap:0.875rem;"> style="padding:1.25rem; display:flex; flex-direction:column; gap:0.875rem;">
@@ -352,6 +354,7 @@
</div> </div>
<button type="submit" class="btn btn-primary">{% trans "Сохранить" %}</button> <button type="submit" class="btn btn-primary">{% trans "Сохранить" %}</button>
</form> </form>
</div>
</div> </div>
<script>if (typeof initSearchableSelects === 'function') initSearchableSelects(document);</script> <script>if (typeof initSearchableSelects === 'function') initSearchableSelects(document);</script>
+11 -11
View File
@@ -122,8 +122,10 @@
</div> </div>
{% if can_edit_rro %} {% if can_edit_rro %}
<div id="rro-form-overlay" onclick="rroCloseForm()" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div> <div id="rro-form-panel" role="dialog" aria-modal="true"
<div id="rro-form-panel" style="position:fixed; top:0; right:0; height:100vh; width:28rem; max-width:96vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;"> style="display:none; position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.4); align-items:flex-start; justify-content:center; padding:1.5rem 1rem; overflow-y:auto;"
onclick="if(event.target===this) rroCloseForm()">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 20px 60px rgb(0 0 0/0.2); width:100%; max-width:36rem; margin:auto;">
<form id="rro-register-form" hx-post="/rro/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"> <form id="rro-register-form" hx-post="/rro/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %} {% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;"> <div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
@@ -222,6 +224,7 @@
</button> </button>
</div> </div>
</form> </form>
</div>
</div> </div>
<script type="application/json" id="rro-registers-json">{{ registers_json|safe }}</script> <script type="application/json" id="rro-registers-json">{{ registers_json|safe }}</script>
@@ -236,7 +239,6 @@
var TITLE_EDIT = '{% filter escapejs %}{% trans "Редактирование РРО / ПРРО" %}{% endfilter %}'; var TITLE_EDIT = '{% filter escapejs %}{% trans "Редактирование РРО / ПРРО" %}{% endfilter %}';
function panel() { return document.getElementById('rro-form-panel'); } function panel() { return document.getElementById('rro-form-panel'); }
function overlay() { return document.getElementById('rro-form-overlay'); }
function formEl() { return document.getElementById('rro-register-form'); } function formEl() { return document.getElementById('rro-register-form'); }
window.rroKindToggle = function (kind) { window.rroKindToggle = function (kind) {
@@ -245,17 +247,15 @@
}; };
window.rroCloseForm = function () { window.rroCloseForm = function () {
var p = panel(), o = overlay(); var p = panel();
if (p) p.style.transform = 'translateX(100%)'; if (p) p.style.display = 'none';
if (o) o.style.display = 'none'; document.body.style.overflow = '';
}; };
function openPanel() { function openPanel() {
var p = panel(), o = overlay(); var p = panel();
if (o) o.style.display = 'block'; if (p) p.style.display = 'flex';
requestAnimationFrame(function () { document.body.style.overflow = 'hidden';
if (p) p.style.transform = 'translateX(0)';
});
} }
function setVal(id, value) { function setVal(id, value) {