139 lines
6.1 KiB
HTML
139 lines
6.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Robots y Automatizaciones - 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: #f8fafc; font-family: 'Inter', sans-serif; }
|
|
.card-robot { border: none; border-radius: 12px; transition: all 0.3s ease; border-left: 5px solid #cbd5e1; }
|
|
.card-robot.active { border-left-color: #22c55e; }
|
|
.card-robot.inactive { border-left-color: #ef4444; }
|
|
.service-item { border-radius: 10px; background: white; border: 1px solid #e2e8f0; }
|
|
.badge-provider { font-size: 0.7rem; font-weight: 800; text-transform: uppercase; padding: 4px 8px; }
|
|
.provider-homeserve { background-color: #fee2e2; color: #991b1b; }
|
|
.provider-multiasistencia { background-color: #dbeafe; color: #1e40af; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="container-fluid py-4">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<h4 class="mb-4 fw-bold">🤖 Gestión de Robots</h4>
|
|
|
|
<div id="robotsContainer">
|
|
</div>
|
|
|
|
<div class="card shadow-sm mt-4 bg-dark text-white">
|
|
<div class="card-body">
|
|
<h6 class="text-secondary small">LOG DE ACTIVIDAD</h6>
|
|
<div id="logConsole" class="small font-monospace" style="height: 150px; overflow-y: auto;">
|
|
> Sistema iniciado...<br>
|
|
> Esperando sincronización...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-8">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h4 class="fw-bold">Buzón de Servicios Detectados</h4>
|
|
<button onclick="loadScrapedServices()" class="btn btn-outline-primary btn-sm rounded-pill">
|
|
<i class="fas fa-sync-alt me-2"></i>Actualizar Buzón
|
|
</button>
|
|
</div>
|
|
|
|
<div id="servicesInbox" class="d-flex flex-column gap-3">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="./js/layout.js"></script>
|
|
<script>
|
|
// 1. CARGAR SERVICIOS DEL ROBOT
|
|
async function loadScrapedServices() {
|
|
const inbox = document.getElementById('servicesInbox');
|
|
inbox.innerHTML = '<div class="text-center py-5"><div class="spinner-border text-primary"></div></div>';
|
|
|
|
try {
|
|
const res = await fetch(`${API_URL}/providers/scraped`, {
|
|
headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.services.length === 0) {
|
|
inbox.innerHTML = '<div class="alert alert-light text-center border-dashed py-5">No hay servicios nuevos pendientes.</div>';
|
|
return;
|
|
}
|
|
|
|
inbox.innerHTML = '';
|
|
data.services.forEach(svc => {
|
|
const raw = svc.raw_data;
|
|
// NOTA: Aquí usamos los campos "_fixed" que crea el robot inteligente
|
|
// o fallbacks manuales para que no salga 'undefined'
|
|
const name = raw.clientName_fixed || raw.clientName || "Cliente sin nombre";
|
|
const addr = raw.address_fixed || raw.address || "Sin dirección";
|
|
const phone = raw.phone_fixed || raw.phone || "Sin teléfono";
|
|
|
|
const card = document.createElement('div');
|
|
card.className = 'service-item p-3 shadow-sm d-flex justify-content-between align-items-center';
|
|
card.innerHTML = `
|
|
<div class="flex-grow-1">
|
|
<div class="d-flex align-items-center gap-2 mb-1">
|
|
<span class="badge badge-provider provider-${svc.provider}">${svc.provider}</span>
|
|
<span class="text-muted small">#${svc.service_ref}</span>
|
|
<span class="text-muted small"><i class="far fa-clock ms-2"></i> ${new Date(svc.created_at).toLocaleTimeString()}</span>
|
|
</div>
|
|
<h6 class="mb-1 fw-bold">${name}</h6>
|
|
<div class="small text-secondary">
|
|
<i class="fas fa-map-marker-alt me-1"></i> ${addr} |
|
|
<i class="fas fa-phone ms-2 me-1"></i> ${phone}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button onclick="importService(${svc.id})" class="btn btn-success btn-sm px-4">
|
|
<i class="fas fa-download me-2"></i>Importar
|
|
</button>
|
|
</div>
|
|
`;
|
|
inbox.appendChild(card);
|
|
});
|
|
} catch (e) {
|
|
inbox.innerHTML = '<div class="alert alert-danger">Error al conectar con el servidor.</div>';
|
|
}
|
|
}
|
|
|
|
// 2. IMPORTAR SERVICIO AL CRM
|
|
async function importService(id) {
|
|
if (!confirm("¿Importar este servicio a tu CRM usando tus reglas de mapeo?")) return;
|
|
|
|
try {
|
|
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("✅ Servicio importado correctamente.");
|
|
loadScrapedServices(); // Recargar lista
|
|
} else {
|
|
alert("❌ Error: " + data.error);
|
|
}
|
|
} catch (e) {
|
|
alert("Error en la conexión.");
|
|
}
|
|
}
|
|
|
|
// Inicializar al cargar
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
loadScrapedServices();
|
|
// Aquí podrías cargar también las credenciales si quieres el panel completo
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html> |