feat(dept): SysGroupVo 补 memberCount/memberNames,getTree 回填部门成员数与姓名预览
build / build-push (push) Successful in 2m23s
build / build-push (push) Successful in 2m23s
- SysGroupVo 新增 memberCount(直属成员数)与 memberNames(前 50 个姓名预览) - SysGroupService 新增 fillMemberStats:整棵树只发两次查询(关联表 in + 用户表 in), getTree()/getTree(scope) 均回填,口径同 oapi 部门目录(sys_user_group_rel 按 groupId 计数,不排除转出) - 预览上限 MEMBER_PREVIEW_LIMIT=50,避免大部门把名单塞进 getTree;完整名单走 /api/sysuser/List?groupId=
This commit is contained in:
@@ -20,6 +20,13 @@ public class SysGroupVo {
|
||||
private Integer status;
|
||||
/** 包含子组(2026-10-21):1=部门列表含下级部门 / 0=仅本级;BeanUtils 同名拷贝,null 视为 1 由前端兜底 */
|
||||
private Integer includeChildren;
|
||||
/** 直属成员数(部门表格「人员」列);口径同 oapi 部门目录:sys_user_group_rel 按 groupId 计数,不排除转出。 */
|
||||
private Long memberCount;
|
||||
/**
|
||||
* 直属成员姓名预览,最多 {@code SysGroupService.MEMBER_PREVIEW_LIMIT} 个。<br>
|
||||
* 完整名单不走这里(部门可能上百人),前端点「查看全部」调 /api/sysuser/List?groupId=xxx。
|
||||
*/
|
||||
private List<String> memberNames = new ArrayList<>();
|
||||
/** 子组(递归);默认空列表,避免 JSON 序列化出现 null。 */
|
||||
private List<SysGroupVo> children = new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -63,6 +63,13 @@ public class SysGroupService implements ISysGroupService {
|
||||
/** 开放接口/oapi 写操作无登录态时使用的审计人哨兵值(非真实用户ID),用于兜底 create_user/update_user 的 NOT NULL 约束。 */
|
||||
private static final int SYSTEM_USER_ID = 0;
|
||||
|
||||
/**
|
||||
* 部门表格「人员」列的姓名预览上限。<br>
|
||||
* 表格最多显示 3 个名字 + 计数,tooltip 展示这份预览;部门上百人时不把这些名字塞进 getTree 响应,
|
||||
* 完整名单由前端点「查看全部」走 /api/sysuser/List?groupId=xxx 分页取。
|
||||
*/
|
||||
static final int MEMBER_PREVIEW_LIMIT = 50;
|
||||
|
||||
/**
|
||||
* 层级类型约束:父类型 -> 允许直接创建的子类型集合。
|
||||
* key 为 {@code null} 表示「根节点(教育云中心)」。
|
||||
@@ -363,7 +370,9 @@ public class SysGroupService implements ISysGroupService {
|
||||
Map<Integer, List<SysGroup>> childrenMap = snapshot.getChildrenMap();
|
||||
// 从根(pid=0)开始组装树
|
||||
List<SysGroup> roots = childrenMap.getOrDefault(ROOT_PARENT_ID, new ArrayList<>());
|
||||
return roots.stream().map(r -> buildNode(r, childrenMap)).collect(Collectors.toList());
|
||||
List<SysGroupVo> tree = roots.stream().map(r -> buildNode(r, childrenMap)).collect(Collectors.toList());
|
||||
fillMemberStats(tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -375,7 +384,83 @@ public class SysGroupService implements ISysGroupService {
|
||||
if (scope == null || scope.isSuper()) {
|
||||
return getTree();
|
||||
}
|
||||
return buildTrimmedTree(scope, snapshot.getAll(), false);
|
||||
List<SysGroupVo> tree = buildTrimmedTree(scope, snapshot.getAll(), false);
|
||||
fillMemberStats(tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* 给树节点补直属成员数与前 N 个姓名预览(部门表格「人员」列)。<br>
|
||||
* 口径与 oapi 部门目录一致:sys_user_group_rel 按 groupId 计数,不排除转出;
|
||||
* 整棵树只发两次查询(关联表 in + 用户表 in),不受节点数影响。
|
||||
*/
|
||||
private void fillMemberStats(List<SysGroupVo> tree) {
|
||||
List<Integer> groupIds = new ArrayList<>();
|
||||
collectGroupIds(tree, groupIds);
|
||||
if (groupIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<SysUserGroupRel> rels = sysUserGroupRelRepository.findByGroupIdIn(groupIds);
|
||||
if (rels == null || rels.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<Integer, List<Integer>> relByGroup = new HashMap<>();
|
||||
Set<Integer> userIds = new HashSet<>();
|
||||
for (SysUserGroupRel rel : rels) {
|
||||
if (rel.getGroupId() == null || rel.getUserId() == null) {
|
||||
continue;
|
||||
}
|
||||
relByGroup.computeIfAbsent(rel.getGroupId(), k -> new ArrayList<>()).add(rel.getUserId());
|
||||
userIds.add(rel.getUserId());
|
||||
}
|
||||
Map<Integer, String> nameById = new HashMap<>();
|
||||
for (SysUser user : sysUserRepository.findAllById(userIds)) {
|
||||
nameById.put(user.getId(),
|
||||
StringUtils.hasText(user.getRealName()) ? user.getRealName() : user.getAccount());
|
||||
}
|
||||
Map<Integer, SysGroupVo> voById = new HashMap<>();
|
||||
collectVoById(tree, voById);
|
||||
for (Map.Entry<Integer, List<Integer>> entry : relByGroup.entrySet()) {
|
||||
SysGroupVo vo = voById.get(entry.getKey());
|
||||
if (vo == null) {
|
||||
continue;
|
||||
}
|
||||
List<Integer> members = entry.getValue();
|
||||
vo.setMemberCount((long) members.size());
|
||||
List<String> preview = new ArrayList<>();
|
||||
for (Integer uid : members) {
|
||||
if (preview.size() >= MEMBER_PREVIEW_LIMIT) {
|
||||
break;
|
||||
}
|
||||
String name = nameById.get(uid);
|
||||
if (name != null) {
|
||||
preview.add(name);
|
||||
}
|
||||
}
|
||||
vo.setMemberNames(preview);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectGroupIds(List<SysGroupVo> nodes, List<Integer> out) {
|
||||
for (SysGroupVo vo : nodes) {
|
||||
if (vo.getId() != null) {
|
||||
out.add(vo.getId());
|
||||
}
|
||||
if (vo.getChildren() != null) {
|
||||
collectGroupIds(vo.getChildren(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectVoById(List<SysGroupVo> nodes, Map<Integer, SysGroupVo> out) {
|
||||
for (SysGroupVo vo : nodes) {
|
||||
if (vo.getId() != null) {
|
||||
out.put(vo.getId(), vo);
|
||||
}
|
||||
if (vo.getChildren() != null) {
|
||||
collectVoById(vo.getChildren(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user