From 71a358fa77cfcb61a29ca0d3f741a7c6b8128ef5 Mon Sep 17 00:00:00 2001 From: songqq Date: Thu, 16 Oct 2025 15:47:33 +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=8F=91=E7=A5=A8=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 实现合同发票的增删改查功能,包括: 1. 添加ContractInvoiceVo实体类及相关ViewModel 2. 创建合同发票数据库表CONTRACT_INVOICE 3. 实现前后端发票管理服务ContractInvoiceService 4. 开发发票管理界面及标签页 5. 添加发票表格单元格组件 6. 完善销售订单表结构,增加客户联系人字段 7. 更新pom.xml版本至0.0.122-SNAPSHOT 修复销售订单界面搜索字段命名不一致问题 --- client/pom.xml | 6 +- .../contract/ContractInvoiceManagerSkin.java | 24 +++ ...ontractInvoiceManagerWindowController.java | 48 +++++ .../ContractInvoiceWindowController.java | 50 +++++ .../contract/ContractTabSkinSaleOrders.java | 24 +-- .../contract/ContractWindowController.java | 3 +- .../tab/ContractInvoiceTabSkinBase.java | 31 +++ .../tab/ContractTabSkinInvoices.java | 124 +++++++++++ .../tab/ContractTabSkinItemsV2.java | 5 + .../table/cell/ContractInvoiceTableCell.java | 59 ++++++ .../service/ContractInvoiceService.java | 67 ++++++ .../contract/service/EmployeeService.java | 1 - .../contract/vm/ContractInvoiceViewModel.java | 119 +++++++++++ .../ui/contract/contract-invoice-manager.fxml | 61 ++++++ .../ui/contract/contract-invoice.fxml | 100 +++++++++ .../ui/contract/contract-tab-invoices.fxml | 39 ++++ .../ui/contract/contract-tab-sale-orders.fxml | 3 +- common/pom.xml | 4 +- .../ecep/contract/vo/ContractInvoiceVo.java | 50 +++++ .../com/ecep/contract/vo/SalesOrderVo.java | 1 + docs/db/CONTRACT_INVOICE.sql | 37 ++++ docs/db/CONTRACT_SALES_ORDER.sql | 37 ++++ pom.xml | 2 +- server/pom.xml | 6 +- .../ds/contract/model/ContractInvoice.java | 139 ++++++++++++ .../repository/ContractInvoiceRepository.java | 35 +++ .../service/ContractInvoiceService.java | 200 ++++++++++++++++++ .../ds/customer/model/SalesOrder.java | 39 +++- 28 files changed, 1274 insertions(+), 40 deletions(-) create mode 100644 client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerSkin.java create mode 100644 client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerWindowController.java create mode 100644 client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceWindowController.java create mode 100644 client/src/main/java/com/ecep/contract/controller/tab/ContractInvoiceTabSkinBase.java create mode 100644 client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinInvoices.java create mode 100644 client/src/main/java/com/ecep/contract/controller/table/cell/ContractInvoiceTableCell.java create mode 100644 client/src/main/java/com/ecep/contract/service/ContractInvoiceService.java create mode 100644 client/src/main/java/com/ecep/contract/vm/ContractInvoiceViewModel.java create mode 100644 client/src/main/resources/ui/contract/contract-invoice-manager.fxml create mode 100644 client/src/main/resources/ui/contract/contract-invoice.fxml create mode 100644 client/src/main/resources/ui/contract/contract-tab-invoices.fxml create mode 100644 common/src/main/java/com/ecep/contract/vo/ContractInvoiceVo.java create mode 100644 docs/db/CONTRACT_INVOICE.sql create mode 100644 docs/db/CONTRACT_SALES_ORDER.sql create mode 100644 server/src/main/java/com/ecep/contract/ds/contract/model/ContractInvoice.java create mode 100644 server/src/main/java/com/ecep/contract/ds/contract/repository/ContractInvoiceRepository.java create mode 100644 server/src/main/java/com/ecep/contract/ds/contract/service/ContractInvoiceService.java diff --git a/client/pom.xml b/client/pom.xml index 28831e4..1356444 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -6,12 +6,12 @@ com.ecep.contract Contract-Manager - 0.0.102-SNAPSHOT + 0.0.122-SNAPSHOT com.ecep.contract client - 0.0.102-SNAPSHOT + 0.0.122-SNAPSHOT ${java.version} @@ -22,7 +22,7 @@ com.ecep.contract common - 0.0.102-SNAPSHOT + 0.0.122-SNAPSHOT org.springframework.boot diff --git a/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerSkin.java b/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerSkin.java new file mode 100644 index 0000000..7afe183 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerSkin.java @@ -0,0 +1,24 @@ +package com.ecep.contract.controller.contract; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ecep.contract.controller.AbstEntityManagerSkin; +import com.ecep.contract.vm.ContractInvoiceViewModel; +import com.ecep.contract.vo.ContractInvoiceVo; + +public class ContractInvoiceManagerSkin extends + AbstEntityManagerSkin { + + private static final Logger logger = LoggerFactory.getLogger(ContractInvoiceManagerSkin.class); + + public ContractInvoiceManagerSkin(ContractInvoiceManagerWindowController controller) { + super(controller); + } + + @Override + public void initializeTable() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'initializeTable'"); + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerWindowController.java b/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerWindowController.java new file mode 100644 index 0000000..ae73187 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceManagerWindowController.java @@ -0,0 +1,48 @@ +package com.ecep.contract.controller.contract; + +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 com.ecep.contract.controller.AbstManagerWindowController; +import com.ecep.contract.service.ContractInvoiceService; +import com.ecep.contract.util.FxmlPath; +import com.ecep.contract.vm.ContractInvoiceViewModel; +import com.ecep.contract.vo.ContractInvoiceVo; + +import javafx.scene.control.TableColumn; +import javafx.stage.Stage; + +@Lazy +@Scope("prototype") +@Component +@FxmlPath("/ui/contract/contract-invoice-manager.fxml") +public class ContractInvoiceManagerWindowController extends AbstManagerWindowController { + + public TableColumn idColumn; + public TableColumn codeColumn; + public TableColumn nameColumn; + public TableColumn contractColumn; + public TableColumn contractItemColumn; + + @Autowired + private ContractInvoiceService contractInvoiceService; + + @Override + public ContractInvoiceService getViewModelService() { + return contractInvoiceService; + } + + @Override + protected ContractInvoiceManagerSkin createDefaultSkin() { + ContractInvoiceManagerSkin skin = new ContractInvoiceManagerSkin(this); + return skin; + } + + @Override + public void show(Stage stage) { + super.show(stage); + getTitle().set("合同发票管理"); + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceWindowController.java b/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceWindowController.java new file mode 100644 index 0000000..0728685 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/contract/ContractInvoiceWindowController.java @@ -0,0 +1,50 @@ +package com.ecep.contract.controller.contract; + +import org.springframework.stereotype.Component; + +import com.ecep.contract.controller.AbstEntityController; +import com.ecep.contract.controller.tab.ContractInvoiceTabSkinBase; +import com.ecep.contract.service.ContractInvoiceService; +import com.ecep.contract.util.FxmlPath; +import com.ecep.contract.vm.ContractInvoiceViewModel; +import com.ecep.contract.vo.ContractInvoiceVo; + +import javafx.collections.ObservableList; +import javafx.scene.control.Button; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.stage.Window; + +@FxmlPath("/ui/contract/contract-invoice.fxml") +@Component +public class ContractInvoiceWindowController + extends AbstEntityController { + + public static void show(ContractInvoiceViewModel viewModel, Window owner) { + show(ContractInvoiceWindowController.class, viewModel, owner); + } + + public Tab baseInfoTab; + public TextField codeField; + public TextField nameField; + public TextField invoiceField; + public TextField amountField; + public TextArea remarkField; + public Button saveBtn; + public Button cancelBtn; + + @Override + public ContractInvoiceService getViewModelService() { + return getBean(ContractInvoiceService.class); + } + + @Override + protected void registerTabSkins() { + TabPane tabPane = baseInfoTab.getTabPane(); + ObservableList tabs = tabPane.getTabs(); + registerTabSkin(baseInfoTab, tab -> new ContractInvoiceTabSkinBase(this)); + } + +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/controller/contract/ContractTabSkinSaleOrders.java b/client/src/main/java/com/ecep/contract/controller/contract/ContractTabSkinSaleOrders.java index 015e8e2..9980df2 100644 --- a/client/src/main/java/com/ecep/contract/controller/contract/ContractTabSkinSaleOrders.java +++ b/client/src/main/java/com/ecep/contract/controller/contract/ContractTabSkinSaleOrders.java @@ -3,24 +3,21 @@ package com.ecep.contract.controller.contract; import java.time.LocalDate; import com.ecep.contract.ContractPayWay; +import com.ecep.contract.controller.contract.sale_order.SalesOrderWindowController; import com.ecep.contract.controller.tab.TabSkin; import com.ecep.contract.controller.table.cell.CompanyTableCell; import com.ecep.contract.controller.table.cell.EmployeeTableCell; -import com.ecep.contract.util.FxmlPath; -import com.ecep.contract.controller.contract.sale_order.SalesOrderWindowController; import com.ecep.contract.controller.table.cell.LocalDateFieldTableCell; import com.ecep.contract.converter.EmployeeStringConverter; import com.ecep.contract.service.CompanyService; import com.ecep.contract.service.SaleOrdersService; +import com.ecep.contract.util.FxmlPath; import com.ecep.contract.vm.SalesOrderViewModel; - import com.ecep.contract.vo.SalesOrderVo; -import javafx.scene.control.Button; + import javafx.scene.control.MenuItem; import javafx.scene.control.Tab; import javafx.scene.control.TableColumn; -import javafx.scene.control.TextField; -import javafx.scene.input.KeyCode; import lombok.Setter; /** @@ -56,7 +53,6 @@ public class ContractTabSkinSaleOrders public TableColumn verifierDateColumn; public TableColumn refIdColumn; public TableColumn taxRateColumn; - public TableColumn customerColumn; public TableColumn customerAddressColumn; /** * 修改人, Employee @@ -70,8 +66,6 @@ public class ContractTabSkinSaleOrders public TableColumn closerDateColumn; public TableColumn descriptionColumn; public MenuItem subContractTable_menu_refresh; - public TextField contractSearchKeyField; - public Button searchBtn; private Tab tab; public ContractTabSkinSaleOrders(ContractWindowController controller, Tab tab) { @@ -98,13 +92,7 @@ public class ContractTabSkinSaleOrders @Override public void initializeTab() { - contractSearchKeyField.setOnKeyReleased(event -> { - if (event.getCode() == KeyCode.ENTER) { - searchBtn.fire(); - } - }); - - searchBtn.setOnAction(this::onTableRefreshAction); + super.initializeTab(); subContractTable_menu_refresh.setOnAction(this::onTableRefreshAction); idColumn.setCellValueFactory(param -> param.getValue().getId()); @@ -123,8 +111,6 @@ public class ContractTabSkinSaleOrders // 设置新增字段的单元格值工厂和工厂类 refIdColumn.setCellValueFactory(param -> param.getValue().getRefId()); taxRateColumn.setCellValueFactory(param -> param.getValue().getTaxRate()); - customerColumn.setCellValueFactory(param -> param.getValue().getCustomer()); - customerColumn.setCellFactory(CompanyTableCell.forTableColumn(getCompanyService())); customerAddressColumn.setCellValueFactory(param -> param.getValue().getCustomerAddress()); modifierColumn.setCellValueFactory(param -> param.getValue().getModifier()); modifierColumn.setCellFactory(EmployeeTableCell.forTableColumn(getEmployeeService())); @@ -136,7 +122,7 @@ public class ContractTabSkinSaleOrders closerDateColumn.setCellFactory(LocalDateFieldTableCell.forTableColumn()); descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription()); - super.initializeTab(); + } @Override 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 f38e16d..53e981d 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 @@ -13,6 +13,7 @@ import com.ecep.contract.controller.AbstEntityController; import com.ecep.contract.controller.company.CompanyWindowController; import com.ecep.contract.controller.tab.ContractTabSkinBase; import com.ecep.contract.controller.tab.ContractTabSkinFiles; +import com.ecep.contract.controller.tab.ContractTabSkinInvoices; import com.ecep.contract.controller.tab.ContractTabSkinItemsV2; import com.ecep.contract.controller.tab.ContractTabSkinPayPlan; import com.ecep.contract.controller.tab.ContractTabSkinSubContract; @@ -154,7 +155,7 @@ public class ContractWindowController registerTabSkin(saleOrderTab, tab -> new ContractTabSkinSaleOrders(this, tab)); Tab invoiceTab = new Tab("发票"); tabs.add(invoiceTab); - // registerTabSkin(invoiceTab, tab -> new ContractTabSkinInvoices(this, tab)); + registerTabSkin(invoiceTab, tab -> new ContractTabSkinInvoices(this, tab)); tabs.add(new Tab("出库单")); tabs.add(new Tab("发货单")); tabs.add(new Tab("签收单")); diff --git a/client/src/main/java/com/ecep/contract/controller/tab/ContractInvoiceTabSkinBase.java b/client/src/main/java/com/ecep/contract/controller/tab/ContractInvoiceTabSkinBase.java new file mode 100644 index 0000000..ace0895 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/tab/ContractInvoiceTabSkinBase.java @@ -0,0 +1,31 @@ +package com.ecep.contract.controller.tab; + +import com.ecep.contract.controller.contract.ContractInvoiceWindowController; +import com.ecep.contract.vm.ContractInvoiceViewModel; +import com.ecep.contract.vo.ContractInvoiceVo; +import javafx.scene.control.Tab; + +/** + * 合同发票基础信息标签页皮肤 + */ +public class ContractInvoiceTabSkinBase + extends AbstEntityBasedTabSkin + implements TabSkin { + + public ContractInvoiceTabSkinBase(ContractInvoiceWindowController controller) { + super(controller); + } + + @Override + public Tab getTab() { + return controller.baseInfoTab; + } + + @Override + public void initializeTab() { + // 可以在这里进行标签页的初始化工作 + controller.codeField.textProperty().bindBidirectional(viewModel.getCode()); + controller.nameField.textProperty().bindBidirectional(viewModel.getName()); + controller.remarkField.textProperty().bindBidirectional(viewModel.getRemark()); + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinInvoices.java b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinInvoices.java new file mode 100644 index 0000000..c0be320 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/tab/ContractTabSkinInvoices.java @@ -0,0 +1,124 @@ +package com.ecep.contract.controller.tab; + +import java.time.LocalDate; +import java.util.Objects; + +import org.controlsfx.glyphfont.Glyph; +import org.springframework.stereotype.Component; + +import com.ecep.contract.controller.contract.AbstContractTableTabSkin; +import com.ecep.contract.controller.contract.ContractInvoiceWindowController; +import com.ecep.contract.controller.contract.ContractWindowController; +import com.ecep.contract.controller.table.EditableEntityTableTabSkin; +import com.ecep.contract.controller.table.cell.ContractInvoiceTableCell; +import com.ecep.contract.controller.table.cell.EmployeeTableCell; +import com.ecep.contract.controller.table.cell.NumberTableCell; +import com.ecep.contract.model.IdentityEntity; +import com.ecep.contract.service.ContractInvoiceService; +import com.ecep.contract.service.ContractService; +import com.ecep.contract.service.InvoiceService; +import com.ecep.contract.util.FxmlPath; +import com.ecep.contract.util.UITools; +import com.ecep.contract.vm.ContractInvoiceViewModel; +import com.ecep.contract.vo.ContractInvoiceVo; + +import javafx.beans.binding.Bindings; +import javafx.beans.property.SimpleStringProperty; +import javafx.event.ActionEvent; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.Tab; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.TextField; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.control.cell.TextFieldTableCell; +import javafx.scene.layout.Region; +import javafx.util.StringConverter; +import javafx.util.converter.CurrencyStringConverter; + +@FxmlPath("/ui/contract/contract-tab-invoices.fxml") +public class ContractTabSkinInvoices + extends AbstContractTableTabSkin + implements TabSkin, EditableEntityTableTabSkin { + + private Tab tab; + + + public TableColumn idColumn; + public TableColumn codeColumn; + public TableColumn nameColumn; + public TableColumn invoiceColumn; + public TableColumn amountColumn; + public TableColumn remarkColumn; + public TableColumn creatorColumn; + public TableColumn createDateColumn; + public TableColumn updaterColumn; + public TableColumn updateDateColumn; + + public Label totalAmountLabel; + + public ContractTabSkinInvoices(ContractWindowController controller, Tab tab) { + super(controller); + this.tab = tab; + } + + @Override + public Tab getTab() { + return tab; + } + + @Override + protected ContractInvoiceService getViewModelService() { + return getBean(ContractInvoiceService.class); + } + + @Override + public void initializeTable() { + super.initializeTable(); + getTableView().setEditable(true); + + // 初始化列 + idColumn.setCellValueFactory(new PropertyValueFactory<>("id")); + idColumn.setPrefWidth(50); + + codeColumn.setCellValueFactory(new PropertyValueFactory<>("code")); + codeColumn.setPrefWidth(120); + codeColumn.setCellFactory(TextFieldTableCell.forTableColumn()); + + nameColumn.setCellValueFactory(new PropertyValueFactory<>("name")); + nameColumn.setPrefWidth(200); + nameColumn.setCellFactory(TextFieldTableCell.forTableColumn()); + + // 发票列 + invoiceColumn.setCellValueFactory(new PropertyValueFactory<>("invoice")); + invoiceColumn.setPrefWidth(100); + invoiceColumn.setCellFactory(ContractInvoiceTableCell.forTableColumn(getCachedBean(InvoiceService.class))); + + // 金额列 + amountColumn.setCellValueFactory(new PropertyValueFactory<>("amount")); + amountColumn.setPrefWidth(100); + amountColumn.setCellFactory(NumberTableCell.forTableColumn(new CurrencyStringConverter(getLocale()))); + + remarkColumn.setCellValueFactory(new PropertyValueFactory<>("remark")); + remarkColumn.setPrefWidth(150); + remarkColumn.setCellFactory(TextFieldTableCell.forTableColumn()); + + // 创建人列 + creatorColumn.setCellValueFactory(new PropertyValueFactory<>("creator")); + creatorColumn.setPrefWidth(80); + creatorColumn.setCellFactory(EmployeeTableCell.forTableColumn(getEmployeeService())); + + createDateColumn.setCellValueFactory(new PropertyValueFactory<>("createDate")); + createDateColumn.setPrefWidth(120); + + // 更新人列 + updaterColumn.setCellValueFactory(new PropertyValueFactory<>("updater")); + updaterColumn.setPrefWidth(80); + updaterColumn.setCellFactory(EmployeeTableCell.forTableColumn(getEmployeeService())); + + updateDateColumn.setCellValueFactory(new PropertyValueFactory<>("updateDate")); + updateDateColumn.setPrefWidth(120); + } + +} \ 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 66a3765..4575d2f 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 @@ -4,6 +4,8 @@ import java.text.NumberFormat; import java.time.LocalDate; import java.time.LocalDateTime; +import javax.naming.Binding; + import org.springframework.data.domain.Pageable; import com.ecep.contract.ContractPayWay; @@ -28,6 +30,7 @@ import com.ecep.contract.vo.InventoryVo; import com.ecep.contract.vo.PurchaseOrderItemVo; import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; import javafx.scene.control.Tab; @@ -196,6 +199,8 @@ public class ContractTabSkinItemsV2 } showInOwner(InventoryWindowController.class, InventoryViewModel.from(inventory)); }); + showInventory.visibleProperty().bind( + Bindings.select(getTableView().getSelectionModel().selectedItemProperty(), "inventory", "value").isNotNull()); contextMenu.getItems().addAll(showInventory); } diff --git a/client/src/main/java/com/ecep/contract/controller/table/cell/ContractInvoiceTableCell.java b/client/src/main/java/com/ecep/contract/controller/table/cell/ContractInvoiceTableCell.java new file mode 100644 index 0000000..730db38 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/controller/table/cell/ContractInvoiceTableCell.java @@ -0,0 +1,59 @@ +package com.ecep.contract.controller.table.cell; + +import static com.ecep.contract.SpringApp.getBean; + +import com.ecep.contract.service.InvoiceService; +import com.ecep.contract.vo.InvoiceVo; + +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.util.Callback; +import lombok.NoArgsConstructor; + +/** + * 合同发票表格单元格 + * 用于在表格中显示合同发票信息 + */ +@NoArgsConstructor +public class ContractInvoiceTableCell extends AsyncUpdateTableCell { + + /** + * 创建一个ContractInvoiceTableCell的TableCell工厂,自动获取InvoiceService实例 + * + * @param 表格行类型 + * @return TableCell工厂回调 + */ + public static Callback, TableCell> forTableColumn() { + return forTableColumn(getBean(InvoiceService.class)); + } + + /** + * 创建一个ContractInvoiceTableCell的TableCell工厂,使用提供的InvoiceService实例 + * + * @param 表格行类型 + * @param service InvoiceService实例 + * @return TableCell工厂回调 + */ + public static Callback, TableCell> forTableColumn(InvoiceService service) { + return param -> new ContractInvoiceTableCell(service); + } + + /** + * 使用指定的InvoiceService创建ContractInvoiceTableCell + * + * @param invoiceService InvoiceService实例 + */ + public ContractInvoiceTableCell(InvoiceService invoiceService) { + setService(invoiceService); + } + + @Override + protected InvoiceService getServiceBean() { + return getBean(InvoiceService.class); + } + + @Override + public String format(InvoiceVo entity) { + return entity.getCode(); + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/service/ContractInvoiceService.java b/client/src/main/java/com/ecep/contract/service/ContractInvoiceService.java new file mode 100644 index 0000000..83bf4d2 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/service/ContractInvoiceService.java @@ -0,0 +1,67 @@ +package com.ecep.contract.service; + +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.stereotype.Service; + +import com.ecep.contract.vm.ContractInvoiceViewModel; +import com.ecep.contract.vo.ContractInvoiceVo; + +@Service +@CacheConfig(cacheNames = "contract-invoice") +public class ContractInvoiceService extends QueryService { + + @Cacheable(key = "#p0") + @Override + public ContractInvoiceVo findById(Integer id) { + return super.findById(id); + } + + @Caching(evict = { + @CacheEvict(key = "#p0.id"), + @CacheEvict(key = "'code-'+#p0.code") + }) + public ContractInvoiceVo save(ContractInvoiceVo invoice) { + return super.save(invoice); + } + + @Caching(evict = { + @CacheEvict(key = "#p0.id"), + @CacheEvict(key = "'code-'+#p0.code") + }) + public void delete(ContractInvoiceVo invoice) { + super.delete(invoice); + } + + @Cacheable(key = "'code-'+#p0") + public ContractInvoiceVo findByCode(String code) { + try { + return async("findByCode", code, String.class).handle((response, ex) -> { + if (ex != null) { + throw new RuntimeException("远程方法+findByCode+调用失败", ex); + } + if (response != null) { + return updateValue(createNewEntity(), response); + } + return null; + }).get(); + } catch (Exception e) { + throw new RuntimeException("查找合同发票 " + code + " 时发生错误", e); + } + } + + public ContractInvoiceVo findByContractId(Integer contractId) { + try { + return async("findByContractId", contractId, Integer.class).handle((response, ex) -> { + if (response != null) { + return updateValue(createNewEntity(), response); + } + return null; + }).get(); + } catch (Exception e) { + throw new RuntimeException("查找合同ID为 " + contractId + " 的发票时发生错误", e); + } + } +} \ No newline at end of file diff --git a/client/src/main/java/com/ecep/contract/service/EmployeeService.java b/client/src/main/java/com/ecep/contract/service/EmployeeService.java index d4f5aa8..5ab33f7 100644 --- a/client/src/main/java/com/ecep/contract/service/EmployeeService.java +++ b/client/src/main/java/com/ecep/contract/service/EmployeeService.java @@ -10,7 +10,6 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; -import com.ecep.contract.model.EmployeeRole; import com.ecep.contract.vm.EmployeeViewModel; import com.ecep.contract.vo.EmployeeRoleVo; import com.ecep.contract.vo.EmployeeVo; diff --git a/client/src/main/java/com/ecep/contract/vm/ContractInvoiceViewModel.java b/client/src/main/java/com/ecep/contract/vm/ContractInvoiceViewModel.java new file mode 100644 index 0000000..0f33a68 --- /dev/null +++ b/client/src/main/java/com/ecep/contract/vm/ContractInvoiceViewModel.java @@ -0,0 +1,119 @@ +package com.ecep.contract.vm; + +import java.time.LocalDate; +import java.util.Objects; + +import com.ecep.contract.util.NumberUtils; +import com.ecep.contract.vo.ContractInvoiceVo; + +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ContractInvoiceViewModel extends IdentityViewModel { + private final SimpleStringProperty code = new SimpleStringProperty(); + private final SimpleStringProperty name = new SimpleStringProperty(); + /** + * 关联的合同对象, Contract + */ + private final SimpleObjectProperty contract = new SimpleObjectProperty<>(); + /** + * 关联的发票对象, Invoice + */ + private final SimpleObjectProperty invoice = new SimpleObjectProperty<>(); + /** + * 发票金额 + */ + private final SimpleObjectProperty amount = new SimpleObjectProperty<>(); + /** + * 备注 + */ + private final SimpleStringProperty remark = new SimpleStringProperty(); + private final SimpleObjectProperty createDate = new SimpleObjectProperty<>(); + private final SimpleObjectProperty updateDate = new SimpleObjectProperty<>(); + private final SimpleObjectProperty creator = new SimpleObjectProperty<>(); + private final SimpleObjectProperty updater = new SimpleObjectProperty<>(); + + @Override + protected void updateFrom(ContractInvoiceVo v) { + super.updateFrom(v); + code.set(v.getCode()); + name.set(v.getName()); + contract.set(v.getContractId()); + invoice.set(v.getInvoiceId()); + amount.set(v.getAmount() != null ? v.getAmount() : 0.0); + remark.set(v.getRemark()); + + updateDate.set(v.getUpdateDate()); + creator.set(v.getSetupPersonId()); + updater.set(v.getUpdatePersonId()); + } + + @Override + public boolean copyTo(ContractInvoiceVo v) { + boolean modified = super.copyTo(v); + + if (!Objects.equals(code.get(), v.getCode())) { + v.setCode(code.get()); + modified = true; + } + + if (!Objects.equals(name.get(), v.getName())) { + v.setName(name.get()); + modified = true; + } + + if (!Objects.equals(contract.get(), v.getContractId())) { + v.setContractId(contract.get()); + modified = true; + } + + if (!Objects.equals(invoice.get(), v.getInvoiceId())) { + v.setInvoiceId(invoice.get()); + modified = true; + } + + if (!NumberUtils.equals(amount.get(), v.getAmount())) { + v.setAmount(amount.get()); + modified = true; + } + + if (!Objects.equals(remark.get(), v.getRemark())) { + v.setRemark(remark.get()); + modified = true; + } + if (!Objects.equals(creator.get(), v.getSetupPersonId())) { + v.setSetupPersonId(creator.get()); + modified = true; + } + if (!Objects.equals(updater.get(), v.getUpdatePersonId())) { + v.setUpdatePersonId(updater.get()); + modified = true; + } + if (!Objects.equals(createDate.get(), v.getSetupDate())) { + v.setSetupDate(createDate.get()); + modified = true; + } + if (!Objects.equals(updateDate.get(), v.getUpdateDate())) { + v.setUpdateDate(updateDate.get()); + modified = true; + } + + return modified; + } + + /** + * 从VO对象创建ViewModel实例 + * + * @param vo 发票VO对象 + * @return 发票ViewModel实例 + */ + public static ContractInvoiceViewModel from(ContractInvoiceVo vo) { + ContractInvoiceViewModel viewModel = new ContractInvoiceViewModel(); + viewModel.updateFrom(vo); + return viewModel; + } +} \ No newline at end of file diff --git a/client/src/main/resources/ui/contract/contract-invoice-manager.fxml b/client/src/main/resources/ui/contract/contract-invoice-manager.fxml new file mode 100644 index 0000000..811b0a7 --- /dev/null +++ b/client/src/main/resources/ui/contract/contract-invoice-manager.fxml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + +