init
parent
91ca987bca
commit
f64b49b626
|
|
@ -7,7 +7,7 @@ use Slowlyo\OwlAdmin\Renderers\Page;
|
|||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
use Slowlyo\OwlAdmin\Renderers\Operation;
|
||||
use App\Services\Admin\AdService;
|
||||
use App\Admin\Services\AdService;
|
||||
use App\Admin\Components;
|
||||
use App\Models\Keyword;
|
||||
use App\Models\Ad;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Traits\CustomActionTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController as Controller;
|
||||
use Slowlyo\OwlAdmin\Exceptions\AdminException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @property \App\Admin\Services\BaseService $service
|
||||
*/
|
||||
abstract class AdminController extends Controller
|
||||
{
|
||||
use CustomActionTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
if ($this->actionOfQuickEdit()) {
|
||||
$result = $this->service->quickEdit($request->all());
|
||||
} elseif ($this->actionOfQuickEditItem()) {
|
||||
$result = $this->service->quickEditItem($request->all());
|
||||
} else {
|
||||
$result = $this->service->store($request->all());
|
||||
}
|
||||
|
||||
if (! $result) {
|
||||
admin_abort($this->service->getError() ?: __('admin.save').__('admin.failed'));
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
} catch (Throwable $th) {
|
||||
DB::rollBack();
|
||||
return $this->renderException($th);
|
||||
}
|
||||
|
||||
return $this->response()->successMessage(__('admin.save').__('admin.successfully'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function update(Request $request)
|
||||
{
|
||||
$input = Arr::except($request->all(), $this->service->primaryKey());
|
||||
|
||||
if ($request->filled('_fields')) {
|
||||
$input = Arr::only($input, explode(',', $request->input('_fields')));
|
||||
}
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$result = $this->service->update($this->getPrimaryValue($request), $input);
|
||||
|
||||
if (! $result) {
|
||||
admin_abort($this->service->getError() ?: __('admin.save').__('admin.failed'));
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
} catch (Throwable $th) {
|
||||
DB::rollBack();
|
||||
return $this->renderException($th);
|
||||
}
|
||||
|
||||
return $this->response()->successMessage(__('admin.save').__('admin.successfully'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy($ids)
|
||||
{
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$result = $this->service->delete($ids);
|
||||
if ($result === false) {
|
||||
admin_abort($this->service->getError());
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
} catch (Throwable $th) {
|
||||
DB::rollBack();
|
||||
return $this->renderException($th);
|
||||
}
|
||||
|
||||
return $this->response()->successMessage(__('admin.delete').__('admin.successfully'));
|
||||
}
|
||||
|
||||
public function getQuickEditItemPath(array $fields = ['*'])
|
||||
{
|
||||
$path = $this->getUpdatePath();
|
||||
|
||||
if ($fields != ['*']) {
|
||||
$path .= '?_fields='.implode(',', $fields);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function renderException(Throwable $e)
|
||||
{
|
||||
report($e);
|
||||
|
||||
if ($e instanceof AdminException) {
|
||||
return $e->render();
|
||||
}
|
||||
|
||||
$message = $e->getMessage();
|
||||
|
||||
if ($e instanceof ValidationException) {
|
||||
$message = Arr::first($e->errors());
|
||||
if (is_array($message)) {
|
||||
$message = Arr::first($message) ?: '参数错误';
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response()->fail($message);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminRoleController as AdminRoleBaseController;
|
||||
|
||||
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',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\Operation;
|
||||
use Slowlyo\OwlAdmin\Renderers\SwitchControl;
|
||||
use Slowlyo\OwlAdmin\Renderers\TableColumn;
|
||||
use App\Services\Admin\AdminUserService;
|
||||
use Slowlyo\OwlAdmin\Services\AdminRoleService;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
|
||||
/**
|
||||
* @property AdminUserService $service
|
||||
*/
|
||||
class AdminUserController extends AdminController
|
||||
{
|
||||
protected string $serviceName = AdminUserService::class;
|
||||
|
||||
public function list(): Page
|
||||
{
|
||||
$crud = $this->baseCRUD()
|
||||
->headerToolbar([
|
||||
$this->createButton(true),
|
||||
...$this->baseHeaderToolBar(),
|
||||
])
|
||||
->filter($this->baseFilter()->body(
|
||||
amisMake()->TextControl('keyword', __('admin.keyword'))
|
||||
->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(),
|
||||
amisMake()->TableColumn('avatar', __('admin.admin_user.avatar'))->type('avatar')->src('${avatar}'),
|
||||
amisMake()->TableColumn('username', __('admin.username')),
|
||||
amisMake()->TableColumn('name', __('admin.admin_user.name')),
|
||||
amisMake()->TableColumn('roles', __('admin.admin_user.roles'))->type('each')->items(
|
||||
amisMake()->Tag()->label('${name}')->className('my-1')
|
||||
),
|
||||
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}'),
|
||||
]),
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
}
|
||||
|
||||
public function form(): Form
|
||||
{
|
||||
return $this->baseForm()->body([
|
||||
amisMake()->ImageControl('avatar', __('admin.admin_user.avatar'))->receiver($this->uploadImagePath()),
|
||||
amisMake()->TextControl('name', __('admin.admin_user.name'))->required(),
|
||||
amisMake()->TextControl('username', __('admin.username'))->required(),
|
||||
amisMake()->TextControl('password', __('admin.password'))->type('input-password')->required()->validations(['minLength' => 6])->hiddenOn('${id > 0}'),
|
||||
amisMake()->TextControl('confirm_password', __('admin.confirm_password'))->type('input-password')->required()->validations(['minLength' => 6])->hiddenOn('${id > 0}'),
|
||||
amisMake()->SelectControl('roles', __('admin.admin_user.roles'))
|
||||
->searchable()
|
||||
->multiple()
|
||||
->labelField('name')
|
||||
->valueField('id')
|
||||
->joinValues(false)
|
||||
->extractValue()
|
||||
->options(AdminRoleService::make()->query()->get(['id', 'name'])),
|
||||
SwitchControl::make()->name('lock')->label(__('admin.admin_user.lock'))->value(false),
|
||||
]);
|
||||
}
|
||||
|
||||
public function detail(): Form
|
||||
{
|
||||
return $this->baseDetail()->body([]);
|
||||
}
|
||||
|
||||
public function editPassword()
|
||||
{
|
||||
return amisMake()->DialogAction()->icon('fa-regular fa-lightbulb')->label(__('admin.admin_user.edit_password'))->level('link')->dialog(
|
||||
amisMake()->Dialog()->title(__('admin.admin_user.edit_password'))->body([
|
||||
amisMake()->Form()->title('')
|
||||
->api([
|
||||
'method'=>'PUT',
|
||||
'url'=> admin_url('system/admin_users/$id')
|
||||
])
|
||||
->body([
|
||||
amisMake()->TextControl('id')->value('${id}')->hidden(true),
|
||||
amisMake()->TextControl('username')->value('${username}')->hidden(true),
|
||||
amisMake()->TextControl('password', __('admin.password'))->type('input-password')->required()->validations(['minLength' => 6]),
|
||||
amisMake()->TextControl('confirm_password', __('admin.confirm_password'))->type('input-password')->required()->validations(['minLength' => 6]),
|
||||
]),
|
||||
])->size('md')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ use Slowlyo\OwlAdmin\Admin;
|
|||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
use App\Services\Admin\ArticleService;
|
||||
use App\Admin\Services\ArticleService;
|
||||
use App\Admin\Components;
|
||||
use App\Models\Keyword;
|
||||
use App\Traits\CustomActionTrait;
|
||||
|
|
|
|||
|
|
@ -2,20 +2,22 @@
|
|||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use App\Admin\Services\System\AdminUserService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Slowlyo\OwlAdmin\Models\AdminUser;
|
||||
use Slowlyo\OwlAdmin\Controllers\AuthController as AdminAuthController;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Controllers\AuthController as AdminAuthController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class AuthController extends AdminAuthController
|
||||
{
|
||||
protected string $serviceName = AdminUserService::class;
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
if (Admin::config('admin.auth.login_captcha')) {
|
||||
if (!$request->has('captcha')) {
|
||||
if (! $request->has('captcha')) {
|
||||
return $this->response()->fail(__('admin.required', ['attribute' => __('admin.captcha')]));
|
||||
}
|
||||
|
||||
|
|
@ -29,22 +31,25 @@ class AuthController extends AdminAuthController
|
|||
'username' => 'required',
|
||||
'password' => 'required',
|
||||
], [
|
||||
'username' . '.required' => __('admin.required', ['attribute' => __('admin.username')]),
|
||||
'password.required' => __('admin.required', ['attribute' => __('admin.password')]),
|
||||
'username'.'.required' => __('admin.required', ['attribute' => __('admin.username')]),
|
||||
'password.required' => __('admin.required', ['attribute' => __('admin.password')]),
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
abort(Response::HTTP_BAD_REQUEST, $validator->errors()->first());
|
||||
}
|
||||
$adminModel = Admin::config("admin.auth.model", AdminUser::class);
|
||||
$user = $adminModel::query()->where('username', $request->username)->first();
|
||||
if($user && $user->lock){
|
||||
|
||||
$adminModel = Admin::adminUserModel();
|
||||
$user = $adminModel::query()->where('username', $request->username)->first();
|
||||
|
||||
if ($user && $user->lock) {
|
||||
abort(Response::HTTP_BAD_REQUEST, '您的账号已被锁定,需要联系超级管理员解锁。');
|
||||
}else{
|
||||
} else {
|
||||
if ($user && Hash::check($request->password, $user->password)) {
|
||||
$module = Admin::currentModule(true);
|
||||
$prefix = $module ? $module . '.' : '';
|
||||
$token = $user->createToken($prefix . 'admin')->plainTextToken;
|
||||
$prefix = $module ? $module.'.' : '';
|
||||
$token = $user->createToken($prefix.'admin')->plainTextToken;
|
||||
|
||||
return $this->response()->success(compact('token'), __('admin.login_successful'));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\System;
|
||||
|
||||
use App\Admin\Controllers\AdminController;
|
||||
use App\Admin\Services\System\AdminMenuService;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
|
||||
/**
|
||||
* @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->createTypeButton('drawer', '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->rowEditTypeButton('drawer', '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([]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\System;
|
||||
|
||||
use App\Admin\Controllers\AdminController;
|
||||
use App\Admin\Services\System\AdminMenuService;
|
||||
use App\Admin\Services\System\AdminPermissionService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
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->createTypeButton('drawer', 'lg')->visible(Admin::user()->can('admin.system.admin_permissions.create')),
|
||||
...$this->baseHeaderToolBar(),
|
||||
])
|
||||
->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->rowEditTypeButton('drawer', '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.'*';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\System;
|
||||
|
||||
use App\Admin\Controllers\AdminController;
|
||||
use App\Admin\Services\System\AdminRoleService;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Renderers\DrawerAction;
|
||||
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->createTypeButton('drawer', 'lg')
|
||||
->visible(Admin::user()->can('admin.system.admin_roles.create')),
|
||||
...$this->baseHeaderToolBar(),
|
||||
])
|
||||
->bulkActions([])
|
||||
->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->rowSetMenuButton()
|
||||
->visible(Admin::user()->can('admin.system.admin_roles.set_menus'))
|
||||
->visibleOn('${slug != "administrator"}'),
|
||||
$this->rowSetPermissionButton()
|
||||
->visible(Admin::user()->can('admin.system.admin_roles.set_permissions'))
|
||||
->visibleOn('${slug != "administrator"}'),
|
||||
$this->rowEditTypeButton('drawer', 'lg')
|
||||
->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 rowSetPermissionButton(): DrawerAction
|
||||
{
|
||||
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()
|
||||
->heightAuto()
|
||||
->showIcon(false)
|
||||
->initiallyOpen(false)
|
||||
// ->size('full')
|
||||
// ->className('h-full b-none')
|
||||
// ->inputClassName('h-full tree-full')
|
||||
->labelField('name')
|
||||
->valueField('id'),
|
||||
),
|
||||
])->size('lg')
|
||||
);
|
||||
}
|
||||
|
||||
public function savePermissions()
|
||||
{
|
||||
$this->service->savePermissions(request('id'), request('permissions'));
|
||||
|
||||
return $this->autoResponse('success', __('admin.save'));
|
||||
}
|
||||
|
||||
protected function rowSetMenuButton(): DrawerAction
|
||||
{
|
||||
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()
|
||||
->heightAuto()
|
||||
->showIcon(false)
|
||||
->initiallyOpen(false)
|
||||
// ->size('full')
|
||||
// ->className('h-full b-none')
|
||||
// ->inputClassName('h-full tree-full')
|
||||
->labelField('title')
|
||||
->valueField('id')
|
||||
),
|
||||
])->size('lg')
|
||||
);
|
||||
}
|
||||
|
||||
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([]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers\System;
|
||||
|
||||
use App\Admin\Controllers\AdminController;
|
||||
use App\Admin\Services\System\AdminUserService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Renderers\DrawerAction;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Renderers\TableColumn;
|
||||
use Slowlyo\OwlAdmin\Services\AdminRoleService;
|
||||
|
||||
/**
|
||||
* @property AdminUserService $service
|
||||
*/
|
||||
class AdminUserController extends AdminController
|
||||
{
|
||||
protected string $serviceName = AdminUserService::class;
|
||||
|
||||
public function list(): Page
|
||||
{
|
||||
$crud = $this->baseCRUD()
|
||||
->headerToolbar([
|
||||
$this->createTypeButton('drawer', 'lg')->visible(Admin::user()->can('admin.system.admin_users.create')),
|
||||
...$this->baseHeaderToolBar(),
|
||||
])
|
||||
->bulkActions([])
|
||||
->filter($this->baseFilter()->body(
|
||||
amis()->TextControl('keyword', __('admin.keyword'))
|
||||
->size('md')
|
||||
->placeholder(__('admin.admin_user.search_username'))
|
||||
))
|
||||
->filterDefaultVisible()
|
||||
->quickSaveItemApi($this->getQuickEditItemPath(['lock']))
|
||||
->itemCheckableOn('${id !== 1}')
|
||||
->columns([
|
||||
amis()->TableColumn('id', 'ID')->sortable(),
|
||||
amis()->TableColumn('avatar', __('admin.admin_user.avatar'))->type('avatar')->src('${avatar}'),
|
||||
amis()->TableColumn('username', __('admin.username')),
|
||||
amis()->TableColumn('name', __('admin.admin_user.name')),
|
||||
amis()->TableColumn('roles', __('admin.admin_user.roles'))->type('each')->items(
|
||||
amis()->Tag()->label('${name}')->className('my-1')
|
||||
),
|
||||
tap(amis()->TableColumn('lock', __('admin.admin_user.lock')), function (TableColumn $column) {
|
||||
if (Admin::user()->can('admin.system.admin_users.update')) {
|
||||
return $column->quickEdit(
|
||||
amis()->SwitchControl()->saveImmediately()->mode('inline')->disabledOn('${id === 1}')
|
||||
);
|
||||
}
|
||||
|
||||
return $column->type('status')->source([
|
||||
0 => ['label' => '未锁定', 'icon' => 'fa fa-times-circle', 'color' => '#30bf13'],
|
||||
1 => ['label' => '已锁定', 'icon' => 'fa fa-check-circle', 'color' => '#f70e47'],
|
||||
]);
|
||||
}),
|
||||
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
|
||||
$this->rowActions([
|
||||
$this->rowChangePasswordButton()
|
||||
->visible(Admin::user()->can('admin.system.admin_users.change_password'))
|
||||
->visibleOn('${id != 1}'),
|
||||
$this->rowEditTypeButton('drawer', 'lg')
|
||||
->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}'),
|
||||
]),
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
}
|
||||
|
||||
public function form(): Form
|
||||
{
|
||||
return $this->baseForm()->body([
|
||||
amis()->ImageControl('avatar', __('admin.admin_user.avatar'))->receiver(admin_url('upload_image') . '?full-url=1'),
|
||||
amis()->TextControl('name', __('admin.admin_user.name'))->required(),
|
||||
amis()->TextControl('username', __('admin.username'))->required(),
|
||||
amis()->TextControl('password', __('admin.password'))->type('input-password')->required()->validations(['minLength' => 6])->hiddenOn('${id > 0}'),
|
||||
amis()->TextControl('confirm_password', __('admin.confirm_password'))->type('input-password')->required()->validations(['minLength' => 6])->hiddenOn('${id > 0}'),
|
||||
amis()->SelectControl('roles', __('admin.admin_user.roles'))
|
||||
->searchable()
|
||||
->multiple()
|
||||
->labelField('name')
|
||||
->valueField('id')
|
||||
->joinValues(false)
|
||||
->extractValue()
|
||||
->options(AdminRoleService::make()->query()->get(['id', 'name'])),
|
||||
amis()->SwitchControl()->name('lock')->label(__('admin.admin_user.lock'))->value(false),
|
||||
]);
|
||||
}
|
||||
|
||||
public function detail(): Form
|
||||
{
|
||||
return $this->baseDetail()->body([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
public function changePassword($id, Request $request)
|
||||
{
|
||||
$validator = Validator::make(
|
||||
data: $request->input(),
|
||||
rules: [
|
||||
'password' => ['bail', 'required', 'confirmed', 'min:6'],
|
||||
],
|
||||
attributes: [
|
||||
'password' => '密码',
|
||||
],
|
||||
);
|
||||
|
||||
if ($validator->fails()) {
|
||||
admin_abort($validator->errors()->first());
|
||||
}
|
||||
|
||||
$this->service->update($id, $request->only(['password']));
|
||||
|
||||
return $this->autoResponse('success', __('admin.save'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码按钮
|
||||
*/
|
||||
protected function rowChangePasswordButton(): DrawerAction
|
||||
{
|
||||
return amis()->DrawerAction()->icon('fa-regular fa-lightbulb')->label(__('admin.admin_user.edit_password'))->level('link')->drawer(
|
||||
amis()->Drawer()->title(__('admin.admin_user.edit_password'))->body([
|
||||
amis()->Form()->title('')
|
||||
->api([
|
||||
'method' => 'POST',
|
||||
'url' => admin_url('system/admin_users/$id/change-password'),
|
||||
])
|
||||
->body([
|
||||
amis()->TextControl('password', __('admin.password'))->type('input-password')->required()->validations(['minLength' => 6]),
|
||||
amis()->TextControl('password_confirmation', __('admin.confirm_password'))->type('input-password')->required()->validations(['minLength' => 6]),
|
||||
]),
|
||||
])->size('lg')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
namespace App\Admin\Controllers\System;
|
||||
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use App\Admin\Components;
|
||||
use App\Admin\Controllers\AdminController;
|
||||
use App\Admin\Services\System\KeywordService;
|
||||
use Illuminate\Http\Request;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||
use Slowlyo\OwlAdmin\Renderers\TableColumn;
|
||||
use Slowlyo\OwlAdmin\Renderers\TextControl;
|
||||
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||
use App\Services\Admin\KeywordService;
|
||||
use App\Admin\Components;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* @property KeywordService $service
|
||||
*/
|
||||
class KeywordController extends AdminController
|
||||
{
|
||||
protected string $serviceName = KeywordService::class;
|
||||
|
|
@ -23,32 +27,26 @@ class KeywordController extends AdminController
|
|||
->footerToolbar([])
|
||||
//去掉分页-end
|
||||
->headerToolbar([
|
||||
$this->createButton(true),
|
||||
$this->createTypeButton('drawer', 'lg')->visible(Admin::user()->can('admin.system.keywords.create')),
|
||||
$this->exportAction(),
|
||||
amis('reload')->align('right'),
|
||||
amis('filter-toggler')->align('right'),
|
||||
...$this->baseHeaderToolBar(),
|
||||
])
|
||||
->bulkActions([])
|
||||
->filter($this->baseFilter()->body([
|
||||
amis()->TextControl('name', __('admin.keyword'))
|
||||
->size('md')
|
||||
->placeholder(__('admin.keywords.search_name')),
|
||||
amis()->TextControl('parent_name', __('admin.keywords.parent_keyword'))
|
||||
->size('md')
|
||||
->placeholder(__('admin.keywords.search_name'))
|
||||
]
|
||||
))
|
||||
amis()->TextControl('search', __('admin.keyword'))->placeholder(__('admin.keywords.search_name'))->size('md'),
|
||||
]))
|
||||
->filterDefaultVisible()
|
||||
->columns([
|
||||
// TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||||
TableColumn::make()->name('name')->label('名称'),
|
||||
TableColumn::make()->name('key')->label('KEY')->copyable(true),
|
||||
TableColumn::make()->name('value')->label('值'),
|
||||
TableColumn::make()->name('sort')->label('排序'),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
amisMake()->Operation()->label(__('admin.actions'))->buttons([
|
||||
//按钮权限示例;
|
||||
// amis()->action()->label('判断权限')->permission('keywords.custom', amis()->TextControl()->hidden()),
|
||||
$this->rowEditButton(true),
|
||||
$this->rowDeleteButton(),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
amis()->Operation()->label(__('admin.actions'))->buttons([
|
||||
$this->rowEditTypeButton('drawer', 'lg')
|
||||
->visible(Admin::user()->can('admin.system.keywords.update')),
|
||||
$this->rowDeleteButton()->visible(Admin::user()->can('admin.system.keywords.delete')),
|
||||
]),
|
||||
]);
|
||||
|
||||
|
|
@ -62,11 +60,12 @@ class KeywordController extends AdminController
|
|||
TextControl::make()->name('name')->label('名称')->required(true),
|
||||
TextControl::make()->name('key')->label('KEY')->required(true),
|
||||
TextControl::make()->name('value')->label('值'),
|
||||
amisMake()->NumberControl()->name('sort')->value(0)->min()->label('排序'),
|
||||
amis()->NumberControl()->name('sort')->value(0)->min()->label('排序'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getTreeList(Request $request){
|
||||
return $this->service->getTree();
|
||||
}
|
||||
public function getTreeList(Request $request)
|
||||
{
|
||||
return $this->service->getTree();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
<?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,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Response;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
|
||||
class Authenticate
|
||||
{
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (Admin::permission()->authIntercept($request)) {
|
||||
return Admin::response()
|
||||
->additional(['code' => Response::HTTP_UNAUTHORIZED])
|
||||
->doNotDisplayToast()
|
||||
->fail(__('admin.please_login'));
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Support\Cores\Permission;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CheckPermission
|
||||
{
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $exceptPaths = [
|
||||
'/api/*',
|
||||
'/start_chunk_upload_file',
|
||||
'/save_chunk_upload_file',
|
||||
'/finish_chunk_upload_file',
|
||||
'/upload_file',
|
||||
'/upload_image',
|
||||
'/upload_rich'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $exceptRoutes = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if ($this->inExceptArray($request) || $this->checkRoutePermission($request)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return Admin::response()->fail(__('admin.unauthorized'), ['route' => $request->route()->getName()]);
|
||||
}
|
||||
|
||||
protected function checkRoutePermission(Request $request): bool
|
||||
{
|
||||
if (is_null($user = Admin::user())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ability = $this->normalizeRouteAbility(
|
||||
$original = $request->route()->getName()
|
||||
);
|
||||
|
||||
return collect($ability)
|
||||
->when($ability !== $original, fn (Collection $collection) => $collection->push($original))
|
||||
->contains(fn ($ability) => $user->can($ability));
|
||||
}
|
||||
|
||||
protected function normalizeRouteAbility(string $ability)
|
||||
{
|
||||
foreach ($this->resourceAbilityMap() as $method => $map) {
|
||||
if (str_ends_with($ability, ".{$method}")) {
|
||||
return preg_replace("/(.*)\.{$method}$/", '${1}.'.$map, $ability);
|
||||
}
|
||||
}
|
||||
|
||||
return $ability;
|
||||
}
|
||||
|
||||
protected function resourceAbilityMap(): array
|
||||
{
|
||||
return [
|
||||
'index' => 'list',
|
||||
'show' => 'view',
|
||||
'store' => 'create',
|
||||
'edit' => 'update',
|
||||
'destroy' => 'delete',
|
||||
];
|
||||
}
|
||||
|
||||
protected function inExceptArray(Request $request): bool
|
||||
{
|
||||
if (in_array($request->route()->getName(), $this->exceptRoutes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$permission = Admin::permission();
|
||||
|
||||
return $request->is(
|
||||
collect($this->exceptPaths)
|
||||
->when(Admin::permission(), fn (Collection $collection, Permission $permission) => $collection->merge($permission->authExcept)->merge($permission->permissionExcept))
|
||||
->map(function ($path) {
|
||||
$path = trim((string) config('admin.route.prefix'), '/').'/'.trim((string) $path, '/');
|
||||
|
||||
return ltrim($path, '/');
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
namespace App\Admin\Services;
|
||||
|
||||
use App\Models\Ad;
|
||||
use App\Models\Filters\AdFilter;
|
||||
use App\ModelFilters\AdFilter;
|
||||
use App\Traits\UploadTrait;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
namespace App\Admin\Services;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
namespace App\Admin\Services;
|
||||
|
||||
use App\Models\Article;
|
||||
use App\Models\Filters\ArticleFilter;
|
||||
use App\ModelFilters\ArticleFilter;
|
||||
use App\Traits\UploadTrait;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Services;
|
||||
|
||||
use Slowlyo\OwlAdmin\Services\AdminService;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @method Region getModel()
|
||||
* @method Region|\Illuminate\Database\Query\Builder query()
|
||||
*/
|
||||
class BaseService extends AdminService
|
||||
{
|
||||
protected string $modelFilterName = '';
|
||||
|
||||
protected bool $modelSortAble = false;
|
||||
|
||||
protected Model $currentModel;
|
||||
|
||||
public function getCurrentModel()
|
||||
{
|
||||
return $this->currentModel;
|
||||
}
|
||||
|
||||
public function sortColumn()
|
||||
{
|
||||
return 'id';
|
||||
}
|
||||
|
||||
public function getTree()
|
||||
{
|
||||
$list = $this->query()->orderByDesc('sort')->get();
|
||||
$minNum = $list->min('parent_id');
|
||||
|
||||
return array2tree($list->toArray(), $minNum);
|
||||
}
|
||||
|
||||
public function list()
|
||||
{
|
||||
$query = $this->listQuery();
|
||||
if (request()->input('_all')) {
|
||||
$list = (clone $query)->get();
|
||||
$items = $list->all();
|
||||
$total = $list->count();
|
||||
} else {
|
||||
$list = (clone $query)->paginate(request()->input('perPage', 20));
|
||||
$items = $list->items();
|
||||
$total = $list->total();
|
||||
}
|
||||
|
||||
return compact('items', 'total');
|
||||
}
|
||||
|
||||
public function getModelFilter()
|
||||
{
|
||||
return $this->modelFilterName;
|
||||
}
|
||||
|
||||
public function listQuery()
|
||||
{
|
||||
$query = $this->query();
|
||||
|
||||
$this->addRelations($query);
|
||||
|
||||
if ($filter = $this->getModelFilter()) {
|
||||
$query->filter(request()->input(), $filter);
|
||||
}
|
||||
|
||||
if ($this->modelSortAble) {
|
||||
$query->sort();
|
||||
}
|
||||
|
||||
$this->sortable($query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function store($data): bool
|
||||
{
|
||||
$data = $this->resloveData($data);
|
||||
|
||||
$validate = $this->validate($data);
|
||||
if ($validate !== true) {
|
||||
$this->setError($validate);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$model = $this->modelName::create($data);
|
||||
$this->currentModel = $model;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update($primaryKey, $data): bool
|
||||
{
|
||||
$model = $this->query()->whereKey($primaryKey)->firstOrFail();
|
||||
$data = $this->resloveData($data, $model);
|
||||
$validate = $this->validate($data, $model);
|
||||
if ($validate !== true) {
|
||||
$this->setError($validate);
|
||||
|
||||
return false;
|
||||
}
|
||||
$model->update($data);
|
||||
$this->currentModel = $model;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function delete(string $ids): mixed
|
||||
{
|
||||
$this->preDelete(explode(',', $ids));
|
||||
|
||||
return parent::delete($ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表单数据
|
||||
*
|
||||
* @param array $data
|
||||
* @param Model $model 空 : 添加, 非空: 修改
|
||||
* @return array
|
||||
*/
|
||||
public function resloveData($data, $model = null)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单验证
|
||||
*
|
||||
* @param array $data
|
||||
* @param Model $model 空: 添加, 非空: 修改
|
||||
* @return mixed true: 验证通过, string: 错误提示
|
||||
*/
|
||||
public function validate($data, $model = null)
|
||||
{
|
||||
// $createRules = [
|
||||
// 'key' => ['required', Rule::unique('keywords', 'key')],
|
||||
// 'name' => ['required'],
|
||||
// ];
|
||||
// $updateRules = [
|
||||
// 'key' => [Rule::unique('keywords', 'key')->ignore($model->id)]
|
||||
// ];
|
||||
// $validator = Validator::make($data, $model ? $updateRules : $createRules, [
|
||||
// 'key.unique' => ':input 已经存在'
|
||||
// ]);
|
||||
// if ($validator->fails()) {
|
||||
// return $validator->errors()->first();
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除的前置方法
|
||||
*
|
||||
* @param array $ids 主键id
|
||||
*/
|
||||
public function preDelete(array $ids): void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Services\System;
|
||||
|
||||
use App\Admin\Services\BaseService;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Services\System;
|
||||
|
||||
use App\Admin\Services\BaseService;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Services\System;
|
||||
|
||||
use App\Admin\Services\BaseService;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin\Services\System;
|
||||
|
||||
use App\Admin\Services\BaseService;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
|
||||
class AdminUserService extends BaseService
|
||||
{
|
||||
protected string $modelName;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->modelName = Admin::adminUserModel();
|
||||
}
|
||||
|
||||
public function getEditData($id): Model|\Illuminate\Database\Eloquent\Collection|Builder|array|null
|
||||
{
|
||||
$adminUser = parent::getEditData($id)->makeHidden('password');
|
||||
|
||||
$adminUser->load('roles');
|
||||
|
||||
return $adminUser;
|
||||
}
|
||||
|
||||
public function store($data): bool
|
||||
{
|
||||
if ($this->checkUsernameUnique($data['username'])) {
|
||||
admin_abort(__('admin.admin_user.username_already_exists'));
|
||||
}
|
||||
|
||||
if (! data_get($data, 'password')) {
|
||||
admin_abort(__('admin.required', ['attribute' => __('admin.password')]));
|
||||
}
|
||||
|
||||
if (array_key_exists('confirm_password', $data)) {
|
||||
if ($data['password'] !== $data['confirm_password']) {
|
||||
admin_abort(__('admin.admin_user.password_confirmation'));
|
||||
}
|
||||
unset($data['confirm_password']);
|
||||
}
|
||||
|
||||
if (Hash::needsRehash($data['password'])) {
|
||||
$data['password'] = Hash::make($data['password']);
|
||||
}
|
||||
|
||||
$model = $this->getModel();
|
||||
$user = $model::create(Arr::except($data, ['roles']));
|
||||
|
||||
if (isset($data['roles'])) {
|
||||
$user->roles()->attach($data['roles']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update($primaryKey, $data): bool
|
||||
{
|
||||
if (isset($data['username']) && $this->checkUsernameUnique($data['username'], $primaryKey)) {
|
||||
admin_abort(__('admin.admin_user.username_already_exists'));
|
||||
}
|
||||
|
||||
if (isset($data['password']) && Hash::needsRehash($data['password'])) {
|
||||
$data['password'] = Hash::make($data['password']);
|
||||
}
|
||||
|
||||
$user = $this->query()->whereKey($primaryKey)->firstOrFail();
|
||||
|
||||
foreach (['username', 'password', 'name', 'avatar', 'lock'] as $attribute) {
|
||||
if (array_key_exists($attribute, $data)) {
|
||||
$user->{$attribute} = $data[$attribute];
|
||||
}
|
||||
}
|
||||
|
||||
if ($user->isDirty('lock') && $user->lock != 1) {
|
||||
$user->error_num = 0;
|
||||
$user->last_error_at = null;
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
if (isset($data['roles'])) {
|
||||
$roles = Arr::pull($data, 'roles');
|
||||
$user->roles()->detach();
|
||||
$user->roles()->attach(Arr::has($roles, '0.id') ? Arr::pluck($roles, 'id') : $roles);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkUsernameUnique($username, $id = 0): bool
|
||||
{
|
||||
return $this->query()
|
||||
->where('username', $username)
|
||||
->when($id, fn ($query) => $query->where('id', '<>', $id))
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function updateUserSetting($primaryKey, $data): bool
|
||||
{
|
||||
$this->passwordHandler($data, $primaryKey);
|
||||
|
||||
return parent::update($primaryKey, $data);
|
||||
}
|
||||
|
||||
public function passwordHandler(&$data, $id = null)
|
||||
{
|
||||
$password = Arr::get($data, 'password');
|
||||
|
||||
if ($password) {
|
||||
if ($password !== Arr::get($data, 'confirm_password')) {
|
||||
admin_abort(__('admin.admin_user.password_confirmation'));
|
||||
}
|
||||
|
||||
if (strlen($password) < 6) {
|
||||
admin_abort('密码长度至少6个字符');
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
if (! Arr::get($data, 'old_password')) {
|
||||
admin_abort(__('admin.admin_user.old_password_required'));
|
||||
}
|
||||
|
||||
$oldPassword = $this->query()->where('id', $id)->value('password');
|
||||
|
||||
if (! Hash::check($data['old_password'], $oldPassword)) {
|
||||
admin_abort(__('admin.admin_user.old_password_error'));
|
||||
}
|
||||
}
|
||||
|
||||
$data['password'] = bcrypt($password);
|
||||
|
||||
unset($data['confirm_password']);
|
||||
unset($data['old_password']);
|
||||
}
|
||||
}
|
||||
|
||||
public function list()
|
||||
{
|
||||
$keyword = request()->keyword;
|
||||
|
||||
$query = $this
|
||||
->query()
|
||||
->with('roles')
|
||||
->select(['id', 'name', 'username', 'avatar', 'created_at', 'lock'])
|
||||
->when($keyword, function ($query) use ($keyword) {
|
||||
$query->where('username', 'like', "%{$keyword}%")->orWhere('name', 'like', "%{$keyword}%");
|
||||
});
|
||||
|
||||
$this->sortable($query);
|
||||
|
||||
$items = (clone $query)->paginate(request()->input('perPage', 20))->items();
|
||||
$total = (clone $query)->count();
|
||||
|
||||
return compact('items', 'total');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
namespace App\Admin\Services\System;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use App\ModelFilters\KeywordFilter;
|
||||
use App\Admin\Services\BaseService;
|
||||
use App\Models\Keyword;
|
||||
use App\Models\Filters\KeywordFilter;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* @method Keyword getModel()
|
||||
|
|
@ -13,13 +14,15 @@ use App\Models\Filters\KeywordFilter;
|
|||
class KeywordService extends BaseService
|
||||
{
|
||||
protected string $modelName = Keyword::class;
|
||||
|
||||
protected string $modelFilterName = KeywordFilter::class;
|
||||
|
||||
public function getTree()
|
||||
{
|
||||
$list = $this->query()->filter(request()->all(), $this->modelFilterName)->orderByDesc('sort')->get();
|
||||
$list = $this->query()->sort()->filter(request()->all(), $this->modelFilterName)->get();
|
||||
$minNum = $list->min('parent_id');
|
||||
return !$list->isEmpty() ? array2tree($list->toArray(), $minNum) :[];
|
||||
|
||||
return ! $list->isEmpty() ? array2tree($list->toArray(), $minNum) : [];
|
||||
}
|
||||
|
||||
public function parentIsChild($id, $pid): bool
|
||||
|
|
@ -53,7 +56,7 @@ class KeywordService extends BaseService
|
|||
$model = $this->getModel();
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
if (!in_array($k, $columns)) {
|
||||
if (! in_array($k, $columns)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +78,7 @@ class KeywordService extends BaseService
|
|||
if ($pid != 0) {
|
||||
if ($this->parentIsChild($primaryKey, $pid)) {
|
||||
$this->setError('父级不允许设置为当前子权限');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +86,7 @@ class KeywordService extends BaseService
|
|||
$model = $this->query()->whereKey($primaryKey)->first();
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
if (!in_array($k, $columns)) {
|
||||
if (! in_array($k, $columns)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -94,10 +98,11 @@ class KeywordService extends BaseService
|
|||
|
||||
public function hasRepeated($data, $id = 0): bool
|
||||
{
|
||||
$query = $this->query()->when($id, fn($query) => $query->where('id', '<>', $id));
|
||||
$query = $this->query()->when($id, fn ($query) => $query->where('id', '<>', $id));
|
||||
|
||||
if ((clone $query)->where('key', $data['key'])->exists()) {
|
||||
$this->setError('KEY重复');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +112,7 @@ class KeywordService extends BaseService
|
|||
public function delete(string $ids): mixed
|
||||
{
|
||||
$ids = explode(',', $ids);
|
||||
if(count($ids) == 1){
|
||||
if (count($ids) == 1) {
|
||||
$this->query()->where('path', 'like', '%-'.$ids[0].'-%')->delete();
|
||||
}
|
||||
|
||||
|
|
@ -19,15 +19,8 @@ Route::group([
|
|||
|
||||
$router->post('login', [App\Admin\Controllers\AuthController::class, 'login']);
|
||||
|
||||
$router->resource('system/admin_users', App\Admin\Controllers\AdminUserController::class);
|
||||
$router->post('quick-edit/admin_users/{admin_user}',[\App\Admin\Controllers\AdminUserController::class, 'update']);
|
||||
|
||||
$router->get('system/admin_roles', [App\Admin\Controllers\AdminRoleController::class, 'index']);
|
||||
|
||||
$router->resource('system/settings', \App\Admin\Controllers\SettingController::class);
|
||||
|
||||
$router->resource('system/keywords', \App\Admin\Controllers\KeywordController::class);
|
||||
|
||||
$router->resource('articles', \App\Admin\Controllers\ArticleController::class);
|
||||
|
||||
$router->resource('ads', \App\Admin\Controllers\AdController::class);
|
||||
|
|
@ -40,4 +33,26 @@ Route::group([
|
|||
$router->post('start_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'startChunk']);
|
||||
$router->post('save_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'saveChunk']);
|
||||
$router->post('finish_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'finishChunk']);
|
||||
|
||||
|
||||
$router->group([
|
||||
'prefix' => 'system',
|
||||
'as' => 'system.',
|
||||
], function (Router $router) {
|
||||
// 账号管理
|
||||
$router->resource('admin_users', App\Admin\Controllers\System\AdminUserController::class);
|
||||
$router->post('/admin_users/{admin_user}/change-password', [App\Admin\Controllers\System\AdminUserController::class, 'changePassword'])->name('admin_users.change_password');
|
||||
// 角色管理
|
||||
$router->resource('admin_roles', App\Admin\Controllers\System\AdminRoleController::class);
|
||||
$router->post('admin_roles/{admin_role}/menus', [App\Admin\Controllers\System\AdminRoleController::class, 'saveMenus'])->name('admin_roles.set_menus');
|
||||
$router->post('admin_roles/{admin_role}/permissions', [App\Admin\Controllers\System\AdminRoleController::class, 'savePermissions'])->name('admin_roles.set_permissions');
|
||||
// 权限管理
|
||||
$router->resource('admin_permissions', App\Admin\Controllers\System\AdminPermissionController::class);
|
||||
// 菜单管理
|
||||
$router->resource('admin_menus', App\Admin\Controllers\System\AdminMenuController::class);
|
||||
// 系统设置
|
||||
$router->resource('settings', \App\Admin\Controllers\SettingController::class);
|
||||
// 数据字典
|
||||
$router->resource('keywords', App\Admin\Controllers\System\KeywordController::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Filters;
|
||||
namespace App\ModelFilters;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use EloquentFilter\ModelFilter;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Filters;
|
||||
namespace App\ModelFilters;
|
||||
|
||||
use EloquentFilter\ModelFilter;
|
||||
use Illuminate\Support\Arr;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\ModelFilters;
|
||||
|
||||
use EloquentFilter\ModelFilter;
|
||||
|
||||
class KeywordFilter extends ModelFilter
|
||||
{
|
||||
public function search($name)
|
||||
{
|
||||
return $this->where('name', 'like', '%'.$name.'%')->orWhere('key', 'like', '%'.$name.'%');
|
||||
}
|
||||
|
||||
public function parentKey($key)
|
||||
{
|
||||
return $this->where('parent_key', $key);
|
||||
}
|
||||
}
|
||||
|
|
@ -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(), 'admin_role_menus', 'role_id', 'menu_id');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Collection;
|
||||
use Slowlyo\OwlAdmin\Admin;
|
||||
use Slowlyo\OwlAdmin\Models\AdminUser as Model;
|
||||
|
||||
class AdminUser extends Model
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Support\Collection
|
||||
*/
|
||||
protected $allAbilities;
|
||||
|
||||
|
||||
public function roles(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Admin::adminRoleModel(), 'admin_role_users', 'user_id', 'role_id')->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取此用户的全部能力
|
||||
*/
|
||||
public function allAbilities(): Collection
|
||||
{
|
||||
if ($this->allAbilities) {
|
||||
return $this->allAbilities;
|
||||
}
|
||||
|
||||
$model = Admin::adminPermissionModel();
|
||||
$allPermissions = $model::all(['id', 'parent_id', 'slug'])->keyBy('id');
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection 此用户的所有角色的权限集合 */
|
||||
$rolePermissions = $this->roles
|
||||
->pluck('permissions')
|
||||
->flatten()
|
||||
->keyBy('id');
|
||||
|
||||
$abilities = $rolePermissions->map(fn ($permission) => $permission->slug);
|
||||
|
||||
foreach ($rolePermissions as $rolePermission) {
|
||||
if (is_null($rolePermission->parent_id) || $abilities->has($rolePermission->parent_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parent = $allPermissions->get($rolePermission->parent_id);
|
||||
|
||||
while ($parent) {
|
||||
$abilities->put($parent->id, $parent->slug);
|
||||
|
||||
if (is_null($parent->parent_id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$parent = $allPermissions->get($parent->parent_id);
|
||||
}
|
||||
}
|
||||
|
||||
unset($allPermissions, $rolePermissions);
|
||||
|
||||
return $this->allAbilities = $abilities;
|
||||
}
|
||||
|
||||
public function can($abilities, $arguments = []): bool
|
||||
{
|
||||
if (empty($abilities)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isAdministrator()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return collect($abilities)->every(
|
||||
fn ($ability) => $this->allAbilities()->contains($ability)
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Filters;
|
||||
|
||||
use EloquentFilter\ModelFilter;
|
||||
use App\Models\Keyword;
|
||||
|
||||
class KeywordFilter extends ModelFilter
|
||||
{
|
||||
/**
|
||||
* 关键字
|
||||
*/
|
||||
public function name($name)
|
||||
{
|
||||
return $this->where('name','like', '%'.$name.'%')
|
||||
->orWhere('key','like', '%'.$name.'%');
|
||||
}
|
||||
|
||||
public function parentName($parent_name)
|
||||
{
|
||||
if(request('has_owner', 1)){
|
||||
$this->where(function($q) use ($parent_name){
|
||||
$q->where('name','like', '%'.$parent_name.'%')
|
||||
->orWhere('key','like', '%'.$parent_name.'%');
|
||||
});
|
||||
}
|
||||
return $this->orWhere('path','like', '%-'.
|
||||
Keyword::where('name','like', '%'.$parent_name.'%')->orWhere('key','like', '%'.$parent_name.'%')->value('id')
|
||||
. '-%' ?? '');
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,21 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Admin\Components;
|
||||
use App\ModelFilters\KeywordFilter;
|
||||
use EloquentFilter\Filterable;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use EloquentFilter\Filterable;
|
||||
use App\Admin\Components;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Keyword extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Filterable;
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['name', 'key', 'value', 'parent_id', 'parent_key', 'path', 'sort', 'lv'];
|
||||
|
||||
|
||||
protected function serializeDate(\DateTimeInterface $date)
|
||||
{
|
||||
return $date->format('Y-m-d H:i:s');
|
||||
|
|
@ -23,26 +25,27 @@ class Keyword extends Model
|
|||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// 监听 Keyword 的创建事件,用于初始化 path 和 lv 字段值
|
||||
static::saving(function ($keyword) {
|
||||
// 如果创建的是一个根类目
|
||||
if (! $keyword->parent_id) {
|
||||
// 将层级设为 1
|
||||
$keyword->lv = 1;
|
||||
// 将 path 设为 -
|
||||
$keyword->path = '-';
|
||||
if(empty($keyword->key)){
|
||||
$keyword->key = Str::quickRandom($length = 16);
|
||||
static::saving(function (Keyword $keyword) {
|
||||
if (is_null($parent = $keyword->parent)) {
|
||||
$keyword->forceFill([
|
||||
'path' => '-',
|
||||
'lv' => 1,
|
||||
]);
|
||||
|
||||
if ((string) $keyword->key === '') {
|
||||
$keyword->key = Str::random(16);
|
||||
}
|
||||
} else {
|
||||
// 将层级设为父类目的层级 + 1
|
||||
$keyword->lv = $keyword->parent->lv + 1;
|
||||
$keyword->parent_key = $keyword->parent->key;
|
||||
// 将 path 值设为父类目的 path 追加父类目 ID 以及最后跟上一个 - 分隔符
|
||||
$keyword->path = $keyword->parent->path.$keyword->parent_id.'-';
|
||||
//当前key是否为空
|
||||
if(empty($keyword->key)){
|
||||
$keyword->key = $keyword->parent_key . '_' . (self::where('parent_key', $keyword->parent_key)->count() + 1);
|
||||
$keyword->forceFill([
|
||||
'parent_key' => $parent->lv > 1 ? $parent->parent_key : $parent->key,
|
||||
'path' => $parent->full_path,
|
||||
'lv' => $parent->lv + 1,
|
||||
]);
|
||||
|
||||
if ((string) $keyword->key === '') {
|
||||
$keyword->key = $parent->key.'_'.($parent->children()->count() + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -58,19 +61,32 @@ class Keyword extends Model
|
|||
return $this->hasMany(static::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function scopeAllChildrenOfKey($q, $parentKey)
|
||||
public function scopeSort($q)
|
||||
{
|
||||
$q->where('path','like', '%-'.
|
||||
static::where('key', $parentKey)->value('id')
|
||||
. '-%' ?? '');
|
||||
return $q->orderBy('sort', 'asc');
|
||||
}
|
||||
|
||||
public static function tagsMap(String $key)
|
||||
public function scopeAllChildrenOfKey($q, $parentKey)
|
||||
{
|
||||
$q->where('path', 'like', '%-'.
|
||||
static::where('key', $parentKey)->value('id')
|
||||
.'-%' ?? '');
|
||||
}
|
||||
|
||||
public static function tagsMap(string $key)
|
||||
{
|
||||
$mapArr = [];
|
||||
self::query()->where('parent_key', $key)->get()->map(function($item) use (&$mapArr){
|
||||
self::query()->where('parent_key', $key)->get()->map(function ($item) use (&$mapArr) {
|
||||
$mapArr[$item->id] = Components::make()->keywordsTag($item->name, $item->value);
|
||||
});
|
||||
|
||||
return $mapArr;
|
||||
}
|
||||
|
||||
protected function fullPath(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn (mixed $value, array $attributes) => $attributes['path'].$attributes['id'].'-',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
|
@ -11,8 +14,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
|
||||
$this->app->singleton('admin.menu', \App\Admin\Menu::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -20,6 +22,24 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
\Schema::defaultStringLength(191);
|
||||
JsonResource::withoutWrapping();
|
||||
|
||||
$this->definePolymorphicTypes();
|
||||
|
||||
Validator::extend('phone', function ($attribute, $value, $parameters, $validator) {
|
||||
return preg_match('/^1[\d]{10}$/', $value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义多态类型
|
||||
*/
|
||||
protected function definePolymorphicTypes(): void
|
||||
{
|
||||
Relation::enforceMorphMap(
|
||||
collect([
|
||||
\App\Models\AdminUser::class,
|
||||
])->mapWithKeys(fn ($model) => [(new $model)->getTable() => $model])->all()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use Slowlyo\OwlAdmin\Services\AdminService;
|
||||
|
||||
/**
|
||||
* @method Region getModel()
|
||||
* @method Region|\Illuminate\Database\Query\Builder query()
|
||||
*/
|
||||
class BaseService extends AdminService
|
||||
{
|
||||
protected array $withRelationships = [];
|
||||
|
||||
protected string $modelFilterName = '';
|
||||
|
||||
protected bool $modelSortAble = false;
|
||||
|
||||
public function getTree()
|
||||
{
|
||||
$list = $this->query()->orderByDesc('sort')->get();
|
||||
$minNum = $list->min('parent_id');
|
||||
return array2tree($list->toArray(), $minNum);
|
||||
}
|
||||
|
||||
public function getModelFilter()
|
||||
{
|
||||
return $this->modelFilterName;
|
||||
}
|
||||
|
||||
public function listQuery()
|
||||
{
|
||||
$model = $this->getModel();
|
||||
$filter = $this->getModelFilter();
|
||||
|
||||
$query = $this->query();
|
||||
if($this->withRelationships){
|
||||
$query->with($this->withRelationships);
|
||||
}
|
||||
|
||||
if ($filter) {
|
||||
$query->filter(request()->input(), $filter);
|
||||
}
|
||||
|
||||
if($this->modelSortAble){
|
||||
$query->sort();
|
||||
}
|
||||
|
||||
$this->sortable($query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function getDetail($id)
|
||||
{
|
||||
return $this->query()->with($this->withRelationships)->find($id);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,26 +2,32 @@
|
|||
|
||||
return [
|
||||
// 应用名称
|
||||
'name' => 'Owl Admin',
|
||||
'name' => 'Owl Admin',
|
||||
|
||||
// 应用 logo
|
||||
'logo' => '/admin-assets/logo.png',
|
||||
'logo' => '/admin-assets/logo.png',
|
||||
|
||||
// 默认头像
|
||||
'default_avatar' => '/admin-assets/default-avatar.png',
|
||||
|
||||
// 应用安装目录
|
||||
'directory' => app_path('Admin'),
|
||||
'directory' => app_path('Admin'),
|
||||
|
||||
// 引导文件
|
||||
'bootstrap' => app_path('Admin/bootstrap.php'),
|
||||
'bootstrap' => app_path('Admin/bootstrap.php'),
|
||||
|
||||
// 应用路由
|
||||
'route' => [
|
||||
'prefix' => 'admin-api',
|
||||
'domain' => null,
|
||||
'namespace' => 'App\\Admin\\Controllers',
|
||||
'middleware' => ['admin'],
|
||||
'route' => [
|
||||
'prefix' => 'admin-api',
|
||||
'domain' => null,
|
||||
'namespace' => 'App\\Admin\\Controllers',
|
||||
'middleware' => [
|
||||
\App\Admin\Middleware\Authenticate::class,
|
||||
'admin.bootstrap',
|
||||
\App\Admin\Middleware\CheckPermission::class,
|
||||
'sanctum',
|
||||
'substitute',
|
||||
],
|
||||
// 不包含额外路由, 配置后, 不会追加新增/详情/编辑页面路由
|
||||
'without_extra_routes' => [
|
||||
'/dashboard',
|
||||
|
|
@ -30,70 +36,69 @@ return [
|
|||
|
||||
'auth' => [
|
||||
// 是否开启验证码
|
||||
'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true),
|
||||
'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true),
|
||||
// 是否开启认证
|
||||
'enable' => true,
|
||||
'enable' => true,
|
||||
// 是否开启鉴权
|
||||
'permission' => true,
|
||||
'permission' => true,
|
||||
// token 有效期 (分钟), 为空则不会过期
|
||||
'token_expiration' => null,
|
||||
'guard' => 'admin',
|
||||
'guards' => [
|
||||
'guard' => 'admin',
|
||||
'guards' => [
|
||||
'admin' => [
|
||||
'driver' => 'sanctum',
|
||||
'driver' => 'sanctum',
|
||||
'provider' => 'admin',
|
||||
],
|
||||
],
|
||||
'providers' => [
|
||||
'providers' => [
|
||||
'admin' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
|
||||
'model' => \App\Models\AdminUser::class,
|
||||
],
|
||||
],
|
||||
'except' => [
|
||||
|
||||
'except' => [
|
||||
],
|
||||
],
|
||||
|
||||
'upload' => [
|
||||
'disk' => env("FILESYSTEM_DISK", 'public'),
|
||||
'disk' => env('FILESYSTEM_DISK', 'public'),
|
||||
// 文件上传目录
|
||||
'directory' => [
|
||||
'image' => 'images',
|
||||
'file' => 'files',
|
||||
'rich' => 'rich',
|
||||
'file' => 'files',
|
||||
'rich' => 'rich',
|
||||
],
|
||||
// 临时目录
|
||||
'tem_directory' => [
|
||||
'image' => 'temporary/images',
|
||||
'file' => 'temporary/file',
|
||||
'rich' => 'temporary/rich',
|
||||
]
|
||||
'file' => 'temporary/file',
|
||||
'rich' => 'temporary/rich',
|
||||
],
|
||||
],
|
||||
|
||||
'https' => env('ADMIN_HTTPS', false),
|
||||
'https' => env('ADMIN_HTTPS', false),
|
||||
|
||||
// 是否显示 [开发者工具]
|
||||
'show_development_tools' => env('ADMIN_SHOW_DEVELOPMENT_TOOLS', true),
|
||||
'show_development_tools' => env('ADMIN_SHOW_DEVELOPMENT_TOOLS', false),
|
||||
|
||||
// 是否显示 [权限] 功能中的自动生成按钮
|
||||
'show_auto_generate_permission_button' => env('ADMIN_SHOW_AUTO_GENERATE_PERMISSION_BUTTON', true),
|
||||
|
||||
// 扩展
|
||||
'extension' => [
|
||||
'extension' => [
|
||||
'dir' => base_path('extensions'),
|
||||
],
|
||||
|
||||
'layout' => [
|
||||
// 浏览器标题, 功能名称使用 %title% 代替
|
||||
'title' => '%title% | OwlAdmin',
|
||||
'header' => [
|
||||
'title' => '%title% | 门店助手-管理后台',
|
||||
'header' => [
|
||||
// 是否显示 [刷新] 按钮
|
||||
'refresh' => true,
|
||||
'refresh' => true,
|
||||
// 是否显示 [暗色模式] 按钮
|
||||
'dark' => true,
|
||||
'dark' => true,
|
||||
// 是否显示 [全屏] 按钮
|
||||
'full_screen' => true,
|
||||
'full_screen' => true,
|
||||
// 是否显示 [主题配置] 按钮
|
||||
'theme_config' => true,
|
||||
],
|
||||
|
|
@ -108,17 +113,17 @@ return [
|
|||
*/
|
||||
'keep_alive_exclude' => [],
|
||||
// 底部信息
|
||||
'footer' => '<a href="https://github.com/slowlyo/owl-admin" target="_blank">Owl Admin</a>',
|
||||
'footer' => '',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'connection' => env('ADMIN_DB_CONNECTION') ?? env('DB_CONNECTION', 'mysql'),
|
||||
'connection' => env('DB_CONNECTION', 'mysql'),
|
||||
],
|
||||
|
||||
'models' => [
|
||||
'admin_user' => \Slowlyo\OwlAdmin\Models\AdminUser::class,
|
||||
'admin_role' => \Slowlyo\OwlAdmin\Models\AdminRole::class,
|
||||
'admin_menu' => \Slowlyo\OwlAdmin\Models\AdminMenu::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,
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -1,231 +1,228 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'remember_me' => '记住我',
|
||||
'login' => '登 录',
|
||||
'logout' => '退出登录',
|
||||
'username' => '用户名',
|
||||
'password' => '密码',
|
||||
'old_password' => '旧密码',
|
||||
'remember_me' => '记住我',
|
||||
'login' => '登 录',
|
||||
'logout' => '退出登录',
|
||||
'username' => '用户名',
|
||||
'password' => '密码',
|
||||
'old_password' => '旧密码',
|
||||
'confirm_password' => '确认密码',
|
||||
'captcha' => '验证码',
|
||||
'captcha_error' => '验证码有误',
|
||||
'required' => '请填写:attribute',
|
||||
'captcha' => '验证码',
|
||||
'captcha_error' => '验证码有误',
|
||||
'required' => '请填写:attribute',
|
||||
'login_successful' => '登录成功',
|
||||
'login_failed' => '用户名或密码错误',
|
||||
'user_setting' => '个人设置',
|
||||
'created_at' => '创建时间',
|
||||
'updated_at' => '更新时间',
|
||||
'deleted_at' => '删除时间',
|
||||
'actions' => '操作',
|
||||
'create' => '新增',
|
||||
'edit' => '编辑',
|
||||
'show' => '查看',
|
||||
'delete' => '删除',
|
||||
'copy' => '复制',
|
||||
'confirm_delete' => '确认删除选中项?',
|
||||
'back' => '返回',
|
||||
'reset' => '重置',
|
||||
'search' => '搜索',
|
||||
'list' => '列表',
|
||||
'add' => '新增',
|
||||
'save' => '保存',
|
||||
'detail' => '详情',
|
||||
'login_failed' => '用户名或密码错误',
|
||||
'user_setting' => '个人设置',
|
||||
'created_at' => '创建时间',
|
||||
'updated_at' => '更新时间',
|
||||
'deleted_at' => '删除时间',
|
||||
'actions' => '操作',
|
||||
'create' => '新增',
|
||||
'edit' => '编辑',
|
||||
'show' => '查看',
|
||||
'delete' => '删除',
|
||||
'copy' => '复制',
|
||||
'confirm_delete' => '确认删除选中项?',
|
||||
'confirm' => '是否确定?',
|
||||
'back' => '返回',
|
||||
'reset' => '重置',
|
||||
'search' => '搜索',
|
||||
'list' => '列表',
|
||||
'add' => '新增',
|
||||
'save' => '保存',
|
||||
'detail' => '详情',
|
||||
|
||||
'developer' => '开发',
|
||||
'code_generator' => '代码生成器',
|
||||
'visual_editor' => '可视化编辑器',
|
||||
'terminal' => '终端',
|
||||
'administrator' => '管理员',
|
||||
'soft_delete' => '软删除',
|
||||
'keyword' => '关键字',
|
||||
'unknown_error' => '未知错误',
|
||||
'upload_file_error' => '上传文件错误',
|
||||
'parent' => '父级',
|
||||
'order' => '排序',
|
||||
'order_desc' => '降序排序',
|
||||
'order_asc' => '升序排序',
|
||||
'menus' => '菜单',
|
||||
'successfully' => '成功',
|
||||
'failed' => '失败',
|
||||
'successfully_message' => ':attribute成功',
|
||||
'failed_message' => ':attribute失败',
|
||||
'action_success' => '操作成功',
|
||||
'action_failed' => '操作失败',
|
||||
'save_success' => '保存成功',
|
||||
'save_failed' => '保存失败',
|
||||
'yes' => '是',
|
||||
'no' => '否',
|
||||
'developer' => '开发',
|
||||
'code_generator' => '代码生成器',
|
||||
'visual_editor' => '可视化编辑器',
|
||||
'terminal' => '终端',
|
||||
'administrator' => '管理员',
|
||||
'soft_delete' => '软删除',
|
||||
'keyword' => '关键字',
|
||||
'unknown_error' => '未知错误',
|
||||
'upload_file_error' => '上传文件错误',
|
||||
'parent' => '父级',
|
||||
'order' => '排序',
|
||||
'order_desc' => '降序排序',
|
||||
'order_asc' => '升序排序',
|
||||
'menus' => '菜单',
|
||||
'successfully' => '成功',
|
||||
'failed' => '失败',
|
||||
'successfully_message' => ':attribute成功',
|
||||
'failed_message' => ':attribute失败',
|
||||
'action_success' => '操作成功',
|
||||
'action_failed' => '操作失败',
|
||||
'save_success' => '保存成功',
|
||||
'save_failed' => '保存失败',
|
||||
'yes' => '是',
|
||||
'no' => '否',
|
||||
'need_start_with_slash' => '需要以 / 开头',
|
||||
'cancel' => '取消',
|
||||
'please_login' => '请先登录',
|
||||
'unauthorized' => '无权访问',
|
||||
'user_disabled' => '用户已被禁用',
|
||||
'cancel' => '取消',
|
||||
'please_login' => '请先登录',
|
||||
'unauthorized' => '无权访问',
|
||||
|
||||
'code_generators' => [
|
||||
'remark1' => '额外参数请参考',
|
||||
'remark2' => '数据库迁移',
|
||||
'remark3' => '多个参数使用英文逗号分割',
|
||||
'table_name' => '表名',
|
||||
'model_name' => '模型',
|
||||
'controller_name' => '控制器',
|
||||
'service_name' => 'Service',
|
||||
'primary_key' => '主键名称',
|
||||
'primary_key_description' => '使用 increments 方法',
|
||||
'options' => '可选项',
|
||||
'remark1' => '额外参数请参考',
|
||||
'remark2' => '数据库迁移',
|
||||
'remark3' => '多个参数使用英文逗号分割',
|
||||
'table_name' => '表名',
|
||||
'model_name' => '模型',
|
||||
'controller_name' => '控制器',
|
||||
'service_name' => 'Service',
|
||||
'primary_key' => '主键名称',
|
||||
'primary_key_description' => '使用 increments 方法',
|
||||
'options' => '可选项',
|
||||
'create_database_migration' => '创建数据库迁移文件',
|
||||
'create_table' => '创建数据表',
|
||||
'create_model' => '创建模型',
|
||||
'create_controller' => '创建控制器',
|
||||
'create_service' => '创建Service',
|
||||
'app_title' => '功能名称',
|
||||
'column_name' => '字段名',
|
||||
'type' => '类型',
|
||||
'extra_params' => '额外参数',
|
||||
'nullable' => '允许空值',
|
||||
'index' => '索引',
|
||||
'default_value' => '默认值',
|
||||
'comment' => '注释',
|
||||
'exists_table' => '已有数据表',
|
||||
'generate_code' => '生成代码',
|
||||
'expand_more_settings' => '更多设置',
|
||||
'collapse_settings' => '收起设置',
|
||||
'confirm_generate_code' => '确认生成代码?',
|
||||
'preview' => '预览',
|
||||
'base_info' => '基本信息',
|
||||
'column_info' => '字段信息',
|
||||
'route_config' => '路由配置',
|
||||
'page_config' => '页面配置',
|
||||
'gen_route_menu' => '生成路由&菜单',
|
||||
'route' => '路由',
|
||||
'menu_name' => '菜单名称',
|
||||
'parent_menu' => '父级菜单',
|
||||
'menu_icon' => '菜单图标',
|
||||
'name_label_desc' => 'name和label属性取字段名和注释',
|
||||
'column_warning' => '如果字段名存在 no、status 会导致 form 回显失败!',
|
||||
'add_column' => '添加字段',
|
||||
'scope' => '作用域',
|
||||
'list_component' => '列表组件',
|
||||
'list_component_desc' => '列表组件, 默认为 TableColumn',
|
||||
'form_component' => '表单组件',
|
||||
'form_component_desc' => '表单组件, 默认为 TextControl',
|
||||
'detail_component' => '详情组件',
|
||||
'detail_component_desc' => '详情组件, 默认为 TextControl',
|
||||
'model_config' => '模型配置',
|
||||
'file_column' => '文件字段',
|
||||
'file_column_desc' => '文件字段会自动在模型中添加 获取/修改器 方法',
|
||||
'preview_code' => '预览代码',
|
||||
'property' => '属性',
|
||||
'property_name' => '属性名称',
|
||||
'value' => '值',
|
||||
'dialog_form' => '弹窗表单',
|
||||
'dialog_size' => '弹窗大小',
|
||||
'copy_record' => '复制记录',
|
||||
'copy_record_description' => '你可以复制后分享到 <a href="https://github.com/Slowlyo/owl-admin/discussions/categories/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E8%AE%B0%E5%BD%95" target="_blank">Github</a>',
|
||||
'import_record' => '导入记录',
|
||||
'create_table' => '创建数据表',
|
||||
'create_model' => '创建模型',
|
||||
'create_controller' => '创建控制器',
|
||||
'create_service' => '创建Service',
|
||||
'app_title' => '功能名称',
|
||||
'column_name' => '字段名',
|
||||
'type' => '类型',
|
||||
'extra_params' => '额外参数',
|
||||
'nullable' => '允许空值',
|
||||
'index' => '索引',
|
||||
'default_value' => '默认值',
|
||||
'comment' => '注释',
|
||||
'exists_table' => '已有数据表',
|
||||
'generate_code' => '生成代码',
|
||||
'expand_more_settings' => '更多设置',
|
||||
'collapse_settings' => '收起设置',
|
||||
'confirm_generate_code' => '确认生成代码?',
|
||||
'preview' => '预览',
|
||||
'base_info' => '基本信息',
|
||||
'column_info' => '字段信息',
|
||||
'route_config' => '路由配置',
|
||||
'page_config' => '页面配置',
|
||||
'gen_route_menu' => '生成路由&菜单',
|
||||
'route' => '路由',
|
||||
'menu_name' => '菜单名称',
|
||||
'parent_menu' => '父级菜单',
|
||||
'menu_icon' => '菜单图标',
|
||||
'name_label_desc' => 'name和label属性取字段名和注释',
|
||||
'column_warning' => '如果字段名存在 no、status 会导致 form 回显失败!',
|
||||
'add_column' => '添加字段',
|
||||
'scope' => '作用域',
|
||||
'list_component' => '列表组件',
|
||||
'list_component_desc' => '列表组件, 默认为 TableColumn',
|
||||
'form_component' => '表单组件',
|
||||
'form_component_desc' => '表单组件, 默认为 TextControl',
|
||||
'detail_component' => '详情组件',
|
||||
'detail_component_desc' => '详情组件, 默认为 TextControl',
|
||||
'model_config' => '模型配置',
|
||||
'file_column' => '文件字段',
|
||||
'file_column_desc' => '文件字段会自动在模型中添加 获取/修改器 方法',
|
||||
'preview_code' => '预览代码',
|
||||
'property' => '属性',
|
||||
'property_name' => '属性名称',
|
||||
'value' => '值',
|
||||
'dialog_form' => '弹窗表单',
|
||||
'dialog_size' => '弹窗大小',
|
||||
'copy_record' => '复制记录',
|
||||
'copy_record_description' => '你可以复制后分享到 <a href="https://github.com/Slowlyo/owl-admin/discussions/categories/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E8%AE%B0%E5%BD%95" target="_blank">Github</a>',
|
||||
'import_record' => '导入记录',
|
||||
'import_record_placeholder' => '请输入导入的json记录',
|
||||
'import_record_desc' => '你可以在 <a href="https://github.com/Slowlyo/owl-admin/discussions/categories/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E8%AE%B0%E5%BD%95" target="_blank">Github</a> 找到一些其他人分享的记录',
|
||||
'load_config' => '加载配置',
|
||||
'load_component_config' => '加载 :c 配置',
|
||||
'fill' => '填充',
|
||||
'save_current_config' => '保存当前配置',
|
||||
'input_config_name' => '请填写配置名称',
|
||||
'same_name_tips' => '相同名称的配置将会被覆盖',
|
||||
'save_path_dir' => '主应用',
|
||||
'save_path_select' => '选择目录',
|
||||
'save_path_select_tips' => '可选择项目根目录或插件根目录',
|
||||
'save_path_label_prefix' => '插件 -> ',
|
||||
'import_record_desc' => '你可以在 <a href="https://github.com/Slowlyo/owl-admin/discussions/categories/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E8%AE%B0%E5%BD%95" target="_blank">Github</a> 找到一些其他人分享的记录',
|
||||
'load_config' => '加载配置',
|
||||
'load_component_config' => '加载 :c 配置',
|
||||
'fill' => '填充',
|
||||
'save_current_config' => '保存当前配置',
|
||||
'input_config_name' => '请填写配置名称',
|
||||
'same_name_tips' => '相同名称的配置将会被覆盖',
|
||||
],
|
||||
|
||||
'admin_users' => '管理员',
|
||||
'admin_user' => [
|
||||
'avatar' => '头像',
|
||||
'name' => '姓名',
|
||||
'roles' => '角色',
|
||||
'search_username' => '搜索用户名/名称',
|
||||
'password_confirmation' => '两次输入密码不一致',
|
||||
'old_password_required' => '请输入原密码',
|
||||
'old_password_error' => '原密码错误',
|
||||
'admin_user' => [
|
||||
'avatar' => '头像',
|
||||
'name' => '姓名',
|
||||
'roles' => '角色',
|
||||
'lock' => '锁定',
|
||||
'edit_password' => '修改密码',
|
||||
'search_username' => '搜索用户名/姓名',
|
||||
'password_confirmation' => '两次输入密码不一致',
|
||||
'old_password_required' => '请输入原密码',
|
||||
'old_password_error' => '原密码错误',
|
||||
'username_already_exists' => '用户名已存在',
|
||||
'cannot_delete' => '不可删除超级管理员',
|
||||
],
|
||||
|
||||
'admin_roles' => '角色',
|
||||
'admin_role' => [
|
||||
'name' => '名称',
|
||||
'slug' => '标识',
|
||||
'permissions' => '权限',
|
||||
'slug_description' => '角色的唯一标识, 不可重复',
|
||||
'admin_role' => [
|
||||
'name' => '名称',
|
||||
'slug' => '标识',
|
||||
'permissions' => '权限',
|
||||
'slug_description' => '角色的唯一标识, 不可重复',
|
||||
'name_already_exists' => '角色名称已存在',
|
||||
'slug_already_exists' => '角色标识已存在',
|
||||
'set_permissions' => '设置权限',
|
||||
'cannot_delete' => '不可删除超级管理员',
|
||||
'used' => '不可删除正在使用的角色',
|
||||
'set_permissions' => '设置权限',
|
||||
'set_menus' => '设置菜单',
|
||||
],
|
||||
|
||||
'admin_permissions' => '权限',
|
||||
'admin_permission' => [
|
||||
'name' => '名称',
|
||||
'slug' => '标识',
|
||||
'http_method' => '请求方式',
|
||||
'admin_permission' => [
|
||||
'name' => '名称',
|
||||
'slug' => '标识',
|
||||
'http_method' => '请求方式',
|
||||
'http_method_description' => '不选则为ANY',
|
||||
'http_path' => '路由',
|
||||
'auto_generate' => '自动生成',
|
||||
'auto_generate_confirm' => '权限信息会在 截断权限表&权限菜单关联表 后重新生成, 是否继续操作 ?',
|
||||
'parent_id_not_allow' => '父级不允许设置为当前子权限',
|
||||
'name_already_exists' => '权限名称已存在',
|
||||
'slug_already_exists' => '权限标识已存在',
|
||||
'http_path' => '路由',
|
||||
'auto_generate' => '自动生成',
|
||||
'auto_generate_confirm' => '权限信息会在 截断权限表&权限菜单关联表 后重新生成, 是否继续操作 ?',
|
||||
'parent_id_not_allow' => '父级不允许设置为当前子权限',
|
||||
'name_already_exists' => '权限名称已存在',
|
||||
'slug_already_exists' => '权限标识已存在',
|
||||
],
|
||||
|
||||
'admin_menus' => '菜单',
|
||||
'admin_menu' => [
|
||||
'parent_id' => '父级',
|
||||
'order' => '排序',
|
||||
'title' => '名称',
|
||||
'icon' => '图标',
|
||||
'icon_description' => '请参考',
|
||||
'url' => '链接',
|
||||
'visible' => '可见',
|
||||
'type' => '类型',
|
||||
'iframe' => 'Iframe',
|
||||
'iframe_description' => '开启后页面将缓存,重新打开时不会重新加载',
|
||||
'api' => '页面Api',
|
||||
'api_description' => 'schemaApi, 页面初始化请求的api, 需要与Controller中的queryPath一致',
|
||||
'route' => '路由',
|
||||
'keep_alive' => '缓存页面',
|
||||
'link' => '外链',
|
||||
'class_name' => '类名',
|
||||
'admin_menu' => [
|
||||
'parent_id' => '父级',
|
||||
'order' => '排序',
|
||||
'title' => '名称',
|
||||
'icon' => '图标',
|
||||
'icon_description' => '请参考',
|
||||
'url' => '链接',
|
||||
'visible' => '可见',
|
||||
'type' => '类型',
|
||||
'api' => '页面Api',
|
||||
'api_description' => 'schemaApi, 页面初始化请求的api, 需要与Controller中的queryPath一致',
|
||||
'route' => '路由',
|
||||
'link' => '外链',
|
||||
'class_name' => '类名',
|
||||
'class_name_description' => '菜单的CSS类名, 一般用于自定义样式',
|
||||
'show' => '可见',
|
||||
'hide' => '隐藏',
|
||||
'is_home' => '首页',
|
||||
'is_home_description' => '在多页签卡模式下,页面标签将固定在左侧',
|
||||
'is_full' => '全屏',
|
||||
'is_full_description' => '开启后将隐藏该页面的菜单栏部分',
|
||||
'parent_id_not_allow' => '父级菜单不允许设置为当前子菜单',
|
||||
'component' => '组件',
|
||||
'component_desc' => '默认为 amis , 非自定义前端页面请勿修改',
|
||||
'url_exists' => '菜单路径重复',
|
||||
'show' => '可见',
|
||||
'hide' => '隐藏',
|
||||
'is_home' => '首页',
|
||||
'is_home_description' => '在多页签卡模式下,页面标签将固定在左侧',
|
||||
'is_full' => '全屏',
|
||||
'is_full_description' => '开启后将隐藏该页面的菜单栏部分',
|
||||
'parent_id_not_allow' => '父级菜单不允许设置为当前子菜单',
|
||||
'component' => '组件',
|
||||
'component_desc' => '默认为 amis , 非自定义前端页面请勿修改',
|
||||
],
|
||||
|
||||
'keywords' => [
|
||||
'search_name' => '名称/KEY',
|
||||
'parent_keyword' => '父级关键字',
|
||||
],
|
||||
|
||||
'extensions' => [
|
||||
'name_invalid' => '无效的扩展名称',
|
||||
'exists' => '该扩展已存在:',
|
||||
'menu' => '扩展',
|
||||
'page_title' => '扩展',
|
||||
'create' => '创建',
|
||||
'install' => '安装',
|
||||
'create_extension' => '创建扩展',
|
||||
'create_tips' => '创建成功后会在<br><b>:dir</b><br>目录下创建基础的扩展目录结构',
|
||||
'local_install' => '本地安装',
|
||||
'more_extensions' => '更多扩展',
|
||||
'setting' => '设置',
|
||||
'enable' => '启用',
|
||||
'enable_confirm' => '确定要启用该扩展吗?',
|
||||
'disable' => '禁用',
|
||||
'disable_confirm' => '确定要禁用该扩展吗?',
|
||||
'uninstall' => '卸载',
|
||||
'uninstall_confirm' => '
|
||||
'name_invalid' => '无效的扩展名称',
|
||||
'exists' => '该扩展已存在:',
|
||||
'menu' => '扩展',
|
||||
'page_title' => '扩展',
|
||||
'create' => '创建',
|
||||
'install' => '安装',
|
||||
'create_extension' => '创建扩展',
|
||||
'create_tips' => '创建成功后会在<br><b>:dir</b><br>目录下创建基础的扩展目录结构',
|
||||
'local_install' => '本地安装',
|
||||
'more_extensions' => '更多扩展',
|
||||
'setting' => '设置',
|
||||
'enable' => '启用',
|
||||
'enable_confirm' => '确定要启用该扩展吗?',
|
||||
'disable' => '禁用',
|
||||
'disable_confirm' => '确定要禁用该扩展吗?',
|
||||
'uninstall' => '卸载',
|
||||
'uninstall_confirm' => '
|
||||
<div class="text-danger">
|
||||
确认卸载该扩展?<br>
|
||||
卸载将会删除启用扩展后发布的所有文件及数据库, 且不可找回!!!<br>
|
||||
|
|
@ -234,73 +231,34 @@ return [
|
|||
</div>
|
||||
',
|
||||
'filter_placeholder' => '输入扩展名称',
|
||||
'form' => [
|
||||
'create_extension' => '创建扩展',
|
||||
'name' => '名称',
|
||||
'namespace' => '命名空间',
|
||||
'form' => [
|
||||
'create_extension' => '创建扩展',
|
||||
'name' => '名称',
|
||||
'namespace' => '命名空间',
|
||||
'create_description' => '创建成功后会在 :dir 目录下创建基础的扩展目录结构',
|
||||
],
|
||||
'card' => [
|
||||
'author' => '作者',
|
||||
'version' => '版本',
|
||||
'card' => [
|
||||
'author' => '作者',
|
||||
'version' => '版本',
|
||||
'homepage' => '主页',
|
||||
'status' => '状态',
|
||||
'status' => '状态',
|
||||
],
|
||||
'status_map' => [
|
||||
'enabled' => '已启用',
|
||||
'status_map' => [
|
||||
'enabled' => '已启用',
|
||||
'disabled' => '已禁用',
|
||||
],
|
||||
'validation' => [
|
||||
'file' => '请选择文件',
|
||||
'validation' => [
|
||||
'file' => '请选择文件',
|
||||
'invalid_package' => '无效的扩展包',
|
||||
],
|
||||
],
|
||||
'export' => [
|
||||
'title' => '导出',
|
||||
'all' => '全部',
|
||||
'page' => '本页',
|
||||
'selected_rows' => '选中行',
|
||||
'page_no_data' => '本页无数据',
|
||||
'selected_rows_no_data' => '请选择要导出的数据',
|
||||
'export' => [
|
||||
'title' => '导出',
|
||||
'all' => '全部',
|
||||
'page' => '本页',
|
||||
'selected_rows' => '选中行',
|
||||
'page_no_data' => '本页无数据',
|
||||
'selected_rows_no_data' => '请选择要导出的数据',
|
||||
'please_install_laravel_excel' => '请先安装 laravel-excel 扩展',
|
||||
],
|
||||
'keywords' => [
|
||||
'search_name' => '名称/KEY',
|
||||
'parent_keyword' => '父级关键字',
|
||||
],
|
||||
'articles' => [
|
||||
'id' => '主键ID',
|
||||
'title' => '标题',
|
||||
'content' => '内容',
|
||||
'cover' =>'封面',
|
||||
'category' => '分类',
|
||||
'tags' => '标签',
|
||||
't_ids' => '标签',
|
||||
'published_at' => '定时发布',
|
||||
'published_at_g' => '发布时间',
|
||||
'is_enable' => '显示',
|
||||
'is_recommend' => '推荐',
|
||||
'sort' => '排序',
|
||||
'appendixes' => '附件',
|
||||
'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间',
|
||||
],
|
||||
'ads' => [
|
||||
'id' => 'ID',
|
||||
'address' => '位置',
|
||||
'resource' =>'内容',
|
||||
'published_at' => '定时发布',
|
||||
'published_at_g' => '发布时间',
|
||||
'is_enable' => '显示',
|
||||
'remark' => '备注',
|
||||
'sort' => '排序',
|
||||
'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间',
|
||||
'jump_type' => '跳转类型',
|
||||
'jump_config'=>'跳转配置',
|
||||
'jump_config_arr'=>[
|
||||
'web_link' => '网页地址',
|
||||
'app_link' => '应用路径',
|
||||
'mini_id' => '小程序ID',
|
||||
'mini_link'=> '小程序路径'
|
||||
],
|
||||
]
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue