4
0
Fork 0

Compare commits

...

19 Commits

Author SHA1 Message Date
panliang ee02f1b67d remove banner 2022-10-26 11:36:26 +08:00
panliang 38b3e1e1bb 更新 'packages/setting/src/Http/Controllers/SettingController.php' 2022-10-17 14:15:00 +08:00
vine_liutk 66dba4bf19 调整totree数据类型bug 2022-10-14 11:45:10 +08:00
panliang 9183e81cc3 add menu 2022-10-12 14:02:21 +08:00
panliang bd03c095fc config/admin.php 2022-10-12 13:43:49 +08:00
panliang 158f3f9b58 更新 'resources/views/show/field.blade.php' 2022-09-23 15:59:03 +08:00
panliang 2ddbaff1b8 更新 'src/Show/Field.php' 2022-09-23 15:58:39 +08:00
panliang 361ff11542 更新 'src/Traits/ModelTree.php' 2022-09-23 15:02:50 +08:00
panliang 5f3683ec2b 更新 'packages/keywords/src/Http/Admin/KeywordsController.php' 2022-09-23 11:32:00 +08:00
panliang 6998832612 更新 'src/Http/Auth/Permission.php' 2022-09-23 11:21:16 +08:00
panliang 8040f128f1 更新 'src/Http/Middleware/Permission.php' 2022-09-23 11:06:13 +08:00
panliang 0f60563460 更新 'src/Http/Auth/Permission.php' 2022-09-23 11:05:22 +08:00
vine_liutk f45495b6fb 调整banner 2022-09-21 16:56:40 +08:00
vine_liutk 6ba5088785 Merge branch 'master' of https://gitea.peidikeji.cn/pdkj/dcat-admin 2022-09-21 13:33:20 +08:00
vine_liutk bc66a76cc8 调整权限选择 2022-09-21 13:33:03 +08:00
panliang 56ee1dcb4d update widget form add back button 2022-09-21 13:30:58 +08:00
panliang 11bcca4213 tag 2022-09-19 15:47:08 +08:00
panliang a32043e86a update banner 2022-09-16 17:15:02 +08:00
panliang b3418d033c remove extension article 2022-09-16 15:40:09 +08:00
63 changed files with 12445 additions and 1428 deletions

View File

