blobt
5 years ago
17 changed files with 3963 additions and 0 deletions
-
269vendor/blobt/assets/bootstrap-daterangepicker/css/daterangepicker.css
-
1653vendor/blobt/assets/bootstrap-daterangepicker/js/daterangepicker.js
-
203vendor/blobt/grid/ActionColumn.php
-
162vendor/blobt/grid/CheckboxColumn.php
-
40vendor/blobt/grid/Column.php
-
71vendor/blobt/grid/DataColumn.php
-
641vendor/blobt/grid/GridView.php
-
0vendor/blobt/web/AlertifyAsset.php
-
0vendor/blobt/web/DatePickerAsset.php
-
0vendor/blobt/web/DateRangePickerAsset.php
-
51vendor/blobt/web/DaterangeBootstrapAsset.php
-
0vendor/blobt/web/GridViewAsset.php
-
0vendor/blobt/web/Select2Asset.php
-
163vendor/blobt/widgets/DatePicker.php
-
277vendor/blobt/widgets/DateRangePicker.php
-
332vendor/blobt/widgets/Menu.php
-
101vendor/blobt/widgets/Select2.php
@ -0,0 +1,269 @@ |
|||
.daterangepicker { |
|||
position: absolute; |
|||
color: inherit; |
|||
background-color: #fff; |
|||
border-radius: 4px; |
|||
width: 278px; |
|||
padding: 4px; |
|||
margin-top: 1px; |
|||
top: 100px; |
|||
left: 20px; |
|||
/* Calendars */ } |
|||
.daterangepicker:before, .daterangepicker:after { |
|||
position: absolute; |
|||
display: inline-block; |
|||
border-bottom-color: rgba(0, 0, 0, 0.2); |
|||
content: ''; } |
|||
.daterangepicker:before { |
|||
top: -7px; |
|||
border-right: 7px solid transparent; |
|||
border-left: 7px solid transparent; |
|||
border-bottom: 7px solid #ccc; } |
|||
.daterangepicker:after { |
|||
top: -6px; |
|||
border-right: 6px solid transparent; |
|||
border-bottom: 6px solid #fff; |
|||
border-left: 6px solid transparent; } |
|||
.daterangepicker.opensleft:before { |
|||
right: 9px; } |
|||
.daterangepicker.opensleft:after { |
|||
right: 10px; } |
|||
.daterangepicker.openscenter:before { |
|||
left: 0; |
|||
right: 0; |
|||
width: 0; |
|||
margin-left: auto; |
|||
margin-right: auto; } |
|||
.daterangepicker.openscenter:after { |
|||
left: 0; |
|||
right: 0; |
|||
width: 0; |
|||
margin-left: auto; |
|||
margin-right: auto; } |
|||
.daterangepicker.opensright:before { |
|||
left: 9px; } |
|||
.daterangepicker.opensright:after { |
|||
left: 10px; } |
|||
.daterangepicker.dropup { |
|||
margin-top: -5px; } |
|||
.daterangepicker.dropup:before { |
|||
top: initial; |
|||
bottom: -7px; |
|||
border-bottom: initial; |
|||
border-top: 7px solid #ccc; } |
|||
.daterangepicker.dropup:after { |
|||
top: initial; |
|||
bottom: -6px; |
|||
border-bottom: initial; |
|||
border-top: 6px solid #fff; } |
|||
.daterangepicker.dropdown-menu { |
|||
max-width: none; |
|||
z-index: 3001; } |
|||
.daterangepicker.single .ranges, .daterangepicker.single .calendar { |
|||
float: none; } |
|||
.daterangepicker.show-calendar .calendar { |
|||
display: block; } |
|||
.daterangepicker .calendar { |
|||
display: none; |
|||
max-width: 270px; |
|||
margin: 4px; } |
|||
.daterangepicker .calendar.single .calendar-table { |
|||
border: none; } |
|||
.daterangepicker .calendar th, .daterangepicker .calendar td { |
|||
white-space: nowrap; |
|||
text-align: center; |
|||
min-width: 32px; } |
|||
.daterangepicker .calendar-table { |
|||
border: 1px solid #fff; |
|||
padding: 4px; |
|||
border-radius: 4px; |
|||
background-color: #fff; } |
|||
.daterangepicker table { |
|||
width: 100%; |
|||
margin: 0; } |
|||
.daterangepicker td, .daterangepicker th { |
|||
text-align: center; |
|||
width: 20px; |
|||
height: 20px; |
|||
border-radius: 4px; |
|||
border: 1px solid transparent; |
|||
white-space: nowrap; |
|||
cursor: pointer; } |
|||
.daterangepicker td.available:hover, .daterangepicker th.available:hover { |
|||
background-color: #eee; |
|||
border-color: transparent; |
|||
color: inherit; } |
|||
.daterangepicker td.week, .daterangepicker th.week { |
|||
font-size: 80%; |
|||
color: #ccc; } |
|||
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date { |
|||
background-color: #fff; |
|||
border-color: transparent; |
|||
color: #999; } |
|||
.daterangepicker td.in-range { |
|||
background-color: #ebf4f8; |
|||
border-color: transparent; |
|||
color: #000; |
|||
border-radius: 0; } |
|||
.daterangepicker td.start-date { |
|||
border-radius: 4px 0 0 4px; } |
|||
.daterangepicker td.end-date { |
|||
border-radius: 0 4px 4px 0; } |
|||
.daterangepicker td.start-date.end-date { |
|||
border-radius: 4px; } |
|||
.daterangepicker td.active, .daterangepicker td.active:hover { |
|||
background-color: #357ebd; |
|||
border-color: transparent; |
|||
color: #fff; } |
|||
.daterangepicker th.month { |
|||
width: auto; } |
|||
.daterangepicker td.disabled, .daterangepicker option.disabled { |
|||
color: #999; |
|||
cursor: not-allowed; |
|||
text-decoration: line-through; } |
|||
.daterangepicker select.monthselect, .daterangepicker select.yearselect { |
|||
font-size: 12px; |
|||
padding: 1px; |
|||
height: auto; |
|||
margin: 0; |
|||
cursor: default; } |
|||
.daterangepicker select.monthselect { |
|||
margin-right: 2%; |
|||
width: 56%; } |
|||
.daterangepicker select.yearselect { |
|||
width: 40%; } |
|||
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect { |
|||
width: 50px; |
|||
margin-bottom: 0; } |
|||
.daterangepicker .input-mini { |
|||
border: 1px solid #ccc; |
|||
border-radius: 4px; |
|||
color: #555; |
|||
height: 30px; |
|||
line-height: 30px; |
|||
display: block; |
|||
vertical-align: middle; |
|||
margin: 0 0 5px 0; |
|||
padding: 0 6px 0 28px; |
|||
width: 100%; } |
|||
.daterangepicker .input-mini.active { |
|||
border: 1px solid #08c; |
|||
border-radius: 4px; } |
|||
.daterangepicker .daterangepicker_input { |
|||
position: relative; } |
|||
.daterangepicker .daterangepicker_input i { |
|||
position: absolute; |
|||
left: 8px; |
|||
top: 8px; } |
|||
.daterangepicker.rtl .input-mini { |
|||
padding-right: 28px; |
|||
padding-left: 6px; } |
|||
.daterangepicker.rtl .daterangepicker_input i { |
|||
left: auto; |
|||
right: 8px; } |
|||
.daterangepicker .calendar-time { |
|||
text-align: center; |
|||
margin: 5px auto; |
|||
line-height: 30px; |
|||
position: relative; |
|||
padding-left: 28px; } |
|||
.daterangepicker .calendar-time select.disabled { |
|||
color: #ccc; |
|||
cursor: not-allowed; } |
|||
|
|||
.ranges { |
|||
font-size: 11px; |
|||
float: none; |
|||
margin: 4px; |
|||
text-align: left; } |
|||
.ranges ul { |
|||
list-style: none; |
|||
margin: 0 auto; |
|||
padding: 0; |
|||
width: 100%; } |
|||
.ranges li { |
|||
font-size: 13px; |
|||
background-color: #f5f5f5; |
|||
border: 1px solid #f5f5f5; |
|||
border-radius: 4px; |
|||
color: #08c; |
|||
padding: 3px 12px; |
|||
margin-bottom: 8px; |
|||
cursor: pointer; } |
|||
.ranges li:hover { |
|||
background-color: #08c; |
|||
border: 1px solid #08c; |
|||
color: #fff; } |
|||
.ranges li.active { |
|||
background-color: #08c; |
|||
border: 1px solid #08c; |
|||
color: #fff; } |
|||
|
|||
/* Larger Screen Styling */ |
|||
@media (min-width: 564px) { |
|||
.daterangepicker { |
|||
width: auto; } |
|||
.daterangepicker .ranges ul { |
|||
width: 160px; } |
|||
.daterangepicker.single .ranges ul { |
|||
width: 100%; } |
|||
.daterangepicker.single .calendar.left { |
|||
clear: none; } |
|||
.daterangepicker.single.ltr .ranges, .daterangepicker.single.ltr .calendar { |
|||
float: left; } |
|||
.daterangepicker.single.rtl .ranges, .daterangepicker.single.rtl .calendar { |
|||
float: right; } |
|||
.daterangepicker.ltr { |
|||
direction: ltr; |
|||
text-align: left; } |
|||
.daterangepicker.ltr .calendar.left { |
|||
clear: left; |
|||
margin-right: 0; } |
|||
.daterangepicker.ltr .calendar.left .calendar-table { |
|||
border-right: none; |
|||
border-top-right-radius: 0; |
|||
border-bottom-right-radius: 0; } |
|||
.daterangepicker.ltr .calendar.right { |
|||
margin-left: 0; } |
|||
.daterangepicker.ltr .calendar.right .calendar-table { |
|||
border-left: none; |
|||
border-top-left-radius: 0; |
|||
border-bottom-left-radius: 0; } |
|||
.daterangepicker.ltr .left .daterangepicker_input { |
|||
padding-right: 12px; } |
|||
.daterangepicker.ltr .calendar.left .calendar-table { |
|||
padding-right: 12px; } |
|||
.daterangepicker.ltr .ranges, .daterangepicker.ltr .calendar { |
|||
float: left; } |
|||
.daterangepicker.rtl { |
|||
direction: rtl; |
|||
text-align: right; } |
|||
.daterangepicker.rtl .calendar.left { |
|||
clear: right; |
|||
margin-left: 0; } |
|||
.daterangepicker.rtl .calendar.left .calendar-table { |
|||
border-left: none; |
|||
border-top-left-radius: 0; |
|||
border-bottom-left-radius: 0; } |
|||
.daterangepicker.rtl .calendar.right { |
|||
margin-right: 0; } |
|||
.daterangepicker.rtl .calendar.right .calendar-table { |
|||
border-right: none; |
|||
border-top-right-radius: 0; |
|||
border-bottom-right-radius: 0; } |
|||
.daterangepicker.rtl .left .daterangepicker_input { |
|||
padding-left: 12px; } |
|||
.daterangepicker.rtl .calendar.left .calendar-table { |
|||
padding-left: 12px; } |
|||
.daterangepicker.rtl .ranges, .daterangepicker.rtl .calendar { |
|||
text-align: right; |
|||
float: right; } } |
|||
@media (min-width: 730px) { |
|||
.daterangepicker .ranges { |
|||
width: auto; } |
|||
.daterangepicker.ltr .ranges { |
|||
float: left; } |
|||
.daterangepicker.rtl .ranges { |
|||
float: right; } |
|||
.daterangepicker .calendar.left { |
|||
clear: none !important; } } |
1653
vendor/blobt/assets/bootstrap-daterangepicker/js/daterangepicker.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,203 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\grid; |
|||
|
|||
use Yii; |
|||
use yii\helpers\Html; |
|||
use yii\helpers\Url; |
|||
use blobt\grid\Column; |
|||
|
|||
class ActionColumn extends Column { |
|||
|
|||
/** |
|||
* @var string 处理的控制器ID |
|||
*/ |
|||
public $controller; |
|||
|
|||
/** |
|||
* @var string 按钮模板 |
|||
*/ |
|||
public $template = '{view} {update} {delete}'; |
|||
|
|||
/** |
|||
* @var array 以按钮名为键,以匿名函数为值,通过匿名函数返回html,用来控制按钮的表现形式 |
|||
* 匿名函数必须遵循以下申明方式: |
|||
* |
|||
* ```php |
|||
* function ($url, $model, $key) { |
|||
* // return the button HTML code
|
|||
* } |
|||
* ``` |
|||
* |
|||
* - `$url`: 按钮的跳转路径 |
|||
* - `$model`: 每行的模型 |
|||
* - `$key`: id值 |
|||
* |
|||
* 使用案例: |
|||
* ```php |
|||
* [ |
|||
* 'update' => function ($url, $model, $key) { |
|||
* return $model->status === 'editable' ? Html::a('Update', $url) : ''; |
|||
* }, |
|||
* ], |
|||
* |
|||
*/ |
|||
public $buttons = []; |
|||
|
|||
/** @var array 和上述$buttons功能类似,只是匿名函数返回布尔,只控制是否展示 |
|||
* 匿名函数必须遵循以下申明方式: |
|||
* |
|||
* ```php |
|||
* function ($model, $key, $index) { |
|||
* return $model->status === 'editable'; |
|||
* } |
|||
* ``` |
|||
* |
|||
* 使用案例: |
|||
* ```php |
|||
* [ |
|||
* 'update' => \Yii::$app->user->can('update'), |
|||
* ], |
|||
* ``` |
|||
* @since 2.0.7 |
|||
*/ |
|||
public $visibleButtons = []; |
|||
|
|||
/** |
|||
* @var callable 匿名函数,用作控制按钮Url |
|||
* |
|||
* 匿名函数必须遵循以下申明方式: |
|||
* ```php |
|||
* function (string $action, mixed $model, mixed $key, integer $index, ActionColumn $this) { |
|||
* //return string;
|
|||
* } |
|||
* ``` |
|||
* |
|||
* 如果没有设置,默认使用本类的[[createUrl()]]. |
|||
*/ |
|||
public $urlCreator; |
|||
|
|||
/** |
|||
* @var array 按钮的html属性 |
|||
*/ |
|||
public $buttonOptions = []; |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function init() { |
|||
parent::init(); |
|||
$this->initDefaultButtons(); |
|||
} |
|||
|
|||
/** |
|||
* 初始化默认按钮 |
|||
*/ |
|||
protected function initDefaultButtons() { |
|||
$this->initDefaultButton('view', 'eye-open'); |
|||
$this->initDefaultButton('update', 'pencil'); |
|||
$this->initDefaultButton('delete', 'trash', [ |
|||
'alertify-confirm' => Yii::t('yii', 'Are you sure you want to delete this item?') |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 初始化按钮 |
|||
* @param string $name |
|||
* @param string $iconName |
|||
* @param array $additionalOptions 附加html属性 |
|||
*/ |
|||
protected function initDefaultButton($name, $iconName, $additionalOptions = []) { |
|||
if (!isset($this->buttons[$name]) && strpos($this->template, '{' . $name . '}') !== false) { |
|||
$this->buttons[$name] = function ($url, $model, $key) use ($name, $iconName, $additionalOptions) { |
|||
switch ($name) { |
|||
case 'view': |
|||
$title = Yii::t('yii', 'View'); |
|||
break; |
|||
case 'update': |
|||
$title = Yii::t('yii', 'Update'); |
|||
break; |
|||
case 'delete': |
|||
$title = Yii::t('yii', 'Delete'); |
|||
break; |
|||
default: |
|||
$title = ucfirst($name); |
|||
} |
|||
$options = array_merge([ |
|||
'title' => $title, |
|||
'aria-label' => $title, |
|||
'data-pjax' => '0', |
|||
], $additionalOptions, $this->buttonOptions); |
|||
$icon = Html::tag('span', '', ['class' => "glyphicon glyphicon-$iconName"]); |
|||
return Html::a($icon, $url, $options); |
|||
}; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 通过给定的action和model创建一个URL. |
|||
* |
|||
* @param string $action 按钮名 |
|||
* @param \yii\db\ActiveRecordInterface $model 数据模型 |
|||
* @param mixed $key 模型的ID |
|||
* @param int $index 行号 |
|||
* @return string the created URL |
|||
*/ |
|||
public function createUrl($action, $model, $key, $index) { |
|||
if (is_callable($this->urlCreator)) { |
|||
return call_user_func($this->urlCreator, $action, $model, $key, $index, $this); |
|||
} |
|||
|
|||
$params = is_array($key) ? $key : ['id' => (string) $key]; |
|||
$params[0] = $this->controller ? $this->controller . '/' . $action : $action; |
|||
|
|||
return Url::toRoute($params); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
protected function renderDataCellContent($model, $key, $index) { |
|||
return preg_replace_callback('/\\{([\w\-\/]+)\\}/', function ($matches) use ($model, $key, $index) { |
|||
$name = $matches[1]; |
|||
|
|||
if (isset($this->visibleButtons[$name])) { |
|||
$isVisible = $this->visibleButtons[$name] instanceof \Closure ? call_user_func($this->visibleButtons[$name], $model, $key, $index) : $this->visibleButtons[$name]; |
|||
} else { |
|||
$isVisible = true; |
|||
} |
|||
|
|||
if ($isVisible && isset($this->buttons[$name])) { |
|||
$url = $this->createUrl($name, $model, $key, $index); |
|||
return call_user_func($this->buttons[$name], $url, $model, $key); |
|||
} |
|||
|
|||
return ''; |
|||
}, $this->template); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,162 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\grid; |
|||
|
|||
use Closure; |
|||
use yii\base\InvalidConfigException; |
|||
use yii\helpers\Html; |
|||
use yii\helpers\Json; |
|||
use blobt\grid\DataColumn; |
|||
|
|||
class CheckboxColumn extends Column { |
|||
|
|||
/** |
|||
* @var string the name of the input checkbox input fields. This will be appended with `[]` to ensure it is an array. |
|||
*/ |
|||
public $name = 'selection'; |
|||
|
|||
/** |
|||
* @var array|\Closure the HTML attributes for checkboxes. This can either be an array of |
|||
* attributes or an anonymous function ([[Closure]]) that returns such an array. |
|||
* The signature of the function should be the following: `function ($model, $key, $index, $column)`. |
|||
* Where `$model`, `$key`, and `$index` refer to the model, key and index of the row currently being rendered |
|||
* and `$column` is a reference to the [[CheckboxColumn]] object. |
|||
* A function may be used to assign different attributes to different rows based on the data in that row. |
|||
* Specifically if you want to set a different value for the checkbox |
|||
* you can use this option in the following way (in this example using the `name` attribute of the model): |
|||
* |
|||
* ```php |
|||
* 'checkboxOptions' => function ($model, $key, $index, $column) { |
|||
* return ['value' => $model->name]; |
|||
* } |
|||
* ``` |
|||
* |
|||
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. |
|||
*/ |
|||
public $checkboxOptions = []; |
|||
|
|||
/** |
|||
* @var bool whether it is possible to select multiple rows. Defaults to `true`. |
|||
*/ |
|||
public $multiple = true; |
|||
|
|||
/** |
|||
* @var string the css class that will be used to find the checkboxes. |
|||
* @since 2.0.9 |
|||
*/ |
|||
public $cssClass; |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
* @throws \yii\base\InvalidConfigException if [[name]] is not set. |
|||
*/ |
|||
public function init() { |
|||
parent::init(); |
|||
if (empty($this->name)) { |
|||
throw new InvalidConfigException('The "name" property must be set.'); |
|||
} |
|||
if (substr_compare($this->name, '[]', -2, 2)) { |
|||
$this->name .= '[]'; |
|||
} |
|||
|
|||
$this->registerClientScript(); |
|||
} |
|||
|
|||
/** |
|||
* Renders the header cell content. |
|||
* The default implementation simply renders [[header]]. |
|||
* This method may be overridden to customize the rendering of the header cell. |
|||
* @return string the rendering result |
|||
*/ |
|||
protected function renderHeaderCellContent() { |
|||
if ($this->header !== null || !$this->multiple) { |
|||
return parent::renderHeaderCellContent(); |
|||
} |
|||
|
|||
return Html::checkbox($this->getHeaderCheckBoxName(), false, ['class' => 'select-on-check-all']); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
protected function renderDataCellContent($model, $key, $index) { |
|||
if ($this->content !== null) { |
|||
return parent::renderDataCellContent($model, $key, $index); |
|||
} |
|||
|
|||
if ($this->checkboxOptions instanceof Closure) { |
|||
$options = call_user_func($this->checkboxOptions, $model, $key, $index, $this); |
|||
} else { |
|||
$options = $this->checkboxOptions; |
|||
} |
|||
|
|||
if (!isset($options['value'])) { |
|||
$options['value'] = is_array($key) ? Json::encode($key) : $key; |
|||
} |
|||
|
|||
if ($this->cssClass !== null) { |
|||
Html::addCssClass($options, $this->cssClass); |
|||
} |
|||
|
|||
return Html::checkbox($this->name, !empty($options['checked']), $options); |
|||
} |
|||
|
|||
/** |
|||
* Returns header checkbox name. |
|||
* @return string header checkbox name |
|||
* @since 2.0.8 |
|||
*/ |
|||
protected function getHeaderCheckBoxName() { |
|||
$name = $this->name; |
|||
if (substr_compare($name, '[]', -2, 2) === 0) { |
|||
$name = substr($name, 0, -2); |
|||
} |
|||
if (substr_compare($name, ']', -1, 1) === 0) { |
|||
$name = substr($name, 0, -1) . '_all]'; |
|||
} else { |
|||
$name .= '_all'; |
|||
} |
|||
|
|||
return $name; |
|||
} |
|||
|
|||
/** |
|||
* Registers the needed JavaScript. |
|||
* @since 2.0.8 |
|||
*/ |
|||
public function registerClientScript() { |
|||
$id = $this->grid->options['id']; |
|||
$options = Json::encode([ |
|||
'name' => $this->name, |
|||
'class' => $this->cssClass, |
|||
'multiple' => $this->multiple, |
|||
'checkAll' => $this->grid->showHeader ? $this->getHeaderCheckBoxName() : null, |
|||
]); |
|||
$this->grid->getView()->registerJs("jQuery('#$id').yiiGridView('setSelectionColumn', $options);"); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,40 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\grid; |
|||
|
|||
use Closure; |
|||
use yii\base\InvalidConfigException; |
|||
use yii\helpers\Html; |
|||
use yii\helpers\Json; |
|||
use yii\grid\Column as YiiColumn; |
|||
|
|||
class Column extends YiiColumn { |
|||
|
|||
public $width; |
|||
public $align; |
|||
|
|||
} |
@ -0,0 +1,71 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\grid; |
|||
|
|||
/** |
|||
* |
|||
* |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* @created Aug 13, 2019 |
|||
*/ |
|||
class DataColumn extends Column { |
|||
|
|||
/** |
|||
* @var string 本列需要显示的模型属性值, |
|||
* 如果设置了value,则会显示value。 |
|||
*/ |
|||
public $attribute; |
|||
|
|||
/** |
|||
* @var string 列首的label。如果不设置,则会显示attribute关联的label |
|||
*/ |
|||
public $label; |
|||
|
|||
/** |
|||
* @var bool 是否需要html转义 |
|||
*/ |
|||
public $encodeLabel = true; |
|||
|
|||
/** |
|||
* @var string|array|Closure 每个数据模型的值应以哪种格式显示(例如“raw”`、“text”`、“html”`,`[date','php:y-m-d']`)。 |
|||
* 默认格式为“文本” |
|||
*/ |
|||
public $format = 'text'; |
|||
|
|||
/** |
|||
* @var bool 有时候我们记录数据时候,使用了整数值来代替字符,当此属性被设置成true时候, |
|||
* 会视图找到数值对应的字符,并显示出来 |
|||
*/ |
|||
public $showConstText = false; |
|||
|
|||
/** |
|||
* @var bool 是否开始排序 |
|||
*/ |
|||
public $enableSorting = false; |
|||
|
|||
} |
@ -0,0 +1,641 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\grid; |
|||
|
|||
use Closure; |
|||
use Yii; |
|||
use yii\base\InvalidConfigException; |
|||
use yii\base\Model; |
|||
use yii\helpers\Html; |
|||
use yii\helpers\Json; |
|||
use yii\helpers\Url; |
|||
use yii\helpers\ArrayHelper; |
|||
use yii\i18n\Formatter; |
|||
use yii\widgets\BaseListView; |
|||
use blobt\web\GridViewAsset; |
|||
|
|||
/** |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* @created Aug 13, 2019 |
|||
*/ |
|||
class GridView extends BaseListView { |
|||
|
|||
/** |
|||
* @var string 渲染列数据的类,默认是'yii\grid\DataColumn' |
|||
*/ |
|||
public $dataColumnClass; |
|||
|
|||
/** |
|||
* @var array 表格说明的html属性 |
|||
*/ |
|||
public $captionOptions = []; |
|||
|
|||
/** |
|||
* @var array 表格外层div的属性 |
|||
*/ |
|||
public $options = ['class' => 'box']; |
|||
|
|||
/** |
|||
* @var array table的html属性 |
|||
*/ |
|||
public $tableOptions = ['class' => 'table table-bordered table-hover dataTable']; |
|||
|
|||
/** |
|||
* @var array 表格头部html属性 |
|||
*/ |
|||
public $headerRowOptions = []; |
|||
|
|||
/** |
|||
* @var array 表格脚部html属性 |
|||
*/ |
|||
public $footerRowOptions = []; |
|||
|
|||
/** |
|||
* @var array|Cloure 表格每一行的html属性 |
|||
* 这个参数除了可以是一个options数组外,还可以是一个匿名函数,该函数必须返回一个options数组, |
|||
* 渲染每一行都会调用该函数 |
|||
* 该函数必须遵循以下声明规则 |
|||
* ```php |
|||
* function ($model, $key, $index, $grid) |
|||
* ``` |
|||
* |
|||
* - `$model`: 每行的模型 |
|||
* - `$key`: id值 |
|||
* - `$index`: [[dataProvider]]提供的索引号 |
|||
* - `$grid`: GridView 对象 |
|||
*/ |
|||
public $rowOptions = []; |
|||
|
|||
/** |
|||
* @var Closure an 一个匿名函数(结构和[[rowOptions]]一样),每行渲染前后都会被调用 |
|||
*/ |
|||
public $beforeRow; |
|||
public $afterRow; |
|||
|
|||
/** |
|||
* @var bool 是否显示表格头 |
|||
*/ |
|||
public $showHeader = true; |
|||
|
|||
/** |
|||
* @var bool 是否显示表格脚 |
|||
*/ |
|||
public $showFooter = false; |
|||
|
|||
/** |
|||
* @var bool 没有数据情况下是否显示 |
|||
*/ |
|||
public $showOnEmpty = true; |
|||
|
|||
/** |
|||
* @var array|Formatter 用来格式化输出属性值 |
|||
*/ |
|||
public $formatter; |
|||
|
|||
/** |
|||
* @var string 摘要的显示样式 |
|||
* |
|||
* |
|||
* - `{begin}`: 开始条数 |
|||
* - `{end}`: 结束条数 |
|||
* - `{count}`: 显示条数 |
|||
* - `{totalCount}`: 总记录条数 |
|||
* - `{page}`: 显示分页 |
|||
* - `{pageCount}`: 总分页数 |
|||
* - `{select}`: 显示页数 |
|||
*/ |
|||
public $summary = "{select} 显示{begin}~{end}条 共{totalCount}条"; |
|||
|
|||
/** |
|||
* @var array 摘要的html属性 |
|||
*/ |
|||
public $summaryOptions = ['class' => 'summary']; |
|||
|
|||
/** |
|||
* @var array 列配置数组. 数组每一项代表一个列,列数组可以包括class、attribute、format、label等。 |
|||
* 例子: |
|||
* ```php |
|||
* [ |
|||
* ['class' => SerialColumn::className()], |
|||
* [ |
|||
* 'class' => DataColumn::className(), //渲染用到的类,没一列都默认使用[[DataColumn]]渲染,所以这里可以忽略
|
|||
* 'attribute' => 'name', //代表每一行的数据原
|
|||
* 'format' => 'text', //输出的格式
|
|||
* 'label' => 'Name', //label
|
|||
* '' => '' |
|||
* ], |
|||
* ['class' => CheckboxColumn::className()], |
|||
* ] |
|||
* ``` |
|||
* |
|||
* 当然,也支持简写成这样:[[DataColumn::attribute|attribute]], [[DataColumn::format|format]], |
|||
* 或 [[DataColumn::label|label]] options: `"attribute:format:label"`. |
|||
* 所以上面例子的 "name" 列能简写成这样 : `"name:text:Name"`. |
|||
* 甚至"format"和"label"都是可以不制定的,因为它们都有默认值。 |
|||
* |
|||
* 其实大多数情况下都可以使用简写: |
|||
* |
|||
* ```php |
|||
* [ |
|||
* 'id', |
|||
* 'amount:currency:Total Amount', |
|||
* 'created_at:datetime', |
|||
* ] |
|||
* ``` |
|||
* |
|||
* 当[[dataProvider]]提供active records, 且active record又和其它 active record建立了关联关系的, |
|||
* 例如 the `name` 属性是 和 `author` 关联,那么你可以这样制定数据: |
|||
* |
|||
* ```php |
|||
* // shortcut syntax
|
|||
* 'author.name', |
|||
* // full syntax
|
|||
* [ |
|||
* 'attribute' => 'author.name', |
|||
* // ...
|
|||
* ] |
|||
* ``` |
|||
*/ |
|||
public $columns = []; |
|||
|
|||
/** |
|||
* @var string 当单元格数据为空时候显示的内容。 |
|||
*/ |
|||
public $emptyCell = ' '; |
|||
|
|||
/** |
|||
* @var string TODO:这个目前用来做页数选择,具体原理没有研究清楚 |
|||
*/ |
|||
public $filterSelector = 'select[name="per-page"]'; |
|||
|
|||
/** |
|||
* @var type |
|||
*/ |
|||
public $filter; |
|||
|
|||
/** |
|||
* @var array 批量操作的选项 |
|||
*/ |
|||
public $batch; |
|||
|
|||
/** |
|||
* @var string 表格的layout: |
|||
* |
|||
* - `{summary}`: 摘要. |
|||
* - `{items}`: 表格项. |
|||
* - `{pager}`: 分页. |
|||
* - `{batch}`: 批量处理 |
|||
*/ |
|||
public $layout = <<< HTML |
|||
<div class="box-body"> |
|||
<div id="example2_wrapper" class="dataTables_wrapper form-inline dt-bootstrap"> |
|||
<div class="row"> |
|||
<div class="error-summary"><ul></ul></div> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-3"> |
|||
{batch} |
|||
<a href="create" class="btn btn-default"><i class="fa fa-plus"></i>添加</a> |
|||
<button type="button" class="btn btn-default"><i class="fa fa-file-excel-o"></i>导出</button> |
|||
</div> |
|||
<div class="col-sm-9"> |
|||
{filter} |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12"> |
|||
{items} |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-5"> |
|||
<div class="dataTables_info" id="example2_info" role="status" aria-live="polite"> |
|||
{summary} |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-7"> |
|||
<div class="dataTables_paginate paging_simple_numbers"> |
|||
{pager} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
HTML; |
|||
public $batchTemplate = <<< HTML |
|||
<div class="btn-group"> |
|||
<button type="button" class="btn btn-default btn checkbox-toggle"><i class="fa fa-square-o"></i></button> |
|||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">批量操作</button> |
|||
<ul class="dropdown-menu" role="menu"> |
|||
{items} |
|||
</ul> |
|||
</div> |
|||
HTML; |
|||
|
|||
/** |
|||
* 初始化 grid view. |
|||
* 初始化必须的属性和每个列对象 |
|||
* @return |
|||
*/ |
|||
public function init() { |
|||
parent::init(); |
|||
if ($this->formatter === null) { |
|||
$this->formatter = Yii::$app->getFormatter(); |
|||
} elseif (is_array($this->formatter)) { |
|||
$this->formatter = Yii::createObject($this->formatter); |
|||
} |
|||
if (!$this->formatter instanceof Formatter) { |
|||
throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.'); |
|||
} |
|||
|
|||
$this->initColumns(); |
|||
} |
|||
|
|||
public function run() { |
|||
$view = $this->getView(); |
|||
GridViewAsset::register($view); |
|||
$this->registerGridJs(); |
|||
$this->registerIcheckJs(); |
|||
$this->registerConfirmJs(); |
|||
parent::run(); |
|||
} |
|||
|
|||
/** |
|||
* 注册GridView Js |
|||
*/ |
|||
protected function registerGridJs() { |
|||
$options = Json::htmlEncode(['filterUrl' => Url::to(Yii::$app->request->url), |
|||
'filterSelector' => $this->filterSelector]); |
|||
$id = $this->options['id']; |
|||
$this->getView()->registerJs("jQuery('#$id').yiiGridView($options);"); |
|||
} |
|||
|
|||
/** |
|||
* 注册icheck Js |
|||
*/ |
|||
protected function registerIcheckJs() { |
|||
$js = <<<SCRIPT |
|||
$('.dataTable input[type="checkbox"]').iCheck({ |
|||
checkboxClass: 'icheckbox_flat-blue', |
|||
radioClass: 'iradio_flat-blue' |
|||
}); |
|||
$(".checkbox-toggle").click(function () { |
|||
var clicks = $(this).data('clicks'); |
|||
if (clicks) { |
|||
//Uncheck all checkboxes
|
|||
$(".dataTable input[type='checkbox']").iCheck("uncheck"); |
|||
$(".fa", this).removeClass("fa-check-square-o").addClass('fa-square-o'); |
|||
} else { |
|||
//Check all checkboxes
|
|||
$(".dataTable input[type='checkbox']").iCheck("check"); |
|||
$(".fa", this).removeClass("fa-square-o").addClass('fa-check-square-o'); |
|||
} |
|||
$(this).data("clicks", !clicks); |
|||
}); |
|||
SCRIPT; |
|||
$this->getView()->registerJs($js); |
|||
} |
|||
|
|||
/** |
|||
* 注册批量操作js |
|||
*/ |
|||
protected function registerBatchJs() { |
|||
$js = <<<SCRIPT |
|||
$("a.batch_item").click(function(){ |
|||
var url = $(this).data("url"); |
|||
var act = $(this).text(); |
|||
var selected = []; |
|||
|
|||
$(".checked input").each(function(){ |
|||
selected.push($(this).val()); |
|||
}); |
|||
|
|||
if(selected.length > 0){ |
|||
alertify.confirm('系统提示', "确定执行批量 '"+act+"' 操作?", function(){ |
|||
$.ajax({ |
|||
type: "POST", |
|||
url: url, |
|||
traditional:true, |
|||
data:{ 'ids[]':selected}, |
|||
dataType: "json", |
|||
async:false |
|||
}); |
|||
window.location.reload(); |
|||
},function(){ |
|||
|
|||
}); |
|||
} |
|||
return false; |
|||
}) |
|||
SCRIPT; |
|||
$this->getView()->registerJs($js); |
|||
} |
|||
|
|||
protected function registerConfirmJs() { |
|||
$js = <<<SCRIPT |
|||
$("a[alertify-confirm]").click(function(){ |
|||
var message = $(this).attr('alertify-confirm'); |
|||
var url = $(this).attr('href'); |
|||
var id = $(this).data('id'); |
|||
alertify.confirm('系统提示', message,function(){ |
|||
$.ajax({ |
|||
type: "POST", |
|||
url: url, |
|||
traditional:true, |
|||
data:{ id:id }, |
|||
dataType: "json", |
|||
async:false |
|||
}); |
|||
window.location.reload(); |
|||
},function(){ |
|||
|
|||
}); |
|||
return false; |
|||
}); |
|||
SCRIPT; |
|||
$this->getView()->registerJs($js); |
|||
} |
|||
|
|||
/** |
|||
* 渲染局部 |
|||
* @return string|bool |
|||
*/ |
|||
public function renderSection($name) { |
|||
switch ($name) { |
|||
case '{summary}': |
|||
return $this->renderSummary(); |
|||
case '{items}': |
|||
return $this->renderItems(); |
|||
case '{pager}': |
|||
return $this->renderPager(); |
|||
case '{sorter}': |
|||
return $this->renderSorter(); |
|||
case '{filter}': |
|||
return $this->renderFilter(); |
|||
case '{batch}': |
|||
return $this->renderBatch(); |
|||
default: |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 渲染表格的html真实table |
|||
* @return string |
|||
*/ |
|||
public function renderItems() { |
|||
$tableHeader = $this->showHeader ? $this->renderTableHeader() : false; |
|||
$tableBody = $this->renderTableBody(); |
|||
|
|||
$content = array_filter([ |
|||
$tableHeader, |
|||
$tableBody |
|||
]); |
|||
|
|||
return Html::tag('table', implode("\n", $content), $this->tableOptions); |
|||
} |
|||
|
|||
/** |
|||
* 初始化每列 |
|||
* @throws InvalidConfigException |
|||
*/ |
|||
protected function initColumns() { |
|||
if (empty($this->columns)) { |
|||
throw new InvalidConfigException('The "columns" property must be set.'); |
|||
} |
|||
|
|||
foreach ($this->columns as $i => $column) { |
|||
if (is_string($column)) { |
|||
$column = $this->createDataColumn($column); |
|||
} else { |
|||
$column = Yii::createObject(array_merge([ |
|||
'class' => $this->dataColumnClass ?: DataColumn::className(), |
|||
'grid' => $this, |
|||
], $column)); |
|||
} |
|||
if (!$column->visible) { |
|||
unset($this->columns[$i]); |
|||
continue; |
|||
} |
|||
|
|||
$this->columns[$i] = $column; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 渲染表头 |
|||
* @return string |
|||
*/ |
|||
public function renderTableHeader() { |
|||
$cells = []; |
|||
foreach ($this->columns as $column) { |
|||
/* @var $column Column */ |
|||
$cells[] = $column->renderHeaderCell(); |
|||
} |
|||
|
|||
$content = Html::tag('tr', implode('', $cells), $this->headerRowOptions); |
|||
return "<thead>\n" . $content . "\n</thead>"; |
|||
} |
|||
|
|||
/** |
|||
* 渲染表格体 |
|||
* @return string |
|||
*/ |
|||
public function renderTableBody() { |
|||
$models = $this->dataProvider->getModels(); |
|||
$keys = $this->dataProvider->getKeys(); |
|||
$rows = []; |
|||
|
|||
foreach ($models as $index => $model) { |
|||
$key = $keys[$index]; |
|||
|
|||
if ($this->beforeRow !== null) { |
|||
$row = call_user_func($this->beforeRow, $model, $key, $index, $this); |
|||
if (!empty($row)) { |
|||
$rows[] = $row; |
|||
} |
|||
} |
|||
|
|||
$rows[] = $this->renderTableRow($model, $key, $index); |
|||
|
|||
if ($this->afterRow !== null) { |
|||
$row = call_user_func($this->afterRow, $model, $key, $index, $this); |
|||
if (!empty($row)) { |
|||
$rows[] = $row; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (empty($rows) && $this->emptyText !== false) { |
|||
$colspan = count($this->columns); |
|||
|
|||
return "<tbody>\n<tr><td colspan=\"$colspan\">" . $this->renderEmpty() . "</td></tr>\n</tbody>";
|
|||
} |
|||
|
|||
return "<tbody>\n" . implode("\n", $rows) . "\n</tbody>"; |
|||
} |
|||
|
|||
/** |
|||
* 渲染表格的每行 |
|||
* @param Objetc $model |
|||
* @param int $key |
|||
* @param int $index |
|||
* @return string |
|||
*/ |
|||
public function renderTableRow($model, $key, $index) { |
|||
$cells = []; |
|||
foreach ($this->columns as $column) { |
|||
$cells[] = $column->renderDataCell($model, $key, $index); |
|||
} |
|||
if ($this->rowOptions instanceof Closure) { |
|||
$options = call_user_func($this->rowOptions, $model, $key, $index, $this); |
|||
} else { |
|||
$options = $this->rowOptions; |
|||
} |
|||
$options['data-key'] = is_array($key) ? json_encode($key) : (string) $key; |
|||
|
|||
//TODO 各行变色放到这里不合理
|
|||
if ($index % 2 == 0) { |
|||
$oddEven = 'odd'; |
|||
} else { |
|||
$oddEven = 'even'; |
|||
} |
|||
|
|||
if (isset($options['class'])) { |
|||
$options['class'] += " " . $oddEven; |
|||
} else { |
|||
$options['class'] = $oddEven; |
|||
} |
|||
|
|||
return Html::tag('tr', implode('', $cells), $options); |
|||
} |
|||
|
|||
/** |
|||
* 渲染摘要显示 |
|||
* @return string |
|||
*/ |
|||
public function renderSummary() { |
|||
$count = $this->dataProvider->getCount(); |
|||
if ($count <= 0) { |
|||
return ''; |
|||
} |
|||
$summaryOptions = $this->summaryOptions; |
|||
$tag = ArrayHelper::remove($summaryOptions, 'tag', 'div'); |
|||
if (($pagination = $this->dataProvider->getPagination()) !== false) { |
|||
$totalCount = $this->dataProvider->getTotalCount(); |
|||
$begin = $pagination->getPage() * $pagination->pageSize + 1; |
|||
$end = $begin + $count - 1; |
|||
if ($begin > $end) { |
|||
$begin = $end; |
|||
} |
|||
$page = $pagination->getPage() + 1; |
|||
$pageCount = $pagination->pageCount; |
|||
} |
|||
|
|||
return Yii::$app->getI18n()->format($this->summary, [ |
|||
'begin' => $begin, |
|||
'end' => $end, |
|||
'count' => $count, |
|||
'totalCount' => $totalCount, |
|||
'page' => $page, |
|||
'pageCount' => $pageCount, |
|||
'select' => $this->renderCountSelect() |
|||
], Yii::$app->language); |
|||
} |
|||
|
|||
/** |
|||
* 渲染批量操作 |
|||
*/ |
|||
public function renderBatch() { |
|||
if (empty($this->batch) && !is_array($this->batch)) { |
|||
return ""; |
|||
} |
|||
|
|||
$this->registerBatchJs(); |
|||
|
|||
$items = ""; |
|||
foreach ($this->batch as $item) { |
|||
$items .= Html::tag('li', Html::a(Html::encode($item['label']), '#', ["data-url" => Html::encode($item['url']), "class" => "batch_item"])); |
|||
} |
|||
|
|||
return strtr($this->batchTemplate, [ |
|||
"{items}" => $items |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 渲染表格的页数select |
|||
* @return string |
|||
*/ |
|||
protected function renderCountSelect() { |
|||
$items = [ |
|||
"20" => 20, |
|||
"50" => 50, |
|||
"100" => 100 |
|||
]; |
|||
|
|||
$per = "条/页"; |
|||
|
|||
$options = []; |
|||
foreach ($items as $key => $val) { |
|||
$options[$val] = "{$key}{$per}"; |
|||
} |
|||
|
|||
$perPage = !empty($_GET['per-page']) ? $_GET['per-page'] : 20; |
|||
return Html::dropDownList('per-page', $perPage, $options, ["class" => "form-control input-sm"]); |
|||
} |
|||
|
|||
/** |
|||
* 渲染表格的筛选部分 |
|||
* @return string |
|||
*/ |
|||
protected function renderFilter() { |
|||
return $this->filter; |
|||
} |
|||
|
|||
/** |
|||
* 根据给定格式,创建一个 [[DataColumn]] 对象 |
|||
* @param string $text DataColumn 格式 |
|||
* @return DataColumn 实例 |
|||
* @throws InvalidConfigException |
|||
*/ |
|||
protected function createDataColumn($text) { |
|||
if (!preg_match('/^([^:]+)(:(\w*))?(:(.*))?$/', $text, $matches)) { |
|||
throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:label"'); |
|||
} |
|||
|
|||
return Yii::createObject([ |
|||
'class' => $this->dataColumnClass ?: DataColumn::className(), |
|||
'grid' => $this, |
|||
'attribute' => $matches[1], |
|||
'format' => isset($matches[3]) ? $matches[3] : 'text', |
|||
'label' => isset($matches[5]) ? $matches[5] : null, |
|||
]); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,51 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\web; |
|||
|
|||
use yii\web\AssetBundle; |
|||
|
|||
/** |
|||
* Description of AdminlteAsset |
|||
* |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* @created Aug 27, 2019 |
|||
*/ |
|||
class DaterangeBootstrapAsset extends AssetBundle { |
|||
|
|||
public $sourcePath = "@blobt/assets/bootstrap-daterangepicker"; |
|||
public $css = [ |
|||
'css/daterangepicker.css' |
|||
]; |
|||
public $js = [ |
|||
'js/daterangepicker.js' |
|||
]; |
|||
public $depends = [ |
|||
'yii\bootstrap\BootstrapAsset', |
|||
]; |
|||
|
|||
} |
@ -0,0 +1,163 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\widgets; |
|||
|
|||
use yii\widgets\InputWidget; |
|||
use Yii; |
|||
use yii\base\InvalidConfigException; |
|||
use yii\helpers\ArrayHelper; |
|||
use yii\helpers\Html; |
|||
use yii\web\JsExpression; |
|||
use yii\helpers\Json; |
|||
use blobt\web\DatepickBootstrapAsset; |
|||
use blobt\helpers\DatetimeHelper; |
|||
|
|||
/** |
|||
* 此DatePicker只适用于使用Unix时间戳保存时间的model |
|||
* |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* @created Aug 19, 2019 |
|||
*/ |
|||
class DatePicker extends InputWidget { |
|||
|
|||
/** |
|||
* @var string 日期显示格式 |
|||
*/ |
|||
public $format = "Y-m-d"; |
|||
|
|||
/** |
|||
* @var string datepicker的日期显示input框的id,只用做显示 |
|||
*/ |
|||
public $pickerInputId; |
|||
|
|||
/** |
|||
* @var boll 是否自动填充当天日期 |
|||
*/ |
|||
public $autoFill = false; |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
* @throws InvalidConfigException |
|||
* @throws \ReflectionException |
|||
*/ |
|||
public function run() { |
|||
$this->initSetting(); |
|||
$this->registerAsset(); |
|||
echo $this->renderHiddenInput(); |
|||
echo $this->renderDatapickerInput(); |
|||
} |
|||
|
|||
/** |
|||
* 初始化小物件的配置 |
|||
*/ |
|||
protected function initSetting() { |
|||
//初始化日期格式
|
|||
if (empty($this->format)) { |
|||
$this->format = Yii::$app->formatter->dateFormat; |
|||
} |
|||
|
|||
//关闭自动完成
|
|||
$this->options["autocomplete"] = "off"; |
|||
|
|||
//生成一个picker input的 id
|
|||
$this->pickerInputId = $this->options['id'] . "_" . Yii::$app->security->generateRandomKey(32); |
|||
} |
|||
|
|||
/** |
|||
* 注册js和css |
|||
*/ |
|||
protected function registerAsset() { |
|||
$view = $this->getView(); |
|||
DatepickBootstrapAsset::register($view); |
|||
|
|||
$options = [ |
|||
"format" => $this->convertDateFormat($this->format), |
|||
"language" => "zh-CN" |
|||
]; |
|||
$jsOptions = Json::encode($options); |
|||
|
|||
|
|||
$js = <<< SCRIPT |
|||
$('#{$this->pickerInputId}').datepicker({$jsOptions}).on('changeDate', function(e) { |
|||
$('#{$this->options['id']}').val(String(e.date.getTime()).substring(0,10)); |
|||
});; |
|||
SCRIPT; |
|||
$view->registerJs($js); |
|||
} |
|||
|
|||
/** |
|||
* 渲染一个用作保存Datepicker Unix时间错的hidden input |
|||
* @return string |
|||
*/ |
|||
protected function renderHiddenInput() { |
|||
if ($this->hasModel()) { |
|||
return Html::activeInput('hidden', $this->model, $this->attribute, $this->options); |
|||
} |
|||
return Html::input('hidden', $this->name, $this->value, $this->options); |
|||
} |
|||
|
|||
/** |
|||
* TODO:自动填充了今天为默认日期 |
|||
* 渲染一个用作显示日期的字符格式 text input |
|||
* @return string |
|||
*/ |
|||
protected function renderDatapickerInput() { |
|||
$value = ''; |
|||
$options = $this->options; |
|||
$options['id'] = $this->pickerInputId; |
|||
|
|||
if ($this->hasModel()) { |
|||
$timestamp = ArrayHelper::getValue($this->model, $this->attribute); |
|||
} |
|||
|
|||
if (empty($timestamp) && $this->autoFill) { |
|||
$timestamp = time(); |
|||
$value = date($this->format, $timestamp); |
|||
} |
|||
|
|||
return Html::input('text', $this->name, $value, $options); |
|||
} |
|||
|
|||
/** |
|||
* 转换php日期格式为bootstrap日期格式 |
|||
* |
|||
* TODO:没有弄清所有格式的转换,后续添加 |
|||
* |
|||
* @param string $format PHP日期格式字符串 |
|||
* @return string |
|||
*/ |
|||
protected static function convertDateFormat($format) { |
|||
$conversions = [ |
|||
'd' => 'dd', |
|||
'm' => 'mm', |
|||
'Y' => 'yyyy', |
|||
]; |
|||
return strtr($format, $conversions); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,277 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\widgets; |
|||
|
|||
use yii\widgets\InputWidget; |
|||
use Yii; |
|||
use yii\base\InvalidConfigException; |
|||
use yii\helpers\ArrayHelper; |
|||
use yii\helpers\Html; |
|||
use yii\web\JsExpression; |
|||
use blobt\helpers\DatetimeHelper; |
|||
use blobt\web\DaterangeBootstrapAsset; |
|||
use yii\helpers\Json; |
|||
|
|||
/** |
|||
* |
|||
* |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* @created Aug 13, 2019 |
|||
*/ |
|||
class DateRangePicker extends InputWidget { |
|||
|
|||
/** |
|||
* @var boolean 是否需要把值做转义 |
|||
*/ |
|||
public $encodeValue = true; |
|||
|
|||
/** |
|||
* @var array input的html属性 |
|||
*/ |
|||
public $options = []; |
|||
|
|||
/** |
|||
* @var string label |
|||
*/ |
|||
public $label = "日期范围"; |
|||
|
|||
/** |
|||
* @var string 确定按钮显示内容 |
|||
*/ |
|||
public $applyLabel = "确定"; |
|||
|
|||
/** |
|||
* @var string 关闭按钮显示内容 |
|||
*/ |
|||
public $cancelLabel = "关闭"; |
|||
|
|||
/** |
|||
* @var string 自定义按钮显示内容 |
|||
*/ |
|||
public $customRangeLabel = "自定义"; |
|||
|
|||
/** |
|||
* @var array 星期一到星期日的显示 |
|||
*/ |
|||
public $daysOfWeek = ["日", "一", "二", "三", "四", "五", "六"]; |
|||
|
|||
/** |
|||
* @var array 12个月份的显示 |
|||
*/ |
|||
public $monthNames = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]; |
|||
|
|||
/** |
|||
* @var array 选择器的基础配置参数 |
|||
*/ |
|||
protected $locale = []; |
|||
|
|||
/** |
|||
* @var 快捷选择建 |
|||
*/ |
|||
public $ranges = []; |
|||
|
|||
/** |
|||
* @var string 选择器默认选中的开始日期 |
|||
*/ |
|||
public $startDate; |
|||
|
|||
/** |
|||
* @var string 选择器默认选中的结束日期 |
|||
*/ |
|||
public $endDate; |
|||
|
|||
/** |
|||
* @var string 左侧显示的图标 |
|||
*/ |
|||
public $iconClass = "fa fa-calendar"; |
|||
|
|||
/** |
|||
* @var string 日期显示格式 |
|||
*/ |
|||
public $format = "Y-m-d"; |
|||
|
|||
/** |
|||
* @var string 选择框打开的位置 |
|||
*/ |
|||
public $opens = 'left'; |
|||
|
|||
/** |
|||
* @var bool 是否自动填入日期 |
|||
*/ |
|||
public $autoFill = false; |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
* @throws InvalidConfigException |
|||
* @throws \ReflectionException |
|||
*/ |
|||
public function run() { |
|||
$this->initSetting(); |
|||
$this->registerAsset(); |
|||
|
|||
echo $this->renderInputHtml('text'); |
|||
} |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
*/ |
|||
public function init() { |
|||
parent::init(); |
|||
} |
|||
|
|||
/** |
|||
* 初始化小物件的配置 |
|||
*/ |
|||
protected function initSetting() { |
|||
//初始化日期格式
|
|||
if (empty($this->format)) { |
|||
$this->format = Yii::$app->formatter->dateFormat; |
|||
} |
|||
$this->format = $this->convertDateFormat($this->format); |
|||
|
|||
//初始化基础配置
|
|||
$this->locale = [ |
|||
'cancelLabel' => $this->cancelLabel, |
|||
'applyLabel' => $this->applyLabel, |
|||
"customRangeLabel" => $this->customRangeLabel, |
|||
"daysOfWeek" => $this->daysOfWeek, |
|||
"monthNames" => $this->monthNames, |
|||
"format" => $this->format |
|||
]; |
|||
//初始化快捷键
|
|||
$this->initRange(); |
|||
|
|||
//关闭自动提示
|
|||
$this->options = ArrayHelper::merge($this->options, [ |
|||
"autocomplete" => "off", |
|||
"class" => "form-control", |
|||
"style" => "width:190px;" |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 注册js和css |
|||
*/ |
|||
protected function registerAsset() { |
|||
$view = $this->getView(); |
|||
DaterangeBootstrapAsset::register($view); |
|||
|
|||
|
|||
$options = [ |
|||
"opens" => $this->opens, |
|||
"autoUpdateInput" => $this->autoFill, |
|||
"locale" => $this->locale, |
|||
"ranges" => $this->ranges |
|||
]; |
|||
|
|||
if (!empty($this->startDate)) { |
|||
$options["startDate"] = new JsExpression("moment('{$this->startDate}')"); |
|||
} |
|||
if (!empty($this->endDate)) { |
|||
$options["endDate"] = new JsExpression("moment('{$this->endDate}')"); |
|||
} |
|||
|
|||
|
|||
$jsOptions = Json::encode($options); |
|||
$js = <<< SCRIPT |
|||
$('#{$this->options['id']}').daterangepicker({$jsOptions}); |
|||
$('#{$this->options['id']}').on('apply.daterangepicker', function(ev, picker) { |
|||
$(this).val(picker.startDate.format('{$this->format}') + ' ~ ' + picker.endDate.format('{$this->format}')); |
|||
}); |
|||
|
|||
$('#{$this->options['id']}').on('cancel.daterangepicker', function(ev, picker) { |
|||
$(this).val(''); |
|||
}); |
|||
SCRIPT; |
|||
$view->registerJs($js); |
|||
} |
|||
|
|||
/** |
|||
* 初始化快捷按键数组 |
|||
*/ |
|||
protected function initRange() { |
|||
$this->ranges = [ |
|||
'今天' => [new JsExpression("moment()"), new JsExpression("moment()")], |
|||
'昨天' => [new JsExpression("moment().subtract(1, 'days')"), new JsExpression("moment().subtract(1, 'days')")], |
|||
'最近7天' => [new JsExpression("moment().subtract(6, 'days')"), new JsExpression("moment()")], |
|||
'最近30天' => [new JsExpression("moment().subtract(29, 'days')"), new JsExpression("moment()")], |
|||
'本月' => [new JsExpression("moment().startOf('month')"), new JsExpression("moment().endOf('month')")], |
|||
'上月' => [new JsExpression("moment().subtract(1, 'month').startOf('month')"), new JsExpression("moment().subtract(1, 'month').endOf('month')")] |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* 转换php日期格式为Moment.js 日期格式 |
|||
* @param string $format PHP日期格式字符串 |
|||
* @return string |
|||
*/ |
|||
protected static function convertDateFormat($format) { |
|||
$conversions = [ |
|||
// second (带有前导零)
|
|||
's' => 'ss', |
|||
// minute (带有前导零)
|
|||
'i' => 'mm', |
|||
// hour in 12-hour format (没带前导零)
|
|||
'g' => 'h', |
|||
// hour in 12-hour format (带有前导零)
|
|||
'h' => 'hh', |
|||
// hour in 24-hour format (没带前导零)
|
|||
'G' => 'H', |
|||
// hour in 24-hour format (带有前导零)
|
|||
'H' => 'HH', |
|||
// day of the week locale
|
|||
'w' => 'e', |
|||
// day of the week ISO
|
|||
'W' => 'E', |
|||
// day of month (没带前导零)
|
|||
'j' => 'D', |
|||
// day of month (带有前导零)
|
|||
'd' => 'DD', |
|||
// day name short
|
|||
'D' => 'DDD', |
|||
// day name long
|
|||
'l' => 'DDDD', |
|||
// month of year (没带前导零)
|
|||
'n' => 'M', |
|||
// month of year (带有前导零)
|
|||
'm' => 'MM', |
|||
// month name short
|
|||
'M' => 'MMM', |
|||
// month name long
|
|||
'F' => 'MMMM', |
|||
// year (2位年)
|
|||
'y' => 'YY', |
|||
// year (4位年)
|
|||
'Y' => 'YYYY', |
|||
// unix timestamp
|
|||
'U' => 'X', |
|||
]; |
|||
return strtr($format, $conversions); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,332 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\widgets; |
|||
|
|||
use Yii; |
|||
use yii\base\Widget; |
|||
use yii\helpers\ArrayHelper; |
|||
use yii\helpers\Html; |
|||
use yii\helpers\Url; |
|||
|
|||
/** |
|||
* 参照yii\widgets\Menu,根据AdminLTE样式从写的一个小物件 |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* 使用例子 |
|||
* <?php |
|||
* echo Menu::widget([ |
|||
* 'items' => [ |
|||
* ['label' => 'MAIN NAVIGATION', 'is_header' => true], |
|||
* ['label' => 'Documentation', 'url' => 'https:www.baidu.com', 'icon' => 'fa-book'], |
|||
* ['label' => 'Products', 'url' => ['product/index'], 'items' => [ |
|||
* ['label' => 'New Arrivals', 'url' => ['product/index', 'tag' => 'new']], |
|||
* ['label' => 'Most Popular', 'url' => ['product/index', 'tag' => 'popular']], |
|||
* ]], |
|||
* ['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], |
|||
* ] |
|||
* ]); |
|||
* ?>
|
|||
* |
|||
* |
|||
*/ |
|||
class Menu extends Widget { |
|||
|
|||
/** |
|||
* @var array 菜单的item数组。 |
|||
* 菜单的item同时也是一个数组,结构如下所述: |
|||
* lable: string, optional,指定选项的label |
|||
* encode:boolean, optional,label是否需要转义 |
|||
* url: string or array, optional, 生产菜单的路径 |
|||
* 产生结果和yii的Url::to()方法一致,并且会套用[[linkTemplate]]模板 |
|||
* visible: boolean, optional, 选项是否可见,默认是true(可见) |
|||
* active: boolean or Closure, optional, 是否被选中 |
|||
* 如果为true,则会在css中添加[[activeCssClass]] |
|||
* 当使用Closure时候,匿名函数必须是`function ($item, $hasActiveChild, $isItemActive, $widget)` |
|||
* 匿名函数必须返回true或者false |
|||
* 如果不是使用匿名函数,就会使用[[isItemActive]]来判断item是否被选中 |
|||
* items: array, optional, 指定子菜单选项,格式和父菜单是一样的 |
|||
* template: string, optional,选项的渲染模板 |
|||
* submenuTemplate: string, optional, 子菜单渲染模板 |
|||
* options: array, optional, 指定html属性 |
|||
*/ |
|||
public $items = []; |
|||
|
|||
/** |
|||
* @var array html属性,这些指定的属性会加到所有的item中 |
|||
*/ |
|||
public $itemOptions = []; |
|||
|
|||
/** |
|||
* @var string 链接的渲染模板 |
|||
*/ |
|||
public $linkTemplateWithSub = "<a href=\"{url}\"><i class=\"fa {icon}\"></i><span>{label}</span><span class=\"pull-right-container\"><i class=\"fa fa-angle-left pull-right\"></i></span></a>"; |
|||
public $linkTemplateNoSub = "<a href=\"{url}\"><i class=\"fa {icon}\"></i><span>{label}</span></a>"; |
|||
|
|||
/** |
|||
* @var string label的渲染模板 |
|||
*/ |
|||
public $labelTemplate = '{label}'; |
|||
|
|||
/** |
|||
* @var string 子菜单的渲染模板 |
|||
*/ |
|||
public $submenuTemplate = "\n<ul class=\"treeview-menu\">\n{items}\n</ul>\n"; |
|||
|
|||
/** |
|||
* @var boolean label是否要进行html转义 |
|||
*/ |
|||
public $encodeLabels = true; |
|||
|
|||
/** |
|||
* @var string 被选中的菜单的CSS类 |
|||
*/ |
|||
public $activeCssClass = 'active'; |
|||
|
|||
/** |
|||
* @var string 控制二级菜单开合 |
|||
*/ |
|||
public $menuOpenClass = 'menu-open'; |
|||
|
|||
/** |
|||
* @var boolean 是否根据路由去判断菜单项是否被选中 |
|||
*/ |
|||
public $activateItems = true; |
|||
|
|||
/** |
|||
* @var boolean 当某一个子菜单的选中时候是否也关联选中父菜单 |
|||
*/ |
|||
public $activateParents = true; |
|||
|
|||
/** |
|||
* @var boolean 如果item的url没有设置时,是否不显示该item |
|||
*/ |
|||
public $hideEmptyItems = true; |
|||
|
|||
/** |
|||
* @var array 菜单容器标签的属性 |
|||
*/ |
|||
public $options = [ |
|||
'class' => 'sidebar-menu', |
|||
'data-widget' => 'tree' |
|||
]; |
|||
|
|||
/** |
|||
* @var string 第一个菜单item的css类 |
|||
*/ |
|||
public $firstItemCssClass; |
|||
|
|||
/** |
|||
* @var string 最后一个菜单item的css类 |
|||
*/ |
|||
public $lastItemCssClass; |
|||
|
|||
/** |
|||
* @var string 路由 ,run的时候会自动获取当前路由 |
|||
*/ |
|||
public $route; |
|||
|
|||
/** |
|||
* @var string $_GET参数 |
|||
*/ |
|||
public $params; |
|||
|
|||
/** |
|||
* @var string 菜单项默认Icon |
|||
*/ |
|||
public $defaultIcon = 'fa-circle-o'; |
|||
|
|||
/** |
|||
* 渲染菜单 |
|||
*/ |
|||
public function run() { |
|||
if ($this->route === null && Yii::$app->controller !== null) { |
|||
$this->route = Yii::$app->controller->getRoute(); |
|||
} |
|||
if ($this->params === null) { |
|||
$this->params = Yii::$app->request->getQueryParams(); |
|||
} |
|||
|
|||
$items = $this->normalizeItems($this->items, $hasActiveChild); |
|||
|
|||
if (!empty($items)) { |
|||
$options = $this->options; |
|||
$tag = ArrayHelper::remove($options, 'tag', 'ul'); |
|||
return Html::tag($tag, $this->renderItems($items), $options); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 渲染菜单 |
|||
* @param array $items |
|||
* @return string 渲染结果 |
|||
*/ |
|||
protected function renderItems($items) { |
|||
$lines = []; |
|||
foreach ($items as $i => $item) { |
|||
/* 获取菜单项的自定义属性 */ |
|||
$options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); |
|||
$tag = ArrayHelper::remove($options, 'tag', 'li'); |
|||
$class = []; |
|||
|
|||
if ($item['active']) { |
|||
$class[] = $this->activeCssClass; |
|||
if (isset($item['items'])) { |
|||
$class[] = $this->menuOpenClass; |
|||
} |
|||
} |
|||
if ($i === 0 && $this->firstItemCssClass !== null) { |
|||
$class[] = $this->firstItemCssClass; |
|||
} |
|||
if ($i === $n - 1 && $this->lastItemCssClass !== null) { |
|||
$class[] = $this->lastItemCssClass; |
|||
} |
|||
if (isset($item['items'])) { |
|||
$class[] = 'treeview'; |
|||
} |
|||
if (isset($item['is_header']) && $item['is_header']) { |
|||
$class[] = "header"; |
|||
} |
|||
|
|||
Html::addCssClass($options, $class); |
|||
|
|||
$menu = $this->renderItem($item); |
|||
if (!empty($item['items'])) { |
|||
$submenuTemplate = ArrayHelper::getValue($item, 'submenuTemplate', $this->submenuTemplate); |
|||
$menu .= strtr($submenuTemplate, [ |
|||
'{items}' => $this->renderItems($item['items']), |
|||
]); |
|||
} |
|||
|
|||
$lines[] = Html::tag($tag, $menu, $options); |
|||
} |
|||
return implode("\n", $lines); |
|||
} |
|||
|
|||
/** |
|||
* 渲染菜单项 |
|||
* @param array $item |
|||
* @return string 渲染结果 |
|||
*/ |
|||
protected function renderItem($item) { |
|||
if (isset($item['url'])) { |
|||
if (isset($item['template'])) { |
|||
$template = $item['template']; |
|||
} else { |
|||
$template = isset($item['items']) ? $this->linkTemplateWithSub : $this->linkTemplateNoSub; |
|||
} |
|||
return strtr($template, [ |
|||
'{url}' => Html::encode(Url::to($item['url'])), |
|||
'{label}' => Html::encode($item['label']), |
|||
'{icon}' => Html::encode($item['icon']) |
|||
]); |
|||
} |
|||
|
|||
$template = ArrayHelper::getValue($item, 'template', $this->labelTemplate); |
|||
|
|||
return strtr($template, [ |
|||
'{label}' => $item['label'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 判断菜单项是否被选中 |
|||
* @param $item array |
|||
* @return boolean $item |
|||
*/ |
|||
protected function isItemActive($item) { |
|||
if (isset($item['url']) && is_array($item['url']) && isset($item['url'][0])) { |
|||
$route = Yii::getAlias($item['url'][0]); |
|||
|
|||
if ($route[0] !== '/' && Yii::$app->controller) { |
|||
$route = Yii::$app->controller->module->getUniqueId() . '/' . $route; |
|||
} |
|||
|
|||
if (ltrim($route, '/') !== $this->route) { |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 格式化菜单item |
|||
* @param string $item |
|||
* @param bool $active |
|||
*/ |
|||
protected function normalizeItems($items, &$active) { |
|||
foreach ($items as $i => $item) { |
|||
/* 去除visible 为 false的item */ |
|||
if (isset($item['visible']) && !$item['visible']) { |
|||
unset($items[$i]); |
|||
continue; |
|||
} |
|||
|
|||
/* 添加默认icon */ |
|||
if (!isset($item['icon'])) { |
|||
if (!empty($this->defaultIcon)) { |
|||
$items[$i]['icon'] = $this->defaultIcon; |
|||
} |
|||
} |
|||
|
|||
/* 添加label */ |
|||
if (!isset($item['label'])) { |
|||
$item['label'] = ''; |
|||
} |
|||
|
|||
/* 转义HTML */ |
|||
$encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels; |
|||
if ($encodeLabel) { |
|||
$items[$i]['label'] = Html::encode($item['label']); |
|||
} |
|||
|
|||
/* 格式化子菜单 item */ |
|||
$hasActiveChild = false; |
|||
if (isset($item['items'])) { |
|||
$items[$i]['items'] = $this->normalizeItems($item['items'], $hasActiveChild); |
|||
if (empty($items[$i]['items']) && $this->hideEmptyItems) { |
|||
unset($items[$i]['items']); |
|||
} |
|||
} |
|||
|
|||
/* 处理菜单是否被选中 */ |
|||
if (!isset($item['active'])) { |
|||
if ($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item)) { |
|||
$active = $items[$i]['active'] = true; |
|||
} |
|||
} elseif ($item['active'] instanceof Closure) { |
|||
$active = $items[$i]['active'] = call_user_func($item['active'], $item, $hasActiveChild, $this->isItemActive($item), $this); |
|||
} elseif ($item['active']) { |
|||
$active = true; |
|||
} |
|||
} |
|||
return array_values($items); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,101 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* The MIT License |
|||
* |
|||
* Copyright 2019 Blobt. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
|
|||
namespace blobt\widgets; |
|||
|
|||
use yii\widgets\InputWidget; |
|||
use Yii; |
|||
use yii\base\InvalidConfigException; |
|||
use yii\helpers\ArrayHelper; |
|||
use yii\helpers\Html; |
|||
use blobt\web\Select2Asset; |
|||
|
|||
/** |
|||
* Description of Select2 |
|||
* |
|||
* @author Blobt |
|||
* @email 380255922@qq.com |
|||
* @created Aug 20, 2019 |
|||
*/ |
|||
class Select2 extends InputWidget { |
|||
|
|||
/** |
|||
* @var array select的选项 |
|||
*/ |
|||
public $data = []; |
|||
|
|||
/** |
|||
* @var array select 的html选择 |
|||
*/ |
|||
public $options; |
|||
|
|||
/** |
|||
* @inheritdoc |
|||
* @throws \ReflectionException |
|||
* @throws \yii\base\InvalidConfigException |
|||
*/ |
|||
public function run() { |
|||
d($this->id); |
|||
$this->registerAsset(); |
|||
$this->registerSelect2Js(); |
|||
return $this->renderSelect(); |
|||
} |
|||
|
|||
public function init() { |
|||
parent::init(); |
|||
if ($this->hasModel() && !isset($options['name'])) { |
|||
$this->name = $this->options['name'] = Html::getInputName($this->model, $this->attribute); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 注册js和css |
|||
*/ |
|||
protected function registerAsset() { |
|||
$view = $this->getView(); |
|||
Select2Asset::register($view); |
|||
} |
|||
|
|||
protected function registerSelect2Js() { |
|||
$js = <<<SCRIPT |
|||
$('#category-icon_type').select2(); |
|||
SCRIPT; |
|||
$this->getView()->registerJs($js); |
|||
} |
|||
|
|||
/** |
|||
* 渲染一个select |
|||
* @return string |
|||
*/ |
|||
protected function renderSelect() { |
|||
$value = null; |
|||
if ($this->hasModel()) { |
|||
$value = ArrayHelper::getValue($this->model, $this->attribute); |
|||
} |
|||
return Html::dropDownList($this->name, $value, $this->data, $this->options); |
|||
} |
|||
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue