BPM 模型重构 7:任务分配规则的前端,增加指定用户、自定义脚本等

This commit is contained in:
YunaiV 2022-01-15 00:31:56 +08:00
parent 842cb6bd6b
commit f46090243f
23 changed files with 391 additions and 12 deletions

View File

@ -7,6 +7,10 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.B
import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmUserGroupConvert; 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.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService; 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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@ -19,6 +23,8 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "用户组") @Api(tags = "用户组")
@ -71,4 +77,13 @@ public class BpmUserGroupController {
return success(BpmUserGroupConvert.INSTANCE.convertPage(pageResult)); 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

@ -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

@ -9,6 +9,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUse
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
/** /**
@ -31,4 +32,6 @@ public interface BpmUserGroupConvert {
PageResult<BpmUserGroupRespVO> convertPage(PageResult<BpmUserGroupDO> page); PageResult<BpmUserGroupRespVO> convertPage(PageResult<BpmUserGroupDO> page);
@Named("convertList2")
List<BpmUserGroupRespVO> convertList2(List<BpmUserGroupDO> list);
} }

View File

@ -7,6 +7,8 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/** /**
* 用户组 Mapper * 用户组 Mapper
* *
@ -23,4 +25,8 @@ public interface BpmUserGroupMapper extends BaseMapperX<BpmUserGroupDO> {
.orderByDesc("id")); .orderByDesc("id"));
} }
default List<BpmUserGroupDO> selectListByStatus(Integer status) {
return selectList("status", status);
}
} }

View File

@ -54,4 +54,6 @@ public interface BpmErrorCodeConstants {
// ========== 用户组模块 1-009-011-000 ========== // ========== 用户组模块 1-009-011-000 ==========
ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在"); ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在");
ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1009011001, "名字为【{}】的用户组已被禁用");
} }

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,26 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script;
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);
}

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

@ -54,6 +54,14 @@ public interface BpmUserGroupService {
*/ */
List<BpmUserGroupDO> getUserGroupList(Collection<Long> ids); List<BpmUserGroupDO> getUserGroupList(Collection<Long> ids);
/**
* 获得指定状态的用户组列表
*
* @param status 状态
* @return 用户组列表
*/
List<BpmUserGroupDO> getUserGroupListByStatus(Integer status);
/** /**
* 获得用户组分页 * 获得用户组分页
* *
@ -62,4 +70,13 @@ public interface BpmUserGroupService {
*/ */
PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO); PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO);
/**
* 校验用户组们是否有效如下情况视为无效
* 1. 用户组编号不存在
* 2. 用户组被禁用
*
* @param ids 用户组编号数组
*/
void validUserGroups(Set<Long> ids);
} }

View File

