列的显示和扩展

数据表格内置了很多对于列的操作方法,可以通过这些方法很灵活的操作列数据。

根据条件显示不同的组件

有些情况我们需要根据某个条件去判断是否使用列的某个显示功能:

{tip} 需要注意的是,Grid\Column::if只对列的显示相关功能有效,其他方法如表头的相关操作都不能使用此方法!

  1. $grid->column('config')
  2. ->if(function ($column) {
  3. // 获取当前行其他字段值
  4. $username = $this->username;
  5. // $column->getValue() 是当前字段的值
  6. return $column->getValue();
  7. })
  8. ->display($view)
  9. ->copyable()
  10. ->else()
  11. ->display('');

上面写法等同于

  1. $grid->column('config')
  2. ->if(function ($column) {
  3. return $column->getValue();
  4. })
  5. ->then(function (Grid\Column $column) {
  6. $column->display($view)->copyable();
  7. })
  8. ->else(function (Grid\Column $column) {
  9. $column->display('');
  10. });

支持多个if

  1. $grid->column('config')
  2. ->if(...)
  3. ->then(...)
  4. ->else(...)
  5. ->if(...)
  6. ->then(...)
  7. ->else(...);

终结条件判断end

  1. $grid->column('status')
  2. ->if(...) // 条件1
  3. ->display(...)
  4. ->display(...)
  5. ->if(...) // 条件2
  6. ->display(...)
  7. ->display(...)
  8. ->end() // 终结前面的条件判断
  9. ->display(...); // 所有条件都能生效

列显示

model-grid内置了若干方法来帮助你扩展列功能

display

Dcat\Admin\Grid\Column对象内置了display()方法来通过传入的回调函数来处理当前列的值,

  1. $grid->column('title')->display(function ($title) {
  2. return "<span style='color:blue'>$title</span>";
  3. });

在传入的匿名函数中可以通过任何方式对数据进行处理,另外匿名函数绑定了当前列的数据作为父对象,可以在函数中调用当前行的数据:

  1. $grid->column('first_name');
  2. $grid->column('last_name');
  3. // 不存在的`full_name`字段
  4. $grid->column('full_name')->display(function () {
  5. return $this->first_name . ' ' . $this->last_name;
  6. });

设置列的HTML属性

设列的html属性

  1. $grid->column('name')->setAttributes(['style' => 'font-size:14px']);

列视图

view方法可以引入一个视图文件。

  1. $grid->column('content')->view('admin.fields.content');

默认会传入视图的三个变量:

  • $model 当前行数据
  • $name 字段名称
  • $value 为当前列的值

模板代码如下:

  1. <label>名称:{{ $name }}</label>
  2. <label>值:{{ $value }}</label>
  3. <label>其他字段:{{ $model->title }}</label>

图片

  1. $grid->column('picture')->image();
  2. //设置服务器和宽高
  3. $grid->column('picture')->image('http://xxx.com', 100, 100);
  4. // 显示多图
  5. $grid->column('pictures')->display(function ($pictures) {
  6. return json_decode($pictures, true);
  7. })->image('http://xxx.com', 100, 100);

显示label标签

支持Dcat\Admin\Color类中内置的所有颜色

  1. use Dcat\Admin\Admin;
  2. $grid->column('name')->label();
  3. // 设置颜色,直接传别名
  4. $grid->column('name')->label('danger');
  5. // 也可以这样使用
  6. $grid->column('name')->label(Admin::color()->danger());
  7. // 也可以直接传颜色代码
  8. $grid->column('name')->label('#222');

给不同的值设置不同的颜色

  1. use Dcat\Admin\Admin;
  2. $grid->column('state')->using([1 => '未处理', 2 => '已处理', ...])->label([
  3. 'default' => 'primary', // 设置默认颜色,不设置则默认为 default
  4. 1 => 'primary',
  5. 2 => 'danger',
  6. 3 => 'success',
  7. 4 => Admin::color()->info(),
  8. ]);

显示badge标签

