Dcat-Admin筆記

slqgenius發表於2023-04-26
no-gutters
.row 上帶有 margin-left: -15px;margin-right: -15px; 屬性,你可以在.row 上上定義.no-gutters 屬性,從而消除這個屬性,使頁面不會額外寬出 30px,即 <div class="row no-gutters"...

$content->row(function (Row $row) {
    // 啟用 no-gutters
    $row->noGutters();

    $row->column(9, function (Column $column) {
        $column->row($this->card(['col-md-12', 20], '#4DB6AC'));

        $column->row(function (Row $row) {
            // 啟用 no-gutters
            $row->noGutters();

            $row->column(4, $this->card(['col-md-4', 30], '#80CBC4'));
            $row->column(4, $this->card(['col-md-4', 30], '#4DB6AC'));
            $row->column(4, function (Column $column) {
                $column->row(function (Row $row) {
                    // 啟用 no-gutters
                    $row->noGutters();

                    $row->column(6, $this->card(['col-md-6', 30], '#26A69A'));
                    $row->column(6, $this->card(['col-md-6', 30], '#26A69A'));
                });
            });
        });
    });
});

效果如下

Dcat-Admin筆記

$grid->column('picture')->image();  
//設定伺服器和寬高  
$grid->column('picture')->image('http://xxx.com',  100,  100);  // 顯示多圖 
$grid->column('pictures')->display(function  ($pictures)  {          return  json_decode($pictures,  true);  
})->image('http://xxx.com',  100,  100);

$grid->column('state')->using([1  =>  '未處理',  2  =>  '已處理',  ...])

顯示 badge 標籤

$grid->column('name')->badge();

// 設定顏色,直接傳別名
$grid->column('name')->badge('danger');

// 也可以這樣使用
$grid->column('name')->badge(Admin::color()->danger());

// 也可以直接傳顏色程式碼
$grid->column('name')->badge('#222');

布林值顯示 (bool)#

將這一列轉為 bool 值之後顯示為

$grid->column('approved')->bool();

你也可以按照這一列的值指定顯示,比如欄位的值為 YN 表示 truefalse

$grid->column('approved')->bool(['Y' => true, 'N' => false]);

圓點字首 (dot)
透過 dot 方法可以在列文字前面加上一個帶顏色的圓點

use Dcat\Admin\Admin;

$grid->column('state')
    ->using([1 => '未處理', 2 => '已處理', ...])
    ->dot(
        [
            1 => 'primary',
            2 => 'danger',
            3 => 'success',
            4 => Admin::color()->info(),
        ], 
        'primary' // 第二個引數為預設值
    );

expand 方法可以把內容隱藏,點選按鈕的時候顯示在表格下一行

use Dcat\Admin\Widgets\Card;

$grid->column('content')->expand(function (Grid\Displayers\Expand $expand) {
    // 設定按鈕名稱
    $expand->button('詳情');

    // 返回顯示的詳情
    // 這裡返回 content 欄位內容,並用 Card 包裹起來
    $card = new Card(null, $this->content);

    return "<div style='padding:10px 10px 0'>$card</div>";
});
// 可以在閉包內返回非同步載入類的例項
$grid->post->expand(function () {
    // 允許在閉包內返回非同步載入類的例項

    return Post::make(['title' => $this->title]);
});

非同步載入#
定義渲染類,繼承 Dcat\Admin\Support\LazyRenderable

use App\Models\Post as PostModel;
use Dcat\Admin\Support\LazyRenderable;
use Dcat\Admin\Widgets\Table;

class Post extends LazyRenderable
{
    public function render()
    {
        // 獲取ID
        $id = $this->key;

        // 獲取其他自定義引數
        $type = $this->post_type;

        $data = PostModel::where('user_id', $id)
            ->where('type', $type)
            ->get(['title', 'body', 'body', 'created_at'])
            ->toArray();

        $titles = [
            'User ID',
            'Title',
            'Body',
            'Created At',
        ];

        return Table::make($titles, $data);
    }
}

使用

$grid->post->display('View')->expand(Post::make(['post_type' => 1]));

// 可以在閉包內返回非同步載入類的例項
$grid->post->expand(function () {
    // 允許在閉包內返回非同步載入類的例項

    return Post::make(['title' => $this->title]);
});

彈出模態框 (modal)
modal 方法可以把內容隱藏,點選按鈕的時候顯示在模態框中

