mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 22:57:17 +08:00 
			
		
		
		
	feat: 角色管理增加授权用户功能 (#93)
This commit is contained in:
		| @@ -16,11 +16,13 @@ | ||||
|  | ||||
| package top.continew.admin.system.service; | ||||
|  | ||||
| import cn.hutool.core.lang.tree.Tree; | ||||
| import top.continew.admin.system.model.entity.DeptDO; | ||||
| import top.continew.admin.system.model.query.DeptQuery; | ||||
| import top.continew.admin.system.model.req.DeptReq; | ||||
| import top.continew.admin.system.model.resp.DeptResp; | ||||
| import top.continew.starter.data.mp.service.IService; | ||||
| import top.continew.starter.extension.crud.model.query.SortQuery; | ||||
| import top.continew.starter.extension.crud.service.BaseService; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -56,4 +58,14 @@ public interface DeptService extends BaseService<DeptResp, DeptResp, DeptQuery, | ||||
|      * @return 部门数量 | ||||
|      */ | ||||
|     int countByNames(List<String> deptNames); | ||||
|  | ||||
|     /** | ||||
|      * 部门用户树 | ||||
|      * | ||||
|      * @param query 部门查询条件 | ||||
|      * @param sortQuery 排序条件 | ||||
|      * @param isSimple 是否只返回简单部门树 | ||||
|      * @return 部门数量 | ||||
|      */ | ||||
|     List<Tree<String>> treeWithUsers(DeptQuery query, SortQuery sortQuery, boolean isSimple); | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
|  | ||||
| package top.continew.admin.system.service; | ||||
|  | ||||
| import top.continew.admin.system.model.entity.UserDO; | ||||
| import top.continew.admin.system.model.entity.UserRoleDO; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -37,6 +38,14 @@ public interface UserRoleService { | ||||
|      */ | ||||
|     boolean add(List<Long> roleIds, Long userId); | ||||
|  | ||||
|     /** | ||||
|      * 关联用户 | ||||
|      * | ||||
|      * @param roleId 角色id | ||||
|      * @param userIds 用户id列表 | ||||
|      * @return 是否新增成功(true:成功;false:无变更/失败) | ||||
|      */ | ||||
|     boolean bindUserIds(Long roleId,List<Long> userIds); | ||||
|     /** | ||||
|      * 根据用户 ID 删除 | ||||
|      * | ||||
| @@ -51,6 +60,8 @@ public interface UserRoleService { | ||||
|      */ | ||||
|     void saveBatch(List<UserRoleDO> list); | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 根据用户 ID 查询 | ||||
|      * | ||||
| @@ -74,4 +85,5 @@ public interface UserRoleService { | ||||
|      * @return 是否已关联(true:已关联;false:未关联) | ||||
|      */ | ||||
|     boolean isRoleIdExists(List<Long> roleIds); | ||||
|  | ||||
| } | ||||
| @@ -17,7 +17,12 @@ | ||||
| package top.continew.admin.system.service.impl; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.lang.tree.Tree; | ||||
| import cn.hutool.core.lang.tree.TreeNodeConfig; | ||||
| import cn.hutool.core.lang.tree.TreeUtil; | ||||
| import cn.hutool.core.text.CharSequenceUtil; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import cn.hutool.core.util.ReflectUtil; | ||||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||
| import jakarta.annotation.Resource; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| @@ -26,21 +31,26 @@ import top.continew.admin.common.enums.DisEnableStatusEnum; | ||||
| import top.continew.admin.system.mapper.DeptMapper; | ||||
| import top.continew.admin.system.model.entity.DeptDO; | ||||
| import top.continew.admin.system.model.query.DeptQuery; | ||||
| import top.continew.admin.system.model.query.UserQuery; | ||||
| import top.continew.admin.system.model.req.DeptReq; | ||||
| import top.continew.admin.system.model.resp.DeptResp; | ||||
| import top.continew.admin.system.model.resp.UserResp; | ||||
| import top.continew.admin.system.service.DeptService; | ||||
| import top.continew.admin.system.service.RoleDeptService; | ||||
| import top.continew.admin.system.service.UserService; | ||||
| import top.continew.starter.core.util.ReflectUtils; | ||||
| import top.continew.starter.core.util.validate.CheckUtils; | ||||
| import top.continew.starter.data.core.enums.DatabaseType; | ||||
| import top.continew.starter.data.core.util.MetaUtils; | ||||
| import top.continew.starter.extension.crud.annotation.TreeField; | ||||
| import top.continew.starter.extension.crud.model.query.SortQuery; | ||||
| import top.continew.starter.extension.crud.service.impl.BaseServiceImpl; | ||||
| import top.continew.starter.extension.crud.util.TreeUtils; | ||||
|  | ||||
| import javax.sql.DataSource; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| import java.lang.reflect.Field; | ||||
| import java.util.*; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * 部门业务实现 | ||||
| @@ -80,6 +90,71 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes | ||||
|         return (int)this.count(Wrappers.<DeptDO>lambdaQuery().in(DeptDO::getName, deptNames)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<Tree<String>> treeWithUsers(DeptQuery query, SortQuery sortQuery, boolean isSimple) { | ||||
|         List<DeptResp> list = this.list(query, sortQuery); | ||||
|         if (CollUtil.isEmpty(list)) { | ||||
|             return new ArrayList<>(0); | ||||
|         } else { | ||||
|             TreeNodeConfig treeNodeConfig = TreeUtils.DEFAULT_CONFIG; | ||||
|             TreeField treeField = this.getListClass().getDeclaredAnnotation(TreeField.class); | ||||
|             if (!isSimple) { | ||||
|                 treeNodeConfig = TreeUtils.genTreeNodeConfig(treeField); | ||||
|             } | ||||
|  | ||||
|             // 创建一个部门ID到用户的映射 | ||||
|             UserQuery userQuery = new UserQuery(); | ||||
|             userQuery.setStatus(DisEnableStatusEnum.ENABLE); | ||||
|             Map<Long, List<UserResp>> userMap = userService.list(userQuery, null).stream() | ||||
|                     .collect(Collectors.groupingBy(UserResp::getDeptId)); | ||||
|  | ||||
|             String rootId = "dept_0"; | ||||
|  | ||||
|             return TreeUtil.build(list, rootId, treeNodeConfig, (node, tree) -> { | ||||
|                 Long departmentId = ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value()), new Object[0]); | ||||
|                 String uniqueDeptId = "dept_" + departmentId; | ||||
|                 tree.setId(uniqueDeptId); | ||||
|                 Long parentId =  ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey()), new Object[0]); | ||||
|                 tree.setParentId(parentId != null ? "dept_" + parentId : null); | ||||
|                 tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey()), new Object[0])); | ||||
|                 tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey()), new Object[0])); | ||||
|                 tree.putExtra("origId", departmentId); | ||||
|                 tree.putExtra("isUser", false); | ||||
|  | ||||
|                 // 添加用户信息到树节点 | ||||
|                 if (userMap.containsKey(departmentId)) { | ||||
|                     List<UserResp> userList = userMap.get(departmentId); | ||||
|                     List<Tree<String>> userTrees = userList.stream() | ||||
|                             .map(user -> { | ||||
|                                 Tree<String> userTree = new Tree<>(); | ||||
|                                 String uniqueUserId = "user_" + user.getId(); | ||||
|                                 String userAliasName = user.getUsername() + "(" + user.getNickname() + ")"; | ||||
|                                 userTree.setId(uniqueUserId); | ||||
|                                 userTree.setParentId(uniqueDeptId); | ||||
|                                 userTree.setName(userAliasName); | ||||
|                                 userTree.setWeight(0); | ||||
|                                 userTree.putExtra("origId", user.getId()); // 添加原始用户ID | ||||
|                                 userTree.putExtra("isUser", true); // 添加原始用户ID | ||||
|                                 return userTree; | ||||
|                             }) | ||||
|                             .collect(Collectors.toList()); | ||||
|                     tree.setChildren(userTrees); | ||||
|                 } | ||||
|  | ||||
|                 if (!isSimple) { | ||||
|                     List<Field> fieldList = ReflectUtils.getNonStaticFields(this.getListClass()); | ||||
|                     fieldList.removeIf((f) -> { | ||||
|                         return CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), new CharSequence[]{treeField.value(), treeField.parentIdKey(), treeField.nameKey(), treeField.weightKey(), treeField.childrenKey()}); | ||||
|                     }); | ||||
|                     fieldList.forEach((f) -> { | ||||
|                         tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f.getName()), new Object[0])); | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void beforeAdd(DeptReq req) { | ||||
|         String name = req.getName(); | ||||
| @@ -105,13 +180,13 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes | ||||
|         if (ObjectUtil.notEqual(newStatus, oldDept.getStatus())) { | ||||
|             List<DeptDO> children = this.listChildren(id); | ||||
|             long enabledChildrenCount = children.stream() | ||||
|                 .filter(d -> DisEnableStatusEnum.ENABLE.equals(d.getStatus())) | ||||
|                 .count(); | ||||
|                     .filter(d -> DisEnableStatusEnum.ENABLE.equals(d.getStatus())) | ||||
|                     .count(); | ||||
|             CheckUtils.throwIf(DisEnableStatusEnum.DISABLE | ||||
|                 .equals(newStatus) && enabledChildrenCount > 0, "禁用 [{}] 前,请先禁用其所有下级部门", oldName); | ||||
|                     .equals(newStatus) && enabledChildrenCount > 0, "禁用 [{}] 前,请先禁用其所有下级部门", oldName); | ||||
|             DeptDO oldParentDept = this.getByParentId(oldParentId); | ||||
|             CheckUtils.throwIf(DisEnableStatusEnum.ENABLE.equals(newStatus) && DisEnableStatusEnum.DISABLE | ||||
|                 .equals(oldParentDept.getStatus()), "启用 [{}] 前,请先启用其所有上级部门", oldName); | ||||
|                     .equals(oldParentDept.getStatus()), "启用 [{}] 前,请先启用其所有上级部门", oldName); | ||||
|         } | ||||
|         // 变更上级部门 | ||||
|         if (ObjectUtil.notEqual(req.getParentId(), oldParentId)) { | ||||
| @@ -126,12 +201,12 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes | ||||
|     @Override | ||||
|     protected void beforeDelete(List<Long> ids) { | ||||
|         List<DeptDO> list = baseMapper.lambdaQuery() | ||||
|             .select(DeptDO::getName, DeptDO::getIsSystem) | ||||
|             .in(DeptDO::getId, ids) | ||||
|             .list(); | ||||
|                 .select(DeptDO::getName, DeptDO::getIsSystem) | ||||
|                 .in(DeptDO::getId, ids) | ||||
|                 .list(); | ||||
|         Optional<DeptDO> isSystemData = list.stream().filter(DeptDO::getIsSystem).findFirst(); | ||||
|         CheckUtils.throwIf(isSystemData::isPresent, "所选部门 [{}] 是系统内置部门,不允许删除", isSystemData.orElseGet(DeptDO::new) | ||||
|             .getName()); | ||||
|                 .getName()); | ||||
|         CheckUtils.throwIf(this.countChildren(ids) > 0, "所选部门存在下级部门,不允许删除"); | ||||
|         CheckUtils.throwIf(userService.countByDeptIds(ids) > 0, "所选部门存在用户关联,请解除关联后重试"); | ||||
|         // 删除角色和部门关联 | ||||
| @@ -148,10 +223,10 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes | ||||
|      */ | ||||
|     private boolean isNameExists(String name, Long parentId, Long id) { | ||||
|         return baseMapper.lambdaQuery() | ||||
|             .eq(DeptDO::getName, name) | ||||
|             .eq(DeptDO::getParentId, parentId) | ||||
|             .ne(null != id, DeptDO::getId, id) | ||||
|             .exists(); | ||||
|                 .eq(DeptDO::getName, name) | ||||
|                 .eq(DeptDO::getParentId, parentId) | ||||
|                 .ne(null != id, DeptDO::getId, id) | ||||
|                 .exists(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -189,8 +264,8 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes | ||||
|         } | ||||
|         DatabaseType databaseType = MetaUtils.getDatabaseTypeOrDefault(dataSource, DatabaseType.MYSQL); | ||||
|         return ids.stream() | ||||
|             .mapToLong(id -> baseMapper.lambdaQuery().apply(databaseType.findInSet(id, "ancestors")).count()) | ||||
|             .sum(); | ||||
|                 .mapToLong(id -> baseMapper.lambdaQuery().apply(databaseType.findInSet(id, "ancestors")).count()) | ||||
|                 .sum(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -36,6 +36,7 @@ import top.continew.admin.common.context.UserContextHolder; | ||||
| import top.continew.admin.common.enums.DataScopeEnum; | ||||
| import top.continew.admin.system.mapper.RoleMapper; | ||||
| import top.continew.admin.system.model.entity.RoleDO; | ||||
| import top.continew.admin.system.model.entity.UserDO; | ||||
| import top.continew.admin.system.model.query.RoleQuery; | ||||
| import top.continew.admin.system.model.req.RoleReq; | ||||
| import top.continew.admin.system.model.resp.MenuResp; | ||||
| @@ -198,6 +199,8 @@ public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, RoleDO, RoleRes | ||||
|         return (int)this.count(Wrappers.<RoleDO>lambdaQuery().in(RoleDO::getName, roleNames)); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 名称是否存在 | ||||
|      * | ||||
|   | ||||
| @@ -23,9 +23,11 @@ import lombok.RequiredArgsConstructor; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| import top.continew.admin.common.constant.ContainerConstants; | ||||
| import top.continew.admin.common.constant.SysConstants; | ||||
| import top.continew.admin.system.mapper.UserRoleMapper; | ||||
| import top.continew.admin.system.model.entity.UserRoleDO; | ||||
| import top.continew.admin.system.service.UserRoleService; | ||||
| import top.continew.starter.core.util.validate.CheckUtils; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @@ -61,7 +63,28 @@ public class UserRoleServiceImpl implements UserRoleService { | ||||
|         List<UserRoleDO> userRoleList = roleIds.stream().map(roleId -> new UserRoleDO(userId, roleId)).toList(); | ||||
|         return baseMapper.insertBatch(userRoleList); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean bindUserIds(Long roleId, List<Long> userIds) { | ||||
|         // 检查是否有变更 | ||||
|         List<Long> oldRoleIdList = baseMapper.lambdaQuery() | ||||
|                 .select(UserRoleDO::getUserId) | ||||
|                 .eq(UserRoleDO::getRoleId, roleId) | ||||
|                 .list() | ||||
|                 .stream() | ||||
|                 .map(UserRoleDO::getRoleId) | ||||
|                 .toList(); | ||||
|         if (CollUtil.isEmpty(CollUtil.disjunction(userIds, oldRoleIdList))) { | ||||
|             return false; | ||||
|         } | ||||
|         if (SysConstants.SUPER_ROLE_ID.equals(roleId) && !userIds.contains(SysConstants.SUPER_ADMIN_ID)){ | ||||
|             CheckUtils.throwIf(true,"不能移除管理员默认超管角色组"); | ||||
|         } | ||||
|         // 删除原有关联 | ||||
|         baseMapper.lambdaUpdate().eq(UserRoleDO::getRoleId, roleId).remove(); | ||||
|         // 保存最新关联 | ||||
|         List<UserRoleDO> userRoleList = userIds.stream().map(userId -> new UserRoleDO(userId, roleId)).toList(); | ||||
|         return baseMapper.insertBatch(userRoleList); | ||||
|     } | ||||
|     @Override | ||||
|     public void deleteByUserIds(List<Long> userIds) { | ||||
|         baseMapper.lambdaUpdate().in(UserRoleDO::getUserId, userIds).remove(); | ||||
| @@ -72,6 +95,8 @@ public class UserRoleServiceImpl implements UserRoleService { | ||||
|         baseMapper.insert(list); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     @ContainerMethod(namespace = ContainerConstants.USER_ROLE_ID_LIST, type = MappingType.ORDER_OF_KEYS) | ||||
|     public List<Long> listRoleIdByUserId(Long userId) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Wanghy
					Wanghy