关于 unopim-datagrid
面向 UnoPim 管理后台数据网格和列表页开发的仓库专用技能,说明查询、列、操作、本地化及 Blade 约定,并提供参考实现。
主要功能
- 01数据网格结构与查询规则
- 02列和操作的配置要求
- 03操作的权限检查
- 04HTML 转义与标签翻译
- 05控制器和列表 Blade 模式
适用场景
- 01实现管理后台列表网格
- 02添加受权限控制的行或批量操作
- 03创建模块列表页
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ unopim/ agent-skills --skill unopim-datagrid安装后在 Claude Code 中输入/unopim-datagrid确认已加载。
详细介绍
UnoPim DataGrid
参照以下示例复制其结构——切勿臆造引擎 API:
- Grid 类:
packages/Webkul/AiAgent/src/DataGrids/Credential/CredentialDataGrid.php - 批量操作:
packages/Webkul/Admin/src/DataGrids/Catalog/ProductDataGrid.php - 列表 Blade:
packages/Webkul/Webhook/src/Resources/views/webhooks/index.blade.php - 带前缀的原始 SQL:
packages/Webkul/Measurement/src/DataGrids/UnitDataGrid.php
规则
- Grid 位于子目录中——
src/DataGrids/{Section}/{Name}DataGrid.php——并继承Webkul\DataGrid\DataGrid。 prepareQueryBuilder()必须使用DB::table()和不带前缀的表名(Laravel 会应用env('DB_PREFIX', ''))。此处绝不要查询 Eloquent 模型。- 任何命名表的原始片段(
selectRaw、whereRaw、orderByRaw、DB::raw)都必须添加DB::getTablePrefix()前缀——参见packages/Webkul/Measurement/src/DataGrids/UnitDataGrid.php。CI 同时运行 MySQL 和 PostgreSQL:不得使用仅适用于 MySQL 的 SQL(GROUP_CONCAT、反引号、DATE_FORMAT)。 addColumn()必须设置全部六个键——index、label、type、searchable、filterable、sortable。引擎读取这三个标志时不会使用 null 合并;省略任何一个都会在请求时触发「Undefined array key」。- 钩子签名:抽象基类中的
prepareColumns()/prepareActions()没有类型声明,因此仅含 PHPDoc@return的写法(较旧的 Admin Grid)和: void(较新的 Grid,包括 Credential 示例)都能编译。新代码请写: void;编辑时遵循现有风格。绝不要将任一种风格判定为违规。 - 操作的
url接受任何可调用对象——优先使用fn ($row): string => route(...)。批量操作的url必须是普通的route(...)字符串,不能是可调用对象。 - 每个操作和批量操作都必须通过
bouncer()->hasPermission()进行权限检查。批量操作 ACL 键使用 snake_case({module-slug}.credentials.mass_delete),并与路由名称一致——绝不要使用带连字符的形式(mass-delete)。 - 列
closure的输出会作为原始 HTML 渲染;引擎只会对纯字符串单元格执行strip_tags()。在closureHTML 中插入的任何用户提供值都必须使用e()转义。 - 每个标签和标题都使用
trans(),并先将键添加到en_US,再添加到全部 33 个语言区域设置中。布尔徽章:label-active(true)、label-info text-gray-600 dark:text-gray-300(false)。 - 方法体或数组字面量中不得有注释。方法 PHPDoc 必须是单行祈使式摘要;仅在没有原生返回类型时使用
@return。
Grid 类
<?php
namespace Webkul\{ModuleName}\DataGrids\Credential;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Webkul\DataGrid\DataGrid;
class CredentialDataGrid extends DataGrid
{
/**
* Prepare query builder.
*
* @return Builder
*/
public function prepareQueryBuilder()
{
return DB::table('{module}_credentials')
->select('id', 'label', 'status', 'created_at');
}
/**
* Prepare columns.
*/
public function prepareColumns(): void
{
$this->addColumn([
'index' => 'label',
'label' => trans('{module-name}::app.credentials.datagrid.label'),
'type' => 'string',
'searchable' => true,
'filterable' => true,
'sortable' => true,
]);
$this->addColumn([
'index' => 'status',
'label' => trans('{module-name}::app.credentials.datagrid.status'),
'type' => 'boolean',
'searchable' => false,
'filterable' => true,
'sortable' => true,
'closure' => fn ($row): string => $row->status
? '<span class="label-active">'.trans('admin::app.common.yes').'</span>'
: '<span class="label-info text-gray-600 dark:text-gray-300">'.trans('admin::app.common.no').'</span>',
]);
}
/**
* Prepare actions.
*/
public function prepareActions(): void
{
if (bouncer()->hasPermission('{module-slug}.credentials.edit')) {
$this->addAction([
'icon' => 'icon-edit',
'title' => trans('{module-name}::app.credentials.datagrid.edit'),
'method' => 'GET',
'url' => fn ($row): string => route('{module-slug}.credentials.edit', $row->id),
]);
}
if (bouncer()->hasPermission('{module-slug}.credentials.delete')) {
$this->addAction([
'icon' => 'icon-delete',
'title' => trans('{module-name}::app.credentials.datagrid.delete'),
'method' => 'DELETE',
'url' => fn ($row): string => route('{module-slug}.credentials.destroy', $row->id),
]);
}
}
/**
* Prepare mass actions.
*/
public function prepareMassActions(): void
{
if (bouncer()->hasPermission('{module-slug}.credentials.mass_delete')) {
$this->addMassAction([
'title' => trans('{module-name}::app.credentials.datagrid.delete'),
'url' => route('{module-slug}.credentials.mass_delete'),
'method' => 'POST',
'options' => ['actionType' => 'delete'],
]);
}
}
}
对于状态批量更新,请从 packages/Webkul/Admin/src/DataGrids/Catalog/ProductDataGrid.php 中的 catalog.products.mass_update 块复制 options 标签/值对数组。
控制器
public function index()
{
if (request()->ajax()) {
return resolve(CredentialDataGrid::class)->toJson();
}
return view('{module-name}::credentials.index');
}
列表 Blade
admin::layouts.master 和 @extends 不存在——admin 布局是一个组件。创建操作是在索引页上的模态框,其 store() 会重定向到编辑页(从 Webhook 示例复制 v-create-webhook-form);不要添加 GET 创建页面。
<x-admin::layouts>
<x-slot:title>
@lang('{module-name}::app.credentials.index.title')
</x-slot>
<x-admin::layouts.page-header :title="trans('{module-name}::app.credentials.index.title')" />
<x-admin::datagrid :src="route('{module-slug}.credentials.index')" />
</x-admin::layouts>
评论
支持 Markdown