1. 修复回滚父子角色功能时错误的代码逻辑,补全单元测试用例
2. 新增支持切换后业务菜单查询需限定只查询该公司业务数据能力
This commit is contained in:
@@ -25,11 +25,15 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static java.util.Collections.singleton;
|
||||
|
||||
/**
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Tag(name = "管理后台 - 角色")
|
||||
@RestController
|
||||
@RequestMapping("/system/role")
|
||||
@@ -43,7 +47,7 @@ public class RoleController {
|
||||
@Operation(summary = "创建角色")
|
||||
@PreAuthorize("@ss.hasPermission('system:role:create')")
|
||||
public CommonResult<Long> createRole(@Valid @RequestBody RoleSaveReqVO createReqVO) {
|
||||
return success(roleService.createRole(createReqVO, null));
|
||||
return success(roleService.createRole(createReqVO, createReqVO.getType() == null ? null : Integer.valueOf(createReqVO.getType())));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@@ -76,6 +80,20 @@ public class RoleController {
|
||||
@PreAuthorize("@ss.hasPermission('system:role:query')")
|
||||
public CommonResult<PageResult<RoleRespVO>> getRolePage(RolePageReqVO pageReqVO) {
|
||||
PageResult<RoleDO> pageResult = roleService.getRolePage(pageReqVO);
|
||||
// 获取所有父级角色信息
|
||||
List<Long> parentIds = pageResult.getList().stream().filter(role -> role.getParentId() != null && role.getParentId() > 0)
|
||||
.map(RoleDO::getParentId)
|
||||
.distinct()
|
||||
.toList();
|
||||
List<RoleDO> parentRoles = roleService.getRoleList(parentIds);
|
||||
// 将父级角色信息转换为 id 与 name 的 Map
|
||||
var parentRoleMap = parentRoles.stream().collect(Collectors.toMap(RoleDO::getId, RoleDO::getName, (v1, v2) -> v1));
|
||||
// 补全父级角色名称
|
||||
pageResult.getList().forEach(role -> {
|
||||
if (role.getParentId() != null && role.getParentId() > 0) {
|
||||
role.setParentName(parentRoleMap.get(role.getParentId()));
|
||||
}
|
||||
});
|
||||
return success(BeanUtils.toBean(pageResult, RoleRespVO.class));
|
||||
}
|
||||
|
||||
@@ -87,6 +105,16 @@ public class RoleController {
|
||||
return success(BeanUtils.toBean(list, RoleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping({"/list-all-extend-simple", "/simple-extend-list"})
|
||||
@Operation(summary = "获取所有可继承角色精简信息列表", description = "只包含被开启的角色,主要用于前端的下拉选项")
|
||||
public CommonResult<List<RoleRespVO>> getParentSimpleRoleList() {
|
||||
List<RoleDO> list = roleService.getRoleListByStatus(singleton(CommonStatusEnum.ENABLE.getStatus()));
|
||||
// 过滤掉系统内置角色(如有需要)
|
||||
list.removeIf(role -> role.getType() != null && role.getType().equals(1));
|
||||
list.sort(Comparator.comparing(RoleDO::getSort));
|
||||
return success(BeanUtils.toBean(list, RoleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出角色 Excel")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
|
||||
@@ -12,6 +12,9 @@ import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Schema(description = "管理后台 - 角色信息 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@@ -56,4 +59,11 @@ public class RoleRespVO {
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "父级角色名称", example = "1")
|
||||
@ExcelProperty("父级角色名称")
|
||||
private String parentName;
|
||||
|
||||
@Schema(description = "父级角色 Id", example = "1")
|
||||
@ExcelProperty("父级角色 Id")
|
||||
private Long parentId;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public class RoleDO extends TenantBaseDO {
|
||||
private String name;
|
||||
/**
|
||||
* 角色标识
|
||||
*
|
||||
* 枚举
|
||||
*/
|
||||
private String code;
|
||||
@@ -43,13 +42,11 @@ public class RoleDO extends TenantBaseDO {
|
||||
private Integer sort;
|
||||
/**
|
||||
* 角色状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 角色类型
|
||||
*
|
||||
* 枚举 {@link RoleTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
@@ -60,16 +57,27 @@ public class RoleDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 数据范围
|
||||
*
|
||||
* 枚举 {@link DataScopeEnum}
|
||||
*/
|
||||
private Integer dataScope;
|
||||
/**
|
||||
* 数据范围(指定部门数组)
|
||||
*
|
||||
* 适用于 {@link #dataScope} 的值为 {@link DataScopeEnum#DEPT_CUSTOM} 时
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Set<Long> dataScopeDeptIds;
|
||||
|
||||
/**
|
||||
* 父级标准角色 Id : 继承的标准角色Id,系统角色为 -1、标准角色为 0
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 父级角色名称
|
||||
* 仅用于前端角色界面展示
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String parentName;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.iocoder.yudao.module.system.dal.dataobject.rolemenuexclusion;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 角色菜单剔除 DO
|
||||
*
|
||||
* @author 管理员
|
||||
*/
|
||||
@TableName("system_role_menu_exclusion")
|
||||
@KeySequence("system_role_menu_exclusion_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RoleMenuExclusionDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
/**
|
||||
* 菜单ID
|
||||
*/
|
||||
private Long menuId;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.dal.dataobject.user;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import cn.iocoder.yudao.module.system.enums.common.SexEnum;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
@@ -53,6 +54,16 @@ public class AdminUserDO extends TenantBaseDO {
|
||||
*/
|
||||
@TableField(exist = false, typeHandler = JacksonTypeHandler.class )
|
||||
private Set<Long> deptIds;
|
||||
/**
|
||||
* 公司 ID 列表
|
||||
*/
|
||||
@TableField(exist = false, typeHandler = JacksonTypeHandler.class )
|
||||
private Set<Long> companyIds;
|
||||
/**
|
||||
* 公司与部门关系列表
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private Set<CompanyDeptInfo> companyDeptInfos;
|
||||
/**
|
||||
* 岗位编号数组
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,9 @@ import org.springframework.lang.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Mapper
|
||||
public interface RoleMapper extends BaseMapperX<RoleDO> {
|
||||
|
||||
@@ -36,4 +39,8 @@ public interface RoleMapper extends BaseMapperX<RoleDO> {
|
||||
return selectList(RoleDO::getStatus, statuses);
|
||||
}
|
||||
|
||||
default long selectCountByParentId(Long parentId) {
|
||||
return selectCount(RoleDO::getParentId, parentId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.system.dal.mysql.rolemenuexclusion;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.rolemenuexclusion.RoleMenuExclusionDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色菜单剔除 Mapper
|
||||
*
|
||||
* @author 管理员
|
||||
*/
|
||||
@Mapper
|
||||
public interface RoleMenuExclusionMapper extends BaseMapperX<RoleMenuExclusionDO> {
|
||||
|
||||
/**
|
||||
* 根据角色编号,查询角色菜单剔除列表
|
||||
*
|
||||
* @param roleIds 角色编号
|
||||
*/
|
||||
default List<RoleMenuExclusionDO> selectMenuIdListByRoleId(Collection<Long> roleIds) {
|
||||
return selectList(RoleMenuExclusionDO::getRoleId, roleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色编号,菜单编号,删除角色菜单剔除列表
|
||||
*
|
||||
* @param roleId 角色编号
|
||||
* @param menuIds 菜单编号
|
||||
*/
|
||||
default void deleteListByRoleIdAndMenuIds(Long roleId, Collection<Long> menuIds) {
|
||||
delete(new LambdaQueryWrapper<RoleMenuExclusionDO>()
|
||||
.eq(RoleMenuExclusionDO::getRoleId, roleId)
|
||||
.in(RoleMenuExclusionDO::getMenuId, menuIds));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.system.service.dept;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
@@ -115,4 +116,6 @@ public interface DeptService {
|
||||
void validateDeptList(Collection<Long> ids);
|
||||
|
||||
List<DeptDO> getUserCompanyList();
|
||||
|
||||
Set<CompanyDeptInfo> getCompanyDeptInfoListByUserId(Long userId);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.dept;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
|
||||
@@ -263,4 +264,43 @@ public class DeptServiceImpl implements DeptService {
|
||||
return getDeptList(companyIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询其归属公司及直属部门关系列表(不递归下级公司)
|
||||
*/
|
||||
@Override
|
||||
public Set<CompanyDeptInfo> getCompanyDeptInfoListByUserId(Long userId) {
|
||||
// 查询用户所属部门
|
||||
Set<Long> deptIds = userDeptMapper.selectValidListByUserIds(singleton(userId))
|
||||
.stream()
|
||||
.map(UserDeptDO::getDeptId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollUtil.isEmpty(deptIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
// 查询所有部门信息
|
||||
Map<Long, DeptDO> deptMap = getDeptList(deptIds).stream()
|
||||
.collect(Collectors.toMap(DeptDO::getId, d -> d));
|
||||
Set<CompanyDeptInfo> result = new HashSet<>();
|
||||
for (Long deptId : deptIds) {
|
||||
DeptDO dept = deptMap.get(deptId);
|
||||
if (dept == null) continue;
|
||||
// 向上查找公司,如果到达顶层(parentId为PARENT_ID_ROOT)还没找到公司,则用顶层部门作为公司
|
||||
DeptDO company = dept;
|
||||
while (company != null && !Boolean.TRUE.equals(company.getIsCompany())) {
|
||||
if (company.getParentId() == null || DeptDO.PARENT_ID_ROOT.equals(company.getParentId())) {
|
||||
break;
|
||||
}
|
||||
company = getDept(company.getParentId());
|
||||
}
|
||||
if (company == null) continue;
|
||||
CompanyDeptInfo info = new CompanyDeptInfo();
|
||||
info.setCompanyId(company.getId());
|
||||
info.setCompanyName(company.getName());
|
||||
info.setDeptId(dept.getId());
|
||||
info.setDeptName(dept.getName());
|
||||
result.add(info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
@@ -199,7 +200,12 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
|
||||
AdminUserDO user = adminUserService.getUser(userId);
|
||||
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
|
||||
.put(LoginUser.INFO_KEY_TENANT_ID, user.getTenantId().toString()).build();
|
||||
.put(LoginUser.INFO_KEY_TENANT_ID, user.getTenantId().toString())
|
||||
.put(LoginUser.INFO_KEY_COMPANY_IDS, CollUtil.isEmpty(user.getCompanyIds()) ? "[]" : JsonUtils.toJsonString(user.getCompanyIds()))
|
||||
.put(LoginUser.INFO_KEY_DEPT_IDS, CollUtil.isEmpty(user.getDeptIds()) ? "[]" : JsonUtils.toJsonString(user.getDeptIds()))
|
||||
.put(LoginUser.INFO_KEY_COMPANY_DEPT_SET, CollUtil.isEmpty(user.getCompanyDeptInfos()) ? "[]" : JsonUtils.toJsonString(user.getCompanyDeptInfos()))
|
||||
.put(LoginUser.INFO_KEY_POST_IDS, CollUtil.isEmpty(user.getPostIds()) ? "[]" : JsonUtils.toJsonString(user.getPostIds()))
|
||||
.build();
|
||||
} else if (userType.equals(UserTypeEnum.MEMBER.getValue())) {
|
||||
// 注意:目前 Member 暂时不读取,可以按需实现
|
||||
return Collections.emptyMap();
|
||||
|
||||
@@ -12,9 +12,11 @@ import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.rolemenuexclusion.RoleMenuExclusionDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.userdept.UserDeptDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.rolemenuexclusion.RoleMenuExclusionMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
|
||||
@@ -69,6 +71,8 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
@Resource
|
||||
private RoleMenuExclusionMapper roleMenuExclusionMapper;
|
||||
@Resource
|
||||
private UserDeptService userDeptService;
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
@@ -210,8 +214,14 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
if (roleService.hasAnySuperAdmin(roleIds)) {
|
||||
return convertSet(menuService.getMenuList(), MenuDO::getId);
|
||||
}
|
||||
// 如果是非管理员的情况下,获得拥有的菜单编号
|
||||
return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId);
|
||||
// 递归获取所有父角色id
|
||||
Set<Long> allRoleIds = roleService.getAllParentAndSelfRoleIds(roleIds);
|
||||
// 如果是非管理员的情况下,获得拥有的菜单编号(含父角色,需要剔除当前角色排除的菜单)
|
||||
Set<Long> menuIds = convertSet(roleMenuMapper.selectListByRoleId(allRoleIds), RoleMenuDO::getMenuId);
|
||||
// 排除当前角色排除的菜单编号
|
||||
Set<Long> excludeMenuIds = convertSet(roleMenuExclusionMapper.selectMenuIdListByRoleId(allRoleIds), RoleMenuExclusionDO::getMenuId);
|
||||
menuIds.removeAll(excludeMenuIds);
|
||||
return menuIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -123,4 +123,12 @@ public interface RoleService {
|
||||
*/
|
||||
void validateRoleList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获取所有父角色id(递归)
|
||||
* @param roleIds 当前角色id集合
|
||||
* @return 包含自身和所有父级的id集合
|
||||
*/
|
||||
Set<Long> getAllParentAndSelfRoleIds(Collection<Long> roleIds);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.mzt.logapi.context.LogRecordContext;
|
||||
import com.mzt.logapi.service.impl.DiffParseFunction;
|
||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
@@ -69,8 +71,11 @@ public class RoleServiceImpl implements RoleService {
|
||||
// 2. 插入到数据库
|
||||
RoleDO role = BeanUtils.toBean(createReqVO, RoleDO.class)
|
||||
.setType(ObjectUtil.defaultIfNull(type, RoleTypeEnum.CUSTOM.getType()))
|
||||
// 如果类型不为公司角色则设置 parentId 为 0
|
||||
.setParentId(!ObjectUtil.equal(RoleTypeEnum.CUSTOM.getType(), type) ? 0L : createReqVO.getParentId())
|
||||
.setStatus(ObjUtil.defaultIfNull(createReqVO.getStatus(), CommonStatusEnum.ENABLE.getStatus()))
|
||||
.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限
|
||||
// 默认可查看所有数据。原因是,可能一些项目不需要项目权限
|
||||
.setDataScope(DataScopeEnum.ALL.getScope());
|
||||
roleMapper.insert(role);
|
||||
|
||||
// 3. 记录操作日志上下文
|
||||
@@ -87,6 +92,11 @@ public class RoleServiceImpl implements RoleService {
|
||||
RoleDO role = validateRoleForUpdate(updateReqVO.getId());
|
||||
// 1.2 校验角色的唯一字段是否重复
|
||||
validateRoleDuplicate(updateReqVO.getName(), updateReqVO.getCode(), updateReqVO.getId());
|
||||
// 1.3 校验角色当前修改的父角色是否为当前角色的子角色
|
||||
if (updateReqVO.getParentId() != null && !updateReqVO.getParentId().equals(0L) && isChildRole(updateReqVO.getId(), updateReqVO.getParentId())) {
|
||||
throw exception(ROLE_PARENT_IS_CHILD, updateReqVO.getName());
|
||||
}
|
||||
|
||||
|
||||
// 2. 更新到数据库
|
||||
RoleDO updateObj = BeanUtils.toBean(updateReqVO, RoleDO.class);
|
||||
@@ -112,6 +122,7 @@ public class RoleServiceImpl implements RoleService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheEvict(value = RedisKeyConstants.ROLE, key = "#id")
|
||||
@LogRecord(type = SYSTEM_ROLE_TYPE, subType = SYSTEM_ROLE_DELETE_SUB_TYPE, bizNo = "{{#id}}",
|
||||
@@ -120,6 +131,11 @@ public class RoleServiceImpl implements RoleService {
|
||||
// 1. 校验是否可以更新
|
||||
RoleDO role = validateRoleForUpdate(id);
|
||||
|
||||
// 1.1 校验角色是否存在子角色,如果存在,则不允许删除
|
||||
if (roleMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(ROLE_CAN_NOT_DELETE_HAS_CHILDREN , role.getName());
|
||||
}
|
||||
|
||||
// 2.1 标记删除
|
||||
roleMapper.deleteById(id);
|
||||
// 2.2 删除相关数据
|
||||
@@ -214,7 +230,7 @@ public class RoleServiceImpl implements RoleService {
|
||||
if (CollectionUtil.isEmpty(ids)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return roleMapper.selectBatchIds(ids);
|
||||
return roleMapper.selectByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,7 +278,7 @@ public class RoleServiceImpl implements RoleService {
|
||||
return;
|
||||
}
|
||||
// 获得角色信息
|
||||
List<RoleDO> roles = roleMapper.selectBatchIds(ids);
|
||||
List<RoleDO> roles = roleMapper.selectByIds(ids);
|
||||
Map<Long, RoleDO> roleMap = convertMap(roles, RoleDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
@@ -276,6 +292,29 @@ public class RoleServiceImpl implements RoleService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> getAllParentAndSelfRoleIds(Collection<Long> roleIds) {
|
||||
// 递归获取所有父角色id,最多递归5层,防止环
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
RoleServiceImpl self = getSelf();
|
||||
return roleIds.stream()
|
||||
.flatMap(id -> {
|
||||
Set<Long> chain = new LinkedHashSet<>();
|
||||
Long current = id;
|
||||
for (int depth = 0; current != null && current > 0 && depth < 5 && chain.add(current); depth++) {
|
||||
RoleDO role = self.getRoleFromCache(current);
|
||||
if (role == null || role.getParentId() == null || role.getParentId() <= 0) {
|
||||
break;
|
||||
}
|
||||
current = role.getParentId();
|
||||
}
|
||||
return chain.stream();
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得自身的代理对象,解决 AOP 生效问题
|
||||
*
|
||||
@@ -285,4 +324,24 @@ public class RoleServiceImpl implements RoleService {
|
||||
return SpringUtil.getBean(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 parentId 是否为 roleId 的子孙节点,递归最多5次
|
||||
*/
|
||||
public boolean isChildRole(Long parentId, Long id) {
|
||||
return isChildRole(parentId, id, 0);
|
||||
}
|
||||
public boolean isChildRole(Long parentId, Long id, int depth) {
|
||||
if (parentId.equals(id)) {
|
||||
return true;
|
||||
}
|
||||
if (depth >= 5) {
|
||||
return false;
|
||||
}
|
||||
RoleDO parent = roleMapper.selectById(id);
|
||||
if (parent == null || parent.getParentId() == null || parent.getParentId().equals(0L) || parent.getParentId().equals(-1L)) {
|
||||
return false;
|
||||
}
|
||||
return isChildRole(parentId, parent.getParentId(), depth + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CompanyDeptInfo;
|
||||
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.BeanUtils;
|
||||
@@ -39,6 +40,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
@@ -284,9 +286,11 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
@Override
|
||||
public AdminUserDO getUser(Long id) {
|
||||
AdminUserDO adminUserDO = userMapper.selectListByIds(singleton(id)).stream().findFirst().orElseThrow(() -> exception(USER_NOT_EXISTS));
|
||||
// 查询用户关联的部门编号
|
||||
List<UserDeptDO> userDeptList = userDeptService.getValidUserDeptListByUserIds(singleton(id));
|
||||
adminUserDO.setDeptIds(convertSet(userDeptList, UserDeptDO::getDeptId));
|
||||
Set<CompanyDeptInfo> companyDeptInfoListByUserId = deptService.getCompanyDeptInfoListByUserId(id);
|
||||
adminUserDO.setDeptIds(companyDeptInfoListByUserId.stream().map(CompanyDeptInfo::getDeptId).collect(Collectors.toSet()));
|
||||
adminUserDO.setCompanyIds(companyDeptInfoListByUserId.stream().map(CompanyDeptInfo::getCompanyId).collect(Collectors.toSet()));
|
||||
adminUserDO.setCompanyDeptInfos(companyDeptInfoListByUserId);
|
||||
// 设置用户的部门名称集合
|
||||
return adminUserDO;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ xxl:
|
||||
job:
|
||||
enabled: false # 是否开启调度中心,默认为 true 开启
|
||||
admin:
|
||||
addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址
|
||||
addresses: http://172.16.46.63:30082/xxl-job-admin # 调度中心部署跟地址
|
||||
|
||||
--- #################### 服务保障相关配置 ####################
|
||||
|
||||
|
||||
Reference in New Issue
Block a user