feat(pdf): adicionar exportação de ficha do consultor em PDF

- Novo endpoint GET /api/v1/consultor/{id}/pdf para download
- Serviço PDFService usando WeasyPrint para geração
- Template HTML com layout padrão governo federal
- Botão de exportar PDF no card e modal de dados brutos
This commit is contained in:
Frederico Castro
2025-12-18 22:43:42 -03:00
parent 9d93e42a12
commit 47f0a80f3f
13 changed files with 1607 additions and 9 deletions

View File

@@ -240,6 +240,7 @@ const RawDataModal = ({ idPessoa, nome, onClose }) => {
const [viewMode, setViewMode] = useState('formatted');
const [filterType, setFilterType] = useState('all');
const [copyFeedback, setCopyFeedback] = useState(false);
const [downloadingPDF, setDownloadingPDF] = useState(false);
useEffect(() => {
const fetchData = async () => {
@@ -280,6 +281,19 @@ const RawDataModal = ({ idPessoa, nome, onClose }) => {
}
};
const handleDownloadPDF = async () => {
if (downloadingPDF) return;
setDownloadingPDF(true);
try {
await rankingService.downloadFichaPDF(idPessoa, nome);
} catch (err) {
console.error('Erro ao baixar PDF:', err);
alert('Erro ao gerar PDF. Tente novamente.');
} finally {
setDownloadingPDF(false);
}
};
const source = data?._source || {};
const dadosPessoais = source.dadosPessoais || {};
const atuacoes = source.atuacoes || [];
@@ -303,6 +317,20 @@ const RawDataModal = ({ idPessoa, nome, onClose }) => {
<span className="raw-modal-subtitle">{nome} (ID: {idPessoa})</span>
</div>
<div className="raw-modal-header-actions">
<div className="btn-export-pdf-wrap">
<button
className={`btn-export-pdf ${downloadingPDF ? 'loading' : ''}`}
onClick={handleDownloadPDF}
disabled={downloadingPDF}
title="Exportar ficha completa em PDF"
>
<svg className="pdf-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
</svg>
<span>PDF</span>
</button>
</div>
<div className="view-toggle">
<button
className={viewMode === 'formatted' ? 'active' : ''}