Initial commit: EFINTEL ERP Django Port
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="header-section" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem;">
|
||||
<h1>Panel de Gestión Administrativa</h1>
|
||||
</div>
|
||||
|
||||
<div class="glass-card tabs-container" style="padding: 2rem;">
|
||||
<nav class="tabs-nav">
|
||||
<button class="tab-btn active" onclick="switchTab(event, 'tab-proyectos')">📁 Proyectos</button>
|
||||
<button class="tab-btn" onclick="switchTab(event, 'tab-responsables')">👥 Colaboradores / Responsables</button>
|
||||
<button class="tab-btn" onclick="switchTab(event, 'tab-config')">⚙️ Configuración</button>
|
||||
<button class="tab-btn" onclick="switchTab(event, 'tab-bitacora')">📜 Bitácora de Auditoría</button>
|
||||
</nav>
|
||||
|
||||
<!-- Pestaña Proyectos -->
|
||||
<div id="tab-proyectos" class="tab-content active">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem;">
|
||||
<h2>Proyectos del Sistema</h2>
|
||||
<a href="{% url 'project_create' %}" class="btn btn-primary">➕ Nuevo Proyecto</a>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Descripción</th>
|
||||
<th>Encargado (Responsable)</th>
|
||||
<th>Creado Por</th>
|
||||
<th>Última Modificación</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for project in projects %}
|
||||
<tr>
|
||||
<td style="font-weight: 600; color: var(--accent-secondary);">{{ project.name }}</td>
|
||||
<td>{{ project.description|default:"Sin descripción" }}</td>
|
||||
<td>
|
||||
{% if project.manager %}
|
||||
<span style="font-weight: 500;">{{ project.manager.username }}</span>
|
||||
{% else %}
|
||||
<em style="color: var(--text-secondary);">No asignado</em>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ project.created_by.username|default:"Sistema" }}</td>
|
||||
<td>{{ project.updated_at|date:"d/m/Y H:i" }}</td>
|
||||
<td>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<a href="{% url 'project_edit' project.id %}" class="btn btn-outline" style="padding: 0.35rem 0.75rem; font-size: 0.8rem;">✏️ Editar</a>
|
||||
<form action="{% url 'project_delete' project.id %}" method="POST" style="display: inline;" onsubmit="return confirm('¿Estás seguro de que deseas eliminar este proyecto? Se eliminarán todos los gastos asociados.');">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-danger" style="padding: 0.35rem 0.75rem; font-size: 0.8rem;">🗑️ Eliminar</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="6" style="text-align: center;">No hay proyectos registrados.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pestaña Responsables -->
|
||||
<div id="tab-responsables" class="tab-content">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem;">
|
||||
<h2>Responsables y Colaboradores</h2>
|
||||
<a href="{% url 'responsable_create' %}" class="btn btn-primary">➕ Nuevo Responsable</a>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Usuario</th>
|
||||
<th>Correo</th>
|
||||
<th>Rol / Permiso</th>
|
||||
<th>Descripción / Bio</th>
|
||||
<th>F. Registro</th>
|
||||
<th>F. Modificación</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for resp in responsables %}
|
||||
<tr>
|
||||
<td style="font-weight: 600; color: var(--text-primary);">{{ resp.username }}</td>
|
||||
<td>{{ resp.email|default:"-" }}</td>
|
||||
<td>
|
||||
{% if resp.groups.all %}
|
||||
{% with role=resp.groups.all.0.name %}
|
||||
{% if role == 'Administrador' %}
|
||||
<span class="badge badge-admin">Administrador</span>
|
||||
{% elif role == 'Director de Proyecto' %}
|
||||
<span class="badge badge-director">Director</span>
|
||||
{% else %}
|
||||
<span class="badge badge-gestor">Gestor</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<span class="badge badge-gestor">Sin Rol</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ resp.profile.description|default:"Sin descripción personal" }}</td>
|
||||
<td>{{ resp.profile.created_at|date:"d/m/Y"|default:"-" }}</td>
|
||||
<td>{{ resp.profile.updated_at|date:"d/m/Y H:i"|default:"-" }}</td>
|
||||
<td>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<a href="{% url 'responsable_edit' resp.id %}" class="btn btn-outline" style="padding: 0.35rem 0.75rem; font-size: 0.8rem;">✏️ Editar</a>
|
||||
{% if resp != request.user %}
|
||||
<form action="{% url 'responsable_delete' resp.id %}" method="POST" style="display: inline;" onsubmit="return confirm('¿Estás seguro de que deseas eliminar este responsable?');">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-danger" style="padding: 0.35rem 0.75rem; font-size: 0.8rem;">🗑️ Eliminar</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="7" style="text-align: center;">No hay responsables registrados.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pestaña Configuración -->
|
||||
<div id="tab-config" class="tab-content">
|
||||
<div style="margin-bottom: 1.5rem;">
|
||||
<h2>Configuración General del Sistema</h2>
|
||||
</div>
|
||||
<div style="max-width: 500px; display: flex; flex-direction: column; gap: 1.5rem;">
|
||||
<div class="glass-card" style="padding: 1.5rem; background: rgba(0, 0, 0, 0.2);">
|
||||
<div style="color: var(--text-secondary); font-size: 0.9rem; margin-bottom: 0.5rem;">Presupuesto General Asignado</div>
|
||||
<div style="font-size: 2rem; font-weight: 700; color: var(--accent-secondary);">${{ settings.global_budget|default:"100000.00" }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{% url 'settings_edit' %}" class="btn btn-primary">✏️ Modificar Presupuesto General</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pestaña Bitácora -->
|
||||
<div id="tab-bitacora" class="tab-content">
|
||||
<div style="margin-bottom: 1.5rem;">
|
||||
<h2>Bitácora de Auditoría y Trazabilidad (Logs)</h2>
|
||||
<p style="color: var(--text-secondary); font-size: 0.9rem;">Historial detallado de operaciones realizadas por los administradores en el sistema.</p>
|
||||
</div>
|
||||
<div class="log-list">
|
||||
{% for log in logs %}
|
||||
<div class="log-item">
|
||||
<div class="log-info">
|
||||
<div class="log-action">
|
||||
{% if "Creado" in log.action or "Creación" in log.action %}
|
||||
🟢 {{ log.action }}
|
||||
{% elif "Eliminado" in log.action or "Eliminación" in log.action %}
|
||||
🔴 {{ log.action }}
|
||||
{% else %}
|
||||
🟡 {{ log.action }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="log-desc">{{ log.description }}</div>
|
||||
</div>
|
||||
<div class="log-meta">
|
||||
<div style="font-weight: 500; color: var(--accent-primary);">@{{ log.user.username|default:"Sistema" }}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-secondary); margin-top: 0.25rem;">{{ log.timestamp|date:"d/m/Y H:i:s" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div style="text-align: center; color: var(--text-secondary); padding: 2rem;">No hay registros en la bitácora de auditoría.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
function switchTab(evt, tabId) {
|
||||
// Ocultar todos los contenidos de pestaña
|
||||
const contents = document.querySelectorAll('.tab-content');
|
||||
contents.forEach(content => content.classList.remove('active'));
|
||||
|
||||
// Desactivar todos los botones de pestaña
|
||||
const buttons = document.querySelectorAll('.tab-btn');
|
||||
buttons.forEach(btn => btn.classList.remove('active'));
|
||||
|
||||
// Activar pestaña actual
|
||||
document.getElementById(tabId).classList.add('active');
|
||||
evt.currentTarget.classList.add('active');
|
||||
|
||||
// Guardar la pestaña activa en localStorage
|
||||
localStorage.setItem('activeTab', tabId);
|
||||
}
|
||||
|
||||
// Restaurar pestaña activa al cargar la página
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const activeTab = localStorage.getItem('activeTab');
|
||||
if (activeTab && document.getElementById(activeTab)) {
|
||||
const btn = Array.from(document.querySelectorAll('.tab-btn')).find(b => b.getAttribute('onclick').includes(activeTab));
|
||||
if (btn) {
|
||||
// Simular clic en el botón
|
||||
btn.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user