动作基本使用
<h1>动作基本使用</h1>
<p>开发者通过 <code>Action</code> 动作类可以非常方便的开发出一个含有特定功能的操作,可以非常方便的让用户与服务器产生交互。</p>
<p>例如,页面上需要一个按钮,用户点击之后可以向服务器发起请求,通过弹窗展示当前登录用户的信息,那么这个功能按钮就可以用 <code>Action</code> 来开发。</p>
<h2>示例</h2>
<p>下面我们就开始开发一个用于查看登录用户信息的按钮:</p>
<h3>使用命令创建Action类</h3>
<p>首先需要先创建 <code>Action</code> 类,运行命令</p>
<pre><code class="language-bash">php artisan admin:action</code></pre>
<p>运行成功之后会看到命令窗口出现如下信息,让开发者选择一个 <code>Action</code> 类的类型,这里我们输入 <code>0</code> 就行</p>
<p>> {tip} <code>default</code>类型的动作类,可以用在页面的任意位置。</p>
<pre><code class="language-bash"> Which type of action would you like to make?:
[0] default
[1] grid-batch
[2] grid-row
[3] grid-tool
[4] form-tool
[5] show-tool
[6] tree-tool
&gt; 0 # 输入 0
</code></pre>
<p>接着输入 <code>Action</code> 类名称,这里需要输入 <code>大驼峰</code> 风格的英文字母</p>
<pre><code class="language-bash">
Please enter a name of action class:
&gt; ShowCurrentAdminUser
</code></pre>
<p>类名输入完成之后会出现以下信息让开发者输入类的命名空间,默认的命名空间是 <code>App\Admin\Actions</code>,这里我们直接按回车跳过就行了</p>
<pre><code class="language-bash">
Please enter the namespace of action class [App\Admin\Actions]:
&gt;
</code></pre>
<p>这样一个 <code>Action</code> 类就创建完成了,刚刚创建的类路径是 <code>app/Admin/Actions/ShowCurrentAdminUser.php</code></p>
<h3>使用</h3>
<p>修改 <code>Action</code> 类如下</p>
<p>> {tip} 如果你的动作类中需要通过构造方法传递参数,则一定要给构造方法的所有参数都设置一个默认值!</p>
<pre><code class="language-php">&lt;?php
namespace App\Admin\Actions;
use Dcat\Admin\Admin;
use Dcat\Admin\Widgets\Table;
use Dcat\Admin\Actions\Action;
use Dcat\Admin\Actions\Response;
use Dcat\Admin\Traits\HasPermissions;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class ShowCurrentAdminUser extends Action
{
/**
* 按钮标题
*
* @var string
*/
protected $title = '个人信息';
/**
* @var string
*/
protected $modalId = 'show-current-user';
/**
* 处理当前动作的请求接口,如果不需要请直接删除
*
* @param Request $request
*
* @return Response
*/
public function handle(Request $request)
{
// 获取当前登录用户模型
$user = Admin::user();
// 这里我们用表格展示模型数据
$table = Table::make($user-&gt;toArray());
return $this-&gt;response()
-&gt;success('查询成功')
-&gt;html($table);
}
/**
* 处理响应的HTML字符串,附加到弹窗节点中
*
* @return string
*/
protected function handleHtmlResponse()
{
return &lt;&lt;&lt;'JS'
function (target, html, data) {
var $modal = $(target.data('target'));
$modal.find('.modal-body').html(html)
$modal.modal('show')
}
JS;
}
/**
* 设置HTML标签的属性
*
* @return void
*/
protected function setupHtmlAttributes()
{
// 添加class
$this-&gt;addHtmlClass('btn btn-primary');
// 保存弹窗的ID
$this-&gt;setHtmlAttribute('data-target', '#'.$this-&gt;modalId);
parent::setupHtmlAttributes();
}
/**
* 设置按钮的HTML,这里我们需要附加上弹窗的HTML
*
* @return string|void
*/
public function html()
{
// 按钮的html
$html = parent::html();
return &lt;&lt;&lt;HTML
{$html}
&lt;div class=&quot;modal fade&quot; id=&quot;{$this-&gt;modalId}&quot; tabindex=&quot;-1&quot; role=&quot;dialog&quot;&gt;
&lt;div class=&quot;modal-dialog modal-lg&quot; role=&quot;document&quot;&gt;
&lt;div class=&quot;modal-content&quot;&gt;
&lt;div class=&quot;modal-header&quot;&gt;
&lt;button type=&quot;button&quot; class=&quot;close&quot; data-dismiss=&quot;modal&quot; aria-label=&quot;Close&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&amp;times;&lt;/span&gt;&lt;/button&gt;
&lt;h4 class=&quot;modal-title&quot;&gt;{$this-&gt;title()}&lt;/h4&gt;
&lt;/div&gt;
&lt;div class=&quot;modal-body&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
HTML;
}
/**
* 确认弹窗信息,如不需要可以删除此方法
*
* @return string|void
*/
public function confirm()
{
// return ['Confirm?', 'contents'];
}
/**
* 动作权限判断,返回false则表示无权限,如果不需要可以删除此方法
*
* @param Model|Authenticatable|HasPermissions|null $user
*
* @return bool
*/
protected function authorize($user): bool
{
return true;
}
/**
* 通过这个方法可以设置动作发起请求时需要附带的参数,如果不需要可以删除此方法
*
* @return array
*/
protected function parameters()
{
return [];
}
}</code></pre>
<p>修改完之后就可以开始使用了</p>
<pre><code class="language-php">&lt;?php
use App\Admin\Actions\ShowCurrentAdminUser;
class IndexController
{
public function index(Content $content)
{
return $content-&gt;body(ShowCurrentAdminUser::make());
}
}</code></pre>
<p>效果如下</p>
<p><a href="{{public}}/assets/img/screenshots/action-default.png" target="_blank">
<img class="img img-full" src="{{public}}/assets/img/screenshots/action-default.png" />
</a></p>
<h2>属性</h2>
<p><code>Dcat\Admin\Actions\Action</code> 类可用属性说明</p>
<table>
<thead>
<tr>
<th>属性名</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>title</td>
<td><code>string</code></td>
<td></td>
<td>标题</td>
</tr>
<tr>
<td>selectorPrefix</td>
<td><code>public</code> <code>string</code></td>
<td><code>.admin-action-</code></td>
<td>目标元素的<code>Css</code>选择器</td>
</tr>
<tr>
<td>method</td>
<td><code>string</code></td>
<td><code>POST</code></td>
<td>与服务器交互的请求方法</td>
</tr>
<tr>
<td>event</td>
<td><code>string</code></td>
<td><code>click</code></td>
<td>目标元素绑定的事件,默认为点击事件</td>
</tr>
<tr>
<td>disabled</td>
<td><code>bool</code></td>
<td><code>false</code></td>
<td>是否渲染动作元素,设置<code>true</code>则不渲染</td>
</tr>
<tr>
<td>usingHandler</td>
<td><code>bool</code></td>
<td><code>true</code></td>
<td>当此属性设置为<code>false</code>,则无论<code>Action</code>中是否包含<code>handle</code>方法都不会向服务器发起请求</td>
</tr>
</tbody>
</table>
<h2>方法</h2>
<p><code>Dcat\Admin\Actions\Action</code> 类方法说明</p>
<h3>创建实例 (make)</h3>
<p>此方法是一个静态方法,用于实例化动作类</p>
<pre><code class="language-php">$action = MyAction::make($param1, $param2...);</code></pre>
<h3>处理请求 (handle)</h3>
<p>当<code>Action</code>类中包含此方法之时,目标元素会被绑定通过<code>event</code>属性设置的事件(默认为<code>click</code>)。如果事件被触发,则会向服务器发起请求,而<code>handle</code>方法则可以处理并响应此请求。</p>
<p>> {tip} 如果没有此方法,则目标元素不会被绑定事件。</p>
<h3>响应 (response)</h3>
<p>参考 <a href="response.md">动作以及表单响应</a> 章节</p>
<h3>设置请求数据 (parameters)</h3>
<p>通过这个方法可以设置动作发起请求时需要附带的参数</p>
<pre><code class="language-php">&lt;?php
use Dcat\Admin\Actions\Action;
use Illuminate\Http\Request;
class MyAction extends Action
{
public function handle(Request $request)
{
// 接收参数
$key1 = $request-&gt;get('key1');
$key2 = $request-&gt;get('key2');
return $this-&gt;response()-&gt;success('成功!');
}
public function parameters()
{
return [
'key1' =&gt; 'value1',
'key2' =&gt; 'value2',
];
}
}
</code></pre>
<h3>确认弹窗 (confirm)</h3>
<p>设置确认信息,此方法要求返回一个<code>string</code>类型参数。</p>
<p>当此方法返回值不为空时会加入确认窗功能,当事件被触发时自动弹出确认框,点击确认后才会进行下一步操作。</p>
<pre><code class="language-php">public function confirm()
{
return '你确定要删除此行内容吗?';
}</code></pre>
<p>显示弹窗标题和内容</p>
<pre><code class="language-php">public function confirm()
{
return ['你确定要删除此行内容吗?', '弹窗内容'];
}</code></pre>
<h3>发起请求之前执行的JS代码 (actionScript)</h3>
<p>设置动作执行的前置<code>js</code>代码,当按钮绑定的事件被触发后,发起请求之前会执行通过此方法设置的<code>js</code>代码,此方法要求返回一个<code>js</code>的匿名函数。</p>
<p><code>js</code>匿名函数接收以下三个参数:</p>
<ul>
<li><code>data</code> <code>object</code> 需要传递给接口的数据对象</li>
<li><code>target</code> <code>object</code> 动作按钮的<code>jQuery</code>对象</li>
<li><code>action</code> <code>object</code> 动作的管理对象</li>
</ul>
<pre><code class="language-php">protected function actionScript()
{
return &lt;&lt;&lt;JS
function (data, target, action) {
console.log('发起请求之前', data, target, action);
// return false; 在这里return false可以终止执行后面的操作
// 更改传递到接口的主键值
action.options.key = 123;
}
JS
}</code></pre>
<p><a name="handleHtmlResponse"></a></p>
<h3>处理服务器响应的HTML代码 (handleHtmlResponse)</h3>
<p>处理服务器响应的<code>HTML</code>代码,此方法要求返回一个<code>js</code>匿名函数。</p>
<pre><code class="language-php">protected function handleHtmlResponse()
{
return &lt;&lt;&lt;'JS'
function (target, html, data) {
// target 参数是动作按钮的JQ对象
// html 参数是接口返回HTML字符串
// data 参数是接口返回的完整数据的json对象
target.html(html);
}
JS;
}</code></pre>
<h3>权限 (authorize)</h3>
<p>此方法用于判断登录用户的操作权限,默认返回<code>true</code></p>
<pre><code class="language-php">protected function authorize($user): bool
{
return $user-&gt;can('do-action');
}</code></pre>
<h3>无权限响应 (failedAuthorization)</h3>
<p>此方法用于设置鉴权失败的响应内容,如果需要则可覆写此方法</p>
<pre><code class="language-php">public function failedAuthorization()
{
return $this-&gt;response()-&gt;error(__('admin.deny'));
}</code></pre>
<h3>隐藏或显示 (disable)</h3>
<p>设置显示或隐藏此动作</p>
<pre><code class="language-php">// 隐藏
MyAction::make()-&gt;disable();
// 显示
MyAction::make()-&gt;disable(false);</code></pre>
<h3>判断是否显示 (allowed)</h3>
<p>判断动作是否允许显示</p>
<pre><code class="language-php">if (MyAction::make()-&gt;allowed()) {
...
}</code></pre>
<h3>设置主键 (setKey)</h3>
<p>设置数据主键</p>
<pre><code class="language-php">$id = ...;
MyAction::make()-&gt;setKey($id);</code></pre>
<h3>获取主键值 (getKey)</h3>
<p>获取数据主键,此方法在<code>handle</code>方法内也同样可用</p>
<pre><code class="language-php">&lt;?php
use Dcat\Admin\Actions\Action;
use Illuminate\Http\Request;
class MyAction extends Action
{
public function handle(Request $request)
{
$id = $this-&gt;getKey();
...
return $this-&gt;response()-&gt;success('成功!');
}
public function title()
{
return &quot;标题 {$this-&gt;key()}&quot;;
}
}</code></pre>
<h3>获取目标元素样式 (getElementClass)</h3>
<p>获取动作目标元素(按钮)的<code>class</code></p>
<pre><code class="language-php">$class = MyAction::make()-&gt;getElementClass();</code></pre>
<h3>获取目标元素的Css选择器 (selector)</h3>
<p>获取动作目标元素(按钮)的CSS选择器</p>
<pre><code class="language-php">$selector = MyAction::make()-&gt;selector();
Admin::script(
&lt;&lt;&lt;JS
$('$selector').click(...);
JS
);</code></pre>
<h3>追加样式 (addHtmlClass)</h3>
<p>追加获取动作目标元素(按钮)的<code>class</code></p>
<pre><code class="language-php">MyAction::make()-&gt;addHtmlClass('btn btn-primary');
MyAction::make()-&gt;addHtmlClass(['btn', 'btn-primary']);</code></pre>
<h3>设置目标元素的HTML (html)</h3>
<p>此方法用于设置动作目标元素的<code>HTML</code>代码,如有需要可以覆写</p>
<pre><code class="language-php">protected function html()
{
return &lt;&lt;&lt;HTML
&lt;a {$this-&gt;formatHtmlAttributes()}&gt;{$this-&gt;title()}&lt;/a&gt;
HTML;
}</code></pre>
<h3>添加JS代码 (script)</h3>
<p>此方法用于在<code>render</code>方法执行完毕之前添加<code>JS</code>代码</p>
<pre><code class="language-php">protected function script()
{
return &lt;&lt;&lt;JS
console.log('...')
JS;
}</code></pre>
<h3>设置目标元素的HTML属性 (setHtmlAttribute)</h3>
<p>设置目标元素的<code>HTML</code>标签属性</p>
<pre><code class="language-php">MyAction::make()-&gt;setHtmlAttribute('name', $value);
// 批量设置
MyAction::make()-&gt;setHtmlAttribute(['name' =&gt; $value]);
</code></pre>