From 5d6b894ca686bd971063f198da4aa55d4769ea70 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Tue, 6 Jan 2026 14:10:37 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20=D1=81?= =?UTF-8?q?=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B2=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=B0=D1=82=D0=B8=D0=B2=D0=BD=D1=8B=D1=85=20=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=80=D0=BE=D0=B2=20=D0=B8=20=D0=B3=D1=80=D1=83?= =?UTF-8?q?=D0=BF=D0=BF=20=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BD=D0=B0=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=86=D1=8B=20/products/all/=20=D0=B8=20/products/catalog/.=20?= =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=20=D1=82=D0=B0=D0=B1?= =?UTF-8?q?=D0=BB=D0=B8=D1=87=D0=BD=D1=8B=D0=B9=20=D1=80=D0=B5=D0=B6=D0=B8?= =?UTF-8?q?=D0=BC=20=D0=BA=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3=D0=B0=20?= =?UTF-8?q?=D1=81=20=D1=84=D0=B8=D0=BA=D1=81=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D0=BE=D0=B9=20=D1=81=D0=B5=D1=82=D0=BA=D0=BE=D0=B9?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BB=D0=BE=D0=BD=D0=BE=D0=BA,=20=D0=B4=D0=B2?= =?UTF-8?q?=D1=83=D1=85=D1=81=D1=82=D1=80=D0=BE=D1=87=D0=BD=D1=8B=D0=BC?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=D0=BC?= =?UTF-8?q?=D0=B8=20=D0=B8=20=D0=B2=D1=8B=D1=80=D0=B0=D0=B2=D0=BD=D0=B8?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BF=D0=BE=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=D0=B9=20=D1=88=D0=B8=D1=80=D0=B8=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../products/templates/products/catalog.html | 149 +++++++++++------- myproject/products/views/catalog_views.py | 38 +++++ myproject/products/views/product_views.py | 16 ++ 3 files changed, 142 insertions(+), 61 deletions(-) diff --git a/myproject/products/templates/products/catalog.html b/myproject/products/templates/products/catalog.html index aa0f05f..4a09008 100644 --- a/myproject/products/templates/products/catalog.html +++ b/myproject/products/templates/products/catalog.html @@ -69,7 +69,7 @@ font-size: 0.65rem; padding: 0.15rem 0.35rem; } - /* Режим списка */ + /* Режим списка - табличная структура с фиксированными колонками */ .catalog-list.row { gap: 1px !important; } @@ -79,19 +79,22 @@ padding: 0 !important; } .catalog-list .catalog-item .card { - flex-direction: row; - align-items: stretch; + display: grid; + grid-template-columns: 50px 1fr 150px 120px 120px; + align-items: center; padding: 0; border-radius: 0.25rem; overflow: hidden; + min-height: 50px; } .catalog-list .catalog-item .card .position-relative { - flex-shrink: 0; + height: 50px; + width: 50px; + align-self: start; } .catalog-list .catalog-item .card .position-relative img, .catalog-list .catalog-item .card .position-relative > div { - height: 100% !important; - min-height: 36px; + height: 50px; width: 50px; border-radius: 0; object-fit: cover; @@ -100,20 +103,40 @@ display: none; } .catalog-list .catalog-item .card-body { - flex-grow: 1; - display: flex; - align-items: center; - padding: 0 0.5rem !important; - gap: 0.75rem; + display: contents; } - .catalog-list .catalog-item .card-body > div:first-child { - flex-grow: 1; + /* Название товара - ограничиваем 2 строками */ + .catalog-list .catalog-item .product-name { + padding: 0.4rem 0.5rem; + line-height: 1.3; + max-height: 3.4em; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + font-size: 0.85rem; + align-self: center; } - .catalog-list .catalog-item .card-body > div:last-child { - display: flex; - align-items: center; - gap: 0.75rem; - white-space: nowrap; + /* Остатки */ + .catalog-list .catalog-item .product-stock { + padding: 0.4rem 0.25rem; + text-align: left; + font-size: 0.8rem; + align-self: center; + } + /* Цена */ + .catalog-list .catalog-item .product-price { + padding: 0.4rem 0.25rem; + text-align: left; + font-size: 0.85rem; + align-self: center; + } + /* Артикул */ + .catalog-list .catalog-item .product-sku { + padding: 0.4rem 0.5rem 0.4rem 0.25rem; + text-align: left; + font-size: 0.8rem; + align-self: center; } .catalog-list .catalog-item .card-body .mt-1 { margin-top: 0 !important; @@ -239,6 +262,20 @@
+ + {% if action_buttons %} +
+ +
+ {% endif %} +
Товары и комплекты @@ -260,6 +297,7 @@ {% for item in items %}
+
{% if item.cached_main_photo %} {{ item.name }} @@ -272,8 +310,10 @@ {% if item.item_type == 'kit' %}К{% else %}Т{% endif %}
+
-
+ +
{% if item.item_type == 'kit' %} {{ item.name }} {% else %} @@ -281,72 +321,59 @@ {% endif %}
- {% if item.item_type == 'product' %} - {# Информация об остатках для товаров #} -
- - - {{ item.total_free|floatformat:"-3" }} свободно - / {{ item.total_available|floatformat:"-3" }} всего - -
- {% elif item.item_type == 'kit' %} - {# Информация об остатках для комплектов #} -
- - - {{ item.total_free|floatformat:"0" }} компл. доступно - -
- {% endif %} - -
+ +
{% if item.item_type == 'product' %} -
+ + + {{ item.total_free|floatformat:"-3" }} + / {{ item.total_available|floatformat:"-3" }} + + {% elif item.item_type == 'kit' %} + + + {{ item.total_free|floatformat:"0" }} компл. + + {% endif %} +
+ + +
+ {% if item.item_type == 'product' %} +
{% if item.sale_price %} - {# Скидочная цена #} - {{ item.sale_price|floatformat:2 }} руб. + title="Скидочная цена"> + {{ item.sale_price|floatformat:2 }} - {# Обычная цена зачеркнутая #} +
- {{ item.price|floatformat:2 }} руб. + title="Обычная цена"> + {{ item.price|floatformat:2 }} - {# Кнопка удаления скидки #} - {% else %} - {# Только обычная цена #} + title="Цена"> {{ item.price|floatformat:2 }} руб. - {# Кнопка добавления скидки #} - {% endif %}
{% else %} - {# ProductKit - не редактируется #} {{ item.actual_price|floatformat:2 }} руб. {% endif %} +
+ + +
{{ item.sku }}
diff --git a/myproject/products/views/catalog_views.py b/myproject/products/views/catalog_views.py index bb064c2..d66639d 100644 --- a/myproject/products/views/catalog_views.py +++ b/myproject/products/views/catalog_views.py @@ -6,6 +6,7 @@ from django.views.generic import ListView from django.db.models import Prefetch, Sum, Value, DecimalField, Q from django.db.models.functions import Coalesce from django.core.paginator import Paginator +from django.urls import reverse_lazy from ..models import Product, ProductKit, ProductCategory, ProductPhoto, ProductKitPhoto, KitItem @@ -108,4 +109,41 @@ class CatalogView(LoginRequiredMixin, ListView): category_tree = self.build_category_tree(categories, parent=None) context['category_tree'] = category_tree + # Кнопки действий + action_buttons = [] + + if self.request.user.has_perm('products.add_product'): + action_buttons.append({ + 'url': reverse_lazy('products:product-create'), + 'text': 'Создать товар', + 'class': 'btn-primary', + 'icon': 'plus-circle' + }) + + if self.request.user.has_perm('products.add_productkit'): + action_buttons.append({ + 'url': reverse_lazy('products:productkit-create'), + 'text': 'Создать комплект', + 'class': 'btn-outline-primary', + 'icon': 'box-seam' + }) + + if self.request.user.has_perm('products.add_configurableproduct'): + action_buttons.append({ + 'url': reverse_lazy('products:configurableproduct-create'), + 'text': 'Создать вариативный товар', + 'class': 'btn-outline-success', + 'icon': 'grid-3x3-gap' + }) + + if self.request.user.has_perm('products.add_productvariantgroup'): + action_buttons.append({ + 'url': reverse_lazy('products:variantgroup-create'), + 'text': 'Создать группу вариантов', + 'class': 'btn-outline-info', + 'icon': 'collection' + }) + + context['action_buttons'] = action_buttons + return context diff --git a/myproject/products/views/product_views.py b/myproject/products/views/product_views.py index 3588f6e..ab3ae01 100644 --- a/myproject/products/views/product_views.py +++ b/myproject/products/views/product_views.py @@ -402,6 +402,22 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis 'icon': 'box-seam' }) + if self.request.user.has_perm('products.add_configurableproduct'): + action_buttons.append({ + 'url': reverse_lazy('products:configurableproduct-create'), + 'text': 'Создать вариативный товар', + 'class': 'btn-outline-success', + 'icon': 'grid-3x3-gap' + }) + + if self.request.user.has_perm('products.add_productvariantgroup'): + action_buttons.append({ + 'url': reverse_lazy('products:variantgroup-create'), + 'text': 'Создать группу вариантов', + 'class': 'btn-outline-info', + 'icon': 'collection' + }) + context['action_buttons'] = action_buttons return context