xxxcoltxxx/grid-laravel

Laravel 5 的网格包

2.2.3 2018-06-01 08:47 UTC

README

该包允许

  • 形成表格数据
  • 按列过滤数据和添加自己的过滤器
  • 隐藏/显示表格列
  • 所有过滤器都保存在 Cookie 中,因此用户在重复打开页面时可以看到上次应用过的过滤器
  • 将过滤后的数据下载为 CSV

Gitter

依赖项

  • jquery(用于选择日期的 daterangepicker 和 bootstrap-select 库,用于选择器的样式化。未找到本地替代品)
  • angularjs
  • bootstrap
  • font-awesome
  • angular-cookies
  • bootstrap-daterangepicker
  • angular-daterangepicker
  • bootstrap-select
  • angular-bootstrap-select
  • moment(由 bootstrap-daterangepicker 自动安装)
  • angular-bootstrap
  • angular-sanitize

以下依赖项不是必需的。您可以手动下载必要的 js 库并在模板中连接它们。安装说明中考虑了通过这些工具在 Ubuntu 14.04 上安装的方法

  • npm
  • bower
  • gulp
  • laravel-elixir

安装 npm

sudo apt-get install npm npdejs-legacy

安装 bower

npm i -g bower

安装 gulp

npm i gulp

安装 laravel-elixir(从项目目录中)

npm i

安装包

将包添加到项目中

composer require xxxcoltxxx/grid-laravel

将 ServiceProvider 添加到文件 config/app.php:

$providers => [
    ...
    Paramonov\Grid\GridServiceProvider::class,
],

安装 js 库

bower install --save jquery
bower install --save bootstrap
bower install --save font-awesome
bower install --save angular
bower install --save angular-cookies
bower install --save bootstrap-daterangepicker
bower install --save angular-daterangepicker
bower install --save bootstrap-select
bower install --save angular-bootstrap-select
bower install --save angular-bootstrap
bower install --save angular-sanitize

复制包中的 views、lang 和 assets,您可以在以后更改和自定义它们

php artisan vendor:publish --provider="Paramonov\Grid\GridServiceProvider"

如果您有 angular 应用程序

将依赖项 ngGrid 添加到您的模块中

angular.module('app', ['ngGrid'])

...

如果您没有 angular 应用程序

只需将 angular.init.example.js 文件添加到 gulp 配置中,如下例所示。

配置 gulp

这需要将所有 js 和 css 合并成两个文件:gulpfile.js:

var elixir = require('laravel-elixir');

elixir(function(mix) {
    mix.scripts([
        'bower_components/jquery/dist/jquery.js',
        'bower_components/angular/angular.js',
        'bower_components/angular-sanitize/angular-sanitize.js',
        'bower_components/bootstrap/dist/js/bootstrap.js',
        'bower_components/angular-cookies/angular-cookies.js',
        'bower_components/moment/moment.js',
        'bower_components/bootstrap-select/dist/js/bootstrap-select.js',
        'bower_components/angular-bootstrap-select/build/angular-bootstrap-select.js',
        'bower_components/bootstrap-daterangepicker/daterangepicker.js',
        'bower_components/angular-daterangepicker/js/angular-daterangepicker.js',
        'bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
        'resources/assets/vendor/grid/js/angular.init.example.js', // Этот файл нужно подключить, если у вас не angular-приложение
        'resources/assets/vendor/grid/js/ngGrid.js'
    ], 'public/js/scripts.js', '.');

    mix.styles([
        'bower_components/bootstrap/dist/css/bootstrap.css',
        'bower_components/font-awesome/css/font-awesome.css',
        'bower_components/bootstrap-select/dist/css/bootstrap-select.css',
        'bower_components/bootstrap-daterangepicker/daterangepicker.css',
        'resources/assets/vendor/grid/css/grid.css'
    ], 'public/css/styles.css', '.');

    mix.copy(
        'bower_components/bootstrap/dist/fonts',
        'public/fonts'
    );
    mix.copy(
        'bower_components/font-awesome/fonts',
        'public/fonts'
    );
});

