feat(project): 新增项目资金计划功能 #2

添加项目资金计划模块,包括以下内容:
- 新增项目资金计划实体类及相关数据库表结构
- 实现资金计划Repository和服务层
- 添加资金计划Tab页及FXML界面
- 实现从合同付款计划同步资金计划功能
- 添加资金计划表格展示及更新操作
This commit is contained in:
2025-08-28 19:54:20 +08:00
parent 1514cb0f9f
commit cca51c6fcc
12 changed files with 716 additions and 36 deletions

View File

@@ -0,0 +1,53 @@
-- 项目资金计划表结构
CREATE TABLE `PROJECT_FUND_PLAN` (
`ID` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`PROJECT_ID` int DEFAULT NULL COMMENT '项目ID',
`PAY_DATE` date DEFAULT NULL COMMENT '付款日期',
`PAY_WAY` int DEFAULT NULL COMMENT '付款方式',
`PAY_RATIO` float DEFAULT NULL COMMENT '付款比例',
`PAY_CURRENCY` double DEFAULT NULL COMMENT '付款金额',
`PAY_TERM` varchar(255) DEFAULT NULL COMMENT '付款条件',
`CONTRACT_PAY_PLAN_ID` int DEFAULT NULL COMMENT '合同付款计划ID',
`UPDATE_TIME` datetime DEFAULT NULL COMMENT '更新日期',
PRIMARY KEY (`ID`),
KEY `FK_PROJECT_FUND_PLAN_PROJECT` (`PROJECT_ID`),
KEY `FK_PROJECT_FUND_PLAN_CONTRACT_PAY_PLAN` (`CONTRACT_PAY_PLAN_ID`),
CONSTRAINT `FK_PROJECT_FUND_PLAN_PROJECT` FOREIGN KEY (`PROJECT_ID`) REFERENCES `PROJECT` (`ID`),
CONSTRAINT `FK_PROJECT_FUND_PLAN_CONTRACT_PAY_PLAN` FOREIGN KEY (`CONTRACT_PAY_PLAN_ID`) REFERENCES `CONTRACT_PAY_PLAN` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='项目资金计划';
/** Alert 增加 PAY_WAY **/
ALTER TABLE `PROJECT_FUND_PLAN`
ADD COLUMN `PAY_WAY` int DEFAULT NULL COMMENT '付款方式';
-- 项目投标表结构 (参考)
CREATE TABLE `PROJECT_BID` (
`ID` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`PROJECT_ID` int DEFAULT NULL COMMENT '项目ID',
`LEVEL` int NOT NULL COMMENT '客户资信等级',
`AMOUNT` double DEFAULT NULL COMMENT '报价金额',
`CUS_EVAL_FILE_ID` int DEFAULT NULL COMMENT '评价表单文件ID',
`COST_ID` int DEFAULT NULL COMMENT '成本ID',
`STANDARD_PAY_WAY` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否标准付款方式',
`NO_STANDARD_PAY_WAY_TEXT` varchar(255) DEFAULT NULL COMMENT '非标准付款方式文本',
`STANDARD_CONTRACT_TEXT` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否标准合同文本',
`NO_STANDARD_CONTRACT_TEXT` varchar(255) DEFAULT NULL COMMENT '非标准合同文本',
`AUTHORIZER_FILE` varchar(255) DEFAULT NULL COMMENT '审核文件',
`BID_ACCEPTANCE_LETTER_FILE` varchar(255) DEFAULT NULL COMMENT '中标通知书文件',
`APPLICANT_ID` int DEFAULT NULL COMMENT '申请人ID',
`APPLY_DATE` datetime DEFAULT NULL COMMENT '申请日期',
`AUTHORIZER_ID` int DEFAULT NULL COMMENT '审核人ID',
`AUTHORIZER_DATE` datetime DEFAULT NULL COMMENT '审核时间',
`DESCRIPTION` text COMMENT '说明',
PRIMARY KEY (`ID`),
KEY `FK_PROJECT_BID_PROJECT` (`PROJECT_ID`),
KEY `FK_PROJECT_BID_CUS_EVAL_FILE` (`CUS_EVAL_FILE_ID`),
KEY `FK_PROJECT_BID_COST` (`COST_ID`),
KEY `FK_PROJECT_BID_APPLICANT` (`APPLICANT_ID`),
KEY `FK_PROJECT_BID_AUTHORIZER` (`AUTHORIZER_ID`),
CONSTRAINT `FK_PROJECT_BID_PROJECT` FOREIGN KEY (`PROJECT_ID`) REFERENCES `PROJECT` (`ID`),
CONSTRAINT `FK_PROJECT_BID_CUS_EVAL_FILE` FOREIGN KEY (`CUS_EVAL_FILE_ID`) REFERENCES `COMPANY_CUSTOMER_EVALUATION_FORM_FILE` (`ID`),
CONSTRAINT `FK_PROJECT_BID_COST` FOREIGN KEY (`COST_ID`) REFERENCES `PROJECT_COST` (`ID`),
CONSTRAINT `FK_PROJECT_BID_APPLICANT` FOREIGN KEY (`APPLICANT_ID`) REFERENCES `EMPLOYEE` (`ID`),
CONSTRAINT `FK_PROJECT_BID_AUTHORIZER` FOREIGN KEY (`AUTHORIZER_ID`) REFERENCES `EMPLOYEE` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='项目投标';

View File

@@ -1,15 +1,10 @@
package com.ecep.contract.manager.cloud.tyc; package com.ecep.contract.manager.cloud.tyc;
import com.ecep.contract.manager.SpringApp; import java.time.Instant;
import com.ecep.contract.manager.cloud.CloudInfo; import java.util.List;
import com.ecep.contract.manager.ds.company.model.Company; import java.util.Optional;
import com.ecep.contract.manager.ds.other.repository.SysConfRepository; import java.util.stream.Collectors;
import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.MyStringUtils;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Platform;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -21,10 +16,16 @@ import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.time.Instant; import com.ecep.contract.manager.SpringApp;
import java.util.List; import com.ecep.contract.manager.cloud.CloudInfo;
import java.util.Optional; import com.ecep.contract.manager.ds.company.model.Company;
import java.util.stream.Collectors; import com.ecep.contract.manager.ds.other.service.SysConfService;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.ViewModelService;
import com.ecep.contract.manager.util.MyStringUtils;
import com.ecep.contract.manager.util.UITools;
import javafx.application.Platform;
@Lazy @Lazy
@Service @Service

View File

@@ -1,35 +1,33 @@
package com.ecep.contract.manager.ds.project.controller; package com.ecep.contract.manager.ds.project.controller;
import com.ecep.contract.manager.SpringApp; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import com.ecep.contract.manager.ds.company.CompanyStringConverter; import com.ecep.contract.manager.ds.company.CompanyStringConverter;
import com.ecep.contract.manager.ds.company.service.CompanyService; import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEvaluationFormFile; import com.ecep.contract.manager.ds.customer.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.manager.ds.customer.model.CompanyCustomerFile;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerFileService; import com.ecep.contract.manager.ds.customer.service.CompanyCustomerFileService;
import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService; import com.ecep.contract.manager.ds.customer.service.CompanyCustomerService;
import com.ecep.contract.manager.ds.other.EmployeeStringConverter; import com.ecep.contract.manager.ds.other.EmployeeStringConverter;
import com.ecep.contract.manager.ui.table.cell.EmployeeTableCell;
import com.ecep.contract.manager.ds.other.model.Employee; import com.ecep.contract.manager.ds.other.model.Employee;
import com.ecep.contract.manager.ds.project.controller.bid.ProjectBidWindowController; import com.ecep.contract.manager.ds.project.controller.bid.ProjectBidWindowController;
import com.ecep.contract.manager.ds.project.model.Project; import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectBid; import com.ecep.contract.manager.ds.project.model.ProjectBid;
import com.ecep.contract.manager.ds.project.service.ProjectBidService; import com.ecep.contract.manager.ds.project.service.ProjectBidService;
import com.ecep.contract.manager.ds.project.vo.ProjectBidViewModel; import com.ecep.contract.manager.ds.project.vo.ProjectBidViewModel;
import com.ecep.contract.manager.ui.*; import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.ui.RefreshableSkin;
import com.ecep.contract.manager.ui.tab.TabSkin; import com.ecep.contract.manager.ui.tab.TabSkin;
import com.ecep.contract.manager.ui.table.EditableEntityTableTabSkin; import com.ecep.contract.manager.ui.table.EditableEntityTableTabSkin;
import javafx.scene.control.*; import com.ecep.contract.manager.ui.table.cell.EmployeeTableCell;
import javafx.scene.control.Tab;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.converter.LocalDateStringConverter; import javafx.util.converter.LocalDateStringConverter;
import lombok.Setter; import lombok.Setter;
import org.hibernate.Hibernate;
import org.springframework.util.StringUtils;
import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CompletableFuture;
@FxmlPath("/ui/project/project-tab-bid.fxml") @FxmlPath("/ui/project/project-tab-bid.fxml")
public class ProjectTabSkinBid public class ProjectTabSkinBid

View File

@@ -0,0 +1,255 @@
package com.ecep.contract.manager.ds.project.controller;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ds.contract.model.ContractPayPlan;
import com.ecep.contract.manager.ds.contract.service.ContractPayPlanService;
import com.ecep.contract.manager.ds.contract.service.ContractService;
import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectFundPlan;
import com.ecep.contract.manager.ds.project.service.ProjectFundPlanService;
import com.ecep.contract.manager.ds.project.vo.ProjectFundPlanViewModel;
import com.ecep.contract.manager.ui.FxmlPath;
import com.ecep.contract.manager.ui.RefreshableSkin;
import com.ecep.contract.manager.ui.tab.TabSkin;
import com.ecep.contract.manager.ui.table.EditableEntityTableTabSkin;
import com.ecep.contract.manager.util.NumberUtils;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TableColumn;
import lombok.Setter;
/**
* 项目资金计划
* 工单 #2
* fxml 文件在 /src/main/resources/ui/ 目录
*/
@FxmlPath("/ui/project/project-tab-fund-plan.fxml")
public class ProjectTabSkinFundPlan
extends AbstProjectTableTabSkin<ProjectFundPlan, ProjectFundPlanViewModel>
implements TabSkin, EditableEntityTableTabSkin<ProjectFundPlan, ProjectFundPlanViewModel>, RefreshableSkin {
private static final Logger logger = LoggerFactory.getLogger(ProjectTabSkinFundPlan.class);
public TableColumn<ProjectFundPlanViewModel, Number> idColumn;
public TableColumn<ProjectFundPlanViewModel, Number> versionColumn;
public TableColumn<ProjectFundPlanViewModel, LocalDate> payDateColumn;
public TableColumn<ProjectFundPlanViewModel, Number> payRatioColumn;
public TableColumn<ProjectFundPlanViewModel, Number> payCurrencyColumn;
public TableColumn<ProjectFundPlanViewModel, String> payTermColumn;
public TableColumn<ProjectFundPlanViewModel, LocalDateTime> updateDateColumn;
public TableColumn<ProjectFundPlanViewModel, String> payWayColumn;
public Button updatePlanBtn;
@Setter
private ProjectFundPlanService projectFundPlanService;
public ProjectTabSkinFundPlan(ProjectWindowController controller) {
super(controller);
}
@Override
protected ProjectFundPlanService getViewModelService() {
if (projectFundPlanService == null) {
projectFundPlanService = getBean(ProjectFundPlanService.class);
}
return projectFundPlanService;
}
public ContractPayPlanService getContractPayPlanService() {
return controller.getCachedBean(ContractPayPlanService.class);
}
private ContractService getContractService() {
return controller.getCachedBean(ContractService.class);
}
@Override
public Tab getTab() {
return controller.fundPlanTab;
}
@Override
public void initializeTable() {
super.initializeTable();
// 关闭所有的排序功能
idColumn.setSortable(false);
versionColumn.setSortable(false);
payDateColumn.setSortable(false);
payRatioColumn.setSortable(false);
payCurrencyColumn.setSortable(false);
payTermColumn.setSortable(false);
updateDateColumn.setSortable(false);
payWayColumn.setSortable(false);
bindNumberColumn(idColumn, ProjectFundPlanViewModel::getId);
bindLocalDateColumn(payDateColumn, ProjectFundPlanViewModel::getPayDate);
bindColumn(payWayColumn, model -> {
javafx.beans.property.SimpleStringProperty property = new javafx.beans.property.SimpleStringProperty();
property.set(model.getPayWay().get() != null ? model.getPayWay().get().getText() : "");
return property;
});
bindNumberColumn(payRatioColumn, ProjectFundPlanViewModel::getPayRatio);
bindNumberColumn(payCurrencyColumn, ProjectFundPlanViewModel::getPayCurrency);
bindColumn(payTermColumn, ProjectFundPlanViewModel::getPayTerm);
bindLocalDateTimeColumn(updateDateColumn, ProjectFundPlanViewModel::getUpdateDate);
updatePlanBtn.setOnAction(this::onUpdatePlanAction);
}
@Override
public List<ProjectFundPlanViewModel> loadTableData(Project parent) {
List<ProjectFundPlanViewModel> rows = super.loadTableData(parent);
if (rows == null) {
return null;
}
// TODO 按付款日期排序
// rows.stream().sorted(Comparator.comparing(ProjectFundPlanViewModel::getPayDate)).collect(Collectors.toList());
return rows;
}
/**
* 从合同的付款计划中更新项目的资金计划
* 1. 从项目相关的合同中获取付款计划
* 2. 更新项目的资金计划
*/
private void onUpdatePlanAction(ActionEvent event) {
try {
// 获取当前项目
Project project = getParent();
if (project == null || project.getId() == null) {
setStatus("提示, 无法获取项目信息");
return;
}
List<ProjectFundPlan> fundPlans = getViewModelService().findAllByProject(project);
// 将现有的项目资金计划转为以 ContractPayPlan 的id为key的map
java.util.Map<Number, ProjectFundPlan> fundPlansMap = fundPlans.stream()
.filter(plan -> plan.getContractPayPlan() != null && plan.getContractPayPlan().getId() != null)
.collect(Collectors.toMap(
plan -> plan.getContractPayPlan().getId(),
plan -> plan));
// 获取项目关联的所有合同
List<Contract> contracts = getContractService().findAllByProject(project);
if (contracts == null || contracts.isEmpty()) {
setStatus("提示, 未找到与项目关联的合同");
return;
}
// 遍历所有合同
for (Contract contract : contracts) {
// 获取合同的付款计划
List<ContractPayPlan> payPlans = getContractPayPlanService().findAllByContract(contract);
// 遍历每个付款计划
for (ContractPayPlan payPlan : payPlans) {
// 检查是否已存在相同的合同付款计划
if (fundPlansMap.containsKey(payPlan.getId())) {
// 更新
ProjectFundPlan fundPlan = fundPlansMap.remove(payPlan.getId());
// 检查是否需要更新
boolean needsUpdate = false;
if (!Objects.equals(fundPlan.getPayWay(), contract.getPayWay())) {
fundPlan.setPayWay(contract.getPayWay());
needsUpdate = true;
}
if (!Objects.equals(fundPlan.getPayDate(), payPlan.getPayDate())) {
fundPlan.setPayDate(payPlan.getPayDate());
needsUpdate = true;
}
if (!NumberUtils.equals(fundPlan.getPayRatio(), payPlan.getPayRatio())) {
fundPlan.setPayRatio(payPlan.getPayRatio());
needsUpdate = true;
}
if (!Objects.equals(fundPlan.getPayTerm(), payPlan.getPayTerm())) {
fundPlan.setPayTerm(payPlan.getPayTerm());
needsUpdate = true;
}
if (!NumberUtils.equals(fundPlan.getPayCurrency(), payPlan.getPayCurrency())) {
fundPlan.setPayCurrency(payPlan.getPayCurrency());
needsUpdate = true;
}
if (needsUpdate) {
fundPlan.setContractPayPlan(payPlan);
fundPlan.setUpdateDate(LocalDateTime.now());
saveRowData(fundPlan);
}
continue;
}
// 创建新的项目资金计划
ProjectFundPlan fundPlan = getViewModelService().newInstanceByProject(project);
// 设置资金计划的属性
fundPlan.setPayDate(payPlan.getPayDate());
fundPlan.setPayWay(contract.getPayWay());
fundPlan.setPayRatio(payPlan.getPayRatio());
fundPlan.setPayTerm(payPlan.getPayTerm());
fundPlan.setPayCurrency(payPlan.getPayCurrency());
fundPlan.setContractPayPlan(payPlan);
fundPlan.setUpdateDate(LocalDateTime.now());
saveRowData(fundPlan);
}
}
// 删除
if (!fundPlansMap.isEmpty()) {
for (ProjectFundPlan fundPlan : fundPlansMap.values()) {
getViewModelService().delete(fundPlan);
}
}
// 刷新表格数据
refresh();
} catch (Exception e) {
logger.error("更新项目资金计划失败", e);
}
}
@Override
protected ProjectFundPlanViewModel createNewViewModel() {
ProjectFundPlanViewModel model = new ProjectFundPlanViewModel();
Project project = getParent();
model.getProject().set(project);
model.getUpdateDate().set(LocalDateTime.now());
saveRow(model);
return model;
}
@Override
protected void onTableRowDoubleClickedAction(ProjectFundPlanViewModel item) {
// 可以在这里实现双击打开详情窗口的逻辑
// 目前暂不实现具体的窗口
}
private ProjectFundPlanService getProjectFundPlanService() {
if (projectFundPlanService == null) {
projectFundPlanService = getBean(ProjectFundPlanService.class);
}
return projectFundPlanService;
}
@Override
public void deleteRowData(ProjectFundPlan entity) {
getProjectFundPlanService().delete(entity);
}
@Override
public ProjectFundPlan loadRowData(ProjectFundPlanViewModel row) {
return getProjectFundPlanService().findById(row.getId().get());
}
@Override
public ProjectFundPlan saveRowData(ProjectFundPlan entity) {
return getProjectFundPlanService().save(entity);
}
}

View File

@@ -108,6 +108,13 @@ public class ProjectWindowController extends AbstEntityController<Project, Proje
* 投标 Bid Tab * 投标 Bid Tab
*/ */
public Tab bidTab; public Tab bidTab;
/**
* 资金计划 Tab
*/
public Tab fundPlanTab;
/**
* 顾客满意度 Tab
*/
public Tab satisfactionTab; public Tab satisfactionTab;
@Autowired @Autowired
@@ -144,6 +151,7 @@ public class ProjectWindowController extends AbstEntityController<Project, Proje
registerTabSkin(costTab, tab -> new ProjectTabSkinCost(this)); registerTabSkin(costTab, tab -> new ProjectTabSkinCost(this));
registerTabSkin(quotationApprovalTab, tab -> new ProjectTabSkinQuotation(this)); registerTabSkin(quotationApprovalTab, tab -> new ProjectTabSkinQuotation(this));
registerTabSkin(bidTab, tab -> new ProjectTabSkinBid(this)); registerTabSkin(bidTab, tab -> new ProjectTabSkinBid(this));
registerTabSkin(fundPlanTab, tab -> new ProjectTabSkinFundPlan(this));
// registerTabSkin(costItemTab, this::createCostItemTabSkin); // registerTabSkin(costItemTab, this::createCostItemTabSkin);
registerTabSkin(satisfactionTab, tab -> new ProjectTabSkinCustomerSatisfactionSurvey(this)); registerTabSkin(satisfactionTab, tab -> new ProjectTabSkinCustomerSatisfactionSurvey(this));
} }

