generated from liutk/owl-admin-base
重写菜单
parent
fc1c764d91
commit
aaacc371f7
|
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
|
||||
class Menu
|
||||
{
|
||||
protected array $menus = [];
|
||||
|
||||
public function all()
|
||||
{
|
||||
$menus = $this->userMenus()
|
||||
->push(...array_map(fn($item) => $this->formatItem($item), $this->menus))
|
||||
->sortBy('order')
|
||||
->values()
|
||||
->toArray();
|
||||
|
||||
return array_merge($this->list2Menu($menus), $this->extra());
|
||||
}
|
||||
|
||||
private function userMenus()
|
||||
{
|
||||
/** @var \App\Models\AdminUser */
|
||||
$user = Admin::user();
|
||||
|
||||
return $user->allMenus();
|
||||
}
|
||||
|
||||
private function list2Menu($list, $parentId = 0, $parentName = ''): array
|
||||
{
|
||||
$data = [];
|
||||
foreach ($list as $key => $item) {
|
||||
if ($item['parent_id'] == $parentId) {
|
||||
$idStr = "[{$item['id']}]";
|
||||
$_temp = [
|
||||
'name' => $parentName ? $parentName . '-' . $idStr : $idStr,
|
||||
'path' => $item['url'],
|
||||
'component' => data_get($item, 'component') ?? 'amis',
|
||||
'is_home' => $item['is_home'],
|
||||
'is_full' => $item['is_full'] ?? 0,
|
||||
'is_link' => $item['url_type'] == Admin::adminMenuModel()::TYPE_LINK,
|
||||
'meta' => [
|
||||
'title' => $item['title'],
|
||||
'icon' => $item['icon'] ?? '-',
|
||||
'hide' => $item['visible'] == 0,
|
||||
'order' => $item['order'],
|
||||
],
|
||||
];
|
||||
|
||||
$children = $this->list2Menu($list, (int)$item['id'], $_temp['name']);
|
||||
|
||||
if (!empty($children)) {
|
||||
$_temp['component'] = 'amis';
|
||||
$_temp['children'] = $children;
|
||||
}
|
||||
|
||||
$data[] = $_temp;
|
||||
if (!in_array($_temp['path'], Admin::config('admin.route.without_extra_routes'))) {
|
||||
array_push($data, ...$this->generateRoute($_temp));
|
||||
}
|
||||
unset($list[$key]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function generateRoute($item): array
|
||||
{
|
||||
$url = $item['path'] ?? '';
|
||||
$url = preg_replace('/\?.*/', '', $url);
|
||||
|
||||
if (!$url || array_key_exists('children', $item)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$menu = fn($action, $path) => [
|
||||
'name' => $item['name'] . '-' . $action,
|
||||
'path' => $url . $path,
|
||||
'component' => 'amis',
|
||||
'meta' => [
|
||||
'hide' => true,
|
||||
'icon' => Arr::get($item, 'meta.icon'),
|
||||
'title' => Arr::get($item, 'meta.title') . ' - ' . __('admin.' . $action),
|
||||
],
|
||||
];
|
||||
|
||||
return [
|
||||
$menu('create', '/create'),
|
||||
$menu('show', '/:id'),
|
||||
$menu('edit', '/:id/edit'),
|
||||
];
|
||||
}
|
||||
|
||||
public function add($menus)
|
||||
{
|
||||
$this->menus = array_merge($this->menus, $menus);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function formatItem($item)
|
||||
{
|
||||
return array_merge([
|
||||
'title' => '',
|
||||
'url' => '',
|
||||
'url_type' => 1,
|
||||
'icon' => '',
|
||||
'parent_id' => 0,
|
||||
'id' => 999,
|
||||
'is_home' => 0,
|
||||
'visible' => 1,
|
||||
'order' => 99,
|
||||
], $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 额外菜单
|
||||
*
|
||||
* @return array|array[]
|
||||
*/
|
||||
private function extra()
|
||||
{
|
||||
$extraMenus = [
|
||||
[
|
||||
'name' => 'user_setting',
|
||||
'path' => '/user_setting',
|
||||
'component' => 'amis',
|
||||
'meta' => [
|
||||
'hide' => true,
|
||||
'title' => __('admin.user_setting'),
|
||||
'icon' => 'material-symbols:manage-accounts',
|
||||
'singleLayout' => 'basic',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
if (Admin::config('admin.show_development_tools')) {
|
||||
$extraMenus = array_merge($extraMenus, $this->devToolMenus());
|
||||
}
|
||||
|
||||
return $extraMenus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开发者工具菜单
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
private function devToolMenus()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'dev_tools',
|
||||
'path' => '/dev_tools',
|
||||
'component' => 'amis',
|
||||
'meta' => [
|
||||
'title' => __('admin.developer'),
|
||||
'icon' => 'fluent:window-dev-tools-20-regular',
|
||||
],
|
||||
'children' => [
|
||||
[
|
||||
'name' => 'dev_tools_extensions',
|
||||
'path' => '/dev_tools/extensions',
|
||||
'component' => 'amis',
|
||||
'meta' => [
|
||||
'title' => __('admin.extensions.menu'),
|
||||
'icon' => 'ion:extension-puzzle-outline',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'dev_tools_code_generator',
|
||||
'path' => '/dev_tools/code_generator',
|
||||
'component' => 'amis',
|
||||
'meta' => [
|
||||
'title' => __('admin.code_generator'),
|
||||
'icon' => 'ic:baseline-code',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'dev_tools_editor',
|
||||
'path' => '/dev_tools/editor',
|
||||
'component' => 'editor',
|
||||
'meta' => [
|
||||
'title' => __('admin.visual_editor'),
|
||||
'icon' => 'mdi:monitor-edit',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Models\AdminRole as Model;
|
||||
|
||||
class AdminRole extends Model
|
||||
{
|
||||
protected static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleting(function (AdminRole $model) {
|
||||
$model->menus()->detach();
|
||||
$model->permissions()->detach();
|
||||
});
|
||||
}
|
||||
|
||||
public function menus(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Admin::adminMenuModel()::class, 'admin_role_menus', 'role_id', 'menu_id');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Collection;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Models\AdminUser as Model;
|
||||
|
||||
class AdminUser extends Model
|
||||
{
|
||||
public function roles(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Admin::adminRoleModel(), 'admin_role_users', 'user_id', 'role_id')->withTimestamps();
|
||||
}
|
||||
|
||||
public function allMenus(): Collection
|
||||
{
|
||||
$model = Admin::adminMenuModel();
|
||||
$allMenus = $model::all()->keyBy($this->getKeyName());
|
||||
|
||||
if ($this->isAdministrator()) {
|
||||
return $allMenus;
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$roleMenus = $this->roles
|
||||
->pluck('menus')
|
||||
->flatten()
|
||||
->keyBy($this->getKeyName());
|
||||
|
||||
$allRoleMenus = $roleMenus->collect();
|
||||
|
||||
foreach ($roleMenus as $roleMenu) {
|
||||
if (is_null($roleMenu->parent_id) || $allRoleMenus->has($roleMenu->parent_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parent = $allMenus->get($roleMenu->parent_id);
|
||||
|
||||
while ($parent) {
|
||||
$allRoleMenus->put($parent->id, $parent);
|
||||
|
||||
if (is_null($parent->parent_id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$parent = $allMenus->get($parent->parent_id);
|
||||
};
|
||||
}
|
||||
|
||||
unset($allMenus, $roleMenus);
|
||||
|
||||
return $allRoleMenus;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,8 +11,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
|
||||
$this->app->singleton('admin.menu', \App\Admin\Menu::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ return [
|
|||
'providers' => [
|
||||
'admin' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
|
||||
'model' => \App\Models\AdminUser::class,
|
||||
],
|
||||
],
|
||||
'except' => [
|
||||
|
|
@ -108,8 +108,8 @@ return [
|
|||
],
|
||||
|
||||
'models' => [
|
||||
'admin_user' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
|
||||
'admin_role' => \Slowlyo\OwlAdmin\Models\AdminRole::class,
|
||||
'admin_user' => \App\Models\AdminUser::class,
|
||||
'admin_role' => \App\Models\AdminRole::class,
|
||||
'admin_menu' => \Slowlyo\OwlAdmin\Models\AdminMenu::class,
|
||||
'admin_permission' => \Slowlyo\OwlAdmin\Models\AdminPermission::class,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admin_menus', function (Blueprint $table) {
|
||||
$table->string('slug')->unique()->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('admin_menus', function (Blueprint $table) {
|
||||
$table->dropColumn(['slug']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admin_permissions', function (Blueprint $table) {
|
||||
$table->dropUnique(['name']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('admin_permissions', function (Blueprint $table) {
|
||||
$table->unique(['name']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('admin_permissions', function (Blueprint $table) {
|
||||
$table->string('slug')->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('admin_permissions', function (Blueprint $table) {
|
||||
$table->string('slug', 50)->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admin_role_menus', function (Blueprint $table) {
|
||||
$table->integer('role_id');
|
||||
$table->integer('menu_id');
|
||||
$table->index(['role_id', 'menu_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_role_menus');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Slowlyo\OwlAdmin\Models\AdminMenu;
|
||||
use Slowlyo\OwlAdmin\Models\AdminPermission;
|
||||
|
||||
class AdminPermissionSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 主页
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'home' => [
|
||||
'name' => '主页',
|
||||
'icon' => 'line-md:home-twotone-alt',
|
||||
'uri' => '/',
|
||||
'children' => [],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 系统管理
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'system' => [
|
||||
'name' => '系统管理',
|
||||
'icon' => 'material-symbols:settings-outline',
|
||||
'uri' => '',
|
||||
'children' => [
|
||||
'admin_users' => [
|
||||
'name' => '账号管理',
|
||||
'icon' => 'ph:user-gear',
|
||||
'uri' => '/system/admin_users',
|
||||
'resource' => ['list', 'create', 'update', 'delete'],
|
||||
'children' => ['change_password' => '修改密码'],
|
||||
],
|
||||
'admin_roles' => [
|
||||
'name' => '角色管理',
|
||||
'icon' => 'carbon:user-role',
|
||||
'uri' => '/system/admin_roles',
|
||||
'resource' => ['list', 'create', 'update', 'delete'],
|
||||
'children' => [
|
||||
'set_menus' => '设置菜单',
|
||||
'set_permissions' => '设置权限',
|
||||
],
|
||||
],
|
||||
'admin_permissions' => [
|
||||
'name' => '权限管理',
|
||||
'icon' => 'fluent-mdl2:permissions',
|
||||
'uri' => '/system/admin_permissions',
|
||||
'resource' => ['list', 'create', 'update', 'delete'],
|
||||
'children' => [],
|
||||
],
|
||||
'admin_menus' => [
|
||||
'name' => '菜单管理',
|
||||
'icon' => 'ant-design:menu-unfold-outlined',
|
||||
'uri' => '/system/admin_menus',
|
||||
'resource' => ['list', 'create', 'update', 'delete'],
|
||||
'children' => [],
|
||||
],
|
||||
'settings' => [
|
||||
'name' => '系统设置',
|
||||
'icon' => 'akar-icons:settings-horizontal',
|
||||
'uri' => '/system/settings',
|
||||
'resource' => true,
|
||||
'children' => [],
|
||||
],
|
||||
'keywords' => [
|
||||
'name' => '数据字典',
|
||||
'icon' => 'ph:codesandbox-logo-light',
|
||||
'uri' => '/system/keywords',
|
||||
'resource' => ['list', 'create', 'update', 'delete'],
|
||||
'children' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$this->handleAdminMenus($data);
|
||||
$this->handleAdminPermissions($data);
|
||||
}
|
||||
|
||||
public function handleAdminMenus(array $data, ?AdminMenu $parent = null): void
|
||||
{
|
||||
foreach ($data as $slug => $node) {
|
||||
if (! is_array($node) || ! array_key_exists('uri', $node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var \Slowlyo\OwlAdmin\Models\AdminMenu */
|
||||
$menu = AdminMenu::updateOrCreate([
|
||||
'slug' => ($parent->slug ?? 'admin').'.'.$slug,
|
||||
], [
|
||||
'parent_id' => $parent->id ?? 0,
|
||||
'order' => $node['order'] ?? 0,
|
||||
'title' => $node['name'],
|
||||
'icon' => $node['icon'],
|
||||
'url' => $node['uri'],
|
||||
'url_type' => $node['uri_type'] ?? 1,
|
||||
'visible' => $node['visible'] ?? 1,
|
||||
'is_home' => $node['is_home'] ?? 0,
|
||||
'is_full' => $node['is_full'] ?? 0,
|
||||
]);
|
||||
|
||||
$this->handleAdminMenus($node['children'] ?? [], $menu);
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleAdminPermissions(array $data, ?AdminPermission $parent = null)
|
||||
{
|
||||
foreach ($data as $slug => $node) {
|
||||
$permission = AdminPermission::updateOrCreate([
|
||||
'slug' => ($parent->slug ?? 'admin') . '.' . $slug,
|
||||
], [
|
||||
'parent_id' => $parent->id ?? 0,
|
||||
'name' => is_array($node) ? $node['name'] : $node,
|
||||
]);
|
||||
|
||||
if (! is_array($node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 资源路由权限
|
||||
if (array_key_exists('resource', $node)) {
|
||||
$resourceAbilities = [];
|
||||
|
||||
if (is_array($node['resource'])) {
|
||||
$resourceAbilities = $node['resource'];
|
||||
} elseif ($node['resource'] === true) {
|
||||
$resourceAbilities = array_keys($this->resourceAbilityMap());
|
||||
}
|
||||
|
||||
foreach ($resourceAbilities as $resourceAbility) {
|
||||
AdminPermission::updateOrCreate([
|
||||
'slug' => $permission->slug . '.' . $resourceAbility,
|
||||
], [
|
||||
'parent_id' => $permission->id,
|
||||
'name' => $this->resourceAbilityMap()[$resourceAbility],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->handleAdminPermissions($node['children'] ?? [], $permission);
|
||||
}
|
||||
}
|
||||
|
||||
protected function resourceAbilityMap(): array
|
||||
{
|
||||
return [
|
||||
'list' => '列表',
|
||||
'create' => '新增',
|
||||
'update' => '编辑',
|
||||
'delete' => '删除',
|
||||
'view' => '查看',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ class AdminSeeder extends Seeder
|
|||
{
|
||||
$this->call([
|
||||
KeywordSeeder::class,
|
||||
AdminPermissionSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue