Compare commits

..

7 Commits

Author SHA1 Message Date
f810532824 fix: 将 AsyncUpdateTableCell 的日志级别从 debug 调整为 warn
修改日志级别以减少不必要的调试信息输出,仅保留警告及以上级别的日志
2025-08-27 14:44:45 +08:00
fb28bac53a refactor(ui): 优化表格数据加载和异步单元格更新逻辑
修复表格高度调整时频繁触发数据加载的问题,增加调整阈值判断
改进异步单元格更新逻辑,增加取消机制和状态检查
重构常量命名,使用更清晰的KEY_SYNC_BY前缀
添加日志记录和注释说明
2025-08-27 14:43:55 +08:00
9ff84ebe8a refactor(u8配置): 重构配置管理相关代码
将配置管理相关代码重构为ConfigBounder接口及其实现类,提取公共逻辑到AbstractConfigBounder基类
修复公司创建日期配置的显示问题,使用更直观的中文描述
将合同同步相关配置常量集中到ContractCtx中管理
2025-08-25 19:40:07 +08:00
6711657663 feat(u8): 添加用友U8配置窗口和数据迁移功能
新增用友U8配置窗口,支持日期和文本配置项的编辑与保存。实现从CloudInfo到CloudYu的数据迁移任务,优化任务执行方式。重构多个同步任务类继承Tasker基类,统一任务处理逻辑。扩展YongYouU8Service功能,添加配置相关接口。调整UI布局和菜单项,增加配置入口。

refactor: 重命名CompanyTableCell为EmployeeRoleTableCell

style: 清理无用导入和格式化代码

fix: 修复ContractTypeSyncTask中分类和方向字段设置错误
2025-08-25 18:57:17 +08:00
17e326b35c refactor(ui): 重命名并移动EvaluationFileTableCell为CompanyTableCell
将EvaluationFileTableCell从project.controller包移动到table.cell包,并重命名为CompanyTableCell。同时修改其实现以使用CompanyService而非CompanyCustomerFileService,使其更符合新的业务需求。
2025-08-25 18:56:55 +08:00
danyz
fa25130c9f Merge branch 'main' of http://10.84.210.110/songqq/contract-manager into main 2025-08-25 00:41:45 +08:00
danyz
b0b67b5d7f feat(任务监控): 添加Executor信息监控面板并重构界面
重构任务监控界面布局,将演示任务功能移至监控窗口工具栏
新增Executor信息监控面板,显示线程池详细状态信息
移除主界面中的演示任务按钮,更新项目版本号
2025-08-25 00:41:34 +08:00
44 changed files with 1303 additions and 655 deletions

1
null Normal file
View File

@@ -0,0 +1 @@
Active code page: 65001

View File

@@ -10,7 +10,7 @@
</parent> </parent>
<groupId>com.ecep.contract</groupId> <groupId>com.ecep.contract</groupId>
<artifactId>Contract-Manager</artifactId> <artifactId>Contract-Manager</artifactId>
<version>0.0.45-SNAPSHOT</version> <version>0.0.47-SNAPSHOT</version>
<name>Contract-Manager</name> <name>Contract-Manager</name>
<description>Contract-Manager</description> <description>Contract-Manager</description>
<url/> <url/>

View File

@@ -1,10 +1,28 @@
package com.ecep.contract.manager; package com.ecep.contract.manager;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import com.ecep.contract.manager.ds.other.controller.LoginWidowController; import com.ecep.contract.manager.ds.other.controller.LoginWidowController;
import com.ecep.contract.manager.ui.BaseController; import com.ecep.contract.manager.ui.BaseController;
import com.ecep.contract.manager.ui.MessageHolder; import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.task.TaskMonitorCenter; import com.ecep.contract.manager.ui.task.TaskMonitorCenter;
import com.ecep.contract.manager.util.UITools; import com.ecep.contract.manager.util.UITools;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
@@ -19,18 +37,6 @@ import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import lombok.Getter; import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.*;
import java.util.logging.Level;
/** /**
* JavaFx 应用程序 * JavaFx 应用程序
@@ -122,6 +128,10 @@ public class Desktop extends Application {
} }
} }
public CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFuture.runAsync(runnable, getExecutorService());
}
private void startSpringApp(Stage primaryStage, Parent root, FXMLLoader loader) { private void startSpringApp(Stage primaryStage, Parent root, FXMLLoader loader) {
System.out.println("Desktop.startSpringApp"); System.out.println("Desktop.startSpringApp");
// 更新窗口标题 // 更新窗口标题
@@ -158,7 +168,7 @@ public class Desktop extends Application {
holder.info("启动中,请稍后..."); holder.info("启动中,请稍后...");
CompletableFuture.runAsync(() -> { runAsync(() -> {
try { try {
// //
holder.info("读取配置文件..."); holder.info("读取配置文件...");
@@ -176,7 +186,7 @@ public class Desktop extends Application {
} }
} }
CompletableFuture.runAsync(() -> { runAsync(() -> {
SpringApp.launch(properties, holder); SpringApp.launch(properties, holder);
ConfigurableListableBeanFactory beanFactory = SpringApp.context.getBeanFactory(); ConfigurableListableBeanFactory beanFactory = SpringApp.context.getBeanFactory();

View File

@@ -108,7 +108,7 @@ public class SpringApp {
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
// 在这里调用 startup 性能分析 // 在这里调用 startup 性能分析
analyzeStartupPerformance(startup); analyzeStartupPerformance(startup);
}); }, Desktop.instance.getExecutorService());
} }
/** /**

View File

@@ -12,6 +12,7 @@ import com.ecep.contract.manager.ds.company.repository.CompanyContactRepository;
import com.ecep.contract.manager.ds.company.repository.CompanyOldNameRepository; import com.ecep.contract.manager.ds.company.repository.CompanyOldNameRepository;
import com.ecep.contract.manager.ds.contract.ContractFileType; import com.ecep.contract.manager.ds.contract.ContractFileType;
import com.ecep.contract.manager.ds.other.repository.SysConfRepository; import com.ecep.contract.manager.ds.other.repository.SysConfRepository;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ds.company.repository.CompanyFileRepository; import com.ecep.contract.manager.ds.company.repository.CompanyFileRepository;
import com.ecep.contract.manager.ds.contract.model.Contract; import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.model.ContractFile; import com.ecep.contract.manager.ds.contract.model.ContractFile;
@@ -73,7 +74,7 @@ public class OldVersionService {
@Autowired @Autowired
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
@Autowired @Autowired
private SysConfRepository confRepository; private SysConfService confService;
@Lazy @Lazy
@Autowired @Autowired
private CompanyService companyService; private CompanyService companyService;
@@ -215,7 +216,7 @@ public class OldVersionService {
logger.debug("createSyncTask"); logger.debug("createSyncTask");
} }
boolean autoSyncEnable = confRepository.get("cloud.old.auto_sync.enable", false); boolean autoSyncEnable = confService.getBoolean("cloud.old.auto_sync.enable");
if (!autoSyncEnable) { if (!autoSyncEnable) {
return; return;
} }

View File

@@ -370,7 +370,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
executorService.schedule(() -> { executorService.schedule(() -> {
// 定时 30分钟 运行一次 // 定时 30分钟 运行一次
executorService.scheduleAtFixedRate(() -> { executorService.scheduleAtFixedRate(() -> {
Desktop.instance.getTaskMonitorCenter().registerTask(new CloudRkSyncTask()).submit(); Desktop.instance.getTaskMonitorCenter().registerAndStartTask(new CloudRkSyncTask());
}, 0, 30, TimeUnit.MINUTES); }, 0, 30, TimeUnit.MINUTES);
}, 1, TimeUnit.MINUTES); }, 1, TimeUnit.MINUTES);
} }

View File

@@ -4,7 +4,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@@ -12,14 +12,15 @@ import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp; import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractGroup; import com.ecep.contract.manager.ds.contract.model.ContractGroup;
import com.ecep.contract.manager.ds.contract.service.ContractGroupService; import com.ecep.contract.manager.ds.contract.service.ContractGroupService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import javafx.concurrent.Task;
import lombok.Setter; import lombok.Setter;
/** /**
* 同步合同分组 * 同步合同分组
*/ */
public class ContractGroupSyncTask extends Task<Object> { public class ContractGroupSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(ContractGroupSyncTask.class); private static final Logger logger = LoggerFactory.getLogger(ContractGroupSyncTask.class);
@Setter @Setter
private ContractGroupService contractGroupService; private ContractGroupService contractGroupService;
@@ -36,29 +37,29 @@ public class ContractGroupSyncTask extends Task<Object> {
} }
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Repository repository = null; YongYouU8Service service = null;
try { try {
repository = SpringApp.getBean(YongYouU8Repository.class); service = SpringApp.getBean(YongYouU8Service.class);
} catch (BeansException e) { } catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e); logger.error("can't get bean of YongYouU8Service", e);
holder.error("can't get bean of YongYouU8Service");
return null; return null;
} }
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CM_Group 数据表..."); logger.info("读取 U8 系统 CM_Group 数据表...");
List<Map<String, Object>> list = repository.queryAllContractGroup(); List<Map<String, Object>> list = service.queryAllContractGroup();
int size = list.size(); int size = list.size();
updateMessage("总共读取 CM_Group 数据 " + size + ""); holder.debug("总共读取 CM_Group 数据 " + size + "");
for (Map<String, Object> map : list) { for (Map<String, Object> map : list) {
if (isCancelled()) { if (isCancelled()) {
updateMessage("Cancelled"); holder.info("Cancelled");
return null; return null;
} }
sync(map, msg -> { MessageHolder sub = holder.sub(counter.get() + "/" + size + ">" );
updateMessage(counter.get() + "/" + size + ">" + msg); sync(map, sub);
});
// 更新进度 // 更新进度
updateProgress(counter.incrementAndGet(), size); updateProgress(counter.incrementAndGet(), size);
} }
@@ -66,7 +67,7 @@ public class ContractGroupSyncTask extends Task<Object> {
return null; return null;
} }
private void sync(Map<String, Object> map, Consumer<String> consumer) { private void sync(Map<String, Object> map, MessageHolder holder) {
boolean modified = false; boolean modified = false;
String groupCode = (String) map.get("cGroupID"); String groupCode = (String) map.get("cGroupID");
@@ -77,26 +78,28 @@ public class ContractGroupSyncTask extends Task<Object> {
ContractGroup contractGroup = service.findByCode(groupCode); ContractGroup contractGroup = service.findByCode(groupCode);
if (contractGroup == null) { if (contractGroup == null) {
contractGroup = service.newContractGroup(); contractGroup = service.newContractGroup();
consumer.accept("新建合同分组:" + groupCode); holder.info("新建合同分组:" + groupCode);
modified = true; modified = true;
} }
if (!Objects.equals(contractGroup.getCode(), groupCode)) { if (!Objects.equals(contractGroup.getCode(), groupCode)) {
contractGroup.setCode(groupCode); contractGroup.setCode(groupCode);
holder.info("合同分组代码:" + contractGroup.getCode() + " -> " + groupCode);
modified = true; modified = true;
} }
if (!Objects.equals(contractGroup.getName(), groupName)) { if (!Objects.equals(contractGroup.getName(), groupName)) {
contractGroup.setName(groupName); contractGroup.setName(groupName);
holder.info("合同分组名称:" + contractGroup.getName() + " -> " + groupName);
modified = true; modified = true;
} }
if (!Objects.equals(contractGroup.getTitle(), groupTitle)) { if (!Objects.equals(contractGroup.getTitle(), groupTitle)) {
contractGroup.setTitle(groupTitle); contractGroup.setTitle(groupTitle);
holder.info("合同分组标题:" + contractGroup.getTitle() + " -> " + groupTitle);
modified = true; modified = true;
} }
if (modified) { if (modified) {
service.save(contractGroup); service.save(contractGroup);
consumer.accept("更新" + contractGroup.getName() + " 信息");
} }
} }
} }

