4
0
Fork 0

Compare commits

...

17 Commits
1.2 ... master

43 changed files with 12445 additions and 632 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,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,92 +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::query();
if ($request->filled('q')) {
$query->where('name', 'like', '%'.$request->input('q').'%');
}
$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>";
}
}
/**
* 提交按钮文本.
*