Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:角色管理增加关联用户功能 #93

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ public class SysConstants {
* 管理员角色编码
*/
public static final String ADMIN_ROLE_CODE = "admin";
/**
* 超管角色组ID
*/
public static final Long SUPER_ROLE_ID = 1L;
/**
* 超管账号ID
*/
public static final Long SUPER_ADMIN_ID = 1L;

/**
* 顶级部门 ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 删除
*
Expand All @@ -51,6 +60,8 @@ public interface UserRoleService {
*/
void saveBatch(List<UserRoleDO> list);



/**
* 根据用户 ID 查询
*
Expand All @@ -74,4 +85,5 @@ public interface UserRoleService {
* @return 是否已关联(true:已关联;false:未关联)
*/
boolean isRoleIdExists(List<Long> roleIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,21 +31,26 @@
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;

/**
* 部门业务实现
Expand Down Expand Up @@ -80,6 +90,71 @@ public int countByNames(List<String> deptNames) {
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();
Expand All @@ -105,13 +180,13 @@ protected void beforeUpdate(DeptReq req, Long id) {
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)) {
Expand All @@ -126,12 +201,12 @@ protected void beforeUpdate(DeptReq req, Long id) {
@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, "所选部门存在用户关联,请解除关联后重试");
// 删除角色和部门关联
Expand All @@ -148,10 +223,10 @@ protected void beforeDelete(List<Long> ids) {
*/
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();
}

/**
Expand Down Expand Up @@ -189,8 +264,8 @@ private Long countChildren(List<Long> ids) {
}
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();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
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;
Expand Down Expand Up @@ -198,6 +199,8 @@ public int countByNames(List<String> roleNames) {
return (int)this.count(Wrappers.<RoleDO>lambdaQuery().in(RoleDO::getName, roleNames));
}



/**
* 名称是否存在
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
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;

Expand Down Expand Up @@ -61,7 +63,28 @@ public boolean add(List<Long> roleIds, Long userId) {
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();
Expand All @@ -72,6 +95,8 @@ public void saveBatch(List<UserRoleDO> list) {
baseMapper.insert(list);
}



@Override
@ContainerMethod(namespace = ContainerConstants.USER_ROLE_ID_LIST, type = MappingType.ORDER_OF_KEYS)
public List<Long> listRoleIdByUserId(Long userId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ public List<Tree<Long>> listDeptTree(DeptQuery query, SortQuery sortQuery) {
return deptService.tree(query, sortQuery, true);
}

@Operation(summary = "查询部门用户树", description = "查询树结构的部门列表")
@GetMapping("/tree/deptWithUsers")
public List<Tree<String>> listDeptWithUsersTree(DeptQuery query, SortQuery sortQuery) {
return deptService.treeWithUsers(query, sortQuery, true);
}

@Operation(summary = "查询菜单树", description = "查询树结构的菜单列表")
@GetMapping("/tree/menu")
public List<Tree<Long>> listMenuTree(MenuQuery query, SortQuery sortQuery) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,27 @@

package top.continew.admin.controller.system;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;

import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import top.continew.admin.system.model.query.DeptQuery;
import top.continew.admin.system.model.query.RoleQuery;
import top.continew.admin.system.model.req.RoleReq;
import top.continew.admin.system.model.resp.RoleDetailResp;
import top.continew.admin.system.model.resp.RoleResp;
import top.continew.admin.system.service.RoleService;
import top.continew.admin.system.service.UserRoleService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.controller.BaseController;
import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.extension.crud.model.query.SortQuery;

import java.util.List;

/**
* 角色管理 API
Expand All @@ -37,6 +46,22 @@
*/
@Tag(name = "角色管理 API")
@RestController
@RequiredArgsConstructor
@CrudRequestMapping(value = "/system/role", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
public class RoleController extends BaseController<RoleService, RoleResp, RoleDetailResp, RoleQuery, RoleReq> {

private final UserRoleService userRoleService;

@Operation(summary = "查询角色关联用户", description = "查询角色组绑定的关联用户")
@GetMapping("/listRoleUsers/{id}")
public List<Long> listUsers(@PathVariable("id") Long roleId) {
return userRoleService.listUserIdByRoleId(roleId);
}

@Operation(summary = "关联用户", description = "批量关联用户")
@SaCheckPermission("system:role:bindUsers")
@PostMapping("/bindUsers/{id}")
public void bindUsers(@PathVariable("id") Long roleId,@RequestBody List<Long> userIds) {
userRoleService.bindUserIds(roleId, userIds);
}
}
Loading