sgmp/templates/base.html

243 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% load static %}
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}SGMP - Gestão de Pessoas{% endblock %}</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📊</text></svg>">
<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@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#2563eb',
'primary-hover': '#1d4ed8',
'sidebar-bg': '#0f172a',
'sidebar-border': '#1e293b',
},
fontFamily: { sans: ['Inter', 'sans-serif'] },
}
}
}
</script>
<style>
.sidebar.collapsed { width: 72px; }
.sidebar.collapsed .brand { display: none; }
.sidebar.collapsed .sidebar-header { justify-content: center; padding: 0; }
.sidebar.collapsed .nav-item { justify-content: center; padding: 10px 0; }
.sidebar.collapsed .link-text { opacity: 0; width: 0; display: none; overflow: hidden; }
.sidebar.collapsed .user-info { display: none; }
.sidebar.collapsed .user-section { padding: 16px 0; justify-content: center; }
.wizard-overlay { display: none; }
.wizard-overlay.show { opacity: 1; }
.wizard-overlay.show .wizard-box { transform: scale(1); }
.wizard-step { display: none; }
.wizard-step.active { display: block; }
@media (max-width: 768px) {
.sidebar { position: absolute; height: 100%; width: 260px; transform: translateX(-100%); }
.sidebar.active { transform: translateX(0); }
.sidebar.collapsed { width: 260px; transform: translateX(-100%); }
.sidebar-overlay { display: none; }
.sidebar.active + .sidebar-overlay { display: block; }
}
</style>
{% block css %}{% endblock %}
</head>
<body class="font-sans bg-slate-100 text-slate-700 m-0 p-0 h-screen overflow-hidden antialiased">
<div class="flex w-full h-screen">
<button type="button" class="mobile-menu-btn block md:hidden fixed top-4 left-4 z-40 bg-white border border-slate-200 rounded-md p-2 shadow md:hidden" onclick="toggleSidebarMobile()">
<span class="text-lg"></span>
</button>
<nav id="sidebar" class="sidebar flex flex-col w-[260px] flex-shrink-0 bg-slate-900 text-white border-r border-slate-800 relative z-50 transition-[width] duration-300 ease-out">
<div class="sidebar-header h-16 flex items-center justify-between px-5 border-b border-slate-800">
<div class="brand text-lg font-bold tracking-tight text-white whitespace-nowrap overflow-hidden">SGMP <span>CORP</span></div>
<button type="button" class="toggle-btn bg-transparent border-none text-slate-400 text-xl flex items-center justify-center p-1 rounded hover:text-white hover:bg-slate-800 transition-colors" onclick="toggleSidebarDesktop()" title="Recolher Menu">
<span>«</span>
</button>
</div>
<div class="nav-links py-5 px-3 flex flex-col gap-1.5 flex-grow overflow-y-auto">
<a href="{% url 'solicitacoes:dashboard' %}" class="nav-item flex items-center py-2.5 px-3 rounded-md text-slate-400 text-sm font-medium no-underline border-none bg-transparent w-full cursor-pointer transition-all hover:text-white hover:bg-slate-800" title="Dashboard">
<span class="link-icon text-base min-w-[24px] flex items-center justify-center">📊</span>
<span class="link-text ml-3 whitespace-nowrap overflow-hidden">Dashboard</span>
</a>
{% if user.is_authenticated and usuario_sistema and usuario_sistema.perfil != 'GESTOR' %}
<a href="{% url 'solicitacoes:todas_solicitacoes' %}" class="nav-item flex items-center py-2.5 px-3 rounded-md text-slate-400 text-sm font-medium no-underline border-none bg-transparent w-full cursor-pointer transition-all hover:text-white hover:bg-slate-800" title="Todas as solicitações">
<span class="link-icon text-base min-w-[24px] flex items-center justify-center">📑</span>
<span class="link-text ml-3 whitespace-nowrap overflow-hidden">Todas as solicitações</span>
</a>
{% endif %}
{% if user.is_authenticated and usuario_sistema and usuario_sistema.perfil == 'GESTOR' %}
<button type="button" onclick="openWizard()" class="nav-item flex items-center py-2.5 px-3 rounded-md text-slate-400 text-sm font-medium border-none bg-transparent w-full cursor-pointer transition-all hover:text-white hover:bg-slate-800 text-left" title="Criar Solicitação">
<span class="link-icon text-base min-w-[24px] flex items-center justify-center"></span>
<span class="link-text ml-3 whitespace-nowrap overflow-hidden">Nova Solicitação</span>
</button>
{% endif %}
</div>
{% if user.is_authenticated %}
<div class="user-section py-4 px-4 bg-slate-950 border-t border-slate-800">
<a href="{% url 'solicitacoes:logout' %}" class="user-profile flex items-center gap-3 text-white no-underline overflow-hidden" title="Sair">
<div class="avatar w-8 h-8 rounded-full bg-primary flex items-center justify-center font-semibold text-sm flex-shrink-0">
{% if usuario_sistema %}{{ usuario_sistema.nome|make_list|first }}{% else %}{{ user.username|make_list|first }}{% endif %}
</div>
<div class="user-info flex flex-col whitespace-nowrap overflow-hidden">
<span class="user-name text-sm font-semibold">{% if usuario_sistema %}{{ usuario_sistema.nome }}{% else %}{{ user.username }}{% endif %}</span>
<span class="user-role text-xs text-slate-400">{% if usuario_sistema %}{{ usuario_sistema.get_perfil_display }}{% else %}Usuário{% endif %}</span>
</div>
<span class="link-icon ml-auto text-red-500" title="Sair">🚪</span>
</a>
</div>
{% endif %}
</nav>
<div class="sidebar-overlay fixed inset-0 bg-black/50 z-[45] backdrop-blur-sm md:hidden" onclick="toggleSidebarMobile()"></div>
<main class="main-content flex-grow overflow-y-auto h-screen bg-slate-100 relative">
<div class="container max-w-[1200px] mx-auto py-8 px-8">
{% block content %}{% endblock %}
</div>
</main>
</div>
<div id="createWizard" class="wizard-overlay fixed inset-0 bg-slate-900/60 z-[1000] flex items-center justify-center backdrop-blur-sm opacity-0 transition-opacity duration-200">
<div class="wizard-box bg-white w-full max-w-2xl rounded-xl shadow-2xl overflow-hidden flex flex-col max-h-[85vh] scale-95 transition-transform duration-200">
<div class="wizard-header py-5 px-6 border-b border-slate-200 flex justify-between items-center bg-white">
<h3 id="wizardTitle" class="m-0 text-lg font-semibold text-slate-800">Iniciar Novo Processo</h3>
<button type="button" class="close-wizard bg-transparent border-none text-xl text-slate-500 w-8 h-8 rounded-md flex items-center justify-center cursor-pointer hover:bg-slate-100 hover:text-slate-800 transition-colors" onclick="closeWizard()">×</button>
</div>
<div class="wizard-body p-6 overflow-y-auto bg-white">
<div id="step1" class="wizard-step active">
<p class="text-slate-600 mb-5">Qual tipo de movimentação você deseja realizar hoje?</p>
<div class="type-grid grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="type-card bg-white border border-slate-200 p-5 rounded-lg cursor-pointer transition-all text-center flex flex-col items-center gap-3 hover:border-primary hover:bg-blue-50 hover:-translate-y-0.5 hover:shadow" onclick="goToStep2('desligamento', 'Desligamento')">
<span class="type-icon text-3xl">🚫</span>
<span class="type-title font-semibold text-slate-800 text-sm">Desligamento</span>
</div>
<div class="type-card bg-white border border-slate-200 p-5 rounded-lg cursor-pointer transition-all text-center flex flex-col items-center gap-3 hover:border-primary hover:bg-blue-50 hover:-translate-y-0.5 hover:shadow" onclick="goToStep2('movimentacao', 'Movimentação Interna')">
<span class="type-icon text-3xl">🔄</span>
<span class="type-title font-semibold text-slate-800 text-sm">Movimentação</span>
</div>
<div class="type-card bg-white border border-slate-200 p-5 rounded-lg cursor-pointer transition-all text-center flex flex-col items-center gap-3 hover:border-primary hover:bg-blue-50 hover:-translate-y-0.5 hover:shadow" onclick="goToStep2('aumento-quadro', 'Aumento de Quadro')">
<span class="type-icon text-3xl">📈</span>
<span class="type-title font-semibold text-slate-800 text-sm">Aumento de Quadro</span>
</div>
<div class="type-card bg-white border border-slate-200 p-5 rounded-lg cursor-pointer transition-all text-center flex flex-col items-center gap-3 hover:border-primary hover:bg-blue-50 hover:-translate-y-0.5 hover:shadow" onclick="goToStep2('substituicao', 'Substituição')">
<span class="type-icon text-3xl">👥</span>
<span class="type-title font-semibold text-slate-800 text-sm">Substituição</span>
</div>
</div>
</div>
<div id="step2" class="wizard-step">
<div class="back-link text-slate-500 cursor-pointer text-sm mb-5 inline-flex items-center gap-1 font-medium hover:text-primary" onclick="backToStep1()">
<span></span> Voltar para seleção
</div>
<p class="mb-4 text-slate-800">Selecione o colaborador para o processo de <strong id="selectedTypeLabel"></strong>:</p>
<div class="search-container flex flex-col gap-4">
<div class="search-input-group flex gap-3 relative">
<span class="search-icon-fake absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none">🔍</span>
<input type="text" id="wizardSearchInput" class="search-input flex-1 py-3 pl-10 pr-4 border border-slate-200 rounded-lg text-sm font-sans transition-colors focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20" placeholder="Busque por Nome ou Matrícula..." onkeydown="if(event.key==='Enter') doSearch()">
<button type="button" class="btn-search bg-primary text-white border-none py-0 px-6 rounded-lg font-medium cursor-pointer transition-colors hover:bg-primary-hover" onclick="doSearch()">Buscar</button>
</div>
<div id="loading" class="loading-spinner text-center text-slate-500 py-8 hidden text-sm">
Consultando base de dados...
</div>
<div id="searchResults" class="results-list flex flex-col gap-2.5 mt-2 max-h-[400px] overflow-y-auto">
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function toggleSidebarDesktop() {
const sidebar = document.getElementById('sidebar');
const btn = sidebar.querySelector('.toggle-btn span');
sidebar.classList.toggle('collapsed');
btn.innerHTML = sidebar.classList.contains('collapsed') ? '»' : '«';
}
function toggleSidebarMobile() {
document.getElementById('sidebar').classList.toggle('active');
}
let currentTypeSlug = '';
function openWizard() {
const overlay = document.getElementById('createWizard');
overlay.style.display = 'flex';
setTimeout(() => overlay.classList.add('show'), 10);
backToStep1();
}
function closeWizard() {
const overlay = document.getElementById('createWizard');
overlay.classList.remove('show');
setTimeout(() => { overlay.style.display = 'none'; }, 200);
}
document.getElementById('createWizard').addEventListener('click', function(e) { if (e.target === this) closeWizard(); });
document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeWizard(); });
function goToStep2(slug, label) {
if (slug === 'aumento-quadro') {
window.location.href = "{% url 'solicitacoes:criar_admissao_aumento_quadro' %}";
return;
}
currentTypeSlug = slug;
document.getElementById('selectedTypeLabel').textContent = label;
document.getElementById('step1').classList.remove('active');
document.getElementById('step2').classList.add('active');
document.getElementById('wizardSearchInput').value = '';
document.getElementById('searchResults').innerHTML = '';
setTimeout(() => document.getElementById('wizardSearchInput').focus(), 100);
}
function backToStep1() {
document.getElementById('step2').classList.remove('active');
document.getElementById('step1').classList.add('active');
}
async function doSearch() {
const term = document.getElementById('wizardSearchInput').value.trim();
const resultsDiv = document.getElementById('searchResults');
const loader = document.getElementById('loading');
if (!term) return;
resultsDiv.innerHTML = '';
loader.style.display = 'block';
try {
let url = "{% url 'solicitacoes:listar_colaboradores' %}?q=" + encodeURIComponent(term);
if (currentTypeSlug === 'substituicao') url += "&tipo=substituicao";
const response = await fetch(url);
const doc = new DOMParser().parseFromString(await response.text(), 'text/html');
const rows = doc.querySelectorAll('table tbody tr');
if (rows.length === 0) {
resultsDiv.innerHTML = '<div class="text-center py-5 text-slate-500">Nenhum colaborador encontrado.</div>';
} else {
const linkTextMap = { 'desligamento': 'Desligamento', 'movimentacao': 'Movimentação', 'substituicao': 'Substituição' };
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length < 6) return;
const matricula = cells[0].textContent.trim(), nome = cells[1].textContent.trim(), cargo = cells[2].textContent.trim();
const linkText = linkTextMap[currentTypeSlug];
const actionLink = linkText ? Array.from(row.querySelectorAll('a')).find(l => l.textContent.includes(linkText)) : null;
if (!actionLink) return;
const href = actionLink.getAttribute('href');
const card = document.createElement('div');
card.className = 'result-item flex justify-between items-center p-4 bg-white border border-slate-200 rounded-lg transition-all hover:border-primary hover:bg-slate-50 hover:shadow';
card.innerHTML = '<div class="result-info flex flex-col gap-1"><span class="result-name font-semibold text-slate-800 text-sm">' + nome + '</span><span class="result-meta text-xs text-slate-500">Matrícula: ' + matricula + ' | ' + cargo + '</span></div><a href="' + href + '" class="btn-select bg-white text-primary border border-slate-200 py-2 px-4 rounded-md text-sm font-semibold no-underline transition-all hover:bg-primary hover:text-white hover:border-primary">Selecionar</a>';
resultsDiv.appendChild(card);
});
}
} catch (err) {
console.error(err);
resultsDiv.innerHTML = '<div class="text-red-600 text-center">Erro ao buscar. Tente novamente.</div>';
} finally {
loader.style.display = 'none';
}
}
</script>
{% block scripts %}{% endblock %}
</body>
</html>