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 @@
+