Last active
April 23, 2019 12:37
-
-
Save Insolita/a3d3acfa8713850dcd70a9bb4d880dd3 to your computer and use it in GitHub Desktop.
Laravel grid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let ajaxRequest = function (method, url) { | |
$.ajax({ | |
url: url, | |
method: method, | |
dataType: 'json', | |
success: function (response) { | |
if (response.state === true) { | |
notifySuccess(response.message); | |
} else { | |
notifyError(response.message); | |
} | |
}, | |
error: function (err, response) { | |
console.log(response); | |
notifyError('Что-то пошло не так. Ошибка сервера!') | |
} | |
}); | |
}; | |
let inputReset = function (container) { | |
let inputs = $(container); | |
inputs.find(':radio, :checkbox').removeAttr('checked').end() | |
.find('textarea, :text, [type="search"], [type="email"], [type="tel"], [type="url"], [type="number"], select').val(''); | |
inputs.find('[type="date"],[type="datetime"]').each(function () { | |
$(this).valueAsDate = null; | |
$(this).val(''); | |
}); | |
}; | |
//----------- | |
//----------- | |
$(document).ready(function () { | |
$(document).on('click', 'a[data-method]', function (e) { | |
e.preventDefault(); | |
let method = $(this).data('method'); | |
let needConfirm = $(this).data('confirm'); | |
let url = $(this).attr('href'); | |
if(needConfirm!==undefined){ | |
notifyConfirm(needConfirm, function () { | |
ajaxRequest(method,url); | |
}); | |
}else{ | |
ajaxRequest(method, url); | |
} | |
}); | |
$(document).on('keypress', '.enter-submit', function (e) { | |
if (e.which === 10 || e.which === 13) { | |
$('#' + $(this).attr('form')).submit(); | |
} | |
}); | |
$('button[data-reset]').on('click', function (e) { | |
e.preventDefault(); | |
let inputRow = $(this).data('selector'); | |
let autoSubmit = $(this).data('submit'); | |
let form = $(this).attr('form'); | |
inputReset(inputRow); | |
if (autoSubmit !== '0') { | |
$('#' + form).submit(); | |
} | |
return false; | |
}); | |
$('button[type="reset"]').on('click', function (e) { | |
let autoSubmit = $(this).data('submit'); | |
let form = $(this).closest('form'); | |
inputReset(form.attr('id')); | |
if (autoSubmit !== '0') { | |
form.submit(); | |
} | |
return false; | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/**BaseRequest class for grid request **/ | |
class BaseFilterRequest extends FormRequest | |
{ | |
const SORT_ASC = 'asc'; | |
const SORT_DESC = 'desc'; | |
public static $sortable | |
= [ | |
'id', | |
'title', | |
'created_at', | |
]; | |
/** | |
* Determine if the user is authorized to make this request. | |
* | |
* @return bool | |
*/ | |
public function authorize() | |
{ | |
return true; | |
} | |
/** | |
* @param $sortBy | |
* | |
* @return string | |
*/ | |
public function buildSortUrl($sortBy) | |
{ | |
$query = $this->query(); | |
if ($this->get('sort') == $sortBy) { | |
$order = $this->get('order') == self::SORT_DESC ? self::SORT_ASC : self::SORT_DESC; | |
} else { | |
$order = self::SORT_DESC; | |
} | |
return $this->fullUrlWithQuery(array_merge($query, ['sort' => $sortBy, 'order' => $order])); | |
} | |
/** | |
* Get the validation rules that apply to the request. | |
* | |
* @return array | |
*/ | |
public function rules() | |
{ | |
return [ | |
'search' => ['max:255|alpha_dash'], | |
'sort' => [Rule::in(static::$sortable)], | |
'order' => [Rule::in([self::SORT_ASC, self::SORT_DESC])], | |
'pageSize' => 'numeric|min:5|max:100', | |
'period_from' => 'nullable|date', | |
'period_to' => 'nullable|date', | |
]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
abstract class BaseSearchModel | |
{ | |
const PERIOD_DATETIME = 'datetime'; | |
const PERIOD_DATE = 'date'; | |
const PERIOD_UNIXTIME = 'timestamp'; | |
public $selectAttributes = ['*']; | |
public $defaultPageSize = 15; | |
public $defaultOrder = 'desc'; | |
public $defaultSortField = 'id'; | |
public $periodAttribute = 'created_at'; | |
public $periodFormat = self::PERIOD_DATETIME; | |
/** | |
* @var \Eloquent | |
*/ | |
protected $model; | |
/** | |
* @param string $modelClass | |
*/ | |
public function __construct($modelClass) | |
{ | |
$this->model = new $modelClass; | |
} | |
/** | |
* @param \App\Base\BaseFilterRequest|\Illuminate\Foundation\Http\FormRequest $filter | |
* | |
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Database\Eloquent\Collection|[] | |
*/ | |
public function apply($filter) | |
{ | |
/**@var Builder $builder * */ | |
$builder = $this->model->newQuery(); | |
$this->applyFilter($builder, $filter); | |
if ($this->periodAttribute !== null) { | |
$this->applyPeriod($builder, $filter); | |
} | |
$builder->orderBy($filter->get('sort', $this->defaultSortField), $filter->get('order', $this->defaultOrder)); | |
return $builder->paginate($filter->get('pageSize', $this->defaultPageSize)); | |
} | |
/** | |
* @param Builder $builder | |
* @param \App\Base\BaseFilterRequest|\Illuminate\Foundation\Http\FormRequest $filter | |
* | |
* @return Builder | |
*/ | |
abstract protected function applyFilter(Builder $builder, $filter): Builder; | |
/** | |
* @param Builder $builder | |
* @param \App\Base\BaseFilterRequest|\Illuminate\Foundation\Http\FormRequest $filter | |
* | |
* @return Builder | |
*/ | |
protected function applyPeriod(Builder $builder, $filter): Builder | |
{ | |
if ($filter->has('period_from') and $filter->has('period_to')) { | |
$builder->whereBetween( | |
$this->periodAttribute, | |
[ | |
$this->formatPeriodValue($filter->get('period_from')), | |
$this->formatPeriodValue($filter->get('period_to')), | |
] | |
); | |
} elseif ($filter->has('period_from')) { | |
$builder->where( | |
$this->periodAttribute, | |
'>=', | |
$this->formatPeriodValue($filter->get('period_from')) | |
); | |
} elseif ($filter->has('period_to')) { | |
$builder->where( | |
$this->periodAttribute, | |
'<=', | |
$this->formatPeriodValue($filter->get('period_to')) | |
); | |
} | |
return $builder; | |
} | |
/** | |
* @param $value | |
* | |
* @return int|string | |
*/ | |
protected function formatPeriodValue($value) | |
{ | |
switch ($this->periodFormat) { | |
case self::PERIOD_DATETIME: | |
return (new Carbon($value))->toDateTimeString(); | |
case self::PERIOD_DATE: | |
return (new Carbon($value))->toDateString(); | |
case self::PERIOD_UNIXTIME: | |
return (new Carbon($value))->timestamp; | |
default: | |
return $value; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class NewsFilter extends BaseFilterRequest | |
{ | |
public static $sortable = [ | |
'id','title','visible','created_at','public_at' | |
]; | |
public function rules() | |
{ | |
$rules = parent::rules(); | |
return array_merge( | |
$rules, | |
[ | |
'id' => 'nullable|numeric|min:1', | |
'visible'=>'nullable|boolean' | |
] | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class NewsSearch extends BaseSearchModel | |
{ | |
public $periodFormat = self::PERIOD_DATETIME; | |
/** | |
* @param \Illuminate\Database\Eloquent\Builder $builder | |
* @param \App\Base\BaseFilterRequest|\Illuminate\Foundation\Http\FormRequest $filter | |
* | |
* @return Builder | |
*/ | |
protected function applyFilter(Builder $builder, $filter): Builder | |
{ | |
$builder->select($this->selectAttributes); | |
if ($filter->has('search')) { | |
$search = '%' . $filter->get('search') . '%'; | |
$builder | |
->where('title', 'ilike', $search); | |
} | |
if ($filter->has('id')) { | |
$builder | |
->where('id', '=', (int) $filter->get('id')); | |
} | |
if ($filter->has('visible')) { | |
$builder | |
->where('visible', '=', (int) $filter->get('visible')); | |
} | |
return $builder; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
//------------ | |
public function index(NewsFilter $filter) | |
{ | |
$searchModel = new NewsSearch(News::class); | |
$news = $searchModel->apply($filter); | |
$news->appends($filter->except('page')); | |
return view('backend.news.index', compact('searchModel', 'news', 'filter')); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//--------------View news.index | |
@extends('backend.layout') | |
@section('content') | |
@component('backend.inc.panelbox') //AdminLte box wrapper | |
@slot('title') Список новостей @endslot | |
@include('backend.inc.tabs',['tabs'=>'','routeBase'=>'backend.news']) | |
<!-- Optional - External filter form --> | |
@include('backend.news._filter') | |
<!-- Inline filter form declaration --> | |
<form id="grid_filter">{{csrf_field()}} @include('_partials.form_invalids')</form> | |
<!--// Inline filter form declaration --> | |
<div class="table-responsive"> | |
<table class="table table-bordered table-condensed news-table"> | |
<thead> | |
<!-- Sortable headers--> | |
<tr> | |
@include('backend.grid.sortableTh',['name'=>'#','attribute'=>'id','filter'=>$filter]) | |
@include('backend.grid.sortableTh',['name'=>'Заголовок','attribute'=>'title','filter'=>$filter]) | |
@include('backend.grid.sortableTh',['name'=>'Дата публикации','attribute'=>'public_at', | |
'filter'=>$filter]) | |
@include('backend.grid.sortableTh',['name'=>'Создано','attribute'=>'created_at', | |
'filter'=>$filter]) | |
@include('backend.grid.sortableTh',['name'=>'Статус','attribute'=>'visible','filter'=>$filter]) | |
<th>Операции</th> | |
</tr> | |
</thead> | |
<!-- inline table filters --> | |
<tr id="grid_filter_row"> | |
@include('backend.grid.filters.input_filter',['attribute'=>'id','type'=>'number']) | |
@include('backend.grid.filters.input_filter',['attribute'=>'search']) | |
<td></td> | |
@include('backend.grid.filters.input_filter',['attribute'=>'period_from','type'=>'date']) | |
@include('backend.grid.filters.select_filter', | |
['attribute'=>'visible','variants'=>[0=>'Черновик',1=>'Ок']]) | |
@include('backend.grid.filter_actions') | |
<!--// inline table filters --> | |
</tr> | |
@forelse ($news as $item) | |
<tr id="item-{{$item->id}}"> | |
<td data-column="pk">{{$item->id}}</td> | |
<td data-column="searchable">{{$item->title}}</td> | |
<td data-column="public_at"> {{$item->public_at->format('d.m.Y H:i')}}</td> | |
<td data-column="crated_at"> {{$item->created_at->format('d.m.Y H:i')}}</td> | |
<td>{{ $item->visible?'Ок':'Черновик' }}</td> | |
<td data-column="actions"> | |
@include('backend.grid.actions.edit',['url'=>route('backend.news.edit',['id'=>$item->id])]) | |
@include('backend.grid.actions.view',['url'=>route('backend.news.show',['id'=>$item->id])]) | |
@include('backend.grid.actions.delete',['url'=>route('backend.news.destroy',['id'=>$item->id])]) | |
</td> | |
</tr> | |
@empty | |
<tr> | |
<td colspan="5">Пока ничего не добавлено</td> | |
</tr> | |
@endforelse | |
</table> | |
</div> | |
@slot('footer') | |
{{$news->links()}} | |
@endslot | |
@endcomponent | |
@endsection | |
//---------sort head partial | |
<th> | |
<a href="{{ $filter->buildSortUrl($attribute)}}" title="Сортировать по столбцу"> | |
{{$name}} | |
@if(request()->get('sort')===$attribute) | |
@if(request()->get('order')==='asc') | |
<i class="fa fa-sort-down"></i> | |
@else | |
<i class="fa fa-sort-up"></i> | |
@endif | |
@endif | |
</a> | |
</th> | |
//---------action partial | |
<a href="{{$url}}" class="btn btn-xs btn-default" data-title="Редактировать"> <i class="fa fa-edit"></i></a> | |
//--------filter actions partial | |
<td> | |
<button class="btn btn-sm bg-purple" form="{{$formId or 'grid_filter'}}"><i class="fa fa-search"></i> Найти</button> | |
<button form="{{$formId or 'grid_filter'}}" data-reset="true" | |
data-selector="#{{$formId or 'grid_filter'}}_row" data-submit="0" | |
class="btn btn-sm btn-default">Сброс</button> | |
</td> | |
//------- inline-filter input partial | |
<td> | |
<input type="{{$type or 'text'}}" name="{{$attribute}}" value="{{request()->get($attribute,'')}}" | |
form="{{$formId or 'grid_filter'}}" class="form-control enter-submit"> | |
</td> | |
//------- inline-filter select partial | |
<td> | |
<select name="{{$attribute}}" form="{{$formId or 'grid_filter'}}" class="form-control enter-submit"> | |
<option value="" {{request()->get($attribute,null)===''?'selected':''}}>---</option> | |
@foreach($variants as $index => $variant) | |
<option value="{{$index}}" {{request()->get($attribute,null)===$index?'selected':''}}>{{$variant}}</option> | |
@endforeach | |
</select> | |
<td> | |
//-------External filter form | |
<div id="grid_filter" class="grid_filter"> | |
@include('_partials.form_invalids') | |
<form class="form-inline" method="get" id="grid_filter_form"> | |
{{csrf_field()}} | |
<div class="form-group"> | |
<label for="filter_search">Поиск</label> | |
<input type="text" name="search" id="filter_search" value="{{$filter->get('search','')}}" | |
class="form-control"> | |
</div> | |
<div class="form-group"> | |
<label for="filter_period_from">С даты</label> | |
<input type="date" name="period_from" id="filter_period_from" value="{{$filter->get('period_from','')}}" | |
class="form-control"> | |
</div> | |
<div class="form-group"> | |
<label for="filter_period_to">По дату</label> | |
<input type="date" name="period_to" id="filter_period_to" value="{{$filter->get('period_to','')}}" | |
class="form-control"> | |
</div> | |
<div class="form-group"> | |
<label for="filter_pagesize">На страницу</label> | |
<input type="number" step="5" min="5" max="100" name="pageSize" id="filter_pagesize" | |
value="{{$filter->get('pageSize',20)}}" | |
class="form-control"> | |
</div> | |
<div class="form-group"> | |
<button class="btn btn-sm bg-purple"><i class="fa fa-search"></i> Найти</button> | |
<button type="reset" class="btn btn-sm btn-default">Сброс</button> | |
</div> | |
</form> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment