!63 工作流的任务分配规则的实现

Merge pull request !63 from 芋道源码/feature/activiti
This commit is contained in:
芋道源码 2022-01-15 05:08:27 +00:00 committed by Gitee
commit 70fe3d31bd
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
130 changed files with 8517 additions and 1025 deletions

3017
sql/activiti.sql Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.*;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.form.BpmFormConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.*;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmFormConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmFormService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import io.swagger.annotations.Api;

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.model.BpmModelConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.service.model.BpmModelService;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmModelConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.io.IoUtils;
@ -47,7 +47,7 @@ public class BpmModelController {
@ApiOperation(value = "新建模型")
@PreAuthorize("@ss.hasPermission('bpm:model:create')")
public CommonResult<String> createModel(@Valid @RequestBody BpmModelCreateReqVO createRetVO) {
return success(bpmModelService.createModel(createRetVO));
return success(bpmModelService.createModel(createRetVO, null));
}
@PostMapping("/import")
@ -56,8 +56,8 @@ public class BpmModelController {
public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException {
BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO);
// 读取文件
createReqVO.setBpmnXml(IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false));
return success(bpmModelService.createModel(createReqVO));
String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false);
return success(bpmModelService.createModel(createReqVO, bpmnXml));
}
@PutMapping("/update")

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

View File