View File

@@ -1,25 +1,26 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractKind;
import com.ecep.contract.manager.ds.contract.service.ContractKindService;
import javafx.concurrent.Task;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractKind;
import com.ecep.contract.manager.ds.contract.service.ContractKindService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import lombok.Setter;
/** /**
* 同步合同分类 * 同步合同分类
*/ */
public class ContractKindSyncTask extends Task<Object> { public class ContractKindSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(ContractKindSyncTask.class); private static final Logger logger = LoggerFactory.getLogger(ContractKindSyncTask.class);
@Setter @Setter
private ContractKindService contractKindService; private ContractKindService contractKindService;
@@ -36,29 +37,29 @@ public class ContractKindSyncTask extends Task<Object> {
} }
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Repository repository = null; YongYouU8Repository repository = null;
try { try {
repository = SpringApp.getBean(YongYouU8Repository.class); repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) { } catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e); logger.error("can't get bean of YongYouU8Repository", e);
holder.error("can't get bean of YongYouU8Repository");
return null; return null;
} }
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CM_Kind 数据表..."); logger.info("读取 U8 系统 CM_Kind 数据表...");
List<Map<String, Object>> list = repository.queryAllContractKind(); List<Map<String, Object>> list = repository.queryAllContractKind();
int size = list.size(); int size = list.size();
updateMessage("总共读取 CM_Kind 数据 " + size + ""); holder.debug("总共读取 CM_Kind 数据 " + size + "");
for (Map<String, Object> map : list) { for (Map<String, Object> map : list) {
if (isCancelled()) { if (isCancelled()) {
updateMessage("Cancelled"); holder.info("Cancelled");
return null; return null;
} }
sync(map, msg -> { MessageHolder sub = holder.sub(counter.get() + "/" + size + ">");
updateMessage(counter.get() + "/" + size + ">" + msg); sync(map, sub);
});
// 更新进度 // 更新进度
updateProgress(counter.incrementAndGet(), size); updateProgress(counter.incrementAndGet(), size);
} }
@@ -66,7 +67,7 @@ public class ContractKindSyncTask extends Task<Object> {
return null; return null;
} }
private void sync(Map<String, Object> map, Consumer<String> consumer) { private void sync(Map<String, Object> map, MessageHolder holder) {
boolean modified = false; boolean modified = false;
String typeCode = (String) map.get("KindID"); String typeCode = (String) map.get("KindID");
@@ -77,26 +78,29 @@ public class ContractKindSyncTask extends Task<Object> {
ContractKind contractKind = kindService.findByCode(typeCode); ContractKind contractKind = kindService.findByCode(typeCode);
if (contractKind == null) { if (contractKind == null) {
contractKind = new ContractKind(); contractKind = new ContractKind();
consumer.accept("新建合同分类:" + typeCode); holder.info("新建合同分类:" + typeCode);
modified = true; modified = true;
} }
if (!Objects.equals(contractKind.getCode(), typeCode)) { if (!Objects.equals(contractKind.getCode(), typeCode)) {
contractKind.setCode(typeCode); contractKind.setCode(typeCode);
holder.info("合同分类代码:" + contractKind.getCode() + " -> " + typeCode);
modified = true; modified = true;
} }
if (!Objects.equals(contractKind.getName(), typeName)) { if (!Objects.equals(contractKind.getName(), typeName)) {
contractKind.setName(typeName); contractKind.setName(typeName);
holder.info("合同分类名称:" + contractKind.getName() + " -> " + typeName);
modified = true; modified = true;
} }
if (!Objects.equals(contractKind.getTitle(), typeTitle)) { if (!Objects.equals(contractKind.getTitle(), typeTitle)) {
contractKind.setTitle(typeTitle); contractKind.setTitle(typeTitle);
holder.info("合同分类描述:" + contractKind.getTitle() + " -> " + typeTitle);
modified = true; modified = true;
} }
if (modified) { if (modified) {
kindService.save(contractKind); kindService.save(contractKind);
consumer.accept("更新" + contractKind.getName() + " 信息");
} }
} }
} }

View File

@@ -1,14 +1,5 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.manager.ui.MessageHolder;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
@@ -16,21 +7,45 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.util.StringUtils;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.manager.ds.contract.tasker.AbstContractRepairTasker;
import com.ecep.contract.manager.ui.MessageHolder;
/** /**
* 合同同步任务 * 合同同步任务
*/ */
public class ContractSyncTask extends AbstContractRepairTasker { public class ContractSyncTask extends AbstContractRepairTasker {
private static final Logger logger = LoggerFactory.getLogger(ContractSyncTask.class); private static final Logger logger = LoggerFactory.getLogger(ContractSyncTask.class);
@Setter
private boolean useLatestId = true;
private YongYouU8Repository repository; private YongYouU8Repository repository;
public ContractSyncTask() { public ContractSyncTask() {
updateTitle("用友U8系统-同步合同"); updateTitle("用友U8系统-同步合同");
} }
@Override
protected void repair(MessageHolder holder) {
updateTitle("用友U8系统-同步合同");
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
holder.error("无法获取 YongYouU8Repository " + e.getMessage());
return;
}
if (getConfService().getBoolean(ContractCtx.KEY_SYNC_USE_LATEST_ID)) {
syncByLatestId(holder);
} else {
syncByLatestDate(holder);
}
}
private void syncByLatestId(MessageHolder holder) { private void syncByLatestId(MessageHolder holder) {
int latestId = getConfService().getInt(ContractService.CONTRACT_LATEST_ID); int latestId = getConfService().getInt(ContractCtx.KEY_SYNC_BY_LATEST_ID);
updateTitle("用友U8系统-同步合同,从 " + latestId + " 开始"); updateTitle("用友U8系统-同步合同,从 " + latestId + " 开始");
Long total = repository.countAllContracts(latestId); Long total = repository.countAllContracts(latestId);
@@ -66,11 +81,11 @@ public class ContractSyncTask extends AbstContractRepairTasker {
updateProgress(counter.incrementAndGet(), total); updateProgress(counter.incrementAndGet(), total);
}); });
} }
getConfService().set(ContractService.CONTRACT_LATEST_ID, String.valueOf(reference.get())); getConfService().set(ContractCtx.KEY_SYNC_BY_LATEST_ID, String.valueOf(reference.get()));
} }
private void syncByLatestDate(MessageHolder holder) { private void syncByLatestDate(MessageHolder holder) {
String strDateTime = getConfService().getString(ContractService.CONTRACT_LATEST_DATE); String strDateTime = getConfService().getString(ContractCtx.KEY_SYNC_BY_LATEST_DATE);
LocalDateTime latestDateTime = null; LocalDateTime latestDateTime = null;
if (StringUtils.hasText(strDateTime)) { if (StringUtils.hasText(strDateTime)) {
try { try {
@@ -120,17 +135,7 @@ public class ContractSyncTask extends AbstContractRepairTasker {
updateProgress(counter.incrementAndGet(), total); updateProgress(counter.incrementAndGet(), total);
}); });
} }
getConfService().set(ContractService.CONTRACT_LATEST_DATE, String.valueOf(reference.get())); getConfService().set(ContractCtx.KEY_SYNC_BY_LATEST_DATE, String.valueOf(reference.get()));
} }
@Override
protected void repair(MessageHolder holder) {
updateTitle("用友U8系统-同步合同");
repository = SpringApp.getBean(YongYouU8Repository.class);
if (useLatestId) {
syncByLatestId(holder);
} else {
syncByLatestDate(holder);
}
}
} }

View File

