MenuService.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. namespace App\Services;
  3. use App\Authority;
  4. use App\Traits\ServiceAppAop;
  5. use App\Menu;
  6. use Illuminate\Database\Eloquent\Collection;
  7. use Illuminate\Support\Facades\Auth;
  8. use Illuminate\Support\Facades\Cache;
  9. class MenuService
  10. {
  11. use ServiceAppAop;
  12. protected $modelClass=Menu::class;
  13. public function getMenu()
  14. {
  15. if (!Cache::has("menus")){
  16. if (Cache::lock("menus",2)){
  17. $this->setMenu();
  18. Cache::lock("menus")->release();
  19. }else{
  20. sleep(1);
  21. return Cache::get("menus") ?? [];
  22. }
  23. }
  24. return Cache::get("menus");
  25. }
  26. public function removeMenuMapping()
  27. {
  28. Cache::tags("AUTHORITY_MENU_MAPPING")->flush();
  29. }
  30. public function setMenu()
  31. {
  32. //如果需要热更新 为所有用户个人菜单锁定缓存 标记TAGS 在此清除 Cache::tag("tags")->flush()
  33. Cache::forever("menus",Menu::query()
  34. ->select("id","name","parent_id","route","font","font_style")
  35. ->orderByRaw("level DESC,sequence")->get());
  36. $this->removeMenuMapping();
  37. }
  38. public function appendMenu(Menu $menu)
  39. {
  40. $menus = $this->getMenu();
  41. if ($menus){
  42. $menus->add($menu);
  43. Cache::forever("menus",$menus);
  44. }
  45. $this->removeMenuMapping();
  46. }
  47. //菜单与权限关联依据为 name与parent_id字段 当两个表中任意此字段发生变更 必须刷掉缓存
  48. public function getVisibleFunctionList($authorities = null,&$mapping = []):array
  49. {
  50. $userId = Auth::id();
  51. $isCache = !$authorities && !$mapping && $userId;
  52. if ($isCache && Cache::tags("AUTHORITY_MENU_MAPPING")->has("am_mapping_".$userId))
  53. return Cache::tags("AUTHORITY_MENU_MAPPING")->get("am_mapping_".$userId);
  54. /** @var Collection $authorities */
  55. if (!$authorities)$authorities = app("AuthorityService")->getUserAuthorityData();
  56. $authMap = app("AuthorityService")->format($authorities);
  57. $menus = $this->format($this->getMenu());
  58. $result = array_values($this->formatMenu($menus,$authMap,$mapping));
  59. if ($isCache)Cache::tags("AUTHORITY_MENU_MAPPING")->forever("am_mapping_".$userId,$result);
  60. return $result;
  61. }
  62. public function getVisibleMenuListAll()
  63. {
  64. $key = "am_mapping_all";
  65. if (Cache::tags("AUTHORITY_MENU_MAPPING")->has($key))
  66. return Cache::tags("AUTHORITY_MENU_MAPPING")->get($key);
  67. /** @var Collection $authorities */
  68. $authorities = app("AuthorityService")->getUserAuthorityData(true); //获取超管权限(全量)
  69. $authMap = app("AuthorityService")->format($authorities);
  70. $menus = $this->format($this->getMenu());//菜单权限(全量)
  71. $result = array_values($this->formatMenu($menus,$authMap));
  72. Cache::tags("AUTHORITY_MENU_MAPPING")->forever($key,$result);
  73. return $result;
  74. }
  75. /**
  76. * 格式化为树状结构
  77. *
  78. * @param Collection $menus
  79. * @return array
  80. */
  81. public function format(Collection $menus):array
  82. {
  83. $menuMap = [];
  84. foreach ($menus as $menu){
  85. $menuMap[$menu->id] = [
  86. "id" => $menu->id,
  87. "child" => [],
  88. "name" => $menu->name,
  89. "font" => $menu->font,
  90. "fontStyle" => $menu->font_style,
  91. "route" => $menu->route,
  92. ];
  93. }
  94. foreach ($menus as $menu){
  95. if ($menu->parent_id){
  96. $menuMap[$menu->parent_id]["child"][] = $menuMap[$menu->id];
  97. unset($menuMap[$menu->id]);
  98. }
  99. }
  100. return $menuMap;
  101. }
  102. /**
  103. * 递归格式化菜单组
  104. *
  105. * @param array $menus
  106. * @param array $authorities
  107. * @param array $mapping
  108. *
  109. * @return array
  110. */
  111. private function formatMenu(array $menus,array $authorities,array &$mapping=[]):array
  112. {
  113. foreach ($menus as $index=>$menu){
  114. $mark = false;
  115. foreach ($authorities as $j=>$authority){
  116. if ($menu["name"] == $authority["name"]){
  117. $mapping[$menu["id"]] = $authority["id"];
  118. $menus[$index]["authId"] = $authority["id"];
  119. $mark = true;
  120. $authorities[$j]["mark"] = true;
  121. if ($authority["child"])$menus[$index]["child"] = array_values($this->formatMenu($menu["child"],$authority["child"],$mapping));
  122. }
  123. }
  124. if (!$mark)unset($menus[$index]);
  125. }
  126. foreach ($authorities as $authority){
  127. if (!isset($authority["mark"])){
  128. $menus[] = [
  129. "name" => $authority["name"],
  130. "route" => "",
  131. ];
  132. }
  133. }
  134. return $menus;
  135. }
  136. /**
  137. * 获取菜单与权限映射
  138. */
  139. public function getMenuAndAuthorityMapping():array
  140. {
  141. $mapping = [];
  142. $this->getVisibleFunctionList(Authority::query()->get(),$mapping);
  143. return $mapping;
  144. }
  145. /**
  146. * 获取唯一名称
  147. */
  148. public function getUniqueName(Menu $menu)
  149. {
  150. if (!$menu->parent_id)return $menu->name;
  151. $menus = $this->getMenu();
  152. $menuMap = [];
  153. foreach ($menus as $m)$menuMap[$m->id] = $m;
  154. $names = [];
  155. while ($menu){
  156. $names[] = $menu->name;
  157. if ($menu->parent_id)$menu = $menuMap[$menu->parent_id] ?? null;
  158. else $menu = null;
  159. }
  160. $name = "";
  161. for ($i=count($names)-1;$i>=0;$i--){
  162. $name .= $names[$i];
  163. if ($i!=0)$name .= "-";
  164. }
  165. return $name;
  166. }
  167. }