diff --git a/app/Admin/Components.php b/app/Admin/Components.php index 7c2f50b..ebfab98 100644 --- a/app/Admin/Components.php +++ b/app/Admin/Components.php @@ -78,10 +78,14 @@ class Components extends BaseRenderer { * 图片上传,带裁剪 */ public function cropImageControl($name, $label, $aspectRatio = null){ - return amis()->ImageControl($name, $label)->joinValues(false) - ->crop([ - 'aspectRatio' => $aspectRatio ?? 1 - ])->autoUpload(true); + $cropImage = amis()->ImageControl($name, $label)->joinValues(false); + // if($aspectRatio){ + $cropImage->crop([ + 'aspectRatio' => $aspectRatio ?? 1 + ]); + // } + $cropImage->autoUpload(true); + return $cropImage; } /** @@ -90,7 +94,6 @@ class Components extends BaseRenderer { public function fileControl($name, $label, $accept = '.txt', $multiple = false){ return amis()->FileControl($name, $label ?? __('admin.components.files')) ->multiple($multiple) - // ->receiver() ->joinValues(false) ->useChunk(false) ->maxSize(20*1024*1024) diff --git a/app/Admin/Controllers/AdController.php b/app/Admin/Controllers/AdController.php new file mode 100644 index 0000000..a67ac73 --- /dev/null +++ b/app/Admin/Controllers/AdController.php @@ -0,0 +1,79 @@ +baseCRUD()->tableLayout('fixed') + ->headerToolbar([ + $this->createButton(), + ...$this->baseHeaderToolBar(), + ]) + ->filter($this->baseFilter()->body()) + ->columns([ + amis()->TableColumn('id', __('admin.ads.id'))->width('50px')->sortable(), + amis()->TableColumn('address', __('admin.ads.address'))->type('mapping') + ->map(Keyword::allChildrenOfKey('banner_address')->pluck('name', 'key')->toArray()) + ->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')), + amis()->TableColumn('sort', __('admin.ads.sort')), + amis()->TableColumn('resource', __('admin.ads.resource'))->type('image')->height('50px')->width('150px')->enlargeAble(true), + amis()->TableColumn('remark', __('admin.ads.remark')), + amis()->TableColumn('published_at', __('admin.ads.published_at'))->remark(__('admin.ads.published_at_remark')), + amis()->TableColumn('is_enable', __('admin.ads.is_enable'))->type('switch'), + amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true), + Operation::make()->label(__('admin.actions'))->buttons([ + $this->rowEditButton(), + $this->rowDeleteButton(), + ]) + ]); + + return $this->baseList($crud); + } + + public function form($isEdit = false): Form + { + return $this->baseForm()->body([ + Components::make()->parentControl(admin_url('api/keywords/tree-list?parent_name=banner_address&has_owner=0'), 'address', __('admin.ads.address'), 'name', 'key')->required(true), + Components::make()->imageControl('resource', __('admin.ads.resource'))->required(true), + amis()->TextControl('remark', __('admin.ads.remark')), + Components::make()->sortControl('sort', __('admin.ads.sort')), + amis()->DateTimeControl('published_at', __('admin.ads.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.ads.published_at_remark')), + amis()->SwitchControl('is_enable', __('admin.ads.is_enable'))->value(false), + amis()->RadiosControl('jump_type', __('admin.ads.jump_type'))->selectFirst(true)->options(Ad::jumpTypeMap())->required(true), + amis()->TextControl('jump_config.web_link', __('admin.ads.jump_config_arr.web_link'))->visibleOn('this.jump_type == '.Ad::TYPE_WEB)->required(true), + amis()->TextControl('jump_config.app_link', __('admin.ads.jump_config_arr.app_link'))->visibleOn('this.jump_type == '.Ad::TYPE_APP)->required(true), + amis()->GroupControl()->body([ + amis()->TextControl('jump_config.mini_id', __('admin.ads.jump_config_arr.mini_id'))->visibleOn('this.jump_type == '.Ad::TYPE_MINI)->required(true), + amis()->TextControl('jump_config.mini_link', __('admin.ads.jump_config_arr.mini_link'))->visibleOn('this.jump_type == '.Ad::TYPE_MINI)->required(true), + ]), + ]); + } + + public function detail(): Form + { + return $this->baseDetail()->body([ + amis()->TextControl('id', 'ID')->static(), + amis()->TextControl('created_at', __('admin.created_at'))->static(), + amis()->TextControl('updated_at', __('admin.updated_at'))->static() + ]); + } +} diff --git a/app/Admin/Controllers/ArticleController.php b/app/Admin/Controllers/ArticleController.php index 85b245c..eec3fa1 100644 --- a/app/Admin/Controllers/ArticleController.php +++ b/app/Admin/Controllers/ArticleController.php @@ -23,7 +23,7 @@ class ArticleController extends AdminController ...$this->baseHeaderToolBar(), ]) ->filter($this->baseFilter()->body()) - ->itemBadge([ + ->itemBadge([//行角标 'text' => __('admin.articles.is_recommend'), 'mode' => 'ribbon', 'position' => 'top-left', @@ -32,7 +32,7 @@ class ArticleController extends AdminController 'size' => 15 ]) ->columns([ - amis()->TableColumn('id', __('admin.id')), + amis()->TableColumn('id', __('admin.id'))->sortable(true), amis()->TableColumn('title', __('admin.articles.title'))->width('300px'), amis()->TableColumn('category', __('admin.articles.category'))->type('mapping') ->map(Keyword::allChildrenOfKey('article_category')->pluck('name', 'key')->toArray()) @@ -42,7 +42,7 @@ class ArticleController extends AdminController amis()->TableColumn('published_at', __('admin.articles.published_at'))->remark(__('admin.articles.published_at_remark')), amis()->TableColumn('is_enable', __('admin.articles.is_enable'))->type('switch'), amis()->TableColumn('is_recommend', __('admin.articles.is_recommend'))->type('switch'), - amis()->TableColumn('created_at', __('admin.created_at')), + amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true), amis()->Operation()->label(__('admin.actions'))->buttons([ $this->rowEditButton(), $this->rowDeleteButton(), @@ -65,7 +65,7 @@ class ArticleController extends AdminController amis()->DateTimeControl('published_at', __('admin.articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.articles.published_at_remark')), amis()->SwitchControl('is_enable', __('admin.articles.is_enable'))->value(false), amis()->SwitchControl('is_recommend', __('admin.articles.is_recommend'))->value(false), - Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx'), + Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx', true), ])->md(4), amis()->Wrapper()->body([ Components::make()->fuEditorControl('content', __('admin.articles.content')), diff --git a/app/Admin/routes.php b/app/Admin/routes.php index faf3ff0..e53cb36 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -30,6 +30,8 @@ Route::group([ $router->resource('articles', \App\Admin\Controllers\ArticleController::class); + $router->resource('ads', \App\Admin\Controllers\AdController::class); + //修改上传 $router->post('upload_file', [\App\Admin\Controllers\IndexController::class, 'uploadFile']); $router->post('upload_image', [\App\Admin\Controllers\IndexController::class, 'uploadImage']); diff --git a/app/Models/Ad.php b/app/Models/Ad.php new file mode 100644 index 0000000..6be8487 --- /dev/null +++ b/app/Models/Ad.php @@ -0,0 +1,86 @@ +format('Y-m-d H:i:s'); + } + + protected $casts = [ + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + 'published_at' => 'datetime', + 'is_enable' => 'boolean', + 'resource' => Storage::class, + 'jump_config' => 'array', + ]; + + protected $fillable = [ + 'resource', + 'address', + 'remark', + 'published_at', + 'is_enable', + 'sort', + 'jump_type', + 'jump_config', + ]; + + public static function jumpTypeMap() :array + { + return [ + self::TYPE_WEB => '网页跳转', + self::TYPE_APP => '应用跳转', + self::TYPE_MINI => '小程序跳转', + self::TYPE_OFF => '无跳转', + ]; + } + + public static function jumpTypeMapLabel() + { + return [ + self::TYPE_OFF => "无跳转", + self::TYPE_WEB => "网页跳转", + self::TYPE_APP => "应用跳转", + self::TYPE_MINI => "小程序跳转", + '*'=>'其他:${jump_type}' + ]; + } + + public static function typeMapLabel() + { + return [ + self::TYPE_IN => "入住缴费", + self::TYPE_CONTINUE => "续住缴费", + self::TYPE_EXIT => "离开结算", + '*'=>'其他:${live_in}' + ]; + } + + public function scopeShow(){ + $q->where('is_enable', true)->where('published_at', '>=', now()); + } + + public function scopeSort($q) + { + $q->orderBy('sort', 'asc') + ->orderBy('published_at', 'desc') + ->orderBy('created_at', 'desc'); + } +} diff --git a/app/Models/Filters/AdFilter.php b/app/Models/Filters/AdFilter.php new file mode 100644 index 0000000..b7e8c68 --- /dev/null +++ b/app/Models/Filters/AdFilter.php @@ -0,0 +1,16 @@ +where('name','like', '%'.$name.'%'); + } +} diff --git a/app/Services/Admin/AdService.php b/app/Services/Admin/AdService.php new file mode 100644 index 0000000..c1feaf6 --- /dev/null +++ b/app/Services/Admin/AdService.php @@ -0,0 +1,112 @@ +getTableColumns(); + $model = $this->getModel(); + + $isEnable = Arr::get($data, 'is_enabled'); + $publishedAt = Arr::get($data, 'published_at'); + if ($isEnable && empty($publishedAt)) { + $data['published_at'] = now(); + } + + $data['resource'] = $this->saveImage('resource', 'ads/resource')[0]; + + //处理跳转配置 + $jumpType = Arr::get($data, 'jump_type'); + if($jumpType !== null){ + switch($jumpType){ + case Ad::TYPE_OFF: + $data['jump_config'] = null; + break; + case Ad::TYPE_WEB: + $data['jump_config'] = Arr::only($data['jump_config'], 'web_link'); + break; + case Ad::TYPE_APP: + $data['jump_config'] = Arr::only($data['jump_config'], 'app_link');; + break; + case Ad::TYPE_MINI: + $data['jump_config'] = Arr::only($data['jump_config'], ['mini_id', 'mini_link']);; + break; + } + } + + foreach ($data as $k => $v) { + if (!in_array($k, $columns)) { + continue; + } + + $model->setAttribute($k, $v); + } + + return $model->save(); + } + + public function update($primaryKey, $data): bool + { + $columns = $this->getTableColumns(); + $model = $this->query()->whereKey($primaryKey)->first(); + + $isEnable = Arr::get($data, 'is_enable'); + $publishedAt = Arr::get($data, 'published_at'); + + if ($isEnable && empty($publishedAt) && empty($model->published_at)) { + $data['published_at'] = now(); + } + + if(isset($data['resource'])){ + $data['resource'] = $this->saveImage('resource', 'ads/resource')[0]; + } + + //处理跳转配置 + $jumpType = Arr::get($data, 'jump_type'); + if($jumpType !== null){ + switch($jumpType){ + case Ad::TYPE_OFF: + $data['jump_config'] = null; + break; + case Ad::TYPE_WEB: + $data['jump_config'] = Arr::only($data['jump_config'], 'web_link'); + break; + case Ad::TYPE_APP: + $data['jump_config'] = Arr::only($data['jump_config'], 'app_link');; + break; + case Ad::TYPE_MINI: + $data['jump_config'] = Arr::only($data['jump_config'], ['mini_id', 'mini_link']);; + break; + } + } + + foreach ($data as $k => $v) { + if (!in_array($k, $columns)) { + continue; + } + + $model->setAttribute($k, $v); + } + + return $model->save(); + } +} \ No newline at end of file diff --git a/app/Services/Admin/AdminUserService.php b/app/Services/Admin/AdminUserService.php index 86935da..eeca23e 100644 --- a/app/Services/Admin/AdminUserService.php +++ b/app/Services/Admin/AdminUserService.php @@ -128,6 +128,8 @@ class AdminUserService extends BaseService $query->where('username', 'like', "%{$keyword}%")->orWhere('name', 'like', "%{$keyword}%"); }); + $this->sortable($query); + $items = (clone $query)->paginate(request()->input('perPage', 20))->items(); $total = (clone $query)->count(); diff --git a/app/Services/Admin/ArticleService.php b/app/Services/Admin/ArticleService.php index 01e2190..69682d2 100644 --- a/app/Services/Admin/ArticleService.php +++ b/app/Services/Admin/ArticleService.php @@ -19,6 +19,8 @@ class ArticleService extends BaseService protected string $modelFilterName = ArticleFilter::class; + protected bool $modelSortAble = true; + public function store($data): bool { $columns = $this->getTableColumns(); @@ -55,9 +57,13 @@ class ArticleService extends BaseService if ($isEnable && empty($publishedAt) && empty($model->published_at)) { $data['published_at'] = now(); } + if(isset($data['cover'])){ + $data['cover'] = $this->saveImage('cover', 'articles/cover')[0]; + } - $data['cover'] = $this->saveImage('cover', 'articles/cover')[0]; - $data['appendixes'] = $this->saveFile('appendixes', 'articles/appendixes'); + if(isset($data['appendixes'])){ + $data['appendixes'] = $this->saveFile('appendixes', 'articles/appendixes'); + } foreach ($data as $k => $v) { if (!in_array($k, $columns)) { diff --git a/app/Services/Admin/BaseService.php b/app/Services/Admin/BaseService.php index a9ec1eb..4fa0ecd 100644 --- a/app/Services/Admin/BaseService.php +++ b/app/Services/Admin/BaseService.php @@ -14,6 +14,8 @@ class BaseService extends AdminService protected string $modelFilterName = ''; + protected bool $modelSortAble = false; + public function getTree() { $list = $this->query()->orderByDesc('sort')->get(); @@ -40,7 +42,13 @@ class BaseService extends AdminService $query->filter(request()->input(), $filter); } - return $query->orderByDesc($model->getUpdatedAtColumn() ?? $model->getKeyName()); + if($this->modelSortAble){ + $query->sort(); + } + + $this->sortable($query); + + return $query; } public function getDetail($id) diff --git a/app/Services/Admin/KeywordService.php b/app/Services/Admin/KeywordService.php index 5143832..7e28bc1 100644 --- a/app/Services/Admin/KeywordService.php +++ b/app/Services/Admin/KeywordService.php @@ -19,7 +19,7 @@ class KeywordService extends BaseService { $list = $this->query()->filter(request()->all(), $this->modelFilterName)->orderByDesc('sort')->get(); $minNum = $list->min('parent_id'); - return array2tree($list->toArray(), $minNum); + return !$list->isEmpty() ? array2tree($list->toArray(), $minNum) :[]; } public function parentIsChild($id, $pid): bool diff --git a/database/migrations/2023_12_18_162317_create_ads_table.php b/database/migrations/2023_12_18_162317_create_ads_table.php new file mode 100644 index 0000000..4b8e06a --- /dev/null +++ b/database/migrations/2023_12_18_162317_create_ads_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('address')->comment('位置'); + $table->string('resource')->comment('资源'); + $table->string('remark')->nullable()->comment('备注'); + $table->timestamp('published_at')->nullable()->comment('发布时间'); + $table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关'); + $table->unsignedInteger('sort')->default(0)->comment('排序'); + $table->unsignedTinyInteger('jump_type')->default(0)->comment('跳转,0:不跳转。1:网页跳转;2应用跳转;3微信小程序跳转'); + $table->text('jump_config')->nullable()->comment('跳转配置'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('ads'); + } +}; diff --git a/database/seeders/AdminMenuSeeder.php b/database/seeders/AdminMenuSeeder.php index fd9e456..64d4d73 100644 --- a/database/seeders/AdminMenuSeeder.php +++ b/database/seeders/AdminMenuSeeder.php @@ -33,7 +33,7 @@ class AdminMenuSeeder extends Seeder ['title' => 'web_content', 'icon' => 'ic:outline-collections-bookmark', 'url' => '', 'order'=>3, 'children' =>[ ['title'=>'articles', 'icon'=>'ic:outline-article','url'=>'/articles', 'order'=>1], - ['title'=>'banners', 'icon'=>'lets-icons:img-box','url'=>'/banners', 'order'=>2], + ['title'=>'ads', 'icon'=>'lets-icons:img-box','url'=>'/ads', 'order'=>2], ] ] ]; diff --git a/lang/zh_CN/admin.php b/lang/zh_CN/admin.php index facb7c5..9632312 100644 --- a/lang/zh_CN/admin.php +++ b/lang/zh_CN/admin.php @@ -60,7 +60,7 @@ return [ 'cancel' => '取消', 'please_login' => '请先登录', 'unauthorized' => '无权访问', - 'id' => '主键', + 'id' => 'ID', 'components' => [ 'content' => '内容', @@ -274,7 +274,7 @@ return [ 'parent_keyword' => '父级关键字', ], 'articles' => [ - 'id' => '主键', + 'id' => 'ID', 'title' => '标题', 'content' => '内容', 'cover' =>'封面', @@ -288,5 +288,24 @@ return [ 'sort' => '排序', 'appendixes' => '附件', 'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间' + ], + 'ads' => [ + 'id' => 'ID', + 'address' => '位置', + 'resource' =>'内容', + 'published_at' => '定时发布', + 'published_at_g' => '发布时间', + 'is_enable' => '显示', + 'remark' => '备注', + 'sort' => '排序', + 'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间', + 'jump_type' => '跳转类型', + 'jump_config'=>'跳转配置', + 'jump_config_arr'=>[ + 'web_link' => '网页地址', + 'app_link' => '应用路径', + 'mini_id' => '小程序ID', + 'mini_link'=> '小程序路径' + ], ] ]; diff --git a/lang/zh_CN/menu.php b/lang/zh_CN/menu.php index 83d4469..dbedcd6 100644 --- a/lang/zh_CN/menu.php +++ b/lang/zh_CN/menu.php @@ -12,5 +12,5 @@ return [ 'keywords' => '数据字典', 'web_content' => '内容管理', 'articles' => '文章管理', - 'banners' => '广告管理', + 'ads' => '广告管理', ];