Erweiterungen

This commit is contained in:
2025-09-16 08:40:21 +02:00
parent 9aef567ef9
commit 2444574d35
8 changed files with 99 additions and 31 deletions

Binary file not shown.

View File

@@ -1,6 +1,7 @@
package de.assecutor.votianlt.config; package de.assecutor.votianlt.config;
import de.assecutor.votianlt.model.task.*; import de.assecutor.votianlt.model.task.*;
import de.assecutor.votianlt.model.task.CommentTask;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
@@ -96,6 +97,17 @@ public class MongoConfig {
((BarcodeTask) task).setMaxBarcodeCount(source.getInteger("max_barcode_count")); ((BarcodeTask) task).setMaxBarcodeCount(source.getInteger("max_barcode_count"));
} }
break; break;
case "de.assecutor.votianlt.model.task.CommentTask":
case "CommentTask":
log.debug("Creating CommentTask");
task = new CommentTask();
if (source.containsKey("comment_text")) {
((CommentTask) task).setCommentText(source.getString("comment_text"));
}
if (source.containsKey("required")) {
((CommentTask) task).setRequired(source.getBoolean("required", false));
}
break;
default: default:
log.warn("Unknown className '{}', falling back to ConfirmationTask", className); log.warn("Unknown className '{}', falling back to ConfirmationTask", className);
task = new ConfirmationTask(); // fallback task = new ConfirmationTask(); // fallback
@@ -109,9 +121,6 @@ public class MongoConfig {
if (source.containsKey("job_id")) { if (source.containsKey("job_id")) {
task.setJobId(source.getObjectId("job_id")); task.setJobId(source.getObjectId("job_id"));
} }
if (source.containsKey("text")) {
task.setText(source.getString("text"));
}
if (source.containsKey("task_order")) { if (source.containsKey("task_order")) {
task.setTaskOrder(source.getInteger("task_order", 0)); task.setTaskOrder(source.getInteger("task_order", 0));
} }
@@ -150,6 +159,8 @@ public class MongoConfig {
return "de.assecutor.votianlt.model.task.TodoListTask"; return "de.assecutor.votianlt.model.task.TodoListTask";
case "BARCODE": case "BARCODE":
return "de.assecutor.votianlt.model.task.BarcodeTask"; return "de.assecutor.votianlt.model.task.BarcodeTask";
case "COMMENT":
return "de.assecutor.votianlt.model.task.CommentTask";
default: default:
return "de.assecutor.votianlt.model.task.ConfirmationTask"; return "de.assecutor.votianlt.model.task.ConfirmationTask";
} }

View File

