Исправлен поиск товаров в форме массового поступления
Проблема:
- На странице /inventory/incoming/create/ не работал поиск товаров
- Использовался обычный <select> с предзагруженным списком всех товаров
- При большом количестве товаров список был неудобным
- Невозможно было искать товары по названию в реальном времени
Решение:
- Заменён обычный <select> на Select2 с AJAX автокомплитом
- Подключен API endpoint /products/api/search-products-variants/
- Поиск товаров работает в реальном времени (с задержкой 250ms)
- Минимальная длина поиска: 0 символов (можно открыть весь список)
- Поддержка русского языка
- Theme: bootstrap-5 для визуального соответствия
Изменения:
- Удалён предзагруженный список товаров из контекста шаблона
- Добавлена инициализация Select2 для каждой новой строки товара
- При удалении строки вызывается select2('destroy') для очистки
- Исправлена логика восстановления товаров при ошибке валидации
- Используется Option API для программной установки значений
Технические детали:
- jQuery и Select2 уже подключены в base.html
- Не дублируем подключение библиотек
- Используем событие 'change' для Select2 вместо 'input'
- Кэширование AJAX запросов включено
Теперь поиск товаров работает корректно! 🎉
This commit is contained in:
@@ -168,14 +168,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const productsJsonInput = document.getElementById('productsJson');
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
// Список всех доступных товаров (преобразуем QuerySet в JSON)
|
||||
const products = [
|
||||
{% for product in products %}
|
||||
{ id: {{ product.id }}, name: "{{ product.name }}" },
|
||||
{% endfor %}
|
||||
];
|
||||
const productOptions = products.map(p => `<option value="${p.id}">${p.name}</option>`).join('');
|
||||
|
||||
let rowCounter = 0;
|
||||
|
||||
// Добавление новой строки товара
|
||||
@@ -193,8 +185,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
row.innerHTML = `
|
||||
<td>
|
||||
<select class="form-control form-control-sm product-select" data-row-id="${rowId}">
|
||||
<option value="">Выберите товар...</option>
|
||||
${productOptions}
|
||||
<option value="">Начните вводить название товара...</option>
|
||||
</select>
|
||||
<div class="error-message" style="display:none;"></div>
|
||||
</td>
|
||||
@@ -221,15 +212,49 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
productsBody.appendChild(row);
|
||||
|
||||
// Инициализируем Select2 для нового селекта товара
|
||||
const productSelect = row.querySelector('.product-select');
|
||||
$(productSelect).select2({
|
||||
theme: 'bootstrap-5',
|
||||
placeholder: 'Начните вводить название товара...',
|
||||
allowClear: true,
|
||||
width: '100%',
|
||||
language: 'ru',
|
||||
minimumInputLength: 0,
|
||||
ajax: {
|
||||
url: '/products/api/search-products-variants/',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
q: params.term || '',
|
||||
type: 'product',
|
||||
page: params.page || 1
|
||||
};
|
||||
},
|
||||
processResults: function (data) {
|
||||
return {
|
||||
results: data.results,
|
||||
pagination: {
|
||||
more: data.pagination.more
|
||||
}
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
}
|
||||
});
|
||||
|
||||
// Добавляем event listeners для новой строки
|
||||
const quantityInput = row.querySelector('.quantity-input');
|
||||
const priceInput = row.querySelector('.price-input');
|
||||
const removeBtn = row.querySelector('.btn-remove-row');
|
||||
|
||||
$(productSelect).on('change', updateTotals);
|
||||
quantityInput.addEventListener('input', updateTotals);
|
||||
priceInput.addEventListener('input', updateTotals);
|
||||
removeBtn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(productSelect).select2('destroy');
|
||||
row.remove();
|
||||
updateTotals();
|
||||
});
|
||||
@@ -298,15 +323,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// Добавляем восстановленные товары
|
||||
savedProducts.forEach(item => {
|
||||
const product = products.find(p => p.id === item.product_id);
|
||||
if (product) {
|
||||
addProductRow();
|
||||
const lastRow = productsBody.querySelector('tr:last-child');
|
||||
const lastSelect = lastRow.querySelector('.product-select');
|
||||
|
||||
// Создаём option и устанавливаем его в Select2
|
||||
const newOption = new Option(item.product_name || `Товар #${item.product_id}`, item.product_id, true, true);
|
||||
$(lastSelect).append(newOption).trigger('change');
|
||||
|
||||
lastRow.querySelector('.product-select').value = item.product_id;
|
||||
lastRow.querySelector('.quantity-input').value = item.quantity;
|
||||
lastRow.querySelector('.price-input').value = item.cost_price;
|
||||
}
|
||||
});
|
||||
|
||||
// Обновляем итоги
|
||||
|
||||
Reference in New Issue
Block a user