支持Dcat\Admin\Color类中内置的所有颜色

  1. $grid->column('name')->badge();
  2. // 设置颜色,直接传别名
  3. $grid->column('name')->badge('danger');
  4. // 也可以这样使用
  5. $grid->column('name')->badge(Admin::color()->danger());
  6. // 也可以直接传颜色代码
  7. $grid->column('name')->badge('#222');

给不同的值设置不同的颜色

  1. use Dcat\Admin\Admin;
  2. $grid->state->using([1 => '未处理', 2 => '已处理', ...])->badge([
  3. 'default' => 'primary', // 设置默认颜色,不设置则默认为 default
  4. 1 => 'primary',
  5. 2 => 'danger',
  6. 3 => 'success',
  7. 4 => Admin::color()->info(),
  8. ]);

布尔值显示 (bool)

将这一列转为bool值之后显示为

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

你也可以按照这一列的值指定显示,比如字段的值为YN表示truefalse

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

效果 列的显示和扩展 - 图1

圆点前缀 (dot)

通过dot方法可以在列文字前面加上一个带颜色的圆点

  1. use Dcat\Admin\Admin;
  2. $grid->column('state')
  3. ->using([1 => '未处理', 2 => '已处理', ...])
  4. ->dot(
  5. [
  6. 1 => 'primary',
  7. 2 => 'danger',
  8. 3 => 'success',
  9. 4 => Admin::color()->info(),
  10. ],
  11. 'primary' // 第二个参数为默认值
  12. );

效果 列的显示和扩展 - 图2

列展开 (expand)

expand方法可以把内容隐藏,点击按钮的时候显示在表格下一行

  1. $grid->column('content')
  2. ->display('详情') // 设置按钮名称
  3. ->expand(function () {
  4. // 返回显示的详情
  5. // 这里返回 content 字段内容,并用 Card 包裹起来
  6. $card = new Card(null, $this->content);
  7. return "<div style='padding:10px 10px 0'>$card</div>";
  8. });

也可以通过以下方式设置按钮

  1. $grid->column('content')->expand(function (Grid\Displayers\Expand $expand) {
  2. // 设置按钮名称
  3. $expand->button('详情');
  4. // 返回显示的详情
  5. // 这里返回 content 字段内容,并用 Card 包裹起来
  6. $card = new Card(null, $this->content);
  7. return "<div style='padding:10px 10px 0'>$card</div>";
  8. });

异步加载

{tip} 更多用法请参考文档异步加载

定义渲染类,继承Dcat\Admin\Support\LazyRenderable

  1. use App\Models\Post as PostModel;
  2. use Dcat\Admin\Support\LazyRenderable;
  3. use Dcat\Admin\Widgets\Table;
  4. class Post extends LazyRenderable
  5. {
  6. public function render()
  7. {
  8. // 获取ID
  9. $id = $this->key;
  10. // 获取其他自定义参数
  11. $type = $this->post_type;
  12. $data = PostModel::where('user_id', $id)
  13. ->where('type', $type)
  14. ->get(['title', 'body', 'body', 'created_at'])
  15. ->toArray();
  16. $titles = [
  17. 'User ID',
  18. 'Title',
  19. 'Body',
  20. 'Created At',
  21. ];
  22. return Table::make($titles, $data);
  23. }
  24. }

使用

  1. $grid->post->display('View')->expand(Post::make(['post_type' => 1]));
  2. // 可以在闭包内返回异步加载类的实例
  3. $grid->post->expand(function () {
  4. // 允许在比包内返回异步加载类的实例
  5. return Post::make(['title' => $this->title]);
  6. });

效果

列的显示和扩展 - 图3

异步加载工具表单

定义工具表单类如下

