97 lines
5.2 KiB
HTML
97 lines
5.2 KiB
HTML
<!-- Vista: Logs de despacho SaaS — historial de notificaciones de pago -->
|
||
<div x-data="dispatchLogsApp()" x-init="init()" class="bg-white rounded-lg shadow">
|
||
<div class="container mx-auto p-6 w-full">
|
||
<div class="flex items-center gap-3 mb-1">
|
||
<a href="/app/saas-api" class="text-blue-500 hover:underline text-sm">← Integraciones</a>
|
||
</div>
|
||
<h1 class="text-2xl font-bold mb-1">Logs de despacho</h1>
|
||
<p class="text-sm text-gray-500 mb-4">Historial de notificaciones enviadas a SaaS externos al confirmar pagos.</p>
|
||
|
||
<!-- Tabla -->
|
||
<div class="overflow-x-auto">
|
||
<table class="table-auto w-full text-sm">
|
||
<thead class="border-b border-gray-200 text-left font-semibold text-gray-600">
|
||
<tr>
|
||
<th class="py-2 px-3 border-b">Fecha</th>
|
||
<th class="py-2 px-3 border-b">Contrato</th>
|
||
<th class="py-2 px-3 border-b">Email</th>
|
||
<th class="py-2 px-3 border-b">Integración</th>
|
||
<th class="py-2 px-3 border-b">Fuente</th>
|
||
<th class="py-2 px-3 border-b">HTTP</th>
|
||
<th class="py-2 px-3 border-b">Estado</th>
|
||
<th class="py-2 px-3 border-b">Respuesta</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="text-gray-500">
|
||
<template x-if="items.length === 0 && !loading">
|
||
<tr><td colspan="8" class="py-4 text-center text-gray-400">Sin registros</td></tr>
|
||
</template>
|
||
<template x-for="item in items" :key="item.ID">
|
||
<tr class="hover:bg-gray-50 border-b border-gray-100">
|
||
<td class="py-2 px-3 text-xs whitespace-nowrap" x-text="fmtDate(item.CreatedAt)"></td>
|
||
<td class="py-2 px-3 font-mono text-xs" x-text="item.referencia || ('#' + item.contrato_id)"></td>
|
||
<td class="py-2 px-3 text-xs" x-text="item.payer_email || '-'"></td>
|
||
<td class="py-2 px-3 text-xs" x-text="item.SaasApiConfig ? item.SaasApiConfig.nombre : ('#' + item.saas_api_config_id)"></td>
|
||
<td class="py-2 px-3">
|
||
<span x-text="item.fuente"
|
||
:class="item.fuente === 'dlocal' ? 'bg-purple-100 text-purple-700' : item.fuente === 'bold' ? 'bg-orange-100 text-orange-700' : 'bg-gray-100 text-gray-600'"
|
||
class="text-xs px-2 py-0.5 rounded-full capitalize"></span>
|
||
</td>
|
||
<td class="py-2 px-3 text-xs font-mono" x-text="item.http_status || '-'"></td>
|
||
<td class="py-2 px-3">
|
||
<span x-text="item.estado"
|
||
:class="item.estado === 'success' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'"
|
||
class="text-xs px-2 py-0.5 rounded-full"></span>
|
||
</td>
|
||
<td class="py-2 px-3 max-w-xs">
|
||
<span x-show="!item.error_msg && item.respuesta" class="font-mono text-xs text-gray-600 truncate block" x-text="item.respuesta"></span>
|
||
<span x-show="item.error_msg" class="font-mono text-xs text-red-500 truncate block" x-text="item.error_msg"></span>
|
||
</td>
|
||
</tr>
|
||
</template>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Loading -->
|
||
<div x-show="loading" class="py-6 text-center text-gray-400 text-sm">Cargando…</div>
|
||
|
||
<!-- Paginación -->
|
||
<div class="flex justify-between items-center mt-4 text-sm text-gray-500">
|
||
<span>Total: <b x-text="total"></b></span>
|
||
<div class="flex gap-1">
|
||
<button @click="load(page-1)" :disabled="page<=1" class="px-3 py-1 border rounded disabled:opacity-40">‹</button>
|
||
<span class="px-3 py-1" x-text="'Pág. ' + page + ' / ' + totalPages"></span>
|
||
<button @click="load(page+1)" :disabled="page>=totalPages" class="px-3 py-1 border rounded disabled:opacity-40">›</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function dispatchLogsApp() {
|
||
return {
|
||
items: [],
|
||
total: 0, totalPages: 1, page: 1, limit: 30,
|
||
loading: false,
|
||
async init() { await this.load(1); },
|
||
async load(p) {
|
||
if (p < 1 || (this.totalPages > 0 && p > this.totalPages)) return;
|
||
this.loading = true;
|
||
this.page = p;
|
||
const res = await fetch(`/app/loadsaasdispatchlogs?page=${p}`);
|
||
const data = await res.json();
|
||
this.items = data.items || [];
|
||
this.total = data.total;
|
||
this.totalPages = data.totalPages;
|
||
this.loading = false;
|
||
},
|
||
fmtDate(s) {
|
||
if (!s) return '-';
|
||
const d = new Date(s);
|
||
return d.toLocaleDateString('es-CO') + ' ' + d.toLocaleTimeString('es-CO', {hour:'2-digit', minute:'2-digit'});
|
||
},
|
||
};
|
||
}
|
||
</script>
|