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 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;
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.ApiModelProperty;
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 节点的属性扩展模型
*/
@ -13,47 +17,71 @@ import lombok.Data;
@Data
public class BpmnJsonNodeProperty {
//************* 审批方式Start **************//
/**
* 发起人节点审批人规则类型
* 审批方式: human(人工审批), autoPassed(自动通过), autoRejection(自动拒绝), nobody(不审批[仅业务节点可能有该值])
*/
@ApiModelProperty(value = "发起人节点: 发起人规则类型 ASSIGN_USER/POSITION/ROLE")
private String initiatorType;
@ApiModelProperty(value = "任务节点: 审批方式", notes = "human: 人工审批, autoPassed: 自动通过, autoRejection: 自动拒绝, nobody: " +
"不审批[仅业务节点可能有该值]")
@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 外的规则具体表达式")
private String assigneeExpression;
@ApiModelProperty(value = "任务节点: 审批人指定的具体值")
@NotEmpty(message = "审批人指定的具体值不能为空")
private List<String> specifyValue;
//************* 审批人指定End **************//
//************* 多人审批时审批方式Start **************//
/**
* 是否是多实例Task节点
* 是否是多实例Task节点, 在安心筑业务中, 所有节点应该都是多实例节点
*/
@ApiModelProperty("任务节点: 是否是多实例Task节点")
private Boolean isMultiTask;
@ApiModelProperty(value = "任务节点: 是否是多实例Task节点", notes = "在安心筑业务中, 所有节点应该都是多实例节点")
private Boolean isMultiTask = true;
/**
* Task 多实例模式OR"或签"AND"会签"
*/
@ApiModelProperty(value = "任务节点: 多实例模式OR或签AND会签")
@NotNull(message = "多实例模式不能为空")
private BpmnFlowNodeMode multiMode;
//************* 多人审批时审批方式End **************//
//************* 审批人为空时Start **************//
/**
* 审批人为空是否允许自动跳过
*/
@ApiModelProperty(value = "任务节点: 审批人为空是否允许自动跳过")
private Boolean allowSkip = false;
@ApiModelProperty(value = "任务节点: 审批人为空处理方式", notes = "autoPassed: 自动通过, autoSkipped: 自动跳过, transferToAdmin: 转交给管理员")
@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 = "后端不做任何解析, 前端给什么样,就返什么样")
private String buttonPermission;
//************* 条件节点Start **************//
/**
* 条件节点中是否是默认分支可以都不传;
*/
@ApiModelProperty(value = "条件节点: 是否是默认条件分支")
private Boolean defaultBranch;
/**
* 条件分支的Key
*/
@ApiModelProperty(value = "条件节点: 条件分支的Key", notes = "枢智业务使用的极简条件判断方式")
private String conditionBranchKey;
/**
* 条件节点当ConditionKey的值是多少走该分支
*/
@ApiModelProperty(value = "条件节点: 当ConditionKey的值是多少走该分支", notes = "枢智业务使用的极简条件判断方式")
private Integer conditionBranchValue;
@ApiModelProperty(value = "条件节点: 条件分组集合")
private List<BpmnConditionGroup> groups;
//************* 条件节点End **************//
/**
* 发起时使用的表单 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;
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.BpmnNoticeConf;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
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;
/**
@ -45,9 +50,30 @@ public class BpmnModelCreateDTO {
/**
* 流程的Json 结构
*/
@ApiModelProperty(value = "流程的Json 结构", example = "1")
@ApiModelProperty(value = "流程的 Json 结构")
private BpmnJsonNode node;
/**
* 通知管理配置
*/
@ApiModelProperty(value = "通知管理配置")
@Valid
private BpmnNoticeConf noticeConf;
/**
* 流程定义的全局默认按钮权限数据
*/
@ApiModelProperty(value = "流程按钮配置")
@Valid
private BpmnButtonConf buttonConf;
/**
* 流程定义的全局字段管理数据
*/
@ApiModelProperty(value = "流程字段配置")
@Valid
private BpmnFieldConf fieldConf;
/**
* 租户Id
*/

View File

