From 5202921132b8b801c32561b86a0c49fcffa82691 Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Fri, 1 Dec 2023 11:02:18 +0800 Subject: [PATCH] article --- app/Admin/Components.php | 8 --- app/Admin/Controllers/ArticleController.php | 70 +++++++++++++++++++ app/Admin/Services/ArticleService.php | 62 ++++++++++++++++ app/Admin/Services/BaseService.php | 13 ++-- app/Admin/Services/KeywordService.php | 8 +-- app/Admin/routes.php | 5 +- app/Console/{ => Commands}/ModelFillable.php | 0 app/ModelFilters/ArticleFilter.php | 16 +++++ app/ModelFilters/KeywordFilter.php | 5 -- app/Models/Article.php | 48 +++++++++++++ config/admin.php | 2 +- ...023_12_01_102243_create_articles_table.php | 49 +++++++++++++ database/seeders/AdminMenuSeeder.php | 1 + lang/zh_CN/article.php | 17 +++++ 14 files changed, 279 insertions(+), 25 deletions(-) create mode 100644 app/Admin/Controllers/ArticleController.php create mode 100644 app/Admin/Services/ArticleService.php rename app/Console/{ => Commands}/ModelFillable.php (100%) create mode 100644 app/ModelFilters/ArticleFilter.php create mode 100644 app/Models/Article.php create mode 100644 database/migrations/2023_12_01_102243_create_articles_table.php create mode 100644 lang/zh_CN/article.php diff --git a/app/Admin/Components.php b/app/Admin/Components.php index bfeee72..f70317c 100644 --- a/app/Admin/Components.php +++ b/app/Admin/Components.php @@ -77,14 +77,6 @@ class Components extends BaseRenderer ->excludeKeys(['group-video']); } - /** - * 字典表下拉框 - */ - public function keywordTypeControl($type) - { - return amisMake()->SelectControl()->source(admin_url('api/keywords/list').'?type_key='.$type); - } - /** * switch * diff --git a/app/Admin/Controllers/ArticleController.php b/app/Admin/Controllers/ArticleController.php new file mode 100644 index 0000000..a33e904 --- /dev/null +++ b/app/Admin/Controllers/ArticleController.php @@ -0,0 +1,70 @@ +baseCRUD() + ->filterTogglable(false) + ->columnsTogglable(false) + ->headerToolbar([ + $this->createButton(true, 'lg'), + ]) + ->filter($this->baseFilter()->actions([])->body([ + amisMake()->TextControl()->name('title')->label(__('article.title'))->size('md')->clearable(), + // amisMake()->Button()->label(__('admin.reset'))->actionType('clear-and-submit'), + amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'), + ])) + ->quickSaveItemApi(admin_url('quick-edit/article/$id')) + ->columns([ + amisMake()->TableColumn()->name('id')->label(__('article.id'))->sortable(true), + amisMake()->TableColumn()->name('title')->label(__('article.title')), + amisMake()->TableColumn()->name('category.name')->label(__('article.category_id'))->className('text-primary'), + amisMake()->Image()->name('cover')->label(__('article.cover'))->width(100), + amisMake()->TableColumn()->name('sort')->label(__('article.sort'))->align('center')->quickEdit(Components::make()->sortControl('sort', __('article.sort'))->saveImmediately(true)), + Components::make()->switchControl('table')->name('is_enable')->label(__('article.is_enable')), + amisMake()->TableColumn()->name('published_at')->label(__('article.published_at')), + $this->rowActions(true, 'lg'), + ]); + + return $this->baseList($crud); + } + + public function form(): Form + { + return $this->baseForm()->title('')->body([ + amisMake()->TextControl()->name('title')->label(__('article.title'))->required(true), + Components::make()->parentControl(admin_url('api/keywords/tree-list'), 'category_id', __('article.category_id'))->onlyLeaf(true)->required(), + amisMake()->ImageControl()->name('cover')->label(__('article.cover'))->autoUpload(true), + Components::make()->sortControl('sort', __('article.sort')), + amisMake()->DateTimeControl()->name('published_at')->label(__('article.published_at'))->value(now())->format('YYYY-MM-DD HH:mm:ss')->description('*不填写则默认为创建时间'), + Components::make()->switchControl('form')->name('is_enable')->label(__('article.is_enable'))->value(true), + Components::make()->fuEditorControl('content', __('article.content')), + ]); + } + + public function detail(): Form + { + return $this->baseDetail()->title('')->body([ + amisMake()->TextControl()->static(true)->name('id')->label(__('article.id')), + amisMake()->TextControl()->static(true)->name('title')->label(__('article.title')), + amisMake()->TextControl()->static(true)->name('category.name')->label(__('article.category_id')), + amisMake()->TextControl()->name('cover')->label(__('article.cover'))->static(true)->staticSchema(amisMake()->Image()), + amisMake()->TextControl()->static(true)->name('sort')->label(__('article.sort')), + Components::make()->switchControl('show')->name('is_enable')->label(__('article.is_enable')), + amisMake()->TextControl()->static(true)->name('published_at')->label(__('article.published_at')), + amisMake()->TextControl()->static(true)->name('created_at')->label(__('article.created_at')), + Components::make()->fuEditorControl('content', __('article.content'))->static(true), + ]); + } +} diff --git a/app/Admin/Services/ArticleService.php b/app/Admin/Services/ArticleService.php new file mode 100644 index 0000000..1a9623e --- /dev/null +++ b/app/Admin/Services/ArticleService.php @@ -0,0 +1,62 @@ +getModel(); + $filter = $this->getModelFilter(); + + $query = $this->query(); + if ($this->withRelationships) { + $query->with($this->withRelationships); + } + + if ($filter) { + $query->filter(request()->input(), $filter); + } + + return $query->sort(); + } + + public function resloveData($data) + { + $cid = data_get($data, 'category_id'); + if ($cid && $category = Keyword::find($cid)) { + $data['category_path'] = $category->path.$category->id.'-'; + } + if (! data_get($data, 'published_at')) { + $data['published_at'] = now(); + } + + return $data; + } + + public function validate($data, $model = null) + { + $createRules = [ + ]; + $updateRules = [ + ]; + $validator = Validator::make($data, $model ? $updateRules : $createRules, [ + ]); + if ($validator->fails()) { + return $validator->errors()->first(); + } + + return true; + } +} diff --git a/app/Admin/Services/BaseService.php b/app/Admin/Services/BaseService.php index 14b11eb..760fe42 100644 --- a/app/Admin/Services/BaseService.php +++ b/app/Admin/Services/BaseService.php @@ -2,6 +2,7 @@ namespace App\Admin\Services; +use Illuminate\Database\Eloquent\Model; use Slowlyo\OwlAdmin\Services\AdminService; /** @@ -80,7 +81,7 @@ class BaseService extends AdminService { $data = $this->resloveData($data); $model = $this->query()->whereKey($primaryKey)->firstOrFail(); - $validate = $this->validate($data, $model->id); + $validate = $this->validate($data, $model); if ($validate !== true) { $this->setError($validate); return false; @@ -102,7 +103,7 @@ class BaseService extends AdminService /** * 处理表单数据 - * + * * @param array $data * @return array */ @@ -113,19 +114,19 @@ class BaseService extends AdminService /** * 表单验证 - * + * * @param array $data - * @param int $id 空: 添加, 非空: 修改 + * @param Model $model 空: 添加, 非空: 修改 * @return mixed true: 验证通过, string: 错误提示 */ - public function validate($data, $id = null) + public function validate($data, $model = null) { return true; } /** * 删除的前置方法 - * + * * @param array $ids 主键id * @return mixed true: 继续后续操作, string: 中断操作, 返回错误提示 */ diff --git a/app/Admin/Services/KeywordService.php b/app/Admin/Services/KeywordService.php index 16883f2..ecd2b23 100644 --- a/app/Admin/Services/KeywordService.php +++ b/app/Admin/Services/KeywordService.php @@ -33,7 +33,7 @@ class KeywordService extends BaseService /** * 删除的前置方法 - * + * * @param array $ids 主键id * @return mixed true: 继续后续操作, string: 中断操作, 返回错误提示 */ @@ -49,16 +49,16 @@ class KeywordService extends BaseService return true; } - public function validate($data, $id = null) + public function validate($data, $model = null) { $createRules = [ 'key' => ['required', Rule::unique('keywords', 'key')], 'name' => ['required'], ]; $updateRules = [ - 'key' => [Rule::unique('keywords', 'key')->ignore($id)] + 'key' => [Rule::unique('keywords', 'key')->ignore($model->id)] ]; - $validator = Validator::make($data, $id ? $updateRules : $createRules, [ + $validator = Validator::make($data, $model ? $updateRules : $createRules, [ 'key.unique' => ':input 已经存在' ]); if ($validator->fails()) { diff --git a/app/Admin/routes.php b/app/Admin/routes.php index dd2f99e..9ae2794 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -11,7 +11,7 @@ Route::group([ $router->resource('dashboard', \App\Admin\Controllers\HomeController::class); $router->get('menus', [\App\Admin\Controllers\HomeController::class, 'menus']); - + $router->get('login', [App\Admin\Controllers\AuthController::class, 'loginPage']); $router->resource('system/settings', \App\Admin\Controllers\SettingController::class); @@ -28,4 +28,7 @@ Route::group([ // 字典表 $router->resource('keywords', \App\Admin\Controllers\KeywordsController::class)->names('admin.keywords'); + + $router->resource('articles', \App\Admin\Controllers\ArticleController::class); + $router->post('quick-edit/article/{article}', [\App\Admin\Controllers\ArticleController::class, 'update']); }); diff --git a/app/Console/ModelFillable.php b/app/Console/Commands/ModelFillable.php similarity index 100% rename from app/Console/ModelFillable.php rename to app/Console/Commands/ModelFillable.php diff --git a/app/ModelFilters/ArticleFilter.php b/app/ModelFilters/ArticleFilter.php new file mode 100644 index 0000000..026b5f6 --- /dev/null +++ b/app/ModelFilters/ArticleFilter.php @@ -0,0 +1,16 @@ + [input_key1, input_key2]]. + * + * @var array + */ + public $relations = []; +} diff --git a/app/ModelFilters/KeywordFilter.php b/app/ModelFilters/KeywordFilter.php index 0a27b0a..7b8dad5 100644 --- a/app/ModelFilters/KeywordFilter.php +++ b/app/ModelFilters/KeywordFilter.php @@ -25,11 +25,6 @@ class KeywordFilter extends ModelFilter $this->whereLike('key', $key); } - public function typeKey($key) - { - $this->where('type_key', $key); - } - public function name($key) { $this->whereLike('name', $key); diff --git a/app/Models/Article.php b/app/Models/Article.php new file mode 100644 index 0000000..2ab0ba5 --- /dev/null +++ b/app/Models/Article.php @@ -0,0 +1,48 @@ + StorageFile::class, + 'files' => 'array', + 'medias' => 'array', + 'extension' => 'array', + 'published_at' => 'datetime', + ]; + + public function category() + { + return $this->belongsTo(Keyword::class, 'category_id'); + } + + public function scopeSort($q) + { + return $q->orderBy('sort', 'asc')->latest('published_at')->latest('id'); + } + + public function scopePublish($q) + { + return $q->where('published_at', '<=', now())->where('is_enable', 1); + } +} diff --git a/config/admin.php b/config/admin.php index f0a5fae..401379d 100644 --- a/config/admin.php +++ b/config/admin.php @@ -31,7 +31,7 @@ return [ // 是否开启验证码 'login_captcha' => env('ADMIN_LOGIN_CAPTCHA', true), // 是否开启鉴权 - 'enable' => true, + 'enable' => false, // 用户模型 'model' => \Slowlyo\OwlAdmin\Models\AdminUser::class, 'controller' => \Slowlyo\OwlAdmin\Controllers\AuthController::class, diff --git a/database/migrations/2023_12_01_102243_create_articles_table.php b/database/migrations/2023_12_01_102243_create_articles_table.php new file mode 100644 index 0000000..f2953aa --- /dev/null +++ b/database/migrations/2023_12_01_102243_create_articles_table.php @@ -0,0 +1,49 @@ +id(); + $table->unsignedBigInteger('category_id')->comment('分类ID'); + $table->string('category_path')->default('-')->comment('分类 path'); + $table->string('title')->comment('文章标题'); + $table->string('key')->nullable('用于指定查询某一篇文章'); + $table->string('description')->nullable()->comment('描述'); + $table->string('author')->nullable()->comment('作者'); + $table->string('cover')->nullable()->comment('封面'); + $table->longText('content')->nullable()->comment('文章内容'); + $table->json('medias')->nullable()->comment('媒体[{name,url,type}]'); + $table->json('files')->nullable()->comment('附件[{name,url,type}]'); + $table->timestamp('published_at')->nullable()->comment('发布时间'); + $table->unsignedInteger('sort')->default(1)->comment('排序(asc)'); + $table->string('remarks')->nullable()->comment('备注'); + + $table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐状态'); + $table->unsignedTinyInteger('is_enable')->default(1)->comment('可用状态'); + + $table->json('extension')->nullable()->comment('扩展字段'); + $table->unsignedBigInteger('party_cate_id')->nullable()->comment('党支部ID'); + + $table->timestamps(); + + $table->comment('文章'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('articles'); + } +}; diff --git a/database/seeders/AdminMenuSeeder.php b/database/seeders/AdminMenuSeeder.php index e7ac603..f15d344 100644 --- a/database/seeders/AdminMenuSeeder.php +++ b/database/seeders/AdminMenuSeeder.php @@ -19,6 +19,7 @@ class AdminMenuSeeder extends Seeder // 图标: https://iconpark.oceanengine.com/official $menus = [ ['title' => '主页', 'icon' => 'icon-park:home-two', 'url' => '/dashboard', 'is_home' => 1], + ['title' => '文章管理', 'icon' => 'icon-park:web-page', 'url' => '/articles'], ['title' => '系统管理', 'icon' => 'icon-park:setting', 'url' => '/system', 'children' => [ ['title' => '用户管理', 'icon' => 'icon-park:people-plus', 'url' => '/system/admin_users'], ['title' => '角色管理', 'icon' => 'icon-park:people-plus-one', 'url' => '/system/admin_roles'], diff --git a/lang/zh_CN/article.php b/lang/zh_CN/article.php new file mode 100644 index 0000000..6c0fae2 --- /dev/null +++ b/lang/zh_CN/article.php @@ -0,0 +1,17 @@ + 'ID', + 'created_at' => '创建时间', + 'description' => '描述', + 'author' => '作者', + 'category_id' => '分类', + 'category_path' => '分类', + 'content' => '内容', + 'cover' => '封面图', + 'is_enable' => '显示', + 'is_recommend' => '推荐', + 'published_at' => '发布时间', + 'sort' => '排序(正序)', + 'title' => '标题', +];