diff --git a/app/Admin/Controllers/ArticleCategoryController.php b/app/Admin/Controllers/ArticleCategoryController.php index 682f590..560643c 100644 --- a/app/Admin/Controllers/ArticleCategoryController.php +++ b/app/Admin/Controllers/ArticleCategoryController.php @@ -2,14 +2,13 @@ namespace App\Admin\Controllers; -use Slowlyo\OwlAdmin\Renderers\Page; -use Slowlyo\OwlAdmin\Renderers\Form; -use Slowlyo\OwlAdmin\Renderers\TableColumn; -use Slowlyo\OwlAdmin\Renderers\TextControl; +use Slowlyo\OwlAdmin\Renderers\{Form, Page}; +use Slowlyo\OwlAdmin\Renderers\{Component, TableColumn, TextControl, Button, Image, Status, NumberControl, SwitchControl, ImageControl}; use Slowlyo\OwlAdmin\Controllers\AdminController; use App\Services\Admin\ArticleCategoryService; use App\Admin\Components; use Illuminate\Http\Request; +use Illuminate\Support\Arr; class ArticleCategoryController extends AdminController { @@ -23,22 +22,22 @@ class ArticleCategoryController extends AdminController ->footerToolbar([]) ->headerToolbar([ $this->createButton(true), - amis('reload')->align('right'), - amis('filter-toggler')->align('right'), + ...$this->baseHeaderToolBar(), ]) + ->filter($this->baseFilter()->actions([])->body([ + TextControl::make()->name('name')->label(__('article-category.name'))->size('md'), + Components::make()->parentControl(admin_url('api/article-categories/tree-list'), 'parent_path')->size('lg'), + Button::make()->label(__('admin.reset'))->actionType('clear-and-submit'), + Component::make()->setType('submit')->label(__('admin.search'))->level('primary'), + ])) ->quickSaveItemApi(admin_url('quick-edit/article-categories/$id')) + ->quickSaveApi(admin_url('quick-edit/article-categories')) ->columns([ - ['name' => 'id', 'label' => __('article-category.id')], - ['name' => 'name', 'label' => __('article-category.name')], - ['name' => 'icon', 'label' => __('article-category.icon'), 'type' => 'image', 'width' => 60], - ['name' => 'sort', 'label' => __('article-category.sort')], - ['name' => 'is_enable', 'label' => __('article-category.is_enable'), 'type' => 'switch', 'quickEdit' => [ - 'type' => 'switch', - 'mode' => 'inline', - 'onText' => __('admin.switch.on'), - 'offText' => __('admin.switch.off'), - 'saveImmediately' => true, - ]], + TableColumn::make()->name('id')->label(__('article-category.id')), + TableColumn::make()->name('name')->label(__('article-category.name')), + TableColumn::make()->name('icon')->label(__('article-category.icon'))->type('image')->width(60), + TableColumn::make()->name('sort')->label(__('article-category.sort'))->align('center')->quickEdit(Components::make()->sortControl('sort', __('article-category.sort'))), + TableColumn::make()->name('is_enable')->label(__('article-category.is_enable'))->type('switch')->quickEdit(SwitchControl::make()->mode('inline')->onText(__('admin.extensions.status_map.enabled'))->offText(__('admin.extensions.status_map.disabled'))->saveImmediately(true)), $this->rowActions(true), ]); @@ -47,21 +46,27 @@ class ArticleCategoryController extends AdminController public function form(): Form { - return $this->baseForm()->body([ - TextControl::make()->name('name')->label('名称')->required(true), - amisMake()->ImageControl()->name('icon')->label('icon')->autoUpload(true), + return $this->baseForm()->title('')->body([ + TextControl::make()->name('name')->label(__('article-category.name'))->required(true), + ImageControl::make()->name('icon')->label(__('article-category.name'))->autoUpload(true), Components::make()->parentControl(admin_url('api/article-categories/tree-list')), - Components::make()->sortControl(), - amisMake()->SwitchControl()->name('is_enable')->value(true)->label('显示'), + Components::make()->sortControl('sort', __('article-category.sort')), + SwitchControl::make()->name('is_enable')->label(__('article-category.is_enable'))->onText(__('admin.extensions.status_map.enabled'))->offText(__('admin.extensions.status_map.disabled'))->value(true), ]); } public function detail(): Form { return $this->baseDetail()->body([ - ['name' => 'id', 'type' => 'static', 'label' => __('article-category.id')], - ['name' => 'name', 'type' => 'static', 'label' => __('article-category.name')], - ['name' => 'created_at', 'type' => 'static', 'label' => __('article-category.created_at')], + TextControl::make()->name('id')->label(__('article-category.id'))->static(true), + TextControl::make()->name('name')->label(__('article-category.name'))->static(true), + TextControl::make()->name('icon')->label(__('article-category.icon'))->static(true)->staticSchema(Image::make()), + TextControl::make()->name('sort')->label(__('article-category.sort'))->static(true), + TextControl::make()->name('is_enable')->label(__('article-category.is_enable'))->static(true)->staticSchema(Status::make()->source([ + ['label' => __('admin.extensions.status_map.disabled'), 'icon' => 'fa fa-close', 'color' => '#cc292e'], + ['label' => __('admin.extensions.status_map.enabled'), 'icon' => 'fa fa-check', 'color' => '#30bf13'], + ])), + TextControl::make()->name('created_at')->label(__('article-category.created_at'))->static(true), ]); } @@ -70,10 +75,17 @@ class ArticleCategoryController extends AdminController return $this->service->getTree(); } - public function quickSave(Request $request) + public function multipleUpdate(Request $request) { - logger('1', $request->all()); - + $diff = $request->input('rowsDiff'); + foreach ($diff as $item) { + $this->service->update(data_get($item, 'id'), Arr::except($item, ['id'])); + } return $this->response()->success(); } + + protected function switchFiled($name = 'is_enable') + { + + } } diff --git a/app/Admin/routes.php b/app/Admin/routes.php index 68af157..334ac52 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -24,6 +24,7 @@ Route::group([ // 文章分类 $router->resource('article-categories', \App\Admin\Controllers\ArticleCategoryController::class); $router->post('quick-edit/article-categories/{article_category}', [\App\Admin\Controllers\ArticleCategoryController::class, 'update']); + $router->post('quick-edit/article-categories', [\App\Admin\Controllers\ArticleCategoryController::class, 'multipleUpdate']); //文章管理 $router->resource('articles', \App\Admin\Controllers\ArticleController::class); //图片位置 diff --git a/app/Filters/ArticleCategoryFilter.php b/app/Filters/ArticleCategoryFilter.php new file mode 100644 index 0000000..33c70bc --- /dev/null +++ b/app/Filters/ArticleCategoryFilter.php @@ -0,0 +1,31 @@ + [input_key1, input_key2]]. + * + * @var array + */ + public $relations = []; + + public function name($v) + { + $this->whereLike('name', $v); + } + + public function parentId($v) + { + $this->where('parent_id', $v); + } + + public function parentPath($v) + { + $this->where('path', 'like', '%-'.$v.'-%'); + } +} diff --git a/app/Models/Article.php b/app/Models/Article.php index 384a9f3..f149ecb 100644 --- a/app/Models/Article.php +++ b/app/Models/Article.php @@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use EloquentFilter\Filterable; +/** + * 文章 + */ class Article extends Model { use HasFactory; diff --git a/app/Models/ArticleCategory.php b/app/Models/ArticleCategory.php index c83da40..75703f5 100644 --- a/app/Models/ArticleCategory.php +++ b/app/Models/ArticleCategory.php @@ -8,6 +8,9 @@ use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; +/** + * 文章分类 + */ class ArticleCategory extends Model { use Filterable; @@ -36,4 +39,14 @@ class ArticleCategory extends Model { return $this->hasMany(static::class, 'parent_id'); } + + public function scopeSort($q) + { + return $q->orderBy('sort', 'desc'); + } + + public function scopeShow($q) + { + return $q->where('is_enable', 1); + } } diff --git a/app/Services/Admin/ArticleCategoryService.php b/app/Services/Admin/ArticleCategoryService.php index 52fc6fd..70aa0ca 100644 --- a/app/Services/Admin/ArticleCategoryService.php +++ b/app/Services/Admin/ArticleCategoryService.php @@ -2,22 +2,23 @@ namespace App\Services\Admin; -use App\Models\ArticleCategory; -use Slowlyo\OwlAdmin\Services\AdminService; +use App\Models\{ArticleCategory, Article}; use Illuminate\Http\Request; +use App\Filters\ArticleCategoryFilter; /** * @method ArticleCategory getModel() * @method ArticleCategory|\Illuminate\Database\Query\Builder query() */ -class ArticleCategoryService extends AdminService +class ArticleCategoryService extends BaseService { protected string $modelName = ArticleCategory::class; + protected string $modelFilterName = ArticleCategoryFilter::class; public function getTree() { - $list = $this->query()->orderByDesc('sort')->get()->toArray(); - return array2tree($list); + $list = $this->query()->filter(request()->all(), $this->modelFilterName)->sort()->get()->toArray(); + return array2tree($list, request('parent_path', 0)); } public function list() @@ -38,8 +39,31 @@ class ArticleCategoryService extends AdminService return parent::store($data); } + public function update($primaryKey, $data): bool + { + $pid = data_get($data, 'parent_id', 0); + if ($pid && $parent = ArticleCategory::find($pid)) { + $data['level'] = $parent->level + 1; + $data['path'] = $parent->path . $parent->id . '-'; + } else { + $data['level'] = 1; + $data['path'] = '-'; + } + return parent::update($primaryKey, $data); + } + public function delete(string $ids): mixed { - return $this->query()->whereIn($this->primaryKey(), explode(',', $ids))->delete(); + $id = collect(explode(',', $ids)); + // 所有下级ID + foreach ($id as $value) { + $item_ids = ArticleCategory::where('path', 'like', '%-'.$value.'-%')->pluck('id'); + $id = $id->merge($item_ids); + } + $id = $id->unique(); + if (Article::whereIn('category_id', $id)->exists()) { + return $this->setError('请先删除分类下的文章'); + } + return $this->query()->whereIn($this->primaryKey(), $id)->delete(); } } diff --git a/database/seeders/ArticleSeeder.php b/database/seeders/ArticleSeeder.php new file mode 100644 index 0000000..f9e94fc --- /dev/null +++ b/database/seeders/ArticleSeeder.php @@ -0,0 +1,97 @@ + '家用电器', 'children' => [ + ['name' => '电视', 'children' => [ + ['name' => '4K高清'], + ['name' => '智慧屏'], + ['name' => 'OLED电视'], + ]], + ['name' => '冰箱', 'children' => [ + ['name' => '对开门'], + ['name' => '冰柜'], + ['name' => '双门'], + ]], + ['name' => '空调', 'children' => [ + ['name' => '空调挂机'], + ['name' => '空调柜机'], + ['name' => '中央空调'], + ]], + ]], + ['name' => '数码手机', 'children' => [ + ['name' => '手机通讯', 'children' => [ + ['name' => '游戏手机'], + ['name' => '5G手机'], + ['name' => '全面屏手机'], + ]], + ['name' => '手机配件', 'children' => [ + ['name' => '手机壳'], + ['name' => '手机膜'], + ['name' => '数据线'], + ]], + ['name' => '智能设备', 'children' => [ + ['name' => '智能手表'], + ['name' => '监控摄像'], + ['name' => '智能家居'], + ]], + ]], + ['name' => '电脑办公', 'children' => [ + ['name' => '电脑整机', 'children' => [ + ['name' => '台式机'], + ['name' => '笔记本'], + ['name' => '一体机'], + ]], + ['name' => '电脑配件', 'children' => [ + ['name' => 'CPU'], + ['name' => '显卡'], + ['name' => '显示器'], + ]], + ['name' => '外设产品', 'children' => [ + ['name' => '鼠标'], + ['name' => '键盘'], + ['name' => 'U盘'], + ]], + ]], + ]; + ArticleCategory::truncate(); + $this->createCategory($categoryList, 0); + } + + protected function createCategory($list, $pid = 0) + { + $sort = count($list); + foreach($list as $index => $item) { + $params = Arr::except($item, ['children']); + $parent = null; + if ($pid) { + $parent = ArticleCategory::find($pid); + } + $model = ArticleCategory::create(array_merge([ + 'sort' => $sort--, + 'parent_id' => $parent ? $parent->id : 0, + 'level' => $parent ? $parent->level + 1 : 1, + 'path' => ($parent ? $parent->path . $parent->id : '') . '-', + ], $params)); + $children = data_get($item, 'children'); + if ($children && count($children) > 0) { + $this->createCategory($children, $model->id); + } + } + } +} diff --git a/lang/zh_CN/admin.php b/lang/zh_CN/admin.php index 06fb18d..e1480ee 100644 --- a/lang/zh_CN/admin.php +++ b/lang/zh_CN/admin.php @@ -187,9 +187,5 @@ return [ 'page_no_data' => '本页无数据', 'selected_rows_no_data' => '请选择要导出的数据', 'please_install_laravel_excel' => '请先安装 laravel-excel 扩展', - ], - 'switch' => [ - 'on' => '开启', - 'off' => '关闭', ] ]; diff --git a/lang/zh_CN/article-category.php b/lang/zh_CN/article-category.php index dab6310..9d2c57f 100644 --- a/lang/zh_CN/article-category.php +++ b/lang/zh_CN/article-category.php @@ -4,7 +4,8 @@ return [ 'id' => 'ID', 'name' => '名称', 'icon' => '图片', - 'sort' => '排序', + 'sort' => '排序(倒序)', 'is_enable' => '状态', 'created_at' => '创建时间', + 'parent_id' => '父级', ];