Merge remote-tracking branch 'origin/feature/REQ-1609' into feature/REQ-1609

This commit is contained in:
zuoqinbo 2023-11-14 10:52:03 +08:00
commit 8c5b378bcf
15 changed files with 665 additions and 62 deletions

View File

@ -52,7 +52,7 @@ public interface BpmnConstants {
String NUMBER_OF_INSTANCES = "nrOfInstances"; String NUMBER_OF_INSTANCES = "nrOfInstances";
String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter"; String MULTI_INSTANCE_LOOP_COUNTER = "loopCounter";
String TASK_COMPLETE_OPERATION_TYPE = "_TASK_COMPLETE_TYPE";
/** /**
* 会签表达式 * 会签表达式
*/ */

View File

@ -0,0 +1,86 @@
package cn.axzo.workflow.common.model.request.bpmn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
/**
* 流程定义中的按钮配置
*
* @author wangli
* @since 2023/11/13 13:44
*/
@ApiModel("JSON 版本的 BPMN 协议模型中的按钮管理")
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class BpmnButtonConf {
/**
* 发起人的按钮配置信息, JSON 格式
*/
@ApiModelProperty(value = "发起人的按钮配置信息, JSON 格式", example = "{\"agree\": true, \"reject\": true, \"delegate\": " +
"true, \"cancel\": true, \"withdraw\": true, \"revoke\": true\" }")
@NotBlank(message = "发起人的按钮配置信息不能为空")
private String initiator;
/**
* 当前审批人的按钮配置信息, JSON 格式
*/
@ApiModelProperty(value = "当前审批人的按钮配置信息, JSON 格式", example = "{\"agree\": true, \"reject\": true, \"delegate\": " +
"true, \"cancel\": true, \"withdraw\": true, \"revoke\": true\" }")
@NotBlank(message = "当前审批人的按钮配置信息不能为空")
private String current;
/**
* 历史审批人的按钮配置信息, JSON 格式
*/
@ApiModelProperty(value = "历史审批人的按钮配置信息, JSON 格式", example = "{\"agree\": true, \"reject\": true, \"delegate\": " +
"true, \"cancel\": true, \"withdraw\": true, \"revoke\": true\" }")
@NotBlank(message = "历史审批人的按钮配置信息不能为空")
private String history;
/**
* 抄送人的按钮配置信息, JSON 格式
*/
@ApiModelProperty(value = "抄送人的按钮配置信息, JSON 格式", example = "{\"agree\": true, \"reject\": true, \"delegate\": " +
"true, \"cancel\": true, \"withdraw\": true, \"revoke\": true\" }")
@NotBlank(message = "抄送人的按钮配置信息不能为空")
private String carbonCopy;
public String getInitiator() {
return initiator;
}
public void setInitiator(String initiator) {
this.initiator = initiator;
}
public String getCurrent() {
return current;
}
public void setCurrent(String current) {
this.current = current;
}
public String getHistory() {
return history;
}
public void setHistory(String history) {
this.history = history;
}
public String getCarbonCopy() {
return carbonCopy;
}
public void setCarbonCopy(String carbonCopy) {
this.carbonCopy = carbonCopy;
}
}

View File

@ -0,0 +1,154 @@
package cn.axzo.workflow.common.model.request.bpmn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 条件
*
* @author wangli
* @since 2023/11/13 20:33
*/
@ApiModel("JSON 版本的 BPMN 协议模型中的条件")
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class BpmnCondition {
/**
* string(字符串)/number(数字)/radio(单选)/checkbox(复选)
*/
@ApiModelProperty(value = "基础属性:字段类型", notes = "string, number, radio, checkbox", example = "string")
private String filedDateType;
/**
* 字段 code
*/
@ApiModelProperty(value = "基础属性:字段 code", notes = "字段管理中字段的 Code", example = "fieldCode")
private String fieldCode;
/**
* 操作符(与字段类型有关)
* <p>
* 当字段类型为 string , 操作符为 contains, notContains
* 当字段类型为 number , 操作符为 eq, ne, gt, ge, lt, le, between
* 当字段类型为 radio , 操作符为 eq
* 当字段类型为 checkbox , 操作符为 in
*/
@ApiModelProperty(value = "基础属性:操作符", notes = "操作符", example = "eq")
private String operator;
/**
* 默认的比较值
*/
@ApiModelProperty(value = "基础属性:默认的比较值", notes = "同时也用于 fieldDateType = radio", example = "1")
private String defaultValue;
/**
* 只有 fieldDateType = checkbox 才有值
*/
@ApiModelProperty(value = "当 fieldDateType = checkbox时, 选中的值")
private List<String> defaultValues;
/**
* 只有 operator = between 才有值
*/
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 左侧操作符")
private String leftOperator;
/**
* 只有 operator = between 才有值
*/
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 右侧操作符")
private String rightOperator;
/**
* 只有 operator = between 才有值
*/
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 左侧比较值")
private String leftValue;
/**
* 只有 operator = between 才有值
*/
@ApiModelProperty(value = "当 fieldDateType = number 并且 operator = between 时, 右侧比较值")
private String rightValue;
public String getFiledDateType() {
return filedDateType;
}
public void setFiledDateType(String filedDateType) {
this.filedDateType = filedDateType;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getOperator() {
return operator;
}
public void setOperator(String operator) {
this.operator = operator;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public List<String> getDefaultValues() {
return defaultValues;
}
public void setDefaultValues(List<String> defaultValues) {
this.defaultValues = defaultValues;
}
public String getLeftOperator() {
return leftOperator;
}
public void setLeftOperator(String leftOperator) {
this.leftOperator = leftOperator;
}
public String getRightOperator() {
return rightOperator;
}
public void setRightOperator(String rightOperator) {
this.rightOperator = rightOperator;
}
public String getLeftValue() {
return leftValue;
}
public void setLeftValue(String leftValue) {
this.leftValue = leftValue;
}
public String getRightValue() {
return rightValue;
}
public void setRightValue(String rightValue) {
this.rightValue = rightValue;
}
}

View File

@ -0,0 +1,48 @@
package cn.axzo.workflow.common.model.request.bpmn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 条件组
* <p>
* 目前条件中的所有项都是"并且",所以没有第二个属性,如果以后有"或者"的情况,再加
*
* @author wangli
* @since 2023/11/13 19:58
*/
@ApiModel("JSON 版本的 BPMN 协议模型中的条件组")
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class BpmnConditionGroup {
@ApiModelProperty(value = "条件组")
private List<BpmnCondition> conditions;
/**
* 条件间模式,默认为"and"
*/
private String mode = "and";
public List<BpmnCondition> getConditions() {
return conditions;
}
public void setConditions(List<BpmnCondition> conditions) {
this.conditions = conditions;
}
public String getMode() {
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
}

View File

@ -0,0 +1,91 @@
package cn.axzo.workflow.common.model.request.bpmn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.util.List;
/**
* 流程定义中的字段管理
*
* @author wangli
* @since 2023/11/13 13:53
*/
@ApiModel("JSON 版本的 BPMN 协议模型中的字段管理")
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class BpmnFieldConf {
/**
* 字段的 code
*/
@ApiModelProperty(value = "字段的 code", example = "fieldCode", notes = "字段的 code 必须唯一")
@NotBlank(message = "字段的 code 不能为空")
private String code;
/**
* 字段的名称
*/
@ApiModelProperty(value = "字段的名称", example = "字段名称")
@NotBlank(message = "字段的名称不能为空")
private String name;
/**
* 字段的类型
*/
@ApiModelProperty(value = "字段的类型", example = "string", notes = "string, number, date, datetime, boolean, " +
"select, radio, checkbox, textarea, file, image, editor")
@NotBlank(message = "字段的类型不能为空")
private String type;
/**
* 单选或多选的下拉选择框中的数据, 只有单选或多选的时候才会有值,并且内部的属性不应该为空
*/
@ApiModelProperty(value = "单选或多选的下拉选择框中的数据")
@Valid
private List<BpmnFieldOptionConf> options;
}
/**
* 单选/多选的选项配置
*/
@Accessors(chain = true)
@Data
@NoArgsConstructor
class BpmnFieldOptionConf {
/**
* 选项的名称
*/
@ApiModelProperty(value = "选项的名称", example = "选项1")
@NotBlank(message = "选项的名称不能为空")
private String name;
/**
* 选项的值
*/
@ApiModelProperty(value = "选项的值", example = "1")
@NotBlank(message = "选项的值不能为空")
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -1,11 +1,15 @@
package cn.axzo.workflow.common.model.request.bpmn; package cn.axzo.workflow.common.model.request.bpmn;
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode; import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
/** /**
* JSON 版本的 BPMN 协议中 UserTask 节点的属性扩展模型 * JSON 版本的 BPMN 协议中 UserTask 节点的属性扩展模型
*/ */
@ -13,47 +17,71 @@ import lombok.Data;
@Data @Data
public class BpmnJsonNodeProperty { public class BpmnJsonNodeProperty {
//************* 审批方式Start **************//
/** /**
* 发起人节点审批人规则类型 * 审批方式: human(人工审批), autoPassed(自动通过), autoRejection(自动拒绝), nobody(不审批[仅业务节点可能有该值])
*/ */
@ApiModelProperty(value = "发起人节点: 发起人规则类型 ASSIGN_USER/POSITION/ROLE") @ApiModelProperty(value = "任务节点: 审批方式", notes = "human: 人工审批, autoPassed: 自动通过, autoRejection: 自动拒绝, nobody: " +
private String initiatorType; "不审批[仅业务节点可能有该值]")
@NotBlank(message = "审批方式不能为空")
private String approvalMethod;
//************* 审批方式End **************//
//************* 审批人所在范围Start **************//
/**
* 审批人所在范围: EntWorkspace(企业工作台), projectWorkspace(项目工作台), preTaskUserEnt(上节点审批人所在单位)
*/
@ApiModelProperty(value = "任务节点: 审批人所在范围", notes = "EntWorkspace: 企业工作台, projectWorkspace: 项目工作台, preTaskUserEnt:" +
" 上节点审批人所在单位")
private String approverScope;
//************* 审批人所在范围End **************//
//************* 审批人指定Start **************//
/**
* 审批人指定: position(指定岗位), role(指定角色), identity(指定身份), initiatorLeader(发起人主管)
*/
@ApiModelProperty(value = "任务节点: 审批人指定", notes = "position: 指定岗位, role: 指定角色, identity: 指定身份, initiatorLeader: " +
"发起人主管")
@NotBlank(message = "审批人指定不能为空")
private String approverSpecify;
/** /**
* 非指定人时, 发起人和任务节点审批人具体的规则值 * 具体的配置
*/ */
@ApiModelProperty(value = "发起人节点/任务节点: 非 ASSIGN_USER 外的规则具体表达式") @ApiModelProperty(value = "任务节点: 审批人指定的具体值")
private String assigneeExpression; @NotEmpty(message = "审批人指定的具体值不能为空")
private List<String> specifyValue;
//************* 审批人指定End **************//
//************* 多人审批时审批方式Start **************//
/** /**
* 是否是多实例Task节点 * 是否是多实例Task节点, 在安心筑业务中, 所有节点应该都是多实例节点
*/ */
@ApiModelProperty("任务节点: 是否是多实例Task节点") @ApiModelProperty(value = "任务节点: 是否是多实例Task节点", notes = "在安心筑业务中, 所有节点应该都是多实例节点")
private Boolean isMultiTask; private Boolean isMultiTask = true;
/** /**
* Task 多实例模式OR"或签"AND"会签" * Task 多实例模式OR"或签"AND"会签"
*/ */
@ApiModelProperty(value = "任务节点: 多实例模式OR或签AND会签") @ApiModelProperty(value = "任务节点: 多实例模式OR或签AND会签")
@NotNull(message = "多实例模式不能为空")
private BpmnFlowNodeMode multiMode; private BpmnFlowNodeMode multiMode;
//************* 多人审批时审批方式End **************//
//************* 审批人为空时Start **************//
/** /**
* 审批人为空是否允许自动跳过 * 审批人为空是否允许自动跳过
*/ */
@ApiModelProperty(value = "任务节点: 审批人为空是否允许自动跳过") @ApiModelProperty(value = "任务节点: 审批人为空处理方式", notes = "autoPassed: 自动通过, autoSkipped: 自动跳过, transferToAdmin: 转交给管理员")
private Boolean allowSkip = false; @NotBlank(message = "审批人为空处理方式不能为空")
private String approverEmptyHandleType;
//************* 审批人为空时的策略End **************//
/**
* 任务节点审批人规则类型
*/
@ApiModelProperty(value = "任务节点: 审批人规则类型 ASSIGN_USER/POSITION/ROLE")
private String assignedType;
/**
* 指定审批人或发起人时,传入的信息
*/
@ApiModelProperty(value = "发起人节点/任务节点: 指定审批人")
private BpmnTaskDelegateAssigner assigner;
/** /**
* 表单字段权限 * 表单字段权限
@ -67,23 +95,17 @@ public class BpmnJsonNodeProperty {
@ApiModelProperty(value = "发起人节点/任务节点: 按钮权限集合", notes = "后端不做任何解析, 前端给什么样,就返什么样") @ApiModelProperty(value = "发起人节点/任务节点: 按钮权限集合", notes = "后端不做任何解析, 前端给什么样,就返什么样")
private String buttonPermission; private String buttonPermission;
//************* 条件节点Start **************//
/** /**
* 条件节点中是否是默认分支可以都不传; * 条件节点中是否是默认分支可以都不传;
*/ */
@ApiModelProperty(value = "条件节点: 是否是默认条件分支") @ApiModelProperty(value = "条件节点: 是否是默认条件分支")
private Boolean defaultBranch; private Boolean defaultBranch;
/** @ApiModelProperty(value = "条件节点: 条件分组集合")
* 条件分支的Key private List<BpmnConditionGroup> groups;
*/ //************* 条件节点End **************//
@ApiModelProperty(value = "条件节点: 条件分支的Key", notes = "枢智业务使用的极简条件判断方式")
private String conditionBranchKey;
/**
* 条件节点当ConditionKey的值是多少走该分支
*/
@ApiModelProperty(value = "条件节点: 当ConditionKey的值是多少走该分支", notes = "枢智业务使用的极简条件判断方式")
private Integer conditionBranchValue;
/** /**
* 发起时使用的表单 key * 发起时使用的表单 key

View File

@ -0,0 +1,66 @@
package cn.axzo.workflow.common.model.request.bpmn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
/**
* 流程定义中的通知配置
*
* @author wangli
* @since 2023/11/13 13:38
*/
@ApiModel("JSON 版本的 BPMN 协议模型中的通知管理")
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class BpmnNoticeConf {
/**
* 待办消息模板 ID
*/
@ApiModelProperty(value = "待办消息模板 ID")
@NotBlank(message = "待办消息模板 ID 不能为空")
private String pendingMessageId;
/**
* 通知消息模板 ID
*/
@ApiModelProperty(value = "通知消息模板 ID")
@NotBlank(message = "通知消息模板 ID 不能为空")
private String noticeMessageId;
/**
* 短信模板 ID
*/
@ApiModelProperty(value = "短信模板 ID")
private String smsId;
public String getPendingMessageId() {
return pendingMessageId;
}
public void setPendingMessageId(String pendingMessageId) {
this.pendingMessageId = pendingMessageId;
}
public String getNoticeMessageId() {
return noticeMessageId;
}
public void setNoticeMessageId(String noticeMessageId) {
this.noticeMessageId = noticeMessageId;
}
public String getSmsId() {
return smsId;
}
public void setSmsId(String smsId) {
this.smsId = smsId;
}
}

View File

@ -1,12 +1,16 @@
package cn.axzo.workflow.common.model.request.bpmn.model; package cn.axzo.workflow.common.model.request.bpmn.model;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnFieldConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode; import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
/** /**
@ -33,7 +37,8 @@ public class BpmnModelCreateDTO {
/** /**
* 自定义分类 * 自定义分类
*/ */
@ApiModelProperty(value = "自定义分类", notes = "由业务自定义", example = "1") @ApiModelProperty(value = "自定义分类", notes = "由业务自定义")
@NotBlank(message = "自定义分类不能为空")
private String category; private String category;
/** /**
@ -45,9 +50,30 @@ public class BpmnModelCreateDTO {
/** /**
* 流程的Json 结构 * 流程的Json 结构
*/ */
@ApiModelProperty(value = "流程的Json 结构", example = "1") @ApiModelProperty(value = "流程的 Json 结构")
private BpmnJsonNode node; private BpmnJsonNode node;
/**
* 通知管理配置
*/
@ApiModelProperty(value = "通知管理配置")
@Valid
private BpmnNoticeConf noticeConf;
/**
* 流程定义的全局默认按钮权限数据
*/
@ApiModelProperty(value = "流程按钮配置")
@Valid
private BpmnButtonConf buttonConf;
/**
* 流程定义的全局字段管理数据
*/
@ApiModelProperty(value = "流程字段配置")
@Valid
private BpmnFieldConf fieldConf;
/** /**
* 租户Id * 租户Id
*/ */

View File

@ -43,7 +43,7 @@ public enum BpmnErrorCode implements IProjectRespCode {
PROCESS_OPERATION_PARAM_VALID_ERROR("05001", "参数缺失, 请确保传入了 ID 或 businessKey 对流程实例进行操作"), PROCESS_OPERATION_PARAM_VALID_ERROR("05001", "参数缺失, 请确保传入了 ID 或 businessKey 对流程实例进行操作"),
PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS("05002", "流程取消失败,流程不处于运行中"), PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS("05002", "流程取消失败,流程不处于运行中"),
PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF("05003", "流程取消失败,该流程不是你发起的"), PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF("05003", "流程取消失败,该流程不是你发起的"),
PROCESS_INSTANCE_NOT_EXISTS("05004", "流程实例不存在"), PROCESS_INSTANCE_NOT_EXISTS("05004", "流程实例不存在或已结束"),
PROCESS_INSTANCE_ID_NOT_EXISTS("05005", "流程实例【{}】不存在"), PROCESS_INSTANCE_ID_NOT_EXISTS("05005", "流程实例【{}】不存在"),
PROCESS_INSTANCE_CANCELLED("05006", "流程实例已取消"), PROCESS_INSTANCE_CANCELLED("05006", "流程实例已取消"),
// ========== bpmn task 06-001 ========== // ========== bpmn task 06-001 ==========

View File

@ -77,7 +77,9 @@ public class EngineExecutionStartListener implements ExecutionListener {
// UserTask 非多实例 // UserTask 非多实例
if (!userTask.hasMultiInstanceLoopCharacteristics()) { if (!userTask.hasMultiInstanceLoopCharacteristics()) {
//TODO by zuoqinbo assigneeIdList.size==0情况 //TODO by zuoqinbo assigneeIdList.size==0情况
if (!CollectionUtils.isEmpty(assigneeIdList)) {
userTask.setAssignee(assigneeIdList.get(0)); userTask.setAssignee(assigneeIdList.get(0));
}
// remove by wangli, 暂时去除审批人变量, 通过上面直接赋值 // remove by wangli, 暂时去除审批人变量, 通过上面直接赋值
// execution.setVariable("assigneeUserId", assigneeIdList.get(0)); // execution.setVariable("assigneeUserId", assigneeIdList.get(0));

View File

@ -285,7 +285,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
public Boolean cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) { public Boolean cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) {
HistoricProcessInstance instance = null; HistoricProcessInstance instance = null;
if (StringUtils.isNotBlank(dto.getId())) { if (StringUtils.isNotBlank(dto.getId())) {
instance = getProcessInstance(dto.getId(), dto.getInitiator().getTenantId(), false); instance = getProcessInstance(dto.getId(), null, false);
// instance = getProcessInstance(dto.getId(), dto.getInitiator().getTenantId(), false);
} else if (StringUtils.isNotBlank(dto.getBusinessKey())) { } else if (StringUtils.isNotBlank(dto.getBusinessKey())) {
instance = getProcessInstanceByBusinessKey(dto.getBusinessKey(), dto.getInitiator().getTenantId(), false); instance = getProcessInstanceByBusinessKey(dto.getBusinessKey(), dto.getInitiator().getTenantId(), false);
} else { } else {

View File

@ -1,8 +1,13 @@
package cn.axzo.workflow.core.service.impl; package cn.axzo.workflow.core.service.impl;
import cn.axzo.workflow.common.enums.BpmnCountersignType;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.*; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAssigneeDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO;
@ -72,8 +77,8 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NE
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT; import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER; import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER;
import static cn.axzo.workflow.common.constant.BpmnConstants.NUMBER_OF_INSTANCES; import static cn.axzo.workflow.common.constant.BpmnConstants.NUMBER_OF_INSTANCES;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCELLED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus;
@ -286,7 +291,7 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
Task task = checkTask(dto.getApprover().getTenantId(), dto.getApprover().buildAssigneeId(), dto.getTaskId()); Task task = checkTask(dto.getApprover().getTenantId(), dto.getApprover().buildAssigneeId(), dto.getTaskId());
// 校验流程实例存在 // 校验流程实例存在
HistoricProcessInstance instance = processInstanceService.getProcessInstance( HistoricProcessInstance instance = processInstanceService.getProcessInstance(
task.getProcessInstanceId(), dto.getApprover().getTenantId(), true); task.getProcessInstanceId(), null, true);
if (instance == null) { if (instance == null) {
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS); throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
} }
@ -374,7 +379,9 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
query.taskTenantId(tenantId); query.taskTenantId(tenantId);
} }
HistoricProcessInstanceQuery instanceQuery = HistoricProcessInstanceQuery instanceQuery =
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId); historyService.createHistoricProcessInstanceQuery()
.includeProcessVariables()
.processInstanceId(processInstanceId);
if (StringUtils.hasLength(tenantId)) { if (StringUtils.hasLength(tenantId)) {
instanceQuery.processInstanceTenantId(tenantId); instanceQuery.processInstanceTenantId(tenantId);
} }
@ -398,16 +405,12 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
Set<String> taskDefinitionKeys = new HashSet<>(); Set<String> taskDefinitionKeys = new HashSet<>();
int count = 0; int count = 0;
BpmnProcessInstanceResultEnum finalBusinessStatus = valueOfStatus(instance.getBusinessStatus()); BpmnProcessInstanceResultEnum processBusinessStatus = valueOfStatus(instance.getBusinessStatus());
for (BpmnHistoricTaskInstanceVO vo : vos) { for (BpmnHistoricTaskInstanceVO vo : vos) {
if (count == 0 || taskDefinitionKeys.contains(vo.getTaskDefinitionKey())) { vo.setResult(processBusinessStatus);
vo.setResult(finalBusinessStatus); if (Objects.nonNull(vo.getEndTime())) {
if (Objects.nonNull(vo.getEndTime()) && !Objects.equals(finalBusinessStatus, REJECTED) // 只有拒绝时, 为指定的 taskId 设置过拒绝变量
&& !Objects.equals(finalBusinessStatus, CANCELLED)) { vo.setResult((BpmnProcessInstanceResultEnum) instance.getProcessVariables().getOrDefault(TASK_COMPLETE_OPERATION_TYPE + vo.getTaskId(), APPROVED));
vo.setResult(APPROVED);
}
} else {
vo.setResult(APPROVED);
} }
taskDefinitionKeys.add(vo.getTaskDefinitionKey()); taskDefinitionKeys.add(vo.getTaskDefinitionKey());
List<Comment> taskComments = commentByTaskIdMap.getOrDefault(vo.getTaskId(), Collections.emptyList()); List<Comment> taskComments = commentByTaskIdMap.getOrDefault(vo.getTaskId(), Collections.emptyList());
@ -482,9 +485,20 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
List<BpmnTaskInstanceVO> vos = bpmnTaskConverter.toVos(query.list()); List<BpmnTaskInstanceVO> vos = bpmnTaskConverter.toVos(query.list());
List<String> snapshotTaskIds = List<String> snapshotTaskIds =
vos.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId()).collect(Collectors.toList()); vos.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId()).collect(Collectors.toList());
ProcessInstance processInstance =
runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (Objects.isNull(processInstance)) {
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
}
Map<String, VariableInstance> instanceMap = runtimeService.getVariableInstances(processInstanceId, Map<String, VariableInstance> instanceMap = runtimeService.getVariableInstances(processInstanceId,
snapshotTaskIds); snapshotTaskIds);
vos.forEach(i -> i.setAssigner((BpmnTaskDelegateAssigner) instanceMap.get(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId()).getValue())); vos.forEach(i -> {
VariableInstance variableInstance =
instanceMap.get(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId());
if (!Objects.isNull(variableInstance)) {
i.setAssigner((BpmnTaskDelegateAssigner) variableInstance.getValue());
}
});
return vos; return vos;
} }
@ -497,13 +511,11 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
* @param taskId 任务ID * @param taskId 任务ID
*/ */
private Task checkTask(String tenantId, String assignee, String taskId) { private Task checkTask(String tenantId, String assignee, String taskId) {
Task task = getTask(taskId, null, null);
Task task = getTask(taskId, assignee, tenantId);
if (Objects.nonNull(task) && !Objects.equals(assignee, task.getAssignee())) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
}
if (Objects.isNull(task)) { if (Objects.isNull(task)) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_NOT_EXISTS); throw new WorkflowEngineException(TASK_COMPLETE_FAIL_NOT_EXISTS);
} else if (!Objects.equals(assignee, task.getAssignee()) && !Objects.equals(tenantId, task.getTenantId())) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
} }
return task; return task;
} }

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable="http://flowable.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/test">
<process id="DESC1234616312350093314" name="文档借阅" isExecutable="true">
<startEvent id="startEventNode"></startEvent>
<userTask id="NODE1639041346796_0.5413743892974803_0" name="发起">
<extensionElements>
<flowable:executionListener event="start"
delegateExpression="${engineExecutionStartListener}"></flowable:executionListener>
<flowable:taskListener event="all"
delegateExpression="${engineTaskEventListener}"></flowable:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="sequenceFlow_b3da60bc0b404ddf9b871d2c2ed2d396" sourceRef="startEventNode"
targetRef="NODE1639041346796_0.5413743892974803_0"></sequenceFlow>
<userTask id="NODE1687933854432_0.45762305710855467_1" name="审批人">
<extensionElements>
<flowable:executionListener event="start"
delegateExpression="${engineExecutionStartListener}"></flowable:executionListener>
<flowable:taskListener event="all"
delegateExpression="${engineTaskEventListener}"></flowable:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="sequenceFlow_5c4c308bd9b144cd9440a6f2dfd6af99"
sourceRef="NODE1639041346796_0.5413743892974803_0"
targetRef="NODE1687933854432_0.45762305710855467_1"></sequenceFlow>
<endEvent id="endEventNode"></endEvent>
<sequenceFlow id="sequenceFlow_b6ebf56f49bf43f295533ab8e10d09a7"
sourceRef="NODE1687933854432_0.45762305710855467_1" targetRef="endEventNode"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_DESC1234616312350093314">
<bpmndi:BPMNPlane bpmnElement="DESC1234616312350093314" id="BPMNPlane_DESC1234616312350093314">
<bpmndi:BPMNShape bpmnElement="NODE1687933854432_0.45762305710855467_1"
id="BPMNShape_NODE1687933854432_0.45762305710855467_1">
<omgdc:Bounds height="60.0" width="100.0" x="230.0" y="0.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="startEventNode" id="BPMNShape_startEventNode">
<omgdc:Bounds height="30.0" width="30.0" x="0.0" y="15.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="NODE1639041346796_0.5413743892974803_0"
id="BPMNShape_NODE1639041346796_0.5413743892974803_0">
<omgdc:Bounds height="60.0" width="100.0" x="80.0" y="0.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endEventNode" id="BPMNShape_endEventNode">
<omgdc:Bounds height="30.0" width="30.0" x="380.0" y="15.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_b3da60bc0b404ddf9b871d2c2ed2d396"
id="BPMNEdge_sequenceFlow_b3da60bc0b404ddf9b871d2c2ed2d396">
<omgdi:waypoint x="30.0" y="30.0"></omgdi:waypoint>
<omgdi:waypoint x="42.0" y="30.0"></omgdi:waypoint>
<omgdi:waypoint x="42.0" y="30.000000000000007"></omgdi:waypoint>
<omgdi:waypoint x="80.0" y="30.000000000000007"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_b6ebf56f49bf43f295533ab8e10d09a7"
id="BPMNEdge_sequenceFlow_b6ebf56f49bf43f295533ab8e10d09a7">
<omgdi:waypoint x="330.0" y="30.0"></omgdi:waypoint>
<omgdi:waypoint x="342.0" y="30.0"></omgdi:waypoint>
<omgdi:waypoint x="342.0" y="30.000000000000004"></omgdi:waypoint>
<omgdi:waypoint x="380.0" y="30.000000000000004"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_5c4c308bd9b144cd9440a6f2dfd6af99"
id="BPMNEdge_sequenceFlow_5c4c308bd9b144cd9440a6f2dfd6af99">
<omgdi:waypoint x="180.0" y="30.0"></omgdi:waypoint>
<omgdi:waypoint x="192.0" y="30.0"></omgdi:waypoint>
<omgdi:waypoint x="192.0" y="30.000000000000007"></omgdi:waypoint>
<omgdi:waypoint x="230.0" y="30.000000000000007"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

View File

@ -94,6 +94,27 @@ public class BpmnDefaultTaskDelegateImpl implements BpmnTaskDelegate {
assigners.add(assigner2); assigners.add(assigner2);
} }
} }
if (CollectionUtils.isEmpty(assigners) && Objects.equals("69", delegateTask.getTenantId())) {
if (Objects.equals("NODE1639041346796_0.5413743892974803_0", delegateTask.getTaskDefinitionKey())) {
BpmnTaskDelegateAssigner assigner1 = new BpmnTaskDelegateAssigner();
assigner1.setAssignee("1");
assigner1.setAssigneeType("5");
assigner1.setAssignerName("或签人1");
assigner1.setPersonId("100001");
assigner1.setTenantId("296");
assigners.add(assigner1);
}
if (Objects.equals("NODE1687933854432_0.45762305710855467_1", delegateTask.getTaskDefinitionKey())) {
BpmnTaskDelegateAssigner assigner1 = new BpmnTaskDelegateAssigner();
assigner1.setAssignee("1");
assigner1.setAssigneeType("5");
assigner1.setAssignerName("或签人1");
assigner1.setPersonId("100001");
assigner1.setTenantId("296");
assigners.add(assigner1);
}
}
return assigners; return assigners;
} }
} }

View File

@ -32,7 +32,7 @@ spring:
server-addr: ${NACOS_HOST:https://dev-nacos.axzo.cn}:${NACOS_PORT:443} server-addr: ${NACOS_HOST:https://dev-nacos.axzo.cn}:${NACOS_PORT:443}
file-extension: yaml file-extension: yaml
# namespace: ${NACOS_NAMESPACE_ID:1b5d2a22-b340-4503-8464-7d7fc2059d39} # namespace: ${NACOS_NAMESPACE_ID:1b5d2a22-b340-4503-8464-7d7fc2059d39}
namespace: ${NACOS_NAMESPACE_ID:35eada10-9574-4db8-9fea-bc6a4960b6c7} namespace: ${NACOS_NAMESPACE_ID:f82179f1-81a9-41a1-a489-4f9ab5660a6e}
--- ---
#开发环境 #开发环境