Merge remote-tracking branch 'origin/master'

This commit is contained in:
ys.git 2025-12-25 09:49:20 +08:00
commit 57d173a71d
13 changed files with 616 additions and 719 deletions

View File

@ -5,7 +5,7 @@ import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.self_development.controller.form.*; import com.xdap.self_development.controller.form.*;
import com.xdap.self_development.exception.CommonException; import com.xdap.self_development.exception.CommonException;
import com.xdap.self_development.pojo.BenchmarkingReport; import com.xdap.self_development.pojo.BenchmarkingReport;
import com.xdap.self_development.pojo.view.ApprovalFlowView; import com.xdap.self_development.pojo.view.ApprovalFlowNodeView;
import com.xdap.self_development.pojo.view.TodoAndReportView; import com.xdap.self_development.pojo.view.TodoAndReportView;
import com.xdap.self_development.service.BenchmarkingReportService; import com.xdap.self_development.service.BenchmarkingReportService;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
@ -138,7 +138,7 @@ public class BenchmarkingReportController {
public Response getReportProcess( public Response getReportProcess(
@NotBlank String flowId @NotBlank String flowId
) { ) {
ApprovalFlowView approvalFlowView = benchmarkingReportService.getReportProcess(flowId); ApprovalFlowNodeView approvalFlowView = benchmarkingReportService.getReportProcess(flowId);
return Response.ok().data(approvalFlowView); return Response.ok().data(approvalFlowView);
} }
} }

View File

@ -5,8 +5,7 @@ import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.runtime.service.RuntimeDatasourceService; import com.xdap.runtime.service.RuntimeDatasourceService;
import com.xdap.self_development.controller.form.*; import com.xdap.self_development.controller.form.*;
import com.xdap.self_development.exception.CommonException; import com.xdap.self_development.exception.CommonException;
import com.xdap.self_development.pojo.ApprovalFlow; import com.xdap.self_development.pojo.view.ApprovalFlowNodeView;
import com.xdap.self_development.pojo.view.ApprovalFlowView;
import com.xdap.self_development.pojo.view.DepartmentUserView; import com.xdap.self_development.pojo.view.DepartmentUserView;
import com.xdap.self_development.pojo.view.TemplateChangeView; import com.xdap.self_development.pojo.view.TemplateChangeView;
import com.xdap.self_development.service.TemplateApprovalService; import com.xdap.self_development.service.TemplateApprovalService;
@ -15,7 +14,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.List; import java.util.List;
@RestController @RestController
@ -122,7 +120,7 @@ public class TemplateApprovalController {
throw new CommonException(error.getDefaultMessage()); throw new CommonException(error.getDefaultMessage());
}); });
} }
ApprovalFlowView approvalFlowView = templateApprovalService.getApprovalProcess(form); ApprovalFlowNodeView approvalFlowView = templateApprovalService.getApprovalProcess(form);
return Response.ok().data(approvalFlowView); return Response.ok().data(approvalFlowView);
} }
} }

View File

@ -1,5 +1,6 @@
package com.xdap.self_development.controller.form; package com.xdap.self_development.controller.form;
import com.xdap.self_development.pojo.dto.ApprovalNodeDTO;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
@ -8,19 +9,15 @@ import java.util.List;
@Data @Data
public class ApprovalPersonForm { public class ApprovalPersonForm {
@NotEmpty(message = "创建者不能为空")
private String userId;
@NotEmpty(message = "报告不能为空") @NotEmpty(message = "报告不能为空")
private String reportId; private String reportId;
@NotBlank(message = "流程标题不能为空") @NotBlank(message = "流程标题不能为空")
private String processTitle; private String processTitle;
@NotEmpty(message = "校对人员不能为空") // 审批环节配置列表
private List<String> proofreadUsers; @NotEmpty(message = "环节不能为空")
@NotEmpty(message = "审核人员不能为空") private List<ApprovalNodeDTO> nodeList;
private List<String> reviewUsers;
private List<String> countersignUsers; // 可选
@NotEmpty(message = "批准人员不能为空")
private List<String> approveUsers;
private String explanation; private String explanation;
@NotEmpty(message = "创建者不能为空")
private String userId;
} }

View File

@ -1,5 +1,6 @@
package com.xdap.self_development.controller.form; package com.xdap.self_development.controller.form;
import com.xdap.self_development.pojo.dto.ApprovalNodeDTO;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
@ -15,14 +16,8 @@ public class StartApprovalRequest {
private String processTitle; private String processTitle;
@NotBlank(message = "请选择审核内容") @NotBlank(message = "请选择审核内容")
private String templateRowId; private String templateRowId;
@NotEmpty(message = "校对人员不能为空") // 审批环节配置列表
private List<String> proofreadUsers; @NotEmpty(message = "环节不能为空")
@NotEmpty(message = "审核人员不能为空") private List<ApprovalNodeDTO> nodeList;
private List<String> reviewUsers;
private List<String> countersignUsers; // 可选
@NotEmpty(message = "批准人员不能为空")
private List<String> approveUsers;
private String explanation; private String explanation;
} }

View File

