sistema de usuarios completo

This commit is contained in:
2025-09-24 18:03:34 -06:00
parent 11b95c97a7
commit 9f35550e58
3 changed files with 170 additions and 28 deletions

View File

@@ -41,6 +41,10 @@
<button id="exportCsv">Exportar CSV</button>
<button id="addUser">Añadir usuario</button>
</div>
<h3>Usuarios</h3>
<div id="users"></div>
<hr />
<h3>Eventos</h3>
<div id="list" class="list"></div>
<div id="modal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); align-items:center; justify-content:center;">
<div style="background:#fff; color:#222; padding:16px; border-radius:8px; min-width:300px; max-width:90%;">
@@ -60,6 +64,7 @@
<script>
const list = document.getElementById('list');
const usersDiv = document.getElementById('users');
const statusEl = document.getElementById('status');
const countEl = document.getElementById('count');
const btnRefresh = document.getElementById('refresh');
@@ -110,6 +115,63 @@ async function loadHistory() {
history.forEach(renderItem);
}
async function loadUsers() {
const r = await fetch('/api/users');
const data = await r.json();
const users = data.items || [];
usersDiv.innerHTML = '';
const table = document.createElement('table');
table.style.width = '100%';
table.cellPadding = 6;
table.innerHTML = `<tr><th>Usuario</th><th>VLAN</th><th>Estado</th><th>Acciones</th></tr>`;
users.forEach(u => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${u.username}</td>
<td>${u.vlan}</td>
<td>${u.disabled ? 'Desactivado' : 'Activo'}</td>
<td>
<button data-edit="${u.username}">Editar</button>
<button data-toggle="${u.username}">${u.disabled ? 'Activar' : 'Desactivar'}</button>
<button data-del="${u.username}">Eliminar</button>
</td>`;
table.appendChild(tr);
});
usersDiv.appendChild(table);
usersDiv.querySelectorAll('button[data-edit]').forEach(btn => btn.addEventListener('click', () => editUser(btn.getAttribute('data-edit'))));
usersDiv.querySelectorAll('button[data-toggle]').forEach(btn => btn.addEventListener('click', () => toggleUser(btn.getAttribute('data-toggle'))));
usersDiv.querySelectorAll('button[data-del]').forEach(btn => btn.addEventListener('click', () => deleteUser(btn.getAttribute('data-del'))));
}
async function editUser(username) {
const r = await fetch('/api/users');
const data = await r.json();
const u = (data.items || []).find(x => x.username === username);
if (!u) return alert('Usuario no encontrado');
modal.style.display = 'flex';
u_username.value = u.username;
u_password.value = u.password || '';
u_vlan.value = u.vlan || '2';
}
async function toggleUser(username) {
const r = await fetch('/api/users');
const data = await r.json();
const u = (data.items || []).find(x => x.username === username);
if (!u) return alert('Usuario no encontrado');
await fetch(`/api/users/${encodeURIComponent(username)}`, {
method: 'PATCH', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ disabled: !u.disabled })
});
await loadUsers();
}
async function deleteUser(username) {
if (!confirm(`¿Eliminar usuario ${username}?`)) return;
await fetch(`/api/users/${encodeURIComponent(username)}`, { method: 'DELETE' });
await loadUsers();
}
btnRefresh.addEventListener('click', loadHistory);
btnSelfTest.addEventListener('click', async () => {
@@ -196,6 +258,7 @@ saveUser.addEventListener('click', async () => {
if (!data.ok) throw new Error(data.error || 'Error desconocido');
modal.style.display = 'none';
alert('Usuario guardado');
await loadUsers();
} catch (e) {
alert('Error al guardar: ' + e.message);
}
@@ -218,7 +281,7 @@ function connectSSE() {
es.addEventListener('clear', () => { loadHistory(); });
}
loadHistory().then(connectSSE);
Promise.all([loadUsers(), loadHistory()]).then(connectSSE);
</script>
</body>
</html>