Erweiterungen
This commit is contained in:
@@ -24,11 +24,18 @@ import de.assecutor.votianlt.model.task.TodoListTask;
|
|||||||
import de.assecutor.votianlt.model.task.PhotoTask;
|
import de.assecutor.votianlt.model.task.PhotoTask;
|
||||||
import de.assecutor.votianlt.model.task.SignatureTask;
|
import de.assecutor.votianlt.model.task.SignatureTask;
|
||||||
import de.assecutor.votianlt.model.task.ConfirmationTask;
|
import de.assecutor.votianlt.model.task.ConfirmationTask;
|
||||||
|
import de.assecutor.votianlt.model.task.BarcodeTask;
|
||||||
import de.assecutor.votianlt.model.AppUser;
|
import de.assecutor.votianlt.model.AppUser;
|
||||||
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
|
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
|
||||||
import de.assecutor.votianlt.repository.CargoItemRepository;
|
import de.assecutor.votianlt.repository.CargoItemRepository;
|
||||||
import de.assecutor.votianlt.repository.JobRepository;
|
import de.assecutor.votianlt.repository.JobRepository;
|
||||||
import de.assecutor.votianlt.repository.TaskRepository;
|
import de.assecutor.votianlt.repository.TaskRepository;
|
||||||
|
import de.assecutor.votianlt.repository.SignatureRepository;
|
||||||
|
import de.assecutor.votianlt.repository.BarcodeRepository;
|
||||||
|
import de.assecutor.votianlt.repository.PhotoRepository;
|
||||||
|
import de.assecutor.votianlt.model.Signature;
|
||||||
|
import de.assecutor.votianlt.model.Barcode;
|
||||||
|
import de.assecutor.votianlt.model.Photo;
|
||||||
import de.assecutor.votianlt.pages.service.AppUserService;
|
import de.assecutor.votianlt.pages.service.AppUserService;
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
@@ -46,6 +53,9 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
|||||||
private final JobRepository jobRepository;
|
private final JobRepository jobRepository;
|
||||||
private final CargoItemRepository cargoItemRepository;
|
private final CargoItemRepository cargoItemRepository;
|
||||||
private final TaskRepository taskRepository;
|
private final TaskRepository taskRepository;
|
||||||
|
private final SignatureRepository signatureRepository;
|
||||||
|
private final BarcodeRepository barcodeRepository;
|
||||||
|
private final PhotoRepository photoRepository;
|
||||||
private final AppUserService appUserService;
|
private final AppUserService appUserService;
|
||||||
|
|
||||||
private final VerticalLayout content;
|
private final VerticalLayout content;
|
||||||
@@ -54,10 +64,16 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
|||||||
public JobSummaryView(JobRepository jobRepository,
|
public JobSummaryView(JobRepository jobRepository,
|
||||||
CargoItemRepository cargoItemRepository,
|
CargoItemRepository cargoItemRepository,
|
||||||
TaskRepository taskRepository,
|
TaskRepository taskRepository,
|
||||||
|
SignatureRepository signatureRepository,
|
||||||
|
BarcodeRepository barcodeRepository,
|
||||||
|
PhotoRepository photoRepository,
|
||||||
AppUserService appUserService) {
|
AppUserService appUserService) {
|
||||||
this.jobRepository = jobRepository;
|
this.jobRepository = jobRepository;
|
||||||
this.cargoItemRepository = cargoItemRepository;
|
this.cargoItemRepository = cargoItemRepository;
|
||||||
this.taskRepository = taskRepository;
|
this.taskRepository = taskRepository;
|
||||||
|
this.signatureRepository = signatureRepository;
|
||||||
|
this.barcodeRepository = barcodeRepository;
|
||||||
|
this.photoRepository = photoRepository;
|
||||||
this.appUserService = appUserService;
|
this.appUserService = appUserService;
|
||||||
|
|
||||||
setSizeFull();
|
setSizeFull();
|
||||||
@@ -75,12 +91,27 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setParameter(BeforeEvent event, String parameter) {
|
public void setParameter(BeforeEvent event, String parameter) {
|
||||||
if (parameter == null || parameter.isBlank()) return;
|
content.removeAll();
|
||||||
|
|
||||||
|
if (parameter == null || parameter.isBlank()) {
|
||||||
|
content.add(new Span("Fehler: Keine Job-ID angegeben"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ObjectId jobId;
|
ObjectId jobId;
|
||||||
try { jobId = new ObjectId(parameter); } catch (Exception e) { return; }
|
try {
|
||||||
|
jobId = new ObjectId(parameter);
|
||||||
|
} catch (Exception e) {
|
||||||
|
content.add(new Span("Fehler: Ungültige Job-ID Format: " + parameter));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Job job = jobRepository.findById(jobId).orElse(null);
|
Job job = jobRepository.findById(jobId).orElse(null);
|
||||||
if (job == null) return;
|
if (job == null) {
|
||||||
|
content.add(new Span("Fehler: Job mit ID " + parameter + " nicht gefunden"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<CargoItem> cargo = cargoItemRepository.findByJobId(jobId);
|
List<CargoItem> cargo = cargoItemRepository.findByJobId(jobId);
|
||||||
List<BaseTask> tasks = taskRepository.findByJobIdOrderByTaskOrderAsc(jobId);
|
List<BaseTask> tasks = taskRepository.findByJobIdOrderByTaskOrderAsc(jobId);
|
||||||
|
|
||||||
@@ -429,12 +460,123 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
|||||||
}
|
}
|
||||||
content.add(new Span(photoInfo));
|
content.add(new Span(photoInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show photos if task is completed
|
||||||
|
if (task.isCompleted()) {
|
||||||
|
try {
|
||||||
|
ObjectId taskId = new ObjectId(task.getIdAsString());
|
||||||
|
List<Photo> photos = photoRepository.findByTaskId(taskId);
|
||||||
|
|
||||||
|
if (!photos.isEmpty()) {
|
||||||
|
content.add(new Span("")); // Spacer
|
||||||
|
|
||||||
|
// Collect all photos from all Photo entries
|
||||||
|
List<String> allPhotos = new ArrayList<>();
|
||||||
|
for (Photo photo : photos) {
|
||||||
|
if (photo.getPhoto() != null && !photo.getPhoto().isBlank()) {
|
||||||
|
allPhotos.add(photo.getPhoto());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allPhotos.isEmpty()) {
|
||||||
|
content.add(new Span("Aufgenommene Fotos (" + allPhotos.size() + "):"));
|
||||||
|
|
||||||
|
// Create photo gallery container
|
||||||
|
Div photoGallery = createPhotoGallery(allPhotos);
|
||||||
|
content.add(photoGallery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore errors when loading photos
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (task instanceof ConfirmationTask confirmationTask) {
|
} else if (task instanceof ConfirmationTask confirmationTask) {
|
||||||
if (confirmationTask.getButtonText() != null && !confirmationTask.getButtonText().isBlank()) {
|
if (confirmationTask.getButtonText() != null && !confirmationTask.getButtonText().isBlank()) {
|
||||||
content.add(new Span("Button-Text: " + confirmationTask.getButtonText()));
|
content.add(new Span("Button-Text: " + confirmationTask.getButtonText()));
|
||||||
}
|
}
|
||||||
} else if (task instanceof SignatureTask) {
|
} else if (task instanceof SignatureTask signatureTask) {
|
||||||
content.add(new Span("Unterschrift erforderlich"));
|
content.add(new Span("Unterschrift erforderlich"));
|
||||||
|
|
||||||
|
// Show signature if task is completed
|
||||||
|
if (task.isCompleted()) {
|
||||||
|
try {
|
||||||
|
ObjectId taskId = new ObjectId(task.getIdAsString());
|
||||||
|
List<Signature> signatures = signatureRepository.findByTaskId(taskId);
|
||||||
|
|
||||||
|
if (!signatures.isEmpty()) {
|
||||||
|
content.add(new Span("")); // Spacer
|
||||||
|
content.add(new Span("Gespeicherte Unterschrift:"));
|
||||||
|
|
||||||
|
// Display the latest signature (assuming one signature per task)
|
||||||
|
Signature signature = signatures.get(signatures.size() - 1);
|
||||||
|
String svgContent = signature.getSignatureSvg();
|
||||||
|
|
||||||
|
if (svgContent != null && !svgContent.isBlank()) {
|
||||||
|
// Create a div to hold the SVG
|
||||||
|
Div svgContainer = new Div();
|
||||||
|
svgContainer.getStyle()
|
||||||
|
.set("border", "1px solid var(--lumo-contrast-20pct)")
|
||||||
|
.set("border-radius", "var(--lumo-border-radius-m)")
|
||||||
|
.set("padding", "var(--lumo-space-s)")
|
||||||
|
.set("background-color", "white")
|
||||||
|
.set("width", "100%")
|
||||||
|
.set("max-width", "450px")
|
||||||
|
.set("overflow", "hidden")
|
||||||
|
.set("display", "flex")
|
||||||
|
.set("align-items", "center")
|
||||||
|
.set("justify-content", "center");
|
||||||
|
|
||||||
|
// Process SVG to make it responsive
|
||||||
|
String responsiveSvg = makeResponsiveSvg(svgContent);
|
||||||
|
svgContainer.getElement().setProperty("innerHTML", responsiveSvg);
|
||||||
|
content.add(svgContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore errors when loading signature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (task instanceof BarcodeTask barcodeTask) {
|
||||||
|
content.add(new Span("Barcode-Scan erforderlich"));
|
||||||
|
|
||||||
|
// Show barcodes if task is completed
|
||||||
|
if (task.isCompleted()) {
|
||||||
|
try {
|
||||||
|
ObjectId taskId = new ObjectId(task.getIdAsString());
|
||||||
|
List<Barcode> barcodes = barcodeRepository.findByTaskId(taskId);
|
||||||
|
|
||||||
|
if (!barcodes.isEmpty()) {
|
||||||
|
content.add(new Span("")); // Spacer
|
||||||
|
content.add(new Span("Gescannte Barcodes (" + barcodes.size() + "):"));
|
||||||
|
|
||||||
|
// Display all scanned barcodes
|
||||||
|
for (int i = 0; i < barcodes.size(); i++) {
|
||||||
|
Barcode barcode = barcodes.get(i);
|
||||||
|
String barcodeValue = barcode.getBarcode();
|
||||||
|
|
||||||
|
if (barcodeValue != null && !barcodeValue.isBlank()) {
|
||||||
|
// Create a styled container for each barcode
|
||||||
|
Div barcodeContainer = new Div();
|
||||||
|
barcodeContainer.getStyle()
|
||||||
|
.set("border", "1px solid var(--lumo-contrast-20pct)")
|
||||||
|
.set("border-radius", "var(--lumo-border-radius-s)")
|
||||||
|
.set("padding", "var(--lumo-space-s)")
|
||||||
|
.set("margin", "var(--lumo-space-xs) 0")
|
||||||
|
.set("background-color", "var(--lumo-contrast-5pct)")
|
||||||
|
.set("font-family", "monospace")
|
||||||
|
.set("font-size", "var(--lumo-font-size-s)")
|
||||||
|
.set("word-break", "break-all");
|
||||||
|
|
||||||
|
Span barcodeSpan = new Span((i + 1) + ". " + barcodeValue);
|
||||||
|
barcodeContainer.add(barcodeSpan);
|
||||||
|
content.add(barcodeContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore errors when loading barcodes
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,6 +682,8 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
|||||||
return new Icon(VaadinIcon.EDIT);
|
return new Icon(VaadinIcon.EDIT);
|
||||||
} else if (task instanceof ConfirmationTask) {
|
} else if (task instanceof ConfirmationTask) {
|
||||||
return new Icon(VaadinIcon.CHECK_CIRCLE);
|
return new Icon(VaadinIcon.CHECK_CIRCLE);
|
||||||
|
} else if (task instanceof BarcodeTask) {
|
||||||
|
return new Icon(VaadinIcon.BARCODE);
|
||||||
} else {
|
} else {
|
||||||
return new Icon(VaadinIcon.TASKS);
|
return new Icon(VaadinIcon.TASKS);
|
||||||
}
|
}
|
||||||
@@ -571,11 +715,194 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
|
|||||||
} else {
|
} else {
|
||||||
return "Bestätigung erforderlich";
|
return "Bestätigung erforderlich";
|
||||||
}
|
}
|
||||||
|
} else if (task instanceof BarcodeTask) {
|
||||||
|
return "Barcode-Scan erforderlich";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Aufgabe offen";
|
return "Aufgabe offen";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Div createPhotoGallery(List<String> photos) {
|
||||||
|
Div galleryContainer = new Div();
|
||||||
|
galleryContainer.getStyle()
|
||||||
|
.set("border", "1px solid var(--lumo-contrast-20pct)")
|
||||||
|
.set("border-radius", "var(--lumo-border-radius-m)")
|
||||||
|
.set("padding", "var(--lumo-space-m)")
|
||||||
|
.set("background-color", "white")
|
||||||
|
.set("max-width", "600px")
|
||||||
|
.set("min-height", "500px")
|
||||||
|
.set("height", "500px")
|
||||||
|
.set("position", "relative")
|
||||||
|
.set("display", "flex")
|
||||||
|
.set("align-items", "center")
|
||||||
|
.set("justify-content", "center");
|
||||||
|
|
||||||
|
if (photos.size() == 1) {
|
||||||
|
// Single photo - no navigation needed
|
||||||
|
Div photoContainer = createPhotoContainer(photos.get(0));
|
||||||
|
photoContainer.getStyle()
|
||||||
|
.set("flex", "1")
|
||||||
|
.set("display", "flex")
|
||||||
|
.set("align-items", "center")
|
||||||
|
.set("justify-content", "center");
|
||||||
|
galleryContainer.add(photoContainer);
|
||||||
|
} else {
|
||||||
|
// Multiple photos - add navigation
|
||||||
|
final int[] currentIndex = {0}; // Use array to make it effectively final
|
||||||
|
|
||||||
|
// Photo counter
|
||||||
|
Span photoCounter = new Span((currentIndex[0] + 1) + " / " + photos.size());
|
||||||
|
photoCounter.getStyle()
|
||||||
|
.set("position", "absolute")
|
||||||
|
.set("top", "var(--lumo-space-s)")
|
||||||
|
.set("right", "var(--lumo-space-s)")
|
||||||
|
.set("background-color", "rgba(0, 0, 0, 0.6)")
|
||||||
|
.set("color", "white")
|
||||||
|
.set("padding", "var(--lumo-space-xs) var(--lumo-space-s)")
|
||||||
|
.set("border-radius", "var(--lumo-border-radius-s)")
|
||||||
|
.set("font-size", "var(--lumo-font-size-s)")
|
||||||
|
.set("z-index", "10");
|
||||||
|
|
||||||
|
// Photo container
|
||||||
|
Div photoContainer = createPhotoContainer(photos.get(0));
|
||||||
|
photoContainer.getStyle()
|
||||||
|
.set("margin", "0 40px") // Space for buttons
|
||||||
|
.set("flex", "1")
|
||||||
|
.set("display", "flex")
|
||||||
|
.set("align-items", "center")
|
||||||
|
.set("justify-content", "center");
|
||||||
|
|
||||||
|
// Previous button
|
||||||
|
Button prevButton = new Button(new Icon(VaadinIcon.CHEVRON_LEFT));
|
||||||
|
prevButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_ICON);
|
||||||
|
prevButton.getStyle()
|
||||||
|
.set("position", "absolute")
|
||||||
|
.set("left", "var(--lumo-space-s)")
|
||||||
|
.set("top", "50%")
|
||||||
|
.set("transform", "translateY(-50%)")
|
||||||
|
.set("background-color", "rgba(255, 255, 255, 0.8)")
|
||||||
|
.set("border-radius", "50%")
|
||||||
|
.set("z-index", "10");
|
||||||
|
|
||||||
|
// Next button
|
||||||
|
Button nextButton = new Button(new Icon(VaadinIcon.CHEVRON_RIGHT));
|
||||||
|
nextButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_ICON);
|
||||||
|
nextButton.getStyle()
|
||||||
|
.set("position", "absolute")
|
||||||
|
.set("right", "var(--lumo-space-s)")
|
||||||
|
.set("top", "50%")
|
||||||
|
.set("transform", "translateY(-50%)")
|
||||||
|
.set("background-color", "rgba(255, 255, 255, 0.8)")
|
||||||
|
.set("border-radius", "50%")
|
||||||
|
.set("z-index", "10");
|
||||||
|
|
||||||
|
// Navigation logic
|
||||||
|
prevButton.addClickListener(e -> {
|
||||||
|
if (currentIndex[0] > 0) {
|
||||||
|
currentIndex[0]--;
|
||||||
|
updatePhotoDisplay(photoContainer, photos.get(currentIndex[0]), photoCounter, currentIndex[0] + 1, photos.size());
|
||||||
|
}
|
||||||
|
prevButton.setEnabled(currentIndex[0] > 0);
|
||||||
|
nextButton.setEnabled(currentIndex[0] < photos.size() - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
nextButton.addClickListener(e -> {
|
||||||
|
if (currentIndex[0] < photos.size() - 1) {
|
||||||
|
currentIndex[0]++;
|
||||||
|
updatePhotoDisplay(photoContainer, photos.get(currentIndex[0]), photoCounter, currentIndex[0] + 1, photos.size());
|
||||||
|
}
|
||||||
|
prevButton.setEnabled(currentIndex[0] > 0);
|
||||||
|
nextButton.setEnabled(currentIndex[0] < photos.size() - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initial button states
|
||||||
|
prevButton.setEnabled(false);
|
||||||
|
nextButton.setEnabled(photos.size() > 1);
|
||||||
|
|
||||||
|
galleryContainer.add(photoCounter, photoContainer, prevButton, nextButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
return galleryContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Div createPhotoContainer(String base64Photo) {
|
||||||
|
Div photoContainer = new Div();
|
||||||
|
photoContainer.getStyle()
|
||||||
|
.set("width", "100%")
|
||||||
|
.set("height", "100%")
|
||||||
|
.set("display", "flex")
|
||||||
|
.set("align-items", "center")
|
||||||
|
.set("justify-content", "center")
|
||||||
|
.set("overflow", "hidden");
|
||||||
|
|
||||||
|
// Create image element
|
||||||
|
String imgSrc = base64Photo.startsWith("data:") ? base64Photo : "data:image/jpeg;base64," + base64Photo;
|
||||||
|
|
||||||
|
photoContainer.getElement().setProperty("innerHTML",
|
||||||
|
"<img src='" + imgSrc + "' style='max-width: 100%; max-height: 450px; object-fit: contain; border-radius: var(--lumo-border-radius-s); box-shadow: 0 2px 8px rgba(0,0,0,0.1);' />");
|
||||||
|
|
||||||
|
return photoContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePhotoDisplay(Div photoContainer, String base64Photo, Span counter, int current, int total) {
|
||||||
|
String imgSrc = base64Photo.startsWith("data:") ? base64Photo : "data:image/jpeg;base64," + base64Photo;
|
||||||
|
|
||||||
|
photoContainer.getElement().setProperty("innerHTML",
|
||||||
|
"<img src='" + imgSrc + "' style='max-width: 100%; max-height: 450px; object-fit: contain; border-radius: var(--lumo-border-radius-s); box-shadow: 0 2px 8px rgba(0,0,0,0.1);' />");
|
||||||
|
|
||||||
|
counter.setText(current + " / " + total);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeResponsiveSvg(String svgContent) {
|
||||||
|
if (svgContent == null || svgContent.isBlank()) {
|
||||||
|
return svgContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any existing width and height attributes and add responsive styling
|
||||||
|
String responsiveSvg = svgContent
|
||||||
|
.replaceAll("width\\s*=\\s*[\"'][^\"']*[\"']", "")
|
||||||
|
.replaceAll("height\\s*=\\s*[\"'][^\"']*[\"']", "")
|
||||||
|
.replaceAll("style\\s*=\\s*[\"'][^\"']*[\"']", "");
|
||||||
|
|
||||||
|
// Add responsive styling - preserve viewBox if it exists, otherwise try to extract from width/height
|
||||||
|
if (!responsiveSvg.contains("viewBox")) {
|
||||||
|
// Try to extract original dimensions for viewBox
|
||||||
|
String widthMatch = extractAttribute(svgContent, "width");
|
||||||
|
String heightMatch = extractAttribute(svgContent, "height");
|
||||||
|
|
||||||
|
if (widthMatch != null && heightMatch != null) {
|
||||||
|
try {
|
||||||
|
// Clean numbers (remove px, pt, etc.)
|
||||||
|
String cleanWidth = widthMatch.replaceAll("[^0-9.]", "");
|
||||||
|
String cleanHeight = heightMatch.replaceAll("[^0-9.]", "");
|
||||||
|
|
||||||
|
if (!cleanWidth.isEmpty() && !cleanHeight.isEmpty()) {
|
||||||
|
responsiveSvg = responsiveSvg.replaceFirst("<svg",
|
||||||
|
"<svg viewBox=\"0 0 " + cleanWidth + " " + cleanHeight + "\"");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore extraction errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add responsive styling
|
||||||
|
responsiveSvg = responsiveSvg.replaceFirst("<svg",
|
||||||
|
"<svg style=\"max-width: 100%; max-height: 200px; width: auto; height: auto;\"");
|
||||||
|
|
||||||
|
return responsiveSvg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractAttribute(String svg, String attributeName) {
|
||||||
|
String pattern = attributeName + "\\s*=\\s*[\"']([^\"']*)[\"']";
|
||||||
|
java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern, java.util.regex.Pattern.CASE_INSENSITIVE);
|
||||||
|
java.util.regex.Matcher matcher = p.matcher(svg);
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void resetAllTaskCardHoverStates() {
|
private void resetAllTaskCardHoverStates() {
|
||||||
// Reset hover state for all task cards
|
// Reset hover state for all task cards
|
||||||
for (Div taskCard : taskCards) {
|
for (Div taskCard : taskCards) {
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import org.bson.types.ObjectId;
|
|||||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface BarcodeRepository extends MongoRepository<Barcode, ObjectId> {
|
public interface BarcodeRepository extends MongoRepository<Barcode, ObjectId> {
|
||||||
|
List<Barcode> findByTaskId(ObjectId taskId);
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,9 @@ import org.bson.types.ObjectId;
|
|||||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface SignatureRepository extends MongoRepository<Signature, ObjectId> {
|
public interface SignatureRepository extends MongoRepository<Signature, ObjectId> {
|
||||||
|
List<Signature> findByTaskId(ObjectId taskId);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user