@ -12,9 +12,15 @@ import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRu
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService; 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.BpmProcessDefinitionService;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService; 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.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.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.activiti.core.util.ActivitiUtils;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.BpmnModel;
@ -30,6 +36,7 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*; 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; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/** /**
@ -53,6 +60,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
private SysRoleService roleService; private SysRoleService roleService;
@Resource @Resource
private SysDeptService deptService; private SysDeptService deptService;
@Resource
private SysPostService postService;
@Resource
private SysUserService userService;
@Resource
private BpmUserGroupService userGroupService;
@Resource
private SysDictDataService dictDataService;
@Override @Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
@ -146,8 +161,18 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
} else if (ObjectUtils.equalsAny(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), } else if (ObjectUtils.equalsAny(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
deptService.validDepts(options); 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));
} }
// TODO 其它的
} }
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl; 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.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO; 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.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
@ -7,15 +8,23 @@ import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmUserGroupC
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO; 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.dal.mysql.definition.BpmUserGroupMapper;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService; 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.List; 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.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; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/** /**
@ -72,9 +81,34 @@ public class BpmUserGroupServiceImpl implements BpmUserGroupService {
return userGroupMapper.selectBatchIds(ids); return userGroupMapper.selectBatchIds(ids);
} }
@Override
public List<BpmUserGroupDO> getUserGroupListByStatus(Integer status) {
return userGroupMapper.selectListByStatus(status);
}
@Override @Override
public PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO) { public PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO) {
return userGroupMapper.selectPage(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

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

View File

@ -22,4 +22,7 @@ public interface SysDictTypeConstants {
String SMS_SEND_STATUS = "sys_sms_send_status"; // 短信发送状态 String SMS_SEND_STATUS = "sys_sms_send_status"; // 短信发送状态
String SMS_RECEIVE_STATUS = "sys_sms_receive_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

@ -40,6 +40,7 @@ public interface SysErrorCodeConstants {
ErrorCode USER_NOT_EXISTS = new ErrorCode(1002004003, "用户不存在"); ErrorCode USER_NOT_EXISTS = new ErrorCode(1002004003, "用户不存在");
ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1002004004, "导入用户数据不能为空!"); ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1002004004, "导入用户数据不能为空!");
ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1002004005, "用户密码校验失败"); ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1002004005, "用户密码校验失败");
ErrorCode USER_IS_DISABLE = new ErrorCode(1002003004, "名字为【{}】的用户已被禁用");
// ========== 部门模块 1002005000 ========== // ========== 部门模块 1002005000 ==========
ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1002004001, "已经存在该名字的部门"); ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1002004001, "已经存在该名字的部门");
@ -66,7 +67,7 @@ public interface SysErrorCodeConstants {
// ========== 字典数据 1002007000 ========== // ========== 字典数据 1002007000 ==========
ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1002007001, "当前字典数据不存在"); 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, "已经存在该值的字典数据"); ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1002007003, "已经存在该值的字典数据");
// ========== 通知公告 1002008000 ========== // ========== 通知公告 1002008000 ==========

View File

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

View File

@ -1,5 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.system.service.dept.impl; package cn.iocoder.yudao.adminserver.modules.system.service.dept.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post.SysPostCreateReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
@ -10,14 +13,17 @@ import cn.iocoder.yudao.adminserver.modules.system.convert.dept.SysPostConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.dept.SysPostMapper; import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.dept.SysPostMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService; import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*; import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/** /**
* 岗位 Service 实现类 * 岗位 Service 实现类
@ -78,6 +84,26 @@ public class SysPostServiceImpl implements SysPostService {
return postMapper.selectById(id); return postMapper.selectById(id);
} }
@Override
public void validPosts(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}
// 获得岗位信息
List<SysPostDO> posts = postMapper.selectBatchIds(ids);
Map<Long, SysPostDO> postMap = CollectionUtils.convertMap(posts, SysPostDO::getId);
// 校验
ids.forEach(id -> {
SysPostDO post = postMap.get(id);
if (post == null) {
throw exception(POST_NOT_FOUND);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(post.getStatus())) {
throw exception(POST_NOT_ENABLE, post.getName());
}
});
}
private void checkCreateOrUpdate(Long id, String name, String code) { private void checkCreateOrUpdate(Long id, String name, String code) {
// 校验自己存在 // 校验自己存在
checkPostExists(id); checkPostExists(id);

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDi
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataPageReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataUpdateReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataUpdateReqVO;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -78,4 +79,14 @@ public interface SysDictDataService {
*/ */
int countByDictType(String dictType); int countByDictType(String dictType);
/**
* 校验字典数据们是否有效如下情况视为无效
* 1. 字典数据不存在
* 2. 字典数据被禁用
*
* @param dictType 字典类型
* @param values 字典数据值的数组
*/
void validDictDatas(String dictType, Collection<String> values);
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.adminserver.modules.system.service.dict.impl; package cn.iocoder.yudao.adminserver.modules.system.service.dict.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataExportReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataPageReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data.SysDictDataPageReqVO;
@ -11,16 +12,16 @@ import cn.iocoder.yudao.adminserver.modules.system.mq.producer.dict.SysDictDataP
import cn.iocoder.yudao.adminserver.modules.system.service.dict.SysDictDataService; import cn.iocoder.yudao.adminserver.modules.system.service.dict.SysDictDataService;
import cn.iocoder.yudao.adminserver.modules.system.service.dict.SysDictTypeService; import cn.iocoder.yudao.adminserver.modules.system.service.dict.SysDictTypeService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO; import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Comparator; import java.util.*;
import java.util.Date;
import java.util.List;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*; import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -133,6 +134,26 @@ public class SysDictDataServiceImpl implements SysDictDataService {
return dictDataMapper.selectCountByDictType(dictType); return dictDataMapper.selectCountByDictType(dictType);
} }
@Override
public void validDictDatas(String dictType, Collection<String> values) {
if (CollUtil.isEmpty(values)) {
return;
}
// 获得字典数据信息
List<SysDictDataDO> dictDatas = dictDataMapper.selectByDictTypeAndValues(dictType, values);
Map<String, SysDictDataDO> dictDataMap = CollectionUtils.convertMap(dictDatas, SysDictDataDO::getValue);
// 校验
values.forEach(value -> {
SysDictDataDO dictData = dictDataMap.get(value);
if (dictData == null) {
throw exception(DICT_DATA_NOT_EXISTS);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus())) {
throw exception(DICT_DATA_NOT_ENABLE, dictData.getLabel());
}
});
}
private void checkCreateOrUpdate(Long id, String value, String dictType) { private void checkCreateOrUpdate(Long id, String value, String dictType) {
// 校验自己存在 // 校验自己存在
checkDictDataExists(id); checkDictDataExists(id);

View File

@ -9,10 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* 后台用户 Service 接口 * 后台用户 Service 接口
@ -177,4 +174,13 @@ public interface SysUserService {
*/ */
List<SysUserDO> getUsersByStatus(Integer status); List<SysUserDO> getUsersByStatus(Integer status);
/**
* 校验用户们是否有效如下情况视为无效
* 1. 用户编号不存在
* 2. 用户被禁用
*
* @param ids 用户编号数组
*/
void validUsers(Set<Long> ids);
} }

View File

@ -182,6 +182,11 @@ public class SysUserServiceImpl implements SysUserService {
return userMapper.selectBatchIds(ids); return userMapper.selectBatchIds(ids);
} }
@Override
public Map<Long, SysUserDO> getUserMap(Collection<Long> ids) {
return SysUserService.super.getUserMap(ids);
}
@Override @Override
public List<SysUserDO> getUsersByNickname(String nickname) { public List<SysUserDO> getUsersByNickname(String nickname) {
return userMapper.selectListByNickname(nickname); return userMapper.selectListByNickname(nickname);
@ -384,4 +389,24 @@ public class SysUserServiceImpl implements SysUserService {
return userMapper.selectListByStatus(status); return userMapper.selectListByStatus(status);
} }
@Override
public void validUsers(Set<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}
// 获得岗位信息
List<SysUserDO> users = userMapper.selectBatchIds(ids);
Map<Long, SysUserDO> userMap = CollectionUtils.convertMap(users, SysUserDO::getId);
// 校验
ids.forEach(id -> {
SysUserDO user = userMap.get(id);
if (user == null) {
throw exception(USER_NOT_EXISTS);
}
if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) {
throw exception(USER_IS_DISABLE, user.getNickname());
}
});
}
} }

