Actualizar panel.html
This commit is contained in:
71
panel.html
71
panel.html
@@ -173,12 +173,16 @@
|
|||||||
|
|
||||||
async function loadDashboardData(token) {
|
async function loadDashboardData(token) {
|
||||||
try {
|
try {
|
||||||
// 1. Pedimos todos los datos (el endpoint de scraped trae todos los del panel también)
|
// 1. Pedimos los expedientes vírgenes (Bandeja / Bolsa)
|
||||||
const resScraped = await fetch(`${API_URL}/providers/scraped`, { headers: { "Authorization": `Bearer ${token}` } });
|
const resScraped = await fetch(`${API_URL}/providers/scraped`, { headers: { "Authorization": `Bearer ${token}` } });
|
||||||
const dataScraped = await resScraped.json();
|
const dataScraped = await resScraped.json();
|
||||||
|
|
||||||
if (dataScraped.ok) {
|
// 2. Pedimos los expedientes en curso (Panel Operativo)
|
||||||
processDashboard(dataScraped.services);
|
const resActive = await fetch(`${API_URL}/services/active`, { headers: { "Authorization": `Bearer ${token}` } });
|
||||||
|
const dataActive = await resActive.json();
|
||||||
|
|
||||||
|
if (dataScraped.ok && dataActive.ok) {
|
||||||
|
processDashboard(dataScraped.services, dataActive.services);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error cargando dashboard:", e);
|
console.error("Error cargando dashboard:", e);
|
||||||
@@ -186,31 +190,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processDashboard(allServices) {
|
function processDashboard(scrapedList, activeList) {
|
||||||
// Filtrar SOLO LOS ACTIVOS reales (Ignoramos los archivados)
|
|
||||||
const activeServices = allServices.filter(s => s.status !== 'archived');
|
|
||||||
|
|
||||||
const todayStr = new Date().toISOString().split('T')[0];
|
const todayStr = new Date().toISOString().split('T')[0];
|
||||||
|
|
||||||
// --- CÁLCULO DE KPIs CORREGIDO ---
|
// 1. LIMPIAR DATOS
|
||||||
|
// Filtramos los archivados y los que ya están importados del Scraped (porque los importados ya vienen en activeList)
|
||||||
|
const trueScraped = scrapedList.filter(s => s.status !== 'archived' && s.status !== 'imported');
|
||||||
|
const trueActive = activeList.filter(s => s.status !== 'archived');
|
||||||
|
|
||||||
// 1. Total (Solución al fallo de la suma doble)
|
// Unimos todo en una gran lista para los gráficos globales
|
||||||
const totalActive = activeServices.length;
|
const allServices = [...trueScraped, ...trueActive];
|
||||||
|
|
||||||
// 2. Sin Asignar
|
// --- CÁLCULO DE KPIs ---
|
||||||
const unassignedCount = activeServices.filter(s => s.status === 'pending' && s.automation_status !== 'in_progress').length;
|
|
||||||
|
|
||||||
// 3. En Rueda
|
|
||||||
const queueCount = activeServices.filter(s => s.status === 'pending' && s.automation_status === 'in_progress').length;
|
|
||||||
|
|
||||||
// 4. Asignados sin cita (Pendientes)
|
// 1. Total (La suma de los dos mundos)
|
||||||
const pendingCount = activeServices.filter(s => s.status === 'imported' && (!s.raw_data.scheduled_date || s.raw_data.scheduled_date === "")).length;
|
const totalActive = allServices.length;
|
||||||
|
|
||||||
// 5. Citas de hoy
|
|
||||||
const todayVisits = activeServices.filter(s => s.raw_data && s.raw_data.scheduled_date === todayStr);
|
|
||||||
|
|
||||||
// 6. Urgencias (NUEVO)
|
// 2. Sin Asignar (Los de scraped que no están en rueda)
|
||||||
const urgentVisits = activeServices.filter(s => {
|
const unassignedCount = trueScraped.filter(s => s.automation_status !== 'in_progress').length;
|
||||||
|
|
||||||
|
// 3. En Rueda (Los de scraped buscando operario)
|
||||||
|
const queueCount = trueScraped.filter(s => s.automation_status === 'in_progress').length;
|
||||||
|
|
||||||
|
// 4. Asignados sin cita (Los activos que no tienen fecha agendada)
|
||||||
|
const pendingCount = trueActive.filter(s => !s.raw_data.scheduled_date || s.raw_data.scheduled_date === "").length;
|
||||||
|
|
||||||
|
// 5. Citas de hoy (Los activos con fecha de hoy)
|
||||||
|
const todayVisits = trueActive.filter(s => s.raw_data.scheduled_date === todayStr);
|
||||||
|
|
||||||
|
// 6. Urgencias (Cualquiera que tenga la palabra URGENTE)
|
||||||
|
const urgentVisits = allServices.filter(s => {
|
||||||
const raw = s.raw_data || {};
|
const raw = s.raw_data || {};
|
||||||
return raw['Urgente'] === 'Sí' || raw['Urgente'] === 'true' || raw['URGENTE'] === 'SI';
|
return raw['Urgente'] === 'Sí' || raw['Urgente'] === 'true' || raw['URGENTE'] === 'SI';
|
||||||
});
|
});
|
||||||
@@ -226,8 +235,8 @@
|
|||||||
// --- RENDERIZAR WIDGETS ---
|
// --- RENDERIZAR WIDGETS ---
|
||||||
renderTodaySchedule(todayVisits);
|
renderTodaySchedule(todayVisits);
|
||||||
renderUrgentSchedule(urgentVisits);
|
renderUrgentSchedule(urgentVisits);
|
||||||
renderCompanyDistribution(activeServices);
|
renderCompanyDistribution(allServices);
|
||||||
renderLatestActivity(allServices); // Aquí pasamos todos para ver los recién entrados
|
renderLatestActivity(allServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
// WIDGET 1: Agenda Hoy
|
// WIDGET 1: Agenda Hoy
|
||||||
@@ -247,7 +256,7 @@
|
|||||||
container.innerHTML = visits.map(s => {
|
container.innerHTML = visits.map(s => {
|
||||||
const raw = s.raw_data;
|
const raw = s.raw_data;
|
||||||
const time = raw.scheduled_time ? raw.scheduled_time.substring(0,5) : "--:--";
|
const time = raw.scheduled_time ? raw.scheduled_time.substring(0,5) : "--:--";
|
||||||
const op = s.current_worker_name || raw.assigned_to_name || "Sin Asignar";
|
const op = s.assigned_name || raw.assigned_to_name || "Sin Asignar";
|
||||||
const name = raw['Nombre Cliente'] || raw['CLIENTE'] || "Asegurado";
|
const name = raw['Nombre Cliente'] || raw['CLIENTE'] || "Asegurado";
|
||||||
const pop = raw['Población'] || raw['POBLACION-PROVINCIA'] || "Dirección no especificada";
|
const pop = raw['Población'] || raw['POBLACION-PROVINCIA'] || "Dirección no especificada";
|
||||||
|
|
||||||
@@ -295,7 +304,7 @@
|
|||||||
container.innerHTML = visits.map(s => {
|
container.innerHTML = visits.map(s => {
|
||||||
const raw = s.raw_data;
|
const raw = s.raw_data;
|
||||||
const name = raw['Nombre Cliente'] || raw['CLIENTE'] || "Asegurado";
|
const name = raw['Nombre Cliente'] || raw['CLIENTE'] || "Asegurado";
|
||||||
const op = s.current_worker_name || raw.assigned_to_name || "Buscando Operario...";
|
const op = s.assigned_name || raw.assigned_to_name || "Buscando Operario...";
|
||||||
return `
|
return `
|
||||||
<div class="p-4 rounded-2xl bg-red-50/50 border border-red-100 flex justify-between items-center">
|
<div class="p-4 rounded-2xl bg-red-50/50 border border-red-100 flex justify-between items-center">
|
||||||
<div>
|
<div>
|
||||||
@@ -309,12 +318,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WIDGET 3: Distribución Compañías
|
// WIDGET 3: Distribución Compañías
|
||||||
function renderCompanyDistribution(activeServices) {
|
function renderCompanyDistribution(allServices) {
|
||||||
const container = document.getElementById("companyDistribution");
|
const container = document.getElementById("companyDistribution");
|
||||||
if (activeServices.length === 0) { container.innerHTML = "<p class="text-xs text-slate-400">Sin datos</p>"; return; }
|
if (allServices.length === 0) { container.innerHTML = "<p class='text-xs text-slate-400'>Sin datos</p>"; return; }
|
||||||
|
|
||||||
const counts = {};
|
const counts = {};
|
||||||
activeServices.forEach(s => {
|
allServices.forEach(s => {
|
||||||
const raw = s.raw_data || {};
|
const raw = s.raw_data || {};
|
||||||
let comp = (raw['Compañía'] || raw['COMPAÑIA'] || raw['Procedencia'] || (s.provider === 'MANUAL' ? 'PARTICULAR' : 'OTRA')).toUpperCase().trim();
|
let comp = (raw['Compañía'] || raw['COMPAÑIA'] || raw['Procedencia'] || (s.provider === 'MANUAL' ? 'PARTICULAR' : 'OTRA')).toUpperCase().trim();
|
||||||
if(comp.includes("HOMESERVE")) comp = "HOMESERVE";
|
if(comp.includes("HOMESERVE")) comp = "HOMESERVE";
|
||||||
@@ -342,7 +351,7 @@
|
|||||||
// WIDGET 4: Última Actividad
|
// WIDGET 4: Última Actividad
|
||||||
function renderLatestActivity(allServices) {
|
function renderLatestActivity(allServices) {
|
||||||
const container = document.getElementById("latestActivity");
|
const container = document.getElementById("latestActivity");
|
||||||
// Ordenar por ID o Created At descendente y coger 5
|
// Ordenar por fecha de creación descendente (el ID suele ser correlativo)
|
||||||
const latest = allServices.sort((a, b) => b.id - a.id).slice(0, 5);
|
const latest = allServices.sort((a, b) => b.id - a.id).slice(0, 5);
|
||||||
|
|
||||||
if (latest.length === 0) { container.innerHTML = "<p class='text-xs text-slate-400'>Sin actividad reciente</p>"; return; }
|
if (latest.length === 0) { container.innerHTML = "<p class='text-xs text-slate-400'>Sin actividad reciente</p>"; return; }
|
||||||
@@ -369,7 +378,7 @@
|
|||||||
let start = 0;
|
let start = 0;
|
||||||
const duration = 800;
|
const duration = 800;
|
||||||
const range = end - start;
|
const range = end - start;
|
||||||
if(range === 0) { obj.innerText = "0"; return; }
|
if(range === 0) { obj.innerText = end; return; }
|
||||||
const minTimer = 50;
|
const minTimer = 50;
|
||||||
let stepTime = Math.abs(Math.floor(duration / range));
|
let stepTime = Math.abs(Math.floor(duration / range));
|
||||||
stepTime = Math.max(stepTime, minTimer);
|
stepTime = Math.max(stepTime, minTimer);
|
||||||
|
|||||||
Reference in New Issue
Block a user