mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
commit:升级到vue3,更新最近工作流技术栈,支持sa-token
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package com.orangeforms.common.flow.advice;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.object.ResponseResult;
|
||||
import com.orangeforms.common.core.util.ContextUtil;
|
||||
import com.orangeforms.common.flow.exception.FlowEmptyUserException;
|
||||
import com.orangeforms.common.flow.model.FlowTaskComment;
|
||||
import com.orangeforms.common.flow.service.FlowTaskCommentService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.api.FlowableException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 流程业务层的异常处理类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@Order(1)
|
||||
@RestControllerAdvice("com.orangeforms")
|
||||
public class FlowExceptionHandler {
|
||||
|
||||
@Autowired
|
||||
private FlowTaskCommentService flowTaskCommentService;
|
||||
|
||||
@ExceptionHandler(value = FlowableException.class)
|
||||
public ResponseResult<Void> exceptionHandle(FlowableException ex, HttpServletRequest request) {
|
||||
if (ex instanceof FlowEmptyUserException) {
|
||||
FlowEmptyUserException flowEmptyUserException = (FlowEmptyUserException) ex;
|
||||
FlowTaskComment comment = JSON.parseObject(flowEmptyUserException.getMessage(), FlowTaskComment.class);
|
||||
flowTaskCommentService.saveNew(comment);
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, "下一个任务节点的审批人为空,提交被自动驳回!");
|
||||
}
|
||||
log.error("Unhandled FlowException from URL [" + request.getRequestURI() + "]", ex);
|
||||
ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
return ResponseResult.error(ErrorCodeEnum.UNHANDLED_EXCEPTION, ex.getMessage());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends Exception> T findCause(Throwable ex, Class<T> clazz) {
|
||||
if (ex.getCause() == null) {
|
||||
return null;
|
||||
}
|
||||
if (ex.getCause().getClass().equals(clazz)) {
|
||||
return (T) ex.getCause();
|
||||
} else {
|
||||
return this.findCause(ex.getCause(), clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.orangeforms.common.flow.base.service;
|
||||
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
|
||||
/**
|
||||
* 工作流在线表单的服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface BaseFlowOnlineService {
|
||||
|
||||
/**
|
||||
* 更新在线表单主表数据的流程状态字段值。
|
||||
*
|
||||
* @param workOrder 工单对象。
|
||||
*/
|
||||
void updateFlowStatus(FlowWorkOrder workOrder);
|
||||
|
||||
/**
|
||||
* 根据工单对象级联删除业务数据。
|
||||
*
|
||||
* @param workOrder 工单对象。
|
||||
*/
|
||||
void deleteBusinessData(FlowWorkOrder workOrder);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.orangeforms.common.flow.config;
|
||||
|
||||
import com.orangeforms.common.core.config.DynamicDataSource;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.AbstractEngineConfiguration;
|
||||
import org.flowable.common.engine.impl.EngineConfigurator;
|
||||
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 服务启动过程中动态切换flowable引擎内置表所在的数据源。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class CustomEngineConfigurator implements EngineConfigurator {
|
||||
|
||||
@Override
|
||||
public void beforeInit(AbstractEngineConfiguration engineConfiguration) {
|
||||
DataSource dataSource = engineConfiguration.getDataSource();
|
||||
if (dataSource instanceof TransactionAwareDataSourceProxy) {
|
||||
TransactionAwareDataSourceProxy proxy = (TransactionAwareDataSourceProxy) dataSource;
|
||||
DataSource targetDataSource = proxy.getTargetDataSource();
|
||||
if (targetDataSource instanceof DynamicDataSource) {
|
||||
DynamicDataSource dynamicDataSource = (DynamicDataSource) targetDataSource;
|
||||
Map<Object, DataSource> dynamicDataSourceMap = dynamicDataSource.getResolvedDataSources();
|
||||
DataSource flowDataSource = dynamicDataSourceMap.get(ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE);
|
||||
if (flowDataSource != null) {
|
||||
engineConfiguration.setDataSource(flowDataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(AbstractEngineConfiguration engineConfiguration) {
|
||||
// 默认实现。
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.orangeforms.common.flow.config;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
/**
|
||||
* common-flow模块的自动配置引导类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@EnableConfigurationProperties({FlowProperties.class})
|
||||
public class FlowAutoConfig {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.orangeforms.common.flow.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 工作流的配置对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "common-flow")
|
||||
public class FlowProperties {
|
||||
|
||||
/**
|
||||
* 工作落工单操作接口的URL前缀。
|
||||
*/
|
||||
private String urlPrefix;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
/**
|
||||
* 工作流任务触发BUTTON。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowApprovalType {
|
||||
|
||||
/**
|
||||
* 保存。
|
||||
*/
|
||||
public static final String SAVE = "save";
|
||||
/**
|
||||
* 同意。
|
||||
*/
|
||||
public static final String AGREE = "agree";
|
||||
/**
|
||||
* 拒绝。
|
||||
*/
|
||||
public static final String REFUSE = "refuse";
|
||||
/**
|
||||
* 驳回。
|
||||
*/
|
||||
public static final String REJECT = "reject";
|
||||
/**
|
||||
* 撤销。
|
||||
*/
|
||||
public static final String REVOKE = "revoke";
|
||||
/**
|
||||
* 指派。
|
||||
*/
|
||||
public static final String TRANSFER = "transfer";
|
||||
/**
|
||||
* 多实例会签。
|
||||
*/
|
||||
public static final String MULTI_SIGN = "multi_sign";
|
||||
/**
|
||||
* 会签同意。
|
||||
*/
|
||||
public static final String MULTI_AGREE = "multi_agree";
|
||||
/**
|
||||
* 会签拒绝。
|
||||
*/
|
||||
public static final String MULTI_REFUSE = "multi_refuse";
|
||||
/**
|
||||
* 会签弃权。
|
||||
*/
|
||||
public static final String MULTI_ABSTAIN = "multi_abstain";
|
||||
/**
|
||||
* 多实例加签。
|
||||
*/
|
||||
public static final String MULTI_CONSIGN = "multi_consign";
|
||||
/**
|
||||
* 多实例减签。
|
||||
*/
|
||||
public static final String MULTI_MINUS_SIGN = "multi_minus_sign";
|
||||
/**
|
||||
* 中止。
|
||||
*/
|
||||
public static final String STOP = "stop";
|
||||
/**
|
||||
* 干预。
|
||||
*/
|
||||
public static final String INTERVENE = "intervene";
|
||||
/**
|
||||
* 自由跳转。
|
||||
*/
|
||||
public static final String FREE_JUMP = "free_jump";
|
||||
/**
|
||||
* 流程复活。
|
||||
*/
|
||||
public static final String REUSED = "reused";
|
||||
/**
|
||||
* 流程复活。
|
||||
*/
|
||||
public static final String REVIVE = "revive";
|
||||
/**
|
||||
* 超时自动审批。
|
||||
*/
|
||||
public static final String TIMEOUT_AUTO_COMPLETE = "timeout_auto_complete";
|
||||
/**
|
||||
* 空审批人自动审批。
|
||||
*/
|
||||
public static final String EMPTY_USER_AUTO_COMPLETE = "empty_user_auto_complete";
|
||||
/**
|
||||
* 空审批人自动退回。
|
||||
*/
|
||||
public static final String EMPTY_USER_AUTO_REJECT = "empty_user_auto_reject";
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowApprovalType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
/**
|
||||
* 待办任务回退类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowBackType {
|
||||
|
||||
/**
|
||||
* 驳回。
|
||||
*/
|
||||
public static final int REJECT = 0;
|
||||
/**
|
||||
* 撤回。
|
||||
*/
|
||||
public static final int REVOKE = 1;
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowBackType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
/**
|
||||
* 内置的流程审批状态。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public class FlowBuiltinApprovalStatus {
|
||||
|
||||
/**
|
||||
* 同意。
|
||||
*/
|
||||
public static final int AGREED = 1;
|
||||
/**
|
||||
* 拒绝。
|
||||
*/
|
||||
public static final int REFUSED = 2;
|
||||
/**
|
||||
* 会签同意。
|
||||
*/
|
||||
public static final int MULTI_AGREED = 3;
|
||||
/**
|
||||
* 会签拒绝。
|
||||
*/
|
||||
public static final int MULTI_REFUSED = 4;
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowBuiltinApprovalStatus() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
/**
|
||||
* 工作流中的常量数据。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public class FlowConstant {
|
||||
|
||||
/**
|
||||
* 标识流程实例启动用户的变量名。
|
||||
*/
|
||||
public static final String START_USER_NAME_VAR = "${startUserName}";
|
||||
|
||||
/**
|
||||
* 流程实例发起人变量名。
|
||||
*/
|
||||
public static final String PROC_INSTANCE_INITIATOR_VAR = "initiator";
|
||||
|
||||
/**
|
||||
* 流程实例中发起人用户的变量名。
|
||||
*/
|
||||
public static final String PROC_INSTANCE_START_USER_NAME_VAR = "startUserName";
|
||||
|
||||
/**
|
||||
* 流程任务的指定人变量。
|
||||
*/
|
||||
public static final String TASK_APPOINTED_ASSIGNEE_VAR = "appointedAssignee";
|
||||
|
||||
/**
|
||||
* 操作类型变量。
|
||||
*/
|
||||
public static final String OPERATION_TYPE_VAR = "operationType";
|
||||
|
||||
/**
|
||||
* 提交用户。
|
||||
*/
|
||||
public static final String SUBMIT_USER_VAR = "submitUser";
|
||||
|
||||
/**
|
||||
* 多任务拒绝数量变量。
|
||||
*/
|
||||
public static final String MULTI_REFUSE_COUNT_VAR = "multiRefuseCount";
|
||||
|
||||
/**
|
||||
* 多任务同意数量变量。
|
||||
*/
|
||||
public static final String MULTI_AGREE_COUNT_VAR = "multiAgreeCount";
|
||||
|
||||
/**
|
||||
* 多任务弃权数量变量。
|
||||
*/
|
||||
public static final String MULTI_ABSTAIN_COUNT_VAR = "multiAbstainCount";
|
||||
|
||||
/**
|
||||
* 会签发起任务。
|
||||
*/
|
||||
public static final String MULTI_SIGN_START_TASK_VAR = "multiSignStartTask";
|
||||
|
||||
/**
|
||||
* 会签任务总数量。
|
||||
*/
|
||||
public static final String MULTI_SIGN_NUM_OF_INSTANCES_VAR = "multiNumOfInstances";
|
||||
|
||||
/**
|
||||
* 会签任务执行的批次Id。
|
||||
*/
|
||||
public static final String MULTI_SIGN_TASK_EXECUTION_ID_VAR = "taskExecutionId";
|
||||
|
||||
/**
|
||||
* 多实例实例数量变量。
|
||||
*/
|
||||
public static final String NUMBER_OF_INSTANCES_VAR = "nrOfInstances";
|
||||
|
||||
/**
|
||||
* 多实例已完成实例数量变量。
|
||||
*/
|
||||
public static final String NUMBER_OF_COMPLETED_INSTANCES_VAR = "nrOfCompletedInstances";
|
||||
|
||||
/**
|
||||
* 多任务指派人列表变量。
|
||||
*/
|
||||
public static final String MULTI_ASSIGNEE_LIST_VAR = "assigneeList";
|
||||
|
||||
/**
|
||||
* 上级部门领导审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_UP_DEPT_POST_LEADER_VAR = "upDeptPostLeader";
|
||||
|
||||
/**
|
||||
* 本部门领导审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_DEPT_POST_LEADER_VAR = "deptPostLeader";
|
||||
|
||||
/**
|
||||
* 所有部门岗位审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_ALL_DEPT_POST_VAR = "allDeptPost";
|
||||
|
||||
/**
|
||||
* 本部门岗位审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_SELF_DEPT_POST_VAR = "selfDeptPost";
|
||||
|
||||
/**
|
||||
* 同级部门岗位审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_SIBLING_DEPT_POST_VAR = "siblingDeptPost";
|
||||
|
||||
/**
|
||||
* 上级部门岗位审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_UP_DEPT_POST_VAR = "upDeptPost";
|
||||
|
||||
/**
|
||||
* 任意部门关联的岗位审批变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_DEPT_POST_VAR = "deptPost";
|
||||
|
||||
/**
|
||||
* 指定角色分组变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_ROLE_VAR = "role";
|
||||
|
||||
/**
|
||||
* 指定部门分组变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_DEPT_VAR = "dept";
|
||||
|
||||
/**
|
||||
* 指定用户分组变量。
|
||||
*/
|
||||
public static final String GROUP_TYPE_USER_VAR = "user";
|
||||
|
||||
/**
|
||||
* 指定审批人。
|
||||
*/
|
||||
public static final String GROUP_TYPE_ASSIGNEE = "ASSIGNEE";
|
||||
|
||||
/**
|
||||
* 岗位。
|
||||
*/
|
||||
public static final String GROUP_TYPE_POST = "POST";
|
||||
|
||||
/**
|
||||
* 上级部门领导审批。
|
||||
*/
|
||||
public static final String GROUP_TYPE_UP_DEPT_POST_LEADER = "UP_DEPT_POST_LEADER";
|
||||
|
||||
/**
|
||||
* 本部门岗位领导审批。
|
||||
*/
|
||||
public static final String GROUP_TYPE_DEPT_POST_LEADER = "DEPT_POST_LEADER";
|
||||
|
||||
/**
|
||||
* 本部门岗位前缀。
|
||||
*/
|
||||
public static final String SELF_DEPT_POST_PREFIX = "SELF_DEPT_";
|
||||
|
||||
/**
|
||||
* 上级部门岗位前缀。
|
||||
*/
|
||||
public static final String UP_DEPT_POST_PREFIX = "UP_DEPT_";
|
||||
|
||||
/**
|
||||
* 同级部门岗位前缀。
|
||||
*/
|
||||
public static final String SIBLING_DEPT_POST_PREFIX = "SIBLING_DEPT_";
|
||||
|
||||
/**
|
||||
* 当前流程实例所有任务的抄送数据前缀。
|
||||
*/
|
||||
public static final String COPY_DATA_MAP_PREFIX = "copyDataMap_";
|
||||
|
||||
/**
|
||||
* 作为临时变量存入任务变量JSONObject对象时的key。
|
||||
*/
|
||||
public static final String COPY_DATA_KEY = "copyDataKey";
|
||||
|
||||
/**
|
||||
* 流程中业务快照数据中,主表数据的Key。
|
||||
*/
|
||||
public static final String MASTER_DATA_KEY = "masterData";
|
||||
|
||||
/**
|
||||
* 流程中业务快照数据中,关联从表数据的Key。
|
||||
*/
|
||||
public static final String SLAVE_DATA_KEY = "slaveData";
|
||||
|
||||
/**
|
||||
* 流程任务的最近更新状态的Key。
|
||||
*/
|
||||
public static final String LATEST_APPROVAL_STATUS_KEY = "latestApprovalStatus";
|
||||
|
||||
/**
|
||||
* 流程用户任务待办之前的通知类型的Key。
|
||||
*/
|
||||
public static final String USER_TASK_NOTIFY_TYPES_KEY = "flowNotifyTypeList";
|
||||
|
||||
/**
|
||||
* 流程用户任务自动跳过类型的Key。
|
||||
*/
|
||||
public static final String USER_TASK_AUTO_SKIP_KEY = "autoSkipType";
|
||||
|
||||
/**
|
||||
* 流程用户任务驳回类型的Key。
|
||||
*/
|
||||
public static final String USER_TASK_REJECT_TYPE_KEY = "rejectType";
|
||||
|
||||
/**
|
||||
* 驳回时携带的变量数据。
|
||||
*/
|
||||
public static final String REJECT_TO_SOURCE_DATA_VAR = "rejectData";
|
||||
|
||||
/**
|
||||
* 驳回时携带的变量数据。
|
||||
*/
|
||||
public static final String REJECT_BACK_TO_SOURCE_DATA_VAR = "rejectBackData";
|
||||
|
||||
/**
|
||||
* 指定审批人。
|
||||
*/
|
||||
public static final String DELEGATE_ASSIGNEE_VAR = "defaultAssignee";
|
||||
|
||||
/**
|
||||
* 业务主表对象的键。目前仅仅用户在线表单工作流。
|
||||
*/
|
||||
public static final String MASTER_TABLE_KEY = "masterTable";
|
||||
|
||||
/**
|
||||
* 不删除任务超时作业。
|
||||
*/
|
||||
public static final String NOT_DELETE_TIMEOUT_TASK_JOB_KEY = "notDeleteTimeoutTaskJob";
|
||||
|
||||
/**
|
||||
* 用户任务超时小时数。
|
||||
*/
|
||||
public static final String TASK_TIMEOUT_HOURS = "timeoutHours";
|
||||
|
||||
/**
|
||||
* 用户任务超时处理方式。
|
||||
*/
|
||||
public static final String TASK_TIMEOUT_HANDLE_WAY = "timeoutHandleWay";
|
||||
|
||||
/**
|
||||
* 用户任务超时指定审批人。
|
||||
*/
|
||||
public static final String TASK_TIMEOUT_DEFAULT_ASSIGNEE = "defaultAssignee";
|
||||
|
||||
/**
|
||||
* 空处理人处理方式。
|
||||
*/
|
||||
public static final String EMPTY_USER_HANDLE_WAY = "emptyUserHandleWay";
|
||||
|
||||
/**
|
||||
* 空处理人时指定的审批人。
|
||||
*/
|
||||
public static final String EMPTY_USER_TO_ASSIGNEE = "emptyUserToAssignee";
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowConstant() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
/**
|
||||
* 工作流任务类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowTaskStatus {
|
||||
|
||||
/**
|
||||
* 已提交。
|
||||
*/
|
||||
public static final int SUBMITTED = 0;
|
||||
/**
|
||||
* 审批中。
|
||||
*/
|
||||
public static final int APPROVING = 1;
|
||||
/**
|
||||
* 被拒绝。
|
||||
*/
|
||||
public static final int REFUSED = 2;
|
||||
/**
|
||||
* 已结束。
|
||||
*/
|
||||
public static final int FINISHED = 3;
|
||||
/**
|
||||
* 提前停止。
|
||||
*/
|
||||
public static final Integer STOPPED = 4;
|
||||
/**
|
||||
* 已取消。
|
||||
*/
|
||||
public static final Integer CANCELLED = 5;
|
||||
/**
|
||||
* 保存草稿。
|
||||
*/
|
||||
public static final Integer DRAFT = 6;
|
||||
/**
|
||||
* 流程复活。
|
||||
*/
|
||||
public static final Integer REVIVE = 7;
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowTaskStatus() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.orangeforms.common.flow.constant;
|
||||
|
||||
/**
|
||||
* 工作流任务类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowTaskType {
|
||||
|
||||
/**
|
||||
* 其他类型任务。
|
||||
*/
|
||||
public static final int OTHER_TYPE = 0;
|
||||
/**
|
||||
* 用户任务。
|
||||
*/
|
||||
public static final int USER_TYPE = 1;
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowTaskType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.orangeforms.common.flow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import com.orangeforms.common.log.annotation.OperationLog;
|
||||
import com.orangeforms.common.log.model.constant.SysOperationLogType;
|
||||
import com.orangeforms.common.flow.dto.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.vo.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.groups.Default;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流流程分类接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Tag(name = "工作流流程分类接口")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("${common-flow.urlPrefix}/flowCategory")
|
||||
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
|
||||
public class FlowCategoryController {
|
||||
|
||||
@Autowired
|
||||
private FlowCategoryService flowCategoryService;
|
||||
@Autowired
|
||||
private FlowEntryService flowEntryService;
|
||||
|
||||
/**
|
||||
* 新增FlowCategory数据。
|
||||
*
|
||||
* @param flowCategoryDto 新增对象。
|
||||
* @return 应答结果对象,包含新增对象主键Id。
|
||||
*/
|
||||
@ApiOperationSupport(ignoreParameters = {"flowCategoryDto.categoryId"})
|
||||
@SaCheckPermission("flowCategory.all")
|
||||
@OperationLog(type = SysOperationLogType.ADD)
|
||||
@PostMapping("/add")
|
||||
public ResponseResult<Long> add(@MyRequestBody FlowCategoryDto flowCategoryDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowCategoryDto);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowCategory flowCategory = MyModelUtil.copyTo(flowCategoryDto, FlowCategory.class);
|
||||
if (flowCategoryService.existByCode(flowCategory.getCode())) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, "数据验证失败,当前流程分类已经存在!");
|
||||
}
|
||||
flowCategory = flowCategoryService.saveNew(flowCategory);
|
||||
return ResponseResult.success(flowCategory.getCategoryId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新FlowCategory数据。
|
||||
*
|
||||
* @param flowCategoryDto 更新对象。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowCategory.all")
|
||||
@OperationLog(type = SysOperationLogType.UPDATE)
|
||||
@PostMapping("/update")
|
||||
public ResponseResult<Void> update(@MyRequestBody FlowCategoryDto flowCategoryDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowCategoryDto, Default.class, UpdateGroup.class);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowCategory flowCategory = MyModelUtil.copyTo(flowCategoryDto, FlowCategory.class);
|
||||
ResponseResult<FlowCategory> verifyResult = this.doVerifyAndGet(flowCategory.getCategoryId());
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowCategory originalFlowCategory = verifyResult.getData();
|
||||
if (!StrUtil.equals(flowCategory.getCode(), originalFlowCategory.getCode())) {
|
||||
FlowEntry filter = new FlowEntry();
|
||||
filter.setCategoryId(flowCategory.getCategoryId());
|
||||
filter.setStatus(FlowEntryStatus.PUBLISHED);
|
||||
List<FlowEntry> flowEntryList = flowEntryService.getListByFilter(filter);
|
||||
if (CollUtil.isNotEmpty(flowEntryList)) {
|
||||
errorMessage = "数据验证失败,当前流程分类存在已经发布的流程数据,因此分类标识不能修改!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (flowCategoryService.existByCode(flowCategory.getCode())) {
|
||||
errorMessage = "数据验证失败,当前流程分类已经存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, errorMessage);
|
||||
}
|
||||
}
|
||||
if (!flowCategoryService.update(flowCategory, originalFlowCategory)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除FlowCategory数据。
|
||||
*
|
||||
* @param categoryId 删除对象主键Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowCategory.all")
|
||||
@OperationLog(type = SysOperationLogType.DELETE)
|
||||
@PostMapping("/delete")
|
||||
public ResponseResult<Void> delete(@MyRequestBody Long categoryId) {
|
||||
String errorMessage;
|
||||
ResponseResult<FlowCategory> verifyResult = this.doVerifyAndGet(categoryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntry filter = new FlowEntry();
|
||||
filter.setCategoryId(categoryId);
|
||||
List<FlowEntry> flowEntryList = flowEntryService.getListByFilter(filter);
|
||||
if (CollUtil.isNotEmpty(flowEntryList)) {
|
||||
errorMessage = "数据验证失败,请先删除当前流程分类关联的流程数据!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!flowCategoryService.remove(categoryId)) {
|
||||
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出符合过滤条件的FlowCategory列表。
|
||||
*
|
||||
* @param flowCategoryDtoFilter 过滤对象。
|
||||
* @param orderParam 排序参数。
|
||||
* @param pageParam 分页参数。
|
||||
* @return 应答结果对象,包含查询结果集。
|
||||
*/
|
||||
@SaCheckPermission("flowCategory.all")
|
||||
@PostMapping("/list")
|
||||
public ResponseResult<MyPageData<FlowCategoryVo>> list(
|
||||
@MyRequestBody FlowCategoryDto flowCategoryDtoFilter,
|
||||
@MyRequestBody MyOrderParam orderParam,
|
||||
@MyRequestBody MyPageParam pageParam) {
|
||||
if (pageParam != null) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
||||
}
|
||||
FlowCategory flowCategoryFilter = MyModelUtil.copyTo(flowCategoryDtoFilter, FlowCategory.class);
|
||||
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowCategory.class);
|
||||
List<FlowCategory> flowCategoryList = flowCategoryService.getFlowCategoryListWithRelation(flowCategoryFilter, orderBy);
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowCategoryList, FlowCategoryVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看指定FlowCategory对象详情。
|
||||
*
|
||||
* @param categoryId 指定对象主键Id。
|
||||
* @return 应答结果对象,包含对象详情。
|
||||
*/
|
||||
@SaCheckPermission("flowCategory.all")
|
||||
@GetMapping("/view")
|
||||
public ResponseResult<FlowCategoryVo> view(@RequestParam Long categoryId) {
|
||||
ResponseResult<FlowCategory> verifyResult = this.doVerifyAndGet(categoryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
return ResponseResult.success(verifyResult.getData(), FlowCategoryVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字典形式返回全部FlowCategory数据集合。字典的键值为[categoryId, name]。
|
||||
* 白名单接口,登录用户均可访问。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @return 应答结果对象,包含的数据为 List<Map<String, String>>,map中包含两条记录,key的值分别是id和name,value对应具体数据。
|
||||
*/
|
||||
@GetMapping("/listDict")
|
||||
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject FlowCategoryDto filter) {
|
||||
List<FlowCategory> resultList =
|
||||
flowCategoryService.getFlowCategoryList(MyModelUtil.copyTo(filter, FlowCategory.class), null);
|
||||
return ResponseResult.success(
|
||||
MyCommonUtil.toDictDataList(resultList, FlowCategory::getCategoryId, FlowCategory::getName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典Id集合,获取查询后的字典数据。
|
||||
*
|
||||
* @param dictIds 字典Id集合。
|
||||
* @return 应答结果对象,包含字典形式的数据集合。
|
||||
*/
|
||||
@GetMapping("/listDictByIds")
|
||||
public ResponseResult<List<Map<String, Object>>> listDictByIds(@RequestParam List<Long> dictIds) {
|
||||
List<FlowCategory> resultList = flowCategoryService.getInList(new HashSet<>(dictIds));
|
||||
return ResponseResult.success(
|
||||
MyCommonUtil.toDictDataList(resultList, FlowCategory::getCategoryId, FlowCategory::getName));
|
||||
}
|
||||
|
||||
private ResponseResult<FlowCategory> doVerifyAndGet(Long categoryId) {
|
||||
String errorMessage;
|
||||
if (MyCommonUtil.existBlankArgument(categoryId)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||
}
|
||||
FlowCategory flowCategory = flowCategoryService.getById(categoryId);
|
||||
if (flowCategory == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (!StrUtil.equals(flowCategory.getAppCode(), tokenData.getAppCode())) {
|
||||
errorMessage = "数据验证失败,当前应用并不存在该流程分类的定义!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (ObjectUtil.notEqual(flowCategory.getTenantId(), tokenData.getTenantId())) {
|
||||
errorMessage = "数据验证失败,当前租户并不存在该流程分类的定义!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
return ResponseResult.success(flowCategory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
package com.orangeforms.common.flow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import com.orangeforms.common.log.annotation.OperationLog;
|
||||
import com.orangeforms.common.log.model.constant.SysOperationLogType;
|
||||
import com.orangeforms.common.flow.constant.FlowTaskType;
|
||||
import com.orangeforms.common.flow.dto.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.vo.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.groups.Default;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流流程定义接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Tag(name = "工作流流程定义接口")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("${common-flow.urlPrefix}/flowEntry")
|
||||
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
|
||||
public class FlowEntryController {
|
||||
|
||||
@Autowired
|
||||
private FlowEntryService flowEntryService;
|
||||
@Autowired
|
||||
private FlowCategoryService flowCategoryService;
|
||||
@Autowired
|
||||
private FlowEntryVariableService flowEntryVariableService;
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowTaskExtService flowTaskExtService;
|
||||
|
||||
/**
|
||||
* 新增工作流对象数据。
|
||||
*
|
||||
* @param flowEntryDto 新增对象。
|
||||
* @return 应答结果对象,包含新增对象主键Id。
|
||||
*/
|
||||
@ApiOperationSupport(ignoreParameters = {"flowEntryDto.entryId"})
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.ADD)
|
||||
@PostMapping("/add")
|
||||
public ResponseResult<Long> add(@MyRequestBody FlowEntryDto flowEntryDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryDto);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowEntry flowEntry = MyModelUtil.copyTo(flowEntryDto, FlowEntry.class);
|
||||
if (flowEntryService.existByProcessDefinitionKey(flowEntry.getProcessDefinitionKey())) {
|
||||
errorMessage = "数据验证失败,该流程定义标识已存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
// 验证关联Id的数据合法性
|
||||
CallResult callResult = flowEntryService.verifyRelatedData(flowEntry, null);
|
||||
if (!callResult.isSuccess()) {
|
||||
errorMessage = callResult.getErrorMessage();
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
flowEntry = flowEntryService.saveNew(flowEntry);
|
||||
return ResponseResult.success(flowEntry.getEntryId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新工作流对象数据。
|
||||
*
|
||||
* @param flowEntryDto 更新对象。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.UPDATE)
|
||||
@PostMapping("/update")
|
||||
public ResponseResult<Void> update(@MyRequestBody FlowEntryDto flowEntryDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryDto, Default.class, UpdateGroup.class);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowEntry flowEntry = MyModelUtil.copyTo(flowEntryDto, FlowEntry.class);
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(flowEntry.getEntryId());
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntry originalFlowEntry = verifyResult.getData();
|
||||
if (ObjectUtil.notEqual(flowEntry.getProcessDefinitionKey(), originalFlowEntry.getProcessDefinitionKey())) {
|
||||
if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) {
|
||||
errorMessage = "数据验证失败,当前流程为发布状态,流程标识不能修改!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (flowEntryService.existByProcessDefinitionKey(flowEntry.getProcessDefinitionKey())) {
|
||||
errorMessage = "数据验证失败,该流程定义标识已存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
}
|
||||
// 验证关联Id的数据合法性
|
||||
CallResult callResult = flowEntryService.verifyRelatedData(flowEntry, originalFlowEntry);
|
||||
if (!callResult.isSuccess()) {
|
||||
errorMessage = callResult.getErrorMessage();
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!flowEntryService.update(flowEntry, originalFlowEntry)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除工作流对象数据。
|
||||
*
|
||||
* @param entryId 删除对象主键Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.DELETE)
|
||||
@PostMapping("/delete")
|
||||
public ResponseResult<Void> delete(@MyRequestBody Long entryId) {
|
||||
String errorMessage;
|
||||
if (MyCommonUtil.existBlankArgument(entryId)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||
}
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntry originalFlowEntry = verifyResult.getData();
|
||||
if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) {
|
||||
errorMessage = "数据验证失败,当前流程为发布状态,不能删除!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!flowEntryService.remove(entryId)) {
|
||||
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布工作流。
|
||||
*
|
||||
* @param entryId 流程主键Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.PUBLISH)
|
||||
@PostMapping("/publish")
|
||||
public ResponseResult<Void> publish(@MyRequestBody(required = true) Long entryId) throws XMLStreamException {
|
||||
String errorMessage;
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntry flowEntry = verifyResult.getData();
|
||||
if (StrUtil.isBlank(flowEntry.getBpmnXml())) {
|
||||
errorMessage = "数据验证失败,该流程没有流程图不能被发布!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
ResponseResult<TaskInfoVo> taskInfoResult = this.verifyAndGetInitialTaskInfo(flowEntry);
|
||||
if (!taskInfoResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(taskInfoResult);
|
||||
}
|
||||
String taskInfo = taskInfoResult.getData() == null ? null : JSON.toJSONString(taskInfoResult.getData());
|
||||
flowEntryService.publish(flowEntry, taskInfo);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出符合过滤条件的工作流列表。
|
||||
*
|
||||
* @param flowEntryDtoFilter 过滤对象。
|
||||
* @param orderParam 排序参数。
|
||||
* @param pageParam 分页参数。
|
||||
* @return 应答结果对象,包含查询结果集。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@PostMapping("/list")
|
||||
public ResponseResult<MyPageData<FlowEntryVo>> list(
|
||||
@MyRequestBody FlowEntryDto flowEntryDtoFilter,
|
||||
@MyRequestBody MyOrderParam orderParam,
|
||||
@MyRequestBody MyPageParam pageParam) {
|
||||
if (pageParam != null) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
||||
}
|
||||
FlowEntry flowEntryFilter = MyModelUtil.copyTo(flowEntryDtoFilter, FlowEntry.class);
|
||||
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowEntry.class);
|
||||
List<FlowEntry> flowEntryList = flowEntryService.getFlowEntryListWithRelation(flowEntryFilter, orderBy);
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowEntryList, FlowEntryVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看指定工作流对象详情。
|
||||
*
|
||||
* @param entryId 指定对象主键Id。
|
||||
* @return 应答结果对象,包含对象详情。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@GetMapping("/view")
|
||||
public ResponseResult<FlowEntryVo> view(@RequestParam Long entryId) {
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntry flowEntry = flowEntryService.getByIdWithRelation(entryId, MyRelationParam.full());
|
||||
if (flowEntry == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success(flowEntry, FlowEntryVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出指定流程的发布版本列表。
|
||||
*
|
||||
* @param entryId 流程主键Id。
|
||||
* @return 应答结果对象,包含流程发布列表数据。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@GetMapping("/listFlowEntryPublish")
|
||||
public ResponseResult<List<FlowEntryPublishVo>> listFlowEntryPublish(@RequestParam Long entryId) {
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
List<FlowEntryPublish> flowEntryPublishList = flowEntryService.getFlowEntryPublishList(entryId);
|
||||
return ResponseResult.success(MyModelUtil.copyCollectionTo(flowEntryPublishList, FlowEntryPublishVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 以字典形式返回全部FlowEntry数据集合。字典的键值为[entryId, procDefinitionName]。
|
||||
* 白名单接口,登录用户均可访问。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @return 应答结果对象,包含的数据为 List<Map<String, String>>,map中包含两条记录,key的值分别是id和name,value对应具体数据。
|
||||
*/
|
||||
@GetMapping("/listDict")
|
||||
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject FlowEntryDto filter) {
|
||||
List<FlowEntry> resultList =
|
||||
flowEntryService.getFlowEntryList(MyModelUtil.copyTo(filter, FlowEntry.class), null);
|
||||
return ResponseResult.success(
|
||||
MyCommonUtil.toDictDataList(resultList, FlowEntry::getEntryId, FlowEntry::getProcessDefinitionName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有流程分类和流程定义的列表。白名单接口。
|
||||
*
|
||||
* @return 所有流程分类和流程定义的列表
|
||||
*/
|
||||
@GetMapping("/listAll")
|
||||
public ResponseResult<JSONObject> listAll() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("flowEntryList", flowEntryService.getFlowEntryList(null, null));
|
||||
jsonObject.put("flowCategoryList", flowCategoryService.getFlowCategoryList(null, null));
|
||||
return ResponseResult.success(jsonObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 白名单接口,根据流程Id,获取流程引擎需要的流程标识和流程名称。
|
||||
*
|
||||
* @param entryId 流程Id。
|
||||
* @return 流程的部分数据。
|
||||
*/
|
||||
@GetMapping("/viewDict")
|
||||
public ResponseResult<Map<String, Object>> viewDict(@RequestParam Long entryId) {
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntry flowEntry = verifyResult.getData();
|
||||
Map<String, Object> resultMap = new HashMap<>(2);
|
||||
resultMap.put("processDefinitionKey", flowEntry.getProcessDefinitionKey());
|
||||
resultMap.put("processDefinitionName", flowEntry.getProcessDefinitionName());
|
||||
return ResponseResult.success(resultMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换指定工作的发布主版本。
|
||||
*
|
||||
* @param entryId 工作流主键Id。
|
||||
* @param newEntryPublishId 新的工作流发布主版本对象的主键Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.UPDATE)
|
||||
@PostMapping("/updateMainVersion")
|
||||
public ResponseResult<Void> updateMainVersion(
|
||||
@MyRequestBody(required = true) Long entryId,
|
||||
@MyRequestBody(required = true) Long newEntryPublishId) {
|
||||
String errorMessage;
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishFromCache(newEntryPublishId);
|
||||
if (flowEntryPublish == null) {
|
||||
errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
if (ObjectUtil.notEqual(entryId, flowEntryPublish.getEntryId())) {
|
||||
errorMessage = "数据验证失败,当前工作流并不包含该工作流发布版本数据,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (BooleanUtil.isTrue(flowEntryPublish.getMainVersion())) {
|
||||
errorMessage = "数据验证失败,该版本已经为当前工作流的发布主版本,不能重复设置!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
flowEntryService.updateFlowEntryMainVersion(flowEntryService.getById(entryId), flowEntryPublish);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂起工作流的指定发布版本。
|
||||
*
|
||||
* @param entryPublishId 工作发布Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.SUSPEND)
|
||||
@PostMapping("/suspendFlowEntryPublish")
|
||||
public ResponseResult<Void> suspendFlowEntryPublish(@MyRequestBody(required = true) Long entryPublishId) {
|
||||
String errorMessage;
|
||||
FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishFromCache(entryPublishId);
|
||||
if (flowEntryPublish == null) {
|
||||
errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(flowEntryPublish.getEntryId());
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
if (BooleanUtil.isFalse(flowEntryPublish.getActiveStatus())) {
|
||||
errorMessage = "数据验证失败,当前流程发布版本已处于挂起状态!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
flowEntryService.suspendFlowEntryPublish(flowEntryPublish);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活工作流的指定发布版本。
|
||||
*
|
||||
* @param entryPublishId 工作发布Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.RESUME)
|
||||
@PostMapping("/activateFlowEntryPublish")
|
||||
public ResponseResult<Void> activateFlowEntryPublish(@MyRequestBody(required = true) Long entryPublishId) {
|
||||
String errorMessage;
|
||||
FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishFromCache(entryPublishId);
|
||||
if (flowEntryPublish == null) {
|
||||
errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(flowEntryPublish.getEntryId());
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
if (BooleanUtil.isTrue(flowEntryPublish.getActiveStatus())) {
|
||||
errorMessage = "数据验证失败,当前流程发布版本已处于激活状态!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
flowEntryService.activateFlowEntryPublish(flowEntryPublish);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
private ResponseResult<FlowEntry> doVerifyAndGet(Long entryId) {
|
||||
String errorMessage;
|
||||
if (MyCommonUtil.existBlankArgument(entryId)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||
}
|
||||
FlowEntry flowEntry = flowEntryService.getById(entryId);
|
||||
if (flowEntry == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (!StrUtil.equals(flowEntry.getAppCode(), tokenData.getAppCode())) {
|
||||
errorMessage = "数据验证失败,当前应用并不存在该流程定义!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (ObjectUtil.notEqual(flowEntry.getTenantId(), tokenData.getTenantId())) {
|
||||
errorMessage = "数据验证失败,当前租户并不存在该流程定义!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
return ResponseResult.success(flowEntry);
|
||||
}
|
||||
|
||||
private ResponseResult<TaskInfoVo> verifyAndGetInitialTaskInfo(FlowEntry flowEntry) throws XMLStreamException {
|
||||
String errorMessage;
|
||||
BpmnModel bpmnModel = flowApiService.convertToBpmnModel(flowEntry.getBpmnXml());
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
if (process == null) {
|
||||
errorMessage = "数据验证失败,当前流程标识 [" + flowEntry.getProcessDefinitionKey() + "] 关联的流程模型并不存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
Collection<FlowElement> elementList = process.getFlowElements();
|
||||
FlowElement startEvent = null;
|
||||
// 这里我们只定位流程模型中的第二个节点。
|
||||
for (FlowElement flowElement : elementList) {
|
||||
if (flowElement instanceof StartEvent) {
|
||||
startEvent = flowElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (startEvent == null) {
|
||||
errorMessage = "数据验证失败,当前流程图没有包含 [开始事件] 节点,请修改流程图!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowElement firstTask = this.findFirstTask(elementList, startEvent);
|
||||
if (firstTask == null) {
|
||||
errorMessage = "数据验证失败,当前流程图没有包含 [开始事件] 节点没有任何连线,请修改流程图!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
TaskInfoVo taskInfoVo;
|
||||
if (firstTask instanceof UserTask) {
|
||||
UserTask userTask = (UserTask) firstTask;
|
||||
String formKey = userTask.getFormKey();
|
||||
if (StrUtil.isNotBlank(formKey)) {
|
||||
taskInfoVo = JSON.parseObject(formKey, TaskInfoVo.class);
|
||||
} else {
|
||||
taskInfoVo = new TaskInfoVo();
|
||||
}
|
||||
taskInfoVo.setAssignee(userTask.getAssignee());
|
||||
taskInfoVo.setTaskKey(userTask.getId());
|
||||
taskInfoVo.setTaskType(FlowTaskType.USER_TYPE);
|
||||
Map<String, List<ExtensionElement>> extensionMap = userTask.getExtensionElements();
|
||||
if (MapUtil.isNotEmpty(extensionMap)) {
|
||||
taskInfoVo.setOperationList(flowTaskExtService.buildOperationListExtensionElement(extensionMap));
|
||||
taskInfoVo.setVariableList(flowTaskExtService.buildVariableListExtensionElement(extensionMap));
|
||||
}
|
||||
} else {
|
||||
taskInfoVo = new TaskInfoVo();
|
||||
taskInfoVo.setTaskType(FlowTaskType.OTHER_TYPE);
|
||||
}
|
||||
return ResponseResult.success(taskInfoVo);
|
||||
}
|
||||
|
||||
private FlowElement findFirstTask(Collection<FlowElement> elementList, FlowElement startEvent) {
|
||||
for (FlowElement flowElement : elementList) {
|
||||
if (flowElement instanceof SequenceFlow) {
|
||||
SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
|
||||
if (sequenceFlow.getSourceFlowElement().equals(startEvent)) {
|
||||
return sequenceFlow.getTargetFlowElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.orangeforms.common.flow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import com.orangeforms.common.flow.vo.*;
|
||||
import com.orangeforms.common.flow.dto.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.*;
|
||||
import com.orangeforms.common.core.constant.*;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import com.orangeforms.common.log.annotation.OperationLog;
|
||||
import com.orangeforms.common.log.model.constant.SysOperationLogType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
import jakarta.validation.groups.Default;
|
||||
|
||||
/**
|
||||
* 工作流流程变量接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Tag(name = "工作流流程变量接口")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("${common-flow.urlPrefix}/flowEntryVariable")
|
||||
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
|
||||
public class FlowEntryVariableController {
|
||||
|
||||
@Autowired
|
||||
private FlowEntryVariableService flowEntryVariableService;
|
||||
|
||||
/**
|
||||
* 新增流程变量数据。
|
||||
*
|
||||
* @param flowEntryVariableDto 新增对象。
|
||||
* @return 应答结果对象,包含新增对象主键Id。
|
||||
*/
|
||||
@ApiOperationSupport(ignoreParameters = {"flowEntryVariableDto.variableId"})
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.ADD)
|
||||
@PostMapping("/add")
|
||||
public ResponseResult<Long> add(@MyRequestBody FlowEntryVariableDto flowEntryVariableDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryVariableDto);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowEntryVariable flowEntryVariable = MyModelUtil.copyTo(flowEntryVariableDto, FlowEntryVariable.class);
|
||||
flowEntryVariable = flowEntryVariableService.saveNew(flowEntryVariable);
|
||||
return ResponseResult.success(flowEntryVariable.getVariableId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新流程变量数据。
|
||||
*
|
||||
* @param flowEntryVariableDto 更新对象。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.UPDATE)
|
||||
@PostMapping("/update")
|
||||
public ResponseResult<Void> update(@MyRequestBody FlowEntryVariableDto flowEntryVariableDto) {
|
||||
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryVariableDto, Default.class, UpdateGroup.class);
|
||||
if (errorMessage != null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowEntryVariable flowEntryVariable = MyModelUtil.copyTo(flowEntryVariableDto, FlowEntryVariable.class);
|
||||
FlowEntryVariable originalFlowEntryVariable = flowEntryVariableService.getById(flowEntryVariable.getVariableId());
|
||||
if (originalFlowEntryVariable == null) {
|
||||
// NOTE: 修改下面方括号中的话述
|
||||
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
if (!flowEntryVariableService.update(flowEntryVariable, originalFlowEntryVariable)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程变量数据。
|
||||
*
|
||||
* @param variableId 删除对象主键Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@OperationLog(type = SysOperationLogType.DELETE)
|
||||
@PostMapping("/delete")
|
||||
public ResponseResult<Void> delete(@MyRequestBody Long variableId) {
|
||||
String errorMessage;
|
||||
if (MyCommonUtil.existBlankArgument(variableId)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||
}
|
||||
// 验证关联Id的数据合法性
|
||||
FlowEntryVariable originalFlowEntryVariable = flowEntryVariableService.getById(variableId);
|
||||
if (originalFlowEntryVariable == null) {
|
||||
// NOTE: 修改下面方括号中的话述
|
||||
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
if (!flowEntryVariableService.remove(variableId)) {
|
||||
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出符合过滤条件的流程变量列表。
|
||||
*
|
||||
* @param flowEntryVariableDtoFilter 过滤对象。
|
||||
* @param orderParam 排序参数。
|
||||
* @param pageParam 分页参数。
|
||||
* @return 应答结果对象,包含查询结果集。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@PostMapping("/list")
|
||||
public ResponseResult<MyPageData<FlowEntryVariableVo>> list(
|
||||
@MyRequestBody FlowEntryVariableDto flowEntryVariableDtoFilter,
|
||||
@MyRequestBody MyOrderParam orderParam,
|
||||
@MyRequestBody MyPageParam pageParam) {
|
||||
if (pageParam != null) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
||||
}
|
||||
FlowEntryVariable flowEntryVariableFilter = MyModelUtil.copyTo(flowEntryVariableDtoFilter, FlowEntryVariable.class);
|
||||
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowEntryVariable.class);
|
||||
List<FlowEntryVariable> flowEntryVariableList =
|
||||
flowEntryVariableService.getFlowEntryVariableListWithRelation(flowEntryVariableFilter, orderBy);
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowEntryVariableList, FlowEntryVariableVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看指定流程变量对象详情。
|
||||
*
|
||||
* @param variableId 指定对象主键Id。
|
||||
* @return 应答结果对象,包含对象详情。
|
||||
*/
|
||||
@SaCheckPermission("flowEntry.all")
|
||||
@GetMapping("/view")
|
||||
public ResponseResult<FlowEntryVariableVo> view(@RequestParam Long variableId) {
|
||||
if (MyCommonUtil.existBlankArgument(variableId)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||
}
|
||||
FlowEntryVariable flowEntryVariable = flowEntryVariableService.getByIdWithRelation(variableId, MyRelationParam.full());
|
||||
if (flowEntryVariable == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
return ResponseResult.success(flowEntryVariable, FlowEntryVariableVo.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.orangeforms.common.flow.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
import com.orangeforms.common.flow.model.constant.FlowMessageType;
|
||||
import com.orangeforms.common.flow.model.FlowMessage;
|
||||
import com.orangeforms.common.flow.service.FlowMessageService;
|
||||
import com.orangeforms.common.flow.vo.FlowMessageVo;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工作流消息接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Tag(name = "工作流消息接口")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("${common-flow.urlPrefix}/flowMessage")
|
||||
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
|
||||
public class FlowMessageController {
|
||||
|
||||
@Autowired
|
||||
private FlowMessageService flowMessageService;
|
||||
|
||||
/**
|
||||
* 获取当前用户的未读消息总数。
|
||||
* NOTE:白名单接口。
|
||||
*
|
||||
* @return 应答结果对象,包含当前用户的未读消息总数。
|
||||
*/
|
||||
@GetMapping("/getMessageCount")
|
||||
public ResponseResult<JSONObject> getMessageCount() {
|
||||
JSONObject resultData = new JSONObject();
|
||||
resultData.put("remindingMessageCount", flowMessageService.countRemindingMessageListByUser());
|
||||
resultData.put("copyMessageCount", flowMessageService.countCopyMessageByUser());
|
||||
return ResponseResult.success(resultData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的催办消息列表。
|
||||
* 不仅仅包含,其中包括当前用户所属角色、部门和岗位的候选组催办消息。
|
||||
* NOTE:白名单接口。
|
||||
*
|
||||
* @return 应答结果对象,包含查询结果集。
|
||||
*/
|
||||
@PostMapping("/listRemindingTask")
|
||||
public ResponseResult<MyPageData<FlowMessageVo>> listRemindingTask(@MyRequestBody MyPageParam pageParam) {
|
||||
if (pageParam != null) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
|
||||
}
|
||||
List<FlowMessage> flowMessageList = flowMessageService.getRemindingMessageListByUser();
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowMessageList, FlowMessageVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的抄送消息列表。
|
||||
* 不仅仅包含,其中包括当前用户所属角色、部门和岗位的候选组抄送消息。
|
||||
* NOTE:白名单接口。
|
||||
*
|
||||
* @param read true表示已读,false表示未读。
|
||||
* @return 应答结果对象,包含查询结果集。
|
||||
*/
|
||||
@PostMapping("/listCopyMessage")
|
||||
public ResponseResult<MyPageData<FlowMessageVo>> listCopyMessage(
|
||||
@MyRequestBody MyPageParam pageParam, @MyRequestBody Boolean read) {
|
||||
if (pageParam != null) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
|
||||
}
|
||||
List<FlowMessage> flowMessageList = flowMessageService.getCopyMessageListByUser(read);
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowMessageList, FlowMessageVo.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取抄送消息,同时更新当前用户对指定抄送消息的读取状态。
|
||||
*
|
||||
* @param messageId 消息Id。
|
||||
* @return 应答结果对象。
|
||||
*/
|
||||
@PostMapping("/readCopyTask")
|
||||
public ResponseResult<Void> readCopyTask(@MyRequestBody Long messageId) {
|
||||
String errorMessage;
|
||||
// 验证流程任务的合法性。
|
||||
FlowMessage flowMessage = flowMessageService.getById(messageId);
|
||||
if (flowMessage == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
if (flowMessage.getMessageType() != FlowMessageType.COPY_TYPE) {
|
||||
errorMessage = "数据验证失败,当前消息不是抄送类型消息!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!flowMessageService.isCandidateIdentityOnMessage(messageId)) {
|
||||
errorMessage = "数据验证失败,当前用户没有权限访问该消息!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
flowMessageService.readCopyTask(messageId);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,941 @@
|
||||
package com.orangeforms.common.flow.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.annotation.DisableDataFilter;
|
||||
import com.orangeforms.common.core.annotation.MyRequestBody;
|
||||
import com.orangeforms.common.core.constant.ErrorCodeEnum;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.log.annotation.OperationLog;
|
||||
import com.orangeforms.common.log.model.constant.SysOperationLogType;
|
||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
||||
import com.orangeforms.common.flow.exception.FlowOperationException;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.util.FlowOperationHelper;
|
||||
import com.orangeforms.common.flow.vo.FlowTaskCommentVo;
|
||||
import com.orangeforms.common.flow.vo.FlowTaskVo;
|
||||
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
||||
import com.orangeforms.common.flow.vo.TaskInfoVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.history.HistoricActivityInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 工作流流程操作接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Tag(name = "工作流流程操作接口")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("${common-flow.urlPrefix}/flowOperation")
|
||||
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
|
||||
public class FlowOperationController {
|
||||
|
||||
@Autowired
|
||||
private FlowEntryService flowEntryService;
|
||||
@Autowired
|
||||
private FlowTaskCommentService flowTaskCommentService;
|
||||
@Autowired
|
||||
private FlowTaskExtService flowTaskExtService;
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowWorkOrderService flowWorkOrderService;
|
||||
@Autowired
|
||||
private FlowMessageService flowMessageService;
|
||||
@Autowired
|
||||
private FlowOperationHelper flowOperationHelper;
|
||||
@Autowired
|
||||
private FlowCustomExtFactory flowCustomExtFactory;
|
||||
@Autowired
|
||||
private FlowMultiInstanceTransService flowMultiInstanceTransService;
|
||||
|
||||
private static final String ACTIVE_MULTI_INST_TASK = "activeMultiInstanceTask";
|
||||
private static final String SHOW_NAME = "showName";
|
||||
private static final String INSTANCE_ID = "processInstanceId";
|
||||
|
||||
/**
|
||||
* 获取开始节点之后的第一个任务节点的数据。
|
||||
*
|
||||
* @param processDefinitionKey 流程标识。
|
||||
* @return 任务节点的自定义对象数据。
|
||||
*/
|
||||
@GetMapping("/viewInitialTaskInfo")
|
||||
public ResponseResult<TaskInfoVo> viewInitialTaskInfo(@RequestParam String processDefinitionKey) {
|
||||
ResponseResult<FlowEntry> flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey);
|
||||
if (!flowEntryResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(flowEntryResult);
|
||||
}
|
||||
FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
|
||||
String initTaskInfo = flowEntryPublish.getInitTaskInfo();
|
||||
TaskInfoVo taskInfo = StrUtil.isBlank(initTaskInfo)
|
||||
? null : JSON.parseObject(initTaskInfo, TaskInfoVo.class);
|
||||
if (taskInfo != null) {
|
||||
String loginName = TokenData.takeFromRequest().getLoginName();
|
||||
taskInfo.setAssignedMe(StrUtil.equalsAny(
|
||||
taskInfo.getAssignee(), loginName, FlowConstant.START_USER_NAME_VAR));
|
||||
}
|
||||
return ResponseResult.success(taskInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程运行时指定任务的信息。
|
||||
*
|
||||
* @param processDefinitionId 流程引擎的定义Id。
|
||||
* @param processInstanceId 流程引擎的实例Id。
|
||||
* @param taskId 流程引擎的任务Id。
|
||||
* @return 任务节点的自定义对象数据。
|
||||
*/
|
||||
@GetMapping("/viewRuntimeTaskInfo")
|
||||
public ResponseResult<TaskInfoVo> viewRuntimeTaskInfo(
|
||||
@RequestParam String processDefinitionId,
|
||||
@RequestParam String processInstanceId,
|
||||
@RequestParam String taskId) {
|
||||
Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
|
||||
ResponseResult<TaskInfoVo> taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task);
|
||||
if (!taskInfoResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(taskInfoResult);
|
||||
}
|
||||
TaskInfoVo taskInfoVo = taskInfoResult.getData();
|
||||
FlowTaskExt flowTaskExt =
|
||||
flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskInfoVo.getTaskKey());
|
||||
if (flowTaskExt != null) {
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) {
|
||||
taskInfoVo.setOperationList(JSON.parseArray(flowTaskExt.getOperationListJson(), JSONObject.class));
|
||||
}
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getVariableListJson())) {
|
||||
taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class));
|
||||
}
|
||||
}
|
||||
return ResponseResult.success(taskInfoVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程运行时指定任务的信息。
|
||||
*
|
||||
* @param processDefinitionId 流程引擎的定义Id。
|
||||
* @param processInstanceId 流程引擎的实例Id。
|
||||
* @param taskId 流程引擎的任务Id。
|
||||
* @return 任务节点的自定义对象数据。
|
||||
*/
|
||||
@GetMapping("/viewHistoricTaskInfo")
|
||||
public ResponseResult<TaskInfoVo> viewHistoricTaskInfo(
|
||||
@RequestParam String processDefinitionId,
|
||||
@RequestParam String processInstanceId,
|
||||
@RequestParam String taskId) {
|
||||
String errorMessage;
|
||||
HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
|
||||
String loginName = TokenData.takeFromRequest().getLoginName();
|
||||
if (!StrUtil.equals(taskInstance.getAssignee(), loginName)) {
|
||||
errorMessage = "数据验证失败,当前用户不是指派人!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
TaskInfoVo taskInfoVo = JSON.parseObject(taskInstance.getFormKey(), TaskInfoVo.class);
|
||||
FlowTaskExt flowTaskExt =
|
||||
flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskInstance.getTaskDefinitionKey());
|
||||
if (flowTaskExt != null) {
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) {
|
||||
taskInfoVo.setOperationList(JSON.parseArray(flowTaskExt.getOperationListJson(), JSONObject.class));
|
||||
}
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getVariableListJson())) {
|
||||
taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class));
|
||||
}
|
||||
}
|
||||
return ResponseResult.success(taskInfoVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取第一个提交表单数据的任务信息。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 任务节点的自定义对象数据。
|
||||
*/
|
||||
@GetMapping("/viewInitialHistoricTaskInfo")
|
||||
public ResponseResult<TaskInfoVo> viewInitialHistoricTaskInfo(@RequestParam String processInstanceId) {
|
||||
String errorMessage;
|
||||
List<FlowTaskComment> taskCommentList =
|
||||
flowTaskCommentService.getFlowTaskCommentList(processInstanceId);
|
||||
if (CollUtil.isEmpty(taskCommentList)) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
FlowTaskComment taskComment = taskCommentList.get(0);
|
||||
HistoricTaskInstance task = flowApiService.getHistoricTaskInstance(processInstanceId, taskComment.getTaskId());
|
||||
if (StrUtil.isBlank(task.getFormKey())) {
|
||||
errorMessage = "数据验证失败,指定任务的formKey属性不存在,请重新修改流程图!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
TaskInfoVo taskInfo = JSON.parseObject(task.getFormKey(), TaskInfoVo.class);
|
||||
taskInfo.setTaskKey(task.getTaskDefinitionKey());
|
||||
return ResponseResult.success(taskInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务的用户信息列表。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 流程任务Id。
|
||||
* @param historic 是否为历史任务。
|
||||
* @return 任务相关的用户信息列表。
|
||||
*/
|
||||
@DisableDataFilter
|
||||
@GetMapping("/viewTaskUserInfo")
|
||||
public ResponseResult<List<FlowUserInfoVo>> viewTaskUserInfo(
|
||||
@RequestParam String processDefinitionId,
|
||||
@RequestParam String processInstanceId,
|
||||
@RequestParam String taskId,
|
||||
@RequestParam Boolean historic) {
|
||||
TaskInfo taskInfo;
|
||||
HistoricTaskInstance hisotricTask;
|
||||
if (BooleanUtil.isFalse(historic)) {
|
||||
taskInfo = flowApiService.getTaskById(taskId);
|
||||
if (taskInfo == null) {
|
||||
hisotricTask = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
|
||||
taskInfo = hisotricTask;
|
||||
historic = true;
|
||||
}
|
||||
} else {
|
||||
hisotricTask = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
|
||||
taskInfo = hisotricTask;
|
||||
}
|
||||
if (taskInfo == null) {
|
||||
String errorMessage = "数据验证失败,任务Id不存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
|
||||
}
|
||||
String taskKey = taskInfo.getTaskDefinitionKey();
|
||||
FlowTaskExt taskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskKey);
|
||||
boolean isMultiInstanceTask = flowApiService.isMultiInstanceTask(taskInfo.getProcessDefinitionId(), taskKey);
|
||||
List<FlowUserInfoVo> resultUserInfoList =
|
||||
flowTaskExtService.getCandidateUserInfoList(processInstanceId, taskExt, taskInfo, isMultiInstanceTask, historic);
|
||||
if (BooleanUtil.isTrue(historic) || isMultiInstanceTask) {
|
||||
List<FlowTaskComment> taskCommentList = buildApprovedFlowTaskCommentList(taskInfo, isMultiInstanceTask);
|
||||
Map<String, FlowUserInfoVo> resultUserInfoMap =
|
||||
resultUserInfoList.stream().collect(Collectors.toMap(FlowUserInfoVo::getLoginName, c -> c));
|
||||
for (FlowTaskComment taskComment : taskCommentList) {
|
||||
FlowUserInfoVo flowUserInfoVo = resultUserInfoMap.get(taskComment.getCreateLoginName());
|
||||
if (flowUserInfoVo != null) {
|
||||
flowUserInfoVo.setLastApprovalTime(taskComment.getCreateTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ResponseResult.success(resultUserInfoList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多实例会签任务的指派人列表。
|
||||
* NOTE: 白名单接口。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 多实例任务的上一级任务Id。
|
||||
* @return 应答结果,指定会签任务的指派人列表。
|
||||
*/
|
||||
@GetMapping("/listMultiSignAssignees")
|
||||
public ResponseResult<List<JSONObject>> listMultiSignAssignees(
|
||||
@RequestParam String processInstanceId, @RequestParam String taskId) {
|
||||
ResponseResult<JSONObject> verifyResult = this.doVerifyMultiSign(processInstanceId, taskId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
Task activeMultiInstanceTask =
|
||||
verifyResult.getData().getObject(ACTIVE_MULTI_INST_TASK, Task.class);
|
||||
String multiInstanceExecId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
activeMultiInstanceTask.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR);
|
||||
FlowMultiInstanceTrans trans =
|
||||
flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId);
|
||||
List<FlowTaskComment> commentList =
|
||||
flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
|
||||
List<String> assigneeList = StrUtil.split(trans.getAssigneeList(), ",");
|
||||
Set<String> approvedAssigneeSet = commentList.stream()
|
||||
.map(FlowTaskComment::getCreateLoginName).collect(Collectors.toSet());
|
||||
List<JSONObject> resultList = new LinkedList<>();
|
||||
Map<String, String> usernameMap =
|
||||
flowCustomExtFactory.getFlowIdentityExtHelper().mapUserShowNameByLoginName(new HashSet<>(assigneeList));
|
||||
for (String assignee : assigneeList) {
|
||||
JSONObject resultData = new JSONObject();
|
||||
resultData.put("assignee", assignee);
|
||||
resultData.put(SHOW_NAME, usernameMap.get(assignee));
|
||||
resultData.put("approved", approvedAssigneeSet.contains(assignee));
|
||||
resultList.add(resultData);
|
||||
}
|
||||
return ResponseResult.success(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交多实例加签或减签。
|
||||
* NOTE: 白名单接口。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 多实例任务的上一级任务Id。
|
||||
* @param newAssignees 加签减签人列表,多个指派人之间逗号分隔。
|
||||
* @param isAdd 是否为加签,如果没有该参数,为了保持兼容性,缺省值为true。
|
||||
* @return 应答结果。
|
||||
*/
|
||||
@PostMapping("/submitConsign")
|
||||
public ResponseResult<Void> submitConsign(
|
||||
@MyRequestBody(required = true) String processInstanceId,
|
||||
@MyRequestBody(required = true) String taskId,
|
||||
@MyRequestBody(required = true) String newAssignees,
|
||||
@MyRequestBody Boolean isAdd) {
|
||||
String errorMessage;
|
||||
ResponseResult<JSONObject> verifyResult = this.doVerifyMultiSign(processInstanceId, taskId);
|
||||
if (!verifyResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(verifyResult);
|
||||
}
|
||||
HistoricTaskInstance taskInstance =
|
||||
verifyResult.getData().getObject("taskInstance", HistoricTaskInstance.class);
|
||||
Task activeMultiInstanceTask =
|
||||
verifyResult.getData().getObject(ACTIVE_MULTI_INST_TASK, Task.class);
|
||||
String multiInstanceExecId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
activeMultiInstanceTask.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR);
|
||||
JSONArray assigneeArray = JSON.parseArray(newAssignees);
|
||||
if (isAdd == null) {
|
||||
isAdd = true;
|
||||
}
|
||||
if (!isAdd) {
|
||||
List<FlowTaskComment> commentList =
|
||||
flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
|
||||
if (CollUtil.isNotEmpty(commentList)) {
|
||||
Set<String> approvedAssigneeSet = commentList.stream()
|
||||
.map(FlowTaskComment::getCreateLoginName).collect(Collectors.toSet());
|
||||
String loginName = this.findExistAssignee(approvedAssigneeSet, assigneeArray);
|
||||
if (loginName != null) {
|
||||
errorMessage = "数据验证失败,用户 [" + loginName + "] 已经审批,不能减签该用户!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 避免同一人被重复加签。
|
||||
FlowMultiInstanceTrans trans =
|
||||
flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId);
|
||||
Set<String> assigneeSet = new HashSet<>(StrUtil.split(trans.getAssigneeList(), ","));
|
||||
String loginName = this.findExistAssignee(assigneeSet, assigneeArray);
|
||||
if (loginName != null) {
|
||||
errorMessage = "数据验证失败,用户 [" + loginName + "] 已经是会签人,不能重复指定!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
}
|
||||
try {
|
||||
flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd);
|
||||
} catch (FlowOperationException e) {
|
||||
errorMessage = e.getMessage();
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前用户待办的任务列表。
|
||||
*
|
||||
* @param processDefinitionKey 流程标识。
|
||||
* @param processDefinitionName 流程定义名 (模糊查询)。
|
||||
* @param taskName 任务名称 (模糊查询)。
|
||||
* @param pageParam 分页对象。
|
||||
* @return 返回当前用户待办的任务列表。如果指定流程标识,则仅返回该流程的待办任务列表。
|
||||
*/
|
||||
@DisableDataFilter
|
||||
@PostMapping("/listRuntimeTask")
|
||||
public ResponseResult<MyPageData<FlowTaskVo>> listRuntimeTask(
|
||||
@MyRequestBody String processDefinitionKey,
|
||||
@MyRequestBody String processDefinitionName,
|
||||
@MyRequestBody String taskName,
|
||||
@MyRequestBody(required = true) MyPageParam pageParam) {
|
||||
String username = TokenData.takeFromRequest().getLoginName();
|
||||
MyPageData<Task> pageData = flowApiService.getTaskListByUserName(
|
||||
username, processDefinitionKey, processDefinitionName, taskName, pageParam);
|
||||
List<FlowTaskVo> flowTaskVoList = flowApiService.convertToFlowTaskList(pageData.getDataList());
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(flowTaskVoList, pageData.getTotalCount()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前用户待办的任务数量。
|
||||
*
|
||||
* @return 返回当前用户待办的任务数量。
|
||||
*/
|
||||
@PostMapping("/countRuntimeTask")
|
||||
public ResponseResult<Long> countRuntimeTask() {
|
||||
String username = TokenData.takeFromRequest().getLoginName();
|
||||
long totalCount = flowApiService.getTaskCountByUserName(username);
|
||||
return ResponseResult.success(totalCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动驳回当前的待办任务到开始节点,只用当前待办任务的指派人或者候选者才能完成该操作。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 待办任务Id。
|
||||
* @param taskComment 驳回备注。
|
||||
* @return 操作应答结果。
|
||||
*/
|
||||
@PostMapping("/rejectToStartUserTask")
|
||||
public ResponseResult<Void> rejectToStartUserTask(
|
||||
@MyRequestBody(required = true) String processInstanceId,
|
||||
@MyRequestBody(required = true) String taskId,
|
||||
@MyRequestBody(required = true) String taskComment) {
|
||||
ResponseResult<Task> taskResult =
|
||||
flowOperationHelper.verifySubmitAndGetTask(processInstanceId, taskId, null);
|
||||
if (!taskResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(taskResult);
|
||||
}
|
||||
FlowTaskComment firstTaskComment = flowTaskCommentService.getFirstFlowTaskComment(processInstanceId);
|
||||
CallResult result = flowApiService.backToRuntimeTask(
|
||||
taskResult.getData(), firstTaskComment.getTaskKey(), true, taskComment);
|
||||
if (!result.isSuccess()) {
|
||||
return ResponseResult.errorFrom(result);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 主动驳回当前的待办任务,只用当前待办任务的指派人或者候选者才能完成该操作。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 待办任务Id。
|
||||
* @param taskComment 驳回备注。
|
||||
* @return 操作应答结果。
|
||||
*/
|
||||
@PostMapping("/rejectRuntimeTask")
|
||||
public ResponseResult<Void> rejectRuntimeTask(
|
||||
@MyRequestBody(required = true) String processInstanceId,
|
||||
@MyRequestBody(required = true) String taskId,
|
||||
@MyRequestBody(required = true) String taskComment) {
|
||||
String errorMessage;
|
||||
ResponseResult<Task> taskResult =
|
||||
flowOperationHelper.verifySubmitAndGetTask(processInstanceId, taskId, null);
|
||||
if (!taskResult.isSuccess()) {
|
||||
return ResponseResult.errorFrom(taskResult);
|
||||
}
|
||||
CallResult result = flowApiService.backToRuntimeTask(taskResult.getData(), null, true, taskComment);
|
||||
if (!result.isSuccess()) {
|
||||
return ResponseResult.errorFrom(result);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回当前用户提交的,但是尚未被审批的待办任务。只有已办任务的指派人才能完成该操作。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 待撤回的已办任务Id。
|
||||
* @param taskComment 撤回备注。
|
||||
* @return 操作应答结果。
|
||||
*/
|
||||
@PostMapping("/revokeHistoricTask")
|
||||
public ResponseResult<Void> revokeHistoricTask(
|
||||
@MyRequestBody(required = true) String processInstanceId,
|
||||
@MyRequestBody(required = true) String taskId,
|
||||
@MyRequestBody(required = true) String taskComment) {
|
||||
String errorMessage;
|
||||
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
|
||||
errorMessage = "数据验证失败,当前流程实例已经结束,不能执行撤回!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
|
||||
if (taskInstance == null) {
|
||||
errorMessage = "数据验证失败,当前任务不存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!StrUtil.equals(taskInstance.getAssignee(), TokenData.takeFromRequest().getLoginName())) {
|
||||
errorMessage = "数据验证失败,任务指派人与当前用户不匹配!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
FlowTaskComment latestComment = flowTaskCommentService.getLatestFlowTaskComment(processInstanceId);
|
||||
if (latestComment == null) {
|
||||
errorMessage = "数据验证失败,当前实例没有任何审批提交记录!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!latestComment.getTaskId().equals(taskId)) {
|
||||
errorMessage = "数据验证失败,当前审批任务已被办理,不能撤回!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
List<Task> activeTaskList = flowApiService.getProcessInstanceActiveTaskList(processInstanceId);
|
||||
if (CollUtil.isEmpty(activeTaskList)) {
|
||||
errorMessage = "数据验证失败,当前流程没有任何待办任务!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (latestComment.getApprovalType().equals(FlowApprovalType.TRANSFER)) {
|
||||
if (activeTaskList.size() > 1) {
|
||||
errorMessage = "数据验证失败,转办任务数量不能多于1个!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
// 如果是转办任务,无需节点跳转,将指派人改为当前用户即可。
|
||||
Task task = activeTaskList.get(0);
|
||||
task.setAssignee(TokenData.takeFromRequest().getLoginName());
|
||||
} else {
|
||||
CallResult result =
|
||||
flowApiService.backToRuntimeTask(activeTaskList.get(0), null, false, taskComment);
|
||||
if (!result.isSuccess()) {
|
||||
return ResponseResult.errorFrom(result);
|
||||
}
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前流程任务的审批列表。
|
||||
*
|
||||
* @param processInstanceId 当前运行时的流程实例Id。
|
||||
* @return 当前流程实例的详情数据。
|
||||
*/
|
||||
@GetMapping("/listFlowTaskComment")
|
||||
public ResponseResult<List<FlowTaskCommentVo>> listFlowTaskComment(@RequestParam String processInstanceId) {
|
||||
List<FlowTaskComment> flowTaskCommentList =
|
||||
flowTaskCommentService.getFlowTaskCommentList(processInstanceId);
|
||||
List<FlowTaskCommentVo> resultList = MyModelUtil.copyCollectionTo(flowTaskCommentList, FlowTaskCommentVo.class);
|
||||
return ResponseResult.success(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定流程定义的流程图。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 流程图。
|
||||
*/
|
||||
@GetMapping("/viewProcessBpmn")
|
||||
public ResponseResult<String> viewProcessBpmn(@RequestParam String processDefinitionId) throws IOException {
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
BpmnModel bpmnModel = flowApiService.getBpmnModelByDefinitionId(processDefinitionId);
|
||||
byte[] xmlBytes = converter.convertToXML(bpmnModel);
|
||||
InputStream in = new ByteArrayInputStream(xmlBytes);
|
||||
return ResponseResult.success(StreamUtils.copyToString(in, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程图高亮数据。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 流程图高亮数据。
|
||||
*/
|
||||
@GetMapping("/viewHighlightFlowData")
|
||||
public ResponseResult<JSONObject> viewHighlightFlowData(@RequestParam String processInstanceId) {
|
||||
List<HistoricActivityInstance> activityInstanceList =
|
||||
flowApiService.getHistoricActivityInstanceList(processInstanceId);
|
||||
Set<String> finishedTaskSet = activityInstanceList.stream()
|
||||
.filter(s -> !StrUtil.equals(s.getActivityType(), "sequenceFlow"))
|
||||
.map(HistoricActivityInstance::getActivityId).collect(Collectors.toSet());
|
||||
Set<String> finishedSequenceFlowSet = activityInstanceList.stream()
|
||||
.filter(s -> StrUtil.equals(s.getActivityType(), "sequenceFlow"))
|
||||
.map(HistoricActivityInstance::getActivityId).collect(Collectors.toSet());
|
||||
//获取流程实例当前正在待办的节点
|
||||
List<HistoricActivityInstance> unfinishedInstanceList =
|
||||
flowApiService.getHistoricUnfinishedInstanceList(processInstanceId);
|
||||
Set<String> unfinishedTaskSet = new LinkedHashSet<>();
|
||||
for (HistoricActivityInstance unfinishedActivity : unfinishedInstanceList) {
|
||||
unfinishedTaskSet.add(unfinishedActivity.getActivityId());
|
||||
}
|
||||
JSONObject jsonData = new JSONObject();
|
||||
jsonData.put("finishedTaskSet", finishedTaskSet);
|
||||
jsonData.put("finishedSequenceFlowSet", finishedSequenceFlowSet);
|
||||
jsonData.put("unfinishedTaskSet", unfinishedTaskSet);
|
||||
return ResponseResult.success(jsonData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的已办理的审批任务列表。
|
||||
*
|
||||
* @param processDefinitionName 流程名。
|
||||
* @param beginDate 流程发起开始时间。
|
||||
* @param endDate 流程发起结束时间。
|
||||
* @param pageParam 分页对象。
|
||||
* @return 查询结果应答。
|
||||
*/
|
||||
@DisableDataFilter
|
||||
@PostMapping("/listHistoricTask")
|
||||
public ResponseResult<MyPageData<Map<String, Object>>> listHistoricTask(
|
||||
@MyRequestBody String processDefinitionName,
|
||||
@MyRequestBody String beginDate,
|
||||
@MyRequestBody String endDate,
|
||||
@MyRequestBody(required = true) MyPageParam pageParam) throws ParseException {
|
||||
MyPageData<HistoricTaskInstance> pageData =
|
||||
flowApiService.getHistoricTaskInstanceFinishedList(processDefinitionName, beginDate, endDate, pageParam);
|
||||
List<Map<String, Object>> resultList = new LinkedList<>();
|
||||
pageData.getDataList().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance)));
|
||||
List<HistoricTaskInstance> taskInstanceList = pageData.getDataList();
|
||||
if (CollUtil.isNotEmpty(taskInstanceList)) {
|
||||
Set<String> instanceIdSet = taskInstanceList.stream()
|
||||
.map(HistoricTaskInstance::getProcessInstanceId).collect(Collectors.toSet());
|
||||
List<HistoricProcessInstance> instanceList = flowApiService.getHistoricProcessInstanceList(instanceIdSet);
|
||||
Set<String> loginNameSet = instanceList.stream()
|
||||
.map(HistoricProcessInstance::getStartUserId).collect(Collectors.toSet());
|
||||
List<FlowUserInfoVo> userInfoList = flowCustomExtFactory
|
||||
.getFlowIdentityExtHelper().getUserInfoListByUsernameSet(loginNameSet);
|
||||
Map<String, FlowUserInfoVo> userInfoMap =
|
||||
userInfoList.stream().collect(Collectors.toMap(FlowUserInfoVo::getLoginName, c -> c));
|
||||
Map<String, HistoricProcessInstance> instanceMap =
|
||||
instanceList.stream().collect(Collectors.toMap(HistoricProcessInstance::getId, c -> c));
|
||||
List<FlowWorkOrder> workOrderList =
|
||||
flowWorkOrderService.getInList(INSTANCE_ID, instanceIdSet);
|
||||
Map<String, FlowWorkOrder> workOrderMap =
|
||||
workOrderList.stream().collect(Collectors.toMap(FlowWorkOrder::getProcessInstanceId, c -> c));
|
||||
resultList.forEach(result -> {
|
||||
String instanceId = result.get(INSTANCE_ID).toString();
|
||||
HistoricProcessInstance instance = instanceMap.get(instanceId);
|
||||
result.put("processDefinitionKey", instance.getProcessDefinitionKey());
|
||||
result.put("processDefinitionName", instance.getProcessDefinitionName());
|
||||
result.put("startUser", instance.getStartUserId());
|
||||
FlowUserInfoVo userInfo = userInfoMap.get(instance.getStartUserId());
|
||||
result.put(SHOW_NAME, userInfo.getShowName());
|
||||
result.put("headImageUrl", userInfo.getHeadImageUrl());
|
||||
result.put("businessKey", instance.getBusinessKey());
|
||||
FlowWorkOrder flowWorkOrder = workOrderMap.get(instanceId);
|
||||
if (flowWorkOrder != null) {
|
||||
result.put("workOrderCode", flowWorkOrder.getWorkOrderCode());
|
||||
}
|
||||
});
|
||||
Set<String> taskIdSet =
|
||||
taskInstanceList.stream().map(HistoricTaskInstance::getId).collect(Collectors.toSet());
|
||||
List<FlowTaskComment> commentList = flowTaskCommentService.getFlowTaskCommentListByTaskIds(taskIdSet);
|
||||
Map<String, List<FlowTaskComment>> commentMap =
|
||||
commentList.stream().collect(Collectors.groupingBy(FlowTaskComment::getTaskId));
|
||||
resultList.forEach(result -> {
|
||||
List<FlowTaskComment> comments = commentMap.get(result.get("id").toString());
|
||||
if (CollUtil.isNotEmpty(comments)) {
|
||||
result.put("approvalType", comments.get(0).getApprovalType());
|
||||
comments.remove(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(resultList, pageData.getTotalCount()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据输入参数查询,当前用户的历史流程数据。
|
||||
*
|
||||
* @param processDefinitionName 流程名。
|
||||
* @param beginDate 流程发起开始时间。
|
||||
* @param endDate 流程发起结束时间。
|
||||
* @param pageParam 分页对象。
|
||||
* @return 查询结果应答。
|
||||
*/
|
||||
@DisableDataFilter
|
||||
@PostMapping("/listHistoricProcessInstance")
|
||||
public ResponseResult<MyPageData<Map<String, Object>>> listHistoricProcessInstance(
|
||||
@MyRequestBody String processDefinitionName,
|
||||
@MyRequestBody String beginDate,
|
||||
@MyRequestBody String endDate,
|
||||
@MyRequestBody(required = true) MyPageParam pageParam) throws ParseException {
|
||||
String loginName = TokenData.takeFromRequest().getLoginName();
|
||||
MyPageData<HistoricProcessInstance> pageData = flowApiService.getHistoricProcessInstanceList(
|
||||
null, processDefinitionName, loginName, beginDate, endDate, pageParam, true);
|
||||
Set<String> loginNameSet = pageData.getDataList().stream()
|
||||
.map(HistoricProcessInstance::getStartUserId).collect(Collectors.toSet());
|
||||
List<FlowUserInfoVo> userInfoList = flowCustomExtFactory
|
||||
.getFlowIdentityExtHelper().getUserInfoListByUsernameSet(loginNameSet);
|
||||
if (CollUtil.isEmpty(userInfoList)) {
|
||||
userInfoList = new LinkedList<>();
|
||||
}
|
||||
Map<String, FlowUserInfoVo> userInfoMap =
|
||||
userInfoList.stream().collect(Collectors.toMap(FlowUserInfoVo::getLoginName, c -> c));
|
||||
Set<String> instanceIdSet = pageData.getDataList().stream()
|
||||
.map(HistoricProcessInstance::getId).collect(Collectors.toSet());
|
||||
List<FlowWorkOrder> workOrderList =
|
||||
flowWorkOrderService.getInList(INSTANCE_ID, instanceIdSet);
|
||||
Map<String, FlowWorkOrder> workOrderMap =
|
||||
workOrderList.stream().collect(Collectors.toMap(FlowWorkOrder::getProcessInstanceId, c -> c));
|
||||
List<Map<String, Object>> resultList = new LinkedList<>();
|
||||
pageData.getDataList().forEach(instance -> {
|
||||
Map<String, Object> data = BeanUtil.beanToMap(instance);
|
||||
FlowUserInfoVo userInfo = userInfoMap.get(instance.getStartUserId());
|
||||
if (userInfo != null) {
|
||||
data.put(SHOW_NAME, userInfo.getShowName());
|
||||
data.put("headImageUrl", userInfo.getHeadImageUrl());
|
||||
}
|
||||
FlowWorkOrder workOrder = workOrderMap.get(instance.getId());
|
||||
if (workOrder != null) {
|
||||
data.put("workOrderCode", workOrder.getWorkOrderCode());
|
||||
data.put("flowStatus", workOrder.getFlowStatus());
|
||||
}
|
||||
resultList.add(data);
|
||||
});
|
||||
return ResponseResult.success(MyPageUtil.makeResponseData(resultList, pageData.getTotalCount()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据输入参数查询,所有历史流程数据。
|
||||
*
|
||||
* @param processDefinitionName 流程名。
|
||||
* @param startUser 流程发起用户。
|
||||
* @param beginDate 流程发起开始时间。
|
||||
* @param endDate 流程发起结束时间。
|
||||
* @param pageParam 分页对象。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
@PostMapping("/listAllHistoricProcessInstance")
|
||||
public ResponseResult<MyPageData<Map<String, Object>>> listAllHistoricProcessInstance(
|
||||
@MyRequestBody String processDefinitionName,
|
||||
@MyRequestBody String startUser,
|
||||
@MyRequestBody String beginDate,
|
||||
@MyRequestBody String endDate,
|
||||
@MyRequestBody(required = true) MyPageParam pageParam) throws ParseException {
|
||||
MyPageData<HistoricProcessInstance> pageData = flowApiService.getHistoricProcessInstanceList(
|
||||
null, processDefinitionName, startUser, beginDate, endDate, pageParam, false);
|
||||
List<Map<String, Object>> resultList = new LinkedList<>();
|
||||
pageData.getDataList().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance)));
|
||||
List<String> unfinishedProcessInstanceIds = pageData.getDataList().stream()
|
||||
.filter(c -> c.getEndTime() == null)
|
||||
.map(HistoricProcessInstance::getId)
|
||||
.collect(Collectors.toList());
|
||||
MyPageData<Map<String, Object>> pageResultData =
|
||||
MyPageUtil.makeResponseData(resultList, pageData.getTotalCount());
|
||||
if (CollUtil.isEmpty(unfinishedProcessInstanceIds)) {
|
||||
return ResponseResult.success(pageResultData);
|
||||
}
|
||||
Set<String> processInstanceIds = pageData.getDataList().stream()
|
||||
.map(HistoricProcessInstance::getId).collect(Collectors.toSet());
|
||||
List<Task> taskList = flowApiService.getTaskListByProcessInstanceIds(unfinishedProcessInstanceIds);
|
||||
Map<String, List<Task>> taskMap =
|
||||
taskList.stream().collect(Collectors.groupingBy(Task::getProcessInstanceId));
|
||||
for (Map<String, Object> result : resultList) {
|
||||
String processInstanceId = result.get(INSTANCE_ID).toString();
|
||||
List<Task> instanceTaskList = taskMap.get(processInstanceId);
|
||||
if (instanceTaskList != null) {
|
||||
JSONArray taskArray = new JSONArray();
|
||||
for (Task task : instanceTaskList) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("taskId", task.getId());
|
||||
jsonObject.put("taskName", task.getName());
|
||||
jsonObject.put("taskKey", task.getTaskDefinitionKey());
|
||||
jsonObject.put("assignee", task.getAssignee());
|
||||
taskArray.add(jsonObject);
|
||||
}
|
||||
result.put("runtimeTaskInfoList", taskArray);
|
||||
}
|
||||
}
|
||||
return ResponseResult.success(pageResultData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 催办工单,只有流程发起人才可以催办工单。
|
||||
* 催办场景必须要取消数据权限过滤,因为流程的指派很可能是跨越部门的。
|
||||
* 既然被指派和催办了,这里就应该禁用工单表的数据权限过滤约束。
|
||||
* 如果您的系统没有支持数据权限过滤,DisableDataFilter不会有任何影响,建议保留。
|
||||
*
|
||||
* @param workOrderId 工单Id。
|
||||
* @return 应答结果。
|
||||
*/
|
||||
@DisableDataFilter
|
||||
@OperationLog(type = SysOperationLogType.REMIND_TASK)
|
||||
@PostMapping("/remindRuntimeTask")
|
||||
public ResponseResult<Void> remindRuntimeTask(@MyRequestBody(required = true) Long workOrderId) {
|
||||
FlowWorkOrder flowWorkOrder = flowWorkOrderService.getById(workOrderId);
|
||||
if (flowWorkOrder == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
String errorMessage;
|
||||
if (!flowWorkOrder.getCreateUserId().equals(TokenData.takeFromRequest().getUserId())) {
|
||||
errorMessage = "数据验证失败,只有流程发起人才能催办工单!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.FINISHED)
|
||||
|| flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.CANCELLED)
|
||||
|| flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.STOPPED)) {
|
||||
errorMessage = "数据验证失败,已经结束的流程,不能催办工单!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.DRAFT)) {
|
||||
errorMessage = "数据验证失败,流程草稿不能催办工单!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
flowMessageService.saveNewRemindMessage(flowWorkOrder);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消工作流工单,仅当没有进入任何审批流程之前,才可以取消工单。
|
||||
*
|
||||
* @param workOrderId 工单Id。
|
||||
* @param cancelReason 取消原因。
|
||||
* @return 应答结果。
|
||||
*/
|
||||
@OperationLog(type = SysOperationLogType.CANCEL_FLOW)
|
||||
@DisableDataFilter
|
||||
@PostMapping("/cancelWorkOrder")
|
||||
public ResponseResult<Void> cancelWorkOrder(
|
||||
@MyRequestBody(required = true) Long workOrderId,
|
||||
@MyRequestBody(required = true) String cancelReason) {
|
||||
FlowWorkOrder flowWorkOrder = flowWorkOrderService.getById(workOrderId);
|
||||
if (flowWorkOrder == null) {
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
|
||||
}
|
||||
String errorMessage;
|
||||
if (!flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.SUBMITTED)
|
||||
&& !flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.DRAFT)) {
|
||||
errorMessage = "数据验证失败,当前流程已经进入审批状态,不能撤销工单!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
if (!flowWorkOrder.getCreateUserId().equals(TokenData.takeFromRequest().getUserId())) {
|
||||
errorMessage = "数据验证失败,当前用户不是工单所有者,不能撤销工单!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
CallResult result;
|
||||
// 草稿工单直接删除当前工单。
|
||||
if (flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.DRAFT)) {
|
||||
result = flowWorkOrderService.removeDraft(flowWorkOrder);
|
||||
} else {
|
||||
result = flowApiService.stopProcessInstance(
|
||||
flowWorkOrder.getProcessInstanceId(), cancelReason, true);
|
||||
}
|
||||
if (!result.isSuccess()) {
|
||||
return ResponseResult.errorFrom(result);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定流程定义Id的所有用户任务数据列表。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
@GetMapping("/listAllUserTask")
|
||||
public ResponseResult<List<JSONObject>> listAllUserTask(@RequestParam String processDefinitionId) {
|
||||
Map<String, UserTask> taskMap = flowApiService.getAllUserTaskMap(processDefinitionId);
|
||||
List<JSONObject> resultList = new LinkedList<>();
|
||||
for (UserTask t : taskMap.values()) {
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("id", t.getId());
|
||||
data.put("name", t.getName());
|
||||
resultList.add(data);
|
||||
}
|
||||
return ResponseResult.success(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 终止流程实例,将任务从当前节点直接流转到主流程的结束事件。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param stopReason 停止原因。
|
||||
* @return 执行结果应答。
|
||||
*/
|
||||
@SaCheckPermission("flowOperation.all")
|
||||
@OperationLog(type = SysOperationLogType.STOP_FLOW)
|
||||
@DisableDataFilter
|
||||
@PostMapping("/stopProcessInstance")
|
||||
public ResponseResult<Void> stopProcessInstance(
|
||||
@MyRequestBody(required = true) String processInstanceId,
|
||||
@MyRequestBody(required = true) String stopReason) {
|
||||
CallResult result = flowApiService.stopProcessInstance(processInstanceId, stopReason, false);
|
||||
if (!result.isSuccess()) {
|
||||
return ResponseResult.errorFrom(result);
|
||||
}
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程实例。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 执行结果应答。
|
||||
*/
|
||||
@SaCheckPermission("flowOperation.all")
|
||||
@OperationLog(type = SysOperationLogType.DELETE_FLOW)
|
||||
@PostMapping("/deleteProcessInstance")
|
||||
public ResponseResult<Void> deleteProcessInstance(@MyRequestBody(required = true) String processInstanceId) {
|
||||
flowApiService.deleteProcessInstance(processInstanceId);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
private List<FlowTaskComment> buildApprovedFlowTaskCommentList(TaskInfo taskInfo, boolean isMultiInstanceTask) {
|
||||
List<FlowTaskComment> taskCommentList;
|
||||
if (isMultiInstanceTask) {
|
||||
String multiInstanceExecId;
|
||||
FlowMultiInstanceTrans trans =
|
||||
flowMultiInstanceTransService.getByExecutionId(taskInfo.getExecutionId(), taskInfo.getId());
|
||||
if (trans != null) {
|
||||
multiInstanceExecId = trans.getMultiInstanceExecId();
|
||||
} else {
|
||||
multiInstanceExecId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
taskInfo.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR);
|
||||
}
|
||||
taskCommentList = flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
|
||||
} else {
|
||||
taskCommentList = flowTaskCommentService.getFlowTaskCommentListByExecutionId(
|
||||
taskInfo.getProcessInstanceId(), taskInfo.getId(), taskInfo.getExecutionId());
|
||||
}
|
||||
return taskCommentList;
|
||||
}
|
||||
|
||||
private ResponseResult<JSONObject> doVerifyMultiSign(String processInstanceId, String taskId) {
|
||||
String errorMessage;
|
||||
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
|
||||
errorMessage = "数据验证失败,当前流程实例已经结束,不能执行加签!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
|
||||
if (taskInstance == null) {
|
||||
errorMessage = "数据验证失败,当前任务不存在!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
String loginName = TokenData.takeFromRequest().getLoginName();
|
||||
if (!StrUtil.equals(taskInstance.getAssignee(), loginName)) {
|
||||
errorMessage = "数据验证失败,任务指派人与当前用户不匹配!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
List<Task> activeTaskList = flowApiService.getProcessInstanceActiveTaskList(processInstanceId);
|
||||
Task activeMultiInstanceTask = null;
|
||||
Map<String, UserTask> userTaskMap = flowApiService.getAllUserTaskMap(taskInstance.getProcessDefinitionId());
|
||||
for (Task activeTask : activeTaskList) {
|
||||
UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey());
|
||||
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
||||
errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
String startTaskId = flowApiService.getTaskVariableStringWithSafe(
|
||||
activeTask.getId(), FlowConstant.MULTI_SIGN_START_TASK_VAR);
|
||||
if (StrUtil.equals(startTaskId, taskId)) {
|
||||
activeMultiInstanceTask = activeTask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (activeMultiInstanceTask == null) {
|
||||
errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!";
|
||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||
}
|
||||
JSONObject resultData = new JSONObject();
|
||||
resultData.put("taskInstance", taskInstance);
|
||||
resultData.put(ACTIVE_MULTI_INST_TASK, activeMultiInstanceTask);
|
||||
return ResponseResult.success(resultData);
|
||||
}
|
||||
|
||||
private String findExistAssignee(Set<String> assigneeSet, JSONArray assigneeArray) {
|
||||
for (int i = 0; i < assigneeArray.size(); i++) {
|
||||
String loginName = assigneeArray.getString(i);
|
||||
if (assigneeSet.contains(loginName)) {
|
||||
return loginName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowCategory;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* FlowCategory数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowCategoryMapper extends BaseDaoMapper<FlowCategory> {
|
||||
|
||||
/**
|
||||
* 获取过滤后的对象列表。
|
||||
*
|
||||
* @param flowCategoryFilter 主表过滤对象。
|
||||
* @param orderBy 排序字符串,order by从句的参数。
|
||||
* @return 对象列表。
|
||||
*/
|
||||
List<FlowCategory> getFlowCategoryList(
|
||||
@Param("flowCategoryFilter") FlowCategory flowCategoryFilter, @Param("orderBy") String orderBy);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowEntry;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* FlowEntry数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowEntryMapper extends BaseDaoMapper<FlowEntry> {
|
||||
|
||||
/**
|
||||
* 获取过滤后的对象列表。
|
||||
*
|
||||
* @param flowEntryFilter 主表过滤对象。
|
||||
* @param orderBy 排序字符串,order by从句的参数。
|
||||
* @return 对象列表。
|
||||
*/
|
||||
List<FlowEntry> getFlowEntryList(
|
||||
@Param("flowEntryFilter") FlowEntry flowEntryFilter, @Param("orderBy") String orderBy);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowEntryPublish;
|
||||
|
||||
/**
|
||||
* 数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowEntryPublishMapper extends BaseDaoMapper<FlowEntryPublish> {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowEntryPublishVariable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowEntryPublishVariableMapper extends BaseDaoMapper<FlowEntryPublishVariable> {
|
||||
|
||||
/**
|
||||
* 批量插入流程发布的变量列表。
|
||||
*
|
||||
* @param entryPublishVariableList 流程发布的变量列表。
|
||||
*/
|
||||
void insertList(List<FlowEntryPublishVariable> entryPublishVariableList);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowEntryVariable;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程变量数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowEntryVariableMapper extends BaseDaoMapper<FlowEntryVariable> {
|
||||
|
||||
/**
|
||||
* 获取过滤后的对象列表。
|
||||
*
|
||||
* @param flowEntryVariableFilter 主表过滤对象。
|
||||
* @param orderBy 排序字符串,order by从句的参数。
|
||||
* @return 对象列表。
|
||||
*/
|
||||
List<FlowEntryVariable> getFlowEntryVariableList(
|
||||
@Param("flowEntryVariableFilter") FlowEntryVariable flowEntryVariableFilter,
|
||||
@Param("orderBy") String orderBy);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowMessageCandidateIdentity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 流程任务消息的候选身份数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowMessageCandidateIdentityMapper extends BaseDaoMapper<FlowMessageCandidateIdentity> {
|
||||
|
||||
/**
|
||||
* 删除指定流程实例的消息关联数据。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
*/
|
||||
void deleteByProcessInstanceId(@Param("processInstanceId") String processInstanceId);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowMessageIdentityOperation;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 流程任务消息所属用户的操作数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowMessageIdentityOperationMapper extends BaseDaoMapper<FlowMessageIdentityOperation> {
|
||||
|
||||
/**
|
||||
* 删除指定流程实例的消息关联数据。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
*/
|
||||
void deleteByProcessInstanceId(@Param("processInstanceId") String processInstanceId);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowMessage;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 工作流消息数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowMessageMapper extends BaseDaoMapper<FlowMessage> {
|
||||
|
||||
/**
|
||||
* 获取指定用户和身份分组Id集合的催办消息列表。
|
||||
*
|
||||
* @param tenantId 租户Id。
|
||||
* @param appCode 应用编码。
|
||||
* @param loginName 用户的登录名。与流程任务的assignee精确匹配。
|
||||
* @param groupIdSet 用户身份分组Id集合。
|
||||
* @return 查询后的催办消息列表。
|
||||
*/
|
||||
List<FlowMessage> getRemindingMessageListByUser(
|
||||
@Param("tenantId") Long tenantId,
|
||||
@Param("appCode") String appCode,
|
||||
@Param("loginName") String loginName,
|
||||
@Param("groupIdSet") Set<String> groupIdSet);
|
||||
|
||||
/**
|
||||
* 获取指定用户和身份分组Id集合的抄送消息列表。
|
||||
*
|
||||
* @param tenantId 租户Id。
|
||||
* @param appCode 应用编码。
|
||||
* @param loginName 用户登录名。
|
||||
* @param groupIdSet 用户身份分组Id集合。
|
||||
* @param read true表示已读,false表示未读。
|
||||
* @return 查询后的抄送消息列表。
|
||||
*/
|
||||
List<FlowMessage> getCopyMessageListByUser(
|
||||
@Param("tenantId") Long tenantId,
|
||||
@Param("appCode") String appCode,
|
||||
@Param("loginName") String loginName,
|
||||
@Param("groupIdSet") Set<String> groupIdSet,
|
||||
@Param("read") Boolean read);
|
||||
|
||||
/**
|
||||
* 计算当前用户催办消息的数量。
|
||||
*
|
||||
* @param tenantId 租户Id。
|
||||
* @param appCode 应用编码。
|
||||
* @param loginName 用户登录名。
|
||||
* @param groupIdSet 用户身份分组Id集合。
|
||||
* @return 数据数量。
|
||||
*/
|
||||
int countRemindingMessageListByUser(
|
||||
@Param("tenantId") Long tenantId,
|
||||
@Param("appCode") String appCode,
|
||||
@Param("loginName") String loginName,
|
||||
@Param("groupIdSet") Set<String> groupIdSet);
|
||||
|
||||
/**
|
||||
* 计算当前用户未读抄送消息的数量。
|
||||
*
|
||||
* @param tenantId 租户Id。
|
||||
* @param appCode 应用编码。
|
||||
* @param loginName 用户登录名。
|
||||
* @param groupIdSet 用户身份分组Id集合。
|
||||
* @return 数据数量
|
||||
*/
|
||||
int countCopyMessageListByUser(
|
||||
@Param("tenantId") Long tenantId,
|
||||
@Param("appCode") String appCode,
|
||||
@Param("loginName") String loginName,
|
||||
@Param("groupIdSet") Set<String> groupIdSet);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowMultiInstanceTrans;
|
||||
|
||||
/**
|
||||
* 流程多实例任务执行流水访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowMultiInstanceTransMapper extends BaseDaoMapper<FlowMultiInstanceTrans> {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowTaskComment;
|
||||
|
||||
/**
|
||||
* 流程任务批注数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowTaskCommentMapper extends BaseDaoMapper<FlowTaskComment> {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowTaskExt;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程任务扩展数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowTaskExtMapper extends BaseDaoMapper<FlowTaskExt> {
|
||||
|
||||
/**
|
||||
* 批量插入流程任务扩展信息列表。
|
||||
*
|
||||
* @param flowTaskExtList 流程任务扩展信息列表。
|
||||
*/
|
||||
void insertList(List<FlowTaskExt> flowTaskExtList);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrderExt;
|
||||
|
||||
/**
|
||||
* 工作流工单扩展数据操作访问接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowWorkOrderExtMapper extends BaseDaoMapper<FlowWorkOrderExt> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.orangeforms.common.flow.dao;
|
||||
|
||||
import com.orangeforms.common.core.annotation.EnableDataPerm;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流工单表数据操作访问接口。
|
||||
* 如果当前系统支持数据权限过滤,当前用户必须要能看自己的工单数据,所以需要把EnableDataPerm
|
||||
* 的mustIncludeUserRule参数设置为true,即便当前用户的数据权限中并不包含DataPermRuleType.TYPE_USER_ONLY,
|
||||
* 数据过滤拦截组件也会自动补偿该类型的数据权限,以便当前用户可以看到自己发起的工单。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@EnableDataPerm(mustIncludeUserRule = true)
|
||||
public interface FlowWorkOrderMapper extends BaseDaoMapper<FlowWorkOrder> {
|
||||
|
||||
/**
|
||||
* 获取过滤后的对象列表。
|
||||
*
|
||||
* @param flowWorkOrderFilter 主表过滤对象。
|
||||
* @param orderBy 排序字符串,order by从句的参数。
|
||||
* @return 对象列表。
|
||||
*/
|
||||
List<FlowWorkOrder> getFlowWorkOrderList(
|
||||
@Param("flowWorkOrderFilter") FlowWorkOrder flowWorkOrderFilter, @Param("orderBy") String orderBy);
|
||||
|
||||
/**
|
||||
* 计算指定前缀工单编码的最大值。
|
||||
*
|
||||
* @param prefix 工单编码前缀。
|
||||
* @return 该工单编码前缀的最大值。
|
||||
*/
|
||||
@Select("SELECT MAX(work_order_code) FROM zz_flow_work_order WHERE work_order_code LIKE '${prefix}'")
|
||||
String getMaxWorkOrderCodeByPrefix(@Param("prefix") String prefix);
|
||||
|
||||
/**
|
||||
* 根据工单编码查询指定工单,查询过程也会考虑逻辑删除的数据。
|
||||
* @param workOrderCode 工单编码。
|
||||
* @return 工单编码的流程工单数量。
|
||||
*/
|
||||
@Select("SELECT COUNT(*) FROM zz_flow_work_order WHERE work_order_code = #{workOrderCode}")
|
||||
int getCountByWorkOrderCode(@Param("workOrderCode") String workOrderCode);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowCategoryMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowCategory">
|
||||
<id column="category_id" jdbcType="BIGINT" property="categoryId"/>
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
|
||||
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
|
||||
<result column="name" jdbcType="VARCHAR" property="name"/>
|
||||
<result column="code" jdbcType="VARCHAR" property="code"/>
|
||||
<result column="show_order" jdbcType="INTEGER" property="showOrder"/>
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||
<sql id="filterRef">
|
||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||
<include refid="com.orangeforms.common.flow.dao.FlowCategoryMapper.inputFilterRef"/>
|
||||
</sql>
|
||||
|
||||
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
|
||||
<sql id="inputFilterRef">
|
||||
<if test="flowCategoryFilter != null">
|
||||
<if test="flowCategoryFilter.tenantId == null">
|
||||
AND zz_flow_category.tenant_id IS NULL
|
||||
</if>
|
||||
<if test="flowCategoryFilter.tenantId != null">
|
||||
AND zz_flow_category.tenant_id = #{flowCategoryFilter.tenantId}
|
||||
</if>
|
||||
<if test="flowCategoryFilter.appCode == null">
|
||||
AND zz_flow_category.app_code IS NULL
|
||||
</if>
|
||||
<if test="flowCategoryFilter.appCode != null">
|
||||
AND zz_flow_category.app_code = #{flowCategoryFilter.appCode}
|
||||
</if>
|
||||
<if test="flowCategoryFilter.name != null and flowCategoryFilter.name != ''">
|
||||
AND zz_flow_category.name = #{flowCategoryFilter.name}
|
||||
</if>
|
||||
<if test="flowCategoryFilter.code != null and flowCategoryFilter.code != ''">
|
||||
AND zz_flow_category.code = #{flowCategoryFilter.code}
|
||||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getFlowCategoryList" resultMap="BaseResultMap" parameterType="com.orangeforms.common.flow.model.FlowCategory">
|
||||
SELECT * FROM zz_flow_category
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
</where>
|
||||
<if test="orderBy != null and orderBy != ''">
|
||||
ORDER BY ${orderBy}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowEntryMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowEntry">
|
||||
<id column="entry_id" jdbcType="BIGINT" property="entryId"/>
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
|
||||
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
|
||||
<result column="process_definition_name" jdbcType="VARCHAR" property="processDefinitionName"/>
|
||||
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
|
||||
<result column="category_id" jdbcType="BIGINT" property="categoryId"/>
|
||||
<result column="main_entry_publish_id" jdbcType="BIGINT" property="mainEntryPublishId"/>
|
||||
<result column="latest_publish_time" jdbcType="TIMESTAMP" property="latestPublishTime"/>
|
||||
<result column="status" jdbcType="INTEGER" property="status"/>
|
||||
<result column="bpmn_xml" jdbcType="LONGVARCHAR" property="bpmnXml"/>
|
||||
<result column="diagram_type" jdbcType="INTEGER" property="diagramType"/>
|
||||
<result column="bind_form_type" jdbcType="INTEGER" property="bindFormType"/>
|
||||
<result column="page_id" jdbcType="BIGINT" property="pageId"/>
|
||||
<result column="default_form_id" jdbcType="BIGINT" property="defaultFormId"/>
|
||||
<result column="default_router_name" jdbcType="VARCHAR" property="defaultRouterName"/>
|
||||
<result column="encoded_rule" jdbcType="VARCHAR" property="encodedRule"/>
|
||||
<result column="extension_data" jdbcType="VARCHAR" property="extensionData"/>
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||
<sql id="filterRef">
|
||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||
<include refid="com.orangeforms.common.flow.dao.FlowEntryMapper.inputFilterRef"/>
|
||||
</sql>
|
||||
|
||||
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
|
||||
<sql id="inputFilterRef">
|
||||
<if test="flowEntryFilter != null">
|
||||
<if test="flowEntryFilter.tenantId == null">
|
||||
AND zz_flow_entry.tenant_id IS NULL
|
||||
</if>
|
||||
<if test="flowEntryFilter.tenantId != null">
|
||||
AND zz_flow_entry.tenant_id = #{flowEntryFilter.tenantId}
|
||||
</if>
|
||||
<if test="flowEntryFilter.appCode == null">
|
||||
AND zz_flow_entry.app_code IS NULL
|
||||
</if>
|
||||
<if test="flowEntryFilter.appCode != null">
|
||||
AND zz_flow_entry.app_code = #{flowEntryFilter.appCode}
|
||||
</if>
|
||||
<if test="flowEntryFilter.processDefinitionName != null and flowEntryFilter.processDefinitionName != ''">
|
||||
AND zz_flow_entry.process_definition_name = #{flowEntryFilter.processDefinitionName}
|
||||
</if>
|
||||
<if test="flowEntryFilter.processDefinitionKey != null and flowEntryFilter.processDefinitionKey != ''">
|
||||
AND zz_flow_entry.process_definition_key = #{flowEntryFilter.processDefinitionKey}
|
||||
</if>
|
||||
<if test="flowEntryFilter.categoryId != null">
|
||||
AND zz_flow_entry.category_id = #{flowEntryFilter.categoryId}
|
||||
</if>
|
||||
<if test="flowEntryFilter.status != null">
|
||||
AND zz_flow_entry.status = #{flowEntryFilter.status}
|
||||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getFlowEntryList" resultMap="BaseResultMap" parameterType="com.orangeforms.common.flow.model.FlowEntry">
|
||||
SELECT
|
||||
entry_id,
|
||||
app_code,
|
||||
process_definition_name,
|
||||
process_definition_key,
|
||||
category_id,
|
||||
main_entry_publish_id,
|
||||
latest_publish_time,
|
||||
status,
|
||||
diagram_type,
|
||||
bind_form_type,
|
||||
page_id,
|
||||
default_form_id,
|
||||
default_router_name,
|
||||
encoded_rule,
|
||||
extension_data,
|
||||
update_time,
|
||||
update_user_id,
|
||||
create_time,
|
||||
create_user_id
|
||||
FROM
|
||||
zz_flow_entry
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
</where>
|
||||
<if test="orderBy != null and orderBy != ''">
|
||||
ORDER BY ${orderBy}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowEntryPublishMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowEntryPublish">
|
||||
<id column="entry_publish_id" jdbcType="BIGINT" property="entryPublishId"/>
|
||||
<result column="entry_id" jdbcType="BIGINT" property="entryId"/>
|
||||
<result column="deploy_id" jdbcType="VARCHAR" property="deployId"/>
|
||||
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
|
||||
<result column="publish_version" jdbcType="INTEGER" property="publishVersion"/>
|
||||
<result column="active_status" jdbcType="BOOLEAN" property="activeStatus"/>
|
||||
<result column="main_version" jdbcType="BOOLEAN" property="mainVersion"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="publish_time" jdbcType="TIMESTAMP" property="publishTime"/>
|
||||
<result column="init_task_info" jdbcType="VARCHAR" property="initTaskInfo"/>
|
||||
<result column="analyzed_node_json" jdbcType="VARCHAR" property="analyzedNodeJson"/>
|
||||
<result column="extension_data" jdbcType="VARCHAR" property="extensionData"/>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowEntryPublishVariableMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowEntryPublishVariable">
|
||||
<id column="variable_id" jdbcType="BIGINT" property="variableId"/>
|
||||
<result column="entry_publish_id" jdbcType="BIGINT" property="entryPublishId"/>
|
||||
<result column="variable_name" jdbcType="VARCHAR" property="variableName"/>
|
||||
<result column="show_name" jdbcType="VARCHAR" property="showName"/>
|
||||
<result column="variable_type" jdbcType="INTEGER" property="variableType"/>
|
||||
<result column="bind_datasource_id" jdbcType="BIGINT" property="bindDatasourceId"/>
|
||||
<result column="bind_relation_id" jdbcType="BIGINT" property="bindRelationId"/>
|
||||
<result column="bind_column_id" jdbcType="BIGINT" property="bindColumnId"/>
|
||||
<result column="builtin" jdbcType="BOOLEAN" property="builtin"/>
|
||||
</resultMap>
|
||||
|
||||
<insert id="insertList">
|
||||
INSERT INTO zz_flow_entry_publish_variable VALUES
|
||||
<foreach collection="list" index="index" item="item" separator="," >
|
||||
(#{item.variableId},
|
||||
#{item.entryPublishId},
|
||||
#{item.variableName},
|
||||
#{item.showName},
|
||||
#{item.variableType},
|
||||
#{item.bindDatasourceId},
|
||||
#{item.bindRelationId},
|
||||
#{item.bindColumnId},
|
||||
#{item.builtin})
|
||||
</foreach>
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowEntryVariableMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowEntryVariable">
|
||||
<id column="variable_id" jdbcType="BIGINT" property="variableId"/>
|
||||
<result column="entry_id" jdbcType="BIGINT" property="entryId"/>
|
||||
<result column="variable_name" jdbcType="VARCHAR" property="variableName"/>
|
||||
<result column="show_name" jdbcType="VARCHAR" property="showName"/>
|
||||
<result column="variable_type" jdbcType="INTEGER" property="variableType"/>
|
||||
<result column="bind_datasource_id" jdbcType="BIGINT" property="bindDatasourceId"/>
|
||||
<result column="bind_relation_id" jdbcType="BIGINT" property="bindRelationId"/>
|
||||
<result column="bind_column_id" jdbcType="BIGINT" property="bindColumnId"/>
|
||||
<result column="builtin" jdbcType="BOOLEAN" property="builtin"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||
<sql id="filterRef">
|
||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||
<include refid="com.orangeforms.common.flow.dao.FlowEntryVariableMapper.inputFilterRef"/>
|
||||
</sql>
|
||||
|
||||
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
|
||||
<sql id="inputFilterRef">
|
||||
<if test="flowEntryVariableFilter != null">
|
||||
<if test="flowEntryVariableFilter.entryId != null">
|
||||
AND zz_flow_entry_variable.entry_id = #{flowEntryVariableFilter.entryId}
|
||||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getFlowEntryVariableList" resultMap="BaseResultMap" parameterType="com.orangeforms.common.flow.model.FlowEntryVariable">
|
||||
SELECT * FROM zz_flow_entry_variable
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
</where>
|
||||
<if test="orderBy != null and orderBy != ''">
|
||||
ORDER BY ${orderBy}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowMessageCandidateIdentityMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowMessageCandidateIdentity">
|
||||
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||
<result column="message_id" jdbcType="BIGINT" property="messageId"/>
|
||||
<result column="candidate_type" jdbcType="VARCHAR" property="candidateType"/>
|
||||
<result column="candidate_id" jdbcType="VARCHAR" property="candidateId"/>
|
||||
</resultMap>
|
||||
|
||||
<delete id="deleteByProcessInstanceId">
|
||||
DELETE FROM zz_flow_msg_candidate_identity a
|
||||
WHERE EXISTS (SELECT * FROM zz_flow_message b
|
||||
WHERE a.message_id = b.message_id AND b.process_instance_id = #{processInstanceId})
|
||||
</delete>
|
||||
</mapper>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowMessageIdentityOperationMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowMessageIdentityOperation">
|
||||
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||
<result column="message_id" jdbcType="BIGINT" property="messageId"/>
|
||||
<result column="login_name" jdbcType="VARCHAR" property="loginName"/>
|
||||
<result column="operation_type" jdbcType="INTEGER" property="operationType"/>
|
||||
<result column="operation_time" jdbcType="TIMESTAMP" property="operationTime"/>
|
||||
</resultMap>
|
||||
|
||||
<delete id="deleteByProcessInstanceId">
|
||||
DELETE FROM zz_flow_msg_identity_operation a
|
||||
WHERE EXISTS (SELECT * FROM zz_flow_message b
|
||||
WHERE a.message_id = b.message_id AND b.process_instance_id = #{processInstanceId})
|
||||
</delete>
|
||||
</mapper>
|
||||
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowMessageMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowMessage">
|
||||
<id column="message_id" jdbcType="BIGINT" property="messageId"/>
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
|
||||
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
|
||||
<result column="message_type" jdbcType="TINYINT" property="messageType"/>
|
||||
<result column="message_content" jdbcType="VARCHAR" property="messageContent"/>
|
||||
<result column="remind_count" jdbcType="INTEGER" property="remindCount"/>
|
||||
<result column="work_order_id" jdbcType="BIGINT" property="workOrderId"/>
|
||||
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
|
||||
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
|
||||
<result column="process_definition_name" jdbcType="VARCHAR" property="processDefinitionName"/>
|
||||
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
|
||||
<result column="process_instance_initiator" jdbcType="VARCHAR" property="processInstanceInitiator"/>
|
||||
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
|
||||
<result column="task_definition_key" jdbcType="VARCHAR" property="taskDefinitionKey"/>
|
||||
<result column="task_name" jdbcType="VARCHAR" property="taskName"/>
|
||||
<result column="task_start_time" jdbcType="TIMESTAMP" property="taskStartTime"/>
|
||||
<result column="task_assignee" jdbcType="VARCHAR" property="taskAssignee"/>
|
||||
<result column="task_finished" jdbcType="BOOLEAN" property="taskFinished"/>
|
||||
<result column="business_data_shot" jdbcType="LONGVARCHAR" property="businessDataShot"/>
|
||||
<result column="online_form_data" jdbcType="BOOLEAN" property="onlineFormData"/>
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="filterRef">
|
||||
<if test="tenantId == null">
|
||||
AND a.tenant_id IS NULL
|
||||
</if>
|
||||
<if test="tenantId != null">
|
||||
AND a.tenant_id = #{tenantId}
|
||||
</if>
|
||||
<if test="appCode == null">
|
||||
AND a.app_code IS NULL
|
||||
</if>
|
||||
<if test="appCode != null">
|
||||
AND a.app_code = #{appCode}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getRemindingMessageListByUser" resultMap="BaseResultMap">
|
||||
SELECT a.* FROM zz_flow_message a
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
AND a.task_finished = false
|
||||
AND a.message_type = 0
|
||||
AND (a.task_assignee = #{loginName} OR EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
|
||||
WHERE a.message_id = b.message_id AND b.candidate_id IN
|
||||
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>))
|
||||
</where>
|
||||
ORDER BY a.update_time DESC
|
||||
</select>
|
||||
|
||||
<select id="getCopyMessageListByUser" resultMap="BaseResultMap">
|
||||
SELECT a.* FROM zz_flow_message a
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
AND a.message_type = 1
|
||||
AND EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
|
||||
WHERE a.message_id = b.message_id AND b.candidate_id IN
|
||||
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>)
|
||||
<if test="!read">
|
||||
AND NOT EXISTS (SELECT * FROM zz_flow_msg_identity_operation c
|
||||
WHERE a.message_id = c.message_id AND c.login_name = #{loginName})
|
||||
</if>
|
||||
<if test="read">
|
||||
AND EXISTS (SELECT * FROM zz_flow_msg_identity_operation c
|
||||
WHERE a.message_id = c.message_id AND c.login_name = #{loginName})
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY a.update_time DESC
|
||||
</select>
|
||||
|
||||
<select id="countRemindingMessageListByUser" resultType="java.lang.Integer">
|
||||
SELECT COUNT(1) FROM zz_flow_message a
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
AND a.task_finished = false
|
||||
AND a.message_type = 0
|
||||
AND (a.task_assignee = #{loginName} OR EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
|
||||
WHERE a.message_id = b.message_id AND b.candidate_id IN
|
||||
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>))
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="countCopyMessageListByUser" resultType="java.lang.Integer">
|
||||
SELECT COUNT(1) FROM zz_flow_message a
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
AND a.message_type = 1
|
||||
AND EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
|
||||
WHERE a.message_id = b.message_id AND b.candidate_id IN
|
||||
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>)
|
||||
AND NOT EXISTS (SELECT * FROM zz_flow_msg_identity_operation c
|
||||
WHERE a.message_id = c.message_id AND c.login_name = #{loginName})
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowMultiInstanceTransMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowMultiInstanceTrans">
|
||||
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
|
||||
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
|
||||
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
|
||||
<result column="multi_instance_exec_id" jdbcType="VARCHAR" property="multiInstanceExecId"/>
|
||||
<result column="execution_id" jdbcType="VARCHAR" property="executionId"/>
|
||||
<result column="assignee_list" jdbcType="LONGVARCHAR" property="assigneeList"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="create_login_name" jdbcType="VARCHAR" property="createLoginName"/>
|
||||
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowTaskCommentMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowTaskComment">
|
||||
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
|
||||
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
|
||||
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
|
||||
<result column="task_name" jdbcType="VARCHAR" property="taskName"/>
|
||||
<result column="target_task_key" jdbcType="VARCHAR" property="targetTaskKey"/>
|
||||
<result column="execution_id" jdbcType="VARCHAR" property="executionId"/>
|
||||
<result column="multi_instance_exec_id" jdbcType="VARCHAR" property="multiInstanceExecId"/>
|
||||
<result column="approval_type" jdbcType="VARCHAR" property="approvalType"/>
|
||||
<result column="delegate_assignee" jdbcType="VARCHAR" property="delegateAssignee"/>
|
||||
<result column="custom_business_data" jdbcType="LONGVARCHAR" property="customBusinessData"/>
|
||||
<result column="task_comment" jdbcType="VARCHAR" property="taskComment"/>
|
||||
<result column="head_image_url" jdbcType="VARCHAR" property="headImageUrl"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="create_login_name" jdbcType="VARCHAR" property="createLoginName"/>
|
||||
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowTaskExtMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowTaskExt">
|
||||
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
|
||||
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
|
||||
<result column="operation_list_json" jdbcType="LONGVARCHAR" property="operationListJson"/>
|
||||
<result column="variable_list_json" jdbcType="LONGVARCHAR" property="variableListJson"/>
|
||||
<result column="assignee_list_json" jdbcType="LONGVARCHAR" property="assigneeListJson"/>
|
||||
<result column="group_type" jdbcType="VARCHAR" property="groupType"/>
|
||||
<result column="dept_post_list_json" jdbcType="VARCHAR" property="deptPostListJson"/>
|
||||
<result column="role_ids" jdbcType="VARCHAR" property="roleIds"/>
|
||||
<result column="dept_ids" jdbcType="VARCHAR" property="deptIds"/>
|
||||
<result column="candidate_usernames" jdbcType="VARCHAR" property="candidateUsernames"/>
|
||||
<result column="copy_list_json" jdbcType="VARCHAR" property="copyListJson"/>
|
||||
<result column="extra_data_json" jdbcType="VARCHAR" property="extraDataJson"/>
|
||||
</resultMap>
|
||||
|
||||
<insert id="insertList">
|
||||
INSERT INTO zz_flow_task_ext VALUES
|
||||
<foreach collection="list" index="index" item="item" separator="," >
|
||||
(#{item.processDefinitionId},
|
||||
#{item.taskId},
|
||||
#{item.operationListJson},
|
||||
#{item.variableListJson},
|
||||
#{item.assigneeListJson},
|
||||
#{item.groupType},
|
||||
#{item.deptPostListJson},
|
||||
#{item.roleIds},
|
||||
#{item.deptIds},
|
||||
#{item.candidateUsernames},
|
||||
#{item.copyListJson},
|
||||
#{item.extraDataJson})
|
||||
</foreach>
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowWorkOrderExtMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowWorkOrderExt">
|
||||
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||
<result column="work_order_id" jdbcType="BIGINT" property="workOrderId"/>
|
||||
<result column="draft_data" jdbcType="LONGVARCHAR" property="draftData"/>
|
||||
<result column="business_data" jdbcType="LONGVARCHAR" property="businessData"/>
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
|
||||
</resultMap>
|
||||
</mapper>
|
||||
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.orangeforms.common.flow.dao.FlowWorkOrderMapper">
|
||||
<resultMap id="BaseResultMap" type="com.orangeforms.common.flow.model.FlowWorkOrder">
|
||||
<id column="work_order_id" jdbcType="BIGINT" property="workOrderId"/>
|
||||
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
|
||||
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
|
||||
<result column="work_order_code" jdbcType="VARCHAR" property="workOrderCode"/>
|
||||
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
|
||||
<result column="process_definition_name" jdbcType="VARCHAR" property="processDefinitionName"/>
|
||||
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
|
||||
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
|
||||
<result column="online_table_id" jdbcType="BIGINT" property="onlineTableId"/>
|
||||
<result column="table_name" jdbcType="VARCHAR" property="tableName"/>
|
||||
<result column="business_key" jdbcType="VARCHAR" property="businessKey"/>
|
||||
<result column="latest_approval_status" jdbcType="INTEGER" property="latestApprovalStatus"/>
|
||||
<result column="flow_status" jdbcType="INTEGER" property="flowStatus"/>
|
||||
<result column="submit_username" jdbcType="VARCHAR" property="submitUsername"/>
|
||||
<result column="dept_id" jdbcType="BIGINT" property="deptId"/>
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
|
||||
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
|
||||
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||
<sql id="filterRef">
|
||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||
<include refid="com.orangeforms.common.flow.dao.FlowWorkOrderMapper.inputFilterRef"/>
|
||||
AND zz_flow_work_order.deleted_flag = ${@com.orangeforms.common.core.constant.GlobalDeletedFlag@NORMAL}
|
||||
</sql>
|
||||
|
||||
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
|
||||
<sql id="inputFilterRef">
|
||||
<if test="flowWorkOrderFilter != null">
|
||||
<if test="flowWorkOrderFilter.tenantId == null">
|
||||
AND zz_flow_work_order.tenant_id IS NULL
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.tenantId != null">
|
||||
AND zz_flow_work_order.tenant_id = #{flowWorkOrderFilter.tenantId}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.appCode == null">
|
||||
AND zz_flow_work_order.app_code IS NULL
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.appCode != null">
|
||||
AND zz_flow_work_order.app_code = #{flowWorkOrderFilter.appCode}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.workOrderCode != null and flowWorkOrderFilter.workOrderCode != ''">
|
||||
AND zz_flow_work_order.work_order_code = #{flowWorkOrderFilter.workOrderCode}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.processDefinitionKey != null and flowWorkOrderFilter.processDefinitionKey != ''">
|
||||
AND zz_flow_work_order.process_definition_key = #{flowWorkOrderFilter.processDefinitionKey}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.latestApprovalStatus != null">
|
||||
AND zz_flow_work_order.latest_approval_status = #{flowWorkOrderFilter.latestApprovalStatus}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.flowStatus != null">
|
||||
AND zz_flow_work_order.flow_status = #{flowWorkOrderFilter.flowStatus}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.createTimeStart != null and flowWorkOrderFilter.createTimeStart != ''">
|
||||
AND zz_flow_work_order.create_time >= #{flowWorkOrderFilter.createTimeStart}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.createTimeEnd != null and flowWorkOrderFilter.createTimeEnd != ''">
|
||||
AND zz_flow_work_order.create_time <= #{flowWorkOrderFilter.createTimeEnd}
|
||||
</if>
|
||||
<if test="flowWorkOrderFilter.createUserId != null">
|
||||
AND zz_flow_work_order.create_user_id = #{flowWorkOrderFilter.createUserId}
|
||||
</if>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="getFlowWorkOrderList" resultMap="BaseResultMap" parameterType="com.orangeforms.common.flow.model.FlowWorkOrder">
|
||||
SELECT * FROM zz_flow_work_order
|
||||
<where>
|
||||
<include refid="filterRef"/>
|
||||
</where>
|
||||
<if test="orderBy != null and orderBy != ''">
|
||||
ORDER BY ${orderBy}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程分类的Dto对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "流程分类的Dto对象")
|
||||
@Data
|
||||
public class FlowCategoryDto {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Schema(description = "主键Id")
|
||||
@NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class})
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 显示名称。
|
||||
*/
|
||||
@Schema(description = "显示名称")
|
||||
@NotBlank(message = "数据验证失败,显示名称不能为空!")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 分类编码。
|
||||
*/
|
||||
@Schema(description = "分类编码")
|
||||
@NotBlank(message = "数据验证失败,分类编码不能为空!")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 实现顺序。
|
||||
*/
|
||||
@Schema(description = "实现顺序")
|
||||
@NotNull(message = "数据验证失败,实现顺序不能为空!")
|
||||
private Integer showOrder;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.orangeforms.common.core.validator.ConstDictRef;
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import com.orangeforms.common.flow.model.constant.FlowBindFormType;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程的Dto对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "流程的Dto对象")
|
||||
@Data
|
||||
public class FlowEntryDto {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Schema(description = "主键Id")
|
||||
@NotNull(message = "数据验证失败,主键不能为空!", groups = {UpdateGroup.class})
|
||||
private Long entryId;
|
||||
|
||||
/**
|
||||
* 流程名称。
|
||||
*/
|
||||
@Schema(description = "流程名称")
|
||||
@NotBlank(message = "数据验证失败,流程名称不能为空!")
|
||||
private String processDefinitionName;
|
||||
|
||||
/**
|
||||
* 流程标识Key。
|
||||
*/
|
||||
@Schema(description = "流程标识Key")
|
||||
@NotBlank(message = "数据验证失败,流程标识Key不能为空!")
|
||||
private String processDefinitionKey;
|
||||
|
||||
/**
|
||||
* 流程分类。
|
||||
*/
|
||||
@Schema(description = "流程分类")
|
||||
@NotNull(message = "数据验证失败,流程分类不能为空!")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 流程状态。
|
||||
*/
|
||||
@Schema(description = "流程状态")
|
||||
@ConstDictRef(constDictClass = FlowEntryStatus.class, message = "数据验证失败,工作流状态为无效值!")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 流程定义的xml。
|
||||
*/
|
||||
@Schema(description = "流程定义的xml")
|
||||
private String bpmnXml;
|
||||
|
||||
/**
|
||||
* 流程图类型。0: 普通流程图,1: 钉钉风格的流程图。
|
||||
*/
|
||||
@Schema(description = "流程图类型。0: 普通流程图,1: 钉钉风格的流程图")
|
||||
private Integer diagramType;
|
||||
|
||||
/**
|
||||
* 绑定表单类型。
|
||||
*/
|
||||
@Schema(description = "绑定表单类型")
|
||||
@ConstDictRef(constDictClass = FlowBindFormType.class, message = "数据验证失败,工作流绑定表单类型为无效值!")
|
||||
@NotNull(message = "数据验证失败,工作流绑定表单类型不能为空!")
|
||||
private Integer bindFormType;
|
||||
|
||||
/**
|
||||
* 在线表单的页面Id。
|
||||
*/
|
||||
@Schema(description = "在线表单的页面Id")
|
||||
private Long pageId;
|
||||
|
||||
/**
|
||||
* 在线表单的缺省路由名称。
|
||||
*/
|
||||
@Schema(description = "在线表单的缺省路由名称")
|
||||
private String defaultRouterName;
|
||||
|
||||
/**
|
||||
* 在线表单Id。
|
||||
*/
|
||||
@Schema(description = "在线表单Id")
|
||||
private Long defaultFormId;
|
||||
|
||||
/**
|
||||
* 工单表编码字段的编码规则,如果为空则不计算工单编码。
|
||||
*/
|
||||
@Schema(description = "工单表编码字段的编码规则")
|
||||
private String encodedRule;
|
||||
|
||||
/**
|
||||
* 流程的自定义扩展数据(JSON格式)。
|
||||
*/
|
||||
@Schema(description = "流程的自定义扩展数据")
|
||||
private String extensionData;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.orangeforms.common.core.validator.ConstDictRef;
|
||||
import com.orangeforms.common.core.validator.UpdateGroup;
|
||||
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 流程变量Dto对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "流程变量Dto对象")
|
||||
@Data
|
||||
public class FlowEntryVariableDto {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Schema(description = "主键Id")
|
||||
@NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class})
|
||||
private Long variableId;
|
||||
|
||||
/**
|
||||
* 流程Id。
|
||||
*/
|
||||
@Schema(description = "流程Id")
|
||||
@NotNull(message = "数据验证失败,流程Id不能为空!")
|
||||
private Long entryId;
|
||||
|
||||
/**
|
||||
* 变量名。
|
||||
*/
|
||||
@Schema(description = "变量名")
|
||||
@NotBlank(message = "数据验证失败,变量名不能为空!")
|
||||
private String variableName;
|
||||
|
||||
/**
|
||||
* 显示名。
|
||||
*/
|
||||
@Schema(description = "显示名")
|
||||
@NotBlank(message = "数据验证失败,显示名不能为空!")
|
||||
private String showName;
|
||||
|
||||
/**
|
||||
* 流程变量类型。
|
||||
*/
|
||||
@Schema(description = "流程变量类型")
|
||||
@ConstDictRef(constDictClass = FlowVariableType.class, message = "数据验证失败,流程变量类型为无效值!")
|
||||
@NotNull(message = "数据验证失败,流程变量类型不能为空!")
|
||||
private Integer variableType;
|
||||
|
||||
/**
|
||||
* 绑定数据源Id。
|
||||
*/
|
||||
@Schema(description = "绑定数据源Id")
|
||||
private Long bindDatasourceId;
|
||||
|
||||
/**
|
||||
* 绑定数据源关联Id。
|
||||
*/
|
||||
@Schema(description = "绑定数据源关联Id")
|
||||
private Long bindRelationId;
|
||||
|
||||
/**
|
||||
* 绑定字段Id。
|
||||
*/
|
||||
@Schema(description = "绑定字段Id")
|
||||
private Long bindColumnId;
|
||||
|
||||
/**
|
||||
* 是否内置。
|
||||
*/
|
||||
@Schema(description = "是否内置")
|
||||
@NotNull(message = "数据验证失败,是否内置不能为空!")
|
||||
private Boolean builtin;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 工作流通知消息Dto对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "工作流通知消息Dto对象")
|
||||
@Data
|
||||
public class FlowMessageDto {
|
||||
|
||||
/**
|
||||
* 消息类型。
|
||||
*/
|
||||
@Schema(description = "消息类型")
|
||||
private Integer messageType;
|
||||
|
||||
/**
|
||||
* 工单Id。
|
||||
*/
|
||||
@Schema(description = "工单Id")
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 流程名称。
|
||||
*/
|
||||
@Schema(description = "流程名称")
|
||||
private String processDefinitionName;
|
||||
|
||||
/**
|
||||
* 流程任务名称。
|
||||
*/
|
||||
@Schema(description = "流程任务名称")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 更新时间范围过滤起始值(>=)。
|
||||
*/
|
||||
@Schema(description = "updateTime 范围过滤起始值")
|
||||
private String updateTimeStart;
|
||||
|
||||
/**
|
||||
* 更新时间范围过滤结束值(<=)。
|
||||
*/
|
||||
@Schema(description = "updateTime 范围过滤结束值")
|
||||
private String updateTimeEnd;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 流程任务的批注。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "流程任务的批注")
|
||||
@Data
|
||||
public class FlowTaskCommentDto {
|
||||
|
||||
/**
|
||||
* 流程任务触发按钮类型,内置值可参考FlowTaskButton。
|
||||
*/
|
||||
@Schema(description = "流程任务触发按钮类型")
|
||||
@NotNull(message = "数据验证失败,任务的审批类型不能为空!")
|
||||
private String approvalType;
|
||||
|
||||
/**
|
||||
* 流程任务的批注内容。
|
||||
*/
|
||||
@Schema(description = "流程任务的批注内容")
|
||||
@NotBlank(message = "数据验证失败,任务审批内容不能为空!")
|
||||
private String taskComment;
|
||||
|
||||
/**
|
||||
* 委托指定人,比如加签、转办等。
|
||||
*/
|
||||
@Schema(description = "委托指定人,比如加签、转办等")
|
||||
private String delegateAssignee;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.orangeforms.common.flow.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 工作流工单Dto对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Schema(description = "工作流工单Dto对象")
|
||||
@Data
|
||||
public class FlowWorkOrderDto {
|
||||
|
||||
/**
|
||||
* 工单编码。
|
||||
*/
|
||||
@Schema(description = "工单编码")
|
||||
private String workOrderCode;
|
||||
|
||||
/**
|
||||
* 流程状态。参考FlowTaskStatus常量值对象。
|
||||
*/
|
||||
@Schema(description = "流程状态")
|
||||
private Integer flowStatus;
|
||||
|
||||
/**
|
||||
* createTime 范围过滤起始值(>=)。
|
||||
*/
|
||||
@Schema(description = "createTime 范围过滤起始值")
|
||||
private String createTimeStart;
|
||||
|
||||
/**
|
||||
* createTime 范围过滤结束值(<=)。
|
||||
*/
|
||||
@Schema(description = "createTime 范围过滤结束值")
|
||||
private String createTimeEnd;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.orangeforms.common.flow.exception;
|
||||
|
||||
import org.flowable.common.engine.api.FlowableException;
|
||||
|
||||
/**
|
||||
* 流程空用户异常。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public class FlowEmptyUserException extends FlowableException {
|
||||
|
||||
/**
|
||||
* 构造函数。
|
||||
*
|
||||
* @param msg 错误信息。
|
||||
*/
|
||||
public FlowEmptyUserException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.orangeforms.common.flow.exception;
|
||||
|
||||
/**
|
||||
* 流程操作异常。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public class FlowOperationException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* 构造函数。
|
||||
*/
|
||||
public FlowOperationException() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数。
|
||||
*
|
||||
* @param throwable 引发异常对象。
|
||||
*/
|
||||
public FlowOperationException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数。
|
||||
*
|
||||
* @param msg 错误信息。
|
||||
*/
|
||||
public FlowOperationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.model.FlowTaskComment;
|
||||
import com.orangeforms.common.flow.model.FlowTaskExt;
|
||||
import com.orangeforms.common.flow.object.FlowTaskOperation;
|
||||
import com.orangeforms.common.flow.service.FlowApiService;
|
||||
import com.orangeforms.common.flow.service.FlowTaskCommentService;
|
||||
import com.orangeforms.common.flow.service.FlowTaskExtService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.ExtensionAttribute;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程任务自动审批跳过的监听器。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class AutoSkipTaskListener implements TaskListener {
|
||||
|
||||
private final transient FlowTaskCommentService flowTaskCommentService =
|
||||
ApplicationContextHolder.getBean(FlowTaskCommentService.class);
|
||||
private final transient FlowApiService flowApiService =
|
||||
ApplicationContextHolder.getBean(FlowApiService.class);
|
||||
private final transient FlowTaskExtService flowTaskExtService =
|
||||
ApplicationContextHolder.getBean(FlowTaskExtService.class);
|
||||
|
||||
/**
|
||||
* 流程的发起者等于当前任务的Assignee。
|
||||
*/
|
||||
private static final String EQ_START_USER = "0";
|
||||
/**
|
||||
* 上一步的提交者等于当前任务的Assignee。
|
||||
*/
|
||||
private static final String EQ_PREV_SUBMIT_USER = "1";
|
||||
/**
|
||||
* 当前任务的Assignee之前提交过审核。
|
||||
*/
|
||||
private static final String EQ_HISTORIC_SUBMIT_USER = "2";
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask t) {
|
||||
UserTask userTask = flowApiService.getUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey());
|
||||
List<ExtensionAttribute> attributes = userTask.getAttributes().get(FlowConstant.USER_TASK_AUTO_SKIP_KEY);
|
||||
Set<String> skipTypes = new HashSet<>(StrUtil.split(attributes.get(0).getValue(), ","));
|
||||
String assignedUser = this.getAssignedUser(userTask, t.getProcessDefinitionId(), t.getExecutionId());
|
||||
if (StrUtil.isBlank(assignedUser)) {
|
||||
return;
|
||||
}
|
||||
for (String skipType : skipTypes) {
|
||||
if (this.verifyAndHandle(userTask, t, skipType, assignedUser)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean verifyAndHandle(UserTask userTask, DelegateTask task, String skipType, String assignedUser) {
|
||||
FlowTaskComment comment = null;
|
||||
switch (skipType) {
|
||||
case EQ_START_USER:
|
||||
Object v = task.getVariable(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR);
|
||||
if (ObjectUtil.equal(v, assignedUser)) {
|
||||
comment = flowTaskCommentService.getFirstFlowTaskComment(task.getProcessInstanceId());
|
||||
}
|
||||
break;
|
||||
case EQ_PREV_SUBMIT_USER:
|
||||
Object v2 = task.getVariable(FlowConstant.SUBMIT_USER_VAR);
|
||||
if (ObjectUtil.equal(v2, assignedUser)) {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
comment = new FlowTaskComment();
|
||||
comment.setCreateUserId(tokenData.getUserId());
|
||||
comment.setCreateLoginName(tokenData.getLoginName());
|
||||
comment.setCreateUsername(tokenData.getShowName());
|
||||
}
|
||||
break;
|
||||
case EQ_HISTORIC_SUBMIT_USER:
|
||||
List<FlowTaskComment> comments =
|
||||
flowTaskCommentService.getFlowTaskCommentList(task.getProcessInstanceId());
|
||||
List<FlowTaskComment> resultComments = new LinkedList<>();
|
||||
for (FlowTaskComment c : comments) {
|
||||
if (StrUtil.equals(c.getCreateLoginName(), assignedUser)) {
|
||||
resultComments.add(c);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(resultComments)) {
|
||||
comment = resultComments.get(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (comment != null) {
|
||||
FlowTaskExt flowTaskExt = flowTaskExtService
|
||||
.getByProcessDefinitionIdAndTaskId(task.getProcessDefinitionId(), userTask.getId());
|
||||
JSONObject taskVariableData = new JSONObject();
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) {
|
||||
List<FlowTaskOperation> taskOperationList =
|
||||
JSONArray.parseArray(flowTaskExt.getOperationListJson(), FlowTaskOperation.class);
|
||||
taskOperationList.stream()
|
||||
.filter(op -> op.getType().equals(FlowApprovalType.AGREE))
|
||||
.map(FlowTaskOperation::getLatestApprovalStatus).findFirst()
|
||||
.ifPresent(status -> taskVariableData.put(FlowConstant.LATEST_APPROVAL_STATUS_KEY, status));
|
||||
}
|
||||
Task t = flowApiService.getTaskById(task.getId());
|
||||
comment.fillWith(t);
|
||||
comment.setApprovalType(FlowApprovalType.AGREE);
|
||||
comment.setTaskComment(StrFormatter.format("自动跳过审批。审批人 [{}], 跳过原因 [{}]。",
|
||||
userTask.getAssignee(), this.getMessageBySkipType(skipType)));
|
||||
flowApiService.completeTask(t, comment, taskVariableData);
|
||||
}
|
||||
return comment != null;
|
||||
}
|
||||
|
||||
private String getAssignedUser(UserTask userTask, String processDefinitionId, String executionId) {
|
||||
String assignedUser = userTask.getAssignee();
|
||||
if (StrUtil.isNotBlank(assignedUser)) {
|
||||
if (assignedUser.startsWith("${") && assignedUser.endsWith("}")) {
|
||||
String variableName = assignedUser.substring(2, assignedUser.length() - 1);
|
||||
assignedUser = flowApiService.getExecutionVariableStringWithSafe(executionId, variableName);
|
||||
}
|
||||
} else {
|
||||
FlowTaskExt flowTaskExt = flowTaskExtService
|
||||
.getByProcessDefinitionIdAndTaskId(processDefinitionId, userTask.getId());
|
||||
List<String> candidateUsernames;
|
||||
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
|
||||
candidateUsernames = Collections.emptyList();
|
||||
} else if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
|
||||
candidateUsernames = StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
|
||||
} else {
|
||||
String value = flowApiService
|
||||
.getExecutionVariableStringWithSafe(executionId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
|
||||
candidateUsernames = value == null ? null : StrUtil.split(value, ",");
|
||||
}
|
||||
if (candidateUsernames != null && candidateUsernames.size() == 1) {
|
||||
assignedUser = candidateUsernames.get(0);
|
||||
}
|
||||
}
|
||||
return assignedUser;
|
||||
}
|
||||
|
||||
private String getMessageBySkipType(String skipType) {
|
||||
return switch (skipType) {
|
||||
case EQ_PREV_SUBMIT_USER -> "审批人与上一审批节点处理人相同";
|
||||
case EQ_START_USER -> "审批人为发起人";
|
||||
case EQ_HISTORIC_SUBMIT_USER -> "审批人审批过";
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 当用户任务的候选组为本部门领导岗位时,该监听器会在任务创建时,获取当前流程实例发起人的部门领导。
|
||||
* 并将其指派为当前任务的候选组。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class DeptPostLeaderListener implements TaskListener {
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
Map<String, Object> variables = delegateTask.getVariables();
|
||||
if (variables.get(FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR) == null) {
|
||||
delegateTask.setAssignee(variables.get(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.orangeforms.common.core.object.GlobalThreadLocal;
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
import com.orangeforms.common.flow.service.FlowWorkOrderService;
|
||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
|
||||
/**
|
||||
* 流程实例监听器,在流程实例结束的时候,需要完成一些自定义的业务行为。如:
|
||||
* 1. 更新流程工单表的审批状态字段。
|
||||
* 2. 业务数据同步。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class FlowFinishedListener implements ExecutionListener {
|
||||
|
||||
private final transient FlowWorkOrderService flowWorkOrderService =
|
||||
ApplicationContextHolder.getBean(FlowWorkOrderService.class);
|
||||
private final transient FlowCustomExtFactory flowCustomExtFactory =
|
||||
ApplicationContextHolder.getBean(FlowCustomExtFactory.class);
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution execution) {
|
||||
if (!StrUtil.equals("end", execution.getEventName())) {
|
||||
return;
|
||||
}
|
||||
boolean enabled = GlobalThreadLocal.setDataFilter(false);
|
||||
try {
|
||||
String processInstanceId = execution.getProcessInstanceId();
|
||||
FlowWorkOrder workOrder = flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(processInstanceId);
|
||||
if (workOrder == null) {
|
||||
return;
|
||||
}
|
||||
int flowStatus = FlowTaskStatus.FINISHED;
|
||||
if (workOrder.getFlowStatus().equals(FlowTaskStatus.CANCELLED)
|
||||
|| workOrder.getFlowStatus().equals(FlowTaskStatus.STOPPED)) {
|
||||
flowStatus = workOrder.getFlowStatus();
|
||||
}
|
||||
workOrder.setFlowStatus(flowStatus);
|
||||
// 更新流程工单中的流程状态。
|
||||
flowWorkOrderService.updateFlowStatusByProcessInstanceId(processInstanceId, flowStatus);
|
||||
// 处理在线表单工作流的自定义状态更新。
|
||||
flowCustomExtFactory.getOnlineBusinessDataExtHelper().updateFlowStatus(workOrder);
|
||||
} finally {
|
||||
GlobalThreadLocal.setDataFilter(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.model.FlowTaskExt;
|
||||
import com.orangeforms.common.flow.object.FlowUserTaskExtData;
|
||||
import com.orangeforms.common.flow.service.FlowApiService;
|
||||
import com.orangeforms.common.flow.service.FlowTaskExtService;
|
||||
import com.orangeforms.common.flow.util.BaseFlowNotifyExtHelper;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.vo.FlowTaskVo;
|
||||
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务进入待办状态时的通知监听器。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class FlowTaskNotifyListener implements TaskListener {
|
||||
|
||||
private final transient FlowTaskExtService flowTaskExtService =
|
||||
ApplicationContextHolder.getBean(FlowTaskExtService.class);
|
||||
private final transient FlowApiService flowApiService =
|
||||
ApplicationContextHolder.getBean(FlowApiService.class);
|
||||
private final transient FlowCustomExtFactory flowCustomExtFactory =
|
||||
ApplicationContextHolder.getBean(FlowCustomExtFactory.class);
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
String definitionId = delegateTask.getProcessDefinitionId();
|
||||
String instanceId = delegateTask.getProcessInstanceId();
|
||||
String taskId = delegateTask.getId();
|
||||
String taskKey = delegateTask.getTaskDefinitionKey();
|
||||
FlowTaskExt taskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(definitionId, taskKey);
|
||||
if (StrUtil.isBlank(taskExt.getExtraDataJson())) {
|
||||
return;
|
||||
}
|
||||
FlowUserTaskExtData extData = JSON.parseObject(taskExt.getExtraDataJson(), FlowUserTaskExtData.class);
|
||||
if (CollUtil.isEmpty(extData.getFlowNotifyTypeList())) {
|
||||
return;
|
||||
}
|
||||
ProcessInstance instance = flowApiService.getProcessInstance(instanceId);
|
||||
Object initiator = flowApiService.getProcessInstanceVariable(instanceId, FlowConstant.PROC_INSTANCE_INITIATOR_VAR);
|
||||
boolean isMultiInstanceTask = flowApiService.isMultiInstanceTask(definitionId, taskKey);
|
||||
Task task = flowApiService.getProcessInstanceActiveTask(instanceId, taskId);
|
||||
List<FlowUserInfoVo> userInfoList =
|
||||
flowTaskExtService.getCandidateUserInfoList(instanceId, taskExt, task, isMultiInstanceTask, false);
|
||||
if (CollUtil.isEmpty(userInfoList)) {
|
||||
log.warn("ProcessDefinition [{}] Task [{}] don't find the candidate users for notification.",
|
||||
instance.getProcessDefinitionName(), task.getName());
|
||||
return;
|
||||
}
|
||||
BaseFlowNotifyExtHelper helper = flowCustomExtFactory.getFlowNotifyExtHelper();
|
||||
Assert.notNull(helper);
|
||||
for (String notifyType : extData.getFlowNotifyTypeList()) {
|
||||
FlowTaskVo flowTaskVo = new FlowTaskVo();
|
||||
flowTaskVo.setProcessDefinitionId(definitionId);
|
||||
flowTaskVo.setProcessInstanceId(instanceId);
|
||||
flowTaskVo.setTaskKey(taskKey);
|
||||
flowTaskVo.setTaskName(delegateTask.getName());
|
||||
flowTaskVo.setTaskId(delegateTask.getId());
|
||||
flowTaskVo.setBusinessKey(instance.getBusinessKey());
|
||||
flowTaskVo.setProcessInstanceInitiator(initiator.toString());
|
||||
helper.doNotify(notifyType, userInfoList, flowTaskVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程任务通用监听器。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class FlowUserTaskListener implements TaskListener {
|
||||
|
||||
private final transient RuntimeService runtimeService =
|
||||
ApplicationContextHolder.getBean(RuntimeService.class);
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
Map<String, Object> variables = delegateTask.getVariables();
|
||||
if (variables.get(FlowConstant.DELEGATE_ASSIGNEE_VAR) != null) {
|
||||
delegateTask.setAssignee(variables.get(FlowConstant.DELEGATE_ASSIGNEE_VAR).toString());
|
||||
runtimeService.removeVariableLocal(delegateTask.getExecutionId(), FlowConstant.DELEGATE_ASSIGNEE_VAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 当用户任务的候选组为上级部门领导岗位时,该监听器会在任务创建时,获取当前流程实例发起人的部门领导。
|
||||
* 并将其指派为当前任务的候选组。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class UpDeptPostLeaderListener implements TaskListener {
|
||||
|
||||
@Override
|
||||
public void notify(DelegateTask delegateTask) {
|
||||
Map<String, Object> variables = delegateTask.getVariables();
|
||||
if (variables.get(FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR) == null) {
|
||||
delegateTask.setAssignee(variables.get(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.orangeforms.common.flow.listener;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.orangeforms.common.core.util.ApplicationContextHolder;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
import com.orangeforms.common.flow.service.FlowWorkOrderService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.delegate.DelegateExecution;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
import org.flowable.engine.impl.el.FixedValue;
|
||||
|
||||
/**
|
||||
* 更新流程的最后审批状态的监听器,目前用于排他网关到任务结束节点的连线上,
|
||||
* 以便于准确的判断流程实例的最后审批状态。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
public class UpdateLatestApprovalStatusListener implements ExecutionListener {
|
||||
|
||||
private FixedValue latestApprovalStatus;
|
||||
|
||||
private final transient FlowWorkOrderService flowWorkOrderService =
|
||||
ApplicationContextHolder.getBean(FlowWorkOrderService.class);
|
||||
|
||||
public void setAutoStoreVariablesExp(FixedValue approvalStatus) {
|
||||
this.latestApprovalStatus = approvalStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(DelegateExecution execution) {
|
||||
if (StrUtil.isNotBlank(latestApprovalStatus.getExpressionText())) {
|
||||
FlowWorkOrder workOrder =
|
||||
flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(execution.getProcessInstanceId());
|
||||
if (workOrder == null) {
|
||||
return;
|
||||
}
|
||||
Integer approvalStatus = Integer.valueOf(latestApprovalStatus.getExpressionText());
|
||||
String processInstanceId = execution.getProcessInstanceId();
|
||||
flowWorkOrderService.updateLatestApprovalStatusByProcessInstanceId(processInstanceId, approvalStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程分类的实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_category")
|
||||
public class FlowCategory {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "category_id")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 租户Id。
|
||||
*/
|
||||
@Column(value = "tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@Column(value = "app_code")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 显示名称。
|
||||
*/
|
||||
@Column(value = "name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 分类编码。
|
||||
*/
|
||||
@Column(value = "code")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 实现顺序。
|
||||
*/
|
||||
@Column(value = "show_order")
|
||||
private Integer showOrder;
|
||||
|
||||
/**
|
||||
* 更新时间。
|
||||
*/
|
||||
@Column(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新者Id。
|
||||
*/
|
||||
@Column(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import com.orangeforms.common.core.annotation.RelationOneToOne;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程的实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_entry")
|
||||
public class FlowEntry {
|
||||
|
||||
/**
|
||||
* 主键。
|
||||
*/
|
||||
@Id(value = "entry_id")
|
||||
private Long entryId;
|
||||
|
||||
/**
|
||||
* 租户Id。
|
||||
*/
|
||||
@Column(value = "tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@Column(value = "app_code")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 流程名称。
|
||||
*/
|
||||
@Column(value = "process_definition_name")
|
||||
private String processDefinitionName;
|
||||
|
||||
/**
|
||||
* 流程标识Key。
|
||||
*/
|
||||
@Column(value = "process_definition_key")
|
||||
private String processDefinitionKey;
|
||||
|
||||
/**
|
||||
* 流程分类。
|
||||
*/
|
||||
@Column(value = "category_id")
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 工作流部署的发布主版本Id。
|
||||
*/
|
||||
@Column(value = "main_entry_publish_id")
|
||||
private Long mainEntryPublishId;
|
||||
|
||||
/**
|
||||
* 最新发布时间。
|
||||
*/
|
||||
@Column(value = "latest_publish_time")
|
||||
private Date latestPublishTime;
|
||||
|
||||
/**
|
||||
* 流程状态。
|
||||
*/
|
||||
@Column(value = "status")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 流程定义的xml。
|
||||
*/
|
||||
@Column(value = "bpmn_xml")
|
||||
private String bpmnXml;
|
||||
|
||||
/**
|
||||
* 流程图类型。0: 普通流程图,1: 钉钉风格的流程图。
|
||||
*/
|
||||
@Column(value = "diagram_type")
|
||||
private Integer diagramType;
|
||||
|
||||
/**
|
||||
* 绑定表单类型。
|
||||
*/
|
||||
@Column(value = "bind_form_type")
|
||||
private Integer bindFormType;
|
||||
|
||||
/**
|
||||
* 在线表单的页面Id。
|
||||
*/
|
||||
@Column(value = "page_id")
|
||||
private Long pageId;
|
||||
|
||||
/**
|
||||
* 在线表单Id。
|
||||
*/
|
||||
@Column(value = "default_form_id")
|
||||
private Long defaultFormId;
|
||||
|
||||
/**
|
||||
* 静态表单的缺省路由名称。
|
||||
*/
|
||||
@Column(value = "default_router_name")
|
||||
private String defaultRouterName;
|
||||
|
||||
/**
|
||||
* 工单表编码字段的编码规则,如果为空则不计算工单编码。
|
||||
*/
|
||||
@Column(value = "encoded_rule")
|
||||
private String encodedRule;
|
||||
|
||||
/**
|
||||
* 流程的自定义扩展数据(JSON格式)。
|
||||
*/
|
||||
@Column(value = "extension_data")
|
||||
private String extensionData;
|
||||
|
||||
/**
|
||||
* 更新时间。
|
||||
*/
|
||||
@Column(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新者Id。
|
||||
*/
|
||||
@Column(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
@Column(ignore = true)
|
||||
private FlowEntryPublish mainFlowEntryPublish;
|
||||
|
||||
@RelationOneToOne(
|
||||
masterIdField = "categoryId",
|
||||
slaveModelClass = FlowCategory.class,
|
||||
slaveIdField = "categoryId")
|
||||
@Column(ignore = true)
|
||||
private FlowCategory flowCategory;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程发布数据的实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_entry_publish")
|
||||
public class FlowEntryPublish {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "entry_publish_id")
|
||||
private Long entryPublishId;
|
||||
|
||||
/**
|
||||
* 流程Id。
|
||||
*/
|
||||
@Column(value = "entry_id")
|
||||
private Long entryId;
|
||||
|
||||
/**
|
||||
* 流程引擎的部署Id。
|
||||
*/
|
||||
@Column(value = "deploy_id")
|
||||
private String deployId;
|
||||
|
||||
/**
|
||||
* 流程引擎中的流程定义Id。
|
||||
*/
|
||||
@Column(value = "process_definition_id")
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 发布版本。
|
||||
*/
|
||||
@Column(value = "publish_version")
|
||||
private Integer publishVersion;
|
||||
|
||||
/**
|
||||
* 激活状态。
|
||||
*/
|
||||
@Column(value = "active_status")
|
||||
private Boolean activeStatus;
|
||||
|
||||
/**
|
||||
* 是否为主版本。
|
||||
*/
|
||||
@Column(value = "main_version")
|
||||
private Boolean mainVersion;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 发布时间。
|
||||
*/
|
||||
@Column(value = "publish_time")
|
||||
private Date publishTime;
|
||||
|
||||
/**
|
||||
* 第一个非开始节点任务的附加信息。
|
||||
*/
|
||||
@Column(value = "init_task_info")
|
||||
private String initTaskInfo;
|
||||
|
||||
/**
|
||||
* 分析后的节点JSON信息。
|
||||
*/
|
||||
@Column(value = "analyzed_node_json")
|
||||
private String analyzedNodeJson;
|
||||
|
||||
/**
|
||||
* 流程的自定义扩展数据(JSON格式)。
|
||||
*/
|
||||
@Column(value = "extension_data")
|
||||
private String extensionData;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* FlowEntryPublishVariable实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_entry_publish_variable")
|
||||
public class FlowEntryPublishVariable {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "variable_id")
|
||||
private Long variableId;
|
||||
|
||||
/**
|
||||
* 流程Id。
|
||||
*/
|
||||
@Column(value = "entry_publish_id")
|
||||
private Long entryPublishId;
|
||||
|
||||
/**
|
||||
* 变量名。
|
||||
*/
|
||||
@Column(value = "variable_name")
|
||||
private String variableName;
|
||||
|
||||
/**
|
||||
* 显示名。
|
||||
*/
|
||||
@Column(value = "show_name")
|
||||
private String showName;
|
||||
|
||||
/**
|
||||
* 变量类型。
|
||||
*/
|
||||
@Column(value = "variable_type")
|
||||
private Integer variableType;
|
||||
|
||||
/**
|
||||
* 是否内置。
|
||||
*/
|
||||
@Column(value = "builtin")
|
||||
private Boolean builtin;
|
||||
|
||||
/**
|
||||
* 绑定数据源Id。
|
||||
*/
|
||||
@Column(value = "bind_datasource_id")
|
||||
private Long bindDatasourceId;
|
||||
|
||||
/**
|
||||
* 绑定数据源关联Id。
|
||||
*/
|
||||
@Column(value = "bind_relation_id")
|
||||
private Long bindRelationId;
|
||||
|
||||
/**
|
||||
* 绑定字段Id。
|
||||
*/
|
||||
@Column(value = "bind_column_id")
|
||||
private Long bindColumnId;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程变量实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_entry_variable")
|
||||
public class FlowEntryVariable {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "variable_id")
|
||||
private Long variableId;
|
||||
|
||||
/**
|
||||
* 流程Id。
|
||||
*/
|
||||
@Column(value = "entry_id")
|
||||
private Long entryId;
|
||||
|
||||
/**
|
||||
* 变量名。
|
||||
*/
|
||||
@Column(value = "variable_name")
|
||||
private String variableName;
|
||||
|
||||
/**
|
||||
* 显示名。
|
||||
*/
|
||||
@Column(value = "show_name")
|
||||
private String showName;
|
||||
|
||||
/**
|
||||
* 流程变量类型。
|
||||
*/
|
||||
@Column(value = "variable_type")
|
||||
private Integer variableType;
|
||||
|
||||
/**
|
||||
* 绑定数据源Id。
|
||||
*/
|
||||
@Column(value = "bind_datasource_id")
|
||||
private Long bindDatasourceId;
|
||||
|
||||
/**
|
||||
* 绑定数据源关联Id。
|
||||
*/
|
||||
@Column(value = "bind_relation_id")
|
||||
private Long bindRelationId;
|
||||
|
||||
/**
|
||||
* 绑定字段Id。
|
||||
*/
|
||||
@Column(value = "bind_column_id")
|
||||
private Long bindColumnId;
|
||||
|
||||
/**
|
||||
* 是否内置。
|
||||
*/
|
||||
@Column(value = "builtin")
|
||||
private Boolean builtin;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 工作流通知消息实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_message")
|
||||
public class FlowMessage {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "message_id")
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 租户Id。
|
||||
*/
|
||||
@Column(value = "tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@Column(value = "app_code")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 消息类型。
|
||||
*/
|
||||
@Column(value = "message_type")
|
||||
private Integer messageType;
|
||||
|
||||
/**
|
||||
* 消息内容。
|
||||
*/
|
||||
@Column(value = "message_content")
|
||||
private String messageContent;
|
||||
|
||||
/**
|
||||
* 催办次数。
|
||||
*/
|
||||
@Column(value = "remind_count")
|
||||
private Integer remindCount;
|
||||
|
||||
/**
|
||||
* 工单Id。
|
||||
*/
|
||||
@Column(value = "work_order_id")
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 流程定义Id。
|
||||
*/
|
||||
@Column(value = "process_definition_id")
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 流程定义标识。
|
||||
*/
|
||||
@Column(value = "process_definition_key")
|
||||
private String processDefinitionKey;
|
||||
|
||||
/**
|
||||
* 流程名称。
|
||||
*/
|
||||
@Column(value = "process_definition_name")
|
||||
private String processDefinitionName;
|
||||
|
||||
/**
|
||||
* 流程实例Id。
|
||||
*/
|
||||
@Column(value = "process_instance_id")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 流程实例发起者。
|
||||
*/
|
||||
@Column(value = "process_instance_initiator")
|
||||
private String processInstanceInitiator;
|
||||
|
||||
/**
|
||||
* 流程任务Id。
|
||||
*/
|
||||
@Column(value = "task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 流程任务定义标识。
|
||||
*/
|
||||
@Column(value = "task_definition_key")
|
||||
private String taskDefinitionKey;
|
||||
|
||||
/**
|
||||
* 流程任务名称。
|
||||
*/
|
||||
@Column(value = "task_name")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "task_start_time")
|
||||
private Date taskStartTime;
|
||||
|
||||
/**
|
||||
* 任务指派人登录名。
|
||||
*/
|
||||
@Column(value = "task_assignee")
|
||||
private String taskAssignee;
|
||||
|
||||
/**
|
||||
* 任务是否已完成。
|
||||
*/
|
||||
@Column(value = "task_finished")
|
||||
private Boolean taskFinished;
|
||||
|
||||
/**
|
||||
* 业务数据快照。
|
||||
*/
|
||||
@Column(value = "business_data_shot")
|
||||
private String businessDataShot;
|
||||
|
||||
/**
|
||||
* 是否为在线表单消息数据。
|
||||
*/
|
||||
@Column(value = "online_form_data")
|
||||
private Boolean onlineFormData;
|
||||
|
||||
/**
|
||||
* 更新时间。
|
||||
*/
|
||||
@Column(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新者Id。
|
||||
*/
|
||||
@Column(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 创建者显示名。
|
||||
*/
|
||||
@Column(value = "create_username")
|
||||
private String createUsername;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程任务消息的候选身份实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_msg_candidate_identity")
|
||||
public class FlowMessageCandidateIdentity {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 任务消息Id。
|
||||
*/
|
||||
@Column(value = "message_id")
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 候选身份类型。
|
||||
*/
|
||||
@Column(value = "candidate_type")
|
||||
private String candidateType;
|
||||
|
||||
/**
|
||||
* 候选身份Id。
|
||||
*/
|
||||
@Column(value = "candidate_id")
|
||||
private String candidateId;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程任务消息所属用户的操作表。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_msg_identity_operation")
|
||||
public class FlowMessageIdentityOperation {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 任务消息Id。
|
||||
*/
|
||||
@Column(value = "message_id")
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 用户登录名。
|
||||
*/
|
||||
@Column(value = "login_name")
|
||||
private String loginName;
|
||||
|
||||
/**
|
||||
* 操作类型。
|
||||
* 常量值参考FlowMessageOperationType对象。
|
||||
*/
|
||||
@Column(value = "operation_type")
|
||||
private Integer operationType;
|
||||
|
||||
/**
|
||||
* 操作时间。
|
||||
*/
|
||||
@Column(value = "operation_time")
|
||||
private Date operationTime;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程多实例任务执行流水对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Table(value = "zz_flow_multi_instance_trans")
|
||||
public class FlowMultiInstanceTrans {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 流程实例Id。
|
||||
*/
|
||||
@Column(value = "process_instance_id")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 任务Id。
|
||||
*/
|
||||
@Column(value = "task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 任务标识。
|
||||
*/
|
||||
@Column(value = "task_key")
|
||||
private String taskKey;
|
||||
|
||||
/**
|
||||
* 会签任务的执行Id。
|
||||
*/
|
||||
@Column(value = "multi_instance_exec_id")
|
||||
private String multiInstanceExecId;
|
||||
|
||||
/**
|
||||
* 任务的执行Id。
|
||||
*/
|
||||
@Column(value = "execution_id")
|
||||
private String executionId;
|
||||
|
||||
/**
|
||||
* 会签指派人列表。
|
||||
*/
|
||||
@Column(value = "assignee_list")
|
||||
private String assigneeList;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 创建者登录名。
|
||||
*/
|
||||
@Column(value = "create_login_name")
|
||||
private String createLoginName;
|
||||
|
||||
/**
|
||||
* 创建者显示名。
|
||||
*/
|
||||
@Column(value = "create_username")
|
||||
private String createUsername;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
public FlowMultiInstanceTrans(TaskInfo task) {
|
||||
this.fillWith(task);
|
||||
}
|
||||
|
||||
public void fillWith(TaskInfo task) {
|
||||
this.taskId = task.getId();
|
||||
this.taskKey = task.getTaskDefinitionKey();
|
||||
this.processInstanceId = task.getProcessInstanceId();
|
||||
this.executionId = task.getExecutionId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import com.orangeforms.common.core.util.ContextUtil;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* FlowTaskComment实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Table(value = "zz_flow_task_comment")
|
||||
public class FlowTaskComment {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 流程实例Id。
|
||||
*/
|
||||
@Column(value = "process_instance_id")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 任务Id。
|
||||
*/
|
||||
@Column(value = "task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 任务标识。
|
||||
*/
|
||||
@Column(value = "task_key")
|
||||
private String taskKey;
|
||||
|
||||
/**
|
||||
* 任务名称。
|
||||
*/
|
||||
@Column(value = "task_name")
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 用于驳回和自由跳的目标任务标识。
|
||||
*/
|
||||
@Column(value = "target_task_key")
|
||||
private String targetTaskKey;
|
||||
|
||||
/**
|
||||
* 任务的执行Id。
|
||||
*/
|
||||
@Column(value = "execution_id")
|
||||
private String executionId;
|
||||
|
||||
/**
|
||||
* 会签任务的执行Id。
|
||||
*/
|
||||
@Column(value = "multi_instance_exec_id")
|
||||
private String multiInstanceExecId;
|
||||
|
||||
/**
|
||||
* 审批类型。
|
||||
*/
|
||||
@Column(value = "approval_type")
|
||||
private String approvalType;
|
||||
|
||||
/**
|
||||
* 批注内容。
|
||||
*/
|
||||
@Column(value = "task_comment")
|
||||
private String taskComment;
|
||||
|
||||
/**
|
||||
* 委托指定人,比如加签、转办等。
|
||||
*/
|
||||
@Column(value = "delegate_assignee")
|
||||
private String delegateAssignee;
|
||||
|
||||
/**
|
||||
* 自定义数据。开发者可自行扩展,推荐使用JSON格式数据。
|
||||
*/
|
||||
@Column(value = "custom_business_data")
|
||||
private String customBusinessData;
|
||||
|
||||
/**
|
||||
* 审批人头像。
|
||||
*/
|
||||
@Column(value = "head_image_url")
|
||||
private String headImageUrl;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 创建者登录名。
|
||||
*/
|
||||
@Column(value = "create_login_name")
|
||||
private String createLoginName;
|
||||
|
||||
/**
|
||||
* 创建者显示名。
|
||||
*/
|
||||
@Column(value = "create_username")
|
||||
private String createUsername;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
private static final String REQ_ATTRIBUTE_KEY = "flowTaskComment";
|
||||
|
||||
public FlowTaskComment(TaskInfo task) {
|
||||
this.fillWith(task);
|
||||
}
|
||||
|
||||
public static void setToRequest(FlowTaskComment comment) {
|
||||
if (ContextUtil.getHttpRequest() != null) {
|
||||
ContextUtil.getHttpRequest().setAttribute(REQ_ATTRIBUTE_KEY, comment);
|
||||
}
|
||||
}
|
||||
|
||||
public static FlowTaskComment getFromRequest() {
|
||||
if (ContextUtil.getHttpRequest() == null) {
|
||||
return null;
|
||||
}
|
||||
return (FlowTaskComment) ContextUtil.getHttpRequest().getAttribute(REQ_ATTRIBUTE_KEY);
|
||||
}
|
||||
|
||||
public void fillWith(TaskInfo task) {
|
||||
this.taskId = task.getId();
|
||||
this.taskKey = task.getTaskDefinitionKey();
|
||||
this.taskName = task.getName();
|
||||
this.processInstanceId = task.getProcessInstanceId();
|
||||
this.executionId = task.getExecutionId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程任务扩展实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_task_ext")
|
||||
public class FlowTaskExt {
|
||||
|
||||
/**
|
||||
* 流程引擎的定义Id。
|
||||
*/
|
||||
@Column(value = "process_definition_id")
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 流程引擎任务Id。
|
||||
*/
|
||||
@Column(value = "task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 操作列表JSON。
|
||||
*/
|
||||
@Column(value = "operation_list_json")
|
||||
private String operationListJson;
|
||||
|
||||
/**
|
||||
* 变量列表JSON。
|
||||
*/
|
||||
@Column(value = "variable_list_json")
|
||||
private String variableListJson;
|
||||
|
||||
/**
|
||||
* 存储多实例的assigneeList的JSON。
|
||||
*/
|
||||
@Column(value = "assignee_list_json")
|
||||
private String assigneeListJson;
|
||||
|
||||
/**
|
||||
* 分组类型。
|
||||
*/
|
||||
@Column(value = "group_type")
|
||||
private String groupType;
|
||||
|
||||
/**
|
||||
* 保存岗位相关的数据。
|
||||
*/
|
||||
@Column(value = "dept_post_list_json")
|
||||
private String deptPostListJson;
|
||||
|
||||
/**
|
||||
* 逗号分隔的角色Id。
|
||||
*/
|
||||
@Column(value = "role_ids")
|
||||
private String roleIds;
|
||||
|
||||
/**
|
||||
* 逗号分隔的部门Id。
|
||||
*/
|
||||
@Column(value = "dept_ids")
|
||||
private String deptIds;
|
||||
|
||||
/**
|
||||
* 逗号分隔候选用户名。
|
||||
*/
|
||||
@Column(value = "candidate_usernames")
|
||||
private String candidateUsernames;
|
||||
|
||||
/**
|
||||
* 抄送相关的数据。
|
||||
*/
|
||||
@Column(value = "copy_list_json")
|
||||
private String copyListJson;
|
||||
|
||||
/**
|
||||
* 用户任务的扩展属性,存储为JSON的字符串格式。
|
||||
*/
|
||||
@Column(value = "extra_data_json")
|
||||
private String extraDataJson;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import com.orangeforms.common.core.annotation.DeptFilterColumn;
|
||||
import com.orangeforms.common.core.annotation.UserFilterColumn;
|
||||
import com.orangeforms.common.core.annotation.RelationConstDict;
|
||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流工单实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_work_order")
|
||||
public class FlowWorkOrder {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "work_order_id")
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 租户Id。
|
||||
*/
|
||||
@Column(value = "tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 应用编码。为空时,表示非第三方应用接入。
|
||||
*/
|
||||
@Column(value = "app_code")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 工单编码字段。
|
||||
*/
|
||||
@Column(value = "work_order_code")
|
||||
private String workOrderCode;
|
||||
|
||||
/**
|
||||
* 流程定义标识。
|
||||
*/
|
||||
@Column(value = "process_definition_key")
|
||||
private String processDefinitionKey;
|
||||
|
||||
/**
|
||||
* 流程名称。
|
||||
*/
|
||||
@Column(value = "process_definition_name")
|
||||
private String processDefinitionName;
|
||||
|
||||
/**
|
||||
* 流程引擎的定义Id。
|
||||
*/
|
||||
@Column(value = "process_definition_id")
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 流程实例Id。
|
||||
*/
|
||||
@Column(value = "process_instance_id")
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 在线表单的主表Id。
|
||||
*/
|
||||
@Column(value = "online_table_id")
|
||||
private Long onlineTableId;
|
||||
|
||||
/**
|
||||
* 静态表单所使用的数据表名。
|
||||
*/
|
||||
@Column(value = "table_name")
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 业务主键值。
|
||||
*/
|
||||
@Column(value = "business_key")
|
||||
private String businessKey;
|
||||
|
||||
/**
|
||||
* 最近的审批状态。
|
||||
*/
|
||||
@Column(value = "latest_approval_status")
|
||||
private Integer latestApprovalStatus;
|
||||
|
||||
/**
|
||||
* 流程状态。参考FlowTaskStatus常量值对象。
|
||||
*/
|
||||
@Column(value = "flow_status")
|
||||
private Integer flowStatus;
|
||||
|
||||
/**
|
||||
* 提交用户登录名称。
|
||||
*/
|
||||
@Column(value = "submit_username")
|
||||
private String submitUsername;
|
||||
|
||||
/**
|
||||
* 提交用户所在部门Id。
|
||||
*/
|
||||
@DeptFilterColumn
|
||||
@Column(value = "dept_id")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 更新时间。
|
||||
*/
|
||||
@Column(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新者Id。
|
||||
*/
|
||||
@Column(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@UserFilterColumn
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
|
||||
*/
|
||||
@Column(value = "deleted_flag", isLogicDelete = true)
|
||||
private Integer deletedFlag;
|
||||
|
||||
/**
|
||||
* createTime 范围过滤起始值(>=)。
|
||||
*/
|
||||
@Column(ignore = true)
|
||||
private String createTimeStart;
|
||||
|
||||
/**
|
||||
* createTime 范围过滤结束值(<=)。
|
||||
*/
|
||||
@Column(ignore = true)
|
||||
private String createTimeEnd;
|
||||
|
||||
@RelationConstDict(
|
||||
masterIdField = "flowStatus",
|
||||
constantDictClass = FlowTaskStatus.class)
|
||||
@Column(ignore = true)
|
||||
private Map<String, Object> flowStatusDictMap;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.orangeforms.common.flow.model;
|
||||
|
||||
import com.mybatisflex.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 工作流工单扩展数据实体对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
@Table(value = "zz_flow_work_order_ext")
|
||||
public class FlowWorkOrderExt {
|
||||
|
||||
/**
|
||||
* 主键Id。
|
||||
*/
|
||||
@Id(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 流程工单Id。
|
||||
*/
|
||||
@Column(value = "work_order_id")
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 草稿数据。
|
||||
*/
|
||||
@Column(value = "draft_data")
|
||||
private String draftData;
|
||||
|
||||
/**
|
||||
* 业务数据。
|
||||
*/
|
||||
@Column(value = "business_data")
|
||||
private String businessData;
|
||||
|
||||
/**
|
||||
* 更新时间。
|
||||
*/
|
||||
@Column(value = "update_time")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新者Id。
|
||||
*/
|
||||
@Column(value = "update_user_id")
|
||||
private Long updateUserId;
|
||||
|
||||
/**
|
||||
* 创建时间。
|
||||
*/
|
||||
@Column(value = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建者Id。
|
||||
*/
|
||||
@Column(value = "create_user_id")
|
||||
private Long createUserId;
|
||||
|
||||
/**
|
||||
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
|
||||
*/
|
||||
@Column(value = "deleted_flag", isLogicDelete = true)
|
||||
private Integer deletedFlag;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.orangeforms.common.flow.model.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流绑定表单类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowBindFormType {
|
||||
|
||||
/**
|
||||
* 在线表单。
|
||||
*/
|
||||
public static final int ONLINE_FORM = 0;
|
||||
/**
|
||||
* 路由表单。
|
||||
*/
|
||||
public static final int ROUTER_FORM = 1;
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(ONLINE_FORM, "在线表单");
|
||||
DICT_MAP.put(ROUTER_FORM, "路由表单");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否为当前常量字典的合法值。
|
||||
*
|
||||
* @param value 待验证的参数值。
|
||||
* @return 合法返回true,否则false。
|
||||
*/
|
||||
public static boolean isValid(Integer value) {
|
||||
return value != null && DICT_MAP.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowBindFormType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.orangeforms.common.flow.model.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流状态。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowEntryStatus {
|
||||
|
||||
/**
|
||||
* 未发布。
|
||||
*/
|
||||
public static final int UNPUBLISHED = 0;
|
||||
/**
|
||||
* 已发布。
|
||||
*/
|
||||
public static final int PUBLISHED = 1;
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(UNPUBLISHED, "未发布");
|
||||
DICT_MAP.put(PUBLISHED, "已发布");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否为当前常量字典的合法值。
|
||||
*
|
||||
* @param value 待验证的参数值。
|
||||
* @return 合法返回true,否则false。
|
||||
*/
|
||||
public static boolean isValid(Integer value) {
|
||||
return value != null && DICT_MAP.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowEntryStatus() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.orangeforms.common.flow.model.constant;
|
||||
|
||||
/**
|
||||
* 工作流消息操作类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowMessageOperationType {
|
||||
|
||||
/**
|
||||
* 已读操作。
|
||||
*/
|
||||
public static final int READ_FINISHED = 0;
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowMessageOperationType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.orangeforms.common.flow.model.constant;
|
||||
|
||||
/**
|
||||
* 工作流消息类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowMessageType {
|
||||
|
||||
/**
|
||||
* 催办消息。
|
||||
*/
|
||||
public static final int REMIND_TYPE = 0;
|
||||
|
||||
/**
|
||||
* 抄送消息。
|
||||
*/
|
||||
public static final int COPY_TYPE = 1;
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowMessageType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.orangeforms.common.flow.model.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程变量类型。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public final class FlowVariableType {
|
||||
|
||||
/**
|
||||
* 流程实例变量。
|
||||
*/
|
||||
public static final int INSTANCE = 0;
|
||||
/**
|
||||
* 任务变量。
|
||||
*/
|
||||
public static final int TASK = 1;
|
||||
|
||||
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
|
||||
static {
|
||||
DICT_MAP.put(INSTANCE, "流程实例变量");
|
||||
DICT_MAP.put(TASK, "任务变量");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断参数是否为当前常量字典的合法值。
|
||||
*
|
||||
* @param value 待验证的参数值。
|
||||
* @return 合法返回true,否则false。
|
||||
*/
|
||||
public static boolean isValid(Integer value) {
|
||||
return value != null && DICT_MAP.containsKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 私有构造函数,明确标识该常量类的作用。
|
||||
*/
|
||||
private FlowVariableType() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程任务的扩展属性。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowElementExtProperty {
|
||||
|
||||
/**
|
||||
* 最近的审批状态,该值目前仅仅用于流程线元素,即SequenceElement。
|
||||
*/
|
||||
private Integer latestApprovalStatus;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程扩展数据对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowEntryExtensionData {
|
||||
|
||||
/**
|
||||
* 通知类型。
|
||||
*/
|
||||
private List<String> notifyTypes;
|
||||
/**
|
||||
* 流程审批状态字典数据列表。Map的key是id和name。
|
||||
*/
|
||||
private List<Map<String, String>> approvalStatusDict;
|
||||
/**
|
||||
* 级联删除业务数据。
|
||||
*/
|
||||
private Boolean cascadeDeleteBusinessData = false;
|
||||
/**
|
||||
* 是否支持流程复活。
|
||||
*/
|
||||
private Boolean supportRevive = false;
|
||||
/**
|
||||
* 复活数据保留天数。0表示永久保留。
|
||||
*/
|
||||
private Integer keptReviveDays = 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
|
||||
/**
|
||||
* 工作流运行时常用对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowRumtimeObject {
|
||||
|
||||
/**
|
||||
* 运行时流程实例对象。
|
||||
*/
|
||||
private ProcessInstance instance;
|
||||
/**
|
||||
* 运行时流程任务对象。
|
||||
*/
|
||||
private Task task;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 表示多实例任务的指派人信息。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowTaskMultiSignAssign {
|
||||
|
||||
/**
|
||||
* 指派人类型。参考常量类 UserFilterGroup。
|
||||
*/
|
||||
private String assigneeType;
|
||||
/**
|
||||
* 逗号分隔的指派人列表。
|
||||
*/
|
||||
private String assigneeList;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程图中的用户任务操作数据。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowTaskOperation {
|
||||
|
||||
/**
|
||||
* 操作Id。
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 操作的标签名。
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* 操作类型。
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 显示顺序。
|
||||
*/
|
||||
private Integer showOrder;
|
||||
/**
|
||||
* 最后审批状态。
|
||||
*/
|
||||
private Integer latestApprovalStatus;
|
||||
/**
|
||||
* 在流程图中定义的多实例会签的指定人员信息。
|
||||
*/
|
||||
private FlowTaskMultiSignAssign multiSignAssignee;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程任务岗位候选组数据。仅用于流程任务的候选组类型为岗位时。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowTaskPostCandidateGroup {
|
||||
|
||||
/**
|
||||
* 唯一值,目前仅前端使用。
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 岗位类型。
|
||||
* 1. 所有部门岗位审批变量,值为 (allDeptPost)。
|
||||
* 2. 本部门岗位审批变量,值为 (selfDeptPost)。
|
||||
* 3. 上级部门岗位审批变量,值为 (upDeptPost)。
|
||||
* 4. 任意部门关联的岗位审批变量,值为 (deptPost)。
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 岗位Id。type为(1,2,3)时使用该值。
|
||||
*/
|
||||
private String postId;
|
||||
/**
|
||||
* 部门岗位Id。type为(4)时使用该值。
|
||||
*/
|
||||
private String deptPostId;
|
||||
|
||||
public static List<String> buildCandidateGroupList(List<FlowTaskPostCandidateGroup> groupDataList) {
|
||||
List<String> candidateGroupList = new LinkedList<>();
|
||||
for (FlowTaskPostCandidateGroup groupData : groupDataList) {
|
||||
switch (groupData.getType()) {
|
||||
case FlowConstant.GROUP_TYPE_ALL_DEPT_POST_VAR:
|
||||
candidateGroupList.add(groupData.getPostId());
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_DEPT_POST_VAR:
|
||||
candidateGroupList.add(groupData.getDeptPostId());
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_SELF_DEPT_POST_VAR:
|
||||
candidateGroupList.add("${" + FlowConstant.SELF_DEPT_POST_PREFIX + groupData.getPostId() + "}");
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_SIBLING_DEPT_POST_VAR:
|
||||
candidateGroupList.add("${" + FlowConstant.SIBLING_DEPT_POST_PREFIX + groupData.getPostId() + "}");
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_UP_DEPT_POST_VAR:
|
||||
candidateGroupList.add("${" + FlowConstant.UP_DEPT_POST_PREFIX + groupData.getPostId() + "}");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return candidateGroupList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.orangeforms.common.flow.object;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程用户任务扩展数据对象。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Data
|
||||
public class FlowUserTaskExtData {
|
||||
|
||||
public static final String NOTIFY_TYPE_MSG = "message";
|
||||
public static final String NOTIFY_TYPE_EMAIL = "email";
|
||||
|
||||
public static final String TIMEOUT_AUTO_COMPLETE = "autoComplete";
|
||||
public static final String TIMEOUT_SEND_MSG = "sendMessage";
|
||||
|
||||
public static final String EMPTY_USER_TO_ASSIGNEE = "toAssignee";
|
||||
public static final String EMPTY_USER_AUTO_REJECT = "autoReject";
|
||||
public static final String EMPTY_USER_AUTO_COMPLETE = "autoComplete";
|
||||
|
||||
/**
|
||||
* 拒绝后再提交,走重新审批。
|
||||
*/
|
||||
public static final String REJECT_TYPE_REDO = "0";
|
||||
/**
|
||||
* 拒绝后再提交,直接回到驳回前的节点。
|
||||
*/
|
||||
public static final String REJECT_TYPE_BACK_TO_SOURCE = "1";
|
||||
|
||||
/**
|
||||
* 任务通知类型列表。
|
||||
*/
|
||||
private List<String> flowNotifyTypeList;
|
||||
/**
|
||||
* 拒绝后再次提交的审批类型。
|
||||
*/
|
||||
private String rejectType = REJECT_TYPE_REDO;
|
||||
/**
|
||||
* 到期提醒的小时数(从待办任务被创建的时候开始计算)。
|
||||
*/
|
||||
private Integer timeoutHours;
|
||||
/**
|
||||
* 任务超时的处理方式。
|
||||
*/
|
||||
private String timeoutHandleWay;
|
||||
/**
|
||||
* 默认审批人。
|
||||
*/
|
||||
private String defaultAssignee;
|
||||
/**
|
||||
* 空用户审批处理方式。
|
||||
*/
|
||||
private String emptyUserHandleWay;
|
||||
/**
|
||||
* 空用户审批时设定的审批人。
|
||||
*/
|
||||
private String emptyUserToAssignee;
|
||||
}
|
||||
@@ -0,0 +1,568 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.object.CallResult;
|
||||
import com.orangeforms.common.core.object.MyPageData;
|
||||
import com.orangeforms.common.core.object.MyPageParam;
|
||||
import com.orangeforms.common.core.object.Tuple2;
|
||||
import com.orangeforms.common.flow.model.FlowTaskComment;
|
||||
import com.orangeforms.common.flow.model.FlowTaskExt;
|
||||
import com.orangeforms.common.flow.vo.FlowTaskVo;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FieldExtension;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.delegate.ExecutionListener;
|
||||
import org.flowable.engine.delegate.TaskListener;
|
||||
import org.flowable.engine.history.HistoricActivityInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 流程引擎API的接口封装服务。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowApiService {
|
||||
|
||||
/**
|
||||
* 启动流程实例。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param dataId 业务主键Id。
|
||||
* @return 新启动的流程实例。
|
||||
*/
|
||||
ProcessInstance start(String processDefinitionId, Object dataId);
|
||||
|
||||
/**
|
||||
* 完成第一个用户任务。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param flowTaskComment 审批对象。
|
||||
* @param taskVariableData 流程任务的变量数据。
|
||||
* @return 新完成的任务对象。
|
||||
*/
|
||||
Task takeFirstTask(String processInstanceId, FlowTaskComment flowTaskComment, JSONObject taskVariableData);
|
||||
|
||||
/**
|
||||
* 启动流程实例,如果当前登录用户为第一个用户任务的指派者,或者Assginee为流程启动人变量时,
|
||||
* 则自动完成第一个用户任务。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param dataId 当前流程主表的主键数据。
|
||||
* @param flowTaskComment 审批对象。
|
||||
* @param taskVariableData 流程任务的变量数据。
|
||||
* @return 新启动的流程实例。
|
||||
*/
|
||||
ProcessInstance startAndTakeFirst(
|
||||
String processDefinitionId, Object dataId, FlowTaskComment flowTaskComment, JSONObject taskVariableData);
|
||||
|
||||
/**
|
||||
* 多实例加签减签。
|
||||
*
|
||||
* @param startTaskInstance 会签对象的发起任务实例。
|
||||
* @param multiInstanceActiveTask 正在执行的多实例任务对象。
|
||||
* @param newAssignees 新指派人,多个指派人之间逗号分隔。
|
||||
* @param isAdd 是否为加签。
|
||||
*/
|
||||
void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees, boolean isAdd);
|
||||
|
||||
/**
|
||||
* 完成任务,同时提交审批数据。
|
||||
*
|
||||
* @param task 工作流任务对象。
|
||||
* @param flowTaskComment 审批对象。
|
||||
* @param taskVariableData 流程任务的变量数据。
|
||||
*/
|
||||
void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData);
|
||||
|
||||
/**
|
||||
* 判断当前登录用户是否为流程实例中的用户任务的指派人。或是候选人之一,如果是候选人则拾取该任务并成为指派人。
|
||||
* 如果都不是,就会返回具体的错误信息。
|
||||
*
|
||||
* @param task 流程实例中的用户任务。
|
||||
* @return 调用结果。
|
||||
*/
|
||||
CallResult verifyAssigneeOrCandidateAndClaim(Task task);
|
||||
|
||||
/**
|
||||
* 初始化并返回流程实例的变量Map。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 初始化后的流程实例变量Map。
|
||||
*/
|
||||
Map<String, Object> initAndGetProcessInstanceVariables(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 判断当前登录用户是否为流程实例中的用户任务的指派人。或是候选人之一。
|
||||
*
|
||||
* @param task 流程实例中的用户任务。
|
||||
* @return 是返回true,否则false。
|
||||
*/
|
||||
boolean isAssigneeOrCandidate(TaskInfo task);
|
||||
|
||||
/**
|
||||
* 获取指定流程定义的全部流程节点。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 当前流程定义的全部节点集合。
|
||||
*/
|
||||
Collection<FlowElement> getProcessAllElements(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 判断当前登录用户是否为流程实例的发起人。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 是返回true,否则false。
|
||||
*/
|
||||
boolean isProcessInstanceStarter(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 为流程实例设置BusinessKey。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param dataId 通常为主表的主键Id。
|
||||
*/
|
||||
void setBusinessKeyForProcessInstance(String processInstanceId, Object dataId);
|
||||
|
||||
/**
|
||||
* 判断指定的流程实例Id是否存在。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 存在返回true,否则false。
|
||||
*/
|
||||
boolean existActiveProcessInstance(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取指定的流程实例对象。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 流程实例对象。
|
||||
*/
|
||||
ProcessInstance getProcessInstance(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取指定的流程实例对象。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param businessKey 业务主键Id。
|
||||
* @return 流程实例对象。
|
||||
*/
|
||||
ProcessInstance getProcessInstanceByBusinessKey(String processDefinitionId, String businessKey);
|
||||
|
||||
/**
|
||||
* 获取流程实例的列表。
|
||||
*
|
||||
* @param processInstanceIdSet 流程实例Id集合。
|
||||
* @return 流程实例列表。
|
||||
*/
|
||||
List<ProcessInstance> getProcessInstanceList(Set<String> processInstanceIdSet);
|
||||
|
||||
/**
|
||||
* 根据流程定义Id查询流程定义对象。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 流程定义对象。
|
||||
*/
|
||||
ProcessDefinition getProcessDefinitionById(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 根据流程部署Id查询流程定义对象。
|
||||
*
|
||||
* @param deployId 流程部署Id。
|
||||
* @return 流程定义对象。
|
||||
*/
|
||||
ProcessDefinition getProcessDefinitionByDeployId(String deployId);
|
||||
|
||||
/**
|
||||
* 获取流程定义的列表。
|
||||
*
|
||||
* @param processDefinitionIdSet 流程定义Id集合。
|
||||
* @return 流程定义列表。
|
||||
*/
|
||||
List<ProcessDefinition> getProcessDefinitionList(Set<String> processDefinitionIdSet);
|
||||
|
||||
/**
|
||||
* 挂起流程定义对象。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
*/
|
||||
void suspendProcessDefinition(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 激活流程定义对象。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
*/
|
||||
void activateProcessDefinition(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 获取指定流程定义的BpmnModel。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 关联的BpmnModel。
|
||||
*/
|
||||
BpmnModel getBpmnModelByDefinitionId(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 判断任务是否为多实例任务。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param taskKey 流程任务标识。
|
||||
* @return true为多实例,否则false。
|
||||
*/
|
||||
boolean isMultiInstanceTask(String processDefinitionId, String taskKey);
|
||||
|
||||
/**
|
||||
* 设置流程实例的变量集合。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param variableMap 变量名。
|
||||
*/
|
||||
void setProcessInstanceVariables(String processInstanceId, Map<String, Object> variableMap);
|
||||
|
||||
/**
|
||||
* 获取流程实例的变量。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param variableName 变量名。
|
||||
* @return 变量值。
|
||||
*/
|
||||
Object getProcessInstanceVariable(String processInstanceId, String variableName);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例和任务Id的当前活动任务。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 流程任务Id。
|
||||
* @return 当前流程实例的活动任务。
|
||||
*/
|
||||
Task getProcessInstanceActiveTask(String processInstanceId, String taskId);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的当前活动任务列表。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 当前流程实例的活动任务。
|
||||
*/
|
||||
List<Task> getProcessInstanceActiveTaskList(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的当前活动任务列表,同时转换为流出任务视图对象列表。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 当前流程实例的活动任务。
|
||||
*/
|
||||
List<FlowTaskVo> getProcessInstanceActiveTaskListAndConvert(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 根据任务Id,获取当前运行时任务。
|
||||
*
|
||||
* @param taskId 任务Id。
|
||||
* @return 运行时任务对象。
|
||||
*/
|
||||
Task getTaskById(String taskId);
|
||||
|
||||
/**
|
||||
* 获取用户的任务列表。这其中包括当前用户作为指派人和候选人。
|
||||
*
|
||||
* @param username 指派人。
|
||||
* @param definitionKey 流程定义的标识。
|
||||
* @param definitionName 流程定义名。
|
||||
* @param taskName 任务名称。
|
||||
* @param pageParam 分页对象。
|
||||
* @return 用户的任务列表。
|
||||
*/
|
||||
MyPageData<Task> getTaskListByUserName(
|
||||
String username, String definitionKey, String definitionName, String taskName, MyPageParam pageParam);
|
||||
|
||||
/**
|
||||
* 获取用户的任务数量。这其中包括当前用户作为指派人和候选人。
|
||||
*
|
||||
* @param username 指派人。
|
||||
* @return 用户的任务数量。
|
||||
*/
|
||||
long getTaskCountByUserName(String username);
|
||||
|
||||
/**
|
||||
* 获取流程实例Id集合的运行时任务列表。
|
||||
*
|
||||
* @param processInstanceIdSet 流程实例Id集合。
|
||||
* @return 运行时任务列表。
|
||||
*/
|
||||
List<Task> getTaskListByProcessInstanceIds(List<String> processInstanceIdSet);
|
||||
|
||||
/**
|
||||
* 将流程任务列表数据,转换为前端可以显示的流程对象。
|
||||
*
|
||||
* @param taskList 流程引擎中的任务列表。
|
||||
* @return 前端可以显示的流程任务列表。
|
||||
*/
|
||||
List<FlowTaskVo> convertToFlowTaskList(List<Task> taskList);
|
||||
|
||||
/**
|
||||
* 添加流程实例结束的监听器。
|
||||
*
|
||||
* @param bpmnModel 流程模型。
|
||||
* @param listenerClazz 流程监听器的Class对象。
|
||||
*/
|
||||
void addProcessInstanceEndListener(BpmnModel bpmnModel, Class<? extends ExecutionListener> listenerClazz);
|
||||
|
||||
/**
|
||||
* 添加流程任务的执行监听器。
|
||||
*
|
||||
* @param flowElement 指定任务节点。
|
||||
* @param listenerClazz 执行监听器。
|
||||
* @param event 事件。
|
||||
* @param fieldExtensions 执行监听器的扩展变量列表。
|
||||
*/
|
||||
void addExecutionListener(
|
||||
FlowElement flowElement,
|
||||
Class<? extends ExecutionListener> listenerClazz,
|
||||
String event,
|
||||
List<FieldExtension> fieldExtensions);
|
||||
|
||||
/**
|
||||
* 添加流程任务创建的任务监听器。
|
||||
*
|
||||
* @param userTask 用户任务。
|
||||
* @param listenerClazz 任务监听器。
|
||||
*/
|
||||
void addTaskCreateListener(UserTask userTask, Class<? extends TaskListener> listenerClazz);
|
||||
|
||||
/**
|
||||
* 获取流程实例的历史流程实例。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 历史流程实例。
|
||||
*/
|
||||
HistoricProcessInstance getHistoricProcessInstance(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取流程实例的历史流程实例列表。
|
||||
*
|
||||
* @param processInstanceIdSet 流程实例Id集合。
|
||||
* @return 历史流程实例列表。
|
||||
*/
|
||||
List<HistoricProcessInstance> getHistoricProcessInstanceList(Set<String> processInstanceIdSet);
|
||||
|
||||
/**
|
||||
* 查询历史流程实例的列表。
|
||||
*
|
||||
* @param processDefinitionKey 流程标识名。
|
||||
* @param processDefinitionName 流程名。
|
||||
* @param startUser 流程发起用户。
|
||||
* @param beginDate 流程发起开始时间。
|
||||
* @param endDate 流程发起结束时间。
|
||||
* @param pageParam 分页对象。
|
||||
* @param finishedOnly 仅仅返回已经结束的流程。
|
||||
* @return 分页后的查询列表对象。
|
||||
* @throws ParseException 日期参数解析失败。
|
||||
*/
|
||||
MyPageData<HistoricProcessInstance> getHistoricProcessInstanceList(
|
||||
String processDefinitionKey,
|
||||
String processDefinitionName,
|
||||
String startUser,
|
||||
String beginDate,
|
||||
String endDate,
|
||||
MyPageParam pageParam,
|
||||
boolean finishedOnly) throws ParseException;
|
||||
|
||||
/**
|
||||
* 获取流程实例的已完成历史任务列表。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 流程实例已完成的历史任务列表。
|
||||
*/
|
||||
List<HistoricActivityInstance> getHistoricActivityInstanceList(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取流程实例的已完成历史任务列表,同时按照每个活动实例的开始时间升序排序。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 流程实例已完成的历史任务列表。
|
||||
*/
|
||||
List<HistoricActivityInstance> getHistoricActivityInstanceListOrderByStartTime(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取当前用户的历史已办理任务列表。
|
||||
*
|
||||
* @param processDefinitionName 流程名。
|
||||
* @param beginDate 流程发起开始时间。
|
||||
* @param endDate 流程发起结束时间。
|
||||
* @param pageParam 分页对象。
|
||||
* @return 分页后的查询列表对象。
|
||||
* @throws ParseException 日期参数解析失败。
|
||||
*/
|
||||
MyPageData<HistoricTaskInstance> getHistoricTaskInstanceFinishedList(
|
||||
String processDefinitionName,
|
||||
String beginDate,
|
||||
String endDate,
|
||||
MyPageParam pageParam) throws ParseException;
|
||||
|
||||
/**
|
||||
* 获取指定的历史任务实例。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskId 任务Id。
|
||||
* @return 历史任务实例。
|
||||
*/
|
||||
HistoricTaskInstance getHistoricTaskInstance(String processInstanceId, String taskId);
|
||||
|
||||
/**
|
||||
* 获取流程实例的待完成任务列表。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 流程实例待完成的任务列表。
|
||||
*/
|
||||
List<HistoricActivityInstance> getHistoricUnfinishedInstanceList(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 终止流程实例,将任务从当前节点直接流转到主流程的结束事件。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param stopReason 停止原因。
|
||||
* @param forCancel 是否由取消工单触发。
|
||||
* @return 执行结果。
|
||||
*/
|
||||
CallResult stopProcessInstance(String processInstanceId, String stopReason, boolean forCancel);
|
||||
|
||||
/**
|
||||
* 终止流程实例,将任务从当前节点直接流转到主流程的结束事件。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param stopReason 停止原因。
|
||||
* @param status 流程状态。
|
||||
* @return 执行结果。
|
||||
*/
|
||||
CallResult stopProcessInstance(String processInstanceId, String stopReason, int status);
|
||||
|
||||
/**
|
||||
* 删除流程实例。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
*/
|
||||
void deleteProcessInstance(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取任务的指定本地变量。
|
||||
*
|
||||
* @param taskId 任务Id。
|
||||
* @param variableName 变量名。
|
||||
* @return 变量值。
|
||||
*/
|
||||
Object getTaskVariable(String taskId, String variableName);
|
||||
|
||||
/**
|
||||
* 安全的获取任务变量,并返回字符型的变量值。
|
||||
*
|
||||
* @param taskId 任务Id。
|
||||
* @param variableName 变量名。
|
||||
* @return 返回变量值的字符串形式,如果变量不存在不会抛异常,返回null。
|
||||
*/
|
||||
String getTaskVariableStringWithSafe(String taskId, String variableName);
|
||||
|
||||
/**
|
||||
* 获取任务执行时的指定本地变量。
|
||||
*
|
||||
* @param executionId 任务执行时Id。
|
||||
* @param variableName 变量名。
|
||||
* @return 变量值。
|
||||
*/
|
||||
Object getExecutionVariable(String executionId, String variableName);
|
||||
|
||||
/**
|
||||
* 安全的获取任务执行时变量,并返回字符型的变量值。
|
||||
*
|
||||
* @param executionId 任务执行时Id。
|
||||
* @param variableName 变量名。
|
||||
* @return 返回变量值的字符串形式,如果变量不存在不会抛异常,返回null。
|
||||
*/
|
||||
String getExecutionVariableStringWithSafe(String executionId, String variableName);
|
||||
|
||||
/**
|
||||
* 获取历史流程变量。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param variableName 变量名。
|
||||
* @return 获取历史流程变量。
|
||||
*/
|
||||
Object getHistoricProcessInstanceVariable(String processInstanceId, String variableName);
|
||||
|
||||
/**
|
||||
* 将xml格式的流程模型字符串,转换为标准的流程模型。
|
||||
*
|
||||
* @param bpmnXml xml格式的流程模型字符串。
|
||||
* @return 转换后的标准的流程模型。
|
||||
* @throws XMLStreamException XML流处理异常
|
||||
*/
|
||||
BpmnModel convertToBpmnModel(String bpmnXml) throws XMLStreamException;
|
||||
|
||||
/**
|
||||
* 回退到上一个用户任务节点。如果没有指定,则回退到上一个任务。
|
||||
*
|
||||
* @param task 当前活动任务。
|
||||
* @param targetKey 指定回退到的任务标识。如果为null,则回退到上一个任务。
|
||||
* @param forReject true表示驳回,false为撤回。
|
||||
* @param reason 驳回或者撤销的原因。
|
||||
* @return 回退结果。
|
||||
*/
|
||||
CallResult backToRuntimeTask(Task task, String targetKey, boolean forReject, String reason);
|
||||
|
||||
/**
|
||||
* 转办任务给他人。
|
||||
*
|
||||
* @param task 流程任务。
|
||||
* @param flowTaskComment 审批对象。
|
||||
*/
|
||||
void transferTo(Task task, FlowTaskComment flowTaskComment);
|
||||
|
||||
/**
|
||||
* 获取当前任务在流程图中配置候选用户组数据。
|
||||
*
|
||||
* @param flowTaskExt 流程任务扩展对象。
|
||||
* @param taskId 运行时任务Id。
|
||||
* @return 候选用户组数据。
|
||||
*/
|
||||
List<String> getCandidateUsernames(FlowTaskExt flowTaskExt, String taskId);
|
||||
|
||||
/**
|
||||
* 获取当前任务在流程图中配置到的部门岗位Id集合和岗位Id集合。
|
||||
*
|
||||
* @param flowTaskExt 流程任务扩展对象。
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param historic 是否为历史任务。
|
||||
* @return first为部门岗位Id集合,second是岗位Id集合。
|
||||
*/
|
||||
Tuple2<Set<String>, Set<String>> getDeptPostIdAndPostIds(
|
||||
FlowTaskExt flowTaskExt, String processInstanceId, boolean historic);
|
||||
|
||||
/**
|
||||
* 获取流程图中所有用户任务的映射。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @return 流程图中所有用户任务的映射。
|
||||
*/
|
||||
Map<String, UserTask> getAllUserTaskMap(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 获取流程图中指定的用户任务。
|
||||
*
|
||||
* @param processDefinitionId 流程定义Id。
|
||||
* @param taskKey 用户任务标识。
|
||||
* @return 用户任务。
|
||||
*/
|
||||
UserTask getUserTask(String processDefinitionId, String taskKey);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* FlowCategory数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowCategoryService extends IBaseService<FlowCategory, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowCategory 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
FlowCategory saveNew(FlowCategory flowCategory);
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param flowCategory 更新的对象。
|
||||
* @param originalFlowCategory 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean update(FlowCategory flowCategory, FlowCategory originalFlowCategory);
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param categoryId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean remove(Long categoryId);
|
||||
|
||||
/**
|
||||
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
|
||||
* 如果需要同时获取关联数据,请移步(getFlowCategoryListWithRelation)方法。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowCategory> getFlowCategoryList(FlowCategory filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
|
||||
* 如果仅仅需要获取主表数据,请移步(getFlowCategoryList),以便获取更好的查询性能。
|
||||
*
|
||||
* @param filter 主表过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowCategory> getFlowCategoryListWithRelation(FlowCategory filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 当前流程分类编码是否存在。
|
||||
*
|
||||
* @param code 流程分类编码。
|
||||
* @return true存在,否则false。
|
||||
*/
|
||||
boolean existByCode(String code);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* FlowEntry数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowEntryService extends IBaseService<FlowEntry, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowEntry 新增工作流对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
FlowEntry saveNew(FlowEntry flowEntry);
|
||||
|
||||
/**
|
||||
* 发布指定流程。
|
||||
*
|
||||
* @param flowEntry 待发布的流程对象。
|
||||
* @param initTaskInfo 第一个非开始节点任务的附加信息。
|
||||
* @throws XMLStreamException 解析bpmn.xml的异常。
|
||||
*/
|
||||
void publish(FlowEntry flowEntry, String initTaskInfo) throws XMLStreamException;
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param flowEntry 更新的对象。
|
||||
* @param originalFlowEntry 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean update(FlowEntry flowEntry, FlowEntry originalFlowEntry);
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param entryId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean remove(Long entryId);
|
||||
|
||||
/**
|
||||
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
|
||||
* 如果需要同时获取关联数据,请移步(getFlowEntryListWithRelation)方法。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowEntry> getFlowEntryList(FlowEntry filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
|
||||
* 如果仅仅需要获取主表数据,请移步(getFlowEntryList),以便获取更好的查询性能。
|
||||
*
|
||||
* @param filter 主表过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowEntry> getFlowEntryListWithRelation(FlowEntry filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 根据流程定义标识获取流程对象。从缓存中读取,如不存在则从数据库读取后,再同步到缓存。
|
||||
*
|
||||
* @param processDefinitionKey 流程定义标识。
|
||||
* @return 流程对象。
|
||||
*/
|
||||
FlowEntry getFlowEntryFromCache(String processDefinitionKey);
|
||||
|
||||
/**
|
||||
* 根据流程Id获取流程发布列表数据。
|
||||
*
|
||||
* @param entryId 流程Id。
|
||||
* @return 流程关联的发布列表数据。
|
||||
*/
|
||||
List<FlowEntryPublish> getFlowEntryPublishList(Long entryId);
|
||||
|
||||
/**
|
||||
* 根据流程引擎中的流程定义Id集合,查询流程发布对象。
|
||||
*
|
||||
* @param processDefinitionIdSet 流程引擎中的流程定义Id集合。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
List<FlowEntryPublish> getFlowEntryPublishList(Set<String> processDefinitionIdSet);
|
||||
|
||||
/**
|
||||
* 获取指定工作流发布版本对象。从缓存中读取,如缓存中不存在,从数据库读取并同步缓存。
|
||||
*
|
||||
* @param entryPublishId 工作流发布对象Id。
|
||||
* @return 查询后的对象。
|
||||
*/
|
||||
FlowEntryPublish getFlowEntryPublishFromCache(Long entryPublishId);
|
||||
|
||||
/**
|
||||
* 为指定工作流更新发布的主版本。
|
||||
*
|
||||
* @param flowEntry 工作流对象。
|
||||
* @param newMainFlowEntryPublish 工作流新的发布主版本对象。
|
||||
*/
|
||||
void updateFlowEntryMainVersion(FlowEntry flowEntry, FlowEntryPublish newMainFlowEntryPublish);
|
||||
|
||||
/**
|
||||
* 挂起指定的工作流发布对象。
|
||||
*
|
||||
* @param flowEntryPublish 待挂起的工作流发布对象。
|
||||
*/
|
||||
void suspendFlowEntryPublish(FlowEntryPublish flowEntryPublish);
|
||||
|
||||
/**
|
||||
* 激活指定的工作流发布对象。
|
||||
*
|
||||
* @param flowEntryPublish 待恢复的工作流发布对象。
|
||||
*/
|
||||
void activateFlowEntryPublish(FlowEntryPublish flowEntryPublish);
|
||||
|
||||
/**
|
||||
* 判断指定流程定义标识是否存在。
|
||||
* @param processDefinitionKey 流程定义标识。
|
||||
* @return true存在,否则false。
|
||||
*/
|
||||
boolean existByProcessDefinitionKey(String processDefinitionKey);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程变量数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowEntryVariableService extends IBaseService<FlowEntryVariable, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowEntryVariable 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
FlowEntryVariable saveNew(FlowEntryVariable flowEntryVariable);
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param flowEntryVariable 更新的对象。
|
||||
* @param originalFlowEntryVariable 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean update(FlowEntryVariable flowEntryVariable, FlowEntryVariable originalFlowEntryVariable);
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param variableId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean remove(Long variableId);
|
||||
|
||||
/**
|
||||
* 删除指定流程Id的所有变量。
|
||||
*
|
||||
* @param entryId 流程Id。
|
||||
*/
|
||||
void removeByEntryId(Long entryId);
|
||||
|
||||
/**
|
||||
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
|
||||
* 如果需要同时获取关联数据,请移步(getFlowEntryVariableListWithRelation)方法。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowEntryVariable> getFlowEntryVariableList(FlowEntryVariable filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
|
||||
* 如果仅仅需要获取主表数据,请移步(getFlowEntryVariableList),以便获取更好的查询性能。
|
||||
*
|
||||
* @param filter 主表过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowEntryVariable> getFlowEntryVariableListWithRelation(FlowEntryVariable filter, String orderBy);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.flow.model.FlowMessage;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
import org.flowable.task.api.Task;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工作流消息数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowMessageService extends IBaseService<FlowMessage, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowMessage 新增对象。
|
||||
* @return 保存后的消息对象。
|
||||
*/
|
||||
FlowMessage saveNew(FlowMessage flowMessage);
|
||||
|
||||
/**
|
||||
* 根据工单参数,保存催单消息对象。如果当前工单存在多个待办任务,则插入多条催办消息数据。
|
||||
*
|
||||
* @param flowWorkOrder 待催办的工单。
|
||||
*/
|
||||
void saveNewRemindMessage(FlowWorkOrder flowWorkOrder);
|
||||
|
||||
/**
|
||||
* 保存抄送消息对象。
|
||||
*
|
||||
* @param task 待抄送的任务。
|
||||
* @param copyDataJson 抄送人员或者组的Id数据。
|
||||
*/
|
||||
void saveNewCopyMessage(Task task, JSONObject copyDataJson);
|
||||
|
||||
/**
|
||||
* 更新指定运行时任务Id的消费为已完成状态。
|
||||
*
|
||||
* @param taskId 运行时任务Id。
|
||||
*/
|
||||
void updateFinishedStatusByTaskId(String taskId);
|
||||
|
||||
/**
|
||||
* 更新指定流程实例Id的消费为已完成状态。
|
||||
*
|
||||
* @param processInstanceId 流程实例IdId。
|
||||
*/
|
||||
void updateFinishedStatusByProcessInstanceId(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取当前用户的催办消息列表。
|
||||
*
|
||||
* @return 查询后的催办消息列表。
|
||||
*/
|
||||
List<FlowMessage> getRemindingMessageListByUser();
|
||||
|
||||
/**
|
||||
* 获取当前用户的抄送消息列表。
|
||||
*
|
||||
* @param read true表示已读,false表示未读。
|
||||
* @return 查询后的抄送消息列表。
|
||||
*/
|
||||
List<FlowMessage> getCopyMessageListByUser(Boolean read);
|
||||
|
||||
/**
|
||||
* 判断当前用户是否有权限访问指定消息Id。
|
||||
*
|
||||
* @param messageId 消息Id。
|
||||
* @return true为合法访问者,否则false。
|
||||
*/
|
||||
boolean isCandidateIdentityOnMessage(Long messageId);
|
||||
|
||||
/**
|
||||
* 读取抄送消息,同时更新当前用户对指定抄送消息的读取状态。
|
||||
*
|
||||
* @param messageId 消息Id。
|
||||
*/
|
||||
void readCopyTask(Long messageId);
|
||||
|
||||
/**
|
||||
* 计算当前用户催办消息的数量。
|
||||
*
|
||||
* @return 当前用户催办消息数量。
|
||||
*/
|
||||
int countRemindingMessageListByUser();
|
||||
|
||||
/**
|
||||
* 计算当前用户未读抄送消息的数量。
|
||||
*
|
||||
* @return 当前用户未读抄送消息数量。
|
||||
*/
|
||||
int countCopyMessageByUser();
|
||||
|
||||
/**
|
||||
* 删除指定流程实例的消息。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
*/
|
||||
void removeByProcessInstanceId(String processInstanceId);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.flow.model.FlowMultiInstanceTrans;
|
||||
|
||||
/**
|
||||
* 会签任务操作流水数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowMultiInstanceTransService extends IBaseService<FlowMultiInstanceTrans, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowMultiInstanceTrans 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
FlowMultiInstanceTrans saveNew(FlowMultiInstanceTrans flowMultiInstanceTrans);
|
||||
|
||||
/**
|
||||
* 根据流程执行Id获取对象。
|
||||
*
|
||||
* @param executionId 流程执行Id。
|
||||
* @param taskId 执行任务Id。
|
||||
* @return 数据对象。
|
||||
*/
|
||||
FlowMultiInstanceTrans getByExecutionId(String executionId, String taskId);
|
||||
|
||||
/**
|
||||
* 根据多实例的统一执行Id,获取assgineeList字段不为空的数据。
|
||||
*
|
||||
* @param multiInstanceExecId 多实例统一执行Id。
|
||||
* @return 数据对象。
|
||||
*/
|
||||
FlowMultiInstanceTrans getWithAssigneeListByMultiInstanceExecId(String multiInstanceExecId);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程任务批注数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowTaskCommentService extends IBaseService<FlowTaskComment, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowTaskComment 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
FlowTaskComment saveNew(FlowTaskComment flowTaskComment);
|
||||
|
||||
/**
|
||||
* 查询指定流程实例Id下的所有审批任务的批注。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowTaskComment> getFlowTaskCommentList(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 查询与指定流程任务Id集合关联的所有审批任务的批注。
|
||||
*
|
||||
* @param taskIdSet 流程任务Id集合。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowTaskComment> getFlowTaskCommentListByTaskIds(Set<String> taskIdSet);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的最后一条审批任务。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
FlowTaskComment getLatestFlowTaskComment(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例和任务定义标识的最后一条审批任务。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param taskDefinitionKey 任务定义标识。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
FlowTaskComment getLatestFlowTaskComment(String processInstanceId, String taskDefinitionKey);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的第一条审批任务。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
FlowTaskComment getFirstFlowTaskComment(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取指定任务实例和执行批次的审批数据列表。
|
||||
*
|
||||
* @param processInstanceId 流程实例。
|
||||
* @param taskId 任务Id
|
||||
* @param executionId 任务执行Id
|
||||
* @return 审批数据列表。
|
||||
*/
|
||||
List<FlowTaskComment> getFlowTaskCommentListByExecutionId(
|
||||
String processInstanceId, String taskId, String executionId);
|
||||
|
||||
/**
|
||||
* 根据多实例执行Id获取任务审批对象数据列表。
|
||||
*
|
||||
* @param multiInstanceExecId 多实例执行Id。
|
||||
* @return 审批数据列表。
|
||||
*/
|
||||
List<FlowTaskComment> getFlowTaskCommentListByMultiInstanceExecId(String multiInstanceExecId);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.object.FlowElementExtProperty;
|
||||
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程任务扩展数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowTaskExtService extends IBaseService<FlowTaskExt, String> {
|
||||
|
||||
/**
|
||||
* 批量插入流程任务扩展信息列表。
|
||||
*
|
||||
* @param flowTaskExtList 流程任务扩展信息列表。
|
||||
*/
|
||||
void saveBatch(List<FlowTaskExt> flowTaskExtList);
|
||||
|
||||
/**
|
||||
* 查询指定的流程任务扩展对象。
|
||||
*
|
||||
* @param processDefinitionId 流程引擎的定义Id。
|
||||
* @param taskId 流程引擎的任务Id。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
FlowTaskExt getByProcessDefinitionIdAndTaskId(String processDefinitionId, String taskId);
|
||||
|
||||
/**
|
||||
* 查询指定的流程定义的任务扩展对象。
|
||||
*
|
||||
* @param processDefinitionId 流程引擎的定义Id。
|
||||
* @return 查询结果。
|
||||
*/
|
||||
List<FlowTaskExt> getByProcessDefinitionId(String processDefinitionId);
|
||||
|
||||
/**
|
||||
* 获取任务扩展信息中的候选人用户信息列表。
|
||||
*
|
||||
* @param processInstanceId 流程引擎的实例Id。
|
||||
* @param flowTaskExt 任务扩展对象。
|
||||
* @param taskInfo 任务信息。
|
||||
* @param isMultiInstanceTask 是否为多实例任务。
|
||||
* @param historic 是否为历史任务。
|
||||
* @return 候选人用户信息列表。
|
||||
*/
|
||||
List<FlowUserInfoVo> getCandidateUserInfoList(
|
||||
String processInstanceId,
|
||||
FlowTaskExt flowTaskExt,
|
||||
TaskInfo taskInfo,
|
||||
boolean isMultiInstanceTask,
|
||||
boolean historic);
|
||||
|
||||
/**
|
||||
* 获取指定任务的用户列表信息。
|
||||
*
|
||||
* @param processInstanceId 流程实例。
|
||||
* @param executionId 执行实例。
|
||||
* @param flowTaskExt 流程用户任务的扩展对象。
|
||||
* @return 候选人用户信息列表。
|
||||
*/
|
||||
List<FlowUserInfoVo> getCandidateUserInfoList(
|
||||
String processInstanceId,
|
||||
String executionId,
|
||||
FlowTaskExt flowTaskExt);
|
||||
|
||||
/**
|
||||
* 通过UserTask对象中的扩展节点信息,构建FLowTaskExt对象。
|
||||
*
|
||||
* @param userTask 流程图中定义的用户任务对象。
|
||||
* @return 构建后的流程任务扩展信息对象。
|
||||
*/
|
||||
FlowTaskExt buildTaskExtByUserTask(UserTask userTask);
|
||||
|
||||
/**
|
||||
* 获取指定流程图中所有UserTask对象的扩展节点信息,构建FLowTaskExt对象列表。
|
||||
*
|
||||
* @param bpmnModel 流程图模型对象。
|
||||
* @return 当前流程图中所有用户流程任务的扩展信息对象列表。
|
||||
*/
|
||||
List<FlowTaskExt> buildTaskExtList(BpmnModel bpmnModel);
|
||||
|
||||
/**
|
||||
* 根据流程定义中用户任务的扩展节点数据,构建出前端所需的操作列表数据对象。
|
||||
* @param extensionMap 用户任务的扩展节点。
|
||||
* @return 前端所需的操作列表数据对象。
|
||||
*/
|
||||
List<JSONObject> buildOperationListExtensionElement(Map<String, List<ExtensionElement>> extensionMap);
|
||||
|
||||
/**
|
||||
* 根据流程定义中用户任务的扩展节点数据,构建出前端所需的变量列表数据对象。
|
||||
* @param extensionMap 用户任务的扩展节点。
|
||||
* @return 前端所需的变量列表数据对象。
|
||||
*/
|
||||
List<JSONObject> buildVariableListExtensionElement(Map<String, List<ExtensionElement>> extensionMap);
|
||||
|
||||
/**
|
||||
* 读取流程定义中,流程元素的扩展属性数据。
|
||||
*
|
||||
* @param element 流程图中定义的流程元素。
|
||||
* @return 流程元素的扩展属性数据。
|
||||
*/
|
||||
FlowElementExtProperty buildFlowElementExt(FlowElement element);
|
||||
|
||||
/**
|
||||
* 读取流程定义中,流程元素的扩展属性数据。
|
||||
*
|
||||
* @param element 流程图中定义的流程元素。
|
||||
* @return 流程元素的扩展属性数据,并转换为JSON对象。
|
||||
*/
|
||||
JSONObject buildFlowElementExtToJson(FlowElement element);
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.orangeforms.common.flow.service;
|
||||
|
||||
import com.orangeforms.common.core.base.service.IBaseService;
|
||||
import com.orangeforms.common.core.object.CallResult;
|
||||
import com.orangeforms.common.core.object.MyOrderParam;
|
||||
import com.orangeforms.common.core.object.MyPageData;
|
||||
import com.orangeforms.common.core.object.MyPageParam;
|
||||
import com.orangeforms.common.flow.dto.FlowWorkOrderDto;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrderExt;
|
||||
import com.orangeforms.common.flow.vo.FlowWorkOrderVo;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流工单表数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
public interface FlowWorkOrderService extends IBaseService<FlowWorkOrder, Long> {
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param instance 流程实例对象。
|
||||
* @param dataId 流程实例的BusinessKey。
|
||||
* @param onlineTableId 在线数据表的主键Id。
|
||||
* @param tableName 面向静态表单所使用的表名。
|
||||
* @return 新增的工作流工单对象。
|
||||
*/
|
||||
FlowWorkOrder saveNew(ProcessInstance instance, Object dataId, Long onlineTableId, String tableName);
|
||||
|
||||
/**
|
||||
* 保存工单草稿。
|
||||
*
|
||||
* @param instance 流程实例对象。
|
||||
* @param onlineTableId 在线表单的主表Id。
|
||||
* @param tableName 静态表单的主表表名。
|
||||
* @param masterData 主表数据。
|
||||
* @param slaveData 从表数据。
|
||||
* @return 工单对象。
|
||||
*/
|
||||
FlowWorkOrder saveNewWithDraft(
|
||||
ProcessInstance instance, Long onlineTableId, String tableName, String masterData, String slaveData);
|
||||
|
||||
/**
|
||||
* 更新流程工单的草稿数据。
|
||||
*
|
||||
* @param workOrderId 工单Id。
|
||||
* @param masterData 主表数据。
|
||||
* @param slaveData 从表数据。
|
||||
*/
|
||||
void updateDraft(Long workOrderId, String masterData, String slaveData);
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param workOrderId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
boolean remove(Long workOrderId);
|
||||
|
||||
/**
|
||||
* 删除指定流程实例Id的关联工单。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
*/
|
||||
void removeByProcessInstanceId(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 获取工作流工单单表查询结果。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowWorkOrder> getFlowWorkOrderList(FlowWorkOrder filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 获取工作流工单列表及其关联字典数据。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
List<FlowWorkOrder> getFlowWorkOrderListWithRelation(FlowWorkOrder filter, String orderBy);
|
||||
|
||||
/**
|
||||
* 根据流程实例Id,查询关联的工单对象。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 工作流工单对象。
|
||||
*/
|
||||
FlowWorkOrder getFlowWorkOrderByProcessInstanceId(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 根据业务主键,查询是否存在指定的工单。
|
||||
*
|
||||
* @param tableName 静态表单工作流使用的数据表。
|
||||
* @param businessKey 业务数据主键Id。
|
||||
* @param unfinished 是否为没有结束工单。
|
||||
* @return 存在返回true,否则false。
|
||||
*/
|
||||
boolean existByBusinessKey(String tableName, Object businessKey, boolean unfinished);
|
||||
|
||||
/**
|
||||
* 根据流程定义和业务主键,查询是否存在指定的未完成工单。
|
||||
*
|
||||
* @param processDefinitionKey 静态表单工作流使用的数据表。
|
||||
* @param businessKey 业务数据主键Id。
|
||||
* @return 存在返回true,否则false。
|
||||
*/
|
||||
boolean existUnfinished(String processDefinitionKey, Object businessKey);
|
||||
|
||||
/**
|
||||
* 根据流程实例Id,更新流程状态。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param flowStatus 新的流程状态值,如果该值为null,不执行任何更新。
|
||||
*/
|
||||
void updateFlowStatusByProcessInstanceId(String processInstanceId, Integer flowStatus);
|
||||
|
||||
/**
|
||||
* 根据流程实例Id,更新流程最后审批状态。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @param approvalStatus 新的流程最后审批状态,如果该值为null,不执行任何更新。
|
||||
*/
|
||||
void updateLatestApprovalStatusByProcessInstanceId(String processInstanceId, Integer approvalStatus);
|
||||
|
||||
/**
|
||||
* 是否有查看该工单的数据权限。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 存在返回true,否则false。
|
||||
*/
|
||||
boolean hasDataPermOnFlowWorkOrder(String processInstanceId);
|
||||
|
||||
/**
|
||||
* 根据工单列表中的submitUserName,找到映射的userShowName,并会写到Vo中指定字段。
|
||||
* 同时这也是一个如何通过插件方法,将loginName映射到showName的示例,
|
||||
*
|
||||
* @param dataList 工单Vo对象列表。
|
||||
*/
|
||||
void fillUserShowNameByLoginName(List<FlowWorkOrderVo> dataList);
|
||||
|
||||
/**
|
||||
* 根据工单Id获取工单扩展对象数据。
|
||||
*
|
||||
* @param workOrderId 工单Id。
|
||||
* @return 工单扩展对象。
|
||||
*/
|
||||
FlowWorkOrderExt getFlowWorkOrderExtByWorkOrderId(Long workOrderId);
|
||||
|
||||
/**
|
||||
* 根据工单Id集合获取工单扩展对象数据列表。
|
||||
*
|
||||
* @param workOrderIds 工单Id集合。
|
||||
* @return 工单扩展对象列表。
|
||||
*/
|
||||
List<FlowWorkOrderExt> getFlowWorkOrderExtByWorkOrderIds(Set<Long> workOrderIds);
|
||||
|
||||
/**
|
||||
* 移除草稿工单,同时停止已经启动的流程实例。
|
||||
*
|
||||
* @param flowWorkOrder 工单对象。
|
||||
* @return 停止流程实例的结果。
|
||||
*/
|
||||
CallResult removeDraft(FlowWorkOrder flowWorkOrder);
|
||||
|
||||
/**
|
||||
* 获取分页后的工单列表同时构建部分任务数据。该方法主要是为了尽量减少路由表单工作流listWorkOrder的重复代码。
|
||||
*
|
||||
* @param filter 工单过滤对象。
|
||||
* @param pageParam 分页参数对象。
|
||||
* @param orderParam 排序参数对象。
|
||||
* @param processDefinitionKey 流程定义标识。
|
||||
* @return 分页的工单列表。
|
||||
*/
|
||||
MyPageData<FlowWorkOrderVo> getPagedWorkOrderListAndBuildData(
|
||||
FlowWorkOrderDto filter, MyPageParam pageParam, MyOrderParam orderParam, String processDefinitionKey);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,129 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.MyRelationParam;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import com.orangeforms.common.flow.dao.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowCategoryService")
|
||||
public class FlowCategoryServiceImpl extends BaseService<FlowCategory, Long> implements FlowCategoryService {
|
||||
|
||||
@Autowired
|
||||
private FlowCategoryMapper flowCategoryMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowCategory> mapper() {
|
||||
return flowCategoryMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowCategory saveNew(FlowCategory flowCategory) {
|
||||
flowCategory.setCategoryId(idGenerator.nextLongId());
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
flowCategory.setAppCode(tokenData.getAppCode());
|
||||
flowCategory.setTenantId(tokenData.getTenantId());
|
||||
flowCategory.setUpdateUserId(tokenData.getUserId());
|
||||
flowCategory.setCreateUserId(tokenData.getUserId());
|
||||
Date now = new Date();
|
||||
flowCategory.setUpdateTime(now);
|
||||
flowCategory.setCreateTime(now);
|
||||
flowCategoryMapper.insert(flowCategory);
|
||||
return flowCategory;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean update(FlowCategory flowCategory, FlowCategory originalFlowCategory) {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
flowCategory.setAppCode(tokenData.getAppCode());
|
||||
flowCategory.setTenantId(tokenData.getTenantId());
|
||||
flowCategory.setUpdateUserId(tokenData.getUserId());
|
||||
flowCategory.setCreateUserId(originalFlowCategory.getCreateUserId());
|
||||
flowCategory.setUpdateTime(new Date());
|
||||
flowCategory.setCreateTime(originalFlowCategory.getCreateTime());
|
||||
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
|
||||
return flowCategoryMapper.update(flowCategory, false) == 1;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean remove(Long categoryId) {
|
||||
return flowCategoryMapper.deleteById(categoryId) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowCategory> getFlowCategoryList(FlowCategory filter, String orderBy) {
|
||||
if (filter == null) {
|
||||
filter = new FlowCategory();
|
||||
}
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
filter.setTenantId(tokenData.getTenantId());
|
||||
filter.setAppCode(tokenData.getAppCode());
|
||||
return flowCategoryMapper.getFlowCategoryList(filter, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowCategory> getFlowCategoryListWithRelation(FlowCategory filter, String orderBy) {
|
||||
List<FlowCategory> resultList = this.getFlowCategoryList(filter, orderBy);
|
||||
// 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。
|
||||
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
|
||||
int batchSize = resultList instanceof Page ? 0 : 1000;
|
||||
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existByCode(String code) {
|
||||
FlowCategory filter = new FlowCategory();
|
||||
filter.setCode(code);
|
||||
return CollUtil.isNotEmpty(this.getFlowCategoryList(filter, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowCategory> getInList(Set<Long> categoryIds) {
|
||||
QueryWrapper qw = new QueryWrapper();
|
||||
qw.in(FlowCategory::getCategoryId, categoryIds);
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (tokenData.getAppCode() == null) {
|
||||
qw.isNull(FlowCategory::getAppCode);
|
||||
} else {
|
||||
qw.eq(FlowCategory::getAppCode, tokenData.getAppCode());
|
||||
}
|
||||
if (tokenData.getTenantId() == null) {
|
||||
qw.isNull(FlowCategory::getTenantId);
|
||||
} else {
|
||||
qw.eq(FlowCategory::getTenantId, tokenData.getTenantId());
|
||||
}
|
||||
return flowCategoryMapper.selectListByQuery(qw);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.CallResult;
|
||||
import com.orangeforms.common.core.object.MyRelationParam;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.MyModelUtil;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.redis.util.CommonRedisUtil;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import com.orangeforms.common.flow.listener.*;
|
||||
import com.orangeforms.common.flow.object.*;
|
||||
import com.orangeforms.common.flow.util.FlowRedisKeyUtil;
|
||||
import com.orangeforms.common.flow.util.BaseFlowIdentityExtHelper;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.dao.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowEntryStatus;
|
||||
import com.orangeforms.common.flow.model.constant.FlowVariableType;
|
||||
import lombok.Cleanup;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowEntryService")
|
||||
public class FlowEntryServiceImpl extends BaseService<FlowEntry, Long> implements FlowEntryService {
|
||||
|
||||
@Autowired
|
||||
private FlowEntryMapper flowEntryMapper;
|
||||
@Autowired
|
||||
private FlowEntryPublishMapper flowEntryPublishMapper;
|
||||
@Autowired
|
||||
private FlowEntryPublishVariableMapper flowEntryPublishVariableMapper;
|
||||
@Autowired
|
||||
private FlowEntryVariableService flowEntryVariableService;
|
||||
@Autowired
|
||||
private FlowCategoryService flowCategoryService;
|
||||
@Autowired
|
||||
private FlowTaskExtService flowTaskExtService;
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowCustomExtFactory flowCustomExtFactory;
|
||||
@Autowired
|
||||
private RepositoryService repositoryService;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
@Autowired
|
||||
private CommonRedisUtil commonRedisUtil;
|
||||
|
||||
private static final Integer FLOW_ENTRY_PUBLISH_TTL = 60 * 60 * 24;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowEntry> mapper() {
|
||||
return flowEntryMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowEntry saveNew(FlowEntry flowEntry) {
|
||||
flowEntry.setEntryId(idGenerator.nextLongId());
|
||||
flowEntry.setStatus(FlowEntryStatus.UNPUBLISHED);
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
flowEntry.setAppCode(tokenData.getAppCode());
|
||||
flowEntry.setTenantId(tokenData.getTenantId());
|
||||
flowEntry.setUpdateUserId(tokenData.getUserId());
|
||||
flowEntry.setCreateUserId(tokenData.getUserId());
|
||||
Date now = new Date();
|
||||
flowEntry.setUpdateTime(now);
|
||||
flowEntry.setCreateTime(now);
|
||||
flowEntryMapper.insert(flowEntry);
|
||||
this.insertBuiltinEntryVariables(flowEntry.getEntryId());
|
||||
return flowEntry;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void publish(FlowEntry flowEntry, String initTaskInfo) throws XMLStreamException {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||
FlowCategory flowCategory = flowCategoryService.getById(flowEntry.getCategoryId());
|
||||
InputStream xmlStream = new ByteArrayInputStream(
|
||||
flowEntry.getBpmnXml().getBytes(StandardCharsets.UTF_8));
|
||||
@Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(xmlStream);
|
||||
BpmnXMLConverter converter = new BpmnXMLConverter();
|
||||
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
|
||||
bpmnModel.getMainProcess().setName(flowEntry.getProcessDefinitionName());
|
||||
bpmnModel.getMainProcess().setId(flowEntry.getProcessDefinitionKey());
|
||||
flowApiService.addProcessInstanceEndListener(bpmnModel, FlowFinishedListener.class);
|
||||
List<FlowTaskExt> flowTaskExtList = flowTaskExtService.buildTaskExtList(bpmnModel);
|
||||
if (StrUtil.isNotBlank(flowEntry.getExtensionData())) {
|
||||
FlowEntryExtensionData flowEntryExtensionData =
|
||||
JSON.parseObject(flowEntry.getExtensionData(), FlowEntryExtensionData.class);
|
||||
this.mergeTaskNotifyData(flowEntryExtensionData, flowTaskExtList);
|
||||
}
|
||||
this.processFlowTaskExtList(flowTaskExtList, bpmnModel);
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
Deployment deploy = repositoryService.createDeployment()
|
||||
.addBpmnModel(flowEntry.getProcessDefinitionKey() + ".bpmn", bpmnModel)
|
||||
.tenantId(tokenData.getTenantId() != null ? tokenData.getTenantId().toString() : tokenData.getAppCode())
|
||||
.name(flowEntry.getProcessDefinitionName())
|
||||
.key(flowEntry.getProcessDefinitionKey())
|
||||
.category(flowCategory.getCode())
|
||||
.deploy();
|
||||
ProcessDefinition processDefinition = flowApiService.getProcessDefinitionByDeployId(deploy.getId());
|
||||
FlowEntryPublish flowEntryPublish = new FlowEntryPublish();
|
||||
flowEntryPublish.setEntryPublishId(idGenerator.nextLongId());
|
||||
flowEntryPublish.setEntryId(flowEntry.getEntryId());
|
||||
flowEntryPublish.setProcessDefinitionId(processDefinition.getId());
|
||||
flowEntryPublish.setDeployId(processDefinition.getDeploymentId());
|
||||
flowEntryPublish.setPublishVersion(processDefinition.getVersion());
|
||||
flowEntryPublish.setActiveStatus(true);
|
||||
flowEntryPublish.setMainVersion(flowEntry.getStatus().equals(FlowEntryStatus.UNPUBLISHED));
|
||||
flowEntryPublish.setCreateUserId(TokenData.takeFromRequest().getUserId());
|
||||
flowEntryPublish.setPublishTime(new Date());
|
||||
flowEntryPublish.setInitTaskInfo(initTaskInfo);
|
||||
flowEntryPublish.setExtensionData(flowEntry.getExtensionData());
|
||||
flowEntryPublishMapper.insert(flowEntryPublish);
|
||||
FlowEntry updatedFlowEntry = new FlowEntry();
|
||||
updatedFlowEntry.setEntryId(flowEntry.getEntryId());
|
||||
updatedFlowEntry.setStatus(FlowEntryStatus.PUBLISHED);
|
||||
updatedFlowEntry.setLatestPublishTime(new Date());
|
||||
// 对于从未发布过的工作,第一次发布的时候会将本地发布置位主版本。
|
||||
if (flowEntry.getStatus().equals(FlowEntryStatus.UNPUBLISHED)) {
|
||||
updatedFlowEntry.setMainEntryPublishId(flowEntryPublish.getEntryPublishId());
|
||||
}
|
||||
flowEntryMapper.update(updatedFlowEntry);
|
||||
FlowEntryVariable flowEntryVariableFilter = new FlowEntryVariable();
|
||||
flowEntryVariableFilter.setEntryId(flowEntry.getEntryId());
|
||||
List<FlowEntryVariable> flowEntryVariableList =
|
||||
flowEntryVariableService.getFlowEntryVariableList(flowEntryVariableFilter, null);
|
||||
if (CollUtil.isNotEmpty(flowTaskExtList)) {
|
||||
flowTaskExtList.forEach(t -> t.setProcessDefinitionId(processDefinition.getId()));
|
||||
flowTaskExtService.saveBatch(flowTaskExtList);
|
||||
}
|
||||
this.insertEntryPublishVariables(flowEntryVariableList, flowEntryPublish.getEntryPublishId());
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean update(FlowEntry flowEntry, FlowEntry originalFlowEntry) {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
flowEntry.setAppCode(tokenData.getAppCode());
|
||||
flowEntry.setTenantId(tokenData.getTenantId());
|
||||
flowEntry.setUpdateUserId(tokenData.getUserId());
|
||||
flowEntry.setCreateUserId(originalFlowEntry.getCreateUserId());
|
||||
flowEntry.setUpdateTime(new Date());
|
||||
flowEntry.setCreateTime(originalFlowEntry.getCreateTime());
|
||||
flowEntry.setPageId(originalFlowEntry.getPageId());
|
||||
return flowEntryMapper.update(flowEntry) == 1;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean remove(Long entryId) {
|
||||
FlowEntry flowEntry = this.getById(entryId);
|
||||
if (flowEntry != null) {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||
}
|
||||
if (flowEntryMapper.deleteById(entryId) != 1) {
|
||||
return false;
|
||||
}
|
||||
flowEntryVariableService.removeByEntryId(entryId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowEntry> getFlowEntryList(FlowEntry filter, String orderBy) {
|
||||
if (filter == null) {
|
||||
filter = new FlowEntry();
|
||||
}
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
filter.setTenantId(tokenData.getTenantId());
|
||||
filter.setAppCode(tokenData.getAppCode());
|
||||
return flowEntryMapper.getFlowEntryList(filter, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowEntry> getFlowEntryListWithRelation(FlowEntry filter, String orderBy) {
|
||||
List<FlowEntry> resultList = this.getFlowEntryList(filter, orderBy);
|
||||
// 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。
|
||||
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
|
||||
int batchSize = resultList instanceof Page ? 0 : 1000;
|
||||
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
|
||||
Set<Long> mainEntryPublishIdSet = resultList.stream()
|
||||
.map(FlowEntry::getMainEntryPublishId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
if (CollUtil.isNotEmpty(mainEntryPublishIdSet)) {
|
||||
List<FlowEntryPublish> mainEntryPublishList =
|
||||
flowEntryPublishMapper.selectListByIds(mainEntryPublishIdSet);
|
||||
MyModelUtil.makeOneToOneRelation(FlowEntry.class, resultList, FlowEntry::getMainEntryPublishId,
|
||||
mainEntryPublishList, FlowEntryPublish::getEntryPublishId, "mainFlowEntryPublish");
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowEntry getFlowEntryFromCache(String processDefinitionKey) {
|
||||
String key = FlowRedisKeyUtil.makeFlowEntryKey(processDefinitionKey);
|
||||
QueryWrapper qw = new QueryWrapper();
|
||||
qw.eq(FlowEntry::getProcessDefinitionKey, processDefinitionKey);
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (StrUtil.isNotBlank(tokenData.getAppCode())) {
|
||||
qw.eq(FlowEntry::getAppCode, tokenData.getAppCode());
|
||||
} else {
|
||||
qw.isNull(FlowEntry::getAppCode);
|
||||
}
|
||||
if (tokenData.getTenantId() != null) {
|
||||
qw.eq(FlowEntry::getTenantId, tokenData.getTenantId());
|
||||
} else {
|
||||
qw.isNull(FlowEntry::getTenantId);
|
||||
}
|
||||
return commonRedisUtil.getFromCacheWithQueryWrapper(key, qw, flowEntryMapper::selectOneByQuery, FlowEntry.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowEntryPublish> getFlowEntryPublishList(Long entryId) {
|
||||
FlowEntryPublish filter = new FlowEntryPublish();
|
||||
filter.setEntryId(entryId);
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(filter);
|
||||
queryWrapper.orderBy(FlowEntryPublish::getEntryPublishId, false);
|
||||
return flowEntryPublishMapper.selectListByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowEntryPublish> getFlowEntryPublishList(Set<String> processDefinitionIdSet) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.in(FlowEntryPublish::getProcessDefinitionId, processDefinitionIdSet);
|
||||
return flowEntryPublishMapper.selectListByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowEntryPublish getFlowEntryPublishFromCache(Long entryPublishId) {
|
||||
String key = FlowRedisKeyUtil.makeFlowEntryPublishKey(entryPublishId);
|
||||
return commonRedisUtil.getFromCache(
|
||||
key, entryPublishId, flowEntryPublishMapper::selectOneById, FlowEntryPublish.class, FLOW_ENTRY_PUBLISH_TTL);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateFlowEntryMainVersion(FlowEntry flowEntry, FlowEntryPublish newMainFlowEntryPublish) {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryKey(flowEntry.getProcessDefinitionKey()));
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryPublishKey(newMainFlowEntryPublish.getEntryPublishId()));
|
||||
FlowEntryPublish oldMainFlowEntryPublish =
|
||||
flowEntryPublishMapper.selectOneById(flowEntry.getMainEntryPublishId());
|
||||
if (oldMainFlowEntryPublish != null) {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryPublishKey(oldMainFlowEntryPublish.getEntryPublishId()));
|
||||
oldMainFlowEntryPublish.setMainVersion(false);
|
||||
flowEntryPublishMapper.update(oldMainFlowEntryPublish);
|
||||
}
|
||||
newMainFlowEntryPublish.setMainVersion(true);
|
||||
flowEntryPublishMapper.update(newMainFlowEntryPublish);
|
||||
FlowEntry updatedEntry = new FlowEntry();
|
||||
updatedEntry.setEntryId(flowEntry.getEntryId());
|
||||
updatedEntry.setMainEntryPublishId(newMainFlowEntryPublish.getEntryPublishId());
|
||||
flowEntryMapper.update(updatedEntry);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void suspendFlowEntryPublish(FlowEntryPublish flowEntryPublish) {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryPublishKey(flowEntryPublish.getEntryPublishId()));
|
||||
FlowEntryPublish updatedEntryPublish = new FlowEntryPublish();
|
||||
updatedEntryPublish.setEntryPublishId(flowEntryPublish.getEntryPublishId());
|
||||
updatedEntryPublish.setActiveStatus(false);
|
||||
flowEntryPublishMapper.update(updatedEntryPublish);
|
||||
flowApiService.suspendProcessDefinition(flowEntryPublish.getProcessDefinitionId());
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void activateFlowEntryPublish(FlowEntryPublish flowEntryPublish) {
|
||||
commonRedisUtil.evictFormCache(
|
||||
FlowRedisKeyUtil.makeFlowEntryPublishKey(flowEntryPublish.getEntryPublishId()));
|
||||
FlowEntryPublish updatedEntryPublish = new FlowEntryPublish();
|
||||
updatedEntryPublish.setEntryPublishId(flowEntryPublish.getEntryPublishId());
|
||||
updatedEntryPublish.setActiveStatus(true);
|
||||
flowEntryPublishMapper.update(updatedEntryPublish);
|
||||
flowApiService.activateProcessDefinition(flowEntryPublish.getProcessDefinitionId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existByProcessDefinitionKey(String processDefinitionKey) {
|
||||
FlowEntry filter = new FlowEntry();
|
||||
filter.setProcessDefinitionKey(processDefinitionKey);
|
||||
return CollUtil.isNotEmpty(this.getFlowEntryList(filter, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallResult verifyRelatedData(FlowEntry flowEntry, FlowEntry originalFlowEntry) {
|
||||
String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!";
|
||||
if (this.needToVerify(flowEntry, originalFlowEntry, FlowEntry::getCategoryId)
|
||||
&& !flowCategoryService.existId(flowEntry.getCategoryId())) {
|
||||
return CallResult.error(String.format(errorMessageFormat, "流程类别Id"));
|
||||
}
|
||||
return CallResult.ok();
|
||||
}
|
||||
|
||||
private void insertBuiltinEntryVariables(Long entryId) {
|
||||
Date now = new Date();
|
||||
FlowEntryVariable operationTypeVariable = new FlowEntryVariable();
|
||||
operationTypeVariable.setVariableId(idGenerator.nextLongId());
|
||||
operationTypeVariable.setEntryId(entryId);
|
||||
operationTypeVariable.setVariableName(FlowConstant.OPERATION_TYPE_VAR);
|
||||
operationTypeVariable.setShowName("审批类型");
|
||||
operationTypeVariable.setVariableType(FlowVariableType.TASK);
|
||||
operationTypeVariable.setBuiltin(true);
|
||||
operationTypeVariable.setCreateTime(now);
|
||||
flowEntryVariableService.saveNew(operationTypeVariable);
|
||||
FlowEntryVariable startUserNameVariable = new FlowEntryVariable();
|
||||
startUserNameVariable.setVariableId(idGenerator.nextLongId());
|
||||
startUserNameVariable.setEntryId(entryId);
|
||||
startUserNameVariable.setVariableName("startUserName");
|
||||
startUserNameVariable.setShowName("流程启动用户");
|
||||
startUserNameVariable.setVariableType(FlowVariableType.INSTANCE);
|
||||
startUserNameVariable.setBuiltin(true);
|
||||
startUserNameVariable.setCreateTime(now);
|
||||
flowEntryVariableService.saveNew(startUserNameVariable);
|
||||
}
|
||||
|
||||
private void insertEntryPublishVariables(List<FlowEntryVariable> entryVariableList, Long entryPublishId) {
|
||||
if (CollUtil.isEmpty(entryVariableList)) {
|
||||
return;
|
||||
}
|
||||
List<FlowEntryPublishVariable> entryPublishVariableList =
|
||||
MyModelUtil.copyCollectionTo(entryVariableList, FlowEntryPublishVariable.class);
|
||||
for (FlowEntryPublishVariable variable : entryPublishVariableList) {
|
||||
variable.setVariableId(idGenerator.nextLongId());
|
||||
variable.setEntryPublishId(entryPublishId);
|
||||
}
|
||||
flowEntryPublishVariableMapper.insertList(entryPublishVariableList);
|
||||
}
|
||||
|
||||
private void mergeTaskNotifyData(FlowEntryExtensionData flowEntryExtensionData, List<FlowTaskExt> flowTaskExtList) {
|
||||
if (CollUtil.isEmpty(flowEntryExtensionData.getNotifyTypes())) {
|
||||
return;
|
||||
}
|
||||
List<String> flowTaskNotifyTypes =
|
||||
flowEntryExtensionData.getNotifyTypes().stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(flowTaskNotifyTypes)) {
|
||||
return;
|
||||
}
|
||||
for (FlowTaskExt flowTaskExt : flowTaskExtList) {
|
||||
if (flowTaskExt.getExtraDataJson() == null) {
|
||||
JSONObject o = new JSONObject();
|
||||
o.put(FlowConstant.USER_TASK_NOTIFY_TYPES_KEY, flowTaskNotifyTypes);
|
||||
flowTaskExt.setExtraDataJson(o.toJSONString());
|
||||
} else {
|
||||
FlowUserTaskExtData taskExtData =
|
||||
JSON.parseObject(flowTaskExt.getExtraDataJson(), FlowUserTaskExtData.class);
|
||||
if (CollUtil.isEmpty(taskExtData.getFlowNotifyTypeList())) {
|
||||
taskExtData.setFlowNotifyTypeList(flowTaskNotifyTypes);
|
||||
} else {
|
||||
Set<String> notifyTypesSet = taskExtData.getFlowNotifyTypeList()
|
||||
.stream().filter(StrUtil::isNotBlank).collect(Collectors.toSet());
|
||||
notifyTypesSet.addAll(flowTaskNotifyTypes);
|
||||
taskExtData.setFlowNotifyTypeList(new LinkedList<>(notifyTypesSet));
|
||||
}
|
||||
flowTaskExt.setExtraDataJson(JSON.toJSONString(taskExtData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doAddLatestApprovalStatusListener(Collection<FlowElement> elementList) {
|
||||
List<FlowElement> sequenceFlowList =
|
||||
elementList.stream().filter(SequenceFlow.class::isInstance).toList();
|
||||
for (FlowElement sequenceFlow : sequenceFlowList) {
|
||||
FlowElementExtProperty extProperty = flowTaskExtService.buildFlowElementExt(sequenceFlow);
|
||||
if (extProperty != null && extProperty.getLatestApprovalStatus() != null) {
|
||||
List<FieldExtension> fieldExtensions = new LinkedList<>();
|
||||
FieldExtension fieldExtension = new FieldExtension();
|
||||
fieldExtension.setFieldName(FlowConstant.LATEST_APPROVAL_STATUS_KEY);
|
||||
fieldExtension.setStringValue(extProperty.getLatestApprovalStatus().toString());
|
||||
fieldExtensions.add(fieldExtension);
|
||||
flowApiService.addExecutionListener(
|
||||
sequenceFlow, UpdateLatestApprovalStatusListener.class, "start", fieldExtensions);
|
||||
}
|
||||
}
|
||||
List<SubProcess> subProcesseList = elementList.stream()
|
||||
.filter(SubProcess.class::isInstance).map(SubProcess.class::cast).toList();
|
||||
for (SubProcess subProcess : subProcesseList) {
|
||||
this.doAddLatestApprovalStatusListener(subProcess.getFlowElements());
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateAllElementList(Collection<FlowElement> elements, List<FlowElement> resultList) {
|
||||
resultList.addAll(elements);
|
||||
for (FlowElement element : elements) {
|
||||
if (element instanceof SubProcess) {
|
||||
this.calculateAllElementList(((SubProcess) element).getFlowElements(), resultList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processFlowTaskExtList(List<FlowTaskExt> flowTaskExtList, BpmnModel bpmnModel) {
|
||||
List<FlowElement> elementList = new LinkedList<>();
|
||||
this.calculateAllElementList(bpmnModel.getMainProcess().getFlowElements(), elementList);
|
||||
this.doAddLatestApprovalStatusListener(elementList);
|
||||
Map<String, FlowElement> elementMap = elementList.stream()
|
||||
.filter(UserTask.class::isInstance).collect(Collectors.toMap(FlowElement::getId, c -> c));
|
||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
for (FlowTaskExt t : flowTaskExtList) {
|
||||
UserTask userTask = (UserTask) elementMap.get(t.getTaskId());
|
||||
flowApiService.addTaskCreateListener(userTask, FlowUserTaskListener.class);
|
||||
Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes();
|
||||
if (CollUtil.isNotEmpty(attributes.get(FlowConstant.USER_TASK_AUTO_SKIP_KEY))) {
|
||||
flowApiService.addTaskCreateListener(userTask, AutoSkipTaskListener.class);
|
||||
}
|
||||
// 如果流程图中包含部门领导审批和上级部门领导审批的选项,就需要注册 FlowCustomExtFactory 工厂中的
|
||||
// BaseFlowIdentityExtHelper 对象,该注册操作需要业务模块中实现。
|
||||
if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER)) {
|
||||
userTask.setCandidateGroups(
|
||||
CollUtil.newArrayList("${" + FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR + "}"));
|
||||
Assert.notNull(flowIdentityExtHelper);
|
||||
flowApiService.addTaskCreateListener(userTask, flowIdentityExtHelper.getUpDeptPostLeaderListener());
|
||||
} else if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_DEPT_POST_LEADER)) {
|
||||
userTask.setCandidateGroups(
|
||||
CollUtil.newArrayList("${" + FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR + "}"));
|
||||
Assert.notNull(flowIdentityExtHelper);
|
||||
flowApiService.addTaskCreateListener(userTask, flowIdentityExtHelper.getDeptPostLeaderListener());
|
||||
} else if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_POST)) {
|
||||
Assert.notNull(t.getDeptPostListJson());
|
||||
List<FlowTaskPostCandidateGroup> groupDataList =
|
||||
JSON.parseArray(t.getDeptPostListJson(), FlowTaskPostCandidateGroup.class);
|
||||
List<String> candidateGroupList =
|
||||
FlowTaskPostCandidateGroup.buildCandidateGroupList(groupDataList);
|
||||
userTask.setCandidateGroups(candidateGroupList);
|
||||
}
|
||||
this.processFlowTaskExtListener(userTask, t);
|
||||
}
|
||||
}
|
||||
|
||||
private void processFlowTaskExtListener(UserTask userTask, FlowTaskExt taskExt) {
|
||||
if (StrUtil.isBlank(taskExt.getExtraDataJson())) {
|
||||
return;
|
||||
}
|
||||
FlowUserTaskExtData userTaskExtData =
|
||||
JSON.parseObject(taskExt.getExtraDataJson(), FlowUserTaskExtData.class);
|
||||
if (CollUtil.isNotEmpty(userTaskExtData.getFlowNotifyTypeList())) {
|
||||
flowApiService.addTaskCreateListener(userTask, FlowTaskNotifyListener.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.dao.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.MyRelationParam;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import com.github.pagehelper.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程变量数据操作服务类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowEntryVariableService")
|
||||
public class FlowEntryVariableServiceImpl extends BaseService<FlowEntryVariable, Long> implements FlowEntryVariableService {
|
||||
|
||||
@Autowired
|
||||
private FlowEntryVariableMapper flowEntryVariableMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowEntryVariable> mapper() {
|
||||
return flowEntryVariableMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowEntryVariable 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowEntryVariable saveNew(FlowEntryVariable flowEntryVariable) {
|
||||
flowEntryVariable.setVariableId(idGenerator.nextLongId());
|
||||
flowEntryVariable.setCreateTime(new Date());
|
||||
flowEntryVariableMapper.insert(flowEntryVariable);
|
||||
return flowEntryVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据对象。
|
||||
*
|
||||
* @param flowEntryVariable 更新的对象。
|
||||
* @param originalFlowEntryVariable 原有数据对象。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean update(FlowEntryVariable flowEntryVariable, FlowEntryVariable originalFlowEntryVariable) {
|
||||
flowEntryVariable.setCreateTime(originalFlowEntryVariable.getCreateTime());
|
||||
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
|
||||
return flowEntryVariableMapper.update(flowEntryVariable, false) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param variableId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean remove(Long variableId) {
|
||||
return flowEntryVariableMapper.deleteById(variableId) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定流程Id的所有变量。
|
||||
*
|
||||
* @param entryId 流程Id。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void removeByEntryId(Long entryId) {
|
||||
flowEntryVariableMapper.deleteByQuery(new QueryWrapper().eq(FlowEntryVariable::getEntryId, entryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
|
||||
* 如果需要同时获取关联数据,请移步(getFlowEntryVariableListWithRelation)方法。
|
||||
*
|
||||
* @param filter 过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
@Override
|
||||
public List<FlowEntryVariable> getFlowEntryVariableList(FlowEntryVariable filter, String orderBy) {
|
||||
return flowEntryVariableMapper.getFlowEntryVariableList(filter, orderBy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
|
||||
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
|
||||
* 如果仅仅需要获取主表数据,请移步(getFlowEntryVariableList),以便获取更好的查询性能。
|
||||
*
|
||||
* @param filter 主表过滤对象。
|
||||
* @param orderBy 排序参数。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
@Override
|
||||
public List<FlowEntryVariable> getFlowEntryVariableListWithRelation(FlowEntryVariable filter, String orderBy) {
|
||||
List<FlowEntryVariable> resultList = flowEntryVariableMapper.getFlowEntryVariableList(filter, orderBy);
|
||||
// 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。
|
||||
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
|
||||
int batchSize = resultList instanceof Page ? 0 : 1000;
|
||||
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize);
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.model.constant.FlowMessageOperationType;
|
||||
import com.orangeforms.common.flow.model.constant.FlowMessageType;
|
||||
import com.orangeforms.common.flow.dao.FlowMessageIdentityOperationMapper;
|
||||
import com.orangeforms.common.flow.dao.FlowMessageCandidateIdentityMapper;
|
||||
import com.orangeforms.common.flow.dao.FlowMessageMapper;
|
||||
import com.orangeforms.common.flow.object.FlowTaskPostCandidateGroup;
|
||||
import com.orangeforms.common.flow.service.FlowApiService;
|
||||
import com.orangeforms.common.flow.service.FlowMessageService;
|
||||
import com.orangeforms.common.flow.service.FlowTaskExtService;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.vo.TaskInfoVo;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流消息数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowMessageService")
|
||||
public class FlowMessageServiceImpl extends BaseService<FlowMessage, Long> implements FlowMessageService {
|
||||
|
||||
@Autowired
|
||||
private FlowMessageMapper flowMessageMapper;
|
||||
@Autowired
|
||||
private FlowMessageCandidateIdentityMapper flowMessageCandidateIdentityMapper;
|
||||
@Autowired
|
||||
private FlowMessageIdentityOperationMapper flowMessageIdentityOperationMapper;
|
||||
@Autowired
|
||||
private FlowTaskExtService flowTaskExtService;
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowCustomExtFactory flowCustomExtFactory;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowMessage> mapper() {
|
||||
return flowMessageMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowMessage saveNew(FlowMessage flowMessage) {
|
||||
flowMessage.setMessageId(idGenerator.nextLongId());
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (tokenData != null) {
|
||||
flowMessage.setTenantId(tokenData.getTenantId());
|
||||
flowMessage.setAppCode(tokenData.getAppCode());
|
||||
flowMessage.setCreateUserId(tokenData.getUserId());
|
||||
flowMessage.setCreateUsername(tokenData.getShowName());
|
||||
flowMessage.setUpdateUserId(tokenData.getUserId());
|
||||
}
|
||||
flowMessage.setCreateTime(new Date());
|
||||
flowMessage.setUpdateTime(flowMessage.getCreateTime());
|
||||
flowMessageMapper.insert(flowMessage);
|
||||
return flowMessage;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveNewRemindMessage(FlowWorkOrder flowWorkOrder) {
|
||||
List<Task> taskList =
|
||||
flowApiService.getProcessInstanceActiveTaskList(flowWorkOrder.getProcessInstanceId());
|
||||
for (Task task : taskList) {
|
||||
FlowMessage filter = new FlowMessage();
|
||||
filter.setTaskId(task.getId());
|
||||
List<FlowMessage> messageList = flowMessageMapper.selectListByQuery(QueryWrapper.create(filter));
|
||||
// 同一个任务只能催办一次,多次催办则累加催办次数。
|
||||
if (CollUtil.isNotEmpty(messageList)) {
|
||||
for (FlowMessage flowMessage : messageList) {
|
||||
flowMessage.setRemindCount(flowMessage.getRemindCount() + 1);
|
||||
flowMessageMapper.update(flowMessage);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
FlowMessage flowMessage = BeanUtil.copyProperties(flowWorkOrder, FlowMessage.class);
|
||||
flowMessage.setMessageType(FlowMessageType.REMIND_TYPE);
|
||||
flowMessage.setRemindCount(1);
|
||||
flowMessage.setProcessInstanceInitiator(flowWorkOrder.getSubmitUsername());
|
||||
flowMessage.setTaskId(task.getId());
|
||||
flowMessage.setTaskName(task.getName());
|
||||
flowMessage.setTaskStartTime(task.getCreateTime());
|
||||
flowMessage.setTaskAssignee(task.getAssignee());
|
||||
flowMessage.setTaskFinished(false);
|
||||
if (TokenData.takeFromRequest() == null) {
|
||||
Set<String> usernameSet = CollUtil.newHashSet(flowWorkOrder.getSubmitUsername());
|
||||
Map<String, String> m = flowCustomExtFactory.getFlowIdentityExtHelper().mapUserShowNameByLoginName(usernameSet);
|
||||
flowMessage.setCreateUsername(m.containsKey(flowWorkOrder.getSubmitUsername())
|
||||
? m.get(flowWorkOrder.getSubmitUsername()) : flowWorkOrder.getSubmitUsername());
|
||||
}
|
||||
this.saveNew(flowMessage);
|
||||
FlowTaskExt flowTaskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(
|
||||
flowWorkOrder.getProcessDefinitionId(), task.getTaskDefinitionKey());
|
||||
if (flowTaskExt != null) {
|
||||
// 插入与当前消息关联任务的候选人
|
||||
this.saveMessageCandidateIdentityWithMessage(
|
||||
flowWorkOrder.getProcessInstanceId(), flowTaskExt, task, flowMessage.getMessageId());
|
||||
}
|
||||
// 插入与当前消息关联任务的指派人。
|
||||
if (StrUtil.isNotBlank(task.getAssignee())) {
|
||||
this.saveMessageCandidateIdentity(
|
||||
flowMessage.getMessageId(), FlowConstant.GROUP_TYPE_USER_VAR, task.getAssignee());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveNewCopyMessage(Task task, JSONObject copyDataJson) {
|
||||
if (copyDataJson.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ProcessInstance instance = flowApiService.getProcessInstance(task.getProcessInstanceId());
|
||||
FlowMessage flowMessage = new FlowMessage();
|
||||
flowMessage.setMessageType(FlowMessageType.COPY_TYPE);
|
||||
flowMessage.setRemindCount(0);
|
||||
flowMessage.setProcessDefinitionId(instance.getProcessDefinitionId());
|
||||
flowMessage.setProcessDefinitionKey(instance.getProcessDefinitionKey());
|
||||
flowMessage.setProcessDefinitionName(instance.getProcessDefinitionName());
|
||||
flowMessage.setProcessInstanceId(instance.getProcessInstanceId());
|
||||
flowMessage.setProcessInstanceInitiator(instance.getStartUserId());
|
||||
flowMessage.setTaskId(task.getId());
|
||||
flowMessage.setTaskDefinitionKey(task.getTaskDefinitionKey());
|
||||
flowMessage.setTaskName(task.getName());
|
||||
flowMessage.setTaskStartTime(task.getCreateTime());
|
||||
flowMessage.setTaskAssignee(task.getAssignee());
|
||||
flowMessage.setTaskFinished(false);
|
||||
flowMessage.setOnlineFormData(true);
|
||||
// 如果是在线表单,这里就保存关联的在线表单Id,便于在线表单业务数据的查找。
|
||||
if (BooleanUtil.isTrue(flowMessage.getOnlineFormData())) {
|
||||
TaskInfoVo taskInfo = JSON.parseObject(task.getFormKey(), TaskInfoVo.class);
|
||||
flowMessage.setBusinessDataShot(taskInfo.getFormId().toString());
|
||||
}
|
||||
this.saveNew(flowMessage);
|
||||
for (Map.Entry<String, Object> entry : copyDataJson.entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
this.saveMessageCandidateIdentityList(
|
||||
flowMessage.getMessageId(), entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateFinishedStatusByTaskId(String taskId) {
|
||||
FlowMessage flowMessage = new FlowMessage();
|
||||
flowMessage.setTaskFinished(true);
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowMessage::getTaskId, taskId);
|
||||
flowMessageMapper.updateByQuery(flowMessage, queryWrapper);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateFinishedStatusByProcessInstanceId(String processInstanceId) {
|
||||
FlowMessage flowMessage = new FlowMessage();
|
||||
flowMessage.setTaskFinished(true);
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowMessage::getProcessInstanceId, processInstanceId);
|
||||
flowMessageMapper.updateByQuery(flowMessage, queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowMessage> getRemindingMessageListByUser() {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
return flowMessageMapper.getRemindingMessageListByUser(
|
||||
tokenData.getTenantId(), tokenData.getAppCode(), tokenData.getLoginName(), buildGroupIdSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowMessage> getCopyMessageListByUser(Boolean read) {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
return flowMessageMapper.getCopyMessageListByUser(
|
||||
tokenData.getTenantId(), tokenData.getAppCode(), tokenData.getLoginName(), buildGroupIdSet(), read);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCandidateIdentityOnMessage(Long messageId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowMessageCandidateIdentity::getMessageId, messageId);
|
||||
queryWrapper.in(FlowMessageCandidateIdentity::getCandidateId, buildGroupIdSet());
|
||||
return flowMessageCandidateIdentityMapper.selectCountByQuery(queryWrapper) > 0;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void readCopyTask(Long messageId) {
|
||||
FlowMessageIdentityOperation operation = new FlowMessageIdentityOperation();
|
||||
operation.setId(idGenerator.nextLongId());
|
||||
operation.setMessageId(messageId);
|
||||
operation.setLoginName(TokenData.takeFromRequest().getLoginName());
|
||||
operation.setOperationType(FlowMessageOperationType.READ_FINISHED);
|
||||
operation.setOperationTime(new Date());
|
||||
flowMessageIdentityOperationMapper.insert(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countRemindingMessageListByUser() {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
return flowMessageMapper.countRemindingMessageListByUser(
|
||||
tokenData.getTenantId(), tokenData.getAppCode(), tokenData.getLoginName(), buildGroupIdSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countCopyMessageByUser() {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
return flowMessageMapper.countCopyMessageListByUser(
|
||||
tokenData.getTenantId(), tokenData.getAppCode(), tokenData.getLoginName(), buildGroupIdSet());
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void removeByProcessInstanceId(String processInstanceId) {
|
||||
flowMessageCandidateIdentityMapper.deleteByProcessInstanceId(processInstanceId);
|
||||
flowMessageIdentityOperationMapper.deleteByProcessInstanceId(processInstanceId);
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowMessage::getProcessInstanceId, processInstanceId);
|
||||
flowMessageMapper.deleteByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
private Set<String> buildGroupIdSet() {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
Set<String> groupIdSet = new HashSet<>(1);
|
||||
groupIdSet.add(tokenData.getLoginName());
|
||||
this.parseAndAddIdArray(groupIdSet, tokenData.getRoleIds());
|
||||
this.parseAndAddIdArray(groupIdSet, tokenData.getDeptPostIds());
|
||||
this.parseAndAddIdArray(groupIdSet, tokenData.getPostIds());
|
||||
if (tokenData.getDeptId() != null) {
|
||||
groupIdSet.add(tokenData.getDeptId().toString());
|
||||
}
|
||||
return groupIdSet;
|
||||
}
|
||||
|
||||
private void parseAndAddIdArray(Set<String> groupIdSet, String idArray) {
|
||||
if (StrUtil.isNotBlank(idArray)) {
|
||||
if (groupIdSet == null) {
|
||||
groupIdSet = new HashSet<>();
|
||||
}
|
||||
groupIdSet.addAll(StrUtil.split(idArray, ','));
|
||||
}
|
||||
}
|
||||
|
||||
private void saveMessageCandidateIdentityWithMessage(
|
||||
String processInstanceId, FlowTaskExt flowTaskExt, Task task, Long messageId) {
|
||||
List<String> candidates = flowApiService.getCandidateUsernames(flowTaskExt, task.getId());
|
||||
if (CollUtil.isNotEmpty(candidates)) {
|
||||
this.saveMessageCandidateIdentityList(
|
||||
messageId, FlowConstant.GROUP_TYPE_USER_VAR, CollUtil.join(candidates, ","));
|
||||
}
|
||||
this.saveMessageCandidateIdentityList(
|
||||
messageId, FlowConstant.GROUP_TYPE_ROLE_VAR, flowTaskExt.getRoleIds());
|
||||
this.saveMessageCandidateIdentityList(
|
||||
messageId, FlowConstant.GROUP_TYPE_DEPT_VAR, flowTaskExt.getDeptIds());
|
||||
if (StrUtil.equals(flowTaskExt.getGroupType(), FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER)) {
|
||||
Object v = flowApiService.getProcessInstanceVariable(
|
||||
processInstanceId, FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR);
|
||||
if (v != null) {
|
||||
this.saveMessageCandidateIdentity(
|
||||
messageId, FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR, v.toString());
|
||||
}
|
||||
} else if (StrUtil.equals(flowTaskExt.getGroupType(), FlowConstant.GROUP_TYPE_DEPT_POST_LEADER)) {
|
||||
Object v = flowApiService.getProcessInstanceVariable(
|
||||
processInstanceId, FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR);
|
||||
if (v != null) {
|
||||
this.saveMessageCandidateIdentity(
|
||||
messageId, FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR, v.toString());
|
||||
}
|
||||
} else if (StrUtil.equals(flowTaskExt.getGroupType(), FlowConstant.GROUP_TYPE_POST)) {
|
||||
Assert.notBlank(flowTaskExt.getDeptPostListJson());
|
||||
List<FlowTaskPostCandidateGroup> groupDataList =
|
||||
JSONArray.parseArray(flowTaskExt.getDeptPostListJson(), FlowTaskPostCandidateGroup.class);
|
||||
for (FlowTaskPostCandidateGroup groupData : groupDataList) {
|
||||
this.saveMessageCandidateIdentity(messageId, processInstanceId, groupData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveMessageCandidateIdentity(
|
||||
Long messageId, String processInstanceId, FlowTaskPostCandidateGroup groupData) {
|
||||
FlowMessageCandidateIdentity candidateIdentity = new FlowMessageCandidateIdentity();
|
||||
candidateIdentity.setId(idGenerator.nextLongId());
|
||||
candidateIdentity.setMessageId(messageId);
|
||||
candidateIdentity.setCandidateType(groupData.getType());
|
||||
switch (groupData.getType()) {
|
||||
case FlowConstant.GROUP_TYPE_ALL_DEPT_POST_VAR:
|
||||
candidateIdentity.setCandidateId(groupData.getPostId());
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_DEPT_POST_VAR:
|
||||
candidateIdentity.setCandidateId(groupData.getDeptPostId());
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_SELF_DEPT_POST_VAR:
|
||||
Object v = flowApiService.getProcessInstanceVariable(
|
||||
processInstanceId, FlowConstant.SELF_DEPT_POST_PREFIX + groupData.getPostId());
|
||||
if (v != null) {
|
||||
candidateIdentity.setCandidateId(v.toString());
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
}
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_UP_DEPT_POST_VAR:
|
||||
Object v2 = flowApiService.getProcessInstanceVariable(
|
||||
processInstanceId, FlowConstant.UP_DEPT_POST_PREFIX + groupData.getPostId());
|
||||
if (v2 != null) {
|
||||
candidateIdentity.setCandidateId(v2.toString());
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
}
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_SIBLING_DEPT_POST_VAR:
|
||||
Object v3 = flowApiService.getProcessInstanceVariable(
|
||||
processInstanceId, FlowConstant.SIBLING_DEPT_POST_PREFIX + groupData.getPostId());
|
||||
if (v3 != null) {
|
||||
List<String> candidateIds = StrUtil.split(v3.toString(), ",");
|
||||
for (String candidateId : candidateIds) {
|
||||
candidateIdentity.setId(idGenerator.nextLongId());
|
||||
candidateIdentity.setCandidateId(candidateId);
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void saveMessageCandidateIdentity(Long messageId, String candidateType, String candidateId) {
|
||||
FlowMessageCandidateIdentity candidateIdentity = new FlowMessageCandidateIdentity();
|
||||
candidateIdentity.setId(idGenerator.nextLongId());
|
||||
candidateIdentity.setMessageId(messageId);
|
||||
candidateIdentity.setCandidateType(candidateType);
|
||||
candidateIdentity.setCandidateId(candidateId);
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
}
|
||||
|
||||
private void saveMessageCandidateIdentityList(Long messageId, String candidateType, String identityIds) {
|
||||
if (StrUtil.isNotBlank(identityIds)) {
|
||||
for (String identityId : StrUtil.split(identityIds, ',')) {
|
||||
FlowMessageCandidateIdentity candidateIdentity = new FlowMessageCandidateIdentity();
|
||||
candidateIdentity.setId(idGenerator.nextLongId());
|
||||
candidateIdentity.setMessageId(messageId);
|
||||
candidateIdentity.setCandidateType(candidateType);
|
||||
candidateIdentity.setCandidateId(identityId);
|
||||
flowMessageCandidateIdentityMapper.insert(candidateIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.flow.dao.FlowMultiInstanceTransMapper;
|
||||
import com.orangeforms.common.flow.model.FlowMultiInstanceTrans;
|
||||
import com.orangeforms.common.flow.service.FlowMultiInstanceTransService;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 会签任务操作流水数据操作服务接口。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowMultiInstanceTransService")
|
||||
public class FlowMultiInstanceTransServiceImpl
|
||||
extends BaseService<FlowMultiInstanceTrans, Long> implements FlowMultiInstanceTransService {
|
||||
|
||||
@Autowired
|
||||
private FlowMultiInstanceTransMapper flowMultiInstanceTransMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowMultiInstanceTrans> mapper() {
|
||||
return flowMultiInstanceTransMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowMultiInstanceTrans 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowMultiInstanceTrans saveNew(FlowMultiInstanceTrans flowMultiInstanceTrans) {
|
||||
flowMultiInstanceTrans.setId(idGenerator.nextLongId());
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
flowMultiInstanceTrans.setCreateUserId(tokenData.getUserId());
|
||||
flowMultiInstanceTrans.setCreateLoginName(tokenData.getLoginName());
|
||||
flowMultiInstanceTrans.setCreateUsername(tokenData.getShowName());
|
||||
flowMultiInstanceTrans.setCreateTime(new Date());
|
||||
flowMultiInstanceTransMapper.insert(flowMultiInstanceTrans);
|
||||
return flowMultiInstanceTrans;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowMultiInstanceTrans getByExecutionId(String executionId, String taskId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowMultiInstanceTrans::getExecutionId, executionId);
|
||||
queryWrapper.eq(FlowMultiInstanceTrans::getTaskId, taskId);
|
||||
return flowMultiInstanceTransMapper.selectOneByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowMultiInstanceTrans getWithAssigneeListByMultiInstanceExecId(String multiInstanceExecId) {
|
||||
if (multiInstanceExecId == null) {
|
||||
return null;
|
||||
}
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowMultiInstanceTrans::getMultiInstanceExecId, multiInstanceExecId);
|
||||
queryWrapper.isNotNull(FlowMultiInstanceTrans::getAssigneeList);
|
||||
return flowMultiInstanceTransMapper.selectOneByQuery(queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.dao.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.object.TokenData;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 流程任务批注数据操作服务类。
|
||||
*
|
||||
* @author Jerry
|
||||
* @date 2024-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowTaskCommentService")
|
||||
public class FlowTaskCommentServiceImpl extends BaseService<FlowTaskComment, Long> implements FlowTaskCommentService {
|
||||
|
||||
@Autowired
|
||||
private FlowTaskCommentMapper flowTaskCommentMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowTaskComment> mapper() {
|
||||
return flowTaskCommentMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param flowTaskComment 新增对象。
|
||||
* @return 返回新增对象。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowTaskComment saveNew(FlowTaskComment flowTaskComment) {
|
||||
flowTaskComment.setId(idGenerator.nextLongId());
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
if (tokenData != null) {
|
||||
flowTaskComment.setHeadImageUrl(tokenData.getHeadImageUrl());
|
||||
flowTaskComment.setCreateUserId(tokenData.getUserId());
|
||||
flowTaskComment.setCreateLoginName(tokenData.getLoginName());
|
||||
flowTaskComment.setCreateUsername(tokenData.getShowName());
|
||||
}
|
||||
flowTaskComment.setCreateTime(new Date());
|
||||
flowTaskCommentMapper.insert(flowTaskComment);
|
||||
FlowTaskComment.setToRequest(flowTaskComment);
|
||||
return flowTaskComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定流程实例Id下的所有审批任务的批注。
|
||||
*
|
||||
* @param processInstanceId 流程实例Id。
|
||||
* @return 查询结果集。
|
||||
*/
|
||||
@Override
|
||||
public List<FlowTaskComment> getFlowTaskCommentList(String processInstanceId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowTaskComment::getProcessInstanceId, processInstanceId);
|
||||
queryWrapper.orderBy(FlowTaskComment::getId, true);
|
||||
return flowTaskCommentMapper.selectListByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowTaskComment> getFlowTaskCommentListByTaskIds(Set<String> taskIdSet) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper().in(FlowTaskComment::getTaskId, taskIdSet);
|
||||
queryWrapper.orderBy(FlowTaskComment::getId, false);
|
||||
return flowTaskCommentMapper.selectListByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowTaskComment getLatestFlowTaskComment(String processInstanceId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowTaskComment::getProcessInstanceId, processInstanceId);
|
||||
queryWrapper.orderBy(FlowTaskComment::getId, false);
|
||||
Page<FlowTaskComment> pageData = flowTaskCommentMapper.paginate(new Page<>(1, 1), queryWrapper);
|
||||
return CollUtil.isEmpty(pageData.getRecords()) ? null : pageData.getRecords().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowTaskComment getLatestFlowTaskComment(String processInstanceId, String taskDefinitionKey) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowTaskComment::getProcessInstanceId, processInstanceId);
|
||||
queryWrapper.eq(FlowTaskComment::getTaskKey, taskDefinitionKey);
|
||||
queryWrapper.orderBy(FlowTaskComment::getId, false);
|
||||
Page<FlowTaskComment> pageData = flowTaskCommentMapper.paginate(new Page<>(1, 1), queryWrapper);
|
||||
return CollUtil.isEmpty(pageData.getRecords()) ? null : pageData.getRecords().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowTaskComment getFirstFlowTaskComment(String processInstanceId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowTaskComment::getProcessInstanceId, processInstanceId);
|
||||
queryWrapper.orderBy(FlowTaskComment::getId, true);
|
||||
Page<FlowTaskComment> pageData = flowTaskCommentMapper.paginate(new Page<>(1, 1), queryWrapper);
|
||||
return CollUtil.isEmpty(pageData.getRecords()) ? null : pageData.getRecords().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowTaskComment> getFlowTaskCommentListByExecutionId(
|
||||
String processInstanceId, String taskId, String executionId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowTaskComment::getProcessInstanceId, processInstanceId);
|
||||
queryWrapper.eq(FlowTaskComment::getTaskId, taskId);
|
||||
queryWrapper.eq(FlowTaskComment::getExecutionId, executionId);
|
||||
queryWrapper.orderBy(FlowTaskComment::getCreateTime, true);
|
||||
return flowTaskCommentMapper.selectListByQuery(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowTaskComment> getFlowTaskCommentListByMultiInstanceExecId(String multiInstanceExecId) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowTaskComment::getMultiInstanceExecId, multiInstanceExecId);
|
||||
return flowTaskCommentMapper.selectListByQuery(queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.exception.MyRuntimeException;
|
||||
import com.orangeforms.common.core.object.Tuple2;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.flow.constant.FlowApprovalType;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.object.FlowElementExtProperty;
|
||||
import com.orangeforms.common.flow.object.FlowTaskMultiSignAssign;
|
||||
import com.orangeforms.common.flow.object.FlowUserTaskExtData;
|
||||
import com.orangeforms.common.flow.service.*;
|
||||
import com.orangeforms.common.flow.dao.*;
|
||||
import com.orangeforms.common.flow.model.*;
|
||||
import com.orangeforms.common.flow.util.BaseFlowIdentityExtHelper;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.flow.vo.FlowUserInfoVo;
|
||||
import com.orangeforms.common.flow.vo.TaskInfoVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.task.api.TaskInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowTaskExtService")
|
||||
public class FlowTaskExtServiceImpl extends BaseService<FlowTaskExt, String> implements FlowTaskExtService {
|
||||
|
||||
@Autowired
|
||||
private FlowTaskExtMapper flowTaskExtMapper;
|
||||
@Autowired
|
||||
private FlowEntryVariableService flowEntryVariableService;
|
||||
@Autowired
|
||||
private FlowCustomExtFactory flowCustomExtFactory;
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowMultiInstanceTransService flowMultiInstanceTransService;
|
||||
@Autowired
|
||||
private FlowTaskCommentService flowTaskCommentService;
|
||||
|
||||
private static final String ID = "id";
|
||||
private static final String TYPE = "type";
|
||||
private static final String LABEL = "label";
|
||||
private static final String NAME = "name";
|
||||
private static final String VALUE = "value";
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowTaskExt> mapper() {
|
||||
return flowTaskExtMapper;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void saveBatch(List<FlowTaskExt> flowTaskExtList) {
|
||||
if (CollUtil.isNotEmpty(flowTaskExtList)) {
|
||||
flowTaskExtMapper.insertList(flowTaskExtList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowTaskExt getByProcessDefinitionIdAndTaskId(String processDefinitionId, String taskId) {
|
||||
FlowTaskExt filter = new FlowTaskExt();
|
||||
filter.setProcessDefinitionId(processDefinitionId);
|
||||
filter.setTaskId(taskId);
|
||||
return flowTaskExtMapper.selectOneByQuery(QueryWrapper.create(filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowTaskExt> getByProcessDefinitionId(String processDefinitionId) {
|
||||
FlowTaskExt filter = new FlowTaskExt();
|
||||
filter.setProcessDefinitionId(processDefinitionId);
|
||||
return flowTaskExtMapper.selectListByQuery(QueryWrapper.create(filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowUserInfoVo> getCandidateUserInfoList(
|
||||
String processInstanceId,
|
||||
FlowTaskExt flowTaskExt,
|
||||
TaskInfo taskInfo,
|
||||
boolean isMultiInstanceTask,
|
||||
boolean historic) {
|
||||
List<FlowUserInfoVo> resultUserMapList = new LinkedList<>();
|
||||
if (!isMultiInstanceTask && this.buildTransferUserList(taskInfo, resultUserMapList)) {
|
||||
return resultUserMapList;
|
||||
}
|
||||
Set<String> loginNameSet = new HashSet<>();
|
||||
this.buildFlowUserInfoListByDeptAndRoleIds(flowTaskExt, loginNameSet, resultUserMapList);
|
||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
Set<String> usernameSet = new HashSet<>();
|
||||
switch (flowTaskExt.getGroupType()) {
|
||||
case FlowConstant.GROUP_TYPE_ASSIGNEE:
|
||||
usernameSet.add(taskInfo.getAssignee());
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_DEPT_POST_LEADER:
|
||||
String deptPostLeaderId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
taskInfo.getExecutionId(), FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR);
|
||||
List<FlowUserInfoVo> userInfoList =
|
||||
flowIdentityExtHelper.getUserInfoListByDeptPostIds(CollUtil.newHashSet(deptPostLeaderId));
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER:
|
||||
String upDeptPostLeaderId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
taskInfo.getExecutionId(), FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR);
|
||||
List<FlowUserInfoVo> upUserInfoList =
|
||||
flowIdentityExtHelper.getUserInfoListByDeptPostIds(CollUtil.newHashSet(upDeptPostLeaderId));
|
||||
this.buildUserMapList(upUserInfoList, loginNameSet, resultUserMapList);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
List<String> candidateUsernames = flowApiService.getCandidateUsernames(flowTaskExt, taskInfo.getId());
|
||||
if (CollUtil.isNotEmpty(candidateUsernames)) {
|
||||
usernameSet.addAll(candidateUsernames);
|
||||
}
|
||||
if (isMultiInstanceTask) {
|
||||
List<String> assigneeList = this.getAssigneeList(taskInfo.getExecutionId(), taskInfo.getId());
|
||||
if (CollUtil.isNotEmpty(assigneeList)) {
|
||||
usernameSet.addAll(assigneeList);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(usernameSet)) {
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByUsernameSet(usernameSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
Tuple2<Set<String>, Set<String>> tuple2 =
|
||||
flowApiService.getDeptPostIdAndPostIds(flowTaskExt, processInstanceId, historic);
|
||||
Set<String> postIdSet = tuple2.getSecond();
|
||||
Set<String> deptPostIdSet = tuple2.getFirst();
|
||||
if (CollUtil.isNotEmpty(postIdSet)) {
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByPostIds(postIdSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(deptPostIdSet)) {
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByDeptPostIds(deptPostIdSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
return resultUserMapList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowUserInfoVo> getCandidateUserInfoList(
|
||||
String processInstanceId,
|
||||
String executionId,
|
||||
FlowTaskExt flowTaskExt) {
|
||||
List<FlowUserInfoVo> resultUserMapList = new LinkedList<>();
|
||||
Set<String> loginNameSet = new HashSet<>();
|
||||
this.buildFlowUserInfoListByDeptAndRoleIds(flowTaskExt, loginNameSet, resultUserMapList);
|
||||
Set<String> usernameSet = new HashSet<>();
|
||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
switch (flowTaskExt.getGroupType()) {
|
||||
case FlowConstant.GROUP_TYPE_DEPT_POST_LEADER:
|
||||
String deptPostLeaderId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
executionId, FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR);
|
||||
List<FlowUserInfoVo> userInfoList =
|
||||
flowIdentityExtHelper.getUserInfoListByDeptPostIds(CollUtil.newHashSet(deptPostLeaderId));
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
break;
|
||||
case FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER:
|
||||
String upDeptPostLeaderId = flowApiService.getExecutionVariableStringWithSafe(
|
||||
executionId, FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR);
|
||||
List<FlowUserInfoVo> upUserInfoList =
|
||||
flowIdentityExtHelper.getUserInfoListByDeptPostIds(CollUtil.newHashSet(upDeptPostLeaderId));
|
||||
this.buildUserMapList(upUserInfoList, loginNameSet, resultUserMapList);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
List<String> candidateUsernames;
|
||||
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
|
||||
candidateUsernames = Collections.emptyList();
|
||||
} else {
|
||||
if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
|
||||
candidateUsernames = StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
|
||||
} else {
|
||||
Object v = flowApiService.getExecutionVariableStringWithSafe(executionId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
|
||||
candidateUsernames = v == null ? null : StrUtil.split(v.toString(), ",");
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(candidateUsernames)) {
|
||||
usernameSet.addAll(candidateUsernames);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(usernameSet)) {
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByUsernameSet(usernameSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
Tuple2<Set<String>, Set<String>> tuple2 =
|
||||
flowApiService.getDeptPostIdAndPostIds(flowTaskExt, processInstanceId, false);
|
||||
Set<String> postIdSet = tuple2.getSecond();
|
||||
Set<String> deptPostIdSet = tuple2.getFirst();
|
||||
if (CollUtil.isNotEmpty(postIdSet)) {
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByPostIds(postIdSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(deptPostIdSet)) {
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByDeptPostIds(deptPostIdSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
return resultUserMapList;
|
||||
}
|
||||
|
||||
private void buildUserMapList(
|
||||
List<FlowUserInfoVo> userInfoList, Set<String> loginNameSet, List<FlowUserInfoVo> userMapList) {
|
||||
if (CollUtil.isEmpty(userInfoList)) {
|
||||
return;
|
||||
}
|
||||
for (FlowUserInfoVo userInfo : userInfoList) {
|
||||
if (!loginNameSet.contains(userInfo.getLoginName())) {
|
||||
loginNameSet.add(userInfo.getLoginName());
|
||||
userMapList.add(userInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowTaskExt buildTaskExtByUserTask(UserTask userTask) {
|
||||
FlowTaskExt flowTaskExt = new FlowTaskExt();
|
||||
flowTaskExt.setTaskId(userTask.getId());
|
||||
String formKey = userTask.getFormKey();
|
||||
if (StrUtil.isNotBlank(formKey)) {
|
||||
TaskInfoVo taskInfoVo = JSON.parseObject(formKey, TaskInfoVo.class);
|
||||
flowTaskExt.setGroupType(taskInfoVo.getGroupType());
|
||||
}
|
||||
JSONObject extraDataJson = this.buildFlowTaskExtensionData(userTask);
|
||||
if (extraDataJson != null) {
|
||||
flowTaskExt.setExtraDataJson(extraDataJson.toJSONString());
|
||||
}
|
||||
Map<String, List<ExtensionElement>> extensionMap = userTask.getExtensionElements();
|
||||
if (MapUtil.isEmpty(extensionMap)) {
|
||||
return flowTaskExt;
|
||||
}
|
||||
List<JSONObject> operationList = this.buildOperationListExtensionElement(extensionMap);
|
||||
if (CollUtil.isNotEmpty(operationList)) {
|
||||
flowTaskExt.setOperationListJson(JSON.toJSONString(operationList));
|
||||
}
|
||||
List<JSONObject> variableList = this.buildVariableListExtensionElement(extensionMap);
|
||||
if (CollUtil.isNotEmpty(variableList)) {
|
||||
flowTaskExt.setVariableListJson(JSON.toJSONString(variableList));
|
||||
}
|
||||
JSONObject assigneeListObject = this.buildAssigneeListExtensionElement(extensionMap);
|
||||
if (assigneeListObject != null) {
|
||||
flowTaskExt.setAssigneeListJson(JSON.toJSONString(assigneeListObject));
|
||||
}
|
||||
List<JSONObject> deptPostList = this.buildDeptPostListExtensionElement(extensionMap);
|
||||
if (deptPostList != null) {
|
||||
flowTaskExt.setDeptPostListJson(JSON.toJSONString(deptPostList));
|
||||
}
|
||||
List<JSONObject> copyList = this.buildCopyListExtensionElement(extensionMap);
|
||||
if (copyList != null) {
|
||||
flowTaskExt.setCopyListJson(JSON.toJSONString(copyList));
|
||||
}
|
||||
JSONObject candidateGroupObject = this.buildUserCandidateGroupsExtensionElement(extensionMap);
|
||||
if (candidateGroupObject != null) {
|
||||
String type = candidateGroupObject.getString(TYPE);
|
||||
String value = candidateGroupObject.getString(VALUE);
|
||||
switch (type) {
|
||||
case "DEPT":
|
||||
flowTaskExt.setDeptIds(value);
|
||||
break;
|
||||
case "ROLE":
|
||||
flowTaskExt.setRoleIds(value);
|
||||
break;
|
||||
case "USERS":
|
||||
flowTaskExt.setCandidateUsernames(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return flowTaskExt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowTaskExt> buildTaskExtList(BpmnModel bpmnModel) {
|
||||
List<Process> processList = bpmnModel.getProcesses();
|
||||
List<FlowTaskExt> flowTaskExtList = new LinkedList<>();
|
||||
for (Process process : processList) {
|
||||
for (FlowElement element : process.getFlowElements()) {
|
||||
this.doBuildTaskExtList(element, flowTaskExtList);
|
||||
}
|
||||
}
|
||||
return flowTaskExtList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JSONObject> buildOperationListExtensionElement(Map<String, List<ExtensionElement>> extensionMap) {
|
||||
List<ExtensionElement> formOperationElements =
|
||||
this.getMyExtensionElementList(extensionMap, "operationList", "formOperation");
|
||||
if (CollUtil.isEmpty(formOperationElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<JSONObject> resultList = new LinkedList<>();
|
||||
for (ExtensionElement e : formOperationElements) {
|
||||
JSONObject operationJsonData = new JSONObject();
|
||||
operationJsonData.put(ID, e.getAttributeValue(null, ID));
|
||||
operationJsonData.put(LABEL, e.getAttributeValue(null, LABEL));
|
||||
operationJsonData.put(TYPE, e.getAttributeValue(null, TYPE));
|
||||
operationJsonData.put("showOrder", e.getAttributeValue(null, "showOrder"));
|
||||
operationJsonData.put("latestApprovalStatus", e.getAttributeValue(null, "latestApprovalStatus"));
|
||||
String multiSignAssignee = e.getAttributeValue(null, "multiSignAssignee");
|
||||
if (StrUtil.isNotBlank(multiSignAssignee)) {
|
||||
operationJsonData.put("multiSignAssignee",
|
||||
JSON.parseObject(multiSignAssignee, FlowTaskMultiSignAssign.class));
|
||||
}
|
||||
resultList.add(operationJsonData);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JSONObject> buildVariableListExtensionElement(Map<String, List<ExtensionElement>> extensionMap) {
|
||||
List<ExtensionElement> formVariableElements =
|
||||
this.getMyExtensionElementList(extensionMap, "variableList", "formVariable");
|
||||
if (CollUtil.isEmpty(formVariableElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Set<Long> variableIdSet = new HashSet<>();
|
||||
for (ExtensionElement e : formVariableElements) {
|
||||
String id = e.getAttributeValue(null, ID);
|
||||
variableIdSet.add(Long.parseLong(id));
|
||||
}
|
||||
List<FlowEntryVariable> variableList = flowEntryVariableService.getInList(variableIdSet);
|
||||
List<JSONObject> resultList = new LinkedList<>();
|
||||
for (FlowEntryVariable variable : variableList) {
|
||||
resultList.add((JSONObject) JSON.toJSON(variable));
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowElementExtProperty buildFlowElementExt(FlowElement element) {
|
||||
JSONObject propertiesData = this.buildFlowElementExtToJson(element);
|
||||
return propertiesData == null ? null : propertiesData.toJavaObject(FlowElementExtProperty.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject buildFlowElementExtToJson(FlowElement element) {
|
||||
Map<String, List<ExtensionElement>> extensionMap = element.getExtensionElements();
|
||||
List<ExtensionElement> propertiesElements =
|
||||
this.getMyExtensionElementList(extensionMap, "properties", "property");
|
||||
if (CollUtil.isEmpty(propertiesElements)) {
|
||||
return null;
|
||||
}
|
||||
JSONObject propertiesData = new JSONObject();
|
||||
for (ExtensionElement e : propertiesElements) {
|
||||
String name = e.getAttributeValue(null, NAME);
|
||||
String value = e.getAttributeValue(null, VALUE);
|
||||
propertiesData.put(name, value);
|
||||
}
|
||||
return propertiesData;
|
||||
}
|
||||
|
||||
private void doBuildTaskExtList(FlowElement element, List<FlowTaskExt> flowTaskExtList) {
|
||||
if (element instanceof UserTask) {
|
||||
FlowTaskExt flowTaskExt = this.buildTaskExtByUserTask((UserTask) element);
|
||||
flowTaskExtList.add(flowTaskExt);
|
||||
} else if (element instanceof SubProcess) {
|
||||
Collection<FlowElement> flowElements = ((SubProcess) element).getFlowElements();
|
||||
for (FlowElement element1 : flowElements) {
|
||||
this.doBuildTaskExtList(element1, flowTaskExtList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFlowUserInfoListByDeptAndRoleIds(
|
||||
FlowTaskExt flowTaskExt, Set<String> loginNameSet, List<FlowUserInfoVo> resultUserMapList) {
|
||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getDeptIds())) {
|
||||
Set<String> deptIdSet = CollUtil.newHashSet(StrUtil.split(flowTaskExt.getDeptIds(), ','));
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByDeptIds(deptIdSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
if (StrUtil.isNotBlank(flowTaskExt.getRoleIds())) {
|
||||
Set<String> roleIdSet = CollUtil.newHashSet(StrUtil.split(flowTaskExt.getRoleIds(), ','));
|
||||
List<FlowUserInfoVo> userInfoList = flowIdentityExtHelper.getUserInfoListByRoleIds(roleIdSet);
|
||||
this.buildUserMapList(userInfoList, loginNameSet, resultUserMapList);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFlowTaskTimeoutExtensionData(
|
||||
Map<String, List<ExtensionAttribute>> attributeMap, JSONObject extraDataJson) {
|
||||
List<ExtensionAttribute> timeoutHandleWayAttributes = attributeMap.get(FlowConstant.TASK_TIMEOUT_HANDLE_WAY);
|
||||
if (CollUtil.isNotEmpty(timeoutHandleWayAttributes)) {
|
||||
String handleWay = timeoutHandleWayAttributes.get(0).getValue();
|
||||
extraDataJson.put(FlowConstant.TASK_TIMEOUT_HANDLE_WAY, handleWay);
|
||||
List<ExtensionAttribute> timeoutHoursAttributes = attributeMap.get(FlowConstant.TASK_TIMEOUT_HOURS);
|
||||
if (CollUtil.isEmpty(timeoutHoursAttributes)) {
|
||||
throw new MyRuntimeException("没有设置任务超时小时数!");
|
||||
}
|
||||
Integer timeoutHours = Integer.valueOf(timeoutHoursAttributes.get(0).getValue());
|
||||
extraDataJson.put(FlowConstant.TASK_TIMEOUT_HOURS, timeoutHours);
|
||||
if (StrUtil.equals(handleWay, FlowUserTaskExtData.TIMEOUT_AUTO_COMPLETE)) {
|
||||
List<ExtensionAttribute> defaultAssigneeAttributes =
|
||||
attributeMap.get(FlowConstant.TASK_TIMEOUT_DEFAULT_ASSIGNEE);
|
||||
if (CollUtil.isEmpty(defaultAssigneeAttributes)) {
|
||||
throw new MyRuntimeException("没有设置超时任务处理人!");
|
||||
}
|
||||
extraDataJson.put(FlowConstant.TASK_TIMEOUT_DEFAULT_ASSIGNEE, defaultAssigneeAttributes.get(0).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFlowTaskEmptyUserExtensionData(
|
||||
Map<String, List<ExtensionAttribute>> attributeMap, JSONObject extraDataJson) {
|
||||
List<ExtensionAttribute> emptyUserHandleWayAttributes = attributeMap.get(FlowConstant.EMPTY_USER_HANDLE_WAY);
|
||||
if (CollUtil.isNotEmpty(emptyUserHandleWayAttributes)) {
|
||||
String handleWay = emptyUserHandleWayAttributes.get(0).getValue();
|
||||
extraDataJson.put(FlowConstant.EMPTY_USER_HANDLE_WAY, handleWay);
|
||||
if (StrUtil.equals(handleWay, FlowUserTaskExtData.EMPTY_USER_TO_ASSIGNEE)) {
|
||||
List<ExtensionAttribute> emptyUserToAssigneeAttributes = attributeMap.get(FlowConstant.EMPTY_USER_TO_ASSIGNEE);
|
||||
if (CollUtil.isEmpty(emptyUserToAssigneeAttributes)) {
|
||||
throw new MyRuntimeException("没有设置空审批人的指定处理人!");
|
||||
}
|
||||
extraDataJson.put(FlowConstant.EMPTY_USER_TO_ASSIGNEE, emptyUserToAssigneeAttributes.get(0).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject buildFlowTaskExtensionData(UserTask userTask) {
|
||||
JSONObject extraDataJson = this.buildFlowElementExtToJson(userTask);
|
||||
Map<String, List<ExtensionAttribute>> attributeMap = userTask.getAttributes();
|
||||
if (MapUtil.isEmpty(attributeMap)) {
|
||||
return extraDataJson;
|
||||
}
|
||||
if (extraDataJson == null) {
|
||||
extraDataJson = new JSONObject();
|
||||
}
|
||||
this.buildFlowTaskTimeoutExtensionData(attributeMap, extraDataJson);
|
||||
this.buildFlowTaskEmptyUserExtensionData(attributeMap, extraDataJson);
|
||||
List<ExtensionAttribute> rejectTypeAttributes = attributeMap.get(FlowConstant.USER_TASK_REJECT_TYPE_KEY);
|
||||
if (CollUtil.isNotEmpty(rejectTypeAttributes)) {
|
||||
extraDataJson.put(FlowConstant.USER_TASK_REJECT_TYPE_KEY, rejectTypeAttributes.get(0).getValue());
|
||||
}
|
||||
List<ExtensionAttribute> sendMsgTypeAttributes = attributeMap.get("sendMessageType");
|
||||
if (CollUtil.isNotEmpty(sendMsgTypeAttributes)) {
|
||||
ExtensionAttribute attribute = sendMsgTypeAttributes.get(0);
|
||||
extraDataJson.put(FlowConstant.USER_TASK_NOTIFY_TYPES_KEY, StrUtil.split(attribute.getValue(), ","));
|
||||
}
|
||||
return extraDataJson;
|
||||
}
|
||||
|
||||
private JSONObject buildUserCandidateGroupsExtensionElement(Map<String, List<ExtensionElement>> extensionMap) {
|
||||
JSONObject jsonData = null;
|
||||
List<ExtensionElement> elementCandidateGroupsList = extensionMap.get("userCandidateGroups");
|
||||
if (CollUtil.isEmpty(elementCandidateGroupsList)) {
|
||||
return jsonData;
|
||||
}
|
||||
jsonData = new JSONObject();
|
||||
ExtensionElement ee = elementCandidateGroupsList.get(0);
|
||||
jsonData.put(TYPE, ee.getAttributeValue(null, TYPE));
|
||||
jsonData.put(VALUE, ee.getAttributeValue(null, VALUE));
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
private JSONObject buildAssigneeListExtensionElement(Map<String, List<ExtensionElement>> extensionMap) {
|
||||
JSONObject jsonData = null;
|
||||
List<ExtensionElement> elementAssigneeList = extensionMap.get("assigneeList");
|
||||
if (CollUtil.isEmpty(elementAssigneeList)) {
|
||||
return jsonData;
|
||||
}
|
||||
ExtensionElement ee = elementAssigneeList.get(0);
|
||||
Map<String, List<ExtensionElement>> childExtensionMap = ee.getChildElements();
|
||||
if (MapUtil.isEmpty(childExtensionMap)) {
|
||||
return jsonData;
|
||||
}
|
||||
List<ExtensionElement> assigneeElements = childExtensionMap.get("assignee");
|
||||
if (CollUtil.isEmpty(assigneeElements)) {
|
||||
return jsonData;
|
||||
}
|
||||
JSONArray assigneeIdArray = new JSONArray();
|
||||
for (ExtensionElement e : assigneeElements) {
|
||||
assigneeIdArray.add(e.getAttributeValue(null, ID));
|
||||
}
|
||||
jsonData = new JSONObject();
|
||||
String assigneeType = ee.getAttributeValue(null, TYPE);
|
||||
jsonData.put("assigneeType", assigneeType);
|
||||
jsonData.put("assigneeList", assigneeIdArray);
|
||||
return jsonData;
|
||||
}
|
||||
|
||||
private List<JSONObject> buildDeptPostListExtensionElement(Map<String, List<ExtensionElement>> extensionMap) {
|
||||
List<ExtensionElement> deptPostElements =
|
||||
this.getMyExtensionElementList(extensionMap, "deptPostList", "deptPost");
|
||||
if (CollUtil.isEmpty(deptPostElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<JSONObject> resultList = new LinkedList<>();
|
||||
for (ExtensionElement e : deptPostElements) {
|
||||
JSONObject deptPostJsonData = new JSONObject();
|
||||
deptPostJsonData.put(ID, e.getAttributeValue(null, ID));
|
||||
deptPostJsonData.put(TYPE, e.getAttributeValue(null, TYPE));
|
||||
String postId = e.getAttributeValue(null, "postId");
|
||||
if (postId != null) {
|
||||
deptPostJsonData.put("postId", postId);
|
||||
}
|
||||
String deptPostId = e.getAttributeValue(null, "deptPostId");
|
||||
if (deptPostId != null) {
|
||||
deptPostJsonData.put("deptPostId", deptPostId);
|
||||
}
|
||||
resultList.add(deptPostJsonData);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
private List<JSONObject> buildCopyListExtensionElement(Map<String, List<ExtensionElement>> extensionMap) {
|
||||
List<ExtensionElement> copyElements =
|
||||
this.getMyExtensionElementList(extensionMap, "copyItemList", "copyItem");
|
||||
if (CollUtil.isEmpty(copyElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<JSONObject> resultList = new LinkedList<>();
|
||||
for (ExtensionElement e : copyElements) {
|
||||
JSONObject copyJsonData = new JSONObject();
|
||||
String type = e.getAttributeValue(null, TYPE);
|
||||
copyJsonData.put(TYPE, type);
|
||||
if (!StrUtil.equalsAny(type, FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR,
|
||||
FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR,
|
||||
FlowConstant.GROUP_TYPE_USER_VAR,
|
||||
FlowConstant.GROUP_TYPE_ROLE_VAR,
|
||||
FlowConstant.GROUP_TYPE_DEPT_VAR,
|
||||
FlowConstant.GROUP_TYPE_DEPT_POST_VAR,
|
||||
FlowConstant.GROUP_TYPE_ALL_DEPT_POST_VAR,
|
||||
FlowConstant.GROUP_TYPE_SIBLING_DEPT_POST_VAR,
|
||||
FlowConstant.GROUP_TYPE_SELF_DEPT_POST_VAR,
|
||||
FlowConstant.GROUP_TYPE_UP_DEPT_POST_VAR)) {
|
||||
throw new MyRuntimeException("Invalid TYPE [" + type + " ] for CopyItenList Extension!");
|
||||
}
|
||||
String id = e.getAttributeValue(null, ID);
|
||||
if (StrUtil.isNotBlank(id)) {
|
||||
copyJsonData.put(ID, id);
|
||||
}
|
||||
resultList.add(copyJsonData);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
private List<ExtensionElement> getMyExtensionElementList(
|
||||
Map<String, List<ExtensionElement>> extensionMap, String rootName, String childName) {
|
||||
if (extensionMap == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<ExtensionElement> elementList = extensionMap.get(rootName);
|
||||
if (CollUtil.isEmpty(elementList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (StrUtil.isBlank(childName)) {
|
||||
return elementList;
|
||||
}
|
||||
ExtensionElement ee = elementList.get(0);
|
||||
Map<String, List<ExtensionElement>> childExtensionMap = ee.getChildElements();
|
||||
if (MapUtil.isEmpty(childExtensionMap)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<ExtensionElement> childrenElements = childExtensionMap.get(childName);
|
||||
if (CollUtil.isEmpty(childrenElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return childrenElements;
|
||||
}
|
||||
|
||||
private List<String> getAssigneeList(String executionId, String taskId) {
|
||||
FlowMultiInstanceTrans flowMultiInstanceTrans =
|
||||
flowMultiInstanceTransService.getByExecutionId(executionId, taskId);
|
||||
String multiInstanceExecId;
|
||||
if (flowMultiInstanceTrans == null) {
|
||||
multiInstanceExecId = flowApiService.getTaskVariableStringWithSafe(
|
||||
taskId, FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR);
|
||||
} else {
|
||||
multiInstanceExecId = flowMultiInstanceTrans.getMultiInstanceExecId();
|
||||
}
|
||||
flowMultiInstanceTrans =
|
||||
flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId);
|
||||
return flowMultiInstanceTrans == null ? null
|
||||
: StrUtil.split(flowMultiInstanceTrans.getAssigneeList(), ",");
|
||||
}
|
||||
|
||||
private boolean buildTransferUserList(TaskInfo taskInfo, List<FlowUserInfoVo> resultUserMapList) {
|
||||
BaseFlowIdentityExtHelper flowIdentityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
List<FlowTaskComment> taskCommentList = flowTaskCommentService.getFlowTaskCommentListByExecutionId(
|
||||
taskInfo.getProcessInstanceId(), taskInfo.getId(), taskInfo.getExecutionId());
|
||||
if (CollUtil.isEmpty(taskCommentList)) {
|
||||
return false;
|
||||
}
|
||||
FlowTaskComment transferComment = null;
|
||||
for (int i = taskCommentList.size() - 1; i >= 0; i--) {
|
||||
FlowTaskComment comment = taskCommentList.get(i);
|
||||
if (StrUtil.equalsAny(comment.getApprovalType(),
|
||||
FlowApprovalType.TRANSFER, FlowApprovalType.INTERVENE)) {
|
||||
transferComment = comment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (transferComment == null || StrUtil.isBlank(transferComment.getDelegateAssignee())) {
|
||||
return false;
|
||||
}
|
||||
Set<String> loginNameSet = new HashSet<>(StrUtil.split(transferComment.getDelegateAssignee(), ","));
|
||||
resultUserMapList.addAll(flowIdentityExtHelper.getUserInfoListByUsernameSet(loginNameSet));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
package com.orangeforms.common.flow.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.github.pagehelper.page.PageMethod;
|
||||
import com.orangeforms.common.core.annotation.DisableDataFilter;
|
||||
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
|
||||
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
|
||||
import com.orangeforms.common.core.base.service.BaseService;
|
||||
import com.orangeforms.common.core.constant.ApplicationConstant;
|
||||
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
|
||||
import com.orangeforms.common.core.object.*;
|
||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||
import com.orangeforms.common.core.util.MyPageUtil;
|
||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||
import com.orangeforms.common.flow.dao.FlowWorkOrderExtMapper;
|
||||
import com.orangeforms.common.flow.dao.FlowWorkOrderMapper;
|
||||
import com.orangeforms.common.flow.dto.FlowWorkOrderDto;
|
||||
import com.orangeforms.common.flow.model.FlowEntry;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrder;
|
||||
import com.orangeforms.common.flow.model.FlowWorkOrderExt;
|
||||
import com.orangeforms.common.flow.util.FlowOperationHelper;
|
||||
import com.orangeforms.common.flow.vo.FlowWorkOrderVo;
|
||||
import com.orangeforms.common.flow.service.FlowApiService;
|
||||
import com.orangeforms.common.flow.service.FlowEntryService;
|
||||
import com.orangeforms.common.flow.service.FlowWorkOrderService;
|
||||
import com.orangeforms.common.flow.util.BaseFlowIdentityExtHelper;
|
||||
import com.orangeforms.common.flow.util.FlowCustomExtFactory;
|
||||
import com.orangeforms.common.redis.util.CommonRedisUtil;
|
||||
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@MyDataSourceResolver(
|
||||
resolver = DefaultDataSourceResolver.class,
|
||||
intArg = ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE)
|
||||
@Service("flowWorkOrderService")
|
||||
public class FlowWorkOrderServiceImpl extends BaseService<FlowWorkOrder, Long> implements FlowWorkOrderService {
|
||||
|
||||
@Autowired
|
||||
private FlowWorkOrderMapper flowWorkOrderMapper;
|
||||
@Autowired
|
||||
private FlowWorkOrderExtMapper flowWorkOrderExtMapper;
|
||||
@Autowired
|
||||
private IdGeneratorWrapper idGenerator;
|
||||
@Autowired
|
||||
private FlowCustomExtFactory flowCustomExtFactory;
|
||||
@Autowired
|
||||
private FlowApiService flowApiService;
|
||||
@Autowired
|
||||
private FlowEntryService flowEntryService;
|
||||
@Autowired
|
||||
private CommonRedisUtil commonRedisUtil;
|
||||
@Autowired
|
||||
private FlowOperationHelper flowOperationHelper;
|
||||
|
||||
/**
|
||||
* 返回当前Service的主表Mapper对象。
|
||||
*
|
||||
* @return 主表Mapper对象。
|
||||
*/
|
||||
@Override
|
||||
protected BaseDaoMapper<FlowWorkOrder> mapper() {
|
||||
return flowWorkOrderMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新增对象。
|
||||
*
|
||||
* @param instance 流程实例对象。
|
||||
* @param dataId 流程实例的BusinessKey。
|
||||
* @param onlineTableId 在线数据表的主键Id。
|
||||
* @param tableName 面向静态表单所使用的表名。
|
||||
* @return 新增的工作流工单对象。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowWorkOrder saveNew(ProcessInstance instance, Object dataId, Long onlineTableId, String tableName) {
|
||||
// 正常插入流程工单数据。
|
||||
FlowWorkOrder flowWorkOrder = this.createWith(instance);
|
||||
flowWorkOrder.setWorkOrderCode(this.generateWorkOrderCode(instance.getProcessDefinitionKey()));
|
||||
flowWorkOrder.setBusinessKey(dataId.toString());
|
||||
flowWorkOrder.setOnlineTableId(onlineTableId);
|
||||
flowWorkOrder.setTableName(tableName);
|
||||
flowWorkOrder.setFlowStatus(FlowTaskStatus.SUBMITTED);
|
||||
flowWorkOrderMapper.insert(flowWorkOrder);
|
||||
return flowWorkOrder;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public FlowWorkOrder saveNewWithDraft(
|
||||
ProcessInstance instance, Long onlineTableId, String tableName, String masterData, String slaveData) {
|
||||
FlowWorkOrder flowWorkOrder = this.createWith(instance);
|
||||
flowWorkOrder.setWorkOrderCode(this.generateWorkOrderCode(instance.getProcessDefinitionKey()));
|
||||
flowWorkOrder.setOnlineTableId(onlineTableId);
|
||||
flowWorkOrder.setTableName(tableName);
|
||||
flowWorkOrder.setFlowStatus(FlowTaskStatus.DRAFT);
|
||||
JSONObject draftData = new JSONObject();
|
||||
if (masterData != null) {
|
||||
draftData.put(FlowConstant.MASTER_DATA_KEY, masterData);
|
||||
}
|
||||
if (slaveData != null) {
|
||||
draftData.put(FlowConstant.SLAVE_DATA_KEY, slaveData);
|
||||
}
|
||||
FlowWorkOrderExt flowWorkOrderExt =
|
||||
BeanUtil.copyProperties(flowWorkOrder, FlowWorkOrderExt.class);
|
||||
flowWorkOrderExt.setId(idGenerator.nextLongId());
|
||||
flowWorkOrderExt.setDraftData(JSON.toJSONString(draftData));
|
||||
flowWorkOrderExtMapper.insert(flowWorkOrderExt);
|
||||
flowWorkOrderMapper.insert(flowWorkOrder);
|
||||
return flowWorkOrder;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateDraft(Long workOrderId, String masterData, String slaveData) {
|
||||
JSONObject draftData = new JSONObject();
|
||||
if (masterData != null) {
|
||||
draftData.put(FlowConstant.MASTER_DATA_KEY, masterData);
|
||||
}
|
||||
if (slaveData != null) {
|
||||
draftData.put(FlowConstant.SLAVE_DATA_KEY, slaveData);
|
||||
}
|
||||
FlowWorkOrderExt flowWorkOrderExt = new FlowWorkOrderExt();
|
||||
flowWorkOrderExt.setDraftData(JSON.toJSONString(draftData));
|
||||
flowWorkOrderExt.setUpdateTime(new Date());
|
||||
flowWorkOrderExtMapper.updateByQuery(flowWorkOrderExt,
|
||||
new QueryWrapper().eq(FlowWorkOrderExt::getWorkOrderId, workOrderId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定数据。
|
||||
*
|
||||
* @param workOrderId 主键Id。
|
||||
* @return 成功返回true,否则false。
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public boolean remove(Long workOrderId) {
|
||||
return flowWorkOrderMapper.deleteById(workOrderId) == 1;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void removeByProcessInstanceId(String processInstanceId) {
|
||||
FlowWorkOrder filter = new FlowWorkOrder();
|
||||
filter.setProcessInstanceId(processInstanceId);
|
||||
super.removeBy(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowWorkOrder> getFlowWorkOrderList(FlowWorkOrder filter, String orderBy) {
|
||||
if (filter == null) {
|
||||
filter = new FlowWorkOrder();
|
||||
}
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
filter.setTenantId(tokenData.getTenantId());
|
||||
filter.setAppCode(tokenData.getAppCode());
|
||||
return flowWorkOrderMapper.getFlowWorkOrderList(filter, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowWorkOrder> getFlowWorkOrderListWithRelation(FlowWorkOrder filter, String orderBy) {
|
||||
List<FlowWorkOrder> resultList = this.getFlowWorkOrderList(filter, orderBy);
|
||||
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly());
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowWorkOrder getFlowWorkOrderByProcessInstanceId(String processInstanceId) {
|
||||
FlowWorkOrder filter = new FlowWorkOrder();
|
||||
filter.setProcessInstanceId(processInstanceId);
|
||||
return flowWorkOrderMapper.selectOneByQuery(QueryWrapper.create(filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existByBusinessKey(String tableName, Object businessKey, boolean unfinished) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowWorkOrder::getBusinessKey, businessKey.toString());
|
||||
queryWrapper.eq(FlowWorkOrder::getTableName, tableName);
|
||||
if (unfinished) {
|
||||
queryWrapper.notIn(FlowWorkOrder::getFlowStatus,
|
||||
FlowTaskStatus.FINISHED, FlowTaskStatus.CANCELLED, FlowTaskStatus.STOPPED);
|
||||
}
|
||||
return flowWorkOrderMapper.selectCountByQuery(queryWrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existUnfinished(String processDefinitionKey, Object businessKey) {
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowWorkOrder::getBusinessKey, businessKey.toString());
|
||||
queryWrapper.eq(FlowWorkOrder::getProcessDefinitionKey, processDefinitionKey);
|
||||
queryWrapper.notIn(FlowWorkOrder::getFlowStatus,
|
||||
FlowTaskStatus.FINISHED, FlowTaskStatus.CANCELLED, FlowTaskStatus.STOPPED);
|
||||
return flowWorkOrderMapper.selectCountByQuery(queryWrapper) > 0;
|
||||
}
|
||||
|
||||
@DisableDataFilter
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateFlowStatusByProcessInstanceId(String processInstanceId, Integer flowStatus) {
|
||||
if (flowStatus == null) {
|
||||
return;
|
||||
}
|
||||
FlowWorkOrder flowWorkOrder = new FlowWorkOrder();
|
||||
flowWorkOrder.setFlowStatus(flowStatus);
|
||||
if (FlowTaskStatus.FINISHED != flowStatus) {
|
||||
flowWorkOrder.setUpdateTime(new Date());
|
||||
flowWorkOrder.setUpdateUserId(TokenData.takeFromRequest().getUserId());
|
||||
}
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
queryWrapper.eq(FlowWorkOrder::getProcessInstanceId, processInstanceId);
|
||||
flowWorkOrderMapper.updateByQuery(flowWorkOrder, queryWrapper);
|
||||
}
|
||||
|
||||
@DisableDataFilter
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateLatestApprovalStatusByProcessInstanceId(String processInstanceId, Integer approvalStatus) {
|
||||
if (approvalStatus == null) {
|
||||
return;
|
||||
}
|
||||
FlowWorkOrder flowWorkOrder = this.getFlowWorkOrderByProcessInstanceId(processInstanceId);
|
||||
flowWorkOrder.setLatestApprovalStatus(approvalStatus);
|
||||
flowWorkOrder.setUpdateTime(new Date());
|
||||
flowWorkOrder.setUpdateUserId(TokenData.takeFromRequest().getUserId());
|
||||
flowWorkOrderMapper.update(flowWorkOrder);
|
||||
// 处理在线表单工作流的自定义状态更新。
|
||||
flowCustomExtFactory.getOnlineBusinessDataExtHelper().updateFlowStatus(flowWorkOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDataPermOnFlowWorkOrder(String processInstanceId) {
|
||||
// 开启数据权限,并进行验证。
|
||||
boolean originalFlag = GlobalThreadLocal.setDataFilter(true);
|
||||
long count;
|
||||
try {
|
||||
FlowWorkOrder filter = new FlowWorkOrder();
|
||||
filter.setProcessInstanceId(processInstanceId);
|
||||
count = flowWorkOrderMapper.selectCountByQuery(QueryWrapper.create(filter));
|
||||
} finally {
|
||||
// 恢复之前的数据权限标记
|
||||
GlobalThreadLocal.setDataFilter(originalFlag);
|
||||
}
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillUserShowNameByLoginName(List<FlowWorkOrderVo> dataList) {
|
||||
BaseFlowIdentityExtHelper identityExtHelper = flowCustomExtFactory.getFlowIdentityExtHelper();
|
||||
Set<String> loginNameSet = dataList.stream()
|
||||
.map(FlowWorkOrderVo::getSubmitUsername).collect(Collectors.toSet());
|
||||
if (CollUtil.isEmpty(loginNameSet)) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> userNameMap = identityExtHelper.mapUserShowNameByLoginName(loginNameSet);
|
||||
dataList.forEach(workOrder -> {
|
||||
if (StrUtil.isNotBlank(workOrder.getSubmitUsername())) {
|
||||
workOrder.setUserShowName(userNameMap.get(workOrder.getSubmitUsername()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowWorkOrderExt getFlowWorkOrderExtByWorkOrderId(Long workOrderId) {
|
||||
return flowWorkOrderExtMapper.selectOneByQuery(
|
||||
new QueryWrapper().eq(FlowWorkOrderExt::getWorkOrderId, workOrderId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowWorkOrderExt> getFlowWorkOrderExtByWorkOrderIds(Set<Long> workOrderIds) {
|
||||
return flowWorkOrderExtMapper.selectListByQuery(
|
||||
new QueryWrapper().in(FlowWorkOrderExt::getWorkOrderId, workOrderIds));
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public CallResult removeDraft(FlowWorkOrder flowWorkOrder) {
|
||||
CallResult r = flowApiService.stopProcessInstance(flowWorkOrder.getProcessInstanceId(), "撤销草稿", true);
|
||||
if (!r.isSuccess()) {
|
||||
return r;
|
||||
}
|
||||
flowWorkOrderMapper.deleteById(flowWorkOrder.getWorkOrderId());
|
||||
return CallResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyPageData<FlowWorkOrderVo> getPagedWorkOrderListAndBuildData(
|
||||
FlowWorkOrderDto flowWorkOrderDtoFilter, MyPageParam pageParam, MyOrderParam orderParam, String processDefinitionKey) {
|
||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
|
||||
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowWorkOrder.class);
|
||||
FlowWorkOrder filter = flowOperationHelper.makeWorkOrderFilter(flowWorkOrderDtoFilter, processDefinitionKey);
|
||||
List<FlowWorkOrder> flowWorkOrderList = this.getFlowWorkOrderList(filter, orderBy);
|
||||
MyPageData<FlowWorkOrderVo> resultData =
|
||||
MyPageUtil.makeResponseData(flowWorkOrderList, FlowWorkOrderVo.class);
|
||||
if (CollUtil.isEmpty(resultData.getDataList())) {
|
||||
return resultData;
|
||||
}
|
||||
flowOperationHelper.buildWorkOrderApprovalStatus(processDefinitionKey, resultData.getDataList());
|
||||
// 根据工单的提交用户名获取用户的显示名称,便于前端显示。
|
||||
// 同时这也是一个如何通过插件方法,将loginName映射到showName的示例,
|
||||
this.fillUserShowNameByLoginName(resultData.getDataList());
|
||||
// 组装工单中需要返回给前端的流程任务数据。
|
||||
flowOperationHelper.buildWorkOrderTaskInfo(resultData.getDataList());
|
||||
return resultData;
|
||||
}
|
||||
|
||||
private FlowWorkOrder createWith(ProcessInstance instance) {
|
||||
TokenData tokenData = TokenData.takeFromRequest();
|
||||
Date now = new Date();
|
||||
FlowWorkOrder flowWorkOrder = new FlowWorkOrder();
|
||||
flowWorkOrder.setWorkOrderId(idGenerator.nextLongId());
|
||||
flowWorkOrder.setProcessDefinitionKey(instance.getProcessDefinitionKey());
|
||||
flowWorkOrder.setProcessDefinitionName(instance.getProcessDefinitionName());
|
||||
flowWorkOrder.setProcessDefinitionId(instance.getProcessDefinitionId());
|
||||
flowWorkOrder.setProcessInstanceId(instance.getId());
|
||||
flowWorkOrder.setSubmitUsername(tokenData.getLoginName());
|
||||
flowWorkOrder.setDeptId(tokenData.getDeptId());
|
||||
flowWorkOrder.setAppCode(tokenData.getAppCode());
|
||||
flowWorkOrder.setTenantId(tokenData.getTenantId());
|
||||
flowWorkOrder.setCreateUserId(tokenData.getUserId());
|
||||
flowWorkOrder.setUpdateUserId(tokenData.getUserId());
|
||||
flowWorkOrder.setCreateTime(now);
|
||||
flowWorkOrder.setUpdateTime(now);
|
||||
flowWorkOrder.setDeletedFlag(GlobalDeletedFlag.NORMAL);
|
||||
return flowWorkOrder;
|
||||
}
|
||||
|
||||
private String generateWorkOrderCode(String processDefinitionKey) {
|
||||
FlowEntry flowEntry = flowEntryService.getFlowEntryFromCache(processDefinitionKey);
|
||||
if (StrUtil.isBlank(flowEntry.getEncodedRule())) {
|
||||
return null;
|
||||
}
|
||||
ColumnEncodedRule rule = JSON.parseObject(flowEntry.getEncodedRule(), ColumnEncodedRule.class);
|
||||
if (rule.getIdWidth() == null) {
|
||||
rule.setIdWidth(10);
|
||||
}
|
||||
return commonRedisUtil.generateTransId(
|
||||
rule.getPrefix(), rule.getPrecisionTo(), rule.getMiddle(), rule.getIdWidth());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user