From eda3248af3dd034383b28fefc00733f1b7bd41fa Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Fri, 1 Dec 2023 21:04:56 +0800 Subject: [PATCH] banner --- app/Admin/Controllers/ArticleController.php | 26 ++++- app/Admin/Controllers/BannerController.php | 108 ++++++++++++++++++ app/Admin/Services/BannerService.php | 32 ++++++ app/Admin/Services/PartyCateService.php | 28 ++++- app/Admin/routes.php | 4 + app/Enums/TargetType.php | 22 ++++ app/ModelFilters/BannerFilter.php | 16 +++ app/Models/Article.php | 5 + app/Models/Banner.php | 43 +++++++ ...2023_12_01_200448_create_banners_table.php | 36 ++++++ database/seeders/AdminMenuSeeder.php | 3 +- database/seeders/AdminSeeder.php | 5 + database/seeders/KeywordSeeder.php | 7 ++ lang/zh_CN/article.php | 1 + lang/zh_CN/banner.php | 16 +++ tests/Feature/ExampleTest.php | 3 - tests/Unit/ExampleTest.php | 3 + 17 files changed, 352 insertions(+), 6 deletions(-) create mode 100644 app/Admin/Controllers/BannerController.php create mode 100644 app/Admin/Services/BannerService.php create mode 100644 app/Enums/TargetType.php create mode 100644 app/ModelFilters/BannerFilter.php create mode 100644 app/Models/Banner.php create mode 100644 database/migrations/2023_12_01_200448_create_banners_table.php create mode 100644 lang/zh_CN/banner.php diff --git a/app/Admin/Controllers/ArticleController.php b/app/Admin/Controllers/ArticleController.php index 277d0f3..06de6c1 100644 --- a/app/Admin/Controllers/ArticleController.php +++ b/app/Admin/Controllers/ArticleController.php @@ -4,6 +4,8 @@ namespace App\Admin\Controllers; use App\Admin\Components; use App\Admin\Services\ArticleService; +use App\Models\Article; +use App\Models\PartyCate; use Slowlyo\OwlAdmin\Controllers\AdminController; use Slowlyo\OwlAdmin\Renderers\Form; use Slowlyo\OwlAdmin\Renderers\Page; @@ -12,6 +14,8 @@ class ArticleController extends AdminController { protected string $serviceName = ArticleService::class; + protected $categoryOptions; + protected $partyCateOptions; public function list(): Page { $crud = $this->baseCRUD() @@ -22,6 +26,7 @@ class ArticleController extends AdminController ]) ->filter($this->baseFilter()->actions([])->body([ amisMake()->TextControl()->name('title')->label(__('article.title'))->size('md')->clearable(), + amisMake()->SelectControl()->name('category_id')->label(__('article.category_id'))->options($this->getCategoryOptions())->size('md')->clearable(), // amisMake()->Button()->label(__('admin.reset'))->actionType('clear-and-submit'), amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'), ])) @@ -44,7 +49,8 @@ class ArticleController extends AdminController { 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()->SelectControl()->name('category_id')->label(__('article.category_id'))->options($this->getCategoryOptions())->required(), + amisMake()->SelectControl()->name('party_cate_id')->label(__('article.party_cate_id'))->options($this->getPartyCateOptions()), 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('*不填写则默认为创建时间'), @@ -67,4 +73,22 @@ class ArticleController extends AdminController Components::make()->fuEditorControl('content', __('article.content'))->static(true), ]); } + + public function getCategoryOptions() + { + if (!$this->categoryOptions) { + $this->categoryOptions = Article::getCategoryList()->map(fn($item) => ['value' => $item->id, 'label' => $item->name]); + } + + return $this->categoryOptions; + } + + public function getPartyCateOptions() + { + if (!$this->partyCateOptions) { + $this->partyCateOptions = PartyCate::select(['id as value', 'name as label'])->get();; + } + + return $this->partyCateOptions; + } } diff --git a/app/Admin/Controllers/BannerController.php b/app/Admin/Controllers/BannerController.php new file mode 100644 index 0000000..60d5693 --- /dev/null +++ b/app/Admin/Controllers/BannerController.php @@ -0,0 +1,108 @@ +baseCRUD() + ->filterTogglable(false) + ->columnsTogglable(false) + ->headerToolbar([ + $this->createButton(true), + ]) + ->quickSaveItemApi(admin_url('quick-edit/banner/$id')) + ->filter($this->baseFilter()->actions()->body([ + amisMake()->SelectControl()->name('place_id')->label(__('banner.place_id'))->options($this->getPlaceOptions())->size('md')->clearable(), + amisMake()->TextControl()->name('title')->label(__('banner.title'))->size('md')->clearable(), + amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'), + ])) + ->columns([ + amisMake()->TableColumn()->name('id')->label(__('banner.id')), + amisMake()->TableColumn()->name('place_id')->label(__('banner.place_id')), + amisMake()->TableColumn()->name('title')->label(__('banner.title')), + amisMake()->Image()->name('picture')->label(__('banner.picture'))->width(30), + amisMake() + ->TableColumn() + ->name('sort') + ->label(__('banner.sort')) + ->align('center') + ->quickEdit(Components::make()->sortControl('sort', __('banner.sort'))->saveImmediately(true)), + Components::make()->switchControl('table')->name('is_enable')->label(__('article.is_enable')), + $this->rowActions(true), + ]); + + return $this->baseList($crud); + } + + public function form(): Form + { + return $this->baseForm()->title('')->body([ + amisMake()->SelectControl()->name('place_id')->label(__('banner.place_id'))->options($this->getPlaceOptions())->required(true), + amisMake()->TextControl()->name('title')->label(__('banner.title'))->required(true), + amisMake()->ImageControl()->name('picture')->label(__('banner.picture'))->autoUpload(true), + // {target_type: app/h5, target_url: ''} + amisMake() + ->ComboControl() + ->scaffold(['target_type' => TargetType::App, 'target_url' => '']) + ->subFormMode('horizontal') + ->multiLine() + ->name('link_config') + ->label(__('banner.link_config')) + ->items([ + amisMake()->SelectControl()->name('target_type')->label(__('banner.target_type'))->options(TargetType::map()), + amisMake()->TextControl()->name('target_url')->label(__('banner.target_url')), + ]), + Components::make()->sortControl('sort', __('banner.sort')), + amisMake()->TextareaControl()->name('description')->label(__('banner.description')), + amisMake()->DateTimeControl()->name('published_at')->label(__('banner.published_at'))->value(now())->format('YYYY-MM-DD HH:mm:ss')->description('*默认当前时间'), + Components::make()->switchControl('form')->name('is_enable')->label(__('banner.is_enable'))->value(true), + ]); + } + + public function detail(): Form + { + return $this->baseDetail()->title('')->body([ + amisMake()->TextControl()->name('place.name')->label(__('banner.place_id'))->static(), + amisMake()->TextControl()->name('title')->label(__('banner.title'))->static(), + amisMake()->TextControl()->name('picture')->label(__('banner.picture'))->static()->staticSchema(amisMake()->image()), + amisMake() + ->ComboControl() + ->subFormMode('horizontal') + ->multiLine() + ->static(true) + ->name('link_config') + ->label(__('banner.link_config')) + ->items([ + amisMake()->SelectControl()->name('target_type')->label(__('banner.target_type'))->options(TargetType::map())->static(true), + amisMake()->TextControl()->name('target_url')->label(__('banner.target_url'))->static(true), + ]), + amisMake()->TextControl()->name('sort')->label(__('banner.sort'))->static(true), + amisMake()->TextControl()->name('description')->label(__('banner.description'))->static(true), + amisMake()->TextControl()->name('published_at')->label(__('banner.published_at'))->static(true), + Components::make()->switchControl('show')->name('is_enable')->label(__('banner.is_enable')), + amisMake()->TextControl()->name('created_at')->label(__('banner.created_at'))->static(true), + ]); + } + + public function getPlaceOptions() + { + if (!$this->placeOptions) { + $this->placeOptions = Banner::getPlaceList()->map(fn($item) => ['value' => $item->id, 'label' => $item->name]); + } + + return $this->placeOptions; + } +} diff --git a/app/Admin/Services/BannerService.php b/app/Admin/Services/BannerService.php new file mode 100644 index 0000000..887c204 --- /dev/null +++ b/app/Admin/Services/BannerService.php @@ -0,0 +1,32 @@ +getModel(); + $filter = $this->getModelFilter(); + + $query = $this->query(); + if ($this->withRelationships) { + $query->with($this->withRelationships); + } + + if ($filter) { + $query->filter(request()->input(), $filter); + } + + return $query->orderBy('place_id')->sort(); + } +} diff --git a/app/Admin/Services/PartyCateService.php b/app/Admin/Services/PartyCateService.php index eaf9632..2ce74f3 100644 --- a/app/Admin/Services/PartyCateService.php +++ b/app/Admin/Services/PartyCateService.php @@ -3,10 +3,11 @@ namespace App\Admin\Services; use App\ModelFilters\PartyCateFilter; -use App\Models\Keyword; use App\Models\PartyCate; use App\Models\PartyUser; use App\Models\UserScore; +use Slowlyo\OwlAdmin\Models\AdminPermission; +use Slowlyo\OwlAdmin\Services\AdminPermissionService; class PartyCateService extends BaseService { @@ -16,6 +17,29 @@ class PartyCateService extends BaseService protected string $modelFilterName = PartyCateFilter::class; + public function store($data): bool + { + $data = $this->resloveData($data); + + $validate = $this->validate($data); + if ($validate !== true) { + $this->setError($validate); + return false; + } + + $info = $this->modelName::create($data); + + // 创建权限 + $parent = AdminPermission::firstOrCreate(['slug' => 'party_cate'], ['name' => '党支部']); + AdminPermissionService::make()->store([ + 'slug' => 'party_cate_' . $info->id, + 'name' => $info->name, + 'parent_id' => $parent->id + ]); + + return true; + } + public function preDelete(array $ids) { $userIds = PartyUser::whereIn('cate_id', $ids)->pluck('id'); @@ -23,6 +47,8 @@ class PartyCateService extends BaseService PartyUser::whereIn('cate_id', $ids)->delete(); // 删除党员下面的审核记录 UserScore::whereIn('user_id', $userIds)->delete(); + // 删除权限 + AdminPermission::whereIn('slug', array_map(fn ($v) => 'party_cate_' . $v, $ids))->delete(); return true; } diff --git a/app/Admin/routes.php b/app/Admin/routes.php index a3456f5..67ab52f 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -29,6 +29,10 @@ Route::group([ // 字典表 $router->resource('keywords', \App\Admin\Controllers\KeywordsController::class)->names('admin.keywords'); + // 广告 + $router->resource('banner', \App\Admin\Controllers\BannerController::class)->names('admin.banner'); + $router->post('quick-edit/banner/{banner}', [\App\Admin\Controllers\BannerController::class, 'update']); + // 文章 $router->resource('articles', \App\Admin\Controllers\ArticleController::class)->names('admin.article'); $router->post('quick-edit/article/{article}', [\App\Admin\Controllers\ArticleController::class, 'update']); diff --git a/app/Enums/TargetType.php b/app/Enums/TargetType.php new file mode 100644 index 0000000..84ffbd2 --- /dev/null +++ b/app/Enums/TargetType.php @@ -0,0 +1,22 @@ +value => '内部跳转', + self::Web->value => '外部链接', + ]; + } + + public function text() + { + return data_get(self::map(), $this->value); + } +} diff --git a/app/ModelFilters/BannerFilter.php b/app/ModelFilters/BannerFilter.php new file mode 100644 index 0000000..c842990 --- /dev/null +++ b/app/ModelFilters/BannerFilter.php @@ -0,0 +1,16 @@ + [input_key1, input_key2]]. + * + * @var array + */ + public $relations = []; +} diff --git a/app/Models/Article.php b/app/Models/Article.php index 2ab0ba5..2b99cfc 100644 --- a/app/Models/Article.php +++ b/app/Models/Article.php @@ -31,6 +31,11 @@ class Article extends Model 'published_at' => 'datetime', ]; + public static function getCategoryList() + { + return Keyword::where('key', 'like', 'category_%')->get(); + } + public function category() { return $this->belongsTo(Keyword::class, 'category_id'); diff --git a/app/Models/Banner.php b/app/Models/Banner.php new file mode 100644 index 0000000..6c488f6 --- /dev/null +++ b/app/Models/Banner.php @@ -0,0 +1,43 @@ + StorageFile::class, + 'link_config' => 'array', + ]; + + public static function getPlaceList() + { + return Keyword::where('key', 'like', 'banner_%')->get(); + } + + public function place() + { + return $this->belongsTo(Keyword::class, 'place_id'); + } + + public function scopeSort($q) + { + return $q->orderBy('sort', 'desc'); + } + + public function scopeEnable($q) + { + return $q->where('is_enable', 1)->where('published_at', '<=', now()); + } +} diff --git a/database/migrations/2023_12_01_200448_create_banners_table.php b/database/migrations/2023_12_01_200448_create_banners_table.php new file mode 100644 index 0000000..3886ab7 --- /dev/null +++ b/database/migrations/2023_12_01_200448_create_banners_table.php @@ -0,0 +1,36 @@ +id(); + $table->string('title')->nullable()->comment('标题'); + $table->string('picture')->nullable()->comment('图片'); + $table->text('description')->nullable()->comment('描述'); + $table->unsignedBigInteger('place_id')->comment('位置, keywords.id'); + $table->string('path')->default('-')->comment('位置, 所有上级, -1-2-3-'); + $table->timestamp('published_at')->nullable()->comment('发布时间'); + $table->unsignedTinyInteger('is_enable')->default(1)->comment('是否显示'); + $table->unsignedInteger('sort')->default(0)->comment('排序(倒序)'); + $table->json('link_config')->nullable()->comment('跳转配置'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('banners'); + } +}; diff --git a/database/seeders/AdminMenuSeeder.php b/database/seeders/AdminMenuSeeder.php index 847a093..cfcfb3a 100644 --- a/database/seeders/AdminMenuSeeder.php +++ b/database/seeders/AdminMenuSeeder.php @@ -22,7 +22,8 @@ class AdminMenuSeeder extends Seeder ['title' => '支部管理', 'icon' => 'icon-park:flag', 'url' => '/party-cate'], ['title' => '党员管理', 'icon' => 'icon-park:every-user', 'url' => '/party-user'], ['title' => '审核评定', 'icon' => 'icon-park:internal-data', 'url' => '/user-score'], - ['title' => '文章管理', 'icon' => 'icon-park:web-page', 'url' => '/articles'], + ['title' => '信息管理', 'icon' => 'icon-park:web-page', 'url' => '/articles'], + ['title' => '广告管理', 'icon' => 'icon-park:picture-one', 'url' => '/banner'], ['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/database/seeders/AdminSeeder.php b/database/seeders/AdminSeeder.php index 4d13480..78c38c6 100644 --- a/database/seeders/AdminSeeder.php +++ b/database/seeders/AdminSeeder.php @@ -55,6 +55,11 @@ class AdminSeeder extends Seeder AdminPermission::query()->truncate(); AdminPermission::query()->insert($permissions); + AdminPermission::create([ + 'name' => '党支部', + 'slug' => 'party_cate', + 'order' => count($permissions) + 1, + ]); DB::table('admin_permission_menu')->truncate(); foreach ($permissions as $item) { diff --git a/database/seeders/KeywordSeeder.php b/database/seeders/KeywordSeeder.php index 24db1ef..0970bb1 100644 --- a/database/seeders/KeywordSeeder.php +++ b/database/seeders/KeywordSeeder.php @@ -23,6 +23,13 @@ class KeywordSeeder extends Seeder ['key' => 'score_cate_3', 'name' => '政治担当'], ['key' => 'score_cate_4', 'name' => '政治能力'], ['key' => 'score_cate_5', 'name' => '政治自律'], + ]], + ['key' => 'banner', 'name' => '广告位', 'children' => [ + ['key' => 'banner_1', 'name' => '首页广告'], + ]], + ['key' => 'category', 'name' => '文章分类', 'children' => [ + ['key' => 'category_1', 'name' => '共性指标'], + ['key' => 'category_2', 'name' => '进阶指标'], ]] ]; diff --git a/lang/zh_CN/article.php b/lang/zh_CN/article.php index 6c0fae2..df7319c 100644 --- a/lang/zh_CN/article.php +++ b/lang/zh_CN/article.php @@ -14,4 +14,5 @@ return [ 'published_at' => '发布时间', 'sort' => '排序(正序)', 'title' => '标题', + 'party_cate_id' => '党支部', ]; diff --git a/lang/zh_CN/banner.php b/lang/zh_CN/banner.php new file mode 100644 index 0000000..87e2999 --- /dev/null +++ b/lang/zh_CN/banner.php @@ -0,0 +1,16 @@ + 'ID', + 'created_at' => '创建时间', + 'is_enable' => '显示', + 'link_config' => '跳转', + 'title' => '标题', + 'description' => '描述', + 'picture' => '图片', + 'place_id' => '位置', + 'published_at' => '发布时间', + 'sort' => '排序(正序)', + 'target_type' => '类型', + 'target_url' => '地址', +]; diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php index 8364a84..db9eea7 100644 --- a/tests/Feature/ExampleTest.php +++ b/tests/Feature/ExampleTest.php @@ -12,8 +12,5 @@ class ExampleTest extends TestCase */ public function test_the_application_returns_a_successful_response(): void { - $response = $this->get('/'); - - $response->assertStatus(200); } } diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php index 5773b0c..34606ce 100644 --- a/tests/Unit/ExampleTest.php +++ b/tests/Unit/ExampleTest.php @@ -11,6 +11,9 @@ class ExampleTest extends TestCase */ public function test_that_true_is_true(): void { + $ids = ['1', '2']; + $a = array_map(fn ($v) => 'party_cate_' . $v, $ids); + dump($a); $this->assertTrue(true); } }