From cf0a7e18ea72980353db253bbf65b0da03fd3580 Mon Sep 17 00:00:00 2001 From: songqq Date: Thu, 16 Oct 2025 00:09:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(contract):=20=E6=96=B0=E5=A2=9E=E5=90=88?= =?UTF-8?q?=E5=90=8C=E5=86=85=E5=AE=B9=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加合同内容窗口控制器及相关视图模型 - 实现合同内容基础信息标签页 - 添加金额计算功能 - 完善合同内容相关字段绑定 - 优化合同内容界面布局 --- .../ContractItemWindowController.java | 140 +++++++++++++++++ .../contract/ContractWindowController.java | 12 +- .../inventory/InventoryWindowController.java | 15 ++ .../tab/ContractItemTabSkinBase.java | 84 ++++++++++ .../tab/ContractTabSkinItemsV2.java | 13 +- .../contract/vm/ContractItemViewModel.java | 65 +++++--- .../resources/ui/contract/contract-item.fxml | 148 ++++++++++++++++++ 7 files changed, 445 insertions(+), 32 deletions(-) create mode 100644 client/src/main/java/com/ecep/contract/controller/contract/ContractItemWindowController.java create mode 100644 client/src/main/java/com/ecep/contract/controller/tab/ContractItemTabSkinBase.java create mode 100644 client/src/main/resources/ui/contract/contract-item.fxml diff --git a/client/src/main/java/com/ecep/contract/controller/contract/ContractItemWindowController.java b/client/src/main/java/com/ecep/contract/controller/contract/ContractItemWindowController.java new file mode 100644 index 0000000..90a46a1 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/contract/ContractItemWindowController.java @@ -0,0 +1,140 @@ +package com.ecep.contract.controller.contract; + +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.ecep.contract.controller.AbstEntityController; +import com.ecep.contract.controller.inventory.InventoryWindowController; +import com.ecep.contract.controller.tab.ContractItemTabSkinBase; +import com.ecep.contract.service.ContractItemService; +import com.ecep.contract.service.InventoryService; +import com.ecep.contract.util.FxmlPath; +import com.ecep.contract.util.UITools; +import com.ecep.contract.vm.ContractItemViewModel; +import com.ecep.contract.vm.InventoryViewModel; +import com.ecep.contract.vo.ContractItemVo; +import com.ecep.contract.vo.InventoryVo; + +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.scene.control.Button; +import javafx.scene.control.DatePicker; +import javafx.scene.control.Label; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.scene.layout.BorderPane; +import javafx.stage.Window; +import javafx.stage.WindowEvent; + +@Lazy +@Scope("prototype") +@Component +@FxmlPath("/ui/contract/contract-item.fxml") +public class ContractItemWindowController + extends AbstEntityController { + + public static void show(ContractItemVo contractItem, Window owner) { + show(ContractItemViewModel.from(contractItem), owner); + } + + /** + * 显示界面 + */ + public static void show(ContractItemViewModel viewModel, Window window) { + show(ContractItemWindowController.class, viewModel, window); + } + + public BorderPane root; + public Tab baseInfoTab; + + // 基本信息字段 + public Label idLabel; + public TextField codeField; + public TextField titleField; + public TextField specificationField; + public TextField unitField; + public TextField inventoryField; + public Button openInventoryBtn; + + // 财务信息字段 + public TextField exclusiveTaxPriceField; + public TextField taxRateField; + public TextField taxPriceField; + public TextField quantityField; + public TextField taxAmountField; + public TextField exclusiveTaxAmountField; + + // 日期信息字段 + public DatePicker startDateField; + public DatePicker endDateField; + public TextField createDateLabel; + public TextField updateDateLabel; + public TextField creatorLabel; + public TextField updaterLabel; + + // 其他信息 + public TextField refIdField; + public TextArea remarkField; + + @Override + public ContractItemService getViewModelService() { + return getCachedBean(ContractItemService.class); + } + + public InventoryService getInventoryService() { + return getCachedBean(InventoryService.class); + } + + public void onShown(WindowEvent windowEvent) { + super.onShown(windowEvent); + getTitle().bind(viewModel.getTitle() + .map(title -> "[" + viewModel.getId() + "] " + title + " 合同内容详情")); + root.getScene().getStylesheets().add("/ui/contract/contract.css"); + + } + + @Override + protected void registerTabSkins() { + super.registerTabSkins(); + TabPane tabPane = baseInfoTab.getTabPane(); + ObservableList tabs = tabPane.getTabs(); + registerTabSkin(baseInfoTab, tab -> new ContractItemTabSkinBase(this)); + } + + /** + * 打开关联的存货信息 + */ + public void onOpenInventoryAction(ActionEvent event) { + try { + if (viewModel.getInventory() == null) { + UITools.showAlertAndWait("没有关联的存货信息"); + return; + } + Integer inventoryId = viewModel.getInventory().get(); + InventoryVo inventory = getInventoryService().findById(inventoryId); + if (inventory != null) { + InventoryWindowController.show(InventoryViewModel.from(inventory), root.getScene().getWindow()); + } else { + UITools.showAlertAndWait("未找到关联的存货信息"); + } + } catch (Exception e) { + UITools.showAlertAndWait("打开存货信息失败: " + e.getMessage()); + } + } + + /** + * 计算税额和金额 + */ + public void onCalculateAmountsAction(ActionEvent event) { + try { + viewModel.calculateAmounts(); + UITools.showAlertAndWait("金额计算完成"); + } catch (Exception e) { + UITools.showAlertAndWait("计算失败: " + e.getMessage()); + } + } + +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/controller/contract/ContractWindowController.java b/client/src/main/java/com/ecep/contract/controller/contract/ContractWindowController.java index 77ccff2..f38e16d 100644 --- a/client/src/main/java/com/ecep/contract/controller/contract/ContractWindowController.java +++ b/client/src/main/java/com/ecep/contract/controller/contract/ContractWindowController.java @@ -152,7 +152,13 @@ public class ContractWindowController payPlanTab.setText("收款计划"); tabs.add(saleOrderTab); registerTabSkin(saleOrderTab, tab -> new ContractTabSkinSaleOrders(this, tab)); - tabs.add(new Tab("票据")); + Tab invoiceTab = new Tab("发票"); + tabs.add(invoiceTab); + // registerTabSkin(invoiceTab, tab -> new ContractTabSkinInvoices(this, tab)); + tabs.add(new Tab("出库单")); + tabs.add(new Tab("发货单")); + tabs.add(new Tab("签收单")); + } else if (payWay == ContractPayWay.PAY) { registerTabSkin(extendVendorInfo, t -> new ContractTabSkinExtendVendorInfo(this)); tabs.remove(contractTab); @@ -162,9 +168,9 @@ public class ContractWindowController tabs.add(purchaseOrderTab); registerTabSkin(purchaseOrderTab, tab -> new ContractTabSkinPurchaseOrders(this, tab)); - tabs.add(new Tab("发货单")); - tabs.add(new Tab("签收单")); + tabs.add(new Tab("入库单")); tabs.add(new Tab("付款单")); + payPlanTab.setText("付款计划"); } diff --git a/client/src/main/java/com/ecep/contract/controller/inventory/InventoryWindowController.java b/client/src/main/java/com/ecep/contract/controller/inventory/InventoryWindowController.java index 96f3152..7217e1f 100644 --- a/client/src/main/java/com/ecep/contract/controller/inventory/InventoryWindowController.java +++ b/client/src/main/java/com/ecep/contract/controller/inventory/InventoryWindowController.java @@ -5,10 +5,12 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import com.ecep.contract.controller.AbstEntityController; +import com.ecep.contract.controller.BaseController; import com.ecep.contract.service.InventoryService; import com.ecep.contract.util.FxmlPath; import com.ecep.contract.vm.InventoryViewModel; import com.ecep.contract.vo.InventoryVo; +import javafx.stage.Window; import javafx.beans.binding.Bindings; import javafx.fxml.FXML; @@ -26,6 +28,19 @@ import javafx.stage.WindowEvent; @Component @FxmlPath("/ui/inventory/inventory.fxml") public class InventoryWindowController extends AbstEntityController { + /** + * 显示界面 + */ + public static void show(InventoryViewModel viewModel, Window window) { + BaseController.show(InventoryWindowController.class, viewModel, window); + } + + /** + * 显示界面 + */ + public static void show(InventoryVo inventory, Window owner) { + show(InventoryViewModel.from(inventory), owner); + } @FXML public BorderPane root; @FXML diff --git a/client/src/main/java/com/ecep/contract/controller/tab/ContractItemTabSkinBase.java b/client/src/main/java/com/ecep/contract/controller/tab/ContractItemTabSkinBase.java new file mode 100644 index 0000000..0e1d666 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/tab/ContractItemTabSkinBase.java @@ -0,0 +1,84 @@ +package com.ecep.contract.controller.tab; + +import com.ecep.contract.controller.contract.ContractItemWindowController; +import com.ecep.contract.service.InventoryService; +import com.ecep.contract.util.UITools; +import com.ecep.contract.vm.ContractItemViewModel; +import com.ecep.contract.vo.ContractItemVo; + +import javafx.scene.control.Tab; +import javafx.util.converter.LocalDateTimeStringConverter; + +/** + * 合同项目基础信息标签页 + */ +public class ContractItemTabSkinBase + extends AbstEntityBasedTabSkin { + + public ContractItemTabSkinBase(ContractItemWindowController controller) { + super(controller); + } + + @Override + public Tab getTab() { + return controller.baseInfoTab; + } + + @Override + public void initializeTab() { + // 数据绑定 + controller.idLabel.textProperty().bind(viewModel.getId().asString()); + controller.codeField.textProperty().bindBidirectional(viewModel.getCode()); + controller.titleField.textProperty().bindBidirectional(viewModel.getTitle()); + controller.specificationField.textProperty().bindBidirectional(viewModel.getSpecification()); + controller.unitField.textProperty().bindBidirectional(viewModel.getUnit()); + + // 财务信息绑定 + controller.exclusiveTaxPriceField.textProperty().bindBidirectional(viewModel.getExclusiveTaxPrice().asObject(), + new javafx.util.converter.DoubleStringConverter()); + controller.taxRateField.textProperty().bindBidirectional(viewModel.getTaxRate().asObject(), + new javafx.util.converter.DoubleStringConverter()); + controller.taxPriceField.textProperty().bindBidirectional(viewModel.getTaxPrice().asObject(), + new javafx.util.converter.DoubleStringConverter()); + controller.quantityField.textProperty().bindBidirectional(viewModel.getQuantity().asObject(), + new javafx.util.converter.DoubleStringConverter()); + controller.taxAmountField.textProperty().bindBidirectional(viewModel.getTaxAmount().asObject(), + new javafx.util.converter.DoubleStringConverter()); + controller.exclusiveTaxAmountField.textProperty().bindBidirectional( + viewModel.getExclusiveTaxAmount().asObject(), + new javafx.util.converter.DoubleStringConverter()); + + // 日期绑定 + controller.startDateField.valueProperty().bindBidirectional(viewModel.getStartDate()); + controller.endDateField.valueProperty().bindBidirectional(viewModel.getEndDate()); + + // 其他信息绑定 + controller.refIdField.textProperty().bindBidirectional(viewModel.getRefId().asObject(), + new javafx.util.converter.IntegerStringConverter()); + controller.remarkField.textProperty().bindBidirectional(viewModel.getRemark()); + + // 设置只读字段 + LocalDateTimeStringConverter localDateTimeStringConverter = controller.getCurrentEmployee() + .getLocalDateTimeStringConverter(); + + controller.createDateLabel.textProperty().bindBidirectional(viewModel.getCreateDate(), + localDateTimeStringConverter); + controller.updateDateLabel.textProperty().bindBidirectional(viewModel.getUpdateDate(), + localDateTimeStringConverter); + + UITools.autoCompletion(controller.updaterLabel, viewModel.getCreator(), controller.getEmployeeService()); + UITools.autoCompletion(controller.updaterLabel, viewModel.getUpdater(), controller.getEmployeeService()); + + // 设置存货显示信息 + UITools.autoCompletion(controller.inventoryField, viewModel.getInventory(), + getCachedBean(InventoryService.class)); + } + + @Override + protected ContractItemVo save(ContractItemVo entity) { + // 保存前自动计算金额 + viewModel.calculateAmounts(); + return super.save(entity); + } + +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinItemsV2.java b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinItemsV2.java index b073516..66a3765 100644 --- a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinItemsV2.java +++ b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinItemsV2.java @@ -3,7 +3,8 @@ package com.ecep.contract.controller.tab; import java.text.NumberFormat; import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.HashMap; + +import org.springframework.data.domain.Pageable; import com.ecep.contract.ContractPayWay; import com.ecep.contract.SpringApp; @@ -20,22 +21,24 @@ import com.ecep.contract.service.InventoryService; import com.ecep.contract.service.PurchaseOrderItemService; import com.ecep.contract.util.FxmlPath; import com.ecep.contract.util.ParamUtils; -import com.ecep.contract.vm.ContractItemComposeViewModel; import com.ecep.contract.vm.ContractItemViewModel; import com.ecep.contract.vm.InventoryViewModel; import com.ecep.contract.vo.ContractItemVo; import com.ecep.contract.vo.InventoryVo; - import com.ecep.contract.vo.PurchaseOrderItemVo; + import javafx.application.Platform; -import javafx.scene.control.*; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.Tab; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; import javafx.scene.control.cell.TextFieldTableCell; import javafx.util.Callback; import javafx.util.StringConverter; import javafx.util.converter.CurrencyStringConverter; import javafx.util.converter.NumberStringConverter; import lombok.Setter; -import org.springframework.data.domain.Pageable; @FxmlPath("/ui/contract/contract-tab-item-v2.fxml") public class ContractTabSkinItemsV2 diff --git a/client/src/main/java/com/ecep/contract/vm/ContractItemViewModel.java b/client/src/main/java/com/ecep/contract/vm/ContractItemViewModel.java index 32fc659..a548360 100644 --- a/client/src/main/java/com/ecep/contract/vm/ContractItemViewModel.java +++ b/client/src/main/java/com/ecep/contract/vm/ContractItemViewModel.java @@ -10,57 +10,55 @@ import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import lombok.Data; -import lombok.EqualsAndHashCode; /** * 合同内容 */ @Data -@EqualsAndHashCode(callSuper = false) public class ContractItemViewModel extends IdentityViewModel { /** * 关联的合同对象,Contract */ - SimpleObjectProperty contract = new SimpleObjectProperty<>(); + private final SimpleObjectProperty contract = new SimpleObjectProperty<>(); /** * 关联的用友系统中的数据ID */ - SimpleIntegerProperty refId = new SimpleIntegerProperty(); - SimpleObjectProperty code = new SimpleObjectProperty<>(); - SimpleObjectProperty title = new SimpleObjectProperty<>(); - SimpleObjectProperty specification = new SimpleObjectProperty<>(); - SimpleObjectProperty unit = new SimpleObjectProperty<>(); + private final SimpleIntegerProperty refId = new SimpleIntegerProperty(); + private final SimpleObjectProperty code = new SimpleObjectProperty<>(); + private final SimpleObjectProperty title = new SimpleObjectProperty<>(); + private final SimpleObjectProperty specification = new SimpleObjectProperty<>(); + private final SimpleObjectProperty unit = new SimpleObjectProperty<>(); /** * 存货,Inventory */ - SimpleObjectProperty inventory = new SimpleObjectProperty<>(); + private final SimpleObjectProperty inventory = new SimpleObjectProperty<>(); /** * */ - SimpleDoubleProperty taxRate = new SimpleDoubleProperty(); - SimpleDoubleProperty exclusiveTaxPrice = new SimpleDoubleProperty(); - SimpleDoubleProperty taxPrice = new SimpleDoubleProperty(); - SimpleDoubleProperty quantity = new SimpleDoubleProperty(); - SimpleDoubleProperty taxAmount = new SimpleDoubleProperty(); - SimpleDoubleProperty exclusiveTaxAmount = new SimpleDoubleProperty(); + private final SimpleDoubleProperty taxRate = new SimpleDoubleProperty(); + private final SimpleDoubleProperty exclusiveTaxPrice = new SimpleDoubleProperty(); + private final SimpleDoubleProperty taxPrice = new SimpleDoubleProperty(); + private final SimpleDoubleProperty quantity = new SimpleDoubleProperty(); + private final SimpleDoubleProperty taxAmount = new SimpleDoubleProperty(); + private final SimpleDoubleProperty exclusiveTaxAmount = new SimpleDoubleProperty(); - SimpleObjectProperty startDate = new SimpleObjectProperty<>(); - SimpleObjectProperty endDate = new SimpleObjectProperty<>(); + private final SimpleObjectProperty startDate = new SimpleObjectProperty<>(); + private final SimpleObjectProperty endDate = new SimpleObjectProperty<>(); - SimpleObjectProperty createDate = new SimpleObjectProperty<>(); - SimpleObjectProperty updateDate = new SimpleObjectProperty<>(); + private final SimpleObjectProperty createDate = new SimpleObjectProperty<>(); + private final SimpleObjectProperty updateDate = new SimpleObjectProperty<>(); /** * 关联的创建人,Employee */ - SimpleObjectProperty creator = new SimpleObjectProperty<>(); + private final SimpleObjectProperty creator = new SimpleObjectProperty<>(); /** * 关联的更新人,Employee */ - SimpleObjectProperty updater = new SimpleObjectProperty<>(); + private final SimpleObjectProperty updater = new SimpleObjectProperty<>(); - SimpleObjectProperty remark = new SimpleObjectProperty<>(); + private final SimpleObjectProperty remark = new SimpleObjectProperty<>(); @Override protected void updateFrom(ContractItemVo v) { @@ -87,8 +85,7 @@ public class ContractItemViewModel extends IdentityViewModel { getUpdater().set(v.getUpdaterId()); getRemark().set(v.getRemark()); - getTaxAmount().set(v.getTaxPrice() * v.getQuantity()); - getExclusiveTaxAmount().set(v.getExclusiveTaxPrice() * v.getQuantity()); + calculateAmounts(); } @Override @@ -172,6 +169,26 @@ public class ContractItemViewModel extends IdentityViewModel { return modified; } + /** + * 计算税额相关字段 + */ + public void calculateAmounts() { + double price = getExclusiveTaxPrice().get(); + double rate = getTaxRate().get(); + double qty = getQuantity().get(); + + // 计算含税单价 + double taxPrice = price * (1 + rate / 100); + // 计算税额 + double taxAmount = price * rate / 100 * qty; + // 计算不含税金额 + double exclusiveTaxAmount = price * qty; + + getTaxPrice().set(taxPrice); + getTaxAmount().set(taxAmount); + getExclusiveTaxAmount().set(exclusiveTaxAmount); + } + /** * 判断两个 double 值是否相等 * diff --git a/client/src/main/resources/ui/contract/contract-item.fxml b/client/src/main/resources/ui/contract/contract-item.fxml new file mode 100644 index 0000000..3e0c20c --- /dev/null +++ b/client/src/main/resources/ui/contract/contract-item.fxml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +