mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
This commit is contained in:
		| @ -53,7 +53,13 @@ | |||||||
|             <scope>provided</scope> <!-- 设置为 provided,主要是 GlobalExceptionHandler 使用 --> |             <scope>provided</scope> <!-- 设置为 provided,主要是 GlobalExceptionHandler 使用 --> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |  | ||||||
|         <!-- xss --> |         <!-- 工具类相关 --> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.google.guava</groupId> | ||||||
|  |             <artifactId>guava</artifactId> | ||||||
|  |             <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 --> | ||||||
|  |         </dependency> | ||||||
|  |  | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.jsoup</groupId> |             <groupId>org.jsoup</groupId> | ||||||
|             <artifactId>jsoup</artifactId> |             <artifactId>jsoup</artifactId> | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; | |||||||
| import com.fasterxml.jackson.databind.exc.InvalidFormatException; | import com.fasterxml.jackson.databind.exc.InvalidFormatException; | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.apache.commons.lang3.concurrent.UncheckedExecutionException; | ||||||
| import org.springframework.http.converter.HttpMessageNotReadableException; | import org.springframework.http.converter.HttpMessageNotReadableException; | ||||||
| import org.springframework.security.access.AccessDeniedException; | import org.springframework.security.access.AccessDeniedException; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| @ -106,6 +107,9 @@ public class GlobalExceptionHandler { | |||||||
|         if (ex instanceof AccessDeniedException) { |         if (ex instanceof AccessDeniedException) { | ||||||
|             return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); |             return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); | ||||||
|         } |         } | ||||||
|  |         if (ex instanceof UncheckedExecutionException && ex.getCause() != ex) { | ||||||
|  |             return allExceptionHandler(request, ex.getCause()); | ||||||
|  |         } | ||||||
|         return defaultExceptionHandler(request, ex); |         return defaultExceptionHandler(request, ex); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -252,6 +256,16 @@ public class GlobalExceptionHandler { | |||||||
|         return CommonResult.error(FORBIDDEN); |         return CommonResult.error(FORBIDDEN); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 处理 Guava UncheckedExecutionException | ||||||
|  |      * | ||||||
|  |      * 例如说,缓存加载报错,可见 <a href="https://t.zsxq.com/UszdH">https://t.zsxq.com/UszdH</a> | ||||||
|  |      */ | ||||||
|  |     @ExceptionHandler(value = UncheckedExecutionException.class) | ||||||
|  |     public CommonResult<?> uncheckedExecutionExceptionHandler(HttpServletRequest req, UncheckedExecutionException ex) { | ||||||
|  |         return allExceptionHandler(req, ex.getCause()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 处理业务异常 ServiceException |      * 处理业务异常 ServiceException | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -7,44 +7,35 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCand | |||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | 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.framework.flowable.core.util.FlowableUtils; | ||||||
| import lombok.Setter; | import lombok.Setter; | ||||||
| import org.flowable.bpmn.model.Activity; | import org.flowable.bpmn.model.*; | ||||||
| import org.flowable.bpmn.model.CallActivity; |  | ||||||
| import org.flowable.bpmn.model.FlowElement; |  | ||||||
| import org.flowable.bpmn.model.UserTask; |  | ||||||
| import org.flowable.engine.delegate.DelegateExecution; | import org.flowable.engine.delegate.DelegateExecution; | ||||||
| import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; | import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; | ||||||
| import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; | import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; | ||||||
|  | import org.flowable.engine.impl.persistence.entity.ExecutionEntity; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 自定义的【并行】的【多个】流程任务的 assignee 负责人的分配 |  * 自定义的【串行】的【多个】流程任务的 assignee 负责人的分配 | ||||||
|  * 第一步,基于分配规则,计算出分配任务的【多个】候选人们。 |  | ||||||
|  * 第二步,将【多个】任务候选人们,设置到 DelegateExecution 的 collectionVariable 变量中,以便 BpmUserTaskActivityBehavior 使用它 |  | ||||||
|  * |  * | ||||||
|  * @author kemengkai |  * 本质上,实现和 {@link BpmParallelMultiInstanceBehavior} 一样,只是继承的类不一样 | ||||||
|  * @since 2022-04-21 16:57 |  * | ||||||
|  |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @Setter | @Setter | ||||||
| public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { | public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceBehavior { | ||||||
|  |  | ||||||
|     private BpmTaskCandidateInvoker taskCandidateInvoker; |     private BpmTaskCandidateInvoker taskCandidateInvoker; | ||||||
|  |  | ||||||
|     public BpmParallelMultiInstanceBehavior(Activity activity, |     public BpmSequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { | ||||||
|                                             AbstractBpmnActivityBehavior innerActivityBehavior) { |  | ||||||
|         super(activity, innerActivityBehavior); |         super(activity, innerActivityBehavior); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 重写该方法,主要实现两个功能: |      * 逻辑和 {@link BpmParallelMultiInstanceBehavior#resolveNrOfInstances(DelegateExecution)} 类似 | ||||||
|      * 1. 忽略原有的 collectionVariable、collectionElementVariable 表达式,而是采用自己定义的 |  | ||||||
|      * 2. 获得任务的处理人,并设置到 collectionVariable 中,用于 BpmUserTaskActivityBehavior 从中可以获取任务的处理人 |  | ||||||
|      * |      * | ||||||
|      * 注意,多个任务实例,每个任务实例对应一个处理人,所以返回的数量就是任务处理人的数量 |      * 差异的点:是在【第二步】的时候,需要返回 LinkedHashSet 集合!因为它需要有序! | ||||||
|      * |  | ||||||
|      * @param execution 执行任务 |  | ||||||
|      * @return 数量 |  | ||||||
|      */ |      */ | ||||||
|     @Override |     @Override | ||||||
|     protected int resolveNrOfInstances(DelegateExecution execution) { |     protected int resolveNrOfInstances(DelegateExecution execution) { | ||||||
| @ -58,8 +49,9 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav | |||||||
|             super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); |             super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); | ||||||
|  |  | ||||||
|             // 第二步,获取任务的所有处理人 |             // 第二步,获取任务的所有处理人 | ||||||
|  |             // 不使用 execution.getVariable 原因:目前依次审批任务回退后 collectionVariable 变量没有清理, 如果重新进入该任务不会重新分配审批人 | ||||||
|             @SuppressWarnings("unchecked") |             @SuppressWarnings("unchecked") | ||||||
|             Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class); |             Set<Long> assigneeUserIds = (Set<Long>) execution.getVariableLocal(super.collectionVariable, Set.class); | ||||||
|             if (assigneeUserIds == null) { |             if (assigneeUserIds == null) { | ||||||
|                 assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution); |                 assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution); | ||||||
|                 if (CollUtil.isEmpty(assigneeUserIds)) { |                 if (CollUtil.isEmpty(assigneeUserIds)) { | ||||||
| @ -88,4 +80,19 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav | |||||||
|         return super.resolveNrOfInstances(execution); |         return super.resolveNrOfInstances(execution); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected void executeOriginalBehavior(DelegateExecution execution, ExecutionEntity multiInstanceRootExecution, int loopCounter) { | ||||||
|  |         // 参见 https://t.zsxq.com/53Meo 情况 | ||||||
|  |         if (execution.getCurrentFlowElement() instanceof CallActivity | ||||||
|  |                 || execution.getCurrentFlowElement() instanceof SubProcess) { | ||||||
|  |             super.executeOriginalBehavior(execution, multiInstanceRootExecution, loopCounter); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 参见 https://gitee.com/zhijiantianya/yudao-cloud/issues/IC239F | ||||||
|  |         super.collectionExpression = null; | ||||||
|  |         super.collectionVariable = FlowableUtils.formatExecutionCollectionVariable(execution.getCurrentActivityId()); | ||||||
|  |         super.collectionElementVariable = FlowableUtils.formatExecutionCollectionElementVariable(execution.getCurrentActivityId()); | ||||||
|  |         super.executeOriginalBehavior(execution, multiInstanceRootExecution, loopCounter); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -67,7 +67,6 @@ import java.util.*; | |||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode; | import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode; | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | ||||||
| import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; | ||||||
| @ -221,11 +220,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|         List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, |         List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, | ||||||
|                 processDefinitionInfo, |                 processDefinitionInfo, | ||||||
|                 processVariables, activities); |                 processVariables, activities); | ||||||
|         // 3.3 如果是发起动作,activityId 为开始节点,不校验审批人自选节点 |  | ||||||
|         if (ObjUtil.equals(reqVO.getActivityId(), BpmnModelConstants.START_USER_NODE_ID)) { |  | ||||||
|             simulateActivityNodes.removeIf(node -> |  | ||||||
|                     BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy().equals(node.getCandidateStrategy())); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 4. 拼接最终数据 |         // 4. 拼接最终数据 | ||||||
|         return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, |         return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, | ||||||
| @ -415,7 +409,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|         endActivities.forEach(activity -> { |         endActivities.forEach(activity -> { | ||||||
|             // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点 |             // StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点 | ||||||
|             if (ELEMENT_EVENT_START.equals(activity.getActivityType()) |             if (ELEMENT_EVENT_START.equals(activity.getActivityType()) | ||||||
|                     && BpmModelTypeEnum.BPMN.getType().equals(processDefinitionInfo.getModelType())) { |                     && BpmModelTypeEnum.BPMN.getType().equals(processDefinitionInfo.getModelType()) | ||||||
|  |                     && !CollUtil.contains(activities, // 特殊:如果已经存在用户手动创建的 START_USER_NODE_ID 节点,则忽略 StartEvent | ||||||
|  |                     historicActivity -> historicActivity.getActivityId().equals(START_USER_NODE_ID))) { | ||||||
|                 ActivityNodeTask startTask = new ActivityNodeTask().setId(BpmnModelConstants.START_USER_NODE_ID) |                 ActivityNodeTask startTask = new ActivityNodeTask().setId(BpmnModelConstants.START_USER_NODE_ID) | ||||||
|                         .setAssignee(startUserId).setStatus(BpmTaskStatusEnum.APPROVE.getStatus()); |                         .setAssignee(startUserId).setStatus(BpmTaskStatusEnum.APPROVE.getStatus()); | ||||||
|                 ActivityNode startNode = new ActivityNode().setId(startTask.getId()) |                 ActivityNode startNode = new ActivityNode().setId(startTask.getId()) | ||||||
| @ -555,7 +551,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|         // 情况一:BPMN 设计器 |         // 情况一:BPMN 设计器 | ||||||
|         if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) { |         if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) { | ||||||
|             List<FlowElement> flowElements = BpmnModelUtils.simulateProcess(bpmnModel, processVariables); |             List<FlowElement> flowElements = BpmnModelUtils.simulateProcess(bpmnModel, processVariables); | ||||||
|             return convertList(flowElements, flowElement -> buildNotRunApproveNodeForBpmn(startUserId, bpmnModel, |             return convertList(flowElements, flowElement -> buildNotRunApproveNodeForBpmn( | ||||||
|  |                     startUserId, bpmnModel, flowElements, | ||||||
|                     processDefinitionInfo, processVariables, flowElement, runActivityIds)); |                     processDefinitionInfo, processVariables, flowElement, runActivityIds)); | ||||||
|         } |         } | ||||||
|         // 情况二:SIMPLE 设计器 |         // 情况二:SIMPLE 设计器 | ||||||
| @ -563,7 +560,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|             BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), |             BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), | ||||||
|                     BpmSimpleModelNodeVO.class); |                     BpmSimpleModelNodeVO.class); | ||||||
|             List<BpmSimpleModelNodeVO> simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables); |             List<BpmSimpleModelNodeVO> simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables); | ||||||
|             return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel, |             return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple( | ||||||
|  |                     startUserId, bpmnModel, | ||||||
|                     processDefinitionInfo, processVariables, simpleNode, runActivityIds)); |                     processDefinitionInfo, processVariables, simpleNode, runActivityIds)); | ||||||
|         } |         } | ||||||
|         throw new IllegalArgumentException("未知设计器类型:" + processDefinitionInfo.getModelType()); |         throw new IllegalArgumentException("未知设计器类型:" + processDefinitionInfo.getModelType()); | ||||||
| @ -618,8 +616,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, |     private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, List<FlowElement> flowElements, | ||||||
|                                                        BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables, |                                                        BpmProcessDefinitionInfoDO processDefinitionInfo, | ||||||
|  |                                                        Map<String, Object> processVariables, | ||||||
|                                                        FlowElement node, Set<String> runActivityIds) { |                                                        FlowElement node, Set<String> runActivityIds) { | ||||||
|         if (runActivityIds.contains(node.getId())) { |         if (runActivityIds.contains(node.getId())) { | ||||||
|             return null; |             return null; | ||||||
| @ -634,6 +633,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|  |  | ||||||
|         // 1. 开始节点 |         // 1. 开始节点 | ||||||
|         if (node instanceof StartEvent) { |         if (node instanceof StartEvent) { | ||||||
|  |             if (CollUtil.contains(flowElements, // 特殊:如果已经存在用户手动创建的 START_USER_NODE_ID 节点,则忽略 StartEvent | ||||||
|  |                     flowElement -> flowElement.getId().equals(START_USER_NODE_ID))) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|             return activityNode.setName(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getName()) |             return activityNode.setName(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getName()) | ||||||
|                     .setNodeType(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()); |                     .setNodeType(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -159,10 +159,10 @@ public class CrmContactServiceImpl implements CrmContactService { | |||||||
|         // 2. 删除联系人 |         // 2. 删除联系人 | ||||||
|         contactMapper.deleteById(id); |         contactMapper.deleteById(id); | ||||||
|  |  | ||||||
|         // 4.1 删除数据权限 |         // 4.1 删除商机关联 | ||||||
|         permissionService.deletePermission(CrmBizTypeEnum.CRM_CONTACT.getType(), id); |  | ||||||
|         // 4.2 删除商机关联 |  | ||||||
|         contactBusinessService.deleteContactBusinessByContactId(id); |         contactBusinessService.deleteContactBusinessByContactId(id); | ||||||
|  |         // 4.2 删除数据权限 | ||||||
|  |         permissionService.deletePermission(CrmBizTypeEnum.CRM_CONTACT.getType(), id); | ||||||
|  |  | ||||||
|         // 记录操作日志上下文 |         // 记录操作日志上下文 | ||||||
|         LogRecordContext.putVariable("contactName", contact.getName()); |         LogRecordContext.putVariable("contactName", contact.getName()); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV