diff --git a/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java b/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java index 5dcaf46..dd618d7 100644 --- a/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java +++ b/src/main/java/mx/gob/jumapacelaya/api/RedmineClient.java @@ -7,7 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; - import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; diff --git a/src/main/java/mx/gob/jumapacelaya/models/encuestas/Pregunta.java b/src/main/java/mx/gob/jumapacelaya/models/encuestas/Pregunta.java new file mode 100644 index 0000000..7bb8de8 --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/models/encuestas/Pregunta.java @@ -0,0 +1,48 @@ +package mx.gob.jumapacelaya.models.encuestas; + +public class Pregunta { + + private int preguntaId; + private int encuestaId; + private String pregunta; + private int orden; + + public Pregunta(int preguntaId, int encuestaId, String pregunta, int orden) { + this.preguntaId = preguntaId; + this.encuestaId = encuestaId; + this.pregunta = pregunta; + this.orden = orden; + } + + public int getPreguntaId() { + return preguntaId; + } + + public void setPreguntaId(int preguntaId) { + this.preguntaId = preguntaId; + } + + public int getEncuestaId() { + return encuestaId; + } + + public void setEncuestaId(int encuestaId) { + this.encuestaId = encuestaId; + } + + public String getPregunta() { + return pregunta; + } + + public void setPregunta(String pregunta) { + this.pregunta = pregunta; + } + + public int getOrden() { + return orden; + } + + public void setOrden(int orden) { + this.orden = orden; + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/models/encuestas/Respuesta.java b/src/main/java/mx/gob/jumapacelaya/models/encuestas/Respuesta.java new file mode 100644 index 0000000..5265cf5 --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/models/encuestas/Respuesta.java @@ -0,0 +1,70 @@ +package mx.gob.jumapacelaya.models.encuestas; + +import java.sql.Timestamp; + +public class Respuesta { + + private int respuestaId; + private int mantenimientoId; + private int preguntaId; + private Timestamp fechaResp; + private Boolean respuesta; + private int emepleadoId; + + public Respuesta(int respuestaId, int mantenimientoId, int preguntaId, Timestamp fechaResp, Boolean respuesta, int emepleadoId) { + this.respuestaId = respuestaId; + this.mantenimientoId = mantenimientoId; + this.preguntaId = preguntaId; + this.fechaResp = fechaResp; + this.respuesta = respuesta; + this.emepleadoId = emepleadoId; + } + + public int getRespuestaId() { + return respuestaId; + } + + public void setRespuestaId(int respuestaId) { + this.respuestaId = respuestaId; + } + + public int getMantenimientoId() { + return mantenimientoId; + } + + public void setMantenimientoId(int mantenimientoId) { + this.mantenimientoId = mantenimientoId; + } + + public int getPreguntaId() { + return preguntaId; + } + + public void setPreguntaId(int preguntaId) { + this.preguntaId = preguntaId; + } + + public Timestamp getFechaResp() { + return fechaResp; + } + + public void setFechaResp(Timestamp fechaResp) { + this.fechaResp = fechaResp; + } + + public Boolean getRespuesta() { + return respuesta; + } + + public void setRespuesta(Boolean respuesta) { + this.respuesta = respuesta; + } + + public int getEmepleadoId() { + return emepleadoId; + } + + public void setEmepleadoId(int emepleadoId) { + this.emepleadoId = emepleadoId; + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/services/encuestas/EncuestasDBService.java b/src/main/java/mx/gob/jumapacelaya/services/encuestas/EncuestasDBService.java new file mode 100644 index 0000000..bba634b --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/services/encuestas/EncuestasDBService.java @@ -0,0 +1,84 @@ +package mx.gob.jumapacelaya.services.encuestas; + +import mx.gob.jumapacelaya.models.encuestas.Pregunta; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +@Service +public class EncuestasDBService { + + @Value("${db.url}") + private String dbUrl; + @Value("${db.user}") + private String dbUser; + @Value("${db.pass}") + private String dbPass; + + private Connection getEncuestasConn() throws SQLException { + return DriverManager.getConnection(dbUrl, dbUser, dbPass); + } + + + public List getPreguntas() { + List preguntas = new ArrayList<>(); + String query = """ + select p.* + from PREGUNTAS p + join ENCUESTAS e on e.ENCUESTAID = p.ENCUESTAID + where e.ENCUESTAID = 1 + order by p.ORDEN ASC + """; + + try (Connection conn = getEncuestasConn(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(query)) { + + while (rs.next()) { + Pregunta pregunta = new Pregunta( + rs.getInt("preguntaid"), + rs.getInt("encuestaid"), + rs.getString("pregunta"), + rs.getInt("orden") + ); + preguntas.add(pregunta); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return preguntas; + } + + + public void insertRespuestas(int manteniminetoId, int preguntaId, Timestamp fechaResp, + boolean respuesta, int empleadoid) { + + String query = """ + insert into RESPUESTAS + (MANTENIMIENTOID,PREGUNTAID,FECHARESPUESTA,RESPUESTA,EMPLEADOID) + values + (?,?,?,?,?) + """; + + try (Connection conn = getEncuestasConn(); + PreparedStatement st = conn.prepareStatement(query)) { + + st.setInt(1,manteniminetoId); + st.setInt(2, preguntaId); + if (fechaResp != null) { + st.setTimestamp(3, fechaResp); + } else + st.setNull(3, Types.DATE); + st.setBoolean(4, respuesta); + st.setInt(5, empleadoid); + + st.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + System.err.println("Error al insertar respuesta: " + e.getMessage()); + } + } +} diff --git a/src/main/java/mx/gob/jumapacelaya/ui/DetallesMantView.java b/src/main/java/mx/gob/jumapacelaya/ui/DetallesMantView.java index b837d38..6d8f816 100644 --- a/src/main/java/mx/gob/jumapacelaya/ui/DetallesMantView.java +++ b/src/main/java/mx/gob/jumapacelaya/ui/DetallesMantView.java @@ -12,7 +12,9 @@ import com.vaadin.flow.component.UI; import com.vaadin.flow.component.html.Anchor; import com.vaadin.flow.server.StreamRegistration; import com.vaadin.flow.server.StreamResource; +import mx.gob.jumapacelaya.services.EmailService; import mx.gob.jumapacelaya.services.ReportService; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.vaadin.lineawesome.LineAwesomeIcon; @@ -54,7 +56,11 @@ import mx.gob.jumapacelaya.services.SecurityService; @CssImport("./themes/sistema-mantenimiento/styles.css") public class DetallesMantView extends VerticalLayout implements BeforeEnterObserver { + @Value("${app.base-url}") + private String baseUrl; + private final H3 id; + private final EmailService emailService; private HorizontalLayout fechasLayout; private TextField txtId; private final TextField txtEquipo; @@ -68,9 +74,10 @@ public class DetallesMantView extends VerticalLayout implements BeforeEnterObser private final GridPro gridActualizaciones; private final Button btnEditar; private final Button btnEditarFirmas; - private final Button btnImprimirRepo; + private final Button btnImprimirRepo = new Button("Imprimir Reporte", new Icon(VaadinIcon.PRINT)); private final Button btnCancelar; private final Button btnGuardar; + private final Button btnEnviarEncuesta = new Button("Enviar encuesta", LineAwesomeIcon.ENVELOPE_SOLID.create()); private int planAnualIdActual; private int mantenimientoIdActual; private Dialog confirmDialog; @@ -88,7 +95,7 @@ public class DetallesMantView extends VerticalLayout implements BeforeEnterObser private final DatabaseService service; - public DetallesMantView(SecurityService securityService, DatabaseService service, ReportService reportService) { + public DetallesMantView(SecurityService securityService, DatabaseService service, ReportService reportService, EmailService emailService) { this.service = service; setPadding(true); @@ -192,15 +199,18 @@ public class DetallesMantView extends VerticalLayout implements BeforeEnterObser gridActualizaciones.addThemeVariants(GridVariant.LUMO_ROW_STRIPES); + HorizontalLayout botonesHeaderLyt = new HorizontalLayout(); + botonesHeaderLyt.setWidthFull(); + botonesHeaderLyt.add(btnImprimirRepo,btnEnviarEncuesta); + HorizontalLayout botonesLayout = new HorizontalLayout(); botonesLayout.setWidthFull(); botonesLayout.setJustifyContentMode(JustifyContentMode.CENTER); btnEditar = new Button("Editar", new Icon(VaadinIcon.EDIT)); - btnImprimirRepo = new Button("Imprimir Reporte", new Icon(VaadinIcon.PRINT)); btnEditarFirmas = new Button("Editar firmas", LineAwesomeIcon.SIGNATURE_SOLID.create()); btnGuardar = new Button("Guardar", LineAwesomeIcon.SAVE_SOLID.create()); btnCancelar = new Button("Cancelar", new Icon(VaadinIcon.CLOSE_CIRCLE_O)); - botonesLayout.add(btnEditar,btnEditarFirmas,btnImprimirRepo,btnGuardar,btnCancelar); + botonesLayout.add(btnEditar,btnEditarFirmas,btnGuardar,btnCancelar); btnGuardar.setVisible(false); btnGuardar.getStyle().set("background-color", "#008000"); @@ -294,6 +304,9 @@ public class DetallesMantView extends VerticalLayout implements BeforeEnterObser }); + btnEnviarEncuesta.addClickListener(e -> enviarCorreo()); + + // Se dispara el dialogo de confirmacion btnGuardar.addClickListener(e -> confirmDialog.open()); @@ -362,7 +375,9 @@ public class DetallesMantView extends VerticalLayout implements BeforeEnterObser addSignatureSection(); mainLayout.add(headerLayout, layout2,fechasLayout, layout3,gridHardware,gridActualizaciones,firmasLAyout, botonesLayout); - add(mainLayout); + add(botonesHeaderLyt,mainLayout); + this.setSpacing(false); + this.emailService = emailService; } @@ -505,6 +520,27 @@ public class DetallesMantView extends VerticalLayout implements BeforeEnterObser } + // METODO PARA ENVIAR LOS CORREOS ELECTRONICOS + private void enviarCorreo() { + Usuario usuarioDestino = cbUsuario.getValue(); + if (usuarioDestino != null && usuarioDestino.getEmail() != null) { + String destinatario = usuarioDestino.getEmail(); + String asunto = "Encuesta de satisfacción -Mantenimiento #" + mantenimientoIdActual; + + String linkEncuesta = baseUrl + "/encuesta?mantenimientoId=" + mantenimientoIdActual; + + String cuerpo = linkEncuesta; + String imagePath = ""; + + emailService.enviarCorreo(destinatario,asunto,cuerpo,imagePath); + Notification.show("Encuesta enviada correctamente para el mantenimiento No. " + mantenimientoIdActual, 3000, Notification.Position.MIDDLE) + .addThemeVariants(NotificationVariant.LUMO_SUCCESS); + } else { + Notification.show("Por favor, seleccione un usuario destino", 3000, Notification.Position.MIDDLE); + } + } + + @Override public void beforeEnter(BeforeEnterEvent event) { String idParam = event.getLocation().getQueryParameters().getParameters().get("id") != null diff --git a/src/main/java/mx/gob/jumapacelaya/ui/EncuestaView.java b/src/main/java/mx/gob/jumapacelaya/ui/EncuestaView.java new file mode 100644 index 0000000..0670416 --- /dev/null +++ b/src/main/java/mx/gob/jumapacelaya/ui/EncuestaView.java @@ -0,0 +1,214 @@ +package mx.gob.jumapacelaya.ui; + +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; +import com.vaadin.flow.component.html.*; +import com.vaadin.flow.component.icon.Icon; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.notification.Notification; +import com.vaadin.flow.component.notification.NotificationVariant; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.radiobutton.RadioButtonGroup; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.BeforeEnterObserver; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.server.auth.AnonymousAllowed; +import mx.gob.jumapacelaya.models.encuestas.Pregunta; +import mx.gob.jumapacelaya.models.encuestas.Respuesta; +import mx.gob.jumapacelaya.services.encuestas.EncuestasDBService; + +import javax.swing.*; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; + +@Route("encuesta") +@PageTitle("Encuesta de satisfacción") +@AnonymousAllowed +public class EncuestaView extends VerticalLayout implements BeforeEnterObserver { + + private EncuestasDBService encuestasDBService; + private int mantenimientoId = -1; + private final VerticalLayout mainLyt = new VerticalLayout(); + private Span pregunta1Txt = new Span(); + private RadioButtonGroup pregunta1Rb = new RadioButtonGroup<>(); + private Button btnEnviar = new Button("Enviar"); + private TextField txtNumEmpl = new TextField("No. Empleado:"); + + + private static class RespuestaComponente { + Pregunta pregunta; + RadioButtonGroup radios; + + RespuestaComponente(Pregunta pregunta, RadioButtonGroup radios) { + this.pregunta = pregunta; + this.radios = radios; + } + } + + private final List respuestasUI = new ArrayList<>(); + + public EncuestaView(EncuestasDBService encuestasDBService) { + this.encuestasDBService = encuestasDBService; + + setSpacing(true); + setPadding(true); + setSizeFull(); + + this.getStyle() + .set("background-image", "url('/images/LOGO_1024X768.jpg')") + .set("background-repeat", "no-repeat") + .set("background-size", "cover") + .set("background-position", "center"); + + + mainLyt.setHeightFull(); + mainLyt.setWidth("55%"); + mainLyt.getStyle() + .set("box-shadow", "0 4px 8px rgba(0,0,0,0.2)") + .set("border-radius", "12px") + .set("background-color", "white") + .set("padding", "1rem") + .set("margin", "1rem auto"); + + btnEnviar.addClickListener(e -> procesarRespuestas()); + + this.add(mainLyt); + } + + @Override + public void beforeEnter(BeforeEnterEvent beforeEnterEvent) { + List params = beforeEnterEvent.getLocation().getQueryParameters() + .getParameters().get("mantenimientoId"); + + if (params != null && !params.isEmpty()) { + try { + mantenimientoId = Integer.parseInt(params.get(0)); + mostrarMensaje(); + } catch (NumberFormatException e) { + add(new H2("Enlace inválido")); + } + } else { + add(new H2("No se recibió ningún numero de mantenimiento")); + } + } + + private void mostrarMensaje() { + + txtNumEmpl.setRequired(true); + txtNumEmpl.setErrorMessage("Por favor, llena este campo"); + + VerticalLayout titulos = new VerticalLayout(); + titulos.setSpacing(false); + titulos.setPadding(false); + titulos.add( + new H2("Mantenimiento Preventivo a Equipo de Computo"), + new Paragraph("La siguiente encuesta tiene como objetivo valorar el servicio que se brinda al proporcionar el mantenimiento preventivo del equipo de computo en el Organismo."), + txtNumEmpl + ); + + VerticalLayout preguntasLyt = new VerticalLayout(); + preguntasLyt.setWidthFull(); + preguntasLyt.setPadding(false); + preguntasLyt.setSpacing(false); + + List preguntas = encuestasDBService.getPreguntas(); + + for (Pregunta p : preguntas) { + HorizontalLayout fila = new HorizontalLayout(); + fila.setWidthFull(); + fila.setAlignItems(Alignment.CENTER); + fila.getStyle().set("padding", "0.4rem"); + fila.getStyle().set("border-bottom", "1px solid #e0e0e0"); + + Span texto = new Span(p.getPregunta()); + texto.getStyle().set("font-weight", "600"); + + RadioButtonGroup radios = new RadioButtonGroup<>(); + radios.setItems("Si", "No"); + + fila.add(texto,radios); + preguntasLyt.add(fila); + + respuestasUI.add(new RespuestaComponente(p,radios)); + } + + HorizontalLayout gracias = new HorizontalLayout(new H3("¡Gracias!")); + gracias.setWidthFull(); + gracias.setJustifyContentMode(JustifyContentMode.CENTER); + + btnEnviar.setWidthFull(); + btnEnviar.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + HorizontalLayout btnEnviarLyt = new HorizontalLayout(btnEnviar); + btnEnviarLyt.setWidthFull(); + btnEnviarLyt.setJustifyContentMode(JustifyContentMode.CENTER); + btnEnviarLyt.setSpacing(false); + btnEnviarLyt.setPadding(false); + + + mainLyt.removeAll(); + mainLyt.add(titulos,preguntasLyt,gracias, btnEnviarLyt); + } + + private void procesarRespuestas() { + + if (txtNumEmpl.isEmpty()) { + txtNumEmpl.setInvalid(true); + return; + } + + int empleadoId = Integer.parseInt(txtNumEmpl.getValue()); + Timestamp ahora = new Timestamp(System.currentTimeMillis()); + + for (RespuestaComponente rc : respuestasUI) { + + Pregunta pregunta = rc.pregunta; + String respuestaTexto = rc.radios.getValue(); + + if (respuestaTexto == null) { + System.out.println("Pregunta no respondida: " + pregunta.getPregunta()); + continue; + } + + boolean respuestaBool = respuestaTexto.equals("Si"); + + encuestasDBService.insertRespuestas( + mantenimientoId, + pregunta.getPreguntaId(), + ahora, + respuestaBool, + empleadoId + ); + } + + NotiEncuesta(); + mainLyt.setVisible(false); + + this.setEnabled(false); + } + + private void NotiEncuesta() { + Notification ntf = new Notification(); + ntf.setPosition(Notification.Position.MIDDLE); + ntf.addThemeVariants(NotificationVariant.LUMO_SUCCESS); + ntf.setDuration(0); + + H2 titulo = new H2("Encuesta enviada"); + titulo.getStyle().set("color","white"); + Span msj = new Span("Sus respuestas se han guardado correctamente."); + Span msj2 = new Span("Gracias por participar en nuestra encuesta."); + + Icon succesIcon = new Icon(VaadinIcon.CHECK_CIRCLE); + succesIcon.setSize("48px"); + + VerticalLayout layout = new VerticalLayout(succesIcon,titulo,msj,msj2); + layout.setAlignItems(Alignment.CENTER); + + ntf.add(layout); + ntf.open(); + } +} diff --git a/src/main/resources/META-INF/resources/images/LOGO_1024X768.jpg b/src/main/resources/META-INF/resources/images/LOGO_1024X768.jpg new file mode 100644 index 0000000..7e63a9b Binary files /dev/null and b/src/main/resources/META-INF/resources/images/LOGO_1024X768.jpg differ diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 5240f8b..c027611 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,4 +1,7 @@ #Configuracion de la base de datos db.url=jdbc:mysql://localhost:3307/mantenimientosdb db.user=mantenimientos -db.pass=mantenimientos \ No newline at end of file +db.pass=mantenimientos + +# URL base local +app.base-url=http://localhost:8080 \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index c908743..944847e 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -2,4 +2,7 @@ db.url=jdbc:mysql://db:3306/mantenimientosdb #db.url=jdbc:oracle:thin:@//SVRAPPS:1521/XEPDB1 db.user=mantenimientos -db.pass=mantenimientos \ No newline at end of file +db.pass=mantenimientos + +# URL base productivo +app.base-url=https://smt.jumapacelaya.gob.mx \ No newline at end of file