Files
erp-efintel-2026-portainer/templates/base.html
T
2026-09-07 18:44:32 -03:00

169 lines
8.8 KiB
HTML

{% load static %}
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EFINTEL | ERP Interno I+D+i</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500;700;800&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<link rel="stylesheet" href="{% static 'css/style.css' %}?v=2.1">
<meta name="csrf-token" content="{{ csrf_token }}">
</head>
<body>
<!-- Top Corporate ERP Header -->
<header class="app-header">
<div class="brand-section">
<div class="brand-logo-container">
<img src="{% static 'img/efintel_logo.png' %}" alt="EFINTEL Logo" class="brand-logo-img" />
</div>
<div class="brand-title">
<h1>EFINTEL | ERP Interno I+D+i</h1>
<p>Sistema Integrado de Control Financiero, Operaciones, Talento y Proyectos</p>
</div>
</div>
<!-- Normalized Action Bar for ERP -->
<div class="header-actions">
<div style="font-size:0.8rem; font-weight: 600; color: white; margin-right: 15px;">
Usuario: {{ request.user.username }} | Rol: {% if request.user.groups.all %}{{ request.user.groups.all.0.name }}{% else %}Usuario{% endif %}
</div>
<a href="{% url 'export_csv' %}" class="btn-primary" style="background:#107c41; text-decoration: none;">
<i data-lucide="file-spreadsheet" style="width:16px;"></i> Exportar CSV
</a>
<a href="{% url 'expense_create' %}" class="btn-primary" style="text-decoration: none;">
<i data-lucide="plus-circle" style="width:16px;"></i> + Registrar Erogación
</a>
<a href="{% url 'logout' %}" class="btn-danger" style="text-decoration: none;">
<i data-lucide="log-out" style="width:16px;"></i> Salir
</a>
</div>
</header>
<!-- Corporate Ecosystem Navigation Bar -->
<nav class="nav-bar">
<a href="{% url 'dashboard' %}" class="nav-tab {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}">
<i data-lucide="pie-chart" style="width:16px;"></i> Resumen Financiero
</a>
<a href="{% url 'expense_list' %}" class="nav-tab {% if request.resolver_match.url_name == 'expense_list' or request.resolver_match.url_name == 'expense_report_list' %}active{% endif %}">
<i data-lucide="truck" style="width:16px;"></i> Operaciones y Erogaciones
</a>
<a href="{% url 'project_list' %}" class="nav-tab {% if 'project' in request.resolver_match.url_name %}active{% endif %}">
<i data-lucide="folder-kanban" style="width:16px;"></i> Control de Proyectos
</a>
<a href="{% url 'procurement:catalog_list' %}" class="nav-tab {% if 'procurement' in request.resolver_match.namespace %}active{% endif %}">
<i data-lucide="shopping-cart" style="width:16px;"></i> Compras & OC
</a>
<a href="{% url 'payroll:employee_list' %}" class="nav-tab {% if 'payroll' in request.resolver_match.namespace %}active{% endif %}">
<i data-lucide="users" style="width:16px;"></i> Remuneraciones
</a>
<a href="{% url 'talent:candidate_list' %}" class="nav-tab {% if 'talent' in request.resolver_match.namespace %}active{% endif %}">
<i data-lucide="award" style="width:16px;"></i> Cartera Talento
</a>
{% if 'Administrador Finanzas' in request.user.groups.all.0.name or 'Administrador' in request.user.groups.all.0.name or request.user.is_superuser %}
<a href="{% url 'accounts_payable' %}" class="nav-tab {% if request.resolver_match.url_name == 'accounts_payable' %}active{% endif %}">
<i data-lucide="calculator" style="width:16px;"></i> Cuentas por Pagar (CXP)
</a>
{% endif %}
{% if 'Administrador' in request.user.groups.all.0.name or request.user.is_superuser %}
<a href="{% url 'gestion_panel' %}" class="nav-tab {% if request.resolver_match.url_name == 'gestion_panel' %}active{% endif %}" style="margin-left:auto; background:var(--efintel-petroleum); color:white;">
<i data-lucide="settings" style="width:16px;"></i> Gestión ERP
</a>
{% endif %}
</nav>
<main class="main-container">
{% if messages %}
<div class="messages-container" style="margin-bottom: 1rem;">
{% for message in messages %}
<div class="alert alert-{{ message.tags }}" style="padding: 10px; border-radius: 4px; background: var(--efintel-light); border-left: 4px solid var(--efintel-blue); font-weight: 600;">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
{% block content %}{% endblock %}
</main>
<!-- Requerimiento 3: Modal Universal de Previsualización de Evidencias (JPG/PNG/PDF) -->
<div id="evidencePreviewModal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(15,23,42,0.85); z-index:9999; backdrop-filter:blur(4px); align-items:center; justify-content:center;">
<div style="background:white; border-radius:12px; width:90%; max-width:900px; height:85vh; display:flex; flex-direction:column; overflow:hidden; box-shadow:0 25px 50px -12px rgba(0,0,0,0.5);">
<div style="padding:1rem 1.5rem; background:var(--efintel-dark, #1e293b); color:white; display:flex; justify-content:space-between; align-items:center;">
<h3 id="previewModalTitle" style="margin:0; font-size:1.1rem; font-weight:700; color:white;">Vista Previa de Evidencia</h3>
<div style="display:flex; gap:0.5rem; align-items:center;">
<a id="previewModalDownloadBtn" href="#" target="_blank" class="btn-primary" style="padding:0.3rem 0.8rem; font-size:0.8rem; text-decoration:none; background:#0284c7;">
<i data-lucide="download" style="width:14px;"></i> Descargar
</a>
<button onclick="closePreviewModal()" style="background:transparent; border:none; color:white; font-size:1.5rem; cursor:pointer; padding:0 0.5rem;">&times;</button>
</div>
</div>
<div id="previewModalContent" style="flex:1; background:#f8fafc; display:flex; align-items:center; justify-content:center; padding:1rem; overflow:auto;">
<!-- Contenido dinámico embebido (Image o PDF) -->
</div>
</div>
</div>
<script>
if (window.lucide) {
lucide.createIcons();
}
function previewDocument(fileUrl, title, isPdf) {
const modal = document.getElementById('evidencePreviewModal');
const modalTitle = document.getElementById('previewModalTitle');
const downloadBtn = document.getElementById('previewModalDownloadBtn');
const content = document.getElementById('previewModalContent');
modalTitle.textContent = title || 'Vista Previa de Evidencia';
downloadBtn.href = fileUrl;
if (isPdf || fileUrl.toLowerCase().endsWith('.pdf')) {
content.innerHTML = `<object data="${fileUrl}" type="application/pdf" width="100%" height="100%" style="min-height:70vh; border:none;">
<iframe src="${fileUrl}" width="100%" height="100%" style="min-height:70vh; border:none;">
Tu navegador no soporta visualización directa de PDF. <a href="${fileUrl}" target="_blank">Haz clic aquí para descargar.</a>
</iframe>
</object>`;
} else {
content.innerHTML = `<img src="${fileUrl}" alt="Evidencia" style="max-width:100%; max-height:75vh; object-fit:contain; border-radius:8px; box-shadow:0 4px 6px -1px rgba(0,0,0,0.1);" />`;
}
modal.style.display = 'flex';
}
function closePreviewModal() {
const modal = document.getElementById('evidencePreviewModal');
const content = document.getElementById('previewModalContent');
modal.style.display = 'none';
content.innerHTML = '';
}
// Formateador automático global para cualquier formulario presente o futuro
function styleAllFormControls() {
document.querySelectorAll('form input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="hidden"]), form select, form textarea').forEach(function(el) {
if (!el.classList.contains('form-control') && !el.classList.contains('form-input')) {
el.classList.add('form-control');
}
});
}
document.addEventListener('DOMContentLoaded', styleAllFormControls);
const formObserver = new MutationObserver(styleAllFormControls);
if (document.body) {
formObserver.observe(document.body, { childList: true, subtree: true });
}
// Cerrar modal al presionar Escape
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closePreviewModal();
});
</script>
{% block extra_js %}{% endblock %}
</body>
</html>