@ -18,15 +18,10 @@ public class ApprovalFlow extends MpaasBasePojo {
private String id; private String id;
private String processTitle; private String processTitle;
private String templateId; private String templateId;
private String currentNode; // 节点PROOFREAD, REVIEW, COUNTERSIGN, APPROVE private Integer currentNode; // 节点PROOFREAD, REVIEW, COUNTERSIGN, APPROVE
private String flowStatus; //DRAFT(草稿)APPROVING审批中COMPLETE(已完成)RETURNED(已撤回)REJECTED(已拒绝) private String flowStatus; //DRAFT(草稿)APPROVING审批中COMPLETE(已完成)RETURNED(已撤回)REJECTED(已拒绝)
private Integer returnNum; private Integer returnNum;
private String proofreadUsers; // 校对人员
private String reviewUsers; // 审核人员
private String countersignUsers; // 会签人员
private String approveUsers; // 批准人员
private String createBy; private String createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp createdTime; private Timestamp createdTime;

View File

@ -5,17 +5,13 @@ import lombok.Data;
import java.util.List; import java.util.List;
@Data @Data
public class ApprovalFlowView { public class ApprovalFlowNodeView {
private String explanation; private String explanation;
private List<ApprovalNodeView> proofreadNodes;
private List<ApprovalNodeView> reviewNodes;
private List<ApprovalNodeView> countersignNodes;
private List<ApprovalNodeView> approveNodes;
private String flowStatus; private String flowStatus;
private String progressTitle; private String progressTitle;
private String ContentName; private String ContentName;
private Integer templateVersion; private Integer templateVersion;
private List<FlowNode> flowNodes;
} }

View File

@ -0,0 +1,26 @@
package com.xdap.self_development.pojo.view;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.sql.Timestamp;
import java.util.List;
@Data
public class FlowNode {
// 节点名
private String node;
// 节点处理人
private String todoUserName;
// 节点未处理人
private String undoUserName;
// 处理意见
private List<String> opinions;
// 节点状态
private String result; // PASS, REJECT
// 节点顺序
private Integer nodeOrder;
// 节点处理时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp approvalTime;
}

View File

@ -11,7 +11,7 @@ import java.util.List;
@SQLQuery(value = { @SQLQuery(value = {
@SQL(view = "getAllReportApprovalList", @SQL(view = "getAllReportApprovalList",
sql = "SELECT af.id AS \"flowId\", r.id AS \"reportId\", r.title AS \"title\", af.flow_status AS \"status\", af.create_by AS \"createBy\" , xu.username AS \"username\", af.created_time AS \"createdTime\" , CASE WHEN current_node = 'PROOFREAD' THEN proofread_users WHEN current_node = 'REVIEW' THEN review_users WHEN current_node = 'COUNTERSIGN' THEN countersign_users WHEN current_node = 'APPROVE' THEN approve_users END AS current_users FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_benchmarking_report r ON af.template_id = r.id LEFT JOIN xdap_users xu ON xu.id = af.create_by WHERE af.flow_type = 2 AND r.title LIKE CONCAT('%', #title, '%') AND af.flow_status LIKE CONCAT('%', #status, '%') AND af.created_time LIKE CONCAT('%', #createdTime, '%') AND xu.username LIKE CONCAT('%', #username, '%') ORDER BY CASE af.flow_status WHEN 'COMPLETE' THEN 1 WHEN 'APPROVING' THEN 2 WHEN 'DRAFT' THEN 3 WHEN 'REJECTED' THEN 4 ELSE 5 END ASC, af.created_time DESC") sql = "SELECT af.id AS \"flowId\", r.id AS \"reportId\", r.title AS \"title\", af.flow_status AS \"status\", af.create_by AS \"createBy\" , xu.username AS \"username\", af.created_time AS \"createdTime\", ac.assignees AS current_users FROM yfsjglpt_model_approval_flow af JOIN approval_config ac ON af.id = ac.approval_id AND af.current_node = ac.node_order JOIN yfsjglpt_model_benchmarking_report r ON af.template_id = r.id LEFT JOIN xdap_users xu ON xu.id = af.create_by WHERE af.flow_type = 2 AND r.title LIKE CONCAT('%', #title, '%') AND af.flow_status LIKE CONCAT('%', #status, '%') AND af.created_time LIKE CONCAT('%', #createdTime, '%') AND xu.username LIKE CONCAT('%', #username, '%') ORDER BY CASE af.flow_status WHEN 'COMPLETE' THEN 1 WHEN 'APPROVING' THEN 2 WHEN 'DRAFT' THEN 3 WHEN 'REJECTED' THEN 4 ELSE 5 END ASC, af.created_time DESC")
}) })
@Data @Data
public class TodoAndReportListView { public class TodoAndReportListView {

View File

@ -11,7 +11,7 @@ import java.util.List;
@SQLQuery(value = { @SQLQuery(value = {
@SQL(view = "getAllApproval", @SQL(view = "getAllApproval",
sql = "SELECT af.id AS \"flowId\", t.id AS \"templateId\", t.template_name AS \"templateName\", t.version AS \"version\", af.flow_status AS \"status\" , af.create_by AS \"createBy\" , xu.username AS \"username\", af.created_time AS \"createdTime\" , CASE WHEN current_node = 'PROOFREAD' THEN proofread_users WHEN current_node = 'REVIEW' THEN review_users WHEN current_node = 'COUNTERSIGN' THEN countersign_users WHEN current_node = 'APPROVE' THEN approve_users END AS current_users FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_template t ON af.template_id = t.id LEFT JOIN xdap_users xu ON xu.id = af.create_by WHERE t.template_name LIKE CONCAT('%', #templateName, '%') AND af.flow_status LIKE CONCAT('%', #status, '%') AND af.created_time LIKE CONCAT('%', #createdTime, '%') AND xu.username LIKE CONCAT('%', #username, '%') AND af.flow_type = 1 ORDER BY CASE af.flow_status WHEN 'COMPLETE' THEN 1 WHEN 'APPROVING' THEN 2 WHEN 'DRAFT' THEN 3 WHEN 'REJECTED' THEN 4 ELSE 5 END ASC"), sql = "SELECT af.id AS \"flowId\", t.id AS \"templateId\", t.template_name AS \"templateName\", t.version AS \"version\", af.flow_status AS \"status\" , af.create_by AS \"createBy\", xu.username AS \"username\", af.created_time AS \"createdTime\", ac.assignees AS current_users FROM yfsjglpt_model_approval_flow af JOIN approval_config ac ON af.id = ac.approval_id AND af.current_node = ac.node_order JOIN yfsjglpt_model_template t ON af.template_id = t.id LEFT JOIN xdap_users xu ON xu.id = af.create_by WHERE t.template_name LIKE CONCAT('%', #templateName, '%') AND af.flow_status LIKE CONCAT('%', #status, '%') AND af.created_time LIKE CONCAT('%', #createdTime, '%') AND xu.username LIKE CONCAT('%', #username, '%') AND af.flow_type = 1 ORDER BY CASE af.flow_status WHEN 'COMPLETE' THEN 1 WHEN 'APPROVING' THEN 2 WHEN 'DRAFT' THEN 3 WHEN 'REJECTED' THEN 4 ELSE 5 END ASC"),
@SQL(view = "getApprovalByUserIdAndIds", @SQL(view = "getApprovalByUserIdAndIds",
sql = "SELECT af.id AS \"flowId\", t.id AS \"templateId\", t.template_name AS \"templateName\", t.version AS \"version\", af.flow_status AS \"status\" , af.create_by AS \"createBy\", af.created_time AS \"createdTime\" , CASE WHEN current_node = 'PROOFREAD' THEN proofread_users WHEN current_node = 'REVIEW' THEN review_users WHEN current_node = 'COUNTERSIGN' THEN countersign_users WHEN current_node = 'APPROVE' THEN approve_users END AS current_users FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_template t ON af.template_id = t.id WHERE t.template_name like CONCAT('%',#templateName, '%') and af.flow_status like CONCAT('%',#status, '%') and af.flow_type = 1 and af.id NOT IN (#ids) AND af.create_by = #createBy"), sql = "SELECT af.id AS \"flowId\", t.id AS \"templateId\", t.template_name AS \"templateName\", t.version AS \"version\", af.flow_status AS \"status\" , af.create_by AS \"createBy\", af.created_time AS \"createdTime\" , CASE WHEN current_node = 'PROOFREAD' THEN proofread_users WHEN current_node = 'REVIEW' THEN review_users WHEN current_node = 'COUNTERSIGN' THEN countersign_users WHEN current_node = 'APPROVE' THEN approve_users END AS current_users FROM yfsjglpt_model_approval_flow af JOIN yfsjglpt_model_template t ON af.template_id = t.id WHERE t.template_name like CONCAT('%',#templateName, '%') and af.flow_status like CONCAT('%',#status, '%') and af.flow_type = 1 and af.id NOT IN (#ids) AND af.create_by = #createBy"),
@SQL(view = "getTodoAndTemplate", @SQL(view = "getTodoAndTemplate",

View File

@ -3,7 +3,7 @@ package com.xdap.self_development.service;
import com.definesys.mpaas.query.db.PageQueryResult; import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.self_development.controller.form.*; import com.xdap.self_development.controller.form.*;
import com.xdap.self_development.pojo.BenchmarkingReport; import com.xdap.self_development.pojo.BenchmarkingReport;
import com.xdap.self_development.pojo.view.ApprovalFlowView; import com.xdap.self_development.pojo.view.ApprovalFlowNodeView;
import com.xdap.self_development.pojo.view.TodoAndReportListView; import com.xdap.self_development.pojo.view.TodoAndReportListView;
import com.xdap.self_development.pojo.view.TodoAndReportView; import com.xdap.self_development.pojo.view.TodoAndReportView;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -25,7 +25,7 @@ public interface BenchmarkingReportService {
BenchmarkingReport getReportDetail(@NotBlank String reportId); BenchmarkingReport getReportDetail(@NotBlank String reportId);
ApprovalFlowView getReportProcess(@NotBlank String flowId); ApprovalFlowNodeView getReportProcess(@NotBlank String flowId);
String uploadFile(MultipartFile file, @NotBlank String createBy); String uploadFile(MultipartFile file, @NotBlank String createBy);

View File

@ -2,7 +2,7 @@ package com.xdap.self_development.service;
import com.definesys.mpaas.query.db.PageQueryResult; import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.self_development.controller.form.*; import com.xdap.self_development.controller.form.*;
import com.xdap.self_development.pojo.view.ApprovalFlowView; import com.xdap.self_development.pojo.view.ApprovalFlowNodeView;
import com.xdap.self_development.pojo.view.TemplateChangeView; import com.xdap.self_development.pojo.view.TemplateChangeView;
import com.xdap.self_development.pojo.view.TodoAndTemplateView; import com.xdap.self_development.pojo.view.TodoAndTemplateView;
@ -17,7 +17,7 @@ public interface TemplateApprovalService {
PageQueryResult<TemplateChangeView> getTemplateChanges(@Valid ApprovalAndParameterForm form); PageQueryResult<TemplateChangeView> getTemplateChanges(@Valid ApprovalAndParameterForm form);
ApprovalFlowView getApprovalProcess(@Valid ApprovalFlowForm form); ApprovalFlowNodeView getApprovalProcess(@Valid ApprovalFlowForm form);
void handleReturn(@Valid HandleApprovalRequest request); void handleReturn(@Valid HandleApprovalRequest request);
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.definesys.mpaas.query.db.PageQueryResult; import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.api.moudle.user.pojo.XdapUsers;
import com.xdap.runtime.service.RuntimeAppContextService; import com.xdap.runtime.service.RuntimeAppContextService;
import com.xdap.self_development.config.BusinessDatabase; import com.xdap.self_development.config.BusinessDatabase;
import com.xdap.self_development.controller.form.*; import com.xdap.self_development.controller.form.*;
@ -13,10 +14,8 @@ import com.xdap.self_development.feign.dto.AppTokenDTO;
import com.xdap.self_development.feign.dto.FileUploadDTO; import com.xdap.self_development.feign.dto.FileUploadDTO;
import com.xdap.self_development.feign.dto.UserTokenDT0; import com.xdap.self_development.feign.dto.UserTokenDT0;
import com.xdap.self_development.pojo.*; import com.xdap.self_development.pojo.*;
import com.xdap.self_development.pojo.view.ApprovalFlowView; import com.xdap.self_development.pojo.dto.ApprovalNodeDTO;
import com.xdap.self_development.pojo.view.ApprovalNodeView; import com.xdap.self_development.pojo.view.*;
import com.xdap.self_development.pojo.view.TodoAndReportListView;
import com.xdap.self_development.pojo.view.TodoAndReportView;
import com.xdap.self_development.service.BenchmarkingReportService; import com.xdap.self_development.service.BenchmarkingReportService;
import com.xdap.self_development.service.XdapDeptUsersService; import com.xdap.self_development.service.XdapDeptUsersService;
import com.xdap.self_development.utils.RedisLockUtil; import com.xdap.self_development.utils.RedisLockUtil;
@ -56,13 +55,77 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
private static final String FLOW_LOCK_PREFIX = "report:lock:"; private static final String FLOW_LOCK_PREFIX = "report:lock:";
private static final int FLOW_LOCK_EXPIRE_SECONDS = 15; private static final int FLOW_LOCK_EXPIRE_SECONDS = 15;
private String getNodeName(String node) { @Override
switch (node) { @Transactional(rollbackFor = Exception.class)
case "PROOFREAD": return "校对"; public void startReportApproval(ApprovalPersonForm form) {
case "REVIEW": return "SE审核"; BenchmarkingReport report = bd.getBusinessDatabase()
case "APPROVE": return "部门长审核"; .eq("id", form.getReportId())
default: return "-"; .doQueryFirst(BenchmarkingReport.class);
ApprovalFlow approvalFlow = bd.getBusinessDatabase()
.eq("template_id", report.getId())
.doQueryFirst(ApprovalFlow.class);
if (approvalFlow != null && Objects.equals(approvalFlow.getFlowStatus(), "APPROVING")) {
throw new CommonException("该报告正在审批中,请勿重复发起审批");
} }
// 创建审批流程
ApprovalFlow flow = new ApprovalFlow();
flow.setTemplateId(report.getId());
flow.setCurrentNode(1);
flow.setFlowStatus("APPROVING");
flow.setProcessTitle(form.getProcessTitle());
flow.setCreateBy(form.getUserId());
flow.setCreatedTime(Timestamp.valueOf(LocalDateTime.now()));
flow.setFlowType(2); // 设置为报告审批流程
flow.setExplanation(form.getExplanation());
flow.setProcessTitle(form.getProcessTitle());
bd.getBusinessDatabase().doInsert(flow);
// 创建审批配置
List<ApprovalConfigPojo> approvalConfigs = new ArrayList<>();
ApprovalNodeDTO firstNode = new ApprovalNodeDTO();
for (ApprovalNodeDTO node : form.getNodeList()) {
if (node.getNodeOrder() == 1) {
firstNode.setNodeOrder(1);
firstNode.setAssignees(node.getAssignees());
firstNode.setNodeName(node.getNodeName());
}
ApprovalConfigPojo config = new ApprovalConfigPojo();
config.setNodeName(node.getNodeName());
config.setNodeOrder(node.getNodeOrder());
config.setAssignees(JSON.toJSONString(node.getAssignees()));
config.setApprovalId(flow.getId());
approvalConfigs.add(config);
}
bd.getBusinessDatabase().doBatchInsert(approvalConfigs);
List<TodoTaskPojo> list = new ArrayList<>();
for (String person : firstNode.getAssignees()) {
TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(form.getUserId());
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(form.getUserId()).getUsername());
todoTask.setCurrentNode("");
todoTask.setDataType("对标报告审核");
todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
todoTask.setIsDelete(0);
todoTask.setModelId(report.getId());
todoTask.setModelName(report.getProjectName() + "对标报告");
todoTask.setProcessTitle(form.getProcessTitle());
todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(1);
todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(firstNode.getAssignees()));
list.add(todoTask);
}
bd.getBusinessDatabase().doBatchInsert(list);
// 更新报告状态为校对中
bd.getBusinessDatabase()
.eq("id", report.getId())
.update("status", "APPROVING")
.doUpdate(BenchmarkingReport.class);
} }
@Override @Override
@ -161,61 +224,6 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
bd.getBusinessDatabase().doInsert(report); bd.getBusinessDatabase().doInsert(report);
} }
@Override
public void startReportApproval(ApprovalPersonForm form) {
BenchmarkingReport report = bd.getBusinessDatabase()
.eq("id", form.getReportId())
.doQueryFirst(BenchmarkingReport.class);
ApprovalFlow approvalFlow = bd.getBusinessDatabase()
.eq("template_id", report.getId())
.doQueryFirst(ApprovalFlow.class);
if (approvalFlow != null && Objects.equals(approvalFlow.getFlowStatus(), "APPROVING")) {
throw new CommonException("该报告正在审批中,请勿重复发起审批");
}
ApprovalFlow flow = new ApprovalFlow();
flow.setTemplateId(report.getId());
flow.setCurrentNode("PROOFREAD");
flow.setFlowStatus("APPROVING");
flow.setProofreadUsers(JSON.toJSONString(form.getProofreadUsers()));
flow.setReviewUsers(JSON.toJSONString(form.getReviewUsers()));
flow.setCountersignUsers(JSON.toJSONString(form.getCountersignUsers()));
flow.setApproveUsers(JSON.toJSONString(form.getApproveUsers()));
flow.setCreateBy(form.getUserId());
flow.setCreatedTime(Timestamp.valueOf(LocalDateTime.now()));
flow.setFlowType(2); // 设置为报告审批流程
flow.setExplanation(form.getExplanation());
flow.setProcessTitle(form.getProcessTitle());
bd.getBusinessDatabase().doInsert(flow);
bd.getBusinessDatabase()
.eq("id", report.getId())
.update("status", "APPROVING")
.doUpdate(BenchmarkingReport.class);
List<TodoTaskPojo> list = new ArrayList<>();
for (String person : form.getProofreadUsers()) {
TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(form.getUserId());
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(form.getUserId()).getUsername());
todoTask.setCurrentNode(getNodeName(flow.getCurrentNode()));
todoTask.setDataType("对标报告审核");
todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
todoTask.setIsDelete(0);
todoTask.setModelId(report.getId());
todoTask.setModelName(report.getProjectName()+"对标报告");
todoTask.setProcessTitle(form.getProcessTitle());
todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(1);
todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(getNodeUsers(flow, flow.getCurrentNode())));
list.add(todoTask);
}
bd.getBusinessDatabase().doBatchInsert(list);
}
@Override @Override
public void updateReport(UpdateBenchmarkingReportForm form) { public void updateReport(UpdateBenchmarkingReportForm form) {
BenchmarkingReport report = bd.getBusinessDatabase() BenchmarkingReport report = bd.getBusinessDatabase()
@ -247,6 +255,7 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void handleReportApproval(HandleApprovalRequest request) { public void handleReportApproval(HandleApprovalRequest request) {
// 验证流程状态
ApprovalFlow flow = bd.getBusinessDatabase() ApprovalFlow flow = bd.getBusinessDatabase()
.eq("id", request.getFlowId()) .eq("id", request.getFlowId())
.eq("flow_type", 2) .eq("flow_type", 2)
@ -255,10 +264,15 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
throw new CommonException("流程不存在或已结束"); throw new CommonException("流程不存在或已结束");
} }
String currentNode = flow.getCurrentNode(); // 获取当前流程节点
ApprovalConfigPojo currentNode = bd.getBusinessDatabase()
.eq("approval_id", flow.getId())
.eq("node_order", flow.getCurrentNode())
.doQueryFirst(ApprovalConfigPojo.class);
// 验证当前用户是否有权限处理 // 验证当前用户是否有权限处理
if (!hasPermission(flow, currentNode, request.getUserId())) { if (!hasPermission(currentNode, request.getUserId())) {
throw new CommonException("无权限处理"); throw new CommonException("无权限处理或已被处理");
} }
String lockKey = FLOW_LOCK_PREFIX + flow.getId() + ":" + currentNode; String lockKey = FLOW_LOCK_PREFIX + flow.getId() + ":" + currentNode;
@ -272,7 +286,7 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
int processedCount = bd.getBusinessDatabase() int processedCount = bd.getBusinessDatabase()
.eq("document_no", flow.getId()) .eq("document_no", flow.getId())
.eq("is_delete", 1) .eq("is_delete", 1)
.eq("current_node", getNodeName(flow.getCurrentNode())) .eq("current_node", currentNode.getNodeName())
.doQuery(TodoTaskPojo.class).size(); .doQuery(TodoTaskPojo.class).size();
if (processedCount > 0) { if (processedCount > 0) {
throw new CommonException("此节点已被他人处理"); throw new CommonException("此节点已被他人处理");
@ -283,6 +297,142 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
} }
} }
// 验证是否为当前处理人
private boolean hasPermission(ApprovalConfigPojo node, String userId) {
return JSON.parseArray(node.getAssignees())
.toJavaList(String.class).contains(userId);
}
public void processApprovalLogic(ApprovalFlow flow, HandleApprovalRequest request, ApprovalConfigPojo currentNode) {
// 记录审批结果
ApprovalRecord record = new ApprovalRecord();
record.setFlowId(flow.getId());
record.setNode(currentNode.getNodeName());
record.setUserId(request.getUserId());
record.setOpinion(request.getOpinion());
record.setResult(request.getResult());
record.setApprovalTime(Timestamp.valueOf(LocalDateTime.now()));
bd.getBusinessDatabase().doInsert(record);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("owner_id", request.getUserId())
.eq("current_node", currentNode.getNodeName())
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.update("is_delete", 1)
.doUpdate(TodoTaskPojo.class);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.ne("owner_id", request.getUserId())
.eq("current_node", currentNode.getNodeName())
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.update("is_delete", 2)
.doUpdate(TodoTaskPojo.class);
// 处理驳回逻辑
if ("REJECT".equals(request.getResult())) {
cancelProcess(flow, "REJECTED", request.getUserId());
return;
}
// 处理通过逻辑流转到下一节点
processNextNode(flow, currentNode, request.getUserId());
}
private void processNextNode(ApprovalFlow flow, ApprovalConfigPojo currentNode, String userId) {
// 更新报告状态
BenchmarkingReport report = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(BenchmarkingReport.class);
// 获取下一个节点
ApprovalConfigPojo nextNode = bd.getBusinessDatabase()
.eq("approval_id", flow.getId())
.eq("node_order", currentNode.getNodeOrder() + 1)
.doQueryFirst(ApprovalConfigPojo.class);
if (nextNode == null) {
// 流程结束
flow.setFlowStatus("COMPLETE");
flow.setCurrentNode(null);
report.setStatus("COMPLETE");
bd.getBusinessDatabase()
.rowid("id", report.getRowId())
.update("status", report.getStatus())
.doUpdate(BenchmarkingReport.class);
// 待办环节修改
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已完成")
.doUpdate(TodoTaskPojo.class);
} else {
flow.setCurrentNode(1);
addNodeTodo(flow, nextNode, report, userId);
}
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.update("current_node", flow.getCurrentNode())
.doUpdate(ApprovalFlow.class);
}
private void addNodeTodo(ApprovalFlow flow, ApprovalConfigPojo node, BenchmarkingReport report, String createBy) {
List<String> users = JSON.parseArray(node.getAssignees()).toJavaList(String.class);
// 新增待办
List<TodoTaskPojo> list = new ArrayList<>();
for (String person : users) {
TodoTaskPojo todoTaskPojo = bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("owner_id", person).doQueryFirst(TodoTaskPojo.class);
if (todoTaskPojo != null) {
todoTaskPojo.setCurrentNode(node.getNodeName());
todoTaskPojo.setCurrentProcessor(JSON.toJSONString(node.getAssignees()));
bd.getBusinessDatabase().doUpdate(todoTaskPojo);
bd.getBusinessDatabase().doUpdate(todoTaskPojo);
} else {
TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(createBy);
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(createBy).getUsername());
todoTask.setCurrentNode("1");
todoTask.setDataType("对标报告审核");
todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
todoTask.setIsDelete(0);
todoTask.setModelId(report.getId());
todoTask.setModelName(report.getProjectName() + "对标报告");
todoTask.setProcessTitle(flow.getProcessTitle());
todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(1);
todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(node.getAssignees()));
list.add(todoTask);
}
}
bd.getBusinessDatabase().doBatchInsert(list);
}
private void cancelProcess(ApprovalFlow flow, String status, String userId) {
flow.setFlowStatus(status);
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.doUpdate(ApprovalFlow.class);
// 更新报告状态
BenchmarkingReport report = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(BenchmarkingReport.class);
report.setStatus(status);
bd.getBusinessDatabase()
.rowid("id", report.getRowId())
.update("status", report.getStatus())
.doUpdate(BenchmarkingReport.class);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已拒绝")
.doUpdate(TodoTaskPojo.class);
// 清除所有待办
clearAllTodo(flow, userId);
}
@Override @Override
public BenchmarkingReport getReportDetail(String reportId) { public BenchmarkingReport getReportDetail(String reportId) {
return bd.getBusinessDatabase() return bd.getBusinessDatabase()
@ -293,88 +443,71 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
} }
@Override @Override
public ApprovalFlowView getReportProcess(String flowId) { public ApprovalFlowNodeView getReportProcess(String flowId) {
ApprovalFlowView approvalFlowView = new ApprovalFlowView(); ApprovalFlowNodeView flowNodeView = new ApprovalFlowNodeView();
ApprovalFlow flow = bd.getBusinessDatabase() ApprovalFlow approvalFlow = bd.getBusinessDatabase()
.eq("id", flowId) .eq("id", flowId)
.eq("flow_type", 2)
.doQueryFirst(ApprovalFlow.class); .doQueryFirst(ApprovalFlow.class);
// 无流程创建空返回
if (flowId == null || flowId.isEmpty() || flow == null) { if (approvalFlow == null) {
return approvalFlowView; return flowNodeView;
} }
approvalFlowView.setExplanation(flow.getExplanation()); BenchmarkingReport report = bd.getBusinessDatabase()
approvalFlowView.setFlowStatus(flow.getFlowStatus()); .eq("id", approvalFlow.getTemplateId())
if (!"APPROVING".equals(flow.getFlowStatus())) { .doQueryFirst(BenchmarkingReport.class);
setAllCompletedNodes(approvalFlowView, flow); // 获取流程信息
return approvalFlowView; flowNodeView.setProgressTitle(approvalFlow.getProcessTitle());
} flowNodeView.setContentName(report.getTitle());
processApprovalNodes(approvalFlowView, flow); flowNodeView.setTemplateVersion(1);
return approvalFlowView; flowNodeView.setExplanation(approvalFlow.getExplanation());
} flowNodeView.setFlowStatus(approvalFlow.getFlowStatus());
// 获取节点信息
private void setAllCompletedNodes(ApprovalFlowView view, ApprovalFlow flow) { List<ApprovalConfigPojo> nodes = bd.getBusinessDatabase()
view.setProofreadNodes(getNodeList(flow.getId(), "PROOFREAD")); .eq("approval_id", flowId)
view.setReviewNodes(getNodeList(flow.getId(), "REVIEW")); .doQuery(ApprovalConfigPojo.class);
view.setApproveNodes(getNodeList(flow.getId(), "APPROVE")); List<FlowNode> flowNodes = new ArrayList<>();
} nodes.forEach(node -> {
FlowNode nodeView = new FlowNode();
private void processApprovalNodes(ApprovalFlowView view, ApprovalFlow flow) { ApprovalRecord record = bd.getBusinessDatabase()
// 处理校对节点 .eq("flow_id", flowId)
List<ApprovalNodeView> proofreadNodes = getNodeList(flow.getId(), "PROOFREAD"); .eq("node", node.getNodeName())
if (proofreadNodes.isEmpty()) { .doQueryFirst(ApprovalRecord.class);
view.setProofreadNodes(createApprovingNode(flow.getProofreadUsers())); if (record != null) {
view.setReviewNodes(new ArrayList<>()); // 节点已完成
view.setApproveNodes(new ArrayList<>()); nodeView.setNodeOrder(node.getNodeOrder());
return; nodeView.setNode(node.getNodeName());
} nodeView.setResult(record.getResult());
view.setProofreadNodes(proofreadNodes); nodeView.setOpinions(Collections.singletonList(getUserNames(Collections.singletonList(record.getUserId())) + ":" + record.getOpinion()));
nodeView.setApprovalTime(record.getApprovalTime());
// 处理审核节点 nodeView.setTodoUserName(getUserNames(Collections.singletonList(record.getUserId())));
List<ApprovalNodeView> reviewNodes = getNodeList(flow.getId(), "REVIEW"); nodeView.setUndoUserName(getUserNames(JSON.parseArray(node.getAssignees()).toJavaList(String.class)));
if (reviewNodes.isEmpty()) {
view.setReviewNodes(createApprovingNode(flow.getReviewUsers()));
view.setApproveNodes(new ArrayList<>());
return;
}
view.setReviewNodes(reviewNodes);
List<ApprovalNodeView> approveNodes = getNodeList(flow.getId(), "APPROVE");
if (approveNodes.isEmpty()) {
view.setApproveNodes(createApprovingNode(flow.getApproveUsers()));
} else { } else {
view.setApproveNodes(approveNodes); // 节点未完成
nodeView.setNodeOrder(node.getNodeOrder());
nodeView.setNode(node.getNodeName());
nodeView.setResult("待审批");
nodeView.setTodoUserName("");
nodeView.setUndoUserName(getUserNames(JSON.parseArray(node.getAssignees()).toJavaList(String.class)));
} }
flowNodes.add(nodeView);
});
List<FlowNode> sortedNode = flowNodes.stream().sorted(Comparator.comparing(FlowNode::getNodeOrder)).collect(Collectors.toList());
flowNodeView.setFlowNodes(sortedNode);
return flowNodeView;
} }
private List<ApprovalNodeView> createApprovingNode(String userJsonArray) { private String getUserNames(List<String> userIds) {
List<ApprovalNodeView> list = new ArrayList<>(); StringJoiner joiner = new StringJoiner(" ");
for (String userId : userIds) {
if (userJsonArray == null || userJsonArray.trim().isEmpty()) { String username = bd.getBusinessDatabase().eq("id", userId).doQueryFirst(XdapUsers.class).getUsername();
return list; if (username != null) {
} joiner.add(username);
} else {
List<String> userIds = JSON.parseArray(userJsonArray).toJavaList(String.class); // 处理空值情况
if (userIds.isEmpty()) { joiner.add(userId);
return list;
}
Map<String, ApprovalXdapUsers> usersMap = batchQueryUsers(userIds);
StringBuilder usernames = new StringBuilder();
for (String id : userIds) {
ApprovalXdapUsers user = usersMap.get(id);
if (user != null) {
usernames.append(user.getUsername()).append(" ");
} }
} }
if (usernames.length() > 0) { return joiner.toString();
ApprovalNodeView node = new ApprovalNodeView();
node.setNode("APPROVING");
node.setUserName(usernames.toString().trim());
node.setResult("APPROVING");
node.setApprovalTime(Timestamp.valueOf(LocalDateTime.now()));
list.add(node);
}
return list;
} }
private Map<String, ApprovalXdapUsers> batchQueryUsers(List<String> userIds) { private Map<String, ApprovalXdapUsers> batchQueryUsers(List<String> userIds) {
@ -409,159 +542,6 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
return list; return list;
} }
private boolean hasPermission(ApprovalFlow flow, String node, String userId) {
switch (node) {
case "PROOFREAD":
return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class).contains(userId);
case "REVIEW":
return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class).contains(userId);
case "APPROVE":
return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class).contains(userId);
default:
return false;
}
}
public void processApprovalLogic(ApprovalFlow flow, HandleApprovalRequest request, String currentNode) {
// 记录审批结果
ApprovalRecord record = new ApprovalRecord();
record.setFlowId(flow.getId());
record.setNode(currentNode);
record.setUserId(request.getUserId());
record.setOpinion(request.getOpinion());
record.setResult(request.getResult());
record.setApprovalTime(Timestamp.valueOf(LocalDateTime.now()));
bd.getBusinessDatabase().doInsert(record);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("owner_id", request.getUserId())
.eq("current_node", getNodeName(flow.getCurrentNode()))
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.update("is_delete", 1)
.doUpdate(TodoTaskPojo.class);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.ne("owner_id", request.getUserId())
.eq("current_node", getNodeName(flow.getCurrentNode()))
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.update("is_delete", 2)
.doUpdate(TodoTaskPojo.class);
// 处理驳回逻辑
if ("REJECT".equals(request.getResult())) {
cancelProcess(flow, "REJECTED", request.getUserId());
return;
}
// 处理通过逻辑流转到下一节点
processNextNode(flow, currentNode, request.getUserId());
}
private void processNextNode(ApprovalFlow flow, String currentNode, String userId) {
// 更新报告状态
BenchmarkingReport report = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(BenchmarkingReport.class);
String nextNode = getNextNode(currentNode, flow);
if (nextNode == null) {
// 流程结束
flow.setFlowStatus("COMPLETE");
flow.setCurrentNode(null);
report.setStatus("COMPLETE");
bd.getBusinessDatabase()
.rowid("id", report.getRowId())
.update("status", report.getStatus())
.doUpdate(BenchmarkingReport.class);
// 待办环节修改
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已完成")
.doUpdate(ApprovalNodeView.class);
} else {
flow.setCurrentNode(nextNode);
addNodeTodo(flow, nextNode, report, userId);
}
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.update("current_node", flow.getCurrentNode())
.doUpdate(ApprovalFlow.class);
}
private void addNodeTodo(ApprovalFlow flow, String node, BenchmarkingReport report, String createBy) {
List<String> users = getNodeUsers(flow, node);
// 新增待办
List<TodoTaskPojo> list = new ArrayList<>();
for (String person : users) {
TodoTaskPojo todoTaskPojo = bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("owner_id", person).doQueryFirst(TodoTaskPojo.class);
if (todoTaskPojo != null) {
todoTaskPojo.setCurrentNode(getNodeName(node));
todoTaskPojo.setCurrentProcessor(JSON.toJSONString(getNodeUsers(flow, node)));
bd.getBusinessDatabase().doUpdate(todoTaskPojo);
} else {
TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(createBy);
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(createBy).getUsername());
todoTask.setCurrentNode(getNodeName(flow.getCurrentNode()));
todoTask.setDataType("对标报告审核");
todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
todoTask.setIsDelete(0);
todoTask.setModelId(report.getId());
todoTask.setModelName(report.getProjectName() + "对标报告");
todoTask.setProcessTitle(flow.getProcessTitle());
todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(1);
todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(getNodeUsers(flow, flow.getCurrentNode())));
list.add(todoTask);
}
}
bd.getBusinessDatabase().doBatchInsert(list);
}
private String getNextNode(String currentNode, ApprovalFlow flow) {
switch (currentNode) {
case "PROOFREAD":
return "REVIEW";
case "REVIEW":
return "APPROVE";
case "APPROVE":
return null; // 流程结束
default:
return null;
}
}
private void cancelProcess(ApprovalFlow flow, String status, String userId) {
flow.setFlowStatus(status);
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.doUpdate(ApprovalFlow.class);
// 更新报告状态
BenchmarkingReport report = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(BenchmarkingReport.class);
report.setStatus(status);
bd.getBusinessDatabase()
.rowid("id", report.getRowId())
.update("status", report.getStatus())
.doUpdate(BenchmarkingReport.class);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已拒绝")
.doUpdate(ApprovalNodeView.class);
// 清除所有待办
clearAllTodo(flow, userId);
}
private void clearAllTodo(ApprovalFlow flow, String userId) { private void clearAllTodo(ApprovalFlow flow, String userId) {
// 清除已有待办 // 清除已有待办
bd.getBusinessDatabase() bd.getBusinessDatabase()
@ -571,14 +551,4 @@ public class BenchmarkingReportServiceImpl implements BenchmarkingReportService
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now())) .update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.doUpdate(TodoTaskPojo.class); .doUpdate(TodoTaskPojo.class);
} }
private List<String> getNodeUsers(ApprovalFlow flow, String node) {
switch (node) {
case "PROOFREAD": return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class);
case "REVIEW": return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class);
case "APPROVE": return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class);
default: return Collections.emptyList();
}
}
} }

