|
|
@ -11,6 +11,7 @@ import com.vaadin.flow.component.dependency.CssImport; |
|
|
import com.vaadin.flow.component.dialog.Dialog; |
|
|
import com.vaadin.flow.component.dialog.Dialog; |
|
|
import com.vaadin.flow.component.grid.Grid; |
|
|
import com.vaadin.flow.component.grid.Grid; |
|
|
import com.vaadin.flow.component.grid.GridVariant; |
|
|
import com.vaadin.flow.component.grid.GridVariant; |
|
|
|
|
|
import com.vaadin.flow.component.html.Anchor; |
|
|
import com.vaadin.flow.component.html.Div; |
|
|
import com.vaadin.flow.component.html.Div; |
|
|
import com.vaadin.flow.component.html.H3; |
|
|
import com.vaadin.flow.component.html.H3; |
|
|
import com.vaadin.flow.component.html.Span; |
|
|
import com.vaadin.flow.component.html.Span; |
|
|
@ -25,8 +26,11 @@ import com.vaadin.flow.component.popover.Popover; |
|
|
import com.vaadin.flow.component.popover.PopoverPosition; |
|
|
import com.vaadin.flow.component.popover.PopoverPosition; |
|
|
import com.vaadin.flow.component.richtexteditor.RichTextEditor; |
|
|
import com.vaadin.flow.component.richtexteditor.RichTextEditor; |
|
|
import com.vaadin.flow.data.renderer.ComponentRenderer; |
|
|
import com.vaadin.flow.data.renderer.ComponentRenderer; |
|
|
|
|
|
import com.vaadin.flow.function.SerializableBiConsumer; |
|
|
import com.vaadin.flow.router.PageTitle; |
|
|
import com.vaadin.flow.router.PageTitle; |
|
|
import com.vaadin.flow.router.Route; |
|
|
import com.vaadin.flow.router.Route; |
|
|
|
|
|
import com.vaadin.flow.server.StreamRegistration; |
|
|
|
|
|
import com.vaadin.flow.server.StreamResource; |
|
|
import jakarta.annotation.security.PermitAll; |
|
|
import jakarta.annotation.security.PermitAll; |
|
|
import mx.gob.jumapacelaya.api.RedmineClient; |
|
|
import mx.gob.jumapacelaya.api.RedmineClient; |
|
|
import mx.gob.jumapacelaya.api.ServerProperties; |
|
|
import mx.gob.jumapacelaya.api.ServerProperties; |
|
|
@ -36,8 +40,18 @@ import mx.gob.jumapacelaya.models.Ticket; |
|
|
import mx.gob.jumapacelaya.services.LdapService; |
|
|
import mx.gob.jumapacelaya.services.LdapService; |
|
|
import mx.gob.jumapacelaya.services.UserService; |
|
|
import mx.gob.jumapacelaya.services.UserService; |
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.poi.ss.usermodel.Cell; |
|
|
|
|
|
import org.apache.poi.ss.usermodel.Row; |
|
|
|
|
|
import org.apache.poi.ss.usermodel.Sheet; |
|
|
|
|
|
import org.apache.poi.ss.usermodel.Workbook; |
|
|
|
|
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
|
|
|
|
|
import org.slf4j.Logger; |
|
|
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
|
|
import org.vaadin.lineawesome.LineAwesomeIcon; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
import java.io.IOException; |
|
|
import java.io.IOException; |
|
|
import java.text.SimpleDateFormat; |
|
|
import java.text.SimpleDateFormat; |
|
|
import java.time.LocalDate; |
|
|
import java.time.LocalDate; |
|
|
@ -54,13 +68,15 @@ import java.util.stream.Stream; |
|
|
@CssImport("./themes/sistema-mantenimiento/styles.css") |
|
|
@CssImport("./themes/sistema-mantenimiento/styles.css") |
|
|
public class ActDiariaView extends VerticalLayout { |
|
|
public class ActDiariaView extends VerticalLayout { |
|
|
|
|
|
|
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(ActDiariaView.class); |
|
|
private final RedmineClient redmineClient; |
|
|
private final RedmineClient redmineClient; |
|
|
private final UserService userService; |
|
|
private final UserService userService; |
|
|
private final Grid<Ticket> grid; |
|
|
private final Grid<Ticket> grid; |
|
|
private final HorizontalLayout showColumnsLyt; |
|
|
private final HorizontalLayout showColumnsLyt; |
|
|
private final Button btnColumns; |
|
|
private final Button btnColumns; |
|
|
|
|
|
private final Button btnExport; |
|
|
private final HorizontalLayout opcionesLyt; |
|
|
private final HorizontalLayout opcionesLyt; |
|
|
private final Checkbox chkVerCerrados; |
|
|
|
|
|
|
|
|
private Checkbox chkSoloAbiertos; |
|
|
private DatePicker fechaDesde; |
|
|
private DatePicker fechaDesde; |
|
|
private DatePicker fechaHasta; |
|
|
private DatePicker fechaHasta; |
|
|
private Button btnBuscar; |
|
|
private Button btnBuscar; |
|
|
@ -72,7 +88,7 @@ public class ActDiariaView extends VerticalLayout { |
|
|
|
|
|
|
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); |
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); |
|
|
|
|
|
|
|
|
// Configuracion de las opciones de arriba |
|
|
|
|
|
|
|
|
// Layout de opciones |
|
|
opcionesLyt = new HorizontalLayout(); |
|
|
opcionesLyt = new HorizontalLayout(); |
|
|
opcionesLyt.setWidthFull(); |
|
|
opcionesLyt.setWidthFull(); |
|
|
opcionesLyt.setMargin(false); |
|
|
opcionesLyt.setMargin(false); |
|
|
@ -83,26 +99,33 @@ public class ActDiariaView extends VerticalLayout { |
|
|
.set("padding", "1rem") |
|
|
.set("padding", "1rem") |
|
|
.set("margin", "1rem auto"); |
|
|
.set("margin", "1rem auto"); |
|
|
|
|
|
|
|
|
|
|
|
// Checkbox para ver solo abiertos |
|
|
|
|
|
chkSoloAbiertos = new Checkbox("Ver solo abiertos"); |
|
|
|
|
|
chkSoloAbiertos.setValue(false); // inicial: mostrar cerrados |
|
|
|
|
|
|
|
|
|
|
|
fechaDesde = new DatePicker("Fecha desde:"); |
|
|
|
|
|
fechaHasta = new DatePicker("Fecha hasta:"); |
|
|
|
|
|
btnBuscar = new Button("Buscar"); |
|
|
|
|
|
|
|
|
chkVerCerrados = new Checkbox(); |
|
|
|
|
|
chkVerCerrados.setLabel("Ver solo abiertos"); |
|
|
|
|
|
chkVerCerrados.addValueChangeListener(e -> { |
|
|
|
|
|
boolean soloAbiertos = e.getValue().equals(false); |
|
|
|
|
|
|
|
|
// Listener del checkbox |
|
|
|
|
|
chkSoloAbiertos.addValueChangeListener(e -> { |
|
|
|
|
|
boolean soloAbiertos = e.getValue(); // marcado = abiertos |
|
|
loadTickets(soloAbiertos); |
|
|
loadTickets(soloAbiertos); |
|
|
fechaDesde.setEnabled(false); |
|
|
|
|
|
fechaHasta.setEnabled(false); |
|
|
|
|
|
btnBuscar.setEnabled(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fechaDesde.setEnabled(!soloAbiertos); |
|
|
|
|
|
fechaHasta.setEnabled(!soloAbiertos); |
|
|
|
|
|
btnBuscar.setEnabled(!soloAbiertos); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
fechaDesde = new DatePicker("Fecha desde:"); |
|
|
|
|
|
|
|
|
// Estado inicial |
|
|
fechaDesde.setEnabled(true); |
|
|
fechaDesde.setEnabled(true); |
|
|
|
|
|
|
|
|
fechaHasta = new DatePicker("Fecha hasta:"); |
|
|
|
|
|
fechaHasta.setEnabled(true); |
|
|
fechaHasta.setEnabled(true); |
|
|
|
|
|
btnBuscar.setEnabled(true); |
|
|
|
|
|
|
|
|
btnBuscar = new Button("Buscar"); |
|
|
|
|
|
opcionesLyt.add(chkVerCerrados,fechaDesde,fechaHasta,btnBuscar); |
|
|
|
|
|
|
|
|
// Cargar tickets iniciales (cerrados) |
|
|
|
|
|
loadTickets(false); |
|
|
|
|
|
|
|
|
|
|
|
opcionesLyt.add(chkSoloAbiertos, fechaDesde, fechaHasta, btnBuscar); |
|
|
|
|
|
|
|
|
// Configuración de columnas del grid |
|
|
// Configuración de columnas del grid |
|
|
grid.addColumn(Ticket::getId).setHeader("No.") |
|
|
grid.addColumn(Ticket::getId).setHeader("No.") |
|
|
@ -114,49 +137,54 @@ public class ActDiariaView extends VerticalLayout { |
|
|
.setAutoWidth(true) |
|
|
.setAutoWidth(true) |
|
|
.setKey("tipo"); |
|
|
.setKey("tipo"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> ticket.tiempoEst(ticket.getTrackerId())) |
|
|
grid.addColumn(ticket -> ticket.tiempoEst(ticket.getTrackerId())) |
|
|
.setHeader("Tiempo estimado") |
|
|
.setHeader("Tiempo estimado") |
|
|
.setAutoWidth(true) |
|
|
.setAutoWidth(true) |
|
|
.setKey("tiempoEst"); |
|
|
.setKey("tiempoEst"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(Ticket::getSubject) |
|
|
|
|
|
.setHeader("Asunto") |
|
|
|
|
|
.setWidth("25rem") |
|
|
|
|
|
.setKey("asunto"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> |
|
|
|
|
|
ticket.getAuthor() != null ? ticket.getAuthor().getUsername() : "") |
|
|
|
|
|
.setHeader("Autor") |
|
|
|
|
|
.setAutoWidth(true) |
|
|
|
|
|
.setKey("autor"); |
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(createStatusRender()).setHeader("Estado") |
|
|
|
|
|
.setKey("estado"); |
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> { |
|
|
grid.addColumn(ticket -> { |
|
|
LocalDateTime fecha = ticket.getDateCreate(); |
|
|
LocalDateTime fecha = ticket.getDateCreate(); |
|
|
return fecha != null ? fecha.format(formatter) : ""; |
|
|
|
|
|
|
|
|
return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) : ""; |
|
|
}).setHeader("Fecha creación") |
|
|
}).setHeader("Fecha creación") |
|
|
.setAutoWidth(true) |
|
|
.setAutoWidth(true) |
|
|
.setKey("fechaCreacion"); |
|
|
.setKey("fechaCreacion"); |
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> { |
|
|
grid.addColumn(ticket -> { |
|
|
LocalDateTime fecha = ticket.getDateClose(); |
|
|
LocalDateTime fecha = ticket.getDateClose(); |
|
|
return fecha != null ? fecha.format(formatter) : ""; |
|
|
|
|
|
|
|
|
return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) : ""; |
|
|
}).setHeader("Fecha cierre") |
|
|
}).setHeader("Fecha cierre") |
|
|
.setAutoWidth(true) |
|
|
.setAutoWidth(true) |
|
|
.setKey("fechaCierre"); |
|
|
.setKey("fechaCierre"); |
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> { |
|
|
grid.addColumn(ticket -> { |
|
|
LocalDateTime fecha = ticket.getUpdateOn(); |
|
|
LocalDateTime fecha = ticket.getUpdateOn(); |
|
|
return fecha != null ? fecha.format(formatter) : ""; |
|
|
|
|
|
|
|
|
return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) : ""; |
|
|
}).setHeader("Fecha actualización") |
|
|
}).setHeader("Fecha actualización") |
|
|
.setAutoWidth(true) |
|
|
.setAutoWidth(true) |
|
|
.setKey("fechaActualizacion"); |
|
|
.setKey("fechaActualizacion"); |
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> { |
|
|
|
|
|
if (ticket.getDateCreateLocal() != null && ticket.getDateCloseLocal() != null) { |
|
|
|
|
|
LocalDateTime inicio = ticket.getDateCreateLocal(); |
|
|
|
|
|
LocalDateTime fin = ticket.getDateCloseLocal(); |
|
|
|
|
|
|
|
|
|
|
|
long horasReales = ChronoUnit.HOURS.between(inicio, fin); |
|
|
|
|
|
Double horasEstimadas = ticket.getEstimatedHrs(); |
|
|
|
|
|
|
|
|
|
|
|
if (horasEstimadas != null) { |
|
|
|
|
|
return horasReales <= horasEstimadas ? "✅ En tiempo" : "⚠️ Excedido"; |
|
|
|
|
|
} else { |
|
|
|
|
|
return "Sin estimación"; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
return ""; |
|
|
|
|
|
} |
|
|
|
|
|
}).setHeader("Situación").setAutoWidth(true).setKey("cumplimientoHoras"); |
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(createStatusRender()) |
|
|
|
|
|
.setHeader("Estado") |
|
|
|
|
|
.setKey("estado"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> { |
|
|
grid.addColumn(ticket -> { |
|
|
if (ticket.getDateCreateLocal() != null) { |
|
|
if (ticket.getDateCreateLocal() != null) { |
|
|
@ -172,6 +200,19 @@ public class ActDiariaView extends VerticalLayout { |
|
|
}).setHeader("Duración").setAutoWidth(true).setKey("duracion"); |
|
|
}).setHeader("Duración").setAutoWidth(true).setKey("duracion"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(ticket -> |
|
|
|
|
|
ticket.getAuthor() != null ? ticket.getAuthor().getUsername() : "") |
|
|
|
|
|
.setHeader("Autor") |
|
|
|
|
|
.setAutoWidth(true) |
|
|
|
|
|
.setKey("autor"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addColumn(Ticket::getSubject) |
|
|
|
|
|
.setHeader("Asunto") |
|
|
|
|
|
.setWidth("25rem") |
|
|
|
|
|
.setKey("asunto"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grid.addComponentColumn(ticket -> { |
|
|
grid.addComponentColumn(ticket -> { |
|
|
Button btnVer = new Button(new Icon(VaadinIcon.EYE)); |
|
|
Button btnVer = new Button(new Icon(VaadinIcon.EYE)); |
|
|
btnVer.addClickListener(event -> showDescription(ticket)); |
|
|
btnVer.addClickListener(event -> showDescription(ticket)); |
|
|
@ -179,18 +220,18 @@ public class ActDiariaView extends VerticalLayout { |
|
|
return btnVer; |
|
|
return btnVer; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
//grid.addColumn(buttonTicketComponentRenderer()).setAutoWidth(true); |
|
|
|
|
|
|
|
|
|
|
|
grid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT); |
|
|
grid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT); |
|
|
grid.addThemeVariants(GridVariant.LUMO_ROW_STRIPES); |
|
|
grid.addThemeVariants(GridVariant.LUMO_ROW_STRIPES); |
|
|
//grid.getStyle().set("opacity", "0.8"); |
|
|
|
|
|
//grid.setAllRowsVisible(false); |
|
|
|
|
|
grid.setSizeFull(); |
|
|
grid.setSizeFull(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Mostrar boton para elegir que columnas mostrar |
|
|
|
|
|
/**/btnColumns = new Button(VaadinIcon.GRID_H.create()); |
|
|
|
|
|
/**/showColumnsLyt = new HorizontalLayout(btnColumns); |
|
|
|
|
|
|
|
|
// Botón para mostrar/ocultar columnas |
|
|
|
|
|
btnColumns = new Button(VaadinIcon.GRID_H.create()); |
|
|
|
|
|
// Botón para exportar |
|
|
|
|
|
btnExport = new Button("Exportar", LineAwesomeIcon.FILE_EXCEL.create()); |
|
|
|
|
|
btnExport.addClickListener(e -> exportTicketsCerrados()); |
|
|
|
|
|
showColumnsLyt = new HorizontalLayout(btnExport, btnColumns); |
|
|
|
|
|
showColumnsLyt.setJustifyContentMode(JustifyContentMode.END); |
|
|
|
|
|
showColumnsLyt.setWidthFull(); |
|
|
HorizontalLayout columnsSelectorLyt = new HorizontalLayout(); |
|
|
HorizontalLayout columnsSelectorLyt = new HorizontalLayout(); |
|
|
columnsSelectorLyt.setAlignItems(Alignment.END); |
|
|
columnsSelectorLyt.setAlignItems(Alignment.END); |
|
|
Popover popover = new Popover(); |
|
|
Popover popover = new Popover(); |
|
|
@ -220,46 +261,44 @@ public class ActDiariaView extends VerticalLayout { |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
Set<String> defaultColumns = Set.of("tipo","asunto","autor","estado","fechaCreacion","fechaCierre"); |
|
|
|
|
|
|
|
|
Set<String> defaultColumns = Set.of("tipo","tiempoEst","fechaCreacion","fechaCierre","cumplimientoHoras","estado","duracion","autor","asunto"); |
|
|
chkColumns.setValue(defaultColumns); |
|
|
chkColumns.setValue(defaultColumns); |
|
|
popover.add(heading, chkColumns); |
|
|
popover.add(heading, chkColumns); |
|
|
/****/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ajustar tamaño del Grid y Layout |
|
|
|
|
|
|
|
|
// Ajustar tamaños |
|
|
grid.setSizeFull(); |
|
|
grid.setSizeFull(); |
|
|
setSizeFull(); |
|
|
setSizeFull(); |
|
|
add(opcionesLyt, showColumnsLyt, grid); |
|
|
add(opcionesLyt, showColumnsLyt, grid); |
|
|
//expand(grid); |
|
|
|
|
|
setMargin(false); |
|
|
setMargin(false); |
|
|
|
|
|
|
|
|
loadTickets(true); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTA: Ajuste en la carga de tickets para que ahora haga LazyLoad al cargar todos los ticktes cerrados |
|
|
// NOTA: Ajuste en la carga de tickets para que ahora haga LazyLoad al cargar todos los ticktes cerrados |
|
|
private void loadTickets(boolean soloAbiertos) { |
|
|
private void loadTickets(boolean soloAbiertos) { |
|
|
RedmineUser user = userService.getRedmineUser(); |
|
|
RedmineUser user = userService.getRedmineUser(); |
|
|
|
|
|
|
|
|
|
|
|
// Invertir parámetro para que coincida con RedmineClient |
|
|
|
|
|
boolean paramCliente = !soloAbiertos; |
|
|
|
|
|
|
|
|
grid.setItems( |
|
|
grid.setItems( |
|
|
query -> { |
|
|
query -> { |
|
|
int offset = query.getOffset(); |
|
|
int offset = query.getOffset(); |
|
|
int limit = query.getLimit(); |
|
|
int limit = query.getLimit(); |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
List<Ticket> ticketsPage = redmineClient.getTickets(user, soloAbiertos, offset, limit); |
|
|
|
|
|
|
|
|
List<Ticket> ticketsPage = redmineClient.getTickets(user, paramCliente, offset, limit); |
|
|
return ticketsPage.stream(); |
|
|
return ticketsPage.stream(); |
|
|
} catch (Exception e) { |
|
|
} catch (Exception e) { |
|
|
e.printStackTrace(); |
|
|
e.printStackTrace(); |
|
|
return Stream.empty(); |
|
|
|
|
|
|
|
|
return Stream.empty(); |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
query -> { |
|
|
|
|
|
return redmineClient.getTotalTickets(user, soloAbiertos); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
query -> redmineClient.getTotalTickets(user, paramCliente) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ComponentRenderer<Span, Ticket> createStatusRender() { |
|
|
private ComponentRenderer<Span, Ticket> createStatusRender() { |
|
|
return new ComponentRenderer<>(ticket -> { |
|
|
return new ComponentRenderer<>(ticket -> { |
|
|
// Creamos un Span para mostrar el estado |
|
|
// Creamos un Span para mostrar el estado |
|
|
@ -267,27 +306,21 @@ public class ActDiariaView extends VerticalLayout { |
|
|
|
|
|
|
|
|
// Estilos basados en el estado del ticket |
|
|
// Estilos basados en el estado del ticket |
|
|
switch (ticket.getStatus().toLowerCase()) { |
|
|
switch (ticket.getStatus().toLowerCase()) { |
|
|
case "análisis": |
|
|
|
|
|
span.getElement().getStyle().set("color","orange"); |
|
|
|
|
|
|
|
|
case "rechazado": |
|
|
|
|
|
String theme1 = String.format("badge %s", "error"); |
|
|
|
|
|
span.getElement().setAttribute("theme",theme1); |
|
|
break; |
|
|
break; |
|
|
case "desarrollo": |
|
|
|
|
|
span.getElement().getStyle().set("color","blue"); |
|
|
|
|
|
break; |
|
|
|
|
|
case "rechazada": |
|
|
|
|
|
span.getElement().getStyle().set("color","red"); |
|
|
|
|
|
break; |
|
|
|
|
|
case "cerrada": |
|
|
|
|
|
span.getElement().getStyle().set("color","grey"); |
|
|
|
|
|
break; |
|
|
|
|
|
case "solicitado": |
|
|
|
|
|
span.getElement().getStyle().set("color","purple"); |
|
|
|
|
|
|
|
|
case "resuelto","cerrado": |
|
|
|
|
|
String theme2 = String.format("badge %s", "success"); |
|
|
|
|
|
span.getElement().setAttribute("theme",theme2); |
|
|
break; |
|
|
break; |
|
|
case "qa": |
|
|
case "qa": |
|
|
span.getElement().getStyle().set("color","#C21DF2"); |
|
|
|
|
|
|
|
|
String theme3 = String.format("badge %s", "warning"); |
|
|
|
|
|
span.getElement().setAttribute("theme",theme3); |
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
span.getElement().getStyle().set("color","green"); |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
String theme4 = String.format("badge %s", ""); |
|
|
|
|
|
span.getElement().setAttribute("theme",theme4); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return span; |
|
|
return span; |
|
|
@ -353,4 +386,71 @@ public class ActDiariaView extends VerticalLayout { |
|
|
|
|
|
|
|
|
dialog.open(); |
|
|
dialog.open(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Metodo para exportar los tickets cerrados a un archivo de Excel |
|
|
|
|
|
private void exportTicketsCerrados() { |
|
|
|
|
|
try { |
|
|
|
|
|
RedmineUser user = userService.getRedmineUser(); |
|
|
|
|
|
|
|
|
|
|
|
List<Ticket> ticketsCerrados = redmineClient.getTickets(user, true, 0, 10000); |
|
|
|
|
|
|
|
|
|
|
|
Workbook workbook = new XSSFWorkbook(); |
|
|
|
|
|
Sheet sheet = workbook.createSheet("Tickets cerrados"); |
|
|
|
|
|
|
|
|
|
|
|
String[] headers = {"ID","Tipo","Estado","Autor","Asunto","Fecha Creación","Fecha Cierre","Fecha actualización","Duración","Situación"}; |
|
|
|
|
|
Row headerRow = sheet.createRow(0); |
|
|
|
|
|
for (int i = 0; i < headers.length; i++) { |
|
|
|
|
|
Cell cell = headerRow.createCell(i); |
|
|
|
|
|
cell.setCellValue(headers[i]); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int rowNum = 1; |
|
|
|
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"); |
|
|
|
|
|
|
|
|
|
|
|
for (Ticket ticket : ticketsCerrados) { |
|
|
|
|
|
Row row = sheet.createRow(rowNum++); |
|
|
|
|
|
row.createCell(0).setCellValue(ticket.getId()); |
|
|
|
|
|
row.createCell(1).setCellValue(ticket.getType()); |
|
|
|
|
|
row.createCell(2).setCellValue(ticket.getStatus()); |
|
|
|
|
|
row.createCell(3).setCellValue(ticket.getAuthor() != null ? ticket.getAuthor().getUsername() : ""); |
|
|
|
|
|
row.createCell(4).setCellValue(ticket.getSubject()); |
|
|
|
|
|
row.createCell(5).setCellValue(ticket.getDateCreate() != null ? ticket.getDateCreate().format(formatter) : ""); |
|
|
|
|
|
row.createCell(6).setCellValue(ticket.getDateClose() != null ? ticket.getDateClose().format(formatter) : ""); |
|
|
|
|
|
row.createCell(7).setCellValue(ticket.getUpdateOn() != null ? ticket.getUpdateOn().format(formatter) : ""); |
|
|
|
|
|
|
|
|
|
|
|
if (ticket.getDateCreateLocal() != null && ticket.getDateCloseLocal() != null) { |
|
|
|
|
|
long dias = ChronoUnit.DAYS.between(ticket.getDateCreateLocal(), ticket.getDateCloseLocal()); |
|
|
|
|
|
row.createCell(8).setCellValue(dias + " dias"); |
|
|
|
|
|
} else { |
|
|
|
|
|
row.createCell(8).setCellValue(""); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ticket.getEstimatedHrs() != null && ticket.getDateCreateLocal() != null && ticket.getDateCloseLocal() != null) { |
|
|
|
|
|
long horasReales = ChronoUnit.HOURS.between(ticket.getDateCreateLocal(), ticket.getDateCloseLocal()); |
|
|
|
|
|
row.createCell(9).setCellValue(horasReales <= ticket.getEstimatedHrs() ? "En tiempo" : "Excedido"); |
|
|
|
|
|
} else { |
|
|
|
|
|
row.createCell(9).setCellValue("Sin estimación"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < headers.length; i++) { |
|
|
|
|
|
sheet.autoSizeColumn(i); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream(); |
|
|
|
|
|
workbook.write(out); |
|
|
|
|
|
workbook.close(); |
|
|
|
|
|
|
|
|
|
|
|
StreamResource resource = new StreamResource("tickets_cerrados.xlsx", () -> new ByteArrayInputStream(out.toByteArray())); |
|
|
|
|
|
|
|
|
|
|
|
StreamRegistration registration = UI.getCurrent().getSession().getResourceRegistry().registerResource(resource); |
|
|
|
|
|
UI.getCurrent().getPage().executeJs("window.open('" + registration.getResourceUri().toString() + "','_blank')"); |
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
log.error("Error exportando tickets", e); |
|
|
|
|
|
Notification.show("Error al exportar los tickets", 5000, Notification.Position.MIDDLE) |
|
|
|
|
|
.addThemeVariants(NotificationVariant.LUMO_ERROR); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |