2026-03-09 18:46:01 +00:00
{% extends "base.html" %}
{% block title %}Dashboard - SGMP{% endblock %}
{% block css %}
< style >
.tab-pane { display: none; }
.tab-pane.active { display: block; }
.tab-btn.active { color: #2563eb; border-bottom-color: #2563eb; font-weight: 600; }
.details-row td { padding: 0 !important; border-bottom: none; }
.request-row.expanded .chevron-icon { transform: rotate(180deg); }
.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); }
.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; }
< / style >
{% endblock %}
{% block content %}
< div class = "dashboard-header mb-8 flex flex-col gap-2" >
< h1 class = "text-2xl md:text-3xl font-bold text-slate-800 m-0 tracking-tight" > SGMP - Movimentação de Pessoas< / h1 >
< p class = "text-slate-500 text-sm md:text-base leading-relaxed m-0" >
Olá, < strong > {{ usuario_sistema.nome }}< / strong > !
< span class = "inline-block bg-slate-200 py-0.5 px-2 rounded text-xs ml-2 text-slate-600" > {{ usuario_sistema.get_perfil_display }}< / span >
< br >
< small class = "text-slate-400" > Matrícula: {{ usuario_sistema.matricula }}< / small >
< / p >
< / div >
{% if messages %}
< ul class = "list-none p-0 m-0 mb-5" >
{% for message in messages %}
< li class = "py-3.5 px-4 mb-3 rounded-lg border text-sm flex items-center
{% if message.tags == 'error' %}bg-red-50 text-red-800 border-red-200
{% elif message.tags == 'success' %}bg-green-50 text-green-800 border-green-200
{% else %}bg-blue-50 text-blue-800 border-blue-200{% endif %}">
{% if message.tags == 'error' %}⚠️{% elif message.tags == 'success' %}✅{% else %}ℹ ️ {% endif %}
{{ message }}
< / li >
{% endfor %}
< / ul >
{% endif %}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
{% if usuario_eh_gestor and not usuario_eh_admin %}
2026-03-09 18:46:01 +00:00
< div class = "mb-8" >
< div class = "bg-amber-50 border border-amber-300 rounded-xl p-4 mb-6 flex gap-3 items-start" >
< span class = "text-2xl" > 💡< / span >
< div >
< h4 class = "m-0 mb-1 text-amber-800 font-semibold" > Lembrete Rápido< / h4 >
< p class = "m-0 text-amber-700 text-sm" >
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 %}
< div class = "metrics-grid grid grid-cols-2 md:grid-cols-[repeat(auto-fit,minmax(220px,1fr))] gap-4 md:gap-6 mb-10" >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< div class = "metric-card bg-white p-4 sm:p-6 rounded-xl border border-slate-200 shadow-sm border-l-4 border-l-blue-500 cursor-pointer transition-all hover:-translate-y-1 hover:shadow-md active" onclick = "filtrarTabela('todos', this)" >
2026-03-09 18:46:01 +00:00
< div class = "metric-label text-xs uppercase tracking-wider text-slate-500 font-bold mb-2" > Total< / div >
< div class = "metric-value text-3xl font-extrabold leading-none text-blue-500" > {{ total }}< / div >
< / div >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< div class = "metric-card bg-white p-4 sm:p-6 rounded-xl border border-slate-200 shadow-sm border-l-4 border-l-amber-500 cursor-pointer transition-all hover:-translate-y-1 hover:shadow-md" onclick = "filtrarTabela('pendente', this)" >
2026-03-09 18:46:01 +00:00
< div class = "metric-label text-xs uppercase tracking-wider text-slate-500 font-bold mb-2" > Pendentes< / div >
< div class = "metric-value text-3xl font-extrabold leading-none text-amber-600" > {{ pendentes }}< / div >
< / div >
< / div >
< div class = "section mb-8" >
< h3 class = "text-slate-800 text-xl font-semibold mb-4 flex items-center gap-2" >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
{% if usuario_eh_admin %}📑 Visão Geral de Solicitações{% elif usuario_eh_gestor %}📋 Minhas Solicitações{% else %}⏳ Pendentes de Aprovação{% endif %}
2026-03-09 18:46:01 +00:00
< / h3 >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
{% if usuario_eh_admin %}
2026-03-09 18:46:01 +00:00
< div class = "bg-blue-50 border border-blue-200 rounded-lg py-3 px-4 mb-5 text-blue-800 text-sm flex items-center gap-2" >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
ℹ ️ Você está com visão administrativa completa e pode atuar conforme o status de cada solicitação.
< / div >
{% elif usuario_eh_gg or usuario_eh_controladoria %}
< div class = "bg-blue-50 border border-blue-200 rounded-lg py-3 px-4 mb-5 text-blue-800 text-sm flex items-center gap-2" >
ℹ ️ Sua fila inclui solicitações < strong > Enviadas< / strong > nas quais falta parecer de Gente e Gestão ou Controladoria. A coluna < strong > Status< / strong > indica qual etapa está pendente.
< / div >
{% elif usuario_eh_head %}
< div class = "bg-blue-50 border border-blue-200 rounded-lg py-3 px-4 mb-5 text-blue-800 text-sm flex items-center gap-2" >
ℹ ️ Sua fila inclui solicitações < strong > Aguardando Head< / strong > dos gestores vinculados a você.
2026-03-09 18:46:01 +00:00
< / div >
{% endif %}
{% if solicitacoes %}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< div id = "dashboard-cards-mobile" class = "md:hidden space-y-3" >
{% for item in solicitacoes_com_acao %}
{% with solicitacao=item.solicitacao %}
< article class = "solicitacao-list-item bg-white rounded-xl shadow border border-slate-200 p-4"
data-id="{{ solicitacao.id }}"
data-status="{% if solicitacao.status == 'FINALIZADA' %}aprovado{% elif solicitacao.status == 'REPROVADA' %}reprovado{% else %}pendente{% endif %}">
< div class = "flex items-start justify-between gap-3 mb-2 min-w-0" >
< p class = "font-semibold text-slate-900 leading-tight text-sm min-w-0 flex-1" > {{ solicitacao.get_tipo_display }}< / p >
< span class = "status-badge inline-flex items-center shrink-0 max-w-[min(100%,14rem)] text-left break-words py-1 px-2.5 rounded-full text-xs font-bold leading-snug status-{{ solicitacao.status }}" > {{ item.status_display_viewer }}< / span >
< / div >
< p class = "text-sm text-slate-700 font-medium break-words" > {% if solicitacao.funcionario %}{{ solicitacao.funcionario.nome }}{% else %}< span class = "text-slate-400" > N/A< / span > {% endif %}< / p >
< p class = "text-sm text-slate-500 mt-1" > {{ solicitacao.criado_em|date:"d/m/Y H:i" }}< / p >
< div class = "flex flex-wrap items-center gap-2 mt-3" >
< a href = "{% url 'solicitacoes:solicitacao_detalhe' solicitacao.id %}" class = "text-primary font-semibold text-sm no-underline hover:underline" > Página completa< / a >
{% if item.pode_dar_parecer %}
< a href = "{% url 'solicitacoes:solicitacao_detalhe' solicitacao.id %}" class = "inline-flex items-center gap-1.5 py-2 px-3 rounded-md text-sm font-semibold bg-primary text-white border border-primary-hover hover:bg-primary-hover no-underline" > 📝 Parecer< / a >
{% endif %}
{% if item.pode_aprovar %}
< button type = "button" class = "py-1.5 px-2.5 text-sm bg-emerald-500 text-white border border-emerald-600 rounded hover:bg-emerald-600" onclick = "abrirModalAprovacao('{{ solicitacao.id }}', 'APROVADO')" title = "Aprovar" > ✅< / button >
< button type = "button" class = "py-1.5 px-2.5 text-sm bg-white text-red-500 border border-red-500 rounded hover:bg-red-50" onclick = "abrirModalAprovacao('{{ solicitacao.id }}', 'REPROVADO')" title = "Reprovar" > ❌< / button >
{% endif %}
< / div >
< / article >
{% endwith %}
{% endfor %}
< / div >
< div class = "table-responsive hidden md:block w-full overflow-x-auto bg-white rounded-xl shadow border border-slate-200" >
< table id = "tabela-solicitacoes" class = "w-full border-collapse min-w-[640px]" >
2026-03-09 18:46:01 +00:00
< thead >
< tr >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< th class = "p-4 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wide whitespace-nowrap" > Tipo< / th >
2026-03-09 18:46:01 +00:00
< th class = "p-4 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wide" > Colaborador< / th >
< th class = "p-4 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wide" > Status< / th >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< th class = "p-4 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wide whitespace-nowrap" > Data< / th >
2026-03-09 18:46:01 +00:00
< th class = "p-4 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wide" > Ações< / th >
< / tr >
< / thead >
< tbody >
{% for item in solicitacoes_com_acao %}
{% with solicitacao=item.solicitacao %}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< tr class = "request-row solicitacao-list-item border-b border-slate-200 hover:bg-slate-50 cursor-pointer"
2026-03-09 18:46:01 +00:00
data-id="{{ solicitacao.id }}"
data-status="{% if solicitacao.status == 'FINALIZADA' %}aprovado{% elif solicitacao.status == 'REPROVADA' %}reprovado{% else %}pendente{% endif %}"
onclick="toggleDetails('{{ solicitacao.id }}', this)">
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< td class = "p-4 min-w-0 max-w-[12rem]" > < strong class = "break-words" > {{ solicitacao.get_tipo_display }}< / strong > < / td >
< td class = "p-4 min-w-0 max-w-[14rem] break-words" >
2026-03-09 18:46:01 +00:00
{% if solicitacao.funcionario %}{{ solicitacao.funcionario.nome }}{% else %}< span class = "text-slate-400" > N/A< / span > {% endif %}
< / td >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< td class = "p-4 min-w-0" >
< span class = "status-badge inline-flex items-center py-1 px-2.5 rounded-full text-xs font-bold leading-snug break-words max-w-xs status-{{ solicitacao.status }}" > {{ item.status_display_viewer }}< / span >
2026-03-09 18:46:01 +00:00
< / td >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< td class = "p-4 text-slate-500 whitespace-nowrap" > {{ solicitacao.criado_em|date:"d/m/Y H:i" }}< / td >
< td class = "p-4 min-w-[10rem]" >
< div class = "flex flex-wrap gap-2 items-center" >
< span class = "expand-btn text-blue-600 font-semibold text-sm whitespace-nowrap" > Detalhes < span class = "chevron-icon inline-block text-xs transition-transform" > ▼< / span > < / span >
2026-03-09 18:46:01 +00:00
{% if item.pode_dar_parecer %}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< a href = "{% url 'solicitacoes:solicitacao_detalhe' solicitacao.id %}" class = "btn-action btn-action-primary inline-flex items-center gap-1.5 py-2.5 px-4 rounded-md text-sm font-semibold bg-primary text-white border border-primary-hover hover:bg-primary-hover no-underline" title = "Fornecer parecer técnico" onclick = "event.stopPropagation();" > 📝 Parecer< / a >
2026-03-09 18:46:01 +00:00
{% endif %}
{% if item.pode_aprovar %}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< div class = "flex flex-wrap gap-1" >
2026-03-09 18:46:01 +00:00
< button type = "button" class = "btn-action btn-action-success py-1 px-2 text-sm bg-emerald-500 text-white border border-emerald-600 rounded hover:bg-emerald-600" onclick = "event.stopPropagation(); abrirModalAprovacao('{{ solicitacao.id }}', 'APROVADO')" title = "Aprovar" > ✅< / button >
< button type = "button" class = "btn-action btn-action-danger py-1 px-2 text-sm bg-white text-red-500 border border-red-500 rounded hover:bg-red-50" onclick = "event.stopPropagation(); abrirModalAprovacao('{{ solicitacao.id }}', 'REPROVADO')" title = "Reprovar" > ❌< / button >
< / div >
{% endif %}
< / div >
< / td >
< / tr >
< tr id = "details-{{ solicitacao.id }}" class = "details-row bg-slate-50" style = "display:none;" >
< td colspan = "5" >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< div class = "details-wrapper p-4 sm:p-6 md:p-8" id = "wrapper-{{ solicitacao.id }}" >
< div class = "flex flex-col sm:flex-row sm:items-stretch sm:justify-between gap-2 border-b border-slate-200 mb-6" >
< div class = "tab-nav flex flex-1 min-w-0 gap-6 md:gap-8 overflow-x-auto pb-0 -mb-px" >
< button type = "button" class = "tab-btn active pb-3 border-b-2 border-transparent text-slate-500 text-sm font-medium whitespace-nowrap hover:text-primary border-b-primary text-primary font-semibold" onclick = "switchTab(event, 'solicitacao', '{{ solicitacao.id }}')" > 📄 Solicitação< / button >
{% if solicitacao.funcionario %}
< button type = "button" class = "tab-btn pb-3 border-b-2 border-transparent text-slate-500 text-sm font-medium whitespace-nowrap hover:text-primary" onclick = "switchTab(event, 'rm', '{{ solicitacao.id }}')" > 🏢 RM (Totvs)< / button >
2026-03-09 18:46:01 +00:00
{% endif %}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
{% for item_acao in solicitacoes_com_acao %}
{% if item_acao.solicitacao.id == solicitacao.id and item_acao.dados_winthor_organizados %}
< button type = "button" class = "tab-btn pb-3 border-b-2 border-transparent text-slate-500 text-sm font-medium whitespace-nowrap hover:text-primary" onclick = "switchTab(event, 'winthor', '{{ solicitacao.id }}')" > 💼 Winthor< / button >
{% endif %}
{% endfor %}
< button type = "button" class = "tab-btn pb-3 border-b-2 border-transparent text-slate-500 text-sm font-medium whitespace-nowrap hover:text-primary" onclick = "switchTab(event, 'auditoria', '{{ solicitacao.id }}')" > 📝 Histórico & Auditoria< / button >
< / div >
< a href = "{% url 'solicitacoes:solicitacao_detalhe' solicitacao.id %}" class = "tab-open-page shrink-0 self-end sm:self-auto inline-flex items-center gap-1 pb-3 text-sm font-medium text-slate-500 hover:text-primary no-underline border-b-2 border-transparent hover:border-slate-300 transition-colors whitespace-nowrap" onclick = "event.stopPropagation();" title = "Abrir esta solicitação em página própria" > Página completa < span class = "text-slate-400" aria-hidden = "true" > ↗< / span > < / a >
2026-03-09 18:46:01 +00:00
< / div >
< div class = "tab-pane active" data-tab = "solicitacao" >
< div class = "details-section mb-6 bg-white p-6 rounded-xl border border-slate-200" >
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2 first:mt-0" > Dados Gerais< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Solicitante< / label > < span class = "text-slate-900 font-medium" > {{ solicitacao.solicitante.nome }} < small class = "text-slate-500" > ({{ solicitacao.solicitante.matricula }})< / small > < / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Tipo< / label > < span class = "font-bold text-primary" > {{ solicitacao.get_tipo_display }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Data Criação< / label > < span class = "text-slate-900 font-medium" > {{ solicitacao.criado_em|date:"d/m/Y H:i" }}< / span > < / div >
{% if solicitacao.enviada_em %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Enviada em< / label > < span class = "text-slate-900 font-medium" > {{ solicitacao.enviada_em|date:"d/m/Y H:i" }}< / span > < / div > {% endif %}
{% if solicitacao.finalizada_em %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Finalizada em< / label > < span class = "text-slate-900 font-medium" > {{ solicitacao.finalizada_em|date:"d/m/Y H:i" }}< / span > < / div > {% endif %}
< / div >
{% if solicitacao.tipo == 'DESLIGAMENTO' and solicitacao.desligamento %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Detalhes do Desligamento< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
{% if solicitacao.desligamento.tipo_desligamento %}
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > 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 flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > 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 flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Data Prevista de Saída< / label > < span > {{ solicitacao.desligamento.data_prevista_desligamento|date:"d/m/Y"|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Detalhamento / Justificativa< / label > < span class = "whitespace-pre-wrap" > {{ solicitacao.desligamento.motivo|default:"—" }}< / span > < / div >
{% if solicitacao.desligamento.arquivo_pedido %}< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Carta de Pedido< / label > < span > < a href = "{{ solicitacao.desligamento.arquivo_pedido.url }}" target = "_blank" class = "text-primary no-underline" > 📎 Ver arquivo< / a > < / span > < / div > {% endif %}
{% if solicitacao.desligamento.observacoes %}< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Observações Adicionais< / label > < span class = "whitespace-pre-wrap" > {{ solicitacao.desligamento.observacoes }}< / span > < / div > {% endif %}
< / div >
{% elif solicitacao.tipo == 'MOVIMENTACAO' and solicitacao.movimentacao %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Detalhes da Movimentação< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > 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 flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Nova Função< / label > < span > {{ solicitacao.movimentacao.novo_cod_funcao|default:"—" }}< / span > < / div > {% endif %}
{% if solicitacao.movimentacao.altera_centro_custo %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Nova Seção< / label > < span > {{ solicitacao.movimentacao.novo_cod_secao|default:"—" }}< / span > < / div > {% endif %}
{% if solicitacao.movimentacao.novo_salario %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Novo Salário< / label > < span > R$ {{ solicitacao.movimentacao.novo_salario }}< / span > < / div > {% endif %}
< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Justificativa< / label > < span > {{ solicitacao.movimentacao.justificativa|default:"—" }}< / span > < / div >
< / div >
{% elif solicitacao.tipo == 'ADM_SUBSTITUICAO' and solicitacao.admissao_substituicao %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Detalhes da Admissão por Substituição< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Data Prevista< / label > < span > {{ solicitacao.admissao_substituicao.data_previsao_contratacao|date:"d/m/Y"|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Coligada Destino< / label > < span > {{ solicitacao.admissao_substituicao.cod_coligada_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Filial Destino< / label > < span > {{ solicitacao.admissao_substituicao.cod_filial_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Seção Destino< / label > < span > {{ solicitacao.admissao_substituicao.cod_secao_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Função Destino< / label > < span > {{ solicitacao.admissao_substituicao.cod_funcao_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Justificativa< / label > < span > {{ solicitacao.admissao_substituicao.justificativa|default:"—" }}< / span > < / div >
< / div >
{% elif solicitacao.tipo == 'ADM_AUMENTO' and solicitacao.admissao_aumento %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Detalhes da Admissão por Aumento de Quadro< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Data Prevista< / label > < span > {{ solicitacao.admissao_aumento.data_previsao_contratacao|date:"d/m/Y"|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Coligada Destino< / label > < span > {{ solicitacao.admissao_aumento.cod_coligada_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Filial Destino< / label > < span > {{ solicitacao.admissao_aumento.cod_filial_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Seção Destino< / label > < span > {{ solicitacao.admissao_aumento.cod_secao_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Função Destino< / label > < span > {{ solicitacao.admissao_aumento.cod_funcao_destino|default:"—" }}< / span > < / div >
< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Justificativa Estratégica< / label > < span > {{ solicitacao.admissao_aumento.justificativa_estrategica|default:"—" }}< / span > < / div >
< / div >
{% endif %}
< div class = "mt-8 pt-6 border-t border-slate-200" >
{% 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 inline-flex items-center gap-1.5 py-2.5 px-4 rounded-md text-sm font-semibold bg-primary text-white border border-primary-hover hover:bg-primary-hover no-underline" > 🚀 Enviar para Aprovação< / a >
{% endif %}
< / div >
< / div >
< / div >
{% if solicitacao.funcionario %}
< div class = "tab-pane" data-tab = "rm" >
< div class = "details-section mb-6 bg-white p-6 rounded-xl border-2 border-primary" >
< div class = "inline-flex items-center gap-2 -mt-4 mb-6 text-primary bg-blue-100 py-2 px-3 rounded-md text-sm font-semibold" > 💾 Snapshot TOTVS RM< / div >
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2 first:mt-0" > Dados Básicos< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Matrícula< / label > < span > < strong > {{ solicitacao.funcionario.matricula }}< / strong > < / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Nome Completo< / label > < span > < strong > {{ solicitacao.funcionario.nome }}< / strong > < / span > < / div >
{% if solicitacao.funcionario.cpf %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > CPF< / label > < span > {{ solicitacao.funcionario.cpf }}< / span > < / div > {% endif %}
{% if solicitacao.funcionario.data_admissao %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > 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 flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Situação< / label > < span > {{ solicitacao.funcionario.situacao }}< / span > < / div > {% endif %}
< / div >
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Dados Profissionais< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Cargo/Função< / label > < span > {{ solicitacao.funcionario.cargo }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Código da Função< / label > < span > {{ solicitacao.funcionario.cod_funcao|default:"N/A" }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Setor/Seção< / label > < span > {{ solicitacao.funcionario.setor }}< / span > < / div >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Centro de Custo< / label > < span > {{ solicitacao.funcionario.centro_custo }}< / span > < / div >
{% if solicitacao.funcionario.salario %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Salário Atual< / label > < span > < strong class = "text-emerald-600 text-lg" > R$ {{ solicitacao.funcionario.salario|floatformat:2 }}< / strong > < / span > < / div > {% endif %}
< / div >
{% if solicitacao.funcionario.saldo_banco_horas_minutos is not None %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Banco de Horas< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Saldo Atual< / label > < span > {% if solicitacao.funcionario.saldo_banco_horas_minutos >= 0 %}< strong class = "text-emerald-600 text-lg" > +{{ solicitacao.funcionario.saldo_banco_horas_minutos }} min< / strong > {% else %}< strong class = "text-red-500 text-lg" > {{ solicitacao.funcionario.saldo_banco_horas_minutos }} min< / strong > {% endif %}< / span > < / div >
< / div >
{% endif %}
< / div >
< / div >
{% endif %}
{% 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 mb-6 bg-white p-6 rounded-xl border-2 border-emerald-500" >
< div class = "inline-flex items-center gap-2 -mt-4 mb-6 text-emerald-700 bg-emerald-100 py-2 px-3 rounded-md text-sm font-semibold" > 💼 Sistema Winthor< / div >
{% if win.basicos %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2 first:mt-0" > Dados Básicos< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
{% if win.basicos.matricula %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Matrícula< / label > < span > < strong > {{ win.basicos.matricula }}< / strong > < / span > < / div > {% endif %}
{% if win.basicos.nome %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Nome< / label > < span > < strong > {{ win.basicos.nome }}< / strong > < / span > < / div > {% endif %}
{% if win.basicos.cpf %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > CPF< / label > < span > {{ win.basicos.cpf }}< / span > < / div > {% endif %}
< / div >
{% endif %}
{% if win.admissao %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Admissão e Situação< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
{% if win.admissao.admissao %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > 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 flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Situação< / label > < span > {{ win.admissao.situacao }}< / span > < / div > {% endif %}
{% if win.admissao.dt_exclusao %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > 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 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Endereço< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
{% if win.endereco.endereco %}< div class = "info-item flex flex-col md:col-span-full" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Endereço< / label > < span > {{ win.endereco.endereco }}< / span > < / div > {% endif %}
{% if win.endereco.bairro %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Bairro< / label > < span > {{ win.endereco.bairro }}< / span > < / div > {% endif %}
{% if win.endereco.cidade %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Cidade< / label > < span > {{ win.endereco.cidade }}< / span > < / div > {% endif %}
{% if win.endereco.estado %}< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Estado< / label > < span > {{ win.endereco.estado }}< / span > < / div > {% endif %}
< / div >
{% endif %}
< / div >
< / div >
{% endwith %}
{% endif %}
{% endfor %}
< div class = "tab-pane" data-tab = "auditoria" >
< div class = "details-section mb-6 bg-white p-6 rounded-xl border border-slate-200" >
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2 first:mt-0" > Status Atual< / h5 >
< div class = "info-grid grid grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-6 mb-6" >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
< div class = "info-item flex flex-col min-w-0" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Status< / label > < span class = "status-badge inline-block max-w-full break-words leading-snug status-{{ solicitacao.status }}" > {{ item.status_display_viewer }}< / span > < / div >
2026-03-09 18:46:01 +00:00
< div class = "info-item flex flex-col" > < label class = "text-xs text-slate-500 mb-1 font-semibold uppercase" > Última Modificação< / label > < span > {{ solicitacao.atualizado_em|date:"d/m/Y H:i" }}< / span > < / div >
< / div >
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Histórico de Aprovações< / h5 >
{% if solicitacao.aprovacoes.all %}
< div class = "timeline pl-8 border-l-2 border-slate-200 ml-2" >
{% for aprovacao in solicitacao.aprovacoes.all %}
< div class = "timeline-item relative pb-8 pl-6 last:pb-0 before:content-[''] before:absolute before:-left-[2.4rem] before:top-1 before:w-3.5 before:h-3.5 before:rounded-full before:bg-slate-300 before:border-[3px] before:border-white before:shadow-[0_0_0_1px_#e2e8f0]" >
< div class = "timeline-header flex flex-wrap gap-2 mb-1 text-sm items-baseline" >
< span class = "timeline-user font-semibold text-slate-800" > {{ aprovacao.usuario.nome }}< / span >
< span class = "timeline-action text-slate-500" > {% if aprovacao.decisao == 'APROVADO' %}< span class = "text-emerald-500" > aprovou< / span > {% else %}< span class = "text-red-500" > reprovou< / span > {% endif %} em {{ aprovacao.get_etapa_display }}< / span >
< span class = "timeline-date text-xs text-slate-400 ml-auto" > {{ aprovacao.decidido_em|date:"d/m/Y H:i" }}< / span >
< / div >
{% if aprovacao.justificativa %}< div class = "timeline-justificativa mt-3 p-4 bg-slate-50 rounded-lg text-sm text-slate-700 border border-slate-200 italic" > "{{ aprovacao.justificativa }}"< / div > {% endif %}
< / div >
{% endfor %}
< / div >
{% else %}
< p class = "text-slate-500 italic bg-slate-50 p-2.5 rounded-md" > ⏳ Nenhuma aprovação registrada ainda.< / p >
{% endif %}
{% if solicitacao.pareceres.all %}
< h5 class = "text-slate-400 text-xs uppercase mt-6 mb-4 font-bold tracking-wider border-b border-slate-100 pb-2" > Pareceres Técnicos< / h5 >
< div class = "mb-6" >
{% for parecer in solicitacao.pareceres.all %}
< div class = "bg-white p-4 rounded-lg mb-3 border border-slate-200 shadow-sm" >
< div class = "flex justify-between mb-2" > < strong class = "text-slate-800" > {{ parecer.get_etapa_display }}< / strong > < small class = "text-slate-500" > {{ parecer.criado_em|date:"d/m/Y H:i" }}< / small > < / div >
< small class = "text-slate-500 block mb-2" > Autor: {{ parecer.usuario.nome }}< / small >
< p class = "m-0 text-slate-700 leading-relaxed" > {{ parecer.texto }}< / p >
{% if parecer.anexo %}< div class = "mt-3 pt-3 border-t border-dashed border-slate-200" > < a href = "{{ parecer.anexo.url }}" target = "_blank" class = "text-primary no-underline text-sm font-medium" > 📎 Visualizar Anexo ({{ parecer.anexo.name|slice:"20:" }})< / a > < / div > {% endif %}
< / div >
{% endfor %}
< / div >
{% endif %}
{% if solicitacao.solicitante.id == usuario_sistema.id and solicitacao.status != 'RASCUNHO' %}
< div class = "bg-slate-100 rounded-lg py-4 px-4 mt-6 text-slate-500 text-center text-sm" > 👁️ 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 text-center py-16 px-5 text-slate-500 bg-white rounded-xl border-2 border-dashed border-slate-300 hidden" >
< p class = "m-0 text-lg" > 🔍 Nenhuma solicitação encontrada com este filtro.< / p >
< / div >
{% if solicitacoes.has_other_pages %}
< div class = "pagination mt-6 flex items-center justify-center gap-1.5 flex-wrap" >
{% if solicitacoes.has_previous %}< a href = "?page=1" class = "py-2 px-3.5 no-underline border border-slate-200 rounded-md text-slate-600 bg-white text-sm transition-all hover:bg-slate-50 hover:border-slate-300 hover:text-slate-800" > « Primeira< / a > < a href = "?page={{ solicitacoes.previous_page_number }}" class = "py-2 px-3.5 no-underline border border-slate-200 rounded-md text-slate-600 bg-white text-sm transition-all hover:bg-slate-50 hover:border-slate-300 hover:text-slate-800" > ‹ Anterior< / a > {% endif %}
< span class = "current py-2 px-3.5 bg-primary text-white rounded-md font-medium border border-primary" > {{ solicitacoes.number }} / {{ solicitacoes.paginator.num_pages }}< / span >
{% if solicitacoes.has_next %}< a href = "?page={{ solicitacoes.next_page_number }}" class = "py-2 px-3.5 no-underline border border-slate-200 rounded-md text-slate-600 bg-white text-sm transition-all hover:bg-slate-50 hover:border-slate-300 hover:text-slate-800" > Próxima › < / a > < a href = "?page={{ solicitacoes.paginator.num_pages }}" class = "py-2 px-3.5 no-underline border border-slate-200 rounded-md text-slate-600 bg-white text-sm transition-all hover:bg-slate-50 hover:border-slate-300 hover:text-slate-800" > Última »< / a > {% endif %}
< / div >
{% endif %}
{% else %}
< div class = "empty-state text-center py-16 px-5 text-slate-500 bg-white rounded-xl border-2 border-dashed border-slate-300" >
< p class = "m-0 text-lg" > 🎉 Nenhuma solicitação encontrada.< / p >
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
{% if usuario_eh_gestor or usuario_eh_admin %}< p class = "text-sm mt-2" > Use o botão "Nova Solicitação" para começar.< / p > {% endif %}
2026-03-09 18:46:01 +00:00
< / div >
{% endif %}
< / div >
{% endblock %}
{% block scripts %}
< script >
function filtrarTabela(status, cardElement) {
document.querySelectorAll('.metric-card').forEach(c => c.classList.remove('active'));
if (cardElement) cardElement.classList.add('active');
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
function applyItem(el, isTableRow) {
const categoria = el.getAttribute('data-status');
const show = (status === 'todos') || (status === 'pendente' & & categoria === 'pendente');
if (isTableRow) {
if (show) { el.style.display = ''; } else {
el.style.display = 'none';
const solicitacaoId = el.getAttribute('data-id');
const detailsRow = document.getElementById('details-' + solicitacaoId);
if (detailsRow & & detailsRow.style.display !== 'none') { detailsRow.style.display = 'none'; el.classList.remove('expanded'); }
}
} else {
el.style.display = show ? '' : 'none';
2026-03-09 18:46:01 +00:00
}
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
return show;
}
let visibleCount = 0;
document.querySelectorAll('#tabela-solicitacoes .request-row.solicitacao-list-item').forEach(row => {
if (applyItem(row, true)) visibleCount++;
2026-03-09 18:46:01 +00:00
});
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
document.querySelectorAll('#dashboard-cards-mobile .solicitacao-list-item').forEach(card => { applyItem(card, false); });
2026-03-09 18:46:01 +00:00
const noResults = document.getElementById('no-results');
const tableContainer = document.querySelector('.table-responsive');
feat(sgmp): API REST, app Next.js, ConfiguracaoSGMP e ajustes de permissões/serviços
- API JSON (auth, dashboard, colaboradores, solicitações) e app Next em frontend/
- Modelo ConfiguracaoSGMP, migrações e permissões (acesso, decorators, context)
- Serviços/views/templates e integrações Winthor/SQL Server
- Docs: MIGRACAO, ARQUITETURA_APROVACAO, README_PERMISSOES; Dockerfile/requirements
- Testes: fluxo de desligamento alinhado a pareceres GG/Ctrl + Diretoria; criar_solicitacao_desligamento com tipo/aviso
Made-with: Cursor
2026-04-15 01:44:49 +00:00
const cardsMobile = document.getElementById('dashboard-cards-mobile');
if (noResults & & tableContainer) {
noResults.style.display = visibleCount === 0 ? 'block' : 'none';
tableContainer.style.display = visibleCount === 0 ? 'none' : '';
}
if (cardsMobile) { cardsMobile.style.display = visibleCount === 0 ? 'none' : ''; }
2026-03-09 18:46:01 +00:00
}
function toggleDetails(solicitacaoId, rowElement) {
const detailsRow = document.getElementById('details-' + solicitacaoId);
if (!detailsRow) return;
if (detailsRow.style.display === 'none' || detailsRow.style.display === '') {
document.querySelectorAll('.details-row').forEach(row => { row.style.display = 'none'; });
document.querySelectorAll('.request-row').forEach(row => { row.classList.remove('expanded'); });
detailsRow.style.display = 'table-row';
if (rowElement) rowElement.classList.add('expanded');
} else {
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;
wrapper.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
wrapper.querySelectorAll('.tab-pane').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';
}
form.action = '/solicitacao/' + solicitacaoId + '/decidir/';
modal.style.display = 'flex';
}
function fecharModalAprovacao() { document.getElementById('modal-aprovacao').style.display = 'none'; }
window.onclick = function(event) { if (event.target === document.getElementById('modal-aprovacao')) fecharModalAprovacao(); };
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 >
< div id = "modal-aprovacao" class = "hidden fixed inset-0 z-[1000] bg-black/50 items-center justify-center" style = "display: none;" >
< div class = "modal-content bg-white p-8 rounded-xl max-w-md w-[90%] shadow-xl border border-slate-200" >
< h3 id = "titulo-modal" class = "mt-0 mb-5 text-xl font-semibold" > 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" class = "hidden mb-5" >
< label for = "justificativa-input" class = "block mb-2 font-semibold text-slate-700" > Justificativa Obrigatória < span class = "text-red-500" > *< / span > < / label >
< textarea id = "justificativa-input" name = "justificativa" rows = "4" class = "w-full p-2.5 border border-slate-300 rounded-md font-sans text-sm focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20" placeholder = "Descreva o motivo..." > < / textarea >
< / div >
< div class = "flex gap-2.5 justify-end mt-6" >
< button type = "button" onclick = "fecharModalAprovacao()" class = "py-2.5 px-5 bg-white text-slate-500 border border-slate-300 rounded-md cursor-pointer font-semibold hover:bg-slate-50" > Cancelar< / button >
< button type = "submit" class = "py-2.5 px-6 bg-primary text-white border-none rounded-md cursor-pointer font-semibold shadow-sm" > Confirmar< / button >
< / div >
< / form >
< / div >
< / div >
{% endblock %}