Actualizar automatizaciones.html

This commit is contained in:
2026-02-15 21:29:50 +00:00
parent 7662d4460e
commit d2b5788833

View File

@@ -45,7 +45,7 @@
<tr class="bg-gray-50 text-[10px] font-black uppercase text-gray-400 border-b">
<th class="p-4">Expediente / Cliente</th>
<th class="p-4">Dirección y Contacto</th>
<th class="p-4">Operarios que fallaron</th>
<th class="p-4">Motivo</th>
<th class="p-4 text-right">Acción</th>
</tr>
</thead>
@@ -57,11 +57,49 @@
</div>
</div>
<div id="rescueModal" class="fixed inset-0 bg-slate-900/80 hidden z-[100] flex items-center justify-center backdrop-blur-sm p-4 text-left text-left">
<div class="bg-white rounded-[2rem] shadow-2xl w-full max-w-2xl flex flex-col max-h-[90vh] overflow-hidden border border-slate-200 fade-in text-left">
<div class="px-6 py-4 border-b border-slate-100 flex justify-between items-center bg-slate-50/50 text-left">
<h3 class="font-black text-slate-800 uppercase tracking-tight flex items-center gap-2 text-left">
<i data-lucide="life-buoy" class="text-red-500 w-5 h-5 text-left"></i> Rescate Manual: #<span id="resRef">--</span>
</h3>
<button onclick="closeRescueModal()" class="text-slate-400 hover:text-red-500 transition-colors text-left"><i data-lucide="x"></i></button>
</div>
<div class="p-6 overflow-y-auto space-y-6 no-scrollbar text-left">
<div class="grid grid-cols-2 gap-4 text-left">
<div class="bg-blue-50/50 p-4 rounded-2xl border border-blue-100 relative text-left">
<span class="text-[9px] font-black text-blue-400 uppercase absolute top-2 left-4 text-left">Asegurado</span>
<p id="resName" class="font-black text-slate-800 uppercase mt-2 text-sm text-left">--</p>
<a id="resPhoneLink" href="#" class="text-emerald-600 font-black text-xs flex items-center gap-1 mt-1 text-left"><i data-lucide="phone" class="w-3 h-3 text-left"></i> <span id="resPhone">--</span></a>
</div>
<div class="bg-slate-50 p-4 rounded-2xl border border-slate-100 relative text-left">
<span class="text-[9px] font-black text-slate-400 uppercase absolute top-2 left-4 text-left">Ubicación</span>
<p id="resAddr" class="font-bold text-slate-700 text-[11px] leading-tight mt-2 uppercase text-left">--</p>
</div>
</div>
<div class="space-y-1 text-left">
<label class="text-[10px] font-black text-slate-400 uppercase ml-2 text-left">Avería del Expediente</label>
<div id="resDesc" class="p-4 bg-slate-50 rounded-2xl text-xs font-medium text-slate-600 border border-slate-100 text-left">--</div>
</div>
<div class="space-y-3 text-left">
<h4 class="text-[10px] font-black text-red-500 uppercase tracking-widest ml-2 text-left">Operarios Disponibles (Llamar para asignar)</h4>
<div id="resWorkersList" class="space-y-2 text-left"></div>
</div>
</div>
<div class="p-4 bg-slate-50 border-t border-slate-100 flex gap-3 text-left">
<button onclick="deleteFailedEntry()" class="bg-white border border-slate-200 text-slate-400 p-3 rounded-xl hover:text-red-500 text-left"><i data-lucide="trash-2"></i></button>
<button onclick="window.location.href='validar.html'" class="flex-1 bg-slate-900 text-white font-black py-4 rounded-2xl text-xs uppercase tracking-widest hover:bg-blue-600 transition-all text-left flex justify-center">Asignar Manualmente</button>
</div>
</div>
</div>
<div id="toast" class="fixed bottom-5 right-5 bg-slate-800 text-white px-6 py-3 rounded-lg shadow-2xl transform translate-y-20 opacity-0 transition-all duration-300 z-50 flex items-center gap-3"><span id="toastMsg">Mensaje</span></div>
<script src="js/layout.js"></script>
<script>
let activeIntervals = [];
let scrapedData = []; // Para almacenar datos localmente
let currentRescueId = null;
document.addEventListener("DOMContentLoaded", () => {
if (!localStorage.getItem("token")) { window.location.href = "index.html"; return; }
@@ -76,26 +114,18 @@
});
const data = await res.json();
if (data.ok) {
scrapedData = data.services || [];
activeIntervals.forEach(clearInterval);
activeIntervals = [];
// Solo mostramos arriba los que están en progreso Y TIENEN un operario con el turno activo
const inQueue = data.services.filter(s =>
s.automation_status === 'in_progress' && s.current_worker_name !== null
);
// Se consideran fallidos los que están marcados como 'failed'
// O los que están 'in_progress' pero ya no tienen a nadie en turno (ronda terminada)
const failed = data.services.filter(s =>
s.automation_status === 'failed' ||
(s.automation_status === 'in_progress' && s.current_worker_name === null)
);
const inQueue = scrapedData.filter(s => s.automation_status === 'in_progress' && s.current_worker_name !== null);
const failed = scrapedData.filter(s => s.automation_status === 'failed' || (s.automation_status === 'in_progress' && s.current_worker_name === null));
renderCards(inQueue);
renderFailedTable(failed);
}
} catch (e) { console.error(e); }
}
}
function renderCards(activeServices) {
const container = document.getElementById('automation-list');
@@ -174,22 +204,16 @@
function renderFailedTable(failedServices) {
const tbody = document.getElementById('failed-list');
if (failedServices.length === 0) {
tbody.innerHTML = `<tr><td colspan="4" class="p-8 text-center text-gray-400 italic">No hay expedientes fallidos ahora.</td></tr>`;
tbody.innerHTML = `<tr><td colspan="4" class="p-8 text-center text-gray-400 italic">No hay fallidos ahora.</td></tr>`;
return;
}
tbody.innerHTML = failedServices.map(s => {
const raw = s.raw_data || {};
const name = raw["Nombre Cliente"] || raw["CLIENTE"] || "Asegurado Desconocido";
const phone = (raw["Teléfono"] || raw["TELEFONO"] || "").match(/[6789]\d{8}/)?.[0] || "";
const address = raw["Dirección"] || raw["DOMICILIO"] || "Sin dirección";
const population = raw["Población"] || raw["POBLACION-PROVINCIA"] || "";
const intentos = s.attempted_workers ? s.attempted_workers.join(', ') : "Sin registros";
return `
<tr class="border-b border-gray-50 hover:bg-slate-50 transition-all text-left">
<tr onclick="openRescue(${s.id})" class="border-b border-gray-50 hover:bg-slate-50 transition-all cursor-pointer text-left">
<td class="p-4 text-left">
<div class="flex flex-col text-left">
<span class="font-black text-slate-700 text-left">#${s.service_ref}</span>
@@ -199,26 +223,67 @@
<td class="p-4 text-left">
<div class="flex flex-col text-left">
<span class="text-xs font-bold text-slate-600 text-left">${address}</span>
<span class="text-[10px] text-gray-400 font-medium text-left">${population} ${raw["Código Postal"] ? '| CP: '+raw["Código Postal"] : ''}</span>
</div>
</td>
<td class="p-4 text-left">
<div class="bg-red-50 p-2 rounded-lg border border-red-100 text-left max-w-xs">
<p class="text-[9px] font-black text-red-500 uppercase leading-none mb-1 text-left">No contestaron:</p>
<p class="text-[10px] text-red-700 font-bold italic truncate text-left">${intentos}</p>
</div>
</td>
<td class="p-4 text-right text-left">
<div class="flex items-center justify-end gap-2 text-left">
${phone ? `<a href="tel:${phone}" class="bg-emerald-500 text-white p-2 rounded-lg hover:bg-emerald-600 shadow-sm text-left"><i data-lucide="phone" class="w-4 h-4"></i></a>` : ''}
<button onclick="window.location.href='validar.html'" class="bg-blue-600 text-white px-3 py-2 rounded-lg font-black text-[10px] uppercase shadow-md active:scale-95 text-left">Asignar a Mano</button>
<span class="text-[10px] text-gray-400 font-medium text-left">${raw["Población"] || ''} ${raw["Código Postal"] ? '| CP: '+raw["Código Postal"] : ''}</span>
</div>
</td>
<td class="p-4 text-left"><span class="text-[10px] font-black text-red-500 uppercase bg-red-100 px-2 py-0.5 rounded text-left">Nadie respondió</span></td>
<td class="p-4 text-right text-left"><i data-lucide="chevron-right" class="inline text-slate-300 text-left"></i></td>
</tr>`;
}).join('');
lucide.createIcons();
}
function openRescue(id) {
const svc = scrapedData.find(s => s.id === id);
if(!svc) return;
currentRescueId = id;
const raw = svc.raw_data || {};
document.getElementById('resRef').innerText = svc.service_ref;
document.getElementById('resName').innerText = raw["Nombre Cliente"] || raw["CLIENTE"] || "S/N";
const phone = (raw["Teléfono"] || raw["TELEFONO"] || "").match(/[6789]\d{8}/)?.[0] || "";
document.getElementById('resPhone').innerText = phone || "Sin Teléfono";
document.getElementById('resPhoneLink').href = phone ? `tel:${phone}` : "#";
document.getElementById('resAddr').innerText = `${raw["Dirección"] || ''} ${raw["Población"] || ''}`;
document.getElementById('resDesc').innerText = raw["Descripción"] || "Sin descripción disponible.";
const list = document.getElementById('resWorkersList');
const workers = svc.attempted_workers_data || [];
if (workers.length === 0) {
list.innerHTML = `<p class="text-[10px] text-slate-400 italic p-4 text-center border-2 border-dashed rounded-2xl">Sin registros de intentos WhatsApp.</p>`;
} else {
list.innerHTML = workers.map(w => `
<div class="flex items-center justify-between p-3 bg-white border border-red-100 rounded-xl shadow-sm text-left">
<div class="flex items-center gap-2 text-left">
<div class="w-2 h-2 rounded-full bg-red-400 text-left"></div>
<span class="text-xs font-black text-slate-700 uppercase text-left">${w.name}</span>
</div>
<a href="tel:${w.phone}" class="bg-red-50 text-red-600 px-3 py-1.5 rounded-lg text-[10px] font-black uppercase flex items-center gap-1 hover:bg-red-600 hover:text-white transition-all text-left">
<i data-lucide="phone" class="w-3 h-3 text-left"></i> Llamar
</a>
</div>
`).join('');
}
document.getElementById('rescueModal').classList.remove('hidden');
lucide.createIcons();
}
function closeRescueModal() { document.getElementById('rescueModal').classList.add('hidden'); }
async function deleteFailedEntry() {
if(!confirm("¿Deseas archivar este expediente fallido?")) return;
try {
const res = await fetch(`${API_URL}/providers/scraped/${currentRescueId}`, {
method: 'PUT',
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
body: JSON.stringify({ status: 'archived' })
});
if (res.ok) { closeRescueModal(); loadAutomations(); showToast("Expediente archivado"); }
} catch(e) { showToast("Error al borrar", true); }
}
async function stopAutomation(id) {
if(!confirm("¿Seguro que quieres detener el proceso automático?")) return;
try {