1
0
Fork 0

完善字典表管理

develop
vine_liutk 2023-03-16 18:36:23 +08:00
parent 58954f3851
commit e09755a197
10 changed files with 324 additions and 19 deletions

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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');
}
}

View File

@ -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',
};
}
}

View File

@ -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();
}
}

View File

@ -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/"
}
}
}

73
composer.lock generated
View File

@ -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",

View File

@ -196,7 +196,7 @@ return [
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\QueryLoggerServiceProvider::class,
],
/*

View File

@ -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();
});
}