From ab7c794dcb12bf86dd87929fd30167dd729e2c87 Mon Sep 17 00:00:00 2001 From: Harry Yang <i.take.today@gmail.com> Date: Fri, 23 Dec 2022 10:59:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=AF=B9=E6=8E=A5=EF=BC=8C?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E9=99=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/backend/ProcessController.java | 92 ++- .../work/model/process/ProcessAttachment.java | 15 + .../work/model/process/ProjectProcess.java | 3 + .../work/model/process/SealTypeArray.java | 8 + .../process/form/SaleContractProcessForm.java | 3 +- .../work/service/ProjectProcessService.java | 64 ++ src/main/resources/sql/2.0.sql | 3 +- .../admin/business/process-completed.ftl | 4 +- .../admin/business/process-detail.ftl | 648 ++++++++++++++++++ .../templates/admin/business/process-new.ftl | 7 +- .../admin/business/process-review.ftl | 4 +- .../service/ProjectProcessServiceTests.java | 27 + 12 files changed, 856 insertions(+), 22 deletions(-) create mode 100644 src/main/java/cn/palmte/work/model/process/ProcessAttachment.java create mode 100644 src/main/java/cn/palmte/work/service/ProjectProcessService.java create mode 100644 src/main/resources/templates/admin/business/process-detail.ftl create mode 100644 src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java 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 519aa8e..9eaed44 100644 --- a/src/main/java/cn/palmte/work/controller/backend/ProcessController.java +++ b/src/main/java/cn/palmte/work/controller/backend/ProcessController.java @@ -1,6 +1,7 @@ package cn.palmte.work.controller.backend; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; import org.springframework.beans.BeanUtils; import org.springframework.data.domain.Example; @@ -36,6 +37,7 @@ 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; @@ -50,6 +52,7 @@ 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.ProcessAttachment; import cn.palmte.work.model.process.ProcurementContract; import cn.palmte.work.model.process.ProjectProcess; import cn.palmte.work.model.process.ProjectProcessRepository; @@ -59,6 +62,8 @@ import cn.palmte.work.model.process.form.ProcessQueryForm; 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.service.ProjectInstanceService; +import cn.palmte.work.service.ProjectProcessService; import cn.palmte.work.utils.InterfaceUtil; import lombok.Builder; import lombok.Data; @@ -82,6 +87,8 @@ public class ProcessController { private final EntityManager entityManager; private final ProjectProcessRepository repository; + private final ProjectInstanceService projectInstanceService; + private final ProjectProcessService processService; static class FormMetadata { // 部门 @@ -132,8 +139,41 @@ public class ProcessController { return "/admin/business/process-review"; } - @GetMapping("/detail") - public String detail(Model model) { + @GetMapping("/detail/{id}") + public String detail(@PathVariable int id, Model model) { + ProjectProcess process = repository.findOne(id); + model.addAttribute("process", process); + + Project project = projectRepository.findById(process.getProjectId()); + model.addAttribute("project", project); + model.addAttribute("projectType", Enumerable.of(ProjectType.class, project.getType()).getDescription()); + model.addAttribute("cooperationType", Enumerable.of(CooperationType.class, project.getCooperateType()).getDescription()); + List<ProcessAttachment> attachments = JSONArray.parseArray(process.getAttachmentUri(), ProcessAttachment.class); + model.addAttribute("attachments", attachments); + + if (process.getProcessType() != null) { + switch (process.getProcessType()) { + case sale_contract: { + TypedQuery<SaleContract> query = entityManager.createQuery( + "from SaleContract where processId=:processId", SaleContract.class); + query.setParameter("processId", process.getId()); + SaleContract contract = query.getSingleResult(); + model.addAttribute("contract", contract); + break; + } + case business_procurement: { + TypedQuery<ProcurementContract> query = entityManager.createQuery( + "from ProcurementContract where processId=:processId", ProcurementContract.class); + query.setParameter("processId", process.getId()); + ProcurementContract contract = query.getSingleResult(); + model.addAttribute("contract", contract); + break; + } + default: + throw new UnsupportedOperationException("还不支持"); + } + } + return "/admin/business/process-detail"; } @@ -170,6 +210,8 @@ public class ProcessController { // 合同金额 public BigDecimal contractAmount; + public String terminalCustomer; + public List<ProjectBudgetIncomeDetail> incomeDetails; // FIXME 垫资 @@ -198,6 +240,7 @@ public class ProcessController { .projectNo(project.getProjectNo()) .applyPersonName(admin.getRealName()) .contractAmount(project.getContractAmount()) + .terminalCustomer(project.getTerminalCustomer()) .projectType(Enumerable.of(ProjectType.class, project.getType()).getDescription()) .cooperationType(Enumerable.of(CooperationType.class, project.getCooperateType()).getDescription()) .build(); @@ -208,15 +251,15 @@ public class ProcessController { @ResponseBody @PostMapping @Transactional - public void post(@RequestBody @Valid SaleContractProcessForm form) { + public void post(@RequestBody @Valid SaleContractProcessForm form) throws Exception { ProjectProcess entity = new ProjectProcess(); - BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate", "applyDept", "attachmentUri"); + BeanUtils.copyProperties(form, entity, "sealTypes", "applyDate", "applyDept", "attachments"); entity.setApplyDate(LocalDate.parse(form.getApplyDate(), formatter)); entity.setSealTypes(SealTypeArray.of(form.getSealTypes())); entity.setApplyDept(String.join(",", form.getApplyDept())); Admin admin = InterfaceUtil.getAdmin(); entity.setApplyPersonId(admin.getId()); - entity.setAttachmentUri(JSON.toJSONString(form.getAttachmentUri())); + entity.setAttachmentUri(JSON.toJSONString(form.getAttachments())); if (entity.getStatus() == null) { entity.setStatus(ProcessStatus.to_be_audit); @@ -224,17 +267,34 @@ public class ProcessController { entityManager.persist(entity); + HashMap<String, Object> variables = new HashMap<>(); if (entity.getProcessType() != null) { switch (entity.getProcessType()) { case sale_contract: SaleContract saleContract = SaleContract.from(form); saleContract.setProcessId(entity.getId()); entityManager.persist(saleContract); + variables.put("contract", saleContract); break; case business_procurement: ProcurementContract procurementContract = ProcurementContract.from(form); procurementContract.setProcessId(entity.getId()); entityManager.persist(procurementContract); + variables.put("contract", procurementContract); + break; + default: + throw new UnsupportedOperationException("还不支持"); + } + } + + if (entity.getStatus() == ProcessStatus.to_be_audit) { + variables.put("process", entity); + switch (entity.getProcessType()) { + case sale_contract: + projectInstanceService.startSaleContractProcess(entity.getId(), variables); + break; + case business_procurement: + projectInstanceService.startBusinessPurchaseProcess(entity.getId(), variables); break; default: throw new UnsupportedOperationException("还不支持"); @@ -302,21 +362,25 @@ public class ProcessController { @ResponseBody @PostMapping("/audit") public void audit(@RequestBody @Valid AuditForm form) { - - } - - @ResponseBody - @GetMapping("/detail/{id}") - public ProjectProcess get(@PathVariable("id") int id, Model model) { -// model.addAttribute(); - return entityManager.find(ProjectProcess.class, id); + ProjectProcess process = repository.findOne(form.processId); + // 2-通过 3-不通过 + int approveType = form.processStatus == ProcessStatus.audit_passed ? 2 : + form.processStatus == ProcessStatus.audit_not_passed ? 3 : -1; + switch (process.getProcessType()) { + case business_procurement: + projectInstanceService.completeBusinessPurchaseTask(process.getId(), approveType, form.auditOpinion); + break; + case sale_contract: + projectInstanceService.completeSaleContractTask(process.getId(), approveType, form.auditOpinion); + break; + } } @ResponseBody @PostMapping("/revoke/{id}") public void revoke(@PathVariable("id") int id) { // TODO 发起申请的人,在第一个人还没审批的情况下可以撤回 - jdbcTemplate.update("update project_process set `status` =? where id =? ", ProcessStatus.draft.getValue(), id); + processService.updateProcessStatus(id, ProcessStatus.draft); } @ResponseBody diff --git a/src/main/java/cn/palmte/work/model/process/ProcessAttachment.java b/src/main/java/cn/palmte/work/model/process/ProcessAttachment.java new file mode 100644 index 0000000..1324a4f --- /dev/null +++ b/src/main/java/cn/palmte/work/model/process/ProcessAttachment.java @@ -0,0 +1,15 @@ +package cn.palmte.work.model.process; + +import lombok.Data; + +/** + * @author <a href="https://github.com/TAKETODAY">Harry Yang</a> + * @since 2.0 2022/12/22 17:50 + */ +@Data +public class ProcessAttachment { + + private String name; + private String uri; + +} diff --git a/src/main/java/cn/palmte/work/model/process/ProjectProcess.java b/src/main/java/cn/palmte/work/model/process/ProjectProcess.java index da4a23d..2a7044b 100644 --- a/src/main/java/cn/palmte/work/model/process/ProjectProcess.java +++ b/src/main/java/cn/palmte/work/model/process/ProjectProcess.java @@ -79,6 +79,9 @@ public class ProjectProcess { // 当前审核人 private String currentAudit; + // 当前审核人ID + private String currentAuditId; + // 最后更新时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") diff --git a/src/main/java/cn/palmte/work/model/process/SealTypeArray.java b/src/main/java/cn/palmte/work/model/process/SealTypeArray.java index 0f90d38..9f0c150 100644 --- a/src/main/java/cn/palmte/work/model/process/SealTypeArray.java +++ b/src/main/java/cn/palmte/work/model/process/SealTypeArray.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.persistence.Convert; @@ -37,6 +38,13 @@ public class SealTypeArray { this.sealTypes.addAll(sealTypes); } + @Override + public String toString() { + return sealTypes.stream() + .map(SealType::getDescription) + .collect(Collectors.joining(",")); + } + // public static SealTypeArray of(SealType... sealTypes) { 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 index de25338..2bb95a6 100644 --- a/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java +++ b/src/main/java/cn/palmte/work/model/process/form/SaleContractProcessForm.java @@ -8,6 +8,7 @@ import javax.validation.constraints.NotNull; import cn.palmte.work.model.enums.ProcessStatus; import cn.palmte.work.model.enums.ProcessType; import cn.palmte.work.model.enums.ProcurementMode; +import cn.palmte.work.model.process.ProcessAttachment; import lombok.Data; /** @@ -76,5 +77,5 @@ public class SaleContractProcessForm { private String supplierName; - private List<String> attachmentUri; + private List<ProcessAttachment> attachments; } diff --git a/src/main/java/cn/palmte/work/service/ProjectProcessService.java b/src/main/java/cn/palmte/work/service/ProjectProcessService.java new file mode 100644 index 0000000..3a44f4c --- /dev/null +++ b/src/main/java/cn/palmte/work/service/ProjectProcessService.java @@ -0,0 +1,64 @@ +package cn.palmte.work.service; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; + +import cn.palmte.work.model.Admin; +import cn.palmte.work.model.enums.ProcessStatus; +import lombok.RequiredArgsConstructor; + +/** + * @author <a href="https://github.com/TAKETODAY">Harry Yang</a> + * @since 2.0 2022/12/23 09:39 + */ +@Service +@RequiredArgsConstructor +public class ProjectProcessService { + + private final JdbcTemplate jdbcTemplate; + private final EntityManager entityManager; + + /** + * 更新流程 审批人,和状态 + * + * @param processId 流程Id + * @param auditId 审批人ID + * @param status 流程状态 可以为空,为空的时候不修改 + */ + public void updateAudit(int processId, ProcessStatus status, List<Integer> auditId) { + String currentAudit = getCurrentAudit(auditId); + String currentAuditId = auditId.stream().map(String::valueOf).collect(Collectors.joining(",")); + if (status != null) { + if (!CollectionUtils.isEmpty(auditId)) { + jdbcTemplate.update( + "update project_process set current_audit=?,current_audit_id=?,status=? where id=?", currentAudit, currentAuditId, status.getValue(), processId); + } + } + else { + jdbcTemplate.update("update project_process set current_audit=?,current_audit_id=? where id=?", currentAudit, currentAuditId, processId); + } + } + + private String getCurrentAudit(List<Integer> auditId) { + TypedQuery<Admin> query = entityManager.createQuery("from Admin where id in (:ids)", Admin.class); + query.setParameter("ids", auditId); + List<Admin> resultList = query.getResultList(); + return resultList.stream().map(Admin::getRealName) + .collect(Collectors.joining(",")); + } + + /** + * 只更新状态 + */ + public void updateProcessStatus(int processId, ProcessStatus status) { + jdbcTemplate.update("update project_process set `status`=? where id=?", status.getValue(), processId); + } + +} diff --git a/src/main/resources/sql/2.0.sql b/src/main/resources/sql/2.0.sql index 0d8511c..d4f36b9 100644 --- a/src/main/resources/sql/2.0.sql +++ b/src/main/resources/sql/2.0.sql @@ -22,6 +22,7 @@ create table project_process attachment_uri text null comment '附件 JSON Array', current_audit varchar(255) null comment '当前审核人', + current_audit_id varchar(255) null comment '当前审核人ID逗号分割', create_at datetime default CURRENT_TIMESTAMP comment '创建时间', last_update_at datetime default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP comment '最后更新时间' @@ -29,7 +30,7 @@ create table project_process ); alter table project_process - add attachment_uri text null comment '附件 JSON Array'; + modify current_audit_id varchar(255) null comment '当前审核人ID逗号分割'; # 采购合同 create table procurement_contract diff --git a/src/main/resources/templates/admin/business/process-completed.ftl b/src/main/resources/templates/admin/business/process-completed.ftl index 6518124..058f36e 100644 --- a/src/main/resources/templates/admin/business/process-completed.ftl +++ b/src/main/resources/templates/admin/business/process-completed.ftl @@ -96,7 +96,7 @@ <span>{{scope.row.status | processStatus}}</span> </template> </el-table-column> - <el-table-column prop="amount" label="当前审核人" width="100"></el-table-column> + <el-table-column prop="currentAudit" label="当前审核人" width="100"></el-table-column> <el-table-column prop="lastUpdateAt" label="最后更新时间" width="170"></el-table-column> <el-table-column label="操作" fixed="right" width="230"> @@ -186,7 +186,7 @@ showDetail(row, scope) { console.log(row) console.log(scope) - + window.location = "${base}/process/detail/" + row.id; }, editProcess(row, scope) { diff --git a/src/main/resources/templates/admin/business/process-detail.ftl b/src/main/resources/templates/admin/business/process-detail.ftl new file mode 100644 index 0000000..2fc5f78 --- /dev/null +++ b/src/main/resources/templates/admin/business/process-detail.ftl @@ -0,0 +1,648 @@ +<#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; + } + + .el-upload-list__item-name [class^="el-icon"] { + 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-u-sm-12 am-u-md-12"> + <el-form :inline="true" ref="saleContractProcessForm" :model="processForm" label-position="right" label-width="100px"> + + <div class="am-form-inline"> + + <el-form-item label="项目标题"> + <span>${process.projectNo}</span> + </el-form-item> + + <el-tooltip effect="light" :content="projectTitle" placement="top-start"> + <el-form-item label="项目标题"> + <span>${process.projectTitle}</span> + </el-form-item> + </el-tooltip> + + <el-form-item label="申请时间"> + <span>${process.applyDate}</span> + </el-form-item> + + <el-form-item label="项目类型"> + <span>${projectType}</span> + </el-form-item> + + <el-form-item label="合作类型"> + <span>${cooperationType}</span> + </el-form-item> + + </div> + + <div> + + <el-form-item label="申请部门"> + <span>${process.applyDept}</span> + </el-form-item> + + <el-form-item label="申请人"> + <span>${process.applyPersonName}</span> + </el-form-item> + + <el-form-item label="申请部门领导"> + <span>${process.applyDeptLeaderName}</span> + </el-form-item> + + <el-form-item label="申请人电话" prop="applyPersonPhone"> + <span>${contract.applyPersonPhone}</span> + </el-form-item> + + </div> + + <div> + + <el-form-item label="合同编号"> + <span>${process.contractNo}</span> + </el-form-item> + + <el-form-item label="合同名称"> + <span>${process.contractName}</span> + </el-form-item> + + <el-form-item label="合同金额"> + <span>${project.contractAmount}</span> + </el-form-item> + + </div> + + <div> + <el-form-item label="客户名称" :rules="[{ required: true, message: '客户名称不能为空'}]"> + <span>${contract.clientName}</span> + </el-form-item> + + <el-form-item label="最终用户名称"> + <span>${project.terminalCustomer}</span> + </el-form-item> + </div> + + <div> + <el-form-item label="用印类型" :rules="[{ required: true, message: '用印类型不能为空'}]"> + <span>${process.sealTypes}</span> + </el-form-item> + </div> + + <div> + + <el-form-item label="税率"> + <span>${process.taxRate}</span> + </el-form-item> + + <el-form-item label="是否垫资"> + <span>${process.isPrepaid}</span> + </el-form-item> + + <el-form-item label="垫资金额"> + <span>${process.repaidAmount}</span> + </el-form-item> + + <el-form-item label="预算毛利率"> + <span>${process.budgetGrossMargin}</span> + </el-form-item> + + </div> + + <div> + <el-form-item label="收款条件"> + <el-input type="textarea" disabled :autosize="{ minRows: 3, maxRows: 10}" cols="90" maxlength="5000" show-word-limit + placeholder="请输入收款条件(限制5000字)"> + ${process.paymentTerms} + </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 + placeholder="请输入备注(限制5000字)" cols="90"> + ${process.remark} + </el-input> + </el-form-item> + </div> + + <div> + <el-form-item label="附件"> + <#list attachments as attachment> + <a href="${attachment.uri}">${attachment.name}</a> + </#list> + </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> + + </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: [], + attachmentUri: [], + attachmentMap: {} + } + } + + const methods = { + changeMode(mode) { + this.mode = mode + }, + + 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 fileList = this.fileList + console.log(fileList) + if (fileList.length === 0) { + this.$message.error("未上传附件"); + return false + } + const loading = this.$loading({ + lock: true, + text: '正在提交', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }) + + const form = { + ...this.processForm, + processType: 'sale_contract', + projectTitle: this.projectTitle, + attachmentUri: fileList.map(file => (file.response.data.url)), + 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 => { + if (response.ok) { + this.$message({ + showClose: true, + message: '提交成功', + type: 'success' + }) + } + else { + return Promise.reject("失败") + } + }).catch(err => { + this.$message.error("项目提交失败"); + }).finally(() => loading.close()) + } + else { + return false; + } + }) + }, + + submitToSaleContractProcess() { + this.goToSaleContractProcess() + }, + + handleRemove(file, fileList) { + this.fileList = fileList + }, + + handleExceed(files, fileList) { + this.$message.warning("当前限制选择只能选择10个文件"); + this.fileList = fileList + }, + + beforeRemove(file, fileList) { + return this.$confirm("确定移除 " + file.name + "?"); + }, + + handleFileUploaded(response, file, fileList) { + if (response.success) { + this.fileList = fileList + } + else { + this.$message.warning("上传失败"); + } + }, + + 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> diff --git a/src/main/resources/templates/admin/business/process-new.ftl b/src/main/resources/templates/admin/business/process-new.ftl index 142aff2..9092b3c 100644 --- a/src/main/resources/templates/admin/business/process-new.ftl +++ b/src/main/resources/templates/admin/business/process-new.ftl @@ -157,7 +157,7 @@ <el-form-item label="最终用户名称"> <#--TODO 最终用户名称--> - <span v-if="projectSelected">{{processForm.finalUserName}}</span> + <span v-if="projectSelected">{{processForm.terminalCustomer}}</span> <span v-else>未选择项目</span> </el-form-item> </div> @@ -751,7 +751,10 @@ ...this.processForm, processType: 'sale_contract', projectTitle: this.projectTitle, - attachmentUri: fileList.map(file => (file.response.data.url)), + attachments: fileList.map(file => ({ + uri: file.response.data.url, + name: file.response.data.originName + })), incomeDetails: this.incomeDetails.map(detail => ({ id: detail.id, expirationDate: detail.expirationDate })) diff --git a/src/main/resources/templates/admin/business/process-review.ftl b/src/main/resources/templates/admin/business/process-review.ftl index 274c5da..570325a 100644 --- a/src/main/resources/templates/admin/business/process-review.ftl +++ b/src/main/resources/templates/admin/business/process-review.ftl @@ -85,7 +85,7 @@ <span>{{scope.row.status | processStatus}}</span> </template> </el-table-column> - <el-table-column prop="amount" label="当前审核人" width="100"></el-table-column> + <el-table-column prop="currentAudit" label="当前审核人" width="100"></el-table-column> <el-table-column prop="lastUpdateAt" label="最后更新时间" width="170"></el-table-column> <el-table-column label="操作" fixed="right" width="140"> @@ -175,7 +175,7 @@ showDetail(row, scope) { console.log(row) console.log(scope) - + window.location = "${base}/process/detail/" + row.id; }, auditProcess(row, scope) { this.auditForm = { diff --git a/src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java b/src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java new file mode 100644 index 0000000..6da307b --- /dev/null +++ b/src/test/java/cn/palmte/work/service/ProjectProcessServiceTests.java @@ -0,0 +1,27 @@ +package cn.palmte.work.service; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; + +/** + * @author <a href="https://github.com/TAKETODAY">Harry Yang</a> + * @since 2.0 2022/12/23 10:42 + */ +@SpringBootTest +@RunWith(SpringRunner.class) +public class ProjectProcessServiceTests { + + @Autowired + ProjectProcessService projectProcessService; + +// @Test + public void testUpdateAudit() { + projectProcessService.updateAudit(2, null, Arrays.asList(93, 94)); + } + +} \ No newline at end of file