PDF: Igualar Sabores a Fragancia-Aroma y layout horizontal para Sensación/Gustos
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m17s

- Sabores ahora usa mismo formato de 2 columnas que Fragancia-Aroma
- Ambas secciones con fuente más pequeña y espaciado compacto (2.6mm)
- Sensación en boca: layout horizontal en 2 filas (3 + 2)
- Gustos predominantes: layout horizontal en 2 filas (3 + 2)
- Ajustadas posiciones Y de las secciones inferiores
This commit is contained in:
2025-11-24 17:47:21 -06:00
parent ce460a17c2
commit 7c3b9a34b7

View File

@@ -50,11 +50,11 @@ export function renderizarFormulario(
renderizarEncabezado(doc, xBase, yBase, muestra) renderizarEncabezado(doc, xBase, yBase, muestra)
renderizarTablaIntensidades(doc, xBase, yBase + 14, muestra) renderizarTablaIntensidades(doc, xBase, yBase + 14, muestra)
renderizarSeccionFraganciaAroma(doc, xBase + 55, yBase + 14, muestra) renderizarSeccionFraganciaAroma(doc, xBase + 55, yBase + 14, muestra)
renderizarSeccionSabores(doc, xBase + 55, yBase + 55, muestra) renderizarSeccionSabores(doc, xBase + 55, yBase + 49, muestra) // Sabores ahora tiene 34mm igual que Fragancia-Aroma
renderizarSeccionSensacionGustos(doc, xBase, yBase + 76, muestra) renderizarSeccionSensacionGustos(doc, xBase, yBase + 84, muestra)
renderizarSeccionTazasDefectos(doc, xBase, yBase + 96, muestra) renderizarSeccionTazasDefectos(doc, xBase, yBase + 100, muestra)
renderizarSeccionOtrasNotas(doc, xBase, yBase + 112, muestra) renderizarSeccionOtrasNotas(doc, xBase, yBase + 116, muestra)
renderizarSeccionSubTotal(doc, xBase, yBase + 122, muestra) renderizarSeccionSubTotal(doc, xBase, yBase + 124, muestra)
} }
/** /**
@@ -184,26 +184,26 @@ function renderizarSeccionFraganciaAroma(
muestra: Muestra muestra: Muestra
): void { ): void {
const width = 144.9 // Ancho total de la sección derecha const width = 144.9 // Ancho total de la sección derecha
const sectionHeight = 41 const sectionHeight = 34
// Borde de la sección // Borde de la sección
dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal)
// Header // Header
doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFontSize(PDF_CONFIG.fontSize.small)
doc.setFont('helvetica', 'bold') doc.setFont('helvetica', 'bold')
doc.text('Fragancia - Aroma', x + 3, y + 5) doc.text('Fragancia - Aroma', x + 3, y + 4)
// Línea después del header // Línea después del header
dibujarLineaHorizontal(doc, x, y + 7, x + width, PDF_CONFIG.lineWidth.thin) dibujarLineaHorizontal(doc, x, y + 5.5, x + width, PDF_CONFIG.lineWidth.thin)
// Determinar qué está seleccionado // Determinar qué está seleccionado
const categoriasSeleccionadas = muestra.fraganciaAromaNotas.categorias const categoriasSeleccionadas = muestra.fraganciaAromaNotas.categorias
const subcategoriasSeleccionadas = muestra.fraganciaAromaNotas.subcategorias const subcategoriasSeleccionadas = muestra.fraganciaAromaNotas.subcategorias
// Espaciado entre checkboxes (mayor margen vertical) // Espaciado entre checkboxes (compacto)
const checkSpacing = 3.2 const checkSpacing = 2.6
const startY = y + 10 const startY = y + 8
// Columna izquierda de checkboxes // Columna izquierda de checkboxes
let checkY = startY let checkY = startY
@@ -228,7 +228,7 @@ function renderizarSeccionFraganciaAroma(
}) })
// Notas específica (sin recuadro, solo texto) // Notas específica (sin recuadro, solo texto)
doc.setFontSize(PDF_CONFIG.fontSize.small) doc.setFontSize(PDF_CONFIG.fontSize.tiny)
doc.setFont('helvetica', 'bold') doc.setFont('helvetica', 'bold')
doc.text('Notas:', x + 3, y + sectionHeight - 2) doc.text('Notas:', x + 3, y + sectionHeight - 2)
@@ -237,15 +237,15 @@ function renderizarSeccionFraganciaAroma(
const notaTruncada = truncarTexto( const notaTruncada = truncarTexto(
doc, doc,
muestra.fraganciaAromaNotas.notaEspecifica, muestra.fraganciaAromaNotas.notaEspecifica,
width - 25, width - 22,
PDF_CONFIG.fontSize.small PDF_CONFIG.fontSize.tiny
) )
doc.text(notaTruncada, x + 18, y + sectionHeight - 2) doc.text(notaTruncada, x + 15, y + sectionHeight - 2)
} }
} }
/** /**
* Renderiza la sección de Sabores * Renderiza la sección de Sabores (exactamente igual a Fragancia-Aroma)
*/ */
function renderizarSeccionSabores( function renderizarSeccionSabores(
doc: jsPDF, doc: jsPDF,
@@ -254,50 +254,51 @@ function renderizarSeccionSabores(
muestra: Muestra muestra: Muestra
): void { ): void {
const width = 144.9 const width = 144.9
const sectionHeight = 21 const sectionHeight = 34 // Mismo tamaño que Fragancia-Aroma
// Borde de la sección // Borde de la sección
dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal)
// Header // Header
doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFontSize(PDF_CONFIG.fontSize.small)
doc.setFont('helvetica', 'bold') doc.setFont('helvetica', 'bold')
doc.text('Sabores', x + 3, y + 5) doc.text('Sabores', x + 3, y + 4)
// Línea después del header // Línea después del header
dibujarLineaHorizontal(doc, x, y + 7, x + width, PDF_CONFIG.lineWidth.thin) dibujarLineaHorizontal(doc, x, y + 5.5, x + width, PDF_CONFIG.lineWidth.thin)
// Determinar qué está seleccionado
const categoriasSeleccionadas = muestra.saborNotas.categorias const categoriasSeleccionadas = muestra.saborNotas.categorias
const subcategoriasSeleccionadas = muestra.saborNotas.subcategorias const subcategoriasSeleccionadas = muestra.saborNotas.subcategorias
// Checkboxes en una sola fila (solo categorías principales sin subcategorías) // Espaciado entre checkboxes (compacto, igual que Fragancia-Aroma)
const checkSpacing = 3 const checkSpacing = 2.6
const startY = y + 11 const startY = y + 8
// Mostrar solo categorías principales // Columna izquierda de checkboxes (mismas categorías que Fragancia-Aroma)
const categoriasPrincipales = [ let checkY = startY
{ key: 'Floral', label: 'Floral' }, CATEGORIAS_PDF.columnaIzquierda.forEach((cat) => {
{ 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 = const isChecked =
categoriasSeleccionadas.includes(cat.key as any) || categoriasSeleccionadas.includes(cat.key as any) ||
subcategoriasSeleccionadas.includes(cat.key) subcategoriasSeleccionadas.includes(cat.key)
dibujarCheckboxConLabel(doc, checkX, startY, cat.label, isChecked) dibujarCheckboxConLabel(doc, x + 3, checkY, cat.label, isChecked, cat.indent)
checkX += 18 checkY += checkSpacing
}) })
// Notas específica de sabor (sin recuadro) // Columna derecha de checkboxes
doc.setFontSize(PDF_CONFIG.fontSize.small) checkY = startY
CATEGORIAS_PDF.columnaDerecha.forEach((cat) => {
const isChecked =
categoriasSeleccionadas.includes(cat.key as any) ||
subcategoriasSeleccionadas.includes(cat.key)
dibujarCheckboxConLabel(doc, x + 75, checkY, cat.label, isChecked, cat.indent)
checkY += checkSpacing
})
// Notas específica (sin recuadro, solo texto)
doc.setFontSize(PDF_CONFIG.fontSize.tiny)
doc.setFont('helvetica', 'bold') doc.setFont('helvetica', 'bold')
doc.text('Notas:', x + 3, y + sectionHeight - 2) doc.text('Notas:', x + 3, y + sectionHeight - 2)
@@ -306,15 +307,16 @@ function renderizarSeccionSabores(
const notaTruncada = truncarTexto( const notaTruncada = truncarTexto(
doc, doc,
muestra.saborNotas.notaEspecifica, muestra.saborNotas.notaEspecifica,
width - 25, width - 22,
PDF_CONFIG.fontSize.small PDF_CONFIG.fontSize.tiny
) )
doc.text(notaTruncada, x + 18, y + sectionHeight - 2) doc.text(notaTruncada, x + 15, y + sectionHeight - 2)
} }
} }
/** /**
* Renderiza la sección de Sensación en boca y Gustos predominantes * Renderiza la sección de Sensación en boca y Gustos predominantes
* Layout horizontal en 2 filas para cada sección
*/ */
function renderizarSeccionSensacionGustos( function renderizarSeccionSensacionGustos(
doc: jsPDF, doc: jsPDF,
@@ -323,7 +325,7 @@ function renderizarSeccionSensacionGustos(
muestra: Muestra muestra: Muestra
): void { ): void {
const width = PDF_CONFIG.formWidth const width = PDF_CONFIG.formWidth
const sectionHeight = 20 const sectionHeight = 16 // Más compacto con layout horizontal
// Borde de la sección // Borde de la sección
dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal) dibujarRectangulo(doc, x, y, width, sectionHeight, PDF_CONFIG.lineWidth.normal)
@@ -331,45 +333,59 @@ function renderizarSeccionSensacionGustos(
// Sección Sensación en boca // Sección Sensación en boca
const sensacionWidth = width * 0.6 const sensacionWidth = width * 0.6
doc.setFontSize(PDF_CONFIG.fontSize.body) doc.setFontSize(PDF_CONFIG.fontSize.small)
doc.setFont('helvetica', 'bold') doc.setFont('helvetica', 'bold')
doc.text('Sensación en boca', x + 3, y + 5) doc.text('Sensación en boca', x + 3, y + 4)
// Línea divisoria vertical // Línea divisoria vertical
dibujarLineaVertical(doc, x + sensacionWidth, y, y + sectionHeight) dibujarLineaVertical(doc, x + sensacionWidth, y, y + sectionHeight)
// Checkboxes de sensación con más espacio vertical // Sensaciones - Layout horizontal en 2 filas
const checkSpacing = 3.5 // Fila 1: Áspero, Aceitoso, Metálico
let checkY = y + 9 // Fila 2: Suave, Deja seca la boca
const sensacionesLabels = [
{ key: 'Áspero', label: 'Áspero' },
{ key: 'Aceitoso', label: 'Aceitoso' },
{ key: 'Metálico', label: 'Metálico' },
{ key: 'Suave', label: 'Suave' },
{ key: 'Deja seca la boca', label: 'Astringente' },
]
SENSACIONES_PDF.forEach((sens) => { const checkSpacingX = 40 // Espacio horizontal entre checkboxes
const row1Y = y + 7
const row2Y = y + 12
// Fila 1: primeros 3
sensacionesLabels.slice(0, 3).forEach((sens, idx) => {
const isChecked = muestra.sensacionEnBoca === sens.key const isChecked = muestra.sensacionEnBoca === sens.key
dibujarCheckboxConLabel(doc, x + 3 + idx * checkSpacingX, row1Y, sens.label, isChecked)
})
// Usar label corto para ahorrar espacio // Fila 2: últimos 2
const labelCorto = sensacionesLabels.slice(3).forEach((sens, idx) => {
sens.key === 'Deja seca la boca' const isChecked = muestra.sensacionEnBoca === sens.key
? 'Deja seca la boca (Astringente)' dibujarCheckboxConLabel(doc, x + 3 + idx * checkSpacingX, row2Y, sens.label, isChecked)
: sens.key === 'Áspero'
? 'Áspero (Arenoso, Rugoso)'
: sens.key === 'Suave'
? 'Suave (Aterciopelado)'
: sens.key
dibujarCheckboxConLabel(doc, x + 3, checkY, labelCorto, isChecked)
checkY += checkSpacing
}) })
// Sección Gustos predominantes // Sección Gustos predominantes
doc.setFont('helvetica', 'bold') doc.setFont('helvetica', 'bold')
doc.text('Gustos predominantes (2)', x + sensacionWidth + 3, y + 5) doc.text('Gustos predominantes (2)', x + sensacionWidth + 3, y + 4)
// Checkboxes de gustos con más espacio vertical // Gustos - Layout horizontal en 2 filas
checkY = y + 9 // Fila 1: Salado, Amargo, Ácido
// Fila 2: Dulce, Umami
const gustosSpacingX = 26
GUSTOS_PDF.forEach((gusto) => { // Fila 1: primeros 3
GUSTOS_PDF.slice(0, 3).forEach((gusto, idx) => {
const isChecked = muestra.gustosPredominantes.includes(gusto.key as any) const isChecked = muestra.gustosPredominantes.includes(gusto.key as any)
dibujarCheckboxConLabel(doc, x + sensacionWidth + 3, checkY, gusto.label, isChecked) dibujarCheckboxConLabel(doc, x + sensacionWidth + 3 + idx * gustosSpacingX, row1Y, gusto.label, isChecked)
checkY += checkSpacing })
// Fila 2: últimos 2
GUSTOS_PDF.slice(3).forEach((gusto, idx) => {
const isChecked = muestra.gustosPredominantes.includes(gusto.key as any)
dibujarCheckboxConLabel(doc, x + sensacionWidth + 3 + idx * gustosSpacingX, row2Y, gusto.label, isChecked)
}) })
} }