package com.persagy.account.manage; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.common.collect.Lists; import com.persagy.account.pojo.dto.SaasAccountRole; import com.persagy.account.pojo.dto.SaasFunction; import com.persagy.account.pojo.dto.SaasMenu; import com.persagy.account.pojo.dto.SaasProduct; import com.persagy.account.pojo.dto.SaasRole; import com.persagy.account.pojo.dto.SaasRoleMenu; import com.persagy.account.pojo.vo.auth.SaasMenuFunctionPageVO; import com.persagy.account.pojo.vo.auth.SaasMenuFunctionVO; import com.persagy.account.pojo.vo.menu.SaasMenuQueryVO; import com.persagy.account.pojo.vo.role.SaasRoleDeleteVO; import com.persagy.account.service.ISaasAccountRoleService; import com.persagy.account.service.ISaasFunctionService; import com.persagy.account.service.ISaasMenuService; import com.persagy.account.service.ISaasProductService; import com.persagy.account.service.ISaasRoleMenuService; import com.persagy.account.service.ISaasRoleService; import com.persagy.common.constant.SaasCommonConstant; import com.persagy.common.exception.BusinessException; import com.persagy.common.utils.StringUtil; import com.persagy.security.constant.CipherConstants; import cn.hutool.core.collection.CollectionUtil; /** * 角色菜单管理 * * @version * @description * @company persagy * @author zhangqiankun * @since 2021年3月15日: 上午10:49:15 */ @Component public class SaasRoleMenuHandler { @Autowired private SaasAuthHandler saasAuthHandler; @Autowired private ISaasRoleService saasRoleService; @Autowired private ISaasMenuService saasMenuService; @Autowired private SaasProductHandler saasProductHandler; @Autowired private ISaasProductService saasProductService; @Autowired private ISaasFunctionService saasFunctionService; @Autowired private ISaasRoleMenuService saasRoleMenuService; @Autowired private ISaasAccountRoleService saasAccountRoleService; /** * 获取菜单权限树,权限过滤,需要判断视角,1-集团视角,2-项目视角 项目ID存在即为项目视角 * * @param queryVO * @return */ public List querySaasMenuTree(SaasMenuQueryVO queryVO) { // 获取此账号对应的菜单范围 Map menuAuth = this.saasAuthHandler.validAccountAuth(queryVO.getAccountId(), queryVO.getGroupCode()); if (StringUtil.isNotBlank(menuAuth.get(CipherConstants.GROUP_CODE))) { queryVO.setGroupCode(menuAuth.get(CipherConstants.GROUP_CODE)); } // 添加数据访问控制,账号可见域,0-所有集团项目,1-单集团所有项目(此时,集团编码需存在),2-其他 String accountType = menuAuth.get(SaasCommonConstant.ACCOUNT_TYPE); // 账号所属,0-运维系统,1-业务系统账号 String accountBelong = menuAuth.get(SaasCommonConstant.ACCOUNT_BELONG); List menuTree = null; if (SaasCommonConstant.STR_STATUS_0.equals(accountType) && SaasCommonConstant.STR_STATUS_0.equals(accountBelong)) { // 如果是运维系统的账号,accountType为0的情况下查询所有菜单权限,其余情况走表关联查询,为1时,后续可添加 menuTree = this.querySaasMenuTree(null, null, queryVO.getProjectId(), queryVO.getAppId(), true, queryVO.isMenu()); } else { menuTree = this.querySaasMenuTree(queryVO.getAccountId(), queryVO.getGroupCode(), queryVO.getProjectId(), queryVO.getAppId(), false, queryVO.isMenu()); } return menuTree; } /** * 查询账号菜单功能权限树,菜单定义和角色定义编码相同,所以这里应该同步传递 * * @param accountId * @param groupCode * @param projectId * @param appId * @param isAdmin 是否为超管 true-是,此为系统超管 * @param isMenu 是否仅查询出菜单树,true-是 * @return 空集合或数据菜单树 */ public List querySaasMenuTree(String accountId, String groupCode, String projectId, String appId, boolean isAdmin, boolean isMenu) { // 1.获取此账号对应菜单集合 List menuTree = null; if (isAdmin) { LambdaQueryWrapper queryWrapper = new SaasMenu.Builder().createQueryWrapper().appIdEq(appId).menuTypeEq(SaasCommonConstant.STR_STATUS_0).builderQueryWrapper(); menuTree = this.saasMenuService.list(queryWrapper); } else { menuTree = this.saasMenuService.querySaasMenuTree(accountId, groupCode, appId, null, SaasCommonConstant.STATUS_1); } if (CollectionUtil.isEmpty(menuTree)) { return Lists.newArrayList(); } // 2.转为菜单树 List topMenus = new ArrayList(); for (int i = menuTree.size() - 1; i >= 0; i--) { SaasMenu saasMenu = menuTree.get(i); if (StringUtil.isBlank(saasMenu.getParentId())) { topMenus.add(saasMenu); menuTree.remove(i); } } List parents = topMenus.stream().sorted(Comparator.comparing(SaasMenu::getMenuSort)).collect(Collectors.toList()); this.setMenuChildrens(accountId, groupCode, projectId, menuTree, parents, isAdmin, !isMenu); return parents; } /** * 生成菜单树 * @param accountId 为null时,isAdmin 为true * @param angle 1-集团视角,2-项目视角 * @param groupCode * @param menuTree 为空时,会去查询,但是不会做权限过滤 * @param parents * @param isAdmin 是否为超管 true-是 * @param menuAndFun */ public void setMenuChildrens(String accountId, String groupCode, String projectId, List menuTree, List parents, boolean isAdmin, boolean menuAndFun) { for (SaasMenu parent : parents) { if (StringUtil.isBlank(parent.getMenuId())) { parent.setMenuId(parent.getId()); } if (StringUtil.isNotBlank(parent.getMenuUrl())) { this.saasProductHandler.queryMenuProductAuths(parent, accountId, groupCode, projectId, isAdmin, menuAndFun); } List childrens = null; if (menuTree == null) { LambdaQueryWrapper queryWrapper = new SaasMenu.Builder().createQueryWrapper().parentIdEq(parent.getId()) .menuTypeEq(parent.getMenuType()).appIdEq(parent.getAppId()).builderQueryWrapper(); childrens = this.saasMenuService.list(queryWrapper.orderByAsc(SaasMenu::getMenuSort)); childrens = CollectionUtil.isEmpty(childrens) ? Lists.newArrayList() : childrens; } else { childrens = new ArrayList(); for (int i = menuTree.size() - 1; i >= 0; i--) { SaasMenu saasMenu = menuTree.get(i); if (parent.getMenuId().equals(saasMenu.getParentId())) { childrens.add(saasMenu); menuTree.remove(i); } } } parent.setChildrens(childrens); this.setMenuChildrens(accountId, groupCode, projectId, menuTree, childrens, isAdmin, menuAndFun); } } /** * 删除角色,级联删除账号角色,角色菜单的关联关系 * * @param deleteVO */ @Transactional public boolean deleteSaasRole(SaasRoleDeleteVO deleteVO) { LambdaQueryWrapper updateWrapper = new SaasRole.Builder().createQueryWrapper().idEq(deleteVO.getId()) .validEq(SaasCommonConstant.STATUS_1).builderQueryWrapper(); boolean result = this.saasRoleService.remove(updateWrapper); if (result) { // 1.级联删除账号和角色关联关系 LambdaQueryWrapper accountRoleWrapper = new SaasAccountRole.Builder().createQueryWrapper().roleIdEq(deleteVO.getId()).builderQueryWrapper(); this.saasAccountRoleService.remove(accountRoleWrapper); // 2.级联删除角色和菜单的关联关系 LambdaQueryWrapper roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().roleIdEq(deleteVO.getId()).builderQueryWrapper(); this.saasRoleMenuService.remove(roleMenuWrapper); } return result; } /** * 删除菜单,级联删除,角色、菜单、功能三者关联关系数据 * * @param menuId * @param productId * @param updateProduct 是否更新产品关联菜单字段 * @return */ @Transactional public boolean deleteSaasMenu(String menuId, String productId, boolean updateProduct) { if (StringUtil.isBlank(menuId)) { return true; } boolean result = this.saasMenuService.removeById(menuId); if (result) { if (updateProduct) { // 更新产品是否已关联菜单字段 SaasProduct saasProduct = new SaasProduct(); saasProduct.setId(productId); saasProduct.setProductMenu(SaasCommonConstant.STR_STATUS_0); result = this.saasProductService.updateById(saasProduct); } // 1.删除此菜单下功能 LambdaQueryWrapper funWrapper = new SaasFunction.Builder().createQueryWrapper().menuIdEq(menuId).builderQueryWrapper(); this.saasFunctionService.remove(funWrapper); // 2.删除此功能对应的菜单、角色关系数据 LambdaQueryWrapper roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().menuIdEq(menuId).builderQueryWrapper(); this.saasRoleMenuService.remove(roleMenuWrapper); // 级联删除此菜单下的所有子菜单和对应的功能点信息 this.casDeleteChildrenMenu(menuId); return true; } throw new BusinessException("菜单信息删除失败"); } /** * 级联删除所有的子菜单和对应的权限信息 * @param menuId * @param productId */ @Transactional public void casDeleteChildrenMenu(String parentId) { LambdaQueryWrapper queryWrapper = new SaasMenu.Builder().createQueryWrapper().parentIdEq(parentId).builderQueryWrapper(); List saasMenus = this.saasMenuService.list(queryWrapper.select(SaasMenu::getId, SaasMenu::getProductId)); if (CollectionUtil.isEmpty(saasMenus)) { return; } for (SaasMenu saasMenu : saasMenus) { boolean updateProduct = false; if (StringUtil.isNotBlank(saasMenu.getProductId())) { // 判断此产品是否仅被此菜单使用 queryWrapper = new SaasMenu.Builder().createQueryWrapper().productId(saasMenu.getProductId()).builderQueryWrapper(); int count = this.saasMenuService.count(queryWrapper); if (count < 2) { updateProduct = true; } } // 删除此菜单 this.deleteSaasMenu(saasMenu.getId(), saasMenu.getProductId(), updateProduct); } } /** * 删除功能,级联删除菜单、功能关系 * * @param funId * @return */ @Transactional public boolean deleteSaasFunction(String funId) { LambdaQueryWrapper queryWrapper = new SaasFunction.Builder().createQueryWrapper().idEq(funId).builderQueryWrapper(); boolean result = this.saasFunctionService.remove(queryWrapper); if (result) { // 1.删除此功能对应的菜单、角色关系数据 LambdaQueryWrapper roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().functionIdEq(funId).builderQueryWrapper(); this.saasRoleMenuService.remove(roleMenuWrapper); } return result; } /** * 先删后新增,仅删除此账号角色下的所有菜单功能点的关联关系,并重新新增 * * @param batchVO * @return */ @Transactional public boolean resetSaasRoleMenu(String groupCode, String roleId, List auths) { LambdaQueryWrapper roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().roleIdEq(roleId).builderQueryWrapper(); this.saasRoleMenuService.remove(roleMenuWrapper); // 1.批量新增 boolean result = this.saasRoleMenuService.batchCreateSaasRoleMenu(groupCode, roleId, auths); if (!result) { throw new BusinessException("重置角色菜单功能权限失败"); } return result; } /** * 创建角色,同时添加菜单关联关系 * @param saasRole * @param auths * @return */ @Transactional public boolean createSaasRole(SaasRole saasRole, List auths) { // 1.创建角色信息 boolean result = this.saasRoleService.save(saasRole); if (result && CollectionUtil.isNotEmpty(auths)) { // 2.删除并创建角色信息 this.resetSaasRoleMenu(saasRole.getGroupCode(), saasRole.getId(), auths); } return result; } /** * 更新角色,同时更新菜单关联关系 * @param saasRole * @param auths * @return */ @Transactional public boolean updateSaasRole(SaasRole saasRole, List auths) { boolean result = this.saasRoleService.updateById(saasRole); if (result && CollectionUtil.isNotEmpty(auths)) { this.resetSaasRoleMenu(saasRole.getGroupCode(), saasRole.getId(), auths); } return result; } /** * 删除新增角色菜单页面关联关系 * @param groupCode * @param roleId * @param auths * @return */ @Transactional public boolean resetSaasRoleMenuPage(String groupCode, String roleId, List auths) { LambdaQueryWrapper roleMenuWrapper = new SaasRoleMenu.Builder().createQueryWrapper().roleIdEq(roleId).builderQueryWrapper(); this.saasRoleMenuService.remove(roleMenuWrapper); // 1.批量新增 boolean result = this.saasRoleMenuService.batchCreateSaasRoleMenuPage(groupCode, roleId, auths); if (!result) { throw new BusinessException("重置角色菜单页面功能权限失败"); } return result; } }