diff --git a/PDF_Example_wrong_grammar.png b/PDF_Example_wrong_grammar.png new file mode 100644 index 0000000..c185be3 Binary files /dev/null and b/PDF_Example_wrong_grammar.png differ diff --git a/nuxt4/app/composables/usePdfExport.ts b/nuxt4/app/composables/usePdfExport.ts index 118be38..2a4f9dc 100644 --- a/nuxt4/app/composables/usePdfExport.ts +++ b/nuxt4/app/composables/usePdfExport.ts @@ -7,7 +7,7 @@ import { jsPDF } from 'jspdf' import type { Muestra, SesionCatacion } from '~/types/catacion' import { renderizarFormulario } from '~/utils/pdf' -const FORMULARIOS_POR_PAGINA = 3 +const FORMULARIOS_POR_PAGINA = 2 export const usePdfExport = () => { const exportando = ref(false) diff --git a/nuxt4/app/utils/pdf/pdfFormulario.ts b/nuxt4/app/utils/pdf/pdfFormulario.ts index 7987355..eb54411 100644 --- a/nuxt4/app/utils/pdf/pdfFormulario.ts +++ b/nuxt4/app/utils/pdf/pdfFormulario.ts @@ -19,7 +19,6 @@ import { dibujarCheckbox, dibujarCheckboxConLabel, dibujarCasillasTazas, - dibujarCeldaTexto, dibujarRectangulo, dibujarLineaHorizontal, dibujarLineaVertical, @@ -47,15 +46,15 @@ export function renderizarFormulario( PDF_CONFIG.lineWidth.thick ) - // Renderizar cada sección + // Renderizar cada sección con posiciones ajustadas para formulario de 130mm renderizarEncabezado(doc, xBase, yBase, muestra) - renderizarTablaIntensidades(doc, xBase, yBase + 10, muestra) - renderizarSeccionFraganciaAroma(doc, xBase + 48, yBase + 10, muestra) - renderizarSeccionSabores(doc, xBase + 48, yBase + 32, muestra) - renderizarSeccionSensacionGustos(doc, xBase, yBase + 46, muestra) - renderizarSeccionTazasDefectos(doc, xBase, yBase + 58, muestra) - renderizarSeccionOtrasNotas(doc, xBase, yBase + 70, muestra) - renderizarSeccionSubTotal(doc, xBase, yBase + 78, muestra) + renderizarTablaIntensidades(doc, xBase, yBase + 14, muestra) + renderizarSeccionFraganciaAroma(doc, xBase + 55, yBase + 14, muestra) + renderizarSeccionSabores(doc, xBase + 55, yBase + 55, muestra) + renderizarSeccionSensacionGustos(doc, xBase, yBase + 76, muestra) + renderizarSeccionTazasDefectos(doc, xBase, yBase + 96, muestra) + renderizarSeccionOtrasNotas(doc, xBase, yBase + 112, muestra) + renderizarSeccionSubTotal(doc, xBase, yBase + 122, muestra) } /** @@ -70,28 +69,28 @@ function renderizarEncabezado( const width = PDF_CONFIG.formWidth // Línea separadora del encabezado - dibujarLineaHorizontal(doc, x, y + 10, x + width, PDF_CONFIG.lineWidth.normal) + dibujarLineaHorizontal(doc, x, y + 14, x + width, PDF_CONFIG.lineWidth.normal) // Título principal doc.setFontSize(PDF_CONFIG.fontSize.title) doc.setFont('helvetica', 'bold') - doc.text('EVALUACION DEL VALOR DEL CAFE / DESCRIPTIVA-AFECTIVA', x + 2, y + 4) + doc.text('EVALUACION DEL VALOR DEL CAFE / DESCRIPTIVA-AFECTIVA', x + 3, y + 5) // Código EVC-IH01 doc.setFontSize(PDF_CONFIG.fontSize.header) - doc.text('EVC-IH01', x + width - 20, y + 4) + doc.text('EVC-IH01', x + width - 22, y + 5) // Línea separadora después del título - dibujarLineaHorizontal(doc, x, y + 5.5, x + width, PDF_CONFIG.lineWidth.thin) + dibujarLineaHorizontal(doc, x, y + 7, x + width, PDF_CONFIG.lineWidth.thin) // MUESTRA doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFont('helvetica', 'bold') - doc.text('MUESTRA:', x + 2, y + 8.5) + doc.text('MUESTRA:', x + 3, y + 11) doc.setFont('helvetica', 'normal') - const nombreTruncado = truncarTexto(doc, muestra.nombre, 40, PDF_CONFIG.fontSize.body) - doc.text(nombreTruncado, x + 20, y + 8.5) + const nombreTruncado = truncarTexto(doc, muestra.nombre, 60, PDF_CONFIG.fontSize.body) + doc.text(nombreTruncado, x + 25, y + 11) } /** @@ -104,56 +103,36 @@ function renderizarTablaIntensidades( muestra: Muestra ): void { const colWidths = { - parametro: 22, - descriptiva: 12, - afectiva: 12, + parametro: 28, + descriptiva: 13, + afectiva: 13, } - const rowHeight = 3.5 + const rowHeight = 5 const tableWidth = colWidths.parametro + colWidths.descriptiva + colWidths.afectiva + const tableHeight = rowHeight * 10 // Borde de la tabla - dibujarRectangulo(doc, x, y, tableWidth, rowHeight * 10, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, tableWidth, tableHeight, PDF_CONFIG.lineWidth.normal) // Headers - doc.setFontSize(PDF_CONFIG.fontSize.tiny) + doc.setFontSize(PDF_CONFIG.fontSize.small) doc.setFont('helvetica', 'bold') - // Header: Intensidad - dibujarCeldaTexto(doc, x, y, colWidths.parametro, rowHeight, 'Intensidad', { - fontSize: PDF_CONFIG.fontSize.tiny, - fontStyle: 'bold', - }) - - // Subheaders de intensidad - doc.setFontSize(PDF_CONFIG.fontSize.tiny - 0.5) - doc.text('Parámetro', x + 1, y + rowHeight + 2.5) + // Header: Intensidad/Parámetro + doc.text('Intensidad', x + 2, y + 4) + doc.setFontSize(PDF_CONFIG.fontSize.tiny) + doc.text('Parámetro', x + 2, y + rowHeight + 4) // Header: Descriptiva - dibujarCeldaTexto( - doc, - x + colWidths.parametro, - y, - colWidths.descriptiva, - rowHeight * 2, - '', - { border: true } - ) + dibujarLineaVertical(doc, x + colWidths.parametro, y, y + tableHeight) doc.setFontSize(PDF_CONFIG.fontSize.tiny) - doc.text('Descriptiva', x + colWidths.parametro + 1, y + 3) - doc.text('(1 al 15)', x + colWidths.parametro + 2, y + 6) + doc.text('Descriptiva', x + colWidths.parametro + 1, y + 4) + doc.text('(1 al 15)', x + colWidths.parametro + 2, y + 8) // Header: Afectiva - dibujarCeldaTexto( - doc, - x + colWidths.parametro + colWidths.descriptiva, - y, - colWidths.afectiva, - rowHeight * 2, - '', - { border: true } - ) - doc.text('Afectiva', x + colWidths.parametro + colWidths.descriptiva + 1.5, y + 3) - doc.text('(1 al 9)', x + colWidths.parametro + colWidths.descriptiva + 2.5, y + 6) + dibujarLineaVertical(doc, x + colWidths.parametro + colWidths.descriptiva, y, y + tableHeight) + doc.text('Afectiva', x + colWidths.parametro + colWidths.descriptiva + 2, y + 4) + doc.text('(1 al 9)', x + colWidths.parametro + colWidths.descriptiva + 3, y + 8) // Línea horizontal después de headers dibujarLineaHorizontal(doc, x, y + rowHeight * 2, x + tableWidth) @@ -168,14 +147,14 @@ function renderizarTablaIntensidades( // Parámetro doc.setFontSize(PDF_CONFIG.fontSize.tiny) doc.setFont('helvetica', 'normal') - doc.text(param.label, x + 1, currentY + 2.5) + doc.text(param.label, x + 2, currentY + 3.5) // Valor descriptiva if (intensidad.descriptiva !== null) { doc.text( String(intensidad.descriptiva), x + colWidths.parametro + colWidths.descriptiva / 2 - 1, - currentY + 2.5 + currentY + 3.5 ) } @@ -184,7 +163,7 @@ function renderizarTablaIntensidades( doc.text( String(intensidad.afectiva), x + colWidths.parametro + colWidths.descriptiva + colWidths.afectiva / 2 - 1, - currentY + 2.5 + currentY + 3.5 ) } @@ -193,15 +172,6 @@ function renderizarTablaIntensidades( currentY += rowHeight }) - - // Líneas verticales de la tabla - dibujarLineaVertical(doc, x + colWidths.parametro, y, y + rowHeight * 10) - dibujarLineaVertical( - doc, - x + colWidths.parametro + colWidths.descriptiva, - y, - y + rowHeight * 10 - ) } /** @@ -213,92 +183,64 @@ function renderizarSeccionFraganciaAroma( y: number, muestra: Muestra ): void { - const width = 151.9 // Ancho total de la sección derecha - const colWidth = width / 2 + const width = 144.9 // Ancho total de la sección derecha + const sectionHeight = 41 // Borde de la sección - dibujarRectangulo(doc, x, y, width, 22, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) // Header - doc.setFontSize(PDF_CONFIG.fontSize.small) + doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFont('helvetica', 'bold') - doc.text('Fragancia - Aroma', x + 2, y + 3) + doc.text('Fragancia - Aroma', x + 3, y + 5) // Línea después del header - dibujarLineaHorizontal(doc, x, y + 4.5, x + width, PDF_CONFIG.lineWidth.thin) - - // Header columna Notas - doc.text('Notas', x + colWidth + 2, y + 3) - - // Línea vertical divisoria - dibujarLineaVertical(doc, x + colWidth, y, y + 22) - - // Checkboxes columna izquierda - let checkY = y + 6 - const checkSpacing = 1.8 + dibujarLineaHorizontal(doc, x, y + 7, x + width, PDF_CONFIG.lineWidth.thin) // Determinar qué está seleccionado const categoriasSeleccionadas = muestra.fraganciaAromaNotas.categorias const subcategoriasSeleccionadas = muestra.fraganciaAromaNotas.subcategorias - // Columna izquierda de checkboxes (primera mitad de categorías) - const categoriasIzq = CATEGORIAS_PDF.columnaIzquierda.slice(0, 6) - categoriasIzq.forEach((cat) => { + // Espaciado entre checkboxes (mayor margen vertical) + const checkSpacing = 3.2 + const startY = y + 10 + + // Columna izquierda de checkboxes + let checkY = startY + CATEGORIAS_PDF.columnaIzquierda.forEach((cat) => { const isChecked = categoriasSeleccionadas.includes(cat.key as any) || subcategoriasSeleccionadas.includes(cat.key) - dibujarCheckboxConLabel(doc, x + 2, checkY, cat.label, isChecked, cat.indent) + dibujarCheckboxConLabel(doc, x + 3, checkY, cat.label, isChecked, cat.indent) checkY += checkSpacing }) - // Continuar en columna media - checkY = y + 6 - const categoriasMed = CATEGORIAS_PDF.columnaIzquierda.slice(6) - categoriasMed.forEach((cat) => { + // Columna derecha de checkboxes + checkY = startY + CATEGORIAS_PDF.columnaDerecha.forEach((cat) => { const isChecked = categoriasSeleccionadas.includes(cat.key as any) || subcategoriasSeleccionadas.includes(cat.key) - dibujarCheckboxConLabel(doc, x + 28, checkY, cat.label, isChecked, cat.indent) + dibujarCheckboxConLabel(doc, x + 75, checkY, cat.label, isChecked, cat.indent) checkY += checkSpacing }) - // Columna derecha de checkboxes (Notas) - checkY = y + 6 - const categoriasDer = CATEGORIAS_PDF.columnaDerecha.slice(0, 6) - categoriasDer.forEach((cat) => { - const isChecked = - categoriasSeleccionadas.includes(cat.key as any) || - subcategoriasSeleccionadas.includes(cat.key) + // Notas específica (sin recuadro, solo texto) + doc.setFontSize(PDF_CONFIG.fontSize.small) + doc.setFont('helvetica', 'bold') + doc.text('Notas:', x + 3, y + sectionHeight - 2) - dibujarCheckboxConLabel(doc, x + colWidth + 2, checkY, cat.label, isChecked, cat.indent) - checkY += checkSpacing - }) - - // Segunda columna de Notas - checkY = y + 6 - const categoriasDer2 = CATEGORIAS_PDF.columnaDerecha.slice(6) - categoriasDer2.forEach((cat) => { - const isChecked = - categoriasSeleccionadas.includes(cat.key as any) || - subcategoriasSeleccionadas.includes(cat.key) - - dibujarCheckboxConLabel(doc, x + colWidth + 35, checkY, cat.label, isChecked, cat.indent) - checkY += checkSpacing - }) - - // Nota específica if (muestra.fraganciaAromaNotas.notaEspecifica) { - doc.setFontSize(PDF_CONFIG.fontSize.tiny) doc.setFont('helvetica', 'normal') const notaTruncada = truncarTexto( doc, muestra.fraganciaAromaNotas.notaEspecifica, - colWidth - 10, - PDF_CONFIG.fontSize.tiny + width - 25, + PDF_CONFIG.fontSize.small ) - doc.text(notaTruncada, x + 2, y + 20) + doc.text(notaTruncada, x + 18, y + sectionHeight - 2) } } @@ -311,91 +253,63 @@ function renderizarSeccionSabores( y: number, muestra: Muestra ): void { - const width = 151.9 - const colWidth = width / 2 + const width = 144.9 + const sectionHeight = 21 // Borde de la sección - dibujarRectangulo(doc, x, y, width, 14, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) // Header - doc.setFontSize(PDF_CONFIG.fontSize.small) + doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFont('helvetica', 'bold') - doc.text('Sabores', x + 2, y + 3) - - // Header Notas - doc.text('Notas', x + colWidth + 2, y + 3) + doc.text('Sabores', x + 3, y + 5) // Línea después del header - dibujarLineaHorizontal(doc, x, y + 4.5, x + width, PDF_CONFIG.lineWidth.thin) - - // Línea vertical divisoria - dibujarLineaVertical(doc, x + colWidth, y, y + 14) - - // Checkboxes (mismas categorías que fragancia) - let checkY = y + 6 - const checkSpacing = 1.6 + dibujarLineaHorizontal(doc, x, y + 7, x + width, PDF_CONFIG.lineWidth.thin) const categoriasSeleccionadas = muestra.saborNotas.categorias const subcategoriasSeleccionadas = muestra.saborNotas.subcategorias - // Columna izquierda (primeras 4) - const categoriasIzq = CATEGORIAS_PDF.columnaIzquierda.slice(0, 4) - categoriasIzq.forEach((cat) => { + // Checkboxes en una sola fila (solo categorías principales sin subcategorías) + const checkSpacing = 3 + const startY = y + 11 + + // Mostrar solo categorías principales + const categoriasPrincipales = [ + { key: 'Floral', label: 'Floral' }, + { key: 'Afrutado', label: 'Afrutado' }, + { key: 'Verde Vegetal', label: 'Verde/Vegetal' }, + { key: 'Otro', label: 'Otra' }, + { key: 'Tostado', label: 'Tostado' }, + { key: 'Nueces/Cacao', label: 'Nueces/Cacao' }, + { key: 'Especias', label: 'Especias' }, + { key: 'Dulce', label: 'Dulce' }, + ] + + let checkX = x + 3 + categoriasPrincipales.forEach((cat) => { const isChecked = categoriasSeleccionadas.includes(cat.key as any) || subcategoriasSeleccionadas.includes(cat.key) - dibujarCheckboxConLabel(doc, x + 2, checkY, cat.label, isChecked, cat.indent) - checkY += checkSpacing + dibujarCheckboxConLabel(doc, checkX, startY, cat.label, isChecked) + checkX += 18 }) - // Columna media - checkY = y + 6 - const categoriasMed = CATEGORIAS_PDF.columnaIzquierda.slice(4, 8) - categoriasMed.forEach((cat) => { - const isChecked = - categoriasSeleccionadas.includes(cat.key as any) || - subcategoriasSeleccionadas.includes(cat.key) + // Notas específica de sabor (sin recuadro) + doc.setFontSize(PDF_CONFIG.fontSize.small) + doc.setFont('helvetica', 'bold') + doc.text('Notas:', x + 3, y + sectionHeight - 2) - dibujarCheckboxConLabel(doc, x + 28, checkY, cat.label, isChecked, cat.indent) - checkY += checkSpacing - }) - - // Columna derecha - checkY = y + 6 - const categoriasDer = CATEGORIAS_PDF.columnaDerecha.slice(0, 4) - categoriasDer.forEach((cat) => { - const isChecked = - categoriasSeleccionadas.includes(cat.key as any) || - subcategoriasSeleccionadas.includes(cat.key) - - dibujarCheckboxConLabel(doc, x + colWidth + 2, checkY, cat.label, isChecked, cat.indent) - checkY += checkSpacing - }) - - // Segunda columna derecha - checkY = y + 6 - const categoriasDer2 = CATEGORIAS_PDF.columnaDerecha.slice(4, 8) - categoriasDer2.forEach((cat) => { - const isChecked = - categoriasSeleccionadas.includes(cat.key as any) || - subcategoriasSeleccionadas.includes(cat.key) - - dibujarCheckboxConLabel(doc, x + colWidth + 35, checkY, cat.label, isChecked, cat.indent) - checkY += checkSpacing - }) - - // Nota específica de sabor if (muestra.saborNotas.notaEspecifica) { - doc.setFontSize(PDF_CONFIG.fontSize.tiny) doc.setFont('helvetica', 'normal') const notaTruncada = truncarTexto( doc, muestra.saborNotas.notaEspecifica, - colWidth - 10, - PDF_CONFIG.fontSize.tiny + width - 25, + PDF_CONFIG.fontSize.small ) - doc.text(notaTruncada, x + 2, y + 12.5) + doc.text(notaTruncada, x + 18, y + sectionHeight - 2) } } @@ -409,70 +323,53 @@ function renderizarSeccionSensacionGustos( muestra: Muestra ): void { const width = PDF_CONFIG.formWidth + const sectionHeight = 20 // Borde de la sección - dibujarRectangulo(doc, x, y, width, 12, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) // Sección Sensación en boca const sensacionWidth = width * 0.6 - doc.setFontSize(PDF_CONFIG.fontSize.small) + doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFont('helvetica', 'bold') - doc.text('Sensación en boca', x + 2, y + 3) + doc.text('Sensación en boca', x + 3, y + 5) // Línea divisoria vertical - dibujarLineaVertical(doc, x + sensacionWidth, y, y + 12) + dibujarLineaVertical(doc, x + sensacionWidth, y, y + sectionHeight) - // Checkboxes de sensación - let checkY = y + 5 - const checkSpacing = 2.2 - let checkX = x + 2 + // Checkboxes de sensación con más espacio vertical + const checkSpacing = 3.5 + let checkY = y + 9 - SENSACIONES_PDF.forEach((sens, index) => { + SENSACIONES_PDF.forEach((sens) => { const isChecked = muestra.sensacionEnBoca === sens.key - // Ajustar posición para layout de 2 filas - if (index === 3) { - checkY = y + 5 - checkX = x + 60 - } else if (index > 0 && index < 3) { - checkY += checkSpacing - } else if (index > 3) { - checkY += checkSpacing - } - // Usar label corto para ahorrar espacio const labelCorto = sens.key === 'Deja seca la boca' - ? 'Deja seca boca' + ? 'Deja seca la boca (Astringente)' : sens.key === 'Áspero' - ? 'Áspero' - : sens.key + ? 'Áspero (Arenoso, Rugoso)' + : sens.key === 'Suave' + ? 'Suave (Aterciopelado)' + : sens.key - dibujarCheckboxConLabel(doc, checkX, checkY, labelCorto, isChecked) + dibujarCheckboxConLabel(doc, x + 3, checkY, labelCorto, isChecked) + checkY += checkSpacing }) // Sección Gustos predominantes doc.setFont('helvetica', 'bold') - doc.text('Gustos predominantes (2)', x + sensacionWidth + 2, y + 3) + doc.text('Gustos predominantes (2)', x + sensacionWidth + 3, y + 5) - // Checkboxes de gustos - checkY = y + 5 - checkX = x + sensacionWidth + 2 + // Checkboxes de gustos con más espacio vertical + checkY = y + 9 - GUSTOS_PDF.forEach((gusto, index) => { + GUSTOS_PDF.forEach((gusto) => { const isChecked = muestra.gustosPredominantes.includes(gusto.key as any) - - if (index === 3) { - checkY = y + 5 - checkX = x + sensacionWidth + 35 - } else if (index > 0 && index < 3) { - checkY += checkSpacing - } else if (index > 3) { - checkY += checkSpacing - } - - dibujarCheckboxConLabel(doc, checkX, checkY, gusto.label, isChecked) + dibujarCheckboxConLabel(doc, x + sensacionWidth + 3, checkY, gusto.label, isChecked) + checkY += checkSpacing }) } @@ -486,26 +383,29 @@ function renderizarSeccionTazasDefectos( muestra: Muestra ): void { const width = PDF_CONFIG.formWidth + const sectionHeight = 16 // Borde de la sección - dibujarRectangulo(doc, x, y, width, 12, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) // Tazas NO Uniformes - dibujarCasillasTazas(doc, x + 2, y + 2, muestra.tazasNoUniformes, 'Tazas NO Uniformes:') + dibujarCasillasTazas(doc, x + 3, y + 3, muestra.tazasNoUniformes, 'Tazas NO Uniformes:') // Tazas Defectuosas - dibujarCasillasTazas(doc, x + 55, y + 2, muestra.tazasDefectuosas, 'Tazas defectuosas:') + dibujarCasillasTazas(doc, x + 70, y + 3, muestra.tazasDefectuosas, 'Tazas defectuosas:') - // Defectos + // Defectos - Header alineado con checkboxes doc.setFontSize(PDF_CONFIG.fontSize.small) doc.setFont('helvetica', 'bold') - doc.text('Defecto (de beberse):', x + 110, y + 3) + doc.text('Defecto (de haberse):', x + 140, y + 5) - let checkX = x + 150 + // Checkboxes alineados bajo el header + let checkX = x + 140 + const checkY = y + 10 DEFECTOS_PDF.forEach((defecto) => { const isChecked = muestra.defecto === defecto.key - dibujarCheckboxConLabel(doc, checkX, y + 5, defecto.label, isChecked) - checkX += 18 + dibujarCheckboxConLabel(doc, checkX, checkY, defecto.label, isChecked) + checkX += 20 }) } @@ -519,14 +419,15 @@ function renderizarSeccionOtrasNotas( muestra: Muestra ): void { const width = PDF_CONFIG.formWidth + const sectionHeight = 10 // Borde de la sección - dibujarRectangulo(doc, x, y, width, 8, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) // Label - doc.setFontSize(PDF_CONFIG.fontSize.small) + doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFont('helvetica', 'bold') - doc.text('OTRAS NOTAS:', x + 2, y + 4) + doc.text('OTRAS NOTAS:', x + 3, y + 6) // Valor if (muestra.otrasNotas) { @@ -534,14 +435,14 @@ function renderizarSeccionOtrasNotas( const notaTruncada = truncarTexto( doc, muestra.otrasNotas, - width - 35, - PDF_CONFIG.fontSize.small + width - 45, + PDF_CONFIG.fontSize.body ) - doc.text(notaTruncada, x + 30, y + 4) + doc.text(notaTruncada, x + 38, y + 6) } // Línea para escribir - dibujarLineaHorizontal(doc, x + 30, y + 5, x + width - 2, PDF_CONFIG.lineWidth.thin) + dibujarLineaHorizontal(doc, x + 38, y + 7, x + width - 3, PDF_CONFIG.lineWidth.thin) } /** @@ -554,9 +455,10 @@ function renderizarSeccionSubTotal( muestra: Muestra ): void { const width = PDF_CONFIG.formWidth + const sectionHeight = 8 // Borde de la sección - dibujarRectangulo(doc, x, y, width, 7, PDF_CONFIG.lineWidth.normal) + dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) // Cálculos const sumatoriaAfectiva = calcularSumatoriaAfectiva(muestra) @@ -567,7 +469,7 @@ function renderizarSeccionSubTotal( doc.setFontSize(PDF_CONFIG.fontSize.small) doc.setFont('helvetica', 'bold') - doc.text('SUB TOTAL:', x + 2, y + 4) + doc.text('SUB TOTAL:', x + 3, y + 5) // Valores const valores = [ @@ -577,14 +479,14 @@ function renderizarSeccionSubTotal( { label: 'Total (100%) - Daño:', valor: (scaa - dano).toFixed(2) }, ] - let currentX = x + 28 + let currentX = x + 32 valores.forEach((item) => { doc.setFont('helvetica', 'normal') - doc.text(item.label, currentX, y + 4) + doc.text(item.label, currentX, y + 5) currentX += doc.getTextWidth(item.label) + 1 doc.setFont('helvetica', 'bold') - doc.text(item.valor, currentX, y + 4) - currentX += doc.getTextWidth(item.valor) + 5 + doc.text(item.valor, currentX, y + 5) + currentX += doc.getTextWidth(item.valor) + 6 }) } diff --git a/nuxt4/app/utils/pdf/pdfLayout.ts b/nuxt4/app/utils/pdf/pdfLayout.ts index dbaca7b..c250387 100644 --- a/nuxt4/app/utils/pdf/pdfLayout.ts +++ b/nuxt4/app/utils/pdf/pdfLayout.ts @@ -15,18 +15,18 @@ export const PDF_CONFIG = { marginLeft: 8, marginRight: 8, - // Formulario individual (3 por página) - formHeight: 85, // ~85mm cada formulario + // Formulario individual (2 por página para más espacio) + formHeight: 130, // ~130mm cada formulario (más alto) formWidth: 199.9, // pageWidth - marginLeft - marginRight - formSpacing: 2, // Espacio entre formularios + formSpacing: 3, // Espacio entre formularios // Tipografía fontSize: { - title: 9, - header: 7, - body: 6, - small: 5, - tiny: 4.5, + title: 10, + header: 8, + body: 7, + small: 6, + tiny: 5.5, }, // Colores @@ -44,8 +44,8 @@ export const PDF_CONFIG = { }, // Tamaño de checkbox - checkboxSize: 2.5, - checkboxSpacing: 0.8, + checkboxSize: 3.5, + checkboxSpacing: 1.5, } as const /** @@ -157,7 +157,7 @@ export interface CategoriaPdf { /** * Categorías de notas para el formulario PDF - * Columna izquierda y derecha de checkboxes + * Distribución correcta según formulario físico EVC-IH01 */ export const CATEGORIAS_PDF: { columnaIzquierda: CategoriaPdf[] @@ -167,14 +167,13 @@ export const CATEGORIAS_PDF: { { key: 'Floral', label: 'Floral' }, { key: 'Afrutado', label: 'Afrutado' }, { key: 'Bayas', label: 'Bayas', indent: true }, - { key: 'Ácido', label: 'Ácido', indent: true }, - { key: 'Frutas Deshidratadas', label: 'Frutas Deshid.', indent: true }, - { key: 'Fermentado', label: 'Fermentado', indent: true }, - { key: 'Cítricos', label: 'Cítricos' }, + { key: 'Frutas Deshidratadas', label: 'Frutas Deshidratadas', indent: true }, + { key: 'Cítricos', label: 'Cítricos', indent: true }, { key: 'Verde Vegetal', label: 'Verde/Vegetal' }, - { key: 'Químico', label: 'Químico' }, - { key: 'Humedad/Tierra', label: 'Humedad/Tierra' }, - { key: 'Madera', label: 'Madera' }, + { key: 'Otro', label: 'Otra' }, + { key: 'Químico', label: 'Químico', indent: true }, + { key: 'Humedad/Tierra', label: 'Humedad/Tierra', indent: true }, + { key: 'Madera', label: 'Madera', indent: true }, ], columnaDerecha: [ { key: 'Tostado', label: 'Tostado' },