Files
contract-manager/client/src/main/java/com/ecep/contract/controller/AbstEntityController.java
songqq a1b87de7c0 feat: 添加日志配置和Logback依赖
refactor: 重构实体类equals和hashCode方法

fix: 修复WebSocketService消息发送逻辑

style: 格式化代码和优化导入

docs: 更新JacksonConfig日期序列化格式

test: 添加CompanyFilePathTableCell测试类

chore: 清理无用代码和注释
2025-09-11 19:44:28 +08:00

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();
}