完善字典表管理
parent
58954f3851
commit
e09755a197
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Admin;
|
||||
|
||||
use Slowlyo\OwlAdmin\Renderers\BaseRenderer;
|
||||
|
||||
class Components extends BaseRenderer {
|
||||
|
||||
public function parentControl($apiUrl = '', $name ='parent_id', $labelField = 'name', $valueField = 'id')
|
||||
{
|
||||
return amisMake()->TreeSelectControl()
|
||||
->name('parent_id')->label('父级')
|
||||
->showIcon(false)
|
||||
->labelField($labelField)
|
||||
->valueField($valueField)
|
||||
->value(0)->source($apiUrl);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ 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;
|
||||
|
||||
class KeywordController extends AdminController
|
||||
{
|
||||
|
|
@ -18,16 +20,24 @@ class KeywordController extends AdminController
|
|||
public function list(): Page
|
||||
{
|
||||
$crud = $this->baseCRUD()
|
||||
//关闭查询
|
||||
->filterTogglable(false)
|
||||
//去掉分页-start
|
||||
->loadDataOnce(true)
|
||||
->footerToolbar([])
|
||||
//去掉分页-end
|
||||
->headerToolbar([
|
||||
$this->createButton(true),
|
||||
...$this->baseHeaderToolBar(),
|
||||
amis('reload')->align('right'),
|
||||
amis('filter-toggler')->align('right'),
|
||||
])
|
||||
->columns([
|
||||
TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||||
// TableColumn::make()->name('id')->label('ID')->sortable(true),
|
||||
TableColumn::make()->name('name')->label('名称'),
|
||||
TableColumn::make()->name('key')->label('KEY'),
|
||||
TableColumn::make()->name('value')->label('值'),
|
||||
TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true),
|
||||
TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true),
|
||||
$this->rowActions(true),
|
||||
$this->rowActionsOnlyEditAndDelete(true),
|
||||
]);
|
||||
|
||||
return $this->baseList($crud);
|
||||
|
|
@ -36,18 +46,15 @@ class KeywordController extends AdminController
|
|||
public function form(): Form
|
||||
{
|
||||
return $this->baseForm()->body([
|
||||
TextControl::make()->name('name')->label('名称')->required(),
|
||||
|
||||
|
||||
Components::make()->parentControl(admin_url('api/keywords/tree-list')),
|
||||
TextControl::make()->name('name')->label('名称')->required(true),
|
||||
TextControl::make()->name('key')->label('KEY')->required(true),
|
||||
TextControl::make()->name('value')->label('值')->required(true),
|
||||
amisMake()->NumberControl()->name('sort')->value(0)->min()->label('排序'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function detail(): Form
|
||||
{
|
||||
return $this->baseDetail()->body([
|
||||
TextControl::make()->static(true)->name('id')->label('ID'),
|
||||
TextControl::make()->static(true)->name('created_at')->label('创建时间'),
|
||||
TextControl::make()->static(true)->name('updated_at')->label('更新时间')
|
||||
]);
|
||||
}
|
||||
public function getTreeList(Request $request){
|
||||
return $this->service->getTree();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@ Route::group([
|
|||
'prefix' => config('admin.route.prefix'),
|
||||
'middleware' => config('admin.route.middleware'),
|
||||
], function (Router $router) {
|
||||
$router->group([
|
||||
'prefix' => 'api',
|
||||
], function (Router $router) {
|
||||
$router->get('keywords/tree-list', '\App\Admin\Controllers\KeywordController@getTreeList')->name('api.keywords.tree-list');
|
||||
});
|
||||
|
||||
$router->resource('dashboard', \App\Admin\Controllers\HomeController::class);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,44 @@ namespace App\Models;
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use EloquentFilter\Filterable;
|
||||
|
||||
class Keyword extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Filterable;
|
||||
|
||||
protected $fillable = ['name', 'key', 'value', 'parent_id', 'type_key', 'path', 'sort', 'level'];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
// 监听 Keyword 的创建事件,用于初始化 path 和 level 字段值
|
||||
static::creating(function ($keyword) {
|
||||
// 如果创建的是一个根类目
|
||||
if (! $keyword->parent_id) {
|
||||
// 将层级设为 1
|
||||
$keyword->level = 1;
|
||||
// 将 path 设为 -
|
||||
$keyword->path = '-';
|
||||
} else {
|
||||
// 将层级设为父类目的层级 + 1
|
||||
$keyword->level = $keyword->parent->level + 1;
|
||||
$keyword->type_key = $keyword->parent->key;
|
||||
// 将 path 值设为父类目的 path 追加父类目 ID 以及最后跟上一个 - 分隔符
|
||||
$keyword->path = $keyword->parent->path.$keyword->parent_id.'-';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(static::class, 'parent_id');
|
||||
}
|
||||
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany(static::class, 'parent_id');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Database\Events\QueryExecuted;
|
||||
use Illuminate\Database\Events\TransactionBeginning;
|
||||
use Illuminate\Database\Events\TransactionCommitted;
|
||||
use Illuminate\Database\Events\TransactionRolledBack;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class QueryLoggerServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
if (! config('app.debug')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->app['events']->listen([
|
||||
QueryExecuted::class,
|
||||
TransactionBeginning::class,
|
||||
TransactionCommitted::class,
|
||||
TransactionRolledBack::class,
|
||||
], function ($event) {
|
||||
Log::debug(match (true) {
|
||||
$event instanceof TransactionBeginning => 'begin transaction',
|
||||
$event instanceof TransactionCommitted => 'commit transaction',
|
||||
$event instanceof TransactionRolledBack => 'rollback transaction',
|
||||
default => $this->prepareSql($event),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Database\Events\QueryExecuted $query
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareSql(QueryExecuted $query): string
|
||||
{
|
||||
$sql = str_replace(['%', '?'], ['%%', '%s'], $query->sql);
|
||||
|
||||
$bindings = $query->connection->prepareBindings($query->bindings);
|
||||
|
||||
if (count($bindings)) {
|
||||
$sql = vsprintf($sql, array_map([$query->connection->getPdo(), 'quote'], $bindings));
|
||||
}
|
||||
|
||||
return sprintf('[%s] %s', $this->formatDuration($query->time), $sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $milliseconds
|
||||
* @return string
|
||||
*/
|
||||
protected function formatDuration($milliseconds): string
|
||||
{
|
||||
return match (true) {
|
||||
$milliseconds >= 1000 => round($milliseconds / 1000, 2).'s',
|
||||
$milliseconds < 0.01 => round($milliseconds * 1000).'μs',
|
||||
default => $milliseconds.'ms',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Services\Admin;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use App\Models\Keyword;
|
||||
use Slowlyo\OwlAdmin\Services\AdminService;
|
||||
|
||||
|
|
@ -12,4 +13,102 @@ use Slowlyo\OwlAdmin\Services\AdminService;
|
|||
class KeywordService extends AdminService
|
||||
{
|
||||
protected string $modelName = Keyword::class;
|
||||
|
||||
public function getTree()
|
||||
{
|
||||
$list = $this->query()->orderByDesc('sort')->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 list()
|
||||
{
|
||||
return ['items' => $this->getTree()];
|
||||
}
|
||||
|
||||
public function store($data): bool
|
||||
{
|
||||
if ($this->hasRepeated($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$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
|
||||
{
|
||||
if ($this->hasRepeated($data, $primaryKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$columns = $this->getTableColumns();
|
||||
|
||||
$parent_id = Arr::get($data, 'parent_id');
|
||||
if ($parent_id != 0) {
|
||||
if ($this->parentIsChild($primaryKey, $parent_id)) {
|
||||
$this->setError('父级不允许设置为当前子权限');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$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 hasRepeated($data, $id = 0): bool
|
||||
{
|
||||
$query = $this->query()->when($id, fn($query) => $query->where('id', '<>', $id));
|
||||
|
||||
if ((clone $query)->where('key', $data['key'])->exists()) {
|
||||
$this->setError('KEY重复');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function delete(string $ids): mixed
|
||||
{
|
||||
$ids = explode(',', $ids);
|
||||
if(count($ids) == 1){
|
||||
$this->query()->where('path', 'like', '%-'.$ids[0].'-%')->delete();
|
||||
}
|
||||
|
||||
return $this->query()->whereIn('id', $ids)->delete();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"laravel/framework": "^9.19",
|
||||
"laravel/sanctum": "^3.0",
|
||||
"laravel/tinker": "^2.7",
|
||||
"slowlyo/owl-admin": "^2.1"
|
||||
"slowlyo/owl-admin": "^2.1",
|
||||
"tucker-eric/eloquentfilter": "^3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
|
|
@ -66,7 +67,7 @@
|
|||
"repositories": {
|
||||
"packagist": {
|
||||
"type": "composer",
|
||||
"url": "https://packagist.phpcomposer.com"
|
||||
"url": "https://mirrors.aliyun.com/composer/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "a5b72c385ebe487317edadb68fb376ab",
|
||||
"content-hash": "0955c00d24fb997149c86a6cf19f653a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
|
@ -3983,6 +3983,77 @@
|
|||
"homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
|
||||
"time": "2023-01-03T09:29:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tucker-eric/eloquentfilter",
|
||||
"version": "3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Tucker-Eric/EloquentFilter.git",
|
||||
"reference": "faaad783b7f23af7ba7e23baaa56d71af51504a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Tucker-Eric/EloquentFilter/zipball/faaad783b7f23af7ba7e23baaa56d71af51504a9",
|
||||
"reference": "faaad783b7f23af7ba7e23baaa56d71af51504a9",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"illuminate/config": "~6.0|~7.0|~8.0|~9.0|~10.0",
|
||||
"illuminate/console": "~6.0|~7.0|~8.0|~9.0|~10.0",
|
||||
"illuminate/database": "~6.0|~7.0|~8.0|~9.0|~10.0",
|
||||
"illuminate/filesystem": "~6.0|~7.0|~8.0|~9.0|~10.0",
|
||||
"illuminate/pagination": "~6.0|~7.0|~8.0|~9.0|~10.0",
|
||||
"illuminate/support": "~6.0|~7.0|~8.0|~9.0|~10.0",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.3",
|
||||
"phpunit/phpunit": "^8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"EloquentFilter\\ServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"EloquentFilter\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eric Tucker",
|
||||
"email": "tucker.ericm@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An Eloquent way to filter Eloquent Models",
|
||||
"keywords": [
|
||||
"eloquent",
|
||||
"filter",
|
||||
"laravel",
|
||||
"model",
|
||||
"query",
|
||||
"search"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Tucker-Eric/EloquentFilter/issues",
|
||||
"source": "https://github.com/Tucker-Eric/EloquentFilter/tree/3.2.0"
|
||||
},
|
||||
"time": "2023-02-07T18:34:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.5.0",
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ return [
|
|||
// App\Providers\BroadcastServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
|
||||
App\Providers\QueryLoggerServiceProvider::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ return new class extends Migration
|
|||
$table->unsignedInteger('sort')->default(0)->comment('排序');
|
||||
$table->unsignedBigInteger('parent_id')->default(0)->comment('上级ID');
|
||||
$table->unsignedInteger('level')->default(1)->comment('层级');
|
||||
$table->string('path')->default('-')->comment('所有的父级ID');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue