Actualizar automatizaciones.html

This commit is contained in:
2026-02-13 18:07:31 +00:00
parent 96a31a06fc
commit 375ba5351e

View File

@@ -2,15 +2,13 @@
<html lang="es"> <html lang="es">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Buzón Inteligente - Integra Repara</title> <title>Buzón Inteligente - Integra Repara</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style> <style>
body { background-color: #f1f5f9; font-family: 'Inter', sans-serif; } body { background-color: #f1f5f9; font-family: 'Inter', sans-serif; }
.service-card { border: none; border-radius: 12px; background: white; transition: transform 0.2s; border-left: 6px solid #3b82f6; } .service-card { border: none; border-radius: 12px; background: white; border-left: 6px solid #22c55e; margin-bottom: 1rem; }
.service-card:hover { transform: translateY(-3px); } .badge-provider { font-weight: 800; font-size: 0.7rem; padding: 4px 10px; border-radius: 20px; text-transform: uppercase; }
.badge-provider { font-weight: 800; font-size: 0.7rem; padding: 4px 10px; border-radius: 20px; }
.homeserve { background: #fee2e2; color: #991b1b; } .homeserve { background: #fee2e2; color: #991b1b; }
.multiasistencia { background: #dbeafe; color: #1e40af; } .multiasistencia { background: #dbeafe; color: #1e40af; }
</style> </style>
@@ -18,94 +16,93 @@
<body> <body>
<div class="container py-5"> <div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-5"> <div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold"><i class="fas fa-robot text-primary me-3"></i>Buzón de Servicios Detectados</h2> <h2 class="fw-bold"><i class="fas fa-inbox text-primary me-2"></i>Buzón con Mapeo Activo</h2>
<button onclick="loadServices()" class="btn btn-primary rounded-pill px-4"> <button onclick="init()" class="btn btn-outline-primary rounded-pill"><i class="fas fa-sync-alt"></i></button>
<i class="fas fa-sync-alt me-2"></i>Actualizar Buzón
</button>
</div> </div>
<div id="inboxContainer" class="d-flex flex-column gap-3"> <div id="inboxContainer"></div>
</div>
</div> </div>
<script src="./js/layout.js"></script> <script src="./js/layout.js"></script>
<script> <script>
async function loadServices() { let userMappings = {};
async function init() {
const container = document.getElementById('inboxContainer'); const container = document.getElementById('inboxContainer');
container.innerHTML = '<div class="text-center py-5"><div class="spinner-border text-primary"></div></div>'; container.innerHTML = '<div class="text-center py-5"><div class="spinner-border text-primary"></div><p>Aplicando tus reglas de mapeo...</p></div>';
try { try {
// 1. Cargamos servicios y mapeos al mismo tiempo // 1. Cargamos los servicios detectados
const [svcRes, mapRes] = await Promise.all([ const svcRes = await fetch(`${API_URL}/providers/scraped`, {
fetch(`${API_URL}/providers/scraped`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }}), headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
fetch(`${API_URL}/config/company`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }}) // Necesitamos una ruta que de los mappings, pero usaremos el importador inteligente del server });
]);
const svcData = await svcRes.json(); const svcData = await svcRes.json();
if (svcData.services.length === 0) { // 2. Cargamos tus reglas de mapeo (el diccionario que hiciste)
container.innerHTML = '<div class="alert alert-light text-center py-5 border-dashed">😴 No hay nada nuevo por aquí.</div>'; const mapRes = await fetch(`${API_URL}/discovery/mappings`, {
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
});
const mapData = await mapRes.json();
// Organizamos los mapeos por proveedor para acceso rápido
userMappings = mapData.reduce((acc, curr) => {
if (!acc[curr.provider]) acc[curr.provider] = {};
acc[curr.provider][curr.target_key] = curr.original_key;
return acc;
}, {});
renderInbox(svcData.services);
} catch (e) {
container.innerHTML = '<div class="alert alert-danger">Error al cargar datos o mapeos.</div>';
}
}
function renderInbox(services) {
const container = document.getElementById('inboxContainer');
if (!services || services.length === 0) {
container.innerHTML = '<p class="text-center">No hay servicios nuevos.</p>';
return; return;
} }
container.innerHTML = ''; container.innerHTML = '';
svcData.services.forEach(svc => { services.forEach(svc => {
const raw = svc.raw_data; const raw = svc.raw_data || {};
const provider = svc.provider;
const myMap = userMappings[provider] || {};
// --- LÓGICA DE VISUALIZACIÓN INTELIGENTE --- // APLICAMOS TU MAPEO: "Busca lo que yo te dije que es el nombre"
// Intentamos leer de los campos fijos del robot o de lo que sea que haya const name = raw[myMap['clientName']] || raw.clientName_fixed || "Sin nombre";
const name = raw.clientName_fixed || raw.clientName || raw.ASEGURADO || raw.CLIENTE || "Cliente Desconocido"; const addr = raw[myMap['address']] || raw.address_fixed || "Sin dirección";
const addr = raw.address_fixed || raw.address || raw.DOMICILIO || raw.DIRECCION || "Sin dirección"; const phone = raw[myMap['phone']] || raw.phone_fixed || "Sin teléfono";
const phone = raw.phone_fixed || raw.phone || raw.TELEFONO || raw.MOVIL || "Sin teléfono";
const desc = raw.description_fixed || raw.description || raw['Descripción de la Reparación'] || "Sin descripción disponible";
const card = document.createElement('div'); const card = document.createElement('div');
card.className = 'service-card shadow-sm p-4 d-flex justify-content-between align-items-center'; card.className = 'service-card shadow-sm p-4 d-flex justify-content-between align-items-center';
card.innerHTML = ` card.innerHTML = `
<div style="max-width: 70%;"> <div>
<div class="d-flex align-items-center gap-2 mb-2"> <span class="badge-provider ${provider}">${provider}</span>
<span class="badge-provider ${svc.provider}">${svc.provider.toUpperCase()}</span> <h5 class="fw-bold mt-2 mb-1">${name}</h5>
<span class="text-muted fw-bold small">#${svc.service_ref}</span> <div class="small text-secondary">
<span class="text-muted small ms-2"><i class="far fa-clock me-1"></i>${new Date(svc.created_at).toLocaleTimeString()}</span> <i class="fas fa-map-marker-alt"></i> ${addr} |
</div> <i class="fas fa-phone"></i> ${phone}
<h5 class="mb-1 fw-bold text-dark">${name}</h5>
<p class="mb-2 text-secondary small">
<i class="fas fa-map-marker-alt me-1 text-primary"></i> ${addr}
<i class="fas fa-phone ms-3 me-1 text-primary"></i> ${phone}
</p>
<div class="text-truncate text-muted small" style="max-width: 500px;">
${desc}
</div> </div>
</div> </div>
<button onclick="importNow(${svc.id})" class="btn btn-success px-4 py-2 fw-bold rounded-pill"> <button onclick="importSvc(${svc.id})" class="btn btn-success fw-bold rounded-pill">IMPORTAR</button>
<i class="fas fa-cloud-download-alt me-2"></i>IMPORTAR
</button>
`; `;
container.appendChild(card); container.appendChild(card);
}); });
} catch (e) {
container.innerHTML = '<div class="alert alert-danger">Error de conexión con la API.</div>';
}
} }
async function importNow(id) { async function importSvc(id) {
try {
const res = await fetch(`${API_URL}/providers/import/${id}`, { const res = await fetch(`${API_URL}/providers/import/${id}`, {
method: 'POST', method: 'POST',
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
}); });
const data = await res.json(); const data = await res.json();
if(data.ok) { if(data.ok) { alert("¡Importado correctamente!"); init(); }
alert("🚀 ¡Importado con éxito! Ya lo tienes en tu lista de servicios.");
loadServices();
} else {
alert("❌ Error: " + data.error);
}
} catch(e) { alert("Error de red."); }
} }
document.addEventListener('DOMContentLoaded', loadServices); document.addEventListener('DOMContentLoaded', init);
</script> </script>
</body> </body>
</html> </html>