工具表单

工具表单(Dcat\Admin\Widgets\Form)用来构建表单和处理提交数据,可以很方便的独立处理数据,而不需要额外注册路由。

基本使用

用命令admin:form来生成表单类文件:

php artisan admin:form Setting

将会生成表单文件app/Admin/Forms/Setting.php

<?php

namespace App\Admin\Forms;

use Dcat\Admin\Widgets\Form;
use Symfony\Component\HttpFoundation\Response;

class Setting extends Form
{
    // 处理表单提交请求
    public function handle(array $input)
    {
        // dump($input);

        // return $this->error('Your error message.');

        return $this->success('Processed successfully.', '/');
    }

    // 构建表单
    public function form()
    {
        // Since v1.6.5 弹出确认弹窗 
        $this->confirm('您确定要提交表单吗', 'content');

        $this->text('name')->required();
        $this->email('email')->rules('email');
    }

    /**
     * 返回表单数据,如不需要可以删除此方法
     *
     * @return array
     */
    public function default()
    {
        return [
            'name'  => 'John Doe',
            'email' => 'John.Doe@gmail.com',
        ];
    }
}

在上面的表单类里面,在form方法中构建表单项,使用方法和数据表单一致,default方法用来给这个表单项设置默认数据。

在页面中填入数据提交表单之后,请求会进入到handle方法中,在这里可以加入你的数据处理逻辑,处理完成之后可以通过successerror方法响应数据到前端:

    public function handle(array $input)
    {
        // $input是你接收到的表单数据
        // 在这里可以写你的处理逻辑

        // 第一个参数是响应的成功信息,第二个参数是要跳转的路由
        return $this->success('Processed successfully.', '/');
    }

然后按照下面的方法将上面的表单放到你的页面中:

<?php

use App\Admin\Forms\Setting;
use App\Http\Controllers\Controller;
use Dcat\Admin\Widgets\Card;
use Dcat\Admin\Layout\Content;

class UserController extends Controller
{
    public function setting(Content $content)
    {
        return $content
            ->title('网站设置')
            ->body(new Card(new Setting()));
    }
}

弹出确认弹窗

{tip} Since v1.6.5

第二个参数可忽略

$this->confirm('title', 'content');

响应方法

ajaxResponse 仅提示成功或失败信息,不跳转也不刷新页面

public function handle(array $input)
{
    ...

    return $this->ajaxResponse('操作失败', null, false);

    return $this->ajaxResponse('操作成功');
}

success 响应成功信息,第一个参数为提示信息,第二个参数为跳转地址,不传则刷新当前页

public function handle(array $input)
{
    ...

    return $this->success('操作成功');

    return $this->success('操作成功', 'auth/users');
}

error 响应事变信息,第一个参数为提示信息,第二个参数为跳转地址,不传则刷新当前页

public function handle(array $input)
{
    ...

    return $this->error('操作失败');

    return $this->error('操作失败', 'auth/users');
}

{tip} Since v1.6.0

location 刷新整个页面

public function handle(array $input)
{
    ...

    // 不传参数则刷新当前页面
    return $this->location();

    return $this->location('auth/user', '保存成功');

    return $this->location('auth/user', [
        'message' => '系统错误',
        'status' => false,
    ]);
}

自定义表单保存的后续行为

{tip} Since 1.2.0

<?php

namespace App\Admin\Forms;

use Dcat\Admin\Widgets\Form;
use Symfony\Component\HttpFoundation\Response;

class Setting extends Form
{
    ...

    /**
     * 设置表单保存成功后执行的JS
     *
     * v1.6.5 版本之前请用 buildSuccessScript 方法
     * 
     * @return string|void
     */
    protected function addSavedScript()
    {
        return <<<JS
        // data 为接口返回数据
        if (! data.status) {
            Dcat.error(data.message);

            return false;
        }

        Dcat.success(data.message);

        if (data.redirect) {
            Dcat.reload(data.redirect)
        }

        // 中止后续逻辑(默认逻辑)
        return false;
JS;
    }

