fix: corrigir filtro de ativos, remover count de areas e navegacao ao clicar

This commit is contained in:
Frederico Castro
2025-12-20 12:22:45 -03:00
parent 45ab7412fe
commit 342e52880e
10 changed files with 2179 additions and 15 deletions

View File

@@ -0,0 +1,262 @@
from __future__ import annotations
from pathlib import Path
import datetime
from html import escape
from openpyxl import load_workbook
from weasyprint import HTML, CSS
XLSX_PATH = Path("/home/fred/Downloads/Definição Ranking_ATUACAPES - Aba1 a Aba4(7).xlsx")
PDF_PATH = Path("/home/fred/projetos/ranking/docs/Criterios_Ranking_Consultores.pdf")
LOGO_PATH = Path("/home/fred/projetos/ranking/docs/assets/logo-capes.png")
def _fmt(cell) -> str:
if cell is None:
return ""
return str(cell).replace("\n", " ").strip()
def _table_html(headers, rows, code_cols=None) -> str:
code_cols = set(code_cols or [])
thead = "<tr>" + "".join(f"<th>{escape(_fmt(h))}</th>" for h in headers) + "</tr>"
body_rows = []
for row in rows:
cols = []
for idx, cell in enumerate(row):
text = _fmt(cell)
if idx in code_cols and text:
text = f"<code>{escape(text)}</code>"
else:
text = escape(text)
cols.append(f"<td>{text}</td>")
body_rows.append("<tr>" + "".join(cols) + "</tr>")
tbody = "\n".join(body_rows)
return f"<table class=\"criteria-table\"><thead>{thead}</thead><tbody>{tbody}</tbody></table>"
def load_planilha() -> dict:
wb = load_workbook(XLSX_PATH, data_only=True)
def extract(sheet, header_cols, row_cols, skip_score=False, formula=False):
ws = wb[sheet]
headers = [_fmt(c) for c in ws[1][:header_cols]]
rows = []
formula_row = ""
for r in ws.iter_rows(min_row=2, values_only=True):
if not any(r):
continue
if formula and r[0] is None and isinstance(r[1], str) and "tempo =" in r[1]:
formula_row = r[1]
continue
if skip_score and _fmt(r[0]).lower() == "score":
continue
rows.append(r[:row_cols])
return headers, rows, formula_row
h1, r1, _ = extract("Aba1_Mapa_Atuacoes", 9, 9)
h2, r2, _ = extract("Aba2_Pontuacao_Base", 4, 4)
h3, r3, f3 = extract("Aba3_Regras_Tempo", 7, 7, formula=True)
h4, r4, _ = extract("Aba4_Bonus_Extras", 12, 12)
h5, r5, _ = extract("Aba5_Detalh. Perfil_Indicadores", 6, 6, skip_score=True)
return {
"aba1": {"headers": h1, "rows": r1},
"aba2": {"headers": h2, "rows": r2},
"aba3": {"headers": h3, "rows": r3, "formula": f3},
"aba4": {"headers": h4, "rows": r4},
"aba5": {"headers": h5, "rows": r5},
}
def build_html(data: dict) -> str:
hoje = datetime.date.today().isoformat()
logo_html = ""
if LOGO_PATH.exists():
logo_html = f"<img class=\"cover-logo\" src=\"{LOGO_PATH.as_posix()}\" alt=\"CAPES\" />"
return f"""
<!doctype html>
<html lang="pt-BR">
<head>
<meta charset="utf-8" />
<title>Critérios de Pontuação e Ordenação (Versão Executiva)</title>
<style>
@page {{
size: A4;
margin: 2.1cm 2.1cm 2.3cm 2.1cm;
}}
@page landscape {{
size: A4 landscape;
margin: 1.5cm 1.7cm 1.8cm 1.7cm;
}}
body {{
font-family: "Liberation Serif", "Times New Roman", serif;
color: #0f172a;
font-size: 11pt;
line-height: 1.4;
}}
h1, h2 {{
font-family: "Liberation Sans", "Arial", sans-serif;
color: #0b1f3a;
margin: 0 0 0.4cm 0;
}}
h1 {{
font-size: 25pt;
letter-spacing: 0.3px;
}}
h2 {{
font-size: 16pt;
margin-top: 0;
}}
p {{
margin: 0.3cm 0;
}}
.cover {{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 92vh;
border: 2px solid #0b1f3a;
padding: 2.2cm;
text-align: center;
}}
.cover-logo {{
width: 6.0cm;
height: auto;
margin-bottom: 0.7cm;
}}
.cover-subtitle {{
font-size: 14pt;
color: #1f3b63;
margin-bottom: 1.1cm;
max-width: 14cm;
}}
.cover-meta {{
font-size: 10.6pt;
color: #0f172a;
border-top: 1px solid #1f3b63;
padding-top: 0.5cm;
width: 100%;
text-align: left;
}}
.label {{
font-weight: 700;
color: #0b1f3a;
}}
section {{
break-before: page;
}}
section.first {{
break-before: auto;
}}
.landscape {{
page: landscape;
}}
table.criteria-table {{
width: 100%;
border-collapse: collapse;
margin: 0.35cm 0 0.5cm 0;
font-size: 9.3pt;
table-layout: fixed;
}}
table.criteria-table th, table.criteria-table td {{
border: 1px solid #cbd5f0;
padding: 5px 6px;
vertical-align: top;
word-break: break-word;
hyphens: auto;
}}
table.criteria-table th {{
background: #eef2ff;
text-align: left;
font-weight: 700;
}}
table.criteria-table tr:nth-child(even) td {{
background: #f8fafc;
}}
.landscape table.criteria-table {{
font-size: 8.2pt;
}}
.landscape table.criteria-table th,
.landscape table.criteria-table td {{
padding: 4px 5px;
}}
code {{
font-family: "Liberation Mono", "Courier New", monospace;
background: #f1f5f9;
padding: 0 3px;
border-radius: 3px;
font-size: 9.2pt;
}}
</style>
</head>
<body>
<section class="cover">
{logo_html}
<h1>Sistema de Ranking de Consultores</h1>
<div class="cover-subtitle">Critérios de Pontuação e Ordenação (Versão Executiva)</div>
<div class="cover-meta">
<div><span class="label">Versão:</span> 1.0</div>
<div><span class="label">Data:</span> {hoje}</div>
<div><span class="label">Finalidade:</span> Documento executivo para alta gestão</div>
<div><span class="label">Escopo:</span> Critérios oficiais do ranking conforme planilha de definição (Abas 1 a 5)</div>
</div>
</section>
<section class="first">
<h2>Sumário Executivo</h2>
<p>Este documento consolida, de forma hierárquica e fiel à planilha oficial, todos os critérios utilizados no ranking de consultores. A estrutura está organizada por abas: mapeamento das atuações (Aba 1), pontuação base e tetos (Aba 2), regras de tempo (Aba 3), bônus e selos (Aba 4) e indicadores não pontuáveis (Aba 5).</p>
</section>
<section class="landscape">
<h2>1. Aba 1 — Mapa de Atuações</h2>
{_table_html(data["aba1"]["headers"], data["aba1"]["rows"], code_cols=[3])}
</section>
<section>
<h2>2. Aba 2 — Pontuação Base e Teto por Atuação</h2>
{_table_html(data["aba2"]["headers"], data["aba2"]["rows"], code_cols=[0])}
</section>
<section>
<h2>3. Aba 3 — Regras de Tempo</h2>
{_table_html(data["aba3"]["headers"], data["aba3"]["rows"], code_cols=[0])}
<p><span class="label">Fórmula da planilha:</span> <code>{escape(_fmt(data["aba3"]["formula"]))}</code></p>
</section>
<section class="landscape">
<h2>4. Aba 4 — Bônus e Selos</h2>
{_table_html(data["aba4"]["headers"], data["aba4"]["rows"], code_cols=[0])}
</section>
<section>
<h2>5. Aba 5 — Indicadores Não Pontuáveis</h2>
<p>Os itens abaixo constam na Aba 5 e <strong>não impactam a pontuação</strong>. O indicador <strong>Score</strong> é pontuável e já está coberto pelas regras das Abas 2 a 4.</p>
{_table_html(data["aba5"]["headers"], data["aba5"]["rows"])}
</section>
<section>
<h2>6. Fonte Oficial</h2>
<p>Planilha: <code>{escape(str(XLSX_PATH))}</code></p>
</section>
</body>
</html>
"""
def main() -> None:
data = load_planilha()
html = build_html(data)
HTML(string=html, base_url=str(PDF_PATH.parent)).write_pdf(
target=str(PDF_PATH),
stylesheets=[CSS(string="@page { size: A4; }")],
)
print(f"PDF: {PDF_PATH}")
if __name__ == "__main__":
main()