View File

@@ -0,0 +1,81 @@
package com.ecep.contract.manager.ds.project.model;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.ecep.contract.manager.ds.contract.ContractPayWay;
import com.ecep.contract.manager.ds.contract.model.ContractPayPlan;
import com.ecep.contract.manager.ds.other.model.IdentityEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 项目投标
* <p>
* Approval 审批
*/
@Getter
@Setter
@Entity
@Table(name = "PROJECT_FUND_PLAN")
@ToString
public class ProjectFundPlan implements IdentityEntity, ProjectBasedEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false)
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PROJECT_ID")
private Project project;
/**
* 付款日期
*/
@Column(name = "PAY_DATE")
private LocalDate payDate;
/**
* 付款方式
*/
@Column(name = "PAY_WAY")
@Enumerated(EnumType.ORDINAL)
private ContractPayWay payWay;
/**
* 付款比例
*/
@Column(name = "PAY_RATIO")
private float payRatio;
/**
* 付款金额
*/
@Column(name = "PAY_CURRENCY")
private double payCurrency;
/**
* 付款条件
*/
@Column(name = "PAY_TERM")
private String payTerm;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CONTRACT_PAY_PLAN_ID")
private ContractPayPlan contractPayPlan;
/**
* 更新日期,从销售合同和采购合同中更新
*/
@Column(name = "UPDATE_TIME")
private LocalDateTime updateDate;
}

