fix(catalog): unifica modelos duplicados por variante de carroceria/generacion
- catalog_service.get_models ahora agrupa variantes (p. ej. AVEO Saloon, AVEO Hatchback) bajo un unico display_name y devuelve variant_ids. - Se elige el id_model mas bajo como canonico para presentacion. - /catalog/years y /catalog/engines aceptan model_id como lista separada por comas para consultar todos los MYEs de las variantes agrupadas. - catalog.js usa variant_ids al cargar años/motores y en el selector desplegable (incluyendo carga desde VIN).
This commit is contained in:
@@ -427,6 +427,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
function modelIdsParam(model) {
|
||||
if (!model) return '';
|
||||
if (model.variant_ids && model.variant_ids.length) return model.variant_ids.join(',');
|
||||
return String(model.id);
|
||||
}
|
||||
|
||||
function loadModels() {
|
||||
nav.level = 'models';
|
||||
pushNavState();
|
||||
@@ -440,14 +446,15 @@
|
||||
if (!data || !data.data || !data.data.length) { showEmpty('Sin modelos', 'No hay modelos con partes para ' + nav.brand.name); return; }
|
||||
navGrid.className = 'nav-grid';
|
||||
navGrid.innerHTML = data.data.map(function (m) {
|
||||
return '<div class="nav-card" role="listitem" data-model-id="' + m.id_model + '" data-name="' + esc(m.display_name || m.name_model) + '">' +
|
||||
return '<div class="nav-card" role="listitem" data-model-id="' + m.id_model + '" data-variant-ids="' + esc((m.variant_ids || [m.id_model]).join(',')) + '" data-name="' + esc(m.display_name || m.name_model) + '">' +
|
||||
'<div class="nav-card__name">' + esc(m.display_name || m.name_model) + '</div>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
|
||||
navGrid.querySelectorAll('.nav-card').forEach(function (card) {
|
||||
card.addEventListener('click', function () {
|
||||
nav.model = { id: parseInt(this.dataset.modelId), name: this.dataset.name };
|
||||
var variantIds = (this.dataset.variantIds || this.dataset.modelId).split(',').map(function(x){ return parseInt(x); });
|
||||
nav.model = { id: parseInt(this.dataset.modelId), name: this.dataset.name, variant_ids: variantIds };
|
||||
loadYears();
|
||||
});
|
||||
});
|
||||
@@ -462,7 +469,7 @@
|
||||
setupLevelFilter(false);
|
||||
showLoading();
|
||||
|
||||
apiFetch(API + '/years?model_id=' + nav.model.id).then(function (data) {
|
||||
apiFetch(API + '/years?model_id=' + modelIdsParam(nav.model)).then(function (data) {
|
||||
hideLoading();
|
||||
if (!data || !data.data || !data.data.length) { showEmpty('Sin anios', 'No hay anios con partes para este modelo.'); return; }
|
||||
navGrid.className = 'nav-grid nav-grid--years';
|
||||
@@ -489,7 +496,7 @@
|
||||
setupLevelFilter(false);
|
||||
showLoading();
|
||||
|
||||
apiFetch(API + '/engines?model_id=' + nav.model.id + '&year_id=' + nav.year.id).then(function (data) {
|
||||
apiFetch(API + '/engines?model_id=' + modelIdsParam(nav.model) + '&year_id=' + nav.year.id).then(function (data) {
|
||||
hideLoading();
|
||||
if (!data || !data.data || !data.data.length) { showEmpty('Sin motores', 'No hay configuraciones de motor para esta combinacion.'); return; }
|
||||
|
||||
@@ -1829,7 +1836,8 @@
|
||||
if (!models) return;
|
||||
vsModel.innerHTML = '<option value="">Modelo...</option>' +
|
||||
models.map(function (m) {
|
||||
return '<option value="' + m.id_model + '">' + esc(m.display_name || m.name_model) + '</option>';
|
||||
var variants = (m.variant_ids || [m.id_model]).join(',');
|
||||
return '<option value="' + m.id_model + '" data-variant-ids="' + esc(variants) + '">' + esc(m.display_name || m.name_model) + '</option>';
|
||||
}).join('');
|
||||
});
|
||||
}
|
||||
@@ -1837,13 +1845,17 @@
|
||||
function vsModelChanged() {
|
||||
var modelId = vsModel.value;
|
||||
var yearVal = vsYear.value;
|
||||
var selectedOption = vsModel.options[vsModel.selectedIndex];
|
||||
var variantIds = selectedOption && selectedOption.dataset.variantIds
|
||||
? selectedOption.dataset.variantIds.split(',').map(function(x){ return parseInt(x); })
|
||||
: (modelId ? [parseInt(modelId)] : []);
|
||||
vsEngine.innerHTML = '<option value="">Motor...</option>';
|
||||
vsEngine.disabled = true;
|
||||
|
||||
if (!modelId || !yearVal) return;
|
||||
if (!modelId || !yearVal || !variantIds.length) return;
|
||||
|
||||
vsEngine.disabled = false;
|
||||
apiFetch(API + '/engines?model_id=' + modelId + '&year_id=' + yearVal).then(function (data) {
|
||||
apiFetch(API + '/engines?model_id=' + variantIds.join(',') + '&year_id=' + yearVal).then(function (data) {
|
||||
var engines = data.data || data;
|
||||
if (!engines) return;
|
||||
vsEngine.innerHTML = '<option value="">Motor...</option>' +
|
||||
@@ -1869,8 +1881,12 @@
|
||||
var modelText = vsModel.options[vsModel.selectedIndex].text;
|
||||
var engineText = vsEngine.options[vsEngine.selectedIndex].text;
|
||||
|
||||
var selectedModelOption = vsModel.options[vsModel.selectedIndex];
|
||||
var modelVariantIds = selectedModelOption && selectedModelOption.dataset.variantIds
|
||||
? selectedModelOption.dataset.variantIds.split(',').map(function(x){ return parseInt(x); })
|
||||
: [parseInt(vsModel.value)];
|
||||
nav.brand = { id: parseInt(vsBrand.value), name: brandText };
|
||||
nav.model = { id: parseInt(vsModel.value), name: modelText };
|
||||
nav.model = { id: parseInt(vsModel.value), name: modelText, variant_ids: modelVariantIds };
|
||||
nav.year = { id: parseInt(vsYear.value), year: yearText };
|
||||
nav.engine = { id_mye: parseInt(myeId), name: engineText };
|
||||
nav.level = 'categories';
|
||||
@@ -2058,14 +2074,29 @@
|
||||
if (!models) return;
|
||||
vsModel.innerHTML = '<option value="">Modelo...</option>' +
|
||||
models.map(function (m) {
|
||||
return '<option value="' + m.id_model + '">' + esc(m.display_name || m.name_model) + '</option>';
|
||||
var variants = (m.variant_ids || [m.id_model]).join(',');
|
||||
return '<option value="' + m.id_model + '" data-variant-ids="' + esc(variants) + '">' + esc(m.display_name || m.name_model) + '</option>';
|
||||
}).join('');
|
||||
vsModel.disabled = false;
|
||||
|
||||
if (match.model_id) {
|
||||
vsModel.value = String(match.model_id);
|
||||
// The VIN match may point to a variant that is now grouped under
|
||||
// a canonical model; select the option whose variants include it.
|
||||
var matchedOption = Array.from(vsModel.options).find(function (opt) {
|
||||
if (!opt.value) return false;
|
||||
var vids = (opt.dataset.variantIds || opt.value).split(',').map(function(x){ return parseInt(x); });
|
||||
return vids.indexOf(match.model_id) !== -1;
|
||||
});
|
||||
if (matchedOption) {
|
||||
vsModel.value = matchedOption.value;
|
||||
} else {
|
||||
vsModel.value = String(match.model_id);
|
||||
}
|
||||
var selectedVariantIds = vsModel.selectedIndex >= 0 && vsModel.options[vsModel.selectedIndex].dataset.variantIds
|
||||
? vsModel.options[vsModel.selectedIndex].dataset.variantIds.split(',').map(function(x){ return parseInt(x); })
|
||||
: [match.model_id];
|
||||
// Load engines
|
||||
apiFetch(API + '/engines?model_id=' + match.model_id + '&year_id=' + match.year_id).then(function (engData) {
|
||||
apiFetch(API + '/engines?model_id=' + selectedVariantIds.join(',') + '&year_id=' + match.year_id).then(function (engData) {
|
||||
var engines = engData && (engData.data || engData);
|
||||
if (!engines) return;
|
||||
vsEngine.innerHTML = '<option value="">Motor...</option>' +
|
||||
|
||||
Reference in New Issue
Block a user