Actualizar automatizaciones.html

This commit is contained in:
2026-02-13 18:19:11 +00:00
parent 375ba5351e
commit 72e28a2c6d

View File

@@ -2,107 +2,128 @@
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Buzón Inteligente - Integra Repara</title>
<title>Buzón de Entrada - Integra Repara</title>
<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">
<style>
body { background-color: #f1f5f9; font-family: 'Inter', sans-serif; }
.service-card { border: none; border-radius: 12px; background: white; border-left: 6px solid #22c55e; margin-bottom: 1rem; }
.badge-provider { font-weight: 800; font-size: 0.7rem; padding: 4px 10px; border-radius: 20px; text-transform: uppercase; }
.homeserve { background: #fee2e2; color: #991b1b; }
body { background-color: #f8fafc; font-family: 'Inter', sans-serif; }
.service-card { border: none; border-radius: 15px; background: white; transition: all 0.2s; border-left: 6px solid #e2e8f0; }
.service-card.ready { border-left-color: #22c55e; }
.badge-provider { font-weight: 800; font-size: 0.7rem; padding: 4px 12px; border-radius: 50px; text-transform: uppercase; }
.multiasistencia { background: #dbeafe; color: #1e40af; }
.homeserve { background: #fee2e2; color: #991b1b; }
.data-label { font-weight: 700; color: #64748b; font-size: 0.75rem; text-transform: uppercase; display: block; }
.data-value { color: #1e293b; font-weight: 500; }
</style>
</head>
<body>
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="fw-bold"><i class="fas fa-inbox text-primary me-2"></i>Buzón con Mapeo Activo</h2>
<button onclick="init()" class="btn btn-outline-primary rounded-pill"><i class="fas fa-sync-alt"></i></button>
<div class="d-flex justify-content-between align-items-center mb-5">
<div>
<h2 class="fw-bold mb-0">Buzón de Entrada</h2>
<p class="text-muted">Servicios pendientes de revisión e importación</p>
</div>
<button onclick="fetchData()" class="btn btn-primary rounded-pill px-4 shadow-sm">
<i class="fas fa-sync-alt me-2"></i>Actualizar
</button>
</div>
<div id="inboxContainer"></div>
<div id="inbox" class="row g-4">
</div>
</div>
<script src="./js/layout.js"></script>
<script>
let userMappings = {};
let myRules = {};
async function init() {
const container = document.getElementById('inboxContainer');
container.innerHTML = '<div class="text-center py-5"><div class="spinner-border text-primary"></div><p>Aplicando tus reglas de mapeo...</p></div>';
async function fetchData() {
const container = document.getElementById('inbox');
container.innerHTML = '<div class="col-12 text-center py-5"><div class="spinner-border text-primary"></div></div>';
try {
// 1. Cargamos los servicios detectados
const svcRes = await fetch(`${API_URL}/providers/scraped`, {
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
});
const svcData = await svcRes.json();
// Cargamos servicios y mapeos
const [svcRes, mapRes] = await Promise.all([
fetch(`${API_URL}/providers/scraped`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }}),
fetch(`${API_URL}/discovery/mappings`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }})
]);
// 2. Cargamos tus reglas de mapeo (el diccionario que hiciste)
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) => {
const services = await svcRes.json();
const mappings = await mapRes.json();
// Organizamos reglas: myRules['multiasistencia']['clientName'] = 'Asegurado'
myRules = mappings.reduce((acc, curr) => {
if (!acc[curr.provider]) acc[curr.provider] = {};
acc[curr.provider][curr.target_key] = curr.original_key;
return acc;
}, {});
renderInbox(svcData.services);
render(services.services);
} catch (e) {
container.innerHTML = '<div class="alert alert-danger">Error al cargar datos o mapeos.</div>';
container.innerHTML = '<div class="alert alert-danger">Error al sincronizar con el servidor.</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>';
function render(list) {
const container = document.getElementById('inbox');
if (!list || list.length === 0) {
container.innerHTML = '<div class="col-12 text-center py-5 text-muted">No hay servicios nuevos en el buzón.</div>';
return;
}
container.innerHTML = '';
services.forEach(svc => {
list.forEach(svc => {
const raw = svc.raw_data || {};
const provider = svc.provider;
const myMap = userMappings[provider] || {};
const rules = myRules[svc.provider] || {};
// APLICAMOS TU MAPEO: "Busca lo que yo te dije que es el nombre"
const name = raw[myMap['clientName']] || raw.clientName_fixed || "Sin nombre";
const addr = raw[myMap['address']] || raw.address_fixed || "Sin dirección";
const phone = raw[myMap['phone']] || raw.phone_fixed || "Sin teléfono";
// Sacamos los datos que TÚ configuraste
const name = raw[rules['clientName']] || "Nombre no mapeado";
const addr = raw[rules['address']] || "Dirección no mapeada";
const phone = raw[rules['phone']] || "Teléfono no mapeado";
const isReady = name !== "Nombre no mapeado";
const card = document.createElement('div');
card.className = 'service-card shadow-sm p-4 d-flex justify-content-between align-items-center';
card.innerHTML = `
<div>
<span class="badge-provider ${provider}">${provider}</span>
<h5 class="fw-bold mt-2 mb-1">${name}</h5>
<div class="small text-secondary">
<i class="fas fa-map-marker-alt"></i> ${addr} |
<i class="fas fa-phone"></i> ${phone}
const div = document.createElement('div');
div.className = 'col-12';
div.innerHTML = `
<div class="service-card shadow-sm p-4 ${isReady ? 'ready' : ''} d-flex justify-content-between align-items-center">
<div class="row w-100 align-items-center">
<div class="col-md-2 border-end">
<span class="badge-provider ${svc.provider}">${svc.provider}</span>
<div class="mt-2 fw-bold text-muted small">REF: ${svc.service_ref}</div>
</div>
<div class="col-md-3">
<span class="data-label">Cliente</span>
<span class="data-value">${name}</span>
</div>
<div class="col-md-4">
<span class="data-label">Ubicación</span>
<span class="data-value">${addr}</span>
</div>
<div class="col-md-2">
<span class="data-label">Contacto</span>
<span class="data-value">${phone}</span>
</div>
<div class="col-md-1 text-end">
<button onclick="doImport(${svc.id})" class="btn btn-success btn-sm rounded-circle shadow">
<i class="fas fa-check"></i>
</button>
</div>
</div>
</div>
<button onclick="importSvc(${svc.id})" class="btn btn-success fw-bold rounded-pill">IMPORTAR</button>
`;
container.appendChild(card);
container.appendChild(div);
});
}
async function importSvc(id) {
async function doImport(id) {
const res = await fetch(`${API_URL}/providers/import/${id}`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
});
const data = await res.json();
if(data.ok) { alert("¡Importado correctamente!"); init(); }
if ((await res.json()).ok) fetchData();
}
document.addEventListener('DOMContentLoaded', init);
document.addEventListener('DOMContentLoaded', fetchData);
</script>
</body>
</html>