Files
BrainWind/app/src/lib/export-generic-pdf.tsx
T

164 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Document, Page, Text, View, StyleSheet, Image as PdfImage, pdf } from '@react-pdf/renderer';
import { useWindStore } from '../store/appStore';
import { useCaptureStore } from '../store/captureStore';
const styles = StyleSheet.create({
page: { flexDirection: 'column', padding: 40, fontSize: 10, fontFamily: 'Helvetica', color: '#333' },
header: { marginBottom: 20, borderBottom: '2pt solid #6b21a8', paddingBottom: 10 },
title: { fontSize: 20, fontWeight: 'bold', color: '#6b21a8' },
subtitle: { fontSize: 10, color: '#666', marginTop: 4 },
section: { marginTop: 15, marginBottom: 10 },
sectionTitle: { fontSize: 14, fontWeight: 'bold', marginBottom: 8, color: '#111' },
row: { flexDirection: 'row', marginBottom: 4 },
label: { width: 200, fontWeight: 'bold' },
value: { flex: 1 },
text: { fontSize: 10, marginBottom: 4, lineHeight: 1.4 },
table: { display: 'flex', flexDirection: 'column', marginTop: 10, borderTop: '1pt solid #ccc', borderLeft: '1pt solid #ccc' },
tableRow: { flexDirection: 'row' },
tableHeader: { backgroundColor: '#f3f4f6', fontWeight: 'bold' },
tableCell: { flex: 1, padding: 5, borderRight: '1pt solid #ccc', borderBottom: '1pt solid #ccc', textAlign: 'center' },
tableCellFirst: { flex: 1, padding: 5, borderRight: '1pt solid #ccc', borderBottom: '1pt solid #ccc', textAlign: 'left' },
footer: { position: 'absolute', bottom: 30, left: 40, right: 40, textAlign: 'center', color: '#999', fontSize: 8, borderTop: '1pt solid #eaeaea', paddingTop: 10 },
sceneImage: { width: 480, height: 270, objectFit: 'contain', marginVertical: 8, border: '1pt solid #ddd' },
sceneCaption: { fontSize: 8, color: '#666', fontStyle: 'italic', textAlign: 'center', marginBottom: 8 },
});
export interface GenericPDFSection {
title: string;
type: 'table' | 'text' | 'grid';
content?: string;
tableHeaders?: string[];
tableRows?: (string | number)[][];
gridItems?: { label: string; value: string | number }[];
}
export interface GenericPDFProps {
moduleName: string;
sections: GenericPDFSection[];
wind: ReturnType<typeof useWindStore.getState>;
sceneImage?: string | null;
}
const GenericReportDocument = ({ moduleName, sections, wind, sceneImage }: GenericPDFProps) => {
return (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.header}>
<Text style={styles.title}>VentoApp Memória de Cálculo</Text>
<Text style={styles.subtitle}>Cargas de Vento: {moduleName} NBR 6123:2023</Text>
</View>
<View style={styles.section}>
<Text style={styles.sectionTitle}>1. Parâmetros Globais do Vento e Pressão Dinâmica</Text>
<View style={styles.row}>
<Text style={styles.label}>Velocidade Básica (V):</Text>
<Text style={styles.value}>{wind.v0} m/s (conforme Figura 1 e Anexo C da NBR 6123)</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Fator Topográfico (S):</Text>
<Text style={styles.value}>{wind.s1} (conforme Seção 5.2)</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Fator de Rugosidade (S):</Text>
<Text style={styles.value}>{wind.s2.toFixed(3)} (Categoria {wind.terrainCategory}, Classe {wind.structureClass}, conforme Tabela 2)</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>Fator Estatístico (S):</Text>
<Text style={styles.value}>{wind.s3.toFixed(2)} (Grupo {wind.s3Group}, conforme Tabela 4)</Text>
</View>
<View style={{ marginTop: 10, padding: 8, backgroundColor: '#f9fafb', borderLeft: '3pt solid #6b21a8' }}>
<Text style={{ fontSize: 11, fontWeight: 'bold', marginBottom: 4 }}>Memória de Cálculo (Sec 4.2 e 4.3):</Text>
<Text style={{ fontSize: 10, fontFamily: 'Courier', marginBottom: 4 }}>
Vₖ = V × S × S × S
</Text>
<Text style={{ fontSize: 10, fontFamily: 'Courier', marginBottom: 8, color: '#4b5563' }}>
Vₖ = {wind.v0} × {wind.s1} × {wind.s2.toFixed(3)} × {wind.s3.toFixed(2)} = {wind.vk.toFixed(2)} m/s
</Text>
<Text style={{ fontSize: 10, fontFamily: 'Courier', marginBottom: 4 }}>
q = 0,613 × (Vₖ)²
</Text>
<Text style={{ fontSize: 10, fontFamily: 'Courier', color: '#4b5563' }}>
q = 0,613 × ({wind.vk.toFixed(2)})² = {(0.613 * Math.pow(wind.vk, 2) / 1000).toFixed(4)} kN/m²
</Text>
</View>
</View>
{sceneImage && (
<View style={styles.section}>
<Text style={styles.sectionTitle}>2. Modelo 3D (Captura de Cena)</Text>
<PdfImage src={sceneImage} style={styles.sceneImage} />
<Text style={styles.sceneCaption}>
Vista isométrica capturada em tempo real pelo usuário.
</Text>
</View>
)}
{sections.map((sec, idx) => (
<View style={styles.section} key={idx} wrap={false}>
<Text style={styles.sectionTitle}>
{sceneImage ? idx + 3 : idx + 2}. {sec.title}
</Text>
{sec.type === 'text' && sec.content && (
<Text style={styles.text}>{sec.content}</Text>
)}
{sec.type === 'grid' && sec.gridItems && (
sec.gridItems.map((item, i) => (
<View style={styles.row} key={i}>
<Text style={styles.label}>{item.label}:</Text>
<Text style={styles.value}>{item.value}</Text>
</View>
))
)}
{sec.type === 'table' && sec.tableHeaders && sec.tableRows && (
<View style={styles.table}>
<View style={[styles.tableRow, styles.tableHeader]}>
{sec.tableHeaders.map((th, i) => (
<Text key={i} style={i === 0 ? styles.tableCellFirst : styles.tableCell}>
{th}
</Text>
))}
</View>
{sec.tableRows.map((tr, rIdx) => (
<View style={styles.tableRow} key={rIdx}>
{tr.map((tc, cIdx) => (
<Text key={cIdx} style={cIdx === 0 ? styles.tableCellFirst : styles.tableCell}>
{tc}
</Text>
))}
</View>
))}
</View>
)}
</View>
))}
<Text style={styles.footer}>
Gerado por VentoApp Ferramenta de Auxílio ao Cálculo Estrutural (NBR 6123:2023)
</Text>
</Page>
</Document>
);
};
export async function exportGenericToPDF(moduleName: string, sections: GenericPDFSection[]) {
const wind = useWindStore.getState();
const sceneImage = useCaptureStore.getState().capturedImage;
const blob = await pdf(
<GenericReportDocument moduleName={moduleName} sections={sections} wind={wind} sceneImage={sceneImage} />
).toBlob();
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `memoria_calculo_${moduleName.toLowerCase().replace(/\s+/g, '_')}.pdf`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}