package com.iailab.module.system.service.app; import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; import com.iailab.framework.security.core.util.SecurityFrameworkUtils; import com.iailab.framework.tenant.core.aop.TenantIgnore; import com.iailab.module.system.api.app.dto.AppMenuRespDTO; import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; import com.iailab.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO; import com.iailab.module.system.convert.auth.AuthConvert; import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; import com.iailab.module.system.dal.dataobject.permission.RoleDO; import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; import com.iailab.module.system.dal.dataobject.tenant.TenantDO; import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; import com.iailab.module.system.dal.mysql.app.AppMapper; import com.iailab.module.system.dal.mysql.permission.MenuMapper; import com.iailab.module.system.dal.mysql.permission.RoleMapper; import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; import com.iailab.module.system.dal.mysql.tenant.TenantMapper; import com.iailab.module.system.dal.mysql.tenant.TenantPackageMapper; import com.iailab.module.system.enums.permission.MenuTypeEnum; import com.iailab.module.system.service.permission.MenuService; import com.iailab.module.system.service.permission.PermissionService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.*; import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_EXISTS_CHILDREN; import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_NOT_EXISTS; /** * @author PanZhibao * @Description * @createTime 2024年08月17日 */ @Service @Slf4j public class AppServiceImpl implements AppService { @Resource private AppMapper appMapper; @Resource private MenuMapper menuMapper; @Resource private RoleMapper roleMapper; @Resource private RoleMenuMapper roleMenuMapper; @Resource private PermissionService permissionService; @Resource private TenantPackageMapper tenantPackageMapper; @Resource private TenantMapper tenantMapper; @Resource private MenuService menuService; @Override @Transactional(rollbackFor = Exception.class) @TenantIgnore public Long create(AppSaveReqVO createReqVO) { AppDO app = BeanUtils.toBean(createReqVO, AppDO.class); appMapper.insert(app); // //为应用创建默认菜单并授权 dealAppMenu(1, app); return app.getId(); } @Override @Transactional(rollbackFor = Exception.class) @TenantIgnore public Long update(AppSaveReqVO createReqVO) { AppDO app = BeanUtils.toBean(createReqVO, AppDO.class); appMapper.updateById(app); // //修改默认菜单并授权 dealAppMenu(2, app); return app.getId(); } @Override @Transactional(rollbackFor = Exception.class) @TenantIgnore public void delete(Long id) { AppDO appDO = new AppDO(); appDO.setId(id); dealAppMenu(3, appDO); appMapper.deleteById(id); } @Override public AppDO getInfo(Long id) { return appMapper.selectById(id); } @Override public PageResult getPage(AppPageReqVO pageReqVO) { return appMapper.selectPage(pageReqVO); } @Override public List getList() { Long tenantId = getTenantId(); LambdaQueryWrapperX menuDOLambdaQueryWrapperX = new LambdaQueryWrapperX<>(); menuDOLambdaQueryWrapperX.eq(MenuDO::getParentId, 0) .eq(MenuDO::getAppId, 0); if (tenantId != 1) { //非系统租户查租户套餐 TenantDO tenantDO = tenantMapper.selectById(tenantId); TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); menuDOLambdaQueryWrapperX.in(MenuDO::getId, tenantPackageDO.getMenuIds()); } //查询系统应用菜单 // List menuDOS = menuMapper.selectList(menuDOLambdaQueryWrapperX); // List systemApps = convertMenuToApp(menuDOS); List systemApps = new ArrayList<>(); List appDOS = appMapper.selectList(); //暂时先遍历处理应用菜单和应用类型 appDOS.stream().forEach(appDO -> { List menuDOS = menuMapper.selectList(new LambdaQueryWrapper().eq(MenuDO::getParentId, 0) .eq(MenuDO::getAppId, appDO.getId())); appDO.setAppMenuId(menuDOS.get(0).getId()); appDO.setAppType(2); }); systemApps.addAll(appDOS); return systemApps; } @Override public AppDO getAppByTenantId(Long tenantId) { //暂时支持一个租户对应一个应用 List appDOS = appMapper.selectList(new LambdaQueryWrapper().eq(AppDO::getTenantId, tenantId)); if(ObjectUtils.isNotEmpty(appDOS)) { return appDOS.get(0); } else { AppDO appDO = new AppDO(); appDO.setTenantId(tenantId); appDO.setId(0L); return appDO; } } @Override public List getAppMenu(Long id) { MenuDO menuDO = menuMapper.selectById(id); List children = new LinkedList<>(); // 遍历每一层 Collection parentIds = Collections.singleton(id); for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 // 查询当前层,所有的子应用菜单 List menus = menuMapper.selectListByParentId(parentIds); // 1. 如果没有子菜单,则结束遍历 if (CollUtil.isEmpty(menus)) { break; } // 2. 如果有子应用菜单,继续遍历 children.addAll(menus); parentIds = convertSet(menus, MenuDO::getId); } children = menuService.filterDisableMenus(children); return AuthConvert.INSTANCE.buildMenuTree(children, id, menuDO.getPath()); } private void dealAppMenu(Integer type, AppDO app){ String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname(); MenuDO menuDO = new MenuDO(); menuDO.setAppId(app.getId()); menuDO.setName(app.getAppName()); menuDO.setType(MenuTypeEnum.DIR.getType()); menuDO.setSort(app.getOrderNum()); menuDO.setPath("/" + app.getAppCode()); menuDO.setTenantId(app.getTenantId()); if(type == 1){ menuDO.setCreator(loginUserNickname); menuDO.setCreateTime(app.getCreateTime()); menuDO.setIcon("fa-solid:border-none"); //默认icon menuMapper.insert(menuDO); // //内置租户角色分配菜单 // assignRoleMenu(menuDO.getId(), app.getTenantId()); } else if(type == 2){ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(MenuDO::getAppId, app.getId()); updateWrapper.eq(MenuDO::getParentId, 0L); List menuDOS = menuMapper.selectList(updateWrapper); if(menuDOS.size() > 0){ menuDO.setUpdater(loginUserNickname); menuDO.setUpdateTime(app.getUpdateTime()); menuMapper.update(menuDO, updateWrapper); } else { menuDO.setCreator(loginUserNickname); menuDO.setCreateTime(app.getCreateTime()); menuMapper.insert(menuDO); // //内置租户角色分配菜单 // assignRoleMenu(menuDO.getId(), app.getTenantId()); } } else if(type == 3){ //删除租户、角色权限 app = appMapper.selectById(app.getId()); LambdaQueryWrapperX menuWrapper = new LambdaQueryWrapperX<>(); menuWrapper.eq(MenuDO::getAppId, app.getId()); menuWrapper.eq(MenuDO::getType, MenuTypeEnum.DIR.getType()); menuWrapper.eq(MenuDO::getParentId, 0); MenuDO menu = menuMapper.selectOne(menuWrapper); TenantDO tenantDO = tenantMapper.selectById(app.getTenantId()); if(ObjectUtils.isNotEmpty(menu) && ObjectUtils.isNotEmpty(tenantDO)) { TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); Set menuIds = tenantPackageDO.getMenuIds(); menuIds.remove(menu.getId()); // 校验是否还有子菜单 if (menuMapper.selectCountByParentId(menu.getId()) > 0) { throw exception(MENU_EXISTS_CHILDREN); } // 校验删除的菜单是否存在 if (menuMapper.selectById(menu.getId()) == null) { throw exception(MENU_NOT_EXISTS); } // 标记删除 menuMapper.deleteById(menu.getId()); // 删除授予给角色的权限 permissionService.processMenuDeleted(menu.getId()); //删除菜单 menuMapper.delete(menuWrapper); } } } private void assignRoleMenu(Long menuId, Long tenantId) { //查询内置租户管理员 LambdaQueryWrapperX roleQueryWrapper = new LambdaQueryWrapperX<>(); roleQueryWrapper.eq(RoleDO::getCode, "tenant_admin"); roleQueryWrapper.eq(RoleDO::getTenantId, tenantId); RoleDO roleDO = roleMapper.selectOne(roleQueryWrapper); RoleMenuDO entity = new RoleMenuDO(); entity.setRoleId(roleDO.getId()); entity.setMenuId(menuId); entity.setTenantId(tenantId); roleMenuMapper.insert(entity); TenantDO tenantDO = tenantMapper.selectById(tenantId); TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); Set menuIds = tenantPackageDO.getMenuIds(); menuIds.add(menuId); tenantPackageMapper.updateById(tenantPackageDO); } private List convertMenuToApp(List menuDOS) { List appDOS = new ArrayList<>(); menuDOS.stream().forEach(menuDO -> { AppDO appDO = new AppDO(); appDO.setAppName(menuDO.getName()); appDO.setOrderNum(menuDO.getSort()); appDO.setAppMenuId(menuDO.getId()); appDO.setAppType(1); appDOS.add(appDO); }); return appDOS; } public List selectBatchIds(List ids) { List appDOS = appMapper.selectBatchIds(ids); return appDOS; } }