diff --git a/src/main/java/cn/palmte/work/controller/backend/ProcessController.java b/src/main/java/cn/palmte/work/controller/backend/ProcessController.java index 7da5c09..4ce8d31 100644 --- a/src/main/java/cn/palmte/work/controller/backend/ProcessController.java +++ b/src/main/java/cn/palmte/work/controller/backend/ProcessController.java @@ -1,9 +1,12 @@ package cn.palmte.work.controller.backend; +import org.springframework.beans.BeanUtils; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Controller; +import org.springframework.transaction.annotation.Transactional; import org.springframework.ui.Model; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -23,6 +26,9 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import javax.persistence.EntityManager; +import javax.validation.Valid; + import cn.palmte.work.model.Admin; import cn.palmte.work.model.DeptRepository; import cn.palmte.work.model.Project; @@ -30,12 +36,16 @@ import cn.palmte.work.model.ProjectBudgetIncomeDetail; import cn.palmte.work.model.ProjectRepository; import cn.palmte.work.model.enums.CooperationType; import cn.palmte.work.model.enums.Enumerable; -import cn.palmte.work.model.enums.ProcessStatus; import cn.palmte.work.model.enums.ProjectType; import cn.palmte.work.model.enums.SealType; +import cn.palmte.work.model.process.SaleContractProcess; +import cn.palmte.work.model.process.SealTypeArray; +import cn.palmte.work.model.process.form.SaleContractDetailForm; +import cn.palmte.work.model.process.form.SaleContractProcessForm; import cn.palmte.work.service.ProjectBudgetService; import cn.palmte.work.utils.InterfaceUtil; import lombok.Builder; +import lombok.RequiredArgsConstructor; import lombok.Setter; /** @@ -43,6 +53,7 @@ import lombok.Setter; * @since 1.0 2022/12/8 11:03 */ @Controller +@RequiredArgsConstructor @RequestMapping("/process") public class ProcessController { static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @@ -52,13 +63,7 @@ public class ProcessController { private final ProjectBudgetService projectBudgetService; private final JdbcTemplate jdbcTemplate; - - public ProcessController(ProjectRepository projectRepository, DeptRepository deptRepository, ProjectBudgetService projectBudgetService, JdbcTemplate jdbcTemplate) { - this.projectRepository = projectRepository; - this.deptRepository = deptRepository; - this.projectBudgetService = projectBudgetService; - this.jdbcTemplate = jdbcTemplate; - } + private final EntityManager entityManager; static class FormMetadata { // 部门 @@ -139,6 +144,8 @@ public class ProcessController { // 合同金额 public BigDecimal contractAmount; + public List incomeDetails; + // FIXME 垫资 // 是否垫资 public final String isPrepaid = "是"; @@ -157,9 +164,10 @@ public class ProcessController { Admin admin = InterfaceUtil.getAdmin(); // 可以在对应表数据查询 是否存在再启用 - + List incomeDetails = projectBudgetService.getBudgetIncomeDetail(project); return ProjectReturnValue.builder() .projectId(project.getId()) + .incomeDetails(incomeDetails) .projectName(project.getName()) .projectNo(project.getProjectNo()) .applyPersonName(admin.getRealName()) @@ -170,101 +178,37 @@ public class ProcessController { } // 销售合同流程 - @Setter - static class SaleContractForm { - - public Integer projectId; - - // 项目编号 - public String projectNo; - - public LocalDate applyDate; - - // 项目标题 - public String title; - - // 项目类型 - public String projectType; - - // 合作类型 - public String cooperationType; - - // 申请人 - public String applyPersonName; - - public String applyDept; - - // 申请部门领导 - - public String applyDeptLeaderName; - - // 申请人电话 - public String applyPersonPhone; - - // 合同编号 - public String contractNo; - - // 合同名称 - public String contractName; - - // 客户名称 - public String clientName; - - // 用印类型 - public String[] sealType; - - // 税率 - public String taxRate; - - // 收款条件 - public String paymentTerms; - - public ProcessStatus status; - - } @ResponseBody @PostMapping - public void post(@RequestBody SaleContractForm form) { + @Transactional + public void post(@RequestBody @Valid SaleContractProcessForm form) { System.out.println(form); + SaleContractProcess entity = new SaleContractProcess(); + BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate"); + entity.setApplyDate(LocalDate.parse(form.getApplyDate(), formatter)); + entity.setSealTypes(SealTypeArray.of(form.getSealTypes())); - } + entityManager.persist(entity); - @ResponseBody - @GetMapping("/sale-contract-details/{id}") - public List queryProjectBudgetIncomeDetail(@PathVariable int id) { - Project project = new Project(); - project.setId(id); - return projectBudgetService.getBudgetIncomeDetail(project); - } + List incomeDetails = form.getIncomeDetails(); + if (!CollectionUtils.isEmpty(incomeDetails)) { + jdbcTemplate.batchUpdate("update project_budget_income_detail set expiration_date =? where id =? ", + new BatchPreparedStatementSetter() { - @Setter - public static class SaleContractDetailForm { + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + SaleContractDetailForm detailForm = incomeDetails.get(i); + ps.setString(1, detailForm.getExpirationDate()); + ps.setInt(2, detailForm.getId()); + } - public int id; - - // 5 个字符 - public String expirationDate; - - } - - @ResponseBody - @PostMapping("/sale-contract-details") - public void saleContractDetails(@RequestBody List form) { - jdbcTemplate.batchUpdate("update project_budget_income_detail set expiration_date =? where id =? ", - new BatchPreparedStatementSetter() { - @Override - public void setValues(PreparedStatement ps, int i) throws SQLException { - SaleContractDetailForm detailForm = form.get(i); - ps.setString(1, detailForm.expirationDate); - ps.setInt(2, detailForm.id); - } - - @Override - public int getBatchSize() { - return form.size(); - } - }); + @Override + public int getBatchSize() { + return incomeDetails.size(); + } + }); + } } } diff --git a/src/main/java/cn/palmte/work/model/enums/CooperationType.java b/src/main/java/cn/palmte/work/model/enums/CooperationType.java index 3a2d022..e62194f 100644 --- a/src/main/java/cn/palmte/work/model/enums/CooperationType.java +++ b/src/main/java/cn/palmte/work/model/enums/CooperationType.java @@ -4,12 +4,12 @@ package cn.palmte.work.model.enums; * 合作类型:1战略合作类,2非战略合作类 * * @author Harry Yang - * @since 1.0 2022/12/14 15:20 + * @since 2.0 2022/12/14 15:20 */ public enum CooperationType implements Enumerable { STRATEGIC_COOPERATION(1, "战略合作"), - NOT_STRATEGIC_COOPERATION(2, "战略合作"); + NOT_STRATEGIC_COOPERATION(2, "非战略合作"); private final int value; private final String description; diff --git a/src/main/java/cn/palmte/work/model/enums/Descriptive.java b/src/main/java/cn/palmte/work/model/enums/Descriptive.java index 6429f38..ed1a9d2 100644 --- a/src/main/java/cn/palmte/work/model/enums/Descriptive.java +++ b/src/main/java/cn/palmte/work/model/enums/Descriptive.java @@ -2,6 +2,7 @@ package cn.palmte.work.model.enums; /** * @author Harry Yang + * @since 2.0 */ public interface Descriptive { /** diff --git a/src/main/java/cn/palmte/work/model/enums/Enumerable.java b/src/main/java/cn/palmte/work/model/enums/Enumerable.java index c824e3f..2e4ad20 100644 --- a/src/main/java/cn/palmte/work/model/enums/Enumerable.java +++ b/src/main/java/cn/palmte/work/model/enums/Enumerable.java @@ -8,6 +8,7 @@ import java.util.function.Supplier; * Enumerable for {@link Enum} * * @author Harry Yang + * @since 2.0 */ public interface Enumerable extends Descriptive { diff --git a/src/main/java/cn/palmte/work/model/enums/ProcessStatus.java b/src/main/java/cn/palmte/work/model/enums/ProcessStatus.java index c2afb9f..f8cf2bd 100644 --- a/src/main/java/cn/palmte/work/model/enums/ProcessStatus.java +++ b/src/main/java/cn/palmte/work/model/enums/ProcessStatus.java @@ -2,7 +2,7 @@ package cn.palmte.work.model.enums; /** * @author Harry Yang - * @since 1.0 2022/12/13 16:12 + * @since 2.0 2022/12/13 16:12 */ public enum ProcessStatus implements Enumerable { diff --git a/src/main/java/cn/palmte/work/model/enums/ProcessTaxRate.java b/src/main/java/cn/palmte/work/model/enums/ProcessTaxRate.java index 7004b84..9b5241c 100644 --- a/src/main/java/cn/palmte/work/model/enums/ProcessTaxRate.java +++ b/src/main/java/cn/palmte/work/model/enums/ProcessTaxRate.java @@ -4,7 +4,7 @@ package cn.palmte.work.model.enums; * 业务应用里面的税率 * * @author Harry Yang - * @since 1.0 2022/12/13 15:41 + * @since 2.0 2022/12/13 15:41 */ public enum ProcessTaxRate { diff --git a/src/main/java/cn/palmte/work/model/enums/ProjectType.java b/src/main/java/cn/palmte/work/model/enums/ProjectType.java index 03f51ea..5b9b01a 100644 --- a/src/main/java/cn/palmte/work/model/enums/ProjectType.java +++ b/src/main/java/cn/palmte/work/model/enums/ProjectType.java @@ -4,7 +4,7 @@ package cn.palmte.work.model.enums; * 项目类型:1 工程集成类、2设备集成类、3战略合作类 * * @author Harry Yang - * @since 1.0 2022/12/14 15:10 + * @since 2.0 2022/12/14 15:10 */ public enum ProjectType implements Enumerable { diff --git a/src/main/java/cn/palmte/work/model/enums/SealType.java b/src/main/java/cn/palmte/work/model/enums/SealType.java index ed5f0c4..9db8d3c 100644 --- a/src/main/java/cn/palmte/work/model/enums/SealType.java +++ b/src/main/java/cn/palmte/work/model/enums/SealType.java @@ -4,7 +4,7 @@ package cn.palmte.work.model.enums; * 印章类型 * * @author Harry Yang - * @since 1.0 2022/12/13 15:25 + * @since 2.0 2022/12/13 15:25 */ public enum SealType implements Enumerable { diff --git a/src/main/java/cn/palmte/work/model/process/SaleContractProcess.java b/src/main/java/cn/palmte/work/model/process/SaleContractProcess.java new file mode 100644 index 0000000..53ead23 --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/SaleContractProcess.java @@ -0,0 +1,87 @@ +package cn.palmte.work.model.process; + +import org.hibernate.annotations.GenericGenerator; + +import java.time.LocalDate; + +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import cn.palmte.work.model.enums.ProcessStatus; +import lombok.Data; + +/** + * 销售合同流程 + * + * @author Harry Yang + * @since 2.0 2022/12/14 16:11 + */ +@Data +@Entity +@Table(name = "sale_contract_process") +public class SaleContractProcess { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @GenericGenerator(name = "persistenceGenerator", strategy = "increment") + private Integer id; + + private Integer projectId; + + // 项目编号 + private String projectNo; + + private LocalDate applyDate; + + // 项目标题 + private String projectTitle; + + // 申请人 + private String applyPersonName; + + // 申请部门 + private String applyDept; + + // 申请部门领导 + private String applyDeptLeaderName; + + // 申请人电话 + private String applyPersonPhone; + + // 合同编号 + private String contractNo; + + // 合同名称 + private String contractName; + + // 客户名称 + private String clientName; + + // 用印类型 + @Convert(converter = SealTypeArrayConverter.class) + private SealTypeArray sealTypes; + + // 税率 + private String taxRate; + + // 收款条件 + private String paymentTerms; + + // 状态 + @Enumerated(EnumType.STRING) + private ProcessStatus status; + + // 项目类型 +// @Enumerated(EnumType.STRING) +// private ProjectType projectType; + + // 合作类型 +// @Enumerated(EnumType.STRING) +// private CooperationType cooperationType; +} diff --git a/src/main/java/cn/palmte/work/model/process/SaleContractProcessRepository.java b/src/main/java/cn/palmte/work/model/process/SaleContractProcessRepository.java new file mode 100644 index 0000000..0897bc9 --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/SaleContractProcessRepository.java @@ -0,0 +1,11 @@ +package cn.palmte.work.model.process; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author Harry Yang + * @since 2.0 2022/12/14 17:13 + */ +public interface SaleContractProcessRepository extends JpaRepository { + +} diff --git a/src/main/java/cn/palmte/work/model/process/SealTypeArray.java b/src/main/java/cn/palmte/work/model/process/SealTypeArray.java new file mode 100644 index 0000000..0f90d38 --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/SealTypeArray.java @@ -0,0 +1,58 @@ +package cn.palmte.work.model.process; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.persistence.Convert; + +import cn.palmte.work.model.enums.Enumerable; +import cn.palmte.work.model.enums.SealType; + +/** + * @author Harry Yang + * @since 2.0 2022/12/14 16:35 + */ +//@JsonSerialize +@Convert(converter = SealTypeArrayConverter.class) +public class SealTypeArray { + public static final SealTypeArray EMPTY = new SealTypeArray(); + + private final List sealTypes = new ArrayList<>(); + + public SealTypeArray() { } + + public SealTypeArray(SealType... sealTypes) { + Collections.addAll(this.sealTypes, sealTypes); + } + + public List getSealTypes() { + return sealTypes; + } + + public void setSealTypes(List sealTypes) { + this.sealTypes.clear(); + this.sealTypes.addAll(sealTypes); + } + + // + + public static SealTypeArray of(SealType... sealTypes) { + return new SealTypeArray(sealTypes); + } + + public static SealTypeArray of(String... sealTypes) { + return of(Arrays.stream(sealTypes) + .map(type -> Enumerable.of(SealType.class, type)) + .toArray(SealType[]::new)); + } + + public static SealTypeArray of(Collection sealTypes) { + SealTypeArray sealTypeArray = new SealTypeArray(); + sealTypeArray.sealTypes.addAll(sealTypes); + return sealTypeArray; + } + +} diff --git a/src/main/java/cn/palmte/work/model/process/SealTypeArrayConverter.java b/src/main/java/cn/palmte/work/model/process/SealTypeArrayConverter.java new file mode 100644 index 0000000..eb36c59 --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/SealTypeArrayConverter.java @@ -0,0 +1,44 @@ +package cn.palmte.work.model.process; + +import org.springframework.util.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.persistence.AttributeConverter; + +import cn.palmte.work.model.enums.Enumerable; +import cn.palmte.work.model.enums.SealType; + +/** + * @author Harry Yang + * @since 2.0 2022/12/14 16:36 + */ +public class SealTypeArrayConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(SealTypeArray attribute) { + List sealTypes = attribute.getSealTypes(); + if (sealTypes.isEmpty()) { + return null; + } + return sealTypes.stream() + .map(SealType::getValue) + .collect(Collectors.joining(",")); + } + + @Override + public SealTypeArray convertToEntityAttribute(String dbData) { + return Optional.ofNullable(dbData) + .filter(StringUtils::hasText) + .map(data -> data.split(",")) + .map(Arrays::stream) + .map(stream -> stream.map(element -> Enumerable.of(SealType.class, element)) + .toArray(SealType[]::new)) + .map(SealTypeArray::of) + .orElse(SealTypeArray.EMPTY); + } + +} diff --git a/src/main/java/cn/palmte/work/model/process/form/SaleContractDetailForm.java b/src/main/java/cn/palmte/work/model/process/form/SaleContractDetailForm.java new file mode 100644 index 0000000..8e05fb6 --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/form/SaleContractDetailForm.java @@ -0,0 +1,17 @@ +package cn.palmte.work.model.process.form; + +import lombok.Data; + +/** + * @author Harry Yang + * @since 2.0 2022/12/14 17:17 + */ +@Data +public class SaleContractDetailForm { + + private int id; + + // 5 个字符 + private String expirationDate; + +} diff --git a/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java b/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java new file mode 100644 index 0000000..e441cd2 --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java @@ -0,0 +1,71 @@ +package cn.palmte.work.model.process.form; + +import java.time.LocalDate; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import cn.palmte.work.model.enums.ProcessStatus; +import lombok.Data; + +/** + * 销售合同流程 + * + * @author Harry Yang + * @since 2.0 2022/12/14 17:05 + */ +@Data +public class SaleContractProcessForm { + + @NotNull + private Integer projectId; + + // 项目编号 + private String projectNo; + + private String applyDate; + + // 项目标题 + private String projectTitle; + + // 项目类型 +// private String projectType; + + // 合作类型 +// private String cooperationType; + + // 申请人 + private String applyPersonName; + + private String applyDept; + + // 申请部门领导 + + private String applyDeptLeaderName; + + // 申请人电话 + private String applyPersonPhone; + + // 合同编号 + private String contractNo; + + // 合同名称 + private String contractName; + + // 客户名称 + private String clientName; + + // 用印类型 + private String[] sealTypes; + + // 税率 + private String taxRate; + + // 收款条件 + private String paymentTerms; + + private ProcessStatus status; + + private List incomeDetails; + +} diff --git a/src/main/java/cn/palmte/work/model/process/package-info.java b/src/main/java/cn/palmte/work/model/process/package-info.java new file mode 100644 index 0000000..4c4a60c --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/package-info.java @@ -0,0 +1,7 @@ +/** + * 流程相关的 Model + * + * @author Harry Yang + * @since 2.0 2022/12/14 16:32 + */ +package cn.palmte.work.model.process; \ No newline at end of file diff --git a/src/main/resources/templates/admin/business/process-new.ftl b/src/main/resources/templates/admin/business/process-new.ftl index f598708..a2d9463 100644 --- a/src/main/resources/templates/admin/business/process-new.ftl +++ b/src/main/resources/templates/admin/business/process-new.ftl @@ -160,7 +160,7 @@
- + <#list sealTypes as sealType> ${sealType.description} @@ -246,7 +246,7 @@ <#-- 销售合同清单明细 -->
- + @@ -412,7 +412,7 @@ return { mode: "btn", // btn , newBusinessProcurementContractProcess processForm: { - sealType: [], + sealTypes: [], }, projectSelected: false, applySectorOptions: [ @@ -615,7 +615,8 @@ } ], fileList: [], - saleContractDetails: [], + // 销售合同收入明细 + incomeDetails: [], } } @@ -636,37 +637,9 @@ this.changeMode(saleContractProcess) }, goToSaleContractDetail() { - const { id } = this.processForm - if (id) { + const { projectId } = this.processForm + if (projectId) { this.changeMode(saleContractDetail) - const loading = this.$loading({ - lock: true, - text: '销售合同清单明细', - spinner: 'el-icon-loading', - background: 'rgba(0, 0, 0, 0.7)' - }) - fetch("${base}/process/sale-contract-details/" + id) - .then(res => res.json()) - .then(data => { - // 转换数据 - // @formatter:off - const computeType = (type) => { - switch (type) { - case 1: return '设备' - case 2: return '工程' - case 3: return '服务' - default: return '未知' - } - } - // @formatter:on - this.saleContractDetails = data.map(detail => ({ - ...detail, type: computeType(detail.type) - })) - }) - .catch(err => { - this.$message.error("销售合同清单明细加载失败"); - }) - .finally(() => loading.close()) } else { this.$message.warning("项目还未选择") @@ -681,6 +654,10 @@ console.log(obj) }, + initForm(form) { + this.processForm = { ...form, sealTypes: [] } + }, + queryProject(q, callback) { if (isBlank(q)) { return @@ -704,7 +681,7 @@ handleSelectProject(selected) { const { id, name } = selected if (!id) { - this.processForm = {} + this.initForm({}) return } const loading = this.$loading({ @@ -717,13 +694,24 @@ fetch("${base}/process/projects/" + id) .then(res => res.json()) .then(data => { - this.processForm = { - sealType: [], - projectId: id, - applyDate: new Date().toLocaleDateString(), - ...data + const { incomeDetails, ...form } = data + // 转换数据 + // @formatter:off + const computeType = (type) => { + switch (type) { + case 1: return '设备' + case 2: return '工程' + case 3: return '服务' + default: return '未知' + } } + // @formatter:on + + this.initForm(form) this.projectSelected = true + this.incomeDetails = incomeDetails.map(detail => ({ + ...detail, type: computeType(detail.type) + })) }) .catch(err => { this.$message.error("项目'" + name + "'加载失败"); @@ -732,9 +720,8 @@ }, clearProjectProcess() { this.projectSelected = false - this.processForm = { - sealType: [] - } + this.initForm({}) + this.incomeDetails = [] }, saveDraft() { @@ -752,14 +739,20 @@ background: 'rgba(0, 0, 0, 0.7)' }) - const processForm = this.processForm - console.log(processForm) + const form = { + ...this.processForm, + projectTitle: this.projectTitle, + incomeDetails: this.incomeDetails.map(detail => ({ + id: detail.id, expirationDate: detail.expirationDate + })) + } + fetch("${base}/process", { method: 'POST', // or 'PUT' headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify(processForm), + body: JSON.stringify(form), }).then(response => { this.$message({ showClose: true, @@ -777,32 +770,7 @@ }, submitToSaleContractProcess() { - const loading = this.$loading({ - lock: true, - text: '正在提交', - spinner: 'el-icon-loading', - background: 'rgba(0, 0, 0, 0.7)' - }) - - const form = this.saleContractDetails.map(detail => ({ - id: detail.id, expirationDate: detail.expirationDate - })) - fetch("${base}/process/sale-contract-details", { - method: 'POST', // or 'PUT' - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(form), - }).then(response => { - this.$message({ - showClose: true, - message: '提交成功', - type: 'success' - }) - this.goToSaleContractProcess() - }).catch(err => { - this.$message.error("项目提交失败"); - }).finally(() => loading.close()) + this.goToSaleContractProcess() }, handleRemove(file, fileList) { @@ -863,19 +831,7 @@ methods, mounted() { - fetch("${base}/process/projects/135") - .then(res => res.json()) - .then(data => { - this.processForm = { - sealType: [], - projectId: 135, - ...data - } - this.projectSelected = true - }) - .catch(err => { - this.$message.error("测试项目'加载失败"); - }) + this.handleSelectProject({ id: 135, name: '' }) }, })