Compare commits

..

2 Commits

Author SHA1 Message Date
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
25 changed files with 834 additions and 532 deletions

1
null Normal file
View File

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

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,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,117 @@
package com.ecep.contract.manager.cloud.u8;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CompletableFuture;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
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 com.ecep.contract.manager.ui.BaseController;
import com.ecep.contract.manager.ui.FxmlPath;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import javafx.stage.WindowEvent;
import javafx.util.converter.LocalDateStringConverter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@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("cloud.u8.auto-create-company-after");
config1.setPicker(auto_create_company_after);
config1.initialize();
LocalDateConfig config2 = new LocalDateConfig("cloud.u8.contract.latestDate");
config2.setPicker(contract_latest_date);
config2.initialize();
}
@NoArgsConstructor
public static class LocalDateConfig {
@Setter
private SysConfService confService;
Property<LocalDate> property;
@Setter
javafx.util.StringConverter<LocalDate> converter;
@Setter
DatePicker picker;
String key;
SysConf conf;
public LocalDateConfig(String string) {
key = string;
}
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();
}
public CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFuture.runAsync(runnable, Desktop.instance.getExecutorService()).exceptionally(ex -> {
ex.printStackTrace();
return null;
});
}
public SysConfService getConfService() {
if (confService == null) {
confService = SpringApp.getBean(SysConfService.class);
}
return confService;
}
}
}

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

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

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

@@ -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;
@@ -63,10 +66,10 @@ public class BaseController {
controller.show(loader, owner, Modality.NONE, key);
});
}
@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

@@ -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>
<DatePicker fx:id="auto_create_company_after" GridPane.columnIndex="2" />
<Label text="cloud.u8.auto-create-company-after" />
<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,192 +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>
</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>