refactor: 重构实体类equals和hashCode方法 fix: 修复WebSocketService消息发送逻辑 style: 格式化代码和优化导入 docs: 更新JacksonConfig日期序列化格式 test: 添加CompanyFilePathTableCell测试类 chore: 清理无用代码和注释
247 lines
7.6 KiB
Java
247 lines
7.6 KiB
Java
package com.ecep.contract.controller;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.function.Function;
|
|
|
|
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
|
import com.ecep.contract.controller.tab.RefreshableSkin;
|
|
import com.ecep.contract.controller.tab.TabSkin;
|
|
import com.ecep.contract.model.IdentityEntity;
|
|
import com.ecep.contract.service.QueryService;
|
|
import com.ecep.contract.service.ViewModelService;
|
|
import com.ecep.contract.util.UITools;
|
|
import com.ecep.contract.vm.BaseViewModel;
|
|
import com.ecep.contract.vm.IdentityViewModel;
|
|
|
|
import javafx.application.Platform;
|
|
import javafx.beans.binding.Bindings;
|
|
import javafx.beans.binding.BooleanBinding;
|
|
import javafx.beans.property.BooleanProperty;
|
|
import javafx.collections.FXCollections;
|
|
import javafx.collections.ObservableList;
|
|
import javafx.scene.control.Button;
|
|
import javafx.scene.control.Tab;
|
|
import javafx.stage.WindowEvent;
|
|
import lombok.Getter;
|
|
import lombok.Setter;
|
|
|
|
public abstract class AbstEntityController<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
|
extends BaseController {
|
|
|
|
/**
|
|
* 保存按钮
|
|
*/
|
|
public Button saveBtn;
|
|
|
|
@Getter
|
|
@Setter
|
|
protected TV viewModel;
|
|
|
|
@Getter
|
|
@Setter
|
|
protected CompletableFuture<T> loadedFuture;
|
|
private final ObservableList<TabSkin> tabSkins = FXCollections.observableArrayList();
|
|
|
|
@Override
|
|
public void onShown(WindowEvent windowEvent) {
|
|
super.onShown(windowEvent);
|
|
ViewModelService<T, TV> service = getViewModelService();
|
|
|
|
if (service instanceof QueryService<T, TV> queryService) {
|
|
setStatus("读取...");
|
|
loadedFuture = queryService.asyncFindById(viewModel.getId().get());
|
|
loadedFuture.thenAccept(entity -> {
|
|
// fixed, bind change if new view model create
|
|
if (viewModel != null) {
|
|
viewModel.bindListener();
|
|
}
|
|
setStatus();
|
|
// BaseViewModel.updateInFxApplicationThread(entity, viewModel);
|
|
});
|
|
loadedFuture.exceptionally(ex -> {
|
|
handleException("载入失败,#" + viewModel.getId().get(), ex);
|
|
return null;
|
|
});
|
|
} else {
|
|
loadedFuture = CompletableFuture.supplyAsync(() -> {
|
|
T entity = getViewModelService().findById(viewModel.getId().get());
|
|
if (entity == null) {
|
|
return null;
|
|
}
|
|
Platform.runLater(() -> {
|
|
setStatus();
|
|
viewModel.update(entity);
|
|
});
|
|
viewModel.bindListener();
|
|
return entity;
|
|
});
|
|
}
|
|
|
|
registerTabSkins();
|
|
if (saveBtn != null) {
|
|
saveBtn.disableProperty().bind(createTabSkinChangedBindings().not());
|
|
saveBtn.setOnAction(event -> saveTabSkins());
|
|
}
|
|
|
|
installTabSkins();
|
|
}
|
|
|
|
public T getEntity() {
|
|
return getLoadedFuture().join();
|
|
}
|
|
|
|
protected void setEntity(T entity) {
|
|
loadedFuture = CompletableFuture.completedFuture(entity);
|
|
BaseViewModel.updateInFxApplicationThread(entity, viewModel);
|
|
}
|
|
|
|
protected T saveEntity(T entity) {
|
|
return getViewModelService().save(entity);
|
|
}
|
|
|
|
public T save(T entity) {
|
|
T saved = saveEntity(entity);
|
|
setEntity(saved);
|
|
return saved;
|
|
}
|
|
|
|
protected void registerTabSkins() {
|
|
}
|
|
|
|
protected <K extends AbstEntityBasedTabSkin<?, ?, ?>> K registerTabSkin(Tab tab, Function<Tab, K> func) {
|
|
K f = func.apply(tab);
|
|
if (f != null) {
|
|
tabSkins.add(f);
|
|
}
|
|
return f;
|
|
}
|
|
|
|
protected void installTabSkins() {
|
|
for (TabSkin tabSkin : tabSkins) {
|
|
try {
|
|
tabSkin.install();
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(tabSkin + ".install", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void saveTabSkins() {
|
|
for (TabSkin tabSkin : tabSkins) {
|
|
try {
|
|
tabSkin.save();
|
|
} catch (Exception e) {
|
|
UITools.showExceptionAndWait("Tab" + tabSkin.getTab().getText() + " 保存失败,请检查", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public TabSkin getTabSkin(Tab tab) {
|
|
for (TabSkin tabSkin : tabSkins) {
|
|
if (tabSkin.getTab() == tab) {
|
|
return tabSkin;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public BooleanBinding createTabSkinChangedBindings() {
|
|
return Bindings.createBooleanBinding(() -> {
|
|
for (TabSkin tabSkin : tabSkins) {
|
|
if (tabSkin.changeProperty().get()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}, tabSkins.stream().map(TabSkin::changeProperty).toArray(BooleanProperty[]::new));
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public <C> C getTabSkin(Class<C> skinClass) {
|
|
for (TabSkin tabSkin : tabSkins) {
|
|
if (tabSkin.getClass().isAssignableFrom(skinClass)) {
|
|
return (C) tabSkin;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void onHidden(WindowEvent windowEvent) {
|
|
if (viewModel != null) {
|
|
try {
|
|
viewModel.unBindListener();
|
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
uninstallTabSkins();
|
|
super.onHidden(windowEvent);
|
|
}
|
|
|
|
protected void uninstallTabSkins() {
|
|
tabSkins.forEach(TabSkin::dispose);
|
|
}
|
|
|
|
/**
|
|
* 刷新
|
|
*
|
|
* @param button 按钮
|
|
*/
|
|
public void refreshByButton(Button button) {
|
|
CompletableFuture.runAsync(() -> {
|
|
button.setDisable(true);
|
|
refresh().whenComplete((v, ex) -> {
|
|
button.setDisable(false);
|
|
if (ex != null) {
|
|
setStatus(ex.getMessage());
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
public CompletableFuture<Void> refresh() {
|
|
CompletableFuture<Void> future = new CompletableFuture<>();
|
|
ViewModelService<T, TV> service = getViewModelService();
|
|
if (service instanceof QueryService<T, TV> queryService) {
|
|
loadedFuture = queryService.asyncFindById(viewModel.getId().get());
|
|
loadedFuture.whenComplete((entity, ex) -> {
|
|
if (ex != null) {
|
|
future.completeExceptionally(ex);
|
|
return;
|
|
}
|
|
BaseViewModel.updateInFxApplicationThread(entity, viewModel);
|
|
});
|
|
} else {
|
|
T entity = service.findById(viewModel.getId().get());
|
|
setEntity(entity);
|
|
}
|
|
|
|
List<RefreshableSkin> list = tabSkins.stream()
|
|
.filter(v -> v instanceof RefreshableSkin)
|
|
.map(v -> ((RefreshableSkin) v)).toList();
|
|
|
|
if (list.isEmpty()) {
|
|
future.complete(null);
|
|
return future;
|
|
}
|
|
|
|
return CompletableFuture.allOf(list
|
|
.stream()
|
|
.map(RefreshableSkin::refresh)
|
|
.filter(Objects::nonNull)
|
|
.toArray(CompletableFuture<?>[]::new))
|
|
.whenComplete((v, ex) -> {
|
|
if (ex != null) {
|
|
future.completeExceptionally(ex);
|
|
} else {
|
|
future.complete(null);
|
|
}
|
|
});
|
|
}
|
|
|
|
public abstract ViewModelService<T, TV> getViewModelService();
|
|
}
|