init: UserBaseService (backend + deploy + scripts)
ci-userbase-service / build-and-push (push) Successful in 40s

This commit is contained in:
chenxing
2026-08-10 14:50:22 +08:00
commit 4ec19486e0
234 changed files with 15604 additions and 0 deletions
@@ -0,0 +1,161 @@
package com.yunhai.userbase.service;
import com.yunhai.userbase.model.groupauthz.*;
import java.util.List;
/**
* @author chenx
* @date 2026/7/23
* @description 组应用权限服务(应用开通 + 组授权 + 权限判定)。<br>
*/
public interface IGroupAuthzService {
/**
* 功能1回显:查询系统全量应用列表,并标记该组已开通的应用(checked)。<br>
*
* @param groupId 组ID
* @return 全量应用列表(含开通勾选状态)
*/
List<GroupAppVo> listGroupApps(Integer groupId);
/**
* 功能1保存:全量覆盖式更新组的应用开通记录(先删旧记录再批量插入)。<br>
* 被取消开通的应用,同步清理该组在其模块上的权限记录,避免残留脏数据。<br>
*
* @param request 组ID + 勾选的应用ID全量列表
*/
void assignAppsToGroup(GroupAppAssignRequest request);
/**
* 功能2数据加载:查询该组已开通的应用及其模块树,并回显勾选状态与子组继承开关。<br>
* 仅返回 sys_group_app_rel 中有记录的应用;未开通的应用不显示。<br>
*
* @param groupId 组ID
* @return 已开通应用列表(含模块权限树)
*/
List<GroupAuthzAppVo> findGroupAppsWithModules(Integer groupId);
/**
* 功能2数据加载(按应用分类分组版):与 {@link #findGroupAppsWithModules(Integer)} 数据一致,<br>
* 但按应用类型分类聚合,便于组授权页面按分类面板展示。<br>
* 返回全部分类(含空数组),保证前端分类筛选下拉完整。<br>
*
* @param groupId 组ID
* @return 按应用分类分组的已开通应用列表
*/
List<GroupAuthzCategoryVo> findGroupAppsWithModulesByCategory(Integer groupId);
/**
* 功能2保存:全量覆盖式更新组的模块权限。<br>
* 有旧记录则更新 inheritFlag,无则新增,不在传入列表中的旧记录物理删除。<br>
*
* @param request 组ID + 勾选的模块权限全量列表(moduleId + inheritFlag)
*/
void saveModulePermissions(GroupModulePermRequest request);
/**
* 权限判定(供登录/拦截器使用):判断用户对某模块是否有权限。<br>
* 规则:用户任一所属组,沿祖先链回溯——自身显式勾选即通过;祖先勾选且 inheritFlag=true 即通过。<br>
* 前置校验:该所属组必须已开通模块所属应用(最终权限 = 继承的模块权限 ∩ 该组已开通的应用)。<br>
* 角色授权并集:用户经「启用状态」业务角色获得该模块授权也通过,且不要求组已开通模块所属应用;禁用角色不参与判定。<br>
*
* @param userId 用户ID
* @param moduleId 模块ID
* @return true=有权限
*/
boolean hasModulePermission(Integer userId, Integer moduleId);
/**
* 权限一览:查询指定组下的直接用户列表(不含子组,不分页)。<br>
*
* @param groupId 组ID
* @return 用户列表
*/
List<UserPermissionUserVo> findGroupUsers(Integer groupId);
/**
* 权限一览:全局搜索用户(按账号/姓名/身份证模糊、手机号精确匹配),不分页。<br>
* 返回用户及其主归属部门/组织路径。
*
* @param keyword 搜索关键字
* @return 用户列表
*/
List<UserPermissionUserVo> searchUsers(String keyword);
/**
* 权限一览:根据用户ID聚合该用户的全部已授权应用模块树。<br>
* 只返回<b>有授权模块</b>的应用,并按应用类型分组;无授权的应用类型和应用不显示。<br>
* 权限判定复用 {@link #hasModulePermission(Integer, Integer)} 的祖先链继承逻辑。<br>
* 角色授权并集:最终模块权限 = 组授权模块 ∪ 启用角色授权模块;<br>
* 最终应用范围 = 组开通应用 ∪ 角色模块所属应用(角色模块不要求组必须先开通应用)。<br>
*
* @param groupId 组ID(上下文,可选;目前仅用于校验用户存在性,实际聚合以 userId 为准)
* @param userId 用户ID
* @return 按应用类型分组的已授权应用模块树
*/
List<UserPermissionCategoryVo> findUserPermissionTree(Integer groupId, Integer userId);
/**
* 权限一览:查询用户所属的业务角色列表(中间下方「所属角色」区域展示用)。<br>
* 返回该用户绑定的全部角色(含禁用角色,disabled 字段标记),普通角色回填所属应用名称。<br>
*
* @param userId 用户ID
* @return 用户所属角色列表
*/
List<UserRoleVo> findUserRoles(Integer userId);
/**
* 权限一览:查询用户所属部门树(左侧上方「所属部门」区域展示用)。<br>
* 树仅由「用户直接归属的组 + 其全部祖先组」构成(如:云平台-学校中学-语文组),
* 多个归属组时合并为一棵树(公共祖先只出现一次)。<br>
*
* @param userId 用户ID
* @return 所属部门树(根节点列表);用户无组归属时返回空列表
*/
List<UserGroupNodeVo> findUserGroupTree(Integer userId);
// ===================== 新增:树节点式增量授权(供左侧树 + 右侧 appAuthzList 的勾选交互) =====================
/**
* 获取某组「已开通的应用ID列表」,供前端右侧应用清单回显勾选状态。<br>
* <b>实现思路</b>:应用开通「不继承」(见 SysGroupAppRel 设计)——直接查 sys_group_app_rel 中 group_id=nodeId 的记录,<br>
* 返回其 app_id 集合;<b>不</b>沿祖先链回填父组开通的应用(父组开通不代表子组自动拥有)。<br>
* 与现有 GroupAppList(返回全量应用 + checked)的区别:本接口只返回已选 id 列表,更轻量,适合做勾选回显。
*
* @param nodeId 左侧树点击的组节点ID
* @return 该组已开通的应用ID列表(无则空列表)
*/
List<Integer> findAuthorizedAppIds(Integer nodeId);
/**
* 增量设置某组的应用开通/取消(对应前端「应用多选框」勾选/取消)。<br>
* <b>入参</b>:{@link SchoolAppAuthzRequest} 封装 schid / appids(逗号分隔字符串) / mode。<br>
* <b>实现思路</b>:<br>
* - mode=0(追加/APPEND):对 appids 中每个应用,若 sys_group_app_rel 尚无记录则插入(已存在则跳过,幂等)。<br>
* - mode=2(删除/DELETE):对每个应用删除开通记录,并<b>同步清理该组在该应用下模块的权限残留</b>(与现有 assignAppsToGroup 取消开通时行为一致,避免脏数据)。<br>
* - 应用开通「不继承」,故<b>仅操作传入的 schId 自身,不做子组级联</b>。<br>
* - mode=1(覆盖) 不适用于单条增量,直接拒绝。
*
* @param request 学校组应用授权请求(组ID + 应用ID字符串 + 操作模式)
*/
void setSchoolApps(SchoolAppAuthzRequest request);
/**
* 增量设置「组-应用-模块」的模块授权(对应前端「组授权」面板逐条勾选/取消)。<br>
* <b>实现思路</b>:逐条处理 items 列表(顺序即执行顺序,后者覆盖前者):<br>
* - mode=0(追加):对 (groupId, 展开后的 moduleId) upsert 一条 sys_group_module_perm,inherit_flag=isAll。<br>
* - mode=2(删除):删除对应权限记录。<br>
* - moduleId=0 表示「该应用下全部模块」,展开为应用下每个真实模块各写/删一条(不写 module_id=0 伪记录)。<br>
* - <b>isAll 的语义(重点)</b>:直接映射现有 sys_group_module_perm.inherit_flag 列。<br>
* &nbsp;&nbsp;isAll=1 → inherit_flag=true:子孙组在 hasModulePermission 判定时沿祖先链自动继承该模块权限(逻辑继承,不物理写子组);<br>
* &nbsp;&nbsp;isAll=0 → inherit_flag=false:仅本组生效。<br>
* 这与「应用不继承 / 模块可继承」的对称性一致,且复用现有权限判定逻辑,不破坏其他功能。<br>
* - 越权防护:模块必须属于该 appId;追加前要求该组已开通该应用(与现有 SaveModulePerms 边界一致)。<br>
* <br>
* <i>若产品实际想要「物理写子组」(子组各存一条 perm,而非逻辑继承),把 isAll=1 分支改成「对 groupId + 其全部子孙组分别 upsert」即可,详见实现类注释。</i>
*
* @param items 模块授权条目列表(groupId/appId/moduleId/mode/isAll)
*/
void setGroupModulePerms(List<GroupModuleAuthzItem> items);
}