From c84a9dd67e766ffd60b3685ed4c2a4af810897c1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Jan 2022 22:03:17 +0800 Subject: [PATCH] 优化流程 Model 的部署代码 --- sql/ruoyi-vue-pro.sql | 14 ++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/BpmModelController.java | 14 ++++++++------ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelBaseVO.java | 3 --- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/ModelConvert.java | 14 ++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/BpmDefinitionConvert.java | 24 ++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/ProcessDefinitionConvert.java | 17 ----------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/ProcessDefinitionDO.java | 29 ----------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/package-info.java | 4 ---- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java | 9 +++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmDefinitionService.java | 20 +++++++++++++++++++- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessService.java | 30 ++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessServiceImpl.java | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmDefinitionServiceImpl.java | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/BpmModelService.java | 9 ++++----- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/impl/BpmModelServiceImpl.java | 94 +++++++++++++++++++++++++++------------------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/ProcessService.java | 29 ----------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/impl/ProcessServiceImpl.java | 109 ------------------------------------------------------------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java | 57 --------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmProcessDefinitionServiceImpl.java | 72 ------------------------------------------------------------------------ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java | 289 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-admin-ui/src/api/bpm/model.js | 7 +++---- yudao-admin-ui/src/views/bpm/model/index.vue | 24 +++++++++++++----------- 27 files changed, 819 insertions(+), 704 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/BpmDefinitionConvert.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/ProcessDefinitionConvert.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/ProcessDefinitionDO.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/package-info.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessServiceImpl.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmDefinitionServiceImpl.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/ProcessService.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/impl/ProcessServiceImpl.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmProcessDefinitionServiceImpl.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index 1eb8ad0..90cfbec 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -2391,4 +2391,18 @@ INSERT INTO `tool_test_demo` VALUES (106, '老五1', 0, 1, 1, '牛逼哈2', '', INSERT INTO `tool_test_demo` VALUES (107, '哈哈哈哈', 1, 0, 1, 'biubiubui', '', '2021-02-06 14:00:54', '', '2021-02-06 14:00:54', b'0'); COMMIT; +CREATE TABLE `bpm_process_definition` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `process_definition_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '流程定义的编号', + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '描述', + `form_id` bigint DEFAULT NULL COMMENT '表单编号', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Bpm 流程定义的拓展表\n'; + SET FOREIGN_KEY_CHECKS = 1; + diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/BpmModelController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/BpmModelController.java index 5a2d4e1..3b4f177 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/BpmModelController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/BpmModelController.java @@ -25,10 +25,10 @@ public class BpmModelController { // TODO @芋艿:权限 - @GetMapping ("/page") + @GetMapping("/page") @ApiOperation(value = "获得模型分页") public CommonResult> getModelPage(ModelPageReqVO pageVO) { - return success(bpmModelService.getModelPage(pageVO)); + return success(bpmModelService.getModelPage(pageVO)); } @GetMapping("/get") @@ -43,7 +43,7 @@ public class BpmModelController { @PostMapping("/create") @ApiOperation(value = "新建模型") public CommonResult createModel(@RequestBody BpmModelCreateReqVO createRetVO) { - return success(bpmModelService.createModel(createRetVO)); + return success(bpmModelService.createModel(createRetVO)); } @PutMapping("/update") @@ -56,15 +56,17 @@ public class BpmModelController { @DeleteMapping("/delete") @ApiOperation("删除模型") @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class) - public CommonResult deleteModel(@RequestParam("id") String id) { + public CommonResult deleteModel(@RequestParam("id") String id) { bpmModelService.deleteModel(id); return success(true); } @PostMapping("/deploy") @ApiOperation(value = "部署模型") - public CommonResult deploy(@RequestParam String modelId) { - return bpmModelService.deploy(modelId); + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class) + public CommonResult deployModel(@RequestParam("id") String id) { + bpmModelService.deployModel(id); + return success(true); } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelBaseVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelBaseVO.java index 9ab133b..b3f78c4 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelBaseVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelBaseVO.java @@ -4,7 +4,6 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; /** * 流程模型 Base VO,提供给添加、修改、详细的子 VO 使用 @@ -22,7 +21,6 @@ public class BpmModelBaseVO { private String name; @ApiModelProperty(value = "流程描述", example = "我是描述") - @NotEmpty(message = "流程描述不能为空") private String description; @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1") @@ -30,7 +28,6 @@ public class BpmModelBaseVO { private String category; @ApiModelProperty(value = "表单编号", example = "1024") - @NotNull(message = "表单编号不能为空") private Long formId; } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java index 2492bcc..32260bd 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow; import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; -import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.BpmTaskService; +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/ModelConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/ModelConvert.java index 22dc628..6495f80 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/ModelConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/ModelConvert.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.BpmModelPage import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.BpmModelRespVO; import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.BpmModelUpdateReqVO; import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO; import cn.iocoder.yudao.adminserver.modules.bpm.service.model.dto.BpmModelMetaInfoRespDTO; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; @@ -58,6 +59,19 @@ public interface ModelConvert { BpmModelRespVO convert(Model model); + default BpmDefinitionCreateReqDTO convert2(Model model) { + BpmDefinitionCreateReqDTO createReqDTO = new BpmDefinitionCreateReqDTO(); + createReqDTO.setName(model.getName()); + createReqDTO.setKey(model.getKey()); + createReqDTO.setCategory(model.getCategory()); + BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); + if (metaInfo != null) { + createReqDTO.setDescription(metaInfo.getDescription()); + createReqDTO.setFormId(metaInfo.getFormId()); + } + return createReqDTO; + } + default void copy(Model model, BpmModelCreateReqVO bean) { model.setName(bean.getName()); model.setKey(bean.getKey()); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/BpmDefinitionConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/BpmDefinitionConvert.java new file mode 100644 index 0000000..c3d22ad --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/BpmDefinitionConvert.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow; + +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionRespVO; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO; +import org.activiti.engine.repository.ProcessDefinition; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * Bpm 流程定义的 Convert + * + * @author yunlong.li + */ +@Mapper +public interface BpmDefinitionConvert { + + BpmDefinitionConvert INSTANCE = Mappers.getMapper(BpmDefinitionConvert.class); + + ProcessDefinitionRespVO convert(ProcessDefinition processDefinition); + + BpmProcessDefinitionDO convert(BpmDefinitionCreateReqDTO bean); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/ProcessDefinitionConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/ProcessDefinitionConvert.java deleted file mode 100644 index e2a48c6..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/ProcessDefinitionConvert.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow; - -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionRespVO; -import org.activiti.engine.repository.ProcessDefinition; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -/** - * @author yunlong.li - */ -@Mapper -public interface ProcessDefinitionConvert { - ProcessDefinitionConvert INSTANCE = Mappers.getMapper(ProcessDefinitionConvert.class); - - ProcessDefinitionRespVO convert(ProcessDefinition processDefinition); - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java new file mode 100644 index 0000000..fda5c4b --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition; + +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; +import org.activiti.engine.repository.ProcessDefinition; + +/** + * Bpm 流程定义的拓展表 + * 主要解决 主要进行 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表 + * + * @author 芋道源码 + */ +@TableName(value = "bpm_process_definition", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmProcessDefinitionDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 流程定义的编号 + * + * 关联 {@link ProcessDefinition#getId()} + */ + private String processDefinitionId; + /** + * 描述 + */ + private String description; + /** + * 表单编号 + * + * 关联 {@link BpmFormDO#getId()} + */ + private Long formId; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/ProcessDefinitionDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/ProcessDefinitionDO.java deleted file mode 100644 index d023c91..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/ProcessDefinitionDO.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.process; - -/** - * 流程模型实体类 映射 activiti ProcessDefinition接口 - * - * @author ZJQ - * @date 2021/9/7 23:23 - */ -public class ProcessDefinitionDO { - - private String id; - - private String category; - - private String key; - - private String name; - - private String version; - - private String resourceName; - - private String deploymentId; - - private String diagramResourceName; - - private boolean suspended; - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/package-info.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/package-info.java deleted file mode 100644 index 0410bc3..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/process/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * TODO 芋艿:工作流的定义 - */ -package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.process; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java new file mode 100644 index 0000000..d3f517c --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmProcessDefinitionMapper extends BaseMapper { +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmDefinitionService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmDefinitionService.java index 3d34170..4d902a5 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmDefinitionService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmDefinitionService.java @@ -3,9 +3,11 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.definition; import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.FileResp; import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionPageReqVo; import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionRespVO; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import org.activiti.engine.repository.ProcessDefinition; +import javax.validation.Valid; import java.util.List; import java.util.Set; @@ -31,11 +33,27 @@ public interface BpmDefinitionService { FileResp export(String processDefinitionId); /** + * 获得编号对应的 ProcessDefinition + * + * @param id 编号 + * @return 流程定义 + */ + ProcessDefinition getDefinition(String id); + + /** * 获得 deploymentId 对应的 ProcessDefinition 数组 * * @param deploymentId 部署编号 * @return 流程定义的数组 */ - List getProcessDefinitionListByDeploymentIds(Set deploymentId); + List getDefinitionListByDeploymentIds(Set deploymentId); + + /** + * 创建流程定义 + * + * @param createReqDTO 创建信息 + * @return 流程编号 + */ + String createDefinition(@Valid BpmDefinitionCreateReqDTO createReqDTO); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessService.java new file mode 100644 index 0000000..7e8cb68 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessService.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.definition; + +import org.springframework.web.multipart.MultipartFile; + +/** + * 流程基础管理 + * + * @author ZJQ + * @date 2021/9/5 21:00 + */ +@Deprecated +public interface ProcessService { + + /** + * 上传流程文件,进行流程模型部署 + * @param multipartFile 上传文件 + */ + void deployProcess(MultipartFile multipartFile); + + + /** + * 激活或者挂起流程模型实体 + * @param processDefinitionId 流程模型实体id + * @param type 类型 + * @return 状态 + */ + String setActivOrHang(String processDefinitionId,String type); + + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessServiceImpl.java new file mode 100644 index 0000000..60e8dbe --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/ProcessServiceImpl.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.definition; + +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.ProcessService; +import lombok.extern.slf4j.Slf4j; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.repository.Deployment; +import org.activiti.engine.repository.ProcessDefinition; +import org.apache.commons.io.FilenameUtils; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.zip.ZipInputStream; +import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.FILE_UPLOAD_FAILED; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * 流程基础管理 + * + * @author ZJQ + * @date 2021/9/5 21:04 + */ +@Service +@Slf4j +@Deprecated +public class ProcessServiceImpl implements ProcessService { + + private static final String BPMN20_XML = "bpmn20.xml"; + + @Resource + private RepositoryService repositoryService; + + /** + * 上传流程文件,进行流程部署 + * @param multipartFile 上传文件 + */ + @Override + public void deployProcess(MultipartFile multipartFile) { + String fileName = multipartFile.getOriginalFilename(); + try (InputStream inputStream = multipartFile.getInputStream()){ + Deployment deployment = getDeplymentByType(inputStream,fileName); + //获取部署成功的流程模型 + List processDefinitions = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list(); + processDefinitions.forEach((processDefinition)->{ + //设置线上部署流程模型名字 + String proDefId = processDefinition.getId(); + repositoryService.setProcessDefinitionCategory(proDefId,fileName); + log.info("流程文件部署成功,流程ID="+proDefId); + }); + } catch (IOException e) { + log.error("流程部署出现异常"+e); + } + } + + /** + * 激活或者挂起流程模型实体 + * @param processDefinitionId 流程模型实体id + * @param type 类型 + * @return 提示 + */ + @Override + public String setActivOrHang(String processDefinitionId, String type) { + String result = "无操作"; + switch (type){ + case "active": + repositoryService.activateProcessDefinitionById(processDefinitionId,true,null); + result = "已激活ID为【"+processDefinitionId+"】的流程模型实例"; + break; + case "suspend": + repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null); + result = "已挂起ID为【"+processDefinitionId+"】的流程模型实例"; + break; + default: + break; + } + return result; + } + + + /** + * 根据上传文件类型对应实现不同方式的流程部署 + * @param inputStream 文件输入流 + * @param fileName 文件名 + * @return 文件部署流程 + */ + public Deployment getDeplymentByType(InputStream inputStream,String fileName){ + Deployment deployment; + String type = FilenameUtils.getExtension(fileName); + switch (type){ + case "bpmn": + String baseName = FilenameUtils.getBaseName(fileName); + deployment = repositoryService.createDeployment().addInputStream(baseName+"."+BPMN20_XML,inputStream).deploy(); + break; + case "png": + deployment = repositoryService.createDeployment().addInputStream(fileName,inputStream).deploy(); + break; + case "zip": + case "bar": + ZipInputStream zipInputStream = new ZipInputStream(inputStream); + deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy(); + break; + default: + throw exception(FILE_UPLOAD_FAILED); + } + return deployment; + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java new file mode 100644 index 0000000..6994836 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +/** + * 流程定义创建 Request DTO + */ +@Data +public class BpmDefinitionCreateReqDTO { + + /** + * 流程标识 + */ + @NotEmpty(message = "流程标识不能为空") + private String key; + /** + * 流程名称 + */ + @NotEmpty(message = "流程名称不能为空") + private String name; + /** + * 流程描述 + */ + private String description; + /** + * 流程分类 + * 参见 bpm_model_category 数据字典 + */ + @NotEmpty(message = "流程分类不能为空") + private String category; + /** + * BPMN XML + */ + @NotEmpty(message = "BPMN XML 不能为空") + private String bpmnXml; + /** + * 动态表单编号,允许空 + */ + private Long formId; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmDefinitionServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmDefinitionServiceImpl.java new file mode 100644 index 0000000..5d00473 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmDefinitionServiceImpl.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.FileResp; +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionPageReqVo; +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionRespVO; +import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.BpmDefinitionConvert; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionMapper; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmDefinitionService; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.activiti.bpmn.converter.BpmnXMLConverter; +import org.activiti.bpmn.model.BpmnModel; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.repository.Deployment; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.repository.ProcessDefinitionQuery; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 流程定义实现 + * 主要进行 Activiti {@link ProcessDefinition} 和 {@link Deployment} 的维护 + * + * @author yunlongn + */ +@Service +@Validated +@Slf4j +public class BpmDefinitionServiceImpl implements BpmDefinitionService { + + private static final String BPMN_FILE_SUFFIX = ".bpmn"; + + @Resource + private RepositoryService repositoryService; + + @Resource + private BpmProcessDefinitionMapper processDefinitionMapper; + + @Override + public PageResult pageList(ProcessDefinitionPageReqVo processDefinitionPageReqVo) { + ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); + String likeName = processDefinitionPageReqVo.getName(); + if (StrUtil.isNotBlank(likeName)){ + processDefinitionQuery.processDefinitionNameLike("%"+likeName+"%"); + } + List processDefinitions = processDefinitionQuery.orderByProcessDefinitionId().desc() + .listPage((processDefinitionPageReqVo.getPageNo() - 1) * processDefinitionPageReqVo.getPageSize(), + processDefinitionPageReqVo.getPageSize()); + final List respVOList = processDefinitions.stream() + .map(BpmDefinitionConvert.INSTANCE::convert).collect(Collectors.toList()); + return new PageResult<>(respVOList, processDefinitionQuery.count()); + } + + @Override + public FileResp export(String processDefinitionId) { + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel); + FileResp fileResp = new FileResp(); + fileResp.setFileName( "export"); + fileResp.setFileByte(bpmnBytes); + return fileResp; + } + + @Override + public ProcessDefinition getDefinition(String id) { + return repositoryService.getProcessDefinition(id); + } + + @Override + public List getDefinitionListByDeploymentIds(Set deploymentIds) { + if (CollUtil.isEmpty(deploymentIds)) { + return Collections.emptyList(); + } + return repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).list(); + } + + @Override + @Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作,所以开启事务 + public String createDefinition(BpmDefinitionCreateReqDTO createReqDTO) { + // 创建 Deployment 部署 + Deployment deploy = repositoryService.createDeployment() + .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) + .addString(createReqDTO.getName() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnXml()) + .deploy(); + + // 设置 ProcessDefinition 的 category 分类 + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult(); + repositoryService.setProcessDefinitionCategory(definition.getId(), createReqDTO.getCategory()); + + // 插入拓展表 + BpmProcessDefinitionDO definitionDO = BpmDefinitionConvert.INSTANCE.convert(createReqDTO) + .setProcessDefinitionId(definition.getId()); + processDefinitionMapper.insert(definitionDO); + return definition.getId(); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/BpmModelService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/BpmModelService.java index 62b8ef1..83d68e5 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/BpmModelService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/BpmModelService.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.model; import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import javax.validation.Valid; @@ -45,11 +44,11 @@ public interface BpmModelService { void updateModel(@Valid BpmModelUpdateReqVO updateReqVO); /** - * 部署模型 使模型成为一个 process - * @param modelId 模型Id - * @return 返回成功 + * 将流程模型,部署成一个流程定义 + * + * @param id 编号 */ - CommonResult deploy(String modelId); + void deployModel(String id); /** * 删除模型 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/impl/BpmModelServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/impl/BpmModelServiceImpl.java index 3f23bef..fbfb357 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/impl/BpmModelServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/impl/BpmModelServiceImpl.java @@ -1,45 +1,35 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.model.impl; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*; import cn.iocoder.yudao.adminserver.modules.bpm.convert.model.ModelConvert; import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO; -import cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants; import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmDefinitionService; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO; import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService; import cn.iocoder.yudao.adminserver.modules.bpm.service.model.BpmModelService; import cn.iocoder.yudao.adminserver.modules.bpm.service.model.dto.BpmModelMetaInfoRespDTO; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import lombok.extern.slf4j.Slf4j; -import org.activiti.bpmn.converter.BpmnXMLConverter; -import org.activiti.bpmn.model.BpmnModel; import org.activiti.engine.RepositoryService; -import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.Model; import org.activiti.engine.repository.ModelQuery; import org.activiti.engine.repository.ProcessDefinition; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamReader; -import java.io.ByteArrayInputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.BPMN_MODEL_NOT_EXISTS; import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.BPM_MODEL_KEY_EXISTS; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; @@ -55,8 +45,6 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @Slf4j public class BpmModelServiceImpl implements BpmModelService { - private static final String BPMN_FILE_SUFFIX = ".bpmn"; - @Resource private RepositoryService repositoryService; @Resource @@ -83,8 +71,8 @@ public class BpmModelServiceImpl implements BpmModelService { // 获得 ProcessDefinition Map Set deploymentIds = new HashSet<>(); - models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getId())); - List processDefinitions = bpmDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds); + models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId())); + List processDefinitions = bpmDefinitionService.getDefinitionListByDeploymentIds(deploymentIds); Map processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId); // 拼接结果 @@ -98,9 +86,7 @@ public class BpmModelServiceImpl implements BpmModelService { BpmModelRespVO modelRespVO = ModelConvert.INSTANCE.convert(model); // 拼接 bpmn XML byte[] bpmnBytes = repositoryService.getModelEditorSource(id); - if (ArrayUtil.isNotEmpty(bpmnBytes)) { - modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes)); - } + modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes)); return modelRespVO; } @@ -124,26 +110,13 @@ public class BpmModelServiceImpl implements BpmModelService { return model.getId(); } -// @Override -// @Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作,所以开启事务 -// public String createModel(BpmModelCreateReqVO createReqVO) { -// Deployment deploy = repositoryService.createDeployment() -// .key(createReqVO.getKey()).name(createReqVO.getName()).category(createReqVO.getCategory()) -// .addString(createReqVO.getName() + BPMN_FILE_SUFFIX, createReqVO.getBpmnXml()) -// .deploy(); -// // 设置 ProcessDefinition 的 category 分类 -// ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult(); -// repositoryService.setProcessDefinitionCategory(definition.getId(), createReqVO.getCategory()); -// return definition.getId(); -// } - @Override @Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作,所以开启事务 public void updateModel(BpmModelUpdateReqVO updateReqVO) { // 校验流程模型存在 Model model = repositoryService.getModel(updateReqVO.getId()); if (model == null) { - throw exception(BpmErrorCodeConstants.BPMN_MODEL_NOT_EXISTS); + throw exception(BPMN_MODEL_NOT_EXISTS); } // TODO @芋艿:需要校验下 key 的格式 @@ -156,40 +129,27 @@ public class BpmModelServiceImpl implements BpmModelService { } @Override - public CommonResult deploy(String modelId) { - try { - Model modelData = repositoryService.getModel(modelId); - if (ObjectUtils.isEmpty(modelData)) { - throw exception(BpmErrorCodeConstants.BPMN_MODEL_NOT_EXISTS); - } - byte[] bytes = repositoryService.getModelEditorSource(modelData.getId()); - if (bytes == null) { - throw exception(BpmErrorCodeConstants.BPMN_MODEL_NOT_EXISTS); - } - // 将xml转换为流 - // TODO @Li:这里是标准逻辑,看看 hutool 有没工具类提供。如果没有,咱自己封装一个 - ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); - XMLInputFactory xif = XMLInputFactory.newInstance(); - InputStreamReader in = new InputStreamReader(inputStream, StandardCharsets.UTF_8); - XMLStreamReader xtr = xif.createXMLStreamReader(in); - // 流数据转化为 model - BpmnModel model = new BpmnXMLConverter().convertToBpmnModel(xtr); - if(ObjectUtils.isEmpty(model.getProcesses())){ - throw exception(BpmErrorCodeConstants.BPMN_MODEL_PROCESS_NOT_EXISTS); - } - byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model); - // 部署发布模型流程 - String processName = modelData.getName() + ".bpmn20.xml"; - Deployment deployment = repositoryService.createDeployment() - .name(modelData.getName()) - .addString(processName, new String(bpmnBytes, StandardCharsets.UTF_8)) - .deploy(); - // 部署成功 - return CommonResult.success(deployment.getId()); - } catch (Exception e) { - log.info("模型部署失败!modelId = {} e = {} ", modelId, ExceptionUtils.getStackTrace(e)); - throw exception(BpmErrorCodeConstants.BPMN_MODEL_ERROR); + @Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作,所以开启事务 + public void deployModel(String id) { + // 校验流程模型存在 + Model model = repositoryService.getModel(id); + if (ObjectUtils.isEmpty(model)) { + throw exception(BPMN_MODEL_NOT_EXISTS); } + byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId()); + if (bpmnBytes == null) { + throw exception(BPMN_MODEL_NOT_EXISTS); + } + + // 创建流程定义 + BpmDefinitionCreateReqDTO definitionCreateReqDTO = ModelConvert.INSTANCE.convert2(model) + .setBpmnXml(StrUtil.utf8Str(bpmnBytes)); + String definitionId = bpmDefinitionService.createDefinition(definitionCreateReqDTO); + + // 更新 model 的 deploymentId,进行关联 + ProcessDefinition definition = bpmDefinitionService.getDefinition(definitionId); + model.setDeploymentId(definition.getDeploymentId()); + repositoryService.saveModel(model); } @Override @@ -197,7 +157,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 校验流程模型存在 Model model = repositoryService.getModel(id); if (model == null) { - throw exception(BpmErrorCodeConstants.BPMN_MODEL_NOT_EXISTS); + throw exception(BPMN_MODEL_NOT_EXISTS); } // 执行删除 repositoryService.deleteModel(id); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/ProcessService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/ProcessService.java deleted file mode 100644 index 6a0d636..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/ProcessService.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.process; - -import org.springframework.web.multipart.MultipartFile; - -/** - * 流程基础管理 - * - * @author ZJQ - * @date 2021/9/5 21:00 - */ -public interface ProcessService { - - /** - * 上传流程文件,进行流程模型部署 - * @param multipartFile 上传文件 - */ - void deployProcess(MultipartFile multipartFile); - - - /** - * 激活或者挂起流程模型实体 - * @param processDefinitionId 流程模型实体id - * @param type 类型 - * @return 状态 - */ - String setActivOrHang(String processDefinitionId,String type); - - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/impl/ProcessServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/impl/ProcessServiceImpl.java deleted file mode 100644 index a084cbe..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/process/impl/ProcessServiceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.process.impl; - -import cn.iocoder.yudao.adminserver.modules.bpm.service.process.ProcessService; -import lombok.extern.slf4j.Slf4j; -import org.activiti.engine.RepositoryService; -import org.activiti.engine.repository.Deployment; -import org.activiti.engine.repository.ProcessDefinition; -import org.apache.commons.io.FilenameUtils; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import javax.annotation.Resource; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.zip.ZipInputStream; -import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.FILE_UPLOAD_FAILED; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; - -/** - * 流程基础管理 - * - * @author ZJQ - * @date 2021/9/5 21:04 - */ -@Service -@Slf4j -public class ProcessServiceImpl implements ProcessService { - - private static final String BPMN20_XML = "bpmn20.xml"; - - @Resource - private RepositoryService repositoryService; - - /** - * 上传流程文件,进行流程部署 - * @param multipartFile 上传文件 - */ - @Override - public void deployProcess(MultipartFile multipartFile) { - String fileName = multipartFile.getOriginalFilename(); - try (InputStream inputStream = multipartFile.getInputStream()){ - Deployment deployment = getDeplymentByType(inputStream,fileName); - //获取部署成功的流程模型 - List processDefinitions = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list(); - processDefinitions.forEach((processDefinition)->{ - //设置线上部署流程模型名字 - String proDefId = processDefinition.getId(); - repositoryService.setProcessDefinitionCategory(proDefId,fileName); - log.info("流程文件部署成功,流程ID="+proDefId); - }); - } catch (IOException e) { - log.error("流程部署出现异常"+e); - } - } - - /** - * 激活或者挂起流程模型实体 - * @param processDefinitionId 流程模型实体id - * @param type 类型 - * @return 提示 - */ - @Override - public String setActivOrHang(String processDefinitionId, String type) { - String result = "无操作"; - switch (type){ - case "active": - repositoryService.activateProcessDefinitionById(processDefinitionId,true,null); - result = "已激活ID为【"+processDefinitionId+"】的流程模型实例"; - break; - case "suspend": - repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null); - result = "已挂起ID为【"+processDefinitionId+"】的流程模型实例"; - break; - default: - break; - } - return result; - } - - - /** - * 根据上传文件类型对应实现不同方式的流程部署 - * @param inputStream 文件输入流 - * @param fileName 文件名 - * @return 文件部署流程 - */ - public Deployment getDeplymentByType(InputStream inputStream,String fileName){ - Deployment deployment; - String type = FilenameUtils.getExtension(fileName); - switch (type){ - case "bpmn": - String baseName = FilenameUtils.getBaseName(fileName); - deployment = repositoryService.createDeployment().addInputStream(baseName+"."+BPMN20_XML,inputStream).deploy(); - break; - case "png": - deployment = repositoryService.createDeployment().addInputStream(fileName,inputStream).deploy(); - break; - case "zip": - case "bar": - ZipInputStream zipInputStream = new ZipInputStream(inputStream); - deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy(); - break; - default: - throw exception(FILE_UPLOAD_FAILED); - } - return deployment; - } -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java new file mode 100644 index 0000000..dceba6f --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.task; + +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import java.util.List; + +/** + * 工作流用户任务服务接口 + */ +public interface BpmTaskService { + + + /** + * 获取当前用户的待办任务, 分页 + */ + PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO); + + /** + * 签收任务 + * @param taskId 用户任务id + */ + void claimTask(String taskId); + + /** + * 工作流,完成 userTask, 完成用户任务 一般传入参数 1。是否同意(variables). 2. 评论(comment) + * variables 变量名 和 评论 由前台传入 + * @param taskReq 任务参数 + */ + void completeTask(TaskReqVO taskReq); + + /** + * 根据任务id, 查询已经完成的用户任务,未完成的用户任务 + * @param taskQuery 查询参数 一般 taskId + */ + TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery); + + /** + * 根据流程实例id, 查询历史用户任务,包括已完成,未完成 + * @param processInstanceId 流程实例id + */ + List getHistorySteps(String processInstanceId); + + /** + * 获取用户任务的 formKey, 对应外置表单, 需要根据formKey 对应业务表单 + * @param taskQuery 查询参数 ,一般taskId + */ + TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery); + + + /** + * 返回高亮的流转进程 + * @param processInstanceId 实例Id + * @return {@link FileResp} 返回文件 + */ + FileResp getHighlightImg(String processInstanceId); +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java new file mode 100644 index 0000000..381c4ab --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java @@ -0,0 +1,288 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; +import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert; +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import lombok.extern.slf4j.Slf4j; +import org.activiti.api.runtime.shared.query.Page; +import org.activiti.api.runtime.shared.query.Pageable; +import org.activiti.api.task.model.Task; +import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder; +import org.activiti.api.task.model.builders.TaskPayloadBuilder; +import org.activiti.api.task.runtime.TaskRuntime; +import org.activiti.bpmn.constants.BpmnXMLConstants; +import org.activiti.bpmn.model.BpmnModel; +import org.activiti.bpmn.model.FlowNode; +import org.activiti.bpmn.model.SequenceFlow; +import org.activiti.engine.HistoryService; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.history.HistoricActivityInstance; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.Comment; +import org.activiti.image.ProcessDiagramGenerator; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.HIGHLIGHT_IMG_ERROR; +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +@Slf4j +@Service +public class BpmTaskServiceImpl implements BpmTaskService { + + @Resource + private TaskRuntime taskRuntime; + + @Resource + private org.activiti.engine.TaskService activitiTaskService; + + @Resource + private HistoryService historyService; + + @Resource + private RepositoryService repositoryService; + + @Resource + private RuntimeService runtimeService; + + @Resource + private ProcessDiagramGenerator processDiagramGenerator; + + @Override + public PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO) { + // TODO @jason:封装一个方法,用于转换成 activiti 的分页对象 + final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize()); + Page pageTasks = taskRuntime.tasks(pageable); + int totalItems = pageTasks.getTotalItems(); + List tasks = pageTasks.getContent(); + final List respVOList = tasks.stream().map(task -> { + ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId()); + return TaskConvert.INSTANCE.convert(task, definition); + }).collect(Collectors.toList()); + return new PageResult<>(respVOList, (long)totalItems); + } + + + @Override + public void claimTask(String taskId) { + taskRuntime.claim(new ClaimTaskPayloadBuilder() + .withTaskId(taskId) + .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername()) + .build()); + } + + + + @Override + @Transactional + public void completeTask(TaskReqVO taskReq) { + final Task task = taskRuntime.task(taskReq.getTaskId()); + + activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment()); + + taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId()) + .withVariables(taskReq.getVariables()) + .build()); + } + + + + @Override + public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) { + TaskHandleVO handleVO = new TaskHandleVO(); + final Task task = taskRuntime.task(taskQuery.getTaskId()); + List steps = getTaskSteps(task.getProcessInstanceId()); + handleVO.setHistoryTask(steps); + return handleVO; + } + + + private List getTaskSteps(String processInstanceId) { + // 获得已完成的活动 + List finished = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .activityType("userTask") + .finished() + .orderByHistoricActivityInstanceStartTime().asc().list(); + // 获得对应的步骤 + List steps = new ArrayList<>(); + finished.forEach(instance -> { + TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); + stepVO.setStatus(1); // TODO @jason:1 这个 magic number 要枚举起来。 + // TODO @jason:可以考虑把 comments 读取后,在统一调用 convert 拼接。另外 Comment 是废弃的类,有没其它可以使用的哈? + List comments = activitiTaskService.getTaskComments(instance.getTaskId()); + if (!CollUtil.isEmpty(comments)) { + stepVO.setComment(Optional.ofNullable(comments.get(0)).map(Comment::getFullMessage).orElse("")); + } + steps.add(stepVO); + }); + + // 获得未完成的活动 + List unfinished = historyService + .createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .activityType("userTask") + .unfinished().list(); + // 获得对应的步骤 + for (HistoricActivityInstance instance : unfinished) { + TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); + stepVO.setComment(""); + stepVO.setStatus(0); + steps.add(stepVO); + } + return steps; + } + + + @Override + public List getHistorySteps(String processInstanceId) { + return getTaskSteps(processInstanceId); + } + + @Override + public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) { + final Task task = taskRuntime.task(taskQuery.getTaskId()); + return TaskConvert.INSTANCE.convert(task); + } + + @Override + public FileResp getHighlightImg(String processInstanceId) { + // 查询历史 + //TODO 云扬四海 貌似流程结束后,点击审批进度会报错 + // TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来 + HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + // 如果不存在实例。 说明数据异常 + if (hpi == null) { + throw exception(PROCESS_INSTANCE_NOT_EXISTS); + } + // 如果有结束时间 返回model的流程图 + if (!ObjectUtils.isEmpty(hpi.getEndTime())) { + ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionId(hpi.getProcessDefinitionId()).singleResult(); + String resourceName = Optional.ofNullable(pd.getDiagramResourceName()).orElse(pd.getResourceName()); + BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId()); + InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, new ArrayList<>(1), new ArrayList<>(1), + "宋体", "宋体", "宋体"); + FileResp fileResp = new FileResp(); + fileResp.setFileName( resourceName + ".svg"); + fileResp.setFileByte(IoUtil.readBytes(inputStream)); + return fileResp; + } + // 没有结束时间。说明流程在执行过程中 + // TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来 + ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + + List highLightedActivities = new ArrayList<>(); + // 获取所有活动节点 + List finishedInstances = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).finished().list(); + finishedInstances.stream().map(HistoricActivityInstance::getActivityId) + .forEach(highLightedActivities::add); + // 已完成的节点+当前节点 + highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId)); + + BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); + // 经过的流 + List highLightedFlowIds = getHighLightedFlows(bpmnModel, processInstanceId); + + //设置"宋体" + try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds, + "宋体", "宋体", "宋体")){ + FileResp fileResp = new FileResp(); + fileResp.setFileName( hpi.getProcessDefinitionName() + ".svg"); + fileResp.setFileByte(IoUtil.readBytes(inputStream)); + return fileResp; + } catch (IOException e) { + log.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e); + throw exception(HIGHLIGHT_IMG_ERROR); + } + } + + // TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。 + /** + * 获取指定 processInstanceId 已经高亮的Flows + * 获取已经流转的线 参考: https://blog.csdn.net/qiuxinfa123/article/details/119579863 + * @param bpmnModel model + * @param processInstanceId 流程实例Id + * @return 获取已经流转的列表 + */ + private List getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) { + // 获取所有的线条 + List historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId) + .orderByHistoricActivityInstanceId().asc().list(); + // 高亮流程已发生流转的线id集合 + List highLightedFlowIds = new ArrayList<>(); + // 全部活动节点 + List historicActivityNodes = new ArrayList<>(); + // 已完成的历史活动节点 + List finishedActivityInstances = new ArrayList<>(); + + for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { + FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true); + historicActivityNodes.add(flowNode); + // 结束时间不为空,则是已完成节点 + if (historicActivityInstance.getEndTime() != null) { + finishedActivityInstances.add(historicActivityInstance); + } + } + // 提取活动id 是唯一的。塞入Map + Map historicActivityInstanceMap = CollectionUtils.convertMap(historicActivityInstances, HistoricActivityInstance::getActivityId); + // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的 + for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) { + // 获得当前活动对应的节点信息及outgoingFlows信息 + FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true); + List sequenceFlows = currentFlowNode.getOutgoingFlows(); + + // 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转: + // 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 + // 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转 + if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(currentActivityInstance.getActivityType()) + || BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE.equals(currentActivityInstance.getActivityType())) { + // 遍历历史活动节点,找到匹配流程目标节点的 + for (SequenceFlow sequenceFlow : sequenceFlows) { + FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true); + if (historicActivityNodes.contains(targetFlowNode)) { + highLightedFlowIds.add(targetFlowNode.getId()); + } + } + } else { + long earliestStamp = 0L; + String highLightedFlowId = null; + // 循环流出的流 + for (SequenceFlow sequenceFlow : sequenceFlows) { + HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(sequenceFlow.getTargetRef()); + if (historicActivityInstance == null) { + continue; + } + final long startTime = historicActivityInstance.getStartTime().getTime(); + // 遍历匹配的集合,取得开始时间最早的一个 + if (earliestStamp == 0 || earliestStamp >= startTime) { + highLightedFlowId = sequenceFlow.getId(); + earliestStamp = startTime; + } + } + highLightedFlowIds.add(highLightedFlowId); + } + + } + return highLightedFlowIds; + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java deleted file mode 100644 index 37d14d8..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow; - -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import java.util.List; - -/** - * 工作流用户任务服务接口 - */ -public interface BpmTaskService { - - - /** - * 获取当前用户的待办任务, 分页 - */ - PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO); - - /** - * 签收任务 - * @param taskId 用户任务id - */ - void claimTask(String taskId); - - /** - * 工作流,完成 userTask, 完成用户任务 一般传入参数 1。是否同意(variables). 2. 评论(comment) - * variables 变量名 和 评论 由前台传入 - * @param taskReq 任务参数 - */ - void completeTask(TaskReqVO taskReq); - - /** - * 根据任务id, 查询已经完成的用户任务,未完成的用户任务 - * @param taskQuery 查询参数 一般 taskId - */ - TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery); - - /** - * 根据流程实例id, 查询历史用户任务,包括已完成,未完成 - * @param processInstanceId 流程实例id - */ - List getHistorySteps(String processInstanceId); - - /** - * 获取用户任务的 formKey, 对应外置表单, 需要根据formKey 对应业务表单 - * @param taskQuery 查询参数 ,一般taskId - */ - TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery); - - - /** - * 返回高亮的流转进程 - * @param processInstanceId 实例Id - * @return {@link FileResp} 返回文件 - */ - FileResp getHighlightImg(String processInstanceId); -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmProcessDefinitionServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmProcessDefinitionServiceImpl.java deleted file mode 100644 index 6f835a7..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmProcessDefinitionServiceImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.FileResp; -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionPageReqVo; -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.processdefinition.ProcessDefinitionRespVO; -import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.ProcessDefinitionConvert; -import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmDefinitionService; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.activiti.api.process.runtime.ProcessRuntime; -import org.activiti.bpmn.converter.BpmnXMLConverter; -import org.activiti.bpmn.model.BpmnModel; -import org.activiti.engine.RepositoryService; -import org.activiti.engine.repository.ProcessDefinition; -import org.activiti.engine.repository.ProcessDefinitionQuery; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * 流程定义实现 - * @author yunlongn - */ -@Slf4j -@Service -@RequiredArgsConstructor -public class BpmProcessDefinitionServiceImpl implements BpmDefinitionService { - - private final RepositoryService repositoryService; - - private final ProcessRuntime processRuntime; - - @Override - public PageResult pageList(ProcessDefinitionPageReqVo processDefinitionPageReqVo) { - ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery(); - String likeName = processDefinitionPageReqVo.getName(); - if (StrUtil.isNotBlank(likeName)){ - processDefinitionQuery.processDefinitionNameLike("%"+likeName+"%"); - } - List processDefinitions = processDefinitionQuery.orderByProcessDefinitionId().desc() - .listPage((processDefinitionPageReqVo.getPageNo() - 1) * processDefinitionPageReqVo.getPageSize(), - processDefinitionPageReqVo.getPageSize()); - final List respVOList = processDefinitions.stream() - .map(ProcessDefinitionConvert.INSTANCE::convert).collect(Collectors.toList()); - return new PageResult<>(respVOList, processDefinitionQuery.count()); - } - - @Override - public FileResp export(String processDefinitionId) { - BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); - byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel); - FileResp fileResp = new FileResp(); - fileResp.setFileName( "export"); - fileResp.setFileByte(bpmnBytes); - return fileResp; - } - - @Override - public List getProcessDefinitionListByDeploymentIds(Set deploymentIds) { - if (CollUtil.isEmpty(deploymentIds)) { - return Collections.emptyList(); - } - return repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).list(); - } - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java deleted file mode 100644 index 8ca9bbb..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java +++ /dev/null @@ -1,289 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.IoUtil; -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; -import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert; -import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.BpmTaskService; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import lombok.extern.slf4j.Slf4j; -import org.activiti.api.runtime.shared.query.Page; -import org.activiti.api.runtime.shared.query.Pageable; -import org.activiti.api.task.model.Task; -import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder; -import org.activiti.api.task.model.builders.TaskPayloadBuilder; -import org.activiti.api.task.runtime.TaskRuntime; -import org.activiti.bpmn.constants.BpmnXMLConstants; -import org.activiti.bpmn.model.BpmnModel; -import org.activiti.bpmn.model.FlowNode; -import org.activiti.bpmn.model.SequenceFlow; -import org.activiti.engine.HistoryService; -import org.activiti.engine.RepositoryService; -import org.activiti.engine.RuntimeService; -import org.activiti.engine.history.HistoricActivityInstance; -import org.activiti.engine.history.HistoricProcessInstance; -import org.activiti.engine.repository.ProcessDefinition; -import org.activiti.engine.runtime.ProcessInstance; -import org.activiti.engine.task.Comment; -import org.activiti.image.ProcessDiagramGenerator; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.ObjectUtils; - -import javax.annotation.Resource; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.HIGHLIGHT_IMG_ERROR; -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; - -@Slf4j -@Service -public class BpmTaskServiceImpl implements BpmTaskService { - - @Resource - private TaskRuntime taskRuntime; - - @Resource - private org.activiti.engine.TaskService activitiTaskService; - - @Resource - private HistoryService historyService; - - @Resource - private RepositoryService repositoryService; - - @Resource - private RuntimeService runtimeService; - - @Resource - private ProcessDiagramGenerator processDiagramGenerator; - - @Override - public PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO) { - // TODO @jason:封装一个方法,用于转换成 activiti 的分页对象 - final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize()); - Page pageTasks = taskRuntime.tasks(pageable); - int totalItems = pageTasks.getTotalItems(); - List tasks = pageTasks.getContent(); - final List respVOList = tasks.stream().map(task -> { - ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId()); - return TaskConvert.INSTANCE.convert(task, definition); - }).collect(Collectors.toList()); - return new PageResult<>(respVOList, (long)totalItems); - } - - - @Override - public void claimTask(String taskId) { - taskRuntime.claim(new ClaimTaskPayloadBuilder() - .withTaskId(taskId) - .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername()) - .build()); - } - - - - @Override - @Transactional - public void completeTask(TaskReqVO taskReq) { - final Task task = taskRuntime.task(taskReq.getTaskId()); - - activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment()); - - taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId()) - .withVariables(taskReq.getVariables()) - .build()); - } - - - - @Override - public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) { - TaskHandleVO handleVO = new TaskHandleVO(); - final Task task = taskRuntime.task(taskQuery.getTaskId()); - List steps = getTaskSteps(task.getProcessInstanceId()); - handleVO.setHistoryTask(steps); - return handleVO; - } - - - private List getTaskSteps(String processInstanceId) { - // 获得已完成的活动 - List finished = historyService.createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId) - .activityType("userTask") - .finished() - .orderByHistoricActivityInstanceStartTime().asc().list(); - // 获得对应的步骤 - List steps = new ArrayList<>(); - finished.forEach(instance -> { - TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); - stepVO.setStatus(1); // TODO @jason:1 这个 magic number 要枚举起来。 - // TODO @jason:可以考虑把 comments 读取后,在统一调用 convert 拼接。另外 Comment 是废弃的类,有没其它可以使用的哈? - List comments = activitiTaskService.getTaskComments(instance.getTaskId()); - if (!CollUtil.isEmpty(comments)) { - stepVO.setComment(Optional.ofNullable(comments.get(0)).map(Comment::getFullMessage).orElse("")); - } - steps.add(stepVO); - }); - - // 获得未完成的活动 - List unfinished = historyService - .createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId) - .activityType("userTask") - .unfinished().list(); - // 获得对应的步骤 - for (HistoricActivityInstance instance : unfinished) { - TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); - stepVO.setComment(""); - stepVO.setStatus(0); - steps.add(stepVO); - } - return steps; - } - - - @Override - public List getHistorySteps(String processInstanceId) { - return getTaskSteps(processInstanceId); - } - - @Override - public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) { - final Task task = taskRuntime.task(taskQuery.getTaskId()); - return TaskConvert.INSTANCE.convert(task); - } - - @Override - public FileResp getHighlightImg(String processInstanceId) { - // 查询历史 - //TODO 云扬四海 貌似流程结束后,点击审批进度会报错 - // TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来 - HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); - // 如果不存在实例。 说明数据异常 - if (hpi == null) { - throw exception(PROCESS_INSTANCE_NOT_EXISTS); - } - // 如果有结束时间 返回model的流程图 - if (!ObjectUtils.isEmpty(hpi.getEndTime())) { - ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionId(hpi.getProcessDefinitionId()).singleResult(); - String resourceName = Optional.ofNullable(pd.getDiagramResourceName()).orElse(pd.getResourceName()); - BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId()); - InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, new ArrayList<>(1), new ArrayList<>(1), - "宋体", "宋体", "宋体"); - FileResp fileResp = new FileResp(); - fileResp.setFileName( resourceName + ".svg"); - fileResp.setFileByte(IoUtil.readBytes(inputStream)); - return fileResp; - } - // 没有结束时间。说明流程在执行过程中 - // TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来 - ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); - - List highLightedActivities = new ArrayList<>(); - // 获取所有活动节点 - List finishedInstances = historyService.createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId).finished().list(); - finishedInstances.stream().map(HistoricActivityInstance::getActivityId) - .forEach(highLightedActivities::add); - // 已完成的节点+当前节点 - highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId)); - - BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); - // 经过的流 - List highLightedFlowIds = getHighLightedFlows(bpmnModel, processInstanceId); - - //设置"宋体" - try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds, - "宋体", "宋体", "宋体")){ - FileResp fileResp = new FileResp(); - fileResp.setFileName( hpi.getProcessDefinitionName() + ".svg"); - fileResp.setFileByte(IoUtil.readBytes(inputStream)); - return fileResp; - } catch (IOException e) { - log.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e); - throw exception(HIGHLIGHT_IMG_ERROR); - } - } - - // TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。 - /** - * 获取指定 processInstanceId 已经高亮的Flows - * 获取已经流转的线 参考: https://blog.csdn.net/qiuxinfa123/article/details/119579863 - * @param bpmnModel model - * @param processInstanceId 流程实例Id - * @return 获取已经流转的列表 - */ - private List getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) { - // 获取所有的线条 - List historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId) - .orderByHistoricActivityInstanceId().asc().list(); - // 高亮流程已发生流转的线id集合 - List highLightedFlowIds = new ArrayList<>(); - // 全部活动节点 - List historicActivityNodes = new ArrayList<>(); - // 已完成的历史活动节点 - List finishedActivityInstances = new ArrayList<>(); - - for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { - FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true); - historicActivityNodes.add(flowNode); - // 结束时间不为空,则是已完成节点 - if (historicActivityInstance.getEndTime() != null) { - finishedActivityInstances.add(historicActivityInstance); - } - } - // 提取活动id 是唯一的。塞入Map - Map historicActivityInstanceMap = CollectionUtils.convertMap(historicActivityInstances, HistoricActivityInstance::getActivityId); - // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的 - for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) { - // 获得当前活动对应的节点信息及outgoingFlows信息 - FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true); - List sequenceFlows = currentFlowNode.getOutgoingFlows(); - - // 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转: - // 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 - // 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转 - if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(currentActivityInstance.getActivityType()) - || BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE.equals(currentActivityInstance.getActivityType())) { - // 遍历历史活动节点,找到匹配流程目标节点的 - for (SequenceFlow sequenceFlow : sequenceFlows) { - FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true); - if (historicActivityNodes.contains(targetFlowNode)) { - highLightedFlowIds.add(targetFlowNode.getId()); - } - } - } else { - long earliestStamp = 0L; - String highLightedFlowId = null; - // 循环流出的流 - for (SequenceFlow sequenceFlow : sequenceFlows) { - HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(sequenceFlow.getTargetRef()); - if (historicActivityInstance == null) { - continue; - } - final long startTime = historicActivityInstance.getStartTime().getTime(); - // 遍历匹配的集合,取得开始时间最早的一个 - if (earliestStamp == 0 || earliestStamp >= startTime) { - highLightedFlowId = sequenceFlow.getId(); - earliestStamp = startTime; - } - } - highLightedFlowIds.add(highLightedFlowId); - } - - } - return highLightedFlowIds; - } -} diff --git a/yudao-admin-ui/src/api/bpm/model.js b/yudao-admin-ui/src/api/bpm/model.js index 7c5d0db..8cb7e31 100644 --- a/yudao-admin-ui/src/api/bpm/model.js +++ b/yudao-admin-ui/src/api/bpm/model.js @@ -38,10 +38,9 @@ export function deleteModel(id) { }) } -export function deployModel(data) { +export function deployModel(id) { return request({ - url: '/bpm/model/deploy?modelId='+ data.modelId, - method: 'POST', - data: data + url: '/bpm/model/deploy?id=' + id, + method: 'POST' }) } diff --git a/yudao-admin-ui/src/views/bpm/model/index.vue b/yudao-admin-ui/src/views/bpm/model/index.vue index 264efef..f2cba25 100644 --- a/yudao-admin-ui/src/views/bpm/model/index.vue +++ b/yudao-admin-ui/src/views/bpm/model/index.vue @@ -27,10 +27,9 @@ - - - - + + +