feat: Добавлена функциональность управления заказами и улучшен поиск товаров
Заказы: - Добавлены миграции для исторических записей с полями оплаты и получателя - Расширен admin для заказов с инлайнами товаров/комплектов - Реализованы представления списка, создания, редактирования и удаления заказов - Добавлен шаблон подтверждения удаления заказа - Настроены URL-маршруты для работы с заказами Клиенты: - Добавлена миграция с новыми полями адресов и подтверждений - Обновлена модель клиентов с дополнительными полями - Улучшен admin для работы с клиентами Товары: - Значительно улучшен API поиска товаров с поддержкой фильтрации - Добавлен Select2 виджет для динамического поиска товаров - Создан статический JS файл для интеграции Select2 - Оптимизирована обработка запросов и ответов API Прочее: - Добавлены новые настройки в settings.py - Обновлена навигация в navbar.html - Обновлены URL-маршруты проекта 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
148
myproject/products/static/products/js/select2-product-search.js
Normal file
148
myproject/products/static/products/js/select2-product-search.js
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Select2 Product Search Module
|
||||
* Переиспользуемый модуль для инициализации Select2 с AJAX поиском товаров
|
||||
*/
|
||||
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
// Форматирование результата в выпадающем списке
|
||||
function formatSelectResult(item) {
|
||||
if (item.loading) return item.text;
|
||||
|
||||
// Если это группа (header для товаров/комплектов), просто возвращаем текст
|
||||
if (item.children) {
|
||||
return item.text;
|
||||
}
|
||||
|
||||
var $container = $('<div class="select2-result-item d-flex justify-content-between align-items-center">');
|
||||
|
||||
// Левая часть: иконка + название
|
||||
var $left = $('<div class="d-flex align-items-center">');
|
||||
|
||||
// Добавляем иконку в зависимости от типа
|
||||
if (item.type === 'product') {
|
||||
$left.append($('<span class="me-2">').text('🌹'));
|
||||
} else if (item.type === 'kit') {
|
||||
$left.append($('<span class="me-2">').text('💐'));
|
||||
} else if (item.type === 'variant') {
|
||||
$left.append($('<span class="me-2">').text('🔄'));
|
||||
}
|
||||
|
||||
// Название
|
||||
var $name = $('<span>').text(item.text);
|
||||
$left.append($name);
|
||||
$container.append($left);
|
||||
|
||||
// Правая часть: цена и статус наличия
|
||||
if (item.actual_price || item.price) {
|
||||
var priceText = item.actual_price || item.price;
|
||||
var $price = $('<span class="text-muted small">').text(priceText + ' руб.');
|
||||
$container.append($price);
|
||||
}
|
||||
|
||||
// Индикатор наличия для товаров
|
||||
if (item.type === 'product' && item.in_stock !== undefined) {
|
||||
if (item.in_stock) {
|
||||
$container.append($('<span class="badge bg-success ms-2 small">').text('В наличии'));
|
||||
} else {
|
||||
$container.append($('<span class="badge bg-secondary ms-2 small">').text('Нет'));
|
||||
}
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
// Форматирование выбранного элемента
|
||||
function formatSelectSelection(item) {
|
||||
// Добавляем иконку для выбранного элемента
|
||||
if (item.type === 'product') {
|
||||
return '🌹 ' + item.text;
|
||||
} else if (item.type === 'kit') {
|
||||
return '💐 ' + item.text;
|
||||
} else if (item.type === 'variant') {
|
||||
return '🔄 ' + item.text;
|
||||
}
|
||||
return item.text || item.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Инициализирует Select2 для элемента с AJAX поиском товаров
|
||||
* @param {Element|jQuery} element - DOM элемент или jQuery объект select
|
||||
* @param {string} type - Тип поиска ('product', 'variant', 'kit' или 'all')
|
||||
* @param {string} apiUrl - URL API для поиска
|
||||
* @param {Object} preloadedData - Предзагруженные данные товара
|
||||
*/
|
||||
window.initProductSelect2 = function(element, type, apiUrl, preloadedData) {
|
||||
if (!element) return;
|
||||
|
||||
// Преобразуем в jQuery если нужно
|
||||
var $element = $(element);
|
||||
|
||||
// Если уже инициализирован, пропускаем
|
||||
if ($element.data('select2')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var placeholders = {
|
||||
'product': 'Начните вводить название товара...',
|
||||
'variant': 'Начните вводить название группы...',
|
||||
'kit': 'Начните вводить название комплекта...',
|
||||
'all': 'Начните вводить название товара или комплекта...'
|
||||
};
|
||||
|
||||
var config = {
|
||||
theme: 'bootstrap-5',
|
||||
placeholder: placeholders[type] || 'Выберите...',
|
||||
allowClear: true,
|
||||
language: 'ru',
|
||||
minimumInputLength: 0,
|
||||
ajax: {
|
||||
url: apiUrl,
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
q: params.term || '',
|
||||
type: type,
|
||||
page: params.page || 1
|
||||
};
|
||||
},
|
||||
processResults: function (data) {
|
||||
return {
|
||||
results: data.results,
|
||||
pagination: {
|
||||
more: data.pagination.more
|
||||
}
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
templateResult: formatSelectResult,
|
||||
templateSelection: formatSelectSelection
|
||||
};
|
||||
|
||||
// Если есть предзагруженные данные, создаем option с ними
|
||||
if (preloadedData) {
|
||||
var option = new Option(preloadedData.text, preloadedData.id, true, true);
|
||||
// Сохраняем дополнительные данные для форматирования
|
||||
$(option).data('data', preloadedData);
|
||||
$element.append(option);
|
||||
}
|
||||
|
||||
$element.select2(config);
|
||||
};
|
||||
|
||||
/**
|
||||
* Инициализирует Select2 для всех элементов с данным селектором
|
||||
* @param {string} selector - CSS селектор элементов
|
||||
* @param {string} type - Тип поиска ('product' или 'variant')
|
||||
* @param {string} apiUrl - URL API для поиска
|
||||
*/
|
||||
window.initAllProductSelect2 = function(selector, type, apiUrl) {
|
||||
document.querySelectorAll(selector).forEach(function(element) {
|
||||
window.initProductSelect2(element, type, apiUrl);
|
||||
});
|
||||
};
|
||||
|
||||
})(window);
|
||||
Reference in New Issue
Block a user