From 809d88c8382da2b0c73fcefc941750252654ccf0 Mon Sep 17 00:00:00 2001 From: chenxing Date: Fri, 23 Oct 2026 10:30:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(dept):=20SysGroupVo=20=E8=A1=A5=20memberCo?= =?UTF-8?q?unt/memberNames=EF=BC=8CgetTree=20=E5=9B=9E=E5=A1=AB=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E6=88=90=E5=91=98=E6=95=B0=E4=B8=8E=E5=A7=93=E5=90=8D?= =?UTF-8?q?=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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= --- .../userbase/model/sysgroup/SysGroupVo.java | 7 ++ .../service/impl/SysGroupService.java | 89 ++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/yunhai/userbase/model/sysgroup/SysGroupVo.java b/src/main/java/com/yunhai/userbase/model/sysgroup/SysGroupVo.java index 2bf51f8..f23137d 100644 --- a/src/main/java/com/yunhai/userbase/model/sysgroup/SysGroupVo.java +++ b/src/main/java/com/yunhai/userbase/model/sysgroup/SysGroupVo.java @@ -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} 个。
+ * 完整名单不走这里(部门可能上百人),前端点「查看全部」调 /api/sysuser/List?groupId=xxx。 + */ + private List memberNames = new ArrayList<>(); /** 子组(递归);默认空列表,避免 JSON 序列化出现 null。 */ private List children = new ArrayList<>(); } diff --git a/src/main/java/com/yunhai/userbase/service/impl/SysGroupService.java b/src/main/java/com/yunhai/userbase/service/impl/SysGroupService.java index 6c06808..0bac0c0 100644 --- a/src/main/java/com/yunhai/userbase/service/impl/SysGroupService.java +++ b/src/main/java/com/yunhai/userbase/service/impl/SysGroupService.java @@ -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; + /** + * 部门表格「人员」列的姓名预览上限。
+ * 表格最多显示 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> childrenMap = snapshot.getChildrenMap(); // 从根(pid=0)开始组装树 List roots = childrenMap.getOrDefault(ROOT_PARENT_ID, new ArrayList<>()); - return roots.stream().map(r -> buildNode(r, childrenMap)).collect(Collectors.toList()); + List 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 tree = buildTrimmedTree(scope, snapshot.getAll(), false); + fillMemberStats(tree); + return tree; + } + + /** + * 给树节点补直属成员数与前 N 个姓名预览(部门表格「人员」列)。
+ * 口径与 oapi 部门目录一致:sys_user_group_rel 按 groupId 计数,不排除转出; + * 整棵树只发两次查询(关联表 in + 用户表 in),不受节点数影响。 + */ + private void fillMemberStats(List tree) { + List groupIds = new ArrayList<>(); + collectGroupIds(tree, groupIds); + if (groupIds.isEmpty()) { + return; + } + List rels = sysUserGroupRelRepository.findByGroupIdIn(groupIds); + if (rels == null || rels.isEmpty()) { + return; + } + Map> relByGroup = new HashMap<>(); + Set 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 nameById = new HashMap<>(); + for (SysUser user : sysUserRepository.findAllById(userIds)) { + nameById.put(user.getId(), + StringUtils.hasText(user.getRealName()) ? user.getRealName() : user.getAccount()); + } + Map voById = new HashMap<>(); + collectVoById(tree, voById); + for (Map.Entry> entry : relByGroup.entrySet()) { + SysGroupVo vo = voById.get(entry.getKey()); + if (vo == null) { + continue; + } + List members = entry.getValue(); + vo.setMemberCount((long) members.size()); + List 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 nodes, List 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 nodes, Map out) { + for (SysGroupVo vo : nodes) { + if (vo.getId() != null) { + out.put(vo.getId(), vo); + } + if (vo.getChildren() != null) { + collectVoById(vo.getChildren(), out); + } + } } @Override