| | |
| | | package com.iailab.module.bpm.service.definition; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ArrayUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.iailab.framework.common.pojo.PageResult; |
| | | import com.iailab.framework.common.util.json.JsonUtils; |
| | | import com.iailab.framework.common.util.object.PageUtils; |
| | | import com.iailab.framework.common.util.validation.ValidationUtils; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelSaveReqVO; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| | | import com.iailab.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelUpdateReqVO; |
| | | import com.iailab.module.bpm.convert.definition.BpmModelConvert; |
| | | import com.iailab.module.bpm.dal.dataobject.definition.BpmFormDO; |
| | | import com.iailab.module.bpm.enums.definition.BpmModelFormTypeEnum; |
| | | import com.iailab.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; |
| | | import com.iailab.module.bpm.framework.flowable.core.util.BpmnModelUtils; |
| | | import com.iailab.module.bpm.framework.flowable.core.util.FlowableUtils; |
| | | import com.iailab.module.bpm.framework.flowable.core.util.SimpleModelUtils; |
| | | import com.iailab.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.flowable.bpmn.model.BpmnModel; |
| | |
| | | import javax.annotation.Resource; |
| | | import javax.validation.Valid; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | | import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap; |
| | | import static com.iailab.module.bpm.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * Flowable流程模型实现 |
| | | * 主要进行 Flowable {@link Model} 的维护 |
| | | * |
| | | * @author yunlongn |
| | | * @author iailab |
| | | * @author jason |
| | | */ |
| | | @Service |
| | | @Validated |
| | |
| | | private BpmTaskCandidateInvoker taskCandidateInvoker; |
| | | |
| | | @Override |
| | | public PageResult<Model> getModelPage(BpmModelPageReqVO pageVO) { |
| | | public List<Model> getModelList(String name) { |
| | | ModelQuery modelQuery = repositoryService.createModelQuery(); |
| | | if (StrUtil.isNotBlank(pageVO.getKey())) { |
| | | modelQuery.modelKey(pageVO.getKey()); |
| | | if (StrUtil.isNotEmpty(name)) { |
| | | modelQuery.modelNameLike(name); |
| | | } |
| | | if (StrUtil.isNotBlank(pageVO.getName())) { |
| | | modelQuery.modelNameLike("%" + pageVO.getName() + "%"); // 模糊匹配 |
| | | } |
| | | if (StrUtil.isNotBlank(pageVO.getCategory())) { |
| | | modelQuery.modelCategory(pageVO.getCategory()); |
| | | } |
| | | // 执行查询 |
| | | long count = modelQuery.count(); |
| | | if (count == 0) { |
| | | return PageResult.empty(count); |
| | | } |
| | | // 关闭多租户查询,不添加tenantId条件 |
| | | if (StrUtil.isNotBlank(FlowableUtils.getTenantId())) { |
| | | modelQuery.modelTenantId(FlowableUtils.getTenantId()); |
| | | } |
| | | List<Model> models = modelQuery |
| | | .orderByCreateTime().desc() |
| | | .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); |
| | | return new PageResult<>(models, count); |
| | | return modelQuery.list(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { |
| | | public String createModel(@Valid BpmModelSaveReqVO createReqVO) { |
| | | if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) { |
| | | throw exception(MODEL_KEY_VALID); |
| | | } |
| | | // 校验流程标识已经存在 |
| | | // 1. 校验流程标识已经存在 |
| | | Model keyModel = getModelByKey(createReqVO.getKey()); |
| | | if (keyModel != null) { |
| | | throw exception(MODEL_KEY_EXISTS, createReqVO.getKey()); |
| | | } |
| | | |
| | | // 创建流程定义 |
| | | // 2.1 创建流程定义 |
| | | createReqVO.setSort(System.currentTimeMillis()); // 使用当前时间,作为排序 |
| | | Model model = repositoryService.newModel(); |
| | | BpmModelConvert.INSTANCE.copyToCreateModel(model, createReqVO); |
| | | BpmModelConvert.INSTANCE.copyToModel(model, createReqVO); |
| | | model.setTenantId(FlowableUtils.getTenantId()); |
| | | // 保存流程定义 |
| | | // 2.2 保存流程定义 |
| | | repositoryService.saveModel(model); |
| | | // 保存 BPMN XML |
| | | saveModelBpmnXml(model, bpmnXml); |
| | | return model.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 |
| | | public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) { |
| | | // 校验流程模型存在 |
| | | Model model = getModel(updateReqVO.getId()); |
| | | public void updateModel(Long userId, @Valid BpmModelSaveReqVO updateReqVO) { |
| | | // 1. 校验流程模型存在 |
| | | Model model = validateModelManager(updateReqVO.getId(), userId); |
| | | |
| | | // 修改流程定义 |
| | | BpmModelConvert.INSTANCE.copyToModel(model, updateReqVO); |
| | | // 更新模型 |
| | | repositoryService.saveModel(model); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateModelSortBatch(Long userId, List<String> ids) { |
| | | // 1.1 校验流程模型存在 |
| | | List<Model> models = repositoryService.createModelQuery() |
| | | .modelTenantId(FlowableUtils.getTenantId()).list(); |
| | | models.removeIf(model ->!ids.contains(model.getId())); |
| | | if (ids.size() != models.size()) { |
| | | throw exception(MODEL_NOT_EXISTS); |
| | | } |
| | | Map<String, Model> modelMap = convertMap(models, Model::getId); |
| | | // 1.2 校验是否为管理员 |
| | | ids.forEach(id -> validateModelManager(id, userId)); |
| | | |
| | | // 保存排序 |
| | | long sort = System.currentTimeMillis(); // 使用时间戳 - i 作为排序 |
| | | for (int i = ids.size() - 1; i > 0; i--) { |
| | | Model model = modelMap.get(ids.get(i)); |
| | | // 更新模型 |
| | | BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model).setSort(sort); |
| | | model.setMetaInfo(JsonUtils.toJsonString(metaInfo)); |
| | | repositoryService.saveModel(model); |
| | | // 更新排序 |
| | | processDefinitionService.updateProcessDefinitionSortByModelId(model.getId(), sort); |
| | | sort--; |
| | | } |
| | | } |
| | | |
| | | private Model validateModelExists(String id) { |
| | | Model model = repositoryService.getModel(id); |
| | | if (model == null) { |
| | | throw exception(MODEL_NOT_EXISTS); |
| | | } |
| | | return model; |
| | | } |
| | | |
| | | // 修改流程定义 |
| | | BpmModelConvert.INSTANCE.copyToUpdateModel(model, updateReqVO); |
| | | // 更新模型 |
| | | repositoryService.saveModel(model); |
| | | // 更新 BPMN XML |
| | | saveModelBpmnXml(model, updateReqVO.getBpmnXml()); |
| | | /** |
| | | * 校验是否有流程模型的管理权限 |
| | | * |
| | | * @param id 流程模型编号 |
| | | * @param userId 用户编号 |
| | | * @return 流程模型 |
| | | */ |
| | | private Model validateModelManager(String id, Long userId) { |
| | | Model model = validateModelExists(id); |
| | | BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model); |
| | | if (metaInfo == null || !CollUtil.contains(metaInfo.getManagerUserIds(), userId)) { |
| | | throw exception(MODEL_UPDATE_FAIL_NOT_MANAGER, model.getName()); |
| | | } |
| | | return model; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务 |
| | | public void deployModel(String id) { |
| | | public void deployModel(Long userId, String id) { |
| | | // 1.1 校验流程模型存在 |
| | | Model model = getModel(id); |
| | | if (ObjectUtils.isEmpty(model)) { |
| | | throw exception(MODEL_NOT_EXISTS); |
| | | } |
| | | Model model = validateModelManager(id, userId); |
| | | // 1.2 校验流程图 |
| | | byte[] bpmnBytes = getModelBpmnXML(model.getId()); |
| | | validateBpmnXml(bpmnBytes); |
| | | // 1.3 校验表单已配 |
| | | BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); |
| | | BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model); |
| | | BpmFormDO form = validateFormConfig(metaInfo); |
| | | // 1.4 校验任务分配规则已配置 |
| | | taskCandidateInvoker.validateBpmnConfig(bpmnBytes); |
| | | // 1.5 获取仿钉钉流程设计器模型数据 |
| | | String simpleJson = getModelSimpleJson(model.getId()); |
| | | |
| | | // 2.1 创建流程定义 |
| | | String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, form); |
| | | String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, simpleJson, form); |
| | | |
| | | // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。 |
| | | updateProcessDefinitionSuspended(model.getDeploymentId()); |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteModel(String id) { |
| | | public void deleteModel(Long userId, String id) { |
| | | // 校验流程模型存在 |
| | | Model model = getModel(id); |
| | | if (model == null) { |
| | | throw exception(MODEL_NOT_EXISTS); |
| | | } |
| | | Model model = validateModelManager(id, userId); |
| | | |
| | | // 执行删除 |
| | | repositoryService.deleteModel(id); |
| | | // 禁用流程定义 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void updateModelState(String id, Integer state) { |
| | | public void updateModelState(Long userId, String id, Integer state) { |
| | | // 1.1 校验流程模型存在 |
| | | Model model = getModel(id); |
| | | if (model == null) { |
| | | throw exception(MODEL_NOT_EXISTS); |
| | | } |
| | | Model model = validateModelManager(id, userId); |
| | | // 1.2 校验流程定义存在 |
| | | ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); |
| | | if (definition == null) { |
| | |
| | | return repositoryService.getBpmnModel(processDefinitionId); |
| | | } |
| | | |
| | | @Override |
| | | public BpmSimpleModelNodeVO getSimpleModel(String modelId) { |
| | | Model model = validateModelExists(modelId); |
| | | // 通过 ACT_RE_MODEL 表 EDITOR_SOURCE_EXTRA_VALUE_ID_ ,获取仿钉钉快搭模型的 JSON 数据 |
| | | String json = getModelSimpleJson(model.getId()); |
| | | return JsonUtils.parseObject(json, BpmSimpleModelNodeVO.class); |
| | | } |
| | | |
| | | @Override |
| | | public void updateSimpleModel(Long userId, BpmSimpleModelUpdateReqVO reqVO) { |
| | | // 1. 校验流程模型存在 |
| | | Model model = validateModelManager(reqVO.getId(), userId); |
| | | |
| | | // 2.1 JSON 转换成 bpmnModel |
| | | BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModel()); |
| | | // 2.2 保存 Bpmn XML |
| | | updateModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel)); |
| | | // 2.3 保存 JSON 数据 |
| | | updateModelSimpleJson(model.getId(), reqVO.getSimpleModel()); |
| | | } |
| | | |
| | | /** |
| | | * 校验流程表单已配置 |
| | | * |
| | | * @param metaInfo 流程模型元数据 |
| | | * @return 表单配置 |
| | | */ |
| | | private BpmFormDO validateFormConfig(BpmModelMetaInfoRespDTO metaInfo) { |
| | | private BpmFormDO validateFormConfig(BpmModelMetaInfoVO metaInfo) { |
| | | if (metaInfo == null || metaInfo.getFormType() == null) { |
| | | throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | private void saveModelBpmnXml(Model model, String bpmnXml) { |
| | | @Override |
| | | public void updateModelBpmnXml(String id, String bpmnXml) { |
| | | if (StrUtil.isEmpty(bpmnXml)) { |
| | | return; |
| | | } |
| | | repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); |
| | | repositoryService.addModelEditorSource(id, StrUtil.utf8Bytes(bpmnXml)); |
| | | } |
| | | |
| | | @SuppressWarnings("JavaExistingMethodCanBeUsed") |
| | | private String getModelSimpleJson(String id) { |
| | | byte[] bytes = repositoryService.getModelEditorSourceExtra(id); |
| | | if (ArrayUtil.isEmpty(bytes)) { |
| | | return null; |
| | | } |
| | | return StrUtil.utf8Str(bytes); |
| | | } |
| | | |
| | | private void updateModelSimpleJson(String id, BpmSimpleModelNodeVO node) { |
| | | if (node == null) { |
| | | return; |
| | | } |
| | | byte[] bytes = JsonUtils.toJsonByte(node); |
| | | repositoryService.addModelEditorSourceExtra(id, bytes); |
| | | } |
| | | |
| | | /** |
| | | * 挂起 deploymentId 对应的流程定义 |
| | | * |
| | | * <p> |
| | | * 注意:这里一个 deploymentId 只关联一个流程定义 |
| | | * |
| | | * @param deploymentId 流程发布Id |
| | |
| | | } |
| | | |
| | | private Model getModelByKey(String key) { |
| | | return repositoryService.createModelQuery().modelKey(key).singleResult(); |
| | | return repositoryService.createModelQuery() |
| | | .modelTenantId(FlowableUtils.getTenantId()) |
| | | .modelKey(key).singleResult(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | public byte[] getModelBpmnXML(String id) { |
| | | return repositoryService.getModelEditorSource(id); |
| | | } |
| | | |
| | | } |