diff --git a/app/Admin/Controllers/ArticleController.php b/app/Admin/Controllers/ArticleController.php index 52fe735..20d2b17 100644 --- a/app/Admin/Controllers/ArticleController.php +++ b/app/Admin/Controllers/ArticleController.php @@ -2,10 +2,8 @@ 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\{TableColumn, TextControl, Image, ImageControl, DateTimeControl, SwitchControl, Tabs, Tab}; use Slowlyo\OwlAdmin\Controllers\AdminController; use App\Services\Admin\ArticleService; use App\Admin\Components; @@ -14,26 +12,19 @@ class ArticleController extends AdminController { protected string $serviceName = ArticleService::class; - protected string $pageTitle = '文章管理';//待完善-todo - public function list(): Page { $crud = $this->baseCRUD() ->filterTogglable(false) - ->headerToolbar([ - $this->createButton(true, 'lg'), - ...$this->baseHeaderToolBar(), - ]) ->columns([ - TableColumn::make()->name('id')->label('ID')->sortable(true), - TableColumn::make()->name('title')->label('标题'), - TableColumn::make()->name('category_id')->label('分类')->className('text-primary'), - TableColumn::make()->name('sub_title')->label('副标题'), - TableColumn::make()->name('is_enable')->type('switch')->label('显示'), - TableColumn::make()->name('published_at')->label('发布时间')->type('datetime')->sortable(true), - TableColumn::make()->name('created_at')->label('创建时间')->type('datetime')->sortable(true), - TableColumn::make()->name('updated_at')->label('更新时间')->type('datetime')->sortable(true), - $this->rowActions(true, 'lg'), + TableColumn::make()->name('id')->label(__('article.id'))->sortable(true), + TableColumn::make()->name('title')->label(__('article.title')), + TableColumn::make()->name('category.name')->label(__('article.category_id'))->className('text-primary'), + Image::make()->name('cover')->label(__('article.cover'))->width(100), + TableColumn::make()->name('sub_title')->label(__('article.sub_title')), + TableColumn::make()->name('is_enable')->type('switch')->label(__('article.is_enable')), + TableColumn::make()->name('published_at')->label(__('article.published_at')), + $this->rowActions(), ]); return $this->baseList($crud); @@ -41,25 +32,34 @@ class ArticleController extends AdminController public function form(): Form { - return $this->baseForm()->body([ - TextControl::make()->name('title')->label('标题')->required(true), - TextControl::make()->name('sub_title')->label('副标题'), - \amisMake()->ImageControl()->name('cover')->label('封面')->autoUpload(true), - Components::make()->parentControl('', 'category_id', '分类'), - Components::make()->fuEditorControl(), - Components::make()->sortControl(), - \amisMake()->DateTimeControl()->name('published_at')->label('发布时间')->description('*不填写则默认为创建时间'), - \amisMake()->SwitchControl()->name('is_enable')->label('显示'), - ]); + return $this->baseForm()->title('')->body( + Tabs::make()->tabs([ + Tab::make()->title('基本信息')->body([ + TextControl::make()->name('title')->label(__('article.title'))->required(true), + Components::make()->parentControl(admin_url('api/article-categories/tree-list'), 'category_id', __('article.category_id'))->required(true), + TextControl::make()->name('sub_title')->label(__('article.sub_title')), + ImageControl::make()->name('cover')->label(__('article.cover'))->autoUpload(true), + Components::make()->sortControl('sort', __('article.sort')), + DateTimeControl::make()->name('published_at')->label(__('article.published_at'))->value(now())->format('YYYY-MM-DD HH:mm:ss')->description('*不填写则默认为创建时间'), + SwitchControl::make()->name('is_enable')->label(__('article.is_enable'))->value(true), + ]), + Tab::make()->title('内容')->body(Components::make('content', __('article.content'))->fuEditorControl()) + ])); } public function detail(): Form { - return $this->baseDetail()->body([ - TextControl::make()->static(true)->name('id')->label('ID'), - TextControl::make()->static(true)->name('title')->label('标题'), - TextControl::make()->static(true)->name('created_at')->label('创建时间'), - TextControl::make()->static(true)->name('updated_at')->label('更新时间') - ]); + return $this->baseDetail()->title('')->body( + Tabs::make()->tabs( + Tab::make()->title('基本信息')->body([ + TextControl::make()->static(true)->name('id')->label(__('article.id')), + TextControl::make()->static(true)->name('title')->label(__('article.title')), + TextControl::make()->static(true)->name('category.name')->label(__('article.category_id')), + TextControl::make()->static(true)->name('title')->label(__('article.sub_title')), + TextControl::make()->static(true)->name('created_at')->label(__('article.created_at')), + ]), + Tab::make()->title('内容')->body('1234567') + ) + ); } } diff --git a/app/Models/Article.php b/app/Models/Article.php index f149ecb..9d37435 100644 --- a/app/Models/Article.php +++ b/app/Models/Article.php @@ -2,21 +2,48 @@ namespace App\Models; -use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; use EloquentFilter\Filterable; - +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Storage; +use Illuminate\Database\Eloquent\Casts\Attribute; +use Illuminate\Database\Eloquent\Factories\HasFactory; /** * 文章 */ class Article extends Model { - use HasFactory; use Filterable; - protected $fillable = []; + protected $fillable = ['author', 'category_id', 'category_path', 'content', 'cover', 'is_enable', 'is_recommend', 'published_at', 'sort', 'sub_title', 'title']; - protected function serializeDate(\DateTimeInterface $date){ - return $date->format('Y-m-d H:i:s'); + protected $casts = [ + 'created_at' => 'datetime:Y-m-d H:i:s', + 'updated_at' => 'datetime:Y-m-d H:i:s', + 'published_at' => 'datetime:Y-m-d H:i:s', + 'is_enable' => 'boolean', + 'is_recommend' => 'boolean', + ]; + + protected function cover(): Attribute + { + return Attribute::make( + get: fn($value) => $value ? (Str::startsWith($value, ['http://', 'https://']) ? $value : Storage::url($value)) : '', + ); + } + + public function category() + { + return $this->belongsTo(ArticleCategory::class, 'category_id'); + } + + public function scopeSort($q) + { + return $q->orderBy('sort', 'desc')->orderBy('published_at', 'desc'); + } + + public function scopeShow($q) + { + return $q->where('is_enable', 1)->where(fn ($q1) => $q1->whereNull('published_at')->orWhere('published_at', '<=', now())); } } diff --git a/app/Services/Admin/ArticleService.php b/app/Services/Admin/ArticleService.php index 726efee..aace4a8 100644 --- a/app/Services/Admin/ArticleService.php +++ b/app/Services/Admin/ArticleService.php @@ -3,13 +3,33 @@ namespace App\Services\Admin; use App\Models\Article; -use Slowlyo\OwlAdmin\Services\AdminService; +use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Str; /** * @method Article getModel() * @method Article|\Illuminate\Database\Query\Builder query() */ -class ArticleService extends AdminService +class ArticleService extends BaseService { + protected array $withRelationships = ['category']; + protected string $modelName = Article::class; + + 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); + } + + return $query->sort(); + } } diff --git a/app/Services/Admin/BaseService.php b/app/Services/Admin/BaseService.php index 9915443..92665ed 100644 --- a/app/Services/Admin/BaseService.php +++ b/app/Services/Admin/BaseService.php @@ -10,7 +10,9 @@ use Slowlyo\OwlAdmin\Services\AdminService; */ class BaseService extends AdminService { - protected array $withRelationships = array(); + protected array $withRelationships = []; + + protected string $modelFilterName = ''; public function getTree() { @@ -33,8 +35,15 @@ class BaseService extends AdminService $query->with($this->withRelationships); } - return $query - ->filter(request()->input(), $filter) - ->orderByDesc($model->getUpdatedAtColumn() ?? $model->getKeyName()); + if ($filter) { + $query->filter(request()->input(), $filter); + } + + return $query->orderByDesc($model->getUpdatedAtColumn() ?? $model->getKeyName()); + } + + public function getDetail($id) + { + return $this->query()->with($this->withRelationships)->find($id); } } diff --git a/database/migrations/2023_03_20_114120_create_articles_table.php b/database/migrations/2023_03_20_114120_create_articles_table.php index be9b0b8..47e14c0 100644 --- a/database/migrations/2023_03_20_114120_create_articles_table.php +++ b/database/migrations/2023_03_20_114120_create_articles_table.php @@ -27,7 +27,7 @@ return new class extends Migration // 可能用到的额外字段 $table->string('cover')->nullable()->comment('封面'); $table->string('author')->nullable()->comment('作者/来源'); - $table->string('category_path')->nullable()->comment('上级分类'); + $table->string('category_path')->nullable()->comment('所有上级分类id'); $table->timestamps(); }); } diff --git a/lang/zh_CN/article.php b/lang/zh_CN/article.php new file mode 100644 index 0000000..7564444 --- /dev/null +++ b/lang/zh_CN/article.php @@ -0,0 +1,17 @@ + 'ID', + 'created_at' => '创建时间', + 'author' => '作者', + 'category_id' => '分类', + 'category_path' => '', + 'content' => '内容', + 'cover' => '封面图', + 'is_enable' => '显示', + 'is_recommend' => '推荐', + 'published_at' => '发布时间', + 'sort' => '排序(倒序)', + 'sub_title' => '副标题', + 'title' => '标题', +]; diff --git a/public/admin/index.html b/public/admin/index.html index 90e62bf..6c60cd1 100644 --- a/public/admin/index.html +++ b/public/admin/index.html @@ -5,7 +5,7 @@ -