From fc263288e4d0538440d219dc3c3be9c936f6f94e Mon Sep 17 00:00:00 2001 From: songqq Date: Fri, 12 Sep 2025 00:12:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=90=88=E7=BA=A6?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E7=B1=BB=E5=9E=8B=E6=9C=8D=E5=8A=A1=E5=8F=8A?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 重构合约文件类型相关代码,优化错误处理逻辑 fix: 修复WebSocket会话未绑定用户时的错误处理 style: 调整代码格式,提高可读性 docs: 更新部分代码注释 test: 添加合约文件类型服务的测试用例 chore: 移除无用代码,清理项目结构 --- .../com/ecep/contract/WebSocketService.java | 5 + .../ProjectSaleTypeRequireFilesTabSkin.java | 22 +++-- .../controller/tab/ContractTabSkinFiles.java | 3 +- .../tab/ContractTabSkinSubContract.java | 4 + .../group/VendorGroupRequireFilesTabSkin.java | 36 ++++--- .../contract/service/ContractFileService.java | 20 ++-- .../service/ContractFileTypeService.java | 30 ++++++ .../contract/task/ContractVerifyComm.java | 11 ++- .../vm/ContractFileTypeLocalViewModel.java | 51 ++++++++++ .../contract/service/ContractFileService.java | 35 ------- .../service/ContractFileTypeService.java | 93 +++++++++++++++++++ .../ds/contract/service/ContractService.java | 25 +---- .../contract/tasker/ContractVerifyComm.java | 75 +++++++++++---- .../repository/BaseEnumEntityRepository.java | 4 +- .../contract/handler/WebSocketHandler.java | 40 ++++++-- .../contract/util/SpecificationUtils.java | 27 ++++++ 16 files changed, 357 insertions(+), 124 deletions(-) create mode 100644 client/src/main/java/com/ecep/contract/service/ContractFileTypeService.java create mode 100644 client/src/main/java/com/ecep/contract/vm/ContractFileTypeLocalViewModel.java create mode 100644 server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileTypeService.java diff --git a/client/src/main/java/com/ecep/contract/WebSocketService.java b/client/src/main/java/com/ecep/contract/WebSocketService.java index 6db8bad..0788738 100644 --- a/client/src/main/java/com/ecep/contract/WebSocketService.java +++ b/client/src/main/java/com/ecep/contract/WebSocketService.java @@ -98,6 +98,11 @@ public class WebSocketService { } else { logger.error("未找到对应的回调future: {}", messageId); } + } else if (node.has("errorCode")) { + int errorCode = node.get("errorCode").asInt(); + String errorMsg = node.get("errorMsg").asText(); + // TODO 需要重新登录 + logger.error("收到错误消息: 错误码={}, 错误信息={}", errorCode, errorMsg); } } catch (Exception e) { logger.error("处理WebSocket消息失败: {}", e.getMessage(), e); diff --git a/client/src/main/java/com/ecep/contract/controller/project/sale_type/ProjectSaleTypeRequireFilesTabSkin.java b/client/src/main/java/com/ecep/contract/controller/project/sale_type/ProjectSaleTypeRequireFilesTabSkin.java index b8bbc33..07db750 100644 --- a/client/src/main/java/com/ecep/contract/controller/project/sale_type/ProjectSaleTypeRequireFilesTabSkin.java +++ b/client/src/main/java/com/ecep/contract/controller/project/sale_type/ProjectSaleTypeRequireFilesTabSkin.java @@ -11,6 +11,7 @@ import com.ecep.contract.controller.tab.TabSkin; import com.ecep.contract.model.ContractFileTypeLocal; import com.ecep.contract.model.ProjectSaleTypeRequireFileType; import com.ecep.contract.service.ContractFileService; +import com.ecep.contract.service.ContractFileTypeService; import com.ecep.contract.service.ProjectSaleTypeRequireFileTypeService; import impl.org.controlsfx.skin.ListSelectionViewSkin; @@ -35,7 +36,8 @@ public class ProjectSaleTypeRequireFilesTabSkin extends AbstProjectSaleTypeBased private final SimpleBooleanProperty changed = new SimpleBooleanProperty(false); private ListSelectionView fileTypesField; - private final ObservableMap fileTypeLocalMap = FXCollections.observableHashMap(); + private final ObservableMap fileTypeLocalMap = FXCollections + .observableHashMap(); @Setter private ProjectSaleTypeRequireFileTypeService requireFileTypeService; @@ -61,18 +63,21 @@ public class ProjectSaleTypeRequireFilesTabSkin extends AbstProjectSaleTypeBased public void initializeTab() { initializeListView(); loadSelectedRoles(); - fileTypeLocalMap.putAll(getContractFileService().findAllFileTypes(getLocale().toLanguageTag())); + fileTypeLocalMap.putAll(getCachedBean(ContractFileTypeService.class).findAll(getLocale())); } private void loadSelectedRoles() { - List list = getRequireFileTypeService().findBySaleTypeId(viewModel.getId().get()); + List list = getRequireFileTypeService() + .findBySaleTypeId(viewModel.getId().get()); List types = list.stream().map(ProjectSaleTypeRequireFileType::getFileType).toList(); fileTypesField.getTargetItems().setAll(types); changed.set(false); } + private void initializeListView() { - List types = Arrays.stream(ContractFileType.values()).filter(ContractFileType::isSupportCustomer).toList(); + List types = Arrays.stream(ContractFileType.values()) + .filter(ContractFileType::isSupportCustomer).toList(); fileTypesField.getSourceItems().setAll(types); fileTypesField.setCellFactory(param -> new ListCell<>() { @Override @@ -111,7 +116,8 @@ public class ProjectSaleTypeRequireFilesTabSkin extends AbstProjectSaleTypeBased ListView targetListView = viewSkin.getTargetListView(); targetListView.setOnMouseClicked(event -> { if (event.getClickCount() == 2) { - ContractFileType selectedItem = (ContractFileType) targetListView.getSelectionModel().getSelectedItem(); + ContractFileType selectedItem = (ContractFileType) targetListView.getSelectionModel() + .getSelectedItem(); if (selectedItem != null) { // saveRoles(selectedItem); setStatus("selected " + selectedItem); @@ -128,11 +134,13 @@ public class ProjectSaleTypeRequireFilesTabSkin extends AbstProjectSaleTypeBased } private void saveRequireFileTypes(ActionEvent event) { - List list = getRequireFileTypeService().findBySaleTypeId(viewModel.getId().get()); + List list = getRequireFileTypeService() + .findBySaleTypeId(viewModel.getId().get()); ObservableList types = fileTypesField.getTargetItems(); // 保存 types ,list 中是已经存储的,如果types 中没有则删除,如果 types 中有则新增保存 for (ContractFileType type : types) { - ProjectSaleTypeRequireFileType entity = list.stream().filter(v -> v.getFileType() == type).findFirst().orElse(null); + ProjectSaleTypeRequireFileType entity = list.stream().filter(v -> v.getFileType() == type).findFirst() + .orElse(null); if (entity == null) { entity = new ProjectSaleTypeRequireFileType(); entity.setSaleType(getEntity()); diff --git a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinFiles.java b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinFiles.java index b078254..dc9689e 100644 --- a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinFiles.java +++ b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinFiles.java @@ -40,6 +40,7 @@ import com.ecep.contract.model.ContractFile; import com.ecep.contract.model.ContractFileTypeLocal; import com.ecep.contract.model.ContractType; import com.ecep.contract.service.ContractFileService; +import com.ecep.contract.service.ContractFileTypeService; import com.ecep.contract.util.FxmlPath; import com.ecep.contract.util.UITools; import com.ecep.contract.vm.ContractFileViewModel; @@ -248,7 +249,7 @@ public class ContractTabSkinFiles createVendorContractRequestByTemplateUpdateMenuItem(), createVendorContractApplyByTemplateUpdateMenuItem()); - fileTypeLocalMap.putAll(getContractFileService().findAllFileTypes(getLocale().toLanguageTag())); + fileTypeLocalMap.putAll(getCachedBean(ContractFileTypeService.class).findAll(getLocale())); super.initializeTab(); } diff --git a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinSubContract.java b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinSubContract.java index 0688a2b..a742975 100644 --- a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinSubContract.java +++ b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinSubContract.java @@ -1,6 +1,7 @@ package com.ecep.contract.controller.tab; import java.time.LocalDate; +import java.util.HashMap; import java.util.Map; import com.ecep.contract.ContractPayWay; @@ -62,6 +63,9 @@ public class ContractTabSkinSubContract @Override public Map getSpecification(Contract parent) { Map params = getSpecification(); + if (params == null) { + params = new HashMap<>(); + } params.put("parentCode", parent.getCode()); return params; } diff --git a/client/src/main/java/com/ecep/contract/controller/vendor/group/VendorGroupRequireFilesTabSkin.java b/client/src/main/java/com/ecep/contract/controller/vendor/group/VendorGroupRequireFilesTabSkin.java index 3497d8e..b6e4722 100644 --- a/client/src/main/java/com/ecep/contract/controller/vendor/group/VendorGroupRequireFilesTabSkin.java +++ b/client/src/main/java/com/ecep/contract/controller/vendor/group/VendorGroupRequireFilesTabSkin.java @@ -11,6 +11,7 @@ import com.ecep.contract.controller.tab.TabSkin; import com.ecep.contract.model.ContractFileTypeLocal; import com.ecep.contract.model.VendorGroupRequireFileType; import com.ecep.contract.service.ContractFileService; +import com.ecep.contract.service.ContractFileTypeService; import com.ecep.contract.service.VendorGroupRequireFileTypeService; import impl.org.controlsfx.skin.ListSelectionViewSkin; @@ -26,18 +27,13 @@ import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.scene.control.Skin; import javafx.scene.control.Tab; -import lombok.Setter; public class VendorGroupRequireFilesTabSkin extends AbstVendorGroupBasedTabSkin implements TabSkin { private final SimpleBooleanProperty changed = new SimpleBooleanProperty(false); private ListSelectionView fileTypesField; - private final ObservableMap fileTypeLocalMap = FXCollections.observableHashMap(); - - @Setter - private VendorGroupRequireFileTypeService requireFileTypeService; - @Setter - private ContractFileService contractFileService; + private final ObservableMap fileTypeLocalMap = FXCollections + .observableHashMap(); public VendorGroupRequireFilesTabSkin(VendorGroupWindowController controller) { super(controller); @@ -58,7 +54,7 @@ public class VendorGroupRequireFilesTabSkin extends AbstVendorGroupBasedTabSkin public void initializeTab() { initializeListView(); loadSelectedRoles(); - fileTypeLocalMap.putAll(getContractFileService().findAllFileTypes(getLocale().toLanguageTag())); + fileTypeLocalMap.putAll(getContractFileTypeService().findAll(getLocale())); } private void loadSelectedRoles() { @@ -68,10 +64,10 @@ public class VendorGroupRequireFilesTabSkin extends AbstVendorGroupBasedTabSkin changed.set(false); } - private void initializeListView() { - List types = Arrays.stream(ContractFileType.values()).filter(ContractFileType::isSupportVendor).toList(); + List types = Arrays.stream(ContractFileType.values()) + .filter(ContractFileType::isSupportVendor).toList(); fileTypesField.getSourceItems().setAll(types); fileTypesField.setCellFactory(param -> new ListCell<>() { @Override @@ -110,7 +106,8 @@ public class VendorGroupRequireFilesTabSkin extends AbstVendorGroupBasedTabSkin ListView targetListView = viewSkin.getTargetListView(); targetListView.setOnMouseClicked(event -> { if (event.getClickCount() == 2) { - ContractFileType selectedItem = (ContractFileType) targetListView.getSelectionModel().getSelectedItem(); + ContractFileType selectedItem = (ContractFileType) targetListView.getSelectionModel() + .getSelectedItem(); if (selectedItem != null) { // saveRoles(selectedItem); setStatus("selected " + selectedItem); @@ -131,7 +128,8 @@ public class VendorGroupRequireFilesTabSkin extends AbstVendorGroupBasedTabSkin ObservableList types = fileTypesField.getTargetItems(); // 保存 types ,list 中是已经存储的,如果types 中没有则删除,如果 types 中有则新增保存 for (ContractFileType type : types) { - VendorGroupRequireFileType entity = list.stream().filter(v -> v.getFileType() == type).findFirst().orElse(null); + VendorGroupRequireFileType entity = list.stream().filter(v -> v.getFileType() == type).findFirst() + .orElse(null); if (entity == null) { entity = new VendorGroupRequireFileType(); entity.setGroup(getEntity()); @@ -147,16 +145,14 @@ public class VendorGroupRequireFilesTabSkin extends AbstVendorGroupBasedTabSkin } public VendorGroupRequireFileTypeService getRequireFileTypeService() { - if (requireFileTypeService == null) { - requireFileTypeService = getBean(VendorGroupRequireFileTypeService.class); - } - return requireFileTypeService; + return getCachedBean(VendorGroupRequireFileTypeService.class); } public ContractFileService getContractFileService() { - if (contractFileService == null) { - contractFileService = SpringApp.getBean(ContractFileService.class); - } - return contractFileService; + return getCachedBean(ContractFileService.class); + } + + public ContractFileTypeService getContractFileTypeService() { + return getCachedBean(ContractFileTypeService.class); } } diff --git a/client/src/main/java/com/ecep/contract/service/ContractFileService.java b/client/src/main/java/com/ecep/contract/service/ContractFileService.java index 32d1adc..c5a1470 100644 --- a/client/src/main/java/com/ecep/contract/service/ContractFileService.java +++ b/client/src/main/java/com/ecep/contract/service/ContractFileService.java @@ -1,32 +1,30 @@ package com.ecep.contract.service; +import java.util.HashMap; import java.util.List; import java.util.Map; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import com.ecep.contract.ContractFileType; import com.ecep.contract.model.Contract; import com.ecep.contract.model.ContractFile; -import com.ecep.contract.model.ContractFileTypeLocal; import com.ecep.contract.vm.ContractFileViewModel; @Service public class ContractFileService extends QueryService { - public List findAllByContract(Contract contract) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'findAllByContract'"); - } - - public Map findAllFileTypes(String languageTag) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'findAllFileTypes'"); + Map params = new HashMap<>(); + params.put("contract", contract.getId()); + return findAll(params, Pageable.unpaged()).getContent(); } public List findAllByContractAndFileType(Contract contract, ContractFileType type) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'findAllByContractAndFileType'"); + Map params = new HashMap<>(); + params.put("contract", contract.getId()); + params.put("type", type.name()); + return findAll(params, Pageable.unpaged()).getContent(); } } diff --git a/client/src/main/java/com/ecep/contract/service/ContractFileTypeService.java b/client/src/main/java/com/ecep/contract/service/ContractFileTypeService.java new file mode 100644 index 0000000..d580cc5 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/service/ContractFileTypeService.java @@ -0,0 +1,30 @@ +package com.ecep.contract.service; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import com.ecep.contract.ContractFileType; +import com.ecep.contract.model.ContractFileTypeLocal; +import com.ecep.contract.vm.ContractFileTypeLocalViewModel; + +@Service +@CacheConfig(cacheNames = "contract-file-type") +public class ContractFileTypeService extends QueryService { + + @Cacheable + public Map findAll(Locale locale) { + Map params = new HashMap<>(); + params.put("lang", locale.toLanguageTag()); + return findAll(params, Pageable.unpaged()).stream() + .collect(Collectors.toMap(ContractFileTypeLocal::getType, Function.identity())); + } + +} diff --git a/client/src/main/java/com/ecep/contract/task/ContractVerifyComm.java b/client/src/main/java/com/ecep/contract/task/ContractVerifyComm.java index 5d8363e..833d2ce 100644 --- a/client/src/main/java/com/ecep/contract/task/ContractVerifyComm.java +++ b/client/src/main/java/com/ecep/contract/task/ContractVerifyComm.java @@ -47,6 +47,7 @@ import com.ecep.contract.service.CompanyService; import com.ecep.contract.service.CompanyVendorService; import com.ecep.contract.service.ContractBidVendorService; import com.ecep.contract.service.ContractFileService; +import com.ecep.contract.service.ContractFileTypeService; import com.ecep.contract.service.ContractService; import com.ecep.contract.service.EmployeeService; import com.ecep.contract.service.ExtendVendorInfoService; @@ -77,6 +78,7 @@ public class ContractVerifyComm { // Contract private ContractService contractService; private ContractFileService contractFileService; + private ContractFileTypeService contractFileTypeService; private ContractBidVendorService contractBidVendorService; // Company @@ -150,6 +152,13 @@ public class ContractVerifyComm { return contractFileService; } + private ContractFileTypeService getContractFileTypeService() { + if (contractFileTypeService == null) { + contractFileTypeService = SpringApp.getBean(ContractFileTypeService.class); + } + return contractFileTypeService; + } + private ContractBidVendorService getContractBidVendorService() { if (contractBidVendorService == null) { contractBidVendorService = SpringApp.getBean(ContractBidVendorService.class); @@ -488,7 +497,7 @@ public class ContractVerifyComm { ContractFileTypeLocal getFileTypeLocal(ContractFileType type) { if (fileTypeLocalMap == null) { fileTypeLocalMap = FXCollections - .observableMap(getContractFileService().findAllFileTypes(getLocale().toLanguageTag())); + .observableMap(getContractFileTypeService().findAll(getLocale())); } return fileTypeLocalMap.get(type); } diff --git a/client/src/main/java/com/ecep/contract/vm/ContractFileTypeLocalViewModel.java b/client/src/main/java/com/ecep/contract/vm/ContractFileTypeLocalViewModel.java new file mode 100644 index 0000000..a107fd1 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/vm/ContractFileTypeLocalViewModel.java @@ -0,0 +1,51 @@ +package com.ecep.contract.vm; + +import java.util.Objects; + +import com.ecep.contract.ContractFileType; +import com.ecep.contract.model.ContractFileTypeLocal; + +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ContractFileTypeLocalViewModel extends IdentityViewModel { + private SimpleObjectProperty type = new SimpleObjectProperty<>(); + private SimpleStringProperty suggestFileName = new SimpleStringProperty(); + private SimpleStringProperty lang = new SimpleStringProperty(); + private SimpleStringProperty value = new SimpleStringProperty(); + + @Override + protected void updateFrom(ContractFileTypeLocal v) { + super.updateFrom(v); + type.set(v.getType()); + suggestFileName.set(v.getSuggestFileName()); + lang.set(v.getLang()); + value.set(v.getValue()); + } + + @Override + public boolean copyTo(ContractFileTypeLocal v) { + boolean ret = super.copyTo(v); + if (!Objects.equals(type.get(), v.getType())) { + v.setType(type.get()); + ret = true; + } + if (!Objects.equals(suggestFileName.get(), v.getSuggestFileName())) { + v.setSuggestFileName(suggestFileName.get()); + ret = true; + } + if (!Objects.equals(lang.get(), v.getLang())) { + v.setLang(lang.get()); + ret = true; + } + if (!Objects.equals(value.get(), v.getValue())) { + v.setValue(value.get()); + ret = true; + } + return ret; + } +} diff --git a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileService.java b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileService.java index cd5739b..7c9f946 100644 --- a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileService.java +++ b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileService.java @@ -1,7 +1,6 @@ package com.ecep.contract.ds.contract.service; import java.util.List; -import java.util.Map; import java.util.function.Consumer; import org.slf4j.Logger; @@ -23,10 +22,8 @@ import com.ecep.contract.ContractFileType; import com.ecep.contract.IEntityService; import com.ecep.contract.QueryService; import com.ecep.contract.ds.contract.repository.ContractFileRepository; -import com.ecep.contract.ds.contract.repository.ContractFileTypeLocalRepository; import com.ecep.contract.model.Contract; import com.ecep.contract.model.ContractFile; -import com.ecep.contract.model.ContractFileTypeLocal; import com.ecep.contract.util.SpecificationUtils; import com.fasterxml.jackson.databind.JsonNode; @@ -38,9 +35,6 @@ public class ContractFileService implements IEntityService, QueryS @Lazy @Autowired private ContractFileRepository contractFileRepository; - @Lazy - @Autowired - private ContractFileTypeLocalRepository contractFileTypeLocalRepository; @Override @Cacheable(key = "#p0") @@ -172,33 +166,4 @@ public class ContractFileService implements IEntityService, QueryS }; return contractFileRepository.findAll(spec); } - - // @Cacheable(key = "'type-locals-'+#p0") - // public List findAllFileTypes(String lang) { - // Map map = - // contractFileTypeLocalRepository.getCompleteMapByLocal(lang); - // List list = new ArrayList<>(map.values()); - // list.sort((o1, o2) -> Objects.compare(o1.getValue(), o2.getValue(), - // String::compareTo)); - // return list; - // } - - @Cacheable(key = "'type-locals-'+#p0") - public Map findAllFileTypes(String lang) { - return contractFileTypeLocalRepository.getCompleteMapByLocal(lang); - } - - @Caching(evict = { - @CacheEvict(key = "'type-locals-'+#p0.lang"), - @CacheEvict(key = "'type-'+#p0.type+'-local-'+#p0.lang"), - }) - public ContractFileTypeLocal save(ContractFileTypeLocal type) { - return contractFileTypeLocalRepository.save(type); - } - - @Cacheable(key = "'type-'+#p0+'-local-'+#p1") - public ContractFileTypeLocal findFileTypeLocalByTypeAndLang(ContractFileType type, String lang) { - return contractFileTypeLocalRepository.getCompleteByTypeAndLang(type, lang); - } - } diff --git a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileTypeService.java b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileTypeService.java new file mode 100644 index 0000000..6897e3f --- /dev/null +++ b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractFileTypeService.java @@ -0,0 +1,93 @@ +package com.ecep.contract.ds.contract.service; + +import java.util.Locale; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import com.ecep.contract.ContractFileType; +import com.ecep.contract.IEntityService; +import com.ecep.contract.QueryService; +import com.ecep.contract.ds.contract.repository.ContractFileTypeLocalRepository; +import com.ecep.contract.model.ContractFileTypeLocal; +import com.ecep.contract.util.SpecificationUtils; +import com.fasterxml.jackson.databind.JsonNode; + +@Lazy +@Service +@CacheConfig(cacheNames = "contract-file-type") +public class ContractFileTypeService + implements IEntityService, QueryService { + @Lazy + @Autowired + private ContractFileTypeLocalRepository repository; + + @Override + public Page findAll(JsonNode paramsNode, Pageable pageable) { + Specification spec = null; + if (paramsNode.has("searchText")) { + spec = getSpecification(paramsNode.get("searchText").asText()); + } + + // field + spec = SpecificationUtils.andFieldEqualParam(spec, paramsNode, "lang", "value", "suggestFileName"); + return findAll(spec, pageable); + } + + @Cacheable(key = "'all-'+#p0.getLanguage()") + public Map findAll(Locale locale) { + return repository.getCompleteMapByLocal(locale.getLanguage()); + } + + @Cacheable(key = "#p0") + @Override + public ContractFileTypeLocal findById(Integer id) { + return repository.findById(id).orElse(null); + } + + @Override + public Page findAll(Specification spec, Pageable pageable) { + return repository.findAll(spec, pageable); + } + + @Override + public Specification getSpecification(String searchText) { + if (!StringUtils.hasText(searchText)) { + return null; + } + return (root, query, builder) -> { + return builder.or( + builder.like(root.get("type"), "%" + searchText + "%"), + builder.like(root.get("suggestFileName"), "%" + searchText + "%")); + }; + } + + @Caching(evict = { + @CacheEvict(key = "#p0.id"), + @CacheEvict(key = "'all-'+#p0.getLang()") + }) + @Override + public void delete(ContractFileTypeLocal entity) { + repository.delete(entity); + } + + @Caching(evict = { + @CacheEvict(key = "#p0.id"), + @CacheEvict(key = "'all-'+#p0.getLang()") + }) + @Override + public ContractFileTypeLocal save(ContractFileTypeLocal entity) { + return repository.save(entity); + } + +} diff --git a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java index 6bcb781..adde4e3 100644 --- a/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java +++ b/server/src/main/java/com/ecep/contract/ds/contract/service/ContractService.java @@ -137,35 +137,14 @@ public class ContractService implements IEntityService, QueryService andParam(Specification spec, JsonNode paramsNode, String field) { - if (!paramsNode.has(field)) { - return spec; - } - JsonNode param = paramsNode.get(field); - Integer value = null; - if (param.isInt()) { - value = param.asInt(); - } else if (param.isObject()) { - value = param.get("id").asInt(); - } - if (value == null) { - return spec; - } - final int id = value; - spec = SpecificationUtils.and(spec, (root, query, builder) -> { - return builder.equal(root.get(field).get("id"), id); - }); - return spec; - } - public List findAllByCompany(Company company) { return contractRepository.findAllByCompanyId(company.getId()); } diff --git a/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java b/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java index 049c28b..a7fdcd7 100644 --- a/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java +++ b/server/src/main/java/com/ecep/contract/ds/contract/tasker/ContractVerifyComm.java @@ -1,12 +1,36 @@ package com.ecep.contract.ds.contract.tasker; -import com.ecep.contract.*; +import java.io.File; +import java.text.NumberFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.DoubleSummaryStatistics; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.hibernate.Hibernate; +import org.springframework.security.core.userdetails.User; +import org.springframework.util.StringUtils; + +import com.ecep.contract.CompanyCustomerFileType; +import com.ecep.contract.ContractFileType; +import com.ecep.contract.ContractPayWay; +import com.ecep.contract.MessageHolder; +import com.ecep.contract.MyDateTimeUtils; +import com.ecep.contract.SpringApp; import com.ecep.contract.ds.company.CompanyFileUtils; import com.ecep.contract.ds.company.service.CompanyExtendInfoService; import com.ecep.contract.ds.company.service.CompanyFileService; import com.ecep.contract.ds.company.service.CompanyService; import com.ecep.contract.ds.contract.service.ContractBidVendorService; import com.ecep.contract.ds.contract.service.ContractFileService; +import com.ecep.contract.ds.contract.service.ContractFileTypeService; import com.ecep.contract.ds.contract.service.ContractService; import com.ecep.contract.ds.contract.service.ExtendVendorInfoService; import com.ecep.contract.ds.converter.NumberStringConverter; @@ -14,27 +38,36 @@ import com.ecep.contract.ds.customer.service.CompanyCustomerFileService; import com.ecep.contract.ds.customer.service.CompanyCustomerService; import com.ecep.contract.ds.other.service.EmployeeService; import com.ecep.contract.ds.project.ProjectCostImportItemsFromContractsTasker; -import com.ecep.contract.ds.project.service.*; +import com.ecep.contract.ds.project.service.ProjectBidService; +import com.ecep.contract.ds.project.service.ProjectCostService; +import com.ecep.contract.ds.project.service.ProjectQuotationService; +import com.ecep.contract.ds.project.service.ProjectSaleTypeRequireFileTypeService; +import com.ecep.contract.ds.project.service.ProjectService; +import com.ecep.contract.ds.project.service.SaleTypeService; import com.ecep.contract.ds.vendor.service.CompanyVendorService; import com.ecep.contract.ds.vendor.service.VendorGroupRequireFileTypeService; import com.ecep.contract.ds.vendor.service.VendorGroupService; -import com.ecep.contract.model.*; +import com.ecep.contract.model.Company; +import com.ecep.contract.model.CompanyCustomer; +import com.ecep.contract.model.CompanyCustomerFile; +import com.ecep.contract.model.CompanyExtendInfo; +import com.ecep.contract.model.Contract; +import com.ecep.contract.model.ContractBidVendor; +import com.ecep.contract.model.ContractFile; +import com.ecep.contract.model.ContractFileTypeLocal; +import com.ecep.contract.model.Employee; +import com.ecep.contract.model.ExtendVendorInfo; +import com.ecep.contract.model.Project; +import com.ecep.contract.model.ProjectBid; +import com.ecep.contract.model.ProjectCost; +import com.ecep.contract.model.ProjectQuotation; +import com.ecep.contract.model.ProjectSaleType; +import com.ecep.contract.model.ProjectSaleTypeRequireFileType; +import com.ecep.contract.model.VendorGroup; +import com.ecep.contract.model.VendorGroupRequireFileType; import com.ecep.contract.util.SecurityUtils; import lombok.Data; -import org.hibernate.Hibernate; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.util.StringUtils; - -import java.io.File; -import java.text.NumberFormat; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.*; -import java.util.stream.Collectors; @Data public class ContractVerifyComm { @@ -48,6 +81,7 @@ public class ContractVerifyComm { // Contract private ContractService contractService; private ContractFileService contractFileService; + private ContractFileTypeService contractFileTypeService; private ContractBidVendorService contractBidVendorService; // Company @@ -121,6 +155,13 @@ public class ContractVerifyComm { return contractFileService; } + private ContractFileTypeService getContractFileTypeService() { + if (contractFileTypeService == null) { + contractFileTypeService = SpringApp.getBean(ContractFileTypeService.class); + } + return contractFileTypeService; + } + private ContractBidVendorService getContractBidVendorService() { if (contractBidVendorService == null) { contractBidVendorService = SpringApp.getBean(ContractBidVendorService.class); @@ -469,7 +510,7 @@ public class ContractVerifyComm { ContractFileTypeLocal getFileTypeLocal(ContractFileType type) { if (fileTypeLocalMap == null) { - fileTypeLocalMap = getContractFileService().findAllFileTypes(getLocale().toLanguageTag()); + fileTypeLocalMap = getContractFileTypeService().findAll(getLocale()); } return fileTypeLocalMap.get(type); } diff --git a/server/src/main/java/com/ecep/contract/ds/other/repository/BaseEnumEntityRepository.java b/server/src/main/java/com/ecep/contract/ds/other/repository/BaseEnumEntityRepository.java index f8b81b3..e587bd4 100644 --- a/server/src/main/java/com/ecep/contract/ds/other/repository/BaseEnumEntityRepository.java +++ b/server/src/main/java/com/ecep/contract/ds/other/repository/BaseEnumEntityRepository.java @@ -5,14 +5,14 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.NoRepositoryBean; +import com.ecep.contract.ds.MyRepository; import com.ecep.contract.model.BaseEnumEntity; @NoRepositoryBean public interface BaseEnumEntityRepository, T extends BaseEnumEntity, ID> - extends JpaRepository { + extends MyRepository { List findAllByLang(String lang); default Map getCompleteMapByLocal(String lang) { diff --git a/server/src/main/java/com/ecep/contract/handler/WebSocketHandler.java b/server/src/main/java/com/ecep/contract/handler/WebSocketHandler.java index f6b2272..649394c 100644 --- a/server/src/main/java/com/ecep/contract/handler/WebSocketHandler.java +++ b/server/src/main/java/com/ecep/contract/handler/WebSocketHandler.java @@ -95,6 +95,7 @@ public class WebSocketHandler extends TextWebSocketHandler { if (sessionInfo.getEmployeeId() == null) { logger.error("会话未绑定用户: " + session.getId()); + sendError(session, 401, "会话未绑定用户"); session.close(); return; } @@ -115,6 +116,31 @@ public class WebSocketHandler extends TextWebSocketHandler { sessionInfo.setSchedule(schedule); } + private void sendError(WebSocketSession session, int errorCode, String message) { + if (session == null || !session.isOpen()) { + logger.warn("尝试向已关闭的WebSocket会话发送错误消息: {}", message); + return; + } + + try { + ObjectNode objectNode = objectMapper.createObjectNode(); + objectNode.put("errorCode", errorCode); + objectNode.put("success", false); + objectNode.put("message", message); + String errorMessage = objectMapper.writeValueAsString(objectNode); + + // 检查会话状态并尝试发送错误消息 + if (session.isOpen()) { + session.sendMessage(new TextMessage(errorMessage)); + } else { + logger.warn("会话已关闭,无法发送错误消息: {}", message); + } + } catch (Exception e) { + // 捕获所有可能的异常,防止影响主流程 + logger.error("发送错误消息失败 (会话ID: {})", session.getId(), e); + } + } + /** * 接收文本消息时调用 */ @@ -162,12 +188,12 @@ public class WebSocketHandler extends TextWebSocketHandler { return false; } String messageId = jsonNode.get("messageId").asText(); - + if (!jsonNode.has("service")) { sendError(session, messageId, "缺失 service 参数"); return true; } - + String serviceName = jsonNode.get("service").asText(); Object service = null; try { @@ -181,7 +207,7 @@ public class WebSocketHandler extends TextWebSocketHandler { sendError(session, messageId, "缺失 method 参数"); return true; } - + String methodName = jsonNode.get("method").asText(); try { @@ -198,13 +224,13 @@ public class WebSocketHandler extends TextWebSocketHandler { sendError(session, messageId, "未实现的方法: " + methodName); return true; } - + // 再次检查会话状态 if (!session.isOpen()) { logger.warn("会话已关闭,无法发送处理结果 (消息ID: {})"); return true; } - + ObjectNode objectNode = objectMapper.createObjectNode(); objectNode.put("messageId", messageId); objectNode.set("data", objectMapper.valueToTree(result)); @@ -299,14 +325,14 @@ public class WebSocketHandler extends TextWebSocketHandler { logger.warn("尝试向已关闭的WebSocket会话发送错误消息: {}", message); return; } - + try { ObjectNode objectNode = objectMapper.createObjectNode(); objectNode.put("messageId", messageId); objectNode.put("success", false); objectNode.put("message", message); String errorMessage = objectMapper.writeValueAsString(objectNode); - + // 检查会话状态并尝试发送错误消息 if (session.isOpen()) { session.sendMessage(new TextMessage(errorMessage)); diff --git a/server/src/main/java/com/ecep/contract/util/SpecificationUtils.java b/server/src/main/java/com/ecep/contract/util/SpecificationUtils.java index 35062ed..6bb338d 100644 --- a/server/src/main/java/com/ecep/contract/util/SpecificationUtils.java +++ b/server/src/main/java/com/ecep/contract/util/SpecificationUtils.java @@ -76,4 +76,31 @@ public class SpecificationUtils { } return spec; } + + public static Specification andFieldEqualParam(Specification spec, JsonNode paramsNode, String... fields) { + for (String field : fields) { + if (!paramsNode.has(field)) { + continue; + } + JsonNode param = paramsNode.get(field); + if (param.isInt()) { + spec = SpecificationUtils.and(spec, (root, query, builder) -> { + return builder.equal(root.get(field), param.asInt()); + }); + } else if (param.isTextual()) { + spec = SpecificationUtils.and(spec, (root, query, builder) -> { + return builder.equal(root.get(field), param.asText()); + }); + } else if (param.isFloat() || param.isDouble()) { + spec = SpecificationUtils.and(spec, (root, query, builder) -> { + return builder.equal(root.get(field), param.asDouble()); + }); + } else if (param.isBoolean()) { + spec = SpecificationUtils.and(spec, (root, query, builder) -> { + return builder.equal(root.get(field), param.asBoolean()); + }); + } + } + return spec; + } }