From 7b596a4dc2056c5ed1658fe480e13c602325bf8b Mon Sep 17 00:00:00 2001 From: cursor-agent Date: Thu, 26 Feb 2026 12:56:24 +0000 Subject: [PATCH] =?UTF-8?q?Feature:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D1=82?= =?UTF-8?q?=D0=B0=D0=B1=D0=BB=D0=B8=D1=87=D0=BD=D0=BE=D0=B9=20=D1=87=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20=D0=BF=D0=BE=20=D0=BA=D0=BD=D0=BE=D0=BF?= =?UTF-8?q?=D0=BA=D0=B5-=D0=BA=D1=80=D0=B5=D1=81=D1=82=D0=B8=D0=BA=D1=83?= =?UTF-8?q?=20(=D1=81=D1=80=D0=B0=D0=B7=D1=83,=20=D0=B1=D0=B5=D0=B7=20?= =?UTF-8?q?=D1=87=D0=B5=D0=BA=D0=B1=D0=BE=D0=BA=D1=81=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- HISTORY.md | 10 ++++- app/static/css/theme-compact.css | 22 ++++++++-- app/templates/documents/order_form.html | 37 +++++++++++++---- .../documents/supplier_order_form.html | 41 ++++++++++++++----- 4 files changed, 88 insertions(+), 22 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 082e5f5..5e8bbd6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,14 @@ # История изменений ERP WaterSurf -# История изменений ERP WaterSurf +## 2025-02-25 23:15 UTC – Удаление строки табличной части по кнопке-крестику + +**Проблема**: Удаление строки происходило при сохранении документа (чекбокс «Удалить»), что было неочевидно и неудобно. + +**Решение**: В формах заказа клиента и заказа поставщику чекбокс и подпись «Удалить» заменены на кнопку в виде красного крестика (×). По нажатию строка сразу удаляется из DOM, индексы полей formset пересчитываются (reindexRows), обновляется TOTAL_FORMS и пересчёт сумм по строкам. При добавлении новой строки после вставки клона также вызывается reindexRows(). + +**Изменения**: order_form.html (кнопка .ws-btn-remove-row, reindexRows, делегированный click на tbody), supplier_order_form.html (аналогично), theme-compact.css (стили .ws-btn-remove-row — красный крестик, hover; удалены стили .ws-delete-row-label). + +--- ## 2025-02-25 22:50 UTC – Добавление строки: одна строка за клик, понятное удаление diff --git a/app/static/css/theme-compact.css b/app/static/css/theme-compact.css index d08d353..67f7f77 100644 --- a/app/static/css/theme-compact.css +++ b/app/static/css/theme-compact.css @@ -132,11 +132,25 @@ width: 5%; } -.ws-table-items label.ws-delete-row-label { +.ws-table-items .ws-btn-remove-row { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + padding: 0; + border: none; + border-radius: 4px; + background: transparent; + color: #c62828; + font-size: 18px; + line-height: 1; cursor: pointer; - font-size: 13px; - color: var(--ws-text-muted); - white-space: nowrap; +} + +.ws-table-items .ws-btn-remove-row:hover { + background: rgba(198, 40, 40, 0.12); + color: #b71c1c; } .ws-table-items .ws-col-product select { diff --git a/app/templates/documents/order_form.html b/app/templates/documents/order_form.html index 6f6378d..ec1a246 100644 --- a/app/templates/documents/order_form.html +++ b/app/templates/documents/order_form.html @@ -72,7 +72,7 @@ {{ f.currency }} {{ f.quantity }} — - + {% endfor %} @@ -133,6 +133,34 @@ updateRowAmounts(); + function reindexRows() { + var prefix = getPrefix(); + var rows = tbody.querySelectorAll('.item-row'); + rows.forEach(function(row, i) { + row.querySelectorAll('input, select').forEach(function(el) { + var n = el.getAttribute('name'); + if (n && n.indexOf(prefix) === 0) { + el.setAttribute('name', n.replace(new RegExp('^' + prefix + '\\d+'), prefix + i)); + } + var id = el.getAttribute('id'); + if (id) { + el.setAttribute('id', id.replace(new RegExp(prefix + '\\d+'), prefix + i)); + } + }); + }); + totalInput.value = String(rows.length); + updateRowAmounts(); + } + + tbody.addEventListener('click', function(e) { + var btn = e.target.closest('.ws-btn-remove-row'); + if (!btn) return; + var row = btn.closest('tr.item-row'); + if (!row) return; + row.remove(); + reindexRows(); + }); + document.getElementById('add-order-row').addEventListener('click', function() { var rows = tbody.querySelectorAll('.item-row'); var lastRow = rows[rows.length - 1]; @@ -156,13 +184,8 @@ }); var amountCell = clone.querySelector('.row-amount'); if (amountCell) amountCell.textContent = '—'; - var delCheckbox = clone.querySelector('input[name$="-DELETE"]'); - if (delCheckbox) { - var delLabel = clone.querySelector('label.ws-delete-row-label'); - if (delLabel) delLabel.setAttribute('for', delCheckbox.id); - } tbody.appendChild(clone); - totalInput.value = nextIndex + 1; + reindexRows(); }); })(); diff --git a/app/templates/documents/supplier_order_form.html b/app/templates/documents/supplier_order_form.html index a8d7b39..5301379 100644 --- a/app/templates/documents/supplier_order_form.html +++ b/app/templates/documents/supplier_order_form.html @@ -79,7 +79,7 @@ {{ f.currency }} {{ f.quantity }} — - + {% endfor %} @@ -138,6 +138,34 @@ updateRowAmounts(); + function reindexRows() { + var prefix = getPrefix(); + var rows = tbody.querySelectorAll('.item-row'); + rows.forEach(function(row, i) { + row.querySelectorAll('input, select').forEach(function(el) { + var n = el.getAttribute('name'); + if (n && n.indexOf(prefix) === 0) { + el.setAttribute('name', n.replace(new RegExp('^' + prefix + '\\d+'), prefix + i)); + } + var id = el.getAttribute('id'); + if (id) { + el.setAttribute('id', id.replace(new RegExp(prefix + '\\d+'), prefix + i)); + } + }); + }); + totalInput.value = String(rows.length); + updateRowAmounts(); + } + + tbody.addEventListener('click', function(e) { + var btn = e.target.closest('.ws-btn-remove-row'); + if (!btn) return; + var row = btn.closest('tr.item-row'); + if (!row) return; + row.remove(); + reindexRows(); + }); + document.getElementById('add-supplier-order-row').addEventListener('click', function() { var rows = tbody.querySelectorAll('.item-row'); var lastRow = rows[rows.length - 1]; @@ -151,9 +179,7 @@ el.setAttribute('name', name.replace(new RegExp('^' + prefix + '\\d+-'), prefix + nextIndex + '-')); el.setAttribute('id', (el.getAttribute('id') || '').replace(new RegExp(prefix + '\\d+-'), prefix + nextIndex + '-')); } - if (el.name && el.name.indexOf('-DELETE') !== -1) { - el.checked = false; - } else if (el.name && el.name.indexOf('-id') !== -1) { + if (el.name && el.name.indexOf('-id') !== -1) { el.value = ''; } else if (el.type !== 'hidden') { el.value = ''; @@ -161,13 +187,8 @@ }); var amountCell = clone.querySelector('.row-amount'); if (amountCell) amountCell.textContent = '—'; - var delCheckbox = clone.querySelector('input[name$="-DELETE"]'); - if (delCheckbox) { - var delLabel = clone.querySelector('label.ws-delete-row-label'); - if (delLabel) delLabel.setAttribute('for', delCheckbox.id); - } tbody.appendChild(clone); - totalInput.value = nextIndex + 1; + reindexRows(); }); })();