From 39cc12fae45e23a3960cd2c3589d93d0344403a5 Mon Sep 17 00:00:00 2001 From: cursor-agent Date: Thu, 26 Feb 2026 12:26:28 +0000 Subject: [PATCH] =?UTF-8?q?Feature:=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86?= =?UTF-8?q?=D0=B0=20=D1=82=D0=BE=D0=B2=D0=B0=D1=80=D0=BE=D0=B2=20=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20=D1=81=D0=BA=D1=80=D0=BE=D0=BB=D0=BB=D0=B0,=20?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=B0=D1=80=20=D0=BE=D0=B1=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=D1=81=D1=8F,=20=D1=86=D0=B5=D0=BD=D0=B0/?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D1=8C=20=D1=81?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D0=B8=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BC=20=D1=80=D0=B0=D0=B7=D1=80=D1=8F=D0=B4=D0=BE=D0=B2?= 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 | 60 ++++++++++++++++-- app/templates/documents/order_form.html | 62 ++++++++++++++++--- .../documents/supplier_order_form.html | 62 ++++++++++++++++--- 4 files changed, 168 insertions(+), 26 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 445fc0c..b81f528 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,16 @@ # История изменений ERP WaterSurf +## 2025-02-25 22:35 UTC – Табличная часть заказа: без скролла, цена/стоимость с разделителем + +**Проблема**: В таблице товаров появлялась горизонтальная полоса прокрутки; поле «Товар» слишком широкое; в полях «Цена» и «Стоимость» не было разделителя разрядов. + +**Решение**: Включён table-layout: fixed и заданы доли колонок в % (Товар 28%, Цена 14%, Валюта 12%, Количество 10%, Стоимость 14%, Удалить 5%), чтобы таблица помещалась без скролла. Поле «Товар» ограничено по ширине, select с overflow: hidden. Поля «Цена» и «Стоимость»: выравнивание по правому краю, узкое поле под 8-значную сумму. В JS добавлены formatNum/parseNum: разделитель тысяч (неразрывный пробел) и запятая как десятичный разделитель; при blur цена форматируется, при focus и при submit — пробелы снимаются перед отправкой. Стоимость в ячейке выводится с разделителем. Аналогичные правки в форме заказа поставщику. + +**Изменения**: order_form.html, supplier_order_form.html (colgroup, классы ячеек, JS форматирование), theme-compact.css (ширины колонок). + +--- + ## 2025-02-25 22:25 UTC – Временное отключение авторизации для отладки **Проблема**: Для быстрой разработки и отладки нужно работать без входа. diff --git a/app/static/css/theme-compact.css b/app/static/css/theme-compact.css index 42c1eb7..b1782bd 100644 --- a/app/static/css/theme-compact.css +++ b/app/static/css/theme-compact.css @@ -84,14 +84,54 @@ max-width: 100%; } -/* Таблица товаров: колонка Товар шире, Количество уже */ +/* Таблица товаров: без горизонтального скролла, компактные колонки */ +.ws-table-wrap { + overflow-x: auto; + max-width: 100%; +} + +.ws-table-items { + table-layout: fixed; + width: 100%; + min-width: 0; +} + +/* Товар: ограниченная ширина, длинное название обрезается */ .ws-table-items .ws-col-product { - width: 35%; - min-width: 14rem; + width: 28%; + overflow: hidden; +} + +.ws-table-items .ws-col-product select { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Цена: поле под 8 знаков, значение справа */ +.ws-table-items .ws-col-price { + width: 14%; +} + +.ws-table-items .ws-col-price input { + width: 100% !important; + max-width: 100%; + text-align: right; + font-variant-numeric: tabular-nums; +} + +/* Валюта */ +.ws-table-items .ws-col-currency { + width: 12%; +} + +.ws-table-items .ws-col-currency select { + max-width: 100%; } .ws-table-items .ws-col-qty { - width: 5rem; + width: 10%; + min-width: 4rem; } .ws-table-items td.ws-col-qty input, @@ -101,6 +141,14 @@ box-sizing: border-box; } -.ws-table-items .ws-col-del { - width: 4rem; +/* Стоимость: справа, разделитель в JS */ +.ws-table-items .ws-col-cost { + width: 14%; + text-align: right; + font-variant-numeric: tabular-nums; +} + +.ws-table-items .ws-col-del { + width: 5%; + min-width: 3rem; } diff --git a/app/templates/documents/order_form.html b/app/templates/documents/order_form.html index 1eddbfd..7debfdb 100644 --- a/app/templates/documents/order_form.html +++ b/app/templates/documents/order_form.html @@ -48,10 +48,10 @@ - - + + - + @@ -67,11 +67,11 @@ {% for f in formset %} - - - + + + - + {% endfor %} @@ -101,17 +101,52 @@ return name.replace(/-TOTAL_FORMS$/, ''); } + function formatNum(x) { + var n = parseFloat(x); + if (isNaN(n)) return '—'; + var parts = n.toFixed(2).split('.'); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '\u202f'); + return parts.join(','); + } + function parseNum(s) { + return parseFloat(String(s).replace(/\s/g, '').replace(',', '.')) || 0; + } + function updateRowAmounts() { document.querySelectorAll('#order-items .item-row').forEach(function(row) { - var price = parseFloat(row.querySelector('input[name$="-price"]')?.value) || 0; - var qty = parseFloat(row.querySelector('input[name$="-quantity"]')?.value) || 0; + var priceInput = row.querySelector('input[name$="-price"]'); + var qty = parseNum(row.querySelector('input[name$="-quantity"]')?.value); + var price = parseNum(priceInput?.value); var el = row.querySelector('.row-amount'); - if (el) el.textContent = (price * qty).toFixed(2); + if (el) el.textContent = formatNum(price * qty); }); } form.addEventListener('input', updateRowAmounts); + form.querySelectorAll('#order-items input[name$="-price"]').forEach(function(input) { + input.addEventListener('blur', function() { + var v = parseNum(this.value); + if (!isNaN(v) && this.value.trim() !== '') this.value = formatNum(v).replace(',', '.'); + }); + input.addEventListener('focus', function() { + this.value = String(this.value).replace(/\s/g, '').replace(',', '.'); + }); + }); + form.addEventListener('submit', function() { + form.querySelectorAll('input[name$="-price"]').forEach(function(input) { + input.value = String(input.value).replace(/\s/g, '').replace(',', '.'); + }); + }); + + document.querySelectorAll('#order-items input[name$="-price"]').forEach(function(input) { + if (input.value && input.value.trim() !== '') { + var v = parseNum(input.value); + input.value = formatNum(v).replace(',', '.'); + } + }); + updateRowAmounts(); + document.getElementById('add-order-row').addEventListener('click', function() { var rows = tbody.querySelectorAll('.item-row'); var lastRow = rows[rows.length - 1]; @@ -135,6 +170,13 @@ }); var amountCell = clone.querySelector('.row-amount'); if (amountCell) amountCell.textContent = '—'; + clone.querySelector('input[name$="-price"]')?.addEventListener('blur', function() { + var v = parseNum(this.value); + if (!isNaN(v) && this.value.trim() !== '') this.value = formatNum(v).replace(',', '.'); + }); + clone.querySelector('input[name$="-price"]')?.addEventListener('focus', function() { + this.value = String(this.value).replace(/\s/g, '').replace(',', '.'); + }); tbody.appendChild(clone); totalInput.value = nextIndex + 1; }); diff --git a/app/templates/documents/supplier_order_form.html b/app/templates/documents/supplier_order_form.html index 5d0e6a8..0980a4a 100644 --- a/app/templates/documents/supplier_order_form.html +++ b/app/templates/documents/supplier_order_form.html @@ -55,10 +55,10 @@
{{ f.id }}{{ f.product }}{{ f.price }}{{ f.currency }}{{ f.id }}{{ f.product }}{{ f.price }}{{ f.currency }} {{ f.quantity }} {% if f.DELETE %}{{ f.DELETE }}{% endif %}
- - + + - + @@ -74,11 +74,11 @@ {% for f in formset %} - - - + + + - + {% endfor %} @@ -107,17 +107,52 @@ return name.replace(/-TOTAL_FORMS$/, ''); } + function formatNum(x) { + var n = parseFloat(x); + if (isNaN(n)) return '—'; + var parts = n.toFixed(2).split('.'); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '\u202f'); + return parts.join(','); + } + function parseNum(s) { + return parseFloat(String(s).replace(/\s/g, '').replace(',', '.')) || 0; + } + function updateRowAmounts() { document.querySelectorAll('#supplier-order-items .item-row').forEach(function(row) { - var price = parseFloat(row.querySelector('input[name$="-price"]')?.value) || 0; - var qty = parseFloat(row.querySelector('input[name$="-quantity"]')?.value) || 0; + var priceInput = row.querySelector('input[name$="-price"]'); + var qty = parseNum(row.querySelector('input[name$="-quantity"]')?.value); + var price = parseNum(priceInput?.value); var el = row.querySelector('.row-amount'); - if (el) el.textContent = (price * qty).toFixed(2); + if (el) el.textContent = formatNum(price * qty); }); } form.addEventListener('input', updateRowAmounts); + form.querySelectorAll('#supplier-order-items input[name$="-price"]').forEach(function(input) { + input.addEventListener('blur', function() { + var v = parseNum(this.value); + if (!isNaN(v) && this.value.trim() !== '') this.value = formatNum(v).replace(',', '.'); + }); + input.addEventListener('focus', function() { + this.value = String(this.value).replace(/\s/g, '').replace(',', '.'); + }); + }); + form.addEventListener('submit', function() { + form.querySelectorAll('input[name$="-price"]').forEach(function(input) { + input.value = String(input.value).replace(/\s/g, '').replace(',', '.'); + }); + }); + + document.querySelectorAll('#supplier-order-items input[name$="-price"]').forEach(function(input) { + if (input.value && input.value.trim() !== '') { + var v = parseNum(input.value); + input.value = formatNum(v).replace(',', '.'); + } + }); + updateRowAmounts(); + document.getElementById('add-supplier-order-row').addEventListener('click', function() { var rows = tbody.querySelectorAll('.item-row'); var lastRow = rows[rows.length - 1]; @@ -141,6 +176,13 @@ }); var amountCell = clone.querySelector('.row-amount'); if (amountCell) amountCell.textContent = '—'; + clone.querySelector('input[name$="-price"]')?.addEventListener('blur', function() { + var v = parseNum(this.value); + if (!isNaN(v) && this.value.trim() !== '') this.value = formatNum(v).replace(',', '.'); + }); + clone.querySelector('input[name$="-price"]')?.addEventListener('focus', function() { + this.value = String(this.value).replace(/\s/g, '').replace(',', '.'); + }); tbody.appendChild(clone); totalInput.value = nextIndex + 1; });
{{ f.id }}{{ f.product }}{{ f.price }}{{ f.currency }}{{ f.id }}{{ f.product }}{{ f.price }}{{ f.currency }} {{ f.quantity }} {% if f.DELETE %}{{ f.DELETE }}{% endif %}