@ -100,3 +100,73 @@ protected function renderBack()
HTML;
}
```
## 配置
- config/app.php
```php
return [
'timezone' => env('TIMEZONE', 'Asia/Chongqing'),
'locale' => 'zh_CN',
];
```
- config/auth.php
```php
return [
'api' => [
'driver' => 'sanctum',
'provider' => 'users',
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => Peidikeji\User\Models\User::class,
],
],
];
```
- app\Exceptions\Handler.php
```php
public function register()
{
$this->renderable(function (\Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e, Request $request) {
if ($request->ajax()) {
return response()->json(['code' => 404, 'message' => $e->getMessage(), 'data' => null], 200);
}
});
$this->renderable(function (\Illuminate\Validation\ValidationException $e, Request $request) {
if ($request->ajax()) {
$errors = $e->validator->errors();
return response()->json(['code' => 422, 'message' => $errors->first(), 'data' => $errors], 200);
}
});
}
```
- app\Http\Controllers\Controller.php
```php
use Dcat\Admin\Traits\JsonResponse;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use JsonResponse;
}
```
- app\Providers\RouteServiceProvider.php
```php
protected function configureRateLimiting()
{
RateLimiter::for('sms', function (Request $request) {
return Limit::perMinute(1)->by($request->input('phone'));
});
}
```

View File

@ -114,7 +114,7 @@ return [
| If your page is going to be accessed via https, set it to `true`.
|
*/
'https' => env('ADMIN_HTTPS', false),
'https' => \Illuminate\Support\Str::startsWith(env('APP_URL'), 'https://'),
/*
|--------------------------------------------------------------------------

View File

@ -1,7 +0,0 @@
.DS_Store
phpunit.phar
/vendor
composer.phar
composer.lock
*.project
.idea/

View File

@ -1,3 +0,0 @@
# Dcat Admin Extension

View File

@ -1,31 +0,0 @@
{
"name": "peidikeji/article",
"alias": "文章管理",
"description": "文章管理",
"type": "library",
"keywords": ["dcat-admin", "extension"],
"homepage": "https://github.com/peidikeji/article",
"license": "MIT",
"authors": [
{
"name": "liutk",
"email": "961510893@qq.com"
}
],
"require": {
"php": ">=7.1.0"
},
"autoload": {
"psr-4": {
"Peidikeji\\Article\\": "src/"
}
},
"extra": {
"dcat-admin": "Peidikeji\\Article\\ArticleServiceProvider",
"laravel": {
"providers": [
"Peidikeji\\Article\\ArticleServiceProvider"
]
}
}
}

View File

@ -1,3 +0,0 @@
<?php
return [];

View File

@ -1,3 +0,0 @@
<?php
return [];

View File

@ -1,19 +0,0 @@
<?php
return [
'labels' => [
'ArticleCategory' => '文章分类',
'article-categories'=> '文章分类',
],
'fields' => [
'parent_id' => '上级',
'name' => '名称',
'key' => 'KEY',
'is_enable' => '可用状态',
'is_recommend' => '推荐状态',
'sort' => '排序',
'remarks' => '备注'
],
'options' => [
],
];

View File

@ -1,31 +0,0 @@
<?php
return [
'labels' => [
'Article' => '文章管理',
'articles'=> '文章管理',
],
'fields' => [
'title' => '标题',
'sub_title' => '副标题',
'author' => '作者',
'author_name' => '作者',
'category_id' => '分类',
'category'=>[
'name' => '分类',
],
'admin_user_id' => '创建人',
'cover' => '封面',
'media_path' => '媒体资源',
'is_recommend' => '推荐状态',
'content' => '内容',
'is_enable' => '可用状态',
'sort' => '排序',
'published_at' => '发布时间',
'remarks' => '备注',
'like_nums' => '点赞数',
'read_nums' => '浏览数'
],
'options' => [
],
];

View File

@ -1,27 +0,0 @@
<?php
namespace Peidikeji\Article;
use Dcat\Admin\Extend\ServiceProvider;
use Dcat\Admin\Admin;
class ArticleServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function init()
{
parent::init();
//
}
// public function settingForm()
// {
// return new Setting($this);
// }
}

View File

@ -1,142 +0,0 @@
<?php
namespace Peidikeji\Article\Http\Controllers;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Admin;
use Illuminate\Validation\Rule;
use Peidikeji\Article\Models\Article;
use Dcat\Admin\Grid\Column as GridColumn;
use Peidikeji\Article\Models\ArticleCategory;
use Dcat\Admin\Http\Controllers\AdminController;
class ArticleCategoryController extends AdminController
{
protected $translation = 'peidikeji.article::article-category';
protected $extDefaults = [];//例如:['key1'=>'']
public function grid(){
return Grid::make(new ArticleCategory(), function ($grid) {
$grid->disableRowSelector();
$grid->model()->sort();
$grid->column('name')->tree(true, false);
$grid->column('key');
$grid->column('sort')->editable(['mask' => '{alias:\'numeric\',min:0,max:999}']);
$grid->column('is_enable')->if(function(){
return !config('admin.permission.enable') || Admin::user()->can('dcat.admin.article_categories.edit');
})->then(function (GridColumn $column) {
$column->switch();
})->else(function (GridColumn $column) {
$column->bool();
});
$grid->column('is_recommend')
->if(function(){
return !config('admin.permission.enable') || Admin::user()->can('dcat.admin.article_categories.edit');
})->then(function (GridColumn $column) {
$column->switch();
})->else(function (GridColumn $column) {
$column->bool();
});
$grid->model()->orderBy('sort', 'desc');
$grid->model()->orderBy('created_at', 'desc');
$grid->setDialogFormDimensions('50%', '70%');
$grid->disableCreateButton(!(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.article_categories.create')));
$grid->enableDialogCreate();
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableView();
$actions->disableEdit();
$actions->quickEdit(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.article_categories.edit'));
$actions->delete(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.article_categories.destroy'));
});
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->expand();
$filter->like('name')->width(3);
$filter->like('key')->width(3);
$filter->equal('parent_id', '上级分类')->select(ArticleCategory::selectOptions())->width(3);
});
});
}
public function form()
{
return Form::make(new ArticleCategory(), function (Form $form) {
$form->select('parent_id')->help('不选默认为顶级')->options(ArticleCategory::selectOptions())->default(0);
$form->text('name')->required();
$unique = Rule::unique((new ArticleCategory())->getTable(), 'key');
if ($form->isCreating()) {
$form->text('key')->help('不填则自动生成, 唯一')->rules([$unique]);
} else {
$form->text('key')->required()->help('唯一')->rules([$unique->ignore($form->getKey())]);
}
$form->number('sort')
->min(0)
->default(0)
->help('数值越大, 越靠前');
$form->switch('is_enable')->default(0);
$form->switch('is_recommend')->default(0);
$form->text('remarks');
$form->hidden('level')->default(1);
$form->keyValue('ext', '扩展字段')->default($this->extDefaults)->setKeyLabel('键名')->setValueLabel('键值')
->saving(function($v){
return json_encode($v ?? []);
});
$controller = $this;
$form->saving(function (Form $form) use ($controller) {
if ($form->isCreating() && !$form->key) {
$form->key = $controller->generateKey();
}
});
$form->saved(function (Form $form) {
if ($form->isEditing() && $form->input('is_enable') !== null && $form->input('is_enable') != $form->model()->is_enable) {
//处理分类子级状态同步(层级)父级
ArticleCategory::where('path', 'like', "%-".$form->model()->id."-%")->update(['is_enable' => $form->is_enable]);
//处理父级状态
if($form->is_enable){
//如果状态是开启,判断(层级)父级是否开启
$exPath = trim('-', $form->model()->path);
$parentIds = $exPath ? explode('-', $exPath) : [];
if($parentIds){
ArticleCategory::whereIn('id', $parentIds)->update(['is_enable' => $form->is_enable]);
}
}
}
});
$form->deleting(function (Form $form) {
$hasArticles = Article::where('category_id', $form->getKey())->exists();
if ($hasArticles) {
return $form->response()->error('需要先删除该分类下的文章');
}
$hasChildren = ArticleCategory::where('parent_id', $form->getKey())->exists();
if ($hasChildren) {
return $form->response()->error('需要先删除该分类下的子级');
}
});
});
}
protected function generateKey()
{
do {
$id = ArticleCategory::max('id') + 1;
$key = 'category-' . $id;
} while (ArticleCategory::where('key', $key)->exists());
return $key;
}
}

View File

@ -1,136 +0,0 @@
<?php
namespace Peidikeji\Article\Http\Controllers;
use Carbon\Carbon;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Admin;
use Peidikeji\Article\Models\Article;
use Dcat\Admin\Grid\Column as GridColumn;
use Peidikeji\Article\Models\ArticleCategory;
use Dcat\Admin\Http\Controllers\AdminController;
class ArticleController extends AdminController
{
protected $translation = 'peidikeji.article::article';
protected $extDefaults = [];//例如:['key1'=>'']
public function grid(){
return Grid::make(Article::with(['category', 'adminUser']), function ($grid) {
$grid->disableRowSelector();
$grid->column('category.name')->label();
$grid->column('title')->display(function ($v) {
if (mb_strlen($v) > 20) {
return mb_substr($v, 0, 17) . '...';
} else {
return $v;
}
});
$grid->column('cover')->image(100, 100);
$grid->column('author_name')->display(function (){
return $this->author_name;
});
$grid->column('like_nums');
$grid->column('read_nums');
$grid->column('sort')->editable(['mask' => '{alias:\'numeric\',min:0,max:999}']);
$grid->column('published_at');
$grid->column('is_enable')->if(function(){
return !config('admin.permission.enable') || Admin::user()->can('dcat.admin.articles.edit');
})->then(function (GridColumn $column) {
$column->switch();
})->else(function (GridColumn $column) {
$column->bool();
});
$grid->column('is_recommend')->if(function(){
return !config('admin.permission.enable') || Admin::user()->can('dcat.admin.articles.edit');
})->then(function (GridColumn $column) {
$column->switch();
})->else(function (GridColumn $column) {
$column->bool();
});
// $grid->column('remarks');
$grid->model()->orderBy('sort', 'desc');
$grid->model()->orderBy('created_at', 'desc');
$grid->setDialogFormDimensions('50%', '70%');
$grid->disableCreateButton(!(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.articles.create')));
$grid->enableDialogCreate();
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableView();
$actions->disableEdit();
$actions->quickEdit(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.articles.edit'));
$actions->delete(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.articles.destroy'));
});
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->expand();
$filter->equal('category_id', '分类')->select(ArticleCategory::selectOptions())->width(3);
$filter->like('title')->width(3);
$filter->between('published_at')->datetime()->width(7);
});
});
}
public function form()
{
return Form::make(new Article(), function($form){
$form->select('category_id')->options(ArticleCategory::selectOptions(false));
$form->text('title')->required();
$form->text('sub_title');
$form->image('cover')
->uniqueName()
->move('articles/'.Carbon::now()->toDateString())
->saveFullUrl()
->autoSave(false)
->autoUpload()
->removable(false)//禁止用户从页面点击删除服务器上的文件,可以实现图片覆盖上传效果
->retainable();
$form->text('author');
$form->file('media_path')->chunked()
->accept('mp4,mp3', 'mp4/*,mp3/*')
->move('articles-media/'.Carbon::now()->toDateString())
->maxSize(204800)//默认最大200M
->saveFullUrl()
->removable(false)
->autoUpload()->autoSave(false);
$form->datetime('published_at');
$form->switch('is_enable')->default(0);
$form->switch('is_recommend')->default(0);
$form->number('sort')->min(0)->default(0);
$form->text('remarks');
$form->keyValue('ext', '扩展字段')->default($this->extDefaults)->setKeyLabel('键名')->setValueLabel('键值')
->saving(function($v){
return json_encode($v ?? []);
});
$form->editor('content')->options([
'plugins' => [
'image',
'lists',
'preview',
'fullscreen',
'table',
],
'toolbar' => [
'undo redo | preview fullscreen | styleselect | fontsizeselect bold italic underline strikethrough forecolor backcolor | image blockquote removeformat codesample',
'alignleft aligncenter alignright alignjustify| indent outdent bullist numlist table subscript superscript | code',
]
])->height('800');
Admin::style(<<<css
.tox.tox-silver-sink.tox-tinymce-aux{
z-index:99999999;
}
css);
});
}
}

View File

@ -1,12 +0,0 @@
<?php
use Peidikeji\Article\Http\Controllers;
use Illuminate\Support\Facades\Route;
if(! Route::has('dcat.admin.article_categories.index')){
Route::resource('article-categories', Controllers\ArticleCategoryController::class)->names('article_categories');
}
if(! Route::has('dcat.admin.articles.index')){
Route::resource('articles', Controllers\ArticleController::class);
}

View File

@ -1,75 +0,0 @@
<?php
namespace Peidikeji\Article\Models;
use Dcat\Admin\Admin;
use EloquentFilter\Filterable;
use Dcat\Admin\Models\Administrator;
use Illuminate\Database\Eloquent\Model;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
/**
* @method static \Illuminate\Database\Eloquent\Builder
*/
class Article extends Model
{
use HasFactory;
use HasDateTimeFormatter;
use Filterable;
protected $fillable = [
'author', 'admin_user_id', 'title', 'sub_title', 'cover', 'content',
'is_recommend', 'is_enable', 'sort', 'published_at',
'remarks', 'category_id', 'category_path',
'like_nums', 'read_nums', 'media_path'
];
protected $dates = ['published_at'];
public static function boot()
{
parent::boot();
static::saving(function ($model) {
$model->admin_user_id = Admin::user()->id;
// 添加/修改分类时, 更新 category_path
if ($model->isDirty('category_id')) {
$model->category_path = ArticleCategory::where('id', $model->category_id)->value('path') . $model->category_id . '-';
}
});
}
public function category()
{
return $this->belongsTo(ArticleCategory::class, 'category_id');
}
public function adminUser()
{
return $this->belongsTo(Administrator::class, 'admin_user_id');
}
public function getAuthorNameAttribute()
{
return $this->attributes['author'] ?? ($this->attributes['admin_user_id'] ? (Administrator::find($this->attributes['admin_user_id'])?->name ?? '未知') : '未知');
}
//public function image(): Attribute
//{
// return Attribute::make(
// get: fn ($v) => $v ?: 'https://via.placeholder.com/640x480.png',
// set: fn ($v) => $v ?: 'https://via.placeholder.com/640x480.png',
// );
//}
public function scopeSort($q)
{
return $q->orderBy('sort', 'desc')->latest('published_at')->latest('id');
}
public function scopePublish($q)
{
return $q->where('published_at', '<=', now());
}
}

View File

@ -1,70 +0,0 @@
<?php
namespace Peidikeji\Article\Models;
use Dcat\Admin\Traits\ModelTree;
use EloquentFilter\Filterable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ArticleCategory extends Model
{
use HasFactory;
use ModelTree;
use Filterable;
protected $fillable = ['key', 'name', 'is_recommend', 'is_enable', 'sort', 'level', 'path', 'parent_id', 'remarks'];
protected $titleColumn = 'name';
protected $orderColumn = 'sort';
public static function boot()
{
parent::boot();
static::saving(function ($category) {
// 如果创建的是一个根类目
if (!$category->parent_id) {
// 将层级设为 1
$category->level = 1;
// 将 path 设为 -
$category->path = '-';
} else {
// 将层级设为父类目的层级 + 1
$category->level = $category->parent->level + 1;
// 将 path 值设为父类目的 path 追加父类目 ID 以及最后跟上一个 - 分隔符
$category->path = $category->parent->path . $category->parent_id . '-';
}
});
}
public static function selectOptions($root = true)
{
$rootText = '顶级';
$options = (new static())->withQuery(function ($q) {
return $q->sort();
})->buildSelectOptions();
return collect($options)->when($root, fn ($c) => $c->prepend($rootText, 0))->all();
}
public function articles()
{
return $this->hasMany(Article::class, 'category_id');
}
public function parent()
{
return $this->belongsTo(static::class, 'parent_id');
}
public function children()
{
return $this->hasMany(static::class, 'parent_id')->sort();
}
public function scopeSort($q)
{
return $q->orderBy('sort', 'desc')->orderBy('id');
}
}

View File

@ -1,14 +0,0 @@
<?php
namespace Peidikeji\Article;
use Dcat\Admin\Extend\Setting as Form;
class Setting extends Form
{
public function form()
{
$this->text('key1')->required();
$this->text('key2')->required();
}
}

View File

@ -1,35 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddMediaToArticleTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasTable('articles')) {
Schema::table('articles', function (Blueprint $table) {
$table->string('media_path')->nullable()->comment('资源地址');
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('articles', function (Blueprint $table) {
//
$table->dropColumn('media_path');
});
}
};

View File

@ -1,36 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddnumToArticleTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasTable('articles')) {
Schema::table('articles', function (Blueprint $table) {
$table->unsignedBigInteger('like_nums')->default(0)->comment('点赞数');
$table->unsignedBigInteger('read_nums')->default(0)->comment('阅读数');
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('articles', function (Blueprint $table) {
//
$table->dropColumn(['like_nums', 'read_nums']);
});
}
};

View File

@ -1,70 +0,0 @@
<?php
namespace Database\Seeders;
use Dcat\Admin\Models\Permission;
use Illuminate\Database\Seeder;
class ArticlePermissionSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$permissions = [
'article_categories' => ['name' => '文章分类管理', 'curd' => true],
'articles' => ['name' => '文章管理', 'curd' => true],
];
$this->createPermissionData($permissions);
}
/**
* 插入权限
*
* @param array $permissions
* @param string $key
* @param integer $pId
*/
public function createPermissionData(array $permissions, string $key = '', int $pId = 0)
{
$curdArr = [
'index' => '列表',
'create' => '新增',
'edit' => '修改',
'destroy' => '删除',
'show' => '详情',
];
foreach ($permissions as $slug => $permission) {
//是否已存在该权限
$slugKey = 'dcat.admin.' . ($key ? $key . '.' . $slug : $slug);
$pper = Permission::updateOrCreate(['slug' => $slugKey], ['name' => is_string($permission) ? $permission : $permission['name'], 'parent_id' => $pId]);
if (!is_string($permission)) {
if (!isset($permission['children'])) {
$permission['children'] = [];
}
//判断是否默认插入curd权限
if (isset($permission['curd']) && $permission['curd']) {
if (is_array($permission['curd'])) {
$permission['curd'] = array_reverse($permission['curd']);
foreach ($permission['curd'] as $value) {
$permission['children'] = array_merge([$value => $curdArr[$value]], $permission['children']);
}
} else {
$permission['children'] = array_merge($curdArr, $permission['children']);
}
}
if (count($permission['children']) > 0) {
$_key = $permission['curd'] !== false ? ($key ? $key . '.' . $slug : $slug) : $key;
$this->createPermissionData($permission['children'], $_key ?? $slug, $pper->id);
}
}
}
}
}

View File

@ -1,70 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArticleTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (!Schema::hasTable('article_categories')) {
Schema::create('article_categories', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('名称');
$table->string('key')->unique()->nullable()->comment('key');
$table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐状态');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('可用状态');
$table->unsignedBigInteger('parent_id')->default(0)->comment('上级ID');
$table->unsignedInteger('level')->default(1)->comment('层级');
$table->string('path')->default('-')->comment('所有的父级ID');
$table->unsignedInteger('sort')->default(0)->comment('排序 desc');
$table->string('remarks')->nullable()->comment('备注');
$table->text('ext')->nullable()->comment('扩展字段可用于SEO配置等');
$table->timestamps();
});
}
if (!Schema::hasTable('articles')) {
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('category_id')->nullable()->comment('分类ID');
$table->string('category_path')->default('-')->comment('分类 path');
$table->unsignedBigInteger('admin_user_id')->comment('创建人');
$table->string('title')->comment('文章标题');
$table->string('sub_title')->nullable()->comment('副标题');
$table->string('author')->nullable()->comment('作者');
$table->string('cover')->nullable()->comment('封面');
$table->longText('content')->nullable()->comment('文章内容');
$table->timestamp('published_at')->nullable()->comment('发布时间');
$table->unsignedInteger('sort')->default(1)->comment('排序 desc');
$table->string('remarks')->nullable()->comment('备注');
$table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐状态');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('可用状态');
$table->text('ext')->nullable()->comment('扩展字段可用于SEO配置等');
$table->timestamps();
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('articles');
Schema::dropIfExists('article_categories');
}
};

View File

@ -1,16 +0,0 @@
<?php
return [
'1.0.0' => [
'初始化文章管理',
'CreateArticleTable.php',
],
'1.0.1' => [
'文章添加点赞,浏览字段',
'AddnumToArticleTable.php',
],
'1.0.2' => [
'文章添加媒体内容',
'AddMediaToArticleTable.php',
],
];

View File

@ -1,7 +0,0 @@
.DS_Store
phpunit.phar
/vendor
composer.phar
composer.lock
*.project
.idea/

View File

@ -1,60 +0,0 @@
# Dact-Admin Extension Banner
广告管理
## 权限
```php
$permissions = [
'image' => ['name' => '广告管理', 'curd' => false, 'children' => [
'banner_ads' => ['name' => '广告位置', 'curd' => true],
'banners' => ['name' => '广告内容', 'curd' => true],
]],
];
```
## 菜单
```php
$menus = [
['title' => '广告管理', 'icon' => 'feather icon-image', 'uri' => '', 'permission' => ['banner_ads', 'banners'], 'children' => [
['title' => '广告位置', 'icon' => '', 'uri' => '/banner-ads', 'permission' => 'banner_ads'],
['title' => '广告内容', 'icon' => '', 'uri' => '/banners', 'permission' => 'banners'],
]]
];
```
## 接口文档
[Apifox](https://www.apifox.cn/apidoc/shared-86eb60cb-ba8f-46c6-b718-f33f99de5e7d/api-39896291)
## 数据表
### 广告位: banner_ads
| column | type | nullable | default | comment |
| - | - | - | - | - |
| id | bigint | not null | - | 主键 |
| name | varchar(100) | not null | - | 名称 |
| key | varchar(100) | not null | - | 关键字(unique) |
| width | integer | null | - | 建议尺寸 |
| height | integer | null | - | 建议尺寸 |
| is_enable | integer | not null | 1 | 是否可用 |
| remarks | varchar(100) | null | - | 备注 |
| created_at | timestamp | null | - | 创建时间 |
| updated_at | timestamp | null | - | 更新时间 |
### 广告图: banner
| column | type | nullable | default | comment |
| - | - | - | - | - |
| id | bigint | not null | - | 主键 |
| ad_id | bigint | not null | - | 位置 id |
| path | varchar(191) | not null | - | 图片地址 |
| name | varchar(191) | null | - | 名称 |
| sort | integer | not null | 1 | 排序(asc) |
| is_enable | integer | not null | 1 | 是否可用 |
| ext | json | null | - | 其他配置 |
| remarks | varchar(191) | null | - | 备注 |
| created_at | timestamp | null | - | 创建时间 |
| updated_at | timestamp | null | - | 更新时间 |

View File

@ -1,31 +0,0 @@
{
"name": "peidikeji/banner",
"alias": "广告管理",
"description": "广告管理",
"type": "library",
"keywords": ["dcat-admin", "extension"],
"homepage": "https://github.com/peidikeji/banner",
"license": "MIT",
"authors": [
{
"name": "liutk",
"email": "961510893@qq.com"
}
],
"require": {
"php": ">=7.1.0"
},
"autoload": {
"psr-4": {
"Peidikeji\\Banner\\": "src/"
}
},
"extra": {
"dcat-admin": "Peidikeji\\Banner\\BannerServiceProvider",
"laravel": {
"providers": [
"Peidikeji\\Banner\\BannerServiceProvider"
]
}
}
}

View File

@ -1,3 +0,0 @@
<?php
return [];

View File

@ -1,3 +0,0 @@
<?php
return [];

View File

@ -1,18 +0,0 @@
<?php
return [
'labels' => [
'BannerAd' => '广告位管理',
'banner-ads'=> '广告位管理',
],
'fields' => [
'name' => '名称',
'key' => 'key',
'width' => '宽度',
'height' => '高度',
'is_enable' => '启用',
'remarks' => '备注',
],
'options' => [
],
];

View File

@ -1,19 +0,0 @@
<?php
return [
'labels' => [
'Banner' => '广告图管理',
'banners' => '广告图管理',
],
'fields' => [
'ad_id'=>'广告位',
'name'=>'名称',
'path'=>'内容',
'sort'=>'排序',
'is_enable'=>'启用',
'remarks'=> '备注',
'ext'=>'扩展字段'
],
'options' => [
],
];

View File

@ -1,19 +0,0 @@
<?php
namespace Peidikeji\Banner;
use Dcat\Admin\Extend\ServiceProvider;
class BannerServiceProvider extends ServiceProvider
{
// protected $menu = [
// ['parent' => '', 'title' => '广告管理', 'icon' => 'feather icon-image', 'uri' => ''],
// ['parent' => '广告管理', 'title' => '广告位置', 'icon' => '', 'uri' => 'banner-ads'],
// ['parent' => '广告管理', 'title' => '广告内容', 'icon' => '', 'uri' => 'banners'],
// ];
public function init()
{
parent::init();
}
}

View File

@ -1,88 +0,0 @@
<?php
namespace Peidikeji\Banner\Http\Admin;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Admin;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Peidikeji\Banner\Models\Banner;
use Peidikeji\Banner\Models\BannerAd;
use Dcat\Admin\Grid\Column as GridColumn;
use Dcat\Admin\Http\Controllers\AdminController;
class BannerAdController extends AdminController
{
protected $translation = 'peidikeji.banner::banner-ad';
public function list(Request $request)
{
$query = BannerAd::filter($request->all());
$query->select(['id', 'name as text', 'width', 'height']);
if ($request->filled('_paginate')) {
$list = $query->paginate();
} else {
$list = $query->get();
}
return $list;
}
protected function grid()
{
return Grid::make(new BannerAd(), function ($grid) {
$grid->disableRowSelector();
$grid->column('name');
$grid->column('key');
$grid->column('width');
$grid->column('height');
$grid->column('is_enable')->if(function(){
return !config('admin.permission.enable') || Admin::user()->can('dcat.admin.banner_ads.edit');
})->then(function (GridColumn $column) {
$column->switch();
})->else(function (GridColumn $column) {
$column->bool();
});
$grid->column('remarks');
$grid->disableCreateButton(!(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.banner_ads.create')));
$grid->enableDialogCreate();
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableView();
$actions->disableEdit();
$actions->quickEdit(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.banner_ads.edit'));
$actions->delete(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.banner_ads.destroy'));
});
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->expand();
$filter->like('name')->width(3);
$filter->like('key')->width(3);
});
});
}
protected function form()
{
return Form::make(new BannerAd(), function (Form $form) {
$form->text('name')->required();
$form->text('key')->required()->rules([Rule::unique((new BannerAd())->getTable())]);
$form->number('width')->min(0);
$form->number('height')->min(0);
$form->switch('is_enable')->default(1);
$form->text('remarks');
});
}
public function destroy($id)
{
//如果该广告位下还有内容,则一起删除
Banner::where(['ad_id' => $id])->delete();
return parent::destroy($id);
}
}

View File

@ -1,114 +0,0 @@
<?php
namespace Peidikeji\Banner\Http\Admin;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Admin;
use Dcat\Admin\Widgets\Card;
use Peidikeji\Banner\Models\Banner;
use Dcat\Admin\Grid\Column as GridColumn;
use Dcat\Admin\Http\Controllers\AdminController;
class BannerController extends AdminController
{
protected $translation = 'peidikeji.banner::banner';
protected $extDefaults = [];
protected function grid()
{
return Grid::make(new Banner(), function (Grid $grid) {
$grid->model()->sort();
$grid->disableRowSelector();
$grid->column('path')->image('', 50);
$grid->column('name');
$grid->column('sort');
$grid->column('is_enable')->if(function () {
return !config('admin.permission.enable') || Admin::user()->can('dcat.admin.banners.edit');
})->then(function (GridColumn $column) {
$column->switch();
})->else(function (GridColumn $column) {
$column->bool();
});
$grid->column('ext')
->if(function () {
return $this->ext;
})->then(function (GridColumn $column) {
$column->display('展开')->expand(function () {
// 返回显示的详情
$card = new Card(null, sprintf('<pre class="dump">%s</pre>', json_encode($this->ext, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)));
return "<div style='padding:10px 10px 0'>$card</div>";
});
});
$grid->column('remarks');
$grid->setDialogFormDimensions('50%', '70%');
$grid->disableCreateButton(!(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.banners.create')));
$grid->enableDialogCreate();
$grid->actions(function (Grid\Displayers\Actions $actions) {
$actions->disableView();
$actions->disableEdit();
$actions->quickEdit(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.banners.edit'));
$actions->delete(!config('admin.permission.enable') || Admin::user()->can('dcat.admin.banners.destroy'));
});
$grid->filter(function (Grid\Filter $filter) {
$filter->panel();
$filter->expand();
$filter->like('name')->width(3);
});
});
}
protected function form()
{
return Form::make(new Banner(), function (Form $form) {
$form->select('ad_id')
->options('api/banner-ads')
->required();
$form->text('name');
$form->image('path')
->uniqueName()
->move('banner')
->saveFullUrl()
->autoSave(false)
->autoUpload()
->removable(false) //禁止用户从页面点击删除服务器上的文件,可以实现图片覆盖上传效果
->retainable()
->required()->help('建议尺寸:');
Admin::script(
<<<JS
$('body').on('select2:select', 'select.field_ad_id', function(e){
let url_path = '/admin/api/banner-ads?id=' + e.params.data.id
$.ajax({
type: 'get',
dataType: 'json',
url: url_path,
success: function(result){
//异步渲染提示尺寸;
let cicun = '未设置';
if(result[0]){
if(result[0].width || result[0].height){
cicun = result[0].width + '*' + result[0].height;
}
}
$('input[name=path]').parent().find('span.help-block').html('<i class="fa feather icon-help-circle"></i>&nbsp;建议尺寸:'+ cicun);
}
});
});
JS
);
$form->number('sort')
->min(0)
->help('数值越小, 越靠前');
$form->keyValue('ext')->default($this->extDefaults)->setKeyLabel('键名')->setValueLabel('键值');
$form->switch('is_enable')->default(1);
$form->text('remarks');
});
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace Peidikeji\Banner\Http\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Peidikeji\Banner\Models\BannerAd;
use Peidikeji\Banner\Http\Resources\BannerResource;
class BannerController extends Controller
{
public function index(Request $request)
{
$request->validate([
'key' => 'required'
]);
$keys = $request->input('key');
$keys = is_array($keys) ? $keys : explode(',', $keys);
$ads = BannerAd::with([
'banners' => function ($query) {
$query->enable()->sort();
},
])->enable()->whereIn('key', $keys)->get();
$data = [];
foreach ($keys as $key) {
$ad = $ads->where('key', $key)->first();
$data[$key] = $ad ? BannerResource::collection($ad->banners) : [];
}
return $this->json($data);
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace Peidikeji\Banner\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class BannerResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'path' => $this->path,
'ext' => $this->ext,
];
}
}

View File

@ -1,16 +0,0 @@
<?php
namespace Peidikeji\Banner\Http\Admin;
use Illuminate\Support\Facades\Route;
if(! Route::has('dcat.admin.api.banner_ads')){
Route::get('api/banner-ads', [BannerAdController::class, 'list'])->name('api.banner_ads');
}
if(! Route::has('dcat.admin.banner_ads.index')){
Route::resource('banner-ads', BannerAdController::class)->names('banner_ads');
}
if(! Route::has('dcat.admin.banners.index')){
Route::resource('banners', BannerController::class);
}

View File

@ -1,9 +0,0 @@
<?php
namespace Peidikeji\Banner\Http\Api;
use Illuminate\Support\Facades\Route;
Route::group(['middleware' => 'api', 'prefix' => 'api'], function () {
Route::get('banner', [BannerController::class, 'index']);
});

View File

@ -1,33 +0,0 @@
<?php
namespace Peidikeji\Banner\Models;
use Illuminate\Database\Eloquent\Model;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Banner extends Model
{
use HasFactory, HasDateTimeFormatter;
protected $fillable = ['ad_id', 'path', 'name', 'sort', 'is_enable', 'ext', 'remarks'];
protected $casts = [
'ext' => 'array'
];
public function ad()
{
return $this->belongsTo(BannerAd::class, 'ad_id');
}
public function scopeEnable($query)
{
return $query->where('is_enable', 1);
}
public function scopeSort($q)
{
return $q->orderBy('sort');
}
}

View File

@ -1,23 +0,0 @@
<?php
namespace Peidikeji\Banner\Models;
use Illuminate\Database\Eloquent\Model;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class BannerAd extends Model
{
use HasFactory, HasDateTimeFormatter;
protected $fillable = ['name', 'key', 'width', 'height', 'is_enable', 'remarks'];
public function banners()
{
return $this->hasMany(Banner::class, 'ad_id');
}
public function scopeEnable($query){
return $query->where('is_enable', 1);
}
}

View File

@ -1,56 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBannerTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (!Schema::hasTable('banner_ads')) {
Schema::create('banner_ads', function (Blueprint $table) {
$table->id();
$table->string('name')->comment('名称');
$table->string('key')->unique()->comment('key');
$table->unsignedInteger('width')->nullable()->comment('宽');
$table->unsignedInteger('height')->nullable()->comment('高');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('可用状态');
$table->string('remarks')->nullable()->comment('备注');
$table->timestamps();
});
}
if (!Schema::hasTable('banners')) {
Schema::create('banners', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('ad_id')->comment('位置ID');
$table->string('path')->comment('地址');
$table->string('name')->nullable()->comment('名称');
$table->unsignedInteger('sort')->default(1)->comment('排序(asc)');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('可用状态');
$table->text('ext')->nullable()->comment('扩展字段,可用于跳转配置等');
$table->string('remarks')->nullable()->comment('备注');
$table->timestamps();
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('banners');
Schema::dropIfExists('banner_ads');
}
};

View File

@ -1,7 +0,0 @@
<?php
return [
'1.0.0' => [
'CreateBannerTable.php',
],
];

View File

@ -2,6 +2,7 @@
namespace Peidikeji\Keywords\Http\Admin;
use Dcat\Admin\Admin;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Http\Controllers\AdminController;
@ -30,13 +31,18 @@ class KeywordsController extends AdminController
protected function grid()
{
return Grid::make(new Keywords(), function ($grid) {
return Grid::make(new Keywords(), function (Grid $grid) {
$grid->column('name')->tree();
$grid->column('key');
$grid->column('value');
$grid->enableDialogCreate();
$user = Admin::user();
$grid->showCreateButton($user->can('dcat.admin.keywords.create'));
$grid->showEditButton($user->can('dcat.admin.keywords.edit'));
$grid->showDeleteButton($user->can('dcat.admin.keywords.destroy'));
$grid->quickSearch(['name', 'type_key', 'key']);
});
}
@ -80,6 +86,11 @@ class KeywordsController extends AdminController
$form->hidden('type_key');
$form->hidden('level')->default(1);
$form->disableCreatingCheck();
$form->disableEditingCheck();
$form->disableListButton();
$form->disableDeleteButton();
$form->saving(function (Form $form) {
if ($form->parent_id) {
$parent = Keywords::findOrFail($form->parent_id);

View File

@ -6,12 +6,18 @@ use Dcat\Admin\Extend\ServiceProvider;
class KeywordsServiceProvider extends ServiceProvider
{
// protected $menu = [
// ['title' => 'Keywords', 'uri' => 'keywords', 'icon' => 'feather icon-list'],
// ];
public function init()
{
parent::init();
}
protected function menu()
{
if (config('app.debug')) {
return [
['title' => 'Keywords', 'uri' => 'keywords', 'icon' => 'feather icon-list'],
];
}
return $this->menu;
}
}

View File

@ -64,8 +64,8 @@ class SettingController extends AdminController
if ($form->isEditing()) {
$unique->ignore($form->getKey(), 'slug');
}
$form->text('name')->required();
$form->text('slug')->required()->help('不能重复')->rules([$unique]);
$form->text('name')->required();
$form->textarea('value')->required();
});
}

View File

@ -6,16 +6,18 @@ use Dcat\Admin\Extend\ServiceProvider;
class SettingServiceProvider extends ServiceProvider
{
// protected $menu = [
// ['title' => '配置管理', 'uri' => 'settings', 'icon' => 'fa fa-gear'],
// ];
public function register()
{
}
public function init()
{
parent::init();
}
protected function menu()
{
if (config('app.debug')) {
return [
['title' => '配置管理', 'uri' => 'settings', 'icon' => 'fa fa-gear'],
];
}
return $this->menu;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

12014
resources/dist/vue/vue.js vendored 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
<div class="{{$viewClass['form-group']}}">
<label class="{{$viewClass['label']}} control-label">{!! $label !!}</label>
<div class="{{$viewClass['field']}}">
@include('admin::form.error')
<div class="{{ $class }}" style="padding-left: 40px;" >
<el-tree
show-checkbox
node-key="id"
ref="tree"
highlight-current
:data="permissionNodes"
:indent="25"
:render-after-expand="false"
:default-expand-all="true"
:default-checked-keys="defaultKeys"
:props="defaultProps" v-on:check-change="nodeChange">
<span class="custom-tree-node" slot-scope="{ node, permissionNodes }" >
<span v-on:click="getCheckedNode(node)">@{{ node.label }}</span>
<template v-if="node.level==1">
<span class="tran el-icon-arrow-right" :class="{isactive:node.expanded}"></span>
</template>
</span>
</el-tree>
<input type="hidden" ref="format_attr_value" name="format_attr_value" value="{{ $value }}">
<input type="hidden" name="{{ $name }}" :value="getCheck">
</div>
@include('admin::form.help-block')
</div>
</div>
<script init="{!! $selector !!}">
var app = new Vue({
el: '#' + id,
data: {
defaultProps: {
children: 'children',
label: 'label'
},
checkPermissions:[],
defaultKeys:[],
permissionNodes:[]
},
computed: {
getCheck() {
// console.log(this.checkPermissions);
return JSON.stringify(this.checkPermissions);
}
},
created() {
this.createStart()
},
methods:{
createStart(){
//初始化权限可选项;
var url_path = "{{ admin_route('api.get_permissions') }}";
var that = this;
$.ajax({
type: 'get',
dataType: 'json',
url: url_path,
success: function (result) {
that.permissionNodes = result;
}
})
setTimeout(()=>{
var formatAttrValue = this.$refs.format_attr_value.defaultValue
//编辑时默认选中项
if(formatAttrValue){
formatAttrValue = JSON.parse(formatAttrValue)
// console.log(formatAttrValue)
//赋予defaultKeys值
this.defaultKeys = formatAttrValue
this.checkPermissions = formatAttrValue;
}
}, 100)
},
getCheckedNode(node){
if(this.checkPermissions.indexOf(node.key) != -1){//如果该节点已存在,则取消选中
this.$refs.tree.setChecked(node, false);
}else{
this.$refs.tree.setChecked(node, true);
}
},
nodeChange(node, hasChecked, childrenNodes){
if(node.children.length == 0){
if(hasChecked){
this.checkPermissions.push(node.id);
}else{
this.checkPermissions.splice(this.checkPermissions.indexOf(node.id), 1);
}
}
},
}
})
</script>

View File

@ -22,5 +22,6 @@
{!! $content !!}
@endif
@endif
@include('admin::form.help-block')
</div>
</div>

View File

@ -588,6 +588,8 @@ class Admin
if (config('admin.permission.enable')) {
$router->resource('auth/roles', 'RoleController');
$router->resource('auth/permissions', 'PermissionController');
$router->get('api/get-permissions', 'PermissionController@apiGetPermissions')->name('api.get_permissions');
}
});

View File

@ -3,31 +3,31 @@
namespace Dcat\Admin;
use Closure;
use Dcat\Admin\Actions\Action;
use Dcat\Admin\Contracts\Repository;
use Dcat\Admin\Form\AbstractTool;
use Dcat\Admin\Form\Builder;
use Dcat\Admin\Form\Concerns;
use Dcat\Admin\Form\Condition;
use Dcat\Admin\Form\Field;
use Illuminate\Support\Arr;
use Dcat\Admin\Form\Builder;
use Illuminate\Http\Request;
use Dcat\Admin\Form\Concerns;
use Dcat\Admin\Actions\Action;
use Dcat\Admin\Form\Condition;
use Dcat\Admin\Support\Helper;
use Illuminate\Support\Fluent;
use Dcat\Admin\Form\NestedForm;
use Dcat\Admin\Form\AbstractTool;
use Dcat\Admin\Form\ResolveField;
use Dcat\Admin\Http\JsonResponse;
use Dcat\Admin\Support\Helper;
use Dcat\Admin\Traits\HasBuilderEvents;
use Dcat\Admin\Traits\HasFormResponse;
use Dcat\Admin\Widgets\DialogForm;
use Illuminate\Contracts\Support\MessageProvider;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Fluent;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Traits\Macroable;
use Dcat\Admin\Contracts\Repository;
use Illuminate\Validation\Validator;
use Dcat\Admin\Traits\HasFormResponse;
use Dcat\Admin\Traits\HasBuilderEvents;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Support\Renderable;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Contracts\Support\MessageProvider;
/**
* Class Form.
@ -88,6 +88,7 @@ use Symfony\Component\HttpFoundation\Response;
* @method Field\MultipleSelectTable multipleSelectTable($column, $label = '')
* @method Field\Button button(string $html = null)
* @method Field\Autocomplete autocomplete($column, $label = '')
* @method Field\PermissionSelect permissionSelect($column, $label = '')
*/
class Form implements Renderable
{
@ -172,6 +173,7 @@ class Form implements Renderable
'selectTable' => Field\SelectTable::class,
'multipleSelectTable' => Field\MultipleSelectTable::class,
'autocomplete' => Field\Autocomplete::class,
'permissionSelect' => Field\PermissionSelect::class,
];
/**

View File

@ -0,0 +1,89 @@
<?php
namespace Dcat\Admin\Form\Field;
use Dcat\Admin\Admin;
use Dcat\Admin\Form\Field;
class PermissionSelect extends Field
{
protected $view = 'admin::form.permission-select';
protected $listen = '';
protected static $css = [
'@element',
];
protected static $js = [
'@vue',
'@element',
];
public function render()
{
Admin::style(
<<<CSS
.el-tree>.el-tree-node {
border-top: 1px solid #EBEEF5 !important;
padding: 10px 0;
}
.el-tree-node__children .el-tree-node{
display: flex !important;
}
.el-tree-node__children .el-tree-node .el-tree-node__children{
display: flex !important;
flex-wrap: wrap;
padding-left: 0 !important;
}
.el-tree-node__expand-icon{
display: none !important;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 16px;
padding-right: 8px;
}
.tran{
transition: transform .3s;
}
.isactive{
transform: rotate(90deg) ;
}
.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{
background-color:transparent !important;
}
.el-tree-node__content:hover, .el-upload-list__item:hover{
background-color:transparent !important;
}
CSS
);
$this->addVariables(['listen' => $this->listen]);
return parent::render();
}
/**
* 格式化渲染值
*
* @param [type] $value
* @return void
*/
protected function formatFieldData($data)
{
$value = parent::formatFieldData($data);
$hasChecked = [];
foreach ($value ?? [] as $permission){
$hasChecked[] = $permission['id'];
}
return json_encode($hasChecked);
}
protected function prepareInputValue($value)
{
return json_decode($value);
}
}

View File

@ -86,18 +86,18 @@ class Permission
*
* @throws \Illuminate\Http\Exceptions\HttpResponseException
*/
public static function error()
public static function error($ability = null)
{
if ($error = static::$errorHandler) {
admin_exit($error());
}
if (Helper::isAjaxRequest()) {
abort(403, trans('admin.deny'));
abort(403, trans('admin.deny') . ':' . $ability);
}
admin_exit(
Content::make()->withError(trans('admin.deny'))
Content::make()->withError(trans('admin.deny') . ':' . $ability)
);
}

View File

@ -2,12 +2,14 @@
namespace Dcat\Admin\Http\Controllers;
use Dcat\Admin\Admin;
use Dcat\Admin\Form;
use Dcat\Admin\Http\Repositories\Permission;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Tree;
use Dcat\Admin\Admin;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Http\Repositories\Permission;
use Dcat\Admin\Models\Permission AS PermissionModel;
class PermissionController extends AdminController
{
@ -16,6 +18,38 @@ class PermissionController extends AdminController
return trans('admin.permissions');
}
/**
* 通过接口获取权限数据
*
* @return void
*/
public function apiGetPermissions(Request $request)
{
$permissions = (new PermissionModel())->toTree();
$permissionArr = $this->formatPermissionsTreeToArray($permissions);
return response()->json($permissionArr);
}
/**
* 格式化树
*
* @param array $permissions
* @return void
*/
protected function formatPermissionsTreeToArray(array $permissions)
{
$res = [];
foreach ($permissions as $permission) {
$res[] = [
'id' => $permission->id,
'label' => $permission->name,
'children' => $this->formatPermissionsTreeToArray($permission->children ?? []),
];
}
return $res;
}
public function index(Content $content)
{
return $content

View File

@ -96,38 +96,40 @@ class RoleController extends AdminController
$form->text('name', trans('admin.name'))->required();
$form->tree('permissions')
->nodes(function () {
$permissionModel = config('admin.database.permissions_model');
$permissionModel = new $permissionModel();
$form->permissionSelect('permissions');
return $permissionModel->allNodes();
})
->customFormat(function ($v) {
if (! $v) {
return [];
}
// $form->tree('permissions')
// ->nodes(function () {
// $permissionModel = config('admin.database.permissions_model');
// $permissionModel = new $permissionModel();
return array_column($v, 'id');
});
// return $permissionModel->allNodes();
// })
// ->customFormat(function ($v) {
// if (! $v) {
// return [];
// }
if ($bindMenu) {
$form->tree('menus', trans('admin.menu'))
->treeState(false)
->setTitleColumn('title')
->nodes(function () {
$model = config('admin.database.menu_model');
// return array_column($v, 'id');
// });
return (new $model())->allNodes();
})
->customFormat(function ($v) {
if (! $v) {
return [];
}
// if ($bindMenu) {
// $form->tree('menus', trans('admin.menu'))
// ->treeState(false)
// ->setTitleColumn('title')
// ->nodes(function () {
// $model = config('admin.database.menu_model');
return array_column($v, 'id');
});
}
// return (new $model())->allNodes();
// })
// ->customFormat(function ($v) {
// if (! $v) {
// return [];
// }
// return array_column($v, 'id');
// });
// }
$form->display('created_at', trans('admin.created_at'));
$form->display('updated_at', trans('admin.updated_at'));

View File

@ -55,7 +55,7 @@ class Permission
if (! $user->allPermissions()->first(function ($permission) use ($request) {
return $permission->shouldPassThrough($request);
})) {
Checker::error();
Checker::error($ability);
}
return $next($request);

View File

@ -180,6 +180,13 @@ class Asset
'@autocomplete' => [
'js' => '@admin/dcat/plugins/autocomplete/jquery.autocomplete.min.js',
],
'@element' => [
'css' =>'@admin/element/v2.15.8/app.css',
'js' => '@admin/element/v2.15.8/app.js',
],
'@vue' => [
'js' => '@admin/vue/vue.js'
]
];
/**

View File

@ -56,6 +56,8 @@ class Field implements Renderable
*/
protected $escape = true;
protected $help;
/**
* Field value.
*
@ -702,6 +704,7 @@ HTML;
return [
'content' => $this->value,
'escape' => $this->escape,
'help' => $this->help,
'label' => $this->getLabel(),
'wrapped' => $this->border,
'width' => $this->width,
@ -772,4 +775,11 @@ HTML;
return format_byte($value, $dec);
});
}
public function help($text = '', $icon = 'feather icon-help-circle')
{
$this->help = compact('text', 'icon');
return $this;
}
}

View File

@ -97,7 +97,7 @@ trait ModelTree
*
* @return array
*/
public function toTree(array $nodes = null)
public function toTree($nodes = null)
{
if ($nodes === null) {
$nodes = $this->allNodes();
@ -304,7 +304,7 @@ trait ModelTree
* @param string $space
* @return array
*/
protected function buildSelectOptions(array $nodes = [], $parentId = 0, $prefix = '', $space = '&nbsp;')
public function buildSelectOptions(array $nodes = [], $parentId = 0, $prefix = '', $space = '&nbsp;')
{
$d = '├─';
$prefix = $prefix ?: $d.$space;

View File

@ -140,7 +140,7 @@ class Form implements Renderable
*
* @var array
*/
protected $buttons = ['reset' => true, 'submit' => true];
protected $buttons = ['reset' => true, 'submit' => true, 'back' => false];
/**
* @var bool
@ -489,6 +489,13 @@ class Form implements Renderable
return $this;
}
public function backButton(bool $value = true)
{
$this->buttons['back'] = $value;
return $this;
}
/**
* Disable reset button.
*
@ -500,6 +507,11 @@ class Form implements Renderable
return $this->resetButton(! $value);
}
public function disableBackButton(bool $value = true)
{
return $this->backButton(! $value);
}
/**
* Disable submit button.
*
@ -623,7 +635,7 @@ class Form implements Renderable
return <<<HTML
<div class="box-footer row d-flex">
<div class="col-md-2"> &nbsp;</div>
<div class="col-md-8">{$this->renderResetButton()}{$this->renderSubmitButton()}</div>
<div class="col-md-8">{$this->renderBackButton()}{$this->renderResetButton()}{$this->renderSubmitButton()}</div>
</div>
HTML;
}
@ -644,6 +656,15 @@ HTML;
}
}
protected function renderBackButton()
{
if (! empty($this->buttons['back'])) {
$back = trans('admin.back');
return "<a href=\"javascript: window.history.back()\" class=\"btn btn-white pull-left\"><i class=\"feather icon-arrow-left\"></i> {$back}</a>";
}
}
/**
* 提交按钮文本.
*