use Dcat\Admin\Widgets\Card;

$grid->column('content')
    ->display('檢視') // 設定按鈕名稱
    ->modal(function ($modal) {
        // 設定彈窗標題
        $modal->title('標題 '.$this->username);

        // 自定義圖示
        $modal->icon('feather icon-x');
        //$this->content指的是當前欄位的內容
        $card = new Card(null, $this->content);

        return "<div style='padding:10px 10px 0'>$card</div>";
    });

// 也可以透過這種方式設定彈窗標題
$grid->column('content')
    ->display('檢視') // 設定按鈕名稱
    ->modal('彈窗標題', ...);

非同步載入
定義渲染類,繼承 Dcat\Admin\Support\LazyRenderable

use App\Models\Post as PostModel;
use Dcat\Admin\Support\LazyRenderable;
use Dcat\Admin\Widgets\Table;

class Post extends LazyRenderable
{
    public function render()
    {
        // 獲取ID
        $id = $this->key;

        // 獲取其他自定義引數
        $type = $this->post_type;

        $data = PostModel::where('user_id', $id)
            ->where('type', $type)
            ->get(['title', 'body', 'body', 'created_at'])
            ->toArray();

        $titles = [
            'User ID',
            'Title',
            'Body',
            'Created At',
        ];

        return Table::make($titles, $data);
    }
}

使用

$grid->post->display('View')->modal('Post', Post::make(['post_type' => 2]));

// 可以在閉包內返回非同步載入類的例項
$grid->post->modal(function ($modal) {
    $modal->title('自定義彈窗標題');

    // 允許在閉包內返回非同步載入類的例項
    return Post::make(['title' => $this->title]);
});

非同步載入工具表單#

<?php

namespace App\Admin\Forms;

use Dcat\Admin\Contracts\LazyRenderable;
use Dcat\Admin\Traits\LazyWidget;
use Dcat\Admin\Widgets\Form;

class UserProfile extends Form implements LazyRenderable
{
    use LazyWidget;

    public function handle(array $input)
    {
        // 接收外部傳遞引數
        $type = $this->payload['type'] ?? null;

        return $this->response()->success('儲存成功');
    }

    public function form()
    {
        // 接收外部傳遞引數
        $type = $this->payload['type'] ?? null;

        $this->text('name', trans('admin.name'))->required()->help('使用者暱稱');
        $this->image('avatar', trans('admin.avatar'))->autoUpload();

        $this->password('old_password', trans('admin.old_password'));

        $this->password('password', trans('admin.password'))
            ->minLength(5)
            ->maxLength(20)
            ->customFormat(function ($v) {
                if ($v == $this->password) {
                    return;
                }

                return $v;
            })
            ->help('請輸入5-20個字元');
        $this->password('password_confirmation', trans('admin.password_confirmation'))
            ->same('password')
            ->help('請輸入確認密碼');
    }
}

使用

$grid->user->display('View')->modal(UserProfile::make(['type' => 1]));

進度條 (progressBar)

$grid->rate->progressBar();

//設定顏色,預設`primary`,可選`danger`、`warning`、`info`、`primary`、`success`
$grid->rate->progressBar('success');

// 設定進度條尺寸和最大值
$grid->rate->progressBar('success', 'sm', 100);

showTreeInDialog#
showTreeInDialog 方法可以把一個帶有層級關係的陣列呈現為樹形彈窗,比如許可權就可以用此方法展示

// 查出所有的許可權資料
$nodes = (new $permissionModel)->allNodes();

// 傳入二維陣列(未分層級)
$grid->permissions->showTreeInDialog($nodes);

// 也可以傳入閉包
$grid->permissions->showTreeInDialog(function (Grid\Displayers\DialogTree $tree) use (&$nodes, $roleModel) {
    // 設定所有節點
    $tree->nodes($nodes);

    // 設定節點資料欄位名稱,預設"id","name","parent_id"
    $tree->setIdColumn('id');
    $tree->setTitleColumn('title');
    $tree->setParentColumn('parent_id');

    // $this->roles 可以獲取當前行的欄位值
    foreach (array_column($this->roles, 'slug') as $slug) {
        if ($roleModel::isAdministrator($slug)) {
            // 選中所有節點
            $tree->checkAll();
        }
    }
});

陣列操作
如果當前列輸出的是陣列,可以直接鏈式呼叫 Illuminate\Support\Collection 方法。