View File

@ -42,3 +42,11 @@ export function getUserGroupPage(query) {
params: query params: query
}) })
} }
// 获取用户组精简信息列表
export function listSimpleUserGroups() {
return request({
url: '/bpm/user-group/list-all-simple',
method: 'get'
})
}

View File

@ -40,6 +40,7 @@ export const DICT_TYPE = {
BPM_TASK_ASSIGN_RULE_TYPE: 'bpm_task_assign_rule_type', BPM_TASK_ASSIGN_RULE_TYPE: 'bpm_task_assign_rule_type',
BPM_PROCESS_INSTANCE_STATUS: 'bpm_process_instance_status', BPM_PROCESS_INSTANCE_STATUS: 'bpm_process_instance_status',
BPM_PROCESS_INSTANCE_RESULT: 'bpm_process_instance_result', BPM_PROCESS_INSTANCE_RESULT: 'bpm_process_instance_result',
BPM_TASK_ASSIGN_SCRIPT: 'bpm_task_assign_script',
OA_LEAVE_STATUS: 'flow_status', // todo 芋艿:可以删除 OA_LEAVE_STATUS: 'flow_status', // todo 芋艿:可以删除
OA_LEAVE_TYPE: 'oa_leave_type' OA_LEAVE_TYPE: 'oa_leave_type'
} }
@ -51,6 +52,10 @@ export const DICT_TYPE = {
* @returns {*|Array} 数据字典数组 * @returns {*|Array} 数据字典数组
*/ */
export function getDictDatas(dictType) { export function getDictDatas(dictType) {
// if (dictType === 'bpm_task_assign_script') {
// console.log(store.getters.dict_datas[dictType]);
// debugger
// }
return store.getters.dict_datas[dictType] || [] return store.getters.dict_datas[dictType] || []
} }

View File

@ -37,7 +37,7 @@
</el-form-item> </el-form-item>
<el-form-item label="规则类型" prop="type"> <el-form-item label="规则类型" prop="type">
<el-select v-model="form.type" clearable style="width: 100%"> <el-select v-model="form.type" clearable style="width: 100%">
<el-option v-for="dict in taskAssignRuleDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/> <el-option v-for="dict in taskAssignRuleTypeDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.type === 10" label="指定角色" prop="roleIds"> <el-form-item v-if="form.type === 10" label="指定角色" prop="roleIds">
@ -49,6 +49,27 @@
<treeselect v-model="form.deptIds" :options="deptTreeOptions" multiple flat :defaultExpandLevel="3" <treeselect v-model="form.deptIds" :options="deptTreeOptions" multiple flat :defaultExpandLevel="3"
placeholder="请选择指定部门" :normalizer="normalizer"/> placeholder="请选择指定部门" :normalizer="normalizer"/>
</el-form-item> </el-form-item>
<el-form-item v-if="form.type === 22" label="指定岗位" prop="postIds">
<el-select v-model="form.postIds" multiple clearable style="width: 100%">
<el-option v-for="item in postOptions" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
</el-select>
</el-form-item>
<el-form-item v-if="form.type === 30" label="指定用户" prop="userIds">
<el-select v-model="form.userIds" multiple clearable style="width: 100%">
<el-option v-for="item in userOptions" :key="parseInt(item.id)" :label="item.nickname" :value="parseInt(item.id)" />
</el-select>
</el-form-item>
<el-form-item v-if="form.type === 40" label="指定用户组" prop="userGroupIds">
<el-select v-model="form.userGroupIds" multiple clearable style="width: 100%">
<el-option v-for="item in userGroupOptions" :key="parseInt(item.id)" :label="item.name" :value="parseInt(item.id)" />
</el-select>
</el-form-item>
<el-form-item v-if="form.type === 50" label="指定脚本" prop="scripts">
<el-select v-model="form.scripts" multiple clearable style="width: 100%">
<el-option v-for="dict in taskAssignScriptDictDatas" :key="parseInt(dict.value)"
:label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitAssignRuleForm"> </el-button> <el-button type="primary" @click="submitAssignRuleForm"> </el-button>
@ -66,6 +87,9 @@ import {listSimpleDepts} from "@/api/system/dept";
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import {listSimplePosts} from "@/api/system/post";
import {listSimpleUsers} from "@/api/system/user";
import {listSimpleUserGroups} from "@/api/bpm/userGroup";
export default { export default {
name: "taskAssignRuleDialog", name: "taskAssignRuleDialog",
@ -89,16 +113,24 @@ export default {
type: [{ required: true, message: "规则类型不能为空", trigger: "change" }], type: [{ required: true, message: "规则类型不能为空", trigger: "change" }],
roleIds: [{required: true, message: "指定角色不能为空", trigger: "change" }], roleIds: [{required: true, message: "指定角色不能为空", trigger: "change" }],
deptIds: [{required: true, message: "指定部门不能为空", trigger: "change" }], deptIds: [{required: true, message: "指定部门不能为空", trigger: "change" }],
postIds: [{required: true, message: "指定岗位不能为空", trigger: "change"}],
userIds: [{required: true, message: "指定用户不能为空", trigger: "change"}],
userGroupIds: [{required: true, message: "指定用户组不能为空", trigger: "change"}],
scripts: [{required: true, message: "指定脚本不能为空", trigger: "change"}],
}, },
// //
roleOptions: [], roleOptions: [],
deptOptions: [], deptOptions: [],
deptTreeOptions: [], deptTreeOptions: [],
postOptions: [],
userOptions: [],
userGroupOptions: [],
// //
modelFormTypeDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_FORM_TYPE), modelFormTypeDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_FORM_TYPE),
taskAssignRuleDictDatas: getDictDatas(DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE), taskAssignRuleTypeDictDatas: getDictDatas(DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE),
taskAssignScriptDictDatas: getDictDatas(DICT_TYPE.BPM_TASK_ASSIGN_SCRIPT),
}; };
}, },
methods: { methods: {
@ -132,10 +164,24 @@ export default {
this.deptOptions = []; this.deptOptions = [];
this.deptTreeOptions = []; this.deptTreeOptions = [];
listSimpleDepts().then(response => { listSimpleDepts().then(response => {
// roleOptions
this.deptOptions.push(...response.data); this.deptOptions.push(...response.data);
this.deptTreeOptions.push(...this.handleTree(response.data, "id")); this.deptTreeOptions.push(...this.handleTree(response.data, "id"));
}); });
//
this.postOptions = [];
listSimplePosts().then(response => {
this.postOptions.push(...response.data);
});
//
this.userOptions = [];
listSimpleUsers().then(response => {
this.userOptions.push(...response.data);
});
//
this.userGroupOptions = [];
listSimpleUserGroups().then(response => {
this.userGroupOptions.push(...response.data);
});
}, },
/** 获得任务分配规则列表 */ /** 获得任务分配规则列表 */
getList() { getList() {
@ -157,12 +203,24 @@ export default {
options: [], options: [],
roleIds: [], roleIds: [],
deptIds: [], deptIds: [],
postIds: [],
userIds: [],
userGroupIds: [],
scripts: [],
}; };
// options roleIds // options roleIds
if (row.type === 10) { if (row.type === 10) {
this.form.roleIds.push(...row.options); this.form.roleIds.push(...row.options);
} else if (row.type === 20 || row.type === 21) { } else if (row.type === 20 || row.type === 21) {
this.form.deptIds.push(...row.options); this.form.deptIds.push(...row.options);
} else if (row.type === 22) {
this.form.postIds.push(...row.options);
} else if (row.type === 30) {
this.form.userIds.push(...row.options);
} else if (row.type === 40) {
this.form.userGroupIds.push(...row.options);
} else if (row.type === 50) {
this.form.scripts.push(...row.options);
} }
this.open = true; this.open = true;
}, },
@ -180,9 +238,21 @@ export default {
form.options = form.roleIds; form.options = form.roleIds;
} else if (form.type === 20 || form.type === 21) { } else if (form.type === 20 || form.type === 21) {
form.options = form.deptIds; form.options = form.deptIds;
} else if (form.type === 22) {
form.options = form.postIds;
} else if (form.type === 30) {
form.options = form.userIds;
} else if (form.type === 40) {
form.options = form.userGroupIds;
} else if (form.type === 50) {
form.options = form.scripts;
} }
form.roleIds = undefined; form.roleIds = undefined;
form.deptIds = undefined; form.deptIds = undefined;
form.postIds = undefined;
form.userIds = undefined;
form.userGroupIds = undefined;
form.scripts = undefined;
// //
if (!form.id) { if (!form.id) {
form.modelId = this.modelId; // form.modelId = this.modelId; //
@ -226,6 +296,31 @@ export default {
return deptOption.name; return deptOption.name;
} }
} }
} else if (type === 22) {
for (const postOption of this.postOptions) {
if (postOption.id === option) {
return postOption.name;
}
}
} else if (type === 30) {
for (const userOption of this.userOptions) {
if (userOption.id === option) {
return userOption.nickname;
}
}
} else if (type === 40) {
for (const userGroupOption of this.userGroupOptions) {
if (userGroupOption.id === option) {
return userGroupOption.name;
}
}
} else if (type === 50) {
option = option + ''; // string
for (const dictData of this.taskAssignScriptDictDatas) {
if (dictData.value === option) {
return dictData.label;
}
}
} }
return '未知(' + option + ')'; return '未知(' + option + ')';
}, },