Suggestions
This commit is contained in:
@@ -80,13 +80,11 @@
|
||||
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||
/* Estilos para las sugerencias de autocompletado */
|
||||
.autocomplete-suggestions { position: absolute; width: calc(100% - 2px); /* Ajustar al ancho del input */ background: white; border: 1px solid #ced4da; border-top: none;
|
||||
border-radius: 0 0 4px 4px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); z-index: 1000; max-height: 200px; overflow-y: auto; display: none; /* Inicialmente oculto */ }
|
||||
.autocomplete-item { padding: 8px 12px; cursor: pointer; transition: background-color 0.2s; }
|
||||
.autocomplete-item:hover, .autocomplete-item.active { background-color: #f8f9fa; }
|
||||
.autocomplete-item strong { display: block; margin-bottom: 2px; }
|
||||
.autocomplete-item .text-muted { font-size: 0.85em; color: #6c757d; }
|
||||
.cursor-pointer { cursor: pointer; }
|
||||
#global-autocomplete-suggestions { box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; border: 1px solid #dee2e6 !important; width: calc(100% - 30px) !important; /* Ajusta según el padding de tu contenedor */ }
|
||||
#global-autocomplete-suggestions .autocomplete-item { transition: background-color 0.15s ease; }
|
||||
#global-autocomplete-suggestions .autocomplete-item:hover,
|
||||
#global-autocomplete-suggestions .autocomplete-item.active { background-color: #f8f9fa !important; }
|
||||
#global-autocomplete-suggestions .autocomplete-item:last-child { border-bottom: none; }
|
||||
/* Estilos para validación */
|
||||
.choices.required .choices__inner { border: 1px solid #ced4da; }
|
||||
.choices.is-invalid .choices__inner { border: 1px solid #dc3545; background-color: #fff5f5; }
|
||||
@@ -666,142 +664,243 @@
|
||||
$(document).ready(function() {
|
||||
let timeoutId;
|
||||
let currentRequest = null;
|
||||
let currentInput = null; // Para rastrear qué input está activo
|
||||
|
||||
// Crear un único contenedor de sugerencias al final del body
|
||||
if ($('#global-autocomplete-suggestions').length === 0) {
|
||||
$('#tabla-partidas').after(`
|
||||
<div id="global-autocomplete-suggestions"
|
||||
class="bg-white border shadow-lg w-100"
|
||||
style="display: none;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border-radius: 4px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;">
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
const $globalSuggestions = $('#global-autocomplete-suggestions');
|
||||
|
||||
// Función para configurar autocompletado en un input
|
||||
function setupAutocomplete(input) {
|
||||
const $input = $(input);
|
||||
|
||||
// Crear contenedor de sugerencias si no existe
|
||||
if ($input.siblings('.autocomplete-suggestions').length === 0) {
|
||||
$input.after('<div class="autocomplete-suggestions position-absolute w-100 bg-white border border-top-0 shadow-sm" style="max-height: 200px; overflow-y: auto; z-index: 1000; display: none;"></div>');
|
||||
}
|
||||
|
||||
const $suggestions = $input.siblings('.autocomplete-suggestions');
|
||||
const $row = $input.closest('tr');
|
||||
const $row = $input.closest('tr');
|
||||
|
||||
$input.off('input').on('input', function() {
|
||||
const query = $(this).val().trim();
|
||||
currentInput = $input; // Guardar referencia del input activo
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
if (currentRequest) currentRequest.abort();
|
||||
|
||||
if (query.length < 2) {
|
||||
$suggestions.hide().empty();
|
||||
$globalSuggestions.hide().empty();
|
||||
return;
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
currentRequest = $.ajax({
|
||||
url: '/IMPORTADORES/solicitud_importacion/buscar_productos',
|
||||
method: 'GET',
|
||||
data: { q: query },
|
||||
url: '/IMPORTADORES/solicitud_importacion/buscar_productos',
|
||||
method: 'GET',
|
||||
data: { q: query },
|
||||
dataType: 'json',
|
||||
success: function(productos) {
|
||||
$suggestions.empty();
|
||||
success: function(productos) {
|
||||
$globalSuggestions.empty();
|
||||
|
||||
if (productos && productos.length > 0) {
|
||||
productos.forEach(function(producto) {
|
||||
const $item = $(`
|
||||
<div class="autocomplete-item px-3 py-2 cursor-pointer border-bottom">
|
||||
<strong>${producto.sinonimo}</strong>
|
||||
<div class="row mb-3 small text-muted">
|
||||
<span>${producto.fraccion || 'Sin fracción'}</span>
|
||||
<span>${producto.descripcion?.substring(0, 50) || ''}</span>
|
||||
<div class="autocomplete-item px-3 py-2 cursor-pointer border-bottom hover-bg-light"
|
||||
style="cursor: pointer;">
|
||||
<strong style="color: #333;">${producto.sinonimo}</strong>
|
||||
<div class="small text-muted mt-1">
|
||||
<div>Fracción: ${producto.fraccion || 'Sin fracción'}</div>
|
||||
<div>Desc: ${producto.descripcion?.substring(0, 50) || ''}${producto.descripcion?.length > 50 ? '...' : ''}</div>
|
||||
</div>
|
||||
</div>
|
||||
`).data('producto', producto);
|
||||
|
||||
$item.on('click', function() { selectProduct($(this).data('producto'), $row); });
|
||||
$suggestions.append($item);
|
||||
// Efectos hover
|
||||
$item.on('mouseenter', function() {
|
||||
$globalSuggestions.find('.autocomplete-item').removeClass('active');
|
||||
$(this).addClass('active').css('background-color', '#f8f9fa');
|
||||
}).on('mouseleave', function() {
|
||||
$(this).removeClass('active').css('background-color', '');
|
||||
});
|
||||
|
||||
$item.on('click', function() {
|
||||
selectProduct($(this).data('producto'), currentInput.closest('tr'));
|
||||
});
|
||||
|
||||
$globalSuggestions.append($item);
|
||||
});
|
||||
$suggestions.show();
|
||||
|
||||
// Posicionar y mostrar
|
||||
$globalSuggestions.show();
|
||||
}
|
||||
else {
|
||||
$globalSuggestions.hide();
|
||||
}
|
||||
else { $suggestions.hide(); }
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
if (status !== 'abort') { console.error("Error en búsqueda:", error); }
|
||||
$suggestions.hide();
|
||||
if (status !== 'abort') {
|
||||
console.error("Error en búsqueda:", error);
|
||||
}
|
||||
$globalSuggestions.hide();
|
||||
},
|
||||
complete: function() { currentRequest = null; }
|
||||
complete: function() {
|
||||
currentRequest = null;
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
// Manejar eventos de foco
|
||||
$input.on('focus', function() {
|
||||
currentInput = $input;
|
||||
});
|
||||
|
||||
// Manejar teclado
|
||||
$input.on('keydown', function(e) {
|
||||
const $items = $suggestions.find('.autocomplete-item');
|
||||
if (!$globalSuggestions.is(':visible')) return;
|
||||
|
||||
const $items = $globalSuggestions.find('.autocomplete-item');
|
||||
const $active = $items.filter('.active');
|
||||
|
||||
switch(e.key) {
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
$items.removeClass('active').css('background-color', '');
|
||||
const $next = $active.length ? $active.next() : $items.first();
|
||||
$items.removeClass('active');
|
||||
$next.addClass('active');
|
||||
$next.addClass('active').css('background-color', '#f8f9fa');
|
||||
|
||||
// Scroll automático
|
||||
const containerHeight = $globalSuggestions.height();
|
||||
const itemTop = $next.position().top;
|
||||
const itemHeight = $next.outerHeight();
|
||||
if (itemTop + itemHeight > containerHeight) {
|
||||
$globalSuggestions.scrollTop($globalSuggestions.scrollTop() + itemHeight);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
$items.removeClass('active').css('background-color', '');
|
||||
const $prev = $active.length ? $active.prev() : $items.last();
|
||||
$items.removeClass('active');
|
||||
$prev.addClass('active');
|
||||
$prev.addClass('active').css('background-color', '#f8f9fa');
|
||||
|
||||
// Scroll automático
|
||||
if ($prev.position().top < 0) {
|
||||
$globalSuggestions.scrollTop($globalSuggestions.scrollTop() - $prev.outerHeight());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Enter':
|
||||
if ($active.length) {
|
||||
e.preventDefault();
|
||||
selectProduct($active.data('producto'), $row);
|
||||
selectProduct($active.data('producto'), $input.closest('tr'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Tab':
|
||||
if ($suggestions.is(':visible')) {
|
||||
if ($globalSuggestions.is(':visible')) {
|
||||
e.preventDefault();
|
||||
const $first = $items.first();
|
||||
if ($first.length) selectProduct($first.data('producto'), $row);
|
||||
if ($first.length) {
|
||||
selectProduct($first.data('producto'), $input.closest('tr'));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Escape':
|
||||
$suggestions.hide();
|
||||
$globalSuggestions.hide();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Ocultar al hacer clic fuera
|
||||
$(document).on('click', function(e) { if (!$input.is(e.target) && !$suggestions.is(e.target) && !$suggestions.has(e.target).length) { $suggestions.hide(); } });
|
||||
}
|
||||
|
||||
// Ocultar sugerencias al hacer clic fuera o al hacer scroll
|
||||
$(document).on('click', function(e) {
|
||||
if (!currentInput ||
|
||||
(!currentInput.is(e.target) &&
|
||||
!$globalSuggestions.is(e.target) &&
|
||||
!$globalSuggestions.has(e.target).length)) {
|
||||
$globalSuggestions.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// Ocultar al hacer scroll (opcional)
|
||||
$(window).on('scroll resize', function() {
|
||||
if ($globalSuggestions.is(':visible') && currentInput) {
|
||||
// Reposicionar en lugar de ocultar
|
||||
positionGlobalSuggestions(currentInput);
|
||||
}
|
||||
});
|
||||
|
||||
// Función para seleccionar un producto
|
||||
function selectProduct(producto, $row) {
|
||||
// Campos básicos
|
||||
$row.find('input[name*="[descripcion]"]').val(producto.sinonimo);
|
||||
|
||||
// Tasa preferencial
|
||||
if (producto.preferencia) {
|
||||
const $select = $row.find('select[name*="[tasa_preferencial]"]');
|
||||
if ($select[0] && $select[0]._choices) { $select[0]._choices.setChoiceByValue(producto.preferencia); }
|
||||
else { $select.val(producto.preferencia).trigger('change'); }
|
||||
if ($select[0] && $select[0]._choices) {
|
||||
$select[0]._choices.setChoiceByValue(producto.preferencia);
|
||||
} else {
|
||||
$select.val(producto.preferencia).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
// Unidad de medida
|
||||
if (producto.umc_id) {
|
||||
const $select = $row.find('select[name*="[unidad_comercial_id]"]');
|
||||
setTimeout(() => {
|
||||
if ($select[0] && $select[0]._choices) { $select[0]._choices.setChoiceByValue(producto.umc_id.toString()); }
|
||||
else { $select.val(producto.umc_id).trigger('change'); }
|
||||
if ($select[0] && $select[0]._choices) {
|
||||
$select[0]._choices.setChoiceByValue(producto.umc_id.toString());
|
||||
} else {
|
||||
$select.val(producto.umc_id).trigger('change');
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
// Número de parte
|
||||
if (producto.numero_parte) { $row.find('input[name*="[oma_factura]"]').val(producto.numero_parte); }
|
||||
if (producto.numero_parte) {
|
||||
$row.find('input[name*="[oma_factura]"]').val(producto.numero_parte);
|
||||
}
|
||||
|
||||
// Incrementar frecuencia
|
||||
$.ajax({
|
||||
url: '/IMPORTADORES/solicitud_importacion/incrementar_frecuencia',
|
||||
url: '/IMPORTADORES/solicitud_importacion/incrementar_frecuencia',
|
||||
method: 'POST',
|
||||
data: { producto_id: producto.id }
|
||||
data: { producto_id: producto.id }
|
||||
});
|
||||
|
||||
// Ocultar sugerencias
|
||||
$row.find('.autocomplete-suggestions').hide();
|
||||
$globalSuggestions.hide();
|
||||
|
||||
// Enfocar el siguiente campo si existe
|
||||
const $nextInput = $row.next('tr').find('.descripcion-input');
|
||||
if ($nextInput.length) {
|
||||
setTimeout(() => $nextInput.focus(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializar autocompletado en inputs existentes
|
||||
$('.descripcion-input').each(function() { setupAutocomplete(this); });
|
||||
$('.descripcion-input').each(function() {
|
||||
setupAutocomplete(this);
|
||||
});
|
||||
|
||||
// Configurar autocompletado para nuevas filas
|
||||
$('#add-partida').on('click', function() { setTimeout(function() { $('.descripcion-input').last().each(function() { setupAutocomplete(this); }); }, 100); });
|
||||
$('#add-partida').on('click', function() {
|
||||
setTimeout(function() {
|
||||
$('.descripcion-input').last().each(function() {
|
||||
setupAutocomplete(this);
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user