sgmp/templates/dashboard_original.html

1333 lines
70 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

{% extends "base.html" %}
{% block title %}Dashboard - SGMP{% endblock %}
{% block css %}
<style>
/* --- Header --- */
.dashboard-header {
margin-bottom: 2rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dashboard-header h1 {
font-size: 1.85rem;
font-weight: 700;
color: #1e293b;
margin: 0;
letter-spacing: -0.025em;
}
.dashboard-header p {
color: #64748b;
font-size: 0.95rem;
line-height: 1.5;
}
/* --- Cards de Métricas --- */
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1.5rem;
margin-bottom: 2.5rem;
}
.metric-card {
background: white;
padding: 1.5rem;
border-radius: 12px;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
border-left: 5px solid transparent;
transition: all 0.2s ease-in-out;
cursor: pointer;
position: relative;
overflow: hidden;
}
.metric-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.metric-card.active {
background-color: #f8fafc;
border-color: #cbd5e1;
transform: scale(1.02);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
/* Cores dos Cards */
.card-total { border-left-color: #3b82f6; }
.card-total .metric-value { color: #3b82f6; }
.card-pending { border-left-color: #f59e0b; }
.card-pending .metric-value { color: #d97706; }
.metric-label {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #64748b;
font-weight: 700;
margin-bottom: 0.5rem;
}
.metric-value {
font-size: 2.25rem;
font-weight: 800;
line-height: 1;
}
/* --- Seções e Tabelas --- */
.section { margin-bottom: 30px; }
.section h3 {
color: #1e293b;
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
/* Container responsivo para tabela */
.table-responsive {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
border: 1px solid #e2e8f0;
}
table {
width: 100%;
border-collapse: collapse;
white-space: nowrap; /* Evita quebra de linha indesejada no mobile */
}
th, td {
padding: 16px;
text-align: left;
border-bottom: 1px solid #e2e8f0;
}
th {
background-color: #f8fafc;
font-weight: 600;
color: #475569;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.025em;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background-color: #f8fafc; }
/* Badges de Status */
.status-badge {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 700;
line-height: 1;
}
.status-RASCUNHO { background: #fffbeb; color: #b45309; border: 1px solid #fcd34d; }
.status-AGUARDANDO_HEAD { background: #fef3c7; color: #b45309; border: 1px solid #fcd34d; }
.status-ENVIADA { background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe; }
.status-APROVADA_GG,
.status-APROVADA_CONTROLADORIA,
.status-APROVADA_DIRETORIA { background: #ecfdf5; color: #047857; border: 1px solid #6ee7b7; }
.status-FINALIZADA { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; }
.status-REPROVADA { background: #fef2f2; color: #b91c1c; border: 1px solid #fecaca; }
/* --- Paginação --- */
.pagination {
margin-top: 24px;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
flex-wrap: wrap;
}
.pagination a {
padding: 8px 14px;
text-decoration: none;
border: 1px solid #e2e8f0;
border-radius: 6px;
color: #475569;
background: white;
font-size: 0.9rem;
transition: all 0.2s;
}
.pagination a:hover {
background: #f1f5f9;
border-color: #cbd5e1;
color: #1e293b;
}
.pagination .current {
padding: 8px 14px;
background: #2563eb;
color: white;
border-radius: 6px;
font-weight: 500;
border: 1px solid #2563eb;
}
/* --- Mensagens --- */
.messages ul { list-style: none; padding: 0; margin: 0 0 20px 0; }
.messages li {
padding: 14px 18px;
margin-bottom: 12px;
border-radius: 8px;
border: 1px solid transparent;
font-size: 0.95rem;
display: flex;
align-items: center;
}
.messages .error { background: #fef2f2; color: #991b1b; border-color: #fecaca; }
.messages .success { background: #ecfdf5; color: #065f46; border-color: #a7f3d0; }
.messages .info { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; }
/* --- Empty State --- */
.empty-state {
text-align: center;
padding: 60px 20px;
color: #64748b;
background: white;
border-radius: 12px;
border: 1px dashed #cbd5e1;
}
.empty-state p { margin: 0; font-size: 1.1rem; }
/* --- Detalhes Expansíveis --- */
.details-row { background-color: #f8fafc; box-shadow: inset 0 2px 4px rgba(0,0,0,0.02); }
.details-row td { padding: 0 !important; border-bottom: none; }
.details-wrapper { padding: 2rem; animation: slideDown 0.3s cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes slideDown {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
/* Abas */
.tab-nav {
display: flex;
border-bottom: 1px solid #e2e8f0;
margin-bottom: 1.5rem;
gap: 2rem;
overflow-x: auto; /* Scroll nas abas em mobile */
}
.tab-btn {
background: none;
border: none;
padding: 0.75rem 0;
cursor: pointer;
color: #64748b;
border-bottom: 2px solid transparent;
font-size: 0.95rem;
font-weight: 500;
transition: all 0.2s ease;
white-space: nowrap;
}
.tab-btn:hover { color: #2563eb; }
.tab-btn.active { color: #2563eb; border-bottom-color: #2563eb; font-weight: 600; }
.tab-pane { display: none; }
.tab-pane.active { display: block; animation: fadeIn 0.3s ease; }
/* Seções Internas */
.details-section {
margin-bottom: 1.5rem;
background: white;
padding: 1.5rem;
border-radius: 12px;
border: 1px solid #e2e8f0;
}
.details-section h5 {
color: #94a3b8;
font-size: 0.75rem;
text-transform: uppercase;
margin: 1.5rem 0 1rem 0;
font-weight: 700;
letter-spacing: 0.05em;
border-bottom: 1px solid #f1f5f9;
padding-bottom: 8px;
}
.details-section h5:first-child { margin-top: 0; }
/* Grid de Informações */
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1.5rem;
}
.info-item { display: flex; flex-direction: column; }
.info-item label {
font-size: 0.75rem;
color: #64748b;
margin-bottom: 0.35rem;
font-weight: 600;
text-transform: uppercase;
}
.info-item span {
font-size: 1rem;
color: #0f172a;
font-weight: 500;
word-break: break-word;
line-height: 1.4;
}
/* Timeline */
.timeline { position: relative; padding-left: 2rem; border-left: 2px solid #e2e8f0; margin-left: 0.5rem; }
.timeline-item { position: relative; padding-bottom: 2rem; padding-left: 1.5rem; }
.timeline-item::before {
content: '';
position: absolute;
left: -2.4rem; /* Ajuste fino para centralizar na linha */
top: 0.25rem;
width: 14px;
height: 14px;
border-radius: 50%;
background: #cbd5e1;
border: 3px solid white;
box-shadow: 0 0 0 1px #e2e8f0;
}
.timeline-item:last-child { padding-bottom: 0; }
.timeline-header { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.25rem; font-size: 0.95rem; align-items: baseline; }
.timeline-user { font-weight: 600; color: #1e293b; }
.timeline-action { color: #64748b; }
.timeline-date { font-size: 0.8rem; color: #94a3b8; margin-left: auto; }
.timeline-justificativa {
margin-top: 0.75rem;
padding: 1rem;
background: #f8fafc;
border-radius: 8px;
font-size: 0.9rem;
color: #334155;
border: 1px solid #e2e8f0;
font-style: italic;
}
/* Botões */
.btn-action {
padding: 0.6rem 1.2rem;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
border: 1px solid transparent;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s;
}
.btn-action-primary { background: #2563eb; color: white; border: 1px solid #1d4ed8; }
.btn-action-primary:hover { background: #1d4ed8; box-shadow: 0 2px 4px rgba(37,99,235,0.2); }
.btn-action-success { background: #10b981; color: white; border: 1px solid #059669; }
.btn-action-success:hover { background: #059669; box-shadow: 0 2px 4px rgba(16,185,129,0.2); }
.btn-action-danger { background: white; color: #ef4444; border: 1px solid #ef4444; }
.btn-action-danger:hover { background: #fef2f2; }
/* Forms Internos */
.form-decisao {
background: #f8fafc;
padding: 1.5rem;
border-radius: 12px;
margin-top: 1.5rem;
border: 1px solid #e2e8f0;
}
.form-group input, .form-group select, .form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #cbd5e1;
border-radius: 6px;
font-family: inherit;
font-size: 0.95rem;
transition: border-color 0.2s;
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
/* Seta de expansão */
.chevron-icon {
transition: transform 0.3s ease;
display: inline-block;
font-size: 0.8rem;
}
.request-row.expanded .chevron-icon {
transform: rotate(180deg);
}
/* Modal */
#modal-aprovacao {
backdrop-filter: blur(4px);
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: 12px;
max-width: 500px;
width: 90%;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
border: 1px solid #e2e8f0;
animation: modalFadeIn 0.2s ease-out;
}
@keyframes modalFadeIn {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@media (max-width: 640px) {
.dashboard-header h1 { font-size: 1.5rem; }
.metrics-grid { grid-template-columns: 1fr 1fr; gap: 1rem; }
.metric-value { font-size: 1.75rem; }
.info-grid { grid-template-columns: 1fr; }
.btn-action { width: 100%; justify-content: center; margin-bottom: 0.5rem; }
.details-wrapper { padding: 1rem; }
}
</style>
{% endblock %}
{% block content %}
<div class="dashboard-header">
<h1>SGMP - Movimentação de Pessoas</h1>
<p>
Olá, <strong>{{ usuario_sistema.nome }}</strong>!
<span style="display: inline-block; background: #e2e8f0; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; margin-left: 8px; color: #475569;">
{{ usuario_sistema.get_perfil_display }}
</span>
<br>
<small style="color: #94a3b8;">Matrícula: {{ usuario_sistema.matricula }}</small>
</p>
</div>
{% if messages %}
<div class="messages">
<ul>
{% for message in messages %}
<li class="{{ message.tags }}">
{% if message.tags == 'error' %}⚠️{% elif message.tags == 'success' %}✅{% else %}{% endif %}
&nbsp;{{ message }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if usuario_sistema.perfil == 'GESTOR' %}
<div class="section">
<div style="background: #fffbeb; border: 1px solid #fcd34d; border-radius: 12px; padding: 16px; margin-bottom: 24px; display: flex; gap: 12px; align-items: flex-start;">
<span style="font-size: 1.5rem;">💡</span>
<div>
<h4 style="margin: 0 0 4px 0; color: #92400e;">Lembrete Rápido</h4>
<p style="margin: 0; color: #b45309; font-size: 0.95rem;">
Solicitações em <strong>Rascunho</strong> só são visíveis para você.
Lembre-se de clicar em <strong>"Enviar para Aprovação"</strong> na página de detalhes para iniciar o fluxo.
</p>
</div>
</div>
</div>
{% endif %}
<!-- Cards de Métricas -->
<div class="metrics-grid">
<div class="metric-card card-total active" onclick="filtrarTabela('todos', this)">
<div class="metric-label">Total</div>
<div class="metric-value">{{ total }}</div>
</div>
<div class="metric-card card-pending" onclick="filtrarTabela('pendente', this)">
<div class="metric-label">Pendentes</div>
<div class="metric-value">{{ pendentes }}</div>
</div>
</div>
<div class="section">
<h3>
{% if usuario_sistema.perfil == 'GESTOR' %}
📋 Minhas Solicitações
{% else %}
⏳ Pendentes de Aprovação
{% endif %}
</h3>
{% if usuario_sistema.perfil != 'GESTOR' %}
<div style="background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 12px; margin-bottom: 20px; color: #1e40af; font-size: 0.9rem; display: flex; align-items: center; gap: 8px;">
Você está vendo solicitações com status <strong>Enviada</strong> aguardando sua análise.
</div>
{% endif %}
{% if solicitacoes %}
<div class="table-responsive">
<table id="tabela-solicitacoes">
<thead>
<tr>
<th>Tipo</th>
<th>Colaborador</th>
<th>Status</th>
<th>Data</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
{% for item in solicitacoes_com_acao %}
{% with solicitacao=item.solicitacao %}
<tr class="request-row"
data-id="{{ solicitacao.id }}"
data-status="{% if solicitacao.status == 'FINALIZADA' %}aprovado{% elif solicitacao.status == 'REPROVADA' %}reprovado{% else %}pendente{% endif %}"
onclick="toggleDetails('{{ solicitacao.id }}', this)"
style="cursor: pointer;">
<td><strong>{{ solicitacao.get_tipo_display }}</strong></td>
<td>
{% if solicitacao.funcionario %}
{{ solicitacao.funcionario.nome }}
{% else %}
<span style="color: #94a3b8;">N/A</span>
{% endif %}
</td>
<td>
<span class="status-badge status-{{ solicitacao.status }}">
{{ solicitacao.get_status_display }}
</span>
</td>
<td style="color: #64748b;">{{ solicitacao.criado_em|date:"d/m/Y H:i" }}</td>
<td>
<div style="display: flex; gap: 12px; align-items: center;">
<span class="expand-btn" style="color: #3b82f6; font-weight: 600; font-size: 0.85rem;">
Detalhes <span class="chevron-icon"></span>
</span>
{% if item.pode_dar_parecer %}
<a href="{% url 'solicitacoes:solicitacao_detalhe' solicitacao.id %}"
class="btn-action btn-action-primary"
style="padding: 4px 10px; font-size: 0.75rem;"
title="Fornecer parecer técnico">
📝 Parecer
</a>
{% endif %}
{% if item.pode_aprovar %}
<div style="display: flex; gap: 4px;">
<button class="btn-action btn-action-success"
onclick="event.stopPropagation(); abrirModalAprovacao('{{ solicitacao.id }}', 'APROVADO')"
style="padding: 4px 8px; font-size: 0.75rem;" title="Aprovar">
</button>
<button class="btn-action btn-action-danger"
onclick="event.stopPropagation(); abrirModalAprovacao('{{ solicitacao.id }}', 'REPROVADO')"
style="padding: 4px 8px; font-size: 0.75rem;" title="Reprovar">
</button>
</div>
{% endif %}
</div>
</td>
</tr>
<!-- Linha de detalhes expansível -->
<tr id="details-{{ solicitacao.id }}" class="details-row" style="display:none;">
<td colspan="5">
<div class="details-wrapper" id="wrapper-{{ solicitacao.id }}">
<!-- Barra de navegação das abas -->
<div class="tab-nav">
<button class="tab-btn active" onclick="switchTab(event, 'solicitacao', '{{ solicitacao.id }}')">
📄 Solicitação
</button>
{% if solicitacao.funcionario %}
<button class="tab-btn" onclick="switchTab(event, 'rm', '{{ solicitacao.id }}')">
🏢 RM (Totvs)
</button>
{% endif %}
{% for item_acao in solicitacoes_com_acao %}
{% if item_acao.solicitacao.id == solicitacao.id and item_acao.dados_winthor_organizados %}
<button class="tab-btn" onclick="switchTab(event, 'winthor', '{{ solicitacao.id }}')">
💼 Winthor
</button>
{% endif %}
{% endfor %}
<button class="tab-btn" onclick="switchTab(event, 'auditoria', '{{ solicitacao.id }}')">
📝 Histórico & Auditoria
</button>
</div>
<!-- ABA: SOLICITAÇÃO -->
<div class="tab-pane active" data-tab="solicitacao">
<div class="details-section">
<h5>Dados Gerais</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Solicitante</label>
<span>{{ solicitacao.solicitante.nome }} <small style="color:#64748b">({{ solicitacao.solicitante.matricula }})</small></span>
</div>
<div class="info-item">
<label>Tipo</label>
<span style="font-weight:700; color:#2563eb;">{{ solicitacao.get_tipo_display }}</span>
</div>
<div class="info-item">
<label>Data Criação</label>
<span>{{ solicitacao.criado_em|date:"d/m/Y H:i" }}</span>
</div>
{% if solicitacao.enviada_em %}
<div class="info-item">
<label>Enviada em</label>
<span>{{ solicitacao.enviada_em|date:"d/m/Y H:i" }}</span>
</div>
{% endif %}
{% if solicitacao.finalizada_em %}
<div class="info-item">
<label>Finalizada em</label>
<span>{{ solicitacao.finalizada_em|date:"d/m/Y H:i" }}</span>
</div>
{% endif %}
</div>
<!-- Detalhes específicos por tipo -->
{% if solicitacao.tipo == 'DESLIGAMENTO' and solicitacao.desligamento %}
<h5>Detalhes do Desligamento</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
{% if solicitacao.desligamento.tipo_desligamento %}
<div class="info-item">
<label>Tipo de Desligamento</label>
<span>
{% if solicitacao.desligamento.tipo_desligamento == 'PEDIDO_DEMISSAO' %}
📝 Pedido de Demissão
{% elif solicitacao.desligamento.tipo_desligamento == 'SEM_JUSTA_CAUSA' %}
🚪 Sem Justa Causa
{% elif solicitacao.desligamento.tipo_desligamento == 'COM_JUSTA_CAUSA' %}
⚠️ Por Justa Causa
{% elif solicitacao.desligamento.tipo_desligamento == 'TERMINO_CONTRATO' %}
📅 Término de Contrato
{% elif solicitacao.desligamento.tipo_desligamento == 'OUTROS' %}
📋 Outros
{% else %}
{{ solicitacao.desligamento.get_tipo_desligamento_display|default:"—" }}
{% endif %}
</span>
</div>
{% endif %}
{% if solicitacao.desligamento.aviso_previo %}
<div class="info-item">
<label>Aviso Prévio</label>
<span>
{% if solicitacao.desligamento.aviso_previo == 'TRABALHADO' %}
✅ Trabalhado
{% elif solicitacao.desligamento.aviso_previo == 'INDENIZADO' %}
💰 Indenizado
{% elif solicitacao.desligamento.aviso_previo == 'DISPENSADO' %}
📤 Dispensado
{% else %}
{{ solicitacao.desligamento.get_aviso_previo_display|default:"—" }}
{% endif %}
</span>
</div>
{% endif %}
<div class="info-item">
<label>Data Prevista de Saída</label>
<span>{{ solicitacao.desligamento.data_prevista_desligamento|date:"d/m/Y"|default:"—" }}</span>
</div>
<div class="info-item" style="grid-column: 1 / -1;">
<label>Detalhamento / Justificativa</label>
<span style="white-space: pre-wrap;">{{ solicitacao.desligamento.motivo|default:"—" }}</span>
</div>
{% if solicitacao.desligamento.arquivo_pedido %}
<div class="info-item" style="grid-column: 1 / -1;">
<label>Carta de Pedido</label>
<span>
<a href="{{ solicitacao.desligamento.arquivo_pedido.url }}" target="_blank" style="color: #2563eb; text-decoration: none;">
📎 Ver arquivo
</a>
</span>
</div>
{% endif %}
{% if solicitacao.desligamento.observacoes %}
<div class="info-item" style="grid-column: 1 / -1;">
<label>Observações Adicionais</label>
<span style="white-space: pre-wrap;">{{ solicitacao.desligamento.observacoes }}</span>
</div>
{% endif %}
</div>
{% elif solicitacao.tipo == 'MOVIMENTACAO' and solicitacao.movimentacao %}
<h5>Detalhes da Movimentação</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Data de Efetivação</label>
<span>{{ solicitacao.movimentacao.data_efetivacao|date:"d/m/Y"|default:"—" }}</span>
</div>
{% if solicitacao.movimentacao.altera_funcao %}
<div class="info-item">
<label>Nova Função</label>
<span>{{ solicitacao.movimentacao.novo_cod_funcao|default:"—" }}</span>
</div>
{% endif %}
{% if solicitacao.movimentacao.altera_centro_custo %}
<div class="info-item">
<label>Nova Seção</label>
<span>{{ solicitacao.movimentacao.novo_cod_secao|default:"—" }}</span>
</div>
{% endif %}
{% if solicitacao.movimentacao.novo_salario %}
<div class="info-item">
<label>Novo Salário</label>
<span>R$ {{ solicitacao.movimentacao.novo_salario }}</span>
</div>
{% endif %}
<div class="info-item" style="grid-column: 1 / -1;">
<label>Justificativa</label>
<span>{{ solicitacao.movimentacao.justificativa|default:"—" }}</span>
</div>
</div>
{% elif solicitacao.tipo == 'ADM_SUBSTITUICAO' and solicitacao.admissao_substituicao %}
<h5>Detalhes da Admissão por Substituição</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Data Prevista</label>
<span>{{ solicitacao.admissao_substituicao.data_previsao_contratacao|date:"d/m/Y"|default:"—" }}</span>
</div>
<div class="info-item">
<label>Coligada Destino</label>
<span>{{ solicitacao.admissao_substituicao.cod_coligada_destino|default:"—" }}</span>
</div>
<div class="info-item">
<label>Filial Destino</label>
<span>{{ solicitacao.admissao_substituicao.cod_filial_destino|default:"—" }}</span>
</div>
<div class="info-item">
<label>Seção Destino</label>
<span>{{ solicitacao.admissao_substituicao.cod_secao_destino|default:"—" }}</span>
</div>
<div class="info-item">
<label>Função Destino</label>
<span>{{ solicitacao.admissao_substituicao.cod_funcao_destino|default:"—" }}</span>
</div>
<div class="info-item" style="grid-column: 1 / -1;">
<label>Justificativa</label>
<span>{{ solicitacao.admissao_substituicao.justificativa|default:"—" }}</span>
</div>
</div>
{% elif solicitacao.tipo == 'ADM_AUMENTO' and solicitacao.admissao_aumento %}
<h5>Detalhes da Admissão por Aumento de Quadro</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Data Prevista</label>
<span>{{ solicitacao.admissao_aumento.data_previsao_contratacao|date:"d/m/Y"|default:"—" }}</span>
</div>
<div class="info-item">
<label>Coligada Destino</label>
<span>{{ solicitacao.admissao_aumento.cod_coligada_destino|default:"—" }}</span>
</div>
<div class="info-item">
<label>Filial Destino</label>
<span>{{ solicitacao.admissao_aumento.cod_filial_destino|default:"—" }}</span>
</div>
<div class="info-item">
<label>Seção Destino</label>
<span>{{ solicitacao.admissao_aumento.cod_secao_destino|default:"—" }}</span>
</div>
<div class="info-item">
<label>Função Destino</label>
<span>{{ solicitacao.admissao_aumento.cod_funcao_destino|default:"—" }}</span>
</div>
<div class="info-item" style="grid-column: 1 / -1;">
<label>Justificativa Estratégica</label>
<span>{{ solicitacao.admissao_aumento.justificativa_estrategica|default:"—" }}</span>
</div>
</div>
{% endif %}
<!-- Ações -->
<div style="margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid #e2e8f0;">
{% if solicitacao.pode_enviar and solicitacao.solicitante.id == usuario_sistema.id %}
<a href="{% url 'solicitacoes:enviar_solicitacao' solicitacao.id %}" class="btn-action btn-action-primary">
🚀 Enviar para Aprovação
</a>
{% endif %}
</div>
</div>
</div>
<!-- ABA: RM (Totvs) -->
{% if solicitacao.funcionario %}
<div class="tab-pane" data-tab="rm">
<div class="details-section section-highlight">
<div style="display: flex; align-items: center; gap: 8px; margin: -1rem 0 1.5rem 0; color: #2563eb; background: #dbeafe; padding: 8px 12px; border-radius: 6px; display: inline-flex;">
<span>💾</span>
<span style="font-size: 0.85rem; font-weight: 600;">Snapshot TOTVS RM</span>
</div>
<h5>Dados Básicos</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Matrícula</label>
<span><strong>{{ solicitacao.funcionario.matricula }}</strong></span>
</div>
<div class="info-item">
<label>Nome Completo</label>
<span><strong>{{ solicitacao.funcionario.nome }}</strong></span>
</div>
{% if solicitacao.funcionario.cpf %}
<div class="info-item">
<label>CPF</label>
<span>{{ solicitacao.funcionario.cpf }}</span>
</div>
{% endif %}
{% if solicitacao.funcionario.data_admissao %}
<div class="info-item">
<label>Data de Admissão</label>
<span>{{ solicitacao.funcionario.data_admissao|date:"d/m/Y" }}</span>
</div>
{% endif %}
{% if solicitacao.funcionario.situacao %}
<div class="info-item">
<label>Situação</label>
<span>{{ solicitacao.funcionario.situacao }}</span>
</div>
{% endif %}
</div>
<h5>Dados Profissionais</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Cargo/Função</label>
<span>{{ solicitacao.funcionario.cargo }}</span>
</div>
<div class="info-item">
<label>Código da Função</label>
<span>{{ solicitacao.funcionario.cod_funcao|default:"N/A" }}</span>
</div>
<div class="info-item">
<label>Setor/Seção</label>
<span>{{ solicitacao.funcionario.setor }}</span>
</div>
<div class="info-item">
<label>Centro de Custo</label>
<span>{{ solicitacao.funcionario.centro_custo }}</span>
</div>
{% if solicitacao.funcionario.salario %}
<div class="info-item">
<label>Salário Atual</label>
<span><strong style="color: #10b981; font-size: 1.1rem;">R$ {{ solicitacao.funcionario.salario|floatformat:2 }}</strong></span>
</div>
{% endif %}
</div>
{% if solicitacao.funcionario.saldo_banco_horas_minutos is not None %}
<h5>Banco de Horas</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Saldo Atual</label>
<span>
{% if solicitacao.funcionario.saldo_banco_horas_minutos >= 0 %}
<strong style="color: #10b981; font-size: 1.1rem;">
+{{ solicitacao.funcionario.saldo_banco_horas_minutos }} min
</strong>
{% else %}
<strong style="color: #ef4444; font-size: 1.1rem;">
{{ solicitacao.funcionario.saldo_banco_horas_minutos }} min
</strong>
{% endif %}
</span>
</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
<!-- ABA: WINTHOR -->
{% for item_acao in solicitacoes_com_acao %}
{% if item_acao.solicitacao.id == solicitacao.id and item_acao.dados_winthor_organizados %}
{% with win=item_acao.dados_winthor_organizados %}
<div class="tab-pane" data-tab="winthor">
<div class="details-section section-highlight" style="border-left-color: #10b981;">
<div style="display: flex; align-items: center; gap: 8px; margin: -1rem 0 1.5rem 0; color: #059669; background: #d1fae5; padding: 8px 12px; border-radius: 6px; display: inline-flex;">
<span>💼</span>
<span style="font-size: 0.85rem; font-weight: 600;">Sistema Winthor</span>
</div>
{% if win.basicos %}
<h5>Dados Básicos</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
{% if win.basicos.matricula %}
<div class="info-item">
<label>Matrícula</label>
<span><strong>{{ win.basicos.matricula }}</strong></span>
</div>
{% endif %}
{% if win.basicos.nome %}
<div class="info-item">
<label>Nome</label>
<span><strong>{{ win.basicos.nome }}</strong></span>
</div>
{% endif %}
{% if win.basicos.cpf %}
<div class="info-item">
<label>CPF</label>
<span>{{ win.basicos.cpf }}</span>
</div>
{% endif %}
</div>
{% endif %}
{% if win.admissao %}
<h5>Admissão e Situação</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
{% if win.admissao.admissao %}
<div class="info-item">
<label>Data de Admissão</label>
<span>
{% if win.admissao.admissao|date:"d/m/Y" %}
{{ win.admissao.admissao|date:"d/m/Y" }}
{% else %}
{{ win.admissao.admissao }}
{% endif %}
</span>
</div>
{% endif %}
{% if win.admissao.situacao %}
<div class="info-item">
<label>Situação</label>
<span>{{ win.admissao.situacao }}</span>
</div>
{% endif %}
{% if win.admissao.dt_exclusao %}
<div class="info-item">
<label>Data de Exclusão</label>
<span>
{% if win.admissao.dt_exclusao|date:"d/m/Y" %}
{{ win.admissao.dt_exclusao|date:"d/m/Y" }}
{% else %}
{{ win.admissao.dt_exclusao }}
{% endif %}
</span>
</div>
{% endif %}
</div>
{% endif %}
{% if win.endereco %}
<h5>Endereço</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
{% if win.endereco.endereco %}
<div class="info-item" style="grid-column: 1 / -1;">
<label>Endereço</label>
<span>{{ win.endereco.endereco }}</span>
</div>
{% endif %}
{% if win.endereco.bairro %}
<div class="info-item">
<label>Bairro</label>
<span>{{ win.endereco.bairro }}</span>
</div>
{% endif %}
{% if win.endereco.cidade %}
<div class="info-item">
<label>Cidade</label>
<span>{{ win.endereco.cidade }}</span>
</div>
{% endif %}
{% if win.endereco.estado %}
<div class="info-item">
<label>Estado</label>
<span>{{ win.endereco.estado }}</span>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endwith %}
{% endif %}
{% endfor %}
<!-- ABA: AUDITORIA -->
<div class="tab-pane" data-tab="auditoria">
<div class="details-section">
<h5>Status Atual</h5>
<div class="info-grid" style="margin-bottom: 1.5rem;">
<div class="info-item">
<label>Status</label>
<span class="status-badge status-{{ solicitacao.status }}">{{ solicitacao.get_status_display }}</span>
</div>
<div class="info-item">
<label>Última Modificação</label>
<span>{{ solicitacao.atualizado_em|date:"d/m/Y H:i" }}</span>
</div>
</div>
<h5>Histórico de Aprovações</h5>
{% if solicitacao.aprovacoes.all %}
<div class="timeline">
{% for aprovacao in solicitacao.aprovacoes.all %}
<div class="timeline-item">
<div class="timeline-header">
<span class="timeline-user">{{ aprovacao.usuario.nome }}</span>
<span class="timeline-action">
{% if aprovacao.decisao == 'APROVADO' %}
<span style="color: #10b981;">aprovou</span>
{% else %}
<span style="color: #ef4444;">reprovou</span>
{% endif %}
em {{ aprovacao.get_etapa_display }}
</span>
<span class="timeline-date">{{ aprovacao.decidido_em|date:"d/m/Y H:i" }}</span>
</div>
{% if aprovacao.justificativa %}
<div class="timeline-justificativa">"{{ aprovacao.justificativa }}"</div>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<p style="color: #64748b; font-style: italic; background: #f8fafc; padding: 10px; border-radius: 6px;">
⏳ Nenhuma aprovação registrada ainda.
</p>
{% endif %}
<!-- Pareceres -->
{% if solicitacao.pareceres.all %}
<h5 style="margin-top: 1.5rem;">Pareceres Técnicos</h5>
<div style="margin-bottom: 1.5rem;">
{% for parecer in solicitacao.pareceres.all %}
<div style="background: white; padding: 16px; border-radius: 8px; margin-bottom: 12px; border: 1px solid #e2e8f0; box-shadow: 0 1px 2px rgba(0,0,0,0.05);">
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
<strong style="color: #1e293b;">{{ parecer.get_etapa_display }}</strong>
<small style="color: #64748b;">{{ parecer.criado_em|date:"d/m/Y H:i" }}</small>
</div>
<small style="color: #64748b; display: block; margin-bottom: 8px;">Autor: {{ parecer.usuario.nome }}</small>
<p style="margin: 0; color: #334155; line-height: 1.5;">{{ parecer.texto }}</p>
{% if parecer.anexo %}
<div style="margin-top: 12px; padding-top: 12px; border-top: 1px dashed #e2e8f0;">
<a href="{{ parecer.anexo.url }}" target="_blank" style="color: #3b82f6; text-decoration: none; font-size: 0.9rem; font-weight: 500;">
📎 Visualizar Anexo ({{ parecer.anexo.name|slice:"20:" }})
</a>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
<!-- Form de parecer -->
{% comment %} {% for item_acao in solicitacoes_com_acao %}
{% if item_acao.solicitacao.id == solicitacao.id %}
{% if item_acao.pode_dar_parecer %}
<div class="form-decisao" style="background: #f0f9ff; border: 2px solid #3b82f6;">
<h5 style="margin-top: 0; color: #1e40af; border: none;">📝 Registrar Parecer Técnico</h5>
<p style="color: #64748b; font-size: 0.9rem; margin-bottom: 1rem;">
Forneça sua análise técnica sobre a solicitação. Este parecer será avaliado pela Diretoria para a decisão final.
</p>
<form method="post" action="{% url 'solicitacoes:registrar_parecer' solicitacao.id %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label for="texto-{{ solicitacao.id }}">Análise: <span style="color: #ef4444;">*</span></label>
<textarea name="texto" id="texto-{{ solicitacao.id }}" rows="4" required placeholder="Descreva sua análise detalhada..."></textarea>
</div>
<div class="form-group">
<label for="anexo-{{ solicitacao.id }}">Anexo (opcional):</label>
<input type="file" name="anexo" id="anexo-{{ solicitacao.id }}" accept=".pdf,.doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png">
<small style="color: #64748b; font-size: 0.85rem;">Formatos aceitos: PDF, Office, Imagens</small>
</div>
<button type="submit" class="btn-action btn-action-primary" style="margin-top: 10px; width: 100%; justify-content: center;">
Salvar Parecer
</button>
</form>
</div>
{% endif %}
{% endif %}
{% endfor %} {% endcomment %}
{% comment %} <!-- Form de decisão (igual ao de solicitacao_detalhe.html) -->
{% for item_acao in solicitacoes_com_acao %}
{% if item_acao.solicitacao.id == solicitacao.id %}
{% if item_acao.pode_aprovar and solicitacao.solicitante.id != usuario_sistema.id %}
<div class="action-card" style="background: #fffbeb; border: 2px solid #f59e0b;">
<h3 style="color: #92400e; margin-top: 0;">⚖️ Decisão Final - Diretoria</h3>
<p style="color: #b45309; font-size: 0.9rem; margin-bottom: 1.5rem;">
Esta é a etapa final. Por favor, revise os pareceres técnicos antes de decidir.
</p>
<form method="post" action="{% url 'solicitacoes:decidir_solicitacao' solicitacao.id %}" id="form-decisao-{{ solicitacao.id }}" class="form-decisao-dashboard">
{% csrf_token %}
<div style="margin-bottom: 15px;">
<label for="decisao-{{ solicitacao.id }}" style="display:block; margin-bottom:5px; font-weight:600; color:#334155;">Veredito <span style="color:red">*</span></label>
<select name="decisao" id="decisao-{{ solicitacao.id }}" class="form-control decisao-select" required>
<option value="">Selecione...</option>
<option value="APROVADO">✅ APROVAR SOLICITAÇÃO</option>
<option value="REPROVADO">❌ REPROVAR SOLICITAÇÃO</option>
</select>
</div>
<div style="margin-bottom: 20px;">
<label for="justificativa-{{ solicitacao.id }}" style="display:block; margin-bottom:5px; font-weight:600; color:#334155;">
Justificativa <span id="justificativa-required-{{ solicitacao.id }}" class="justificativa-required" style="color:red; display:none;">*</span>
</label>
<textarea name="justificativa" id="justificativa-{{ solicitacao.id }}" class="form-control justificativa-input" rows="4" placeholder="Obrigatória apenas se reprovado..."></textarea>
</div>
<button type="submit" class="btn btn-warning" style="width: 100%; justify-content: center; font-size: 1rem;">Confirmar Decisão</button>
</form>
</div>
{% endif %}
{% endif %}
{% endfor %}
{% endcomment %}
{% if solicitacao.solicitante.id == usuario_sistema.id and solicitacao.status != 'RASCUNHO' %}
<div style="background: #f1f5f9; border-radius: 8px; padding: 15px; margin-top: 1.5rem; color: #64748b; text-align: center; font-size: 0.9rem;">
👁️ Você é o solicitante. Acompanhe o status acima.
</div>
{% endif %}
</div>
</div>
</div>
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
</div>
<div id="no-results" class="empty-state" style="display: none;">
<p>🔍 Nenhuma solicitação encontrada com este filtro.</p>
</div>
{% if solicitacoes.has_other_pages %}
<div class="pagination">
{% if solicitacoes.has_previous %}
<a href="?page=1">« Primeira</a>
<a href="?page={{ solicitacoes.previous_page_number }}"> Anterior</a>
{% endif %}
<span class="current">
{{ solicitacoes.number }} / {{ solicitacoes.paginator.num_pages }}
</span>
{% if solicitacoes.has_next %}
<a href="?page={{ solicitacoes.next_page_number }}">Próxima </a>
<a href="?page={{ solicitacoes.paginator.num_pages }}">Última »</a>
{% endif %}
</div>
{% endif %}
{% else %}
<div class="empty-state">
<p>🎉 Nenhuma solicitação encontrada.</p>
{% if usuario_sistema.perfil == 'GESTOR' %}
<p style="font-size: 0.9rem; margin-top: 10px;">Use o botão "Nova Solicitação" para começar.</p>
{% endif %}
</div>
{% endif %}
</div>
{% endblock %}
{% block scripts %}
<script>
function filtrarTabela(status, cardElement) {
// Remove active de todos os cards
document.querySelectorAll('.metric-card').forEach(c => c.classList.remove('active'));
// Adiciona active no card clicado
if (cardElement) cardElement.classList.add('active');
const rows = document.querySelectorAll('.request-row');
let visibleCount = 0;
rows.forEach(row => {
const categoria = row.getAttribute('data-status'); // pendente | aprovado | reprovado (aprovado/reprovado não são mais filtrados)
let show = false;
if (status === 'todos') {
show = true;
} else if (status === 'pendente') {
show = (categoria === 'pendente');
} else {
show = false; // Filtros de aprovado/reprovado removidos
}
if (show) {
row.style.display = '';
visibleCount++;
} else {
row.style.display = 'none';
// Fecha detalhes se estiver aberto
const solicitacaoId = row.getAttribute('data-id');
const detailsRow = document.getElementById('details-' + solicitacaoId);
if (detailsRow && detailsRow.style.display !== 'none') {
detailsRow.style.display = 'none';
row.classList.remove('expanded');
}
}
});
// Mostra mensagem se não houver resultados
const noResults = document.getElementById('no-results');
const tableContainer = document.querySelector('.table-responsive');
if (noResults && tableContainer) {
if (visibleCount === 0) {
noResults.style.display = 'block';
tableContainer.style.display = 'none';
} else {
noResults.style.display = 'none';
tableContainer.style.display = 'block';
}
}
}
function toggleDetails(solicitacaoId, rowElement) {
const detailsRow = document.getElementById('details-' + solicitacaoId);
if (!detailsRow) return;
if (detailsRow.style.display === 'none' || detailsRow.style.display === '') {
// Fecha todas as outras linhas
document.querySelectorAll('.details-row').forEach(row => {
row.style.display = 'none';
});
document.querySelectorAll('.request-row').forEach(row => {
row.classList.remove('expanded');
});
// Abre esta linha
detailsRow.style.display = 'table-row';
if(rowElement) rowElement.classList.add('expanded');
} else {
// Fecha esta linha
detailsRow.style.display = 'none';
if(rowElement) rowElement.classList.remove('expanded');
}
}
function switchTab(event, tabName, solicitacaoId) {
event.preventDefault();
event.stopPropagation();
const wrapper = document.getElementById('wrapper-' + solicitacaoId);
if (!wrapper) return;
const buttons = wrapper.querySelectorAll('.tab-btn');
buttons.forEach(btn => btn.classList.remove('active'));
const panes = wrapper.querySelectorAll('.tab-pane');
panes.forEach(pane => pane.classList.remove('active'));
event.currentTarget.classList.add('active');
const targetPane = wrapper.querySelector(`.tab-pane[data-tab="${tabName}"]`);
if (targetPane) {
targetPane.classList.add('active');
}
}
document.addEventListener('DOMContentLoaded', function() {
const cardTotal = document.querySelector('.card-total');
if (cardTotal) {
filtrarTabela('todos', cardTotal);
}
});
function abrirModalAprovacao(solicitacaoId, decisao) {
const modal = document.getElementById('modal-aprovacao');
const form = document.getElementById('form-aprovacao');
const decisaoInput = document.getElementById('decisao-input');
const justificativaDiv = document.getElementById('justificativa-div');
const justificativaInput = document.getElementById('justificativa-input');
const tituloModal = document.getElementById('titulo-modal');
decisaoInput.value = decisao;
justificativaInput.value = '';
justificativaInput.removeAttribute('required');
if (decisao === 'REPROVADO') {
tituloModal.textContent = 'Reprovar Solicitação';
tituloModal.style.color = '#ef4444';
justificativaDiv.style.display = 'block';
justificativaInput.setAttribute('required', 'required');
justificativaInput.placeholder = 'Descreva o motivo da reprovação...';
} else {
tituloModal.textContent = 'Aprovar Solicitação';
tituloModal.style.color = '#10b981';
justificativaDiv.style.display = 'none';
justificativaInput.removeAttribute('required');
}
form.action = '/solicitacao/' + solicitacaoId + '/decidir/';
modal.style.display = 'flex';
}
function fecharModalAprovacao() {
const modal = document.getElementById('modal-aprovacao');
modal.style.display = 'none';
}
window.onclick = function(event) {
const modal = document.getElementById('modal-aprovacao');
if (event.target === modal) {
fecharModalAprovacao();
}
}
// Decisão Final (form igual ao de solicitacao_detalhe): toggle justificativa e validação
document.querySelectorAll('.decisao-select').forEach(function(select) {
select.addEventListener('change', function() {
var form = this.closest('form');
var justificativa = form.querySelector('.justificativa-input');
var requiredMarker = form.querySelector('.justificativa-required');
if (this.value === 'REPROVADO') {
justificativa.setAttribute('required', 'required');
if (requiredMarker) requiredMarker.style.display = 'inline';
justificativa.placeholder = 'Descreva o motivo da reprovação...';
} else {
justificativa.removeAttribute('required');
if (requiredMarker) requiredMarker.style.display = 'none';
justificativa.placeholder = 'Opcional para aprovação...';
}
});
});
document.querySelectorAll('.form-decisao-dashboard').forEach(function(form) {
form.addEventListener('submit', function(e) {
var decisao = form.querySelector('.decisao-select').value;
var justificativa = form.querySelector('.justificativa-input').value.trim();
if (decisao === 'REPROVADO' && !justificativa) {
e.preventDefault();
alert('A justificativa é obrigatória para reprovações.');
form.querySelector('.justificativa-input').focus();
}
});
});
</script>
<!-- Modal de Aprovação/Reprovação -->
<div id="modal-aprovacao" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); align-items: center; justify-content: center;">
<div class="modal-content">
<h3 id="titulo-modal" style="margin-top: 0; margin-bottom: 20px; font-size: 1.25rem;">Aprovar Solicitação</h3>
<form id="form-aprovacao" method="post" action="">
{% csrf_token %}
<input type="hidden" id="decisao-input" name="decisao" value="">
<div id="justificativa-div" style="display: none; margin-bottom: 20px;">
<label for="justificativa-input" style="display: block; margin-bottom: 8px; font-weight: 600; color: #334155;">
Justificativa Obrigatória <span style="color: #ef4444;">*</span>
</label>
<textarea id="justificativa-input" name="justificativa" rows="4"
style="width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 6px; font-family: inherit; font-size: 0.95rem;"
placeholder="Descreva o motivo..."></textarea>
</div>
<div style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 24px;">
<button type="button" onclick="fecharModalAprovacao()"
style="padding: 10px 20px; background: white; color: #64748b; border: 1px solid #cbd5e1; border-radius: 6px; cursor: pointer; font-weight: 600;">
Cancelar
</button>
<button type="submit"
style="padding: 10px 24px; background: #2563eb; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; box-shadow: 0 1px 2px rgba(0,0,0,0.1);">
Confirmar
</button>
</div>
</form>
</div>
</div>
{% endblock %}