feat(客户评估): 实现客户评估表单的搜索和显示功能

添加客户评估表单文件的搜索功能,支持按公司ID和搜索文本查询
新增CompanyCustomerEvaluationFormFileStringConverter用于文件显示转换
优化自动完成功能,支持自定义搜索逻辑
移除不必要的文件路径属性绑定
重构客户评估表单窗口控制器继承结构
This commit is contained in:
2025-10-18 01:36:58 +08:00
parent 7d4961dae4
commit dd49c3927a
10 changed files with 159 additions and 80 deletions

View File

@@ -1,5 +1,6 @@
package com.ecep.contract.controller.bank;
import org.controlsfx.control.SearchableComboBox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
@@ -34,7 +35,6 @@ public class BankManagerWindowController
}
public void onCreateNewAction(ActionEvent event) {
}
public void onReBuildFilesAction(ActionEvent event) {

View File

@@ -6,6 +6,9 @@ import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import com.ecep.contract.controller.AbstEntityController;
import com.ecep.contract.service.ViewModelService;
import com.ecep.contract.util.FxmlPath;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
@@ -50,10 +53,12 @@ import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.stage.WindowEvent;
@Lazy
@Scope("prototype")
@Component
public class CompanyCustomerEvaluationFormFileWindowController extends BaseController {
@FxmlPath("/ui/company/customer/customer_evaluation_form.fxml")
public class CompanyCustomerEvaluationFormFileWindowController extends AbstEntityController<CompanyCustomerEvaluationFormFileVo, CompanyCustomerEvaluationFormFileViewModel> {
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerEvaluationFormFileWindowController.class);
public static void show(CompanyCustomerEvaluationFormFileVo saved, Window window) {
@@ -61,15 +66,7 @@ public class CompanyCustomerEvaluationFormFileWindowController extends BaseContr
}
public static void show(CompanyCustomerEvaluationFormFileViewModel viewModel, Window window) {
String key = viewModel.getClass().getName() + "-" + viewModel.getId().get();
if (toFront(key)) {
return;
}
FxmlUtils.newLoaderAsyncWithRunLater("/ui/company/customer/customer_evaluation_form.fxml", null, loader -> {
CompanyCustomerEvaluationFormFileWindowController controller = loader.getController();
controller.viewModel = viewModel;
controller.show(loader, window, Modality.NONE, key);
});
show(CompanyCustomerEvaluationFormFileWindowController.class, viewModel, window);
}
@@ -91,8 +88,6 @@ public class CompanyCustomerEvaluationFormFileWindowController extends BaseContr
public ScrollPane leftPane;
public Label totalCreditScoreLabel;
private CompanyCustomerEvaluationFormFileViewModel viewModel;
private final SimpleStringProperty catalogProperty = new SimpleStringProperty("");
private final SimpleStringProperty levelProperty = new SimpleStringProperty("");
private final SimpleIntegerProperty score1Property = new SimpleIntegerProperty(-1);
@@ -105,7 +100,9 @@ public class CompanyCustomerEvaluationFormFileWindowController extends BaseContr
private SimpleObjectProperty<Image> imageProperty = new SimpleObjectProperty<>();
private CompletableFuture<CompanyCustomerEvaluationFormFileVo> loadedFuture;
private SimpleStringProperty filePathProperty = new SimpleStringProperty();
private SimpleStringProperty editFilePathProperty = new SimpleStringProperty();
@Lazy
@Autowired
private CompanyCustomerFileService companyCustomerFileService;
@@ -131,24 +128,27 @@ public class CompanyCustomerEvaluationFormFileWindowController extends BaseContr
getTitle().set("客户评估表单");
}
@Override
public void onShown(WindowEvent windowEvent) {
super.onShown(windowEvent);
if (logger.isDebugEnabled()) {
logger.debug("onShown");
}
protected void registerTabSkins() {
initializePane();
}
loadedFuture = CompletableFuture.supplyAsync(() -> {
int id = viewModel.getId().get();
CustomerFileVo customerFile = companyCustomerFileService.findById(id);
CompanyCustomerEvaluationFormFileVo formFile = evaluationFormFileService.findByCustomerFile(customerFile);
Platform.runLater(() -> update(formFile));
return formFile;
@Override
protected void updateViewModel(CompanyCustomerEvaluationFormFileVo entity) {
super.updateViewModel(entity);
CustomerFileVo file = companyCustomerFileService.findById(entity.getCustomerFile());
Platform.runLater(() -> {
filePathProperty.set(file.getFilePath());
editFilePathProperty.set(file.getEditFilePath());
});
}
@Override
public ViewModelService<CompanyCustomerEvaluationFormFileVo, CompanyCustomerEvaluationFormFileViewModel> getViewModelService() {
return evaluationFormFileService;
}
BiConsumer<ToggleGroup, String> stringRadioGroupUpdater = (group, newValue) -> {
if (newValue != null) {
for (Toggle toggle : group.getToggles()) {
@@ -259,8 +259,8 @@ public class CompanyCustomerEvaluationFormFileWindowController extends BaseContr
private void initializePane() {
idField.textProperty().bind(viewModel.getId().asString());
// filePathField.textProperty().bind(viewModel.getFilePath());
// editFilePathField.textProperty().bind(viewModel.getEditFilePath());
filePathField.textProperty().bind(filePathProperty);
editFilePathField.textProperty().bind(editFilePathProperty);
// signDateField.valueProperty().bindBidirectional(viewModel.getSignDate());
// validField.selectedProperty().bindBidirectional(viewModel.getValid());
@@ -300,7 +300,7 @@ public class CompanyCustomerEvaluationFormFileWindowController extends BaseContr
}));
imageView.imageProperty().bind(viewModel.getFilePath().map(path -> {
imageView.imageProperty().bind(filePathProperty.map(path -> {
if (FileUtils.withExtensions(path, FileUtils.PDF)) {
File pdfFile = new File(path);
try (PDDocument pdDocument = Loader.loadPDF(pdfFile)) {

View File

@@ -1,9 +1,5 @@
package com.ecep.contract.controller.project.quotation;
import java.io.File;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CompletableFuture;
import com.ecep.contract.DesktopUtils;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.controller.customer.CompanyCustomerEvaluationFormFileWindowController;
@@ -11,21 +7,13 @@ import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.converter.CompanyStringConverter;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.model.Employee;
import com.ecep.contract.service.CompanyCustomerEvaluationFormFileService;
import com.ecep.contract.service.CompanyCustomerFileService;
import com.ecep.contract.service.CustomerService;
import com.ecep.contract.service.CompanyService;
import com.ecep.contract.service.ProjectQuotationService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.service.*;
import com.ecep.contract.util.ProxyUtils;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.ProjectQuotationViewModel;
import com.ecep.contract.vo.CompanyCustomerEvaluationFormFileVo;
import com.ecep.contract.vo.CompanyVo;
import com.ecep.contract.vo.ProjectQuotationVo;
import com.ecep.contract.vo.ProjectVo;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.scene.control.Tab;
@@ -37,36 +25,22 @@ import javafx.util.converter.LocalDateTimeStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.Setter;
import java.io.File;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CompletableFuture;
/**
* 项目报价单
*/
public class ProjectQuotationTabSkinBase
extends AbstEntityBasedTabSkin<ProjectQuotationWindowController, ProjectQuotationVo, ProjectQuotationViewModel>
implements TabSkin {
@Setter
private LocalDateTimeStringConverter localDateTimeStringConverter;
@Setter
private ProjectQuotationService projectQuotationService;
@Setter
private LocalDateStringConverter localDateStringConverter;
@Setter
private EmployeeStringConverter employeeStringConverter;
@Setter
private CompanyStringConverter companyStringConverter;
@Setter
private CompanyService companyService;
@Setter
private CustomerService customerService;
@Setter
private CompanyCustomerFileService customerFileService;
@Setter
private CompanyCustomerEvaluationFormFileService evaluationFormFileService;
@Setter
private ProjectService projectService;
private ProjectService getProjectService() {
if (projectService == null) {
projectService = getBean(ProjectService.class);
}
return projectService;
return getCachedBean(ProjectService.class);
}
public ProjectQuotationTabSkinBase(ProjectQuotationWindowController controller) {
@@ -133,7 +107,10 @@ public class ProjectQuotationTabSkinBase
new NumberStringConverter(getLocale()));
UITools.autoCompletion(controller.evaluationFileField, viewModel.getEvaluationFile(),
getEvaluationFormFileService());
getEvaluationFormFileService(), getEvaluationFormFileService().getStringConverter(), searchText -> {
var project = getProjectService().findById(getEntity().getProject());
return getEvaluationFormFileService().searchByCompany(project.getCustomerId(), searchText);
});
controller.authorizationFileField.textProperty().bind(viewModel.getAuthorizationFile().map(File::getName));
@@ -220,7 +197,7 @@ public class ProjectQuotationTabSkinBase
}
private void evaluationFileAutoCompletion(TextField textField,
SimpleObjectProperty<CompanyCustomerEvaluationFormFileVo> property) {
SimpleObjectProperty<CompanyCustomerEvaluationFormFileVo> property) {
// 直接使用Vo类不再需要手动转换
}

View File

@@ -0,0 +1,71 @@
package com.ecep.contract.converter;
import java.io.File;
import org.springframework.util.StringUtils;
import com.ecep.contract.SpringApp;
import com.ecep.contract.service.CompanyCustomerEvaluationFormFileService;
import com.ecep.contract.service.CompanyCustomerFileService;
import com.ecep.contract.vo.CompanyCustomerEvaluationFormFileVo;
import com.ecep.contract.vo.CustomerFileVo;
import javafx.util.StringConverter;
/**
* CompanyCustomerEvaluationFormFileVo的StringConverter实现用于JavaFX控件中的显示和转换
*/
public class CompanyCustomerEvaluationFormFileStringConverter
extends StringConverter<CompanyCustomerEvaluationFormFileVo> {
private final CompanyCustomerEvaluationFormFileService service;
private CompanyCustomerFileService customerFileService;
/**
* 构造函数
*
* @param service CompanyCustomerEvaluationFormFileService实例
*/
public CompanyCustomerEvaluationFormFileStringConverter(CompanyCustomerEvaluationFormFileService service) {
this.service = service;
}
private CompanyCustomerFileService getCustomerFileService() {
if (customerFileService == null) {
customerFileService = SpringApp.getBean(CompanyCustomerFileService.class);
}
return customerFileService;
}
/**
* 将CompanyCustomerEvaluationFormFileVo对象转换为字符串
*
* @param formFile CompanyCustomerEvaluationFormFileVo对象
* @return 转换后的字符串
*/
@Override
public String toString(CompanyCustomerEvaluationFormFileVo formFile) {
if (formFile == null || formFile.getCustomerFile() == null) {
return "";
}
CustomerFileVo customerFile = getCustomerFileService().findById(formFile.getCustomerFile());
if (customerFile == null || !StringUtils.hasText(customerFile.getFilePath())) {
return "#" + formFile.getCustomerFile();
}
File file = new File(customerFile.getFilePath());
return file.getName();
}
/**
* 将字符串转换为CompanyCustomerEvaluationFormFileVo对象
*
* @param string 字符串
* @return 转换后的CompanyCustomerEvaluationFormFileVo对象
*/
@Override
public CompanyCustomerEvaluationFormFileVo fromString(String string) {
// 由于文件名称可能不唯一这里返回null
// 实际使用时应该通过ID或其他唯一标识来查找
return null;
}
}

View File

@@ -1,5 +1,7 @@
package com.ecep.contract.service;
import com.ecep.contract.converter.CompanyCustomerEvaluationFormFileStringConverter;
import javafx.util.StringConverter;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@@ -14,6 +16,8 @@ import java.util.List;
public class CompanyCustomerEvaluationFormFileService
extends QueryService<CompanyCustomerEvaluationFormFileVo, CompanyCustomerEvaluationFormFileViewModel> {
private final StringConverter<CompanyCustomerEvaluationFormFileVo> stringConverter = new CompanyCustomerEvaluationFormFileStringConverter(this);
/**
* 根据ID查找客户评估表文件
*/
@@ -39,6 +43,12 @@ public class CompanyCustomerEvaluationFormFileService
return page.getFirst();
}
public List<CompanyCustomerEvaluationFormFileVo> searchByCompany(Integer companyId, String searchText) {
ParamUtils.Builder params = getSpecification(searchText);
params.equals("company", companyId);
return findAll(params.build(), Pageable.ofSize(10)).getContent();
}
/**
* 保存客户评估表文件
*/
@@ -46,4 +56,10 @@ public class CompanyCustomerEvaluationFormFileService
return super.save(formFile);
}
@Override
public StringConverter<CompanyCustomerEvaluationFormFileVo> getStringConverter() {
return stringConverter;
}
}

View File

@@ -250,10 +250,16 @@ public class UITools {
public static <T extends IdentityEntity, TV extends IdentityViewModel<T>> AutoCompletionBinding<T> autoCompletion(
TextField textField, ObjectProperty<Integer> idProperty, QueryService<T, TV> queryService) {
Integer id = idProperty.get();
StringConverter<T> converter = queryService.getStringConverter();
return autoCompletion(textField, idProperty, queryService, converter, queryService::search);
}
public static <T extends IdentityEntity, TV extends IdentityViewModel<T>> AutoCompletionBinding<T> autoCompletion(
TextField textField, ObjectProperty<Integer> idProperty, QueryService<T, TV> service, StringConverter<T> converter, Function<String, List<T>> searcher) {
Integer id = idProperty.get();
if (id != null) {
T entity = queryService.findById(id);
T entity = service.findById(id);
// 先赋值
textField.textProperty().set(converter.toString(entity));
}
@@ -264,7 +270,7 @@ public class UITools {
textField.textProperty().set(null);
return;
}
T newEntity = queryService.findById(newValue);
T newEntity = service.findById(newValue);
textField.textProperty().set(converter.toString(newEntity));
});
@@ -274,7 +280,7 @@ public class UITools {
return null;
}
try {
return queryService.search(p.getUserText());
return searcher.apply(p.getUserText());
} catch (Exception e) {
textField.setText(e.getMessage());
throw new RuntimeException(e);

View File

@@ -24,7 +24,7 @@ public class CompanyCustomerEvaluationFormFileViewModel extends IdentityViewMode
private SimpleIntegerProperty score5 = new SimpleIntegerProperty(0);
private SimpleIntegerProperty scoreTemplateVersion = new SimpleIntegerProperty(1);
private SimpleStringProperty filePath = new SimpleStringProperty();
public static CompanyCustomerEvaluationFormFileViewModel from(CompanyCustomerEvaluationFormFileVo vo) {
CompanyCustomerEvaluationFormFileViewModel viewModel = new CompanyCustomerEvaluationFormFileViewModel();

View File

@@ -209,7 +209,7 @@ fx:controller="com.ecep.contract.controller.customer.CompanyCustomerEvaluationFo
<Label text="★★★★≤200分★★★≤150分★★≤100分★≤60分" />
</children>
</VBox>
<Button mnemonicParsing="false" onAction="#onSaveAction" text="保存" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="10" />
<Button mnemonicParsing="false" text="保存" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="10" />
</children>
<padding>
<Insets right="5.0" />

View File

@@ -1,5 +1,6 @@
package com.ecep.contract.vo;
import java.io.Serial;
import java.io.Serializable;
import com.ecep.contract.model.IdentityEntity;
import lombok.Data;

View File

@@ -2,6 +2,7 @@ package com.ecep.contract.ds.customer.service;
import java.util.List;
import jakarta.persistence.criteria.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -58,9 +59,14 @@ public class CompanyCustomerEvaluationFormFileService
return null;
}
return (root, query, builder) -> {
var customerFile = root.get("customerFile");
return builder.or(
builder.like(root.get("catalog"), "%" + searchText + "%"),
builder.like(root.get("level"), "%" + searchText + "%"));
builder.like(root.get("level"), "%" + searchText + "%"),
builder.and(
customerFile.isNotNull(),
builder.like(customerFile.get("filePath"), "%" + searchText + "%")
));
};
}
@@ -82,7 +88,7 @@ public class CompanyCustomerEvaluationFormFileService
@Override
public Page<CompanyCustomerEvaluationFormFile> findAll(Specification<CompanyCustomerEvaluationFormFile> spec,
Pageable pageable) {
Pageable pageable) {
return repository.findAll(spec, pageable);
}
@@ -94,10 +100,12 @@ public class CompanyCustomerEvaluationFormFileService
}
if (paramsNode.has("customer")) {
CompanyCustomer customer = new CompanyCustomer();
customer.setId(paramsNode.get("customer").asInt());
spec = SpecificationUtils.and(spec,
(root, query, builder) -> builder.equal(root.get("customerFile").get("customer"), customer));
(root, query, builder) -> builder.equal(root.get("customerFile").get("customer").get("id"), paramsNode.get("customer").asInt()));
}
if (paramsNode.has("company")) {
spec = SpecificationUtils.and(spec,
(root, query, builder) -> builder.equal(root.get("customerFile").get("customer").get("company").get("id"), paramsNode.get("company").asInt()));
}
spec = SpecificationUtils.andParam(spec, paramsNode, "customerFile");
@@ -108,7 +116,7 @@ public class CompanyCustomerEvaluationFormFileService
/**
* 根据客户查询所有评估表文件
*
*
* @param customer 客户实体
* @return 评估表文件列表
*/
@@ -118,7 +126,7 @@ public class CompanyCustomerEvaluationFormFileService
/**
* 根据客户ID和文件类型查询评估表文件
*
*
* @param companyCustomerId 客户ID
* @param type 文件类型
* @return 评估表文件列表
@@ -129,7 +137,7 @@ public class CompanyCustomerEvaluationFormFileService
/**
* 根据客户文件查询评估表文件
*
*
* @param customerFile 客户文件实体
* @return 评估表文件列表
*/