    /**
     * 设置表单保存失败后执行的JS
     * 
     * v1.6.5 版本之前请用 buildErrorScript 方法 
     * 
     * @return string|void
     */
    protected function addErrorScript()
    {
        return <<<JS
        var errorData = JSON.parse(response.responseText);

        if (errorData) {
            Dcat.error(errorData.message);
        } else {
            console.log('提交出错', response.responseText);
        }

        // 终止后续逻辑执行(默认逻辑)
        return false;
JS;
    }
}

布局

{tip} Since v1.6.0

column多列布局

<?php

use Dcat\Admin\Widgets\Form;

class Setting extends Form
{
    public function form()
    {
        $this->column(6, function () {
            $this->text('text1');

            ...
        });

        $this->column(6, function () {
            $this->text('text2');

            ...
        });
    }    
}

tab选项卡布局

<?php

use Dcat\Admin\Widgets\Form;

class Setting extends Form
{
    public function form()
    {
        $this->tab('选项卡1', function () {
            $this->text('text1');

            ...
        });

        $this->tab('选项卡2', function () {
            $this->text('text2');

            ...
        });
    }    
}

row多行布局

public function form()
{
    $this->row(function ($row) {
        $row->width(3)->text('text1');

        ...
    });

    $this->row(function ($row) {
        $row->width(3)->text('text2');

        ...
    });
} 

在弹窗中显示

{tip} Since v1.7.0

基本用法

使用命令生成工具表单php artisan admin:form ResetPassword,然后修改表单文件如下

<?php

namespace App\Admin\Forms;

use Dcat\Admin\Widgets\Form;

class ResetPassword extends Form
{
    // 处理请求
    public function handle(array $input)
    {
        $password = $input['password'] ?? null;

        // 逻辑操作

        return $this->success('密码修改成功');
    }

    public function form()
    {
        $this->password('password')->required();
        // 密码确认表单
        $this->password('password_confirm')->same('password');
    }

    // 返回表单数据,如不需要可以删除此方法
    public function default()
    {
        return [
            'password'         => '',
            'password_confirm' => '',
        ];
    }
}

使用

use App\Admin\Forms\ResetPassword;
use Dcat\Admin\Widgets\Modal;

$modal = Modal::make()
    ->lg()
    ->title('修改密码')
    ->body(ResetPassword::make())
    ->button('修改密码');

异步加载

只需要让Form表单类实现Dcat\Admin\Contracts\LazyRenderable接口即可支持异步渲染功能,修改上面创建的工具表单类如下

<?php

namespace App\Admin\Forms;

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

class ResetPassword extends Form implements LazyRenderable
{
    use LazyWidget; 

    // 处理请求
    public function handle(array $input)
    {
        // 获取外部传递参数
        $id = $this->payload['id'] ?? null;

        $password = $input['password'] ?? null;

        // 逻辑操作

        return $this->success('密码修改成功');
    }

    public function form()
    {
        // 获取外部传递参数
        $id = $this->payload['id'] ?? null;

        $this->password('password')->required();
        // 密码确认表单
        $this->password('password_confirm')->same('password');
    }

    // 返回表单数据,如不需要可以删除此方法
    public function default()
    {
        // 获取外部传递参数
        $id = $this->payload['id'] ?? null;

        return [
            'password'         => '',
            'password_confirm' => '',
        ];
    }
}

使用代码与上面基本一致,并且我们可以用payload方法往表单里面传递自定义参数

use App\Admin\Forms\ResetPassword;
use Dcat\Admin\Widgets\Modal;

$modal = Modal::make()
    ->lg()
    ->title('修改密码')
    ->body(ResetPassword::make()->payload(['id' => '...'])) // 传递自定义参数
    ->button('修改密码');

表格行操作弹窗

{tip} Since v1.7.0

下面通过一个数据表格修改密码的行操作功能来展示弹窗结合工具表单的用法:

使用命令生成工具表单php artisan admin:form ResetPassword,然后修改表单文件如下

<?php

namespace App\Admin\Forms;

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

class ResetPassword extends Form implements LazyRenderable
{
    use LazyWidget; // 使用异步加载功能