@ -0,0 +1,4 @@
### 请求 /bpm/task-assign-rule/list 接口 => 成功
GET {{baseUrl}}/bpm/task-assign-rule/list?processDefinitionId=leave:9:59689ba0-7284-11ec-965c-a2380e71991a
tenant-id: 1
Authorization: Bearer {{token}}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import io.swagger.annotations.Api;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "任务分配规则")
@RestController
@RequestMapping("/bpm/task-assign-rule")
@Validated
public class BpmTaskAssignRuleController {
@Resource
private BpmTaskAssignRuleService taskAssignRuleService;
@GetMapping("/list")
public CommonResult<List<BpmTaskAssignRuleRespVO>> getTaskAssignRuleList(
@RequestParam(value = "modelId", required = false) String modelId,
@RequestParam(value = "processDefinitionId", required = false) String processDefinitionId) {
return success(taskAssignRuleService.getTaskAssignRuleList(modelId, processDefinitionId));
}
@PostMapping("/create")
public CommonResult<Long> createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) {
return success(taskAssignRuleService.createTaskAssignRule(reqVO));
}
@PutMapping("/update")
public CommonResult<Boolean> updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) {
taskAssignRuleService.updateTaskAssignRule(reqVO);
return success(true);
}
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmUserGroupConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserSimpleRespVO;
import cn.iocoder.yudao.adminserver.modules.system.convert.user.SysUserConvert;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "用户组")
@RestController
@RequestMapping("/bpm/user-group")
@Validated
public class BpmUserGroupController {
@Resource
private BpmUserGroupService userGroupService;
@PostMapping("/create")
@ApiOperation("创建用户组")
@PreAuthorize("@ss.hasPermission('bpm:user-group:create')")
public CommonResult<Long> createUserGroup(@Valid @RequestBody BpmUserGroupCreateReqVO createReqVO) {
return success(userGroupService.createUserGroup(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新用户组")
@PreAuthorize("@ss.hasPermission('bpm:user-group:update')")
public CommonResult<Boolean> updateUserGroup(@Valid @RequestBody BpmUserGroupUpdateReqVO updateReqVO) {
userGroupService.updateUserGroup(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除用户组")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('bpm:user-group:delete')")
public CommonResult<Boolean> deleteUserGroup(@RequestParam("id") Long id) {
userGroupService.deleteUserGroup(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得用户组")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('bpm:user-group:query')")
public CommonResult<BpmUserGroupRespVO> getUserGroup(@RequestParam("id") Long id) {
BpmUserGroupDO userGroup = userGroupService.getUserGroup(id);
return success(BpmUserGroupConvert.INSTANCE.convert(userGroup));
}
@GetMapping("/page")
@ApiOperation("获得用户组分页")
@PreAuthorize("@ss.hasPermission('bpm:user-group:query')")
public CommonResult<PageResult<BpmUserGroupRespVO>> getUserGroupPage(@Valid BpmUserGroupPageReqVO pageVO) {
PageResult<BpmUserGroupDO> pageResult = userGroupService.getUserGroupPage(pageVO);
return success(BpmUserGroupConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/list-all-simple")
@ApiOperation(value = "获取用户组精简信息列表", notes = "只包含被开启的用户组,主要用于前端的下拉选项")
public CommonResult<List<BpmUserGroupRespVO>> getSimpleUserGroups() {
// 获用户门列表只要开启状态的
List<BpmUserGroupDO> list = userGroupService.getUserGroupListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 排序后返回给前端
return success(BpmUserGroupConvert.INSTANCE.convertList2(list));
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
import lombok.*;
import io.swagger.annotations.*;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
import lombok.*;
import io.swagger.annotations.*;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
import lombok.*;
import io.swagger.annotations.*;

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
/**
* 用户组 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class BpmUserGroupBaseVO {
@ApiModelProperty(value = "组名", required = true, example = "芋道")
@NotNull(message = "组名不能为空")
private String name;
@ApiModelProperty(value = "描述", required = true, example = "芋道源码")
@NotNull(message = "描述不能为空")
private String description;
@ApiModelProperty(value = "成员编号数组", required = true, example = "1,2,3")
@NotNull(message = "成员编号数组不能为空")
private Set<Long> memberUserIds;
@ApiModelProperty(value = "状态", required = true, example = "1")
@NotNull(message = "状态不能为空")
private Integer status;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("用户组创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmUserGroupCreateReqVO extends BpmUserGroupBaseVO {
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("用户组分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmUserGroupPageReqVO extends PageParam {
@ApiModelProperty(value = "组名", example = "芋道")
private String name;
@ApiModelProperty(value = "状态", example = "1")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("用户组 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmUserGroupRespVO extends BpmUserGroupBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("用户组更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmUserGroupUpdateReqVO extends BpmUserGroupBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
@NotNull(message = "编号不能为空")
private Long id;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -9,11 +9,11 @@ import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotNull;
@ApiModel("流程模型的导入 Request VO")
@ApiModel(value = "流程模型的导入 Request VO", description = "相比流程模型的新建来说,只是多了一个 bpmnFile 文件")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmModeImportReqVO extends BpmModelBaseVO {
public class BpmModeImportReqVO extends BpmModelCreateReqVO {
@ApiModelProperty(value = "BPMN 文件", required = true)
@NotNull(message = "BPMN 文件不能为空")

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -27,7 +27,15 @@ public class BpmModelBaseVO {
@NotEmpty(message = "流程分类不能为空")
private String category;
@ApiModelProperty(value = "表单编号", example = "1024")
@ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1")
private Integer formType;
@ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private Long formId;
@ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create",
notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private String formCustomCreatePath;
@ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view",
notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private String formCustomViewPath;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
@ApiModel("流程模型的创建 Request VO")
@Data
public class BpmModelCreateReqVO {
@ApiModelProperty(value = "流程标识", required = true, example = "process_yudao")
@NotEmpty(message = "流程标识不能为空")
private String key;
@ApiModelProperty(value = "流程名称", required = true, example = "芋道")
@NotEmpty(message = "流程名称不能为空")
private String name;
@ApiModelProperty(value = "流程描述", example = "我是描述")
private String description;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -0,0 +1,43 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
@ApiModel("流程模型的更新 Request VO")
@Data
public class BpmModelUpdateReqVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
@NotEmpty(message = "编号不能为空")
private String id;
@ApiModelProperty(value = "流程名称", example = "芋道")
private String name;
@ApiModelProperty(value = "流程描述", example = "我是描述")
private String description;
@ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
private String category;
@ApiModelProperty(value = "BPMN XML", required = true)
private String bpmnXml;
@ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1")
private Integer formType;
@ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private Long formId;
@ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create",
notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private String formCustomCreatePath;
@ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view",
notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private String formCustomViewPath;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import lombok.Data;
import java.util.Set;
@Data
public class BpmTaskAssignRuleBaseVO {
private Integer type;
private Set<Long> options;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class BpmTaskAssignRuleCreateReqVO extends BpmTaskAssignRuleBaseVO {
private String modelId;
private String taskDefinitionKey;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import lombok.Data;
@Data
public class BpmTaskAssignRuleRespVO extends BpmTaskAssignRuleBaseVO {
private Long id;
private String modelId;
private String processDefinitionId;
private String taskDefinitionKey;
private String taskDefinitionName;
}

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import lombok.Data;
import java.util.Set;
@Data
public class BpmTaskAssignRuleUpdateReqVO extends BpmTaskAssignRuleBaseVO {
private Long id;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("用户组精简信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BpmUserGroupSimpleRespVO {
@ApiModelProperty(value = "用户组编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户组名字", required = true, example = "芋道")
private String name;
}

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
@ApiModel("流程模型的创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmModelCreateReqVO extends BpmModelBaseVO {
@ApiModelProperty(value = "BPMN XML", required = true)
@NotEmpty(message = "BPMN XML 不能为空")
private String bpmnXml;
}

View File

@ -1,25 +0,0 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotEmpty;
@ApiModel("流程模型的更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmModelUpdateReqVO extends BpmModelBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
@NotEmpty(message = "编号不能为空")
private String id;
@ApiModelProperty(value = "BPMN XML", required = true)
@NotEmpty(message = "BPMN XML 不能为空")
private String bpmnXml;
}

View File

@ -1,10 +1,10 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.form;
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormSimpleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormSimpleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

View File

@ -1,9 +1,10 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.model;
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.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.adminserver.modules.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import org.activiti.engine.impl.persistence.entity.SuspensionState;
@ -11,14 +12,16 @@ import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 流程定义 Convert
* 流程模型 Convert
*
* @author yunlongn
*/
@ -42,18 +45,15 @@ public interface BpmModelConvert {
default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) {
BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO();
modelRespVO.setId(model.getId());
modelRespVO.setName(model.getName());
modelRespVO.setKey(model.getKey());
modelRespVO.setCategory(model.getCategory());
modelRespVO.setCreateTime(model.getCreateTime());
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
if (metaInfo != null) {
modelRespVO.setDescription(metaInfo.getDescription());
}
// 通用 copy
copyTo(model, modelRespVO);
// Form
if (form != null) {
modelRespVO.setFormId(form.getId());
modelRespVO.setFormName(form.getName());
}
// ProcessDefinition
modelRespVO.setProcessDefinition(this.convert(processDefinition));
if (modelRespVO.getProcessDefinition() != null) {
modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ?
@ -66,49 +66,68 @@ public interface BpmModelConvert {
default BpmModelRespVO convert(Model model) {
BpmModelRespVO modelRespVO = new BpmModelRespVO();
modelRespVO.setId(model.getId());
modelRespVO.setName(model.getName());
modelRespVO.setKey(model.getKey());
modelRespVO.setCategory(model.getCategory());
modelRespVO.setCreateTime(model.getCreateTime());
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
if (metaInfo != null) {
modelRespVO.setFormId(metaInfo.getFormId());
modelRespVO.setDescription(metaInfo.getDescription());
}
// 通用 copy
copyTo(model, modelRespVO);
return modelRespVO;
}
default void copyTo(Model model, BpmModelBaseVO to) {
to.setName(model.getName());
to.setKey(model.getKey());
to.setCategory(model.getCategory());
// metaInfo
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
copyTo(metaInfo, to);
}
void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to);
default BpmDefinitionCreateReqDTO convert2(Model model) {
BpmDefinitionCreateReqDTO createReqDTO = new BpmDefinitionCreateReqDTO();
createReqDTO.setModelId(model.getId());
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());
}
// metaInfo
copyTo(metaInfo, createReqDTO);
return createReqDTO;
}
void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmDefinitionCreateReqDTO to);
default void copy(Model model, BpmModelCreateReqVO bean) {
model.setName(bean.getName());
model.setKey(bean.getKey());
model.setCategory(bean.getCategory());
model.setMetaInfo(JsonUtils.toJsonString(this.buildMetaInfo(bean.getDescription(), bean.getFormId())));
model.setMetaInfo(buildMetaInfoStr(null, bean.getDescription(), null, null,
null, null));
}
default void copy(Model model, BpmModelUpdateReqVO bean) {
model.setName(bean.getName());
model.setCategory(bean.getCategory());
model.setMetaInfo(JsonUtils.toJsonString(this.buildMetaInfo(bean.getDescription(), bean.getFormId())));
model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class),
bean.getDescription(), bean.getFormType(), bean.getFormId(),
bean.getFormCustomCreatePath(), bean.getFormCustomViewPath()));
}
default BpmModelMetaInfoRespDTO buildMetaInfo(String description, Long formId) {
BpmModelMetaInfoRespDTO metaInfo = new BpmModelMetaInfoRespDTO();
default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, String description, Integer formType,
Long formId, String formCustomCreatePath, String formCustomViewPath) {
if (metaInfo == null) {
metaInfo = new BpmModelMetaInfoRespDTO();
}
// 只有非空才进行设置避免更新时的覆盖
if (StrUtil.isNotEmpty(description)) {
metaInfo.setDescription(description);
}
if (Objects.nonNull(formType)) {
metaInfo.setFormType(formType);
metaInfo.setFormId(formId);
return metaInfo;
metaInfo.setFormCustomCreatePath(formCustomCreatePath);
metaInfo.setFormCustomViewPath(formCustomViewPath);
}
return JsonUtils.toJsonString(metaInfo);
}
BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean);

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.engine.impl.persistence.entity.SuspensionState;
@ -11,13 +11,11 @@ import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* Bpm 流程定义的 Convert
@ -25,9 +23,9 @@ import java.util.function.Function;
* @author yunlong.li
*/
@Mapper
public interface BpmDefinitionConvert {
public interface BpmProcessDefinitionConvert {
BpmDefinitionConvert INSTANCE = Mappers.getMapper(BpmDefinitionConvert.class);
BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class);
default List<BpmProcessDefinitionPageItemRespVO> convertList(List<ProcessDefinition> list, Map<String, Deployment> deploymentMap,
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.bpmn.model.UserTask;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@Mapper
public interface BpmTaskAssignRuleConvert {
BpmTaskAssignRuleConvert INSTANCE = Mappers.getMapper(BpmTaskAssignRuleConvert.class);
default List<BpmTaskAssignRuleRespVO> convertList(List<UserTask> tasks, List<BpmTaskAssignRuleDO> rules) {
Map<String, BpmTaskAssignRuleDO> ruleMap = CollectionUtils.convertMap(rules, BpmTaskAssignRuleDO::getTaskDefinitionKey);
// UserTask 为主维度原因是流程图编辑后一些规则实际就没用了
return CollectionUtils.convertList(tasks, task -> {
BpmTaskAssignRuleRespVO respVO = convert(ruleMap.get(task.getId()));
if (respVO == null) {
respVO = new BpmTaskAssignRuleRespVO();
respVO.setTaskDefinitionKey(task.getId());
}
respVO.setTaskDefinitionName(task.getName());
return respVO;
});
}
BpmTaskAssignRuleRespVO convert(BpmTaskAssignRuleDO bean);
BpmTaskAssignRuleDO convert(BpmTaskAssignRuleCreateReqVO bean);
BpmTaskAssignRuleDO convert(BpmTaskAssignRuleUpdateReqVO bean);
List<BpmTaskAssignRuleDO> convertList2(List<BpmTaskAssignRuleRespVO> list);
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
import java.util.*;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
/**
* 用户组 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BpmUserGroupConvert {
BpmUserGroupConvert INSTANCE = Mappers.getMapper(BpmUserGroupConvert.class);
BpmUserGroupDO convert(BpmUserGroupCreateReqVO bean);
BpmUserGroupDO convert(BpmUserGroupUpdateReqVO bean);
BpmUserGroupRespVO convert(BpmUserGroupDO bean);
List<BpmUserGroupRespVO> convertList(List<BpmUserGroupDO> list);
PageResult<BpmUserGroupRespVO> convertPage(PageResult<BpmUserGroupDO> page);
@Named("convertList2")
List<BpmUserGroupRespVO> convertList2(List<BpmUserGroupDO> list);
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form;
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form;
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;

View File

@ -1,10 +1,10 @@
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.Model;
import org.activiti.engine.repository.ProcessDefinition;
/**
@ -33,6 +33,12 @@ public class BpmProcessDefinitionExtDO extends BaseDO {
* 关联 {@link ProcessDefinition#getId()}
*/
private String processDefinitionId;
/**
* 流程模型的编号
*
* 关联 {@link Model#getId()}
*/
private String modelId;
/**
* 描述
*/

View File

@ -0,0 +1,86 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import java.util.Set;
/**
* Bpm 任务分配的规则表用于自定义配置每个任务的负责人候选人的分配规则
* 也就是说废弃 BPMN 原本的 UserTask 设置的 assigneecandidateUsers 等配置而是通过使用该规则进行计算对应的负责人
*
* 1. 默认情况下{@link #processDefinitionId} {@link #PROCESS_DEFINITION_ID_NULL} 表示贵改则与流程模型关联
* 2. 在流程模型部署后会将他的所有规则记录复制出一份新部署出来的流程定义通过设置 {@link #processDefinitionId} 为新的流程定义的编号进行关联
*
* @author 芋道源码
*/
@TableName(value = "bpm_task_assign_rule", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmTaskAssignRuleDO extends BaseDO {
/**
* {@link #processDefinitionId} 空串用于标识属于流程模型而不属于流程定义
*/
public static final String PROCESS_DEFINITION_ID_NULL = "";
/**
* 编号
*/
@TableId
private Long id;
/**
* 流程模型编号
*
* 关联 {@link Model#getId()}
*/
private String modelId;
/**
* 流程定义编号
*
* 关联 {@link ProcessDefinition#getId()}
*/
private String processDefinitionId;
/**
* 流程任务的定义 Key
*
* 关联 {@link Task#getTaskDefinitionKey()}
*/
private String taskDefinitionKey;
/**
* 规则类型
*
* 枚举 {@link BpmTaskAssignRuleTypeEnum}
*/
@TableField("`type`")
private Integer type;
/**
* 规则值数组一般关联指定表的编号
* 根据 type 不同对应的值是不同的
*
* 1. {@link BpmTaskAssignRuleTypeEnum#ROLE} 角色编号
* 2. {@link BpmTaskAssignRuleTypeEnum#DEPT_MEMBER} 部门编号
* 3. {@link BpmTaskAssignRuleTypeEnum#DEPT_LEADER} 部门编号
* 4. {@link BpmTaskAssignRuleTypeEnum#USER} 用户编号
* 5. {@link BpmTaskAssignRuleTypeEnum#USER_GROUP} 用户组编号
* 6. {@link BpmTaskAssignRuleTypeEnum#SCRIPT} 脚本编号目前通过 {@link BpmTaskRuleScriptEnum#getId()} 标识
*/
@TableField(typeHandler = JsonLongSetTypeHandler.class)
private Set<Long> options;
}

View File

@ -0,0 +1,5 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
// TODO 芋艿先埋个坑任务消息的配置规则说白了就是不同的
public class BpmTaskMessageRuleDO {
}

View File

@ -0,0 +1,52 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.util.Set;
/**
* Bpm 用户组
*
* @author 芋道源码
*/
@TableName(value = "bpm_user_group", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmUserGroupDO extends BaseDO {
/**
* 编号自增
*/
@TableId
private Long id;
/**
* 组名
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 成员用户编号数组
*/
@TableField(typeHandler = JsonLongSetTypeHandler.class)
private Set<Long> memberUserIds;
}

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.form;
package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.lang.Nullable;
import java.util.List;
@Mapper
public interface BpmTaskAssignRuleMapper extends BaseMapperX<BpmTaskAssignRuleDO> {
default List<BpmTaskAssignRuleDO> selectListByProcessDefinitionId(String processDefinitionId,
@Nullable String taskDefinitionKey) {
return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
.eq("process_definition_id", processDefinitionId)
.eqIfPresent("task_definition_key", taskDefinitionKey));
}
default List<BpmTaskAssignRuleDO> selectListByModelId(String modelId) {
return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
.eq("model_id", modelId)
.eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL));
}
default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId,
String taskDefinitionKey) {
return selectOne(new QueryWrapperX<BpmTaskAssignRuleDO>()
.eq("model_id", modelId)
.eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)
.eq("task_definition_key", taskDefinitionKey));
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 用户组 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface BpmUserGroupMapper extends BaseMapperX<BpmUserGroupDO> {
default PageResult<BpmUserGroupDO> selectPage(BpmUserGroupPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<BpmUserGroupDO>()
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default List<BpmUserGroupDO> selectListByStatus(Integer status) {
return selectList("status", status);
}
}

View File

@ -25,6 +25,9 @@ public interface BpmErrorCodeConstants {
ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1009002000, "已经存在流程标识为【{}】的流程");
ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1009002001, "流程模型不存在");
ErrorCode MODEL_KEY_VALID = new ErrorCode(1009002002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!");
ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1009002003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置");
ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1009002004, "部署流程失败," +
"原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置");
// ========== 流程定义 1-009-003-000 ==========
ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
@ -37,11 +40,22 @@ public interface BpmErrorCodeConstants {
ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中");
ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的");
// ========== 流程实例 1-009-005-000 ==========
// ========== 流程任务 1-009-005-000 ==========
ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009004000, "审批任务失败,原因:该任务不处于未审批");
// ========== 流程任务分配规则 1-009-006-000 ==========
ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1009006000, "流程({}) 的任务({}) 已经存在分配规则");
ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1009006001, "流程任务分配规则不存在");
ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1009006002, "只有流程模型的任务分配规则,才允许被修改");
ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1009006003, "操作失败,原因:找不到任务的审批人!");
ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1009006004, "操作失败,原因:任务分配脚本({}) 不存在");
// ========== 动态表单模块 1-009-010-000 ==========
ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在");
ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009010000, "表单项({}) 和 ({}) 使用了相同的字段名({})");
// ========== 用户组模块 1-009-011-000 ==========
ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在");
ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1009011001, "名字为【{}】的用户组已被禁用");
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* BPM 模型的表单类型的枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmModelFormTypeEnum {
NORMAL(10, "流程表单"), // 对应 BpmFormDO
CUSTOM(20, "业务表单") // 业务自己定义的表单自己进行数据的存储
;
private final Integer type;
private final String desc;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* BPM 任务分配规则的类型枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmTaskAssignRuleTypeEnum {
ROLE(10, "角色"),
DEPT_MEMBER(20, "部门的成员"), // 包括负责人
DEPT_LEADER(21, "部门的负责人"),
POST(22, "岗位"),
USER(30, "用户"),
USER_GROUP(40, "用户组"),
SCRIPT(50, "自定义脚本"), // 例如说发起人所在部门的领导发起人所在部门的领导的领导
;
/**
* 类型
*/
private final Integer type;
/**
* 描述
*/
private final String desc;
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* BPM 任务规则的脚本枚举
* 目前暂时通过 TODO 硬编码未来可以考虑 Groovy 动态脚本的方式
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmTaskRuleScriptEnum {
ONE(1L, ""),
TWO(2L, "");
/**
* 脚本编号
*/
private final Long id;
/**
* 脚本描述
*/
private final String desc;
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti;
import cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener.BpmTackActivitiEventListener;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.Collections;
/**
* BPM 模块的 Activiti 配置类
*/
@Configuration
public class BpmActivitiConfiguration implements ProcessEngineConfigurationConfigurer {
@Resource
private BpmTackActivitiEventListener taskActivitiEventListener;
@Override
public void configure(SpringProcessEngineConfiguration configuration) {
// 注册监听器例如说 BpmActivitiEventListener
configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener));
}
}

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.config;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.BpmActivityBehaviorFactory;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener.BpmTackActivitiEventListener;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
import java.util.List;
import static org.activiti.spring.boot.ProcessEngineAutoConfiguration.BEHAVIOR_FACTORY_MAPPING_CONFIGURER;
/**
* BPM 模块的 Activiti 配置类
*/
@Configuration
public class BpmActivitiConfiguration {
/**
* BPM 模块的 ProcessEngineConfigurationConfigurer 实现类主要设置各种监听器
*/
@Bean
public ProcessEngineConfigurationConfigurer bpmProcessEngineConfigurationConfigurer(
BpmTackActivitiEventListener taskActivitiEventListener) {
return configuration -> {
// 注册监听器例如说 BpmActivitiEventListener
configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener));
};
}
/**
* 用于设置自定义的 ActivityBehaviorFactory 实现的 ProcessEngineConfigurationConfigurer 实现类
*
* 目的覆盖 {@link org.activiti.spring.boot.ProcessEngineAutoConfiguration}
* defaultActivityBehaviorFactoryMappingConfigurer 方法创建的 Bean
*/
@Bean(name = BEHAVIOR_FACTORY_MAPPING_CONFIGURER)
public ProcessEngineConfigurationConfigurer defaultActivityBehaviorFactoryMappingConfigurer(
BpmActivityBehaviorFactory bpmActivityBehaviorFactory) {
return configuration -> {
// 设置 ActivityBehaviorFactory 实现类用于流程任务的审核人的自定义
configuration.setActivityBehaviorFactory(bpmActivityBehaviorFactory);
};
}
@Bean
public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService,
SysPermissionService permissionService,
SysDeptService deptService,
BpmUserGroupService userGroupService,
SysUserService userService,
List<BpmTaskAssignScript> scripts) {
BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory();
bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService);
bpmActivityBehaviorFactory.setPermissionService(permissionService);
bpmActivityBehaviorFactory.setDeptService(deptService);
bpmActivityBehaviorFactory.setUserGroupService(userGroupService);
bpmActivityBehaviorFactory.setUserService(userService);
bpmActivityBehaviorFactory.setScripts(scripts);
return bpmActivityBehaviorFactory;
}
}

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.ToString;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
import javax.annotation.Resource;
import java.util.List;
/**
* 自定义的 ActivityBehaviorFactory 实现类目的如下
* 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}实现自定义的流程任务的 assignee 负责人的分配
*
* @author 芋道源码
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
@Setter
private BpmTaskAssignRuleService bpmTaskRuleService;
@Setter
private SysPermissionService permissionService;
@Setter
private SysDeptService deptService;
@Setter
private BpmUserGroupService userGroupService;
@Setter
private SysUserService userService;
@Setter
private List<BpmTaskAssignScript> scripts;
@Override
public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask);
userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
userTaskActivityBehavior.setPermissionService(permissionService);
userTaskActivityBehavior.setDeptService(deptService);
userTaskActivityBehavior.setUserGroupService(userGroupService);
userTaskActivityBehavior.setUserService(userService);
userTaskActivityBehavior.setScripts(scripts);
return userTaskActivityBehavior;
}
// TODO 芋艿并行任务 ParallelMultiInstanceBehavior
// TODO 芋艿并行任务 SequentialMultiInstanceBehavior
}

View File

@ -0,0 +1,195 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import com.google.common.annotations.VisibleForTesting;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.el.ExpressionManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
import java.util.*;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
/**
* 自定义的流程任务的 assignee 负责人的分配
*
* @author 芋道源码
*/
@Slf4j
public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
@Setter
private BpmTaskAssignRuleService bpmTaskRuleService;
@Setter
private SysPermissionService permissionService;
@Setter
private SysDeptService deptService;
@Setter
private BpmUserGroupService userGroupService;
@Setter
private SysUserService userService;
/**
* 任务分配脚本
*/
private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
public BpmUserTaskActivitiBehavior(UserTask userTask) {
super(userTask);
}
public void setScripts(List<BpmTaskAssignScript> scripts) {
this.scriptMap = convertMap(scripts, script -> script.getEnum().getId());
}
@Override
protected void handleAssignments(TaskEntityManager taskEntityManager,
String assignee, String owner, List<String> candidateUsers, List<String> candidateGroups,
TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution) {
// 获得任务的规则
BpmTaskAssignRuleDO rule = getTaskRule(task);
// 获得任务的候选用户们
Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule);
// 设置负责人
Long assigneeUserId = chooseTaskAssignee(candidateUserIds);
taskEntityManager.changeTaskAssignee(task, String.valueOf(assigneeUserId));
// 设置候选人们
candidateUserIds.remove(assigneeUserId); // 已经成为负责人了就不要在扮演候选人了
if (CollUtil.isNotEmpty(candidateUserIds)) {
task.addCandidateUsers(convertSet(candidateUserIds, String::valueOf));
}
}
private BpmTaskAssignRuleDO getTaskRule(TaskEntity task) {
List<BpmTaskAssignRuleDO> taskRules = bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(),
task.getTaskDefinitionKey());
if (CollUtil.isEmpty(taskRules)) {
throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则",
task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey()));
}
if (taskRules.size() > 1) {
throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})",
task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), taskRules.size()));
}
return taskRules.get(0);
}
private Long chooseTaskAssignee(Set<Long> candidateUserIds) {
// TODO 芋艿未来可以优化下改成轮询的策略
int index = RandomUtil.randomInt(candidateUserIds.size());
return CollUtil.get(candidateUserIds, index);
}
@VisibleForTesting
Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) {
Set<Long> assigneeUserIds = null;
if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
}
// 移除被禁用的用户
removeDisableUsers(assigneeUserIds);
// 如果候选人为空抛出异常 TODO 芋艿没候选人的策略选择1 - 挂起2 - 直接结束3 - 强制一个兜底人
if (CollUtil.isEmpty(assigneeUserIds)) {
log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]",
task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule));
throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
}
return assigneeUserIds;
}
private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) {
return permissionService.getUserRoleIdListByRoleIds(rule.getOptions());
}
private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<SysUserDO> users = userService.getUsersByDeptIds(rule.getOptions());
return convertSet(users, SysUserDO::getId);
}
private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<SysDeptDO> depts = deptService.getDepts(rule.getOptions());
return convertSet(depts, SysDeptDO::getLeaderUserId);
}
private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<SysUserDO> users = userService.getUsersByPostIds(rule.getOptions());
return convertSet(users, SysUserDO::getId);
}
private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) {
return rule.getOptions();
}
private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
Set<Long> userIds = new HashSet<>();
userGroups.forEach(bpmUserGroupDO -> userIds.addAll(bpmUserGroupDO.getMemberUserIds()));
return userIds;
}
private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) {
// 获得对应的脚本
List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size());
rule.getOptions().forEach(id -> {
BpmTaskAssignScript script = scriptMap.get(id);
if (script == null) {
throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id);
}
scripts.add(script);
});
// 逐个计算任务
Set<Long> userIds = new HashSet<>();
scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task)));
return userIds;
}
@VisibleForTesting
void removeDisableUsers(Set<Long> assigneeUserIds) {
if (CollUtil.isEmpty(assigneeUserIds)) {
return;
}
Map<Long, SysUserDO> userMap = userService.getUserMap(assigneeUserIds);
assigneeUserIds.removeIf(id -> {
SysUserDO user = userMap.get(id);
return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
});
}
}