@@ -1,25 +1,26 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractType;
import com.ecep.contract.manager.ds.contract.service.ContractTypeService;
import javafx.concurrent.Task;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.contract.model.ContractType;
import com.ecep.contract.manager.ds.contract.service.ContractTypeService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import lombok.Setter;
/** /**
* 同步合同类型 * 同步合同类型
*/ */
public class ContractTypeSyncTask extends Task<Object> { public class ContractTypeSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(ContractTypeSyncTask.class); private static final Logger logger = LoggerFactory.getLogger(ContractTypeSyncTask.class);
@Setter @Setter
private ContractTypeService contractTypeService; private ContractTypeService contractTypeService;
@@ -36,29 +37,29 @@ public class ContractTypeSyncTask extends Task<Object> {
} }
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Repository repository = null; YongYouU8Repository repository = null;
try { try {
repository = SpringApp.getBean(YongYouU8Repository.class); repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) { } catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e); logger.error("can't get bean of YongYouU8Service", e);
holder.error("can't get bean of YongYouU8Service");
return null; return null;
} }
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CM_Type,CM_TypeClass 数据表..."); logger.info("读取 U8 系统 CM_Type,CM_TypeClass 数据表...");
List<Map<String, Object>> list = repository.queryAllContractType(); List<Map<String, Object>> list = repository.queryAllContractType();
int size = list.size(); int size = list.size();
updateMessage("总共读取 CM_Type,CM_TypeClass 数据 " + size + ""); holder.debug("总共读取 CM_Type,CM_TypeClass 数据 " + size + "");
for (Map<String, Object> map : list) { for (Map<String, Object> map : list) {
if (isCancelled()) { if (isCancelled()) {
updateMessage("Cancelled"); holder.info("Cancelled");
return null; return null;
} }
sync(map, msg -> { MessageHolder sub = holder.sub(counter.get() + "/" + size + ">" );
updateMessage(counter.get() + "/" + size + ">" + msg); sync(map, sub);
});
// 更新进度 // 更新进度
updateProgress(counter.incrementAndGet(), size); updateProgress(counter.incrementAndGet(), size);
} }
@@ -66,7 +67,7 @@ public class ContractTypeSyncTask extends Task<Object> {
return null; return null;
} }
private void sync(Map<String, Object> map, Consumer<String> consumer) { private void sync(Map<String, Object> map, MessageHolder holder) {
boolean modified = false; boolean modified = false;
String typeCode = (String) map.get("cTypeCode"); String typeCode = (String) map.get("cTypeCode");
@@ -79,34 +80,39 @@ public class ContractTypeSyncTask extends Task<Object> {
ContractType contractType = typeService.findByCode(typeCode); ContractType contractType = typeService.findByCode(typeCode);
if (contractType == null) { if (contractType == null) {
contractType = new ContractType(); contractType = new ContractType();
consumer.accept("新建合同类型:" + typeCode); holder.info("新建合同类型:" + typeCode);
modified = true; modified = true;
} }
if (!Objects.equals(contractType.getCode(), typeCode)) { if (!Objects.equals(contractType.getCode(), typeCode)) {
contractType.setCode(typeCode); contractType.setCode(typeCode);
holder.info("合同类型代码:" + contractType.getCode() + " -> " + typeCode);
modified = true; modified = true;
} }
if (!Objects.equals(contractType.getName(), typeName)) { if (!Objects.equals(contractType.getName(), typeName)) {
contractType.setName(typeName); contractType.setName(typeName);
holder.info("合同类型名称:" + contractType.getName() + " -> " + typeName);
modified = true; modified = true;
} }
if (!Objects.equals(contractType.getTitle(), typeTitle)) { if (!Objects.equals(contractType.getTitle(), typeTitle)) {
contractType.setTitle(typeTitle); contractType.setTitle(typeTitle);
holder.info("合同类型标题:" + contractType.getTitle() + " -> " + typeTitle);
modified = true; modified = true;
} }
if (!Objects.equals(contractType.getCatalog(), typeCatalog)) { if (!Objects.equals(contractType.getCatalog(), typeCatalog)) {
contractType.setTitle(typeTitle); contractType.setCatalog(typeCatalog);
holder.info("合同类型分类:" + contractType.getCatalog() + " -> " + typeCatalog);
modified = true; modified = true;
} }
if (!Objects.equals(contractType.getDirection(), typeDirection)) { if (!Objects.equals(contractType.getDirection(), typeDirection)) {
contractType.setTitle(typeTitle); contractType.setDirection(typeDirection);
holder.info("合同类型方向:" + contractType.getDirection() + " -> " + typeDirection);
modified = true; modified = true;
} }
if (modified) { if (modified) {
typeService.save(contractType); typeService.save(contractType);
consumer.accept("更新" + contractType.getName() + " 信息");
} }
} }
} }

View File

@@ -1,70 +1,99 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.customer.model.CustomerCatalog;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import javafx.concurrent.Task;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.customer.model.CustomerCatalog;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import lombok.Setter;
/** /**
* 同步客户分类 * 同步客户分类
*/ */
public class CustomerClassSyncTask extends Task<Object> { public class CustomerClassSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(CustomerClassSyncTask.class);
@Setter
private CompanyCustomerService companyCustomerService;
public CustomerClassSyncTask() { public CustomerClassSyncTask() {
updateTitle("用友U8系统-同步客户分类信息"); updateTitle("用友U8系统-同步客户分类信息");
} }
CompanyCustomerService getCompanyCustomerService() {
if (companyCustomerService == null) {
companyCustomerService = SpringApp.getBean(CompanyCustomerService.class);
}
return companyCustomerService;
}
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class); YongYouU8Repository repository = null;
CompanyCustomerService customerService = SpringApp.getBean(CompanyCustomerService.class); try {
repository = SpringApp.getBean(YongYouU8Repository.class);
AtomicInteger counter = new AtomicInteger(0); } catch (BeansException e) {
updateMessage("读取 U8 系统 CustomerClass 数据表..."); logger.error("can't get bean of YongYouU8Repository", e);
List<Map<String, Object>> list = service.queryAllCustomerClass(); holder.error("can't get bean of YongYouU8Repository");
int size = list.size();
updateMessage("总共读取 CustomerClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null; return null;
} }
boolean modified = false; AtomicInteger counter = new AtomicInteger(0);
logger.info("读取 U8 系统 CustomerClass 数据表...");
List<Map<String, Object>> list = repository.queryAllCustomerClass();
int size = list.size();
holder.debug("总共读取 CustomerClass 数据 " + size + "");
String code = (String) map.get("cCCCode"); for (Map<String, Object> map : list) {
String name = (String) map.get("cCCName"); if (isCancelled()) {
holder.info("Cancelled");
CustomerCatalog customerCatalog = customerService.findCatalogByCode(code); return null;
if (customerCatalog == null) {
customerCatalog = new CustomerCatalog();
updateMessage("新建客户分类:" + code);
modified = true;
}
if (!Objects.equals(customerCatalog.getCode(), code)) {
customerCatalog.setCode(code);
modified = true;
}
if (!Objects.equals(customerCatalog.getName(), name)) {
customerCatalog.setName(name);
modified = true;
}
if (modified) {
customerService.save(customerCatalog);
updateMessage("更新" + customerCatalog.getName() + " 信息");
} }
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">" );
sync(map, sub);
// 更新进度 // 更新进度
updateProgress(counter.incrementAndGet(), size); updateProgress(counter.incrementAndGet(), size);
} }
return null; return null;
} }
private void sync(Map<String, Object> map, MessageHolder holder) {
boolean modified = false;
String code = (String) map.get("cCCCode");
String name = (String) map.get("cCCName");
CompanyCustomerService customerService = getCompanyCustomerService();
CustomerCatalog customerCatalog = customerService.findCatalogByCode(code);
if (customerCatalog == null) {
customerCatalog = new CustomerCatalog();
holder.info("新建客户分类:" + code);
modified = true;
}
if (!Objects.equals(customerCatalog.getCode(), code)) {
customerCatalog.setCode(code);
holder.info("客户分类代码:" + customerCatalog.getCode() + " -> " + code);
modified = true;
}
if (!Objects.equals(customerCatalog.getName(), name)) {
customerCatalog.setName(name);
holder.info("客户分类名称:" + customerCatalog.getName() + " -> " + name);
modified = true;
}
if (modified) {
customerService.save(customerCatalog);
}
}
} }

View File

@@ -0,0 +1,113 @@
package com.ecep.contract.manager.cloud.u8;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import lombok.Setter;
/**
* 数据迁移任务从CloudInfo迁移到CloudYu
*/
public class DateTransferTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(DateTransferTask.class);
@Setter
private YongYouU8Service yongYouU8Service;
public DateTransferTask() {
updateTitle("用友U8系统-数据迁移任务");
}
YongYouU8Service getYongYouU8Service() {
if (yongYouU8Service == null) {
yongYouU8Service = SpringApp.getBean(YongYouU8Service.class);
}
return yongYouU8Service;
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Service u8Service = null;
try {
u8Service = getYongYouU8Service();
} catch (BeansException e) {
logger.error("获取用友U8服务失败", e);
holder.error("获取用友U8服务失败");
return null;
}
AtomicInteger counter = new AtomicInteger(0);
logger.info("开始数据迁移任务...");
Iterable<CloudInfo> cloudInfos = u8Service.findAllCloudYu();
// 计算总数
int total = 0;
for (@SuppressWarnings("unused")
CloudInfo info : cloudInfos) {
total++;
}
holder.debug("总共需要迁移的数据量: " + total + "");
// 重新获取Iterable以进行遍历
cloudInfos = u8Service.findAllCloudYu();
for (CloudInfo v : cloudInfos) {
if (isCancelled()) {
holder.info("迁移任务已取消");
return null;
}
MessageHolder sub = holder.sub(counter.get() + "/" + total + ">");
try {
sync(v, sub);
} catch (Exception e) {
sub.error("迁移失败: " + e.getMessage());
logger.error("迁移数据失败", e);
}
// 更新进度
updateProgress(counter.incrementAndGet(), total);
}
holder.info("数据迁移任务完成");
return null;
}
private void sync(CloudInfo v, MessageHolder holder) {
YongYouU8Service u8Service = getYongYouU8Service();
CloudYu cloudYu = u8Service.getOrCreateCloudYu(v);
if (copyTo(v, cloudYu)) {
u8Service.save(cloudYu);
holder.info("成功迁移数据: " + v.getCloudId());
} else {
holder.debug("数据未变更,无需迁移: " + v.getCloudId());
}
}
boolean copyTo(CloudInfo v, CloudBaseInfo cloudRk) {
boolean modified = false;
if (!Objects.equals(cloudRk.getLatestUpdate(), v.getLatestUpdate())) {
cloudRk.setLatestUpdate(v.getLatestUpdate());
modified = true;
}
if (!Objects.equals(cloudRk.getCloudId(), v.getCloudId())) {
cloudRk.setCloudId(v.getCloudId());
modified = true;
}
if (!Objects.equals(cloudRk.getCompany(), v.getCompany())) {
cloudRk.setCompany(v.getCompany());
modified = true;
}
return modified;
}
}

View File

