mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 02:28:03 +08:00 
			
		
		
		
	【代码评审】BPM:review 快搭的实现
This commit is contained in:
		| @ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; | |||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||||
|  |  | ||||||
| // TODO @芋艿:后续考虑下,怎么放这个 Controller | // TODO @jason:融合到 BpmModelController 中,url 是 /bpm/model/simple/... 这样,通过一个子目录区分;目的是:逻辑更聚焦! | ||||||
| @Tag(name = "管理后台 - BPM 仿钉钉流程设计器") | @Tag(name = "管理后台 - BPM 仿钉钉流程设计器") | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/bpm/simple") | @RequestMapping("/bpm/simple") | ||||||
|  | |||||||
| @ -46,7 +46,6 @@ public interface BpmModelService { | |||||||
|      */ |      */ | ||||||
|     byte[] getModelBpmnXML(String id); |     byte[] getModelBpmnXML(String id); | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 保存流程模型的 BPMN XML |      * 保存流程模型的 BPMN XML | ||||||
|      * |      * | ||||||
| @ -107,4 +106,13 @@ public interface BpmModelService { | |||||||
|      */ |      */ | ||||||
|     BpmnModel getBpmnModelByDefinitionId(String processDefinitionId); |     BpmnModel getBpmnModelByDefinitionId(String processDefinitionId); | ||||||
|  |  | ||||||
|  |     // ========== 仿钉钉/飞书的精简模型 ========= | ||||||
|  |  | ||||||
|  |     // TODO @jason:使用 ========== 仿钉钉/飞书的精简模型 ========= 分隔下;把相关的 controller、service 懂合并了;另外,vo 可以挪到 model/simple 这样的形式; | ||||||
|  |  | ||||||
|  |     // TODO @jason:BpmSimpleModelServiceImpl 迁移到这里,搞成 updateSimpleModel(BpmSimpleModelUpdateReqVO reqVO) | ||||||
|  |     // TODO @jason:BpmSimpleModelServiceImpl 迁移到这里,搞成 getSimpleModel; | ||||||
|  |  | ||||||
|  |     // TODO @jason:另外个问题,因为是存储到 modelExtra 里,那需要 deploy 存储出快照。和 bpmn xml 一样。目前我想到的,就是存储到 BpmProcessDefinitionInfoDO 加一个 simple_model 字段,text 类型。可以看看还有啥方案? | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,31 +1,19 @@ | |||||||
| package cn.iocoder.yudao.module.bpm.service.definition; | package cn.iocoder.yudao.module.bpm.service.definition; | ||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; |  | ||||||
| import cn.hutool.core.lang.Assert; |  | ||||||
| import cn.hutool.core.map.MapUtil; |  | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelSaveReqVO; | ||||||
| import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType; |  | ||||||
| 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.framework.flowable.core.util.BpmnModelUtils; | ||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils; | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import org.flowable.bpmn.model.*; | import org.flowable.bpmn.model.BpmnModel; | ||||||
| import org.flowable.engine.repository.Model; | import org.flowable.engine.repository.Model; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
|  |  | ||||||
| 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.module.bpm.enums.ErrorCodeConstants.CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_NOT_EXISTS; | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.START_EVENT; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_PARAM; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY; |  | ||||||
|  |  | ||||||
| // TODO @jason:这块可以讨论下,是不是合并成一个 BpmnModelServiceImpl | // TODO @jason:这块可以讨论下,是不是合并成一个 BpmnModelServiceImpl | ||||||
| /** | /** | ||||||
| @ -42,20 +30,12 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public Boolean saveSimpleModel(BpmSimpleModelSaveReqVO reqVO) { |     public Boolean saveSimpleModel(BpmSimpleModelSaveReqVO reqVO) { | ||||||
|  |         // 1.1 校验流程模型存在 | ||||||
|         Model model = bpmModelService.getModel(reqVO.getModelId()); |         Model model = bpmModelService.getModel(reqVO.getModelId()); | ||||||
|         if (model == null) { |         if (model == null) { | ||||||
|             throw exception(MODEL_NOT_EXISTS); |             throw exception(MODEL_NOT_EXISTS); | ||||||
|         } |         } | ||||||
| //        byte[] bpmnBytes = bpmModelService.getModelBpmnXML(reqVO.getModelId()); |  | ||||||
| //        if (ArrayUtil.isEmpty(bpmnBytes)) { |  | ||||||
| //            //  BPMN XML 不存在。新增 |  | ||||||
| //            BpmnModel bpmnModel = BpmnModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); |  | ||||||
| //            bpmModelService.saveModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel)); |  | ||||||
| //            return Boolean.TRUE; |  | ||||||
| //        } else { |  | ||||||
| //            // TODO BPMN XML 已经存在。如何修改 ?? TODO add by 芋艿:感觉一个流程,只能二选一,要么 bpmn、要么 simple |  | ||||||
| //            return Boolean.FALSE; |  | ||||||
| //        } |  | ||||||
|         // 1. JSON 转换成 bpmnModel |         // 1. JSON 转换成 bpmnModel | ||||||
|         BpmnModel bpmnModel = SimpleModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); |         BpmnModel bpmnModel = SimpleModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); | ||||||
|         // 2.1 保存 Bpmn XML |         // 2.1 保存 Bpmn XML | ||||||
| @ -77,96 +57,4 @@ public class BpmSimpleModelServiceImpl implements BpmSimpleModelService { | |||||||
|         return JsonUtils.parseObject(jsonBytes, BpmSimpleModelNodeVO.class); |         return JsonUtils.parseObject(jsonBytes, BpmSimpleModelNodeVO.class); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @jason:一般要支持这个么?感觉 bpmn 转 json 支持会不会太复杂。可以优先级低一点,做下调研~ |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Bpmn Model 转换成 仿钉钉流程设计模型数据结构(json) 待完善 |  | ||||||
|      * |  | ||||||
|      * @param bpmnModel Bpmn Model |  | ||||||
|      * @return 仿钉钉流程设计模型数据结构 |  | ||||||
|      */ |  | ||||||
|     private BpmSimpleModelNodeVO convertBpmnModelToSimpleModel(BpmnModel bpmnModel) { |  | ||||||
|         if (bpmnModel == null) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|         StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel); |  | ||||||
|         if (startEvent == null) { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|         BpmSimpleModelNodeVO rootNode = new BpmSimpleModelNodeVO(); |  | ||||||
|         rootNode.setType(START_EVENT.getType()); |  | ||||||
|         rootNode.setId(startEvent.getId()); |  | ||||||
|         rootNode.setName(startEvent.getName()); |  | ||||||
|         recursiveBuildSimpleModelNode(startEvent, rootNode); |  | ||||||
|         return rootNode; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void recursiveBuildSimpleModelNode(FlowNode currentFlowNode, BpmSimpleModelNodeVO currentSimpleModeNode) { |  | ||||||
|         BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(currentSimpleModeNode.getType()); |  | ||||||
|         Assert.notNull(nodeType, "节点类型不支持"); |  | ||||||
|         // 校验节点是否支持转仿钉钉的流程模型 |  | ||||||
|         List<SequenceFlow> outgoingFlows = validateCanConvertSimpleNode(nodeType, currentFlowNode); |  | ||||||
|         if (CollUtil.isEmpty(outgoingFlows) || CollUtil.getFirst(outgoingFlows).getTargetFlowElement() == null) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         FlowElement targetElement = CollUtil.getFirst(outgoingFlows).getTargetFlowElement(); |  | ||||||
|         // 如果是 EndEvent 直接退出 |  | ||||||
|         if (targetElement instanceof EndEvent) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         if (targetElement instanceof UserTask) { |  | ||||||
|             BpmSimpleModelNodeVO childNode = convertUserTaskToSimpleModelNode((UserTask) targetElement); |  | ||||||
|             currentSimpleModeNode.setChildNode(childNode); |  | ||||||
|             recursiveBuildSimpleModelNode((FlowNode) targetElement, childNode); |  | ||||||
|         } |  | ||||||
|         // TODO 其它节点类型待实现 |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private BpmSimpleModelNodeVO convertUserTaskToSimpleModelNode(UserTask userTask) { |  | ||||||
|         BpmSimpleModelNodeVO simpleModelNodeVO = new BpmSimpleModelNodeVO(); |  | ||||||
|         simpleModelNodeVO.setType(BpmSimpleModelNodeType.USER_TASK.getType()); |  | ||||||
|         simpleModelNodeVO.setName(userTask.getName()); |  | ||||||
|         simpleModelNodeVO.setId(userTask.getId()); |  | ||||||
|         Map<String, Object> attributes = MapUtil.newHashMap(); |  | ||||||
|         // TODO 暂时是普通审批,需要加会签 |  | ||||||
|         attributes.put("approveMethod", 1); |  | ||||||
|         attributes.computeIfAbsent(USER_TASK_CANDIDATE_STRATEGY, (key) -> BpmnModelUtils.parseCandidateStrategy(userTask)); |  | ||||||
|         attributes.computeIfAbsent(USER_TASK_CANDIDATE_PARAM, (key) -> BpmnModelUtils.parseCandidateParam(userTask)); |  | ||||||
|         simpleModelNodeVO.setAttributes(attributes); |  | ||||||
|         return simpleModelNodeVO; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private List<SequenceFlow> validateCanConvertSimpleNode(BpmSimpleModelNodeType nodeType, FlowNode currentFlowNode) { |  | ||||||
|         switch (nodeType) { |  | ||||||
|             case START_EVENT: |  | ||||||
|             case USER_TASK: { |  | ||||||
|                 List<SequenceFlow> outgoingFlows = currentFlowNode.getOutgoingFlows(); |  | ||||||
|                 if (CollUtil.isNotEmpty(outgoingFlows) && outgoingFlows.size() > 1) { |  | ||||||
|                     throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); |  | ||||||
|                 } |  | ||||||
|                 validIsSupportFlowNode(CollUtil.getFirst(outgoingFlows).getTargetFlowElement()); |  | ||||||
|                 return outgoingFlows; |  | ||||||
|             } |  | ||||||
|             default: { |  | ||||||
|                 // TODO 其它节点类型待实现 |  | ||||||
|                 throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private void validIsSupportFlowNode(FlowElement targetElement) { |  | ||||||
|         if (targetElement == null) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         boolean isSupport = false; |  | ||||||
|         for (Class<? extends FlowNode> item : BpmnModelConstants.SUPPORT_CONVERT_SIMPLE_FlOW_NODES) { |  | ||||||
|             if (item.isInstance(targetElement)) { |  | ||||||
|                 isSupport = true; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         if (!isSupport) { |  | ||||||
|             throw exception(CONVERT_TO_SIMPLE_MODEL_NOT_SUPPORT); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV