ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java
@@ -76,13 +76,41 @@
     * 根据 SysDept.parentId 构造部门树
     */
    public static List<SysDept> buildDeptTree(List<SysDept> depts) {
        // 按 deptId 去重,防止 sys_user_dept 一对多关联产生重复的父节点,导致构建部门树时出现问题
        depts = distinctByDeptId(depts);
        return buildTree(depts, SysDept::getDeptId, SysDept::getParentId, SysDept::setChildren);
    }
    /**
     * 一次性获取所有部门叶子节点
     * 从扁平部门列表一次性获取所有叶子部门:即「deptId 不出现在任何节点的 parentId 中」的节点。
     * 入参应为扁平列表(不是 buildDeptTree 的返回值),无需先建树。
     * 会先按 deptId 去重,避免 join 产生的重复部门变成重复叶子。
     */
    public static List<SysDept> getLeafDepts(List<SysDept> depts) {
        return getLeafNodes(depts, SysDept::getHisDeptId, SysDept::getHisParentId);
        return getLeafNodes(distinctByDeptId(depts), SysDept::getDeptId, SysDept::getParentId);
    }
    /**
     * 按 deptId 对部门列表去重,保留首次出现的节点。
     * 查询结果通过 dept_code 关联 sys_user_dept,同一部门可能出现多条记录(重复的父节点),
     * 构建部门树前需去重,避免重复节点导致树结构异常。
     *
     * @param list 部门列表,允许为 null
     * @return 去重后的部门列表;入参为 null 或空时原样返回
     */
    private static List<SysDept> distinctByDeptId(List<SysDept> list) {
        if (list == null || list.isEmpty()) {
            return list;
        }
        Set<Long> deptIdSet = new HashSet<>();
        List<SysDept> distinctList = new ArrayList<>(list.size());
        for (SysDept dept : list) {
            Long deptId = dept.getDeptId();
            // deptId 为空时保留,避免误合并不同部门
            if (deptId == null || deptIdSet.add(deptId)) {
                distinctList.add(dept);
            }
        }
        return distinctList;
    }
}