{tip} 更多用法请参考异步加载

  1. <?php
  2. namespace App\Admin\Forms;
  3. use Dcat\Admin\Contracts\LazyRenderable;
  4. use Dcat\Admin\Traits\LazyWidget;
  5. use Dcat\Admin\Widgets\Form;
  6. class UserProfile extends Form implements LazyRenderable
  7. {
  8. use LazyWidget;
  9. public function handle(array $input)
  10. {
  11. // 接收外部传递参数
  12. $type = $this->payload['type'] ?? null;
  13. return $this->response()->success('保存成功');
  14. }
  15. public function form()
  16. {
  17. // 接收外部传递参数
  18. $type = $this->payload['type'] ?? null;
  19. $this->text('name', trans('admin.name'))->required()->help('用户昵称');
  20. $this->image('avatar', trans('admin.avatar'))->autoUpload();
  21. $this->password('old_password', trans('admin.old_password'));
  22. $this->password('password', trans('admin.password'))
  23. ->minLength(5)
  24. ->maxLength(20)
  25. ->customFormat(function ($v) {
  26. if ($v == $this->password) {
  27. return;
  28. }
  29. return $v;
  30. })
  31. ->help('请输入5-20个字符');
  32. $this->password('password_confirmation', trans('admin.password_confirmation'))
  33. ->same('password')
  34. ->help('请输入确认密码');
  35. }
  36. }

使用

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

弹出模态框 (modal)

modal方法可以把内容隐藏,点击按钮的时候显示在表格下一行

  1. $grid->column('content')
  2. ->display('查看') // 设置按钮名称
  3. ->modal(function ($modal) {
  4. // 设置弹窗标题
  5. $modal->title('标题 '.$this->username);
  6. // 自定义图标
  7. $modal->icon('feather icon-x');
  8. $card = new Card(null, $this->content);
  9. return "<div style='padding:10px 10px 0'>$card</div>";
  10. });
  11. // 也可以通过这种方式设置弹窗标题
  12. $grid->column('content')
  13. ->display('查看') // 设置按钮名称
  14. ->modal('弹窗标题', ...);

异步加载

{tip} 关于异步加载的更具体用法,请参考文档异步加载

定义渲染类,继承Dcat\Admin\Support\LazyRenderable

  1. use App\Models\Post as PostModel;
  2. use Dcat\Admin\Support\LazyRenderable;
  3. use Dcat\Admin\Widgets\Table;
  4. class Post extends LazyRenderable
  5. {
  6. public function render()
  7. {
  8. // 获取ID
  9. $id = $this->key;
  10. // 获取其他自定义参数
  11. $type = $this->post_type;
  12. $data = PostModel::where('user_id', $id)
  13. ->where('type', $type)
  14. ->get(['title', 'body', 'body', 'created_at'])
  15. ->toArray();
  16. $titles = [
  17. 'User ID',
  18. 'Title',
  19. 'Body',
  20. 'Created At',
  21. ];
  22. return Table::make($titles, $data);
  23. }
  24. }

使用

  1. $grid->post->display('View')->modal('Post', Post::make(['post_type' => 2]));
  2. // 可以在闭包内返回异步加载类的实例
  3. $grid->post->modal(function ($modal) {
  4. $modal->title('自定义弹窗标题');
  5. // 允许在比包内返回异步加载类的实例
  6. return Post::make(['title' => $this->title]);
  7. });

效果 列的显示和扩展 - 图4

异步加载工具表单

定义工具表单类如下

{tip} 更多用法请参考异步加载

  1. <?php
  2. namespace App\Admin\Forms;
  3. use Dcat\Admin\Contracts\LazyRenderable;
  4. use Dcat\Admin\Traits\LazyWidget;
  5. use Dcat\Admin\Widgets\Form;
  6. class UserProfile extends Form implements LazyRenderable
  7. {
  8. use LazyWidget;
  9. public function handle(array $input)
  10. {
  11. // 接收外部传递参数
  12. $type = $this->payload['type'] ?? null;
  13. return $this->response()->success('保存成功');
  14. }
  15. public function form()
  16. {
  17. // 接收外部传递参数
  18. $type = $this->payload['type'] ?? null;
  19. $this->text('name', trans('admin.name'))->required()->help('用户昵称');
  20. $this->image('avatar', trans('admin.avatar'))->autoUpload();
  21. $this->password('old_password', trans('admin.old_password'));
  22. $this->password('password', trans('admin.password'))
  23. ->minLength(5)
  24. ->maxLength(20)
  25. ->customFormat(function ($v) {
  26. if ($v == $this->password) {
  27. return;
  28. }
  29. return $v;
  30. })
  31. ->help('请输入5-20个字符');
  32. $this->password('password_confirmation', trans('admin.password_confirmation'))
  33. ->same('password')
  34. ->help('请输入确认密码');
  35. }
  36. }