@@ -1,70 +1,99 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.vendor.model.VendorCatalog;
import com.ecep.contract.manager.ds.vendor.repository.VendorClassRepository;
import javafx.concurrent.Task;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.vendor.model.VendorCatalog;
import com.ecep.contract.manager.ds.vendor.repository.VendorClassRepository;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
import lombok.Setter;
/** /**
* 同步供应商分类 * 同步供应商分类
*/ */
public class VendorClassSyncTask extends Task<Object> { public class VendorClassSyncTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(VendorClassSyncTask.class);
@Setter
private VendorClassRepository vendorClassRepository;
public VendorClassSyncTask() { public VendorClassSyncTask() {
updateTitle("用友U8系统-同步供应商分类信息"); updateTitle("用友U8系统-同步供应商分类信息");
} }
VendorClassRepository getVendorClassRepository() {
if (vendorClassRepository == null) {
vendorClassRepository = SpringApp.getBean(VendorClassRepository.class);
}
return vendorClassRepository;
}
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class); YongYouU8Service service = null;
VendorClassRepository groupRepository = SpringApp.getBean(VendorClassRepository.class); try {
service = SpringApp.getBean(YongYouU8Service.class);
AtomicInteger counter = new AtomicInteger(0); } catch (BeansException e) {
updateMessage("读取 U8 系统 VendorClass 数据表..."); logger.error("can't get bean of YongYouU8Service", e);
List<Map<String, Object>> list = service.queryAllVendorClass(); holder.error("can't get bean of YongYouU8Service");
int size = list.size();
updateMessage("总共读取 VendorClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
return null; return null;
} }
boolean modified = false; AtomicInteger counter = new AtomicInteger(0);
logger.info("读取 U8 系统 VendorClass 数据表...");
List<Map<String, Object>> list = service.queryAllVendorClass();
int size = list.size();
holder.debug("总共读取 VendorClass 数据 " + size + "");
String code = (String) map.get("cVCCode"); for (Map<String, Object> map : list) {
String name = (String) map.get("cVCName"); if (isCancelled()) {
holder.info("Cancelled");
VendorCatalog vendorCatalog = groupRepository.findByCode(code).orElse(null); return null;
if (vendorCatalog == null) {
vendorCatalog = new VendorCatalog();
updateMessage("新建供应商分类:" + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getCode(), code)) {
vendorCatalog.setCode(code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getName(), name)) {
vendorCatalog.setName(name);
modified = true;
}
if (modified) {
groupRepository.save(vendorCatalog);
updateMessage("更新" + vendorCatalog.getName() + " 信息");
} }
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">" );
sync(map, sub);
// 更新进度 // 更新进度
updateProgress(counter.incrementAndGet(), size); updateProgress(counter.incrementAndGet(), size);
} }
return null; return null;
} }
private void sync(Map<String, Object> map, MessageHolder holder) {
boolean modified = false;
String code = (String) map.get("cVCCode");
String name = (String) map.get("cVCName");
VendorClassRepository repository = getVendorClassRepository();
VendorCatalog vendorCatalog = repository.findByCode(code).orElse(null);
if (vendorCatalog == null) {
vendorCatalog = new VendorCatalog();
holder.info("新建供应商分类:" + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getCode(), code)) {
vendorCatalog.setCode(code);
holder.info("供应商分类代码:" + vendorCatalog.getCode() + " -> " + code);
modified = true;
}
if (!Objects.equals(vendorCatalog.getName(), name)) {
vendorCatalog.setName(name);
holder.info("供应商分类名称:" + vendorCatalog.getName() + " -> " + name);
modified = true;
}
if (modified) {
repository.save(vendorCatalog);
}
}
} }

View File

@@ -0,0 +1,59 @@
package com.ecep.contract.manager.cloud.u8;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.ecep.contract.manager.cloud.u8.ctx.CompanyCtx;
import com.ecep.contract.manager.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.manager.ds.other.LocalDateConfig;
import com.ecep.contract.manager.ds.other.StringConfig;
import com.ecep.contract.manager.ui.BaseController;
import com.ecep.contract.manager.ui.FxmlPath;
import javafx.fxml.FXML;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import javafx.stage.WindowEvent;
@Lazy
@Scope("prototype")
@Component
@FxmlPath("/ui/cloud/u8_config.fxml")
public class YongYouU8ConfigWindowController extends BaseController {
@FXML
private DatePicker auto_create_company_after;
@FXML
private DatePicker contract_latest_date;
@FXML
private TextField contract_latest_id;
@FXML
private TextField sync_elapse;
@Override
public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent);
getTitle().set("用友U8配置");
LocalDateConfig config1 = new LocalDateConfig(CompanyCtx.AUTO_CREATE_COMPANY_AFTER);
config1.setPicker(auto_create_company_after);
config1.initialize();
LocalDateConfig config2 = new LocalDateConfig(ContractCtx.KEY_SYNC_BY_LATEST_DATE);
config2.setPicker(contract_latest_date);
config2.initialize();
StringConfig config3 = new StringConfig(ContractCtx.KEY_SYNC_BY_LATEST_ID);
config3.setTextField(contract_latest_id);
config3.initialize();
StringConfig config4 = new StringConfig("cloud.u8.sync.elapse");
config4.setTextField(sync_elapse);
config4.initialize();
}
}

View File

@@ -1,30 +1,26 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.SpringApp; import java.time.LocalDateTime;
import com.ecep.contract.manager.cloud.CloudBaseInfo; import java.util.Objects;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ui.AbstManagerWindowController;
import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.ui.Message;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.UITools;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.control.TableColumn;
import javafx.stage.Stage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import com.ecep.contract.manager.Desktop;
import java.util.Objects; import com.ecep.contract.manager.cloud.CloudBaseInfo;
import java.util.concurrent.CompletableFuture; import com.ecep.contract.manager.cloud.CloudInfo;
import java.util.concurrent.ScheduledExecutorService; import com.ecep.contract.manager.ds.company.model.Company;
import java.util.function.Consumer; import com.ecep.contract.manager.ui.AbstManagerWindowController;
import com.ecep.contract.manager.ui.BaseController;
import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.util.UITools;
import javafx.event.ActionEvent;
import javafx.scene.control.TableColumn;
import javafx.stage.Stage;
@Lazy @Lazy
@Scope("prototype") @Scope("prototype")
@@ -38,9 +34,6 @@ public class YongYouU8ManagerWindowController
show(YongYouU8ManagerWindowController.class, null); show(YongYouU8ManagerWindowController.class, null);
} }
@Autowired
private ScheduledExecutorService scheduledExecutorService;
public TableColumn<CloudYuInfoViewModel, Number> idColumn; public TableColumn<CloudYuInfoViewModel, Number> idColumn;
public TableColumn<CloudYuInfoViewModel, LocalDateTime> latestUpdateColumn; public TableColumn<CloudYuInfoViewModel, LocalDateTime> latestUpdateColumn;
public TableColumn<CloudYuInfoViewModel, Company> companyColumn; public TableColumn<CloudYuInfoViewModel, Company> companyColumn;
@@ -58,73 +51,25 @@ public class YongYouU8ManagerWindowController
return new YongYouU8ManagerSkin(this); return new YongYouU8ManagerSkin(this);
} }
@Override @Override
public void show(Stage stage) { public void show(Stage stage) {
super.show(stage); super.show(stage);
getTitle().set("数据源:用友U8"); getTitle().set("用友U8");
}
/**
* 打开配置窗口
*/
public void onConfigAction(ActionEvent event) {
BaseController.show(YongYouU8ConfigWindowController.class, null);
} }
/** /**
* 数据迁移,从 CloudInfo 迁移到 CloudRk * 数据迁移,从 CloudInfo 迁移到 CloudRk
*/ */
public void onDateTransferAction(ActionEvent event) { public void onDateTransferAction(ActionEvent event) {
DateTransferTask task = new DateTransferTask();
CompletableFuture.runAsync(() -> { Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
com.ecep.contract.manager.cloud.CloudInfoRepository cloudInfoRepository = SpringApp.getBean(com.ecep.contract.manager.cloud.CloudInfoRepository.class);
YongYouU8Service u8Service = SpringApp.getBean(YongYouU8Service.class);
cloudInfoRepository.findAll().forEach(v -> {
try {
CloudYu cloudYu = u8Service.getOrCreateCloudYu(v);
if (copyTo(v, cloudYu)) {
u8Service.save(cloudYu);
}
} catch (Exception e) {
setStatus(e.getMessage());
e.printStackTrace();
}
});
});
}
boolean copyTo(CloudInfo v, CloudBaseInfo cloudRk) {
boolean modified = false;
if (!Objects.equals(cloudRk.getLatestUpdate(), v.getLatestUpdate())) {
cloudRk.setLatestUpdate(v.getLatestUpdate());
modified = true;
}
if (!Objects.equals(cloudRk.getCloudId(), v.getCloudId())) {
cloudRk.setCloudId(v.getCloudId());
modified = true;
}
if (!Objects.equals(cloudRk.getCompany(), v.getCompany())) {
cloudRk.setCompany(v.getCompany());
modified = true;
}
return modified;
}
private <T extends Task<Object>> void initializeTask(T task, String prefix, Consumer<String> consumer) {
task.setOnScheduled(e -> {
consumer.accept("正在从用友U8同步" + prefix + ",请稍后...");
});
task.setOnRunning(e -> {
consumer.accept("开始同步" + prefix + "...");
});
task.setOnSucceeded(e -> {
consumer.accept(prefix + "同步完成...");
});
task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
consumer.accept(newValue.getMessage());
logger.error("同步{}发生异常", prefix, newValue);
});
scheduledExecutorService.submit(task);
consumer.accept("同步任务已创建...");
} }
public void onPersonSyncAction(ActionEvent event) { public void onPersonSyncAction(ActionEvent event) {
@@ -153,39 +98,28 @@ public class YongYouU8ManagerWindowController
} }
public void onContractGroupSyncAction(ActionEvent event) { public void onContractGroupSyncAction(ActionEvent event) {
Task<Object> task = new ContractGroupSyncTask(); ContractGroupSyncTask task = new ContractGroupSyncTask();
UITools.showTaskDialogAndWait("合同分组数据同步", task, consumer -> { Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
initializeTask(task, "合同分组数据", msg -> consumer.accept(Message.info(msg)));
});
} }
public void onContractTypeSyncAction(ActionEvent event) { public void onContractTypeSyncAction(ActionEvent event) {
Task<Object> task = new ContractTypeSyncTask(); ContractTypeSyncTask task = new ContractTypeSyncTask();
UITools.showTaskDialogAndWait("合同分类数据同步", task, consumer -> { Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
initializeTask(task, "合同分类数据", msg -> consumer.accept(Message.info(msg)));
});
} }
public void onContractKindSyncAction(ActionEvent event) { public void onContractKindSyncAction(ActionEvent event) {
Task<Object> task = new ContractKindSyncTask(); ContractKindSyncTask task = new ContractKindSyncTask();
UITools.showTaskDialogAndWait("合同类型数据同步", task, consumer -> { Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
initializeTask(task, "合同类型数据", msg -> consumer.accept(Message.info(msg)));
});
} }
public void onVendorClassSyncAction(ActionEvent event) { public void onVendorClassSyncAction(ActionEvent event) {
Task<Object> task = new VendorClassSyncTask(); VendorClassSyncTask task = new VendorClassSyncTask();
UITools.showTaskDialogAndWait("供应商分类数据同步", task, consumer -> { Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
initializeTask(task, "供应商分类数据", msg -> consumer.accept(Message.info(msg)));
});
} }
public void onCustomerClassSyncAction(ActionEvent event) { public void onCustomerClassSyncAction(ActionEvent event) {
Task<Object> task = new CustomerClassSyncTask(); CustomerClassSyncTask task = new CustomerClassSyncTask();
UITools.showTaskDialogAndWait("客户分类数据同步", task, consumer -> { Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
initializeTask(task, "客户分类数据", msg -> consumer.accept(Message.info(msg)));
});
} }
} }

