feat(ui): expandir modal de dados e melhorar template PDF

- Expandir RawDataModal com mais funcionalidades de visualização
- Ajustar template HTML da ficha do consultor
- Adicionar configuração MCP do projeto
- Atualizar gitignore para ignorar arquivos locais
This commit is contained in:
Frederico Castro
2025-12-19 11:59:41 -03:00
parent 47f0a80f3f
commit cbdeddb5d8
6 changed files with 314 additions and 25 deletions

View File

@@ -15,6 +15,7 @@ class PDFService:
)
self.env.filters['format_date'] = self._format_date
self.env.filters['format_date_short'] = self._format_date_short
self.env.filters['sort_by_date'] = self._sort_by_date
self.template = self.env.get_template("ficha_consultor.html")
def _format_date(self, date_str: str) -> str:
@@ -46,6 +47,68 @@ class PDFService:
except (ValueError, AttributeError, IndexError):
return str(date_str)[:10] if date_str else "-"
def _sort_by_date(self, items, *fields):
if not items or not fields:
return items
def extract_field(value, field):
for part in field.split("."):
if value is None:
return None
if isinstance(value, DictWrapper):
value = value.get(part)
elif isinstance(value, dict):
value = value.get(part)
else:
value = getattr(value, part, None)
return value
def parse_date(value):
if value is None:
return None
if isinstance(value, datetime):
return value
if isinstance(value, (int, float)):
year = int(value)
return datetime(year, 1, 1)
if not isinstance(value, str):
return None
text = value.strip()
if not text:
return None
if text.isdigit() and len(text) == 4:
return datetime(int(text), 1, 1)
if "/" in text:
parts = text.split("/")
try:
if len(parts) == 3:
day = int(parts[0])
month = int(parts[1])
year = int(parts[2])
return datetime(year, month, day)
if len(parts) == 2:
month = int(parts[0])
year = int(parts[1])
return datetime(year, month, 1)
except ValueError:
return None
try:
return datetime.fromisoformat(text.replace("Z", "+00:00"))
except ValueError:
return None
def sort_key(item):
value = None
for field in fields:
value = parse_date(extract_field(item, field))
if value is not None:
break
if value is None:
return (0, datetime.min)
return (1, value)
return sorted(items, key=sort_key, reverse=True)
def _consultor_to_dict(self, consultor: Any) -> Dict:
if is_dataclass(consultor) and not isinstance(consultor, type):
return asdict(consultor)

View File

