Compare commits

..

5 Commits

Author SHA1 Message Date
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
38 changed files with 1173 additions and 633 deletions

1
null Normal file
View File

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

View File

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

View File

@@ -1,10 +1,28 @@
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.ui.BaseController;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.task.TaskMonitorCenter;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
@@ -19,18 +37,6 @@ import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
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 应用程序
@@ -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) {
System.out.println("Desktop.startSpringApp");
// 更新窗口标题
@@ -158,7 +168,7 @@ public class Desktop extends Application {
holder.info("启动中,请稍后...");
CompletableFuture.runAsync(() -> {
runAsync(() -> {
try {
//
holder.info("读取配置文件...");
@@ -176,7 +186,7 @@ public class Desktop extends Application {
}
}
CompletableFuture.runAsync(() -> {
runAsync(() -> {
SpringApp.launch(properties, holder);
ConfigurableListableBeanFactory beanFactory = SpringApp.context.getBeanFactory();

View File

@@ -108,7 +108,7 @@ public class SpringApp {
CompletableFuture.runAsync(() -> {
// 在这里调用 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.contract.ContractFileType;
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.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.model.ContractFile;
@@ -73,7 +74,7 @@ public class OldVersionService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private SysConfRepository confRepository;
private SysConfService confService;
@Lazy
@Autowired
private CompanyService companyService;
@@ -215,7 +216,7 @@ public class OldVersionService {
logger.debug("createSyncTask");
}
boolean autoSyncEnable = confRepository.get("cloud.old.auto_sync.enable", false);
boolean autoSyncEnable = confService.getBoolean("cloud.old.auto_sync.enable");
if (!autoSyncEnable) {
return;
}

View File

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

View File

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

View File

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

View File

@@ -1,14 +1,5 @@
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.time.LocalDateTime;
import java.util.Map;
@@ -16,21 +7,45 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
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 {
private static final Logger logger = LoggerFactory.getLogger(ContractSyncTask.class);
@Setter
private boolean useLatestId = true;
private YongYouU8Repository repository;
public ContractSyncTask() {
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_CONTRACT_SYNC_USE_LATEST_ID)) {
syncByLatestId(holder);
} else {
syncByLatestDate(holder);
}
}
private void syncByLatestId(MessageHolder holder) {
int latestId = getConfService().getInt(ContractService.CONTRACT_LATEST_ID);
int latestId = getConfService().getInt(ContractCtx.CONTRACT_LATEST_ID);
updateTitle("用友U8系统-同步合同,从 " + latestId + " 开始");
Long total = repository.countAllContracts(latestId);
@@ -66,11 +81,11 @@ public class ContractSyncTask extends AbstContractRepairTasker {
updateProgress(counter.incrementAndGet(), total);
});
}
getConfService().set(ContractService.CONTRACT_LATEST_ID, String.valueOf(reference.get()));
getConfService().set(ContractCtx.CONTRACT_LATEST_ID, String.valueOf(reference.get()));
}
private void syncByLatestDate(MessageHolder holder) {
String strDateTime = getConfService().getString(ContractService.CONTRACT_LATEST_DATE);
String strDateTime = getConfService().getString(ContractCtx.CONTRACT_LATEST_DATE);
LocalDateTime latestDateTime = null;
if (StringUtils.hasText(strDateTime)) {
try {
@@ -120,17 +135,7 @@ public class ContractSyncTask extends AbstContractRepairTasker {
updateProgress(counter.incrementAndGet(), total);
});
}
getConfService().set(ContractService.CONTRACT_LATEST_DATE, String.valueOf(reference.get()));
getConfService().set(ContractCtx.CONTRACT_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;
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.Map;
import java.util.Objects;
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 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);
@Setter
private ContractTypeService contractTypeService;
@@ -36,29 +37,29 @@ public class ContractTypeSyncTask extends Task<Object> {
}
@Override
protected Object call() throws Exception {
protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} 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;
}
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();
int size = list.size();
updateMessage("总共读取 CM_Type,CM_TypeClass 数据 " + size + "");
holder.debug("总共读取 CM_Type,CM_TypeClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
holder.info("Cancelled");
return null;
}
sync(map, msg -> {
updateMessage(counter.get() + "/" + size + ">" + msg);
});
MessageHolder sub = holder.sub(counter.get() + "/" + size + ">" );
sync(map, sub);
// 更新进度
updateProgress(counter.incrementAndGet(), size);
}
@@ -66,7 +67,7 @@ public class ContractTypeSyncTask extends Task<Object> {
return null;
}
private void sync(Map<String, Object> map, Consumer<String> consumer) {
private void sync(Map<String, Object> map, MessageHolder holder) {
boolean modified = false;
String typeCode = (String) map.get("cTypeCode");
@@ -79,34 +80,39 @@ public class ContractTypeSyncTask extends Task<Object> {
ContractType contractType = typeService.findByCode(typeCode);
if (contractType == null) {
contractType = new ContractType();
consumer.accept("新建合同类型:" + typeCode);
holder.info("新建合同类型:" + typeCode);
modified = true;
}
if (!Objects.equals(contractType.getCode(), typeCode)) {
contractType.setCode(typeCode);
holder.info("合同类型代码:" + contractType.getCode() + " -> " + typeCode);
modified = true;
}
if (!Objects.equals(contractType.getName(), typeName)) {
contractType.setName(typeName);
holder.info("合同类型名称:" + contractType.getName() + " -> " + typeName);
modified = true;
}
if (!Objects.equals(contractType.getTitle(), typeTitle)) {
contractType.setTitle(typeTitle);
holder.info("合同类型标题:" + contractType.getTitle() + " -> " + typeTitle);
modified = true;
}
if (!Objects.equals(contractType.getCatalog(), typeCatalog)) {
contractType.setTitle(typeTitle);
contractType.setCatalog(typeCatalog);
holder.info("合同类型分类:" + contractType.getCatalog() + " -> " + typeCatalog);
modified = true;
}
if (!Objects.equals(contractType.getDirection(), typeDirection)) {
contractType.setTitle(typeTitle);
contractType.setDirection(typeDirection);
holder.info("合同类型方向:" + contractType.getDirection() + " -> " + typeDirection);
modified = true;
}
if (modified) {
typeService.save(contractType);
consumer.accept("更新" + contractType.getName() + " 信息");
}
}
}

View File

@@ -1,70 +1,99 @@
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.Map;
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.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() {
updateTitle("用友U8系统-同步客户分类信息");
}
CompanyCustomerService getCompanyCustomerService() {
if (companyCustomerService == null) {
companyCustomerService = SpringApp.getBean(CompanyCustomerService.class);
}
return companyCustomerService;
}
@Override
protected Object call() throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class);
CompanyCustomerService customerService = SpringApp.getBean(CompanyCustomerService.class);
protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Repository repository = null;
try {
repository = SpringApp.getBean(YongYouU8Repository.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Repository", e);
holder.error("can't get bean of YongYouU8Repository");
return null;
}
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 CustomerClass 数据表...");
List<Map<String, Object>> list = service.queryAllCustomerClass();
logger.info("读取 U8 系统 CustomerClass 数据表...");
List<Map<String, Object>> list = repository.queryAllCustomerClass();
int size = list.size();
updateMessage("总共读取 CustomerClass 数据 " + size + "");
holder.debug("总共读取 CustomerClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
holder.info("Cancelled");
return null;
}
boolean modified = false;
String code = (String) map.get("cCCCode");
String name = (String) map.get("cCCName");
CustomerCatalog customerCatalog = customerService.findCatalogByCode(code);
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);
}
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;
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.Map;
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.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() {
updateTitle("用友U8系统-同步供应商分类信息");
}
VendorClassRepository getVendorClassRepository() {
if (vendorClassRepository == null) {
vendorClassRepository = SpringApp.getBean(VendorClassRepository.class);
}
return vendorClassRepository;
}
@Override
protected Object call() throws Exception {
YongYouU8Service service = SpringApp.getBean(YongYouU8Service.class);
VendorClassRepository groupRepository = SpringApp.getBean(VendorClassRepository.class);
protected Object execute(MessageHolder holder) throws Exception {
YongYouU8Service service = null;
try {
service = SpringApp.getBean(YongYouU8Service.class);
} catch (BeansException e) {
logger.error("can't get bean of YongYouU8Service", e);
holder.error("can't get bean of YongYouU8Service");
return null;
}
AtomicInteger counter = new AtomicInteger(0);
updateMessage("读取 U8 系统 VendorClass 数据表...");
logger.info("读取 U8 系统 VendorClass 数据表...");
List<Map<String, Object>> list = service.queryAllVendorClass();
int size = list.size();
updateMessage("总共读取 VendorClass 数据 " + size + "");
holder.debug("总共读取 VendorClass 数据 " + size + "");
for (Map<String, Object> map : list) {
if (isCancelled()) {
updateMessage("Cancelled");
holder.info("Cancelled");
return null;
}
boolean modified = false;
String code = (String) map.get("cVCCode");
String name = (String) map.get("cVCName");
VendorCatalog vendorCatalog = groupRepository.findByCode(code).orElse(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);
}
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.CONTRACT_LATEST_DATE);
config2.setPicker(contract_latest_date);
config2.initialize();
StringConfig config3 = new StringConfig(ContractCtx.CONTRACT_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;
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.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 java.time.LocalDateTime;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.cloud.CloudBaseInfo;
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.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
@Scope("prototype")
@@ -38,9 +34,6 @@ public class YongYouU8ManagerWindowController
show(YongYouU8ManagerWindowController.class, null);
}
@Autowired
private ScheduledExecutorService scheduledExecutorService;
public TableColumn<CloudYuInfoViewModel, Number> idColumn;
public TableColumn<CloudYuInfoViewModel, LocalDateTime> latestUpdateColumn;
public TableColumn<CloudYuInfoViewModel, Company> companyColumn;
@@ -58,73 +51,25 @@ public class YongYouU8ManagerWindowController
return new YongYouU8ManagerSkin(this);
}
@Override
public void show(Stage stage) {
super.show(stage);
getTitle().set("数据源:用友U8");
getTitle().set("用友U8");
}
/**
* 打开配置窗口
*/
public void onConfigAction(ActionEvent event) {
BaseController.show(YongYouU8ConfigWindowController.class, null);
}
/**
* 数据迁移,从 CloudInfo 迁移到 CloudRk
*/
public void onDateTransferAction(ActionEvent event) {
CompletableFuture.runAsync(() -> {
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("同步任务已创建...");
DateTransferTask task = new DateTransferTask();
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
}
public void onPersonSyncAction(ActionEvent event) {
@@ -153,39 +98,28 @@ public class YongYouU8ManagerWindowController
}
public void onContractGroupSyncAction(ActionEvent event) {
Task<Object> task = new ContractGroupSyncTask();
UITools.showTaskDialogAndWait("合同分组数据同步", task, consumer -> {
initializeTask(task, "合同分组数据", msg -> consumer.accept(Message.info(msg)));
});
ContractGroupSyncTask task = new ContractGroupSyncTask();
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
}
public void onContractTypeSyncAction(ActionEvent event) {
Task<Object> task = new ContractTypeSyncTask();
UITools.showTaskDialogAndWait("合同分类数据同步", task, consumer -> {
initializeTask(task, "合同分类数据", msg -> consumer.accept(Message.info(msg)));
});
ContractTypeSyncTask task = new ContractTypeSyncTask();
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
}
public void onContractKindSyncAction(ActionEvent event) {
Task<Object> task = new ContractKindSyncTask();
UITools.showTaskDialogAndWait("合同类型数据同步", task, consumer -> {
initializeTask(task, "合同类型数据", msg -> consumer.accept(Message.info(msg)));
});
ContractKindSyncTask task = new ContractKindSyncTask();
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
}
public void onVendorClassSyncAction(ActionEvent event) {
Task<Object> task = new VendorClassSyncTask();
UITools.showTaskDialogAndWait("供应商分类数据同步", task, consumer -> {
initializeTask(task, "供应商分类数据", msg -> consumer.accept(Message.info(msg)));
});
VendorClassSyncTask task = new VendorClassSyncTask();
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
}
public void onCustomerClassSyncAction(ActionEvent event) {
Task<Object> task = new CustomerClassSyncTask();
UITools.showTaskDialogAndWait("客户分类数据同步", task, consumer -> {
initializeTask(task, "客户分类数据", msg -> consumer.accept(Message.info(msg)));
});
CustomerClassSyncTask task = new CustomerClassSyncTask();
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
}
}

View File

@@ -1,18 +1,12 @@
package com.ecep.contract.manager.cloud.u8;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.cloud.u8.ctx.AbstractYongYouU8Ctx;
import com.ecep.contract.manager.ds.company.model.Company;
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 java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import javafx.application.Platform;
import javafx.concurrent.Task;
import org.controlsfx.control.TaskProgressView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,12 +19,19 @@ import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.cloud.CloudInfoRepository;
import com.ecep.contract.manager.cloud.u8.ctx.AbstractYongYouU8Ctx;
import com.ecep.contract.manager.ds.company.model.Company;
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
@Service
@@ -42,6 +43,9 @@ public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoVi
@Lazy
@Autowired
private YongYouU8Repository repository;
@Lazy
@Autowired
private CloudInfoRepository cloudInfoRepository;
@Lazy
@Autowired
private CompanyService companyService;
@@ -230,4 +234,8 @@ public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoVi
ctx.setCompanyVendorService(companyVendorService);
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;
public class CompanyCtx extends AbstractYongYouU8Ctx {
/**
* 自动创建公司的时间
*/
public static final String AUTO_CREATE_COMPANY_AFTER = "cloud.u8.auto-create-company-after";
@Setter
@@ -111,7 +114,7 @@ public class CompanyCtx extends AbstractYongYouU8Ctx {
return null;
}
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)) {
LocalDate miniDate = LocalDate.parse(autoCreateAfter);

View File

@@ -45,6 +45,10 @@ import java.util.stream.Stream;
import static com.ecep.contract.manager.SpringApp.getBean;
public class ContractCtx extends AbstractYongYouU8Ctx {
public static final String CONTRACT_LATEST_DATE = "cloud.u8.contract.latestDate";
public static final String CONTRACT_LATEST_ID = "cloud.u8.contract.latestId";
public static final String KEY_CONTRACT_SYNC_USE_LATEST_ID = "cloud.u8.contract.sync.use-latest-id";
@Setter
private ContractService contractService;
@@ -74,6 +78,7 @@ public class ContractCtx extends AbstractYongYouU8Ctx {
@Setter
private int customerEntityUpdateDelayDays = 1;
public ContractService getContractService() {
if (contractService == null) {
contractService = getBean(ContractService.class);

View File

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

View File

@@ -9,6 +9,7 @@ import java.util.Objects;
import java.util.regex.Matcher;
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.contract.ContractPayWay;
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> {
private static final Logger logger = LoggerFactory.getLogger(ContractService.class);
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
@Autowired
private ContractCatalogService contractCatalogService;
@@ -152,10 +150,10 @@ public class ContractService implements ViewModelService<Contract, ContractViewM
*/
public void updateLatestIdAndDate(Integer latestId, LocalDateTime latestDate) {
if (latestId != null) {
confService.set(CONTRACT_LATEST_ID, String.valueOf(latestId));
confService.set(ContractCtx.CONTRACT_LATEST_ID, String.valueOf(latestId));
}
if (latestDate != null) {
confService.set(CONTRACT_LATEST_DATE, latestDate.toString());
confService.set(ContractCtx.CONTRACT_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
private void init() {
// #2
setInitialized(project -> service.findById(project.getId()));
setSuggestion(service::search);
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) {
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;
import com.ecep.contract.manager.ds.other.model.SysConf;
import com.ecep.contract.manager.ds.other.repository.SysConfRepository;
import java.time.Instant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
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.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
@Service
@@ -22,6 +23,11 @@ public class SysConfService {
return repository.findById(key).orElse(null);
}
@CacheEvict(key = "#p0.id")
public SysConf save(SysConf conf) {
return repository.save(conf);
}
@CacheEvict(key = "#p0")
public SysConf set(String key, String value) {
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

@@ -1,5 +1,20 @@
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.SpringApp;
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.util.FxmlUtils;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@@ -22,20 +38,6 @@ import javafx.stage.Window;
import javafx.stage.WindowEvent;
import lombok.Getter;
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 {
private static final Logger logger = LoggerFactory.getLogger(BaseController.class);
@@ -45,7 +47,8 @@ public class BaseController {
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();
if (toFront(key)) {
return null;
@@ -65,8 +68,8 @@ public class BaseController {
}
@SuppressWarnings("unchecked")
public static <K extends IdentityEntity, M extends IdentityViewModel<K>, T extends BaseController>
void show(Class<T> clz, M viewModel, Window owner) {
public static <K extends IdentityEntity, M extends IdentityViewModel<K>, T extends BaseController> void show(
Class<T> clz, M viewModel, Window owner) {
String key = getKey(clz, viewModel);
if (toFront(key)) {
return;
@@ -76,7 +79,6 @@ public class BaseController {
throw new RuntimeException("@FxmlPath is required");
}
FxmlUtils.newLoaderAsyncWithRunLater(annotation.value(), null, loader -> {
T controller = loader.getController();
if (controller instanceof AbstEntityController<?, ?>) {
@@ -114,7 +116,6 @@ public class BaseController {
});
}
public static boolean toFront(String key) {
Stage stage = stages.get(key);
if (stage != null) {
@@ -161,6 +162,10 @@ public class BaseController {
return future;
}
public CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFuture.runAsync(runnable, Desktop.instance.getExecutorService()).exceptionally(this::handleException);
}
/**
* 窗口标题
*/

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

@@ -162,7 +162,7 @@ public class TaskMonitorCenter {
tooltip.setText("当前运行任务数: " + activeTasks.size());
});
monitorLabel.setOnMouseClicked(event -> {
BaseController.show(TaskMonitorViewController.class, monitorLabel.getScene().getWindow());
BaseController.show(TaskMonitorViewController.class, monitorLabel.getScene().getWindow());
});
}
}

View File

@@ -1,5 +1,9 @@
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 org.springframework.context.annotation.Lazy;
@@ -13,6 +17,7 @@ import com.ecep.contract.manager.ui.Message;
import com.ecep.contract.manager.util.MyDateTimeUtils;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
@@ -30,6 +35,7 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.text.Text;
import javafx.stage.WindowEvent;
@@ -69,10 +75,47 @@ public class TaskMonitorViewController extends BaseController {
private Button cancelTaskButton;
@FXML
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() {
}
/**
* 用于存储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
public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent);
@@ -144,6 +187,94 @@ public class TaskMonitorViewController extends BaseController {
});
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信息时发生错误"));
}
}
/**
@@ -205,7 +336,7 @@ public class TaskMonitorViewController extends BaseController {
text.setFill(Color.ORANGE);
} else if (msg.getLevel() == Level.SEVERE) {
text.setFill(Color.RED);
}else if (msg.getLevel()== Level.CONFIG) {
} else if (msg.getLevel() == Level.CONFIG) {
text.setFill(Color.GRAY);
}
vBox.getChildren().add(text);
@@ -218,4 +349,11 @@ public class TaskMonitorViewController extends BaseController {
alert.getDialogPane().setContent(scrollPane);
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;
public class MyDateTimePropertyUtils {
/**
* 本地日期时间转换为时间戳
*
* @param property
* @return
*/
public static Instant localDateTimeToInstant(SimpleObjectProperty<LocalDateTime> property) {
LocalDateTime dateTime = property.get();
if (dateTime != null) {

View File

@@ -1,14 +1,16 @@
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.net.URL;
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 static FXMLLoader newLoader(String path) {
@@ -22,8 +24,8 @@ public class FxmlUtils {
return loader;
}
public static CompletableFuture<FXMLLoader> newLoaderAsync(String path, java.util.function.Consumer<FXMLLoader> consumer) {
public static CompletableFuture<FXMLLoader> newLoaderAsync(String path,
java.util.function.Consumer<FXMLLoader> consumer) {
return CompletableFuture.supplyAsync(() -> {
FXMLLoader loader = newLoader(path);
try {
@@ -43,16 +45,15 @@ public class FxmlUtils {
/**
* 异步载入显示界面
*
* @param path fxml文件路径类地址 / 开头 根路径
* @param path fxml文件路径类地址 / 开头 根路径
* @param initializeLoader fxml 文件加载完毕后,回调函数
* @param runLater 在JavaFx线程中执行的回调函数
* @param runLater 在JavaFx线程中执行的回调函数
* @return CompletableFuture
*/
public static CompletableFuture<Void> newLoaderAsyncWithRunLater(
String path,
java.util.function.Consumer<FXMLLoader> initializeLoader,
java.util.function.Consumer<FXMLLoader> runLater
) {
java.util.function.Consumer<FXMLLoader> runLater) {
CompletableFuture<Void> future = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try {
@@ -72,7 +73,7 @@ public class FxmlUtils {
} catch (IOException e) {
future.completeExceptionally(new RuntimeException("Unable open " + path, e));
}
}).whenComplete((v, ex) -> {
}, Desktop.instance.getExecutorService()).whenComplete((v, ex) -> {
if (ex != null) {
future.completeExceptionally(ex);
}

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.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">
<children>
<MenuBar VBox.vgrow="NEVER">
@@ -18,7 +18,7 @@
<MenuItem mnemonicParsing="false" text="Save As…"/>
<MenuItem mnemonicParsing="false" text="Revert"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem mnemonicParsing="false" text="Preferences…"/>
<MenuItem mnemonicParsing="false" text="配置…" onAction="#onConfigAction"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem mnemonicParsing="false" text="Quit"/>
</items>

View File

@@ -1,212 +1,192 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import org.controlsfx.control.TaskProgressView?>
<VBox fx:id="root" prefHeight="468.0" prefWidth="737.0" xmlns="http://javafx.com/javafx/22"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.ecep.contract.manager.ds.other.controller.HomeWindowController">
<children>
<MenuBar>
<menus>
<Menu text="文件(_F)">
<items>
<MenuItem mnemonicParsing="false" text="Action 1"/>
<MenuItem mnemonicParsing="false" onAction="#openConfigWindow" text="选项…"/>
<Menu text="数据源">
<MenuItem mnemonicParsing="false" onAction="#openGroupRKResourceWindow" text="集团相关方…"/>
<MenuItem mnemonicParsing="false" onAction="#openTycResourceWindow" text="天眼查…"/>
<MenuItem mnemonicParsing="false" onAction="#openYongYouResourceWindow" text="用友U8…"/>
</Menu>
<children>
<MenuBar>
<menus>
<Menu text="文件(_F)">
<items>
<MenuItem mnemonicParsing="false" text="Action 1"/>
<MenuItem mnemonicParsing="false" onAction="#openConfigWindow" text="选项…"/>
<Menu text="数据源">
<MenuItem mnemonicParsing="false" onAction="#openGroupRKResourceWindow" text="集团相关方…"/>
<MenuItem mnemonicParsing="false" onAction="#openTycResourceWindow" text="天眼查…"/>
</Menu>
</items>
</Menu>
<Menu mnemonicParsing="false" text="公司">
<items>
</items>
</Menu>
<Menu mnemonicParsing="false" text="公司">
<items>
</items>
</Menu>
<Menu mnemonicParsing="false" text="用友U8">
<items>
<MenuItem mnemonicParsing="false" onAction="#createNewU8ContractSyncTaskAction"
text="同步合同"/>
</items>
</Menu>
<Menu text="设置(_S)">
<items>
<MenuItem onAction="#onShowEmployeeManagerWindowAction" text="员工管理(_E)"/>
<MenuItem onAction="#onShowDepartmentManagerWindowAction" text="部门管理(_D)"/>
<MenuItem onAction="#onShowRolesManagerWindowAction" text="角色管理(_R)"/>
<MenuItem onAction="#onShowFunctionManagerWindowAction" text="功能管理(_R)"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem onAction="#onShowBankManagerWindowAction" text="银行管理(_B)"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem onAction="#onShowTaskMonitorWindowAction" text="任务监控(_M)"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem onAction="#onShowInventoryManagerWindowAction" text="存货管理(_I)"/>
</items>
</Menu>
<Menu text="帮助(_H)">
<items>
<MenuItem mnemonicParsing="false" onAction="#openInBrowse" text="国家企业信用信息公示系统"
userData="https://www.gsxt.gov.cn/"/>
<MenuItem mnemonicParsing="false" onAction="#openInBrowse" text="天眼查-商业查询平台"
userData="https://www.tianyancha.com/"/>
<MenuItem mnemonicParsing="false" text="关于"/>
</items>
</Menu>
</menus>
</MenuBar>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="openCompanyManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;"
userData="com.ecep.contract.manager.ds.company.controller.CompanyManagerWindowController">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<viewport>
<Rectangle2D height="46.0" width="64.0"/>
</viewport>
<image>
<Image url="@img/f4.png"/>
</image>
</ImageView>
<Label text="公司">
<VBox.margin>
<Insets top="5.0"/>
</VBox.margin>
</Label>
</children>
</VBox>
</graphic>
</Button>
<Button fx:id="openProjectManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f0.png"/>
<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>
<Button fx:id="openContractManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f1.png"/>
<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>
<Button fx:id="openVendorManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f2.png"/>
<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>
<!-- 客户 -->
<Button fx:id="openCustomManagerWindow" layoutX="138.0" layoutY="10.0" mnemonicParsing="false"
style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f3.png"/>
<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>
<!-- 任务监控演示 -->
<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>
<opaqueInsets>
<Insets/>
</opaqueInsets>
<padding>
<Insets bottom="6.0" left="6.0" right="6.0" top="6.0"/>
</padding>
</ToolBar>
<AnchorPane prefHeight="248.0" prefWidth="2239.0" VBox.vgrow="ALWAYS"/>
<TaskProgressView fx:id="taskProgressView"/>
<HBox fx:id="statusBar" spacing="5.0">
<children>
<Label fx:id="leftStatusLabel" text="Label" wrapText="true"/>
<Pane prefHeight="12.0" prefWidth="12.0" HBox.hgrow="ALWAYS"/>
<Label fx:id="rightStatusLabel" layoutX="10.0" layoutY="10.0" text="-" wrapText="true"
HBox.hgrow="SOMETIMES">
<HBox.margin>
<Insets left="6.0"/>
</HBox.margin>
</Menu>
<Menu mnemonicParsing="false" text="用友U8">
<items>
<MenuItem mnemonicParsing="false" onAction="#createNewU8ContractSyncTaskAction"
text="同步合同"/>
<MenuItem mnemonicParsing="false" onAction="#openYongYouResourceWindow" text="用友U8…"/>
</items>
</Menu>
<Menu text="设置(_S)">
<items>
<MenuItem onAction="#onShowEmployeeManagerWindowAction" text="员工管理(_E)"/>
<MenuItem onAction="#onShowDepartmentManagerWindowAction" text="部门管理(_D)"/>
<MenuItem onAction="#onShowRolesManagerWindowAction" text="角色管理(_R)"/>
<MenuItem onAction="#onShowFunctionManagerWindowAction" text="功能管理(_R)"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem onAction="#onShowBankManagerWindowAction" text="银行管理(_B)"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem onAction="#onShowTaskMonitorWindowAction" text="任务监控(_M)"/>
<SeparatorMenuItem mnemonicParsing="false"/>
<MenuItem onAction="#onShowInventoryManagerWindowAction" text="存货管理(_I)"/>
</items>
</Menu>
<Menu text="帮助(_H)">
<items>
<MenuItem mnemonicParsing="false" onAction="#openInBrowse" text="国家企业信用信息公示系统"
userData="https://www.gsxt.gov.cn/"/>
<MenuItem mnemonicParsing="false" onAction="#openInBrowse" text="天眼查-商业查询平台"
userData="https://www.tianyancha.com/"/>
<MenuItem mnemonicParsing="false" text="关于"/>
</items>
</Menu>
</menus>
</MenuBar>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="openCompanyManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;"
userData="com.ecep.contract.manager.ds.company.controller.CompanyManagerWindowController">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<viewport>
<Rectangle2D height="46.0" width="64.0"/>
</viewport>
<image>
<Image url="@img/f4.png"/>
</image>
</ImageView>
<Label text="公司">
<VBox.margin>
<Insets top="5.0"/>
</VBox.margin>
</Label>
<Label fx:id="taskMonitorLabel" text="任务监控"></Label>
<Label fx:id="employeeStatusLabel" layoutX="711.0" layoutY="10.0" text="管理员" wrapText="true"
HBox.hgrow="SOMETIMES">
<HBox.margin>
<Insets left="6.0"/>
</HBox.margin>
</children>
</VBox>
</graphic>
</Button>
<Button fx:id="openProjectManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f0.png"/>
<viewport>
<Rectangle2D height="46.0" width="64.0"/>
</viewport>
</ImageView>
<Label text="项目">
<VBox.margin>
<Insets top="5.0"/>
</VBox.margin>
</Label>
</children>
</HBox>
</children>
</children>
</VBox>
</graphic>
</Button>
<Button fx:id="openContractManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f1.png"/>
<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>
<Button fx:id="openVendorManagerWindow" mnemonicParsing="false" style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f2.png"/>
<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>
<!-- 客户 -->
<Button fx:id="openCustomManagerWindow" layoutX="138.0" layoutY="10.0" mnemonicParsing="false"
style="-fx-padding: 6px;">
<graphic>
<VBox alignment="CENTER">
<children>
<ImageView fitHeight="46.0" fitWidth="64.0">
<Image url="@img/f3.png"/>
<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>
<opaqueInsets>
<Insets/>
</opaqueInsets>
<padding>
<Insets bottom="6.0" left="6.0" right="6.0" top="6.0"/>
</padding>
</ToolBar>
<AnchorPane prefHeight="248.0" prefWidth="2239.0" VBox.vgrow="ALWAYS"/>
<TaskProgressView fx:id="taskProgressView"/>
<HBox fx:id="statusBar" spacing="5.0">
<children>
<Label fx:id="leftStatusLabel" text="Label" wrapText="true"/>
<Pane prefHeight="12.0" prefWidth="12.0" HBox.hgrow="ALWAYS"/>
<Label fx:id="rightStatusLabel" layoutX="10.0" layoutY="10.0" text="-" wrapText="true"
HBox.hgrow="SOMETIMES">
<HBox.margin>
<Insets left="6.0"/>
</HBox.margin>
</Label>
<Label fx:id="taskMonitorLabel" text="任务监控"/>
<Label fx:id="employeeStatusLabel" layoutX="711.0" layoutY="10.0" text="管理员" wrapText="true"
HBox.hgrow="SOMETIMES">
<HBox.margin>
<Insets left="6.0"/>
</HBox.margin>
</Label>
</children>
</HBox>
</children>
</VBox>

View File

@@ -8,56 +8,83 @@
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.VBox?>
<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">
<tabs>
<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">
<ToolBar>
<items>
<Button fx:id="runTaskMonitorDemoBtn" text="运行演示任务" onAction="#onRunTaskMonitorDemo"/>
</items>
</ToolBar>
<TabPane tabMinWidth="70.0" VBox.vgrow="ALWAYS">
<tabs>
<Tab closable="false" text="活动任务">
<content>
<VBox>
<children>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="cancelTaskButton" text="取消选中任务" />
</items>
</ToolBar>
<TableView fx:id="activeTasksTable">
<columns>
<TableColumn fx:id="activeTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="activeTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="activeTaskProgressColumn" prefWidth="150.0" text="进度" />
<TableColumn fx:id="activeTaskStatusColumn" prefWidth="100.0" text="状态" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</children>
</VBox>
<VBox>
<children>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="cancelTaskButton" text="取消选中任务"/>
</items>
</ToolBar>
<TableView fx:id="activeTasksTable">
<columns>
<TableColumn fx:id="activeTaskIdColumn" prefWidth="150.0" text="任务ID"/>
<TableColumn fx:id="activeTaskTitleColumn" prefWidth="200.0" text="任务标题"/>
<TableColumn fx:id="activeTaskProgressColumn" prefWidth="150.0" text="进度"/>
<TableColumn fx:id="activeTaskStatusColumn" prefWidth="100.0" text="状态"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</children>
</VBox>
</content>
</Tab>
<Tab closable="false" text="任务历史">
<content>
<content>
<!-- 历史任务区域 -->
<VBox spacing="5.0">
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="clearHistoryButton" alignment="CENTER_RIGHT" text="清空历史" />
</items>
</ToolBar>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="clearHistoryButton" alignment="CENTER_RIGHT" text="清空历史"/>
</items>
</ToolBar>
<TableView fx:id="historyTasksTable" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="historyTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="historyTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="historyTaskStatusColumn" prefWidth="100.0" text="状态" />
<TableColumn fx:id="historyTaskStartTimeColumn" prefWidth="150.0" text="开始时间" />
<TableColumn fx:id="historyTaskExecutionTimeColumn" prefWidth="100.0" text="执行耗时" />
<TableColumn fx:id="historyTaskIdColumn" prefWidth="150.0" text="任务ID"/>
<TableColumn fx:id="historyTaskTitleColumn" prefWidth="200.0" text="任务标题"/>
<TableColumn fx:id="historyTaskStatusColumn" prefWidth="100.0" text="状态"/>
<TableColumn fx:id="historyTaskStartTimeColumn" prefWidth="150.0" text="开始时间"/>
<TableColumn fx:id="historyTaskExecutionTimeColumn" prefWidth="100.0" text="执行耗时"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</VBox>
</content>
</content>
</Tab>
</tabs>
</TabPane>
<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>
</TabPane>
</VBox>