基础权限控制

main
Jing Li 2024-03-23 22:01:30 +08:00
parent 970cef0c32
commit 1200bfb1bf
13 changed files with 879 additions and 73 deletions

View File

@ -14,7 +14,7 @@ class Components extends BaseRenderer
public function parentControl($apiUrl = null, $name = 'parent_id', $label = null, $labelField = 'name', $valueField = 'id')
{
return amisMake()->TreeSelectControl()->source($apiUrl)
->name($name)->label($label ?? __('admin.components.parent_select'))
->name($name)->label($label ?? __('admin.parent'))
->showIcon(false)
->labelField($labelField)
->valueField($valueField);
@ -135,10 +135,10 @@ class Components extends BaseRenderer
if ($color) {
$tag = amisMake()->Tag()->label($label ?? __('admin.components.tag'))
->displayMode('rounded')->style([
'color' => '#fff',
'backgroundColor' => $color,
'borderColor' => $color,
]);
'color' => '#fff',
'backgroundColor' => $color,
'borderColor' => $color,
]);
} else {
$tag = amisMake()->Tag()->label($label ?? __('admin.components.tag'))
->displayMode('rounded')->color('inactive');

View File

@ -1,50 +0,0 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Controllers\AdminRoleController as AdminRoleBaseController;
use Slowlyo\OwlAdmin\Renderers\Page;
class AdminRoleController extends AdminRoleBaseController
{
public function list(): Page
{
$crud = $this->baseCRUD()
->headerToolbar([
$this->createButton(true),
...$this->baseHeaderToolBar(),
])
->filterTogglable(false)
->itemCheckableOn('${id !== 1}')
->columns([
amis()->TableColumn()->label('ID')->name('id')->sortable(),
amis()->TableColumn()->label(__('admin.admin_role.name'))->name('name'),
amis()->TableColumn()->label(__('admin.admin_role.slug'))->name('slug')->type('tag'),
amis()->TableColumn()
->label(__('admin.created_at'))
->name('created_at')
->type('datetime')
->sortable(true),
amis()->TableColumn()
->label(__('admin.updated_at'))
->name('updated_at')
->type('datetime')
->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->setPermission()->visibleOn('${slug != "administrator"}'),
$this->rowEditButton(true)->visibleOn('${slug != "administrator"}'),
$this->rowDeleteButton()->visibleOn('${slug != "administrator"}'),
]),
]);
return $this->baseList($crud)->css([
'.tree-full' => [
'overflow' => 'hidden !important',
],
'.cxd-TreeControl > .cxd-Tree' => [
'height' => '100% !important',
'max-height' => '100% !important',
],
]);
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace App\Admin\Controllers\System;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Services\AdminMenuService;
/**
* @property AdminMenuService $service
*/
class AdminMenuController extends AdminController
{
protected string $serviceName = AdminMenuService::class;
public function list(): Page
{
$crud = $this->baseCRUD()
->loadDataOnce()
->syncLocation(false)
->footerToolbar([])
->headerToolbar([
$this->createButton(true, 'lg')->visible(Admin::user()->can('admin.system.admin_menus.create')),
...$this->baseHeaderToolBar(),
])
->filterTogglable(false)
->footerToolbar(['statistics'])
->bulkActions([
$this->bulkDeleteButton()->reload('window')->visible(Admin::user()->can('admin.system.admin_menus.delete')),
])
->columns([
amis()->TableColumn('id', 'ID')->sortable(),
amis()->TableColumn('title', __('admin.admin_menu.title')),
amis()->TableColumn('icon', __('admin.admin_menu.icon'))
->type('flex')
->justify('start')
->items([
amis()->SvgIcon()->icon('${icon}')->className('mr-2 text-lg'),
'${icon}',
]),
amis()->TableColumn('url', __('admin.admin_menu.url')),
amis()->TableColumn('order', __('admin.admin_menu.order'))->quickEdit(
amis()->NumberControl()->min(0)->saveImmediately(true)
),
amis()->TableColumn('visible', __('admin.admin_menu.visible'))->quickEdit(
amis()->SwitchControl()->mode('inline')->saveImmediately(true)
),
amis()->TableColumn('is_home', __('admin.admin_menu.is_home'))->quickEdit(
amis()->SwitchControl()->mode('inline')->saveImmediately(true)
),
$this->rowActions([
$this->rowEditButton(true, 'lg')->visible(Admin::user()->can('admin.system.admin_menus.update')),
$this->rowDeleteButton()->visible(Admin::user()->can('admin.system.admin_menus.delete')),
]),
]);
return $this->baseList($crud);
}
public function form(): Form
{
return $this->baseForm()->body([
amis()->GroupControl()->body([
amis()->TextControl('title', __('admin.admin_menu.title'))->required(),
amis()->TextControl('icon', __('admin.admin_menu.icon'))
->description(
__('admin.admin_menu.icon_description').
'<a href="https://icones.js.org/collection/all" target="_blank"> https://icones.js.org</a>'
),
]),
amis()->GroupControl()->body([
amis()->TreeSelectControl('parent_id', __('admin.admin_menu.parent_id'))
->labelField('title')
->valueField('id')
->showIcon(false)
->value(0)
->source('/system/admin_menus?_action=getData'),
amis()
->TextControl('component', __('admin.admin_menu.component'))
->description(__('admin.admin_menu.component_desc'))
->value('amis'),
]),
amis()->TextControl('url', __('admin.admin_menu.url'))
->required()
->validateOnChange()
->validations(['matchRegexp' => '/^(http(s)?\:\/)?(\/)+/'])
->validationErrors(['matchRegexp' => __('admin.need_start_with_slash')])
->placeholder('eg: /admin_menus'),
amis()->NumberControl('order', __('admin.admin_menu.order'))
->required()
->displayMode('enhance')
->description(__('admin.order_asc'))
->min(0)
->value(0),
amis()->ListControl('url_type', __('admin.admin_menu.type'))
->options(Admin::adminMenuModel()::getType())
->value(Admin::adminMenuModel()::TYPE_ROUTE),
amis()->SwitchControl('visible', __('admin.admin_menu.visible'))
->onText(__('admin.admin_menu.show'))
->offText(__('admin.admin_menu.hide'))
->value(1),
amis()->SwitchControl('is_home', __('admin.admin_menu.is_home'))
->onText(__('admin.yes'))
->offText(__('admin.no'))
->description(__('admin.admin_menu.is_home_description'))
->value(0),
amis()->SwitchControl('is_full', __('admin.admin_menu.is_full'))
->onText(__('admin.yes'))
->offText(__('admin.no'))
->description(__('admin.admin_menu.is_full_description'))
->value(0),
])->onEvent([
'submitSucc' => [
'actions' => [
'actionType' => 'custom',
'script' => 'window.location.reload()',
],
],
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,224 @@
<?php
namespace App\Admin\Controllers\System;
use App\Admin\Services\AdminMenuService;
use App\Admin\Services\AdminPermissionService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Tag;
/**
* @property AdminPermissionService $service
*/
class AdminPermissionController extends AdminController
{
protected string $serviceName = AdminPermissionService::class;
public function list(): Page
{
$crud = $this->baseCRUD()
->loadDataOnce()
->filterTogglable(false)
->footerToolbar([])
->headerToolbar([
$this->createButton(true, 'lg')->visible(Admin::user()->can('admin.system.admin_permissions.create')),
'bulkActions',
amis('reload')->align('right'),
amis('filter-toggler')->align('right'),
])
->bulkActions([
$this->bulkDeleteButton()->visible(Admin::user()->can('admin.system.admin_permissions.delete')),
])
->columns([
amis()->TableColumn('id', 'ID')->sortable(),
amis()->TableColumn('name', __('admin.admin_permission.name')),
amis()->TableColumn('slug', __('admin.admin_permission.slug')),
amis()->TableColumn('http_method', __('admin.admin_permission.http_method'))
->type('each')
->items(
Tag::make()->label('${item}')->className('my-1')
)
->placeholder(Tag::make()->label('ANY')),
amis()->TableColumn('http_path', __('admin.admin_permission.http_path'))
->type('each')
->items(
Tag::make()->label('${item}')->className('my-1')
),
$this->rowActions([
$this->rowEditButton(true, 'lg')->visible(Admin::user()->can('admin.system.admin_permissions.update')),
$this->rowDeleteButton()->visible(Admin::user()->can('admin.system.admin_permissions.delete')),
]),
]);
return $this->baseList($crud);
}
public function form(): Form
{
return $this->baseForm()->body([
amis()->TextControl('name', __('admin.admin_permission.name'))->required(),
amis()->TextControl('slug', __('admin.admin_permission.slug'))->required(),
amis()->TreeSelectControl('parent_id', __('admin.parent'))
->labelField('name')
->valueField('id')
->value(0)
->options($this->service->getTree()),
amis()->CheckboxesControl('http_method', __('admin.admin_permission.http_method'))
->options($this->getHttpMethods())
->description(__('admin.admin_permission.http_method_description'))
->joinValues(false)
->extractValue(),
amis()->NumberControl('order', __('admin.order'))
->required()
->labelRemark(__('admin.order_asc'))
->displayMode('enhance')
->min(0)
->value(0),
amis()->ArrayControl('http_path', __('admin.admin_permission.http_path'))
->items(amis()->TextControl()->options($this->getRoutes())->required()),
amis()->TreeSelectControl('menus', __('admin.menus'))
->searchable()
->multiple()
->showIcon(false)
->options(AdminMenuService::make()->getTree())
->labelField('title')
->valueField('id')
->autoCheckChildren(false)
->joinValues(false)
->extractValue(),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
private function getHttpMethods(): array
{
return collect(Admin::adminPermissionModel()::$httpMethods)->map(fn ($method) => [
'value' => $method,
'label' => $method,
])->toArray();
}
public function getRoutes(): array
{
$prefix = (string) Admin::config('admin.route.prefix');
$container = collect();
return collect(app('router')->getRoutes())->map(function ($route) use ($prefix, $container) {
if (! Str::startsWith($uri = $route->uri(), $prefix) && $prefix && $prefix !== '/') {
return null;
}
if (! Str::contains($uri, '{')) {
if ($prefix !== '/') {
$route = Str::replaceFirst($prefix, '', $uri.'*');
} else {
$route = $uri.'*';
}
$route !== '*' && $container->push($route);
}
$path = preg_replace('/{.*}+/', '*', $uri);
$prefix !== '/' && $path = Str::replaceFirst($prefix, '', $path);
return $path;
})->merge($container)->filter()->unique()->map(function ($method) {
return [
'value' => $method,
'label' => $method,
];
})->values()->all();
}
public function autoGenerate()
{
$menus = Admin::adminMenuModel()::query()->get()->toArray();
$slugMap = Admin::adminPermissionModel()::query()->get(['id', 'slug'])->keyBy('id')->toArray();
$slugCache = [];
$permissions = [];
foreach ($menus as $menu) {
$_httpPath =
$menu['url_type'] == Admin::adminMenuModel()::TYPE_ROUTE ? $this->getHttpPath($menu['url']) : '';
$menuTitle = $menu['title'];
// 避免名称重复
if (in_array($menuTitle, data_get($permissions, '*.name', []))) {
$menuTitle = sprintf('%s(%s)', $menuTitle, $menu['id']);
}
if ($_httpPath) {
$slug = Str::of(explode('?', $_httpPath)[0])->trim('/')->replace('/', '.')->replace('*', '')->value();
} else {
$slug = Str::uuid();
}
if (in_array($slug, $slugCache)) {
$slug = $slug.'.'.$menu['id'];
}
$slugCache[] = $slug;
$permissions[] = [
'id' => $menu['id'],
'name' => $menuTitle,
'slug' => data_get($slugMap, $menu['id'].'.slug') ?: $slug,
'http_path' => json_encode($_httpPath ? [$_httpPath] : ''),
'order' => $menu['order'],
'parent_id' => $menu['parent_id'],
'created_at' => $menu['created_at'],
'updated_at' => $menu['updated_at'],
];
}
Admin::adminPermissionModel()::query()->truncate();
Admin::adminPermissionModel()::query()->insert($permissions);
$permissionClass = Admin::adminPermissionModel();
$pivotTable = (new $permissionClass)->menus()->getTable();
DB::table($pivotTable)->truncate();
foreach ($permissions as $item) {
$query = DB::table($pivotTable);
$query->insert([
'permission_id' => $item['id'],
'menu_id' => $item['id'],
]);
$_id = $item['id'];
while ($item['parent_id'] != 0) {
$query->clone()->insert([
'permission_id' => $_id,
'menu_id' => $item['parent_id'],
]);
$item = Admin::adminMenuModel()::query()->find($item['parent_id']);
}
}
return $this->response()->successMessage(
__('admin.successfully_message', ['attribute' => __('admin.admin_permission.auto_generate')])
);
}
private function getHttpPath($uri)
{
$excepts = ['/', '', '-'];
if (in_array($uri, $excepts)) {
return '';
}
if (! str_starts_with($uri, '/')) {
$uri = '/'.$uri;
}
return $uri.'*';
}
}

View File

@ -0,0 +1,164 @@
<?php
namespace App\Admin\Controllers\System;
use App\Admin\Services\AdminRoleService;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Services\AdminMenuService;
use Slowlyo\OwlAdmin\Services\AdminPermissionService;
/**
* @property AdminRoleService $service
*/
class AdminRoleController extends AdminController
{
protected string $serviceName = AdminRoleService::class;
public function list(): Page
{
$crud = $this->baseCRUD()
->headerToolbar([
$this->createButton(true)
->visible(Admin::user()->can('admin.system.admin_roles.create')),
amis('reload')->align('right'),
amis('filter-toggler')->align('right'),
])
->filterTogglable(false)
->itemCheckableOn('${id !== 1}')
->columns([
amis()->TableColumn()->label('ID')->name('id')->sortable(),
amis()->TableColumn()->label(__('admin.admin_role.name'))->name('name'),
amis()->TableColumn()->label(__('admin.admin_role.slug'))->name('slug')->type('tag'),
amis()->TableColumn()
->label(__('admin.created_at'))
->name('created_at')
->type('datetime')
->sortable(true),
amis()->TableColumn()
->label(__('admin.updated_at'))
->name('updated_at')
->type('datetime')
->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->setMenu()
->visible(Admin::user()->can('admin.system.admin_roles.set_menus'))
->visibleOn('${slug != "administrator"}'),
$this->setPermission()
->visible(Admin::user()->can('admin.system.admin_roles.set_permissions'))
->visibleOn('${slug != "administrator"}'),
$this->rowEditButton(true)
->visible(Admin::user()->can('admin.system.admin_roles.update'))
->visibleOn('${slug != "administrator"}'),
$this->rowDeleteButton()
->visible(Admin::user()->can('admin.system.admin_roles.delete'))
->visibleOn('${slug != "administrator"}'),
]),
]);
return $this->baseList($crud)->css([
'.tree-full' => [
'overflow' => 'hidden !important',
],
'.cxd-TreeControl > .cxd-Tree' => [
'height' => '100% !important',
'max-height' => '100% !important',
],
]);
}
protected function setPermission()
{
return amis()->DrawerAction()->label(__('admin.admin_role.set_permissions'))->icon('fa-solid fa-gear')->level('link')->drawer(
amis()->Drawer()->title(__('admin.admin_role.set_permissions'))->resizable()->closeOnOutside()->closeOnEsc()->body([
amis()
->Form()
->api(admin_url('system/admin_roles/${id}/permissions'))
->mode('normal')
->data(['id' => '${id}'])
->body([
amis()->TreeControl()
->name('permissions')
->label()
->multiple()
->options(AdminPermissionService::make()->getTree())
->searchable()
->cascade()
->value('${permission_ids}')
->joinValues(false)
->extractValue()
->size('full')
->className('h-full b-none')
->inputClassName('h-full tree-full')
->labelField('name')
->valueField('id'),
]),
])
);
}
public function savePermissions()
{
$this->service->savePermissions(request('id'), request('permissions'));
return $this->autoResponse('success', __('admin.save'));
}
protected function setMenu()
{
return amis()->DrawerAction()->label(__('admin.admin_role.set_menus'))->icon('fa-solid fa-gear')->level('link')->drawer(
amis()->Drawer()->title(__('admin.admin_role.set_menus'))->resizable()->closeOnOutside()->closeOnEsc()->body([
amis()
->Form()
->api(admin_url(admin_url('system/admin_roles/${id}/menus')))
->mode('normal')
->data(['id' => '${id}'])
->body([
amis()->TreeControl()
->name('menus')
->label()
->multiple()
->options(AdminMenuService::make()->getTree())
->searchable()
->cascade()
->value('${menu_ids}')
->joinValues(false)
->extractValue()
->size('full')
->className('h-full b-none')
->inputClassName('h-full tree-full')
->labelField('title')
->valueField('id'),
]),
])
);
}
public function saveMenus()
{
$this->service->saveMenus(request('id'), request('menus'));
return $this->autoResponse('success', __('admin.save'));
}
public function form(): Form
{
return $this->baseForm()->body([
amis()->TextControl()->label(__('admin.admin_role.name'))->name('name')->required(),
amis()->TextControl()
->label(__('admin.admin_role.slug'))
->name('slug')
->description(__('admin.admin_role.slug_description'))
->required(),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -1,8 +1,9 @@
<?php
namespace App\Admin\Controllers;
namespace App\Admin\Controllers\System;
use App\Admin\Services\AdminUserService;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Operation;
@ -21,7 +22,7 @@ class AdminUserController extends AdminController
{
$crud = $this->baseCRUD()
->headerToolbar([
$this->createButton(true),
$this->createButton(true)->visible(Admin::user()->can('admin.system.admin_users.create')),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body(
@ -29,7 +30,6 @@ class AdminUserController extends AdminController
->size('md')
->placeholder(__('admin.admin_user.search_username'))
))
->quickSaveItemApi(admin_url('quick-edit/admin_users/$id'))
->itemCheckableOn('${id !== 1}')
->columns([
amisMake()->TableColumn('id', 'ID')->sortable(),
@ -42,10 +42,15 @@ class AdminUserController extends AdminController
amisMake()->TableColumn('lock', __('admin.admin_user.lock'))->quickEdit(SwitchControl::make()->saveImmediately(true)->mode('inline')->disabledOn('${id === 1}')),
amisMake()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
Operation::make()->label(__('admin.actions'))->buttons([
$this->rowEditButton(true)->visibleOn('${id != 1}'),
//单独修改密码
$this->editPassword()->visibleOn('${id != 1}'),
$this->rowDeleteButton()->visibleOn('${id != 1}'),
$this->editPassword()
->visible(Admin::user()->can('admin.system.admin_users.change_password'))
->visibleOn('${id != 1}'),
$this->rowEditButton(true)
->visible(Admin::user()->can('admin.system.admin_users.update'))
->visibleOn('${id != 1}'),
$this->rowDeleteButton()
->visible(Admin::user()->can('admin.system.admin_users.delete'))
->visibleOn('${id != 1}'),
]),
]);

View File

@ -1,16 +1,20 @@
<?php
namespace App\Admin\Controllers;
namespace App\Admin\Controllers\System;
use App\Admin\Components;
use App\Admin\Services\KeywordService;
use Illuminate\Http\Request;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\TableColumn;
use Slowlyo\OwlAdmin\Renderers\TextControl;
/**
* @property KeywordService $service
*/
class KeywordController extends AdminController
{
protected string $serviceName = KeywordService::class;
@ -23,7 +27,7 @@ class KeywordController extends AdminController
->footerToolbar([])
//去掉分页-end
->headerToolbar([
$this->createButton(true),
$this->createButton(true)->visible(Admin::user()->can('admin.system.keywords.create')),
amis('reload')->align('right'),
amis('filter-toggler')->align('right'),
])
@ -44,8 +48,8 @@ class KeywordController extends AdminController
TableColumn::make()->name('sort')->label('排序'),
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
amisMake()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditButton(true),
$this->rowDeleteButton(),
$this->rowEditButton(true)->visible(Admin::user()->can('admin.system.keywords.update')),
$this->rowDeleteButton()->visible(Admin::user()->can('admin.system.keywords.delete')),
]),
]);

View File

@ -0,0 +1,94 @@
<?php
namespace App\Admin\Services;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Models\AdminMenu;
/**
* @method AdminMenu getModel()
* @method AdminMenu|Builder query()
*/
class AdminMenuService extends BaseService
{
public function __construct()
{
$this->modelName = Admin::adminMenuModel();
}
public function getTree(): array
{
$list = $this->query()->orderBy('order')->get()->toArray();
return array2tree($list);
}
public function parentIsChild($id, $parent_id): bool
{
$parent = $this->query()->find($parent_id);
do {
if ($parent->parent_id == $id) {
return true;
}
// 如果没有parent 则为顶级菜单 退出循环
$parent = $parent->parent;
} while ($parent);
return false;
}
public function update($primaryKey, $data): bool
{
$columns = $this->getTableColumns();
$parent_id = Arr::get($data, 'parent_id');
if ($parent_id != 0) {
amis_abort_if($this->parentIsChild($primaryKey, $parent_id), __('admin.admin_menu.parent_id_not_allow'));
}
$model = $this->query()->whereKey($primaryKey)->first();
return $this->saveData($data, $columns, $model);
}
public function store($data): bool
{
$columns = $this->getTableColumns();
$model = $this->getModel();
return $this->saveData($data, $columns, $model);
}
public function changeHomePage($excludeId = 0)
{
$this->query()->when($excludeId, fn ($query) => $query->where('id', '<>', $excludeId))->update(['is_home' => 0]);
}
public function list()
{
return ['items' => $this->getTree()];
}
protected function saveData($data, array $columns, AdminMenu $model): bool
{
foreach ($data as $k => $v) {
if (! in_array($k, $columns)) {
continue;
}
$v = $k == 'parent_id' ? intval($v) : $v;
$model->setAttribute($k, $v);
if ($k == 'is_home' && $v == 1) {
$this->changeHomePage($model->getKey());
}
}
return $model->save();
}
}

View File

@ -0,0 +1,116 @@
<?php
namespace App\Admin\Services;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Models\AdminPermission;
/**
* @method AdminPermission getModel()
* @method AdminPermission|Builder query()
*/
class AdminPermissionService extends BaseService
{
public function __construct()
{
$this->modelName = Admin::adminPermissionModel();
}
public function getTree(): array
{
$list = $this->query()->orderBy('order')->get()->toArray();
return array2tree($list);
}
public function parentIsChild($id, $parent_id): bool
{
$parent = $this->query()->find($parent_id);
do {
if ($parent->parent_id == $id) {
return true;
}
// 如果没有parent 则为顶级 退出循环
$parent = $parent->parent;
} while ($parent);
return false;
}
public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null
{
$permission = parent::getEditData($id);
$permission->load(['menus']);
return $permission;
}
public function store($data): bool
{
$this->checkRepeated($data);
$columns = $this->getTableColumns();
$model = $this->getModel();
return $this->saveData($data, $columns, $model);
}
public function update($primaryKey, $data): bool
{
$this->checkRepeated($data, $primaryKey);
$columns = $this->getTableColumns();
$parent_id = Arr::get($data, 'parent_id');
if ($parent_id != 0) {
amis_abort_if($this->parentIsChild($primaryKey, $parent_id), __('admin.admin_permission.parent_id_not_allow'));
}
$model = $this->query()->whereKey($primaryKey)->first();
return $this->saveData($data, $columns, $model);
}
public function checkRepeated($data, $id = 0)
{
$query = $this->query()->when($id, fn ($query) => $query->where('id', '<>', $id));
amis_abort_if($query->clone()->where('name', $data['name'])
->exists(), __('admin.admin_permission.name_already_exists'));
amis_abort_if($query->clone()->where('slug', $data['slug'])
->exists(), __('admin.admin_permission.slug_already_exists'));
}
public function list()
{
return ['items' => $this->getTree()];
}
protected function saveData($data, array $columns, AdminPermission $model): bool
{
$menus = Arr::pull($data, 'menus');
foreach ($data as $k => $v) {
if (! in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
if ($model->save()) {
$model->menus()->sync(Arr::has($menus, '0.id') ? Arr::pluck($menus, 'id') : $menus);
return true;
}
return false;
}
}

View File

@ -0,0 +1,99 @@
<?php
namespace App\Admin\Services;
use Slowlyo\OwlAdmin\Admin;
class AdminRoleService extends BaseService
{
public function __construct()
{
$this->modelName = Admin::adminRoleModel();
}
public function list()
{
$query = $this->listQuery();
/** @var \Illuminate\Pagination\LengthAwarePaginator */
$list = $query->with(['menus', 'permissions'])->paginate(request()->input('perPage', 20));
$list->through(function ($item) {
$instance = $item->withoutRelations();
$instance->setAttribute('menu_ids', $item->menus->pluck('id'));
$instance->setAttribute('permission_ids', $item->permissions->pluck('id'));
return $instance;
});
$items = $list->items();
$total = $list->total();
return compact('items', 'total');
}
public function store($data): bool
{
$this->checkRepeated($data);
$columns = $this->getTableColumns();
$model = $this->getModel();
foreach ($data as $k => $v) {
if (! in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function update($primaryKey, $data): bool
{
$this->checkRepeated($data, $primaryKey);
$columns = $this->getTableColumns();
$model = $this->query()->whereKey($primaryKey)->first();
foreach ($data as $k => $v) {
if (! in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function checkRepeated($data, $id = 0)
{
$query = $this->query()->when($id, fn ($query) => $query->where('id', '<>', $id));
amis_abort_if($query->clone()
->where('name', $data['name'])
->exists(), __('admin.admin_role.name_already_exists'));
amis_abort_if($query->clone()
->where('slug', $data['slug'])
->exists(), __('admin.admin_role.slug_already_exists'));
}
public function savePermissions($primaryKey, $permissions): void
{
$model = $this->query()->whereKey($primaryKey)->first();
$model->permissions()->detach();
$model->permissions()->attach($permissions);
}
public function saveMenus($primaryKey, $menus): void
{
$model = $this->query()->whereKey($primaryKey)->first();
$model->menus()->detach();
$model->menus()->attach($menus);
}
}

View File

@ -1,5 +1,10 @@
<?php
use App\Admin\Controllers\System\AdminMenuController;
use App\Admin\Controllers\System\AdminPermissionController;
use App\Admin\Controllers\System\AdminRoleController;
use App\Admin\Controllers\System\AdminUserController;
use App\Admin\Controllers\System\KeywordController;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;
@ -40,11 +45,25 @@ Route::group([
| 系统管理
|--------------------------------------------------------------------------
*/
$router->resource('system/admin_users', App\Admin\Controllers\AdminUserController::class);
$router->get('system/admin_roles', [App\Admin\Controllers\AdminRoleController::class, 'index'])->name('admin_roles.index');
$router->resource('system/settings', \App\Admin\Controllers\SettingController::class);
$router->resource('system/keywords', \App\Admin\Controllers\KeywordController::class);
$router->post('quick-edit/admin_users/{admin_user}', [\App\Admin\Controllers\AdminUserController::class, 'update']);
$router->group([
'prefix' => 'system',
'as' => 'system.',
], function (Router $router) {
// 账号管理
$router->resource('admin_users', AdminUserController::class);
// 角色管理
$router->resource('admin_roles', AdminRoleController::class);
$router->post('admin_roles/{admin_role}/menus', [AdminRoleController::class, 'saveMenus'])->name('admin_roles.set_menus');
$router->post('admin_roles/{admin_role}/permissions', [AdminRoleController::class, 'savePermissions'])->name('admin_roles.set_permissions');
// 权限管理
$router->resource('admin_permissions', AdminPermissionController::class);
// 菜单管理
$router->resource('admin_menus', AdminMenuController::class);
// 系统设置
$router->resource('settings', \App\Admin\Controllers\SettingController::class);
// 数据字典
$router->resource('keywords', KeywordController::class);
});
$router->resource('articles', \App\Admin\Controllers\ArticleController::class);
@ -62,6 +81,6 @@ Route::group([
$router->group([
'prefix' => 'api',
], function (Router $router) {
$router->get('keywords/tree-list', [\App\Admin\Controllers\KeywordController::class, 'getTreeList'])->name('api.keywords.tree-list');
$router->get('keywords/tree-list', [KeywordController::class, 'getTreeList'])->name('api.keywords.tree-list');
});
});

View File

@ -20,6 +20,6 @@ class AdminRole extends Model
public function menus(): BelongsToMany
{
return $this->belongsToMany(Admin::adminMenuModel()::class, 'admin_role_menus', 'role_id', 'menu_id');
return $this->belongsToMany(Admin::adminMenuModel(), 'admin_role_menus', 'role_id', 'menu_id');
}
}

View File

@ -137,6 +137,8 @@ return [
'avatar' => '头像',
'name' => '姓名',
'roles' => '角色',
'lock' => '锁定',
'edit_password' => '修改密码',
'search_username' => '搜索用户名/名称',
'password_confirmation' => '两次输入密码不一致',
'old_password_required' => '请输入原密码',
@ -153,6 +155,7 @@ return [
'name_already_exists' => '角色名称已存在',
'slug_already_exists' => '角色标识已存在',
'set_permissions' => '设置权限',
'set_menus' => '设置菜单',
],
'admin_permissions' => '权限',