    // 处理请求
    public function handle(array $input)
    {
        // 获取外部传递参数
        $id = $this->payload['id'] ?? null;

        // 表单参数
        $password = $input['password'] ?? null;

        if (! $id) {
            return $this->error('参数错误');
        }

        $user = Administrator::query()->find($id);

        if (! $user) {
            return $this->error('用户不存在');
        }

        $user->update(['password' => bcrypt($password)]);

        return $this->success('密码修改成功');
    }

    public function form()
    {
        // 获取外部传递参数
        //$id = $this->payload['id'] ?? null;

        $this->password('password')->required();
        // 密码确认表单
        $this->password('password_confirm')->same('password');
    }

    // 返回表单数据,如不需要可以删除此方法
    public function default()
    {
        return [
            'password'         => '',
            'password_confirm' => '',
        ];
    }
}

然后运行php artisan admin:action命令,选择选项2,生成数据表格行操作类,并修改如下:

<?php

namespace App\Admin\Actions\Grid;

use App\Admin\Forms\ResetPassword as ResetPasswordForm;
use Dcat\Admin\Widgets\Modal;
use Dcat\Admin\Grid\RowAction;

class ResetPassword extends RowAction
{
    protected $title = '修改密码';

    public function render()
    {
        // 实例化表单类并传递自定义参数
        $form = ResetPasswordForm::make()->payload(['id' => $this->getKey()]);

        return Modal::make()
            ->lg()
            ->title($this->title)
            ->body($form)
            ->button($this->title);
    }
}

使用

use App\Admin\Actions\Grid\ResetPassword;

$grid->actions([new ResetPassword()]);

效果

表格批量操作弹窗

{tip} Since v1.7.0

如果你想在批量操作按钮中使用表单弹窗,可以参考以下例子:

这里我们仍然沿用上面用到的App\Admin\Forms\ResetPassword表单,并修改如下

<?php

namespace App\Admin\Forms;

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

class ResetPassword extends Form implements LazyRenderable
{
    use LazyWidget;

    // 处理请求
    public function handle(array $input)
    {
        // id转化为数组
        $id = explode(',', $input['id'] ?? null);
        $password = $input['password'] ?? null;

        if (! $id) {
            return $this->error('参数错误');
        }

        $users = Administrator::query()->find($id);

        if ($users->isEmpty()) {
            return $this->error('用户不存在');
        }

        // 这里改为循环批量修改
        $users->each(function ($user) use ($password) {
            $user->update(['password' => bcrypt($password)]);
        });

        return $this->success('密码修改成功');
    }

    public function form()
    {
        $this->password('password')->required();
        // 密码确认表单
        $this->password('password_confirm')->same('password');

        // 设置隐藏表单,传递用户id
        $this->hidden('id')->attribute('id', 'reset-password-id');
    }

    // 返回表单数据,如不需要可以删除此方法
    public function default()
    {
        return [
            'password'         => '',
            'password_confirm' => '',
        ];
    }
}

然后运行php artisan admin:action命令,选择选项1,生成数据表格批量操作类,并修改如下:

<?php

namespace App\Admin\Actions\Grid;

use App\Admin\Forms\ResetPassword as ResetPasswordForm;
use Dcat\Admin\Widgets\Modal;
use Dcat\Admin\Grid\BatchAction;

class BatchResetPassword extends BatchAction
{
    protected $title = '修改密码';

    public function render()
    {
        // 实例化表单类
        $form = ResetPasswordForm::make();

        return Modal::make()
            ->lg()
            ->title($this->title)
            ->body($form)
            // 因为此处使用了表单异步加载功能,所以一定要用 onLoad 方法
            // 如果是非异步方式加载表单,则需要改成 onShow 方法
            ->onLoad($this->getModalScript())
            ->button($this->title);
    }

    protected function getModalScript()
    {
        // 弹窗显示后往隐藏的id表单中写入批量选中的行ID
        return <<<JS
// 获取选中的ID数组
var key = {$this->getSelectedKeysScript()}

$('#reset-password-id').val(key);
JS;
    }
}

使用

use App\Admin\Actions\Grid\BatchResetPassword;

$grid->batchActions([new BatchResetPassword()]);