树状表格
<h1>树状表格</h1>
<p>树状表格支持分页和点击加载功能,特别适合用来展示数据量较大的多层级结构数据。</p>
<p><a href="<a href="http://103.39.211.179:8080/admin/tree"">http://103.39.211.179:8080/admin/tree"</a>; target="_blank">
<img class="img img-full" src="{{public}}/assets/img/screenshots/grid-tree.png">
</a></p>
<h3>表结构和模型</h3>
<p>要使用树状表格,要遵守约定的表结构:</p>
<p>> {tip} 此表结构和模型可完全兼容 <code><a href="model-tree.md">模型树</a></code> 。</p>
<pre><code class="language-sql">CREATE TABLE `demo_categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL DEFAULT '0',
`order` int(11) NOT NULL DEFAULT '0', // order 字段不是必须的,不设置也可以
`title` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci</code></pre>
<p>上面的表格结构里面有三个必要的字段<code>parent_id</code>、<code>title</code>,其它字段没有要求。</p>
<p>对应的模型为<code>app/Models/Category.php</code>:</p>
<p>> {tip} 为了便于阅读,这里不再展示 <code>Repository</code> 代码。</p>
<pre><code class="language-php">&lt;?php
namespace App\Models\Demo;
use Dcat\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use ModelTree;
protected $table = 'demo_categories';
}</code></pre>
<p>表结构中的三个字段<code>parent_id</code>、<code>order</code>、<code>title</code>的字段名也是可以修改的:</p>
<pre><code class="language-php">&lt;?php
namespace App\Models\Demo;
use Dcat\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use ModelTree;
protected $table = 'demo_categories';
protected $titleColumn = 'name';
protected $orderColumn = 'sort';
protected $parentColumn = 'pid';
}</code></pre>
<p>如果你的数据表不需要 <code>order</code> 字段排序,则在模型中添加如下代码即可</p>
<pre><code class="language-php">&lt;?php
namespace App\Models\Demo;
use Dcat\Admin\Traits\ModelTree;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use ModelTree;
protected $table = 'demo_categories';
// 返回空值即可禁用 order 字段
public function getOrderColumn()
{
return null;
}
}</code></pre>
<h3>使用</h3>
<p>通过调用 <code>Grid\Column::tree</code> 方法即可开启树状表格功能,开启之后默认只查询最顶级节点的数据,子节点数据需要点击加载</p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Controllers\Demo;
use App\Models\Category;
use Dcat\Admin\Grid;
use Dcat\Admin\Controllers\AdminController;
class CategoryController extends AdminController
{
protected function grid()
{
return Grid::make(new Category(), function (Grid $grid) {
$grid-&gt;id('ID')-&gt;bold()-&gt;sortable();
$grid-&gt;title-&gt;tree(); // 开启树状表格功能
$grid-&gt;order;
$grid-&gt;created_at;
$grid-&gt;updated_at-&gt;sortable();
$grid-&gt;filter(function (Grid\Filter $filter) {
$filter-&gt;like('slug');
$filter-&gt;like('name');
$filter-&gt;like('http_path');
});
});
}
}</code></pre>
<p>上面的代码执行的 <code>sql</code> 如下(默认只查询 <code>parent = 0</code> 的数据):</p>
<pre><code class="language-sql">select count(*) as aggregate from `demo_categories` where `parent_id` = 0
select * from `demo_categories` where `parent_id` = 0 order by `order` asc, `id` asc limit 20 offset 0</code></pre>
<p><code>Grid\Column::tree</code> 方法参数</p>
<ul>
<li><code>bool</code> <code>$showAll</code> <code>false</code> 是否一次性展示下一层级的所有节点,默认分页展示</li>
<li><code>bool</code> <code>$sortable</code> <code>true</code> 是否开启排序功能</li>
</ul>
<pre><code class="language-php">// 禁用分页功能,一次性加载所有下一层级节点
$grid-&gt;title-&gt;tree(true);
// 不需要 order 字段排序,第二个参数传 false 即可
$grid-&gt;title-&gt;tree(false, false);</code></pre>
<h3>orderable排序</h3>
<p><code>orderable</code> 排序功能依赖 <a href="<a href="https://github.com/spatie/eloquent-sortable"">https://github.com/spatie/eloquent-sortable"</a>; target="__blank">spatie/eloquent-sortable</a> 组件,需要修改模型:</p>
<pre><code class="language-php">use Spatie\EloquentSortable\Sortable;
class Category extends Model implements Sortable
{
use ModelTree;
// 设置排序字段,默认order
protected $orderColumn = 'sort';
}</code></pre>
<p>下面是使用示例</p>
<pre><code class="language-php">class CategoryController extends AdminController
{
protected function grid()
{
return Grid::make(new Category(), function (Grid $grid) {
$grid-&gt;id('ID')-&gt;bold()-&gt;sortable();
$grid-&gt;title-&gt;tree(); // 开启树状表格功能
$grid-&gt;order-&gt;orderable(); // 开启排序功能
...;
});
}
}</code></pre>
<h3>关于数据搜索</h3>
<p>如果在树状表格中使用了搜索功能(<code>Grid::filter</code>、<code>Grid\Column::filter</code>、<code>Grid::quickSearch</code>),为了让用户能搜索到想要的数据,则会<b>取消只查最顶级数据的操作</b>。</p>
<p>> {tip} 使用 <a href="model-grid-filters.md">查询过滤</a>、<a href="model-grid-column-filter.md">列过滤器</a>、<a href="model-grid-quick-search.md">快捷搜索</a> 等搜索功能都会<b>取消只查最顶级数据的操作</b>,只有 <a href="model-grid-selector.md">筛选器</a> 和 <a href="model-grid-filters.md#scope">范围查询scope</a> 等功能例外。</p>
<p>例如下面的代码开启了快捷搜索</p>
<pre><code class="language-php">class CategoryController extends AdminController
{
protected function grid()
{
return Grid::make(new Category(), function (Grid $grid) {
$grid-&gt;id('ID')-&gt;bold()-&gt;sortable();
$grid-&gt;title-&gt;tree(); // 开启树状表格功能
$grid-&gt;order-&gt;orderable(); // 开启排序功能
$grid-&gt;quickSearch(['id', 'title']);
...;
});
}
}</code></pre>
<p>且用户在浏览器中使用了快捷搜索,则产生<code>sql</code>如下</p>
<pre><code class="language-sql">select count(*) as aggregate from `demo_categories` where `id` like &quot;%xxx%&quot; or `title` like &quot;%xxx%&quot;
select * from `demo_categories` where `id` like &quot;%xxx%&quot; or `title` like &quot;%xxx%&quot; order by `order` asc, `id` asc limit 20 offset 0</code></pre>
<h3>与模型树功能的差别</h3>
<p><a href="model-tree.md">模型树</a>同样可用于展示多层级结构数据,并且支持用拖拽的方式实现数据的层级、排序等操作,但是不支持分页和点击加载功能,只能一次性加载完所有数据,
因此<a href="model-tree.md">模型树</a>并不适合用来展示数据量较大的数据。</p>
<p>而树状表格支持分页和点击加载功能,适合用来展示数据量较大的多层级结构数据,但不支持用拖拽的方式实现数据的层级、排序操作。</p>