View File

@ -0,0 +1,7 @@
/**
* 拓展 {@link org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior} 实现基于 {@link cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO} 实现自定义的任务分配规则
* 原因BPMN 默认的 assigncandidateUserscandidateGroups 拓展起来有一定的难度所以选择放弃它们使用自己定义的规则
*
* @author 芋道源码
*/
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior;

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import java.util.List;
/**
* Bpm 任务分配的自定义 Script 脚本
* 使用场景
* 1. 设置审批人为发起人
* 2. 设置审批人为发起人的 Leader
* 3. 甚至审批人为发起人的 Leader Leader
*
* @author 芋道源码
*/
public interface BpmTaskAssignScript {
/**
* 基于流程任务获得任务的候选用户们
*
* @param task 任务
* @return 候选人用户的编号数组
*/
List<Long> calculateTaskCandidateUsers(TaskEntity task);
/**
* 获得枚举值
*
* @return 枚举值
*/
BpmTaskRuleScriptEnum getEnum();
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;

View File

@ -1,10 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
import org.activiti.api.model.shared.event.RuntimeEvent;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.events.ProcessRuntimeEvent;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.events.TaskRuntimeEvent;
import org.activiti.api.task.runtime.events.listener.TaskEventListener;
import org.activiti.api.task.runtime.events.listener.TaskRuntimeEventListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -16,15 +20,22 @@ import javax.annotation.Resource;
* @author 芋道源码
*/
@Component
public class BpmTaskEventListener<T extends TaskRuntimeEvent<? extends Task>>
implements TaskEventListener<T> {
public class BpmTaskEventListener<T extends RuntimeEvent<?, ?>>
implements TaskRuntimeEventListener<T> {
@Resource
@Lazy // 解决循环依赖
private BpmTaskService taskService;
@Override
public void onEvent(T event) {
@SuppressWarnings("unchecked")
public void onEvent(T rawEvent) {
// 由于 TaskRuntimeEventListener 无法保证只监听 TaskRuntimeEvent 事件所以通过这样的方式
if (!(rawEvent instanceof TaskRuntimeEvent)) {
return;
}
TaskRuntimeEvent<Task> event = (TaskRuntimeEvent<Task>) rawEvent;
// 创建时插入拓展表
if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CREATED) {
taskService.createTaskExt(event.getEntity());

View File

@ -0,0 +1,7 @@
/**
* 自定义各种 Activiti 的监听器实现流程示例流程任务的拓展表信息的同步
* 例如说{@link org.activiti.api.task.model.Task} 新建时我们也要新建对应的 {@link cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO} 记录
*
* @author 芋道源码
*/
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;

View File

@ -1,62 +0,0 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.config;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.activiti.api.runtime.shared.identity.UserGroupManager;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import static java.util.Collections.singleton;
@Service
public class UserGroupManagerService implements UserGroupManager {
@Resource
private UserDetailsService userDetailsService;
@Resource
private SysUserService userService;
@Resource
private SysPostService sysPostService;
/**
* 暂时使用岗位来代替
* @param userId
* @return
*/
@Override
public List<String> getUserGroups(String userId) {
// final LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(userId);
// final Long id = loginUser.getId();
final SysUserDO user = userService.getUserByUsername(userId);
return sysPostService.getPosts(user.getPostIds()).stream().map(post -> post.getCode()).collect(Collectors.toList());
}
@Override
public List<String> getUserRoles(String userId) {
return Arrays.asList("ROLE_ACTIVITI_USER");
}
@Override
public List<String> getGroups() {
throw new UnsupportedOperationException("getGroups is now un supported");
}
@Override
public List<String> getUsers() {
throw new UnsupportedOperationException("getGroups is now un supported");
}
}

View File

@ -1,31 +0,0 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.config;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.activiti.api.runtime.shared.security.PrincipalGroupsProvider;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
@Service
public class UserGroupsProvider implements PrincipalGroupsProvider {
@Override
public List<String> getGroups(Principal principal) {
if(principal instanceof Authentication){
Authentication authentication = (Authentication) principal;
final Object user = authentication.getPrincipal();
if( user instanceof LoginUser){
return ((LoginUser) user).getGroups();
}else{
return Collections.emptyList();
}
}else{
return Collections.emptyList();
}
}
}

View File

@ -1,13 +1,12 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.form;
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.engine.repository.Model;
import javax.validation.Valid;
import java.util.Collection;

View File

@ -1,7 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.model;
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.activiti.bpmn.model.BpmnModel;
import javax.validation.Valid;
@ -32,9 +33,10 @@ public interface BpmModelService {
* 创建流程模型
*
* @param modelVO 创建信息
* @param bpmnXml BPMN XML
* @return 创建的流程模型的编号
*/
String createModel(@Valid BpmModelCreateReqVO modelVO);
String createModel(@Valid BpmModelCreateReqVO modelVO, String bpmnXml);
/**
* 修改流程模型
@ -65,4 +67,12 @@ public interface BpmModelService {
*/
void updateModelState(String id, Integer state);
/**
* 获得流程模型编号对应的 BPMN Model
*
* @param id 流程模型编号
* @return BPMN Model
*/
BpmnModel getBpmnModel(String id);
}

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;

View File

@ -0,0 +1,71 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.lang.Nullable;
import javax.validation.Valid;
import java.util.List;
/**
* BPM 任务分配规则 Service 接口
*
* @author 芋道源码
*/
public interface BpmTaskAssignRuleService {
/**
* 获得流程定义的任务分配规则数组
*
* @param processDefinitionId 流程定义的编号
* @param taskDefinitionKey 流程任务定义的 Key允许空
* @return 任务规则数组
*/
List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
@Nullable String taskDefinitionKey);
/**
* 获得流程模型的任务规则数组
*
* @param modelId 流程模型的编号
* @return 任务规则数组
*/
List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId);
/**
* 获得流程定义的任务分配规则数组
*
* @param modelId 流程模型的编号
* @param processDefinitionId 流程定义的编号
* @return 任务规则数组
*/
List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId);
/**
* 创建任务分配规则
*
* @param reqVO 创建信息
* @return 规则编号
*/
Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO);
/**
* 更新任务分配规则
*
* @param reqVO 创建信息
*/
void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO);
/**
* 将流程流程模型的任务分配规则复制一份给流程定义
* 目的每次流程模型部署时都会生成一个新的流程定义此时考虑到每次部署的流程不可变性所以需要复制一份给该流程定义
*
* @param fromModelId 流程模型编号
* @param toProcessDefinitionId 流程定义编号
*/
void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId);
}