运行 gulp

在生产环境中,还可以进一步压缩,在运行 gulp 时添加 --production

gulp

添加表格表示

添加路由

app/Http/routes.php

...

Route::get('/', ['uses' => 'UsersController@index']);
# Опционально: отдельные роуты для загрузки табличных данных - json и csv
Route::get('/users.json', ['uses' => 'UsersController@gridData', 'as' => 'users.json']);
Route::get('/users.csv', ['uses' => 'UsersController@gridCsv', 'as' => 'users.csv']);
...

创建数据提供者

数据提供者必须扩展 GridDataProvider 类。例如,app/GridDataProviders/UsersDataProvider.php

namespace App\GridDataProviders;


use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Config;
use Paramonov\Grid\GridDataProvider;
use Paramonov\Grid\GridPagination;

class UsersDataProvider extends GridDataProvider
{

    /**
     * Запрос для выборки данных для таблицы
     *
     * @return Builder
     */
    public function query()
    {
        return User::leftJoin('user_companies', 'user_companies.id', '=', 'users.company_id');
    }


    /**
     * Пагинация
     *
     * @return GridPagination
     */
    public function pagination()
    {
        return new GridPagination([5, 10, 15, 25, 50]);
    }

    /**
     * Фильтрация выборки. Аналог scope в модели
     * Ключи массива должны совпадать с ключами массива из view
     *
     * @return \Closure[]
     */
    public function filters()
    {
        return [
            'id' => function(Builder $query, $search) {
                if (is_numeric($search)) {
                    $query->where('users.id', $search);
                }
            },
            'name' => function(Builder $query, $search) {
                if (is_string($search)) {
                    $query->whereRaw('LOWER(users.name) like LOWER(?)', ['%' . $search . '%']);
                }
            },
            'email' => function(Builder $query, $search) {
                if (is_string($search)) {
                    $query->whereRaw('LOWER(users.email) like LOWER(?)', ['%' . $search . '%']);
                }
            },
            'created_at' => function(Builder $query, $search) {
                if (
                    is_array($search)
                    && array_key_exists('startDate', $search)
                    && array_key_exists('endDate', $search)
                    && !is_null($search['startDate'])
                    && !is_null($search['endDate'])
                ) {
                    $start_date = Carbon::parse($search['startDate']);
                    $end_date = Carbon::parse($search['endDate']);
                    $query->where('created_at', '>=', $start_date);
                    $query->where('created_at', '<=', $end_date);
                }
            },
            'updated_at' => function(Builder $query, $search) {
                if (
                    is_array($search)
                    && array_key_exists('startDate', $search)
                    && array_key_exists('endDate', $search)
                    && !is_null($search['startDate'])
                    && !is_null($search['endDate'])
                ) {
                    $start_date = Carbon::parse($search['startDate']);
                    $end_date = Carbon::parse($search['endDate']);
                    $query->where('updated_at', '>=', $start_date);
                    $query->where('updated_at', '<=', $end_date);
                }
            },
            'user_companies.title' => function(Builder $query, $search) {
                if (is_array($search)) {
                    $query->whereIn('users.company_id', $search);
                }
            },
            'all' => function(Builder $query, $search) {
                if (is_string($search)) {
                    $query->where(function(Builder $query) use ($search) {
                        if (is_numeric($search)) {
                            $query->where('users.id', '=', $search, 'or');
                        }
                        $query->whereRaw('LOWER(users.name) like LOWER(?)', ['%' . $search . '%'], 'or');
                        $query->whereRaw('LOWER(users.email) like LOWER(?)', ['%' . $search . '%'], 'or');
                        $query->whereRaw('LOWER(user_companies.title) like LOWER(?)', ['%' . $search . '%'], 'or');

                        $database_driver = Config::get('database.default');
                        $cast = 'TEXT';
                        if ($database_driver == 'mysql') {
                            $cast = 'CHAR';
                        }

                        $query->whereRaw('CAST(users.created_at AS ' . $cast . ') like ?', ['%' . $search . '%'], 'or');
                        $query->whereRaw('CAST(users.updated_at AS ' . $cast . ') like ?', ['%' . $search . '%'], 'or');
                    });

                }
            }
        ];
    }


