trabajando en interior

This commit is contained in:
Jaime Jiménez
2025-07-30 22:18:06 +02:00
parent 8b34d6dca9
commit eb0b5610d8
41 changed files with 1082 additions and 201 deletions

View File

@ -0,0 +1,85 @@
package com.imprimelibros.erp.config.Presupuestador;
import java.util.Map;
public class ImagenPresupuesto {
private String id;
private String imagen;
private String alt;
private String texto;
private boolean selected;
private Map<String, String> extra_data;
// Constructores
public ImagenPresupuesto() {}
public ImagenPresupuesto(String id, String imagen, String alt, String texto, boolean selected) {
this.id = id;
this.imagen = imagen;
this.alt = alt;
this.texto = texto;
this.selected = selected;
}
public ImagenPresupuesto(String id, String imagen, String alt, String texto, Map<String, String> extra_data,boolean selected) {
this.id = id;
this.imagen = imagen;
this.alt = alt;
this.texto = texto;
this.selected = selected;
this.extra_data = extra_data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getImagen() {
return imagen;
}
public void setImagen(String imagen) {
this.imagen = imagen;
}
public String getAlt() {
return alt;
}
public void setAlt(String alt) {
this.alt = alt;
}
public String getTexto() {
return texto;
}
public void setTexto(String texto) {
this.texto = texto;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public Map<String, String> getExtra_data() {
return extra_data;
}
public void setExtra_data(Map<String, String> extra_data) {
this.extra_data = extra_data;
}
}

View File

@ -0,0 +1,99 @@
package com.imprimelibros.erp.config.Presupuestador;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import java.util.Locale;
import java.util.Map;
@Component
public class PresupuestadorItems {
@Autowired
private MessageSource messageSource;
public ImagenPresupuesto getImpresionNegro(Locale locale) {
return new ImagenPresupuesto(
"negroEstandar",
"/assets/images/imprimelibros/presupuestador/blancoYnegro.png",
"",
messageSource.getMessage("presupuesto.blanco-negro", null, locale),
false);
}
public ImagenPresupuesto getImpresionNegroPremium(Locale locale) {
return new ImagenPresupuesto(
"negroPremium",
"/assets/images/imprimelibros/presupuestador/negroFoto.png",
"",
messageSource.getMessage("presupuesto.blanco-negro-premium", null, locale),
false);
}
public ImagenPresupuesto getImpresionColor(Locale locale) {
String clave = "presupuesto.color"; // ✅
String texto = messageSource.getMessage(clave, null, locale);
System.out.println("Clave: " + clave + " => Texto: " + texto);
return new ImagenPresupuesto(
"colorEstandar",
"/assets/images/imprimelibros/presupuestador/color.png",
"",
messageSource.getMessage("presupuesto.color", null, locale),
false);
}
public ImagenPresupuesto getImpresionColorPremium(Locale locale) {
return new ImagenPresupuesto(
"colorPremium",
"/assets/images/imprimelibros/presupuestador/colorFoto.png",
"",
messageSource.getMessage("presupuesto.color-premium", null, locale),
false);
}
public ImagenPresupuesto getPapelOffsetBlanco(Locale locale) {
return new ImagenPresupuesto(
"offset-blanco",
"/assets/images/imprimelibros/presupuestador/offset-blanco.png",
"",
messageSource.getMessage("presupuesto.offset-blanco", null, locale),
Map.of("sk-id", "3"),
false);
}
public ImagenPresupuesto getPapelOffsetAhuesado(Locale locale) {
return new ImagenPresupuesto(
"offset-ahuesado",
"/assets/images/imprimelibros/presupuestador/offset-ahuesado.png",
"",
messageSource.getMessage("presupuesto.offset-ahuesado", null, locale),
Map.of("sk-id", "4"),
false);
}
public ImagenPresupuesto getPapelOffsetAhuesadoVolumen(Locale locale) {
return new ImagenPresupuesto(
"offset-ahuesado-volumen",
"/assets/images/imprimelibros/presupuestador/offset-ahuesado-volumen.png",
"",
messageSource.getMessage("presupuesto.offset-ahuesado-volumen", null, locale),
Map.of("sk-id", "6"),
false);
}
public ImagenPresupuesto getPapelEstucadoMate(Locale locale) {
return new ImagenPresupuesto(
"estucado-mate",
"/assets/images/imprimelibros/presupuestador/estucado-mate.png",
"",
messageSource.getMessage("presupuesto.estucado-mate", null, locale),
Map.of("sk-id", "2"),
false);
}
}

View File

@ -31,7 +31,7 @@ public class ConsistentTiradasValidator implements ConstraintValidator<Consisten
continue;
if (t <= podValue)
allAbove = false;
if (t >= podValue)
else // (t > podValue)
allBelow = false;
}

View File

@ -0,0 +1,19 @@
package com.imprimelibros.erp.config.validation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = TamanioValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Tamanio {
String message() default "{presupuesto.errores.tamanio.invalido}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@ -0,0 +1,54 @@
package com.imprimelibros.erp.config.validation;
import com.imprimelibros.erp.entity.Presupuesto;
import com.imprimelibros.erp.service.VariableService;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
public class TamanioValidator implements ConstraintValidator<Tamanio, Presupuesto>{
@Autowired
private VariableService variableService;
@Autowired
private MessageSource messageSource;
@Override
public boolean isValid(Presupuesto presupuesto, ConstraintValidatorContext context) {
if (presupuesto == null)
return true;
Integer min = variableService.getValorEntero("ancho_alto_min");
Integer max = variableService.getValorEntero("ancho_alto_max");
if (presupuesto.getAncho() <= min || presupuesto.getAncho() >= max) {
String mensajeInterpolado = messageSource.getMessage(
"presupuesto.errores.ancho.min_max", // clave del mensaje
new Object[] { min, max }, // parámetros para {0}
LocaleContextHolder.getLocale() // respeta el idioma actual
);
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(mensajeInterpolado)
.addConstraintViolation();
return false;
}
else if (presupuesto.getAlto() <= min || presupuesto.getAlto() >= max) {
String mensajeInterpolado = messageSource.getMessage(
"presupuesto.errores.alto.min_max", // clave del mensaje
new Object[] { min, max }, // parámetros para {0}
LocaleContextHolder.getLocale() // respeta el idioma actual
);
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(mensajeInterpolado)
.addConstraintViolation();
return false;
}
return true;
}
}

View File

@ -40,6 +40,8 @@ public class HomeController {
Map<String, String> translations = translationService.getTranslations(locale, keys);
model.addAttribute("languageBundle", translations);
model.addAttribute("pod", variableService.getValorEntero("POD"));
model.addAttribute("ancho_alto_min", variableService.getValorEntero("ancho_alto_min"));
model.addAttribute("ancho_alto_max", variableService.getValorEntero("ancho_alto_max"));
}
return "imprimelibros/home";
}

View File

@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.imprimelibros.erp.service.PresupuestoService;
import java.util.HashMap;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
@ -33,7 +34,7 @@ public class PresupuestoController {
@PostMapping("/validar/datos-generales")
public ResponseEntity<?> validarDatosGenerales(
@Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto,
BindingResult result) {
BindingResult result, Locale locale) {
Map<String, String> errores = new HashMap<>();
@ -47,7 +48,11 @@ public class PresupuestoController {
return ResponseEntity.badRequest().body(errores);
}
return ResponseEntity.ok().build();
// opciones color
Map<String, Object> resultado = presupuestoService.obtenerOpcionesColor(presupuesto, locale);
// opciones papel interior
resultado.putAll(presupuestoService.obtenerOpcionesPapelInterior(presupuesto, locale));
return ResponseEntity.ok(resultado);
}
}

View File

@ -5,20 +5,30 @@ import jakarta.validation.constraints.NotNull;
import jakarta.persistence.*;
import com.imprimelibros.erp.config.validation.PresupuestoValidationGroups;
import com.imprimelibros.erp.config.validation.Tamanio;
import com.imprimelibros.erp.config.validation.ConsistentTiradas;
import com.imprimelibros.erp.config.validation.Par;
@ConsistentTiradas(groups = PresupuestoValidationGroups.DatosGenerales.class)
@Tamanio(groups = PresupuestoValidationGroups.DatosGenerales.class)
@Entity
@Table(name = "presupuesto")
public class Presupuesto {
public enum TipoImpresion {
fresado, cosido, grapado, espiral, wireo
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Otros campos del presupuesto
@NotNull(message = "{presupuesto.errores.tipo-impresion}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "tipo_impresion")
private TipoImpresion tipoImpresion;
@NotBlank(message = "{presupuesto.errores.titulo}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "titulo")
private String titulo;
@ -42,6 +52,17 @@ public class Presupuesto {
@Column(name = "tirada4")
private Integer tirada4;
@NotNull(message = "{presupuesto.errores.ancho}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "ancho")
private Integer ancho;
@NotNull(message = "{presupuesto.errores.alto}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "alto")
private Integer alto;
@Column(name = "formatoPersonalizado")
private Boolean formatoPersonalizado;
@Par(message = "{presupuesto.errores.paginasNegro.par}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@NotNull(message = "{presupuesto.errores.paginasNegro.required}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "paginas_negro")
@ -56,6 +77,12 @@ public class Presupuesto {
@Column(name = "papel_interior")
private Integer papelInterior;
@Column(name = "posicion_paginas_color")
private String posicionPaginasColor;
@Column(name = "paginas_color_total")
private Integer paginasColorTotal;
// Getters y Setters
@ -111,6 +138,30 @@ public class Presupuesto {
this.tirada4 = tirada4;
}
public Integer getAncho() {
return ancho;
}
public void setAncho(Integer ancho) {
this.ancho = ancho;
}
public Integer getAlto() {
return alto;
}
public void setAlto(Integer alto) {
this.alto = alto;
}
public Boolean getFormatoPersonalizado() {
return formatoPersonalizado;
}
public void setFormatoPersonalizado(Boolean formatoPersonalizado) {
this.formatoPersonalizado = formatoPersonalizado;
}
public String getTitulo() {
return titulo;
}
@ -150,4 +201,30 @@ public class Presupuesto {
public void setPapelInterior(Integer papelInterior) {
this.papelInterior = papelInterior;
}
public TipoImpresion getTipoImpresion() {
return tipoImpresion;
}
public void setTipoImpresion(TipoImpresion tipoImpresion) {
this.tipoImpresion = tipoImpresion;
}
public String getPosicionPaginasColor() {
return posicionPaginasColor;
}
public void setPosicionPaginasColor(String posicionPaginasColor) {
this.posicionPaginasColor = posicionPaginasColor;
}
public Integer getPaginasColorTotal() {
return paginasColorTotal;
}
public void setPaginasColorTotal(Integer paginasColorTotal) {
this.paginasColorTotal = paginasColorTotal;
}
}

View File

@ -1,18 +1,84 @@
package com.imprimelibros.erp.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.imprimelibros.erp.config.Presupuestador.ImagenPresupuesto;
import com.imprimelibros.erp.config.Presupuestador.PresupuestadorItems;
import com.imprimelibros.erp.entity.Presupuesto;
@Service
public class PresupuestoService {
@Autowired
protected VariableService variableService;
private final PresupuestadorItems presupuestadorItems;
public PresupuestoService(PresupuestadorItems presupuestadorItems) {
this.presupuestadorItems = presupuestadorItems;
}
public boolean validateDatosGenerales(int[] tiradas) {
// Implement the logic to validate the tiradas
// For example, check if all tiradas are positive integers
for (int tirada : tiradas) {
if (tirada <= 0) {
return false; // Invalid tirada found
}
}
return true; // All tiradas are valid
return true;
}
public Boolean isPOD(Presupuesto presupuesto){
int pod_value = variableService.getValorEntero("POD");
return (presupuesto.getTirada1() != null && presupuesto.getTirada1() <= pod_value) ||
(presupuesto.getTirada2() != null && presupuesto.getTirada2() <= pod_value) ||
(presupuesto.getTirada3() != null && presupuesto.getTirada3() <= pod_value) ||
(presupuesto.getTirada4() != null && presupuesto.getTirada4() <= pod_value);
}
public Map<String, Object> obtenerOpcionesColor(Presupuesto presupuesto, Locale locale) {
List<ImagenPresupuesto> opciones = new ArrayList<>();
if (presupuesto.getPaginasColor() > 0) {
if (!this.isPOD(presupuesto)) {
// POD solo color foto
opciones.add(this.presupuestadorItems.getImpresionColor(locale));
}
opciones.add(this.presupuestadorItems.getImpresionColorPremium(locale));
} else {
opciones.add(this.presupuestadorItems.getImpresionNegro(locale));
opciones.add(this.presupuestadorItems.getImpresionNegroPremium(locale));
}
Map<String, Object> response = new HashMap<>();
response.put("opciones_color", opciones);
return response;
}
public Map<String, Object> obtenerOpcionesPapelInterior(Presupuesto presupuesto, Locale locale) {
List<ImagenPresupuesto> opciones = new ArrayList<>();
opciones.add(this.presupuestadorItems.getPapelOffsetBlanco(locale));
opciones.add(this.presupuestadorItems.getPapelOffsetAhuesado(locale));
opciones.add(this.presupuestadorItems.getPapelOffsetAhuesadoVolumen(locale));
opciones.add(this.presupuestadorItems.getPapelEstucadoMate(locale));
Map<String, Object> response = new HashMap<>();
response.put("opciones_papel_interior", opciones);
return response;
}
}

View File

@ -19,11 +19,13 @@ presupuesto.orientacion.vertical=Vertical
presupuesto.orientacion.apaisado=Apaisado
presupuesto.orientacion.cuadrado=Cuadrado
presupuesto.formato-personalizado=Formato personalizado
presupuesto.ancho=Ancho
presupuesto.alto=Alto
presupuesto.ancho=Ancho (mm)*
presupuesto.alto=Alto (mm)*
presupuesto.paginas-total=Total Páginas
presupuesto.paginas-negro=Páginas Negro
presupuesto.paginas-color=Páginas Color
presupuesto.paginas-posicion=Posición páginas color
presupuesto.paginas-posicion-descripcion=Intruzca la posición separada por comas. Ej: 3,5,7 ó 4-10,20,155
presupuesto.siempre-pares=Siempre deben ser pares
presupuesto.encuadernacion=Encuadernación
presupuesto.fresado-descripcion=Fresado (a partir de 32 páginas)
@ -92,4 +94,9 @@ presupuesto.errores.tiradas.consistentes=Las tiradas deben ser consistentes (no
presupuesto.errores.paginasNegro.required=El número de páginas en negro es obligatorio
presupuesto.errores.paginasNegro.par=El número de páginas en negro debe ser par
presupuesto.errores.paginasColor.required=El número de páginas en color es obligatorio
presupuesto.errores.paginasColor.par=El número de páginas en color debe ser par
presupuesto.errores.paginasColor.par=El número de páginas en color debe ser par
presupuesto.errores.tipo-impresion=Seleccione el tipo de libro
presupuesto.errores.ancho=El ancho no puede estar vacío
presupuesto.errores.ancho.min_max=El ancho tiene que estar en el rango [{0}, {1}] mm;
presupuesto.errores.alto=El alto no puede estar vacío
presupuesto.errores.alto.min_max=El alto tiene que estar en el rango [{0}, {1}] mm

View File

@ -7,8 +7,98 @@ Website: https://themesbrand.com/
Contact: support@themesbrand.com
File: Main Css File
*/
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Public+Sans:wght@300;400;500;600;700&display=swap");
/* poppins-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Poppins';
font-style: normal;
font-weight: 300;
src: url('../fonts/poppins/poppins-v23-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* poppins-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
src: url('../fonts/poppins/poppins-v23-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* poppins-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Poppins';
font-style: normal;
font-weight: 500;
src: url('../fonts/poppins/poppins-v23-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* poppins-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Poppins';
font-style: normal;
font-weight: 600;
src: url('../fonts/poppins/poppins-v23-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* poppins-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Poppins';
font-style: normal;
font-weight: 700;
src: url('../fonts/poppins/poppins-v23-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* public-sans-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Public Sans';
font-style: normal;
font-weight: 300;
src: url('../fonts/public-sans/public-sans-v20-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* public-sans-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Public Sans';
font-style: normal;
font-weight: 400;
src: url('../fonts/public-sans/public-sans-v20-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* public-sans-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Public Sans';
font-style: normal;
font-weight: 500;
src: url('../fonts/public-sans/public-sans-v20-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* public-sans-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Public Sans';
font-style: normal;
font-weight: 600;
src: url('../fonts/public-sans/public-sans-v20-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* public-sans-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Public Sans';
font-style: normal;
font-weight: 700;
src: url('../fonts/public-sans/public-sans-v20-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
@font-face {
font-family: "hkgrotesk";
src: url("../fonts/hkgrotesk-light.eot");

File diff suppressed because one or more lines are too long

View File

@ -70,4 +70,26 @@
min-height: 70px; /* Alto mínimo */
max-width: 70px; /* Ancho máximo */
max-height: 70px; /* Alto máximo */
}
@keyframes fadeInUpBounce {
0% {
opacity: 0;
transform: translateY(30px);
}
60% {
opacity: 1;
transform: translateY(-10px);
}
80% {
transform: translateY(5px);
}
100% {
transform: translateY(0);
}
}
.animate-fadeInUpBounce {
animation: fadeInUpBounce 0.6s ease-out both;
animation-delay: 0.1s;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

View File

@ -1,23 +1,65 @@
$(() => {
$('.imagen-container-group').on('click', '.imagen-selector', function () {
const clicked = $(this);
const group = clicked.closest('.imagen-container-group');
class imagen_presupuesto {
// Limpiar selección anterior
group.find('.imagen-selector').removeClass('selected preselected')
.find('.image-presupuesto').removeClass('selected');
constructor(data) {
this.id = data.id;
this.imagen = data.imagen;
this.alt = data.alt || "";
this.group = data.group || ""; // Grupo al que pertenece el radio
this.texto = data.texto || ""; // Texto de la etiqueta
this.selected = data.selected || false;
this.extraClass = data.extraClass + " " || "";
this.extraData = data.extra_data || {}; // Datos extra opcionales
}
// Marcar nuevo seleccionado
clicked.addClass('selected');
const img = clicked.find('.image-presupuesto');
img.addClass('selected');
render() {
const contenedor = $('<div>', {
id: this.id,
class: `${this.extraClass}image-container imagen-selector${this.selected ? ' selected' : ''}`
});
// Añadir atributos extra al contenedor
for (const [key, value] of Object.entries(this.extraData)) {
contenedor.attr(`data-${key}`, value);
}
// Aplicar animación (reset antes para que se repita)
img.removeClass('zoom-anim');
void img[0].offsetWidth; // "reflow" para reiniciar animación
img.addClass('zoom-anim');
const input = $('<input>', {
type: 'radio',
name: this.group,
value: this.id,
hidden: true
});
// Guardar ID en hidden si lo necesitas
$('#tipoEncuadernacionSeleccionada').val(clicked.attr('id'));
});
});
const imagen = $('<img>', {
class: 'image-presupuesto',
id: this.id + '-img',
src: this.imagen,
alt: this.alt
});
const etiqueta = $('<label>', {
for: this.id + '-img',
class: 'form-label',
text: this.texto
});
contenedor.append(imagen, etiqueta);
return contenedor;
}
setSelected(selected) {
this.selected = selected;
const contenedor = $(`#${this.id}`);
const radio = contenedor.find('input[type="radio"]');
if (selected) {
contenedor.addClass('selected');
radio.prop('checked', true).trigger('change'); // <-- esto actualiza el input y lanza evento
} else {
contenedor.removeClass('selected');
radio.prop('checked', false);
}
}
}
export default imagen_presupuesto;

View File

@ -0,0 +1,22 @@
$('.imagen-container-group').on('click', '.image-container', function () {
const clicked = $(this);
const group = clicked.closest('.imagen-container-group');
// Limpiar selección anterior
group.find('.image-container').removeClass('selected')
.find('.image-presupuesto').removeClass('zoom-anim');
// Marcar nuevo seleccionado
clicked.addClass('selected');
// Aplicar animación de zoom
const img = clicked.find('.image-presupuesto');
void img[0].offsetWidth; // Forzar reflow
img.addClass('zoom-anim');
// Guardar selección en hidden
$('#tipoEncuadernacionSeleccionada').val(clicked.attr('id'));
clicked.find('input[type="radio"]').prop('checked', true).trigger('change');
});

View File

@ -1,8 +1,38 @@
import imagen_presupuesto from "./imagen-presupuesto.js";
class PresupuestoCliente {
constructor() {
this.DEBUG = true; // Activar o desactivar el modo de depuración
this.formData = {
datosGenerales: {
titulo: '',
autor: '',
isbn: '',
tirada1: '',
tirada2: '',
tirada3: '',
tirada4: '',
ancho: '',
alto: '',
formatoPersonalizado: false,
paginasNegro: '',
paginasColor: '',
posicionPaginasColor: '',
tipoImpresion: 'fresado',
},
interior: {
color: '',
papel: '',
gramaje: '',
},/*
cubierta: {},*/
}
// pestaña datos generales
this.divContentDatosGenerales = $('#content-datos-generales');
this.titulo = $('#titulo');
this.autor = $('#autor');
this.isbn = $('#isbn');
@ -10,25 +40,318 @@ class PresupuestoCliente {
this.tirada2 = $('#tirada2');
this.tirada3 = $('#tirada3');
this.tirada4 = $('#tirada4');
this.formatoPersonalizado = $('#formato-personalizado');
this.divFormato = $('.div-formato');
this.divFormatoPersonalizado = $('.div-formato-personalizado');
this.formato = $('#formato');
this.ancho = $('#ancho');
this.alto = $('#alto');
this.paginasNegro = $('#paginas-negro');
this.paginasColor = $('#paginas-color')
this.paginasColor = $('#paginas-color');
this.divPosicionPaginasColor = $('#div-posicion-paginas-color');
this.posicionPaginasColor = $('#posicionPaginasColor');
this.paginas = $('#paginas');
this.btn_next_datos_generales = $('#next-datos-generales');
this.datos_generales_alert = $('#datos-generales-alert');
// pestaña interior
this.divContentInterior = $('#content-interior');
this.divOpcionesColor = $('#div-opciones-color');
this.divPapelInterior = $('#div-papel-interior');
// pestaña cubierta
this.btn_plantilla_cubierta = $('#btn-plantilla-cubierta');
this.btn_impresion_cubierta_help = $('#impresion-cubierta-help');
}
init() {
this.initButtonsEventListeners();
this.#initDatosGenerales();
this.#initCubierta();
const stored = sessionStorage.getItem("formData");
if (stored) {
this.formData = JSON.parse(stored);
this.#loadDatosGeneralesData();
}
}
initButtonsEventListeners() {
#cacheFormData() {
sessionStorage.setItem("formData", JSON.stringify(this.formData));
}
#changeTab(idContenidoTab) {
const tabButton = document.querySelector(`[data-bs-target="#${idContenidoTab}"]`);
if (tabButton) {
const tab = new bootstrap.Tab(tabButton);
tab.show();
}
}
/******************************
* END OF DATOS GENERALES
******************************/
#initDatosGenerales() {
$('.datos-generales-data').on('change', () => {
const dataToStore = this.#getDatosGeneralesData();
this.#updateDatosGeneralesData(dataToStore);
this.#cacheFormData();
});
$('.paginas').on('change', () => {
this.paginas.val(parseInt(this.paginasNegro.val()) + parseInt(this.paginasColor.val()));
if (parseInt(this.paginasColor.val()) == 0) {
this.divPosicionPaginasColor.addClass('d-none');
this.posicionPaginasColor.val("");
}
else {
this.divPosicionPaginasColor.removeClass('d-none');
}
this.#updateTipoImpresion();
});
this.formatoPersonalizado.on('change', () => {
if (this.formatoPersonalizado.is(':checked')) {
this.divFormato.addClass('d-none');
this.divFormatoPersonalizado.removeClass('d-none');
}
else {
this.divFormatoPersonalizado.addClass('d-none');
this.divFormato.removeClass('d-none');
}
});
this.btn_next_datos_generales.on('click', () => {
this.#nextDatosGenerales();
});
}
#nextDatosGenerales() {
const data = this.#getDatosGeneralesData();
$.ajax({
url: '/presupuesto/validar/datos-generales',
type: 'POST',
data: data,
success: (data) => {
this.#processDatosGenerales(data);
},
error: (xhr, status, error) => {
this.datos_generales_alert.removeClass('d-none');
this.datos_generales_alert.find('#datos-generales-alert-list').empty();
const errors = xhr.responseJSON;
if (errors && typeof errors === 'object') {
if (!this.DEBUG && xhr.responseJSON.error && xhr.responseJSON.error == 'Internal Server Error') {
console.error("Error al validar los datos generales. Internal Server Error");
return;
}
Object.values(errors).forEach(errorMsg => {
this.datos_generales_alert.find('#datos-generales-alert-list').append(`<li>${errorMsg}</li>`);
});
} else {
this.datos_generales_alert.find('#datos-generales-alert-list').append('<li>Error desconocido. Por favor, inténtelo de nuevo más tarde.</li>');
}
$(window).scrollTop(0);
}
});
}
#processDatosGenerales(data) {
this.datos_generales_alert.addClass('d-none');
this.#loadInteriorData(data);
this.#changeTab('pills-inside');
this.divContentInterior.addClass('animate-fadeInUpBounce');
}
#getDatosGeneralesData() {
const tamanio = this.#getTamanio();
return {
titulo: this.titulo.val(),
autor: this.autor.val(),
isbn: this.isbn.val(),
tirada1: this.tirada1.val(),
tirada2: this.tirada2.val(),
tirada3: this.tirada3.val(),
tirada4: this.tirada4.val(),
formatoPersonalizado: this.formatoPersonalizado.is(':checked'),
ancho: parseInt(tamanio.ancho),
alto: parseInt(tamanio.alto),
paginasNegro: this.paginasNegro.val(),
paginasColor: this.paginasColor.val(),
posicionPaginasColor: this.posicionPaginasColor.val(),
tipoImpresion: ($('.tipo-libro.selected').length > 0) ? $('.tipo-libro.selected').attr('id') : 'fresado',
};
}
#updateDatosGeneralesData(data) {
this.formData.datosGenerales = {
titulo: data.titulo,
autor: data.autor,
isbn: data.isbn,
tirada1: data.tirada1,
tirada2: data.tirada2,
tirada3: data.tirada3,
tirada4: data.tirada4,
formatoPersonalizado: data.formatoPersonalizado,
ancho: parseInt(data.ancho),
alto: parseInt(data.alto),
paginasNegro: data.paginasNegro,
paginasColor: data.paginasColor,
posicionPaginasColor: data.posicionPaginasColor,
tipoImpresion: data.tipoImpresion,
};
}
#loadDatosGeneralesData() {
this.titulo.val(this.formData.datosGenerales.titulo);
this.autor.val(this.formData.datosGenerales.autor);
this.isbn.val(this.formData.datosGenerales.isbn);
this.tirada1.val(this.formData.datosGenerales.tirada1);
this.tirada2.val(this.formData.datosGenerales.tirada2);
this.tirada3.val(this.formData.datosGenerales.tirada3);
this.tirada4.val(this.formData.datosGenerales.tirada4);
this.paginasNegro.val(this.formData.datosGenerales.paginasNegro);
this.paginasColor.val(this.formData.datosGenerales.paginasColor);
this.posicionPaginasColor.val(this.formData.datosGenerales.posicionPaginasColor);
$('.tipo-libro').removeClass('selected');
$('.image-container#' + this.formData.datosGenerales.tipoImpresion).trigger('click');
this.#updateTipoImpresion();
this.formatoPersonalizado.prop('checked', this.formData.datosGenerales.formatoPersonalizado).trigger('change');
$('.paginas').trigger('change');
if (this.formatoPersonalizado.is(':checked')) {
this.ancho.val(this.formData.datosGenerales.ancho);
this.alto.val(this.formData.datosGenerales.alto);
} else {
const option = this.formato.find('option').filter(() => {
return $(this).data('ancho') == this.formData.datosGenerales.ancho &&
$(this).data('alto') == this.formData.datosGenerales.alto;
});
if (option.length) {
this.formato.val(option.val()).trigger('change');
}
}
}
#getTamanio() {
if (this.formatoPersonalizado.is(':checked')) {
return {
ancho: this.ancho.val(),
alto: this.alto.val()
};
}
else {
const opcionSeleccionada = $('#formato option:selected');
const ancho = opcionSeleccionada.data('ancho');
const alto = opcionSeleccionada.data('alto');
return {
ancho: ancho,
alto: alto
};
}
}
#updateTipoImpresion() {
const paginas = parseInt(this.paginas.val());
const selectedTipo = $('.tipo-libro.selected').attr('id');
$('.tipo-libro').removeClass('selected');
if (paginas < 32) {
$('.tipo-libro#fresado').addClass('d-none');
$('.tipo-libro#cosido').addClass('d-none');
}
if (paginas < 20) {
$('.tipo-libro#espiral').addClass('d-none');
$('.tipo-libro#wireo').addClass('d-none');
}
if (paginas < 12 || paginas > 40) {
$('.tipo-libro#grapado').addClass('d-none');
}
if (selectedTipo && $('.tipo-libro#' + selectedTipo).length > 0 && !$('.tipo-libro#' + selectedTipo).hasClass('d-none')) {
$('.tipo-libro#' + selectedTipo).addClass('selected');
}
else {
let firstVisible = $('.tipo-libro').not('.d-none').first();
if (firstVisible.length) {
firstVisible.addClass('selected');
}
}
if ($('.tipo-libro.selected').length > 0) {
this.formData.datosGenerales.tipoImpresion = $('.tipo-libro.selected').attr('id');
}
else {
this.formData.datosGenerales.tipoImpresion = '';
}
}
/******************************
* END OF DATOS GENERALES
******************************/
/******************************
* INTERIOR
******************************/
#loadInteriorData(data) {
this.divOpcionesColor.empty();
this.divPapelInterior.empty();
const opciones_color = data.opciones_color;
for (let i = 0; i < opciones_color.length; i++) {
const opcion = opciones_color[i];
const item = new imagen_presupuesto(opcion);
if ((this.formData.interior.color === '' && i === 0) ||
this.formData.interior.color === opcion.color) {
item.setSelected(true);
}
this.divOpcionesColor.append(item.render());
}
const opciones_papel_interior = data.opciones_papel_interior;
for (let i = 0; i < opciones_papel_interior.length; i++) {
const opcion = opciones_papel_interior[i];
const item = new imagen_presupuesto(opcion);
if ((this.formData.interior.papel === '' && i === 0) ||
this.formData.interior.papel === opcion.papel) {
item.setSelected(true);
}
this.divPapelInterior.append(item.render());
}
}
/******************************
* END INTERIOR
******************************/
/******************************
* CUBIERTA
******************************/
#initCubierta() {
this.btn_plantilla_cubierta.on('click', () => {
Swal.fire({
@ -60,48 +383,10 @@ class PresupuestoCliente {
showCloseButton: true
});
});
this.btn_next_datos_generales.on('click', () => {
this.nextDatosGenerales();
});
}
nextDatosGenerales() {
const data = {
titulo: this.titulo.val(),
autor: this.autor.val(),
isbn: this.isbn.val(),
tirada1: this.tirada1.val(),
tirada2: this.tirada2.val(),
tirada3: this.tirada3.val(),
tirada4: this.tirada4.val(),
paginasNegro: this.paginasNegro.val(),
paginasColor: this.paginasColor.val()
}
$.ajax({
url: '/presupuesto/validar/datos-generales',
type: 'POST',
data: data,
success: (response) => {
this.datos_generales_alert.addClass('d-none');
},
error: (xhr, status, error) => {
this.datos_generales_alert.removeClass('d-none');
this.datos_generales_alert.find('#datos-generales-alert-list').empty();
const errors = xhr.responseJSON;
if (errors && typeof errors === 'object') {
Object.values(errors).forEach(errorMsg => {
this.datos_generales_alert.find('#datos-generales-alert-list').append(`<li>${errorMsg}</li>`);
});
} else {
this.datos_generales_alert.find('#datos-generales-alert-list').append('<li>Error desconocido. Por favor, inténtelo de nuevo más tarde.</li>');
}
$(window).scrollTop(0);
}
});
}
/******************************
* END CUBIERTA
******************************/
}

View File

@ -2,7 +2,7 @@
const head = document.head || document.getElementsByTagName("head")[0];
const scripts = [
"https://cdn.jsdelivr.net/npm/toastify-js",
"/assets/libs/toastify-js/src/toastify.js",
"/assets/libs/choices.js/public/assets/scripts/choices.min.js",
"/assets/libs/flatpickr/flatpickr.min.js",
"/assets/libs/feather-icons/feather.min.js" // <- AÑADIMOS feather aquí

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -34,8 +34,8 @@
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
<th:block layout:fragment="pagejs">
<div th:unless="${#authorization.expression('isAuthenticated()')}">
<script th:src="@{/assets/js/pages/imprimelibros/presupuestador/imagen-presupuesto.js}"></script>
<script th:src="@{/assets/js/pages/imprimelibros/presupuestador/presupuestador.js}"></script>
<script th:src="@{/assets/js/pages/imprimelibros/presupuestador/imagen-selector.js}"></script>
<script type="module" th:src="@{/assets/js/pages/imprimelibros/presupuestador/presupuestador.js}"></script>
</div>
<script th:inline="javascript">
window.languageBundle = /*[[${languageBundle}]]*/ {};

View File

@ -7,7 +7,7 @@
<th:block layout:fragment="pagetitle" />
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
<link href="/assets/libs/sweetalert2/sweetalert2.min.css" rel="stylesheet" type="text/css" />
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="/assets/libs/select2/select2.min.css" rel="stylesheet" />
<th:block layout:fragment="pagecss" />
</head>
@ -28,9 +28,9 @@
<th:block layout:fragment="modal" />
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="/assets/libs/jquery/jquery-3.6.0.min.js"></script>
<script src="/assets/libs/sweetalert2/sweetalert2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="/assets/libs/select2/select2.min.js"></script>
<th:block layout:fragment="pagejs" />
<script th:src="@{/assets/js/app.js}"></script>
<script th:src="@{/assets/js/pages/imprimelibros/languageBundle.js}"></script>

View File

@ -22,7 +22,7 @@
<div class="ribbon-content mt-4">
<div class="row justify-content-center imagen-container-group">
<div id="tapa-blanda" class="image-container imagen-selector selected">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/tapa-blanda.jpg"
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/tapa-blanda.png"
alt="">
<label for="titulo" class="form-label" th:text="#{presupuesto.tapa-blanda}">
Tapa blanda
@ -31,7 +31,7 @@
<div id="tapa-dura" class="image-container imagen-selector">
<img class="image-presupuesto"
src="/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-recto.jpg" alt="">
src="/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-recto.png" alt="">
<label class="form-label" th:text="#{presupuesto.tapa-dura}">
Tapa dura
</label>
@ -39,7 +39,7 @@
<div id="tapa-dura-lomo-redondo" class="image-container imagen-selector">
<img class="image-presupuesto"
src="/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-redondo.jpg" alt="">
src="/assets/images/imprimelibros/presupuestador/tapa-dura-lomo-redondo.png" alt="">
<label class="form-label" th:text="#{presupuesto.tapa-dura-lomo-redondo}">
Tapa dura lomo redondo
</label>

View File

@ -1,4 +1,4 @@
<div>
<div id="content-datos-generales" class="animate-fadeInUpBounce">
<!-- Ribbon Shape -->
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow">
<div class="card-body">
@ -23,7 +23,7 @@
<div class="mb-3">
<label for="titulo" class="form-label" th:text="#{presupuesto.titulo}">
>Título*</label>
<input type="text" class="form-control" id="titulo" placeholder="" value="">
<input type="text" class="form-control datos-generales-data" id="titulo" placeholder="" value="">
</div>
</div>
</div>
@ -32,13 +32,13 @@
<div class="col-sm-6">
<div class="mb-3">
<label for="autor" class="form-label" th:text="#{presupuesto.autor}">Autor</label>
<input type="text" class="form-control" id="autor" value="">
<input type="text" class="form-control datos-generales-data" id="autor" value="">
</div>
</div>
<div class="col-sm-6">
<div class="mb-3">
<label for="isbn" class="form-label" th:text="#{presupuesto.isbn}">ISBN</label>
<input type="text" class="form-control" id="isbn" value="">
<input type="text" class="form-control datos-generales-data" id="isbn" value="">
</div>
</div>
</div>
@ -47,19 +47,19 @@
<div class="row">
<div class="col-sm-3 mb-1">
<label for="tirada1" class="form-label" th:text="#{presupuesto.tirada1}">Tirada 1*</label>
<input type="number" class="form-control" id="tirada1" placeholder="" value="10">
<input type="number" class="form-control datos-generales-data" id="tirada1" placeholder="" value="10">
</div>
<div class="col-sm-3 mb-1">
<label for="tirada2" class="form-label" th:text="#{presupuesto.tirada2}">Tirada 2</label>
<input type="number" class="form-control" id="tirada2" placeholder="" value="">
<input type="number" class="form-control datos-generales-data" id="tirada2" placeholder="" value="">
</div>
<div class="col-sm-3 mb-1">
<label for="tirada3" class="form-label" th:text="#{presupuesto.tirada3}">Tirada 3</label>
<input type="number" class="form-control" id="tirada3" placeholder="" value="">
<input type="number" class="form-control datos-generales-data" id="tirada3" placeholder="" value="">
</div>
<div class="col-sm-3 mb-1">
<label for="tirada4" class="form-label" th:text="#{presupuesto.tirada4}">Tirada 4</label>
<input type="number" class="form-control" id="tirada4" placeholder="" value="">
<input type="number" class="form-control datos-generales-data" id="tirada4" placeholder="" value="">
</div>
</div>
<p class="text-muted" th:text="#{presupuesto.tiradasPODnoPOD(${pod})}">
@ -68,46 +68,65 @@
</div>
<div class="row justify-content-center">
<div class="col-sm-4">
<div class="mb-3">
<label for="formato" class="form-label" th:text="#{presupuesto.formato}">Formato</label>
<select class="form-select select2" id="formato">
<optgroup th:label="#{presupuesto.orientacion.vertical}">
<option value="148x210">148x210 (A5)</option>
<option value="115x170">115x170</option>
<option value="210x297">210x297 (A4)</option>
</optgroup>
<optgroup th:label="#{presupuesto.orientacion.cuadrado}">
<option value="210x210">210x210</option>
<option value="230x230">230x230</option>
</optgroup>
<optgroup th:label="#{presupuesto.orientacion.apaisado}">
<option value="210x148">210x148 (A5)</option>
<option value="240x170">240x170</option>
<option value="297x210">297x210 (A4)</option>
</optgroup>
</select>
<div class="col-sm-8">
</div>
<div class="mb-3">
<div class="form-check form-switch form-switch-custom form-switch-primary mb-3">
<input type="checkbox" class="form-check-input form-switch-custom-primary"
id="formato-personalizado" name="formato-personalizado">
<label for="formato-personalizado" class="form-label"
th:text="#{presupuesto.formato-personalizado}">Formato
Personalizado</label>
<div class="row justify-content-center">
<div class="col-sm-4 mb-3 div-formato">
<label for="formato" class="form-label" th:text="#{presupuesto.formato}">Formato</label>
<select class="form-select select2 datos-generales-data" id="formato">
<optgroup th:label="#{presupuesto.orientacion.vertical}">
<option data-ancho="148" data-alto="210" value="148x210">148x210 (A5)</option>
<option data-ancho="120" data-alto="170" value="120x170">120x170</option>
<option data-ancho="210" data-alto="297" value="210x297">210x297 (A4)</option>
</optgroup>
<optgroup th:label="#{presupuesto.orientacion.cuadrado}">
<option data-ancho="210" data-alto="210" value="210x210">210x210</option>
<option data-ancho="230" data-alto="230" value="230x230">230x230</option>
</optgroup>
<optgroup th:label="#{presupuesto.orientacion.apaisado}">
<option data-ancho="210" data-alto="148" value="210x148">210x148 (A5)</option>
<option data-ancho="240" data-alto="170" value="240x170">240x170</option>
<option data-ancho="297" data-alto="210" value="297x210">297x210 (A4)</option>
</optgroup>
</select>
</div>
</div>
<div class="row justify-content-center div-formato-personalizado d-none">
<div class="col-3 col-sm-3 mb-1">
<label for="ancho" class="form-label" th:text="#{presupuesto.ancho}">Ancho (mm)</label>
<input type="number" class="form-control datos-generales-data" id="ancho" name="ancho" value="210"
th:attr="min=${ancho_alto_min}, max=${ancho_alto_max}">
</div>
<div class="col-3 col-sm-3 mb-1">
<label for="alto" class="form-label" th:text="#{presupuesto.alto}">Alto (mm)</label>
<input type="number" class="form-control datos-generales-data" id="alto" name="alto" value="297"
th:attr="min=${ancho_alto_min}, max=${ancho_alto_max}">
</div>
</div>
<div class="row justify-content-center mb-3">
<div class="col-sm-4 d-flex justify-content-center">
<div class="form-check form-switch form-switch-custom form-switch-primary mb-3">
<input type="checkbox" class="form-check-input form-switch-custom-primary datos-generales-data"
id="formato-personalizado" name="formato-personalizado">
<label for="formato-personalizado" class="form-label"
th:text="#{presupuesto.formato-personalizado}">
Formato Personalizado
</label>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center mb-2">
<div class="col-sm-2">
<label for="paginas-negro" class="form-label" th:text="#{presupuesto.paginas-negro}">Páginas
Negro</label>
<input type="number" step="2" class="form-control" id="paginas-negro" name="paginas-negro"
value="0">
<input type="number" step="2" class="form-control paginas datos-generales-data" id="paginas-negro"
name="paginas-negro" value="0">
<div class="form-text" th:text="#{presupuesto.siempre-pares}">
Siempre deben ser pares</div>
</div>
@ -119,8 +138,8 @@
<div class="col-sm-2">
<label for="paginas-color" class="form-label" th:text="#{presupuesto.paginas-color}">Páginas
Color</label>
<input type="number" step="2" class="form-control" id="paginas-color" name="paginas-color"
value="32">
<input type="number" step="2" class="form-control paginas datos-generales-data" id="paginas-color"
name="paginas-color" value="32">
<div class="form-text" th:text="#{presupuesto.siempre-pares}">
Siempre deben ser pares</div>
</div>
@ -135,6 +154,21 @@
<input disabled class="form-control" id="paginas" name="paginas" value="32">
</div>
</div>
<div id="div-posicion-paginas-color" class="row justify-content-center">
<div class="col-sm-9">
<label for="posicionPaginasColor" class="form-label" th:text="#{presupuesto.paginas-posicion}">
Posición páginas color
</label>
<input class="form-control datos-generales-data" id="posicionPaginasColor" value="">
<div class="form-text">
<p th:text="#{presupuesto.paginas-posicion-descripcion}">
Intruzca la posición separada por comas. Ej: 3,5,7 ó 4-10,20,155
</p>
</div>
</div>
</div>
</div>
</div>
@ -152,56 +186,53 @@
<div class="ribbon-content mt-4">
<div class="px-2">
<div class="row justify-content-center imagen-container-group">
<div class="d-flex flex-wrap justify-content-center gap-3 imagen-container-group">
<!-- Opción: Fresado -->
<div class="col-12 col-sm-6 col-md-4 d-flex justify-content-center mb-4">
<div class="image-container imagen-selector selected" id="fresado">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/fresado.png"
alt="Fresado" />
<div class="form-text text-center" th:text="#{presupuesto.fresado-descripcion}">
Fresado (a partir de 32 páginas)</div>
</div>
<div class="tipo-libro image-container imagen-selector selected datos-generales-data" id="fresado">
<input type="radio" name="tipoEncuadernacion" value="fresado" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/fresado.png"
alt="Fresado" />
<div class="form-text text-center" th:text="#{presupuesto.fresado-descripcion}">
Fresado (a partir de 32 páginas)</div>
</div>
<!-- Opción: Cosido -->
<div class="col-12 col-sm-6 col-md-4 d-flex justify-content-center mb-4">
<div class="image-container imagen-selector" id="cosido">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/cosido.png"
alt="Cosido" />
<div class="form-text text-center" th:text="#{presupuesto.cosido-descripcion}">
Cosido (a partir de 32 páginas)</div>
</div>
<div class="tipo-libro image-container imagen-selector datos-generales-data" id="cosido">
<input type="radio" name="tipoEncuadernacion" value="cosido" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/cosido.png"
alt="Cosido" />
<div class="form-text text-center" th:text="#{presupuesto.cosido-descripcion}">
Cosido (a partir de 32 páginas)</div>
</div>
<!-- Opción: Grapado -->
<div class="col-12 col-sm-6 col-md-4 d-flex justify-content-center mb-4">
<div class="image-container imagen-selector" id="grapado">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/grapado.png"
alt="Grapado" />
<div class="form-text text-center" th:text="#{presupuesto.grapado-descripcion}">
Grapado (entre 12 y 40 páginas)</div>
</div>
<div class="tipo-libro image-container imagen-selector datos-generales-data" id="grapado">
<input type="radio" name="tipoEncuadernacion" value="grapado" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/grapado.png"
alt="Grapado" />
<div class="form-text text-center" th:text="#{presupuesto.grapado-descripcion}">
Grapado (entre 12 y 40 páginas)</div>
</div>
<!-- Opción: Espiral -->
<div class="col-12 col-sm-6 col-md-4 d-flex justify-content-center mb-4">
<div class="image-container imagen-selector" id="espiral">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/espiral.png"
alt="Espiral" />
<div class="form-text text-center" th:text="#{presupuesto.espiral-descripcion}">
Espiral (a partir de 20 páginas)</div>
</div>
<div class="tipo-libro image-container imagen-selector datos-generales-data" id="espiral">
<input type="radio" name="tipoEncuadernacion" value="espiral" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/espiral.png"
alt="Espiral" />
<div class="form-text text-center" th:text="#{presupuesto.espiral-descripcion}">
Espiral (a partir de 20 páginas)</div>
</div>
<!-- Opción: Wire-O -->
<div class="col-12 col-sm-6 col-md-4 d-flex justify-content-center mb-4">
<div class="image-container imagen-selector" id="wireo">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/wire-o.png"
alt="Wire-O" />
<div class="form-text text-center" th:text="#{presupuesto.wire-o-descripcion}">
Wire-O (a partir de 20 páginas)</div>
</div>
<div class="tipo-libro image-container imagen-selector datos-generales-data" id="wireo">
<input type="radio" name="tipoEncuadernacion" value="wireo" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/wire-o.png"
alt="Wire-O" />
<div class="form-text text-center" th:text="#{presupuesto.wire-o-descripcion}">
Wire-O (a partir de 20 páginas)</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
<div>
<div id="content-interior">
<!-- Ribbon Shape -->
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow">
<div class="card-body">
@ -9,38 +9,8 @@
</div>
<div class="ribbon-content mt-4">
<div class="row justify-content-center imagen-container-group">
<div id="negroEstandar" class="image-container imagen-selector selected">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/blancoYnegro.png"
alt="Negro">
<label for="titulo" class="form-label" th:text="#{presupuesto.blanco-negro}">
Blanco y Negro
</label>
</div>
<div id="negroPremium" class="image-container imagen-selector">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/negroFoto.png"
alt="NegroPremium">
<label class="form-label" th:text="#{presupuesto.blanco-negro-premium}">
Blanco y Negro Premium
</label>
</div>
<div id="colorEstandar" class="image-container imagen-selector">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/color.png"
alt="Color">
<label class="form-label" th:text="#{presupuesto.color}">
Color
</label>
</div>
<div id="colorPremium" class="image-container imagen-selector">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/colorFoto.png"
alt="ColorPremium">
<label class="form-label" th:text="#{presupuesto.color-premium}">
Color Premium
</label>
</div>
<div id="div-opciones-color" class="row justify-content-center imagen-container-group">
</div>
</div>
</div>
@ -56,7 +26,8 @@
<div class="ribbon-content mt-4">
<div class="row justify-content-center imagen-container-group">
<div id="div-papel-interior" class="row justify-content-center imagen-container-group">
<div id="offset-blanco" data-sk-id="3" class="image-container imagen-selector selected">
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/offset-blanco.png"
alt="">