View File

@@ -1,18 +1,12 @@
package com.ecep.contract.manager.cloud.u8; package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.Desktop; import java.util.List;
import com.ecep.contract.manager.cloud.CloudInfo; import java.util.Map;
import com.ecep.contract.manager.cloud.u8.ctx.AbstractYongYouU8Ctx; import java.util.Optional;
import com.ecep.contract.manager.ds.company.model.Company; import java.util.concurrent.ScheduledExecutorService;
import com.ecep.contract.manager.ds.company.service.CompanyService; import java.util.concurrent.TimeUnit;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService; import java.util.stream.Stream;
import com.ecep.contract.manager.ds.other.service.EmployeeService;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.ui.task.MonitoredTask;
import javafx.application.Platform;
import javafx.concurrent.Task;
import org.controlsfx.control.TaskProgressView; import org.controlsfx.control.TaskProgressView;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -25,12 +19,19 @@ import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.List; import com.ecep.contract.manager.Desktop;
import java.util.Map; import com.ecep.contract.manager.cloud.CloudInfo;
import java.util.Optional; import com.ecep.contract.manager.cloud.CloudInfoRepository;
import java.util.concurrent.ScheduledExecutorService; import com.ecep.contract.manager.cloud.u8.ctx.AbstractYongYouU8Ctx;
import java.util.concurrent.TimeUnit; import com.ecep.contract.manager.ds.company.model.Company;
import java.util.stream.Stream; import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.manager.ds.other.service.EmployeeService;
import com.ecep.contract.manager.ds.vendor.service.CompanyVendorService;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.ui.task.MonitoredTask;
import javafx.concurrent.Task;
@Lazy @Lazy
@Service @Service
@@ -44,6 +45,9 @@ public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoVi
private YongYouU8Repository repository; private YongYouU8Repository repository;
@Lazy @Lazy
@Autowired @Autowired
private CloudInfoRepository cloudInfoRepository;
@Lazy
@Autowired
private CompanyService companyService; private CompanyService companyService;
@Lazy @Lazy
@Autowired @Autowired
@@ -230,4 +234,8 @@ public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoVi
ctx.setCompanyVendorService(companyVendorService); ctx.setCompanyVendorService(companyVendorService);
ctx.setCompanyCustomerService(companyCustomerService); ctx.setCompanyCustomerService(companyCustomerService);
} }
public Iterable<CloudInfo> findAllCloudYu() {
return cloudInfoRepository.findAll();
}
} }

View File

