Merge branch 'dev-yhj' into 1.2.0
commit
969b044daa
|
@ -32,6 +32,7 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.hibernate:hibernate-java8:5.1.0.Final'
|
||||
compile "org.springframework.boot:spring-boot-starter:${springBootVersion}"
|
||||
compile 'org.springframework.boot:spring-boot-starter-web'
|
||||
compile 'org.springframework.boot:spring-boot-starter-freemarker'
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
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;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import cn.palmte.work.model.Admin;
|
||||
import cn.palmte.work.model.DeptRepository;
|
||||
import cn.palmte.work.model.Project;
|
||||
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.ProcessType;
|
||||
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.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 1.0 2022/12/8 11:03
|
||||
*/
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/process")
|
||||
public class ProcessController {
|
||||
static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
private final DeptRepository deptRepository;
|
||||
private final ProjectRepository projectRepository;
|
||||
private final ProjectBudgetService projectBudgetService;
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final EntityManager entityManager;
|
||||
|
||||
static class FormMetadata {
|
||||
// 部门
|
||||
|
||||
// 印章类型
|
||||
public Map<String, String> sealTypes;
|
||||
|
||||
// 税率
|
||||
public List<Integer> taxRate;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/form/metadata")
|
||||
public FormMetadata metadata() {
|
||||
FormMetadata metadata = new FormMetadata();
|
||||
metadata.sealTypes = Arrays.stream(SealType.values())
|
||||
.collect(Collectors.toMap(SealType::getDescription, Enum::name));
|
||||
metadata.taxRate = Arrays.asList(0, 1, 3, 4, 5, 6, 9, 10, 13);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建流程
|
||||
*/
|
||||
@GetMapping("/new")
|
||||
public String newProcess(Model model) {
|
||||
model.addAttribute("sealTypes", SealType.values());
|
||||
model.addAttribute("taxRate", Arrays.asList(0, 1, 3, 4, 5, 6, 9, 10, 13));
|
||||
return "/admin/business/process-new";
|
||||
}
|
||||
|
||||
/**
|
||||
* 已办流程
|
||||
*/
|
||||
@GetMapping("/completed")
|
||||
public String completed() {
|
||||
return "/admin/business/process-completed";
|
||||
}
|
||||
|
||||
/**
|
||||
* 待我审核
|
||||
*/
|
||||
@GetMapping("/review")
|
||||
public String review(Model model) {
|
||||
model.addAttribute("processTypes", ProcessType.values());
|
||||
return "/admin/business/process-review";
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/projects")
|
||||
public List<Map<String, Object>> query(@RequestParam String q) {
|
||||
return projectRepository.findByProjectNoOrName(q)
|
||||
.stream()
|
||||
.map(project -> {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("id", project.getId());
|
||||
map.put("name", project.getName());
|
||||
return map;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Builder
|
||||
public static class ProjectReturnValue {
|
||||
public final String applyDate = LocalDate.now().format(formatter);
|
||||
public String projectNo;
|
||||
public Integer projectId;
|
||||
public String projectName;
|
||||
|
||||
// 申请人
|
||||
public String applyPersonName;
|
||||
|
||||
// 项目类型
|
||||
public String projectType;
|
||||
|
||||
// 合作类型
|
||||
public String cooperationType;
|
||||
|
||||
// 合同金额
|
||||
public BigDecimal contractAmount;
|
||||
|
||||
public List<ProjectBudgetIncomeDetail> incomeDetails;
|
||||
|
||||
// FIXME 垫资
|
||||
// 是否垫资
|
||||
public final String isPrepaid = "是";
|
||||
|
||||
// 垫资金额
|
||||
public final String repaidAmount = "50000元";
|
||||
|
||||
// 预算毛利率
|
||||
public final String budgetGrossMargin = "3.9%";
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/projects/{id}")
|
||||
public ProjectReturnValue query(@PathVariable int id) {
|
||||
Project project = projectRepository.findById(id);
|
||||
Admin admin = InterfaceUtil.getAdmin();
|
||||
|
||||
// 可以在对应表数据查询 是否存在再启用
|
||||
List<ProjectBudgetIncomeDetail> incomeDetails = projectBudgetService.getBudgetIncomeDetail(project);
|
||||
return ProjectReturnValue.builder()
|
||||
.projectId(project.getId())
|
||||
.incomeDetails(incomeDetails)
|
||||
.projectName(project.getName())
|
||||
.projectNo(project.getProjectNo())
|
||||
.applyPersonName(admin.getRealName())
|
||||
.contractAmount(project.getContractAmount())
|
||||
.projectType(Enumerable.of(ProjectType.class, project.getType()).getDescription())
|
||||
.cooperationType(Enumerable.of(CooperationType.class, project.getCooperateType()).getDescription())
|
||||
.build();
|
||||
}
|
||||
|
||||
// 销售合同流程
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public void post(@RequestBody @Valid SaleContractProcessForm form) {
|
||||
SaleContractProcess entity = new SaleContractProcess();
|
||||
BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate", "applyDept");
|
||||
entity.setApplyDate(LocalDate.parse(form.getApplyDate(), formatter));
|
||||
entity.setSealTypes(SealTypeArray.of(form.getSealTypes()));
|
||||
entity.setApplyDept(String.join(",", form.getApplyDept()));
|
||||
|
||||
entityManager.persist(entity);
|
||||
|
||||
List<SaleContractDetailForm> incomeDetails = form.getIncomeDetails();
|
||||
if (!CollectionUtils.isEmpty(incomeDetails)) {
|
||||
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 = incomeDetails.get(i);
|
||||
ps.setString(1, detailForm.getExpirationDate());
|
||||
ps.setInt(2, detailForm.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return incomeDetails.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
static class ProcessQueryForm {
|
||||
|
||||
private String projectNo;
|
||||
private String projectTitle;
|
||||
private String applyPersonName;
|
||||
|
||||
private ProcessType processType;
|
||||
private ProcessStatus processStatus;
|
||||
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping("/query")
|
||||
public List<SaleContractProcess> list(@RequestBody ProcessQueryForm form) {
|
||||
TypedQuery<SaleContractProcess> query = entityManager.createQuery(
|
||||
"from SaleContractProcess ", SaleContractProcess.class);
|
||||
|
||||
// query.setMaxResults();
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
// 审核
|
||||
@Data
|
||||
static class AuditForm {
|
||||
|
||||
private Integer processId;
|
||||
|
||||
@NotNull
|
||||
private String auditOpinion;
|
||||
|
||||
private ProcessStatus processStatus;
|
||||
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping("/audit")
|
||||
public void audit(@RequestBody @Valid AuditForm form) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -37,6 +37,10 @@ public class ProjectBudgetIncomeDetailBase {
|
|||
@Column(name = "tax_rate")
|
||||
private BigDecimal taxRate;
|
||||
|
||||
// 质保期 5 个字符
|
||||
@Column(name = "expiration_date")
|
||||
public String expirationDate;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -117,6 +121,14 @@ public class ProjectBudgetIncomeDetailBase {
|
|||
this.taxRate = taxRate;
|
||||
}
|
||||
|
||||
public String getExpirationDate() {
|
||||
return expirationDate;
|
||||
}
|
||||
|
||||
public void setExpirationDate(String expirationDate) {
|
||||
this.expirationDate = expirationDate;
|
||||
}
|
||||
|
||||
public BigDecimal getTotalTaxInclude(){
|
||||
if(null == price){
|
||||
return null;
|
||||
|
|
|
@ -3,6 +3,7 @@ package cn.palmte.work.model;
|
|||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.Date;
|
||||
|
@ -38,4 +39,9 @@ public interface ProjectRepository extends JpaRepository<Project,Integer> {
|
|||
@Transactional(rollbackOn = Exception.class)
|
||||
@Query(value = "update project set approve_id=?, approve_name=? where approve_id = ?", nativeQuery = true)
|
||||
int batchUpdateApprove(int targetAdminId, String targetAdminName, int adminId);
|
||||
|
||||
@Query(value = "select * from project where `project_no` like concat('%', :q, '%') or `name` like concat('%', :q, '%')",
|
||||
nativeQuery = true)
|
||||
List<Project> findByProjectNoOrName(@Param("q") String query);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* 合作类型:1战略合作类,2非战略合作类
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/14 15:20
|
||||
*/
|
||||
public enum CooperationType implements Enumerable<Integer> {
|
||||
|
||||
STRATEGIC_COOPERATION(1, "战略合作"),
|
||||
NOT_STRATEGIC_COOPERATION(2, "非战略合作");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
CooperationType(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface Descriptive {
|
||||
/**
|
||||
* Return a description
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Enumerable for {@link Enum}
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface Enumerable<V> extends Descriptive {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default V getValue() {
|
||||
return (V) name();
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getDescription() {
|
||||
return name();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default name of the enumeration, this method does not need
|
||||
* to be implemented, the enumeration class is automatically inherited
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Returns Enumerable by {@link Enumerable#getValue() enum value}
|
||||
*
|
||||
* @param enumerable enum
|
||||
* @param value enumeration value
|
||||
* @param <T> enumeration type
|
||||
* @param <V> enumeration value type
|
||||
* @return enumeration instance
|
||||
* @throws NullPointerException if enumerable is {@code null}
|
||||
* @see Enumerable#getValue()
|
||||
*/
|
||||
// @Nullable
|
||||
static <T extends Enumerable<V>, V> T of(Class<T> enumerable, /*@Nullable*/ V value) {
|
||||
if (value != null) {
|
||||
T[] enumConstants = enumerable.getEnumConstants();
|
||||
if (enumConstants != null) {
|
||||
for (T constant : enumConstants) {
|
||||
if (Objects.equals(value, constant.getValue())) {
|
||||
return constant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value corresponding to the name
|
||||
*
|
||||
* @param enumerable enumeration class
|
||||
* @param name enumeration name
|
||||
* @param <T> enum type
|
||||
* @param <V> enumeration value type
|
||||
* @return enumeration value
|
||||
* @see Enumerable#getValue()
|
||||
*/
|
||||
// @Nullable
|
||||
static <T extends Enumerable<V>, V> V getValue(Class<T> enumerable, String name) {
|
||||
T[] enumConstants = enumerable.getEnumConstants();
|
||||
if (enumConstants != null) {
|
||||
for (T constant : enumConstants) {
|
||||
if (Objects.equals(name, constant.name())) {
|
||||
return constant.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T> enum type
|
||||
* @param <V> enumeration value type
|
||||
* @param defaultValue default value
|
||||
* @see #of(Class, V)
|
||||
*/
|
||||
static <T extends Enumerable<V>, V> T of(Class<T> enumerable, V value, Supplier<T> defaultValue) {
|
||||
return find(enumerable, value).orElseGet(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param defaultValue default value
|
||||
* @param <T> enum type
|
||||
* @param <V> enumeration value type
|
||||
* @see #of(Class, V)
|
||||
*/
|
||||
static <T extends Enumerable<V>, V> T of(Class<T> enumerable, V value, T defaultValue) {
|
||||
return find(enumerable, value).orElse(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Optional of T
|
||||
*/
|
||||
static <T extends Enumerable<V>, V> Optional<T> find(Class<T> enumerable, V value) {
|
||||
return Optional.ofNullable(of(enumerable, value));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* 审核状态
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/13 16:12
|
||||
*/
|
||||
public enum ProcessStatus implements Enumerable<String> {
|
||||
|
||||
draft("草稿"),
|
||||
to_be_audit("待审核"),
|
||||
audit_passed("审核通过"),
|
||||
audit_not_passed("审核不通过"),
|
||||
completed("完成");
|
||||
|
||||
private final String description;
|
||||
|
||||
ProcessStatus(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* 业务应用里面的税率
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/13 15:41
|
||||
*/
|
||||
public enum ProcessTaxRate {
|
||||
|
||||
;
|
||||
|
||||
private final String description;
|
||||
|
||||
ProcessTaxRate(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/19 16:47
|
||||
*/
|
||||
public enum ProcessType implements Enumerable<String> {
|
||||
sale_contract("销售合同流程"),
|
||||
business_procurement("业务采购流程");
|
||||
|
||||
private final String description;
|
||||
|
||||
ProcessType(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* 项目类型:1 工程集成类、2设备集成类、3战略合作类
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/14 15:10
|
||||
*/
|
||||
public enum ProjectType implements Enumerable<Integer> {
|
||||
|
||||
ENGINEERING_INTEGRATION(1, "工程集成"),
|
||||
DEVICE_INTEGRATION(2, "设备集成"),
|
||||
STRATEGIC_COOPERATION(3, "战略合作");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
ProjectType(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package cn.palmte.work.model.enums;
|
||||
|
||||
/**
|
||||
* 印章类型
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/13 15:25
|
||||
*/
|
||||
public enum SealType implements Enumerable<String> {
|
||||
|
||||
// "公章"
|
||||
// "法人章"
|
||||
// "合同专用章"
|
||||
// "项目章"
|
||||
// "法人签名章"
|
||||
// "总经理签名章"
|
||||
// "财务专用章"
|
||||
// "电子合同章"
|
||||
// "其他"
|
||||
|
||||
official("公章"),
|
||||
legal("法人章"),
|
||||
contract_special("合同专用章"),
|
||||
project("项目章"),
|
||||
legal_person_signature("法人签名章"),
|
||||
general_manager_signature("总经理签名章"),
|
||||
financial("财务专用章"),
|
||||
electronic_contract("电子合同章"),
|
||||
other("其他");
|
||||
|
||||
private final String description;
|
||||
|
||||
SealType(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package cn.palmte.work.model.process;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
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 <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @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;
|
||||
|
||||
// 当前审核人
|
||||
private String currentAudit;
|
||||
|
||||
// 最后更新时间
|
||||
private LocalDateTime lastUpdateAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
// 项目类型
|
||||
// @Enumerated(EnumType.STRING)
|
||||
// private ProjectType projectType;
|
||||
|
||||
// 合作类型
|
||||
// @Enumerated(EnumType.STRING)
|
||||
// private CooperationType cooperationType;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package cn.palmte.work.model.process;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/14 17:13
|
||||
*/
|
||||
public interface SaleContractProcessRepository extends JpaRepository<SaleContractProcess, Integer> {
|
||||
|
||||
}
|
|
@ -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 <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @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<SealType> sealTypes = new ArrayList<>();
|
||||
|
||||
public SealTypeArray() { }
|
||||
|
||||
public SealTypeArray(SealType... sealTypes) {
|
||||
Collections.addAll(this.sealTypes, sealTypes);
|
||||
}
|
||||
|
||||
public List<SealType> getSealTypes() {
|
||||
return sealTypes;
|
||||
}
|
||||
|
||||
public void setSealTypes(List<SealType> 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<SealType> sealTypes) {
|
||||
SealTypeArray sealTypeArray = new SealTypeArray();
|
||||
sealTypeArray.sealTypes.addAll(sealTypes);
|
||||
return sealTypeArray;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/14 16:36
|
||||
*/
|
||||
public class SealTypeArrayConverter implements AttributeConverter<SealTypeArray, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(SealTypeArray attribute) {
|
||||
List<SealType> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package cn.palmte.work.model.process.form;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/14 17:17
|
||||
*/
|
||||
@Data
|
||||
public class SaleContractDetailForm {
|
||||
|
||||
private int id;
|
||||
|
||||
// 5 个字符
|
||||
private String expirationDate;
|
||||
|
||||
}
|
|
@ -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 <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @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<SaleContractDetailForm> incomeDetails;
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* 流程相关的 Model
|
||||
*
|
||||
* @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
|
||||
* @since 2.0 2022/12/14 16:32
|
||||
*/
|
||||
package cn.palmte.work.model.process;
|
|
@ -1,73 +0,0 @@
|
|||
package cn.palmte.work.service;
|
||||
|
||||
import cn.palmte.work.config.UploadProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import sun.misc.BASE64Decoder;
|
||||
import top.jfunc.common.datetime.DatetimeUtils;
|
||||
import top.jfunc.common.utils.CommonUtil;
|
||||
import top.jfunc.common.utils.FileUtil;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author xiongshiyan at 2020/10/13 , contact me with email yanshixiong@126.com or phone 15208384257
|
||||
*/
|
||||
@Service
|
||||
public class UploadService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(UploadService.class);
|
||||
public static final String DATA_IMAGE_PNG_BASE64 = "data:image/png;base64,";
|
||||
public static final String DATA_IMAGE_JPEG_BASE64 = "data:image/jpeg;base64,";
|
||||
public static final String DATA_IMAGE_JPG_BASE64 = "data:image/jpg;base64,";
|
||||
|
||||
@Autowired
|
||||
private UploadProperties uploadProperties;
|
||||
|
||||
public String upload(String base64Str){
|
||||
String suffix = "png";
|
||||
if (base64Str.contains(DATA_IMAGE_PNG_BASE64)) {
|
||||
base64Str = base64Str.replaceAll(DATA_IMAGE_PNG_BASE64, "");
|
||||
suffix = "png";
|
||||
} else if (base64Str.contains(DATA_IMAGE_JPEG_BASE64)) {
|
||||
base64Str = base64Str.replaceAll(DATA_IMAGE_JPEG_BASE64, "");
|
||||
suffix = "jpeg";
|
||||
}else if (base64Str.contains(DATA_IMAGE_JPG_BASE64)) {
|
||||
base64Str = base64Str.replaceAll(DATA_IMAGE_JPG_BASE64, "");
|
||||
suffix = "jpg";
|
||||
}
|
||||
String uploadPath = uploadProperties.getPath();
|
||||
String uploadPrefix = uploadProperties.getPrefix();
|
||||
String yyyyMMdd = DatetimeUtils.toStr(new Date(), "yyyyMMdd");
|
||||
String saveDir = uploadPath + "/" + yyyyMMdd;
|
||||
FileUtil.makeSureExistDir(saveDir);
|
||||
|
||||
String fileName = CommonUtil.randomString(32) + "." + suffix;
|
||||
String absolutePath = saveDir + "/" + fileName;
|
||||
File file = new File(absolutePath);
|
||||
|
||||
decodeAndWrite(base64Str , file);
|
||||
|
||||
return uploadPrefix + "/" + yyyyMMdd + "/" + fileName;
|
||||
}
|
||||
|
||||
|
||||
private void decodeAndWrite(String base64Str, File destFile) {
|
||||
try {
|
||||
// Base64解码
|
||||
byte[] bytes = new BASE64Decoder().decodeBuffer(base64Str);
|
||||
for (int i = 0; i < bytes.length; ++i) {
|
||||
if (bytes[i] < 0) {
|
||||
// 调整异常数据
|
||||
bytes[i] += 256;
|
||||
}
|
||||
}
|
||||
Files.write(Paths.get(destFile.getAbsolutePath()), bytes);
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,305 +0,0 @@
|
|||
package cn.palmte.work.utils.image;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sun.misc.BASE64Decoder;
|
||||
import top.jfunc.common.utils.ArrayUtil;
|
||||
import top.jfunc.common.utils.RandomUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 滑动验证码相关工具方法
|
||||
*/
|
||||
public class VerifyImageUtil {
|
||||
private static final Logger logger = LoggerFactory.getLogger(VerifyImageUtil.class);
|
||||
/**
|
||||
* 模板图宽度
|
||||
*/
|
||||
private static int CUT_WIDTH = 50;
|
||||
/**
|
||||
* 模板图高度
|
||||
*/
|
||||
private static int CUT_HEIGHT = 50;
|
||||
/**
|
||||
* 抠图凸起圆心
|
||||
*/
|
||||
private static int CIRCLE_R = 5;
|
||||
/**
|
||||
* 抠图内部矩形填充大小
|
||||
*/
|
||||
private static int RECTANGLE_PADDING = 8;
|
||||
/**
|
||||
* 抠图的边框宽度
|
||||
*/
|
||||
private static int SLIDER_IMG_OUT_PADDING = 1;
|
||||
|
||||
private static int CENTER_INDICATOR = 1;
|
||||
private static int BORDER_INDICATOR = 2;
|
||||
private static int OTHER_INDICATOR = 0;
|
||||
|
||||
/**
|
||||
* 根据传入的file生成验证码图片
|
||||
*/
|
||||
public static VerifyImage getVerifyImage(File file) throws IOException {
|
||||
BufferedImage srcImage = ImageIO.read(file);
|
||||
|
||||
return getVerifyImage(srcImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据转入的流生成验证码图片
|
||||
*/
|
||||
public static VerifyImage getVerifyImage(InputStream inputStream) throws IOException {
|
||||
BufferedImage srcImage = ImageIO.read(inputStream);
|
||||
|
||||
return getVerifyImage(srcImage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以左上角为计数起点
|
||||
*/
|
||||
public static VerifyImage getVerifyImage(BufferedImage srcImage) throws IOException {
|
||||
//1/4=75处,最右减1个方块儿,-5是保守的防止超界
|
||||
int locationX = RandomUtil.randomInt(srcImage.getWidth()/4, srcImage.getWidth()-CUT_WIDTH-5);
|
||||
//距离最下方一个方块,-5是保守的防止超界
|
||||
int locationY = RandomUtil.randomInt(5, srcImage.getHeight()-CUT_HEIGHT-5);
|
||||
|
||||
BufferedImage markImage = new BufferedImage(CUT_WIDTH,CUT_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
|
||||
cutImgByTemplate(srcImage, markImage, getBlockData(), locationX, locationY);
|
||||
return new VerifyImage(getImageBASE64(srcImage),
|
||||
getImageBASE64(markImage),
|
||||
locationX,
|
||||
locationY,
|
||||
srcImage.getWidth(),
|
||||
srcImage.getHeight());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成随机滑块形状
|
||||
* <p>
|
||||
* 0 透明像素
|
||||
* 1 滑块像素
|
||||
* 2 阴影像素
|
||||
* @return int[][]
|
||||
*/
|
||||
private static int[][] getBlockData() {
|
||||
int[][] data = new int[CUT_WIDTH][CUT_HEIGHT];
|
||||
SecureRandom random = new SecureRandom();
|
||||
//Random random = new Random();
|
||||
//(x-a)²+(y-b)²=r²
|
||||
//x中心位置左右5像素随机
|
||||
double x1 = RECTANGLE_PADDING + (CUT_WIDTH - 2 * RECTANGLE_PADDING) / 2.0/* - 5 + random.nextInt(10)*/;
|
||||
//y 矩形上边界半径-1像素移动
|
||||
double y1_top = RECTANGLE_PADDING - random.nextInt(3);
|
||||
double y1_bottom = CUT_HEIGHT - RECTANGLE_PADDING + random.nextInt(3);
|
||||
double y1 = random.nextInt(2) == 1 ? y1_top : y1_bottom;
|
||||
|
||||
|
||||
double x2_right = CUT_WIDTH - RECTANGLE_PADDING - CIRCLE_R + random.nextInt(2 * CIRCLE_R - 4);
|
||||
double x2_left = RECTANGLE_PADDING + CIRCLE_R - 2 - random.nextInt(2 * CIRCLE_R - 4);
|
||||
double x2 = random.nextInt(2) == 1 ? x2_right : x2_left;
|
||||
double y2 = RECTANGLE_PADDING + (CUT_HEIGHT - 2 * RECTANGLE_PADDING) / 2.0 - 4 + random.nextInt(10);
|
||||
|
||||
double po = Math.pow(CIRCLE_R, 2);
|
||||
for (int i = 0; i < CUT_WIDTH; i++) {
|
||||
for (int j = 0; j < CUT_HEIGHT; j++) {
|
||||
//矩形区域
|
||||
boolean fill;
|
||||
if ((i >= RECTANGLE_PADDING && i < CUT_WIDTH - RECTANGLE_PADDING)
|
||||
&& (j >= RECTANGLE_PADDING && j < CUT_HEIGHT - RECTANGLE_PADDING)) {
|
||||
data[i][j] = CENTER_INDICATOR;
|
||||
fill = true;
|
||||
} else {
|
||||
data[i][j] = OTHER_INDICATOR;
|
||||
fill = false;
|
||||
}
|
||||
//凸出区域
|
||||
double d3 = Math.pow(i - x1, 2) + Math.pow(j - y1, 2);
|
||||
if (d3 < po) {
|
||||
data[i][j] = CENTER_INDICATOR;
|
||||
} else {
|
||||
if (!fill) {
|
||||
data[i][j] = OTHER_INDICATOR;
|
||||
}
|
||||
}
|
||||
//凹进区域
|
||||
double d4 = Math.pow(i - x2, 2) + Math.pow(j - y2, 2);
|
||||
if (d4 < po) {
|
||||
data[i][j] = OTHER_INDICATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
//边界阴影
|
||||
for (int i = 0; i < CUT_WIDTH; i++) {
|
||||
for (int j = 0; j < CUT_HEIGHT; j++) {
|
||||
//四个正方形边角处理
|
||||
for (int k = 1; k <= SLIDER_IMG_OUT_PADDING; k++) {
|
||||
//左上、右上
|
||||
if (i >= RECTANGLE_PADDING - k && i < RECTANGLE_PADDING
|
||||
&& ((j >= RECTANGLE_PADDING - k && j < RECTANGLE_PADDING)
|
||||
|| (j >= CUT_HEIGHT - RECTANGLE_PADDING - k && j < CUT_HEIGHT - RECTANGLE_PADDING +1))) {
|
||||
data[i][j] = BORDER_INDICATOR;
|
||||
}
|
||||
|
||||
//左下、右下
|
||||
if (i >= CUT_WIDTH - RECTANGLE_PADDING + k - 1 && i < CUT_WIDTH - RECTANGLE_PADDING + 1) {
|
||||
for (int n = 1; n <= SLIDER_IMG_OUT_PADDING; n++) {
|
||||
if (((j >= RECTANGLE_PADDING - n && j < RECTANGLE_PADDING)
|
||||
|| (j >= CUT_HEIGHT - RECTANGLE_PADDING - n && j <= CUT_HEIGHT - RECTANGLE_PADDING ))) {
|
||||
data[i][j] = BORDER_INDICATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data[i][j] == 1 && j - SLIDER_IMG_OUT_PADDING > 0 && data[i][j - SLIDER_IMG_OUT_PADDING] == 0) {
|
||||
data[i][j - SLIDER_IMG_OUT_PADDING] = BORDER_INDICATOR;
|
||||
}
|
||||
if (data[i][j] == 1 && j + SLIDER_IMG_OUT_PADDING > 0 && j + SLIDER_IMG_OUT_PADDING < CUT_HEIGHT && data[i][j + SLIDER_IMG_OUT_PADDING] == 0) {
|
||||
data[i][j + SLIDER_IMG_OUT_PADDING] = BORDER_INDICATOR;
|
||||
}
|
||||
if (data[i][j] == 1 && i - SLIDER_IMG_OUT_PADDING > 0 && data[i - SLIDER_IMG_OUT_PADDING][j] == 0) {
|
||||
data[i - SLIDER_IMG_OUT_PADDING][j] = BORDER_INDICATOR;
|
||||
}
|
||||
if (data[i][j] == 1 && i + SLIDER_IMG_OUT_PADDING > 0 && i + SLIDER_IMG_OUT_PADDING < CUT_WIDTH && data[i + SLIDER_IMG_OUT_PADDING][j] == 0) {
|
||||
data[i + SLIDER_IMG_OUT_PADDING][j] = BORDER_INDICATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//最外边界
|
||||
/*for (int i = 0; i < CUT_WIDTH; i++) {
|
||||
data[0][i] = data[CUT_WIDTH-1][i] = 3;
|
||||
}
|
||||
for (int i = 0; i < CUT_HEIGHT; i++) {
|
||||
data[i][0] = data[i][CUT_HEIGHT-1] = 3;
|
||||
}*/
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪区块
|
||||
* 根据生成的滑块形状,对原图和裁剪块进行变色处理
|
||||
* @param oriImage 原图
|
||||
* @param targetImage 裁剪图
|
||||
* @param blockImage 滑块
|
||||
* @param x 裁剪点x
|
||||
* @param y 裁剪点y
|
||||
*/
|
||||
private static void cutImgByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] blockImage, int x, int y) {
|
||||
|
||||
print(blockImage);
|
||||
|
||||
for (int i = 0; i < CUT_WIDTH; i++) {
|
||||
for (int j = 0; j < CUT_HEIGHT; j++) {
|
||||
int xx = x + i;
|
||||
int yy = y + j;
|
||||
int rgbFlg = blockImage[i][j];
|
||||
int rgb_ori = oriImage.getRGB(xx, yy);
|
||||
|
||||
// 原图中对应位置变色处理
|
||||
if (rgbFlg == CENTER_INDICATOR) {
|
||||
//中心
|
||||
//抠图上复制对应颜色值
|
||||
targetImage.setRGB(i,j, rgb_ori);
|
||||
//原图对应位置颜色变化[透明50%]
|
||||
oriImage.setRGB(xx, yy, rgb_ori & 0x80ffffff);
|
||||
} else if (rgbFlg == BORDER_INDICATOR) {
|
||||
//边框
|
||||
targetImage.setRGB(i, j, Color.WHITE.getRGB());
|
||||
oriImage.setRGB(xx, yy, Color.GRAY.getRGB());
|
||||
}else if(rgbFlg == OTHER_INDICATOR){
|
||||
//int alpha = 0;
|
||||
targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
private static void print(int[][] blockData){
|
||||
StringBuilder builder = new StringBuilder("\r\n");
|
||||
for (int i = 0; i < blockData.length; i++) {
|
||||
for (int j = 0; j < blockData[i].length; j++) {
|
||||
builder.append(blockData[i][j]).append(" ");
|
||||
}
|
||||
builder.append("\r\n");
|
||||
}
|
||||
logger.debug(builder.toString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机获取一张图片文件
|
||||
*/
|
||||
public static File getRandomFile(File dir) throws IOException {
|
||||
File[] fileList = dir.listFiles();
|
||||
if(ArrayUtil.isEmpty(fileList)){
|
||||
return null;
|
||||
}
|
||||
List<String> fileNameList = new ArrayList<>(fileList.length);
|
||||
for (File tempFile: fileList){
|
||||
if (tempFile.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
if (tempFile.getName().endsWith(".png") || tempFile.getName().endsWith(".jpg")){
|
||||
fileNameList.add(tempFile.getAbsolutePath().trim());
|
||||
}
|
||||
}
|
||||
int randomIndex = new SecureRandom().nextInt(fileNameList.size());
|
||||
//int randomIndex = new Random().nextInt(fileNameList.size());
|
||||
return new File(fileNameList.get(randomIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将IMG输出为文件
|
||||
*/
|
||||
public static void writeImg(BufferedImage image, File file) throws IOException {
|
||||
ByteArrayOutputStream bao=new ByteArrayOutputStream();
|
||||
ImageIO.write(image,"png",bao);
|
||||
try (FileOutputStream out = new FileOutputStream(file)){
|
||||
out.write(bao.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将图片转换为BASE64
|
||||
*/
|
||||
public static String getImageBASE64(BufferedImage image) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ImageIO.write(image,"png",out);
|
||||
//转成byte数组
|
||||
byte[] bytes = out.toByteArray();
|
||||
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将BASE64字符串转换为图片
|
||||
*/
|
||||
public static BufferedImage base64String2Image(String base64String) throws IOException {
|
||||
BASE64Decoder decoder=new BASE64Decoder();
|
||||
byte[] bytes1 = decoder.decodeBuffer(base64String);
|
||||
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes1);
|
||||
return ImageIO.read(byteArrayInputStream);
|
||||
}
|
||||
|
||||
/*public static void main(String[] args) throws IOException {
|
||||
VerifyImage verifyImage = VerifyImageUtil.getVerifyImage(new File("C:\\Users\\xiongshiyan\\Desktop\\ssss.png"));
|
||||
System.out.println(verifyImage);
|
||||
VerifyImageUtil.writeImg(VerifyImageUtil.base64String2Image(verifyImage.getSrcImage()), new File("C:\\Users\\xiongshiyan\\Desktop\\src.png"));
|
||||
VerifyImageUtil.writeImg(VerifyImageUtil.base64String2Image(verifyImage.getCutImage()), new File("C:\\Users\\xiongshiyan\\Desktop\\cut.png"));
|
||||
}*/
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
# 创建 流程表
|
||||
create table sale_contract_process
|
||||
(
|
||||
id int auto_increment primary key,
|
||||
apply_date date null,
|
||||
apply_dept varchar(255) null,
|
||||
apply_dept_leader_name varchar(255) null,
|
||||
apply_person_name varchar(255) null,
|
||||
apply_person_phone varchar(255) null,
|
||||
client_name varchar(255) null,
|
||||
contract_name varchar(255) null,
|
||||
contract_no varchar(255) null,
|
||||
payment_terms varchar(255) null,
|
||||
project_id int null,
|
||||
project_no varchar(255) null,
|
||||
project_title varchar(255) null comment '标题',
|
||||
seal_types varchar(255) null comment '印章类型',
|
||||
`status` varchar(255) null,
|
||||
tax_rate varchar(255) null,
|
||||
|
||||
current_audit varchar(255) null comment '当前审核人',
|
||||
|
||||
create_at datetime default CURRENT_TIMESTAMP comment '创建时间',
|
||||
last_update_at datetime on update CURRENT_TIMESTAMP comment '最后更新时间'
|
||||
|
||||
);
|
||||
|
||||
|
||||
alter table sale_contract_process
|
||||
add current_audit varchar(255) null comment '当前审核人';
|
||||
|
||||
alter table sale_contract_process
|
||||
add create_at datetime default CURRENT_TIMESTAMP comment '创建时间';
|
||||
alter table sale_contract_process
|
||||
add last_update_at datetime on update CURRENT_TIMESTAMP comment '最后更新时间';
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 991 B |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 993 B |
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,44 @@
|
|||
<#assign base=request.contextPath />
|
||||
<#import "../../common/defaultLayout.ftl" as defaultLayout>
|
||||
<@defaultLayout.layout>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<div id="app">{{ message }}</div>
|
||||
|
||||
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||||
|
||||
<script>
|
||||
const {createApp} = Vue
|
||||
|
||||
createApp({
|
||||
data() {
|
||||
return {
|
||||
message: 'Hello Vue!'
|
||||
}
|
||||
}
|
||||
}).mount('#app')
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
|
||||
})
|
||||
</script>
|
||||
</@defaultLayout.layout>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,855 @@
|
|||
<#assign base=request.contextPath />
|
||||
<#import "../../common/defaultLayout.ftl" as defaultLayout>
|
||||
<@defaultLayout.layout>
|
||||
<#-- <link rel="stylesheet" href="../assets/css/amazeui.switch.css"/>-->
|
||||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||||
<style>
|
||||
|
||||
#businessPurchaseDetailsModal {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#businessPurchaseDetailsModal > table {
|
||||
|
||||
}
|
||||
|
||||
#newBusinessProcurementContractProcess {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.el-upload__input {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.el-textarea .el-input__count {
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.admin-content-body {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.el-table__empty-block {
|
||||
height: 60px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="admin-content" id="app">
|
||||
<div class="admin-content-body">
|
||||
<div class="am-cf am-padding">
|
||||
<div class="am-fl am-cf"><strong class="am-text-primary am-text-lg">业务应用</strong> /
|
||||
<small>{{subTitle}}</small></div>
|
||||
</div>
|
||||
|
||||
<div class="am-g">
|
||||
<div class="am-u-sm-12 am-u-md-12" v-if="isButtonMode">
|
||||
<button type="button" class="am-btn" @click="goToSaleContractProcess">
|
||||
<img src="${base}/assets/process/销售合同流程@3x.png" width="36"/>
|
||||
销售合同流程
|
||||
</button>
|
||||
<button type="button" class="am-btn" @click="businessProcurementProcessClick">
|
||||
<img src="${base}/assets/process/业务采购流程@3x.png" width="39"/>
|
||||
业务采购流程
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<#-- 业务采购流程 -->
|
||||
<div class="am-modal am-modal-prompt" tabindex="-1" id="businessProcurementProcessModal">
|
||||
<div class="am-modal-dialog">
|
||||
<div class="am-modal-hd"><strong>项目编号</strong></div>
|
||||
<div class="am-modal-bd">
|
||||
<input type="text" class="am-modal-prompt-input" placeholder="请输入项目编号或名称,支持模糊查询"/>
|
||||
</div>
|
||||
<div class="am-modal-footer">
|
||||
<span class="am-modal-btn" data-am-modal-cancel>取消</span>
|
||||
<span class="am-modal-btn" data-am-modal-confirm>查询</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<#-- 新增销售合同流程 -->
|
||||
|
||||
<div class="am-u-sm-12 am-u-md-12" v-if="isSalesContractProcessMode">
|
||||
<el-form :inline="true" ref="saleContractProcessForm" :model="processForm" label-position="right" label-width="100px">
|
||||
|
||||
<div class="am-form-inline">
|
||||
<el-tooltip :disabled="projectSelected" effect="light" content="项目编号或名称,支持模糊查询" placement="top-end">
|
||||
<el-form-item label="项目编号">
|
||||
<el-autocomplete v-model="processForm.projectNo" :fetch-suggestions="queryProject" clearable
|
||||
value-key="name" placeholder="请输入项目编号或名称" @select="handleSelectProject"
|
||||
@clear="clearProjectProcess">
|
||||
</el-autocomplete>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip :disabled="!projectSelected" effect="light" :content="projectTitle" placement="top-start">
|
||||
<el-form-item label="项目标题">
|
||||
<span v-if="projectSelected">{{projectTitle}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-form-item label="申请时间">
|
||||
<span v-if="projectSelected">{{processForm.applyDate}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="项目类型">
|
||||
<span v-if="projectSelected">{{processForm.projectType}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="合作类型">
|
||||
<span v-if="projectSelected">{{processForm.cooperationType}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<el-form-item label="申请部门" :rules="[{ required: true, message: '申请部门电话不能为空'}]" prop="applyDept">
|
||||
<el-cascader :options="applySectorOptions" clearable v-model="processForm.applyDept"></el-cascader>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="申请人">
|
||||
<span v-if="projectSelected">{{processForm.applyPersonName}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="申请部门领导">
|
||||
<span v-if="projectSelected">{{processForm.applyDeptLeaderName}}</span>
|
||||
<span v-else>未选择部门</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="申请人电话" :rules="[{ required: true, message: '申请人电话不能为空'}]" prop="applyPersonPhone">
|
||||
<el-input placeholder="请输入内容" v-model="processForm.applyPersonPhone"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<el-form-item label="合同编号" :rules="[{ required: true, message: '合同编号不能为空'}]" prop="contractNo">
|
||||
<el-input placeholder="请输入合同编号" v-model="processForm.contractNo"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="合同名称" :rules="[{ required: true, message: '合同名称不能为空'}]" prop="contractName">
|
||||
<el-input placeholder="请输入合同名称" v-model="processForm.contractName"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="合同金额">
|
||||
<span v-if="projectSelected">{{processForm.contractAmount}}元</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-form-item label="客户名称" :rules="[{ required: true, message: '客户名称不能为空'}]">
|
||||
<el-input placeholder="请输入客户名称" v-model="processForm.clientName"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="最终用户名称">
|
||||
<#--TODO 最终用户名称-->
|
||||
<span v-if="projectSelected">{{processForm.finalUserName}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-form-item label="用印类型" :rules="[{ required: true, message: '用印类型不能为空'}]">
|
||||
<el-checkbox-group v-model="processForm.sealTypes">
|
||||
<#list sealTypes as sealType>
|
||||
<el-checkbox label="${sealType.name()}" key="key-${sealType.name()}">${sealType.description}</el-checkbox>
|
||||
</#list>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<el-form-item label="税率" :rules="[{ required: true, message: '税率不能为空'}]" prop="taxRate">
|
||||
<el-select v-model="processForm.taxRate" placeholder="请选择税率">
|
||||
<#list taxRate as rate>
|
||||
<el-option label="${rate}%" value="${rate}"></el-option>
|
||||
</#list>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="是否垫资">
|
||||
<span v-if="projectSelected">{{processForm.isPrepaid}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="垫资金额">
|
||||
<span v-if="projectSelected">{{processForm.repaidAmount}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="预算毛利率">
|
||||
<span v-if="projectSelected">{{processForm.budgetGrossMargin}}</span>
|
||||
<span v-else>未选择项目</span>
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-form-item label="收款条件" :rules="[{ required: true, message: '收款条件不能为空'}]" prop="paymentTerms">
|
||||
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" cols="90" maxlength="5000" show-word-limit
|
||||
v-model="processForm.paymentTerms" placeholder="请输入收款条件(限制5000字)"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 10}" maxlength="5000" show-word-limit
|
||||
v-model="processForm.remark" placeholder="请输入备注(限制5000字)" cols="90"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-form-item label="上传附件">
|
||||
<el-upload class="upload-demo"
|
||||
action="https://jsonplaceholder.typicode.com/posts/"
|
||||
:on-preview="handlePreview"
|
||||
:on-remove="handleRemove"
|
||||
:before-remove="beforeRemove"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
:file-list="fileList">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<div slot="tip" class="el-upload__tip">只能上传PDF、excel、word、图片、压缩包,且不超过50MB</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-form-item label="合同清单明细">
|
||||
<el-button type="text" @click="goToSaleContractDetail">详细清单</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
</el-form>
|
||||
|
||||
<#-- <el-row justify="space-around" type="flex" class="row-bg">-->
|
||||
<el-row>
|
||||
<el-button type="info" @click="goToHome">返回上一级</el-button>
|
||||
<el-button type="primary" @click="saveDraft">保存草稿</el-button>
|
||||
<el-button type="success" @click="submit">提交</el-button>
|
||||
</el-row>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<#-- 销售合同清单明细 -->
|
||||
|
||||
<div class="am-u-sm-12 am-u-md-12" v-if="isSaleContractDetailMode">
|
||||
<el-table border :data="incomeDetails" @row-dblclick="dbclick">
|
||||
<el-table-column type="index" :index="1" label="序号" fixed></el-table-column>
|
||||
<el-table-column prop="name" label="名称" fixed width="120"></el-table-column>
|
||||
<el-table-column prop="type" label="类别"></el-table-column>
|
||||
<el-table-column prop="spec" label="规格型号"></el-table-column>
|
||||
<el-table-column prop="param" label="参数"></el-table-column>
|
||||
<el-table-column prop="unit" label="单位"></el-table-column>
|
||||
<el-table-column prop="amount" label="数量"></el-table-column>
|
||||
<el-table-column prop="price" label="单价" width="120"></el-table-column>
|
||||
<el-table-column prop="taxRate" label="税率"></el-table-column>
|
||||
<el-table-column prop="totalTaxInclude" label="含税金额" width="120"></el-table-column>
|
||||
<el-table-column prop="totalTaxExclude" label="不含税金额" width="120"></el-table-column>
|
||||
<el-table-column prop="totalTax" label="税金"></el-table-column>
|
||||
|
||||
<el-table-column prop="expirationDate" label="质保期" fixed="right" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-input maxlength="5" size="mini" placeholder="请输入质保期"
|
||||
v-model="scope.row.expirationDate"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<el-row style="margin: 20px 0">
|
||||
<el-button type="info" @click="goToSaleContractProcess">返回上一级</el-button>
|
||||
<el-button type="primary" @click="submitToSaleContractProcess">保存并返回上一级</el-button>
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
|
||||
<#-- 新增业务采购合同流程 -->
|
||||
|
||||
<div class="am-u-sm-12 am-u-md-12" id="newBusinessProcurementContractProcess" v-if="isBusinessProcurementContractProcessMode">
|
||||
<form role="form" id="newBusinessProcurementContractProcessForm">
|
||||
<div class="am-form-inline">
|
||||
|
||||
<div class="am-form-group">
|
||||
<label class="am-u-md-3 am-form-label">项目编号</label>
|
||||
|
||||
<el-autocomplete v-model="processForm.serialNumber" :fetch-suggestions="queryProject"
|
||||
placeholder="请输入内容" @select="handleSelectProject"></el-autocomplete>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="am-form-group">
|
||||
<label class="am-u-md-3 am-form-label">项目标题</label>
|
||||
<el-input placeholder="请输入内容" v-model="processForm.title" clearable></el-input>
|
||||
</div>
|
||||
<div class="am-form-group">
|
||||
<label class="am-u-md-3 am-form-label">申请时间</label>
|
||||
<input type="text" class="am-form-field am-u-sm-2" :value="processForm.time"/>
|
||||
</div>
|
||||
<div class="am-form-group">
|
||||
<label class="am-u-sm-3 am-form-label">采购模式</label>
|
||||
<input type="text" class="am-form-field" :value="processForm.time"/>
|
||||
</div>
|
||||
<div class="am-form-group">
|
||||
<label class="am-u-md-3 am-form-label">合作类型</label>
|
||||
<input type="text" class="am-form-field" :value="processForm.time"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="am-form-inline">
|
||||
|
||||
<div class="am-form-group am-u-md-4">
|
||||
<label class="am-form-label">申请部门</label>
|
||||
<input type="text" class="am-form-field" :value="processForm.title"/>
|
||||
<input type="text" class="am-form-field" :value="processForm.time"/>
|
||||
<input type="text" class="am-form-field" :value="processForm.time"/>
|
||||
</div>
|
||||
|
||||
<div class="am-form-group am-u-md-4">
|
||||
<label class="am-form-label">申请人</label>
|
||||
<input type="text" class="am-form-field" value="周瑾"/>
|
||||
</div>
|
||||
|
||||
<div class="am-form-group am-u-md-4">
|
||||
<label class="am-form-label">申请部门领导</label>
|
||||
<input type="text" class="am-form-field" value="尹浩"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="am-form-inline">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="am-form-inline">
|
||||
<button type="submit" class="am-btn am-btn-default">登录</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<#-- 选择 业务采购清单明细 -->
|
||||
|
||||
<div class="am-u-sm-12 am-u-md-12" v-if="isBusinessProcurementContractProcessMode">
|
||||
<el-table style="width: 100%" border>
|
||||
|
||||
<el-table-column prop="fee" label="费用项目" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="采购类别" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="产品名称" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="单位" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="数量" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="预算单价" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="税率(%)" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="含税总金额(元)" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="不含税金额(元)" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="税金(元)" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="是否垫资" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="支出时间" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="支出金额(元)" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="已采购数量" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="本次采购数量" width="180"></el-table-column>
|
||||
<el-table-column prop="fee" label="未采购数量" width="180"></el-table-column>
|
||||
|
||||
|
||||
<el-table-column prop="fee" label="供应商名称"></el-table-column>
|
||||
<el-table-column prop="fee" label="设备厂商名称"></el-table-column>
|
||||
<el-table-column prop="fee" label="对应采购清单"></el-table-column>
|
||||
<el-table-column prop="fee" label="规格型号"></el-table-column>
|
||||
<el-table-column prop="fee" label="对应采购数目"></el-table-column>
|
||||
<el-table-column prop="fee" label="采购单价"></el-table-column>
|
||||
<el-table-column prop="fee" label="含税总金额(元)"></el-table-column>
|
||||
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
|
||||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
const newBusinessProcurementContractProcess = "newBusinessProcurementContractProcess"
|
||||
const saleContractProcess = "saleContractProcess"
|
||||
const saleContractDetail = "saleContractDetail"
|
||||
const BUTTON = "btn"
|
||||
|
||||
const isEmpty = (obj) => {
|
||||
return !obj || (obj.length && obj.length === 0)
|
||||
}
|
||||
|
||||
const isNotEmpty = (obj) => {
|
||||
return !isEmpty(obj)
|
||||
}
|
||||
|
||||
const isBlank = (obj) => {
|
||||
return isEmpty(obj) || (obj.trim && isEmpty(obj.trim()))
|
||||
}
|
||||
|
||||
const hasText = (obj) => {
|
||||
return !isBlank(obj)
|
||||
}
|
||||
|
||||
const data = () => {
|
||||
return {
|
||||
mode: "btn", // btn , newBusinessProcurementContractProcess
|
||||
processForm: {
|
||||
sealTypes: [],
|
||||
},
|
||||
projectSelected: false,
|
||||
applySectorOptions: [
|
||||
{
|
||||
value: 'zhinan',
|
||||
label: '指南',
|
||||
children: [{
|
||||
value: 'shejiyuanze',
|
||||
label: '设计原则',
|
||||
children: [{
|
||||
value: 'yizhi',
|
||||
label: '一致'
|
||||
}, {
|
||||
value: 'fankui',
|
||||
label: '反馈'
|
||||
}, {
|
||||
value: 'xiaolv',
|
||||
label: '效率'
|
||||
}, {
|
||||
value: 'kekong',
|
||||
label: '可控'
|
||||
}]
|
||||
}, {
|
||||
value: 'daohang',
|
||||
label: '导航',
|
||||
children: [{
|
||||
value: 'cexiangdaohang',
|
||||
label: '侧向导航'
|
||||
}, {
|
||||
value: 'dingbudaohang',
|
||||
label: '顶部导航'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
value: 'zujian',
|
||||
label: '组件',
|
||||
children: [{
|
||||
value: 'basic',
|
||||
label: 'Basic',
|
||||
children: [{
|
||||
value: 'layout',
|
||||
label: 'Layout 布局'
|
||||
}, {
|
||||
value: 'color',
|
||||
label: 'Color 色彩'
|
||||
}, {
|
||||
value: 'typography',
|
||||
label: 'Typography 字体'
|
||||
}, {
|
||||
value: 'icon',
|
||||
label: 'Icon 图标'
|
||||
}, {
|
||||
value: 'button',
|
||||
label: 'Button 按钮'
|
||||
}]
|
||||
}, {
|
||||
value: 'form',
|
||||
label: 'Form',
|
||||
children: [{
|
||||
value: 'radio',
|
||||
label: 'Radio 单选框'
|
||||
}, {
|
||||
value: 'checkbox',
|
||||
label: 'Checkbox 多选框'
|
||||
}, {
|
||||
value: 'input',
|
||||
label: 'Input 输入框'
|
||||
}, {
|
||||
value: 'input-number',
|
||||
label: 'InputNumber 计数器'
|
||||
}, {
|
||||
value: 'select',
|
||||
label: 'Select 选择器'
|
||||
}, {
|
||||
value: 'cascader',
|
||||
label: 'Cascader 级联选择器'
|
||||
}, {
|
||||
value: 'switch',
|
||||
label: 'Switch 开关'
|
||||
}, {
|
||||
value: 'slider',
|
||||
label: 'Slider 滑块'
|
||||
}, {
|
||||
value: 'time-picker',
|
||||
label: 'TimePicker 时间选择器'
|
||||
}, {
|
||||
value: 'date-picker',
|
||||
label: 'DatePicker 日期选择器'
|
||||
}, {
|
||||
value: 'datetime-picker',
|
||||
label: 'DateTimePicker 日期时间选择器'
|
||||
}, {
|
||||
value: 'upload',
|
||||
label: 'Upload 上传'
|
||||
}, {
|
||||
value: 'rate',
|
||||
label: 'Rate 评分'
|
||||
}, {
|
||||
value: 'form',
|
||||
label: 'Form 表单'
|
||||
}]
|
||||
}, {
|
||||
value: 'data',
|
||||
label: 'Data',
|
||||
children: [{
|
||||
value: 'table',
|
||||
label: 'Table 表格'
|
||||
}, {
|
||||
value: 'tag',
|
||||
label: 'Tag 标签'
|
||||
}, {
|
||||
value: 'progress',
|
||||
label: 'Progress 进度条'
|
||||
}, {
|
||||
value: 'tree',
|
||||
label: 'Tree 树形控件'
|
||||
}, {
|
||||
value: 'pagination',
|
||||
label: 'Pagination 分页'
|
||||
}, {
|
||||
value: 'badge',
|
||||
label: 'Badge 标记'
|
||||
}]
|
||||
}, {
|
||||
value: 'notice',
|
||||
label: 'Notice',
|
||||
children: [{
|
||||
value: 'alert',
|
||||
label: 'Alert 警告'
|
||||
}, {
|
||||
value: 'loading',
|
||||
label: 'Loading 加载'
|
||||
}, {
|
||||
value: 'message',
|
||||
label: 'Message 消息提示'
|
||||
}, {
|
||||
value: 'message-box',
|
||||
label: 'MessageBox 弹框'
|
||||
}, {
|
||||
value: 'notification',
|
||||
label: 'Notification 通知'
|
||||
}]
|
||||
}, {
|
||||
value: 'navigation',
|
||||
label: 'Navigation',
|
||||
children: [{
|
||||
value: 'menu',
|
||||
label: 'NavMenu 导航菜单'
|
||||
}, {
|
||||
value: 'tabs',
|
||||
label: 'Tabs 标签页'
|
||||
}, {
|
||||
value: 'breadcrumb',
|
||||
label: 'Breadcrumb 面包屑'
|
||||
}, {
|
||||
value: 'dropdown',
|
||||
label: 'Dropdown 下拉菜单'
|
||||
}, {
|
||||
value: 'steps',
|
||||
label: 'Steps 步骤条'
|
||||
}]
|
||||
}, {
|
||||
value: 'others',
|
||||
label: 'Others',
|
||||
children: [{
|
||||
value: 'dialog',
|
||||
label: 'Dialog 对话框'
|
||||
}, {
|
||||
value: 'tooltip',
|
||||
label: 'Tooltip 文字提示'
|
||||
}, {
|
||||
value: 'popover',
|
||||
label: 'Popover 弹出框'
|
||||
}, {
|
||||
value: 'card',
|
||||
label: 'Card 卡片'
|
||||
}, {
|
||||
value: 'carousel',
|
||||
label: 'Carousel 走马灯'
|
||||
}, {
|
||||
value: 'collapse',
|
||||
label: 'Collapse 折叠面板'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
value: 'ziyuan',
|
||||
label: '资源',
|
||||
children: [{
|
||||
value: 'axure',
|
||||
label: 'Axure Components'
|
||||
}, {
|
||||
value: 'sketch',
|
||||
label: 'Sketch Templates'
|
||||
}, {
|
||||
value: 'jiaohu',
|
||||
label: '组件交互文档'
|
||||
}]
|
||||
}
|
||||
],
|
||||
fileList: [],
|
||||
// 销售合同收入明细
|
||||
incomeDetails: [],
|
||||
}
|
||||
}
|
||||
|
||||
const methods = {
|
||||
changeMode(mode) {
|
||||
this.mode = mode
|
||||
},
|
||||
|
||||
businessProcurementProcessClick() {
|
||||
const that = this
|
||||
},
|
||||
|
||||
goToHome() {
|
||||
this.changeMode(BUTTON)
|
||||
},
|
||||
|
||||
goToSaleContractProcess() {
|
||||
this.changeMode(saleContractProcess)
|
||||
},
|
||||
goToSaleContractDetail() {
|
||||
const { projectId } = this.processForm
|
||||
if (projectId) {
|
||||
this.changeMode(saleContractDetail)
|
||||
}
|
||||
else {
|
||||
this.$message.warning("项目还未选择")
|
||||
}
|
||||
},
|
||||
|
||||
dbclick(row, event, column) {
|
||||
row.input = !row.input
|
||||
},
|
||||
|
||||
render(obj) {
|
||||
console.log(obj)
|
||||
},
|
||||
|
||||
initForm(form) {
|
||||
this.processForm = { ...form, sealTypes: [] }
|
||||
},
|
||||
|
||||
queryProject(q, callback) {
|
||||
if (isBlank(q)) {
|
||||
return
|
||||
}
|
||||
fetch("${base}/process/projects?q=" + q)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.length === 0) {
|
||||
callback([{
|
||||
name: '未搜索到结果'
|
||||
}])
|
||||
}
|
||||
else {
|
||||
callback(data)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
this.$message.error('项目搜索失败');
|
||||
})
|
||||
},
|
||||
handleSelectProject(selected) {
|
||||
const { id, name } = selected
|
||||
if (!id) {
|
||||
this.initForm({})
|
||||
return
|
||||
}
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在加载项目',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
fetch("${base}/process/projects/" + id)
|
||||
.then(res => res.json())
|
||||
.then(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 + "'加载失败");
|
||||
})
|
||||
.finally(() => loading.close())
|
||||
},
|
||||
clearProjectProcess() {
|
||||
this.projectSelected = false
|
||||
this.initForm({})
|
||||
this.incomeDetails = []
|
||||
},
|
||||
|
||||
saveDraft() {
|
||||
this.processForm.status = 'draft'
|
||||
this.submit()
|
||||
},
|
||||
|
||||
submit() {
|
||||
this.$refs["saleContractProcessForm"].validate((valid) => {
|
||||
if (valid) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在提交',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
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(form),
|
||||
}).then(response => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '提交成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch(err => {
|
||||
this.$message.error("项目提交失败");
|
||||
}).finally(() => loading.close())
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
submitToSaleContractProcess() {
|
||||
this.goToSaleContractProcess()
|
||||
},
|
||||
|
||||
handleRemove(file, fileList) {
|
||||
console.log(file, fileList);
|
||||
},
|
||||
handlePreview(file) {
|
||||
console.log(file);
|
||||
},
|
||||
handleExceed(files, fileList) {
|
||||
this.$message.warning("当前限制选择 3 个文件,本次选择了 " + files.length + " 个文件,共选择了 +" + files.length + fileList.length + " 个文件");
|
||||
},
|
||||
beforeRemove(file, fileList) {
|
||||
return this.$confirm("确定移除 " + file.name + "?");
|
||||
},
|
||||
|
||||
indexMethod(index) {
|
||||
return index * 1;
|
||||
}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data,
|
||||
computed: {
|
||||
projectTitle() {
|
||||
const { projectNo, projectName, applyPersonName, applyDate } = this.processForm
|
||||
if (projectNo && projectName) {
|
||||
return projectNo.trim() + "-" + projectName.trim() + "-" + applyPersonName + "-" + applyDate
|
||||
}
|
||||
return ""
|
||||
},
|
||||
isButtonMode() {
|
||||
return this.mode === BUTTON
|
||||
},
|
||||
isBusinessProcurementContractProcessMode() {
|
||||
return this.mode === newBusinessProcurementContractProcess
|
||||
},
|
||||
isSalesContractProcessMode() {
|
||||
return this.mode === saleContractProcess
|
||||
},
|
||||
isSaleContractDetailMode() {
|
||||
return this.mode === saleContractDetail
|
||||
},
|
||||
subTitle() {
|
||||
switch (this.mode) {
|
||||
case BUTTON:
|
||||
return "新增流程"
|
||||
case saleContractProcess:
|
||||
return "新增销售合同流程"
|
||||
case saleContractDetail:
|
||||
return "销售合同清单明细"
|
||||
case newBusinessProcurementContractProcess:
|
||||
return "新增业务采购合同流程"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods,
|
||||
|
||||
mounted() {
|
||||
this.handleSelectProject({ id: 135, name: '' })
|
||||
},
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</@defaultLayout.layout>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
<#assign base=request.contextPath />
|
||||
<#import "../../common/defaultLayout.ftl" as defaultLayout>
|
||||
<@defaultLayout.layout>
|
||||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||||
<style>
|
||||
|
||||
#businessPurchaseDetailsModal {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#businessPurchaseDetailsModal > table {
|
||||
|
||||
}
|
||||
|
||||
#newBusinessProcurementContractProcess {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.el-upload__input {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.el-textarea .el-input__count {
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.admin-content-body {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.el-table__empty-block {
|
||||
height: 60px !important;
|
||||
}
|
||||
|
||||
.el-radio-button__inner, .el-radio-group {
|
||||
line-height: unset;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="admin-content" id="app">
|
||||
<div class="admin-content-body">
|
||||
<div class="am-cf am-padding">
|
||||
<div class="am-fl am-cf"><strong class="am-text-primary am-text-lg">业务应用</strong> /
|
||||
<small>待我审核</small></div>
|
||||
</div>
|
||||
|
||||
<div class="am-g">
|
||||
<div class="am-u-sm-12 am-u-md-12">
|
||||
<el-form :inline="true" ref="queryForm" :model="queryForm" label-position="right">
|
||||
|
||||
<div>
|
||||
<el-form-item label="标题">
|
||||
<el-input placeholder="请输入标题" v-model="queryForm.projectTitle"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="项目编号">
|
||||
<el-input placeholder="请输入项目编号" v-model="queryForm.projectNo"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="流程类型">
|
||||
<el-select v-model="queryForm.processType" placeholder="请选择">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<#list processTypes as processType>
|
||||
<el-option label="${processType.description}"
|
||||
value="${processType.name()}"></el-option>
|
||||
</#list>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="申请人">
|
||||
<el-input placeholder="请输入申请人" v-model="queryForm.applyPersonName"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-button type="primary" @click="queryTable">查询</el-button>
|
||||
</div>
|
||||
|
||||
</el-form>
|
||||
|
||||
<el-table border :data="tableData">
|
||||
<el-table-column type="index" :index="1" label="序号" fixed></el-table-column>
|
||||
<el-table-column prop="projectNo" label="项目编号" fixed></el-table-column>
|
||||
<el-table-column prop="projectTitle" label="标题"></el-table-column>
|
||||
<el-table-column prop="processType" label="流程类型"></el-table-column>
|
||||
<el-table-column prop="applyPersonName" label="申请人"></el-table-column>
|
||||
<el-table-column prop="status" label="审核状态"></el-table-column>
|
||||
<el-table-column prop="amount" label="当前审核人"></el-table-column>
|
||||
<el-table-column prop="lastUpdateAt" label="最后更新时间"></el-table-column>
|
||||
|
||||
<el-table-column label="操作" fixed="right" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="showDetail(scope.row, scope)">查看详情</el-button>
|
||||
<el-button type="text" @click="auditProcess(scope.row, scope)">审核</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<el-pagination style="text-align: center; margin-top: 10px"
|
||||
@current-change="handlePageChange"
|
||||
layout="prev, pager, next" :total="50"></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog title="审核" :visible.sync="auditFormVisible">
|
||||
<el-form ref="auditForm" :model="auditForm" label-width="80px">
|
||||
|
||||
<el-form-item prop="processStatus" label="审核" :rules="[{ required: true, message: '还没审核'}]">
|
||||
<el-radio-group v-model="auditForm.processStatus">
|
||||
<el-radio label="audit_passed">审核通过</el-radio>
|
||||
<el-radio label="audit_not_passed">审核不通过</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="auditOpinion" label="审核意见" :rules="[{ required: true, message: '审核意见不能为空'}]">
|
||||
<el-input type="textarea" :autosize="{ minRows: 4, maxRows: 10}"
|
||||
maxlength="5000" v-model="auditForm.auditOpinion"
|
||||
placeholder="请输入审核意见" cols="90"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitAudit">提交</el-button>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
|
||||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
const isEmpty = (obj) => {
|
||||
return !obj || (obj.length && obj.length === 0)
|
||||
}
|
||||
|
||||
const isNotEmpty = (obj) => {
|
||||
return !isEmpty(obj)
|
||||
}
|
||||
|
||||
const isBlank = (obj) => {
|
||||
return isEmpty(obj) || (obj.trim && isEmpty(obj.trim()))
|
||||
}
|
||||
|
||||
const hasText = (obj) => {
|
||||
return !isBlank(obj)
|
||||
}
|
||||
|
||||
const data = () => {
|
||||
return {
|
||||
auditForm: {
|
||||
processStatus: null
|
||||
},
|
||||
auditFormVisible: false,
|
||||
tableData: [],
|
||||
queryForm: {},
|
||||
projectSelected: false,
|
||||
fileList: [],
|
||||
// 销售合同收入明细
|
||||
incomeDetails: [],
|
||||
}
|
||||
}
|
||||
|
||||
const methods = {
|
||||
showDetail(row, scope) {
|
||||
console.log(row)
|
||||
console.log(scope)
|
||||
|
||||
},
|
||||
auditProcess(row, scope) {
|
||||
this.auditForm = {
|
||||
processId: row.id,
|
||||
processStatus: null
|
||||
}
|
||||
this.auditFormVisible = true
|
||||
},
|
||||
|
||||
submitAudit() {
|
||||
this.$refs["auditForm"].validate((valid) => {
|
||||
if (valid) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在审核',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
const form = this.auditForm
|
||||
|
||||
fetch("${base}/process/audit", {
|
||||
method: 'POST', // or 'PUT'
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(form),
|
||||
}).then(response => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '审核成功',
|
||||
type: 'success'
|
||||
})
|
||||
// 关闭对话框
|
||||
this.auditFormVisible = false
|
||||
}).catch(err => {
|
||||
this.$message.error("审核失败");
|
||||
}).finally(() => loading.close())
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
render(obj) {
|
||||
console.log(obj)
|
||||
},
|
||||
|
||||
queryTable() {
|
||||
const form = {
|
||||
...this.queryForm,
|
||||
}
|
||||
|
||||
fetch("${base}/process/query", {
|
||||
method: 'POST', // or 'PUT'
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(form),
|
||||
}).then(res => res.json())
|
||||
.then(data => {
|
||||
this.tableData = data
|
||||
})
|
||||
.catch(err => {
|
||||
this.$message.error('项目搜索失败');
|
||||
})
|
||||
},
|
||||
|
||||
handlePageChange(val) {
|
||||
console.log(`当前页:` + val)
|
||||
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data,
|
||||
computed: {
|
||||
projectTitle() {
|
||||
const { projectNo, projectName, applyPersonName, applyDate } = this.processForm
|
||||
if (projectNo && projectName) {
|
||||
return projectNo.trim() + "-" + projectName.trim() + "-" + applyPersonName + "-" + applyDate
|
||||
}
|
||||
return ""
|
||||
},
|
||||
isButtonMode() {
|
||||
return this.mode === BUTTON
|
||||
},
|
||||
isBusinessProcurementContractProcessMode() {
|
||||
return this.mode === newBusinessProcurementContractProcess
|
||||
},
|
||||
isSalesContractProcessMode() {
|
||||
return this.mode === saleContractProcess
|
||||
},
|
||||
isSaleContractDetailMode() {
|
||||
return this.mode === saleContractDetail
|
||||
},
|
||||
subTitle() {
|
||||
switch (this.mode) {
|
||||
case BUTTON:
|
||||
return "新增流程"
|
||||
case saleContractProcess:
|
||||
return "新增销售合同流程"
|
||||
case saleContractDetail:
|
||||
return "销售合同清单明细"
|
||||
case newBusinessProcurementContractProcess:
|
||||
return "新增业务采购合同流程"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods,
|
||||
|
||||
mounted() {
|
||||
this.queryTable()
|
||||
},
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</@defaultLayout.layout>
|
||||
|
Loading…
Reference in New Issue