View File

@ -0,0 +1,82 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
/**
* 用户组 Service 接口
*
* @author 芋道源码
*/
public interface BpmUserGroupService {
/**
* 创建用户组
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createUserGroup(@Valid BpmUserGroupCreateReqVO createReqVO);
/**
* 更新用户组
*
* @param updateReqVO 更新信息
*/
void updateUserGroup(@Valid BpmUserGroupUpdateReqVO updateReqVO);
/**
* 删除用户组
*
* @param id 编号
*/
void deleteUserGroup(Long id);
/**
* 获得用户组
*
* @param id 编号
* @return 用户组
*/
BpmUserGroupDO getUserGroup(Long id);
/**
* 获得用户组列表
*
* @param ids 编号
* @return 用户组列表
*/
List<BpmUserGroupDO> getUserGroupList(Collection<Long> ids);
/**
* 获得指定状态的用户组列表
*
* @param status 状态
* @return 用户组列表
*/
List<BpmUserGroupDO> getUserGroupListByStatus(Integer status);
/**
* 获得用户组分页
*
* @param pageReqVO 分页查询
* @return 用户组分页
*/
PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO);
/**
* 校验用户组们是否有效如下情况视为无效
* 1. 用户组编号不存在
* 2. 用户组被禁用
*
* @param ids 用户组编号数组
*/
void validUserGroups(Set<Long> ids);
}

