diff --git a/servicios2.html b/servicios2.html index f1beb8d..4e6101b 100644 --- a/servicios2.html +++ b/servicios2.html @@ -27,6 +27,7 @@ .border-col-2 { border-left-color: #f59e0b; } /* Ambar: Sin Cita */ .border-col-3 { border-left-color: #3b82f6; } /* Azul: Pendiente Inicio */ .border-col-4 { border-left-color: #10b981; } /* Verde: Trabajando */ + .border-col-5 { border-left-color: #a855f7; } /* Morado: Incidencias */ /* Estilos base para formularios y modales */ .input-modern { @apply w-full bg-slate-50 border border-slate-200 px-4 py-3 rounded-xl text-sm font-semibold text-slate-700 outline-none transition-all focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-100; } @@ -89,46 +90,46 @@ -
+
-

- Sin Asignar -

- 0 +

Sin Asignar

+ 0
-
+
-

- Sin Cita -

- 0 +

Sin Cita

+ 0
-
+
-

- Pte. Inicio -

- 0 +

Pte. Inicio

+ 0
-
+
-

- Trabajando -

- 0 +

Trabajando

+ 0
-
+
+
+ +
+
+

Incidencias

+ 0 +
+
@@ -588,15 +589,50 @@ return res.length > 5 ? res.charAt(0).toUpperCase() + res.slice(1) : texto; } + // ===================================== + // MOTOR KANBAN E INTELIGENCIA DE ESTADOS // ===================================== - // MOTOR KANBAN - // ===================================== + + function getServiceStateInfo(s) { + const raw = s.raw_data || {}; + const dbStat = raw.status_operativo; + + 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', is_final: false }; + } + + if (!s.assigned_name && (!dbStat || dbStat === 'sin_asignar')) { + return systemStatuses.find(st => st.name.toLowerCase().includes('pendiente de asignar')) || systemStatuses[0] || {id: 'sin_asignar', name: 'Sin Asignar', color: 'gray'}; + } + + const foundById = systemStatuses.find(st => String(st.id) === String(dbStat)); + if (foundById) return foundById; + + if (s.assigned_name && (!raw.scheduled_date || raw.scheduled_date === "")) { + const asignado = systemStatuses.find(st => st.name.toLowerCase() === 'asignado'); + const esperando = systemStatuses.find(st => st.name.toLowerCase().includes('esperando')); + if (dbStat === 'esperando_cliente' && esperando) return esperando; + if (asignado) return asignado; + } + + const stLower = String(dbStat).toLowerCase(); + if (stLower === 'citado' || (s.assigned_name && raw.scheduled_date && !dbStat)) { + const citado = systemStatuses.find(st => st.name.toLowerCase().includes('citado')); + if(citado) return citado; + } + if (stLower === 'de_camino') return systemStatuses.find(st => st.name.toLowerCase().includes('camino')) || {name: 'De Camino', color: 'blue'}; + if (stLower === 'trabajando') return systemStatuses.find(st => st.name.toLowerCase().includes('trabajando')) || {name: 'Trabajando', color: 'emerald'}; + if (stLower === 'incidencia') return systemStatuses.find(st => st.name.toLowerCase().includes('incidencia')) || {name: 'Incidencia', color: 'purple'}; + + return { id: 'unknown', name: 'Desconocido', color: 'gray', is_final: false }; + } + function renderKanban() { const searchTerm = document.getElementById('searchFilter').value.toLowerCase(); const selectedOp = document.getElementById('opFilter').value; const weekValue = document.getElementById('weekFilter').value; - const cols = { unassigned: [], unscheduled: [], pending_start: [], working: [] }; + const cols = { c1: [], c2: [], c3: [], c4: [], c5: [] }; localData.forEach(s => { if (s.status === 'archived' || s.provider === 'SYSTEM_BLOCK') return; @@ -618,40 +654,46 @@ if (!raw.scheduled_date || !isDateInWeekString(raw.scheduled_date, weekValue)) return; } - const dbStat = raw.status_operativo; - const statusObj = systemStatuses.find(st => String(st.id) === String(dbStat)); - const stName = (statusObj?.name || "").toLowerCase(); + // INTELIGENCIA DE ESTADOS + const stateInfo = getServiceStateInfo(s); + s._stateInfo = stateInfo; // Guardamos para la tarjeta + const stName = (stateInfo.name || "").toLowerCase(); - // Filtro de Estado (Pastillas superiores) - if (activeStatusFilter !== "ALL" && String(statusObj?.id) !== activeStatusFilter) return; + // Filtro de Pastillas + if (activeStatusFilter !== "ALL" && String(stateInfo.id) !== activeStatusFilter) return; - // Si está finalizado o anulado, NO SE MUESTRA en el tablero Kanban - if (statusObj?.is_final || stName.includes('finaliza') || stName.includes('anulad') || stName.includes('terminad')) return; + // Ocultar finalizados + if (stateInfo.is_final || stName.includes('finaliza') || stName.includes('anulad') || stName.includes('terminad')) return; const isWorking = stName.includes('trabaja') || stName.includes('camino'); const hasDate = raw.scheduled_date && raw.scheduled_date.trim() !== ""; + const isIncident = stName.includes('incidencia') || stName.includes('pausa') || stName.includes('espera'); - // REPARTO KANBAN INTELIGENTE + // REPARTO KANBAN INTELIGENTE (5 COLUMNAS) if (!s.assigned_to) { - cols.unassigned.push(s); + cols.c1.push(s); + } else if (isIncident) { + cols.c5.push(s); } else if (!hasDate) { - cols.unscheduled.push(s); + cols.c2.push(s); } else if (!isWorking) { - cols.pending_start.push(s); + cols.c3.push(s); } else { - cols.working.push(s); + cols.c4.push(s); } }); - document.getElementById('count-unassigned').innerText = cols.unassigned.length; - document.getElementById('count-unscheduled').innerText = cols.unscheduled.length; - document.getElementById('count-pending-start').innerText = cols.pending_start.length; - document.getElementById('count-working').innerText = cols.working.length; + document.getElementById('count-c1').innerText = cols.c1.length; + document.getElementById('count-c2').innerText = cols.c2.length; + document.getElementById('count-c3').innerText = cols.c3.length; + document.getElementById('count-c4').innerText = cols.c4.length; + document.getElementById('count-c5').innerText = cols.c5.length; - document.getElementById('col-unassigned').innerHTML = cols.unassigned.map(s => buildCard(s, 1)).join(''); - document.getElementById('col-unscheduled').innerHTML = cols.unscheduled.map(s => buildCard(s, 2)).join(''); - document.getElementById('col-pending-start').innerHTML = cols.pending_start.map(s => buildCard(s, 3)).join(''); - document.getElementById('col-working').innerHTML = cols.working.map(s => buildCard(s, 4)).join(''); + document.getElementById('col-1').innerHTML = cols.c1.map(s => buildCard(s, 1)).join(''); + document.getElementById('col-2').innerHTML = cols.c2.map(s => buildCard(s, 2)).join(''); + document.getElementById('col-3').innerHTML = cols.c3.map(s => buildCard(s, 3)).join(''); + document.getElementById('col-4').innerHTML = cols.c4.map(s => buildCard(s, 4)).join(''); + document.getElementById('col-5').innerHTML = cols.c5.map(s => buildCard(s, 5)).join(''); lucide.createIcons(); } @@ -674,10 +716,9 @@ if (hasLock) alerts += ``; if (hasEyes) alerts += ``; - // Identificar el estado exacto actual para ponerle color a la etiqueta - const dbStat = raw.status_operativo; - const statusObj = systemStatuses.find(st => String(st.id) === String(dbStat)) || systemStatuses[0]; - const cMap = colorDict[statusObj?.color] || colorDict['gray']; + // Identificar el estado exacto actual leyendo la IA guardada + const stateInfo = s._stateInfo || {name: 'Desconocido', color: 'gray'}; + const cMap = colorDict[stateInfo.color] || colorDict['gray']; // Pie de tarjeta dinámico let bottomInfo = '';