diff --git a/pom.xml b/pom.xml index 8e307cb..a4d8120 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.ecep.contract Contract-Manager - 0.0.46-SNAPSHOT + 0.0.47-SNAPSHOT Contract-Manager Contract-Manager diff --git a/src/main/java/com/ecep/contract/manager/cloud/u8/ContractSyncTask.java b/src/main/java/com/ecep/contract/manager/cloud/u8/ContractSyncTask.java index fc785d5..94dc36b 100644 --- a/src/main/java/com/ecep/contract/manager/cloud/u8/ContractSyncTask.java +++ b/src/main/java/com/ecep/contract/manager/cloud/u8/ContractSyncTask.java @@ -37,7 +37,7 @@ public class ContractSyncTask extends AbstContractRepairTasker { holder.error("无法获取 YongYouU8Repository " + e.getMessage()); return; } - if (getConfService().getBoolean(ContractCtx.KEY_CONTRACT_SYNC_USE_LATEST_ID)) { + if (getConfService().getBoolean(ContractCtx.KEY_SYNC_USE_LATEST_ID)) { syncByLatestId(holder); } else { syncByLatestDate(holder); @@ -45,7 +45,7 @@ public class ContractSyncTask extends AbstContractRepairTasker { } private void syncByLatestId(MessageHolder holder) { - int latestId = getConfService().getInt(ContractCtx.CONTRACT_LATEST_ID); + int latestId = getConfService().getInt(ContractCtx.KEY_SYNC_BY_LATEST_ID); updateTitle("用友U8系统-同步合同,从 " + latestId + " 开始"); Long total = repository.countAllContracts(latestId); @@ -81,11 +81,11 @@ public class ContractSyncTask extends AbstContractRepairTasker { updateProgress(counter.incrementAndGet(), total); }); } - getConfService().set(ContractCtx.CONTRACT_LATEST_ID, String.valueOf(reference.get())); + getConfService().set(ContractCtx.KEY_SYNC_BY_LATEST_ID, String.valueOf(reference.get())); } private void syncByLatestDate(MessageHolder holder) { - String strDateTime = getConfService().getString(ContractCtx.CONTRACT_LATEST_DATE); + String strDateTime = getConfService().getString(ContractCtx.KEY_SYNC_BY_LATEST_DATE); LocalDateTime latestDateTime = null; if (StringUtils.hasText(strDateTime)) { try { @@ -135,7 +135,7 @@ public class ContractSyncTask extends AbstContractRepairTasker { updateProgress(counter.incrementAndGet(), total); }); } - getConfService().set(ContractCtx.CONTRACT_LATEST_DATE, String.valueOf(reference.get())); + getConfService().set(ContractCtx.KEY_SYNC_BY_LATEST_DATE, String.valueOf(reference.get())); } } diff --git a/src/main/java/com/ecep/contract/manager/cloud/u8/YongYouU8ConfigWindowController.java b/src/main/java/com/ecep/contract/manager/cloud/u8/YongYouU8ConfigWindowController.java index 5ffd413..fff2a25 100644 --- a/src/main/java/com/ecep/contract/manager/cloud/u8/YongYouU8ConfigWindowController.java +++ b/src/main/java/com/ecep/contract/manager/cloud/u8/YongYouU8ConfigWindowController.java @@ -42,11 +42,11 @@ public class YongYouU8ConfigWindowController extends BaseController { config1.setPicker(auto_create_company_after); config1.initialize(); - LocalDateConfig config2 = new LocalDateConfig(ContractCtx.CONTRACT_LATEST_DATE); + LocalDateConfig config2 = new LocalDateConfig(ContractCtx.KEY_SYNC_BY_LATEST_DATE); config2.setPicker(contract_latest_date); config2.initialize(); - StringConfig config3 = new StringConfig(ContractCtx.CONTRACT_LATEST_ID); + StringConfig config3 = new StringConfig(ContractCtx.KEY_SYNC_BY_LATEST_ID); config3.setTextField(contract_latest_id); config3.initialize(); diff --git a/src/main/java/com/ecep/contract/manager/cloud/u8/ctx/ContractCtx.java b/src/main/java/com/ecep/contract/manager/cloud/u8/ctx/ContractCtx.java index a473bab..8d17601 100644 --- a/src/main/java/com/ecep/contract/manager/cloud/u8/ctx/ContractCtx.java +++ b/src/main/java/com/ecep/contract/manager/cloud/u8/ctx/ContractCtx.java @@ -44,11 +44,23 @@ import java.util.stream.Stream; import static com.ecep.contract.manager.SpringApp.getBean; +/** + * 合同上下文 + */ public class ContractCtx extends AbstractYongYouU8Ctx { - public static final String CONTRACT_LATEST_DATE = "cloud.u8.contract.latestDate"; - public static final String CONTRACT_LATEST_ID = "cloud.u8.contract.latestId"; - public static final String KEY_CONTRACT_SYNC_USE_LATEST_ID = "cloud.u8.contract.sync.use-latest-id"; - + public static final String KEY_PREFIX = "cloud.u8.contract."; + /** + * 合同同步后的最后一个日期 + */ + public static final String KEY_SYNC_BY_LATEST_DATE = KEY_PREFIX + "latestDate"; + /** + * 合同同步后的最后一个合同ID + */ + public static final String KEY_SYNC_BY_LATEST_ID = KEY_PREFIX + "latestId"; + /** + * 合同同步时是否使用最后更新的Id来判断更新范围,否则使用最后更新的合同日期来判断更新范围 + */ + public static final String KEY_SYNC_USE_LATEST_ID = KEY_PREFIX + "sync.use-latest-id"; @Setter private ContractService contractService; @@ -78,7 +90,6 @@ public class ContractCtx extends AbstractYongYouU8Ctx { @Setter private int customerEntityUpdateDelayDays = 1; - public ContractService getContractService() { if (contractService == null) { contractService = getBean(ContractService.class); @@ -661,7 +672,7 @@ public class ContractCtx extends AbstractYongYouU8Ctx { contract.setGuid(guid); contract.setCode(contractId); contract = service.save(contract); - holder.info("新建合同:" + contractId+", GUID: "+guid); + holder.info("新建合同:" + contractId + ", GUID: " + guid); } } return contract; diff --git a/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractPayPlanService.java b/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractPayPlanService.java index 9c89f76..fe3d8be 100644 --- a/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractPayPlanService.java +++ b/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractPayPlanService.java @@ -19,6 +19,9 @@ import org.springframework.util.StringUtils; import java.util.List; +/** + * 合同支付计划服务 + */ @Lazy @Service @CacheConfig(cacheNames = "contract-pay-plan") diff --git a/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractService.java b/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractService.java index 3ca5ddd..f98c505 100644 --- a/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractService.java +++ b/src/main/java/com/ecep/contract/manager/ds/contract/service/ContractService.java @@ -150,10 +150,10 @@ public class ContractService implements ViewModelService _reloadTableData() { CompletableFuture future = new CompletableFuture<>(); Platform.runLater(() -> { + allowResize = false; // 禁用调整 dataSet.clear(); runAsync(() -> { controller.setStatus("载入中..."); @@ -366,8 +377,10 @@ public abstract class AbstEntityManagerSkin { try { updateTableDataSet(models); + allowResize = true; // 恢复调整 future.complete(null); } catch (Exception e) { + allowResize = true; // 恢复调整 future.completeExceptionally(e); } }); @@ -381,7 +394,23 @@ public abstract class AbstEntityManagerSkin models) { long timeMillis = System.currentTimeMillis(); - dataSet.setAll(models); + // 清除所有选择状态,避免选择状态混乱 + if (getTableView() != null && getTableView().getSelectionModel() != null) { + getTableView().getSelectionModel().clearSelection(); + } + + // 先清空再设置新数据,避免数据叠加 + dataSet.clear(); + if (models != null) { + dataSet.addAll(models); + } + + // 强制刷新表格布局 + if (getTableView() != null) { + getTableView().requestLayout(); + getTableView().refresh(); + } + long timeCost = System.currentTimeMillis() - timeMillis; if (logger.isDebugEnabled()) { logger.debug("update table dataSet cost: {} ms", timeCost); diff --git a/src/main/java/com/ecep/contract/manager/ui/ViewModelService.java b/src/main/java/com/ecep/contract/manager/ui/ViewModelService.java index 2373516..29bf4f1 100644 --- a/src/main/java/com/ecep/contract/manager/ui/ViewModelService.java +++ b/src/main/java/com/ecep/contract/manager/ui/ViewModelService.java @@ -6,6 +6,13 @@ import com.ecep.contract.manager.ds.other.model.IdentityEntity; import com.ecep.contract.manager.ds.other.service.IEntityService; import com.ecep.contract.manager.ds.other.vo.IdentityViewModel; +/** + * 视图模型服务接口 + * + * @param 实体类型 + * @param 视图模型类型 + * @author 2025-08-02 + */ public interface ViewModelService> extends IEntityService { diff --git a/src/main/java/com/ecep/contract/manager/ui/table/cell/AsyncUpdateTableCell.java b/src/main/java/com/ecep/contract/manager/ui/table/cell/AsyncUpdateTableCell.java index fb4aa1d..0e33a51 100644 --- a/src/main/java/com/ecep/contract/manager/ui/table/cell/AsyncUpdateTableCell.java +++ b/src/main/java/com/ecep/contract/manager/ui/table/cell/AsyncUpdateTableCell.java @@ -3,6 +3,8 @@ package com.ecep.contract.manager.ui.table.cell; import java.util.concurrent.Future; import org.hibernate.Hibernate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.ecep.contract.manager.Desktop; import com.ecep.contract.manager.ds.other.model.IdentityEntity; @@ -18,6 +20,8 @@ import javafx.application.Platform; * @param */ public class AsyncUpdateTableCell extends javafx.scene.control.TableCell { + private static final Logger logger = LoggerFactory.getLogger(AsyncUpdateTableCell.class); + /** * 转换为文本 */ @@ -32,6 +36,20 @@ public class AsyncUpdateTableCell extends javafx.sc } private IEntityService service; + Future syncFuture; + + /** + * 通过 #setService 设置服务类,或者子类实现, 提供服务类 + * + * @return + */ + protected IEntityService getServiceBean() { + return null; + } + + public String format(T entity) { + return toString(entity); + } public void setService(IEntityService service) { this.service = service; @@ -44,13 +62,15 @@ public class AsyncUpdateTableCell extends javafx.sc return service; } - protected IEntityService getServiceBean() { - return null; - } - @Override protected void updateItem(T item, boolean empty) { super.updateItem(item, empty); + // 取消之前的异步任务 + if (syncFuture != null) { + syncFuture.cancel(true); + syncFuture = null; + } + if (empty || item == null) { setText(null); return; @@ -59,23 +79,45 @@ public class AsyncUpdateTableCell extends javafx.sc setText(format(item)); return; } + setText("# " + item.getId()); - submit(this::asyncLoadAndUpdate); + syncFuture = submit(this::asyncLoadAndUpdate); } + /** + * 检查实体是否已初始化 + * + * @param proxy + * @return + */ protected boolean isInitialized(T proxy) { return Hibernate.isInitialized(proxy); } + /** + * 初始化实体 + * + * @return + */ + protected T initialize() { + return getService().findById(getItem().getId()); + } + + /** + * 提交异步任务 + * + * @param var1 异步任务 + * @return + */ Future submit(Runnable var1) { return Desktop.instance.getExecutorService().submit(var1); } - public String format(T entity) { - return toString(entity); - } - protected void asyncLoadAndUpdate() { + if (getItem() == null) { + return; + } + T entity = initialize(); String formated; try { @@ -84,14 +126,26 @@ public class AsyncUpdateTableCell extends javafx.sc formated = e.getMessage(); } String texted = formated; + + // 保存当前需要更新的项目信息,避免闭包引用导致的问题 + final T updatedEntity = entity; + final String updatedText = texted; + final T finalCurrentLoadingItem = getItem(); + Platform.runLater(() -> { - setText(texted); - setItem(entity); + // 检查单元格是否仍然显示相同的项目 + // 如果单元格已被重用或当前项目已改变,则不更新 + if (isEmpty() || getItem() == null) { + logger.debug("Skipping async update - cell reused "); + return; + } + if (getItem().getId() != finalCurrentLoadingItem.getId()) { + logger.debug("Skipping async update - cell item changed"); + return; + } + setItem(updatedEntity); + setText(updatedText); }); } - protected T initialize() { - return getService().findById(getItem().getId()); - } - } diff --git a/src/main/java/com/ecep/contract/manager/ui/table/cell/CompanyTableCell.java b/src/main/java/com/ecep/contract/manager/ui/table/cell/CompanyTableCell.java index d3728c1..5930606 100644 --- a/src/main/java/com/ecep/contract/manager/ui/table/cell/CompanyTableCell.java +++ b/src/main/java/com/ecep/contract/manager/ui/table/cell/CompanyTableCell.java @@ -1,11 +1,14 @@ package com.ecep.contract.manager.ui.table.cell; -import com.ecep.contract.manager.ds.company.model.Company; -import com.ecep.contract.manager.ds.company.service.CompanyService; -import lombok.NoArgsConstructor; - import static com.ecep.contract.manager.SpringApp.getBean; +import com.ecep.contract.manager.ds.company.model.Company; +import com.ecep.contract.manager.ds.company.service.CompanyService; + +import lombok.NoArgsConstructor; +/** + * 公司单元格 + */ @NoArgsConstructor public class CompanyTableCell extends AsyncUpdateTableCell { diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 43c821f..c3280f0 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -29,6 +29,7 @@ +