first commit

This commit is contained in:
@jyuhsin
2026-01-14 14:49:41 +08:00
commit 105c955abd
4752 changed files with 911871 additions and 0 deletions
@@ -0,0 +1,33 @@
package com.budwk.app.bpm.controller;
import com.budwk.app.base.result.Result;
import com.budwk.app.bpm.models.BpmProcessInstance;
import com.budwk.app.bpm.models.BpmProcessTask;
import io.swagger.annotations.Api;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import javax.validation.Valid;
import java.util.List;
@IocBean
@At("/platform/bpm/common")
@Api(tags = "bpm公共")
@Ok("json:full")
public class BpmCommonController {
@Inject
private Dao dao;
@At
public Result listTask(@Valid String businessId) {
BpmProcessInstance instance = dao.fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", businessId));
List<BpmProcessTask> tasks = dao.query(BpmProcessTask.class, Cnd.where(BpmProcessTask::getProcessInstanceId, "=", instance.getId()));
return Result.success(tasks);
}
}
@@ -0,0 +1,126 @@
package com.budwk.app.bpm.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.bpm.models.BpmProcessDefine;
import com.budwk.app.bpm.models.BpmProcessNodeDefine;
import com.budwk.app.bpm.service.BpmProcessDefineService;
import com.budwk.app.bpm.util.BpmUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.random.R;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
import java.util.Arrays;
import java.util.List;
@IocBean
@At("/platform/bpm/processDefine")
@Ok("json:full")
public class BpmProcessDefineController {
@Inject
private Dao dao;
@Inject
private BpmProcessDefineService bpmProcessDefineService;
@At("")
@Ok("beetl:/platform/bpm/processDefine/index.html")
@SaCheckPermission("bpm.processDefine")
public void index() {
}
@At
@SaCheckPermission("bpm.processDefine")
public Result pageData(@Valid PageForm param) {
Cnd cnd = Cnd.NEW();
cnd.and("delFlag", "=", false);
Pagination pagination = bpmProcessDefineService.listPage(param.getPageNumber(), param.getPageSize(), cnd);
return Result.success(pagination);
}
@At
@SaCheckPermission("bpm.processDefine")
public Result insert(@Param("define") BpmProcessDefine processDefine) {
int count = dao.count(BpmProcessDefine.class, Cnd.where(BpmProcessDefine::getCode, "=", processDefine.getCode()));
if (count > 0) {
return Result.error("编码重复");
}
dao.insert(processDefine);
return Result.success();
}
@At
@SaCheckPermission("bpm.processDefine")
public Result update(@Param("define") BpmProcessDefine processDefine) {
int count = dao.count(BpmProcessDefine.class, Cnd.where(BpmProcessDefine::getCode, "=", processDefine.getCode())
.and(BpmProcessDefine::getId, "!=", processDefine.getId()));
if (count > 0) {
return Result.error("编码重复");
}
dao.updateIgnoreNull(processDefine);
return Result.success();
}
@At
@SaCheckPermission("bpm.processDefine")
@Aop(TransAop.READ_COMMITTED)
public Result delete(@Param("id") @Valid String id) {
bpmProcessDefineService.vDelete(id);
return Result.success();
}
@At
@SaCheckPermission("bpm.processDefine")
public Result generateNodeId(@Param("ids") String[] ids) {
String id = R.UU32();
while (Arrays.asList(ids).contains(id)) {
id = R.UU32();
}
return Result.success().addData(id);
}
@At
@SaCheckPermission("bpm.processDefine")
public Result nodes(@Valid String id){
List<BpmProcessNodeDefine> nodes = dao.query(BpmProcessNodeDefine.class, Cnd.where(BpmProcessNodeDefine::getProcessDefineId, "=", id)
.asc(BpmProcessNodeDefine::getSort));
return Result.success(nodes);
}
@At
@SaCheckPermission("bpm.processDefine")
@Aop(TransAop.READ_COMMITTED)
public Result updateSubmitNodes(@Param("define") BpmProcessDefine processDefine) {
if (StrUtil.isBlank(processDefine.getId())) {
return Result.error("流程定义ID不能为空");
}
try{
BpmUtil.validateNodes(processDefine.getNodes());
}catch (Exception e){
e.printStackTrace();
return Result.error(e.getMessage());
}
dao.clear(BpmProcessNodeDefine.class,Cnd.where(BpmProcessNodeDefine::getProcessDefineId,"=",processDefine.getId()));
for (int i = 0; i < processDefine.getNodes().size(); i++) {
processDefine.getNodes().get(i).setSort(i+1);
processDefine.getNodes().get(i).setProcessDefineId(processDefine.getId());
}
dao.insert(processDefine.getNodes());
return Result.success();
}
}
@@ -0,0 +1,50 @@
package com.budwk.app.bpm.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.bpm.param.BpmProcessInstancePageForm;
import com.budwk.app.bpm.service.BpmProcessInstanceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
@IocBean
@At("/platform/bpm/processInstance")
@Ok("json:full")
@Api(tags = "BPM流程实例")
public class BpmProcessInstanceController {
@Inject
private BpmProcessInstanceService bpmProcessInstanceService;
@At("")
@Ok("beetl:/platform/bpm/processInstance/index.html")
@SaCheckPermission("bpm.processInstance")
public void index() {
}
@At
@SaCheckPermission("bpm.processInstance")
public Result pageData(@Valid BpmProcessInstancePageForm pageForm){
Cnd cnd = Cnd.NEW();
Pagination pagination = bpmProcessInstanceService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
return Result.success(pagination);
}
@At
@SaCheckPermission("bpm.processInstance")
@ApiOperation("关闭流程实例")
public Result closeInstance(@Param("id") @Valid String id) {
bpmProcessInstanceService.closeInstance(id);
return Result.success();
}
}
@@ -0,0 +1,53 @@
package com.budwk.app.bpm.controller;
import com.budwk.app.base.result.Result;
import com.budwk.app.bpm.enums.BpmTaskApprovalTypeEnum;
import com.budwk.app.bpm.service.BpmService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import java.util.HashMap;
import java.util.List;
@IocBean
@At("/platform/bpm/test")
@Ok("json:full")
public class BpmTestController {
@Inject
private BpmService bpmService;
static final String processDefineCode = "222";
static final String businessId = "businessId";
@At
public Result startSaveProcessInstance() {
bpmService.startSaveProcessInstance(processDefineCode, "测试流程-save-update", businessId, null);
return Result.success();
}
@At
public Result startSubmitProcessInstance() {
HashMap<String, Object> variables = new HashMap<>();
bpmService.startSubmitProcessInstance(processDefineCode, "测试流程-submit-update", businessId, List.of("superadmin"), variables);
return Result.success();
}
@At
public Result completeTask() {
HashMap<String, Object> variables = new HashMap<>();
bpmService.completeTask("a240d4f12e274e2da564ff43b1533123", BpmTaskApprovalTypeEnum.PASS, variables, List.of("1"));
return Result.success();
}
@At
public Result revokeTask() {
bpmService.revokeTask("2c26c249e4a44a7ea90e78e68cf9ec5a");
return Result.success();
}
}
@@ -0,0 +1,18 @@
package com.budwk.app.bpm.dto;
import cn.hutool.json.JSONObject;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 会签复杂任务接收对象
*/
@Data
@Accessors(chain = true)
public class BpmAssignmentDto {
private String loginName;
private JSONObject jsonObject;
}
@@ -0,0 +1,11 @@
package com.budwk.app.bpm.enums;
/**
* 流程实例当前状态
*/
public enum BpmProcessInstanceStatusEnum {
RUNNING,
COMPLETED;
}
@@ -0,0 +1,16 @@
package com.budwk.app.bpm.enums;
import com.budwk.app.base.annotation.DictEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@DictEnum(name = "节点审批类型", key = "BpmProcessNodeApprovalTypeEnum")
@Getter
@AllArgsConstructor
public enum BpmProcessNodeApprovalTypeEnum {
NODE_APPLY("申请"), NODE_PENDING("待审批"),NODE_PASS("审批通过"),NODE_REJECT("审批拒绝"),NODE_BACK("审批退回");
final String desc;
}
@@ -0,0 +1,18 @@
package com.budwk.app.bpm.enums;
/**
* 节点参与类型
*/
public enum BpmProcessNodePerformTypeEnum {
/**
* 普通
*/
ORDINARY,
/**
* 会签
*/
COUNTERSIGN;
}
@@ -0,0 +1,13 @@
package com.budwk.app.bpm.enums;
public enum BpmProcessNodeTypeEnum {
START,
TASK,
BACK,
END;
}
@@ -0,0 +1,9 @@
package com.budwk.app.bpm.enums;
public enum BpmProcessStartEnum {
save,
submit;
}
@@ -0,0 +1,18 @@
package com.budwk.app.bpm.enums;
/**
* 任务状态
*/
public enum BpmProcessTaskStatusEnum {
ACTIVE,
COMPLETE,
AUTO_COMPLETE,
TRANSFER,
REVOKE;
}
@@ -0,0 +1,24 @@
package com.budwk.app.bpm.enums;
import com.budwk.app.base.annotation.DictEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
@DictEnum(name = "任务审批类型", key = "BpmTaskApprovalTypeEnum")
@Getter
@AllArgsConstructor
public enum BpmTaskApprovalTypeEnum {
APPLY,
PASS,
REJECT,
BACK,
BACK_OTHER_NODE,
DYNAMIC;
}
@@ -0,0 +1,47 @@
package com.budwk.app.bpm.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serializable;
import java.util.List;
@Table("bpm_process_define")
@Comment("流程定义")
@Data
@EqualsAndHashCode(callSuper = true)
@TableMeta("{'mysql-charset':'utf8mb4'}")
public class BpmProcessDefine extends BaseModel implements Serializable {
@Column
@Name
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR,width = 30)
@Comment("编码")
private String code;
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("名称")
private String name;
@Column
@ColDefine(type = ColType.VARCHAR,width = 1000)
@Comment("url")
private String url;
@Column
@ColDefine(type = ColType.VARCHAR,width = 1000)
@Comment("h5url")
private String h5url;
private List<BpmProcessNodeDefine> nodes;
}
@@ -0,0 +1,103 @@
package com.budwk.app.bpm.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Table("bpm_process_instance")
@Comment("流程实例")
@Data
@EqualsAndHashCode(callSuper = true)
@TableMeta("{'mysql-charset':'utf8mb4'}")
public class BpmProcessInstance extends BaseModel implements Serializable {
@Column
@Name
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR,width = 32)
@Comment("流程业务ID")
private String processInstanceBusinessId;
@Column
@ColDefine(type = ColType.VARCHAR,width = 32)
@Comment("流程定义ID")
private String processDefineId;
@Column
@ColDefine(type = ColType.VARCHAR,width = 200)
@Comment("流程实例名称")
private String processInstanceName;
@Column
@ColDefine(type = ColType.VARCHAR,width = 32)
@Comment("流程当前节点ID")
private String processInstanceNodeId;
@Column
@ColDefine(type = ColType.INT)
@Comment("流程当前节点code")
private Integer processInstanceNodeCode;
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("流程当前节点名称")
private String processInstanceNodeName;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("流程当前任务ID")
private List<String> processInstanceTaskIds;
@Column
@ColDefine(type = ColType.VARCHAR,width = 32)
@Comment("流程发起人id")
private String processInstanceInitiatorId;
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("流程发起人姓名")
private String processInstanceInitiatorName;
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("流程发起人工号")
private String processInstanceInitiatorLoginName;
@Column
@ColDefine(type = ColType.VARCHAR,width = 100)
@Comment("流程发起人部门")
private String processInstanceInitiatorUnitName;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("流程发起时间")
private Date processInstanceInitiationTime;
@Column
@ColDefine(type = ColType.VARCHAR,width = 500)
@Comment("流程URL")
private String processInstanceUrl;
@Column
@ColDefine(type = ColType.VARCHAR,width = 500)
@Comment("流程H5URL")
private String processInstanceH5Url;
/**
* @see com.budwk.app.bpm.enums.BpmProcessInstanceStatusEnum
*/
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("流程实例当前状态")
private String processInstanceStatus;
}
@@ -0,0 +1,105 @@
package com.budwk.app.bpm.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import java.io.Serializable;
import java.util.List;
@Table("bpm_process_node_define")
@Comment("流程节点定义")
@Data
@EqualsAndHashCode(callSuper = true)
@TableMeta("{'mysql-charset':'utf8mb4'}")
@TableIndexes({
@Index(name = "INDEX_BPM_PROCESS_NODE_DEFINE_NODE_CODE", fields = {"nodeCode"}, unique = false)
})
public class BpmProcessNodeDefine extends BaseModel implements Serializable {
@Column
@Name
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("流程定义ID")
private String processDefineId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("节点名称")
private String nodeName;
@Column
@ColDefine(type = ColType.INT)
@Comment("节点编码")
private Integer nodeCode;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("节点审批类型(pending、node_pass、node_reject,node_back")
private String nodeApprovalType;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("节点类型(start,task,end)")
private String nodeType;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("节点参与类型")
private String nodePerformType;
// @Column
// @ColDefine(type = ColType.VARCHAR,width = 100)
// @Comment("会签节点完成表达式")
// private String nodeCountersignExpression;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("通过下个节点")
private String passNextNodeId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("拒绝下个节点")
private String rejectNextNodeId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("退回下个节点")
private String backNextNodeId;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("动态决策(优先级最高)")
private List<DynamicDecision> dynamicDecisions;
@Column
@ColDefine(type = ColType.INT)
@Comment("排序")
private Integer sort;
@Data
public static class DynamicDecision {
//表达式
private String condition;
//描述
private String desc;
//节点ID
private String toNodeId;
}
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("url")
private String url;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("h5url")
private String h5url;
}
@@ -0,0 +1,167 @@
package com.budwk.app.bpm.models;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Table("bpm_process_task")
@Comment("流程任务")
@Data
@EqualsAndHashCode(callSuper = true)
@TableMeta("{'mysql-charset':'utf8mb4'}")
@TableIndexes({
@Index(name = "INDEX_BPM_PROCESS_TASK_INSTANCE_NODE_CREATED", fields = {"processInstanceId","processTaskNodeCode","createdOn"},unique = false),
@Index(name = "INDEX_BPM_PROCESS_TASK_TRANSFER_AFTER_TASK",fields = {"transferAfterTaskId"},unique = false),
@Index(name = "INDEX_BPM_PROCESS_TASK_STATUS",fields = {"taskStatus"},unique = false),
})
public class BpmProcessTask extends BaseModel implements Serializable {
@Column
@Name
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("流程定义ID")
private String processDefineId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("流程实例ID")
private String processInstanceId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("所属节点ID")
private String processTaskNodeId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("所属节点名称")
private String processTaskNodeName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("所属节点编码")
private Integer processTaskNodeCode;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("上个任务ID")
private String prevTaskId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("上个任务节点ID")
private String prevTaskNodeId;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("任务接收人")
private List<String> assignments;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("任务接收人姓名")
private List<String> assignmentUserNames;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("任务接收人单位")
private List<String> assignmentUnitNames;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("任务创建时间")
private Date createdOn;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("任务完成时间")
private Date endOn;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("办理人ID")
private String actualOwnerId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 120)
@Comment("办理人工号")
private String actualOwnerLoginName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("办理人姓名")
private String actualOwnerUserName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("办理人部门")
private String actualOwnerUnitName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("任务的处理表单URL,用于待办任务的处理界面")
private String formUrl;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("任务的浏览表单URL,用于已办任务的表单查看")
private String formUrlView;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("手机端任务的处理表单URL,用于待办任务的处理界面")
private String formMobileUrl;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("手机端任务的浏览表单URL,用于已办任务的表单查看")
private String formMobileUrlView;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("状态")
private String taskStatus;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("审批意见")
private String taskComment;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否已阅")
private Boolean isRead;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("扩展变量")
private JSONObject extVariable;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("任务生成时的变量")
private JSONObject createVariable;
@Column
@ColDefine(type = ColType.VARCHAR,width = 32)
@Comment("任务转办后的taskId")
private String transferAfterTaskId;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否自动完成")
@Default("0")
private Boolean isAutoComplete;
}
@@ -0,0 +1,18 @@
package com.budwk.app.bpm.param;
import com.budwk.app.base.param.PageForm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@ApiModel(description = "流程实例查询参数")
@Data
public class BpmProcessInstancePageForm extends PageForm {
@ApiModelProperty("流程实例名称")
private String processInstanceName;
}
@@ -0,0 +1,61 @@
package com.budwk.app.bpm.param;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.bpm.enums.BpmTaskApprovalTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@ApiModel("任务审批参数")
public class BpmTaskApprovalParam {
@ApiModelProperty("流程实例ID")
@NotBlank(message = "流程实例ID不能为空")
private String processInstanceId;
@ApiModelProperty("流程业务ID")
@NotBlank(message = "流程业务ID不能为空")
private String processInstanceBusinessId;
@ApiModelProperty("流程任务ID")
@NotBlank(message = "流程任务ID不能为空")
private String processInstanceTaskId;
@ApiModelProperty("任务审批类型")
@NotBlank(message = "任务审批类型不能为空")
private String bpmTaskApprovalType;
public BpmTaskApprovalTypeEnum getBpmTaskApprovalTypeEnum() {
BpmTaskApprovalTypeEnum approvalTypeEnum = EnumUtil.getBy(BpmTaskApprovalTypeEnum.class, val -> val.name().equals(this.getBpmTaskApprovalType()));
if (ObjectUtil.isNull(approvalTypeEnum)) {
throw new RuntimeException("任务审批类型错误,请传入正确的任务审批类型。");
}
this.setBpmTaskApprovalTypeEnum(approvalTypeEnum);
return approvalTypeEnum;
}
public void setBpmTaskApprovalTypeEnum(BpmTaskApprovalTypeEnum bpmTaskApprovalTypeEnum) {
BpmTaskApprovalTypeEnum approvalTypeEnum = EnumUtil.getBy(BpmTaskApprovalTypeEnum.class, val -> val.name().equals(this.getBpmTaskApprovalType()));
if (ObjectUtil.isNull(approvalTypeEnum)) {
throw new RuntimeException("任务审批类型错误,请传入正确的任务审批类型。");
}
this.bpmTaskApprovalTypeEnum = approvalTypeEnum;
}
@ApiModelProperty("任务审批类型枚举")
private BpmTaskApprovalTypeEnum bpmTaskApprovalTypeEnum;
@ApiModelProperty("审批意见")
private String approvalOpinion;
@ApiModelProperty("审批签字")
private String approvalSignature;
@ApiModelProperty("审批备注")
private String approvalRemark;
}
@@ -0,0 +1,9 @@
package com.budwk.app.bpm.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.bpm.models.BpmProcessDefine;
public interface BpmProcessDefineService extends BaseService<BpmProcessDefine> {
}
@@ -0,0 +1,13 @@
package com.budwk.app.bpm.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.bpm.models.BpmProcessInstance;
public interface BpmProcessInstanceService extends BaseService<BpmProcessInstance> {
/**
* 关闭流程实例
* @param id
*/
void closeInstance(String id);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
package com.budwk.app.bpm.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.bpm.models.BpmProcessDefine;
import com.budwk.app.bpm.service.BpmProcessDefineService;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"})
public class BpmProcessDefineServiceImpl extends BaseServiceImpl<BpmProcessDefine> implements BpmProcessDefineService {
public BpmProcessDefineServiceImpl(Dao dao) {
super(dao);
}
}
@@ -0,0 +1,20 @@
package com.budwk.app.bpm.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.bpm.models.BpmProcessInstance;
import com.budwk.app.bpm.service.BpmProcessInstanceService;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"})
public class BpmProcessInstanceServiceImpl extends BaseServiceImpl<BpmProcessInstance> implements BpmProcessInstanceService {
public BpmProcessInstanceServiceImpl(Dao dao) {
super(dao);
}
@Override
public void closeInstance(String id) {
}
}
@@ -0,0 +1,200 @@
package com.budwk.app.bpm.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.expression.ExpressionUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.bpm.enums.BpmProcessNodeApprovalTypeEnum;
import com.budwk.app.bpm.enums.BpmProcessNodeTypeEnum;
import com.budwk.app.bpm.enums.BpmTaskApprovalTypeEnum;
import com.budwk.app.bpm.models.BpmProcessNodeDefine;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 流程工具类
*/
public class BpmUtil {
/**
* 执行动态判断表达式 获取下一个节点
*
* @param decisions
* @param variables
* @return
*/
public static String evalExpressionGetNextTaskNodeId(BpmProcessNodeDefine taskNode, BpmTaskApprovalTypeEnum bpmTaskApprovalTypeEnum, List<BpmProcessNodeDefine.DynamicDecision> decisions, Map<String, Object> variables) {
if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.DYNAMIC)) {
if (ObjectUtil.isEmpty(decisions)) {
throw new BaseException("动态分支节点配置为空");
}
for (BpmProcessNodeDefine.DynamicDecision decision : decisions) {
String expression = decision.getCondition();
Object eval = ExpressionUtil.eval(expression, variables);
if (Convert.toBool(eval, false)) {
return decision.getToNodeId();
}
}
return null;
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.APPLY)) {
if(ObjectUtil.isEmpty(taskNode.getDynamicDecisions())){
return taskNode.getPassNextNodeId();
}else{
for (BpmProcessNodeDefine.DynamicDecision decision : decisions) {
String expression = decision.getCondition();
Object eval = ExpressionUtil.eval(expression, variables);
if (Convert.toBool(eval, false)) {
return decision.getToNodeId();
}
}
}
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.REJECT)) {
return taskNode.getRejectNextNodeId();
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.BACK)) {
return taskNode.getBackNextNodeId();
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.PASS)) {
return taskNode.getPassNextNodeId();
}
throw new BaseException("{}节点{}配置错误", taskNode.getNodeName(), bpmTaskApprovalTypeEnum.name());
}
/**
* 验证流程定义节点是否正确
* @param nodes
*/
public static void validateNodes(List<BpmProcessNodeDefine> nodes) {
//名称必填
for (BpmProcessNodeDefine node : nodes) {
if (StrUtil.isBlank(node.getNodeName())) {
throw new RuntimeException("节点名称不能为空,请检查");
}
}
//code必填
for (BpmProcessNodeDefine node : nodes) {
if (ObjectUtil.isNull(node.getNodeCode())) {
throw new RuntimeException("节点编码不能为空,请检查");
}
}
//节点类型必填
for (BpmProcessNodeDefine node : nodes) {
if (StrUtil.isBlank(node.getNodeType())) {
throw new RuntimeException("节点类型不能为空,请检查");
}
}
//code不能重复
Set<Integer> codes = new HashSet<>();
for (BpmProcessNodeDefine node : nodes) {
if (!codes.add(node.getNodeCode())) {
throw new RuntimeException("节点编码重复,请检查");
}
}
if (nodes.stream().noneMatch(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.START.name()))) {
throw new RuntimeException("流程定义中必须存在开始节点,请检查");
}
if (nodes.stream().noneMatch(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.END.name()))) {
throw new RuntimeException("流程定义中必须存在结束节点,请检查");
}
if (nodes.stream().noneMatch(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.TASK.name()))) {
throw new RuntimeException("流程定义中必须存在任务节点,请检查");
}
//单个判断
for (BpmProcessNodeDefine node : nodes) {
if(node.getNodeType().equals(BpmProcessNodeTypeEnum.START.name())){
validateStartNode(node, nodes);
}else if(node.getNodeType().equals(BpmProcessNodeTypeEnum.END.name())){
validateEndNode(node, nodes);
}else if(node.getNodeType().equals(BpmProcessNodeTypeEnum.TASK.name())){
validateTaskNode(node, nodes);
}else if(node.getNodeType().equals(BpmProcessNodeTypeEnum.BACK.name())){
validateBackNode(node, nodes);
}
}
}
/**
* 验证开始节点
*
* @param startNode
* @param nodes
*/
private static void validateStartNode(BpmProcessNodeDefine startNode, List<BpmProcessNodeDefine> nodes) {
String passNextNodeId = startNode.getPassNextNodeId();
if (StrUtil.isBlank(passNextNodeId) && ObjectUtil.isEmpty(startNode.getDynamicDecisions())) {
throw new RuntimeException("开始节点的通过节点或者动态决策表达式不能为空,请检查");
}
if (passNextNodeId.equals(startNode.getId())) {
throw new RuntimeException("开始节点的通过节点不能指向自己,请检查");
}
// if (StrUtil.isBlank(startNode.getNodeApprovalType())) {
// throw new RuntimeException("开始节点的审批完成类型不能为空,请检查");
// }
// if (!startNode.getNodeApprovalType().equals(BpmProcessNodeApprovalTypeEnum.NODE_APPLY.name())) {
// throw new RuntimeException("开始节点的审批完成类型只能为申请,请检查");
// }
}
/**
* 验证结束节点
*
* @param endNode
* @param nodes
*/
private static void validateEndNode(BpmProcessNodeDefine endNode, List<BpmProcessNodeDefine> nodes) {
}
/**
* 验证任务节点
*
* @param taskNode
* @param nodes
*/
private static void validateTaskNode(BpmProcessNodeDefine taskNode, List<BpmProcessNodeDefine> nodes) {
if (StrUtil.isAllBlank(taskNode.getPassNextNodeId(), taskNode.getRejectNextNodeId(), taskNode.getBackNextNodeId()) && ObjectUtil.isEmpty(taskNode.getDynamicDecisions())) {
throw new RuntimeException("任务节点的通过、拒绝、退回节点和动态决策不能同时为空,请检查");
}
if (ObjectUtil.isEmpty(taskNode.getDynamicDecisions()) && StrUtil.isBlank(taskNode.getPassNextNodeId())) {
throw new RuntimeException("任务节点的通过节点不能为空,请检查");
}
if (StrUtil.isNotBlank(taskNode.getPassNextNodeId()) && taskNode.getPassNextNodeId().equals(taskNode.getId())) {
throw new RuntimeException("任务节点的通过节点不能指向自己,请检查");
}
if (StrUtil.isBlank(taskNode.getNodePerformType())) {
throw new RuntimeException("任务节点的参与类型不能为空,请检查");
}
// if (StrUtil.isBlank(taskNode.getNodeApprovalType())) {
// throw new RuntimeException("任务节点的审批完成类型不能为空,请检查");
// }
}
/**
* 验证退回节点
* @param backNode
* @param nodes
*/
private static void validateBackNode(BpmProcessNodeDefine backNode, List<BpmProcessNodeDefine> nodes) {
}
/**
* 获取开始节点
* @param nodes
* @return
*/
public static BpmProcessNodeDefine getStartNode(List<BpmProcessNodeDefine> nodes) {
return nodes.stream().filter(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.START.name())).findFirst().orElse(null);
}
}
@@ -0,0 +1,42 @@
package com.budwk.app.bpm.vo;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.bpm.models.BpmProcessTask;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel("任务审批记录")
public class BpmProcessTaskVo extends BpmProcessTask {
@ApiModelProperty("完成时间(含有时分秒)")
private String endOnFull;
@ApiModelProperty("完成时间(不含有时分秒)")
private String endOnSimple;
public String getEndOnSimple() {
Date endOn = this.getEndOn();
if (ObjectUtil.isNull(endOn)) {
DateUtil.format(endOn, "yyyy年MM月dd日");
}
return null;
}
public String getEndOnFull() {
Date endOn = this.getEndOn();
if (ObjectUtil.isNull(endOn)) {
DateUtil.format(endOn, "yyyy-MM-dd HH:mm:ss");
}
return null;
}
}
@@ -0,0 +1,25 @@
package com.budwk.app.bpm.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("任务审批记录")
public class BpmTaskApprovalRecordVo {
@ApiModelProperty("节点ID")
private String id;
@ApiModelProperty("节点名称")
private String nodeName;
@ApiModelProperty("节点编码")
private Integer nodeCode;
@ApiModelProperty("审批记录")
private List<BpmProcessTaskVo> tasks;
}
@@ -0,0 +1,69 @@
package com.budwk.app.bpm.vo;
import cn.hutool.json.JSONObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @version 1.0
* @Author zzr
* @nameBpmTaskApprovalVo
* @Date 2024/10/22 18:28
* @注释
*/
@Data
public class BpmTaskApprovalVo {
@ApiModelProperty("流程实例业务ID")
private String id;
@ApiModelProperty("流程实例ID")
private String processInstanceId;
@ApiModelProperty("流程实例当前节点ID")
private String processInstanceNodeId;
@ApiModelProperty("流程实例当前节点代码")
private Integer processInstanceNodeCode;
@ApiModelProperty("流程实例当前节点名称")
private String processInstanceNodeName;
@ApiModelProperty("流程实例任务IDS")
private List<String> processInstanceTaskIds;
@ApiModelProperty("流程实例任务ID")
private String processInstanceTaskId;
@ApiModelProperty("流程实例任务状态")
private String processInstanceTaskStatus;
@ApiModelProperty("流程状态")
private String processInstanceStatus;
@ApiModelProperty("当前节点任务类型")
private String processInstanceTaskNodeType;
@ApiModelProperty("下一节点任务是否有完成的")
private Boolean nextTaskIsComplete;
@ApiModelProperty("下一节点转办任务是否有完成的")
private Boolean nextTransferTaskIsComplete;
@ApiModelProperty("审批参数")
private JSONObject approvalParam;
public JSONObject getApprovalParam() {
JSONObject object = new JSONObject();
object.set("processInstanceBusinessId",this.getId());
object.set("processInstanceId",this.getProcessInstanceId());
object.set("processInstanceNodeCode",this.getProcessInstanceNodeCode());
object.set("processInstanceNodeName",this.getProcessInstanceNodeName());
object.set("processInstanceNodeId",this.getProcessInstanceNodeId());
object.set("processInstanceTaskIds",this.getProcessInstanceTaskIds());
object.set("processInstanceTaskId",this.getProcessInstanceTaskId());
object.set("processInstanceTaskNodeType",this.getProcessInstanceTaskNodeType());
return object;
}
}