Continuidad de reportes Frontend. Se sigue..
This commit is contained in:
		
							
								
								
									
										212
									
								
								Frontend/src/pages/Reportes/ReporteMovimientoBobinasPage.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								Frontend/src/pages/Reportes/ReporteMovimientoBobinasPage.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,212 @@ | ||||
| import React, { useState, useCallback } from 'react'; | ||||
| import { | ||||
|   Box, Typography, Paper, CircularProgress, Alert, Button, | ||||
|   TableContainer, Table, TableHead, TableRow, TableCell, TableBody | ||||
| } from '@mui/material'; | ||||
| import reportesService from '../../services/Reportes/reportesService'; | ||||
| import type { MovimientoBobinasDto } from '../../models/dtos/Reportes/MovimientoBobinasDto'; | ||||
| import SeleccionaReporteMovimientoBobinas from './SeleccionaReporteMovimientoBobinas'; | ||||
| import * as XLSX from 'xlsx'; | ||||
| import axios from 'axios'; | ||||
|  | ||||
| const ReporteMovimientoBobinasPage: React.FC = () => { | ||||
|   const [reportData, setReportData] = useState<MovimientoBobinasDto[]>([]); | ||||
|   const [loading, setLoading] = useState(false); | ||||
|   const [loadingPdf, setLoadingPdf] = useState(false); | ||||
|   const [error, setError] = useState<string | null>(null); | ||||
|   const [apiErrorParams, setApiErrorParams] = useState<string | null>(null); | ||||
|   const [showParamSelector, setShowParamSelector] = useState(true); | ||||
|   const [currentParams, setCurrentParams] = useState<{ | ||||
|     fechaDesde: string; | ||||
|     fechaHasta: string; | ||||
|     idPlanta: number; | ||||
|   } | null>(null); | ||||
|  | ||||
|   const handleGenerarReporte = useCallback(async (params: { | ||||
|     fechaDesde: string; | ||||
|     fechaHasta: string; | ||||
|     idPlanta: number; | ||||
|   }) => { | ||||
|     setLoading(true); | ||||
|     setError(null); | ||||
|     setApiErrorParams(null); | ||||
|     setCurrentParams(params); | ||||
|     try { | ||||
|       const data = await reportesService.getMovimientoBobinas(params); | ||||
|       setReportData(data); | ||||
|       if (data.length === 0) { | ||||
|         setError("No se encontraron datos para los parámetros seleccionados."); | ||||
|       } | ||||
|       setShowParamSelector(false); | ||||
|     } catch (err: any) { | ||||
|       const message = axios.isAxiosError(err) && err.response?.data?.message | ||||
|         ? err.response.data.message | ||||
|         : 'Ocurrió un error al generar el reporte.'; | ||||
|       setApiErrorParams(message); | ||||
|       setReportData([]); | ||||
|     } finally { | ||||
|       setLoading(false); | ||||
|     } | ||||
|   }, []); | ||||
|  | ||||
|   const handleVolverAParametros = useCallback(() => { | ||||
|     setShowParamSelector(true); | ||||
|     setReportData([]); | ||||
|     setError(null); | ||||
|     setApiErrorParams(null); | ||||
|     setCurrentParams(null); | ||||
|   }, []); | ||||
|  | ||||
|   const handleExportToExcel = useCallback(() => { | ||||
|     if (reportData.length === 0) { | ||||
|       alert("No hay datos para exportar."); | ||||
|       return; | ||||
|     } | ||||
|     const dataToExport = reportData.map(item => ({ | ||||
|       "Tipo Bobina": item.tipoBobina, | ||||
|       "Bobinas Iniciales": item.bobinasIniciales, | ||||
|       "Kg Iniciales": item.kilosIniciales, | ||||
|       "Bobinas Compradas": item.bobinasCompradas, | ||||
|       "Kg Comprados": item.kilosComprados, | ||||
|       "Bobinas Consumidas": item.bobinasConsumidas, | ||||
|       "Kg Consumidos": item.kilosConsumidos, | ||||
|       "Bobinas Dañadas": item.bobinasDaniadas, | ||||
|       "Kg Dañados": item.kilosDaniados, | ||||
|       "Bobinas Finales": item.bobinasFinales, | ||||
|       "Kg Finales": item.kilosFinales, | ||||
|     })); | ||||
|  | ||||
|     const ws = XLSX.utils.json_to_sheet(dataToExport); | ||||
|     const headers = Object.keys(dataToExport[0]); | ||||
|     ws['!cols'] = headers.map(h => { | ||||
|       const maxLen = dataToExport.reduce((prev, row) => { | ||||
|         const cell = (row as any)[h]?.toString() ?? ''; | ||||
|         return Math.max(prev, cell.length); | ||||
|       }, h.length); | ||||
|       return { wch: maxLen + 2 }; | ||||
|     }); | ||||
|     ws['!freeze'] = { xSplit: 0, ySplit: 1 }; | ||||
|  | ||||
|     const wb = XLSX.utils.book_new(); | ||||
|     XLSX.utils.book_append_sheet(wb, ws, "MovimientoBobinas"); | ||||
|     let fileName = "ReporteMovimientoBobinas"; | ||||
|     if (currentParams) { | ||||
|       fileName += `_${currentParams.fechaDesde}_a_${currentParams.fechaHasta}_Planta${currentParams.idPlanta}`; | ||||
|     } | ||||
|     fileName += ".xlsx"; | ||||
|     XLSX.writeFile(wb, fileName); | ||||
|   }, [reportData, currentParams]); | ||||
|  | ||||
|   const handleGenerarYAbrirPdf = useCallback(async () => { | ||||
|     if (!currentParams) { | ||||
|       setError("Primero debe generar el reporte en pantalla o seleccionar parámetros."); | ||||
|       return; | ||||
|     } | ||||
|     setLoadingPdf(true); | ||||
|     setError(null); | ||||
|     try { | ||||
|       const blob = await reportesService.getMovimientoBobinasPdf(currentParams); | ||||
|       if (blob.type === "application/json") { | ||||
|         const text = await blob.text(); | ||||
|         const msg = JSON.parse(text).message ?? "Error inesperado al generar PDF."; | ||||
|         setError(msg); | ||||
|       } else { | ||||
|         const url = URL.createObjectURL(blob); | ||||
|         const w = window.open(url, '_blank'); | ||||
|         if (!w) alert("Permite popups para ver el PDF."); | ||||
|       } | ||||
|     } catch { | ||||
|       setError('Ocurrió un error al generar el PDF.'); | ||||
|     } finally { | ||||
|       setLoadingPdf(false); | ||||
|     } | ||||
|   }, [currentParams]); | ||||
|  | ||||
|   if (showParamSelector) { | ||||
|     return ( | ||||
|       <Box sx={{ p: 2, display: 'flex', justifyContent: 'center', mt: 2 }}> | ||||
|         <Paper sx={{ width: '100%', maxWidth: 600 }} elevation={3}> | ||||
|           <SeleccionaReporteMovimientoBobinas | ||||
|             onGenerarReporte={handleGenerarReporte} | ||||
|             onCancel={handleVolverAParametros} | ||||
|             isLoading={loading} | ||||
|             apiErrorMessage={apiErrorParams} | ||||
|           /> | ||||
|         </Paper> | ||||
|       </Box> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   return ( | ||||
|     <Box sx={{ p: 2 }}> | ||||
|       <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2, flexWrap: 'wrap', gap: 1 }}> | ||||
|         <Typography variant="h5">Reporte: Movimiento de Bobinas</Typography> | ||||
|         <Box sx={{ display: 'flex', gap: 1 }}> | ||||
|           <Button | ||||
|             onClick={handleGenerarYAbrirPdf} | ||||
|             variant="contained" | ||||
|             disabled={loadingPdf || reportData.length === 0 || !!error} | ||||
|             size="small" | ||||
|           > | ||||
|             {loadingPdf ? <CircularProgress size={20} color="inherit" /> : "Abrir PDF"} | ||||
|           </Button> | ||||
|           <Button | ||||
|             onClick={handleExportToExcel} | ||||
|             variant="outlined" | ||||
|             disabled={reportData.length === 0 || !!error} | ||||
|             size="small" | ||||
|           > | ||||
|             Exportar a Excel | ||||
|           </Button> | ||||
|           <Button onClick={handleVolverAParametros} variant="outlined" color="secondary" size="small"> | ||||
|             Nuevos Parámetros | ||||
|           </Button> | ||||
|         </Box> | ||||
|       </Box> | ||||
|  | ||||
|       {loading && <Box sx={{ textAlign: 'center' }}><CircularProgress /></Box>} | ||||
|       {error && !loading && <Alert severity="error" sx={{ my: 2 }}>{error}</Alert>} | ||||
|  | ||||
|       {!loading && !error && ( | ||||
|         <TableContainer component={Paper} sx={{ maxHeight: 'calc(100vh - 240px)' }}> | ||||
|           <Table stickyHeader size="small"> | ||||
|             <TableHead> | ||||
|               <TableRow> | ||||
|                 <TableCell>Tipo Bobina</TableCell> | ||||
|                 <TableCell align="right">Cant. Ini.</TableCell> | ||||
|                 <TableCell align="right">Kg Ini.</TableCell> | ||||
|                 <TableCell align="right">Compradas</TableCell> | ||||
|                 <TableCell align="right">Kg Compr.</TableCell> | ||||
|                 <TableCell align="right">Consum.</TableCell> | ||||
|                 <TableCell align="right">Kg Consum.</TableCell> | ||||
|                 <TableCell align="right">Dañadas</TableCell> | ||||
|                 <TableCell align="right">Kg Dañ.</TableCell> | ||||
|                 <TableCell align="right">Cant. Fin.</TableCell> | ||||
|                 <TableCell align="right">Kg Finales</TableCell> | ||||
|               </TableRow> | ||||
|             </TableHead> | ||||
|             <TableBody> | ||||
|               {reportData.map((row, idx) => ( | ||||
|                 <TableRow key={row.tipoBobina + idx}> | ||||
|                   <TableCell>{row.tipoBobina}</TableCell> | ||||
|                   <TableCell align="right">{row.bobinasIniciales.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.kilosIniciales.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.bobinasCompradas.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.kilosComprados.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.bobinasConsumidas.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.kilosConsumidos.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.bobinasDaniadas.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.kilosDaniados.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.bobinasFinales.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.kilosFinales.toLocaleString('es-AR')}</TableCell> | ||||
|                 </TableRow> | ||||
|               ))} | ||||
|             </TableBody> | ||||
|           </Table> | ||||
|         </TableContainer> | ||||
|       )} | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export default ReporteMovimientoBobinasPage; | ||||
		Reference in New Issue
	
	Block a user