使用

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

进度条 (progressBar)

progressBar进度条

  1. $grid->rate->progressBar();
  2. //设置颜色,默认`primary`,可选`danger`、`warning`、`info`、`primary`、`success`
  3. $grid->rate->progressBar('success');
  4. // 设置进度条尺寸和最大值
  5. $grid->rate->progressBar('success', 'sm', 100);

showTreeInDialog

showTreeInDialog方法可以把一个带有层级关系的数组呈现为树形弹窗,比如权限就可以用此方法展示

  1. // 查出所有的权限数据
  2. $nodes = (new $permissionModel)->allNodes();
  3. // 传入二维数组(未分层级)
  4. $grid->permissions->showTreeInDialog($nodes);
  5. // 也可以传入闭包
  6. $grid->permissions->showTreeInDialog(function (Grid\Displayers\DialogTree $tree) use (&$nodes, $roleModel) {
  7. // 设置所有节点
  8. $tree->nodes($nodes);
  9. // 设置节点数据字段名称,默认"id","name","parent_id"
  10. $tree->setIdColumn('id');
  11. $tree->setTitleColumn('title');
  12. $tree->setParentColumn('parent_id');
  13. // $this->roles 可以获取当前行的字段值
  14. foreach (array_column($this->roles, 'slug') as $slug) {
  15. if ($roleModel::isAdministrator($slug)) {
  16. // 选中所有节点
  17. $tree->checkAll();
  18. }
  19. }
  20. });

列的显示和扩展 - 图5

内容映射 (using)

  1. $grid->status->using([0 => '未激活', 1 => '正常']);
  2. // 第二个参数为默认值
  3. $grid->gender->using([1 => '男', 2 => '女'], '未知');

字符串分割为数组

explode方法可以把字符串分割为数组。

  1. $grid->tag->explode()->label();
  2. // 可以指定分隔符,默认","
  3. $grid->tag->explode('|')->label();

prepend

prepend 方法用于给 stringarray 类型的值前面插入内容。

  1. // 当字段值是一个字符串
  2. $grid->email->prepend('mailto:');
  3. // 当字段值是一个数组
  4. $grid->arr->prepend('first item');

prepend方法允许传入闭包参数

  1. $grid->email->prepend(function ($value, $original) {
  2. // $value 是当前字段值
  3. // $original 是当前字段从数据库中查询出来的原始值
  4. // 获取其他字段值
  5. $username = $this->username;
  6. return "[{$username}]";
  7. });

append

append 方法用于给 stringarray 类型的值后面插入内容。

  1. // 当字段值是一个字符串
  2. $grid->email->append('@gmail.com');
  3. // 当字段值是一个数组
  4. $grid->arr->append('last item');

append方法允许传入闭包参数

  1. $grid->email->append(function ($value, $original) {
  2. // $value 是当前字段值
  3. // $original 是当前字段从数据库中查询出来的原始值
  4. // 获取其他字段值
  5. $username = $this->username;
  6. return "[{$username}]";
  7. });

字符串或数组截取 (limit)

  1. // 最多显示50个字符
  2. $grid->column('content')->limit(50, '...');
  3. // 如果字段值是数组也支持
  4. $grid->tags->limit(3);

列二维码 (qrcode)

  1. $grid->website->qrcode(function () {
  2. return $this->url;
  3. }, 200, 200);

可复制 (copyable)

  1. $grid->website->copyable();

可排序 (orderable)

通过Column::orderable可以开启字段可排序功能,此功能需要在你的模型类中use ModelTreeuse SortableTrait,并且需要继承Spatie\EloquentSortable\Sortable接口。

SortableTrait

如果你的数据不是层级结构数据,可以直接使用use SortableTrait,更多用法可参考eloquent-sortable

