Добавлены кнопки +/- для управления количеством витринных комплектов в корзине

Теперь витринные букеты можно увеличивать и уменьшать по экземплярам:

UI изменения:
- Заменен badge на полноценные кнопки +/- как у обычных товаров
- Поле количества readonly с желтым фоном для визуального отличия
- Кнопки используют тот же дизайн что и для обычных товаров

Функционал увеличения (increaseShowcaseKitQty):
- Блокирует еще один доступный экземпляр через API
- Проверяет наличие свободных букетов на витрине
- Показывает сообщение если нет доступных
- Обновляет showcase_item_ids и qty в корзине

Функционал уменьшения (decreaseShowcaseKitQty):
- Снимает блокировку с последнего экземпляра из списка
- При qty=1 полностью удаляет из корзины
- Обновляет список витрины после изменения

Все операции синхронизируются с сервером и Redis.
This commit is contained in:
2025-12-11 22:10:06 +03:00
parent b396029554
commit 741fdc97a8

View File

@@ -901,14 +901,42 @@ function renderCart() {
qtyControl.className = 'd-flex align-items-center'; qtyControl.className = 'd-flex align-items-center';
qtyControl.style.gap = '2px'; qtyControl.style.gap = '2px';
// СПЕЦИАЛЬНАЯ ЛОГИКА для витринных комплектов (только badge, без кнопок) // СПЕЦИАЛЬНАЯ ЛОГИКА для витринных комплектов
if (isShowcaseKit) { if (isShowcaseKit) {
const badge = document.createElement('span'); // Кнопка минус
badge.className = 'badge bg-warning text-dark'; const minusBtn = document.createElement('button');
badge.textContent = `${item.qty} шт (витрина)`; minusBtn.className = 'btn btn-outline-secondary btn-sm';
badge.style.fontSize = '0.85rem'; minusBtn.innerHTML = '<i class="bi bi-dash-circle" style="font-size: 1.2em;"></i>';
badge.style.padding = '0.5rem 0.75rem'; minusBtn.onclick = async (e) => {
qtyControl.appendChild(badge); e.preventDefault();
await decreaseShowcaseKitQty(cartKey);
};
// Поле количества (только для отображения, readonly)
const qtyInput = document.createElement('input');
qtyInput.type = 'number';
qtyInput.className = 'qty-input form-control form-control-sm';
qtyInput.style.width = '60px';
qtyInput.style.textAlign = 'center';
qtyInput.style.padding = '0.375rem 0.25rem';
qtyInput.value = item.qty;
qtyInput.min = 1;
qtyInput.readOnly = true; // Только чтение - изменяем только через +/-
qtyInput.style.backgroundColor = '#fff3cd'; // Желтый фон как у витринных
// Кнопка плюс
const plusBtn = document.createElement('button');
plusBtn.className = 'btn btn-outline-secondary btn-sm';
plusBtn.innerHTML = '<i class="bi bi-plus-circle" style="font-size: 1.2em;"></i>';
plusBtn.onclick = async (e) => {
e.preventDefault();
await increaseShowcaseKitQty(cartKey);
};
// Собираем контейнер
qtyControl.appendChild(minusBtn);
qtyControl.appendChild(qtyInput);
qtyControl.appendChild(plusBtn);
} else { } else {
// ОБЫЧНАЯ ЛОГИКА для товаров и комплектов // ОБЫЧНАЯ ЛОГИКА для товаров и комплектов
@@ -1029,6 +1057,109 @@ async function removeFromCart(cartKey) {
} }
} }
/**
* Увеличивает количество витринного комплекта в корзине
* Добавляет еще один экземпляр через API (если есть доступные)
*/
async function increaseShowcaseKitQty(cartKey) {
const item = cart.get(cartKey);
if (!item || item.type !== 'showcase_kit') return;
try {
// Пытаемся заблокировать еще 1 экземпляр
const response = await fetch(`/pos/api/showcase-kits/${item.id}/add-to-cart/`, {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
},
body: JSON.stringify({ quantity: 1 })
});
const data = await response.json();
if (!response.ok || !data.success) {
// Нет доступных экземпляров
alert(data.error || 'Нет доступных экземпляров этого букета на витрине');
return;
}
// Успешно заблокировали - обновляем корзину
const lockedItemIds = data.locked_item_ids || [];
item.qty += lockedItemIds.length;
item.showcase_item_ids = [...(item.showcase_item_ids || []), ...lockedItemIds];
renderCart();
saveCartToRedis();
// Обновляем список витрины
if (isShowcaseView) {
await loadShowcaseKits();
}
} catch (error) {
console.error('Ошибка при увеличении количества витринного комплекта:', error);
alert('Ошибка сервера. Попробуйте еще раз.');
}
}
/**
* Уменьшает количество витринного комплекта в корзине
* Снимает блокировку с одного экземпляра (последнего в списке)
*/
async function decreaseShowcaseKitQty(cartKey) {
const item = cart.get(cartKey);
if (!item || item.type !== 'showcase_kit') return;
// Если количество = 1, удаляем полностью
if (item.qty <= 1) {
await removeFromCart(cartKey);
return;
}
try {
// Снимаем блокировку с последнего экземпляра
const showcaseItemIds = item.showcase_item_ids || [];
if (showcaseItemIds.length === 0) {
// Нет ID - просто удаляем
await removeFromCart(cartKey);
return;
}
// Берем последний ID из списка
const itemIdToRelease = showcaseItemIds[showcaseItemIds.length - 1];
const response = await fetch(`/pos/api/showcase-kits/${item.id}/remove-from-cart/`, {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
},
body: JSON.stringify({ showcase_item_ids: [itemIdToRelease] })
});
const data = await response.json();
if (!response.ok) {
console.error('Ошибка при снятии блокировки:', data.error);
}
// Обновляем корзину
item.qty -= 1;
item.showcase_item_ids = showcaseItemIds.filter(id => id !== itemIdToRelease);
renderCart();
saveCartToRedis();
// Обновляем список витрины
if (isShowcaseView) {
await loadShowcaseKits();
}
} catch (error) {
console.error('Ошибка при уменьшении количества витринного комплекта:', error);
alert('Ошибка сервера. Попробуйте еще раз.');
}
}
async function clearCart() { async function clearCart() {
// Сбрасываем все свои блокировки витринных букетов // Сбрасываем все свои блокировки витринных букетов
try { try {