View File

@ -1,8 +1,10 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 流程定义创建 Request DTO
@ -10,6 +12,13 @@ import javax.validation.constraints.NotEmpty;
@Data
public class BpmDefinitionCreateReqDTO {
// ========== 模型相关 ==========
/**
* 流程模型的编号
*/
@NotEmpty(message = "流程模型编号不能为空")
private String modelId;
/**
* 流程标识
*/
@ -35,9 +44,30 @@ public class BpmDefinitionCreateReqDTO {
*/
@NotEmpty(message = "BPMN XML 不能为空")
private String bpmnXml;
// ========== 表单相关 ==========
/**
* 动态表单编号允许空
* 表单类型
*/
@NotNull(message = "表单类型不能为空")
private Integer formType;
/**
* 动态表单编号
* 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL}
*/
private Long formId;
/**
* 自定义表单的提交路径使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM}
*/
private String formCustomCreatePath;
/**
* 自定义表单的查看路径使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM}
*/
private String formCustomViewPath;
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.form.dto;
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
import lombok.Data;
/**
* BPM 流程 MetaInfo Response DTO
* 主要用于 {@link org.activiti.engine.repository.Model#setMetaInfo(String)} 的存储
*
* @author 芋道源码
*/
@Data
public class BpmModelMetaInfoRespDTO {
/**
* 流程描述
*/
private String description;
/**
* 表单类型
*/
private Integer formType;
/**
* 表单编号
* 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL}
*/
private Long formId;
/**
* 自定义表单的提交路径使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM}
*/
private String formCustomCreatePath;
/**
* 自定义表单的查看路径使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM}
*/
private String formCustomViewPath;
}

View File

@ -1,14 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.form.impl;
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.form.BpmFormConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.form.BpmFormMapper;
import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.form.dto.BpmFormFieldRespDTO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmFormConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmFormMapper;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmFormService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmFormFieldRespDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import org.springframework.stereotype.Service;

View File

@ -1,26 +1,35 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.model.impl;
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
import cn.hutool.core.collection.CollUtil;
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.BpmModelConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmModelConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
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.adminserver.modules.bpm.service.definition.BpmFormService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
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 cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
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.impl.persistence.entity.SuspensionState;
import org.activiti.engine.impl.util.io.StringStreamSource;
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.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@ -31,9 +40,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
@ -50,9 +61,12 @@ public class BpmModelServiceImpl implements BpmModelService {
@Resource
private RepositoryService repositoryService;
@Resource
private BpmFormService bpmFormService;
private BpmFormService formService;
@Resource
private BpmProcessDefinitionService bpmProcessDefinitionService;
private BpmProcessDefinitionService processDefinitionService;
@Resource
@Lazy // 解决循环依赖
private BpmTaskAssignRuleService taskAssignRuleService;
@Override
public PageResult<BpmModelPageItemRespVO> getModelPage(ModelPageReqVO pageVO) {
@ -75,14 +89,14 @@ public class BpmModelServiceImpl implements BpmModelService {
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
return metaInfo != null ? metaInfo.getFormId() : null;
});
Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds);
Map<Long, BpmFormDO> formMap = formService.getFormMap(formIds);
// 获得 Deployment Map
Set<String> deploymentIds = new HashSet<>();
models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId()));
Map<String, Deployment> deploymentMap = bpmProcessDefinitionService.getDeploymentMap(deploymentIds);
Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds);
// 获得 ProcessDefinition Map
List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
List<ProcessDefinition> processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
Map<String, ProcessDefinition> processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);
// 拼接结果
@ -105,7 +119,7 @@ public class BpmModelServiceImpl implements BpmModelService {
@Override
@Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作所以开启事务
public String createModel(BpmModelCreateReqVO createReqVO) {
public String createModel(BpmModelCreateReqVO createReqVO, String bpmnXml) {
checkKeyNCName(createReqVO.getKey());
// 校验流程标识已经存在
Model keyModel = this.getModelByKey(createReqVO.getKey());
@ -118,15 +132,14 @@ public class BpmModelServiceImpl implements BpmModelService {
BpmModelConvert.INSTANCE.copy(model, createReqVO);
// 保存流程定义
repositoryService.saveModel(model);
// 添加 BPMN XML
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(createReqVO.getBpmnXml()));
// 保存 BPMN XML
saveModelBpmnXml(model, bpmnXml);
return model.getId();
}
@Override
@Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作所以开启事务
public void updateModel(BpmModelUpdateReqVO updateReqVO) {
checkKeyNCName(updateReqVO.getKey());
// 校验流程模型存在
Model model = repositoryService.getModel(updateReqVO.getId());
if (model == null) {
@ -138,7 +151,14 @@ public class BpmModelServiceImpl implements BpmModelService {
// 更新模型
repositoryService.saveModel(model);
// 更新 BPMN XML
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(updateReqVO.getBpmnXml()));
saveModelBpmnXml(model, updateReqVO.getBpmnXml());
}
private void saveModelBpmnXml(Model model, String bpmnXml) {
if (StrUtil.isEmpty(bpmnXml)) {
return;
}
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml));
}
@Override
@ -149,28 +169,60 @@ public class BpmModelServiceImpl implements BpmModelService {
if (ObjectUtils.isEmpty(model)) {
throw exception(MODEL_NOT_EXISTS);
}
// 校验流程图
byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
if (bpmnBytes == null) {
throw exception(MODEL_NOT_EXISTS);
}
// TODO 芋艿校验流程图的有效性例如说是否有开始的元素是否有结束的元素
// 校验表单已配
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
if (metaInfo == null || metaInfo.getFormType() == null) {
throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
}
// 校验任务分配规则已配置
checkTaskAssignRuleAllConfig(id);
// 创建流程定义
BpmDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model)
.setBpmnXml(StrUtil.utf8Str(bpmnBytes));
String definitionId = bpmProcessDefinitionService.createProcessDefinition(definitionCreateReqDTO);
String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO);
// 将老的流程定义进行挂起也就是说只有最新部署的流程定义才可以发起任务
if (StrUtil.isNotEmpty(model.getDeploymentId())) {
ProcessDefinition oldDefinition = bpmProcessDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
if (oldDefinition != null) {
bpmProcessDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
}
}
// 更新 model deploymentId进行关联
ProcessDefinition definition = bpmProcessDefinitionService.getProcessDefinition(definitionId);
ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
model.setDeploymentId(definition.getDeploymentId());
repositoryService.saveModel(model);
// 复制任务分配规则
taskAssignRuleService.copyTaskAssignRules(id, definition.getId());
}
/**
* 校验流程模型的任务分配规则全部都配置了
* 目的如果有规则未配置会导致流程任务找不到负责人进而流程无法进行下去
*
* @param id 流程模型编号
*/
private void checkTaskAssignRuleAllConfig(String id) {
// 一个用户任务都没配置所以无需配置规则
List<BpmTaskAssignRuleRespVO> taskAssignRules = taskAssignRuleService.getTaskAssignRuleList(id, null);
if (CollUtil.isEmpty(taskAssignRules)) {
return;
}
// 校验未配置规则的任务
taskAssignRules.forEach(rule -> {
if (CollUtil.isEmpty(rule.getOptions())) {
throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName());
}
});
}
@Override
@ -192,13 +244,22 @@ public class BpmModelServiceImpl implements BpmModelService {
throw exception(MODEL_NOT_EXISTS);
}
// 校验流程定义存在
ProcessDefinition definition = bpmProcessDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
if (definition == null) {
throw exception(PROCESS_DEFINITION_NOT_EXISTS);
}
// 更新状态
bpmProcessDefinitionService.updateProcessDefinitionState(definition.getId(), state);
processDefinitionService.updateProcessDefinitionState(definition.getId(), state);
}
@Override
public BpmnModel getBpmnModel(String id) {
byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
if (ArrayUtil.isEmpty(bpmnBytes)) {
return null;
}
return ActivitiUtils.buildBpmnModel(bpmnBytes);
}
private Model getModelByKey(String key) {
@ -211,4 +272,10 @@ public class BpmModelServiceImpl implements BpmModelService {
}
}
public static void main(String[] args) {
// 创建转换对象
BpmnXMLConverter converter = new BpmnXMLConverter();
BpmnModel bpmnModel = converter.convertToBpmnModel(new StringStreamSource(""), true, true);
}
}

