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; continue;
if (t <= podValue) if (t <= podValue)
allAbove = false; allAbove = false;
if (t >= podValue) else // (t > podValue)
allBelow = false; 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); Map<String, String> translations = translationService.getTranslations(locale, keys);
model.addAttribute("languageBundle", translations); model.addAttribute("languageBundle", translations);
model.addAttribute("pod", variableService.getValorEntero("POD")); 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"; return "imprimelibros/home";
} }

View File

@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.imprimelibros.erp.service.PresupuestoService; import com.imprimelibros.erp.service.PresupuestoService;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -33,7 +34,7 @@ public class PresupuestoController {
@PostMapping("/validar/datos-generales") @PostMapping("/validar/datos-generales")
public ResponseEntity<?> validarDatosGenerales( public ResponseEntity<?> validarDatosGenerales(
@Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto, @Validated(PresupuestoValidationGroups.DatosGenerales.class) Presupuesto presupuesto,
BindingResult result) { BindingResult result, Locale locale) {
Map<String, String> errores = new HashMap<>(); Map<String, String> errores = new HashMap<>();
@ -47,7 +48,11 @@ public class PresupuestoController {
return ResponseEntity.badRequest().body(errores); 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 jakarta.persistence.*;
import com.imprimelibros.erp.config.validation.PresupuestoValidationGroups; 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.ConsistentTiradas;
import com.imprimelibros.erp.config.validation.Par; import com.imprimelibros.erp.config.validation.Par;
@ConsistentTiradas(groups = PresupuestoValidationGroups.DatosGenerales.class) @ConsistentTiradas(groups = PresupuestoValidationGroups.DatosGenerales.class)
@Tamanio(groups = PresupuestoValidationGroups.DatosGenerales.class)
@Entity @Entity
@Table(name = "presupuesto") @Table(name = "presupuesto")
public class Presupuesto { public class Presupuesto {
public enum TipoImpresion {
fresado, cosido, grapado, espiral, wireo
}
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; 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) @NotBlank(message = "{presupuesto.errores.titulo}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "titulo") @Column(name = "titulo")
private String titulo; private String titulo;
@ -42,6 +52,17 @@ public class Presupuesto {
@Column(name = "tirada4") @Column(name = "tirada4")
private Integer 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) @Par(message = "{presupuesto.errores.paginasNegro.par}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@NotNull(message = "{presupuesto.errores.paginasNegro.required}", groups = PresupuestoValidationGroups.DatosGenerales.class) @NotNull(message = "{presupuesto.errores.paginasNegro.required}", groups = PresupuestoValidationGroups.DatosGenerales.class)
@Column(name = "paginas_negro") @Column(name = "paginas_negro")
@ -56,6 +77,12 @@ public class Presupuesto {
@Column(name = "papel_interior") @Column(name = "papel_interior")
private Integer papelInterior; private Integer papelInterior;
@Column(name = "posicion_paginas_color")
private String posicionPaginasColor;
@Column(name = "paginas_color_total")
private Integer paginasColorTotal;
// Getters y Setters // Getters y Setters
@ -111,6 +138,30 @@ public class Presupuesto {
this.tirada4 = tirada4; 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() { public String getTitulo() {
return titulo; return titulo;
} }
@ -150,4 +201,30 @@ public class Presupuesto {
public void setPapelInterior(Integer papelInterior) { public void setPapelInterior(Integer papelInterior) {
this.papelInterior = 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; 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 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 @Service
public class PresupuestoService { public class PresupuestoService {
@Autowired
protected VariableService variableService;
private final PresupuestadorItems presupuestadorItems;
public PresupuestoService(PresupuestadorItems presupuestadorItems) {
this.presupuestadorItems = presupuestadorItems;
}
public boolean validateDatosGenerales(int[] tiradas) { 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) { for (int tirada : tiradas) {
if (tirada <= 0) { if (tirada <= 0) {
return false; // Invalid tirada found 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.apaisado=Apaisado
presupuesto.orientacion.cuadrado=Cuadrado presupuesto.orientacion.cuadrado=Cuadrado
presupuesto.formato-personalizado=Formato personalizado presupuesto.formato-personalizado=Formato personalizado
presupuesto.ancho=Ancho presupuesto.ancho=Ancho (mm)*
presupuesto.alto=Alto presupuesto.alto=Alto (mm)*
presupuesto.paginas-total=Total Páginas presupuesto.paginas-total=Total Páginas
presupuesto.paginas-negro=Páginas Negro presupuesto.paginas-negro=Páginas Negro
presupuesto.paginas-color=Páginas Color 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.siempre-pares=Siempre deben ser pares
presupuesto.encuadernacion=Encuadernación presupuesto.encuadernacion=Encuadernación
presupuesto.fresado-descripcion=Fresado (a partir de 32 páginas) 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.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.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.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 Contact: support@themesbrand.com
File: Main Css File File: Main Css File
*/ */
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"); /* poppins-300 - latin */
@import url("https://fonts.googleapis.com/css2?family=Public+Sans:wght@300;400;500;600;700&display=swap"); @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-face {
font-family: "hkgrotesk"; font-family: "hkgrotesk";
src: url("../fonts/hkgrotesk-light.eot"); 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 */ min-height: 70px; /* Alto mínimo */
max-width: 70px; /* Ancho máximo */ max-width: 70px; /* Ancho máximo */
max-height: 70px; /* Alto 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 @@
$(() => { class imagen_presupuesto {
$('.imagen-container-group').on('click', '.imagen-selector', function () {
const clicked = $(this);
const group = clicked.closest('.imagen-container-group');
// Limpiar selección anterior constructor(data) {
group.find('.imagen-selector').removeClass('selected preselected') this.id = data.id;
.find('.image-presupuesto').removeClass('selected'); 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 render() {
clicked.addClass('selected'); const contenedor = $('<div>', {
const img = clicked.find('.image-presupuesto'); id: this.id,
img.addClass('selected'); 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) const input = $('<input>', {
img.removeClass('zoom-anim'); type: 'radio',
void img[0].offsetWidth; // "reflow" para reiniciar animación name: this.group,
img.addClass('zoom-anim'); 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 { class PresupuestoCliente {
constructor() { 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 // pestaña datos generales
this.divContentDatosGenerales = $('#content-datos-generales');
this.titulo = $('#titulo'); this.titulo = $('#titulo');
this.autor = $('#autor'); this.autor = $('#autor');
this.isbn = $('#isbn'); this.isbn = $('#isbn');
@ -10,25 +40,318 @@ class PresupuestoCliente {
this.tirada2 = $('#tirada2'); this.tirada2 = $('#tirada2');
this.tirada3 = $('#tirada3'); this.tirada3 = $('#tirada3');
this.tirada4 = $('#tirada4'); 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.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.btn_next_datos_generales = $('#next-datos-generales');
this.datos_generales_alert = $('#datos-generales-alert'); 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 // pestaña cubierta
this.btn_plantilla_cubierta = $('#btn-plantilla-cubierta'); this.btn_plantilla_cubierta = $('#btn-plantilla-cubierta');
this.btn_impresion_cubierta_help = $('#impresion-cubierta-help'); this.btn_impresion_cubierta_help = $('#impresion-cubierta-help');
} }
init() { 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', () => { this.btn_plantilla_cubierta.on('click', () => {
Swal.fire({ Swal.fire({
@ -60,48 +383,10 @@ class PresupuestoCliente {
showCloseButton: true showCloseButton: true
}); });
}); });
this.btn_next_datos_generales.on('click', () => {
this.nextDatosGenerales();
});
} }
/******************************
nextDatosGenerales() { * END CUBIERTA
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);
}
});
}
} }

View File

@ -2,7 +2,7 @@
const head = document.head || document.getElementsByTagName("head")[0]; const head = document.head || document.getElementsByTagName("head")[0];
const scripts = [ 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/choices.js/public/assets/scripts/choices.min.js",
"/assets/libs/flatpickr/flatpickr.min.js", "/assets/libs/flatpickr/flatpickr.min.js",
"/assets/libs/feather-icons/feather.min.js" // <- AÑADIMOS feather aquí "/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 th:replace="~{theme/partials/vendor-scripts :: scripts}" />
<th:block layout:fragment="pagejs"> <th:block layout:fragment="pagejs">
<div th:unless="${#authorization.expression('isAuthenticated()')}"> <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/imagen-selector.js}"></script>
<script th:src="@{/assets/js/pages/imprimelibros/presupuestador/presupuestador.js}"></script> <script type="module" th:src="@{/assets/js/pages/imprimelibros/presupuestador/presupuestador.js}"></script>
</div> </div>
<script th:inline="javascript"> <script th:inline="javascript">
window.languageBundle = /*[[${languageBundle}]]*/ {}; window.languageBundle = /*[[${languageBundle}]]*/ {};

View File

@ -7,7 +7,7 @@
<th:block layout:fragment="pagetitle" /> <th:block layout:fragment="pagetitle" />
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" /> <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="/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" /> <th:block layout:fragment="pagecss" />
</head> </head>
@ -28,9 +28,9 @@
<th:block layout:fragment="modal" /> <th:block layout:fragment="modal" />
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" /> <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="/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" /> <th:block layout:fragment="pagejs" />
<script th:src="@{/assets/js/app.js}"></script> <script th:src="@{/assets/js/app.js}"></script>
<script th:src="@{/assets/js/pages/imprimelibros/languageBundle.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="ribbon-content mt-4">
<div class="row justify-content-center imagen-container-group"> <div class="row justify-content-center imagen-container-group">
<div id="tapa-blanda" class="image-container imagen-selector selected"> <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=""> alt="">
<label for="titulo" class="form-label" th:text="#{presupuesto.tapa-blanda}"> <label for="titulo" class="form-label" th:text="#{presupuesto.tapa-blanda}">
Tapa blanda Tapa blanda
@ -31,7 +31,7 @@
<div id="tapa-dura" class="image-container imagen-selector"> <div id="tapa-dura" class="image-container imagen-selector">
<img class="image-presupuesto" <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}"> <label class="form-label" th:text="#{presupuesto.tapa-dura}">
Tapa dura Tapa dura
</label> </label>
@ -39,7 +39,7 @@
<div id="tapa-dura-lomo-redondo" class="image-container imagen-selector"> <div id="tapa-dura-lomo-redondo" class="image-container imagen-selector">
<img class="image-presupuesto" <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}"> <label class="form-label" th:text="#{presupuesto.tapa-dura-lomo-redondo}">
Tapa dura lomo redondo Tapa dura lomo redondo
</label> </label>

View File

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

View File

@ -1,4 +1,4 @@
<div> <div id="content-interior">
<!-- Ribbon Shape --> <!-- Ribbon Shape -->
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow"> <div class="card ribbon-box border shadow-none mb-lg-0 material-shadow">
<div class="card-body"> <div class="card-body">
@ -9,38 +9,8 @@
</div> </div>
<div class="ribbon-content mt-4"> <div class="ribbon-content mt-4">
<div class="row justify-content-center imagen-container-group"> <div id="div-opciones-color" 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> </div>
</div> </div>
</div> </div>
@ -56,7 +26,8 @@
<div class="ribbon-content mt-4"> <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"> <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" <img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/offset-blanco.png"
alt=""> alt="">