/
evernotenkai
/
DataBaseXJavaProject
Обзор
Документация
Войти
/
evernotenkai
/
DataBaseXJavaProject
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/app/ui/teacher/TeacherReviewCenterView.java
390 строк
17 KB
Makson4ik
Весь проект с src db и прочим делом
12 май 2026, 22:43
12 май 2026, 22:43
431f4aa
Код
Авторство
О чём код?
package app.ui.teacher; import java.util.ArrayList; import java.util.List; import app.model.AssignmentItem; import app.model.CourseItem; import app.model.SubmissionAttachmentData; import app.model.SubmissionItem; import app.service.LmsService; import app.ui.components.NumericField; import app.ui.components.PageHeader; import app.ui.components.UiKit; import app.util.Dialogs; import app.util.HtmlUtil; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.input.MouseButton; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.control.SplitPane; import javafx.scene.layout.VBox; import javafx.scene.web.WebView; public class TeacherReviewCenterView extends VBox { private final LmsService service; private final int teacherId; private final Runnable onChanged; private final ObservableList<SubmissionItem> items = FXCollections.observableArrayList(); private final ComboBox<CourseItem> courseFilter = new ComboBox<CourseItem>(); private final ComboBox<AssignmentItem> assignmentFilter = new ComboBox<AssignmentItem>(); private final ComboBox<String> statusFilter = new ComboBox<String>(); private final TextField search = new TextField(); private final TableView<SubmissionItem> table = new TableView<SubmissionItem>(); private final Label courseValue = UiKit.labeled("-", "detail-value"); private final Label assignmentValue = UiKit.labeled("-", "detail-value"); private final Label studentValue = UiKit.labeled("-", "detail-value"); private final Label dateValue = UiKit.labeled("-", "detail-value"); private final Label statusChipHost = UiKit.labeled("", "detail-value"); private final Label attachmentValue = UiKit.labeled("Вложение отсутствует", "detail-value"); private final WebView contentView = new WebView(); private final NumericField gradeField = new NumericField(1, 100); private final TextArea commentArea = new TextArea(); private SubmissionItem selectedSubmission; public TeacherReviewCenterView(final LmsService service, final int teacherId) { this(service, teacherId, null); } public TeacherReviewCenterView(final LmsService service, final int teacherId, Runnable onChanged) { this.service = service; this.teacherId = teacherId; this.onChanged = onChanged; getStyleClass().add("content-root"); setSpacing(14); getChildren().add(new PageHeader("Работы студентов", "Фильтруй отправки, открывай работу в отдельном окне и ставь оценку без лишних дублей.")); buildFilters(); buildTable(); VBox detailsPanel = buildDetailsPanel(); VBox left = UiKit.card( UiKit.section("Список отправок"), UiKit.subtitle("Дважды кликни по работе, чтобы открыть её в отдельном окне."), table ); SplitPane split = new SplitPane(left, detailsPanel); split.setDividerPositions(0.62); split.widthProperty().addListener((obs, oldW, newW) -> split.setDividerPositions(newW.doubleValue() < 1240 ? 0.54 : 0.62)); split.getStyleClass().add("workspace-split-pane"); SplitPane.setResizableWithParent(left, true); SplitPane.setResizableWithParent(detailsPanel, true); getChildren().add(split); refresh(); } private void buildFilters() { courseFilter.setPromptText("Курс"); assignmentFilter.setPromptText("Задание"); search.setPromptText("Поиск по студенту"); statusFilter.getItems().setAll("Все", "submitted", "checked", "returned"); statusFilter.getSelectionModel().select(0); VBox filters = UiKit.card( UiKit.section("Фильтры"), UiKit.subtitle("Сужай список по курсу, заданию, статусу и имени студента."), UiKit.fieldBox("Курс", courseFilter, null), UiKit.fieldBox("Задание", assignmentFilter, null), UiKit.fieldBox("Статус", statusFilter, null), UiKit.fieldBox("Студент", search, null) ); getChildren().add(filters); courseFilter.valueProperty().addListener((obs, o, n) -> { assignmentFilter.getItems().setAll(n == null ? FXCollections.<AssignmentItem>observableArrayList() : service.findAssignmentsForCourse(n.getId())); assignmentFilter.getSelectionModel().clearSelection(); reloadTable(); }); assignmentFilter.valueProperty().addListener((obs, o, n) -> reloadTable()); statusFilter.valueProperty().addListener((obs, o, n) -> reloadTable()); search.textProperty().addListener((obs, o, n) -> reloadTable()); } private void buildTable() { UiKit.configureTable(table); TableColumn<SubmissionItem, String> c1 = new TableColumn<SubmissionItem, String>("Студент"); c1.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getStudentName())); TableColumn<SubmissionItem, String> c2 = new TableColumn<SubmissionItem, String>("Курс"); c2.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getCourseName())); TableColumn<SubmissionItem, String> c3 = new TableColumn<SubmissionItem, String>("Задание"); c3.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getAssignmentTitle())); TableColumn<SubmissionItem, String> c4 = new TableColumn<SubmissionItem, String>("Дата"); c4.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getSubmissionDate())); TableColumn<SubmissionItem, String> c5 = new TableColumn<SubmissionItem, String>("Статус"); c5.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getStatus())); c5.setCellFactory(col -> new TableCell<SubmissionItem, String>() { protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); setText(empty || item == null ? "" : item); setGraphic(empty || item == null ? null : UiKit.chip(item, UiKit.statusClass(item))); } }); TableColumn<SubmissionItem, String> c6 = new TableColumn<SubmissionItem, String>("Вложение"); c6.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getAttachmentName() == null ? "" : v.getValue().getAttachmentName())); c6.setCellFactory(col -> new TableCell<SubmissionItem, String>() { protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); setText(null); setGraphic(empty || item == null || item.trim().isEmpty() ? null : UiKit.chip(item, "file-chip")); } }); TableColumn<SubmissionItem, String> c7 = new TableColumn<SubmissionItem, String>("Оценка"); c7.setCellValueFactory(v -> new SimpleStringProperty(v.getValue().getGradeValue() == null ? "" : String.valueOf(v.getValue().getGradeValue()))); table.getColumns().addAll(c1, c2, c3, c4, c5, c6, c7); table.setItems(items); VBox.setVgrow(table, Priority.ALWAYS); table.getSelectionModel().selectedItemProperty().addListener((obs, old, sel) -> { selectedSubmission = sel; showSelection(sel); }); table.setOnMouseClicked(e -> { if (e.getButton() == MouseButton.PRIMARY && e.getClickCount() == 2) { openSelectedWindow(); } }); } private VBox buildDetailsPanel() { contentView.setPrefHeight(260); contentView.setContextMenuEnabled(false); VBox.setVgrow(contentView, Priority.ALWAYS); gradeField.setPromptText("1..100"); commentArea.setWrapText(true); commentArea.setPrefRowCount(5); Button save = UiKit.primaryButton("Сохранить проверку"); Button open = UiKit.secondaryButton("Открыть в окне"); Button clear = UiKit.ghostButton("Очистить"); save.setOnAction(e -> saveGrade()); open.setOnAction(e -> openSelectedWindow()); clear.setOnAction(e -> clearSelection()); Button openAttachmentBtn = UiKit.ghostButton("Открыть вложение"); openAttachmentBtn.setOnAction(e -> openAttachment()); HBox buttons = new HBox(10, save, open, openAttachmentBtn, clear); buttons.setAlignment(Pos.CENTER_LEFT); VBox panel = UiKit.card( UiKit.section("Проверка выбранной работы"), UiKit.subtitle("Форма очищается при переключении на другую запись, чтобы не подмешивать старые комментарии."), infoLine("Курс", courseValue), infoLine("Задание", assignmentValue), infoLine("Студент", studentValue), infoLine("Дата сдачи", dateValue), infoLine("Статус", statusChipHost), infoLine("Вложение", attachmentValue), UiKit.fieldBox("Текст сдачи", contentView, "Содержимое открывается как документ"), UiKit.fieldBox("Оценка", gradeField, "Ввод только цифрами: 1..100"), UiKit.fieldBox("Комментарий преподавателя", commentArea, "Обратная связь по работе"), buttons ); return panel; } private HBox infoLine(String label, Label value) { HBox row = new HBox(10); row.setAlignment(Pos.CENTER_LEFT); Label key = UiKit.labeled(label, "detail-line"); row.getChildren().addAll(key, value); return row; } private void showSelection(SubmissionItem sel) { if (sel == null) { courseValue.setText("-"); assignmentValue.setText("-"); studentValue.setText("-"); dateValue.setText("-"); attachmentValue.setText("Вложение отсутствует"); statusChipHost.setGraphic(null); contentView.getEngine().loadContent(HtmlUtil.wrapHtml("")); gradeField.clear(); commentArea.clear(); return; } courseValue.setText(sel.getCourseName()); assignmentValue.setText(sel.getAssignmentTitle()); studentValue.setText(sel.getStudentName()); dateValue.setText(sel.getSubmissionDate()); attachmentValue.setText(sel.getAttachmentName() == null ? "Вложение отсутствует" : sel.getAttachmentName()); statusChipHost.setGraphic(UiKit.chip(sel.getStatus(), UiKit.statusClass(sel.getStatus()))); contentView.getEngine().loadContent(HtmlUtil.wrapHtml(sel.getContentNote())); gradeField.setIntValue(sel.getGradeValue()); commentArea.setText(sel.getTeacherComment() == null ? "" : sel.getTeacherComment()); } private void saveGrade() { try { if (selectedSubmission == null) { Dialogs.info("Проверка", "Сначала выбери работу."); return; } final int id = selectedSubmission.getId(); Integer gradeValue = gradeField.getIntValue(); if (gradeValue == null) { Dialogs.info("Проверка", "Укажи оценку от 1 до 100."); return; } service.upsertGrade(id, gradeValue.intValue(), commentArea.getText()); refresh(); selectById(id); notifyChanged(); Dialogs.info("Проверка", "Оценка сохранена."); } catch (Exception ex) { Dialogs.error("Ошибка проверки", ex); } } private void openSelectedWindow() { if (selectedSubmission == null) { Dialogs.info("Проверка", "Выбери работу в таблице."); return; } final int submissionId = selectedSubmission.getId(); TeacherSubmissionWindow window = new TeacherSubmissionWindow(service, selectedSubmission, new Runnable() { @Override public void run() { refresh(); notifyChanged(); selectById(submissionId); } }); window.show(); } private void openAttachment() { if (selectedSubmission == null) { Dialogs.info("Проверка", "Выбери работу в таблице."); return; } try { SubmissionAttachmentData attachment = service.findSubmissionAttachment(selectedSubmission.getId()); if (attachment == null || !attachment.hasData()) { Dialogs.info("Вложение", "У этой работы нет прикреплённого файла."); return; } TeacherSubmissionWindow.saveAndOpenAttachment(attachment, "submission-" + selectedSubmission.getId()); } catch (Exception ex) { Dialogs.error("Вложение", ex); } } private void clearSelection() { selectedSubmission = null; table.getSelectionModel().clearSelection(); showSelection(null); } private void reloadTable() { items.setAll(service.findTeacherSubmissions(teacherId)); List<SubmissionItem> filtered = new ArrayList<SubmissionItem>(); CourseItem course = courseFilter.getValue(); AssignmentItem ass = assignmentFilter.getValue(); String status = statusFilter.getValue(); String q = search.getText() == null ? "" : search.getText().trim().toLowerCase(); for (SubmissionItem s : items) { if (course != null && s.getCourseId() != course.getId()) continue; if (ass != null && s.getAssignmentId() != ass.getId()) continue; if (status != null && !"Все".equals(status) && !status.equalsIgnoreCase(s.getStatus())) continue; if (!q.isEmpty() && (s.getStudentName() == null || !s.getStudentName().toLowerCase().contains(q))) continue; filtered.add(s); } int selectedBeforeId = selectedSubmission == null ? -1 : selectedSubmission.getId(); items.setAll(filtered); table.setItems(items); if (selectedBeforeId >= 0) { boolean matched = false; for (SubmissionItem item : items) { if (item.getId() == selectedBeforeId) { selectedSubmission = item; table.getSelectionModel().select(item); showSelection(item); matched = true; break; } } if (!matched) { clearSelection(); } } } public void refresh() { List<CourseItem> teacherCourses = service.findTeacherCourses(teacherId); CourseItem currentCourse = courseFilter.getValue(); courseFilter.getItems().setAll(teacherCourses); if (currentCourse != null) { for (CourseItem c : teacherCourses) { if (c.getId() == currentCourse.getId()) { courseFilter.getSelectionModel().select(c); break; } } } if (courseFilter.getValue() == null && !teacherCourses.isEmpty()) { courseFilter.getSelectionModel().select(0); } if (courseFilter.getValue() != null) { assignmentFilter.getItems().setAll(service.findAssignmentsForCourse(courseFilter.getValue().getId())); } else { assignmentFilter.getItems().clear(); } if (assignmentFilter.getValue() != null) { boolean keep = false; for (AssignmentItem item : assignmentFilter.getItems()) { if (item.getId() == assignmentFilter.getValue().getId()) { keep = true; break; } } if (!keep) { assignmentFilter.getSelectionModel().clearSelection(); } } reloadTable(); } private void selectById(int id) { for (SubmissionItem item : items) { if (item.getId() == id) { table.getSelectionModel().select(item); showSelection(item); return; } } } private void notifyChanged() { if (onChanged != null) { onChanged.run(); } } }