You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.9 KiB
102 lines
2.9 KiB
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\AdminUser;
|
|
use App\Models\Menu;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class AdminMenuService
|
|
{
|
|
/** @return array<int, array<string, mixed>> */
|
|
public function treeForUser(AdminUser $user): array
|
|
{
|
|
$menus = $this->menusQueryForUser($user);
|
|
$tree = $this->buildTree($menus);
|
|
|
|
return $tree->values()->all();
|
|
}
|
|
|
|
protected function menusQueryForUser(AdminUser $user): Collection
|
|
{
|
|
$base = Menu::query()->where('status', 1)->orderBy('sort');
|
|
|
|
if ($user->isSuperAdmin()) {
|
|
return $base->get();
|
|
}
|
|
|
|
$roleIds = $user->roles()->where('status', 1)->pluck('id');
|
|
$menuIds = DB::table('role_menus')
|
|
->whereIn('role_id', $roleIds)
|
|
->pluck('menu_id')
|
|
->unique()
|
|
->all();
|
|
|
|
if ($menuIds === []) {
|
|
return collect();
|
|
}
|
|
|
|
$expandedIds = $this->expandMenuParents($menuIds);
|
|
|
|
return $base->whereIn('id', $expandedIds)->get();
|
|
}
|
|
|
|
/**
|
|
* @param array<int, int> $menuIds
|
|
* @return array<int, int>
|
|
*/
|
|
protected function expandMenuParents(array $menuIds): array
|
|
{
|
|
$idSet = collect($menuIds)->flip()->all();
|
|
$queue = $menuIds;
|
|
|
|
while ($queue !== []) {
|
|
$id = array_pop($queue);
|
|
$m = Menu::query()->find($id);
|
|
if ($m && $m->parent_id && ! isset($idSet[$m->parent_id])) {
|
|
$idSet[$m->parent_id] = 0;
|
|
$queue[] = $m->parent_id;
|
|
}
|
|
}
|
|
|
|
return array_map('intval', array_keys($idSet));
|
|
}
|
|
|
|
/**
|
|
* @param Collection<int, Menu> $menus
|
|
* @return \Illuminate\Support\Collection<int, array<string, mixed>>
|
|
*/
|
|
protected function buildTree(Collection $menus): Collection
|
|
{
|
|
$byParent = $menus->groupBy(fn (Menu $m) => $m->parent_id ?? 0);
|
|
|
|
$build = function ($parentId) use (&$build, $byParent): Collection {
|
|
return ($byParent->get($parentId, collect()))->map(function (Menu $m) use (&$build) {
|
|
$node = [
|
|
'id' => $m->id,
|
|
'parent_id' => $m->parent_id,
|
|
'path' => $m->path,
|
|
'name' => $m->name,
|
|
'title' => $m->title,
|
|
'component' => $m->component,
|
|
'icon' => $m->icon,
|
|
'sort' => $m->sort,
|
|
'visible' => $m->visible,
|
|
'keep_alive' => $m->keep_alive,
|
|
'permission_code' => $m->permission_code,
|
|
'status' => (int) $m->status,
|
|
];
|
|
$children = $build($m->id);
|
|
if ($children->isNotEmpty()) {
|
|
$node['children'] = $children->values()->all();
|
|
}
|
|
|
|
return $node;
|
|
});
|
|
};
|
|
|
|
return $build(0);
|
|
}
|
|
}
|