diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java index 2ca0cd3..8328149 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java @@ -181,4 +181,18 @@ public class SysMenuController extends BaseController { return toAjax(menuService.deleteMenuById(menuId)); } + /** + * 复制菜单 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping("/copy/{menuId}") + public R copy(@PathVariable("menuId") Long menuId, @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("复制菜单失败,菜单名称已存在"); + } + return toAjax(menuService.copyMenu(menuId, menu)); + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java index a1bdbb5..9ae57ec 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java @@ -145,4 +145,13 @@ public interface ISysMenuService { * @return 结果 */ boolean checkMenuNameUnique(SysMenuBo menu); + + /** + * 复制菜单 + * + * @param menuId 源菜单ID + * @param menu 新菜单信息 + * @return 结果 + */ + int copyMenu(Long menuId, SysMenuBo menu); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java index 897d94a..8013665 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -27,7 +27,9 @@ import org.dromara.system.mapper.SysRoleMapper; import org.dromara.system.mapper.SysRoleMenuMapper; import org.dromara.system.mapper.SysTenantPackageMapper; import org.dromara.system.service.ISysMenuService; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.*; @@ -140,7 +142,7 @@ public class SysMenuServiceImpl implements ISysMenuService { return getChildPerms(menus, 0); } @Override - public List selectMenuTreeByUserId(Long userId,int pId) { + public List selectMenuTreeByUserId(Long userId, int pId) { List menus; if (LoginHelper.isSuperAdmin(userId)) { menus = baseMapper.selectMenuTreeAll(); @@ -170,20 +172,74 @@ public class SysMenuServiceImpl implements ISysMenuService { */ @Override public List selectMenuListByPackageId(Long packageId) { + // 1. 查询套餐信息 SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); if (CollUtil.isEmpty(menuIds)) { return new ArrayList<>(); } + // 2. 初始化结果列表 + List result = new ArrayList<>(); + int batchSize = 500; // 每批处理1000个参数 + List parentIds = null; if (tenantPackage.getMenuCheckStrictly()) { parentIds = baseMapper.selectObjs(new LambdaQueryWrapper() .select(SysMenu::getParentId) - .in(SysMenu::getMenuId, menuIds), x -> {return Convert.toLong(x);}); + .in(SysMenu::getMenuId, menuIds), x -> { + return Convert.toLong(x); + }); } - return baseMapper.selectObjs(new LambdaQueryWrapper() - .in(SysMenu::getMenuId, menuIds) - .notIn(CollUtil.isNotEmpty(parentIds), SysMenu::getMenuId, parentIds), x -> {return Convert.toLong(x);}); + if (tenantPackage.getMenuCheckStrictly()) { + parentIds = new ArrayList<>(); + // 分批查询父ID + for (int i = 0; i < menuIds.size(); i += batchSize) { + int endIndex = Math.min(i + batchSize, menuIds.size()); + List batchMenuIds = menuIds.subList(i, endIndex); + + List batchParentIds = baseMapper.selectObjs( + new LambdaQueryWrapper() + .select(SysMenu::getParentId) + .in(SysMenu::getMenuId, batchMenuIds), + x -> { + return Convert.toLong(x); + }); + parentIds.addAll(batchParentIds); + } + } + + // 4. 分批查询最终结果 + for (int i = 0; i < menuIds.size(); i += batchSize) { + int endIndex = Math.min(i + batchSize, menuIds.size()); + List batchMenuIds = menuIds.subList(i, endIndex); + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .in(SysMenu::getMenuId, batchMenuIds); + + // 如果有父ID,也需要分批处理 + if (CollUtil.isNotEmpty(parentIds)) { + for (int j = 0; j < parentIds.size(); j += batchSize) { + int parentEndIndex = Math.min(j + batchSize, parentIds.size()); + List batchParentIds = parentIds.subList(j, parentEndIndex); + + wrapper.notIn(SysMenu::getMenuId, batchParentIds); + + // 执行查询并收集结果 + List batchResult = baseMapper.selectObjs(wrapper, x -> { + return Convert.toLong(x); + }); + result.addAll(batchResult); + } + } else { + // 如果没有父ID,直接查询 + List batchResult = baseMapper.selectObjs(wrapper, x -> { + return Convert.toLong(x); + }); + result.addAll(batchResult); + } + } + + return result; } /** @@ -301,7 +357,10 @@ public class SysMenuServiceImpl implements ISysMenuService { @Override public int insertMenu(SysMenuBo bo) { SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); - return baseMapper.insert(menu); + int insert = baseMapper.insert(menu); + assert menu != null; + bo.setMenuId(menu.getMenuId()); + return insert; } /** @@ -342,6 +401,84 @@ public class SysMenuServiceImpl implements ISysMenuService { return !exist; } + /** + * 复制菜单 + * + * @param menuId 源菜单ID + * @param menu 新菜单信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int copyMenu(Long menuId, SysMenuBo menu) { + // 1. 获取源菜单信息 + SysMenuVo sourceMenu = selectMenuById(menuId); + if (sourceMenu == null) { + throw new RuntimeException("源菜单不存在"); + } + + // 2. 创建新菜单对象 + SysMenuBo newMenu = new SysMenuBo(); + BeanUtils.copyProperties(sourceMenu, newMenu); + newMenu.setMenuId(null); + newMenu.setCreateTime(null); + newMenu.setMenuName(menu.getMenuName()); + newMenu.setParentId(menu.getParentId()); + newMenu.setOrderNum(menu.getOrderNum()); + + // 3. 检查菜单名称是否唯一 + if (!checkMenuNameUnique(newMenu)) { + throw new RuntimeException("菜单名称已存在"); + } + + // 4. 插入新菜单 + int rows = insertMenu(newMenu); + if (rows > 0) { + // 5. 获取新插入菜单的ID + Long newMenuId = newMenu.getMenuId(); + + // 6. 递归复制子菜单 + copyChildMenus(menuId, newMenuId); + } + return rows; + } + + /** + * 递归复制子菜单 + * + * @param sourceParentId 源父菜单ID + * @param targetParentId 目标父菜单ID + */ + private void copyChildMenus(Long sourceParentId, Long targetParentId) { + // 1. 查询源父菜单的所有子菜单 + List children = baseMapper.selectVoList( + new LambdaQueryWrapper() + .eq(SysMenu::getParentId, sourceParentId) + ); + + // 2. 递归复制每个子菜单 + if (CollUtil.isNotEmpty(children)) { + for (SysMenuVo child : children) { + // 2.1 创建新的子菜单对象 + SysMenuBo newChildMenu = new SysMenuBo(); + BeanUtils.copyProperties(child, newChildMenu); + newChildMenu.setMenuId(null); + newChildMenu.setCreateTime(null); + newChildMenu.setParentId(targetParentId); + newChildMenu.setMenuName(child.getMenuName()); + + // 2.2 插入新的子菜单 + int rows = insertMenu(newChildMenu); + if (rows > 0) { + // 2.3 获取新插入的子菜单ID + Long newChildMenuId = newChildMenu.getMenuId(); + // 2.4 递归复制下一级子菜单 + copyChildMenus(child.getMenuId(), newChildMenuId); + } + } + } + } + /** * 根据父节点的ID获取所有子节点 *