重新初始化项目

This commit is contained in:
2025-08-22 19:55:19 +08:00
commit 65bc67460b
805 changed files with 83402 additions and 0 deletions

View File

@@ -0,0 +1,439 @@
package com.ecep.contract.manager.ui;
import com.ecep.contract.manager.ds.other.model.IdentityEntity;
import com.ecep.contract.manager.ds.other.vo.IdentityViewModel;
import com.ecep.contract.manager.util.TableViewUtils;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Platform;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.util.converter.NumberStringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
/**
* @param <T> Entity 的类型
* @param <TV> Entity 对应的ViewModel
* @param <Skin> Skin 的类型
* @param <C>
*/
public abstract class AbstEntityManagerSkin<
T extends IdentityEntity,
TV extends IdentityViewModel<T>,
Skin extends ManagerSkin,
C extends AbstManagerWindowController<T, TV, Skin>
> implements ManagerSkin, TableTabSkin<T, TV>, EditableEntityTableTabSkin<T, TV> {
private static final Logger logger = LoggerFactory.getLogger(AbstEntityManagerSkin.class);
/**
*
*/
protected C controller;
protected CompletableFuture<Void> loadedFuture;
protected ObservableList<TV> dataSet = FXCollections.observableArrayList();
protected PageRequest currentPageable = PageRequest.ofSize(25);
protected final SimpleIntegerProperty currentPageNumber = new SimpleIntegerProperty();
public AbstEntityManagerSkin(C controller) {
this.controller = controller;
}
@Override
public TableView<TV> getTableView() {
return controller.table;
}
@Override
public void handleException(String message, Throwable ex) {
if (controller != null) {
controller.handleException(message, ex);
return;
}
if (logger.isErrorEnabled()) {
logger.error(message, ex);
}
UITools.showExceptionAndWait(message, ex);
}
public Locale getLocale() {
return controller.getLocale();
}
public void install() {
onShown();
// 注册 F5 和 Ctrl+R 刷新快捷键
KeyCodeCombination ctrlRCombination = new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN);
KeyCodeCombination f5Combination = new KeyCodeCombination(KeyCode.F5);
getTableView().addEventHandler(KeyEvent.KEY_PRESSED, event -> {
if (ctrlRCombination.match(event) || f5Combination.match(event)) {
System.out.println("loadTableDataSetFuture = " + loadTableDataSetFuture);
if (loadTableDataSetFuture == null) {
loadTableDataSet(false);
}
event.consume();
}
});
}
private void onShown() {
if (loadedFuture == null) {
loadedFuture = runAsync(() -> {
Platform.runLater(() -> {
getTableView().setItems(dataSet);
});
initializeSearchBar();
initializeTable();
initializeFooter();
TableView<TV> table = getTableView();
// 视图更新时
table.layoutBoundsProperty().addListener(this::resizeTable);
// 启用行编辑功能
if (!table.isEditable()) {
TableViewUtils.bindDoubleClicked(table, this::onTableRowDoubleClickedAction);
}
if (table.contextMenuProperty().get() == null) {
ContextMenu contextMenu = new ContextMenu();
createContextMenu(contextMenu);
table.setContextMenu(contextMenu);
}
table.setSortPolicy(v -> {
if (loadTableDataSetFuture == null) {
loadTableDataSet(false);
}
return true;
});
loadTableDataSet(true);
}).exceptionally(this::handleException);
}
}
private void initializeSearchBar() {
if (controller.searchKeyField != null) {
controller.searchKeyField.setOnKeyReleased(event -> {
if (event.getCode() == KeyCode.ENTER) {
controller.searchBtn.fire();
}
});
}
if (controller.searchBtn != null) {
controller.searchBtn.setOnAction(this::onSearchAction);
}
}
private void initializeFooter() {
currentPageNumber.addListener(this::currentPageNumberListener);
//
controller.currentPageNumberField.textProperty().bindBidirectional(currentPageNumber, new NumberStringConverter());
controller.previousPageBtn.setOnAction(event -> {
currentPageable = currentPageable.previous();
loadTableDataSet(true);
});
controller.nextPageBtn.setOnAction(event -> {
currentPageable = currentPageable.next();
loadTableDataSet(true);
});
}
private void currentPageNumberListener(Object obj, Number old, Number newValue) {
int page = newValue.intValue();
if (page < 0) {
page = 0;
}
if (currentPageable.getPageNumber() == page) {
return;
}
currentPageable = currentPageable.withPage(page);
loadTableDataSet(false);
}
public void onSearchAction(ActionEvent event) {
currentPageable = currentPageable.withPage(0);
loadTableDataSet(true);
}
/**
* 根据表格高度重新计算分页的页大小
*/
private void resizeTable(Object observable, Bounds old, Bounds newBounds) {
double tableHeight = newBounds.getHeight();
if (tableHeight <= 0) {
return;
}
TableView<TV> table = getTableView();
Node lookup = table.lookup("TableRow");
if (lookup != null) {
double rowHeight = lookup.prefHeight(-1);
int rows = (int) Math.round(table.getHeight() / rowHeight) - 1;
int pageNumber = (int) Math.abs(currentPageable.getOffset() / rows);
if (currentPageable.getPageNumber() == pageNumber && currentPageable.getPageSize() == rows) {
return;
}
currentPageable = PageRequest.of(pageNumber, rows);
loadTableDataSet(false);
}
}
protected void createContextMenu(ContextMenu contextMenu) {
MenuItem item2 = new MenuItem("刷新");
item2.setOnAction(this::onTableRefreshAction);
contextMenu.getItems().add(item2);
if (this instanceof EditableEntityTableTabSkin) {
MenuItem item1 = new MenuItem("新建");
item1.setOnAction(this::onTableCreateNewAction);
MenuItem item3 = new MenuItem("删除");
item3.setOnAction(this::onTableDeleteAction);
contextMenu.getItems().addAll(item1, item3);
}
}
protected void onTableCreateNewAction(ActionEvent event) {
TV viewModel = createNewViewModel();
dataSet.add(viewModel);
}
protected void onTableRefreshAction(ActionEvent event) {
loadTableDataSet(false);
}
protected void onTableDeleteAction(ActionEvent event) {
ObservableList<TV> selectedItems = getTableView().getSelectionModel().getSelectedItems();
if (selectedItems.isEmpty()) {
return;
}
if (!UITools.showConfirmDialog("删除行", "确认删除选中的" + selectedItems.size() + "条数据?")) {
return;
}
for (TV selectedItem : new ArrayList<>(selectedItems)) {
if (deleteRow(selectedItem)) {
dataSet.remove(selectedItem);
}
}
}
protected <K> void acceptCellEditEvent(TableColumn.CellEditEvent<TV, K> event, Function<TV, Property<K>> function) {
TV row = event.getRowValue();
Property<K> property = function.apply(row);
property.setValue(event.getNewValue());
try {
saveRowData(row);
} catch (Exception e) {
handleException("保存出错", e);
}
}
protected boolean deleteRow(TV row) {
ViewModelService<T, TV> service = getViewModelService();
T entity = service.findById(row.getId().get());
if (entity != null) {
try {
service.delete(entity);
return true;
} catch (UnsupportedOperationException e) {
handleException("删除出错,此操作不支持", e);
} catch (Exception e) {
handleException("删除出错", e);
}
}
return false;
}
protected T createNewEntity(TV row) {
ViewModelService<T, TV> service = getViewModelService();
if (service != null) {
T entity = service.createNewEntity();
if (entity != null) {
return entity;
}
}
return null;
}
protected TV createNewViewModel() {
ViewModelService<T, TV> service = getViewModelService();
if (service != null) {
TV model = service.createNewViewModel();
if (model != null) {
return model;
}
}
return null;
}
protected void saveRowData(TV row) {
ViewModelService<T, TV> service = getViewModelService();
if (service == null) {
handleException("ViewModelService is null", new RuntimeException());
return;
}
row.saveInFxApplicationThread(service);
}
public T loadRowData(TV row) {
return getViewModelService().findById(row.getId().get());
}
public void deleteRowData(T entity) {
getViewModelService().delete(entity);
}
public T saveRowData(T entity) {
return getViewModelService().save(entity);
}
// 记录延时任务信息
private ScheduledFuture<?> loadTableDataSetFuture;
@Override
public void loadTableDataSet() {
loadTableDataSet(false);
}
/**
* 加载表格数据
* 延时任务未执行前,再次调用此函数时,重新延时
*
* @param reloadNow 是否立即刷新立即刷新将直接submit一个任务到 Executor否则 schedule 一个618毫秒的延时任务
*/
public void loadTableDataSet(boolean reloadNow) {
if (loadTableDataSetFuture != null) {
loadTableDataSetFuture.cancel(true);
}
loadTableDataSetFuture = getExecutorService().schedule(() -> {
try {
_reloadTableData().thenRun(() -> loadTableDataSetFuture = null).exceptionally(this::handleException);
} catch (Exception ex) {
handleException(ex);
}
}, reloadNow ? 0 : 618, TimeUnit.MILLISECONDS);
}
private CompletableFuture<Void> _reloadTableData() {
CompletableFuture<Void> future = new CompletableFuture<>();
Platform.runLater(() -> {
dataSet.clear();
runAsync(() -> {
controller.setStatus("载入中...");
List<TV> models = loadTableData();
Platform.runLater(() -> {
try {
updateTableDataSet(models);
future.complete(null);
} catch (Exception e) {
future.completeExceptionally(e);
}
});
}).exceptionally(ex -> {
future.completeExceptionally(ex);
return null;
});
});
return future;
}
protected void updateTableDataSet(List<TV> models) {
dataSet.setAll(models);
}
protected List<TV> loadTableData() {
Specification<T> spec = getSpecification();
ViewModelService<T, TV> service = getViewModelService();
Page<T> page = service.findAll(spec, getPageable());
updateFooter(page);
return page.map(service::from).toList();
}
protected ViewModelService<T, TV> getViewModelService() {
ViewModelService<T, TV> service = controller.getViewModelService();
if (service == null) {
if (logger.isWarnEnabled()) {
logger.warn("ViewModelService is null");
}
}
return service;
}
public Specification<T> getSpecification() {
TextField field = controller.searchKeyField;
if (field != null) {
return getViewModelService().getSpecification(field.getText());
}
return null;
}
protected Specification<T> getSpecification(String searchText) {
return controller.getViewModelService().getSpecification(searchText);
}
/**
* 当表格行被双击时触发
*
* @param item 被双击的行数据
*/
protected void onTableRowDoubleClickedAction(TV item) {
}
protected void updateFooter(Page<T> page) {
Platform.runLater(() -> {
controller.previousPageBtn.setDisable(!page.hasPrevious());
controller.nextPageBtn.setDisable(!page.hasNext());
currentPageNumber.set(page.getNumber());
controller.setStatus((page.getNumber() + 1) + "/" + page.getTotalPages() + " 页, 总 " + page.getTotalElements() + "");
});
}
public List<Sort.Order> getTableOrders() {
return TableViewUtils.getOrders(getTableView());
}
public Sort getSortByTable() {
return Sort.by(getTableOrders());
}
public Pageable getPageable() {
Sort sort = getSortByTable();
return currentPageable.withSort(sort);
}
protected <Controller extends AbstEntityController<T, TV>> void showInOwner(Class<Controller> clz, TV model) {
BaseController.show(clz, model, getTableView().getScene().getWindow());
}
}