View File

@@ -1,16 +1,15 @@
package com.ecep.contract.manager.ds.project.repository; package com.ecep.contract.manager.ds.project.repository;
import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectBid;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
import org.springframework.stereotype.Repository;
import com.ecep.contract.manager.ds.MyRepository;
import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectBid;
@Repository @Repository
public interface ProjectBidRepository public interface ProjectBidRepository extends MyRepository<ProjectBid, Integer> {
extends JpaRepository<ProjectBid, Integer>, JpaSpecificationExecutor<ProjectBid> {
/** /**
* 根据项目查询 * 根据项目查询

View File

@@ -0,0 +1,20 @@
package com.ecep.contract.manager.ds.project.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.ecep.contract.manager.ds.MyRepository;
import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectFundPlan;
@Repository
public interface ProjectFundPlanRepository extends MyRepository<ProjectFundPlan, Integer> {
/**
* 根据项目查询
*
* @param project 项目
* @return ProjectFundPlan list
*/
List<ProjectFundPlan> findAllByProject(Project project);
}

View File

@@ -0,0 +1,72 @@
package com.ecep.contract.manager.ds.project.service;
import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectFundPlan;
import com.ecep.contract.manager.ds.project.repository.ProjectFundPlanRepository;
import com.ecep.contract.manager.ds.project.vo.ProjectFundPlanViewModel;
import com.ecep.contract.manager.ui.ViewModelService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Lazy
@Service
public class ProjectFundPlanService implements ViewModelService<ProjectFundPlan, ProjectFundPlanViewModel> {
private static final Logger logger = LoggerFactory.getLogger(ProjectFundPlanService.class);
@Lazy
@Autowired
private ProjectFundPlanRepository repository;
public ProjectFundPlan findById(Integer id) {
return repository.findById(id).orElse(null);
}
@Override
public Page<ProjectFundPlan> findAll(Specification<ProjectFundPlan> spec, Pageable pageable) {
return repository.findAll(spec, pageable);
}
public List<ProjectFundPlan> findAllByProject(Project project) {
return repository.findAllByProject(project);
}
public ProjectFundPlan save(ProjectFundPlan fundPlan) {
return repository.save(fundPlan);
}
@Override
public Specification<ProjectFundPlan> getSpecification(String searchText) {
return (root, query, builder) -> {
return builder.or(
builder.like(root.get("payTerm"), "%" + searchText + "%"),
builder.like(builder.toString(root.get("payRatio")), "%" + searchText + "%"),
builder.like(builder.toString(root.get("payCurrency")), "%" + searchText + "%")
);
};
}
public void delete(ProjectFundPlan fundPlan) {
repository.delete(fundPlan);
}
public ProjectFundPlan newInstanceByProject(Project project) {
ProjectFundPlan fundPlan = new ProjectFundPlan();
fundPlan.setProject(project);
fundPlan.setUpdateDate(LocalDateTime.now());
return fundPlan;
}
public List<ProjectFundPlan> findAll(Specification<ProjectFundPlan> spec, Sort sort) {
return repository.findAll(spec, sort);
}
}

View File

@@ -0,0 +1,154 @@
package com.ecep.contract.manager.ds.project.vo;
import com.ecep.contract.manager.ds.contract.ContractPayWay;
import com.ecep.contract.manager.ds.contract.model.ContractPayPlan;
import com.ecep.contract.manager.ds.other.vo.IdentityViewModel;
import com.ecep.contract.manager.ds.project.model.Project;
import com.ecep.contract.manager.ds.project.model.ProjectFundPlan;
import com.ecep.contract.manager.util.NumberUtils;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 项目资金计划视图模型
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectFundPlanViewModel extends IdentityViewModel<ProjectFundPlan> implements ProjectBasedViewModel {
/**
* 关联的项目
*/
private SimpleObjectProperty<Project> project = new SimpleObjectProperty<>();
/**
* 付款日期
*/
private SimpleObjectProperty<LocalDate> payDate = new SimpleObjectProperty<>();
/**
* 付款比例
*/
private SimpleFloatProperty payRatio = new SimpleFloatProperty();
/**
* 付款金额
*/
private SimpleDoubleProperty payCurrency = new SimpleDoubleProperty();
/**
* 余额
*/
private SimpleDoubleProperty balance = new SimpleDoubleProperty();
/**
* 付款条件
*/
private SimpleStringProperty payTerm = new SimpleStringProperty();
/**
* 合同付款计划
*/
private SimpleObjectProperty<ContractPayPlan> contractPayPlan = new SimpleObjectProperty<>();
/**
* 更新日期
*/
private SimpleObjectProperty<LocalDateTime> updateDate = new SimpleObjectProperty<>();
/**
* 付款方式
*/
private SimpleObjectProperty<ContractPayWay> payWay = new SimpleObjectProperty<>();
/**
* 从实体对象创建视图模型
*/
public static ProjectFundPlanViewModel from(ProjectFundPlan entity) {
ProjectFundPlanViewModel model = new ProjectFundPlanViewModel();
model.update(entity);
return model;
}
@Override
protected void updateFrom(ProjectFundPlan entity) {
super.updateFrom(entity);
// 设置项目关联
getProject().set(entity.getProject());
// 设置付款相关信息
getPayDate().set(entity.getPayDate());
getPayRatio().set(entity.getPayRatio());
getPayCurrency().set(entity.getPayCurrency());
getPayTerm().set(entity.getPayTerm());
// 设置合同付款计划关联
getContractPayPlan().set(entity.getContractPayPlan());
// 设置更新日期
getUpdateDate().set(entity.getUpdateDate());
// 设置付款方式
getPayWay().set(entity.getPayWay());
}
@Override
public boolean copyTo(ProjectFundPlan entity) {
boolean modified = super.copyTo(entity);
// 复制项目关联
if (!Objects.equals(getProject().get(), entity.getProject())) {
entity.setProject(getProject().get());
modified = true;
}
// 复制付款相关信息
if (!Objects.equals(getPayDate().get(), entity.getPayDate())) {
entity.setPayDate(getPayDate().get());
modified = true;
}
if (!NumberUtils.equals(getPayRatio().get(), entity.getPayRatio())) {
entity.setPayRatio(getPayRatio().get());
modified = true;
}
if (!NumberUtils.equals(getPayCurrency().get(), entity.getPayCurrency())) {
entity.setPayCurrency(getPayCurrency().get());
modified = true;
}
if (!Objects.equals(getPayTerm().get(), entity.getPayTerm())) {
entity.setPayTerm(getPayTerm().get());
modified = true;
}
// 复制合同付款计划关联
if (!Objects.equals(getContractPayPlan().get(), entity.getContractPayPlan())) {
entity.setContractPayPlan(getContractPayPlan().get());
modified = true;
}
// 复制更新日期
if (!Objects.equals(getUpdateDate().get(), entity.getUpdateDate())) {
entity.setUpdateDate(getUpdateDate().get());
modified = true;
}
// 复制付款方式
if (!Objects.equals(getPayWay().get(), entity.getPayWay())) {
entity.setPayWay(getPayWay().get());
modified = true;
}
return modified;
}
}

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.ds.project.controller.ProjectTabSkinFundPlan">
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox spacing="3.0">
<children>
<TextField fx:id="searchKeyField" promptText="检索关键字"/>
<Button fx:id="searchBtn" mnemonicParsing="false" text="检索"/>
<Separator orientation="VERTICAL"/>
<Button fx:id="updatePlanBtn" mnemonicParsing="false" text="更新"/>
</children>
<padding>
<Insets bottom="10.0" left="7.0" right="10.0" top="10.0"/>
</padding>
</HBox>
<TableView fx:id="table" VBox.vgrow="ALWAYS" sortable="false">
<columns>
<TableColumn fx:id="idColumn" prefWidth="60.0" sortable="true" text="ID"/>
<TableColumn fx:id="payDateColumn" prefWidth="120.0" sortable="true" text="付款日期"/>
<TableColumn fx:id="payWayColumn" prefWidth="120.0" sortable="true" text="付款方式"/>
<TableColumn fx:id="payCurrencyColumn" prefWidth="120.0" sortable="true" text="付款金额"/>
<TableColumn fx:id="payRatioColumn" prefWidth="100.0" sortable="true" text="付款比例"/>
<TableColumn fx:id="payTermColumn" prefWidth="200.0" sortable="true" text="付款条件"/>
<TableColumn fx:id="updateDateColumn" prefWidth="180.0" sortable="true" text="更新日期"/>
</columns>
</TableView>
</children>
</VBox>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
</AnchorPane>

View File

@@ -191,6 +191,8 @@
</Tab> </Tab>
<Tab fx:id="contractTab" text="相关合同"> <Tab fx:id="contractTab" text="相关合同">
</Tab> </Tab>
<Tab fx:id="fundPlanTab" text="资金计划">
</Tab>
<Tab fx:id="satisfactionTab" text="顾客满意度"> <Tab fx:id="satisfactionTab" text="顾客满意度">
</Tab> </Tab>
<Tab text="发货"> <Tab text="发货">