sgmp/templates/solicitacoes/todas_solicitacoes.html

151 lines
9.7 KiB
HTML

{% extends "base.html" %}
{% block title %}Todas as Solicitações - SGMP{% endblock %}
{% block css %}
<style>
.filter-pill.active { background-color: #2563eb; color: white; border-color: #2563eb; font-weight: 600; }
.custom-table { table-layout: fixed; }
.custom-table th:nth-child(1) { width: 18%; } .custom-table th:nth-child(2), .custom-table th:nth-child(3) { width: 18%; }
.custom-table th:nth-child(4), .custom-table th:nth-child(5) { width: 12%; } .custom-table th:nth-child(6) { width: 22%; }
.status-RASCUNHO { background: #f3f4f6; color: #4b5563; }
.status-AGUARDANDO_HEAD { background: #fefce8; color: #a16207; }
.status-ENVIADA { background: #eff6ff; color: #1d4ed8; }
.status-APROVADA_GG, .status-APROVADA_CONTROLADORIA { background: #f0fdf4; color: #15803d; }
.status-AGUARDANDO_DIRETORIA { background: #fefce8; color: #a16207; }
.status-FINALIZADA, .status-APROVADA_DIRETORIA { background: #ecfdf5; color: #047857; }
.status-REPROVADA { background: #fef2f2; color: #b91c1c; }
#no-results-message { display: none; }
</style>
{% endblock %}
{% block content %}
<div class="page-header mb-6">
<h1 class="text-2xl font-bold text-slate-800 mb-1">Todas as Solicitações</h1>
<p class="text-slate-500 text-base max-w-xl">Acompanhe, filtre e analise todas as solicitações do sistema de forma rápida e centralizada.</p>
</div>
<div class="control-panel bg-white p-4 md:p-6 rounded-lg shadow border border-slate-200 mb-8">
<div class="filters-header flex flex-wrap justify-between items-center gap-4 mb-4">
<h2 class="text-base font-semibold text-slate-800 m-0">Filtros</h2>
<div class="search-box relative min-w-[280px]">
<svg class="absolute left-3 top-1/2 -translate-y-1/2 w-[18px] h-[18px] text-slate-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" /></svg>
<input type="text" id="searchInput" class="search-input w-full py-2.5 pl-10 pr-3 border border-slate-200 rounded-md text-sm focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20" placeholder="Pesquisar por nome, tipo ou ID...">
</div>
</div>
<div class="filter-pills flex flex-wrap gap-2 border-t border-slate-200 pt-4">
<button type="button" class="filter-pill active px-3 py-1.5 rounded-full text-xs font-medium border border-slate-200 text-slate-500 hover:bg-slate-100 hover:border-slate-300 hover:text-slate-800 transition-colors cursor-pointer" data-status="todos">Todos</button>
{% for valor, label in status_choices %}
<button type="button" class="filter-pill px-3 py-1.5 rounded-full text-xs font-medium border border-slate-200 text-slate-500 hover:bg-slate-100 hover:border-slate-300 hover:text-slate-800 transition-colors cursor-pointer" data-status="{{ valor }}">{{ label }}</button>
{% endfor %}
<button type="button" id="clearFilters" class="clear-filters bg-transparent border-none text-primary font-medium cursor-pointer text-sm py-1 px-1 hover:underline">Limpar Filtros</button>
</div>
</div>
{% if solicitacoes %}
<div class="table-container bg-white rounded-lg shadow border border-slate-200 overflow-x-auto max-w-full">
<table class="custom-table w-full min-w-0 border-collapse">
<thead>
<tr>
<th class="p-3 md:p-3.5 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wider">Tipo da Solicitação</th>
<th class="p-3 md:p-3.5 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wider">Colaborador</th>
<th class="p-3 md:p-3.5 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wider">Solicitante</th>
<th class="p-3 md:p-3.5 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wider">Status</th>
<th class="p-3 md:p-3.5 text-left border-b border-slate-200 bg-slate-50 font-semibold text-slate-600 text-xs uppercase tracking-wider">Data</th>
<th class="p-3 md:p-3.5 text-left border-b border-slate-200 bg-slate-50"></th>
</tr>
</thead>
<tbody id="solicitacoesTbody">
{% for item in solicitacoes_com_acao %}
{% with solicitacao=item.solicitacao %}
<tr class="solicitacao-row border-b border-slate-200 hover:bg-slate-50/50 align-middle"
data-status="{{ solicitacao.status }}"
data-search-term="{{ solicitacao.get_tipo_display|lower }} {{ solicitacao.funcionario.nome|default:''|lower }} {{ solicitacao.solicitante.nome|lower }} #{{ solicitacao.id }}">
<td class="p-3 md:p-3.5 text-left align-middle break-words">
<div class="flex items-center gap-2 min-w-0">
<div class="flex-1 min-w-0">
<strong class="text-slate-800">{{ solicitacao.get_tipo_display }}</strong>
<span class="meta-info block text-xs text-slate-500 mt-0.5">#{{ solicitacao.id }}</span>
</div>
</div>
</td>
<td class="p-3 md:p-3.5 text-left align-middle break-words">
<strong>{% if solicitacao.funcionario %}{{ solicitacao.funcionario.nome }}{% else %}<span class="text-slate-400">N/A</span>{% endif %}</strong>
{% if solicitacao.funcionario and solicitacao.funcionario.chapa %}<span class="meta-info block text-xs text-slate-500">Chapa: {{ solicitacao.funcionario.chapa }}</span>{% endif %}
</td>
<td class="p-3 md:p-3.5 text-left align-middle break-words">
<strong class="text-slate-800">{{ solicitacao.solicitante.nome }}</strong>
<span class="meta-info block text-xs text-slate-500">{{ solicitacao.solicitante.setor|default:"Sem setor" }}</span>
</td>
<td class="p-3 md:p-3.5 text-left align-middle">
<span class="status-badge inline-flex items-center gap-1 py-1 px-2.5 rounded-full text-xs font-semibold status-{{ solicitacao.status }}">{{ solicitacao.get_status_display }}</span>
</td>
<td class="p-3 md:p-3.5 text-left align-middle text-xs text-slate-500"><span class="meta-info">{{ solicitacao.criado_em|timesince }} atrás</span></td>
<td class="p-3 md:p-3.5 text-left align-middle">
<a href="{% url 'solicitacoes:solicitacao_detalhe' solicitacao.id %}" class="btn-action inline-flex items-center gap-1 py-2 px-4 rounded-md text-sm font-semibold no-underline bg-primary text-white border border-primary hover:bg-primary-hover transition-colors whitespace-nowrap">Analisar ◹</a>
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
<div id="no-results-message" class="empty-state text-center py-12 px-6 text-slate-500 bg-white border-2 border-dashed border-slate-200 rounded-lg m-4">
Nenhuma solicitação encontrada com os filtros aplicados.
</div>
</div>
{% if solicitacoes.has_other_pages %}
<div class="pagination mt-6 flex justify-center gap-2"></div>
{% endif %}
{% else %}
<div class="empty-state text-center py-12 px-6 text-slate-500 bg-white rounded-xl border-2 border-dashed border-slate-200">
Nenhuma solicitação encontrada no sistema.
</div>
{% endif %}
{% endblock %}
{% block scripts %}
{{ block.super }}
<script>
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('searchInput');
const filterPills = document.querySelectorAll('.filter-pill');
const clearButton = document.getElementById('clearFilters');
const tableBody = document.getElementById('solicitacoesTbody');
if (!tableBody) return;
const rows = tableBody.getElementsByClassName('solicitacao-row');
const noResultsMessage = document.getElementById('no-results-message');
let currentStatusFilter = 'todos';
let currentSearchTerm = '';
function applyFilters() {
let visibleRows = 0;
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
const statusMatch = (currentStatusFilter === 'todos' || row.dataset.status === currentStatusFilter);
const searchMatch = (row.dataset.searchTerm || '').toLowerCase().includes(currentSearchTerm);
if (statusMatch && searchMatch) { row.style.display = ''; visibleRows++; } else { row.style.display = 'none'; }
}
if (noResultsMessage) noResultsMessage.style.display = visibleRows === 0 ? 'block' : 'none';
}
if (searchInput) searchInput.addEventListener('input', function() { currentSearchTerm = searchInput.value.toLowerCase().trim(); applyFilters(); });
filterPills.forEach(pill => {
pill.addEventListener('click', function() {
if (!this.classList.contains('filter-pill')) return;
filterPills.forEach(p => p.classList.remove('active'));
this.classList.add('active');
currentStatusFilter = this.dataset.status || 'todos';
applyFilters();
});
});
if (clearButton) clearButton.addEventListener('click', function() {
if (searchInput) searchInput.value = '';
currentSearchTerm = '';
filterPills.forEach(p => p.classList.remove('active'));
const todosBtn = document.querySelector('.filter-pill[data-status="todos"]');
if (todosBtn) todosBtn.classList.add('active');
currentStatusFilter = 'todos';
applyFilters();
});
});
</script>
{% endblock %}