模型

  1. <?php
  2. namespace App\Models;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Spatie\EloquentSortable\Sortable;
  5. use Spatie\EloquentSortable\SortableTrait;
  6. class MyModel extends Model implements Sortable
  7. {
  8. use SortableTrait;
  9. protected $sortable = [
  10. // 设置排序字段名称
  11. 'order_column_name' => 'order',
  12. // 是否在创建时自动排序,此参数建议设置为true
  13. 'sort_when_creating' => true,
  14. ];
  15. }

使用

  1. $grid->model()->orderBy('order');
  2. $grid->order->orderable();

ModelTree

如果你的数据是层级结构数据,可以直接使用use Model,下面以权限模型为例来演示用法

{tip} ModelTree实际上也是继承了eloquent-sortable的功能。

  1. <?php
  2. namespace Dcat\Admin\Models;
  3. use Dcat\Admin\Traits\HasDateTimeFormatter;
  4. use Dcat\Admin\Traits\ModelTree;
  5. use Spatie\EloquentSortable\Sortable;
  6. class Permission extends Model implements Sortable
  7. {
  8. use HasDateTimeFormatter,
  9. ModelTree {
  10. ModelTree::boot as treeBoot;
  11. }
  12. ...
  13. }

使用

  1. $grid->order->orderable();

链接 (link)

将字段显示为一个链接。

  1. // link方法不传参数时,链接的`href`和`text`都是当前列的值
  2. $grid->column('homepage')->link();
  3. // 传入闭包
  4. $grid->column('homepage')->link(function ($value) {
  5. return admin_url('users/'.$value);
  6. });

行操作 (action)

{tip} 在使用这个方法之前,请先阅读自定义操作-行操作

这个功能可以将某一列显示为一个行操作的按钮,比如下面所示是一个标星和取消标星的列操作, 点击这一列的星标图标之后, 后台会切换字段的状态,页面图标也跟着切换,具体实现代码如下:

  1. <?php
  2. namespace App\Admin\Extensions\Grid\RowAction;
  3. use Dcat\Admin\Grid\RowAction;
  4. use Illuminate\Http\Request;
  5. class Star extends RowAction
  6. {
  7. protected function html()
  8. {
  9. $icon = ($this->row->{$this->getColumnName()}) ? 'fa-star' : 'fa-star-o';
  10. return <<<HTML
  11. <i class="{$this->getElementClass()} fa {$icon}"></i>
  12. HTML;
  13. }
  14. public function handle(Request $request)
  15. {
  16. try {
  17. $class = $request->class;
  18. $column = $request->column;
  19. $id = $this->getKey();
  20. $model = $class::find($id);
  21. $model->{$column} = (int) !$model->{$column};
  22. $model->save();
  23. return $this->response()->success("success")->refresh();
  24. } catch (\Exception $e) {
  25. return $this->response()->error($e->getMessage());
  26. }
  27. }
  28. public function parameters()
  29. {
  30. return [
  31. 'class' => $this->modelClass(),
  32. 'column' => $this->getColumnName(),
  33. ];
  34. }
  35. public function getColumnName()
  36. {
  37. return $this->column->getName();
  38. }
  39. public function modelClass()
  40. {
  41. return get_class($this->parent->model()->repository()->model());
  42. }
  43. }

使用

  1. protected function grid()
  2. {
  3. $grid = new Grid(new $this->model());
  4. $grid->column('star', '-')->action(Star::class); // here
  5. $grid->column('id', 'ID')->sortable()->bold();
  6. return $grid;
  7. }

效果

列的显示和扩展 - 图6

帮助方法

字符串操作

如果当前里的输出数据为字符串,那么可以通过链式方法调用Illuminate\Support\Str的方法。

比如有如下一列,显示title字段的字符串值:

  1. $grid->title();

title列输出的字符串基础上调用Str::title()方法

  1. $grid->title()->title();

调用方法之后输出的还是字符串,所以可以继续调用Illuminate\Support\Str的方法:

  1. $grid->title()->title()->ucfirst();
  2. $grid->title()->title()->ucfirst()->substr(1, 10);

数组操作

如果当前列输出的是数组,可以直接链式调用Illuminate\Support\Collection方法。

