MenuService.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. declare (strict_types=1);
  3. namespace app\service;
  4. use app\service\PermissionService;
  5. use think\facade\Config;
  6. class MenuService
  7. {
  8. /**
  9. * 获取所有菜单配置
  10. */
  11. public static function getAllMenus(): array
  12. {
  13. return Config::get('menu.menus', []);
  14. }
  15. /**
  16. * 获取用户菜单列表(基于权限过滤)
  17. */
  18. public static function getUserMenus(int $userId): array
  19. {
  20. $roleId = getUserRoleId($userId);
  21. if (!$roleId) {
  22. return [];
  23. }
  24. // 超级管理员返回所有菜单
  25. if (PermissionService::isSuperAdmin($roleId)) {
  26. return self::getAllMenus();
  27. }
  28. // 获取用户权限
  29. $permissions = PermissionService::getUserPermissions($roleId);
  30. // 获取所有菜单并根据权限过滤
  31. $allMenus = self::getAllMenus();
  32. return self::buildMenuTree(self::filterMenusByPermissions($allMenus, $permissions));
  33. }
  34. /**
  35. * 根据权限过滤菜单
  36. */
  37. private static function filterMenusByPermissions(array $menus, array $permissions): array
  38. {
  39. $filtered = [];
  40. foreach ($menus as $menu) {
  41. // 如果有子菜单,先递归过滤子菜单
  42. if (!empty($menu['children'])) {
  43. $filteredChildren = self::filterMenusByPermissions($menu['children'], $permissions);
  44. // 如果子菜单被过滤后还有内容,则保留父菜单
  45. if (!empty($filteredChildren)) {
  46. $menu['children'] = $filteredChildren;
  47. $filtered[] = $menu;
  48. }
  49. }
  50. // 如果菜单有控制器,检查用户是否有该控制器的任意权限
  51. elseif (!empty($menu['controller'])) {
  52. if (self::hasControllerPermission($menu['controller'], $permissions)) {
  53. $filtered[] = $menu;
  54. }
  55. }
  56. // 没有控制器也没有子菜单的菜单(可能是分隔符或静态链接)
  57. else {
  58. $filtered[] = $menu;
  59. }
  60. }
  61. return $filtered;
  62. }
  63. /**
  64. * 检查用户是否有指定控制器的任意权限
  65. */
  66. private static function hasControllerPermission(string $controller, array $permissions): bool
  67. {
  68. $controllerLower = strtolower($controller);
  69. // 检查用户权限中是否有该控制器的任意操作权限
  70. foreach ($permissions as $permission) {
  71. // 权限格式: controller.action
  72. if (strpos($permission, $controllerLower . '.') === 0) {
  73. return true;
  74. }
  75. }
  76. return false;
  77. }
  78. /**
  79. * 获取菜单树形结构(用于前端展示)
  80. */
  81. public static function getMenuTree(int $userId): array
  82. {
  83. $menus = self::getUserMenus($userId);
  84. return self::buildMenuTree($menus);
  85. }
  86. /**
  87. * 构建菜单树
  88. */
  89. private static function buildMenuTree(array $menus): array
  90. {
  91. $tree = [];
  92. foreach ($menus as $menu) {
  93. $node = [
  94. 'title' => $menu['title'],
  95. 'icon' => $menu['icon'] ?? '',
  96. 'url' => $menu['url'] ?? '',
  97. ];
  98. if (!empty($menu['children'])) {
  99. $node['children'] = self::buildMenuTree($menu['children']);
  100. }
  101. $tree[] = $node;
  102. }
  103. return $tree;
  104. }
  105. /**
  106. * 根据ID获取菜单
  107. */
  108. public static function getMenuById(int $menuId): ?array
  109. {
  110. return self::findMenuInTree(self::getAllMenus(), $menuId);
  111. }
  112. /**
  113. * 在菜单树中查找指定ID的菜单
  114. */
  115. private static function findMenuInTree(array $menus, int $menuId): ?array
  116. {
  117. foreach ($menus as $menu) {
  118. if ($menu['id'] == $menuId) {
  119. return $menu;
  120. }
  121. if (!empty($menu['children'])) {
  122. $found = self::findMenuInTree($menu['children'], $menuId);
  123. if ($found) {
  124. return $found;
  125. }
  126. }
  127. }
  128. return null;
  129. }
  130. }