feat: Agregar exportación PDF del formulario de catación EVC-IH01
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 2m51s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 2m51s
- Implementar módulo de generación PDF con jsPDF - Crear composable usePdfExport para exportar muestras y sesiones - Añadir botones de exportación PDF en header y por muestra - Replicar layout exacto del formulario físico IHCAFE - Soportar máximo 3 formularios por hoja carta
This commit is contained in:
150
nuxt4/app/composables/usePdfExport.ts
Normal file
150
nuxt4/app/composables/usePdfExport.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Composable para exportar formularios de catación a PDF
|
||||
* Genera PDFs en formato EVC-IH01 (formulario físico de IHCAFE)
|
||||
*/
|
||||
|
||||
import { jsPDF } from 'jspdf'
|
||||
import type { Muestra, SesionCatacion } from '~/types/catacion'
|
||||
import { renderizarFormulario } from '~/utils/pdf'
|
||||
|
||||
const FORMULARIOS_POR_PAGINA = 3
|
||||
|
||||
export const usePdfExport = () => {
|
||||
const exportando = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
/**
|
||||
* Exporta una muestra individual a PDF
|
||||
*/
|
||||
const exportarMuestra = async (
|
||||
muestra: Muestra,
|
||||
nombreArchivo?: string
|
||||
): Promise<void> => {
|
||||
try {
|
||||
exportando.value = true
|
||||
error.value = null
|
||||
|
||||
const doc = new jsPDF({
|
||||
orientation: 'portrait',
|
||||
unit: 'mm',
|
||||
format: 'letter',
|
||||
})
|
||||
|
||||
renderizarFormulario(doc, muestra, 0)
|
||||
|
||||
const filename =
|
||||
nombreArchivo || `catacion-${sanitizarNombre(muestra.nombre)}-${Date.now()}.pdf`
|
||||
doc.save(filename)
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Error al exportar PDF'
|
||||
console.error('Error exportando PDF:', err)
|
||||
throw err
|
||||
} finally {
|
||||
exportando.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta toda la sesión a PDF (máximo 3 formularios por página)
|
||||
*/
|
||||
const exportarSesion = async (
|
||||
sesion: SesionCatacion,
|
||||
nombreArchivo?: string
|
||||
): Promise<void> => {
|
||||
try {
|
||||
exportando.value = true
|
||||
error.value = null
|
||||
|
||||
const doc = new jsPDF({
|
||||
orientation: 'portrait',
|
||||
unit: 'mm',
|
||||
format: 'letter',
|
||||
})
|
||||
|
||||
const muestras = sesion.muestras
|
||||
|
||||
muestras.forEach((muestra, index) => {
|
||||
const posicionEnPagina = index % FORMULARIOS_POR_PAGINA
|
||||
|
||||
// Nueva página si es necesario (excepto primera)
|
||||
if (index > 0 && posicionEnPagina === 0) {
|
||||
doc.addPage()
|
||||
}
|
||||
|
||||
renderizarFormulario(doc, muestra, posicionEnPagina as 0 | 1 | 2)
|
||||
})
|
||||
|
||||
const filename = nombreArchivo || `catacion-sesion-${sesion.fecha}.pdf`
|
||||
doc.save(filename)
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Error al exportar PDF'
|
||||
console.error('Error exportando PDF de sesión:', err)
|
||||
throw err
|
||||
} finally {
|
||||
exportando.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta muestras seleccionadas a PDF
|
||||
*/
|
||||
const exportarMuestrasSeleccionadas = async (
|
||||
muestras: Muestra[],
|
||||
nombreArchivo?: string
|
||||
): Promise<void> => {
|
||||
try {
|
||||
exportando.value = true
|
||||
error.value = null
|
||||
|
||||
if (muestras.length === 0) {
|
||||
throw new Error('No hay muestras seleccionadas para exportar')
|
||||
}
|
||||
|
||||
const doc = new jsPDF({
|
||||
orientation: 'portrait',
|
||||
unit: 'mm',
|
||||
format: 'letter',
|
||||
})
|
||||
|
||||
muestras.forEach((muestra, index) => {
|
||||
const posicionEnPagina = index % FORMULARIOS_POR_PAGINA
|
||||
|
||||
// Nueva página si es necesario (excepto primera)
|
||||
if (index > 0 && posicionEnPagina === 0) {
|
||||
doc.addPage()
|
||||
}
|
||||
|
||||
renderizarFormulario(doc, muestra, posicionEnPagina as 0 | 1 | 2)
|
||||
})
|
||||
|
||||
const filename = nombreArchivo || `catacion-seleccion-${Date.now()}.pdf`
|
||||
doc.save(filename)
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : 'Error al exportar PDF'
|
||||
console.error('Error exportando PDFs seleccionados:', err)
|
||||
throw err
|
||||
} finally {
|
||||
exportando.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
exportando: readonly(exportando),
|
||||
error: readonly(error),
|
||||
exportarMuestra,
|
||||
exportarSesion,
|
||||
exportarMuestrasSeleccionadas,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitiza un nombre para usar como nombre de archivo
|
||||
*/
|
||||
function sanitizarNombre(nombre: string): string {
|
||||
return nombre
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9áéíóúñ]/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '')
|
||||
.substring(0, 50)
|
||||
}
|
||||
Reference in New Issue
Block a user