比如tags列是从一对多关系取出来的数组数据:

  1. $grid->tags();
  2. array (
  3. 0 =>
  4. array (
  5. 'id' => '16',
  6. 'name' => 'php',
  7. 'created_at' => '2016-11-13 14:03:03',
  8. 'updated_at' => '2016-12-25 04:29:35',
  9. ),
  10. 1 =>
  11. array (
  12. 'id' => '17',
  13. 'name' => 'python',
  14. 'created_at' => '2016-11-13 14:03:09',
  15. 'updated_at' => '2016-12-25 04:30:27',
  16. ),
  17. )

调用Collection::pluck()方法取出数组的中的name

  1. $grid->tags()->pluck('name');
  2. array (
  3. 0 => 'php',
  4. 1 => 'python',
  5. ),

取出name列之后输出的还是数组,还能继续调用用Illuminate\Support\Collection的方法

  1. $grid->tags()->pluck('name')->map('ucwords');
  2. array (
  3. 0 => 'Php',
  4. 1 => 'Python',
  5. ),

将数组输出为字符串

  1. $grid->tags()->pluck('name')->map('ucwords')->implode('-');
  2. "Php-Python"

混合使用

在上面两种类型的方法调用中,只要上一步输出的是确定类型的值,便可以调用类型对应的方法,所以可以很灵活的混合使用。

比如images字段是存储多图片地址数组的JSON格式字符串类型:

  1. $grid->images();
  2. // "['foo.jpg', 'bar.png']"
  3. // 链式方法调用来显示多图
  4. $grid->images()->display(function ($images) {
  5. return json_decode($images, true);
  6. })->map(function ($path) {
  7. return 'http://localhost/images/'. $path;
  8. })->image();

扩展列的显示功能

可以通过两种方式扩展列功能,第一种是通过匿名函数的方式。

扩展列功能方法后IDE默认是不会自动补全的,这时候可以通过php artisan admin:ide-helper生成IDE提示文件。

匿名函数

app/Admin/bootstrap.php加入以下代码:

  1. use Dcat\Admin\Grid\Column;
  2. // 第二个参数是自定义参数
  3. Column::extend('color', function ($value, $color) {
  4. return "<span style='color: $color'>$value</span>";
  5. });

然后在model-grid中使用这个扩展:

  1. $grid->title()->color('#ccc');

扩展类

如果列显示逻辑比较复杂,可以通过扩展类来实现。

扩展类app/Admin/Extensions/Popover.php:

  1. <?php
  2. namespace App\Admin\Extensions;
  3. use Dcat\Admin\Admin;
  4. use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
  5. class Popover extends AbstractDisplayer
  6. {
  7. public function display($placement = 'left')
  8. {
  9. Admin::script("$('[data-toggle=\"popover\"]').popover()");
  10. return <<<EOT
  11. <button type="button"
  12. class="btn btn-secondary"
  13. title="popover"
  14. data-container="body"
  15. data-toggle="popover"
  16. data-placement="$placement"
  17. data-content="{$this->value}"
  18. >
  19. 弹出提示
  20. </button>
  21. EOT;
  22. }
  23. }

然后在app/Admin/bootstrap.php注册扩展类:

  1. use Dcat\Admin\Grid\Column;
  2. use App\Admin\Extensions\Popover;
  3. Column::extend('popover', Popover::class);

然后就能在model-grid中使用了:

  1. $grid->desciption()->popover('right');

指定列名

出了上述两种方式扩展列功能,我们还可以通过指定列名称的方式扩展列功能

app/Admin/bootstrap.php加入以下代码:

  1. use Dcat\Admin\Grid\Column;
  2. // 这个扩展方法等同于
  3. // $grid->title()->display(function ($value) {
  4. // return "<span style='color:red'>$value</span>"
  5. // });
  6. Column::define('title', function ($value) {
  7. return "<span style='color:red'>$value</span>"
  8. });
  9. // 这个扩展方法等同于
  10. // $grid->status()->switch();
  11. Column::define('status', Dcat\Admin\Grid\Displayers\SwitchDisplay::class);

然后在model-gridtitlestatus字段会自动使用以上扩展:

  1. $grid->title();
  2. $grid->status();