Feature: удаление строки табличной части по кнопке-крестику (сразу, без чекбокса)
Made-with: Cursor
This commit is contained in:
10
HISTORY.md
10
HISTORY.md
@@ -1,6 +1,14 @@
|
|||||||
# История изменений ERP WaterSurf
|
# История изменений 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 – Добавление строки: одна строка за клик, понятное удаление
|
## 2025-02-25 22:50 UTC – Добавление строки: одна строка за клик, понятное удаление
|
||||||
|
|
||||||
|
|||||||
@@ -132,11 +132,25 @@
|
|||||||
width: 5%;
|
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;
|
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 {
|
.ws-table-items .ws-col-product select {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
<td class="ws-col-currency">{{ f.currency }}</td>
|
<td class="ws-col-currency">{{ f.currency }}</td>
|
||||||
<td class="ws-col-qty">{{ f.quantity }}</td>
|
<td class="ws-col-qty">{{ f.quantity }}</td>
|
||||||
<td class="row-amount ws-col-cost ws-num">—</td>
|
<td class="row-amount ws-col-cost ws-num">—</td>
|
||||||
<td class="ws-col-del"><label class="ws-delete-row-label">{% if f.DELETE %}{{ f.DELETE }}{% endif %} Удалить</label></td>
|
<td class="ws-col-del"><button type="button" class="ws-btn-remove-row" title="Удалить строку" aria-label="Удалить строку">×</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -133,6 +133,34 @@
|
|||||||
|
|
||||||
updateRowAmounts();
|
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() {
|
document.getElementById('add-order-row').addEventListener('click', function() {
|
||||||
var rows = tbody.querySelectorAll('.item-row');
|
var rows = tbody.querySelectorAll('.item-row');
|
||||||
var lastRow = rows[rows.length - 1];
|
var lastRow = rows[rows.length - 1];
|
||||||
@@ -156,13 +184,8 @@
|
|||||||
});
|
});
|
||||||
var amountCell = clone.querySelector('.row-amount');
|
var amountCell = clone.querySelector('.row-amount');
|
||||||
if (amountCell) amountCell.textContent = '—';
|
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);
|
tbody.appendChild(clone);
|
||||||
totalInput.value = nextIndex + 1;
|
reindexRows();
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
<td class="ws-col-currency">{{ f.currency }}</td>
|
<td class="ws-col-currency">{{ f.currency }}</td>
|
||||||
<td class="ws-col-qty">{{ f.quantity }}</td>
|
<td class="ws-col-qty">{{ f.quantity }}</td>
|
||||||
<td class="row-amount ws-col-cost ws-num">—</td>
|
<td class="row-amount ws-col-cost ws-num">—</td>
|
||||||
<td class="ws-col-del"><label class="ws-delete-row-label">{% if f.DELETE %}{{ f.DELETE }}{% endif %} Удалить</label></td>
|
<td class="ws-col-del"><button type="button" class="ws-btn-remove-row" title="Удалить строку" aria-label="Удалить строку">×</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -138,6 +138,34 @@
|
|||||||
|
|
||||||
updateRowAmounts();
|
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() {
|
document.getElementById('add-supplier-order-row').addEventListener('click', function() {
|
||||||
var rows = tbody.querySelectorAll('.item-row');
|
var rows = tbody.querySelectorAll('.item-row');
|
||||||
var lastRow = rows[rows.length - 1];
|
var lastRow = rows[rows.length - 1];
|
||||||
@@ -151,9 +179,7 @@
|
|||||||
el.setAttribute('name', name.replace(new RegExp('^' + prefix + '\\d+-'), prefix + nextIndex + '-'));
|
el.setAttribute('name', name.replace(new RegExp('^' + prefix + '\\d+-'), prefix + nextIndex + '-'));
|
||||||
el.setAttribute('id', (el.getAttribute('id') || '').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) {
|
if (el.name && el.name.indexOf('-id') !== -1) {
|
||||||
el.checked = false;
|
|
||||||
} else if (el.name && el.name.indexOf('-id') !== -1) {
|
|
||||||
el.value = '';
|
el.value = '';
|
||||||
} else if (el.type !== 'hidden') {
|
} else if (el.type !== 'hidden') {
|
||||||
el.value = '';
|
el.value = '';
|
||||||
@@ -161,13 +187,8 @@
|
|||||||
});
|
});
|
||||||
var amountCell = clone.querySelector('.row-amount');
|
var amountCell = clone.querySelector('.row-amount');
|
||||||
if (amountCell) amountCell.textContent = '—';
|
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);
|
tbody.appendChild(clone);
|
||||||
totalInput.value = nextIndex + 1;
|
reindexRows();
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user