Actualizar servicios2.html
This commit is contained in:
137
servicios2.html
137
servicios2.html
@@ -27,6 +27,7 @@
|
|||||||
.border-col-2 { border-left-color: #f59e0b; } /* Ambar: Sin Cita */
|
.border-col-2 { border-left-color: #f59e0b; } /* Ambar: Sin Cita */
|
||||||
.border-col-3 { border-left-color: #3b82f6; } /* Azul: Pendiente Inicio */
|
.border-col-3 { border-left-color: #3b82f6; } /* Azul: Pendiente Inicio */
|
||||||
.border-col-4 { border-left-color: #10b981; } /* Verde: Trabajando */
|
.border-col-4 { border-left-color: #10b981; } /* Verde: Trabajando */
|
||||||
|
.border-col-5 { border-left-color: #a855f7; } /* Morado: Incidencias */
|
||||||
|
|
||||||
/* Estilos base para formularios y modales */
|
/* 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; }
|
.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 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-6 overflow-x-auto no-scrollbar flex-1 pb-6 w-full fade-in min-w-max">
|
<div class="flex gap-6 overflow-x-auto no-scrollbar flex-1 pb-6 w-full fade-in min-w-max items-start">
|
||||||
|
|
||||||
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
||||||
<div class="flex justify-between items-center mb-4 px-2">
|
<div class="flex justify-between items-center mb-4 px-2">
|
||||||
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2">
|
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2"><span class="w-2.5 h-2.5 rounded-full bg-red-500"></span> Sin Asignar</h3>
|
||||||
<span class="w-2.5 h-2.5 rounded-full bg-red-500"></span> Sin Asignar
|
<span id="count-c1" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
||||||
</h3>
|
|
||||||
<span id="count-unassigned" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="col-unassigned" class="kanban-cards space-y-3 no-scrollbar"></div>
|
<div id="col-1" class="kanban-cards space-y-3 no-scrollbar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
||||||
<div class="flex justify-between items-center mb-4 px-2">
|
<div class="flex justify-between items-center mb-4 px-2">
|
||||||
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2">
|
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2"><span class="w-2.5 h-2.5 rounded-full bg-amber-500 animate-pulse"></span> Sin Cita</h3>
|
||||||
<span class="w-2.5 h-2.5 rounded-full bg-amber-500 animate-pulse"></span> Sin Cita
|
<span id="count-c2" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
||||||
</h3>
|
|
||||||
<span id="count-unscheduled" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="col-unscheduled" class="kanban-cards space-y-3 no-scrollbar"></div>
|
<div id="col-2" class="kanban-cards space-y-3 no-scrollbar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
||||||
<div class="flex justify-between items-center mb-4 px-2">
|
<div class="flex justify-between items-center mb-4 px-2">
|
||||||
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2">
|
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2"><span class="w-2.5 h-2.5 rounded-full bg-blue-500"></span> Pte. Inicio</h3>
|
||||||
<span class="w-2.5 h-2.5 rounded-full bg-blue-500"></span> Pte. Inicio
|
<span id="count-c3" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
||||||
</h3>
|
|
||||||
<span id="count-pending-start" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="col-pending-start" class="kanban-cards space-y-3 no-scrollbar"></div>
|
<div id="col-3" class="kanban-cards space-y-3 no-scrollbar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
||||||
<div class="flex justify-between items-center mb-4 px-2">
|
<div class="flex justify-between items-center mb-4 px-2">
|
||||||
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2">
|
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2"><span class="w-2.5 h-2.5 rounded-full bg-emerald-500"></span> Trabajando</h3>
|
||||||
<span class="w-2.5 h-2.5 rounded-full bg-emerald-500"></span> Trabajando
|
<span id="count-c4" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
||||||
</h3>
|
|
||||||
<span id="count-working" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="col-working" class="kanban-cards space-y-3 no-scrollbar"></div>
|
<div id="col-4" class="kanban-cards space-y-3 no-scrollbar"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="kanban-col bg-slate-100/70 rounded-[2rem] p-4 border border-slate-200/60 shadow-inner">
|
||||||
|
<div class="flex justify-between items-center mb-4 px-2">
|
||||||
|
<h3 class="font-black text-slate-700 uppercase tracking-widest text-xs flex items-center gap-2"><span class="w-2.5 h-2.5 rounded-full bg-purple-500"></span> Incidencias</h3>
|
||||||
|
<span id="count-c5" class="bg-white border border-slate-200 text-slate-600 text-[10px] font-black px-2.5 py-1 rounded-lg shadow-sm">0</span>
|
||||||
|
</div>
|
||||||
|
<div id="col-5" class="kanban-cards space-y-3 no-scrollbar"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -588,15 +589,50 @@
|
|||||||
return res.length > 5 ? res.charAt(0).toUpperCase() + res.slice(1) : texto;
|
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() {
|
function renderKanban() {
|
||||||
const searchTerm = document.getElementById('searchFilter').value.toLowerCase();
|
const searchTerm = document.getElementById('searchFilter').value.toLowerCase();
|
||||||
const selectedOp = document.getElementById('opFilter').value;
|
const selectedOp = document.getElementById('opFilter').value;
|
||||||
const weekValue = document.getElementById('weekFilter').value;
|
const weekValue = document.getElementById('weekFilter').value;
|
||||||
|
|
||||||
const cols = { unassigned: [], unscheduled: [], pending_start: [], working: [] };
|
const cols = { c1: [], c2: [], c3: [], c4: [], c5: [] };
|
||||||
|
|
||||||
localData.forEach(s => {
|
localData.forEach(s => {
|
||||||
if (s.status === 'archived' || s.provider === 'SYSTEM_BLOCK') return;
|
if (s.status === 'archived' || s.provider === 'SYSTEM_BLOCK') return;
|
||||||
@@ -618,40 +654,46 @@
|
|||||||
if (!raw.scheduled_date || !isDateInWeekString(raw.scheduled_date, weekValue)) return;
|
if (!raw.scheduled_date || !isDateInWeekString(raw.scheduled_date, weekValue)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dbStat = raw.status_operativo;
|
// INTELIGENCIA DE ESTADOS
|
||||||
const statusObj = systemStatuses.find(st => String(st.id) === String(dbStat));
|
const stateInfo = getServiceStateInfo(s);
|
||||||
const stName = (statusObj?.name || "").toLowerCase();
|
s._stateInfo = stateInfo; // Guardamos para la tarjeta
|
||||||
|
const stName = (stateInfo.name || "").toLowerCase();
|
||||||
|
|
||||||
// Filtro de Estado (Pastillas superiores)
|
// Filtro de Pastillas
|
||||||
if (activeStatusFilter !== "ALL" && String(statusObj?.id) !== activeStatusFilter) return;
|
if (activeStatusFilter !== "ALL" && String(stateInfo.id) !== activeStatusFilter) return;
|
||||||
|
|
||||||
// Si está finalizado o anulado, NO SE MUESTRA en el tablero Kanban
|
// Ocultar finalizados
|
||||||
if (statusObj?.is_final || stName.includes('finaliza') || stName.includes('anulad') || stName.includes('terminad')) return;
|
if (stateInfo.is_final || stName.includes('finaliza') || stName.includes('anulad') || stName.includes('terminad')) return;
|
||||||
|
|
||||||
const isWorking = stName.includes('trabaja') || stName.includes('camino');
|
const isWorking = stName.includes('trabaja') || stName.includes('camino');
|
||||||
const hasDate = raw.scheduled_date && raw.scheduled_date.trim() !== "";
|
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) {
|
if (!s.assigned_to) {
|
||||||
cols.unassigned.push(s);
|
cols.c1.push(s);
|
||||||
|
} else if (isIncident) {
|
||||||
|
cols.c5.push(s);
|
||||||
} else if (!hasDate) {
|
} else if (!hasDate) {
|
||||||
cols.unscheduled.push(s);
|
cols.c2.push(s);
|
||||||
} else if (!isWorking) {
|
} else if (!isWorking) {
|
||||||
cols.pending_start.push(s);
|
cols.c3.push(s);
|
||||||
} else {
|
} else {
|
||||||
cols.working.push(s);
|
cols.c4.push(s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('count-unassigned').innerText = cols.unassigned.length;
|
document.getElementById('count-c1').innerText = cols.c1.length;
|
||||||
document.getElementById('count-unscheduled').innerText = cols.unscheduled.length;
|
document.getElementById('count-c2').innerText = cols.c2.length;
|
||||||
document.getElementById('count-pending-start').innerText = cols.pending_start.length;
|
document.getElementById('count-c3').innerText = cols.c3.length;
|
||||||
document.getElementById('count-working').innerText = cols.working.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-1').innerHTML = cols.c1.map(s => buildCard(s, 1)).join('');
|
||||||
document.getElementById('col-unscheduled').innerHTML = cols.unscheduled.map(s => buildCard(s, 2)).join('');
|
document.getElementById('col-2').innerHTML = cols.c2.map(s => buildCard(s, 2)).join('');
|
||||||
document.getElementById('col-pending-start').innerHTML = cols.pending_start.map(s => buildCard(s, 3)).join('');
|
document.getElementById('col-3').innerHTML = cols.c3.map(s => buildCard(s, 3)).join('');
|
||||||
document.getElementById('col-working').innerHTML = cols.working.map(s => buildCard(s, 4)).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();
|
lucide.createIcons();
|
||||||
}
|
}
|
||||||
@@ -674,10 +716,9 @@
|
|||||||
if (hasLock) alerts += `<span class="bg-slate-800 text-white p-1 rounded shadow-sm"><i data-lucide="lock" class="w-3 h-3"></i></span>`;
|
if (hasLock) alerts += `<span class="bg-slate-800 text-white p-1 rounded shadow-sm"><i data-lucide="lock" class="w-3 h-3"></i></span>`;
|
||||||
if (hasEyes) alerts += `<span class="bg-amber-500 text-white p-1 rounded shadow-sm animate-pulse"><i data-lucide="eye" class="w-3 h-3"></i></span>`;
|
if (hasEyes) alerts += `<span class="bg-amber-500 text-white p-1 rounded shadow-sm animate-pulse"><i data-lucide="eye" class="w-3 h-3"></i></span>`;
|
||||||
|
|
||||||
// Identificar el estado exacto actual para ponerle color a la etiqueta
|
// Identificar el estado exacto actual leyendo la IA guardada
|
||||||
const dbStat = raw.status_operativo;
|
const stateInfo = s._stateInfo || {name: 'Desconocido', color: 'gray'};
|
||||||
const statusObj = systemStatuses.find(st => String(st.id) === String(dbStat)) || systemStatuses[0];
|
const cMap = colorDict[stateInfo.color] || colorDict['gray'];
|
||||||
const cMap = colorDict[statusObj?.color] || colorDict['gray'];
|
|
||||||
|
|
||||||
// Pie de tarjeta dinámico
|
// Pie de tarjeta dinámico
|
||||||
let bottomInfo = '';
|
let bottomInfo = '';
|
||||||
|
|||||||
Reference in New Issue
Block a user