@@ -325,9 +325,6 @@
`;
systemStatuses.forEach(st => {
- // Por defecto no mostramos los finales en la botonera principal para no saturar, salvo que haya muchos.
- if(st.is_final) return;
-
const isActive = activeStatusFilter === String(st.id);
const colorData = colorDict[st.color] || colorDict['gray'];
@@ -375,44 +372,37 @@
}
// ==========================================
- // 馃殌 C脕LCULO DE ESTADOS Y RENDERIZADO GRID
+ // 馃殌 L脫GICA INTELIGENTE DE ENRUTAMIENTO (ESTADOS)
// ==========================================
function getServiceStateInfo(s) {
const raw = s.raw_data || {};
const dbStat = raw.status_operativo;
- // 1. Si est谩 en la bolsa buscando (Prioridad m谩xima visual)
+ // 1. Bolsa de Trabajo (M谩xima prioridad visual)
if (!s.assigned_name && (s.automation_status === 'in_progress' || s.automation_status === 'failed')) {
- return { id: 'bolsa', name: s.automation_status === 'in_progress' ? 'Buscando Operario' : 'Fallo en Bolsa', color: s.automation_status === 'in_progress' ? 'amber' : 'red', isBlocked: true };
+ return { id: 'bolsa', name: s.automation_status === 'in_progress' ? 'Buscando Operario' : 'Fallo en Bolsa', color: s.automation_status === 'in_progress' ? 'amber' : 'red', isBlocked: true, is_final: false };
}
- // 2. Fallbacks hist贸ricos para compatibilidad
- if (!s.assigned_name || dbStat === 'sin_asignar') {
+ // 2. Si viene limpio del scraper sin estado -> Pendiente de Asignar
+ if (!dbStat || dbStat === 'sin_asignar') {
const found = systemStatuses.find(st => st.name.toLowerCase().includes('pendiente de asignar')) || systemStatuses[0];
- return { id: found?.id, name: found?.name || 'Sin Asignar', color: found?.color || 'gray', isBlocked: false };
+ return { ...found, isBlocked: false };
}
- if (dbStat === 'asignado_operario') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('asignado')) || systemStatuses[1], isBlocked: false };
- if (dbStat === 'citado') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('citado')) || systemStatuses[3], isBlocked: false };
- if (dbStat === 'de_camino') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('camino')) || systemStatuses[4], isBlocked: false };
- if (dbStat === 'trabajando') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('trabajando')) || systemStatuses[5], isBlocked: false };
- if (dbStat === 'incidencia') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('incidencia')) || systemStatuses[6], isBlocked: false };
- if (dbStat === 'terminado') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('terminado')) || systemStatuses[7], isBlocked: false };
// 3. Match directo por ID Num茅rico (El nuevo est谩ndar)
const foundObj = systemStatuses.find(st => String(st.id) === String(dbStat));
if (foundObj) return { ...foundObj, isBlocked: false };
- // 4. 脷ltimo recurso inferido
- if (s.assigned_name && (!raw.scheduled_date || raw.scheduled_date === "")) {
- const f = systemStatuses.find(st => st.name.toLowerCase().includes('pendiente de cita') || st.name.toLowerCase().includes('falta fecha')) || systemStatuses[2];
- return { ...f, isBlocked: false };
- }
- if (s.assigned_name && raw.scheduled_date) {
- const f = systemStatuses.find(st => st.name.toLowerCase().includes('citado')) || systemStatuses[3];
- return { ...f, isBlocked: false };
- }
-
- return { id: 'unknown', name: 'Desconocido', color: 'gray', isBlocked: false };
+ // 4. Fallbacks hist贸ricos de texto (Para que los servicios viejos no se rompan)
+ if (dbStat === 'asignado_operario') return { ...systemStatuses.find(st => st.name.toLowerCase() === 'asignado'), isBlocked: false };
+ if (dbStat === 'citado') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('citado')), isBlocked: false };
+ if (dbStat === 'de_camino') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('camino')), isBlocked: false };
+ if (dbStat === 'trabajando') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('trabajando')), isBlocked: false };
+ if (dbStat === 'incidencia') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('incidencia')), isBlocked: false };
+ if (dbStat === 'terminado') return { ...systemStatuses.find(st => st.name.toLowerCase().includes('terminado') || st.name.toLowerCase().includes('finalizado')), isBlocked: false };
+
+ // 5. Fallback final
+ return { id: 'unknown', name: 'Desconocido', color: 'gray', isBlocked: false, is_final: false };
}
function renderLists() {
@@ -421,11 +411,10 @@
const searchTerm = document.getElementById('searchFilter').value.toLowerCase();
const selectedOp = document.getElementById('opFilter').value;
- // KPIs
let kpiUnassigned = 0;
let kpiScheduled = 0;
let kpiActive = 0;
- let kpiIssues = 0;
+ let kpiFinished = 0;
const filteredData = localData.filter(s => {
const raw = s.raw_data || {};
@@ -437,22 +426,34 @@
const ref = (s.service_ref || "").toLowerCase();
const assigned = s.assigned_name || "";
- // Calculamos el estado real
+ // Calculamos el estado real y lo inyectamos
const stateInfo = getServiceStateInfo(s);
- s._stateInfo = stateInfo; // Lo guardamos para pintar la tarjeta
+ s._stateInfo = stateInfo;
- // L贸gica de KPIs
+ // L贸gica de KPIs de suma agrupada
const stName = stateInfo.name.toLowerCase();
- if (stName.includes('asignar') || stateInfo.isBlocked) kpiUnassigned++;
- else if (stName.includes('citado')) kpiScheduled++;
- else if (stName.includes('camino') || stName.includes('trabajando')) kpiActive++;
- else if (stName.includes('incidencia') || stName.includes('pausa')) kpiIssues++;
+ if (stateInfo.id === 'bolsa' || stName.includes('pendiente de asignar') || stName.includes('desasignado')) {
+ kpiUnassigned++;
+ } else if (stateInfo.is_final || stName.includes('terminado') || stName.includes('anulado') || stName.includes('finalizado')) {
+ kpiFinished++;
+ } else if (stName === 'asignado' || stName.includes('pendiente de cita') || stName.includes('citado')) {
+ kpiScheduled++;
+ } else {
+ kpiActive++; // De Camino, Trabajando, Incidencia y los personalizados
+ }
+ // Aplicar Filtros Visuales
const matchesSearch = searchTerm === "" || name.includes(searchTerm) || ref.includes(searchTerm) || addr.includes(searchTerm) || pop.includes(searchTerm) || phone.includes(searchTerm) || comp.includes(searchTerm);
const matchesOp = selectedOp === "ALL" || assigned === selectedOp;
- // Filtro por la botonera de chips
- const matchesStatus = activeStatusFilter === "ALL" || String(stateInfo.id) === activeStatusFilter;
+ let matchesStatus = false;
+ if (activeStatusFilter === "ALL") {
+ // Si no hay b煤squeda activa, ocultamos los Finalizados por limpieza visual
+ if (stateInfo.is_final && searchTerm === "") matchesStatus = false;
+ else matchesStatus = true;
+ } else {
+ matchesStatus = String(stateInfo.id) === activeStatusFilter;
+ }
return matchesSearch && matchesOp && matchesStatus;
});
@@ -461,13 +462,13 @@
document.getElementById('kpi-unassigned').innerText = kpiUnassigned;
document.getElementById('kpi-scheduled').innerText = kpiScheduled;
document.getElementById('kpi-active').innerText = kpiActive;
- document.getElementById('kpi-issues').innerText = kpiIssues;
+ document.getElementById('kpi-finished').innerText = kpiFinished;
const grid = document.getElementById('servicesGrid');
grid.innerHTML = filteredData.length > 0
? filteredData.map(s => buildGridCard(s)).join('')
: `
-
+
No hay servicios que coincidan con los filtros
`;
@@ -492,7 +493,7 @@
if(raw.scheduled_date) iconEstado = 'calendar';
if(stateInfo.name.toLowerCase().includes('camino')) iconEstado = 'car';
if(stateInfo.name.toLowerCase().includes('reparaci') || stateInfo.name.toLowerCase().includes('trabaja')) iconEstado = 'wrench';
- if(stateInfo.name.toLowerCase().includes('incidencia')) iconEstado = 'alert-triangle';
+ if(stateInfo.name.toLowerCase().includes('incidencia') || stateInfo.name.toLowerCase().includes('pausado')) iconEstado = 'alert-triangle';
const isBlocked = stateInfo.isBlocked;
const clickAction = isBlocked ? `shakeCard(this, '${s.automation_status}'); event.stopPropagation();` : `openDetail(${s.id})`;
@@ -597,7 +598,8 @@
const stateInfo = s._stateInfo;
- if (s.assigned_name && stateInfo.id !== 'bolsa' && !stateInfo.name.toLowerCase().includes('asignar')) {
+ // Mostrar u ocultar paneles de asignaci贸n dependiendo del estado
+ if (s.assigned_name && stateInfo.id !== 'bolsa' && !stateInfo.name.toLowerCase().includes('asignar') && !stateInfo.name.toLowerCase().includes('desasignado')) {
document.getElementById('panelAsignado').classList.remove('hidden');
document.getElementById('panelSinAsignar').classList.add('hidden');
@@ -605,7 +607,6 @@
document.getElementById('dateInput').value = raw.scheduled_date || "";
document.getElementById('timeInput').value = raw.scheduled_time || "";
- // Mapeo del estado calculado al selector
document.getElementById('detStatusMap').value = stateInfo.id;
} else {
document.getElementById('panelAsignado').classList.add('hidden');
@@ -633,7 +634,8 @@
const selectedSt = systemStatuses.find(st => String(st.id) === String(statusMap));
- if (selectedSt && !selectedSt.is_final && !date && !selectedSt.name.toLowerCase().includes('pausa')) {
+ // Avisar si guarda sin fecha en un estado que deber铆a tenerla
+ if (selectedSt && !selectedSt.is_final && !date && !selectedSt.name.toLowerCase().includes('pausa') && !selectedSt.name.toLowerCase().includes('asignar')) {
if(!confirm("No has asignado Fecha para este estado. 驴Deseas continuar?")) return;
}