mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm
# Conflicts: # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
This commit is contained in:
		@@ -18,28 +18,26 @@ import java.util.Objects;
 | 
			
		||||
public enum BpmSimpleModelNodeType implements IntArrayValuable {
 | 
			
		||||
 | 
			
		||||
    // 0 ~ 1 开始和结束
 | 
			
		||||
    START_NODE(0, "startEvent", "开始节点"),
 | 
			
		||||
    END_NODE(1, "endEvent", "结束节点"),
 | 
			
		||||
    START_NODE(0, "开始", "startEvent"),
 | 
			
		||||
    END_NODE(1, "结束", "endEvent"),
 | 
			
		||||
 | 
			
		||||
    // 10 ~ 49 各种节点
 | 
			
		||||
    START_USER_NODE(10, "userTask", "发起人节点"), // 发起人节点。前端的开始节点,Id 固定
 | 
			
		||||
    APPROVE_NODE(11, "userTask", "审批人节点"),
 | 
			
		||||
    COPY_NODE(12, "serviceTask", "抄送人节点"),
 | 
			
		||||
    START_USER_NODE(10, "发起人", "userTask"), // 发起人节点。前端的开始节点,Id 固定
 | 
			
		||||
    APPROVE_NODE(11, "审批人", "userTask"),
 | 
			
		||||
    COPY_NODE(12, "抄送人", "serviceTask"),
 | 
			
		||||
 | 
			
		||||
    // 50 ~ 条件分支
 | 
			
		||||
    CONDITION_NODE(50, "sequenceFlow", "条件节点"), // 用于构建流转条件的表达式
 | 
			
		||||
    CONDITION_BRANCH_NODE(51, "exclusiveGateway", "条件分支节点"),
 | 
			
		||||
    PARALLEL_BRANCH_NODE(52, "parallelGateway", "并行分支节点"),
 | 
			
		||||
    INCLUSIVE_BRANCH_NODE(53, "inclusiveGateway", "包容分支节点"),
 | 
			
		||||
    CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式
 | 
			
		||||
    CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
 | 
			
		||||
    PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"),
 | 
			
		||||
    INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"),
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray();
 | 
			
		||||
 | 
			
		||||
    public static final String BPMN_USER_TASK_TYPE = "userTask";
 | 
			
		||||
 | 
			
		||||
    private final Integer type;
 | 
			
		||||
    private final String bpmnType;
 | 
			
		||||
    private final String name;
 | 
			
		||||
    private final String bpmnType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断是否为分支节点
 | 
			
		||||
@@ -52,16 +50,6 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
 | 
			
		||||
                || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断是否需要记录的节点
 | 
			
		||||
     *
 | 
			
