Skip to content

Commit 73f880e

Browse files
authored
feat: 角色管理增加授权用户功能 (#93)
1 parent 2b47ed7 commit 73f880e

File tree

8 files changed

+186
-20
lines changed

8 files changed

+186
-20
lines changed

continew-admin-common/src/main/java/top/continew/admin/common/constant/SysConstants.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ public class SysConstants {
3838
* 管理员角色编码
3939
*/
4040
public static final String ADMIN_ROLE_CODE = "admin";
41+
/**
42+
* 超管角色组ID
43+
*/
44+
public static final Long SUPER_ROLE_ID = 1L;
45+
/**
46+
* 超管账号ID
47+
*/
48+
public static final Long SUPER_ADMIN_ID = 1L;
4149

4250
/**
4351
* 顶级部门 ID

continew-admin-system/src/main/java/top/continew/admin/system/service/DeptService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package top.continew.admin.system.service;
1818

19+
import cn.hutool.core.lang.tree.Tree;
1920
import top.continew.admin.system.model.entity.DeptDO;
2021
import top.continew.admin.system.model.query.DeptQuery;
2122
import top.continew.admin.system.model.req.DeptReq;
2223
import top.continew.admin.system.model.resp.DeptResp;
2324
import top.continew.starter.data.mp.service.IService;
25+
import top.continew.starter.extension.crud.model.query.SortQuery;
2426
import top.continew.starter.extension.crud.service.BaseService;
2527

2628
import java.util.List;
@@ -56,4 +58,14 @@ public interface DeptService extends BaseService<DeptResp, DeptResp, DeptQuery,
5658
* @return 部门数量
5759
*/
5860
int countByNames(List<String> deptNames);
61+
62+
/**
63+
* 部门用户树
64+
*
65+
* @param query 部门查询条件
66+
* @param sortQuery 排序条件
67+
* @param isSimple 是否只返回简单部门树
68+
* @return 部门数量
69+
*/
70+
List<Tree<String>> treeWithUsers(DeptQuery query, SortQuery sortQuery, boolean isSimple);
5971
}

continew-admin-system/src/main/java/top/continew/admin/system/service/UserRoleService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package top.continew.admin.system.service;
1818

19+
import top.continew.admin.system.model.entity.UserDO;
1920
import top.continew.admin.system.model.entity.UserRoleDO;
2021

2122
import java.util.List;
@@ -37,6 +38,14 @@ public interface UserRoleService {
3738
*/
3839
boolean add(List<Long> roleIds, Long userId);
3940

41+
/**
42+
* 关联用户
43+
*
44+
* @param roleId 角色id
45+
* @param userIds 用户id列表
46+
* @return 是否新增成功(true:成功;false:无变更/失败)
47+
*/
48+
boolean bindUserIds(Long roleId,List<Long> userIds);
4049
/**
4150
* 根据用户 ID 删除
4251
*
@@ -51,6 +60,8 @@ public interface UserRoleService {
5160
*/
5261
void saveBatch(List<UserRoleDO> list);
5362

63+
64+
5465
/**
5566
* 根据用户 ID 查询
5667
*
@@ -74,4 +85,5 @@ public interface UserRoleService {
7485
* @return 是否已关联(true:已关联;false:未关联)
7586
*/
7687
boolean isRoleIdExists(List<Long> roleIds);
88+
7789
}

continew-admin-system/src/main/java/top/continew/admin/system/service/impl/DeptServiceImpl.java

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
package top.continew.admin.system.service.impl;
1818

1919
import cn.hutool.core.collection.CollUtil;
20+
import cn.hutool.core.lang.tree.Tree;
21+
import cn.hutool.core.lang.tree.TreeNodeConfig;
22+
import cn.hutool.core.lang.tree.TreeUtil;
23+
import cn.hutool.core.text.CharSequenceUtil;
2024
import cn.hutool.core.util.ObjectUtil;
25+
import cn.hutool.core.util.ReflectUtil;
2126
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
2227
import jakarta.annotation.Resource;
2328
import lombok.RequiredArgsConstructor;
@@ -26,21 +31,26 @@
2631
import top.continew.admin.system.mapper.DeptMapper;
2732
import top.continew.admin.system.model.entity.DeptDO;
2833
import top.continew.admin.system.model.query.DeptQuery;
34+
import top.continew.admin.system.model.query.UserQuery;
2935
import top.continew.admin.system.model.req.DeptReq;
3036
import top.continew.admin.system.model.resp.DeptResp;
37+
import top.continew.admin.system.model.resp.UserResp;
3138
import top.continew.admin.system.service.DeptService;
3239
import top.continew.admin.system.service.RoleDeptService;
3340
import top.continew.admin.system.service.UserService;
41+
import top.continew.starter.core.util.ReflectUtils;
3442
import top.continew.starter.core.util.validate.CheckUtils;
3543
import top.continew.starter.data.core.enums.DatabaseType;
3644
import top.continew.starter.data.core.util.MetaUtils;
45+
import top.continew.starter.extension.crud.annotation.TreeField;
46+
import top.continew.starter.extension.crud.model.query.SortQuery;
3747
import top.continew.starter.extension.crud.service.impl.BaseServiceImpl;
48+
import top.continew.starter.extension.crud.util.TreeUtils;
3849

3950
import javax.sql.DataSource;
40-
import java.util.ArrayList;
41-
import java.util.Collections;
42-
import java.util.List;
43-
import java.util.Optional;
51+
import java.lang.reflect.Field;
52+
import java.util.*;
53+
import java.util.stream.Collectors;
4454

4555
/**
4656
* 部门业务实现
@@ -80,6 +90,71 @@ public int countByNames(List<String> deptNames) {
8090
return (int)this.count(Wrappers.<DeptDO>lambdaQuery().in(DeptDO::getName, deptNames));
8191
}
8292

93+
@Override
94+
public List<Tree<String>> treeWithUsers(DeptQuery query, SortQuery sortQuery, boolean isSimple) {
95+
List<DeptResp> list = this.list(query, sortQuery);
96+
if (CollUtil.isEmpty(list)) {
97+
return new ArrayList<>(0);
98+
} else {
99+
TreeNodeConfig treeNodeConfig = TreeUtils.DEFAULT_CONFIG;
100+
TreeField treeField = this.getListClass().getDeclaredAnnotation(TreeField.class);
101+
if (!isSimple) {
102+
treeNodeConfig = TreeUtils.genTreeNodeConfig(treeField);
103+
}
104+
105+
// 创建一个部门ID到用户的映射
106+
UserQuery userQuery = new UserQuery();
107+
userQuery.setStatus(DisEnableStatusEnum.ENABLE);
108+
Map<Long, List<UserResp>> userMap = userService.list(userQuery, null).stream()
109+
.collect(Collectors.groupingBy(UserResp::getDeptId));
110+
111+
String rootId = "dept_0";
112+
113+
return TreeUtil.build(list, rootId, treeNodeConfig, (node, tree) -> {
114+
Long departmentId = ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.value()), new Object[0]);
115+
String uniqueDeptId = "dept_" + departmentId;
116+
tree.setId(uniqueDeptId);
117+
Long parentId = ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.parentIdKey()), new Object[0]);
118+
tree.setParentId(parentId != null ? "dept_" + parentId : null);
119+
tree.setName(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.nameKey()), new Object[0]));
120+
tree.setWeight(ReflectUtil.invoke(node, CharSequenceUtil.genGetter(treeField.weightKey()), new Object[0]));
121+
tree.putExtra("origId", departmentId);
122+
tree.putExtra("isUser", false);
123+
124+
// 添加用户信息到树节点
125+
if (userMap.containsKey(departmentId)) {
126+
List<UserResp> userList = userMap.get(departmentId);
127+
List<Tree<String>> userTrees = userList.stream()
128+
.map(user -> {
129+
Tree<String> userTree = new Tree<>();
130+
String uniqueUserId = "user_" + user.getId();
131+
String userAliasName = user.getUsername() + "(" + user.getNickname() + ")";
132+
userTree.setId(uniqueUserId);
133+
userTree.setParentId(uniqueDeptId);
134+
userTree.setName(userAliasName);
135+
userTree.setWeight(0);
136+
userTree.putExtra("origId", user.getId()); // 添加原始用户ID
137+
userTree.putExtra("isUser", true); // 添加原始用户ID
138+
return userTree;
139+
})
140+
.collect(Collectors.toList());
141+
tree.setChildren(userTrees);
142+
}
143+
144+
if (!isSimple) {
145+
List<Field> fieldList = ReflectUtils.getNonStaticFields(this.getListClass());
146+
fieldList.removeIf((f) -> {
147+
return CharSequenceUtil.equalsAnyIgnoreCase(f.getName(), new CharSequence[]{treeField.value(), treeField.parentIdKey(), treeField.nameKey(), treeField.weightKey(), treeField.childrenKey()});
148+
});
149+
fieldList.forEach((f) -> {
150+
tree.putExtra(f.getName(), ReflectUtil.invoke(node, CharSequenceUtil.genGetter(f.getName()), new Object[0]));
151+
});
152+
}
153+
});
154+
}
155+
}
156+
157+
83158
@Override
84159
protected void beforeAdd(DeptReq req) {
85160
String name = req.getName();
@@ -105,13 +180,13 @@ protected void beforeUpdate(DeptReq req, Long id) {
105180
if (ObjectUtil.notEqual(newStatus, oldDept.getStatus())) {
106181
List<DeptDO> children = this.listChildren(id);
107182
long enabledChildrenCount = children.stream()
108-
.filter(d -> DisEnableStatusEnum.ENABLE.equals(d.getStatus()))
109-
.count();
183+
.filter(d -> DisEnableStatusEnum.ENABLE.equals(d.getStatus()))
184+
.count();
110185
CheckUtils.throwIf(DisEnableStatusEnum.DISABLE
111-
.equals(newStatus) && enabledChildrenCount > 0, "禁用 [{}] 前,请先禁用其所有下级部门", oldName);
186+
.equals(newStatus) && enabledChildrenCount > 0, "禁用 [{}] 前,请先禁用其所有下级部门", oldName);
112187
DeptDO oldParentDept = this.getByParentId(oldParentId);
113188
CheckUtils.throwIf(DisEnableStatusEnum.ENABLE.equals(newStatus) && DisEnableStatusEnum.DISABLE
114-
.equals(oldParentDept.getStatus()), "启用 [{}] 前,请先启用其所有上级部门", oldName);
189+
.equals(oldParentDept.getStatus()), "启用 [{}] 前,请先启用其所有上级部门", oldName);
115190
}
116191
// 变更上级部门
117192
if (ObjectUtil.notEqual(req.getParentId(), oldParentId)) {
@@ -126,12 +201,12 @@ protected void beforeUpdate(DeptReq req, Long id) {
126201
@Override
127202
protected void beforeDelete(List<Long> ids) {
128203
List<DeptDO> list = baseMapper.lambdaQuery()
129-
.select(DeptDO::getName, DeptDO::getIsSystem)
130-
.in(DeptDO::getId, ids)
131-
.list();
204+
.select(DeptDO::getName, DeptDO::getIsSystem)
205+
.in(DeptDO::getId, ids)
206+
.list();
132207
Optional<DeptDO> isSystemData = list.stream().filter(DeptDO::getIsSystem).findFirst();
133208
CheckUtils.throwIf(isSystemData::isPresent, "所选部门 [{}] 是系统内置部门,不允许删除", isSystemData.orElseGet(DeptDO::new)
134-
.getName());
209+
.getName());
135210
CheckUtils.throwIf(this.countChildren(ids) > 0, "所选部门存在下级部门,不允许删除");
136211
CheckUtils.throwIf(userService.countByDeptIds(ids) > 0, "所选部门存在用户关联,请解除关联后重试");
137212
// 删除角色和部门关联
@@ -148,10 +223,10 @@ protected void beforeDelete(List<Long> ids) {
148223
*/
149224
private boolean isNameExists(String name, Long parentId, Long id) {
150225
return baseMapper.lambdaQuery()
151-
.eq(DeptDO::getName, name)
152-
.eq(DeptDO::getParentId, parentId)
153-
.ne(null != id, DeptDO::getId, id)
154-
.exists();
226+
.eq(DeptDO::getName, name)
227+
.eq(DeptDO::getParentId, parentId)
228+
.ne(null != id, DeptDO::getId, id)
229+
.exists();
155230
}
156231

157232
/**
@@ -189,8 +264,8 @@ private Long countChildren(List<Long> ids) {
189264
}
190265
DatabaseType databaseType = MetaUtils.getDatabaseTypeOrDefault(dataSource, DatabaseType.MYSQL);
191266
return ids.stream()
192-
.mapToLong(id -> baseMapper.lambdaQuery().apply(databaseType.findInSet(id, "ancestors")).count())
193-
.sum();
267+
.mapToLong(id -> baseMapper.lambdaQuery().apply(databaseType.findInSet(id, "ancestors")).count())
268+
.sum();
194269
}
195270

196271
/**

continew-admin-system/src/main/java/top/continew/admin/system/service/impl/RoleServiceImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import top.continew.admin.common.enums.DataScopeEnum;
3737
import top.continew.admin.system.mapper.RoleMapper;
3838
import top.continew.admin.system.model.entity.RoleDO;
39+
import top.continew.admin.system.model.entity.UserDO;
3940
import top.continew.admin.system.model.query.RoleQuery;
4041
import top.continew.admin.system.model.req.RoleReq;
4142
import top.continew.admin.system.model.resp.MenuResp;
@@ -198,6 +199,8 @@ public int countByNames(List<String> roleNames) {
198199
return (int)this.count(Wrappers.<RoleDO>lambdaQuery().in(RoleDO::getName, roleNames));
199200
}
200201

202+
203+
201204
/**
202205
* 名称是否存在
203206
*

continew-admin-system/src/main/java/top/continew/admin/system/service/impl/UserRoleServiceImpl.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import org.springframework.stereotype.Service;
2424
import org.springframework.transaction.annotation.Transactional;
2525
import top.continew.admin.common.constant.ContainerConstants;
26+
import top.continew.admin.common.constant.SysConstants;
2627
import top.continew.admin.system.mapper.UserRoleMapper;
2728
import top.continew.admin.system.model.entity.UserRoleDO;
2829
import top.continew.admin.system.service.UserRoleService;
30+
import top.continew.starter.core.util.validate.CheckUtils;
2931

3032
import java.util.List;
3133

@@ -61,7 +63,28 @@ public boolean add(List<Long> roleIds, Long userId) {
6163
List<UserRoleDO> userRoleList = roleIds.stream().map(roleId -> new UserRoleDO(userId, roleId)).toList();
6264
return baseMapper.insertBatch(userRoleList);
6365
}
64-
66+
@Override
67+
public boolean bindUserIds(Long roleId, List<Long> userIds) {
68+
// 检查是否有变更
69+
List<Long> oldRoleIdList = baseMapper.lambdaQuery()
70+
.select(UserRoleDO::getUserId)
71+
.eq(UserRoleDO::getRoleId, roleId)
72+
.list()
73+
.stream()
74+
.map(UserRoleDO::getRoleId)
75+
.toList();
76+
if (CollUtil.isEmpty(CollUtil.disjunction(userIds, oldRoleIdList))) {
77+
return false;
78+
}
79+
if (SysConstants.SUPER_ROLE_ID.equals(roleId) && !userIds.contains(SysConstants.SUPER_ADMIN_ID)){
80+
CheckUtils.throwIf(true,"不能移除管理员默认超管角色组");
81+
}
82+
// 删除原有关联
83+
baseMapper.lambdaUpdate().eq(UserRoleDO::getRoleId, roleId).remove();
84+
// 保存最新关联
85+
List<UserRoleDO> userRoleList = userIds.stream().map(userId -> new UserRoleDO(userId, roleId)).toList();
86+
return baseMapper.insertBatch(userRoleList);
87+
}
6588
@Override
6689
public void deleteByUserIds(List<Long> userIds) {
6790
baseMapper.lambdaUpdate().in(UserRoleDO::getUserId, userIds).remove();
@@ -72,6 +95,8 @@ public void saveBatch(List<UserRoleDO> list) {
7295
baseMapper.insert(list);
7396
}
7497

98+
99+
75100
@Override
76101
@ContainerMethod(namespace = ContainerConstants.USER_ROLE_ID_LIST, type = MappingType.ORDER_OF_KEYS)
77102
public List<Long> listRoleIdByUserId(Long userId) {

continew-admin-webapi/src/main/java/top/continew/admin/controller/common/CommonController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ public List<Tree<Long>> listDeptTree(DeptQuery query, SortQuery sortQuery) {
8080
return deptService.tree(query, sortQuery, true);
8181
}
8282

83+
@Operation(summary = "查询部门用户树", description = "查询树结构的部门列表")
84+
@GetMapping("/tree/deptWithUsers")
85+
public List<Tree<String>> listDeptWithUsersTree(DeptQuery query, SortQuery sortQuery) {
86+
return deptService.treeWithUsers(query, sortQuery, true);
87+
}
88+
8389
@Operation(summary = "查询菜单树", description = "查询树结构的菜单列表")
8490
@GetMapping("/tree/menu")
8591
public List<Tree<Long>> listMenuTree(MenuQuery query, SortQuery sortQuery) {

continew-admin-webapi/src/main/java/top/continew/admin/controller/system/RoleController.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,27 @@
1616

1717
package top.continew.admin.controller.system;
1818

19+
import cn.dev33.satoken.annotation.SaCheckPermission;
20+
import cn.hutool.core.lang.tree.Tree;
21+
import io.swagger.v3.oas.annotations.Operation;
1922
import io.swagger.v3.oas.annotations.tags.Tag;
2023

21-
import org.springframework.web.bind.annotation.RestController;
24+
import lombok.RequiredArgsConstructor;
25+
import org.springframework.web.bind.annotation.*;
2226

27+
import top.continew.admin.system.model.query.DeptQuery;
2328
import top.continew.admin.system.model.query.RoleQuery;
2429
import top.continew.admin.system.model.req.RoleReq;
2530
import top.continew.admin.system.model.resp.RoleDetailResp;
2631
import top.continew.admin.system.model.resp.RoleResp;
2732
import top.continew.admin.system.service.RoleService;
33+
import top.continew.admin.system.service.UserRoleService;
2834
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
2935
import top.continew.starter.extension.crud.controller.BaseController;
3036
import top.continew.starter.extension.crud.enums.Api;
37+
import top.continew.starter.extension.crud.model.query.SortQuery;
38+
39+
import java.util.List;
3140

3241
/**
3342
* 角色管理 API
@@ -37,6 +46,22 @@
3746
*/
3847
@Tag(name = "角色管理 API")
3948
@RestController
49+
@RequiredArgsConstructor
4050
@CrudRequestMapping(value = "/system/role", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE})
4151
public class RoleController extends BaseController<RoleService, RoleResp, RoleDetailResp, RoleQuery, RoleReq> {
52+
53+
private final UserRoleService userRoleService;
54+
55+
@Operation(summary = "查询角色关联用户", description = "查询角色组绑定的关联用户")
56+
@GetMapping("/listRoleUsers/{id}")
57+
public List<Long> listUsers(@PathVariable("id") Long roleId) {
58+
return userRoleService.listUserIdByRoleId(roleId);
59+
}
60+
61+
@Operation(summary = "关联用户", description = "批量关联用户")
62+
@SaCheckPermission("system:role:bindUsers")
63+
@PostMapping("/bindUsers/{id}")
64+
public void bindUsers(@PathVariable("id") Long roleId,@RequestBody List<Long> userIds) {
65+
userRoleService.bindUserIds(roleId, userIds);
66+
}
4267
}

0 commit comments

Comments
 (0)