比如 tags 列是從一對多關係取出來的陣列資料:

$grid->tags();

array (
  0 => 
  array (
    'id' => '16',
    'name' => 'php',
    'created_at' => '2016-11-13 14:03:03',
    'updated_at' => '2016-12-25 04:29:35',

  ),
  1 => 
  array (
    'id' => '17',
    'name' => 'python',
    'created_at' => '2016-11-13 14:03:09',
    'updated_at' => '2016-12-25 04:30:27',
  ),
)
呼叫 Collection::pluck() 方法取出陣列的中的 name 列

$grid->tags()->pluck('name');

array (
    0 => 'php',
    1 => 'python',
  ),
比如 images 欄位是儲存多圖片地址陣列的 JSON 格式字串型別:


$grid->images();

// "['foo.jpg', 'bar.png']"

// 鏈式方法呼叫來顯示多圖
$grid->images()->display(function ($images) {
    return json_decode($images, true);

})->map(function ($path) {
    return 'http://localhost/images/'. $path;

})->image();
擴充套件類
如果列顯示邏輯比較複雜,可以透過擴充套件類來實現。

擴充套件類 app/Admin/Extensions/Popover.php:

<?php

namespace App\Admin\Extensions;

use Dcat\Admin\Admin;
use Dcat\Admin\Grid\Displayers\AbstractDisplayer;

class Popover extends AbstractDisplayer
{
    public function display($placement = 'left')
    {
        Admin::script("$('[data-toggle=\"popover\"]').popover()");

        return <<<EOT
<button type="button"
    class="btn btn-secondary"
    title="popover"
    data-container="body"
    data-toggle="popover"
    data-placement="$placement"
    data-content="{$this->value}"
    >
  彈出提示
</button>
EOT;

    }
}
然後在 app/Admin/bootstrap.php 註冊擴充套件類:

use Dcat\Admin\Grid\Column;
use App\Admin\Extensions\Popover;

Column::extend('popover', Popover::class);
Copy
然後就能在 model-grid 中使用了:

$grid->desciption()->popover('right');
切換行操作按鈕顯示方式
全域性預設的行操作按鈕顯示方式可以透過配置引數 admin.grid.grid_action_class 引數進行配置,目前支援的行操作按鈕顯示方式有以下兩種:

Dcat\Admin\Grid\Displayers\DropdownActions 下拉選單方式
Dcat\Admin\Grid\Displayers\Actions 圖示展開方式
Dcat\Admin\Grid\Displayers\ContextMenuActions 滑鼠右鍵顯示下拉選單 (Since v1.4.5)
    ...

    'grid' => [

        /*
        |--------------------------------------------------------------------------
        | The global Grid action display class.
        |--------------------------------------------------------------------------
        */
        'grid_action_class' => Dcat\Admin\Grid\Displayers\DropdownActions::class,
    ],

    ...
Copy
在控制器中切換顯示方式

use Dcat\Admin\Grid;

public function grid()
{
    return Grid(new Model(), function (Grid $grid) {
        $grid->setActionClass(Grid\Displayers\Actions::class);

        ...
    });
}
獲取行序號 (index)
序號從 0 開始計算

// 在 display 回撥中使用
$grid->column('序號')->display(function () {
    return $this->_index + 1;
});


// 在行操作 action 中使用
$grid->actions(function ($actions) {
    $index = $this->_index;

    ...
});
獲取當前行資料
可以透過傳入的 $actions 引數來獲取當前行的資料:

use Dcat\Admin\Grid;

$grid->actions(function (Grid\Displayers\Actions $actions) {
    // 當前行的資料陣列
    $rowArray = $actions->row->toArray();

    // 當前行的某個欄位的資料
    $email = $actions->row->email;

    // 獲取當前行主鍵值
    $id = $actions->getKey();
});
新增自定義按鈕
如果有自定義的操作按鈕,可以透過下面的方式新增:

use Dcat\Admin\Grid;

$grid->actions(function (Grid\Displayers\Actions $actions) {
    // append一個操作
    $actions->append('<a href=""><i class="fa fa-eye"></i></a>');

    // prepend一個操作
    $actions->prepend('<a href=""><i class="fa fa-paper-plane"></i></a>');
});
新增複雜操作按鈕
如果有比較複雜的操作,可以參考下面的方式:

先定義行操作類繼承 Dcat\Admin\Grid\RowAction

