Laravel-admin 創建美觀的樹形無限極分類視圖

版本說明

  • 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。

實現效果圖

  • 首頁(左邊是所有分類,右邊是快捷創建分類。)
 
20498274-786459a9c3f2677e.png
index.png
  • 編輯頁
 
20498274-196bfc79b94e1450.png
edit.png
發佈了63 篇原創文章 · 獲贊 4 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章