@@ -21,7 +21,8 @@ import java.time.LocalDateTime;
@JsonSubTypes.Type(value = SignatureTask.class, name = "SIGNATURE"), @JsonSubTypes.Type(value = SignatureTask.class, name = "SIGNATURE"),
@JsonSubTypes.Type(value = TodoListTask.class, name = "TODOLIST"), @JsonSubTypes.Type(value = TodoListTask.class, name = "TODOLIST"),
@JsonSubTypes.Type(value = PhotoTask.class, name = "PHOTO"), @JsonSubTypes.Type(value = PhotoTask.class, name = "PHOTO"),
@JsonSubTypes.Type(value = BarcodeTask.class, name = "BARCODE") }) @JsonSubTypes.Type(value = BarcodeTask.class, name = "BARCODE"),
@JsonSubTypes.Type(value = CommentTask.class, name = "COMMENT") })
public abstract class BaseTask { public abstract class BaseTask {
@Id @Id
@JsonIgnore @JsonIgnore
@@ -31,9 +32,6 @@ public abstract class BaseTask {
@JsonIgnore @JsonIgnore
private ObjectId jobId; private ObjectId jobId;
@Field("text")
private String text;
@Field("task_order") @Field("task_order")
private Integer taskOrder = 0; private Integer taskOrder = 0;

View File

@@ -0,0 +1,44 @@
package de.assecutor.votianlt.model.task;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Field;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class CommentTask extends BaseTask {
@Field("comment_text")
private String commentText;
@Field("required")
private boolean required = false;
public CommentTask(String commentText, boolean required) {
this.commentText = commentText;
this.required = required;
}
@Override
public String getTaskType() {
return "COMMENT";
}
@Override
public String getDisplayName() {
return "Kommentar";
}
@Override
public Object getTaskSpecificData() {
return new TaskSpecificData();
}
public class TaskSpecificData {
public String taskType = getTaskType();
public String commentText = CommentTask.this.commentText;
public boolean required = CommentTask.this.required;
}
}

View File

@@ -1,7 +1,7 @@
package de.assecutor.votianlt.model.task; package de.assecutor.votianlt.model.task;
public enum TaskType { public enum TaskType {
CONFIRMATION("Bestätigung"), SIGNATURE("Unterschrift"), TODOLIST("To-Do Liste"), PHOTO("Foto"), BARCODE("Barcode"); CONFIRMATION("Bestätigung"), SIGNATURE("Unterschrift"), TODOLIST("To-Do Liste"), PHOTO("Foto"), BARCODE("Barcode"), COMMENT("Kommentar");
private final String displayName; private final String displayName;

View File

@@ -35,6 +35,7 @@ import de.assecutor.votianlt.model.task.SignatureTask;
import de.assecutor.votianlt.model.task.TodoListTask; 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.BarcodeTask; import de.assecutor.votianlt.model.task.BarcodeTask;
import de.assecutor.votianlt.model.task.CommentTask;
import de.assecutor.votianlt.pages.service.AddJobService; import de.assecutor.votianlt.pages.service.AddJobService;
import de.assecutor.votianlt.pages.service.CustomerService; import de.assecutor.votianlt.pages.service.CustomerService;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar; import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
@@ -1531,24 +1532,24 @@ public class AddJobView extends Main {
BaseTask newTask = createTaskByType(selectedType); BaseTask newTask = createTaskByType(selectedType);
BaseTask oldTask = currentTask[0]; BaseTask oldTask = currentTask[0];
newTask.setText(oldTask.getText());
newTask.setCompleted(oldTask.isCompleted()); newTask.setCompleted(oldTask.isCompleted());
newTask.setCompletedAt(oldTask.getCompletedAt()); newTask.setCompletedAt(oldTask.getCompletedAt());
newTask.setCompletedBy(oldTask.getCompletedBy()); newTask.setCompletedBy(oldTask.getCompletedBy());
// Preserve task-specific properties // Preserve task-specific properties
if (oldTask instanceof ConfirmationTask oldConfirmationTask switch (oldTask) {
&& newTask instanceof ConfirmationTask newConfirmationTask) { case ConfirmationTask oldConfirmationTask when newTask instanceof ConfirmationTask newConfirmationTask -> newConfirmationTask.setButtonText(oldConfirmationTask.getButtonText());
newConfirmationTask.setButtonText(oldConfirmationTask.getButtonText()); case TodoListTask oldTodoTask when newTask instanceof TodoListTask newTodoTask -> newTodoTask.setTodoItems(oldTodoTask.getTodoItems());
} else if (oldTask instanceof TodoListTask oldTodoTask && newTask instanceof TodoListTask newTodoTask) { case PhotoTask oldPhotoTask when newTask instanceof PhotoTask newPhotoTask -> {
newTodoTask.setTodoItems(oldTodoTask.getTodoItems()); newPhotoTask.setMinPhotoCount(oldPhotoTask.getMinPhotoCount());
} else if (oldTask instanceof PhotoTask oldPhotoTask && newTask instanceof PhotoTask newPhotoTask) { newPhotoTask.setMaxPhotoCount(oldPhotoTask.getMaxPhotoCount());
newPhotoTask.setMinPhotoCount(oldPhotoTask.getMinPhotoCount()); }
newPhotoTask.setMaxPhotoCount(oldPhotoTask.getMaxPhotoCount()); case BarcodeTask oldBarcodeTask when newTask instanceof BarcodeTask newBarcodeTask -> {
} else if (oldTask instanceof BarcodeTask oldBarcodeTask newBarcodeTask.setMinBarcodeCount(oldBarcodeTask.getMinBarcodeCount());
&& newTask instanceof BarcodeTask newBarcodeTask) { newBarcodeTask.setMaxBarcodeCount(oldBarcodeTask.getMaxBarcodeCount());
newBarcodeTask.setMinBarcodeCount(oldBarcodeTask.getMinBarcodeCount()); }
newBarcodeTask.setMaxBarcodeCount(oldBarcodeTask.getMaxBarcodeCount()); default -> {
}
} }
// Replace in state and preserve order // Replace in state and preserve order
@@ -1577,6 +1578,7 @@ public class AddJobView extends Main {
case TODOLIST -> new TodoListTask(new ArrayList<>()); case TODOLIST -> new TodoListTask(new ArrayList<>());
case PHOTO -> new PhotoTask(1, 10); case PHOTO -> new PhotoTask(1, 10);
case BARCODE -> new BarcodeTask(1, 10); case BARCODE -> new BarcodeTask(1, 10);
case COMMENT -> new CommentTask("", false);
}; };
} }
@@ -1594,8 +1596,6 @@ public class AddJobView extends Main {
configContainer.removeAll(); configContainer.removeAll();
TaskType taskType = TaskType.valueOf(task.getTaskType()); TaskType taskType = TaskType.valueOf(task.getTaskType());
if (taskType == null)
return;
switch (taskType) { switch (taskType) {
case CONFIRMATION: case CONFIRMATION:
@@ -1606,12 +1606,8 @@ public class AddJobView extends Main {
buttonTextField.setValue(confirmationTask.getButtonText() != null ? confirmationTask.getButtonText() : ""); buttonTextField.setValue(confirmationTask.getButtonText() != null ? confirmationTask.getButtonText() : "");
buttonTextField.addValueChangeListener(ev -> { buttonTextField.addValueChangeListener(ev -> {
// Find the current ConfirmationTask in tasksState and update it // Find the current ConfirmationTask in tasksState and update it
for (int i = 0; i < tasksState.size(); i++) { for (BaseTask stateTask : tasksState) {
BaseTask stateTask = tasksState.get(i); ((ConfirmationTask) stateTask).setButtonText(ev.getValue());
if (stateTask == task && stateTask instanceof ConfirmationTask) {
((ConfirmationTask) stateTask).setButtonText(ev.getValue());
break;
}
} }
}); });
configContainer.add(buttonTextField); configContainer.add(buttonTextField);
@@ -1735,8 +1731,7 @@ public class AddJobView extends Main {
private void updateTodoItems(VerticalLayout todoList, BaseTask task) { private void updateTodoItems(VerticalLayout todoList, BaseTask task) {
List<String> todoItems = todoList.getChildren().map(component -> { List<String> todoItems = todoList.getChildren().map(component -> {
if (component instanceof HorizontalLayout) { if (component instanceof HorizontalLayout row) {
HorizontalLayout row = (HorizontalLayout) component;
TextField field = (TextField) row.getChildren().findFirst().orElse(null); TextField field = (TextField) row.getChildren().findFirst().orElse(null);
return field != null ? field.getValue() : null; return field != null ? field.getValue() : null;
} }

View File

@@ -25,6 +25,7 @@ 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.task.BarcodeTask;
import de.assecutor.votianlt.model.task.CommentTask;
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 lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -579,6 +580,16 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
log.debug("Failed to load barcodes for task {}: {}", task.getId(), e.getMessage()); log.debug("Failed to load barcodes for task {}: {}", task.getId(), e.getMessage());
} }
} }
} else if (task instanceof CommentTask commentTask) {
content.add(new Span("Kommentar erforderlich"));
if (commentTask.getCommentText() != null && !commentTask.getCommentText().isBlank()) {
content.add(new Span("Hinweis: " + commentTask.getCommentText()));
}
if (commentTask.isRequired()) {
content.add(new Span("Pflichtfeld"));
}
} }
} }
@@ -667,6 +678,8 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
return new Icon(VaadinIcon.CHECK_CIRCLE); return new Icon(VaadinIcon.CHECK_CIRCLE);
} else if (task instanceof BarcodeTask) { } else if (task instanceof BarcodeTask) {
return new Icon(VaadinIcon.BARCODE); return new Icon(VaadinIcon.BARCODE);
} else if (task instanceof CommentTask) {
return new Icon(VaadinIcon.COMMENT);
} else { } else {
return new Icon(VaadinIcon.TASKS); return new Icon(VaadinIcon.TASKS);
} }
@@ -704,6 +717,12 @@ public class JobSummaryView extends Main implements HasUrlParameter<String> {
} }
} else if (task instanceof BarcodeTask) { } else if (task instanceof BarcodeTask) {
return "Barcode-Scan erforderlich"; return "Barcode-Scan erforderlich";
} else if (task instanceof CommentTask commentTask) {
if (commentTask.getCommentText() != null && !commentTask.getCommentText().isBlank()) {
return "Kommentar: " + commentTask.getCommentText();
} else {
return "Kommentar erforderlich";
}
} }
return "Aufgabe offen"; return "Aufgabe offen";

View File

@@ -145,6 +145,7 @@ public class EmailService {
case "BARCODE" -> "Barcode scannen"; case "BARCODE" -> "Barcode scannen";
case "CONFIRMATION" -> "Bestätigung"; case "CONFIRMATION" -> "Bestätigung";
case "TODO_LIST" -> "Checkliste"; case "TODO_LIST" -> "Checkliste";
case "COMMENT" -> "Kommentar";
default -> taskType; default -> taskType;
}; };
} }