1333 lines
70 KiB
HTML
1333 lines
70 KiB
HTML
|
|
{% 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 %}
|
|||
|
|
{{ 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 %}
|