feat(pos): глобальный поиск товаров независимо от категории
- При поиске (3+ символа) ищет по всем товарам и комплектам, игнорируя выбранную категорию - Добавлена визуальная индикация: кнопка "Все товары" подсвечивается при активном поиске - При очистке поиска возвращается к товарам выбранной категории - Витринные комплекты не участвуют в глобальном поиске Изменения: - terminal.js: loadItems(), updateSearchIndicator(), обработчики поиска - views.py: get_items_api() - игнорирование category_id при search_query
This commit is contained in:
@@ -772,6 +772,8 @@ function renderCategories() {
|
|||||||
showcaseCard.onclick = async () => {
|
showcaseCard.onclick = async () => {
|
||||||
isShowcaseView = true;
|
isShowcaseView = true;
|
||||||
currentCategoryId = null;
|
currentCategoryId = null;
|
||||||
|
currentSearchQuery = ''; // Сбрасываем поиск
|
||||||
|
document.getElementById('searchInput').value = ''; // Очищаем поле поиска
|
||||||
await refreshShowcaseKits(); // Загружаем свежие данные
|
await refreshShowcaseKits(); // Загружаем свежие данные
|
||||||
renderCategories();
|
renderCategories();
|
||||||
renderProducts();
|
renderProducts();
|
||||||
@@ -791,6 +793,7 @@ function renderCategories() {
|
|||||||
allCol.className = 'col-6 col-custom-3 col-md-3 col-lg-2';
|
allCol.className = 'col-6 col-custom-3 col-md-3 col-lg-2';
|
||||||
const allCard = document.createElement('div');
|
const allCard = document.createElement('div');
|
||||||
allCard.className = 'card category-card' + (currentCategoryId === null && !isShowcaseView ? ' active' : '');
|
allCard.className = 'card category-card' + (currentCategoryId === null && !isShowcaseView ? ' active' : '');
|
||||||
|
allCard.dataset.categoryId = 'all'; // Для идентификации в updateSearchIndicator
|
||||||
allCard.onclick = async () => {
|
allCard.onclick = async () => {
|
||||||
currentCategoryId = null;
|
currentCategoryId = null;
|
||||||
isShowcaseView = false;
|
isShowcaseView = false;
|
||||||
@@ -1157,7 +1160,8 @@ async function loadItems(append = false) {
|
|||||||
page_size: 60
|
page_size: 60
|
||||||
});
|
});
|
||||||
|
|
||||||
if (currentCategoryId) {
|
// При активном поиске игнорируем категорию - ищем по всем товарам
|
||||||
|
if (currentCategoryId && !currentSearchQuery) {
|
||||||
params.append('category_id', currentCategoryId);
|
params.append('category_id', currentCategoryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1215,6 +1219,34 @@ function setupInfiniteScroll() {
|
|||||||
observer.observe(sentinel);
|
observer.observe(sentinel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== ВИЗУАЛЬНАЯ ИНДИКАЦИЯ ГЛОБАЛЬНОГО ПОИСКА =====
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обновляет визуальную индикацию глобального поиска.
|
||||||
|
* При активном поиске подсвечивает кнопку "Все товары".
|
||||||
|
*/
|
||||||
|
function updateSearchIndicator() {
|
||||||
|
const allCard = document.querySelector('.category-card[data-category-id="all"]');
|
||||||
|
if (!allCard) return;
|
||||||
|
|
||||||
|
if (currentSearchQuery && currentSearchQuery.length >= 3) {
|
||||||
|
// Активен глобальный поиск - подсвечиваем "Все товары"
|
||||||
|
allCard.classList.add('active');
|
||||||
|
allCard.style.backgroundColor = '#e3f2fd'; // Светло-голубой фон
|
||||||
|
allCard.style.borderColor = '#2196f3'; // Синяя рамка
|
||||||
|
allCard.title = 'Идёт поиск по всем товарам';
|
||||||
|
} else {
|
||||||
|
// Поиск неактивен - возвращаем обычный стиль
|
||||||
|
allCard.style.backgroundColor = '';
|
||||||
|
allCard.style.borderColor = '';
|
||||||
|
allCard.title = '';
|
||||||
|
// Активный класс управляется renderCategories
|
||||||
|
if (currentCategoryId !== null) {
|
||||||
|
allCard.classList.remove('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function addToCart(item) {
|
async function addToCart(item) {
|
||||||
// ПРОВЕРКА НА НАЛИЧИЕ ЕДИНИЦ ПРОДАЖИ
|
// ПРОВЕРКА НА НАЛИЧИЕ ЕДИНИЦ ПРОДАЖИ
|
||||||
// Если у товара одна единица продажи - добавляем сразу
|
// Если у товара одна единица продажи - добавляем сразу
|
||||||
@@ -3815,11 +3847,14 @@ searchInput.addEventListener('input', (e) => {
|
|||||||
clearTimeout(searchDebounceTimer);
|
clearTimeout(searchDebounceTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если поле пустое — очищаем экран
|
// Если поле пустое — очищаем поиск и возвращаемся к выбранной категории
|
||||||
if (query === '') {
|
if (query === '') {
|
||||||
currentSearchQuery = '';
|
currentSearchQuery = '';
|
||||||
ITEMS = []; // Очистка
|
updateSearchIndicator(); // Обновляем индикацию
|
||||||
renderProducts(); // Пустой экран
|
// Возвращаем товары выбранной категории
|
||||||
|
if (!isShowcaseView) {
|
||||||
|
loadItems();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3829,7 +3864,7 @@ searchInput.addEventListener('input', (e) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Для витрины — мгновенная клиентская фильтрация
|
// Для витрины — мгновенная клиентская фильтрация (витрина не участвует в глобальном поиске)
|
||||||
if (isShowcaseView) {
|
if (isShowcaseView) {
|
||||||
renderProducts();
|
renderProducts();
|
||||||
return;
|
return;
|
||||||
@@ -3838,7 +3873,8 @@ searchInput.addEventListener('input', (e) => {
|
|||||||
// Для обычных товаров/комплектов — серверный поиск с debounce 300мс
|
// Для обычных товаров/комплектов — серверный поиск с debounce 300мс
|
||||||
searchDebounceTimer = setTimeout(async () => {
|
searchDebounceTimer = setTimeout(async () => {
|
||||||
currentSearchQuery = query;
|
currentSearchQuery = query;
|
||||||
await loadItems(); // Перезагрузка с серверным поиском
|
updateSearchIndicator(); // Обновляем визуальную индикацию
|
||||||
|
await loadItems(); // Перезагрузка с серверным поиском (по всем категориям)
|
||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3855,8 +3891,13 @@ clearSearchBtn.addEventListener('click', () => {
|
|||||||
searchInput.value = '';
|
searchInput.value = '';
|
||||||
clearSearchBtn.style.display = 'none';
|
clearSearchBtn.style.display = 'none';
|
||||||
currentSearchQuery = '';
|
currentSearchQuery = '';
|
||||||
ITEMS = [];
|
updateSearchIndicator(); // Обновляем индикацию
|
||||||
renderProducts(); // Пустой экран
|
// Возвращаем товары выбранной категории
|
||||||
|
if (!isShowcaseView) {
|
||||||
|
loadItems();
|
||||||
|
} else {
|
||||||
|
renderProducts(); // Для витрины - просто перерисовываем
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
|
|||||||
@@ -839,8 +839,9 @@ def get_items_api(request):
|
|||||||
'sales_units' # Загружаем единицы продажи для POS
|
'sales_units' # Загружаем единицы продажи для POS
|
||||||
)
|
)
|
||||||
|
|
||||||
# Фильтруем по категории, если указана
|
# Фильтруем по категории, если указана И нет поискового запроса
|
||||||
if category_id:
|
# При поиске игнорируем категорию - ищем по всем товарам
|
||||||
|
if category_id and not search_query:
|
||||||
products_qs = products_qs.filter(categories__id=category_id)
|
products_qs = products_qs.filter(categories__id=category_id)
|
||||||
|
|
||||||
# Фильтруем по поисковому запросу (name или sku) - разбиваем на токены
|
# Фильтруем по поисковому запросу (name или sku) - разбиваем на токены
|
||||||
@@ -931,8 +932,9 @@ def get_items_api(request):
|
|||||||
first_kit_photo
|
first_kit_photo
|
||||||
)
|
)
|
||||||
|
|
||||||
# Фильтруем комплекты по категории, если указана
|
# Фильтруем комплекты по категории, если указана И нет поискового запроса
|
||||||
if category_id:
|
# При поиске игнорируем категорию - ищем по всем комплектам
|
||||||
|
if category_id and not search_query:
|
||||||
kits_qs = kits_qs.filter(categories__id=category_id)
|
kits_qs = kits_qs.filter(categories__id=category_id)
|
||||||
|
|
||||||
# Фильтруем комплекты по поисковому запросу (name или sku) - разбиваем на токены
|
# Фильтруем комплекты по поисковому запросу (name или sku) - разбиваем на токены
|
||||||
|
|||||||
Reference in New Issue
Block a user