Feat: Add inline price editing for products in catalog

Implemented inline editing functionality for product prices directly in the catalog view with support for both regular and sale prices.

Features:
- Click-to-edit price fields with visual hover indicators
- Separate editing for price and sale_price fields
- Add/remove sale price with validation
- Real-time UI updates without page reload
- Permission-based access control
- Server-side validation for price constraints

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-25 01:23:46 +03:00
parent 0f212bda69
commit 22bf7e137d
4 changed files with 465 additions and 1 deletions

View File

@@ -140,6 +140,56 @@
opacity: 1 !important;
color: #198754;
}
/* Редактируемые цены */
.editable-price {
cursor: pointer;
padding: 2px 4px;
border-radius: 3px;
transition: background-color 0.15s, border-color 0.15s;
border: 1px solid transparent;
}
.editable-price:hover {
background-color: #f8f9fa;
border: 1px dashed #dee2e6;
}
.editable-price.sale-price:hover {
background-color: #d1f4e0;
border-color: #28a745;
}
.editable-price.regular-price:hover {
background-color: #e7f1ff;
border-color: #0d6efd;
}
.price-edit-input {
width: 90px;
font-size: 0.85rem;
padding: 2px 6px;
border: 2px solid #0d6efd;
border-radius: 3px;
text-align: right;
}
.price-edit-input:focus {
outline: none;
border-color: #0a58ca;
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
}
.remove-sale-price {
opacity: 0;
transition: opacity 0.2s;
}
.price-edit-container:hover .remove-sale-price {
opacity: 0.5;
}
.remove-sale-price:hover {
opacity: 1 !important;
}
.add-sale-price {
opacity: 0;
transition: opacity 0.2s;
}
.price-edit-container:hover .add-sale-price {
opacity: 1;
}
</style>
{% endblock %}
@@ -217,7 +267,52 @@
{% endif %}
</div>
<div class="d-flex justify-content-between align-items-center mt-1">
<span class="fw-bold text-primary small">{{ item.actual_price|floatformat:0 }} руб.</span>
{% if item.item_type == 'product' %}
<div class="price-edit-container d-flex align-items-center gap-1 flex-wrap">
{% if item.sale_price %}
{# Скидочная цена #}
<span class="editable-price sale-price fw-bold text-success small"
data-product-id="{{ item.pk }}"
data-field="sale_price"
data-current-value="{{ item.sale_price }}"
title="Скидочная цена (клик для редактирования)">
{{ item.sale_price|floatformat:2 }} руб.
</span>
{# Обычная цена зачеркнутая #}
<span class="editable-price regular-price text-muted text-decoration-line-through small"
data-product-id="{{ item.pk }}"
data-field="price"
data-current-value="{{ item.price }}"
title="Обычная цена (клик для редактирования)">
{{ item.price|floatformat:2 }} руб.
</span>
{# Кнопка удаления скидки #}
<i class="bi bi-x-circle text-danger remove-sale-price"
data-product-id="{{ item.pk }}"
title="Убрать скидку"
style="cursor: pointer; font-size: 0.85rem;"></i>
{% else %}
{# Только обычная цена #}
<span class="editable-price fw-bold text-primary small"
data-product-id="{{ item.pk }}"
data-field="price"
data-current-value="{{ item.price }}"
title="Цена (клик для редактирования)">
{{ item.price|floatformat:2 }} руб.
</span>
{# Кнопка добавления скидки #}
<button class="btn btn-outline-secondary btn-sm add-sale-price py-0 px-1"
data-product-id="{{ item.pk }}"
title="Добавить скидочную цену"
style="font-size: 0.7rem; line-height: 1.2;">
+ скидка
</button>
{% endif %}
</div>
{% else %}
{# ProductKit - не редактируется #}
<span class="fw-bold text-primary small">{{ item.actual_price|floatformat:2 }} руб.</span>
{% endif %}
<small class="text-muted">{{ item.sku }}</small>
</div>
</div>