调整Laravel-admin菜单层级需确保admin_menu表含nullable parent_id字段并建索引,重写Menu::allNodes()方法支持动态筛选,严格设置父子ID关系,配合权限字段与中间件控制子菜单显示。

要调整 Laravel-admin 的菜单层级父子关系,核心在于修改菜单数据的存储结构和渲染逻辑,而不是单纯改前端显示。菜单本身是树形结构,必须靠 parent_id 字段支撑,同时配合模型方法和配置才能正确识别父子、展开子项、控制权限可见性。
确保菜单表支持父子结构
默认的 admin_menu 表需包含 parent_id 字段,且允许为 NULL(根菜单无父级):
- 迁移中应定义为:
$table->foreignId('parent_id')->nullable()->constrained('admin_menu')->nullOnDelete(); - 字段类型必须是整型(如
bigInteger),不能用字符串或 UUID,否则关联查询会静默失败 - 给
parent_id加索引:$table->index('parent_id');,否则深层菜单加载时性能明显下降
重写菜单模型的 allNodes 方法
菜单渲染依赖 Encore\Admin\Auth\Database\Menu::allNodes()。若需按业务动态控制层级(比如多租户/多应用),可继承该模型并重写此方法:
- 新建自定义菜单模型,例如
App\Models\AdminMenu,继承Encore\Admin\Auth\Database\Menu - 在其中覆盖
allNodes(),加入自己的筛选逻辑,如:where('app_id', session('current_app_id'))或with(['children' => fn($q) => $q->orderBy('order')]) - 在
config/admin.php中更新配置:'menu_model' => App\Models\AdminMenu::class
正确设置父子关系数据
菜单数据插入或编辑时,必须严格遵循树形规则:
- 根菜单:
parent_id必须为NULL(不是 0 或空字符串) - 子菜单:
parent_id值必须指向一个真实存在的菜单 ID,否则前端无法展开 - 推荐使用
ModelTree工具批量管理:在后台菜单管理页启用拖拽排序,它会自动调用saveOrder()更新parent_id和排序字段
控制子菜单是否显示及权限联动
子菜单是否渲染、是否可访问,不仅取决于数据库结构,还受权限系统影响:
- 每个菜单项应绑定
permission字段(如'users.index'),并在路由中对应使用can:users.index中间件 - 父菜单若设了权限,子菜单不会自动继承;需为每个子项单独分配权限,或在
allNodes()中做权限过滤(如只返回当前用户can()的节点) - 若想实现“有任意子权限才显示父菜单”,可在自定义模型中增加判断逻辑:
->whereHas('children', fn($q) => $q->whereHasPermission())


