@ -43,7 +43,7 @@ public enum BpmnErrorCode implements IProjectRespCode {
PROCESS_OPERATION_PARAM_VALID_ERROR("05001", "参数缺失, 请确保传入了 ID 或 businessKey 对流程实例进行操作"),
PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS("05002", "流程取消失败,流程不处于运行中"),
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_CANCELLED("05006", "流程实例已取消"),
// ========== bpmn task 06-001 ==========

View File

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

View File

@ -285,7 +285,8 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
public Boolean cancelProcessInstance(BpmnProcessInstanceCancelDTO dto) {
HistoricProcessInstance instance = null;
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())) {
instance = getProcessInstanceByBusinessKey(dto.getBusinessKey(), dto.getInitiator().getTenantId(), false);
} else {

View File

@ -1,8 +1,13 @@
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.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.bpmn.task.BpmnHistoricTaskInstanceGroupVO;
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.MULTI_INSTANCE_LOOP_COUNTER;
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.CANCELLED;
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.valueOfStatus;
@ -204,7 +209,7 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
NativeHistoricTaskInstanceQuery nativeQuery = historyService.createNativeHistoricTaskInstanceQuery();
String tableName = managementService.getTableName(HistoricTaskInstance.class);
baseQuerySql.append("SELECT a.* FROM ").append(tableName).append(" a JOIN " +
"ACT_HI_PROCINST b")
"ACT_HI_PROCINST b")
.append(" ON b.PROC_INST_ID_ = a.PROC_INST_ID_");
if (StringUtils.hasLength(dto.getTenantId())) {
@ -286,7 +291,7 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
Task task = checkTask(dto.getApprover().getTenantId(), dto.getApprover().buildAssigneeId(), dto.getTaskId());
// 校验流程实例存在
HistoricProcessInstance instance = processInstanceService.getProcessInstance(
task.getProcessInstanceId(), dto.getApprover().getTenantId(), true);
task.getProcessInstanceId(), null, true);
if (instance == null) {
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
}
@ -374,7 +379,9 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
query.taskTenantId(tenantId);
}
HistoricProcessInstanceQuery instanceQuery =
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId);
historyService.createHistoricProcessInstanceQuery()
.includeProcessVariables()
.processInstanceId(processInstanceId);
if (StringUtils.hasLength(tenantId)) {
instanceQuery.processInstanceTenantId(tenantId);
}
@ -394,20 +401,16 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
Map<String, HistoricVariableInstance> variableInstanceMap =
historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list()
.stream().collect(Collectors.toMap(HistoricVariableInstance::getVariableName,
Function.identity(), (s, t) -> s));
Function.identity(), (s, t) -> s));
Set<String> taskDefinitionKeys = new HashSet<>();
int count = 0;
BpmnProcessInstanceResultEnum finalBusinessStatus = valueOfStatus(instance.getBusinessStatus());
BpmnProcessInstanceResultEnum processBusinessStatus = valueOfStatus(instance.getBusinessStatus());
for (BpmnHistoricTaskInstanceVO vo : vos) {
if (count == 0 || taskDefinitionKeys.contains(vo.getTaskDefinitionKey())) {
vo.setResult(finalBusinessStatus);
if (Objects.nonNull(vo.getEndTime()) && !Objects.equals(finalBusinessStatus, REJECTED)
&& !Objects.equals(finalBusinessStatus, CANCELLED)) {
vo.setResult(APPROVED);
}
} else {
vo.setResult(APPROVED);
vo.setResult(processBusinessStatus);
if (Objects.nonNull(vo.getEndTime())) {
// 只有拒绝时, 为指定的 taskId 设置过拒绝变量
vo.setResult((BpmnProcessInstanceResultEnum) instance.getProcessVariables().getOrDefault(TASK_COMPLETE_OPERATION_TYPE + vo.getTaskId(), APPROVED));
}
taskDefinitionKeys.add(vo.getTaskDefinitionKey());
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<String> snapshotTaskIds =
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,
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;
}
@ -497,13 +511,11 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
* @param taskId 任务ID
*/
private Task checkTask(String tenantId, String assignee, String taskId) {
Task task = getTask(taskId, assignee, tenantId);
if (Objects.nonNull(task) && !Objects.equals(assignee, task.getAssignee())) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
}
Task task = getTask(taskId, null, null);
if (Objects.isNull(task)) {
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;
}

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);
}
}
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;
}
}

View File

@ -32,7 +32,7 @@ spring:
server-addr: ${NACOS_HOST:https://dev-nacos.axzo.cn}:${NACOS_PORT:443}
file-extension: yaml
# 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}
---
#开发环境