{tip} 動作類更詳細的用法,請參考動作基本使用以及資料表格動作。

<?php

namespace App\Admin\Extensions;

use Dcat\Admin\Grid\RowAction;

class CheckRow extends RowAction
{
    /**
     * 返回欄位標題
     * 
     * @return string
     */
    public function title()
    {
        return 'Check row';
    }

    /**
     * 新增JS
     * 
     * @return string
     */
    protected function script()
    {
        return <<<JS
$('.grid-check-row').on('click', function () {

    // Your code.
    console.log($(this).data('id'));

});
JS;
    }

    public function html()
    {
        // 獲取當前行資料ID
        $id = $this->getKey();

        // 獲取當前行資料的使用者名稱
        $username = $this->row->username;

        // 這裡需要新增一個class, 和上面script方法對應
        $this->setHtmlAttribute(['data-id' => $id, 'email' => $username, 'class' => 'grid-check-row']);

        return parent::html();
    }
}
然後新增操作:

$grid->actions(new CheckRow());

// 也可以透過這種方式新增
$grid->actions(function (Grid\Displayers\Actions $actions) {
    $actions->append(new CheckRow());
});
操作按鈕需要與 API 互動
如果你的操作類需要與後臺介面互動,則可以在你的操作類中加上 handle 方法,這樣就可以很方便的在同一個類裡面處理完所有邏輯

{tip} 動作類更詳細的用法,請參考動作基本使用以及資料表格動作。

<?php

namespace App\Admin\RowActions;

use Dcat\Admin\Grid\RowAction;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;

class Copy extends RowAction
{
    protected $model;

    public function __construct(string $model = null)
    {
        $this->model = $model;
    }

    /**
     * 標題
     *
     * @return string
     */
    public function title()
    {
        return 'Copy';
    }

    /**
     * 設定確認彈窗資訊,如果返回空值,則不會彈出彈窗
     *
     * 允許返回字串或陣列型別
     *
     * @return array|string|void
     */
    public function confirm()
    {
        return [
            // 確認彈窗 title
            "您確定要複製這行資料嗎?",
            // 確認彈窗 content
            $this->row->username,
        ];
    }

    /**
     * 處理請求
     *
     * @param Request $request
     *
     * @return \Dcat\Admin\Actions\Response
     */
    public function handle(Request $request)
    {
        // 獲取當前行ID
        $id = $this->getKey();

        // 獲取 parameters 方法傳遞的引數
        $username = $request->get('username');
        $model = $request->get('model');

        // 複製資料
        $model::find($id)->replicate()->save();

        // 返回響應結果並重新整理頁面
        return $this->response()->success("複製成功: [{$username}]")->refresh();
    }

    /**
     * 設定要POST到介面的資料
     *
     * @return array
     */
    public function parameters()
    {
        return [
            // 傳送當前行 username 欄位資料到介面
            'username' => $this->row->username,
            // 把模型類名傳遞到介面
            'model' => $this->model,
        ];
    }
}
使用

use App\Models\User;

$grid->actions([new Copy(User::class)]);

// 也可以透過這種方式新增
$grid->actions(function (Grid\Displayers\Actions $actions) {
    $actions->append(new Copy(User::class));
});

表單彈窗
請參考文件工具表單 - 彈窗

多對多#
users 和 roles 表透過中間表 role_users 產生多對多關係

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(190) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_username_unique` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `roles` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `slug` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `roles_name_unique` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `role_users` (
  `role_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  KEY `role_users_role_id_user_id_index` (`role_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
對應的資料模和資料倉儲分別為:

User 模型

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
}
Role 模型

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    public function users()
    {
        return $this->belongsToMany(User::class);
    }
}
資料倉儲

<?php

namespace App\Admin\Repositories;

use App\Models\User as UserModel;
use Dcat\Admin\Repositories\EloquentRepository;

class User extends EloquentRepository
{
    protected $eloquentClass = UserModel::class;
}
同樣這裡支援上述的三種方式關聯資料,限於篇幅這裡不再重複寫所有用法

use App\Admin\Repositories\User;

// 關聯 role 表資料
$grid = Grid::make(new User('roles'), function (Grid $grid) {
    $grid->id('ID')->sortable();
    $grid->username();
    $grid->name();

    $grid->roles()->pluck('name')->label();

    $grid->created_at();
    $grid->updated_at();
});
本作品採用《CC 協議》,轉載必須註明作者和本文連結