		||||
     * @param bpmnType bpmn节点类型
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isRecordNode(String bpmnType) {
 | 
			
		||||
        return Objects.equals(APPROVE_NODE.getBpmnType(), bpmnType)
 | 
			
		||||
                || Objects.equals(END_NODE.getBpmnType(), bpmnType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static BpmSimpleModelNodeType valueOf(Integer type) {
 | 
			
		||||
        return ArrayUtil.firstMatch(nodeType -> nodeType.getType().equals(type), values());
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.enums.task;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ObjUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
@@ -63,4 +64,8 @@ public enum BpmTaskStatusEnum {
 | 
			
		||||
                RETURN.getStatus(), APPROVING.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isCancelStatus(Integer status) {
 | 
			
		||||
        return ObjUtil.equal(status, CANCEL.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,11 +9,14 @@ public class UserSimpleBaseVO {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
 | 
			
		||||
    private String nickname;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "用户头像", example = "https://www.iocoder.cn/1.png")
 | 
			
		||||
    private String avatar;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    private Long deptId;
 | 
			
		||||
    @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部")
 | 
			
		||||
    private String deptName;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -30,7 +30,6 @@ public class BpmSimpleModelNodeVO {
 | 
			
		||||
    @Schema(description = "模型节点名称", example = "领导审批")
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    // TODO @jason:和 gpt 大模型对了下这个字段的命名,貌似叫 displayText 合适点。可以等最后我们全局替换下。(优先级:低)
 | 
			
		||||
    @Schema(description = "节点展示内容", example = "指定成员: 芋道源码")
 | 
			
		||||
    private String showText;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,10 @@ Authorization: Bearer {{token}}
 | 
			
		||||
### 请求 /bpm/process-instance/get-bpmn 接口 => 失败
 | 
			
		||||
#GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processInstanceId=1d5fb5a6-85f8-11ef-b717-7e93075f94e3
 | 
			
		||||
#GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processInstanceId=3ee5c5ba-904a-11ef-a76e-b2ed5d6ef911
 | 
			
		||||
GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processInstanceId=f630dfa2-8f92-11ef-947c-ba5e239a6eb4
 | 
			
		||||
#GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processInstanceId=f630dfa2-8f92-11ef-947c-ba5e239a6eb4
 | 
			
		||||
#GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processInstanceId=9de8bdbf-9133-11ef-ae97-eaf49df1f932
 | 
			
		||||
#GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processInstanceId=dd2188eb-9394-11ef-a039-7a9ac3d9eb6b
 | 
			
		||||
GET {{baseUrl}}/bpm/process-instance/get-approval-detail?processDefinitionId=test-auto:1:c70a799a-9394-11ef-a039-7a9ac3d9eb6b
 | 
			
		||||
Content-Type: application/json
 | 
			
		||||
tenant-id: 1
 | 
			
		||||
Authorization: Bearer {{token}}
 | 
			
		||||
@@ -6,15 +6,20 @@ import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import jakarta.validation.constraints.AssertTrue;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@Schema(description = "管理后台 - 审批详情 Request VO")
 | 
			
		||||
@Data
 | 
			
		||||
public class BpmApprovalDetailReqVO {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "流程定义的编号", example = "1024")
 | 
			
		||||
    private String processDefinitionId; // 发起流程的时候传流程定义 ID
 | 
			
		||||
    private String processDefinitionId; // 使用场景:发起流程时,传流程定义 ID
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "流程变量")
 | 
			
		||||
    private Map<String, Object> processVariables; // 使用场景:同 processDefinitionId,用于流程预测
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "流程实例的编号", example = "1024")
 | 
			
		||||
    private String processInstanceId;  // 流程已发起时候传流程实例 ID
 | 
			
		||||
    private String processInstanceId;  // 使用场景:流程已发起时候传流程实例 ID
 | 
			
		||||
 | 
			
		||||
    // TODO @芋艿:如果未来 BPMN 增加流程图,它没有发起人节点,会有问题。
 | 
			
		||||
    @Schema(description = "流程活动编号", example = "StartUserNode")
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnore;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
@@ -18,8 +19,8 @@ public class BpmApprovalDetailRespVO {
 | 
			
		||||
    @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "审批信息列表", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
			
		||||
    private List<ApprovalNodeInfo> approveNodes;
 | 
			
		||||
    @Schema(description = "活动节点列表", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
			
		||||
    private List<ActivityNode> activityNodes;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "表单字段权限")
 | 
			
		||||
    private Map<String, String> formFieldsPermission;
 | 
			
		||||
@@ -37,9 +38,9 @@ public class BpmApprovalDetailRespVO {
 | 
			
		||||
     */
 | 
			
		||||
    private BpmProcessInstanceRespVO processInstance;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "审批节点信息")
 | 
			
		||||
    @Schema(description = "活动节点信息")
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class ApprovalNodeInfo {
 | 
			
		||||
    public static class ActivityNode {
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "StartUserNode")
 | 
			
		||||
        private String id;
 | 
			
		||||
@@ -59,23 +60,35 @@ public class BpmApprovalDetailRespVO {
 | 
			
		||||
        private LocalDateTime endTime;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "审批节点的任务信息")
 | 
			
		||||
        private List<ApprovalTaskInfo> tasks;
 | 
			
		||||
        private List<ActivityNodeTask> tasks;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "候选人用户 ID 列表", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1818")
 | 
			
		||||
        @JsonIgnore // 不返回,只是方便后续读取,赋值给 candidateUsers
 | 
			
		||||
        private List<Long> candidateUserIds;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "候选人用户列表")
 | 
			
		||||
        private List<UserSimpleBaseVO> candidateUsers; // 用于未运行任务节点
 | 
			
		||||
        private List<UserSimpleBaseVO> candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "审批任务信息")
 | 
			
		||||
    @Schema(description = "活动节点的任务信息")
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class ApprovalTaskInfo {
 | 
			
		||||
    public static class ActivityNodeTask {
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
        private String id;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "任务所属人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1818")
 | 
			
		||||
        @JsonIgnore // 不返回,只是方便后续读取,赋值给 ownerUser
 | 
			
		||||
        private Long owner;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "任务所属人", example = "1024")
 | 
			
		||||
        private UserSimpleBaseVO ownerUser;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "任务分配人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048")
 | 
			
		||||
        @JsonIgnore // 不返回,只是方便后续读取,赋值给 assigneeUser
 | 
			
		||||
        private Long assignee;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "任务分配人", example = "2048")
 | 
			
		||||
        private UserSimpleBaseVO assigneeUser;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
@@ -44,7 +45,7 @@ public class BpmProcessInstanceRespVO {
 | 
			
		||||
    /**
 | 
			
		||||
     * 发起流程的用户
 | 
			
		||||
     */
 | 
			
		||||
    private User startUser;
 | 
			
		||||
    private UserSimpleBaseVO startUser;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
 | 
			
		||||
    private String processDefinitionId;
 | 
			
		||||
@@ -58,24 +59,6 @@ public class BpmProcessInstanceRespVO {
 | 
			
		||||
     */
 | 
			
		||||
    private List<Task> tasks; // 仅在流程实例分页才返回
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "用户信息")
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class User {
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
        private Long id;
 | 
			
		||||
        @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
 | 
			
		||||
        private String nickname;
 | 
			
		||||
        @Schema(description = "用户头像", example = "https://www.iocoder.cn/1.png")
 | 
			
		||||
        private String avatar;
 | 
			
		||||
 | 
			
		||||
        @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
        private Long deptId;
 | 
			
		||||
        @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部")
 | 
			
		||||
        private String deptName;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "流程任务")
 | 
			
		||||
    @Data
 | 
			
		||||
    public static class Task {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
@@ -36,11 +36,11 @@ public class BpmTaskRespVO {
 | 
			
		||||
    /**
 | 
			
		||||
     * 负责人的用户信息
 | 
			
		||||
     */
 | 
			
		||||
    private BpmProcessInstanceRespVO.User ownerUser;
 | 
			
		||||
    private UserSimpleBaseVO ownerUser;
 | 
			
		||||
    /**
 | 
			
		||||
     * 审核的用户信息
 | 
			
		||||
     */
 | 
			
		||||
    private BpmProcessInstanceRespVO.User assigneeUser;
 | 
			
		||||
    private UserSimpleBaseVO assigneeUser;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one")
 | 
			
		||||
    private String taskDefinitionKey;
 | 
			
		||||
@@ -55,7 +55,7 @@ public class BpmTaskRespVO {
 | 
			
		||||
    @Schema(description = "父任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
 | 
			
		||||
    private String parentTaskId;
 | 
			
		||||
    @Schema(description = "子任务列表(由加签生成)", requiredMode = Schema.RequiredMode.REQUIRED, example = "childrenTask")
 | 
			
		||||
    private List<BpmTaskRespVO> children;
 | 
			
		||||
    private List<BpmTaskRespVO> children; // 由加签生成,包含多层子任务
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "表单编号", example = "1024")
 | 
			
		||||
    private Long formId;
 | 
			
		||||
@@ -89,7 +89,7 @@ public class BpmTaskRespVO {
 | 
			
		||||
        /**
 | 
			
		||||
         * 发起人的用户信息
 | 
			
		||||
         */
 | 
			
		||||
        private BpmProcessInstanceRespVO.User startUser;
 | 
			
		||||
        private UserSimpleBaseVO startUser;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,24 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.convert.task;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceBpmnModelViewRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;
 | 
			
		||||
@@ -20,6 +26,7 @@ import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcess
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.bpmn.model.UserTask;
 | 
			
		||||
import org.flowable.engine.history.HistoricProcessInstance;
 | 
			
		||||
import org.flowable.engine.repository.ProcessDefinition;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
@@ -30,11 +37,13 @@ import org.mapstruct.Mapping;
 | 
			
		||||
import org.mapstruct.MappingTarget;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 流程实例 Convert
 | 
			
		||||
@@ -65,7 +74,7 @@ public interface BpmProcessInstanceConvert {
 | 
			
		||||
            if (userMap != null) {
 | 
			
		||||
                AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(pageResult.getList().get(i).getStartUserId()));
 | 
			
		||||
                if (startUser != null) {
 | 
			
		||||
                    respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
                    respVO.setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
 | 
			
		||||
                    MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName()));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -75,7 +84,7 @@ public interface BpmProcessInstanceConvert {
 | 
			
		||||
 | 
			
		||||
    default BpmProcessInstanceRespVO buildProcessInstance(HistoricProcessInstance processInstance,
 | 
			
		||||
                                                          ProcessDefinition processDefinition,
 | 
			
		||||
                                                          BpmProcessDefinitionInfoDO processDefinitionExt,
 | 
			
		||||
                                                          BpmProcessDefinitionInfoDO processDefinitionInfo,
 | 
			
		||||
                                                          AdminUserRespDTO startUser,
 | 
			
		||||
                                                          DeptRespDTO dept) {
 | 
			
		||||
        BpmProcessInstanceRespVO respVO = BeanUtils.toBean(processInstance, BpmProcessInstanceRespVO.class);
 | 
			
		||||
@@ -83,10 +92,10 @@ public interface BpmProcessInstanceConvert {
 | 
			
		||||
        respVO.setFormVariables(FlowableUtils.getProcessInstanceFormVariable(processInstance));
 | 
			
		||||
        // definition
 | 
			
		||||
        respVO.setProcessDefinition(BeanUtils.toBean(processDefinition, BpmProcessDefinitionRespVO.class));
 | 
			
		||||
        copyTo(processDefinitionExt, respVO.getProcessDefinition());
 | 
			
		||||
        copyTo(processDefinitionInfo, respVO.getProcessDefinition());
 | 
			
		||||
        // user
 | 
			
		||||
        if (startUser != null) {
 | 
			
		||||
            respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
            respVO.setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
 | 
			
		||||
            if (dept != null) {
 | 
			
		||||
                respVO.getStartUser().setDeptName(dept.getName());
 | 
			
		||||
            }
 | 
			
		||||
@@ -146,17 +155,27 @@ public interface BpmProcessInstanceConvert {
 | 
			
		||||
        return respVO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default BpmProcessInstanceRespVO.User buildUser(String userId,
 | 
			
		||||
                                                    Map<Long, AdminUserRespDTO> userMap,
 | 
			
		||||
                                                    Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
        if (StrUtil.isBlank(userId)) {
 | 
			
		||||
    default UserSimpleBaseVO buildUser(String userIdStr,
 | 
			
		||||
                                       Map<Long, AdminUserRespDTO> userMap,
 | 
			
		||||
                                       Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
        if (StrUtil.isEmpty(userIdStr)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        AdminUserRespDTO user = userMap.get(NumberUtils.parseLong(userId));
 | 
			
		||||
        Long userId = NumberUtils.parseLong(userIdStr);
 | 
			
		||||
        return buildUser(userId, userMap, deptMap);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default UserSimpleBaseVO buildUser(Long userId,
 | 
			
		||||
                                                    Map<Long, AdminUserRespDTO> userMap,
 | 
			
		||||
                                                    Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
        if (userId == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        AdminUserRespDTO user = userMap.get(userId);
 | 
			
		||||
        if (user == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        BpmProcessInstanceRespVO.User userVO = BeanUtils.toBean(user, BpmProcessInstanceRespVO.User.class);
 | 
			
		||||
        UserSimpleBaseVO userVO = BeanUtils.toBean(user, UserSimpleBaseVO.class);
 | 
			
		||||
        DeptRespDTO dept = user.getDeptId() != null ? deptMap.get(user.getDeptId()) : null;
 | 
			
		||||
        if (dept != null) {
 | 
			
		||||
            userVO.setDeptName(dept.getName());
 | 
			
		||||
@@ -164,4 +183,79 @@ public interface BpmProcessInstanceConvert {
 | 
			
		||||
        return userVO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default BpmApprovalDetailRespVO.ActivityNodeTask buildApprovalTaskInfo(HistoricTaskInstance task) {
 | 
			
		||||
        if (task == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class)
 | 
			
		||||
                .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default Set<Long> parseUserIds(HistoricProcessInstance processInstance,
 | 
			
		||||
                                   List<BpmApprovalDetailRespVO.ActivityNode> activityNodes) {
 | 
			
		||||
        Set<Long> userIds = new HashSet<>();
 | 
			
		||||
        if (processInstance != null) {
 | 
			
		||||
            userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
 | 
			
		||||
        }
 | 
			
		||||
        for (BpmApprovalDetailRespVO.ActivityNode activityNode : activityNodes) {
 | 
			
		||||
            CollUtil.addAll(userIds, convertSet(activityNode.getTasks(), BpmApprovalDetailRespVO.ActivityNodeTask::getAssignee));
 | 
			
		||||
            CollUtil.addAll(userIds, convertSet(activityNode.getTasks(), BpmApprovalDetailRespVO.ActivityNodeTask::getOwner));
 | 
			
		||||
            CollUtil.addAll(userIds, activityNode.getCandidateUserIds());
 | 
			
		||||
        }
 | 
			
		||||
        return userIds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default Set<Long> parseUserIds02(HistoricProcessInstance processInstance,
 | 
			
		||||
                                     List<HistoricTaskInstance> tasks) {
 | 
			
		||||
        Set<Long> userIds = SetUtils.asSet(Long.valueOf(processInstance.getStartUserId()));
 | 
			
		||||
        tasks.forEach(task -> {
 | 
			
		||||
            CollUtil.addIfAbsent(userIds, NumberUtils.parseLong((task.getAssignee())));
 | 
			
		||||
            CollUtil.addIfAbsent(userIds, NumberUtils.parseLong((task.getOwner())));
 | 
			
		||||
        });
 | 
			
		||||
        return userIds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default BpmApprovalDetailRespVO buildApprovalDetail(BpmnModel bpmnModel,
 | 
			
		||||
                                                        ProcessDefinition processDefinition,
 | 
			
		||||
                                                        BpmProcessDefinitionInfoDO processDefinitionInfo,
 | 
			
		||||
                                                        HistoricProcessInstance processInstance,
 | 
			
		||||
                                                        Integer processInstanceStatus,
 | 
			
		||||
                                                        List<BpmApprovalDetailRespVO.ActivityNode> activityNodes,
 | 
			
		||||
                                                        BpmTaskRespVO todoTask,
 | 
			
		||||
                                                        Map<String, String> formFieldsPermission,
 | 
			
		||||
                                                        Map<Long, AdminUserRespDTO> userMap,
 | 
			
		||||
                                                        Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
        // 1. 流程实例
 | 
			
		||||
        BpmProcessInstanceRespVO processInstanceResp = null;
 | 
			
		||||
        if (processInstance != null) {
 | 
			
		||||
            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
 | 
			
		||||
            DeptRespDTO dept = startUser != null ? deptMap.get(startUser.getDeptId()) : null;
 | 
			
		||||
            processInstanceResp = buildProcessInstance(processInstance, null, null, startUser, dept);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 2. 流程定义
 | 
			
		||||
        List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel);
 | 
			
		||||
        BpmProcessDefinitionRespVO definitionResp = BpmProcessDefinitionConvert.INSTANCE.buildProcessDefinition(
 | 
			
		||||
                processDefinition, null, processDefinitionInfo, null, null, bpmnModel, userTaskList);
 | 
			
		||||
 | 
			
		||||
        // 3. 流程节点
 | 
			
		||||
        activityNodes.forEach(approveNode -> {
 | 
			
		||||
            if (approveNode.getTasks() != null) {
 | 
			
		||||
                approveNode.getTasks().forEach(task -> {
 | 
			
		||||
                    task.setAssigneeUser(buildUser(task.getAssignee(), userMap, deptMap));
 | 
			
		||||
                    task.setOwnerUser(buildUser(task.getOwner(), userMap, deptMap));
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            approveNode.setCandidateUsers(convertList(approveNode.getCandidateUserIds(), userId -> buildUser(userId, userMap, deptMap)));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // 4. 拼接起来
 | 
			
		||||
        return new BpmApprovalDetailRespVO().setStatus(processInstanceStatus)
 | 
			
		||||
                .setProcessDefinition(definitionResp)
 | 
			
		||||
                .setProcessInstance(processInstanceResp)
 | 
			
		||||
                .setFormFieldsPermission(formFieldsPermission)
 | 
			
		||||
                .setTodoTask(todoTask)
 | 
			
		||||
                .setActivityNodes(activityNodes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
@@ -30,7 +30,6 @@ import java.util.Map;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
 | 
			
		||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils.isAddSignUserTask;
 | 
			
		||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils.isAssignUserTask;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Bpm 任务 Convert
 | 
			
		||||
@@ -52,7 +51,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
            }
 | 
			
		||||
            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class));
 | 
			
		||||
            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
 | 
			
		||||
            taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
            taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -66,7 +65,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
            // 用户信息
 | 
			
		||||
            AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
 | 
			
		||||
            if (assignUser != null) {
 | 
			
		||||
                taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
                taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, UserSimpleBaseVO.class));
 | 
			
		||||
                findAndThen(deptMap, assignUser.getDeptId(), dept -> taskVO.getAssigneeUser().setDeptName(dept.getName()));
 | 
			
		||||
            }
 | 
			
		||||
            // 流程实例
 | 
			
		||||
@@ -74,7 +73,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
            if (processInstance != null) {
 | 
			
		||||
                AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
 | 
			
		||||
                taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class));
 | 
			
		||||
                taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
                taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
 | 
			
		||||
            }
 | 
			
		||||
            return taskVO;
 | 
			
		||||
        });
 | 
			
		||||
@@ -93,7 +92,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
            // 流程实例
 | 
			
		||||
            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
 | 
			
		||||
            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class));
 | 
			
		||||
            taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
            taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
 | 
			
		||||
            // 表单信息
 | 
			
		||||
            BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class);
 | 
			
		||||
            if (form != null) {
 | 
			
		||||
@@ -113,7 +112,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
        return convertList(taskList, task -> BeanUtils.toBean(task, BpmTaskRespVO.class, taskVO -> {
 | 
			
		||||
            AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
 | 
			
		||||
            if (assignUser != null) {
 | 
			
		||||
                taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
                taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, UserSimpleBaseVO.class));
 | 
			
		||||
                DeptRespDTO dept = deptMap.get(assignUser.getDeptId());
 | 
			
		||||
                if (dept != null) {
 | 
			
		||||
                    taskVO.getAssigneeUser().setDeptName(dept.getName());
 | 
			
		||||
@@ -121,7 +120,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
            }
 | 
			
		||||
            AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(task.getOwner()));
 | 
			
		||||
            if (ownerUser != null) {
 | 
			
		||||
                taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
                taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, UserSimpleBaseVO.class));
 | 
			
		||||
                findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName()));
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
@@ -134,7 +133,8 @@ public interface BpmTaskConvert {
 | 
			
		||||
                                                          Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
       return convertList(todoTaskList, task -> {
 | 
			
		||||
           // 找到分配给当前用户,或者当前用户加签的任务(为了减签)
 | 
			
		||||
           if (!isAssignUserTask(userId, task) && !isAddSignUserTask(userId, task, childrenTaskMap)) {
 | 
			
		||||
           if (!FlowableUtils.isAssignUserTask(userId, task)
 | 
			
		||||
                   && !FlowableUtils.isAddSignUserTask(userId, task, childrenTaskMap)) {
 | 
			
		||||
               return null;
 | 
			
		||||
           }
 | 
			
		||||
           BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
 | 
			
		||||
@@ -166,7 +166,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
                                Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
        AdminUserRespDTO ownerUser = userMap.get(NumberUtils.parseLong(taskOwner));
 | 
			
		||||
        if (ownerUser != null) {
 | 
			
		||||
            task.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
            task.setOwnerUser(BeanUtils.toBean(ownerUser, UserSimpleBaseVO.class));
 | 
			
		||||
            findAndThen(deptMap, ownerUser.getDeptId(), dept -> task.getOwnerUser().setDeptName(dept.getName()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -192,7 +192,7 @@ public interface BpmTaskConvert {
 | 
			
		||||
                                   Map<Long, DeptRespDTO> deptMap) {
 | 
			
		||||
        AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(taskAssignee));
 | 
			
		||||
        if (assignUser != null) {
 | 
			
		||||
            task.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class));
 | 
			
		||||
            task.setAssigneeUser(BeanUtils.toBean(assignUser, UserSimpleBaseVO.class));
 | 
			
		||||
            findAndThen(deptMap, assignUser.getDeptId(), dept -> task.getAssigneeUser().setDeptName(dept.getName()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
 | 
			
		||||
@@ -132,7 +133,7 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
 | 
			
		||||
     * 1. {@link #visible} 只是决定是否可见。即使不可见,还是可以发起
 | 
			
		||||
     * 2. startUserIds 决定某个用户是否可以发起。如果该用户不可发起,则他也是不可见的
 | 
			
		||||
     */
 | 
			
		||||
    @TableField(typeHandler = StringListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤
 | 
			
		||||
    @TableField(typeHandler = LongListTypeHandler.class) // 为了可以使用 find_in_set 进行过滤
 | 
			
		||||
    private List<Long> startUserIds;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -104,10 +104,6 @@ public interface BpmnModelConstants {
 | 
			
		||||
     * BPMN Start Event Node Id
 | 
			
		||||
     */
 | 
			
		||||
    String START_EVENT_NODE_ID = "StartEvent";
 | 
			
		||||
    /**
 | 
			
		||||
     * BPMN Start Event Node Name
 | 
			
		||||
     */
 | 
			
		||||
    String START_EVENT_NODE_NAME = "开始";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 发起人节点 ID
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmActivityService;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
 | 
			
		||||
import com.google.common.collect.ImmutableSet;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
@@ -44,9 +43,6 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy // 解决循环依赖
 | 
			
		||||
    private BpmTaskService taskService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy // 解决循环依赖
 | 
			
		||||
    private BpmActivityService activityService;
 | 
			
		||||
 | 
			
		||||
    public static final Set<FlowableEngineEventType> TASK_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
 | 
			
		||||
            .add(FlowableEngineEventType.TASK_CREATED)
 | 
			
		||||
@@ -72,7 +68,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void activityCancelled(FlowableActivityCancelledEvent event) {
 | 
			
		||||
        List<HistoricActivityInstance> activityList = activityService.getHistoricActivityListByExecutionId(event.getExecutionId());
 | 
			
		||||
        List<HistoricActivityInstance> activityList = taskService.getHistoricActivityListByExecutionId(event.getExecutionId());
 | 
			
		||||
        if (CollUtil.isEmpty(activityList)) {
 | 
			
		||||
            log.error("[activityCancelled][使用 executionId({}) 查找不到对应的活动实例]", event.getExecutionId());
 | 
			
		||||
            return;
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,27 @@ public class FlowableUtils {
 | 
			
		||||
        return (Integer) processVariables.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得流程实例的审批原因
 | 
			
		||||
     *
 | 
			
		||||
     * @param processInstance 流程实例
 | 
			
		||||
     * @return 审批原因
 | 
			
		||||
     */
 | 
			
		||||
    public static String getProcessInstanceReason(HistoricProcessInstance processInstance) {
 | 
			
		||||
        return (String) processInstance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得流程实例的表单
 | 
			
		||||
     *
 | 
			
		||||
     * @param processInstance 流程实例
 | 
			
		||||
     * @return 表单
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, Object> getProcessInstanceFormVariable(ProcessInstance processInstance) {
 | 
			
		||||
        Map<String, Object> processVariables = new HashMap<>(processInstance.getProcessVariables());
 | 
			
		||||
        return filterProcessInstanceFormVariable(processVariables);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得流程实例的表单
 | 
			
		||||
     *
 | 
			
		||||
@@ -105,9 +126,8 @@ public class FlowableUtils {
 | 
			
		||||
     * @return 表单
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, Object> getProcessInstanceFormVariable(HistoricProcessInstance processInstance) {
 | 
			
		||||
        Map<String, Object> formVariables = new HashMap<>(processInstance.getProcessVariables());
 | 
			
		||||
        filterProcessInstanceFormVariable(formVariables);
 | 
			
		||||
        return formVariables;
 | 
			
		||||
        Map<String, Object> processVariables = new HashMap<>(processInstance.getProcessVariables());
 | 
			
		||||
        return filterProcessInstanceFormVariable(processVariables);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -191,7 +211,8 @@ public class FlowableUtils {
 | 
			
		||||
     * @return 是否
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isAssignUserTask(Long userId, Task task) {
 | 
			
		||||
        return ObjectUtil.equal(userId, NumberUtil.parseLong(task.getAssignee(), null));
 | 
			
		||||
        Long assignee = NumberUtil.parseLong(task.getAssignee(), null);
 | 
			
		||||
        return ObjectUtil.equal(userId, assignee);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -202,11 +223,13 @@ public class FlowableUtils {
 | 
			
		||||
     * @return 是否
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isOwnerUserTask(Long userId, Task task) {
 | 
			
		||||
        return ObjectUtil.equal(userId, NumberUtil.parseLong(task.getOwner(), null));
 | 
			
		||||
        Long assignee = NumberUtil.parseLong(task.getAssignee(), null);
 | 
			
		||||
        return ObjectUtil.equal(userId, assignee);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断指定用户,是否是当前任务的加签人
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId 用户 Id
 | 
			
		||||
     * @param task 任务
 | 
			
		||||
     * @param  childrenTaskMap 子任务集合
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,8 @@ public class SimpleModelUtils {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static BpmSimpleModelNodeVO buildStartNode() {
 | 
			
		||||
        return new BpmSimpleModelNodeVO().setId(START_EVENT_NODE_ID).setName(START_EVENT_NODE_NAME)
 | 
			
		||||
        return new BpmSimpleModelNodeVO().setId(START_EVENT_NODE_ID)
 | 
			
		||||
                .setName(BpmSimpleModelNodeType.START_USER_NODE.getName())
 | 
			
		||||
                .setType(BpmSimpleModelNodeType.START_NODE.getType());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.service.task;
 | 
			
		||||
 | 
			
		||||
import org.flowable.engine.history.HistoricActivityInstance;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * BPM 活动实例 Service 接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
public interface BpmActivityService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得指定流程实例的活动实例列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param processInstanceId 流程实例的编号
 | 
			
		||||
     * @return 活动实例列表
 | 
			
		||||
     */
 | 
			
		||||
    List<HistoricActivityInstance> getActivityListByProcessInstanceId(String processInstanceId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得执行编号对应的活动实例
 | 
			
		||||
     *
 | 
			
		||||
     * @param executionId 执行编号
 | 
			
		||||
     * @return 活动实例
 | 
			
		||||
     */
 | 
			
		||||
    List<HistoricActivityInstance> getHistoricActivityListByExecutionId(String executionId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.service.task;
 | 
			
		||||
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.flowable.engine.HistoryService;
 | 
			
		||||
import org.flowable.engine.history.HistoricActivityInstance;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
// TODO 芋艿:准备废弃
 | 
			
		||||
/**
 | 
			
		||||
 * BPM 活动实例 Service 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Validated
 | 
			
		||||
public class BpmActivityServiceImpl implements BpmActivityService {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private HistoryService historyService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<HistoricActivityInstance> getActivityListByProcessInstanceId(String processInstanceId) {
 | 
			
		||||
        return historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
 | 
			
		||||
                .orderByHistoricActivityInstanceStartTime().asc().list();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<HistoricActivityInstance> getHistoricActivityListByExecutionId(String executionId) {
 | 
			
		||||
        return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum;
 | 
			
		||||
import jakarta.validation.Valid;
 | 
			
		||||
import org.flowable.bpmn.model.UserTask;
 | 
			
		||||
import org.flowable.engine.history.HistoricActivityInstance;
 | 
			
		||||
import org.flowable.task.api.Task;
 | 
			
		||||
import org.flowable.task.api.history.HistoricTaskInstance;
 | 
			
		||||
 | 
			
		||||
@@ -130,6 +131,15 @@ public interface BpmTaskService {
 | 
			
		||||
     */
 | 
			
		||||
    List<UserTask> getUserTaskListByReturn(String id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取指定任务的子任务列表(多层)
 | 
			
		||||
     *
 | 
			
		||||
     * @param parentTaskId 父任务 ID
 | 
			
		||||
     * @param tasks 任务列表
 | 
			
		||||
     * @return 子任务列表
 | 
			
		||||
     */
 | 
			
		||||
    List<HistoricTaskInstance> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<HistoricTaskInstance> tasks);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取指定任务的子任务列表
 | 
			
		||||
     *
 | 
			
		||||
@@ -139,12 +149,20 @@ public interface BpmTaskService {
 | 
			
		||||
    List<Task> getTaskListByParentTaskId(String parentTaskId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通过任务 ID,查询任务名 Map
 | 
			
		||||
     * 获得指定流程实例的活动实例列表
 | 
			
		||||
     *
 | 
			
		||||
     * @param taskIds 任务 ID
 | 
			
		||||
     * @return 任务 ID 与名字的 Map
 | 
			
		||||
     * @param processInstanceId 流程实例的编号
 | 
			
		||||
     * @return 活动实例列表
 | 
			
		||||
     */
 | 
			
		||||
    Map<String, String> getTaskNameByTaskIds(Collection<String> taskIds);
 | 
			
		||||
    List<HistoricActivityInstance> getActivityListByProcessInstanceId(String processInstanceId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得执行编号对应的活动实例
 | 
			
		||||
     *
 | 
			
		||||
     * @param executionId 执行编号
 | 
			
		||||
     * @return 活动实例
 | 
			
		||||
     */
 | 
			
		||||
    List<HistoricActivityInstance> getHistoricActivityListByExecutionId(String executionId);
 | 
			
		||||
 | 
			
		||||
    // ========== Update 写入相关方法 ==========
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ import org.flowable.engine.HistoryService;
 | 
			
		||||
import org.flowable.engine.ManagementService;
 | 
			
		||||
import org.flowable.engine.RuntimeService;
 | 
			
		||||
import org.flowable.engine.TaskService;
 | 
			
		||||
import org.flowable.engine.history.HistoricActivityInstance;
 | 
			
		||||
import org.flowable.engine.history.HistoricProcessInstance;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.flowable.task.api.DelegationState;
 | 
			
		||||
@@ -305,6 +306,38 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 | 
			
		||||
        return previousUserList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<HistoricTaskInstance> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<HistoricTaskInstance> tasks) {
 | 
			
		||||
        if (CollUtil.isEmpty(tasks)) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, List<HistoricTaskInstance>> parentTaskMap = convertMultiMap(
 | 
			
		||||
                filterList(tasks, task -> StrUtil.isNotEmpty(task.getParentTaskId())), HistoricTaskInstance::getParentTaskId);
 | 
			
		||||
        if (CollUtil.isEmpty(parentTaskMap)) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<HistoricTaskInstance> result = new ArrayList<>();
 | 
			
		||||
        // 1. 递归获取子级
 | 
			
		||||
        Stack<String> stack = new Stack<>();
 | 
			
		||||
        stack.push(parentTaskId);
 | 
			
		||||
        // 2. 递归遍历
 | 
			
		||||
        for (int i = 0; i < Short.MAX_VALUE; i++) {
 | 
			
		||||
            if (stack.isEmpty()) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            // 2.1 获取子任务们
 | 
			
		||||
            String taskId = stack.pop();
 | 
			
		||||
            List<HistoricTaskInstance> childTaskList = filterList(tasks, task -> StrUtil.equals(task.getParentTaskId(), taskId));
 | 
			
		||||
            // 2.2 如果非空,则添加到 stack 进一步递归
 | 
			
		||||
            if (CollUtil.isNotEmpty(childTaskList)) {
 | 
			
		||||
                stack.addAll(convertList(childTaskList, HistoricTaskInstance::getId));
 | 
			
		||||
                result.addAll(childTaskList);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得所有子任务列表
 | 
			
		||||
     *
 | 
			
		||||
@@ -377,12 +410,14 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Map<String, String> getTaskNameByTaskIds(Collection<String> taskIds) {
 | 
			
		||||
        if (CollUtil.isEmpty(taskIds)) {
 | 
			
		||||
            return Collections.emptyMap();
 | 
			
		||||
        }
 | 
			
		||||
        List<Task> tasks = taskService.createTaskQuery().taskIds(taskIds).list();
 | 
			
		||||
        return convertMap(tasks, Task::getId, Task::getName);
 | 
			
		||||
    public List<HistoricActivityInstance> getActivityListByProcessInstanceId(String processInstanceId) {
 | 
			
		||||
        return historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
 | 
			
		||||
                .orderByHistoricActivityInstanceStartTime().asc().list();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<HistoricActivityInstance> getHistoricActivityListByExecutionId(String executionId) {
 | 
			
		||||
        return historyService.createHistoricActivityInstanceQuery().executionId(executionId).list();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ========== Update 写入相关方法 ==========
 | 
			
		||||
 
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.service.task.bo;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ApprovalNodeInfo;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 已经进行中的审批节点 Response BO
 | 
			
		||||
 *
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class AlreadyRunApproveNodeRespBO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 审批节点信息数组
 | 
			
		||||
     */
 | 
			
		||||
    private List<ApprovalNodeInfo> approveNodes;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 已运行的节点 ID 数组 (对应 Bpmn XML 节点 id)
 | 
			
		||||
     */
 | 
			
		||||
    private Set<String> runNodeIds;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 正在运行的节点的审批信息(key: activityId, value: 审批信息)
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 用于依次审批,需要加上候选人信息
 | 
			
		||||
     */
 | 
			
		||||
    private Map<String, ApprovalNodeInfo> runningApprovalNodes;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user