import ApiService from './ApiService'; import { MaterielBTP, RechercheMaterielParams } from './materielBTPService'; import { ZoneClimatique } from './zoneClimatiqueService'; import { ResultatCalculBriques, ResultatCalculBetonArme } from './calculsTechniquesService'; /** * Service d'export pour les données BTP ultra-détaillées * Permet l'export en CSV, Excel et PDF des matériaux, calculs et zones climatiques */ export type FormatExport = 'CSV' | 'EXCEL' | 'PDF'; export interface OptionsExport { format: FormatExport; includeImages?: boolean; includeCharts?: boolean; filtres?: any; colonnesPersonnalisees?: string[]; template?: 'STANDARD' | 'DETAILLE' | 'RESUME'; } export interface ResultatExport { filename: string; blob: Blob; size: number; format: FormatExport; nbLignes: number; dateGeneration: string; } export class ExportBTPService { /** * Export des matériaux BTP avec filtres */ static async exporterMateriaux(options: OptionsExport & { filtres?: RechercheMaterielParams; }): Promise { try { const blob = await ApiService.post( '/calculs-techniques/materiaux/export', { format: options.format, filtres: options.filtres, template: options.template || 'STANDARD', colonnesPersonnalisees: options.colonnesPersonnalisees }, { responseType: 'blob' } ); const filename = this.genererNomFichier('materiaux', options.format); return { filename, blob, size: blob.size, format: options.format, nbLignes: 0, // Sera calculé côté serveur dateGeneration: new Date().toISOString() }; } catch (error) { console.error('Erreur export matériaux:', error); throw new Error('Impossible d\'exporter les matériaux'); } } /** * Export des zones climatiques */ static async exporterZonesClimatiques(options: OptionsExport): Promise { try { const blob = await ApiService.post( '/calculs-techniques/zones-climatiques/export', { format: options.format, template: options.template || 'STANDARD' }, { responseType: 'blob' } ); const filename = this.genererNomFichier('zones-climatiques', options.format); return { filename, blob, size: blob.size, format: options.format, nbLignes: 0, dateGeneration: new Date().toISOString() }; } catch (error) { console.error('Erreur export zones climatiques:', error); throw new Error('Impossible d\'exporter les zones climatiques'); } } /** * Export des résultats de calculs techniques */ static async exporterCalculs( calculs: Array<{ type: 'BRIQUES' | 'BETON' | 'MORTIER'; resultat: ResultatCalculBriques | ResultatCalculBetonArme | any; parametres: any; }>, options: OptionsExport ): Promise { try { const data = { calculs: calculs, format: options.format, template: options.template || 'DETAILLE', includeCharts: options.includeCharts || false }; const blob = await ApiService.post( '/calculs-techniques/export-calculs', data, { responseType: 'blob' } ); const filename = this.genererNomFichier('calculs-techniques', options.format); return { filename, blob, size: blob.size, format: options.format, nbLignes: calculs.length, dateGeneration: new Date().toISOString() }; } catch (error) { // Fallback : export côté client si serveur indisponible console.warn('Export serveur indisponible, génération côté client'); return this.exporterCalculsCoteClient(calculs, options); } } /** * Export complet du projet BTP (matériaux + zones + calculs) */ static async exporterProjetComplet( chantierId: string, options: OptionsExport & { includeMateriaux?: boolean; includeZones?: boolean; includeCalculs?: boolean; includePhases?: boolean; } ): Promise { try { const data = { chantierId, format: options.format, template: options.template || 'DETAILLE', sections: { materiaux: options.includeMateriaux !== false, zones: options.includeZones !== false, calculs: options.includeCalculs !== false, phases: options.includePhases !== false }, includeCharts: options.includeCharts || false, includeImages: options.includeImages || false }; const blob = await ApiService.post( '/calculs-techniques/export-projet-complet', data, { responseType: 'blob' } ); const filename = this.genererNomFichier(`projet-${chantierId}`, options.format); return { filename, blob, size: blob.size, format: options.format, nbLignes: 0, dateGeneration: new Date().toISOString() }; } catch (error) { console.error('Erreur export projet complet:', error); throw new Error('Impossible d\'exporter le projet complet'); } } /** * Génération de devis BTP détaillé avec matériaux et calculs */ static async genererDevisBTP( devisData: { chantierId: string; phases: Array<{ nom: string; materiaux: Array<{ code: string; quantite: number; prixUnitaire?: number; }>; calculs?: any; }>; client: { nom: string; adresse: string; telephone?: string; email?: string; }; options: { margeCommerciale: number; tva: number; delaiExecution: number; validiteDevis: number; // jours conditionsPaiement: string; }; }, format: FormatExport = 'PDF' ): Promise { try { const blob = await ApiService.post( '/calculs-techniques/generer-devis', { ...devisData, format, template: 'DEVIS_PROFESSIONNEL' }, { responseType: 'blob' } ); const filename = this.genererNomFichier(`devis-${devisData.chantierId}`, format); return { filename, blob, size: blob.size, format, nbLignes: devisData.phases.length, dateGeneration: new Date().toISOString() }; } catch (error) { console.error('Erreur génération devis:', error); throw new Error('Impossible de générer le devis'); } } /** * Export des matériaux avec QR codes pour traçabilité */ static async exporterMateriauxAvecQRCodes( materiaux: MaterielBTP[], options: OptionsExport ): Promise { try { const data = { materiaux: materiaux.map(m => ({ id: m.id, code: m.code, nom: m.nom, categorie: m.categorie, specifications: { resistance: m.resistanceCompression, densite: m.densite, norme: m.normePrincipale } })), format: options.format, includeQRCodes: true, template: 'TRACABILITE' }; const blob = await ApiService.post( '/calculs-techniques/export-tracabilite', data, { responseType: 'blob' } ); const filename = this.genererNomFichier('tracabilite-materiaux', options.format); return { filename, blob, size: blob.size, format: options.format, nbLignes: materiaux.length, dateGeneration: new Date().toISOString() }; } catch (error) { console.error('Erreur export traçabilité:', error); throw new Error('Impossible d\'exporter la traçabilité'); } } // =================== MÉTHODES UTILITAIRES =================== /** * Télécharge automatiquement le fichier exporté */ static telechargerFichier(resultat: ResultatExport): void { const url = window.URL.createObjectURL(resultat.blob); const a = document.createElement('a'); a.href = url; a.download = resultat.filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } /** * Prévisualise le contenu avant export (pour PDF) */ static async previsualiserExport( type: 'MATERIAUX' | 'ZONES' | 'CALCULS' | 'DEVIS', donnees: any, options: OptionsExport ): Promise { try { const response = await ApiService.post<{ previewUrl: string }>( '/calculs-techniques/previsualiser-export', { type, donnees, options } ); return response.previewUrl; } catch (error) { console.error('Erreur prévisualisation:', error); throw new Error('Impossible de générer la prévisualisation'); } } /** * Obtient les templates d'export disponibles */ static async getTemplatesDisponibles(): Promise> { try { const response = await ApiService.get>('/calculs-techniques/templates-export'); return response; } catch (error) { // Templates par défaut return [ { id: 'STANDARD', nom: 'Standard', description: 'Export standard avec informations essentielles', formatsSupportes: ['CSV', 'EXCEL', 'PDF'], sections: ['donnees_base'] }, { id: 'DETAILLE', nom: 'Détaillé', description: 'Export complet avec toutes les spécifications techniques', formatsSupportes: ['EXCEL', 'PDF'], sections: ['donnees_base', 'specifications', 'calculs', 'normes'] }, { id: 'RESUME', nom: 'Résumé', description: 'Export synthétique pour présentation', formatsSupportes: ['PDF'], sections: ['resume', 'graphiques'] } ]; } } /** * Validation des options d'export */ static validerOptionsExport(options: OptionsExport): { valide: boolean; erreurs: string[]; } { const erreurs: string[] = []; if (!options.format) { erreurs.push('Format d\'export requis'); } if (options.format === 'PDF' && options.colonnesPersonnalisees?.length > 20) { erreurs.push('Maximum 20 colonnes pour export PDF'); } if (options.includeImages && options.format === 'CSV') { erreurs.push('Images non supportées en format CSV'); } return { valide: erreurs.length === 0, erreurs }; } // =================== MÉTHODES PRIVÉES =================== /** * Génère un nom de fichier unique */ private static genererNomFichier(prefix: string, format: FormatExport): string { const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5); const extension = format.toLowerCase(); return `${prefix}_${timestamp}.${extension}`; } /** * Export côté client en cas de problème serveur */ private static async exporterCalculsCoteClient( calculs: any[], options: OptionsExport ): Promise { let contenu = ''; if (options.format === 'CSV') { // Génération CSV simple contenu = 'Type,Résultat,Date\n'; calculs.forEach(calcul => { contenu += `${calcul.type},"${JSON.stringify(calcul.resultat)}",${new Date().toISOString()}\n`; }); } else { // Format texte pour autres formats contenu = 'Export des calculs techniques BTP\n\n'; calculs.forEach(calcul => { contenu += `Type: ${calcul.type}\n`; contenu += `Résultat: ${JSON.stringify(calcul.resultat, null, 2)}\n\n`; }); } const blob = new Blob([contenu], { type: 'text/plain;charset=utf-8' }); const filename = this.genererNomFichier('calculs-fallback', 'CSV'); return { filename, blob, size: blob.size, format: 'CSV', nbLignes: calculs.length, dateGeneration: new Date().toISOString() }; } }