版本说明
- laravel/framework: 5.5.*
- encore/laravel-admin: ^1.7
表和模型
- 表结构没啥好说的,其定义如下:
字段名称 | 字段类型 | 字段描述 |
---|---|---|
id | unsigned int primary key | 自增主键 |
pid | unsigned int | 父级分类ID |
cate_name | varchar(30) | 分类名称 |
sort | unsigned smallint | 排序字段 |
- CategoriesModel.php的定义:
<?php
namespace App\Models;
use Encore\Admin\Traits\AdminBuilder;
use Encore\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Model;
class CategoriesModel extends Model
{
use ModelTree, AdminBuilder;
protected $table = 'categories';
protected $fillable = ['pid', 'cate_name', 'sort'];
protected $with = [
'parent'
];
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->setParentColumn('pid'); // 父ID
$this->setOrderColumn('sort'); // 排序
$this->setTitleColumn('cate_name'); // 标题
}
// 该分类下的品牌
public function brand()
{
return $this->hasMany(BrandModel::class, 'cate_id', $this->getKeyName());
}
/**
* 该分类的子分类
*/
public function child()
{
return $this->hasMany(get_class($this), 'pid', $this->getKeyName());
}
/**
* 该分类的父分类
*/
public function parent()
{
return $this->hasOne(get_class($this), $this->getKeyName(), 'pid');
}
}
使用了两个trait: ModelTree
和AdminBuilder
方便构造树形结构数据。 需要注意的是在定义表结构时,需要存在parent_id, order, title字段,当然意义上跟其一致即可,名称可以随意定义,可以在构造方法中设置对应字段的名称。
控制器定义
通过
php artisan admin:make CategoriesController --model=App\\Models\\CategoriesModel
生成控制器。发现CategoriesController是默认继承AdminController类的,点进去看AdminController类的定义如下:
<?php
namespace Encore\Admin\Controllers;
use Encore\Admin\Layout\Content;
use Illuminate\Routing\Controller;
class AdminController extends Controller
{
use HasResourceActions;
/**
* Title for current resource.
*
* @var string
*/
protected $title = 'Title';
/**
* Set description for following 4 action pages.
*
* @var array
*/
protected $description = [
// 'index' => 'Index',
// 'show' => 'Show',
// 'edit' => 'Edit',
// 'create' => 'Create',
];
/**
* Get content title.
*
* @return string
*/
protected function title()
{
return $this->title;
}
/**
* Index interface.
*
* @param Content $content
*
* @return Content
*/
public function index(Content $content)
{
return $content
->title($this->title())
->description($this->description['index'] ?? trans('admin.list'))
->body($this->grid());
}
/**
* Show interface.
*
* @param mixed $id
* @param Content $content
*
* @return Content
*/
public function show($id, Content $content)
{
return $content
->title($this->title())
->description($this->description['show'] ?? trans('admin.show'))
->body($this->detail($id));
}
/**
* Edit interface.
*
* @param mixed $id
* @param Content $content
*
* @return Content
*/
public function edit($id, Content $content)
{
return $content
->title($this->title())
->description($this->description['edit'] ?? trans('admin.edit'))
->body($this->form()->edit($id));
}
/**
* Create interface.
*
* @param Content $content
*
* @return Content
*/
public function create(Content $content)
{
return $content
->title($this->title())
->description($this->description['create'] ?? trans('admin.create'))
->body($this->form());
}
}
- AdminController控制器使用了一个trait:
HasResourceActions
,还有就是对index丶show丶edit丶create操作的封装。点击HasResourceActions,看其定义:
trait HasResourceActions
{
/**
* Update the specified resource in storage.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function update($id)
{
return $this->form()->update($id);
}
/**
* Store a newly created resource in storage.
*
* @return mixed
*/
public function store()
{
return $this->form()->store();
}
/**
* Remove the specified resource from storage.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
return $this->form()->destroy($id);
}
}
发现Trait:
HasResourceActions
是对store丶destroy丶update的封装,类中只有定义了form方法即可实现三种操作。那么我们的分类控制器:
Categories
可以通过继承基本的Controller
和使用trait:HasResourceActions来实现树形图的操作,CategoriesController.php
代码如下:
<?php
namespace App\Admin\Controllers;
use App\Models\CategoriesModel;
use Encore\Admin\Controllers\HasResourceActions;
use Encore\Admin\Layout\{Column, Row, Content};
use Encore\Admin\{Tree,Form};
use Encore\Admin\Widgets\Box;
use Illuminate\Http\RedirectResponse;
/**
* 分类管理
* @package App\Admin\Controllers
*/
class CategoriesController extends Content
{
use HasResourceActions;
protected $title = '分类';
/**
* 首页
* @param Content $content
* @return Content
*/
public function index(Content $content)
{
return $content->title('分类')
->description('列表')
->row(function (Row $row){
// 显示分类树状图
$row->column(6, $this->treeView()->render());
$row->column(6, function (Column $column){
$form = new \Encore\Admin\Widgets\Form();
$form->action(admin_url('categories'));
$form->select('pid', __('Parent Category'))->options(CategoriesModel::selectOptions());
$form->text('cate_name', __('Category Name'))->required();
$form->number('sort', __('Asc Sort'))->default(99)->help('越小越靠前');
$form->hidden('_token')->default(csrf_token());
$column->append((new Box(__('category.new'), $form))->style('success'));
});
});
}
/**
* 树状视图
* @return Tree
*/
protected function treeView()
{
return CategoriesModel::tree(function (Tree $tree){
$tree->disableCreate(); // 关闭新增按钮
$tree->branch(function ($branch) {
return "<strong>{$branch['cate_name']}</strong>"; // 标题添加strong标签
});
});
}
/**
* 详情页
* @param $id
* @return RedirectResponse
*/
public function show($id)
{
return redirect()->route('categories', ['id' => $id]);
}
/**
* 编辑
* @param $id
* @param Content $content
* @return Content
*/
public function edit($id, Content $content)
{
return $content->title(__('Categories'))
->description(__('edit'))
->row($this->form()->edit($id));
}
/**
* 表单
* @return Form
*/
public function form()
{
$form = new Form(new CategoriesModel());
$form->display('id', 'ID');
$form->select('pid', __('Parent Category'))->options(CategoriesModel::selectOptions());
$form->text('cate_name', __('Category Name'))->required();
$form->number('sort', __('Asc Sort'))->default(99)->help('越小越靠前');
return $form;
}
}
- 需要注意的是index方法中的Form和form方法中的form是不同的。
- CategoriesModel::selectOptions()方法可以快捷的列出可选项包括默认值0。
实现效果图
- 首页(左边是所有分类,右边是快捷创建分类。)
- 编辑页