Feature: компактные формы заказов, колонки Товар/Количество
Made-with: Cursor
This commit is contained in:
27
HISTORY.md
27
HISTORY.md
@@ -1,5 +1,32 @@
|
||||
# История изменений ERP WaterSurf
|
||||
|
||||
## 2025-02-25 21:30 UTC – Компактные формы документов (заказы клиента и поставщику)
|
||||
|
||||
**Проблема**: Формы создания/редактирования заказов занимали много места: каждое поле с новой строки на всю ширину.
|
||||
|
||||
**Решение**:
|
||||
- Дата и Номер в одной строке: поле «Дата» — 10 символов (size=10), «Номер» — 15 символов (size=15, maxlength=15).
|
||||
- Вид заказа и Организация в одной строке; Клиент и Автор в одной строке (заказ клиента). Аналогично заказ поставщику: Организация и Поставщик, Валюта и Курс, затем Автор.
|
||||
- Таблица товаров: колонка «Товар» шире (35%, min 14rem), колонка «Количество» уже (поле ввода 4ch, до двухзначного числа).
|
||||
- Добавлены виджеты для даты/номера в формах и для количества в formset (size=3, width: 4ch). Новый файл `static/css/theme-compact.css` с раскладкой строк формы (grid) и ширинами колонок таблицы.
|
||||
|
||||
**Изменения**: documents/forms.py (CustomerOrderForm, SupplierOrderForm, CustomerOrderItemForm, SupplierOrderItemForm, виджеты), documents/order_form.html и supplier_order_form.html (компактная разметка по полям), base.html (подключение theme-compact.css), новый theme-compact.css.
|
||||
|
||||
---
|
||||
|
||||
## 2025-02-25 21:00 UTC – Принудительное применение темы (кэш, шрифт, кнопки)
|
||||
|
||||
**Проблема**: На скриншоте стили не применялись: кнопка бирюзовая вместо синей (#34AFE3), шрифт Geologica не отображался.
|
||||
|
||||
**Решение**:
|
||||
- К ссылке theme.css добавлен параметр ?v=4 для сброса кэша браузера и прокси.
|
||||
- Для кнопки .btn-ws-primary заданы явные цвета #34AFE3 и #00868F и усилена специфичность селекторов (body .btn.btn-ws-primary).
|
||||
- На html и body задан font-family Geologica; для потомков — font-family: inherit, чтобы шрифт применялся ко всей странице.
|
||||
|
||||
**Изменения**: base.html (theme.css?v=4), theme.css (коммент v4, кнопки по HEX, наследование шрифта).
|
||||
|
||||
---
|
||||
|
||||
## 2025-02-25 20:45 UTC – Логотип убран; дизайн строго по брендбуку
|
||||
|
||||
**Проблема**: Логотип в шапке был вставлен некорректно; визуально тема не отличалась от дефолтной — цвета и шрифты не применялись.
|
||||
|
||||
@@ -11,9 +11,29 @@ from .models import (
|
||||
)
|
||||
from django.forms import inlineformset_factory
|
||||
|
||||
|
||||
class CustomerOrderItemForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = CustomerOrderItem
|
||||
fields = ("product", "price", "currency", "quantity")
|
||||
widgets = {
|
||||
"quantity": forms.NumberInput(attrs={"size": 3, "min": 0, "max": 99, "style": "width: 4ch"}),
|
||||
}
|
||||
|
||||
|
||||
class SupplierOrderItemForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SupplierOrderItem
|
||||
fields = ("product", "price", "currency", "quantity")
|
||||
widgets = {
|
||||
"quantity": forms.NumberInput(attrs={"size": 3, "min": 0, "max": 99, "style": "width: 4ch"}),
|
||||
}
|
||||
|
||||
|
||||
CustomerOrderItemFormSet = inlineformset_factory(
|
||||
CustomerOrder,
|
||||
CustomerOrderItem,
|
||||
form=CustomerOrderItemForm,
|
||||
fields=("product", "price", "currency", "quantity"),
|
||||
extra=1,
|
||||
can_delete=True,
|
||||
@@ -22,6 +42,7 @@ CustomerOrderItemFormSet = inlineformset_factory(
|
||||
SupplierOrderItemFormSet = inlineformset_factory(
|
||||
SupplierOrder,
|
||||
SupplierOrderItem,
|
||||
form=SupplierOrderItemForm,
|
||||
fields=("product", "price", "currency", "quantity"),
|
||||
extra=1,
|
||||
can_delete=True,
|
||||
@@ -32,12 +53,20 @@ class CustomerOrderForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = CustomerOrder
|
||||
fields = ("date", "number", "order_kind", "organization", "client", "author")
|
||||
widgets = {
|
||||
"date": forms.DateInput(attrs={"size": 10}),
|
||||
"number": forms.TextInput(attrs={"size": 15, "maxlength": 15}),
|
||||
}
|
||||
|
||||
|
||||
class SupplierOrderForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SupplierOrder
|
||||
fields = ("date", "number", "organization", "supplier", "currency", "rate", "author")
|
||||
widgets = {
|
||||
"date": forms.DateInput(attrs={"size": 10}),
|
||||
"number": forms.TextInput(attrs={"size": 15, "maxlength": 15}),
|
||||
}
|
||||
|
||||
|
||||
class CashInflowForm(forms.ModelForm):
|
||||
|
||||
47
app/static/css/theme-compact.css
Normal file
47
app/static/css/theme-compact.css
Normal file
@@ -0,0 +1,47 @@
|
||||
/* Компактная раскладка форм документов */
|
||||
.ws-form-compact .ws-form-row {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.ws-form-compact .ws-form-row-date-number {
|
||||
grid-template-columns: 10ch 15ch;
|
||||
}
|
||||
|
||||
.ws-form-compact .ws-form-row-date-number .ws-form-group input {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ws-form-compact .ws-form-row-2 {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.ws-form-compact .ws-form-row-2 .ws-form-group input,
|
||||
.ws-form-compact .ws-form-row-2 .ws-form-group select {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Таблица товаров: колонка Товар шире, Количество уже */
|
||||
.ws-table-items .ws-col-product {
|
||||
width: 35%;
|
||||
min-width: 14rem;
|
||||
}
|
||||
|
||||
.ws-table-items .ws-col-qty {
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.ws-table-items td.ws-col-qty input,
|
||||
.ws-table-items .ws-col-qty input {
|
||||
width: 4ch !important;
|
||||
max-width: 5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ws-table-items .ws-col-del {
|
||||
width: 4rem;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* ERP WaterSurf — только цвета и шрифты из брендбука */
|
||||
/* ERP WaterSurf — тема v4 (только цвета и шрифты из брендбука) */
|
||||
|
||||
/* Основные цвета бренда (базовые): White, Gray 01–04, Black */
|
||||
:root {
|
||||
@@ -37,6 +37,12 @@
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
background: var(--ws-bg-page) !important;
|
||||
font-family: var(--ws-font) !important;
|
||||
}
|
||||
|
||||
body,
|
||||
body * {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -230,10 +236,12 @@ body {
|
||||
color: var(--ws-danger-dark) !important;
|
||||
}
|
||||
|
||||
/* Кнопки — акцент только из дополнительных (Blue 02) */
|
||||
.btn-ws-primary {
|
||||
background: var(--ws-accent) !important;
|
||||
color: var(--ws-black) !important;
|
||||
/* Кнопки — акцент только из дополнительных (Blue 02), высокая специфичность */
|
||||
.btn-ws-primary,
|
||||
body .btn.btn-ws-primary,
|
||||
a.btn.btn-ws-primary {
|
||||
background: #34AFE3 !important;
|
||||
color: #0A121D !important;
|
||||
border: none !important;
|
||||
border-radius: var(--ws-radius-sm);
|
||||
padding: 0.5rem 1rem;
|
||||
@@ -243,8 +251,10 @@ body {
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.btn-ws-primary:hover {
|
||||
background: var(--ws-accent-hover) !important;
|
||||
.btn-ws-primary:hover,
|
||||
body .btn.btn-ws-primary:hover,
|
||||
a.btn.btn-ws-primary:hover {
|
||||
background: #00868F !important;
|
||||
color: var(--ws-white) !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geologica:wght@300;500;700&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="{% static 'css/theme.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/theme.css' %}?v=4" rel="stylesheet">
|
||||
<link href="{% static 'css/theme-compact.css' %}?v=1" rel="stylesheet">
|
||||
{% block extra_css %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -3,20 +3,57 @@
|
||||
{% block content %}
|
||||
<div class="ws-card">
|
||||
<h2 class="ws-page-title">{% if object %}Редактировать{% else %}Создать{% endif %} {{ title }}</h2>
|
||||
<form method="post" class="ws-form-card">
|
||||
<form method="post" class="ws-form-card ws-form-compact">
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
{% if field.errors %}<small class="ws-text-danger">{{ field.errors.0 }}</small>{% endif %}
|
||||
<div class="ws-form-row ws-form-row-date-number">
|
||||
<div class="ws-form-group ws-field-date">
|
||||
<label for="{{ form.date.id_for_label }}">{{ form.date.label }}</label>
|
||||
{{ form.date }}
|
||||
{% if form.date.errors %}<small class="ws-text-danger">{{ form.date.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group ws-field-number">
|
||||
<label for="{{ form.number.id_for_label }}">{{ form.number.label }}</label>
|
||||
{{ form.number }}
|
||||
{% if form.number.errors %}<small class="ws-text-danger">{{ form.number.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-row ws-form-row-2">
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.order_kind.id_for_label }}">{{ form.order_kind.label }}</label>
|
||||
{{ form.order_kind }}
|
||||
{% if form.order_kind.errors %}<small class="ws-text-danger">{{ form.order_kind.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.organization.id_for_label }}">{{ form.organization.label }}</label>
|
||||
{{ form.organization }}
|
||||
{% if form.organization.errors %}<small class="ws-text-danger">{{ form.organization.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-row ws-form-row-2">
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.client.id_for_label }}">{{ form.client.label }}</label>
|
||||
{{ form.client }}
|
||||
{% if form.client.errors %}<small class="ws-text-danger">{{ form.client.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.author.id_for_label }}">{{ form.author.label }}</label>
|
||||
{{ form.author }}
|
||||
{% if form.author.errors %}<small class="ws-text-danger">{{ form.author.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="ws-form-section">
|
||||
<h3 class="ws-form-section-title">Товары</h3>
|
||||
{{ formset.management_form }}
|
||||
<div class="ws-table-wrap">
|
||||
<table class="ws-table" id="order-items">
|
||||
<table class="ws-table ws-table-items" id="order-items">
|
||||
<colgroup>
|
||||
<col class="ws-col-product">
|
||||
<col>
|
||||
<col>
|
||||
<col class="ws-col-qty">
|
||||
<col>
|
||||
<col class="ws-col-del">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Товар</th>
|
||||
@@ -33,7 +70,7 @@
|
||||
<td>{{ f.id }}{{ f.product }}</td>
|
||||
<td>{{ f.price }}</td>
|
||||
<td>{{ f.currency }}</td>
|
||||
<td>{{ f.quantity }}</td>
|
||||
<td class="ws-col-qty">{{ f.quantity }}</td>
|
||||
<td class="row-amount ws-num">—</td>
|
||||
<td>{% if f.DELETE %}{{ f.DELETE }}{% endif %}</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,20 +3,64 @@
|
||||
{% block content %}
|
||||
<div class="ws-card">
|
||||
<h2 class="ws-page-title">{% if object %}Редактировать{% else %}Создать{% endif %} {{ title }}</h2>
|
||||
<form method="post" class="ws-form-card">
|
||||
<form method="post" class="ws-form-card ws-form-compact">
|
||||
{% csrf_token %}
|
||||
{% for field in form %}
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
{% if field.errors %}<small class="ws-text-danger">{{ field.errors.0 }}</small>{% endif %}
|
||||
<div class="ws-form-row ws-form-row-date-number">
|
||||
<div class="ws-form-group ws-field-date">
|
||||
<label for="{{ form.date.id_for_label }}">{{ form.date.label }}</label>
|
||||
{{ form.date }}
|
||||
{% if form.date.errors %}<small class="ws-text-danger">{{ form.date.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group ws-field-number">
|
||||
<label for="{{ form.number.id_for_label }}">{{ form.number.label }}</label>
|
||||
{{ form.number }}
|
||||
{% if form.number.errors %}<small class="ws-text-danger">{{ form.number.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-row ws-form-row-2">
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.organization.id_for_label }}">{{ form.organization.label }}</label>
|
||||
{{ form.organization }}
|
||||
{% if form.organization.errors %}<small class="ws-text-danger">{{ form.organization.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.supplier.id_for_label }}">{{ form.supplier.label }}</label>
|
||||
{{ form.supplier }}
|
||||
{% if form.supplier.errors %}<small class="ws-text-danger">{{ form.supplier.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-row ws-form-row-2">
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.currency.id_for_label }}">{{ form.currency.label }}</label>
|
||||
{{ form.currency }}
|
||||
{% if form.currency.errors %}<small class="ws-text-danger">{{ form.currency.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.rate.id_for_label }}">{{ form.rate.label }}</label>
|
||||
{{ form.rate }}
|
||||
{% if form.rate.errors %}<small class="ws-text-danger">{{ form.rate.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-row ws-form-row-2">
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.author.id_for_label }}">{{ form.author.label }}</label>
|
||||
{{ form.author }}
|
||||
{% if form.author.errors %}<small class="ws-text-danger">{{ form.author.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="ws-form-section">
|
||||
<h3 class="ws-form-section-title">Товары</h3>
|
||||
{{ formset.management_form }}
|
||||
<div class="ws-table-wrap">
|
||||
<table class="ws-table" id="supplier-order-items">
|
||||
<table class="ws-table ws-table-items" id="supplier-order-items">
|
||||
<colgroup>
|
||||
<col class="ws-col-product">
|
||||
<col>
|
||||
<col>
|
||||
<col class="ws-col-qty">
|
||||
<col>
|
||||
<col class="ws-col-del">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Товар</th>
|
||||
@@ -33,7 +77,7 @@
|
||||
<td>{{ f.id }}{{ f.product }}</td>
|
||||
<td>{{ f.price }}</td>
|
||||
<td>{{ f.currency }}</td>
|
||||
<td>{{ f.quantity }}</td>
|
||||
<td class="ws-col-qty">{{ f.quantity }}</td>
|
||||
<td class="row-amount ws-num">—</td>
|
||||
<td>{% if f.DELETE %}{{ f.DELETE }}{% endif %}</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user