@@ -195,7 +195,7 @@
</tr>
</thead>
<tbody>
{% for e in emails %}
{% for e in emails|sort_by_date('ultimaAlteracao') %}
<tr>
<td>{{ e.email }}</td>
<td>{{ e.tipo or '-' }}</td>
@@ -275,7 +275,7 @@
</tr>
</thead>
<tbody>
{% for i in identificadores %}
{% for i in identificadores|sort_by_date('fimValidade', 'inicioValidade') %}
<tr>
<td>{{ i.tipo or '-' }}</td>
<td>{{ i.descricao or '-' }}</td>
@@ -291,7 +291,7 @@
<td>{{ identificador_lattes.inicioValidade or '-' }}{% if identificador_lattes.fimValidade %} a {{ identificador_lattes.fimValidade }}{% endif %}</td>
</tr>
{% endif %}
{% for d in documentos %}
{% for d in documentos|sort_by_date('fimValidade', 'inicioValidade') %}
<tr>
<td>{{ d.tipo or '-' }}</td>
<td>{{ d.descricao or '-' }}</td>
@@ -322,7 +322,7 @@
</tr>
</thead>
<tbody>
{% for t in titulacoes %}
{% for t in titulacoes|sort_by_date('fim', 'inicio') %}
<tr>
<td>{{ t.grauAcademico.nome if t.grauAcademico else '-' }}</td>
<td>{{ t.ies.nome if t.ies else '-' }}{% if t.ies and t.ies.sigla %} ({{ t.ies.sigla }}){% endif %}</td>
@@ -370,7 +370,7 @@
</tr>
</thead>
<tbody>
{% for b in bolsas %}
{% for b in bolsas|sort_by_date('fim', 'inicio') %}
<tr>
<td>{{ b.programa or b.tipo or '-' }}</td>
<td>{{ b.ies.nome if b.ies else '-' }}</td>
@@ -475,7 +475,7 @@
</tr>
</thead>
<tbody>
{% for v in consultor.consultoria.vinculos %}
{% for v in consultor.consultoria.vinculos|sort_by_date('periodo.fim', 'periodo.inicio') %}
<tr>
<td>{{ v.ies.nome if v.ies else '-' }}{% if v.ies and v.ies.sigla %} ({{ v.ies.sigla }}){% endif %}</td>
<td>{{ v.periodo.inicio|format_date_short if v.periodo else '-' }} a {{ v.periodo.fim|format_date_short if v.periodo and v.periodo.fim else 'Atual' }}</td>
@@ -549,7 +549,7 @@
</tr>
</thead>
<tbody>
{% for coord in consultor.coordenacoes_capes %}
{% for coord in consultor.coordenacoes_capes|sort_by_date('periodo.fim', 'periodo.inicio') %}
<tr>
<td>{{ coord.codigo }}</td>
<td>{{ coord.area_avaliacao or '-' }}</td>
@@ -630,7 +630,7 @@
</tr>
</thead>
<tbody>
{% for v in consultor.consultoria.vinculos %}
{% for v in consultor.consultoria.vinculos|sort_by_date('periodo.fim', 'periodo.inicio') %}
<tr>
<td>{{ v.ies.nome if v.ies else '-' }}{% if v.ies and v.ies.sigla %} ({{ v.ies.sigla }}){% endif %}</td>
<td>{{ v.periodo.inicio|format_date_short if v.periodo else '-' }} a {{ v.periodo.fim|format_date_short if v.periodo and v.periodo.fim else 'Atual' }}</td>
@@ -689,7 +689,7 @@
</tr>
</thead>
<tbody>
{% for a in consultor.avaliacoes_comissao %}
{% for a in consultor.avaliacoes_comissao|sort_by_date('ano') %}
<tr>
<td>{{ a.codigo }}</td>
<td>{{ a.tipo }}</td>
@@ -715,7 +715,7 @@
</tr>
</thead>
<tbody>
{% for p in consultor.premiacoes %}
{% for p in consultor.premiacoes|sort_by_date('ano') %}
<tr>
<td>{{ p.codigo }}</td>
<td>{{ p.tipo }}</td>
@@ -741,7 +741,7 @@
</tr>
</thead>
<tbody>
{% for i in consultor.inscricoes %}
{% for i in consultor.inscricoes|sort_by_date('ano') %}
<tr>
<td>{{ i.codigo }}</td>
<td>{{ i.tipo }}</td>
@@ -768,7 +768,7 @@
</tr>
</thead>
<tbody>
{% for o in consultor.orientacoes %}
{% for o in consultor.orientacoes|sort_by_date('ano') %}
<tr>
<td>{{ o.codigo }}</td>
<td>{{ o.tipo }}</td>
@@ -794,7 +794,7 @@
</tr>
</thead>
<tbody>
{% for b in consultor.membros_banca %}
{% for b in consultor.membros_banca|sort_by_date('ano') %}
<tr>
<td>{{ b.codigo }}</td>
<td>{{ b.tipo }}</td>
@@ -818,7 +818,7 @@
</tr>
</thead>
<tbody>
{% for p in consultor.participacoes %}
{% for p in consultor.participacoes|sort_by_date('ano') %}
<tr>
<td>{{ p.codigo }}</td>
<td>{{ p.tipo }}</td>
@@ -873,7 +873,7 @@
</tr>
</thead>
<tbody>
{% for a in atuacoes_raw %}
{% for a in atuacoes_raw|sort_by_date('fim', 'inicio') %}
<tr>
<td>{{ a.tipo or '-' }}</td>
<td>{{ a.descricao or a.nome or '-' }}</td>