View File

@ -2,17 +2,17 @@ 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.definition.vo.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmDefinitionConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionListReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmProcessDefinitionConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
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.definition.BpmFormService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
@ -90,7 +90,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
// 拼接结果
long definitionCount = definitionQuery.count();
return new PageResult<>(BpmDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap,
return new PageResult<>(BpmProcessDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap,
processDefinitionDOMap, formMap), definitionCount);
}
@ -112,7 +112,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
BpmProcessDefinitionExtDO::getProcessDefinitionId);
// 执行查询并返回
return BpmDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
return BpmProcessDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
}
@Override
@ -121,6 +121,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
if (bpmnModel == null) {
return null;
}
// TODO 芋艿重构到 activi util
byte[] bpmnBytes = BPMN_XML_CONVERTER.convertToXML(bpmnModel);
return StrUtil.utf8Str(bpmnBytes);
}
@ -179,7 +180,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
// 创建 Deployment 部署
Deployment deploy = repositoryService.createDeployment()
.key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory())
.addString(createReqDTO.getName() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnXml())
.addString(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnXml())
.deploy();
// 设置 ProcessDefinition category 分类
@ -196,7 +197,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
}
// 插入拓展表
BpmProcessDefinitionExtDO definitionDO = BpmDefinitionConvert.INSTANCE.convert2(createReqDTO)
BpmProcessDefinitionExtDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO)
.setProcessDefinitionId(definition.getId());
processDefinitionMapper.insert(definitionDO);
return definition.getId();
@ -206,12 +207,14 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
public void updateProcessDefinitionState(String id, Integer state) {
// 激活
if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
repositoryService.activateProcessDefinitionById(id, true, null);
repositoryService.activateProcessDefinitionById(id, false, null);
return;
}
// 挂起
if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
repositoryService.suspendProcessDefinitionById(id, true, null);
// suspendProcessInstances = false进行中的任务不进行挂起
// 原因只要新的流程不允许发起即可老流程继续可以执行
repositoryService.suspendProcessDefinitionById(id, false, null);
return;
}
log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state);

View File

@ -0,0 +1,178 @@
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.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmTaskAssignRuleConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
import cn.iocoder.yudao.adminserver.modules.system.service.dict.SysDictDataService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.UserTask;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants.BPM_TASK_ASSIGN_RULE_TYPE;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* BPM 任务分配规则 Service 实现类
*/
@Service
@Validated
@Slf4j
public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
@Resource
private BpmTaskAssignRuleMapper taskRuleMapper;
@Resource
@Lazy // 解决循环依赖
private BpmModelService modelService;
@Resource
@Lazy // 解决循环依赖
private BpmProcessDefinitionService processDefinitionService;
@Resource
private SysRoleService roleService;
@Resource
private SysDeptService deptService;
@Resource
private SysPostService postService;
@Resource
private SysUserService userService;
@Resource
private BpmUserGroupService userGroupService;
@Resource
private SysDictDataService dictDataService;
@Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
String taskDefinitionKey) {
return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
}
@Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId) {
return taskRuleMapper.selectListByModelId(modelId);
}
@Override
public List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId) {
// 获得规则
List<BpmTaskAssignRuleDO> rules = Collections.emptyList();
BpmnModel model = null;
if (StrUtil.isNotEmpty(modelId)) {
rules = getTaskAssignRuleListByModelId(modelId);
model = modelService.getBpmnModel(modelId);
} else if (StrUtil.isNotEmpty(processDefinitionId)) {
rules = getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, null);
model = processDefinitionService.getBpmnModel(processDefinitionId);
}
if (model == null) {
return Collections.emptyList();
}
// 获得用户任务只有用户任务才可以设置分配规则
List<UserTask> userTasks = ActivitiUtils.getBpmnModelElements(model, UserTask.class);
if (CollUtil.isEmpty(userTasks)) {
return Collections.emptyList();
}
// 转换数据
return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules);
}
@Override
public Long createTaskAssignRule(BpmTaskAssignRuleCreateReqVO reqVO) {
// 校验参数
validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
// 校验是否已经配置
BpmTaskAssignRuleDO existRule = taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(
reqVO.getModelId(), reqVO.getTaskDefinitionKey());
if (existRule != null) {
throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
}
// 存储
BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
.setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型才允许新建
taskRuleMapper.insert(rule);
return rule.getId();
}
@Override
public void updateTaskAssignRule(BpmTaskAssignRuleUpdateReqVO reqVO) {
// 校验参数
validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
// 校验是否存在
BpmTaskAssignRuleDO existRule = taskRuleMapper.selectById(reqVO.getId());
if (existRule == null) {
throw exception(TASK_ASSIGN_RULE_NOT_EXISTS);
}
// 只允许修改流程模型的规则
if (!Objects.equals(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL, existRule.getProcessDefinitionId())) {
throw exception(TASK_UPDATE_FAIL_NOT_MODEL);
}
// 执行更新
taskRuleMapper.updateById(BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO));
}
@Override
public void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId) {
List<BpmTaskAssignRuleRespVO> rules = getTaskAssignRuleList(fromModelId, null);
if (CollUtil.isEmpty(rules)) {
return;
}
// 开始复制
List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null)
.setCreateTime(null).setUpdateTime(null));
taskRuleMapper.insertBatch(newRules);
}
private void validTaskAssignRuleOptions(Integer type, Set<Long> options) {
if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
roleService.validRoles(options);
} else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
deptService.validDepts(options);
} else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) {
postService.validPosts(options);
} else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER.getType())) {
userService.validUsers(options);
} else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) {
userGroupService.validUserGroups(options);
} else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
dictDataService.validDictDatas(SysDictTypeConstants.BPM_TASK_ASSIGN_SCRIPT,
CollectionUtils.convertSet(options, String::valueOf));
} else {
throw new IllegalArgumentException(StrUtil.format("未知的规则类型({})", type));
}
}
}

