|
|
@@ -0,0 +1,352 @@
|
|
|
+package shop.alien.store.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import shop.alien.entity.result.R;
|
|
|
+import shop.alien.entity.store.LifeSysMenu;
|
|
|
+import shop.alien.entity.store.LifeSysRoleMenu;
|
|
|
+import shop.alien.entity.store.vo.MenuWithRoleVo;
|
|
|
+import shop.alien.mapper.LifeSysRoleMenuMapper;
|
|
|
+import shop.alien.store.service.LifeSysMenuService;
|
|
|
+import shop.alien.store.service.LifeSysRoleMenuService;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 角色菜单关联表 服务实现类
|
|
|
+ *
|
|
|
+ * @author system
|
|
|
+ * @since 2025-01-XX
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Transactional
|
|
|
+public class LifeSysRoleMenuServiceImpl extends ServiceImpl<LifeSysRoleMenuMapper, LifeSysRoleMenu> implements LifeSysRoleMenuService {
|
|
|
+
|
|
|
+ private final LifeSysRoleMenuMapper lifeSysRoleMenuMapper;
|
|
|
+
|
|
|
+ private final LifeSysMenuService lifeSysMenuService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> assignMenus(Long roleId, List<Long> menuIds) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.assignMenus?roleId={}, menuIds={}", roleId, menuIds);
|
|
|
+
|
|
|
+ if (roleId == null) {
|
|
|
+ log.error("角色ID不能为空");
|
|
|
+ return R.fail("角色ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (menuIds == null || menuIds.isEmpty()) {
|
|
|
+ log.warn("菜单ID列表为空,将移除角色的所有菜单");
|
|
|
+ return removeAllMenus(roleId);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 先移除角色的所有菜单
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> deleteWrapper = new LambdaQueryWrapper<>();
|
|
|
+ deleteWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
|
|
|
+ lifeSysRoleMenuMapper.delete(deleteWrapper);
|
|
|
+
|
|
|
+ // 批量分配新菜单
|
|
|
+ for (Long menuId : menuIds) {
|
|
|
+ if (menuId != null) {
|
|
|
+ // 创建新的关联关系
|
|
|
+ LifeSysRoleMenu roleMenu = new LifeSysRoleMenu();
|
|
|
+ roleMenu.setRoleId(roleId);
|
|
|
+ roleMenu.setMenuId(menuId);
|
|
|
+ lifeSysRoleMenuMapper.insert(roleMenu);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("为角色分配菜单成功,角色ID={}, 菜单数量={}", roleId, menuIds.size());
|
|
|
+ return R.success("分配菜单成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("为角色分配菜单失败,角色ID={}", roleId, e);
|
|
|
+ return R.fail("分配菜单失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> removeAllMenus(Long roleId) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.removeAllMenus?roleId={}", roleId);
|
|
|
+
|
|
|
+ if (roleId == null) {
|
|
|
+ log.error("角色ID不能为空");
|
|
|
+ return R.fail("角色ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> deleteWrapper = new LambdaQueryWrapper<>();
|
|
|
+ deleteWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
|
|
|
+ int result = lifeSysRoleMenuMapper.delete(deleteWrapper);
|
|
|
+
|
|
|
+ log.info("移除角色的所有菜单成功,角色ID={}, 删除数量={}", roleId, result);
|
|
|
+ return R.success("移除菜单成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("移除角色的所有菜单失败,角色ID={}", roleId, e);
|
|
|
+ return R.fail("移除菜单失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<List<Long>> getMenuIdsByRoleId(Long roleId) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.getMenuIdsByRoleId?roleId={}", roleId);
|
|
|
+
|
|
|
+ if (roleId == null) {
|
|
|
+ log.error("角色ID不能为空");
|
|
|
+ return R.fail("角色ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
|
|
|
+ List<LifeSysRoleMenu> roleMenuList = lifeSysRoleMenuMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ List<Long> menuIds = roleMenuList.stream()
|
|
|
+ .map(LifeSysRoleMenu::getMenuId)
|
|
|
+ .filter(menuId -> menuId != null)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ log.info("查询角色菜单成功,角色ID={}, 菜单数量={}", roleId, menuIds.size());
|
|
|
+ return R.data(menuIds, "查询成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询角色菜单失败,角色ID={}", roleId, e);
|
|
|
+ return R.fail("查询菜单失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> addMenu(Long roleId, Long menuId) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.addMenu?roleId={}, menuId={}", roleId, menuId);
|
|
|
+
|
|
|
+ if (roleId == null) {
|
|
|
+ log.error("角色ID不能为空");
|
|
|
+ return R.fail("角色ID不能为空");
|
|
|
+ }
|
|
|
+ if (menuId == null) {
|
|
|
+ log.error("菜单ID不能为空");
|
|
|
+ return R.fail("菜单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 检查是否已存在该关联关系
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId)
|
|
|
+ .eq(LifeSysRoleMenu::getMenuId, menuId);
|
|
|
+ LifeSysRoleMenu existing = lifeSysRoleMenuMapper.selectOne(queryWrapper);
|
|
|
+ if (existing != null) {
|
|
|
+ log.warn("角色ID={}已拥有菜单ID={},无需重复添加", roleId, menuId);
|
|
|
+ return R.success("菜单已存在,无需重复添加");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新的关联关系
|
|
|
+ LifeSysRoleMenu roleMenu = new LifeSysRoleMenu();
|
|
|
+ roleMenu.setRoleId(roleId);
|
|
|
+ roleMenu.setMenuId(menuId);
|
|
|
+ int result = lifeSysRoleMenuMapper.insert(roleMenu);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ log.info("为角色添加菜单成功,角色ID={}, 菜单ID={}", roleId, menuId);
|
|
|
+ return R.success("添加菜单成功");
|
|
|
+ } else {
|
|
|
+ return R.fail("添加菜单失败");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("为角色添加菜单失败,角色ID={}, 菜单ID={}", roleId, menuId, e);
|
|
|
+ return R.fail("添加菜单失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<Boolean> removeMenu(Long roleId, Long menuId) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.removeMenu?roleId={}, menuId={}", roleId, menuId);
|
|
|
+
|
|
|
+ if (roleId == null) {
|
|
|
+ log.error("角色ID不能为空");
|
|
|
+ return R.fail("角色ID不能为空");
|
|
|
+ }
|
|
|
+ if (menuId == null) {
|
|
|
+ log.error("菜单ID不能为空");
|
|
|
+ return R.fail("菜单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId)
|
|
|
+ .eq(LifeSysRoleMenu::getMenuId, menuId);
|
|
|
+ int result = lifeSysRoleMenuMapper.delete(queryWrapper);
|
|
|
+
|
|
|
+ if (result > 0) {
|
|
|
+ log.info("移除角色菜单成功,角色ID={}, 菜单ID={}", roleId, menuId);
|
|
|
+ return R.success("移除菜单成功");
|
|
|
+ } else {
|
|
|
+ log.warn("移除角色菜单失败,关联关系不存在,角色ID={}, 菜单ID={}", roleId, menuId);
|
|
|
+ return R.fail("关联关系不存在");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("移除角色菜单失败,角色ID={}, 菜单ID={}", roleId, menuId, e);
|
|
|
+ return R.fail("移除菜单失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<List<Long>> getRoleIdsByMenuId(Long menuId) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.getRoleIdsByMenuId?menuId={}", menuId);
|
|
|
+
|
|
|
+ if (menuId == null) {
|
|
|
+ log.error("菜单ID不能为空");
|
|
|
+ return R.fail("菜单ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeSysRoleMenu::getMenuId, menuId);
|
|
|
+ List<LifeSysRoleMenu> roleMenuList = lifeSysRoleMenuMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ List<Long> roleIds = roleMenuList.stream()
|
|
|
+ .map(LifeSysRoleMenu::getRoleId)
|
|
|
+ .filter(roleId -> roleId != null)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ log.info("查询菜单关联的角色成功,菜单ID={}, 角色数量={}", menuId, roleIds.size());
|
|
|
+ return R.data(roleIds, "查询成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询菜单关联的角色失败,菜单ID={}", menuId, e);
|
|
|
+ return R.fail("查询角色失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<List<MenuWithRoleVo>> getMenusWithRoleStatus(Long roleId) {
|
|
|
+ log.info("LifeSysRoleMenuServiceImpl.getMenusWithRoleStatus?roleId={}", roleId);
|
|
|
+
|
|
|
+ if (roleId == null) {
|
|
|
+ log.error("角色ID不能为空");
|
|
|
+ return R.fail("角色ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 1. 查询所有未删除的菜单
|
|
|
+ R<List<LifeSysMenu>> menuTreeResult = lifeSysMenuService.getMenuTree();
|
|
|
+ if (menuTreeResult == null || menuTreeResult.getData() == null || menuTreeResult.getData().isEmpty()) {
|
|
|
+ log.warn("未查询到任何菜单");
|
|
|
+ return R.data(new ArrayList<>(), "查询成功");
|
|
|
+ }
|
|
|
+ List<LifeSysMenu> allMenus = menuTreeResult.getData();
|
|
|
+
|
|
|
+ // 2. 查询角色已拥有的菜单ID列表
|
|
|
+ LambdaQueryWrapper<LifeSysRoleMenu> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LifeSysRoleMenu::getRoleId, roleId);
|
|
|
+ List<LifeSysRoleMenu> roleMenuList = lifeSysRoleMenuMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ Set<Long> ownedMenuIds = roleMenuList.stream()
|
|
|
+ .map(LifeSysRoleMenu::getMenuId)
|
|
|
+ .filter(menuId -> menuId != null)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ log.info("角色ID={}已拥有的菜单数量={}", roleId, ownedMenuIds.size());
|
|
|
+
|
|
|
+ // 3. 将菜单列表转换为MenuWithRoleVo,并标记是否拥有
|
|
|
+ List<MenuWithRoleVo> menuVoList = convertToMenuWithRoleVo(allMenus, ownedMenuIds);
|
|
|
+
|
|
|
+ // 4. 构建树形结构
|
|
|
+ List<MenuWithRoleVo> treeList = buildMenuTreeWithRole(menuVoList);
|
|
|
+
|
|
|
+ log.info("查询角色权限成功,角色ID={}, 总菜单数={}, 已拥有数={}",
|
|
|
+ roleId, allMenus.size(), ownedMenuIds.size());
|
|
|
+ return R.data(treeList, "查询成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询角色权限失败,角色ID={}", roleId, e);
|
|
|
+ return R.fail("查询权限失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将菜单列表转换为MenuWithRoleVo,并标记是否拥有
|
|
|
+ *
|
|
|
+ * @param menus 菜单列表
|
|
|
+ * @param ownedMenuIds 已拥有的菜单ID集合
|
|
|
+ * @return MenuWithRoleVo列表
|
|
|
+ */
|
|
|
+ private List<MenuWithRoleVo> convertToMenuWithRoleVo(List<LifeSysMenu> menus, Set<Long> ownedMenuIds) {
|
|
|
+ List<MenuWithRoleVo> voList = new ArrayList<>();
|
|
|
+ if (menus == null || menus.isEmpty()) {
|
|
|
+ return voList;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (LifeSysMenu menu : menus) {
|
|
|
+ if (menu == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Boolean hasPermission = ownedMenuIds.contains(menu.getMenuId());
|
|
|
+ MenuWithRoleVo vo = MenuWithRoleVo.fromEntity(menu, hasPermission);
|
|
|
+
|
|
|
+ // 递归处理子菜单
|
|
|
+ if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
|
|
|
+ List<MenuWithRoleVo> children = convertToMenuWithRoleVo(menu.getChildren(), ownedMenuIds);
|
|
|
+ vo.setChildren(children);
|
|
|
+ }
|
|
|
+
|
|
|
+ voList.add(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ return voList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建菜单树形结构(带角色权限标记)
|
|
|
+ *
|
|
|
+ * @param flatList 扁平列表
|
|
|
+ * @return 树形结构列表
|
|
|
+ */
|
|
|
+ private List<MenuWithRoleVo> buildMenuTreeWithRole(List<MenuWithRoleVo> flatList) {
|
|
|
+ if (flatList == null || flatList.isEmpty()) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建映射:ID到节点的映射,父ID到子节点列表的映射
|
|
|
+ Map<Long, MenuWithRoleVo> nodeMap = new HashMap<>();
|
|
|
+ Map<Long, List<MenuWithRoleVo>> parentChildMap = new HashMap<>();
|
|
|
+ List<MenuWithRoleVo> result = new ArrayList<>();
|
|
|
+
|
|
|
+ // 第一步:建立映射关系
|
|
|
+ for (MenuWithRoleVo menu : flatList) {
|
|
|
+ Long menuId = menu.getMenuId();
|
|
|
+ Long parentId = menu.getParentId() != null ? menu.getParentId() : 0L;
|
|
|
+
|
|
|
+ // 存入节点映射
|
|
|
+ nodeMap.put(menuId, menu);
|
|
|
+
|
|
|
+ // 如果是根节点(parentId为0或null),直接添加到结果
|
|
|
+ if (parentId == null || parentId == 0) {
|
|
|
+ result.add(menu);
|
|
|
+ } else {
|
|
|
+ // 否则,记录父子关系
|
|
|
+ parentChildMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(menu);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二步:建立父子关系
|
|
|
+ for (MenuWithRoleVo menu : nodeMap.values()) {
|
|
|
+ Long menuId = menu.getMenuId();
|
|
|
+ if (parentChildMap.containsKey(menuId)) {
|
|
|
+ // 对子节点按排序值排序
|
|
|
+ List<MenuWithRoleVo> children = parentChildMap.get(menuId);
|
|
|
+ children.sort(Comparator.comparing(MenuWithRoleVo::getMenuSort, Comparator.nullsLast(Integer::compareTo)));
|
|
|
+ menu.setChildren(children);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 对根节点按排序值排序
|
|
|
+ result.sort(Comparator.comparing(MenuWithRoleVo::getMenuSort, Comparator.nullsLast(Integer::compareTo)));
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|