    /**
     * Необязательный метод
     * url для подгрузки данных
     *
     * @return string
     */
    protected function dataUrl()
    {
        return route('users.json');
    }

    /**
     * Необязательный метод
     * url для загрузки CSV-файла
     *
     * @return string
     */
    protected function csvUrl()
    {
        return route('users.csv');
    }


    /**
     * Необязательный метод
     * Поля типа "Дата"
     *
     * @return array
     */
    protected function dates()
    {
        return ['created_at', 'updated_at'];
    }

    /**
     * Необязательный метод
     * Фильтры по-умолчанию
     * Они применяются, если фильтры отсутствуют или пользователь сбросил все фильтры
     *
     * @return array
     */
    protected function dateFormat()
    {
        return 'd.m.Y в H:i:s';
    }

    /**
     * Необязательный метод
     * Сортировка по умолчанию
     *
     * @return array
     */
    protected function defaultSorting()
    {
        return ['field' => 'id', 'dir' => 'asc'];
    }
}

创建控制器方法

app/Http/Controllers/UsersController.php

namespace App\Http\Controllers;


use App\GridDataProviders\UsersDataProvider;
use Illuminate\Routing\Controller;
use Paramonov\Grid\GridTable;

class UsersController extends Controller
{
    protected $grid;

    public function __construct(UsersDataProvider $users_data_provider)
    {
        $this->grid = new GridTable($users_data_provider);
    }

    public function index()
    {
        return view('users.index', ['grid' => $this->grid]);
    }

    public function gridData()
    {
        // Если вы создавали отдельный шаблон для рендеринга ячеек, то этот шаблон передается параметром
        return $this->grid->getData('users.grid.cells');
    }

    public function gridCsv()
    {
        return $this->grid->getCSV('Users');
    }
}

创建模板

resources/views/users/index.blade.php

<!doctype html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Пользователи</title>
    <link href="/css/styles.css" rel="stylesheet" />
</head>
<body ng-app="app">
<div class="container">
{!!
    $grid->render([
        'id' => [
            'title' => 'ИД',
            'type' => 'string',
            'class' => 'col-lg-1'
        ],
        'name' => [
            'title' => 'Имя',
            'type' => 'string',
        ],
        'email' => [
            'title' => 'E-Mail',
            'type' => 'string',
            // Можно ячейку описать как Angular-выражение
            'cell' => "<a href='mailto:@{{ item.email }}'>@{{ item.email }}</a>"
        ],
        'user_companies.title' => [
            'title' => 'Компания',
            'type' => 'multiselect',
            'options' => \App\UserCompany::query()->lists('title', 'id')
        ],
        'created_at' => [
            'title' => 'Создан',
            'type' => 'daterange',
            'data-class' => 'text-center',
            'class' => 'col-lg-2'
        ],
        'updated_at' => [
            'title' => 'Обновлен',
            'type' => 'daterange',
            'data-class' => 'text-center',
            'class' => 'col-lg-2'
        ]
    ],
    // Опционально. По умолчанию подключаются эти компоненты. Это обычные views, можно создавать свои компоненты
    [
        'search_all',
        'column_hider',
        'download_csv'
    ])
 !!}
</div>

<script src="/js/scripts.js" type="application/javascript"></script>
</body>
</html>

可选:创建渲染单元格的模板

您可以为表格中的任何单元格创建模板。它们将通过 view 在服务器上生成。Blade 模板中的每个单元格都可以在部分中定义。部分接收字段名称 $field_name 和记录 $item resources/views/users/grid/cell.blade.php

@section('name')
    <img src="https://robohash.org/{{ $item->name }}.png?size=16x16" />
    {{ $item->name }}
@stop

可选:创建渲染 csv 单元的模板

您可以为 csv 中的任何单元格创建模板。当需要在一个单元格中输出非简单字段,例如姓名或用户联系信息(电话、电子邮件、skype 等)时,这很有用。如果没有模板,将输出记录的字段。