版本说明

  • 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: ModelTreeAdminBuilder方便构造树形结构数据。 需要注意的是在定义表结构时,需要存在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。

实现效果图

  • 首页(左边是所有分类,右边是快捷创建分类。)

index.png

  • 编辑页

edit.png