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