@@ -18,6 +18,9 @@ import java.util.Objects;
import static com.ecep.contract.manager.SpringApp.getBean; import static com.ecep.contract.manager.SpringApp.getBean;
public class CompanyCtx extends AbstractYongYouU8Ctx { public class CompanyCtx extends AbstractYongYouU8Ctx {
/**
* 自动创建公司的时间
*/
public static final String AUTO_CREATE_COMPANY_AFTER = "cloud.u8.auto-create-company-after"; public static final String AUTO_CREATE_COMPANY_AFTER = "cloud.u8.auto-create-company-after";
@Setter @Setter
@@ -111,7 +114,7 @@ public class CompanyCtx extends AbstractYongYouU8Ctx {
return null; return null;
} }
CompanyService companyService = getCompanyService(); CompanyService companyService = getCompanyService();
String autoCreateAfter = SpringApp.getBean(SysConfService.class).getString(AUTO_CREATE_COMPANY_AFTER); String autoCreateAfter = getConfService().getString(AUTO_CREATE_COMPANY_AFTER);
// 当配置存在,且开发时间小于指定时间,不创建 // 当配置存在,且开发时间小于指定时间,不创建
if (StringUtils.hasText(autoCreateAfter)) { if (StringUtils.hasText(autoCreateAfter)) {
LocalDate miniDate = LocalDate.parse(autoCreateAfter); LocalDate miniDate = LocalDate.parse(autoCreateAfter);

View File

@@ -44,7 +44,23 @@ import java.util.stream.Stream;
import static com.ecep.contract.manager.SpringApp.getBean; import static com.ecep.contract.manager.SpringApp.getBean;
/**
* 合同上下文
*/
public class ContractCtx extends AbstractYongYouU8Ctx { public class ContractCtx extends AbstractYongYouU8Ctx {
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 @Setter
private ContractService contractService; private ContractService contractService;

View File

@@ -78,7 +78,11 @@ public enum ContractFileType {
/** /**
* 重大项目决策记录单 * 重大项目决策记录单
*/ */
CriticalProjectDecisionRecord(true, true) CriticalProjectDecisionRecord(true, true),
/**
* 顾客满意度调查表
*/
CustomerSatisfactionSurvey(true, false),
; ;
final boolean supportCustomer; final boolean supportCustomer;

View File

@@ -19,6 +19,9 @@ import org.springframework.util.StringUtils;
import java.util.List; import java.util.List;
/**
* 合同支付计划服务
*/
@Lazy @Lazy
@Service @Service
@CacheConfig(cacheNames = "contract-pay-plan") @CacheConfig(cacheNames = "contract-pay-plan")

View File

@@ -9,6 +9,7 @@ import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.ecep.contract.manager.cloud.u8.ctx.ContractCtx;
import com.ecep.contract.manager.ds.company.model.Company; import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.ContractPayWay; import com.ecep.contract.manager.ds.contract.ContractPayWay;
import com.ecep.contract.manager.ds.contract.repository.ContractRepository; import com.ecep.contract.manager.ds.contract.repository.ContractRepository;
@@ -52,9 +53,6 @@ import com.ecep.contract.manager.ui.ViewModelService;
public class ContractService implements ViewModelService<Contract, ContractViewModel> { public class ContractService implements ViewModelService<Contract, ContractViewModel> {
private static final Logger logger = LoggerFactory.getLogger(ContractService.class); private static final Logger logger = LoggerFactory.getLogger(ContractService.class);
public static final String CONTRACT_BASE_PATH = "contract.base.path"; public static final String CONTRACT_BASE_PATH = "contract.base.path";
public static final String CONTRACT_LATEST_ID = "cloud.u8.contract.latestId";
public static final String CONTRACT_LATEST_DATE = "cloud.u8.contract.latestDate";
@Lazy @Lazy
@Autowired @Autowired
private ContractCatalogService contractCatalogService; private ContractCatalogService contractCatalogService;
@@ -152,10 +150,10 @@ public class ContractService implements ViewModelService<Contract, ContractViewM
*/ */
public void updateLatestIdAndDate(Integer latestId, LocalDateTime latestDate) { public void updateLatestIdAndDate(Integer latestId, LocalDateTime latestDate) {
if (latestId != null) { if (latestId != null) {
confService.set(CONTRACT_LATEST_ID, String.valueOf(latestId)); confService.set(ContractCtx.KEY_SYNC_BY_LATEST_ID, String.valueOf(latestId));
} }
if (latestDate != null) { if (latestDate != null) {
confService.set(CONTRACT_LATEST_DATE, latestDate.toString()); confService.set(ContractCtx.KEY_SYNC_BY_LATEST_DATE, latestDate.toString());
} }
} }

View File

@@ -0,0 +1,33 @@
package com.ecep.contract.manager.ds.other;
import java.util.concurrent.CompletableFuture;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.other.model.SysConf;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import lombok.Setter;
public abstract class AbstractConfigBounder implements ConfigBounder {
@Setter
private SysConfService confService;
String key;
SysConf conf;
@Override
public CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFuture.runAsync(runnable, Desktop.instance.getExecutorService()).exceptionally(ex -> {
ex.printStackTrace();
return null;
});
}
@Override
public SysConfService getConfService() {
if (confService == null) {
confService = SpringApp.getBean(SysConfService.class);
}
return confService;
}
}

View File

@@ -22,6 +22,7 @@ public class BankStringConverter extends EntityStringConverter<Bank> {
@PostConstruct @PostConstruct
private void init() { private void init() {
// #2
setInitialized(project -> service.findById(project.getId())); setInitialized(project -> service.findById(project.getId()));
setSuggestion(service::search); setSuggestion(service::search);
setFromString(service::findByName); setFromString(service::findByName);

View File

@@ -0,0 +1,17 @@
package com.ecep.contract.manager.ds.other;
import java.util.concurrent.CompletableFuture;
import com.ecep.contract.manager.ds.other.service.SysConfService;
public interface ConfigBounder {
void setConfService(SysConfService confService);
void initialize();
CompletableFuture<Void> runAsync(Runnable runnable);
SysConfService getConfService();
}

View File

@@ -0,0 +1,57 @@
package com.ecep.contract.manager.ds.other;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CompletableFuture;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.other.model.SysConf;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.DatePicker;
import javafx.util.converter.LocalDateStringConverter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor
public class LocalDateConfig extends AbstractConfigBounder {
Property<LocalDate> property;
@Setter
javafx.util.StringConverter<LocalDate> converter;
@Setter
DatePicker picker;
public LocalDateConfig(String string) {
key = string;
}
@Override
public void initialize() {
picker.setDisable(true);
if (converter == null) {
converter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
}
picker.setConverter(converter);
runAsync(() -> {
conf = getConfService().findById(key);
LocalDate date = converter.fromString(conf.getValue());
property = new SimpleObjectProperty<>(date);
property.addListener(this::propertyChanged);
picker.valueProperty().bindBidirectional(property);
picker.setDisable(false);
});
}
void propertyChanged(ObservableValue<? extends LocalDate> observable, LocalDate oldValue, LocalDate newValue) {
conf.setValue(converter.toString(newValue));
SysConf saved = getConfService().save(conf);
saved.getValue();
}
}

View File

@@ -0,0 +1,42 @@
package com.ecep.contract.manager.ds.other;
import com.ecep.contract.manager.ds.other.model.SysConf;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor
public class StringConfig extends AbstractConfigBounder {
@Setter
private TextField textField;
String key;
SysConf conf;
Property<String> property;
public StringConfig(String string) {
key = string;
}
public void initialize() {
textField.setDisable(true);
runAsync(() -> {
conf = getConfService().findById(key);
property = new SimpleStringProperty(conf.getValue());
property.addListener(this::propertyChanged);
textField.textProperty().bindBidirectional(property);
textField.setDisable(false);
});
}
void propertyChanged(ObservableValue<? extends String> observable, String oldValue, String newValue) {
conf.setValue(newValue);
SysConf saved = getConfService().save(conf);
saved.getValue();
}
}

View File

@@ -220,13 +220,4 @@ public class HomeWindowController extends BaseController {
public void onShowTaskMonitorWindowAction(ActionEvent event) { public void onShowTaskMonitorWindowAction(ActionEvent event) {
showInOwner(TaskMonitorViewController.class); showInOwner(TaskMonitorViewController.class);
} }
/**
* 运行任务监控演示
*/
public void onRunTaskMonitorDemo(ActionEvent event) {
com.ecep.contract.manager.ui.task.DemoTask.runDemo();
// 自动打开任务监控窗口
showInOwner(TaskMonitorViewController.class);
}
} }

View File

@@ -1,7 +1,7 @@
package com.ecep.contract.manager.ds.other.service; package com.ecep.contract.manager.ds.other.service;
import com.ecep.contract.manager.ds.other.model.SysConf; import java.time.Instant;
import com.ecep.contract.manager.ds.other.repository.SysConfRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
@@ -9,7 +9,8 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.Instant; import com.ecep.contract.manager.ds.other.model.SysConf;
import com.ecep.contract.manager.ds.other.repository.SysConfRepository;
@Lazy @Lazy
@Service @Service
@@ -22,6 +23,11 @@ public class SysConfService {
return repository.findById(key).orElse(null); return repository.findById(key).orElse(null);
} }
@CacheEvict(key = "#p0.id")
public SysConf save(SysConf conf) {
return repository.save(conf);
}
@CacheEvict(key = "#p0") @CacheEvict(key = "#p0")
public SysConf set(String key, String value) { public SysConf set(String key, String value) {
SysConf conf = findById(key); SysConf conf = findById(key);

View File

@@ -1,41 +0,0 @@
package com.ecep.contract.manager.ds.project.controller;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerFile;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerFileService;
import com.ecep.contract.manager.ds.project.vo.ProjectBidViewModel;
import javafx.scene.control.TableCell;
import org.hibernate.Hibernate;
import org.springframework.util.StringUtils;
import java.io.File;
class EvaluationFileTableCell extends TableCell<ProjectBidViewModel, CompanyCustomerEvaluationFormFile> {
private CompanyCustomerFileService fileService;
public CompanyCustomerFileService getFileService() {
if (fileService == null) {
fileService = SpringApp.getBean(CompanyCustomerFileService.class);
}
return fileService;
}
@Override
protected void updateItem(CompanyCustomerEvaluationFormFile item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
return;
}
if (!Hibernate.isInitialized(item)) {
item = getFileService().findCustomerEvaluationFormFileById(item.getId());
}
CompanyCustomerFile customerFile = item.getCustomerFile();
String path = customerFile.getFilePath();
if (StringUtils.hasText(path)) {
File file = new File(path);
setText(file.getName());
}
}
}

View File

@@ -195,10 +195,15 @@ public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends
loadTableDataSet(true); loadTableDataSet(true);
} }
private boolean allowResize = true;
/** /**
* 根据表格高度重新计算分页的页大小 * 根据表格高度重新计算分页的页大小
*/ */
private void resizeTable(Object observable, Bounds old, Bounds newBounds) { private void resizeTable(Object observable, Bounds old, Bounds newBounds) {
if (!allowResize) {
return;
}
double tableHeight = newBounds.getHeight(); double tableHeight = newBounds.getHeight();
if (tableHeight <= 0) { if (tableHeight <= 0) {
return; return;
@@ -208,8 +213,13 @@ public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends
if (lookup != null) { if (lookup != null) {
double rowHeight = lookup.prefHeight(-1); double rowHeight = lookup.prefHeight(-1);
int rows = (int) Math.round(table.getHeight() / rowHeight) - 1; int rows = (int) Math.round(table.getHeight() / rowHeight) - 1;
int pageNumber = (int) Math.abs(currentPageable.getOffset() / rows); // 只有当行数变化超过一定阈值时才重新加载数据
int currentRows = currentPageable.getPageSize();
if (Math.abs(rows - currentRows) <= 2) {
return; // 避免微小变化导致频繁刷新
}
int pageNumber = (int) Math.abs(currentPageable.getOffset() / rows);
if (currentPageable.getPageNumber() == pageNumber && currentPageable.getPageSize() == rows) { if (currentPageable.getPageNumber() == pageNumber && currentPageable.getPageSize() == rows) {
return; return;
} }
@@ -359,6 +369,7 @@ public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends
private CompletableFuture<Void> _reloadTableData() { private CompletableFuture<Void> _reloadTableData() {
CompletableFuture<Void> future = new CompletableFuture<>(); CompletableFuture<Void> future = new CompletableFuture<>();
Platform.runLater(() -> { Platform.runLater(() -> {
allowResize = false; // 禁用调整
dataSet.clear(); dataSet.clear();
runAsync(() -> { runAsync(() -> {
controller.setStatus("载入中..."); controller.setStatus("载入中...");
@@ -366,8 +377,10 @@ public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends
Platform.runLater(() -> { Platform.runLater(() -> {
try { try {
updateTableDataSet(models); updateTableDataSet(models);
allowResize = true; // 恢复调整
future.complete(null); future.complete(null);
} catch (Exception e) { } catch (Exception e) {
allowResize = true; // 恢复调整
future.completeExceptionally(e); future.completeExceptionally(e);
} }
}); });
@@ -381,7 +394,23 @@ public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends
protected void updateTableDataSet(List<TV> models) { protected void updateTableDataSet(List<TV> models) {
long timeMillis = System.currentTimeMillis(); 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; long timeCost = System.currentTimeMillis() - timeMillis;
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("update table dataSet cost: {} ms", timeCost); logger.debug("update table dataSet cost: {} ms", timeCost);

View File

@@ -1,5 +1,20 @@
package com.ecep.contract.manager.ui; package com.ecep.contract.manager.ui;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import com.ecep.contract.manager.Desktop; import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.SpringApp; import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.other.model.Employee; import com.ecep.contract.manager.ds.other.model.Employee;
@@ -9,6 +24,7 @@ import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ds.other.vo.IdentityViewModel; import com.ecep.contract.manager.ds.other.vo.IdentityViewModel;
import com.ecep.contract.manager.util.FxmlUtils; import com.ecep.contract.manager.util.FxmlUtils;
import com.ecep.contract.manager.util.UITools; import com.ecep.contract.manager.util.UITools;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@@ -22,20 +38,6 @@ import javafx.stage.Window;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class BaseController { public class BaseController {
private static final Logger logger = LoggerFactory.getLogger(BaseController.class); private static final Logger logger = LoggerFactory.getLogger(BaseController.class);
@@ -45,7 +47,8 @@ public class BaseController {
return show(clz, owner, null); return show(clz, owner, null);
} }
public static <T extends BaseController> CompletableFuture<Void> show(Class<T> clz, Window owner, Consumer<T> consumer) { public static <T extends BaseController> CompletableFuture<Void> show(Class<T> clz, Window owner,
Consumer<T> consumer) {
String key = clz.getName(); String key = clz.getName();
if (toFront(key)) { if (toFront(key)) {
return null; return null;
@@ -65,8 +68,8 @@ public class BaseController {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <K extends IdentityEntity, M extends IdentityViewModel<K>, T extends BaseController> public static <K extends IdentityEntity, M extends IdentityViewModel<K>, T extends BaseController> void show(
void show(Class<T> clz, M viewModel, Window owner) { Class<T> clz, M viewModel, Window owner) {
String key = getKey(clz, viewModel); String key = getKey(clz, viewModel);
if (toFront(key)) { if (toFront(key)) {
return; return;
@@ -76,7 +79,6 @@ public class BaseController {
throw new RuntimeException("@FxmlPath is required"); throw new RuntimeException("@FxmlPath is required");
} }
FxmlUtils.newLoaderAsyncWithRunLater(annotation.value(), null, loader -> { FxmlUtils.newLoaderAsyncWithRunLater(annotation.value(), null, loader -> {
T controller = loader.getController(); T controller = loader.getController();
if (controller instanceof AbstEntityController<?, ?>) { if (controller instanceof AbstEntityController<?, ?>) {
@@ -114,7 +116,6 @@ public class BaseController {
}); });
} }
public static boolean toFront(String key) { public static boolean toFront(String key) {
Stage stage = stages.get(key); Stage stage = stages.get(key);
if (stage != null) { if (stage != null) {
@@ -161,6 +162,10 @@ public class BaseController {
return future; return future;
} }
public CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFuture.runAsync(runnable, Desktop.instance.getExecutorService()).exceptionally(this::handleException);
}
/** /**
* 窗口标题 * 窗口标题
*/ */

View File

@@ -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.service.IEntityService;
import com.ecep.contract.manager.ds.other.vo.IdentityViewModel; import com.ecep.contract.manager.ds.other.vo.IdentityViewModel;
/**
* 视图模型服务接口
*
* @param <T> 实体类型
* @param <TV> 视图模型类型
* @author 2025-08-02
*/
public interface ViewModelService<T extends IdentityEntity, TV extends IdentityViewModel<T>> public interface ViewModelService<T extends IdentityEntity, TV extends IdentityViewModel<T>>
extends IEntityService<T> { extends IEntityService<T> {

View File

@@ -3,6 +3,8 @@ package com.ecep.contract.manager.ui.table.cell;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ecep.contract.manager.Desktop; import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.ds.other.model.IdentityEntity; import com.ecep.contract.manager.ds.other.model.IdentityEntity;
@@ -18,6 +20,8 @@ import javafx.application.Platform;
* @param <T> * @param <T>
*/ */
public class AsyncUpdateTableCell<V, T extends IdentityEntity> extends javafx.scene.control.TableCell<V, T> { public class AsyncUpdateTableCell<V, T extends IdentityEntity> extends javafx.scene.control.TableCell<V, T> {
private static final Logger logger = LoggerFactory.getLogger(AsyncUpdateTableCell.class);
/** /**
* 转换为文本 * 转换为文本
*/ */
@@ -32,6 +36,20 @@ public class AsyncUpdateTableCell<V, T extends IdentityEntity> extends javafx.sc
} }
private IEntityService<T> service; private IEntityService<T> service;
Future<?> syncFuture;
/**
* 通过 #setService 设置服务类,或者子类实现, 提供服务类
*
* @return
*/
protected IEntityService<T> getServiceBean() {
return null;
}
public String format(T entity) {
return toString(entity);
}
public void setService(IEntityService<T> service) { public void setService(IEntityService<T> service) {
this.service = service; this.service = service;
@@ -44,13 +62,15 @@ public class AsyncUpdateTableCell<V, T extends IdentityEntity> extends javafx.sc
return service; return service;
} }
protected IEntityService<T> getServiceBean() {
return null;
}
@Override @Override
protected void updateItem(T item, boolean empty) { protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
// 取消之前的异步任务
if (syncFuture != null) {
syncFuture.cancel(true);
syncFuture = null;
}
if (empty || item == null) { if (empty || item == null) {
setText(null); setText(null);
return; return;
@@ -59,23 +79,45 @@ public class AsyncUpdateTableCell<V, T extends IdentityEntity> extends javafx.sc
setText(format(item)); setText(format(item));
return; return;
} }
setText("# " + item.getId()); setText("# " + item.getId());
submit(this::asyncLoadAndUpdate); syncFuture = submit(this::asyncLoadAndUpdate);
} }
/**
* 检查实体是否已初始化
*
* @param proxy
* @return
*/
protected boolean isInitialized(T proxy) { protected boolean isInitialized(T proxy) {
return Hibernate.isInitialized(proxy); return Hibernate.isInitialized(proxy);
} }
/**
* 初始化实体
*
* @return
*/
protected T initialize() {
return getService().findById(getItem().getId());
}
/**
* 提交异步任务
*
* @param var1 异步任务
* @return
*/
Future<?> submit(Runnable var1) { Future<?> submit(Runnable var1) {
return Desktop.instance.getExecutorService().submit(var1); return Desktop.instance.getExecutorService().submit(var1);
} }
public String format(T entity) { protected void asyncLoadAndUpdate() {
return toString(entity); if (getItem() == null) {
return;
} }
protected void asyncLoadAndUpdate() {
T entity = initialize(); T entity = initialize();
String formated; String formated;
try { try {
@@ -84,14 +126,26 @@ public class AsyncUpdateTableCell<V, T extends IdentityEntity> extends javafx.sc
formated = e.getMessage(); formated = e.getMessage();
} }
String texted = formated; String texted = formated;
// 保存当前需要更新的项目信息,避免闭包引用导致的问题
final T updatedEntity = entity;
final String updatedText = texted;
final T finalCurrentLoadingItem = getItem();
Platform.runLater(() -> { 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());
}
} }

View File

@@ -1,11 +1,14 @@
package com.ecep.contract.manager.ui.table.cell; 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 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 @NoArgsConstructor
public class CompanyTableCell<V> extends AsyncUpdateTableCell<V, Company> { public class CompanyTableCell<V> extends AsyncUpdateTableCell<V, Company> {

View File

@@ -0,0 +1,25 @@
package com.ecep.contract.manager.ui.table.cell;
import com.ecep.contract.manager.ds.other.model.EmployeeRole;
import com.ecep.contract.manager.ds.other.service.EmployeeRoleService;
import lombok.NoArgsConstructor;
import static com.ecep.contract.manager.SpringApp.getBean;
/**
* 角色表格列
*
* @param <V>
*/
@NoArgsConstructor
public class EmployeeRoleTableCell<V> extends AsyncUpdateTableCell<V, EmployeeRole> {
public EmployeeRoleTableCell(EmployeeRoleService service) {
setService(service);
}
@Override
protected EmployeeRoleService getServiceBean() {
return getBean(EmployeeRoleService.class);
}
}

View File

@@ -1,5 +1,9 @@
package com.ecep.contract.manager.ui.task; package com.ecep.contract.manager.ui.task;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@@ -13,6 +17,7 @@ import com.ecep.contract.manager.ui.Message;
import com.ecep.contract.manager.util.MyDateTimeUtils; import com.ecep.contract.manager.util.MyDateTimeUtils;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.Button; import javafx.scene.control.Button;
@@ -30,6 +35,7 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.WindowEvent; import javafx.stage.WindowEvent;
@@ -69,10 +75,47 @@ public class TaskMonitorViewController extends BaseController {
private Button cancelTaskButton; private Button cancelTaskButton;
@FXML @FXML
private Button clearHistoryButton; private Button clearHistoryButton;
@FXML
private Button refreshExecutorInfoButton;
@FXML
private TableView<ExecutorInfo> executorInfoTable;
@FXML
private TableColumn<ExecutorInfo, String> executorFieldColumn;
@FXML
private TableColumn<ExecutorInfo, String> executorValueColumn;
@FXML
private TableColumn<ExecutorInfo, String> executorDescriptionColumn;
public TaskMonitorViewController() { public TaskMonitorViewController() {
} }
/**
* 用于存储ExecutorService信息的内部类
*/
public static class ExecutorInfo {
private final String field;
private final String value;
private final String description;
public ExecutorInfo(String field, String value, String description) {
this.field = field;
this.value = value;
this.description = description;
}
public String getField() {
return field;
}
public String getValue() {
return value;
}
public String getDescription() {
return description;
}
}
@Override @Override
public void onShown(WindowEvent windowEvent) { public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent); super.onShown(windowEvent);
@@ -144,6 +187,94 @@ public class TaskMonitorViewController extends BaseController {
}); });
cancelTaskButton.disableProperty().bind(activeTasksTable.getSelectionModel().selectedItemProperty().isNull()); cancelTaskButton.disableProperty().bind(activeTasksTable.getSelectionModel().selectedItemProperty().isNull());
// 初始化Executor信息表格
initializeExecutorInfoTable();
}
/**
* 初始化Executor信息表格
*/
private void initializeExecutorInfoTable() {
executorFieldColumn.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getField()));
executorValueColumn.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getValue()));
executorDescriptionColumn
.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getDescription()));
// 初始加载Executor信息
refreshExecutorInfo();
// 绑定刷新按钮事件
refreshExecutorInfoButton.setOnAction(event -> refreshExecutorInfo());
}
/**
* 刷新Executor信息
*/
@FXML
private void refreshExecutorInfo() {
executorInfoTable.getItems().clear();
try {
ExecutorService executorService = Desktop.instance.getExecutorService();
if (executorService instanceof ThreadPoolExecutor threadPoolExecutor) {
executorInfoTable.getItems().add(new ExecutorInfo(
"PoolSize",
String.valueOf(threadPoolExecutor.getPoolSize()),
"PoolSize"));
executorInfoTable.getItems().add(new ExecutorInfo(
"活动线程数",
String.valueOf(threadPoolExecutor.getActiveCount()),
"当前正在执行任务的线程数"));
// 添加线程池信息
executorInfoTable.getItems().add(new ExecutorInfo(
"核心线程数",
String.valueOf(threadPoolExecutor.getCorePoolSize()),
"线程池维护的最小线程数"));
executorInfoTable.getItems().add(new ExecutorInfo(
"最大线程数",
String.valueOf(threadPoolExecutor.getMaximumPoolSize()),
"线程池允许的最大线程数"));
executorInfoTable.getItems().add(new ExecutorInfo(
"KeepAliveTime",
String.valueOf(threadPoolExecutor.getKeepAliveTime(TimeUnit.SECONDS)),
"the thread keep-alive time, which is the amount of time that threads may remain idle before being terminated. Threads that wait this amount of time without processing a task will be terminated if there are more than the core number of threads currently in the pool, or if this pool allows core thread timeout."));
executorInfoTable.getItems().add(new ExecutorInfo(
"任务队列大小",
String.valueOf(threadPoolExecutor.getQueue().size()),
"等待执行的任务数量"));
executorInfoTable.getItems().add(new ExecutorInfo(
"已完成任务数",
String.valueOf(threadPoolExecutor.getCompletedTaskCount()),
"已完成执行的任务总数"));
executorInfoTable.getItems().add(new ExecutorInfo(
"LargestPoolSize",
String.valueOf(threadPoolExecutor.getLargestPoolSize()),
"线程池当前状态"));
// 如果是ScheduledExecutorService添加额外信息
if (executorService instanceof ScheduledExecutorService) {
executorInfoTable.getItems().add(new ExecutorInfo(
"线程池类型",
"ScheduledExecutorService",
"可调度的线程池"));
} else {
executorInfoTable.getItems().add(new ExecutorInfo(
"线程池类型",
"ThreadPoolExecutor",
"普通线程池"));
}
} else {
executorInfoTable.getItems().add(new ExecutorInfo(
"错误",
"未知的ExecutorService类型",
"无法获取线程池详细信息"));
}
} catch (Exception e) {
executorInfoTable.getItems().add(new ExecutorInfo(
"异常",
e.getMessage(),
"获取ExecutorService信息时发生错误"));
}
} }
/** /**
@@ -218,4 +349,11 @@ public class TaskMonitorViewController extends BaseController {
alert.getDialogPane().setContent(scrollPane); alert.getDialogPane().setContent(scrollPane);
alert.showAndWait(); alert.showAndWait();
} }
/**
* 运行任务监控演示
*/
public void onRunTaskMonitorDemo(ActionEvent event) {
com.ecep.contract.manager.ui.task.DemoTask.runDemo();
}
} }

View File

@@ -7,6 +7,12 @@ import java.time.LocalDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
public class MyDateTimePropertyUtils { public class MyDateTimePropertyUtils {
/**
* 本地日期时间转换为时间戳
*
* @param property
* @return
*/
public static Instant localDateTimeToInstant(SimpleObjectProperty<LocalDateTime> property) { public static Instant localDateTimeToInstant(SimpleObjectProperty<LocalDateTime> property) {
LocalDateTime dateTime = property.get(); LocalDateTime dateTime = property.get();
if (dateTime != null) { if (dateTime != null) {

View File

@@ -1,14 +1,16 @@
package com.ecep.contract.manager.util; package com.ecep.contract.manager.util;
import com.ecep.contract.manager.AppV2;
import com.ecep.contract.manager.SpringApp;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import com.ecep.contract.manager.AppV2;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.SpringApp;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
public class FxmlUtils { public class FxmlUtils {
public static FXMLLoader newLoader(String path) { public static FXMLLoader newLoader(String path) {
@@ -22,8 +24,8 @@ public class FxmlUtils {
return loader; return loader;
} }
public static CompletableFuture<FXMLLoader> newLoaderAsync(String path,
public static CompletableFuture<FXMLLoader> newLoaderAsync(String path, java.util.function.Consumer<FXMLLoader> consumer) { java.util.function.Consumer<FXMLLoader> consumer) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
FXMLLoader loader = newLoader(path); FXMLLoader loader = newLoader(path);
try { try {
@@ -51,8 +53,7 @@ public class FxmlUtils {
public static CompletableFuture<Void> newLoaderAsyncWithRunLater( public static CompletableFuture<Void> newLoaderAsyncWithRunLater(
String path, String path,
java.util.function.Consumer<FXMLLoader> initializeLoader, java.util.function.Consumer<FXMLLoader> initializeLoader,
java.util.function.Consumer<FXMLLoader> runLater java.util.function.Consumer<FXMLLoader> runLater) {
) {
CompletableFuture<Void> future = new CompletableFuture<>(); CompletableFuture<Void> future = new CompletableFuture<>();
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {
try { try {
@@ -72,7 +73,7 @@ public class FxmlUtils {
} catch (IOException e) { } catch (IOException e) {
future.completeExceptionally(new RuntimeException("Unable open " + path, e)); future.completeExceptionally(new RuntimeException("Unable open " + path, e));
} }
}).whenComplete((v, ex) -> { }, Desktop.instance.getExecutorService()).whenComplete((v, ex) -> {
if (ex != null) { if (ex != null) {
future.completeExceptionally(ex); future.completeExceptionally(ex);
} }

View File

@@ -29,6 +29,7 @@
<logger name="com.ecep.contract.manager.ui.service" level="info"/> <logger name="com.ecep.contract.manager.ui.service" level="info"/>
<logger name="com.ecep.contract.manager.ui.table.AbstEntityTableTabSkin" level="debug"/> <logger name="com.ecep.contract.manager.ui.table.AbstEntityTableTabSkin" level="debug"/>
<logger name="com.ecep.contract.manager.ui.table.cell.AsyncUpdateTableCell" level="warn"/>
<logger name="com.ecep.contract.manager.ui.AbstEntityManagerSkin" level="debug"/> <logger name="com.ecep.contract.manager.ui.AbstEntityManagerSkin" level="debug"/>
<logger name="com.ecep.contract.manager.ui.BaseController" level="debug"/> <logger name="com.ecep.contract.manager.ui.BaseController" level="debug"/>
<logger name="com.ecep.contract.manager.ui.controller" level="info"/> <logger name="com.ecep.contract.manager.ui.controller" level="info"/>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<VBox prefHeight="400.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.cloud.u8.YongYouU8ConfigWindowController">
<children>
<Label text="用友U8配置" />
<GridPane>
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" minWidth="50.0" prefWidth="250.0" />
<ColumnConstraints fillWidth="false" halignment="RIGHT" hgrow="NEVER" maxWidth="5.0" minWidth="5.0" prefWidth="5.0" />
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints fillHeight="false" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints fillHeight="false" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints fillHeight="false" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="同步时未创建的公司时开发日期在此之后的自动创建" />
<DatePicker fx:id="auto_create_company_after" GridPane.columnIndex="2" />
<Label text="cloud.u8.contract.latestDate" GridPane.rowIndex="1" />
<DatePicker fx:id="contract_latest_date" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<Label text="cloud.u8.contract.latestId" GridPane.rowIndex="2" />
<TextField fx:id="contract_latest_id" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<Label text="cloud.u8.sync.elapse" GridPane.rowIndex="3" />
<TextField fx:id="sync_elapse" GridPane.columnIndex="2" GridPane.rowIndex="3" />
</children>
</GridPane>
</children>
</VBox>

View File

@@ -2,7 +2,7 @@
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" <VBox prefHeight="400.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.ecep.contract.manager.cloud.u8.YongYouU8ManagerWindowController"> fx:controller="com.ecep.contract.manager.cloud.u8.YongYouU8ManagerWindowController">
<children> <children>
<MenuBar VBox.vgrow="NEVER"> <MenuBar VBox.vgrow="NEVER">
@@ -18,7 +18,7 @@
<MenuItem mnemonicParsing="false" text="Save As…"/> <MenuItem mnemonicParsing="false" text="Save As…"/>
<MenuItem mnemonicParsing="false" text="Revert"/> <MenuItem mnemonicParsing="false" text="Revert"/>
<SeparatorMenuItem mnemonicParsing="false"/> <SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem mnemonicParsing="false" text="Preferences…"/> <MenuItem mnemonicParsing="false" text="配置…" onAction="#onConfigAction"/>
<SeparatorMenuItem mnemonicParsing="false"/> <SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem mnemonicParsing="false" text="Quit"/> <MenuItem mnemonicParsing="false" text="Quit"/>
</items> </items>

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.image.*?> <?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import org.controlsfx.control.TaskProgressView?> <?import org.controlsfx.control.TaskProgressView?>
<VBox fx:id="root" prefHeight="468.0" prefWidth="737.0" xmlns="http://javafx.com/javafx/22" <VBox fx:id="root" prefHeight="468.0" prefWidth="737.0" xmlns="http://javafx.com/javafx/22"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.ecep.contract.manager.ds.other.controller.HomeWindowController"> fx:controller="com.ecep.contract.manager.ds.other.controller.HomeWindowController">
@@ -18,7 +18,6 @@
<Menu text="数据源"> <Menu text="数据源">
<MenuItem mnemonicParsing="false" onAction="#openGroupRKResourceWindow" text="集团相关方…"/> <MenuItem mnemonicParsing="false" onAction="#openGroupRKResourceWindow" text="集团相关方…"/>
<MenuItem mnemonicParsing="false" onAction="#openTycResourceWindow" text="天眼查…"/> <MenuItem mnemonicParsing="false" onAction="#openTycResourceWindow" text="天眼查…"/>
<MenuItem mnemonicParsing="false" onAction="#openYongYouResourceWindow" text="用友U8…"/>
</Menu> </Menu>
</items> </items>
</Menu> </Menu>
@@ -30,6 +29,7 @@
<items> <items>
<MenuItem mnemonicParsing="false" onAction="#createNewU8ContractSyncTaskAction" <MenuItem mnemonicParsing="false" onAction="#createNewU8ContractSyncTaskAction"
text="同步合同"/> text="同步合同"/>
<MenuItem mnemonicParsing="false" onAction="#openYongYouResourceWindow" text="用友U8…"/>
</items> </items>
</Menu> </Menu>
<Menu text="设置(_S)"> <Menu text="设置(_S)">
@@ -159,26 +159,6 @@
</VBox> </VBox>
</graphic> </graphic>
</Button> </Button>
<!-- 任务监控演示 -->
<Button mnemonicParsing="false" style="-fx-padding: 6px;" onAction="#onRunTaskMonitorDemo">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<viewport>
<Rectangle2D height="46.0" width="64.0"/>
</viewport>
</ImageView>
<Label text="任务监控演示">
<VBox.margin>
<Insets top="5.0"/>
</VBox.margin>
</Label>
</children>
</VBox>
</graphic>
</Button>
</items> </items>
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
@@ -199,7 +179,7 @@
<Insets left="6.0"/> <Insets left="6.0"/>
</HBox.margin> </HBox.margin>
</Label> </Label>
<Label fx:id="taskMonitorLabel" text="任务监控"></Label> <Label fx:id="taskMonitorLabel" text="任务监控"/>
<Label fx:id="employeeStatusLabel" layoutX="711.0" layoutY="10.0" text="管理员" wrapText="true" <Label fx:id="employeeStatusLabel" layoutX="711.0" layoutY="10.0" text="管理员" wrapText="true"
HBox.hgrow="SOMETIMES"> HBox.hgrow="SOMETIMES">
<HBox.margin> <HBox.margin>

View File

@@ -8,8 +8,13 @@
<?import javafx.scene.control.ToolBar?> <?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<VBox minHeight="400.0" minWidth="500.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.ui.task.TaskMonitorViewController">
<TabPane minHeight="400.0" minWidth="500.0" tabMinWidth="70.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.ui.task.TaskMonitorViewController"> <ToolBar>
<items>
<Button fx:id="runTaskMonitorDemoBtn" text="运行演示任务" onAction="#onRunTaskMonitorDemo"/>
</items>
</ToolBar>
<TabPane tabMinWidth="70.0" VBox.vgrow="ALWAYS">
<tabs> <tabs>
<Tab closable="false" text="活动任务"> <Tab closable="false" text="活动任务">
<content> <content>
@@ -59,5 +64,27 @@
</VBox> </VBox>
</content> </content>
</Tab> </Tab>
<Tab closable="false" text="Executor">
<content>
<VBox spacing="5.0">
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="refreshExecutorInfoButton" text="刷新"/>
</items>
</ToolBar>
<TableView fx:id="executorInfoTable" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="executorFieldColumn" prefWidth="150.0" text="字段"/>
<TableColumn fx:id="executorValueColumn" prefWidth="200.0" text="值"/>
<TableColumn fx:id="executorDescriptionColumn" prefWidth="300.0" text="描述"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</VBox>
</content>
</Tab>
</tabs> </tabs>
</TabPane> </TabPane>
</VBox>