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();
});
})();