View File

@ -1,23 +1,21 @@
package com.xdap.self_development.service.impl; package com.xdap.self_development.service.impl;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.definesys.mpaas.log.SWordLogger;
import com.definesys.mpaas.query.db.PageQueryResult; import com.definesys.mpaas.query.db.PageQueryResult;
import com.xdap.runtime.service.RuntimeDatasourceService; import com.xdap.api.moudle.user.pojo.XdapUsers;
import com.xdap.self_development.config.BusinessDatabase; import com.xdap.self_development.config.BusinessDatabase;
import com.xdap.self_development.controller.form.*; import com.xdap.self_development.controller.form.*;
import com.xdap.self_development.exception.CommonException; import com.xdap.self_development.exception.CommonException;
import com.xdap.self_development.pojo.*; import com.xdap.self_development.pojo.*;
import com.xdap.self_development.pojo.view.ApprovalFlowView; import com.xdap.self_development.pojo.dto.ApprovalNodeDTO;
import com.xdap.self_development.pojo.view.ApprovalNodeView; import com.xdap.self_development.pojo.view.ApprovalFlowNodeView;
import com.xdap.self_development.pojo.view.FlowNode;
import com.xdap.self_development.pojo.view.TemplateChangeView; import com.xdap.self_development.pojo.view.TemplateChangeView;
import com.xdap.self_development.pojo.view.TodoAndTemplateView; import com.xdap.self_development.pojo.view.TodoAndTemplateView;
import com.xdap.self_development.service.TemplateApprovalService; import com.xdap.self_development.service.TemplateApprovalService;
import com.xdap.self_development.service.XdapDeptUsersService; import com.xdap.self_development.service.XdapDeptUsersService;
import com.xdap.self_development.utils.RedisLockUtil; import com.xdap.self_development.utils.RedisLockUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -31,18 +29,12 @@ import java.util.stream.Collectors;
@Service @Service
@Slf4j @Slf4j
public class TemplateApprovalServiceImpl implements TemplateApprovalService { public class TemplateApprovalServiceImpl implements TemplateApprovalService {
@Autowired
private StringRedisTemplate redisTemplate;
@Resource @Resource
private BusinessDatabase bd; private BusinessDatabase bd;
@Resource @Resource
private RuntimeDatasourceService runtimeDatasourceService;
@Resource
private RedisLockUtil redisLockUtil; private RedisLockUtil redisLockUtil;
@Resource @Resource
private XdapDeptUsersService xdapDeptUsersService; private XdapDeptUsersService xdapDeptUsersService;
@Autowired
private SWordLogger logger;
// 分布式锁标志 // 分布式锁标志
private static final String FLOW_LOCK_PREFIX = "approval:lock:"; private static final String FLOW_LOCK_PREFIX = "approval:lock:";
@ -52,7 +44,7 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public String startApproval(StartApprovalRequest request) { public String startApproval(StartApprovalRequest request) {
// 验证模板存在 // 验证模板能否发起审批
Template template = bd.getBusinessDatabase() Template template = bd.getBusinessDatabase()
.rowid("id", request.getTemplateRowId()) .rowid("id", request.getTemplateRowId())
.doQueryFirst(Template.class); .doQueryFirst(Template.class);
@ -80,16 +72,12 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
throw new CommonException("空参数模板不允许发起审批"); throw new CommonException("空参数模板不允许发起审批");
} }
// 2. 创建审批流程 // 创建审批流程
ApprovalFlow flow = new ApprovalFlow(); ApprovalFlow flow = new ApprovalFlow();
flow.setTemplateId(template.getId()); flow.setTemplateId(template.getId());
flow.setCurrentNode("PROOFREAD"); flow.setCurrentNode(1);
flow.setFlowStatus("APPROVING"); flow.setFlowStatus("APPROVING");
flow.setProcessTitle(request.getProcessTitle()); flow.setProcessTitle(request.getProcessTitle());
flow.setProofreadUsers(JSON.toJSONString(request.getProofreadUsers()));
flow.setReviewUsers(JSON.toJSONString(request.getReviewUsers()));
flow.setCountersignUsers(JSON.toJSONString(request.getCountersignUsers()));
flow.setApproveUsers(JSON.toJSONString(request.getApproveUsers()));
flow.setCreateBy(request.getUserId()); flow.setCreateBy(request.getUserId());
flow.setCreatedTime(Timestamp.valueOf(LocalDateTime.now())); flow.setCreatedTime(Timestamp.valueOf(LocalDateTime.now()));
flow.setFlowType(1); // 设置为模板审批流程 flow.setFlowType(1); // 设置为模板审批流程
@ -97,13 +85,43 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
flow.setReturnNum(template.getReturnNum()); flow.setReturnNum(template.getReturnNum());
bd.getBusinessDatabase().doInsert(flow); bd.getBusinessDatabase().doInsert(flow);
// 创建审批配置
List<ApprovalConfigPojo> approvalConfigs = new ArrayList<>();
ApprovalNodeDTO firstNode = new ApprovalNodeDTO();
boolean hasUsers = false;
int step = 0;
for (ApprovalNodeDTO node : request.getNodeList()) {
if (node.getAssignees().isEmpty()) {
hasUsers = true;
step++;
continue;
}
if (hasUsers) {
node.setNodeOrder(node.getNodeOrder() - step);
hasUsers = false;
step = 0;
}
if (node.getNodeOrder() == 1) {
firstNode.setNodeOrder(1);
firstNode.setAssignees(node.getAssignees());
firstNode.setNodeName(node.getNodeName());
}
ApprovalConfigPojo config = new ApprovalConfigPojo();
config.setNodeName(node.getNodeName());
config.setNodeOrder(node.getNodeOrder());
config.setAssignees(JSON.toJSONString(node.getAssignees()));
config.setApprovalId(flow.getId());
approvalConfigs.add(config);
}
bd.getBusinessDatabase().doBatchInsert(approvalConfigs);
// 新增待办 // 新增待办
List<TodoTaskPojo> list = new ArrayList<>(); List<TodoTaskPojo> list = new ArrayList<>();
for (String person : request.getProofreadUsers()) { for (String person : firstNode.getAssignees()) {
TodoTaskPojo todoTask = new TodoTaskPojo(); TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(request.getUserId()); todoTask.setCreatedById(request.getUserId());
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(request.getUserId()).getUsername()); todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(request.getUserId()).getUsername());
todoTask.setCurrentNode(getNodeName(flow.getCurrentNode())); todoTask.setCurrentNode(firstNode.getNodeName());
todoTask.setDataType("模板审核"); todoTask.setDataType("模板审核");
todoTask.setDocumentNo(flow.getId()); todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now())); todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
@ -114,12 +132,12 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
todoTask.setStatusCode(flow.getFlowStatus()); todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(template.getVersion()); todoTask.setVersionNumber(template.getVersion());
todoTask.setOwnerId(person); todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(getNodeUsers(flow, flow.getCurrentNode()))); todoTask.setCurrentProcessor(JSON.toJSONString(firstNode.getAssignees()));
list.add(todoTask); list.add(todoTask);
} }
bd.getBusinessDatabase().doBatchInsert(list); bd.getBusinessDatabase().doBatchInsert(list);
// 3. 更新模板状态为校对中 // 更新模板状态为校对中
template.setStatus("APPROVING"); template.setStatus("APPROVING");
bd.getBusinessDatabase() bd.getBusinessDatabase()
.rowid("id", template.getRowId()) .rowid("id", template.getRowId())
@ -128,8 +146,8 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
return flow.getId(); return flow.getId();
} }
// 查询所有流程
@Override @Override
@Transactional
public PageQueryResult<TodoAndTemplateView> getApprovalList(ApprovalListForm form) { public PageQueryResult<TodoAndTemplateView> getApprovalList(ApprovalListForm form) {
PageQueryResult<TodoAndTemplateView> result = bd.getBusinessDatabase() PageQueryResult<TodoAndTemplateView> result = bd.getBusinessDatabase()
.viewQueryMode(true) .viewQueryMode(true)
@ -162,6 +180,7 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void handleApproval(HandleApprovalRequest request) { public void handleApproval(HandleApprovalRequest request) {
// 验证流程状态
ApprovalFlow flow = bd.getBusinessDatabase() ApprovalFlow flow = bd.getBusinessDatabase()
.eq("id", request.getFlowId()) .eq("id", request.getFlowId())
.eq("flow_type", 1) .eq("flow_type", 1)
@ -170,29 +189,32 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
throw new CommonException("流程不存在或已结束"); throw new CommonException("流程不存在或已结束");
} }
String currentNode = flow.getCurrentNode(); // 获取当前流程节点
ApprovalConfigPojo currentNode = bd.getBusinessDatabase()
.eq("approval_id", flow.getId())
.eq("node_order", flow.getCurrentNode())
.doQueryFirst(ApprovalConfigPojo.class);
// 验证当前用户是否有权限处理 // 验证当前用户是否有权限处理
if (!hasPermission(flow, currentNode, request.getUserId())) { if (!hasPermission(currentNode, request.getUserId())) {
throw new CommonException("无权限处理或已被处理"); throw new CommonException("无权限处理或已被处理");
} }
// 抢签节点 // 抢签节点
if (!"COUNTERSIGN".equals(currentNode)) { if (!"会签".equals(currentNode.getNodeName())) {
String lockKey = FLOW_LOCK_PREFIX + flow.getId() + ":" + currentNode; String lockKey = FLOW_LOCK_PREFIX + flow.getId() + ":" + currentNode.getNodeName();
String lockValue = UUID.randomUUID().toString(); String lockValue = UUID.randomUUID().toString();
boolean lockAcquired = redisLockUtil boolean lockAcquired = redisLockUtil
.tryLock(lockKey, lockValue, FLOW_LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS); .tryLock(lockKey, lockValue, FLOW_LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
// 其他人正在处理
if (!lockAcquired) { if (!lockAcquired) {
throw new CommonException("当前节点正在处理,请稍后重试"); throw new CommonException("当前节点正在处理,请稍后重试");
} }
try { try {
int processedCount = bd.getBusinessDatabase() int processedCount = bd.getBusinessDatabase()
.eq("document_no", flow.getId()) .eq("document_no", flow.getId())
.eq("current_node", getNodeName(flow.getCurrentNode()))
.eq("is_delete", 1) .eq("is_delete", 1)
.eq("current_node", currentNode.getNodeName())
.doQuery(TodoTaskPojo.class).size(); .doQuery(TodoTaskPojo.class).size();
// 已被其他人处理
if (processedCount > 0) { if (processedCount > 0) {
throw new CommonException("此节点已被他人处理"); throw new CommonException("此节点已被他人处理");
} }
@ -207,12 +229,18 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
} }
} }
// 验证是否为当前处理人
private boolean hasPermission(ApprovalConfigPojo node, String userId) {
return JSON.parseArray(node.getAssignees())
.toJavaList(String.class).contains(userId);
}
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void processApprovalLogic(ApprovalFlow flow, HandleApprovalRequest request, String currentNode) { public void processApprovalLogic(ApprovalFlow flow, HandleApprovalRequest request, ApprovalConfigPojo currentNode) {
// 记录审批结果 // 记录审批结果
ApprovalRecord record = new ApprovalRecord(); ApprovalRecord record = new ApprovalRecord();
record.setFlowId(flow.getId()); record.setFlowId(flow.getId());
record.setNode(currentNode); record.setNode(currentNode.getNodeName());
record.setUserId(request.getUserId()); record.setUserId(request.getUserId());
record.setOpinion(request.getOpinion()); record.setOpinion(request.getOpinion());
record.setResult(request.getResult()); record.setResult(request.getResult());
@ -220,11 +248,11 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
bd.getBusinessDatabase().doInsert(record); bd.getBusinessDatabase().doInsert(record);
// 完成当前节点的已处理待办 // 完成当前节点的已处理待办
if (!"COUNTERSIGN".equals(flow.getCurrentNode())) { if (!"会签".equals(currentNode.getNodeName())) {
bd.getBusinessDatabase() bd.getBusinessDatabase()
.eq("document_no", flow.getId()) .eq("document_no", flow.getId())
.ne("owner_id", request.getUserId()) .ne("owner_id", request.getUserId())
.eq("current_node", getNodeName(flow.getCurrentNode())) .eq("current_node", currentNode.getNodeName())
.update("is_delete", 2) .update("is_delete", 2)
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now())) .update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.doUpdate(TodoTaskPojo.class); .doUpdate(TodoTaskPojo.class);
@ -232,7 +260,7 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
bd.getBusinessDatabase() bd.getBusinessDatabase()
.eq("document_no", flow.getId()) .eq("document_no", flow.getId())
.eq("owner_id", request.getUserId()) .eq("owner_id", request.getUserId())
.eq("current_node", getNodeName(flow.getCurrentNode())) .eq("current_node", currentNode.getNodeName())
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now())) .update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.update("is_delete", 1) .update("is_delete", 1)
.doUpdate(TodoTaskPojo.class); .doUpdate(TodoTaskPojo.class);
@ -251,6 +279,144 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
processNextNode(flow, currentNode, request.getUserId()); processNextNode(flow, currentNode, request.getUserId());
} }
private void cancelProcess(ApprovalFlow flow, String status, String userId) {
// 更新流程状态
flow.setFlowStatus(status);
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.doUpdate(ApprovalFlow.class);
// 更新模板状态(重新打回草稿状态)
Template template = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(Template.class);
template.setStatus("DRAFT");
bd.getBusinessDatabase()
.rowid("id", template.getRowId())
.update("status", template.getStatus())
.update("return_num", template.getReturnNum() + 1)
.doUpdate(Template.class);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已拒绝")
.doUpdate(TodoTaskPojo.class);
// 清除所有待办
clearAllTodo(flow);
}
private void clearAllTodo(ApprovalFlow flow) {
// 清除已有待办
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("is_delete", 0)
.update("is_delete", 2)
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.doUpdate(TodoTaskPojo.class);
}
// 处理下一节点流转
@Transactional(rollbackFor = Exception.class)
public void processNextNode(ApprovalFlow flow, ApprovalConfigPojo currentNode, String userId) {
// 检查当前节点是否满足流转条件
if (!checkNodeComplete(flow, currentNode)) {
return;
}
// 更新模板状态
Template template = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(Template.class);
// 获取下一个节点
ApprovalConfigPojo nextNode = bd.getBusinessDatabase()
.eq("approval_id", flow.getId())
.eq("node_order", currentNode.getNodeOrder() + 1)
.doQueryFirst(ApprovalConfigPojo.class);
if (nextNode == null) {
// 流程结束
flow.setFlowStatus("COMPLETE");
flow.setCurrentNode(null);
template.setStatus("COMPLETE");
// 将同名的上一个版本的状态改为历史
bd.getBusinessDatabase()
.eq("template_name", template.getTemplateName())
.eq("version", template.getVersion() - 1)
.update("status", "HISTORY")
.doUpdate(Template.class);
// 将当前版本状态改为已发布
bd.getBusinessDatabase()
.rowid("id", template.getRowId())
.update("status", template.getStatus())
.update("published_time", Timestamp.valueOf(LocalDateTime.now()))
.doUpdate(Template.class);
// 待办环节修改
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已完成")
.doUpdate(TodoTaskPojo.class);
// 更新机型版本
// dataEntryEngineModelService.updateModelForNewVersion();
} else {
flow.setCurrentNode(nextNode.getNodeOrder());
addNodeTodo(flow, nextNode, template, userId);
}
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.update("current_node", flow.getCurrentNode())
.doUpdate(ApprovalFlow.class);
}
// 检查节点是否完成
private boolean checkNodeComplete(ApprovalFlow flow, ApprovalConfigPojo node) {
Integer processedCount = bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("is_delete", 1)
.eq("current_node", node.getNodeName())
.doQuery(TodoTaskPojo.class).size();
if ("会签".equals(node.getNodeName())) {
return processedCount.equals(JSON.parseArray(node.getAssignees()).size());
} else {
return processedCount >= 1;
}
}
private void addNodeTodo(ApprovalFlow flow, ApprovalConfigPojo node, Template template, String createBy) {
// 获取处理人
List<String> users = JSON.parseArray(node.getAssignees()).toJavaList(String.class);
// 新增待办
List<TodoTaskPojo> list = new ArrayList<>();
for (String person : users) {
TodoTaskPojo todoTaskPojo = bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("owner_id", person).doQueryFirst(TodoTaskPojo.class);
if (todoTaskPojo != null) {
todoTaskPojo.setCurrentNode(node.getNodeName());
todoTaskPojo.setCurrentProcessor(JSON.toJSONString(node.getAssignees()));
bd.getBusinessDatabase().doUpdate(todoTaskPojo);
} else {
TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(createBy);
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(createBy).getUsername());
todoTask.setCurrentNode(node.getNodeName());
todoTask.setDataType("模板审核");
todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
todoTask.setIsDelete(0);
todoTask.setModelId(template.getId());
todoTask.setModelName(template.getTemplateName());
todoTask.setProcessTitle(flow.getProcessTitle());
todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(template.getVersion());
todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(node.getAssignees()));
list.add(todoTask);
}
}
bd.getBusinessDatabase().doBatchInsert(list);
}
@Override @Override
public PageQueryResult<TemplateChangeView> getTemplateChanges(ApprovalAndParameterForm form) { public PageQueryResult<TemplateChangeView> getTemplateChanges(ApprovalAndParameterForm form) {
Template template = bd.getBusinessDatabase() Template template = bd.getBusinessDatabase()
@ -286,142 +452,98 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
} }
@Override @Override
public ApprovalFlowView getApprovalProcess(ApprovalFlowForm form) { public ApprovalFlowNodeView getApprovalProcess(ApprovalFlowForm form) {
ApprovalFlowView approvalFlowView = new ApprovalFlowView(); ApprovalFlowNodeView flowNodeView = new ApprovalFlowNodeView();
ApprovalFlow flow = bd.getBusinessDatabase() ApprovalFlow approvalFlow = bd.getBusinessDatabase()
.eq("id", form.getFlowId()) .eq("id", form.getFlowId())
.eq("flow_type", 1)
.doQueryFirst(ApprovalFlow.class); .doQueryFirst(ApprovalFlow.class);
// 无流程创建空返回
if (flow == null) { if (approvalFlow == null) {
return approvalFlowView; return flowNodeView;
} }
Template template = bd.getBusinessDatabase() Template template = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId()) .eq("id", approvalFlow.getTemplateId())
.doQueryFirst(Template.class); .doQueryFirst(Template.class);
approvalFlowView.setExplanation(flow.getExplanation()); // 获取流程信息
approvalFlowView.setFlowStatus(flow.getFlowStatus()); flowNodeView.setProgressTitle(approvalFlow.getProcessTitle());
if (!"APPROVING".equals(flow.getFlowStatus())) { flowNodeView.setContentName(template.getTemplateName());
setAllCompletedNodes(approvalFlowView, flow); flowNodeView.setTemplateVersion(template.getVersion());
return approvalFlowView; flowNodeView.setExplanation(approvalFlow.getExplanation());
} flowNodeView.setFlowStatus(approvalFlow.getFlowStatus());
processApprovalNodes(approvalFlowView, flow); // 获取节点信息
approvalFlowView.setProgressTitle(flow.getProcessTitle()); List<ApprovalConfigPojo> nodes = bd.getBusinessDatabase()
approvalFlowView.setContentName(template.getTemplateName()); .eq("approval_id", form.getFlowId())
approvalFlowView.setTemplateVersion(template.getVersion()); .doQuery(ApprovalConfigPojo.class);
return approvalFlowView; List<FlowNode> flowNodes = new ArrayList<>();
} nodes.forEach(node -> {
FlowNode nodeView = new FlowNode();
private void setAllCompletedNodes(ApprovalFlowView view, ApprovalFlow flow) { if (Objects.equals(node.getNodeName(), "会签")) {
view.setProofreadNodes(getNodeList(flow.getId(), "PROOFREAD")); List<ApprovalRecord> records = bd.getBusinessDatabase()
view.setReviewNodes(getNodeList(flow.getId(), "REVIEW")); .eq("flow_id", form.getFlowId())
view.setCountersignNodes(getNodeList(flow.getId(), "COUNTERSIGN")); .eq("node", node.getNodeName())
view.setApproveNodes(getNodeList(flow.getId(), "APPROVE")); .doQuery(ApprovalRecord.class);
} List<String> results = records.stream()
.map(ApprovalRecord::getResult).collect(Collectors.toList());
private void processApprovalNodes(ApprovalFlowView view, ApprovalFlow flow) { List<ApprovalRecord> reversedTime = records.stream().sorted(Comparator
// 处理校对节点 .comparing(ApprovalRecord::getApprovalTime).reversed()).collect(Collectors.toList());
List<ApprovalNodeView> proofreadNodes = getNodeList(flow.getId(), "PROOFREAD"); if (records.size() == JSON.parseArray(node.getAssignees()).size()) {
if (proofreadNodes.isEmpty()) { // 节点已完成
view.setProofreadNodes(createApprovingNode(flow.getProofreadUsers())); nodeView.setNodeOrder(node.getNodeOrder());
view.setReviewNodes(new ArrayList<>()); nodeView.setResult(results.contains("REJECT") ? "REJECT" : "PASS");
view.setCountersignNodes(new ArrayList<>()); nodeView.setNode(node.getNodeName());
view.setApproveNodes(new ArrayList<>()); nodeView.setUndoUserName(getUserNames(JSON.parseArray(node.getAssignees()).toJavaList(String.class)));
return; nodeView.setTodoUserName(getUserNames(JSON.parseArray(node.getAssignees()).toJavaList(String.class)));
} nodeView.setApprovalTime(reversedTime.get(0).getApprovalTime());
view.setProofreadNodes(proofreadNodes); nodeView.setOpinions(records.stream().map(approvalRecord ->
getUserNames(Collections.singletonList(approvalRecord.getUserId())) + ":" + approvalRecord.getOpinion()).collect(Collectors.toList()));
// 处理审核节点
List<ApprovalNodeView> reviewNodes = getNodeList(flow.getId(), "REVIEW");
if (reviewNodes.isEmpty()) {
view.setReviewNodes(createApprovingNode(flow.getReviewUsers()));
view.setCountersignNodes(new ArrayList<>());
view.setApproveNodes(new ArrayList<>());
return;
}
view.setReviewNodes(reviewNodes);
// 处理会签节点
List<String> countersignUserIds = JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class);
if (countersignUserIds.isEmpty()) {
view.setCountersignNodes(new ArrayList<>());
} else { } else {
List<ApprovalNodeView> countersignNodes = getNodeList(flow.getId(), "COUNTERSIGN"); // 节点未完成
if (countersignNodes.isEmpty()) { nodeView.setNodeOrder(node.getNodeOrder());
view.setCountersignNodes(createApprovingNode(flow.getCountersignUsers())); nodeView.setNode(node.getNodeName());
view.setApproveNodes(new ArrayList<>()); nodeView.setResult("待审批");
return; List<String> includedIds = records.stream().map(ApprovalRecord::getUserId).collect(Collectors.toList());
nodeView.setTodoUserName(getUserNames(includedIds));
nodeView.setUndoUserName(getUserNames(JSON.parseArray(node.getAssignees()).toJavaList(String.class)));
}
} else { } else {
if (countersignNodes.size() == countersignUserIds.size()) { ApprovalRecord record = bd.getBusinessDatabase()
view.setCountersignNodes(countersignNodes); .eq("flow_id", form.getFlowId())
.eq("node", node.getNodeName())
.doQueryFirst(ApprovalRecord.class);
nodeView.setNodeOrder(node.getNodeOrder());
nodeView.setNode(node.getNodeName());
if (record != null) {
// 节点已完成
nodeView.setResult(record.getResult());
nodeView.setOpinions(Collections.singletonList(getUserNames(Collections.singletonList(record.getUserId())) + ":" + record.getOpinion()));
nodeView.setApprovalTime(record.getApprovalTime());
nodeView.setTodoUserName(getUserNames(Collections.singletonList(record.getUserId())));
} else { } else {
List<String> completedUserIds = countersignNodes.stream() // 节点未完成
.map(ApprovalNodeView::getUserId) nodeView.setResult("待审批");
.collect(Collectors.toList()); nodeView.setTodoUserName("");
List<String> pendingUserIds = countersignUserIds.stream()
.filter(id -> !completedUserIds.contains(id))
.collect(Collectors.toList());
if (!pendingUserIds.isEmpty()) {
countersignNodes.addAll(createApprovingNode(JSON.toJSONString(pendingUserIds)));
}
view.setCountersignNodes(countersignNodes);
view.setApproveNodes(new ArrayList<>());
return;
} }
nodeView.setUndoUserName(getUserNames(JSON.parseArray(node.getAssignees()).toJavaList(String.class)));
} }
flowNodes.add(nodeView);
});
List<FlowNode> sortedNode = flowNodes.stream().sorted(Comparator.comparing(FlowNode::getNodeOrder)).collect(Collectors.toList());
flowNodeView.setFlowNodes(sortedNode);
return flowNodeView;
} }
List<ApprovalNodeView> approveNodes = getNodeList(flow.getId(), "APPROVE"); private String getUserNames(List<String> userIds) {
if (approveNodes.isEmpty()) { StringJoiner joiner = new StringJoiner(" ");
view.setApproveNodes(createApprovingNode(flow.getApproveUsers())); for (String userId : userIds) {
String username = bd.getBusinessDatabase().eq("id", userId).doQueryFirst(XdapUsers.class).getUsername();
if (username != null) {
joiner.add(username);
} else { } else {
view.setApproveNodes(approveNodes); // 处理空值情况
joiner.add(userId);
} }
} }
return joiner.toString();
private List<ApprovalNodeView> createApprovingNode(String userJsonArray) {
List<ApprovalNodeView> list = new ArrayList<>();
if (userJsonArray == null || userJsonArray.trim().isEmpty()) {
return list;
}
List<String> userIds = JSON.parseArray(userJsonArray).toJavaList(String.class);
if (userIds.isEmpty()) {
return list;
}
Map<String, ApprovalXdapUsers> usersMap = batchQueryUsers(userIds);
StringBuilder usernames = new StringBuilder();
for (String id : userIds) {
ApprovalXdapUsers user = usersMap.get(id);
if (user != null) {
usernames.append(user.getUsername()).append(" ");
}
}
if (usernames.length() > 0) {
ApprovalNodeView node = new ApprovalNodeView();
node.setNode("APPROVING");
node.setUserName(usernames.toString().trim());
node.setResult("APPROVING");
node.setApprovalTime(Timestamp.valueOf(LocalDateTime.now()));
list.add(node);
}
return list;
}
private Map<String, ApprovalXdapUsers> batchQueryUsers(List<String> userIds) {
if (userIds == null || userIds.isEmpty()) {
return new HashMap<>();
}
List<ApprovalXdapUsers> users = bd.getBusinessDatabase()
.in("id", userIds)
.doQuery(ApprovalXdapUsers.class);
return users.stream()
.collect(Collectors.toMap(ApprovalXdapUsers::getId, user -> user));
} }
@Override @Override
@ -438,10 +560,14 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
if (!Objects.equals(flow.getFlowStatus(), "APPROVING")) { if (!Objects.equals(flow.getFlowStatus(), "APPROVING")) {
throw new CommonException("不在流程无法撤回"); throw new CommonException("不在流程无法撤回");
} }
ApprovalConfigPojo currentNode = bd.getBusinessDatabase()
.eq("approval_id", request.getFlowId())
.eq("current_node", Integer.valueOf(flow.getCurrentNode()))
.doQueryFirst(ApprovalConfigPojo.class);
if ("RETURN".equals(request.getResult())) { if ("RETURN".equals(request.getResult())) {
ApprovalRecord record = new ApprovalRecord(); ApprovalRecord record = new ApprovalRecord();
record.setFlowId(flow.getId()); record.setFlowId(flow.getId());
record.setNode(flow.getCurrentNode()); record.setNode(currentNode.getNodeName());
record.setUserId(request.getUserId()); record.setUserId(request.getUserId());
record.setOpinion(request.getOpinion()); record.setOpinion(request.getOpinion());
record.setResult(request.getResult()); record.setResult(request.getResult());
@ -450,215 +576,9 @@ public class TemplateApprovalServiceImpl implements TemplateApprovalService {
// 申请人撤回 // 申请人撤回
cancelProcess(flow, "RETURNED", request.getUserId()); cancelProcess(flow, "RETURNED", request.getUserId());
} } else {
else {
throw new CommonException("无法撤回"); throw new CommonException("无法撤回");
} }
} }
private List<ApprovalNodeView> getNodeList(String flowId, String node) {
List<ApprovalNodeView> list = bd.getBusinessDatabase()
.viewQueryMode(true)
.view("getApprovalNodeInfo")
.setVar("flowId", flowId)
.setVar("node", node)
.doQuery(ApprovalNodeView.class);
if (list != null && !list.isEmpty()) {
list.forEach(approvalNodeView -> {
ApprovalXdapUsers user = runtimeDatasourceService.buildTenantNoSchemaMpaasQuery()
.eq("id", approvalNodeView.getUserId())
.doQueryFirst(ApprovalXdapUsers.class);
approvalNodeView.setUserName(user.getUsername());
});
}
return list;
}
// 处理下一节点流转
@Transactional(rollbackFor = Exception.class)
public void processNextNode(ApprovalFlow flow, String currentNode, String userId) {
// 检查当前节点是否满足流转条件
if (!checkNodeComplete(flow, currentNode)) {
return; // 未满足条件不流转
}
// 更新模板状态
Template template = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(Template.class);
String nextNode = getNextNode(currentNode, flow);
if (nextNode == null) {
// 流程结束
flow.setFlowStatus("COMPLETE");
flow.setCurrentNode(null);
template.setStatus("COMPLETE");
// 将同名的上一个版本的状态改为历史
bd.getBusinessDatabase()
.eq("template_name", template.getTemplateName())
.eq("version", template.getVersion()-1)
.update("status", "HISTORY")
.doUpdate(Template.class);
// 将当前版本状态改为已发布
bd.getBusinessDatabase()
.rowid("id", template.getRowId())
.update("status", template.getStatus())
.update("published_time", Timestamp.valueOf(LocalDateTime.now()))
.doUpdate(Template.class);
// 待办环节修改
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已完成")
.doUpdate(ApprovalNodeView.class);
// 更新机型版本
// dataEntryEngineModelService.updateModelForNewVersion();
} else {
flow.setCurrentNode(nextNode);
addNodeTodo(flow, nextNode, template, userId);
}
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.update("current_node", flow.getCurrentNode())
.doUpdate(ApprovalFlow.class);
}
// 获取下一节点
private String getNextNode(String currentNode, ApprovalFlow flow) {
switch (currentNode) {
case "PROOFREAD":
return "REVIEW";
case "REVIEW":
return flow.getCountersignUsers() != null && !JSON.parseArray(flow.getCountersignUsers()).isEmpty()
? "COUNTERSIGN" : "APPROVE";
case "COUNTERSIGN":
return "APPROVE";
case "APPROVE":
return null; // 流程结束
default:
return null;
}
}
// 检查节点是否完成
private boolean checkNodeComplete(ApprovalFlow flow, String node) {
Integer processedCount = bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("is_delete", 1)
.eq("current_node", getNodeName(flow.getCurrentNode()))
.doQuery(TodoTaskPojo.class).size();
// 会签节点需要所有人处理其他节点只需1人
if ("COUNTERSIGN".equals(node)) {
return processedCount.equals(JSON.parseArray(flow.getCountersignUsers()).size());
} else {
return processedCount >= 1;
}
}
private void cancelProcess(ApprovalFlow flow, String status, String userId) {
// 更新流程状态
flow.setFlowStatus(status);
bd.getBusinessDatabase()
.rowid("id", flow.getRowId())
.update("flow_status", flow.getFlowStatus())
.doUpdate(ApprovalFlow.class);
// 更新模板状态(重新打回草稿状态)
Template template = bd.getBusinessDatabase()
.eq("id", flow.getTemplateId())
.doQueryFirst(Template.class);
template.setStatus("DRAFT");
bd.getBusinessDatabase()
.rowid("id", template.getRowId())
.update("status", template.getStatus())
.update("return_num", template.getReturnNum() + 1)
.doUpdate(Template.class);
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.update("node", "已拒绝")
.doUpdate(ApprovalNodeView.class);
// 清除所有待办
clearAllTodo(flow);
}
private boolean hasPermission(ApprovalFlow flow, String node, String userId) {
switch (node) {
case "PROOFREAD":
return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class).contains(userId);
case "REVIEW":
return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class).contains(userId);
case "COUNTERSIGN":
return flow.getCountersignUsers() != null && JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class).contains(userId);
case "APPROVE":
return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class).contains(userId);
default:
return false;
}
}
private void addNodeTodo(ApprovalFlow flow, String node, Template template, String createBy) {
List<String> users = getNodeUsers(flow, node);
// 新增待办
List<TodoTaskPojo> list = new ArrayList<>();
for (String person : users) {
TodoTaskPojo todoTaskPojo = bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("owner_id", person).doQueryFirst(TodoTaskPojo.class);
if (todoTaskPojo != null) {
todoTaskPojo.setCurrentNode(getNodeName(node));
todoTaskPojo.setCurrentProcessor(JSON.toJSONString(getNodeUsers(flow, node)));
bd.getBusinessDatabase().doUpdate(todoTaskPojo);
} else {
TodoTaskPojo todoTask = new TodoTaskPojo();
todoTask.setCreatedById(createBy);
todoTask.setCreatedBy(xdapDeptUsersService.selectUserByID(createBy).getUsername());
todoTask.setCurrentNode(getNodeName(node));
todoTask.setDataType("模板审核");
todoTask.setDocumentNo(flow.getId());
todoTask.setCreationDate(Timestamp.valueOf(LocalDateTime.now()));
todoTask.setIsDelete(0);
todoTask.setModelId(template.getId());
todoTask.setModelName(template.getTemplateName());
todoTask.setProcessTitle(flow.getProcessTitle());
todoTask.setStatusCode(flow.getFlowStatus());
todoTask.setVersionNumber(template.getVersion());
todoTask.setOwnerId(person);
todoTask.setCurrentProcessor(JSON.toJSONString(getNodeUsers(flow, flow.getCurrentNode())));
list.add(todoTask);
}
}
bd.getBusinessDatabase().doBatchInsert(list);
}
private void clearAllTodo(ApprovalFlow flow) {
// 清除已有待办
bd.getBusinessDatabase()
.eq("document_no", flow.getId())
.eq("is_delete", 0)
.update("is_delete", 2)
.update("last_update_date", Timestamp.valueOf(LocalDateTime.now()))
.doUpdate(TodoTaskPojo.class);
}
private List<String> getNodeUsers(ApprovalFlow flow, String node) {
switch (node) {
case "PROOFREAD": return JSON.parseArray(flow.getProofreadUsers()).toJavaList(String.class);
case "REVIEW": return JSON.parseArray(flow.getReviewUsers()).toJavaList(String.class);
case "COUNTERSIGN": return JSON.parseArray(flow.getCountersignUsers()).toJavaList(String.class);
case "APPROVE": return JSON.parseArray(flow.getApproveUsers()).toJavaList(String.class);
default: return Collections.emptyList();
}
}
private String getNodeName(String node) {
switch (node) {
case "PROOFREAD": return "校对";
case "REVIEW": return "审核";
case "COUNTERSIGN": return "会签";
case "APPROVE": return "批准";
default: return "-";
}
}
} }