View File

@ -0,0 +1,114 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmUserGroupConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmUserGroupMapper;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.USER_GROUP_IS_DISABLE;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.USER_GROUP_NOT_EXISTS;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.USER_IS_DISABLE;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.USER_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 用户组 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class BpmUserGroupServiceImpl implements BpmUserGroupService {
@Resource
private BpmUserGroupMapper userGroupMapper;
@Override
public Long createUserGroup(BpmUserGroupCreateReqVO createReqVO) {
// 插入
BpmUserGroupDO userGroup = BpmUserGroupConvert.INSTANCE.convert(createReqVO);
userGroupMapper.insert(userGroup);
// 返回
return userGroup.getId();
}
@Override
public void updateUserGroup(BpmUserGroupUpdateReqVO updateReqVO) {
// 校验存在
this.validateUserGroupExists(updateReqVO.getId());
// 更新
BpmUserGroupDO updateObj = BpmUserGroupConvert.INSTANCE.convert(updateReqVO);
userGroupMapper.updateById(updateObj);
}
@Override
public void deleteUserGroup(Long id) {
// 校验存在
this.validateUserGroupExists(id);
// 删除
userGroupMapper.deleteById(id);
}
private void validateUserGroupExists(Long id) {
if (userGroupMapper.selectById(id) == null) {
throw exception(USER_GROUP_NOT_EXISTS);
}
}
@Override
public BpmUserGroupDO getUserGroup(Long id) {
return userGroupMapper.selectById(id);
}
@Override
public List<BpmUserGroupDO> getUserGroupList(Collection<Long> ids) {
return userGroupMapper.selectBatchIds(ids);
}
@Override
public List<BpmUserGroupDO> getUserGroupListByStatus(Integer status) {
return userGroupMapper.selectListByStatus(status);
}
@Override
public PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO) {
return userGroupMapper.selectPage(pageReqVO);
}
@Override
public void validUserGroups(Set<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}
// 获得用户组信息
List<BpmUserGroupDO> userGroups = userGroupMapper.selectBatchIds(ids);
Map<Long, BpmUserGroupDO> userGroupMap = CollectionUtils.convertMap(userGroups, BpmUserGroupDO::getId);
// 校验
ids.forEach(id -> {
BpmUserGroupDO userGroup = userGroupMap.get(id);
if (userGroup == null) {
throw exception(USER_GROUP_NOT_EXISTS);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(userGroup.getStatus())) {
throw exception(USER_GROUP_IS_DISABLE, userGroup.getName());
}
});
}
}

View File

@ -1,23 +0,0 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.model.dto;
import lombok.Data;
/**
* BPM 流程 MetaInfo Response DTO
* 主要用于 {@link org.activiti.engine.repository.Model#setMetaInfo(String)} 的存储
*
* @author 芋道源码
*/
@Data
public class BpmModelMetaInfoRespDTO {
/**
* 流程描述
*/
private String description;
/**
* 表单编号
*/
private Long formId;
}

View File

@ -87,8 +87,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
runtimeService.setProcessInstanceName(instance.getId(), definition.getName());
// TODO 芋艿临时使用, 保证分配
List<Task> tasks = taskService.getTasksByProcessInstanceId(instance.getId());
tasks.forEach(task -> taskService.updateTaskAssign(task.getId(), userId));
// List<Task> tasks = taskService.getTasksByProcessInstanceId(instance.getId());
// tasks.forEach(task -> taskService.updateTaskAssign(task.getId(), userId));
// 添加初始的评论 TODO 芋艿在思考下
// Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -28,8 +30,8 @@ public class SysDeptBaseVO {
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@ApiModelProperty(value = "负责人", example = "芋道")
private String leader;
@ApiModelProperty(value = "负责人的用户编号", example = "2048")
private Long leaderUserId;
@ApiModelProperty(value = "联系电话", example = "15601691000")
@Size(max = 11, message = "联系电话长度不能超过11个字符")
@ -42,7 +44,7 @@ public class SysDeptBaseVO {
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SysCommonStatusEnum 枚举")
@NotNull(message = "状态不能为空")
// @InEnum(value = SysCommonStatusEnum.class, message = "修改状态必须是 {value}")
// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
}

View File

