feat: Добавить мобильную адаптацию для POS-терминала
- Добавить фиксированную панель корзины внизу экрана на мобильных - Отображение количества товаров и суммы - Кнопки "Продать" и "Очистить" всегда доступны - Тап на панель открывает корзину как overlay - Фиксировать поиск и категории сверху на мобильных - Поиск всегда виден при скролле - Категории в collapsible-блоке (сворачиваются) - Категории в 3 колонки на мобильных - Улучшить поиск по токенам (разбивает фразу на слова) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -576,3 +576,272 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* На мобильных - такой же вид с текстом */
|
/* На мобильных - такой же вид с текстом */
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
МОБИЛЬНАЯ ПЛАВАЮЩАЯ КОРЗИНА
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
/* Фиксированный бар внизу экрана */
|
||||||
|
.mobile-cart-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: white;
|
||||||
|
border-top: 2px solid #dee2e6;
|
||||||
|
padding: 0.75rem;
|
||||||
|
display: none; /* скрываем на десктопе */
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
z-index: 1000;
|
||||||
|
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Сводка по корзине (кликабельная) */
|
||||||
|
.mobile-cart-summary {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.25rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-summary:hover {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-summary:active {
|
||||||
|
background-color: #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Количество товаров */
|
||||||
|
.mobile-cart-count {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #6c757d;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Итоговая сумма */
|
||||||
|
.mobile-cart-total {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #198754;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Кнопки действий в мобильном баре */
|
||||||
|
.mobile-cart-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-actions .btn {
|
||||||
|
min-height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-actions .btn span {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlay корзины (фон затемнения) */
|
||||||
|
.mobile-cart-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0,0,0,0.5);
|
||||||
|
z-index: 1100;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-overlay.active {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Контент корзины в overlay */
|
||||||
|
.mobile-cart-content {
|
||||||
|
background: white;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 75vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
animation: slideUp 0.3s ease-out;
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
from { transform: translateY(100%); }
|
||||||
|
to { transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Заголовок мобильной корзины */
|
||||||
|
.mobile-cart-header {
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 1px solid #dee2e6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 16px 16px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-header h6 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Тело корзины с прокруткой */
|
||||||
|
.mobile-cart-body {
|
||||||
|
padding: 1rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Копия стилей корзины для мобильного view */
|
||||||
|
.mobile-cart-body .cart-item {
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-cart-body .item-name-price .fw-semibold {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Показываем мобильный бар только на маленьких экранах */
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.mobile-cart-bar {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Скрываем десктопную правую панель на мобильных */
|
||||||
|
.right-panel-fixed {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Добавляем отступы чтобы контент не перекрывался барами */
|
||||||
|
.pos-container {
|
||||||
|
padding-bottom: 80px;
|
||||||
|
padding-top: 70px; /* место для фиксированного поиска */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Фиксируем основной контейнер для работы с позиционированием */
|
||||||
|
.pos-main-container {
|
||||||
|
overflow: visible; /* меняем для работы fixed внутри */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Создаём фиксированный бар поиска на мобильных */
|
||||||
|
.pos-container > .row {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Левая колонка с товарами */
|
||||||
|
.pos-container > .row > .col-12:first-child {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Блок поиска выносим в фиксированный бар */
|
||||||
|
.pos-container > .row > .col-12:first-child > div:first-child,
|
||||||
|
.pos-container > .row > .col-12:first-child > .mb-3:first-child {
|
||||||
|
position: fixed;
|
||||||
|
top: 56px; /* сразу под navbar */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 900;
|
||||||
|
background: white;
|
||||||
|
padding: 0.75rem;
|
||||||
|
margin: 0;
|
||||||
|
border-bottom: 1px solid #dee2e6;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Категории тоже фиксируем под поиском */
|
||||||
|
.pos-container > .row > .col-12:first-child > div:nth-child(2) {
|
||||||
|
position: fixed;
|
||||||
|
top: 115px; /* поиск (56+~55) + категории */
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 899;
|
||||||
|
background: white;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
margin: 0;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Сворачивание категорий на мобильных */
|
||||||
|
.categories-wrapper {
|
||||||
|
margin-bottom: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Кнопка переключения категорий */
|
||||||
|
.categories-toggle {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories-toggle:hover {
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Иконка chevron с поворотом */
|
||||||
|
.categories-toggle .bi-chevron-down {
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories-toggle.collapsed .bi-chevron-down {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Содержимое категорий */
|
||||||
|
.categories-content {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
transition: max-height 0.3s ease, opacity 0.3s ease;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.categories-content.collapsed {
|
||||||
|
max-height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Меньшие карточки категорий на мобильных */
|
||||||
|
.category-card {
|
||||||
|
min-height: 32px !important;
|
||||||
|
padding: 0.25rem 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-card .card-body {
|
||||||
|
padding: 0.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-name {
|
||||||
|
font-size: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Уменьшаем gap между категориями */
|
||||||
|
#categoryGrid {
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Категории в 3 колонки на мобильных */
|
||||||
|
#categoryGrid > div {
|
||||||
|
flex: 0 0 calc(33.333% - 0.33rem);
|
||||||
|
max-width: calc(33.333% - 0.33rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Прокручиваемая область товаров смещаем вниз */
|
||||||
|
.products-scrollable {
|
||||||
|
margin-top: 90px; /* учитываем поиск и категории */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -787,10 +787,12 @@ function renderProducts() {
|
|||||||
// Для витрины — клиентская фильтрация по поиску
|
// Для витрины — клиентская фильтрация по поиску
|
||||||
const searchTerm = document.getElementById('searchInput').value.toLowerCase().trim();
|
const searchTerm = document.getElementById('searchInput').value.toLowerCase().trim();
|
||||||
if (searchTerm) {
|
if (searchTerm) {
|
||||||
|
const tokens = searchTerm.split(/\s+/).filter(t => t.length > 0);
|
||||||
filtered = filtered.filter(item => {
|
filtered = filtered.filter(item => {
|
||||||
const name = (item.name || '').toLowerCase();
|
const name = (item.name || '').toLowerCase();
|
||||||
const sku = (item.sku || '').toLowerCase();
|
const sku = (item.sku || '').toLowerCase();
|
||||||
return name.includes(searchTerm) || sku.includes(searchTerm);
|
// Каждый токен должен совпадать хотя бы с одним словом в name или sku
|
||||||
|
return tokens.every(token => name.includes(token) || sku.includes(token));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1261,6 +1263,7 @@ function renderCart() {
|
|||||||
list.innerHTML = '<p class="text-muted text-center py-4 small">Корзина пуста</p>';
|
list.innerHTML = '<p class="text-muted text-center py-4 small">Корзина пуста</p>';
|
||||||
document.getElementById('cartTotal').textContent = '0.00';
|
document.getElementById('cartTotal').textContent = '0.00';
|
||||||
updateShowcaseButtonState(); // Обновляем состояние кнопки
|
updateShowcaseButtonState(); // Обновляем состояние кнопки
|
||||||
|
updateMobileCartBar(); // Обновляем мобильный бар даже когда корзина пуста
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1423,6 +1426,56 @@ function renderCart() {
|
|||||||
|
|
||||||
// Обновляем состояние кнопки "НА ВИТРИНУ"
|
// Обновляем состояние кнопки "НА ВИТРИНУ"
|
||||||
updateShowcaseButtonState();
|
updateShowcaseButtonState();
|
||||||
|
|
||||||
|
// Обновляем мобильный бар корзины
|
||||||
|
updateMobileCartBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Склонение слов в зависимости от числа
|
||||||
|
* @param {number} number - число
|
||||||
|
* @param {string} one - форма для 1 (товар)
|
||||||
|
* @param {string} two - форма для 2-4 (товара)
|
||||||
|
* @param {string} five - форма для 5+ (товаров)
|
||||||
|
*/
|
||||||
|
function getNoun(number, one, two, five) {
|
||||||
|
const n = Math.abs(number);
|
||||||
|
const n10 = n % 10;
|
||||||
|
const n100 = n % 100;
|
||||||
|
|
||||||
|
if (n100 >= 11 && n100 <= 19) {
|
||||||
|
return five;
|
||||||
|
}
|
||||||
|
if (n10 === 1) {
|
||||||
|
return one;
|
||||||
|
}
|
||||||
|
if (n10 >= 2 && n10 <= 4) {
|
||||||
|
return two;
|
||||||
|
}
|
||||||
|
return five;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обновляет мобильный бар корзины
|
||||||
|
*/
|
||||||
|
function updateMobileCartBar() {
|
||||||
|
const countEl = document.querySelector('.mobile-cart-count');
|
||||||
|
const totalEl = document.querySelector('.mobile-cart-total');
|
||||||
|
|
||||||
|
if (!countEl || !totalEl) return;
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
cart.forEach((item) => {
|
||||||
|
count += item.qty;
|
||||||
|
total += item.qty * item.price;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Округляем количество до целого для отображения
|
||||||
|
const displayCount = Math.round(count);
|
||||||
|
countEl.textContent = `${displayCount} ${getNoun(displayCount, 'товар', 'товара', 'товаров')}`;
|
||||||
|
totalEl.textContent = formatMoney(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeFromCart(cartKey) {
|
async function removeFromCart(cartKey) {
|
||||||
@@ -3260,6 +3313,85 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
document.getElementById('confirmAddUnitToCart').addEventListener('click', () => {
|
document.getElementById('confirmAddUnitToCart').addEventListener('click', () => {
|
||||||
addToCartFromModal();
|
addToCartFromModal();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ===== МОБИЛЬНАЯ КОРЗИНА =====
|
||||||
|
|
||||||
|
// Тап на бар — открываем корзину
|
||||||
|
const mobileCartSummary = document.getElementById('mobileCartSummary');
|
||||||
|
if (mobileCartSummary) {
|
||||||
|
mobileCartSummary.addEventListener('click', () => {
|
||||||
|
const overlay = document.getElementById('mobileCartOverlay');
|
||||||
|
const body = document.getElementById('mobileCartBody');
|
||||||
|
|
||||||
|
// Копируем содержимое корзины
|
||||||
|
if (body && overlay) {
|
||||||
|
const cartList = document.getElementById('cartList');
|
||||||
|
body.innerHTML = cartList ? cartList.innerHTML : '<p class="text-muted text-center py-4">Корзина пуста</p>';
|
||||||
|
overlay.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Кнопка закрытия мобильной корзины
|
||||||
|
const mobileCartClose = document.getElementById('mobileCartClose');
|
||||||
|
if (mobileCartClose) {
|
||||||
|
mobileCartClose.addEventListener('click', () => {
|
||||||
|
const overlay = document.getElementById('mobileCartOverlay');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Закрытие по клику на фон
|
||||||
|
const mobileCartOverlay = document.getElementById('mobileCartOverlay');
|
||||||
|
if (mobileCartOverlay) {
|
||||||
|
mobileCartOverlay.addEventListener('click', (e) => {
|
||||||
|
if (e.target.id === 'mobileCartOverlay') {
|
||||||
|
e.target.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Мобильная кнопка "Продать"
|
||||||
|
const mobileCheckoutBtn = document.getElementById('mobileCheckoutBtn');
|
||||||
|
if (mobileCheckoutBtn) {
|
||||||
|
mobileCheckoutBtn.addEventListener('click', () => {
|
||||||
|
const checkoutBtn = document.getElementById('checkoutNow');
|
||||||
|
if (checkoutBtn) {
|
||||||
|
checkoutBtn.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Мобильная кнопка "Очистить"
|
||||||
|
const mobileClearCartBtn = document.getElementById('mobileClearCartBtn');
|
||||||
|
if (mobileClearCartBtn) {
|
||||||
|
mobileClearCartBtn.addEventListener('click', () => {
|
||||||
|
const clearBtn = document.getElementById('clearCart');
|
||||||
|
if (clearBtn) {
|
||||||
|
clearBtn.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== СВОРАЧИВАНИЕ КАТЕГОРИЙ НА МОБИЛЬНЫХ =====
|
||||||
|
|
||||||
|
const categoriesToggle = document.getElementById('categoriesToggle');
|
||||||
|
const categoriesContent = document.getElementById('categoriesContent');
|
||||||
|
|
||||||
|
if (categoriesToggle && categoriesContent) {
|
||||||
|
categoriesToggle.addEventListener('click', () => {
|
||||||
|
categoriesToggle.classList.toggle('collapsed');
|
||||||
|
categoriesContent.classList.toggle('collapsed');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Автоматически сворачиваем категории на мобильных при загрузке
|
||||||
|
if (window.innerWidth <= 767) {
|
||||||
|
categoriesToggle.classList.add('collapsed');
|
||||||
|
categoriesContent.classList.add('collapsed');
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Смена склада
|
// Смена склада
|
||||||
|
|||||||
@@ -28,8 +28,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Categories -->
|
<!-- Categories -->
|
||||||
<div class="mb-3">
|
<div class="mb-3 categories-wrapper" id="categoriesWrapper">
|
||||||
<div class="row g-3" id="categoryGrid"></div>
|
<button class="categories-toggle w-100 d-flex align-items-center justify-content-between py-2 px-0 bg-transparent border-0" type="button" id="categoriesToggle">
|
||||||
|
<span class="fw-semibold small">Категории</span>
|
||||||
|
<i class="bi bi-chevron-down transition-transform" id="categoriesChevron"></i>
|
||||||
|
</button>
|
||||||
|
<div class="categories-content" id="categoriesContent">
|
||||||
|
<div class="row g-2" id="categoryGrid"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Products Grid (Блок товаров) - Прокручиваемая область -->
|
<!-- Products Grid (Блок товаров) - Прокручиваемая область -->
|
||||||
@@ -123,6 +129,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Мобильная плавающая корзина -->
|
||||||
|
<div class="mobile-cart-bar" id="mobileCartBar">
|
||||||
|
<div class="mobile-cart-summary" id="mobileCartSummary">
|
||||||
|
<span class="mobile-cart-count">0 товаров</span>
|
||||||
|
<span class="mobile-cart-total">0.00 ₽</span>
|
||||||
|
</div>
|
||||||
|
<div class="mobile-cart-actions">
|
||||||
|
<button class="btn btn-success btn-sm" id="mobileCheckoutBtn">
|
||||||
|
<i class="bi bi-check2-circle"></i> <span>Продать</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary btn-sm" id="mobileClearCartBtn" title="Очистить корзину">
|
||||||
|
<i class="bi bi-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Мобильная корзина (overlay) -->
|
||||||
|
<div class="mobile-cart-overlay" id="mobileCartOverlay">
|
||||||
|
<div class="mobile-cart-content">
|
||||||
|
<div class="mobile-cart-header">
|
||||||
|
<h6 class="mb-0">Корзина</h6>
|
||||||
|
<button class="btn-close" id="mobileCartClose"></button>
|
||||||
|
</div>
|
||||||
|
<div class="mobile-cart-body" id="mobileCartBody">
|
||||||
|
<!-- Содержимое корзины динамически -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Modal: Создание временного комплекта на витрину -->
|
<!-- Modal: Создание временного комплекта на витрину -->
|
||||||
<div class="modal fade" id="createTempKitModal" tabindex="-1" aria-labelledby="createTempKitModalLabel" aria-hidden="true">
|
<div class="modal fade" id="createTempKitModal" tabindex="-1" aria-labelledby="createTempKitModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-xl modal-fullscreen-sm-down">
|
<div class="modal-dialog modal-xl modal-fullscreen-sm-down">
|
||||||
|
|||||||
@@ -774,10 +774,13 @@ def get_items_api(request):
|
|||||||
if category_id:
|
if category_id:
|
||||||
products_qs = products_qs.filter(categories__id=category_id)
|
products_qs = products_qs.filter(categories__id=category_id)
|
||||||
|
|
||||||
# Фильтруем по поисковому запросу (name или sku)
|
# Фильтруем по поисковому запросу (name или sku) - разбиваем на токены
|
||||||
if search_query:
|
if search_query:
|
||||||
|
tokens = search_query.split()
|
||||||
|
for token in tokens:
|
||||||
|
if token: # Пропускаем пустые токены
|
||||||
products_qs = products_qs.filter(
|
products_qs = products_qs.filter(
|
||||||
Q(name__icontains=search_query) | Q(sku__icontains=search_query)
|
Q(name__icontains=token) | Q(sku__icontains=token)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Сериализуем товары
|
# Сериализуем товары
|
||||||
@@ -863,10 +866,13 @@ def get_items_api(request):
|
|||||||
if category_id:
|
if category_id:
|
||||||
kits_qs = kits_qs.filter(categories__id=category_id)
|
kits_qs = kits_qs.filter(categories__id=category_id)
|
||||||
|
|
||||||
# Фильтруем комплекты по поисковому запросу (name или sku)
|
# Фильтруем комплекты по поисковому запросу (name или sku) - разбиваем на токены
|
||||||
if search_query:
|
if search_query:
|
||||||
|
tokens = search_query.split()
|
||||||
|
for token in tokens:
|
||||||
|
if token: # Пропускаем пустые токены
|
||||||
kits_qs = kits_qs.filter(
|
kits_qs = kits_qs.filter(
|
||||||
Q(name__icontains=search_query) | Q(sku__icontains=search_query)
|
Q(name__icontains=token) | Q(sku__icontains=token)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Сериализуем комплекты
|
# Сериализуем комплекты
|
||||||
|
|||||||
Reference in New Issue
Block a user