Files
SteelCheck/components/PrintableReport.tsx
admtracksteel 97eb42c243 feat: multi-provider AI support with auto-detection
- Added support for Google Gemini, OpenAI, Anthropic, and Azure OpenAI
- Implemented API key validation with auto model detection
- Added Error Boundary for better error handling
- Migrated PDF generation to native jsPDF (better quality)
- Added PWA support with offline capabilities
- Implemented tests with Vitest
- Fixed language consistency (PT-BR)
- Improved accessibility (ARIA)
2026-04-04 19:32:00 +00:00

111 lines
5.6 KiB
TypeScript

import React from 'react';
import type { ReportData, ComplianceItem } from '../types';
interface PrintableReportProps {
report: ReportData;
}
const formatDate = (dateString: string) => {
// Tries to parse common date formats like DD.MM.YYYY or YYYY-MM-DD
const parts = dateString.split(/[.\-/]/);
if (parts.length === 3) {
// Assuming DD.MM.YYYY
if (parts[0].length === 2) return `${parts[0]}/${parts[1]}/${parts[2]}`;
// Assuming YYYY-MM-DD
if (parts[0].length === 4) return `${parts[2]}/${parts[1]}/${parts[0]}`;
}
return dateString; // fallback
};
const TableRow: React.FC<{item: ComplianceItem}> = ({item}) => (
<tr className="border-b text-xs">
<td className="py-1 px-2 font-medium">{item.property || item.element || item.test}</td>
<td className="py-1 px-2">{item.norm}</td>
<td className="py-1 px-2 font-bold">{item.certificate}</td>
<td className={`py-1 px-2 font-bold ${item.status === 'OK' ? 'text-green-700' : 'text-red-700'}`}>{item.status}</td>
</tr>
)
export const PrintableReport: React.FC<PrintableReportProps> = ({ report }) => {
const { identification, compliance, overPerformance, equivalents, confidence } = report;
const jsonData = JSON.stringify(report);
return (
<div
id="printable-report-container"
data-report={jsonData}
style={{ width: '210mm', minHeight: '297mm' }}
className="bg-white text-gray-900 p-8 font-sans flex flex-col"
>
<header className="flex justify-between items-start pb-2 border-b-2 border-gray-400">
<div>
<h1 className="text-3xl font-bold text-blue-800">SteelBase</h1>
<p className="text-sm">Análise de Qualidade Industrial com IA</p>
</div>
<div className="text-right">
<h2 className="text-2xl font-bold">Relatório de Análise Técnica</h2>
<p className="text-sm">Documento gerado em: {new Date().toLocaleDateString('pt-BR')}</p>
</div>
</header>
<main className="flex-grow">
<section className="mt-4 border border-gray-300 rounded p-3 grid grid-cols-2 gap-x-6 gap-y-2 text-sm">
<div><strong>Produto:</strong> {identification.product}</div>
<div><strong>Norma Principal:</strong> {identification.standards}</div>
<div><strong>Fabricante:</strong> {identification.manufacturer}</div>
<div><strong> Certificado:</strong> {identification.certificateNumber}</div>
<div><strong>Lotes:</strong> {identification.batches}</div>
<div><strong>Corridas:</strong> {identification.heats}</div>
<div><strong>Quantidade:</strong> {identification.quantity}</div>
<div><strong>Data Emissão:</strong> {formatDate(identification.certificateDate)}</div>
</section>
<section className="mt-4">
<h3 className="text-base font-bold text-gray-800">Resumo da Análise</h3>
<div className="mt-1 border border-gray-300 rounded p-2 text-xs">
<p>O material de {identification.product} atende aos requisitos da norma {identification.standards}. Status Geral de Conformidade: <span className={`font-extrabold ${compliance.status === 'CONFORME' ? 'text-green-700' : 'text-red-700'}`}>{compliance.status}</span>.</p>
{compliance.status === 'CONFORME' && overPerformance.length > 0 && (
<p className="mt-1">O material excede os requisitos normativos em pontos-chave, como {overPerformance.map(item => item.property).join(', ')}.</p>
)}
</div>
</section>
<section className="mt-4">
<h3 className="text-base font-bold text-gray-800">Análise de Composição Química</h3>
<table className="w-full mt-1 border-collapse border border-gray-300">
<thead className="bg-gray-200 text-left text-xs uppercase">
<tr><th className="py-1 px-2">Elemento</th><th className="py-1 px-2">Norma</th><th className="py-1 px-2">Certificado</th><th className="py-1 px-2">Status</th></tr>
</thead>
<tbody>{compliance.chemical.map((item, i) => <TableRow key={i} item={item} />)}</tbody>
</table>
</section>
<section className="mt-4">
<h3 className="text-base font-bold text-gray-800">Análise de Propriedades Mecânicas</h3>
<table className="w-full mt-1 border-collapse border border-gray-300">
<thead className="bg-gray-200 text-left text-xs uppercase">
<tr><th className="py-1 px-2">Propriedade</th><th className="py-1 px-2">Norma</th><th className="py-1 px-2">Certificado</th><th className="py-1 px-2">Status</th></tr>
</thead>
<tbody>{compliance.mechanical.map((item, i) => <TableRow key={i} item={item} />)}</tbody>
</table>
</section>
<section className="mt-4">
<h3 className="text-base font-bold text-gray-800">Normas Equivalentes</h3>
<div className="mt-1 grid grid-cols-4 gap-2">
{equivalents.map((item, i) => (
<div key={i} className="bg-gray-100 border border-gray-300 rounded p-2 text-center">
<p className="text-xs font-semibold text-gray-600">{item.system}</p>
<p className="text-sm font-bold text-blue-800">{item.norm}</p>
</div>
))}
</div>
</section>
</main>
<footer className="text-center text-xs text-gray-500 pt-2 border-t border-gray-300">
Relatório gerado por SteelBase | Confiança da Análise: {confidence}%
</footer>
</div>
);
};