@ -59,7 +59,7 @@ public class SysPermissionController {
@GetMapping("/list-user-roles")
// @RequiresPermissions("system:permission:assign-user-role")
public CommonResult<Set<Long>> listAdminRoles(@RequestParam("userId") Long userId) {
return success(permissionService.listUserRoleIs(userId));
return success(permissionService.getUserRoleIdListByUserId(userId));
}
@ApiOperation("赋予用户角色")

View File

@ -97,7 +97,7 @@ public class SysRoleController {
@OperateLog(type = EXPORT)
@PreAuthorize("@ss.hasPermission('system:role:export')")
public void export(HttpServletResponse response, @Validated SysRoleExportReqVO reqVO) throws IOException {
List<SysRoleDO> list = roleService.getRoles(reqVO);
List<SysRoleDO> list = roleService.getRoleList(reqVO);
List<SysRoleExcelVO> data = SysRoleConvert.INSTANCE.convertList03(list);
// 输出
ExcelUtils.write(response, "角色数据.xls", "角色列表", SysRoleExcelVO.class, data);

View File

@ -1,7 +1,10 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.user;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptSimpleRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.*;
import cn.iocoder.yudao.adminserver.modules.system.convert.dept.SysDeptConvert;
import cn.iocoder.yudao.adminserver.modules.system.convert.user.SysUserConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
@ -32,6 +35,8 @@ import java.io.IOException;
import java.util.*;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "用户")
@ -99,7 +104,7 @@ public class SysUserController {
}
// 获得拼接需要的数据
Collection<Long> deptIds = CollectionUtils.convertList(pageResult.getList(), SysUserDO::getDeptId);
Collection<Long> deptIds = convertList(pageResult.getList(), SysUserDO::getDeptId);
Map<Long, SysDeptDO> deptMap = deptService.getDeptMap(deptIds);
// 拼接结果返回
List<SysUserPageItemRespVO> userList = new ArrayList<>(pageResult.getList().size());
@ -111,6 +116,15 @@ public class SysUserController {
return success(new PageResult<>(userList, pageResult.getTotal()));
}
@GetMapping("/list-all-simple")
@ApiOperation(value = "获取用户精简信息列表", notes = "只包含被开启的用户,主要用于前端的下拉选项")
public CommonResult<List<SysUserSimpleRespVO>> getSimpleUsers() {
// 获用户门列表只要开启状态的
List<SysUserDO> list = userService.getUsersByStatus(CommonStatusEnum.ENABLE.getStatus());
// 排序后返回给前端
return success(SysUserConvert.INSTANCE.convertList04(list));
}
@GetMapping("/get")
@ApiOperation("获得用户详情")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@ -129,15 +143,19 @@ public class SysUserController {
List<SysUserDO> users = userService.getUsers(reqVO);
// 获得拼接需要的数据
Collection<Long> deptIds = CollectionUtils.convertList(users, SysUserDO::getDeptId);
Collection<Long> deptIds = convertList(users, SysUserDO::getDeptId);
Map<Long, SysDeptDO> deptMap = deptService.getDeptMap(deptIds);
Map<Long, SysUserDO> deptLeaderUserMap = userService.getUserMap(convertSet(deptMap.values(), SysDeptDO::getLeaderUserId));
// 拼接数据
List<SysUserExcelVO> excelUsers = new ArrayList<>(users.size());
users.forEach(user -> {
SysUserExcelVO excelVO = SysUserConvert.INSTANCE.convert02(user);
// 设置部门
MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> {
excelVO.setDeptName(dept.getName());
excelVO.setDeptLeader(dept.getLeader());
// 设置部门负责人的名字
MapUtils.findAndThen(deptLeaderUserMap, dept.getLeaderUserId(),
deptLeaderUser -> excelVO.setDeptLeaderNickname(deptLeaderUser.getNickname()));
});
excelUsers.add(excelVO);
});

View File

@ -65,7 +65,7 @@ public class SysUserProfileController {
SysUserDO user = userCoreService.getUser(getLoginUserId());
SysUserProfileRespVO resp = SysUserConvert.INSTANCE.convert03(user);
// 获得用户角色
List<SysRoleDO> userRoles = roleService.getRolesFromCache(permissionService.listUserRoleIs(user.getId()));
List<SysRoleDO> userRoles = roleService.getRolesFromCache(permissionService.getUserRoleIdListByUserId(user.getId()));
resp.setRoles(SysUserConvert.INSTANCE.convertList(userRoles));
// 获得部门信息
if (user.getDeptId() != null) {

View File

@ -47,6 +47,6 @@ public class SysUserExcelVO {
private String deptName;
@ExcelProperty("部门负责人")
private String deptLeader;
private String deptLeaderNickname;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ApiModel("用户精简信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SysUserSimpleRespVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋道")
private String nickname;
}

View File

@ -45,4 +45,5 @@ public interface SysUserConvert {
List<SysUserProfileRespVO.SocialUser> convertList03(List<SysSocialUserDO> list);
List<SysUserSimpleRespVO> convertList04(List<SysUserDO> list);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
@ -11,6 +12,7 @@ import lombok.EqualsAndHashCode;
* 部门表
*
* @author ruoyi
* @author 芋道源码
*/
@TableName("sys_dept")
@Data
@ -38,8 +40,10 @@ public class SysDeptDO extends TenantBaseDO {
private Integer sort;
/**
* 负责人
*
* 关联 {@link SysUserDO#getId()}
*/
private String leader;
private Long leaderUserId;
/**
* 联系电话
*/

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.Date;
import java.util.List;
@ -20,6 +21,11 @@ public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
.eq("value", value));
}
default List<SysDictDataDO> selectByDictTypeAndValues(String dictType, Collection<String> values) {
return selectList(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
.in("value", values));
}
default int selectCountByDictType(String dictType) {
return selectCount("dict_type", dictType);
}

View File

@ -16,6 +16,14 @@ public interface SysUserRoleMapper extends BaseMapperX<SysUserRoleDO> {
return selectList(new QueryWrapper<SysUserRoleDO>().eq("user_id", userId));
}
default List<SysUserRoleDO> selectListByRoleId(Long roleId) {
return selectList(new QueryWrapper<SysUserRoleDO>().eq("role_id", roleId));
}
default List<SysUserRoleDO> selectListByRoleIds(Collection<Long> roleIds) {
return selectList("role_id", roleIds);
}
default void insertList(Long userId, Collection<Long> roleIds) {
List<SysUserRoleDO> list = roleIds.stream().map(roleId -> {
SysUserRoleDO entity = new SysUserRoleDO();
@ -23,8 +31,7 @@ public interface SysUserRoleMapper extends BaseMapperX<SysUserRoleDO> {
entity.setRoleId(roleId);
return entity;
}).collect(Collectors.toList());
// TODO 芋艿mybatis plus 增加批量插入的功能
list.forEach(this::insert);
insertBatch(list);
}
default void deleteListByUserIdAndRoleIdIds(Long userId, Collection<Long> roleIds) {

View File

@ -55,7 +55,7 @@ public interface SysUserMapper extends BaseMapperX<SysUserDO> {
return selectList(new QueryWrapperX<SysUserDO>().like("username", username));
}
// TODO 芋艿可废弃该方法
default List<SysUserDO> selectListByDepartIdAndPostId(Long departId, Long postId) {
return selectList(new QueryWrapperX<SysUserDO>()
.eq("status", CommonStatusEnum.ENABLE.getStatus())
@ -64,5 +64,13 @@ public interface SysUserMapper extends BaseMapperX<SysUserDO> {
.likeIfPresent("post_ids", Optional.ofNullable(postId).map(t -> String.valueOf(postId)).orElse("")));
}
default List<SysUserDO> selectListByStatus(Integer status) {
return selectList("status", status);
}
default List<SysUserDO> selectListByDeptIds(Collection<Long> deptIds) {
return selectList("dept_id", deptIds);
}
}

View File

@ -22,4 +22,7 @@ public interface SysDictTypeConstants {
String SMS_SEND_STATUS = "sys_sms_send_status"; // 短信发送状态
String SMS_RECEIVE_STATUS = "sys_sms_receive_status"; // 短信接收状态
String BPM_TASK_ASSIGN_RULE_TYPE = "bpm_task_assign_rule_type"; // 任务分配规则类型
String BPM_TASK_ASSIGN_SCRIPT = "bpm_task_assign_script"; // 任务分配自定义脚本
}

View File

@ -31,6 +31,7 @@ public interface SysErrorCodeConstants {
ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1002003001, "已经存在名为【{}】的角色");
ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1002003002, "已经存在编码为【{}】的角色");
ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1002003004, "不能操作类型为系统内置的角色");
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1002003004, "名字为【{}】的角色已被禁用");
// ========== 用户模块 1002004000 ==========
ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1002004000, "用户账号已经存在");
@ -39,6 +40,7 @@ public interface SysErrorCodeConstants {
ErrorCode USER_NOT_EXISTS = new ErrorCode(1002004003, "用户不存在");
ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1002004004, "导入用户数据不能为空!");
ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1002004005, "用户密码校验失败");
ErrorCode USER_IS_DISABLE = new ErrorCode(1002003004, "名字为【{}】的用户已被禁用");
// ========== 部门模块 1002005000 ==========
ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1002004001, "已经存在该名字的部门");
@ -65,7 +67,7 @@ public interface SysErrorCodeConstants {
// ========== 字典数据 1002007000 ==========
ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1002007001, "当前字典数据不存在");
ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1002007002, "字典数据不处于开启状态,不允许选择");
ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1002007002, "字典数据({})不处于开启状态,不允许选择");
ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1002007003, "已经存在该值的字典数据");
// ========== 通知公告 1002008000 ==========

View File

@ -84,6 +84,14 @@ public interface SysDeptService {
*/
SysDeptDO getDept(Long id);
/**
* 获得部门信息数组
*
* @param ids 部门编号数组
* @return 部门信息数组
*/
List<SysDeptDO> getDepts(Collection<Long> ids);
/**
* 获得所有子部门从缓存中
*
@ -93,4 +101,13 @@ public interface SysDeptService {
*/
List<SysDeptDO> getDeptsByParentIdFromCache(Long parentId, boolean recursive);
/**
* 校验部门们是否有效如下情况视为无效
* 1. 部门编号不存在
* 2. 部门被禁用
*
* @param ids 角色编号数组
*/
void validDepts(Collection<Long> ids);
}

View File

@ -86,4 +86,13 @@ public interface SysPostService {
*/
SysPostDO getPost(Long id);
/**
* 校验岗位们是否有效如下情况视为无效
* 1. 岗位编号不存在
* 2. 岗位被禁用
*
* @param ids 岗位编号数组
*/
void validPosts(Collection<Long> ids);
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.system.service.dept.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
@ -26,6 +27,7 @@ import javax.annotation.Resource;
import java.util.*;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 部门 Service 实现类
@ -180,6 +182,26 @@ public class SysDeptServiceImpl implements SysDeptService {
return result;
}
@Override
public void validDepts(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}
// 获得科室信息
List<SysDeptDO> depts = deptMapper.selectBatchIds(ids);
Map<Long, SysDeptDO> deptMap = CollectionUtils.convertMap(depts, SysDeptDO::getId);
// 校验
ids.forEach(id -> {
SysDeptDO dept = deptMap.get(id);
if (dept == null) {
throw exception(DEPT_NOT_FOUND);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(dept.getStatus())) {
throw exception(DEPT_NOT_ENABLE, dept.getName());
}
});
}
/**
* 递归获取所有的子部门添加到 result 结果
*
@ -210,6 +232,11 @@ public class SysDeptServiceImpl implements SysDeptService {
return deptMapper.selectById(id);
}
@Override
public List<SysDeptDO> getDepts(Collection<Long> ids) {
return deptMapper.selectBatchIds(ids);
}
private void checkCreateOrUpdate(Long id, Long parentId, String name) {
// 校验自己存在
checkDeptExists(id);

Some files were not shown because too many files have changed in this diff Show More