diff --git a/assets/FontawesomeIconpickerAsset.php b/assets/FontawesomeIconpickerAsset.php new file mode 100644 index 0000000..b8c2bd5 --- /dev/null +++ b/assets/FontawesomeIconpickerAsset.php @@ -0,0 +1,19 @@ +=2.5" + "bower-asset/chart.js": ">=2.5", + "bower-asset/fontawesome-iconpicker": "^1.3" }, "require-dev": { "yiisoft/yii2-debug": "*", diff --git a/composer.lock b/composer.lock index 6698d95..1540710 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "47716d6fa73b8f351afd27ba07ca61ea", - "content-hash": "510df4f657a11c48c1c48bbc30239f09", + "hash": "d72e15d1c94855a26467586b784ffcb8", + "content-hash": "50f7bcdee8e1349910fd57865528edf4", "packages": [ { "name": "bower-asset/bootstrap", @@ -87,6 +87,42 @@ ], "description": "Simple HTML5 charts using the canvas element." }, + { + "name": "bower-asset/fontawesome-iconpicker", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/itsjavi/fontawesome-iconpicker.git", + "reference": "6087c66a7395738f59cab3887221bb75cd0e08f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/itsjavi/fontawesome-iconpicker/zipball/6087c66a7395738f59cab3887221bb75cd0e08f7", + "reference": "6087c66a7395738f59cab3887221bb75cd0e08f7", + "shasum": "" + }, + "require": { + "bower-asset/bootstrap": ">=3.0.0,<4.0.0", + "bower-asset/jquery": ">=1.10" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": [ + "dist/css/fontawesome-iconpicker.css", + "dist/css/fontawesome-iconpicker.min.css", + "dist/js/fontawesome-iconpicker.js", + "dist/js/fontawesome-iconpicker.min.js" + ], + "bower-asset-ignore": [ + "\\.*", + "/extension", + "/src", + "index.html", + "/package.json", + "/Gruntfile.js" + ] + } + }, { "name": "bower-asset/handlebars", "version": "v4.0.5", diff --git a/config/main.php b/config/main.php index d20aa51..cc5c9ac 100644 --- a/config/main.php +++ b/config/main.php @@ -44,6 +44,11 @@ return [ 'admin///' => 'admin//', 'admin//' => 'admin//view', 'admin/s' => 'admin//index', + [ + 'class' => 'yii\rest\UrlRule', + 'controller' => ['api/room', 'api/item'], + 'pluralize' => false, + ], ], ], 'view' => [ @@ -53,20 +58,14 @@ return [ 'force_charset' => 'UTF-8', ], 'formatter' => [ -// 'dateFormat' => 'dd.MM.yyyy', -// 'datetimeFormat' => 'php:d.m.Y H:i', 'defaultTimeZone' => 'Europe/Kiev', 'timeZone' => 'Europe/Kiev', ], 'assetManager' => [ 'appendTimestamp' => true, 'bundles' => [ - 'dmstr\web\AdminLteAsset' => [ -// 'skin' => 'skin-purple', - ], 'yii\bootstrap\BootstrapAsset' => [ 'css' => [], -// 'js' => [], ], ], ], diff --git a/giiTemplates/crud/my/views/index.php b/giiTemplates/crud/my/views/index.php index d897040..7ce6c0b 100644 --- a/giiTemplates/crud/my/views/index.php +++ b/giiTemplates/crud/my/views/index.php @@ -17,27 +17,23 @@ echo "indexWidgetType === 'grid' ? "yii\\grid\\GridView" : "yii\\widgets\\ListView" ?>; -enablePjax ? 'use yii\widgets\Pjax;' : '' ?> +indexWidgetType === 'grid' ? null : "use yii\\widgets\\ListView;" ?> +enablePjax ? 'use yii\widgets\Pjax;' . "\n" : '' ?> $this->title = generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>; $this->params['breadcrumbs'][] = $this->title; +$this->params['in-card'] = false; ?> -
-

- Html::a(generateString('Добавить') ?>, ['create'], ['class' => 'btn btn-success']) ?> -

-searchModelClass)): ?> -indexWidgetType === 'grid' ? "// " : "") ?>echo $this->render('_search', ['model' => $searchModel]); ?> - +
+
+ Html::a(generateString('Добавить') ?>, ['create'], ['class' => 'btn btn-default btn-flat']) ?> +
enablePjax ? ' ' . "\n" : '' ?> indexWidgetType === 'grid'): ?> - GridView::widget([ + \app\widgets\DataTable::widget([ 'dataProvider' => $dataProvider, - 'summaryOptions' => ['class' => 'alert alert-info'], - 'layout' => '{summary}
{items}
{pager}', searchModelClass) ? "'filterModel' => \$searchModel,\n 'columns' => [\n" : "'columns' => [\n"; ?> params['breadcrumbs'][] = $this->title;

- Html::a(, ['update', ], ['class' => 'btn btn-primary']) ?> - Html::a(, ['delete', ], [ + Html::a('', ['update', ], ['class' => 'btn btn-primary']) ?> + Html::a('', ['delete', ], [ 'class' => 'btn btn-danger', 'data' => [ 'confirm' => generateString('Are you sure you want to delete this item?') ?>, diff --git a/migrations/m170303_125418_create_item_widget.php b/migrations/m170303_125418_create_item_widget.php new file mode 100644 index 0000000..46b96c9 --- /dev/null +++ b/migrations/m170303_125418_create_item_widget.php @@ -0,0 +1,45 @@ +db->driverName === 'mysql') { + $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; + } + + $this->createTable('item_widget', [ + 'id' => $this->primaryKey(), + 'active' => $this->boolean()->defaultValue(true), + 'type' => $this->smallInteger()->notNull(), + 'value_type' => $this->smallInteger(), + 'sort_order' => $this->integer()->defaultValue(0), + 'item_id' => $this->integer()->notNull(), + 'room_id' => $this->integer(), + 'name' => $this->string()->notNull(), + 'html_class' => $this->string(), + 'icon' => $this->string()->notNull(), + ], $tableOptions); + + $this->createIndex('idx-item_widget-item_id', 'item_widget', 'item_id'); + $this->addForeignKey('fk-item_widget-item_id', 'item_widget', 'item_id', 'item', 'id', 'CASCADE'); + + $this->createIndex('idx-item_widget-room_id', 'item_widget', 'room_id'); + $this->addForeignKey('fk-item_widget-room_id', 'item_widget', 'room_id', 'room', 'id', 'CASCADE'); + } + + public function safeDown() + { + $this->dropForeignKey('fk-item_widget-item_id', 'item_widget'); + $this->dropIndex('idx-item_widget-item_id', 'item_widget'); + + $this->dropForeignKey('fk-item_widget-room_id', 'item_widget'); + $this->dropIndex('idx-item_widget-room_id', 'item_widget'); + + $this->dropTable('item_widget'); + } +} diff --git a/migrations/m170303_150337_create_widgets_for_items.php b/migrations/m170303_150337_create_widgets_for_items.php new file mode 100644 index 0000000..2679cc6 --- /dev/null +++ b/migrations/m170303_150337_create_widgets_for_items.php @@ -0,0 +1,44 @@ +all() as $item) { + $itemWidget = new ItemWidget(); + $itemWidget->active = true; + $itemWidget->item_id = $item->id; + $itemWidget->room_id = $item->room_id; + $itemWidget->name = $item->name; + $itemWidget->html_class = $item->class; + $itemWidget->icon = 'fa-' . $item->icon; + + $itemWidget->type = $item->type; + + if ($item->type == 21 or $item->type == 22 or $item->type == 25 or $item->type == 26) { + $itemWidget->type = 20; + + if ($item->type == 21) { + $itemWidget->value_type = ItemWidget::VALUE_TYPE_CELSIUS; + } elseif ($item->type == 22) { + $itemWidget->value_type = ItemWidget::VALUE_TYPE_PERCENT; + } elseif ($item->type == 25) { + $itemWidget->value_type = ItemWidget::VALUE_TYPE_BOOLEAN; + } elseif ($item->type == 26) { + $itemWidget->value_type = ItemWidget::VALUE_TYPE_DOOR; + } + } + + $itemWidget->save(); + } + } + + public function safeDown() + { + return 0; + } +} diff --git a/migrations/m170303_164850_fix_items.php b/migrations/m170303_164850_fix_items.php new file mode 100644 index 0000000..cbe6f60 --- /dev/null +++ b/migrations/m170303_164850_fix_items.php @@ -0,0 +1,26 @@ +dropColumn('item', 'active'); + $this->dropColumn('item', 'room_id'); + $this->dropColumn('item', 'bg'); + $this->dropColumn('item', 'class'); + $this->dropColumn('item', 'icon'); + $this->dropColumn('item', 'sort_order'); + } + + public function safeDown() + { + $this->addColumn('item', 'active', $this->boolean()->defaultValue(true)); + $this->addColumn('item', 'room_id', $this->integer()->notNull()); + $this->addColumn('item', 'bg', $this->string()); + $this->addColumn('item', 'class', $this->string()); + $this->addColumn('item', 'icon', $this->string()->notNull()); + $this->addColumn('item', 'sort_order', $this->integer()->defaultValue(0)); + } +} diff --git a/models/Item.php b/models/Item.php index 2a8e32e..19453a1 100644 --- a/models/Item.php +++ b/models/Item.php @@ -11,25 +11,20 @@ use yii\helpers\ArrayHelper; * This is the model class for table "item". * * @property integer $id - * @property boolean $active * @property integer $type * @property integer $update_interval * @property boolean $enable_log * @property integer $save_history_interval - * @property integer $room_id * @property integer $board_id * @property integer $pin * @property string $url * @property string $name - * @property string $icon - * @property string $bg - * @property string $class - * @property integer $sort_order * @property string $default_value * * @property History[] $histories * @property Room $room * @property Board $board + * @property ItemWidget $widget */ class Item extends ActiveRecord { @@ -77,19 +72,12 @@ class Item extends ActiveRecord public function rules() { return [ - [['active', 'type', 'room_id', 'name', 'icon', 'bg', 'board_id'], 'required'], + [['type', 'name', 'board_id'], 'required'], [ - ['type', 'update_interval', 'save_history_interval', 'room_id', 'sort_order', 'board_id', 'pin'], + ['type', 'update_interval', 'save_history_interval', 'board_id', 'pin'], 'integer' ], - [['url', 'name', 'icon', 'bg', 'class', 'default_value'], 'string', 'max' => 255], - [ - ['room_id'], - 'exist', - 'skipOnError' => true, - 'targetClass' => Room::className(), - 'targetAttribute' => ['room_id' => 'id'] - ], + [['url', 'name', 'default_value'], 'string', 'max' => 255], [ ['board_id'], 'exist', @@ -97,9 +85,7 @@ class Item extends ActiveRecord 'targetClass' => Board::className(), 'targetAttribute' => ['board_id' => 'id'] ], - [['sort_order', 'update_interval', 'save_history_interval'], 'default', 'value' => 0], - [['active', 'enable_log'], 'default', 'value' => true], - [['active', 'enable_log'], 'boolean'], + [['update_interval', 'save_history_interval'], 'default', 'value' => 0], [['default_value'], 'default', 'value' => null], ]; } @@ -111,20 +97,14 @@ class Item extends ActiveRecord { return [ 'id' => Yii::t('app', 'ID'), - 'active' => Yii::t('app', 'Активно'), 'enable_log' => Yii::t('app', 'Логирование'), 'type' => Yii::t('app', 'Тип'), 'update_interval' => Yii::t('app', 'Интервал обновления'), 'save_history_interval' => Yii::t('app', 'Интервал сохранения в историю'), - 'room_id' => Yii::t('app', 'Комната'), 'board_id' => Yii::t('app', 'Плата'), 'url' => Yii::t('app', 'Url'), 'pin' => Yii::t('app', 'Pin'), 'name' => Yii::t('app', 'Название'), - 'icon' => Yii::t('app', 'Иконка'), - 'bg' => Yii::t('app', 'CSS Background'), - 'class' => Yii::t('app', 'CSS Класс'), - 'sort_order' => Yii::t('app', 'Порядок сортировки'), 'default_value' => Yii::t('app', 'Значение по умолчанию'), ]; } @@ -140,17 +120,17 @@ class Item extends ActiveRecord /** * @return \yii\db\ActiveQuery */ - public function getRoom() + public function getBoard() { - return $this->hasOne(Room::className(), ['id' => 'room_id'])->inverseOf('items'); + return $this->hasOne(Board::className(), ['id' => 'board_id'])->inverseOf('items'); } /** * @return \yii\db\ActiveQuery */ - public function getBoard() + public function getWidget() { - return $this->hasOne(Board::className(), ['id' => 'board_id'])->inverseOf('items'); + return $this->hasOne(ItemWidget::className(), ['item_id' => 'id'])->inverseOf('item'); } /** @@ -174,7 +154,7 @@ class Item extends ActiveRecord self::TYPE_VARIABLE_BOOLEAN_DOOR => 'Переменная boolean дверь', self::TYPE_VARIABLE_TEMPERATURE => 'Переменная температура', self::TYPE_VARIABLE_HUMIDITY => 'Переменная влажность', - self::TYPE_RGB => 'RGB LED', + self::TYPE_RGB => 'RGB', ]; } @@ -188,16 +168,15 @@ class Item extends ActiveRecord /** * @param bool $prependId - * @param bool $appendRoomName * @return array */ - public static function getList($prependId = false, $appendRoomName = false) + public static function getList($prependId = false) { /** @var self[] $models */ $models = self::find()->all(); $result = []; - if (!$appendRoomName and !$prependId) { + if (!$prependId) { return ArrayHelper::map($models, 'id', 'name'); } @@ -210,10 +189,6 @@ class Item extends ActiveRecord $title .= $model->name; - if ($appendRoomName) { - $title .= ' - ' . $model->room->name; - } - $result[$model->id] = $title; } diff --git a/models/ItemSearch.php b/models/ItemSearch.php index 99ec892..6a4f44e 100644 --- a/models/ItemSearch.php +++ b/models/ItemSearch.php @@ -63,8 +63,6 @@ class ItemSearch extends Item 'type' => $this->type, 'update_interval' => $this->update_interval, 'save_history_interval' => $this->save_history_interval, - 'room_id' => $this->room_id, - 'sort_order' => $this->sort_order, ]); $query->andFilterWhere(['like', 'url', $this->url]) diff --git a/models/ItemWidget.php b/models/ItemWidget.php new file mode 100644 index 0000000..2bcd4e1 --- /dev/null +++ b/models/ItemWidget.php @@ -0,0 +1,158 @@ + true], + [['type'], 'in', 'range' => self::getTypesArray()], + [['value_type'], 'in', 'range' => self::getValueTypesArray()], + [['name', 'item_id', 'icon', 'type'], 'required'], + [['name', 'html_class', 'icon'], 'string', 'max' => 255], + [['item_id'], 'exist', 'skipOnError' => true, 'targetClass' => Item::className(), 'targetAttribute' => ['item_id' => 'id']], + [['room_id'], 'exist', 'skipOnError' => true, 'targetClass' => Room::className(), 'targetAttribute' => ['room_id' => 'id']], + ]; + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'id' => Yii::t('app', 'ID'), + 'active' => Yii::t('app', 'Активно'), + 'type' => Yii::t('app', 'Тип'), + 'value_type' => Yii::t('app', 'Тип Значения'), + 'sort_order' => Yii::t('app', 'Порядок сортировки'), + 'item_id' => Yii::t('app', 'Элемент'), + 'room_id' => Yii::t('app', 'Комната'), + 'name' => Yii::t('app', 'Название'), + 'html_class' => Yii::t('app', 'HTML класс'), + 'icon' => Yii::t('app', 'Иконка'), + ]; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getItem() + { + return $this->hasOne(Item::className(), ['id' => 'item_id'])->inverseOf('widget'); + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getRoom() + { + return $this->hasOne(Room::className(), ['id' => 'room_id'])->inverseOf('itemWidgets'); + } + + /** + * @inheritdoc + * @return ItemWidgetQuery the active query used by this AR class. + */ + public static function find() + { + return new ItemWidgetQuery(get_called_class()); + } + + /** + * @return string + */ + public function getName() + { + if ($this->name != null) { + return $this->name; + } + + return $this->item->name; + } + + /** + * @return array + */ + public static function getTypes() + { + return [ + self::TYPE_SWITCH => 'Переключатель', + self::TYPE_VARIABLE => 'Переменная', + self::TYPE_RGB => 'RGB', + ]; + } + + /** + * @return array + */ + public static function getTypesArray() + { + return array_keys(self::getTypes()); + } + + /** + * @return array + */ + public static function getValueTypes() + { + return [ + self::VALUE_TYPE_BOOLEAN => 'Boolean', + self::VALUE_TYPE_DOOR => 'Дверь', + self::VALUE_TYPE_CELSIUS => 'Цельсии', + self::VALUE_TYPE_PERCENT => 'Проценты', + ]; + } + + /** + * @return array + */ + public static function getValueTypesArray() + { + return array_keys(self::getValueTypes()); + } +} diff --git a/models/ItemWidgetQuery.php b/models/ItemWidgetQuery.php new file mode 100644 index 0000000..d9a33d0 --- /dev/null +++ b/models/ItemWidgetQuery.php @@ -0,0 +1,63 @@ +andWhere(['active' => true]); + } + + /** + * @return $this + */ + public function switches() + { + return $this->andWhere(['type' => ItemWidget::TYPE_SWITCH]); + } + + /** + * @return $this + */ + public function variables() + { + return $this->andWhere(['type' => ItemWidget::TYPE_VARIABLE]); + } + + /** + * @return $this + */ + public function rgb() + { + return $this->andWhere(['type' => ItemWidget::TYPE_RGB]); + } + + /** + * @inheritdoc + * @return ItemWidget[]|array + */ + public function all($db = null) + { + return parent::all($db); + } + + /** + * @inheritdoc + * @return ItemWidget|array|null + */ + public function one($db = null) + { + return parent::one($db); + } +} diff --git a/models/Room.php b/models/Room.php index ace37a8..d501df8 100644 --- a/models/Room.php +++ b/models/Room.php @@ -55,6 +55,14 @@ class Room extends \yii\db\ActiveRecord return $this->hasMany(Item::className(), ['room_id' => 'id'])->inverseOf('room'); } + /** + * @return \yii\db\ActiveQuery|ItemWidgetQuery + */ + public function getItemWidgets() + { + return $this->hasMany(ItemWidget::className(), ['room_id' => 'id'])->inverseOf('room'); + } + /** * @inheritdoc * @return RoomQuery the active query used by this AR class. diff --git a/modules/admin/controllers/ItemWidgetController.php b/modules/admin/controllers/ItemWidgetController.php new file mode 100644 index 0000000..9efc836 --- /dev/null +++ b/modules/admin/controllers/ItemWidgetController.php @@ -0,0 +1,125 @@ + [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Lists all ItemWidget models. + * @return mixed + */ + public function actionIndex() + { + $searchModel = new ItemWidgetSearch(); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Displays a single ItemWidget model. + * @param integer $id + * @return mixed + */ + public function actionView($id) + { + return $this->render('view', [ + 'model' => $this->findModel($id), + ]); + } + + /** + * Creates a new ItemWidget model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new ItemWidget(); + $model->active = true; + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } else { + return $this->render('create', [ + 'model' => $model, + ]); + } + } + + /** + * Updates an existing ItemWidget model. + * If update is successful, the browser will be redirected to the 'view' page. + * @param integer $id + * @return mixed + */ + public function actionUpdate($id) + { + $model = $this->findModel($id); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', 'id' => $model->id]); + } else { + return $this->render('update', [ + 'model' => $model, + ]); + } + } + + /** + * Deletes an existing ItemWidget model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * @param integer $id + * @return mixed + */ + public function actionDelete($id) + { + $this->findModel($id)->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the ItemWidget model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * @param integer $id + * @return ItemWidget the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel($id) + { + if (($model = ItemWidget::findOne($id)) !== null) { + return $model; + } else { + throw new NotFoundHttpException('The requested page does not exist.'); + } + } +} diff --git a/modules/admin/models/ItemSearch.php b/modules/admin/models/ItemSearch.php index 9f6a7ec..7a2f101 100644 --- a/modules/admin/models/ItemSearch.php +++ b/modules/admin/models/ItemSearch.php @@ -18,7 +18,7 @@ class ItemSearch extends Item public function rules() { return [ - [['id', 'type', 'room_id', 'board_id', 'sort_order', 'pin'], 'integer'], + [['id', 'type', 'board_id', 'pin'], 'integer'], [['url', 'name'], 'safe'], ]; } @@ -61,9 +61,7 @@ class ItemSearch extends Item $query->andFilterWhere([ 'id' => $this->id, 'type' => $this->type, - 'room_id' => $this->room_id, 'board_id' => $this->board_id, - 'sort_order' => $this->sort_order, 'pin' => $this->pin, ]); diff --git a/modules/admin/models/ItemWidgetSearch.php b/modules/admin/models/ItemWidgetSearch.php new file mode 100644 index 0000000..28ed98c --- /dev/null +++ b/modules/admin/models/ItemWidgetSearch.php @@ -0,0 +1,75 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'active' => $this->active, + 'sort_order' => $this->sort_order, + 'item_id' => $this->item_id, + 'room_id' => $this->room_id, + ]); + + $query->andFilterWhere(['like', 'name', $this->name]) + ->andFilterWhere(['like', 'html_class', $this->html_class]) + ->andFilterWhere(['like', 'icon', $this->icon]); + + return $dataProvider; + } +} diff --git a/modules/admin/views/item-widget/_form.php b/modules/admin/views/item-widget/_form.php new file mode 100644 index 0000000..fb42fb8 --- /dev/null +++ b/modules/admin/views/item-widget/_form.php @@ -0,0 +1,119 @@ +registerJs(" +$('.fontawesome-iconpicker-input').iconpicker({container: 'body', inputSearch: true,}); +", \yii\web\View::POS_READY); +?> + +

+ + + +
+
+ field($model, 'item_id')->widget(Select2::className(), [ + 'data' => Item::getList(true), + 'pluginEvents' => [ + 'change' => "function(e) { + $.get({ + url: '" . \yii\helpers\Url::to([ + '/api/item/view', + 'access-token' => Yii::$app->user->identity->api_key, + ]) . "&id=' + $('#itemwidget-item_id').val(), + success: function (data) { + if (data) { + $('#itemwidget-name').val(data.name).change(); + + var widgetType = data.type; + var valueType; + + if (data.type == 20 || data.type == 21 || data.type == 22 || data.type == 25 || data.type == 26) { + widgetType = 20; + $('.field-itemwidget-value_type').fadeIn().removeClass('hidden'); + } + + if (data.type == 21) { + valueType = 30; + } + + if (data.type == 22) { + valueType = 40; + } + + if (data.type == 25) { + valueType = 10; + } + + if (data.type == 26) { + valueType = 20; + } + + $('#itemwidget-type').val(widgetType).change(); + $('#itemwidget-value_type').val(valueType).change(); + } + } + }); + }", + ], + 'options' => [ + 'placeholder' => 'Выберите элемент ...', + ], + ]) ?> + + field($model, 'name')->textInput(['maxlength' => true]) ?> + + field($model, 'type')->widget(Select2::className(), [ + 'data' => ItemWidget::getTypes(), + 'options' => [ + 'placeholder' => 'Выберите тип ...', + ], + ]) ?> + + field($model, 'value_type', ['options' => ['class' => 'form-group hidden']])->widget(Select2::className(), [ + 'data' => ItemWidget::getValueTypes(), + 'options' => [ + 'placeholder' => 'Выберите тип значения ...', + ], + ]) ?> + + field($model, 'active')->checkbox() ?> +
+
+ field($model, 'icon')->textInput([ + 'maxlength' => true, + 'class' => 'fontawesome-iconpicker-input form-control' + ]) ?> + + field($model, 'room_id')->widget(Select2::className(), [ + 'data' => Room::getList(), + 'options' => [ + 'placeholder' => 'Выберите комнату ...', + ], + ]) ?> + + field($model, 'html_class')->textInput(['maxlength' => true]) ?> + + field($model, 'sort_order')->input('number') ?> +
+
+ +
+ isNewRecord ? 'Добавить' : 'Сохранить', ['class' => 'btn btn-primary']) ?> +
+ + + +
diff --git a/modules/admin/views/item-widget/create.php b/modules/admin/views/item-widget/create.php new file mode 100644 index 0000000..8df393a --- /dev/null +++ b/modules/admin/views/item-widget/create.php @@ -0,0 +1,18 @@ +title = 'Добавить Item Widget'; +$this->params['breadcrumbs'][] = ['label' => 'Item Widgets', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/modules/admin/views/item-widget/index.php b/modules/admin/views/item-widget/index.php new file mode 100644 index 0000000..682e59a --- /dev/null +++ b/modules/admin/views/item-widget/index.php @@ -0,0 +1,53 @@ +title = 'Виджеты'; +$this->params['breadcrumbs'][] = $this->title; +$this->params['in-card'] = false; +?> + +
+
+ 'btn btn-default btn-flat']) ?> +
+ + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + 'id', + 'name', + 'icon', + [ + 'attribute' => 'room_id', + 'filter' => Room::getList(), + 'value' => function ($model) { + /** @var $model ItemWidget */ + return $model->room->name; + }, + ], + [ + 'attribute' => 'item_id', + 'filter' => Item::getList(), + 'value' => function ($model) { + /** @var $model ItemWidget */ + return $model->item->name; + }, + ], + 'active:boolean', + + ['class' => 'app\components\ActionButtonColumn'], + ], + ]); ?> + +
diff --git a/modules/admin/views/item-widget/update.php b/modules/admin/views/item-widget/update.php new file mode 100644 index 0000000..f96156c --- /dev/null +++ b/modules/admin/views/item-widget/update.php @@ -0,0 +1,19 @@ +title = 'Изменить Item Widget: ' . $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Item Widgets', 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; +$this->params['breadcrumbs'][] = 'Редактирование'; +?> +
+ + render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/modules/admin/views/item-widget/view.php b/modules/admin/views/item-widget/view.php new file mode 100644 index 0000000..98ccf39 --- /dev/null +++ b/modules/admin/views/item-widget/view.php @@ -0,0 +1,40 @@ +title = $model->name; +$this->params['breadcrumbs'][] = ['label' => 'Item Widgets', 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ +

+ ', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?> + ', ['delete', 'id' => $model->id], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 'Are you sure you want to delete this item?', + 'method' => 'post', + ], + ]) ?> +

+ + $model, + 'attributes' => [ + 'id', + 'active', + 'sort_order', + 'item_id', + 'room_id', + 'name', + 'html_class', + 'icon', + ], + ]) ?> + +
diff --git a/modules/admin/views/item/_form.php b/modules/admin/views/item/_form.php index e64841f..5486968 100644 --- a/modules/admin/views/item/_form.php +++ b/modules/admin/views/item/_form.php @@ -12,7 +12,6 @@ use yii\helpers\Html; use yii\widgets\ActiveForm; if ($model->isNewRecord) { - $model->active = true; $model->enable_log = true; } ?> @@ -23,8 +22,6 @@ if ($model->isNewRecord) {
-

Основные настройки

- field($model, 'name')->textInput(['maxlength' => true]) ?> field($model, 'type')->dropDownList(Item::getTypesArray(), [ @@ -50,38 +47,8 @@ if ($model->isNewRecord) { field($model, 'save_history_interval')->input('number') ?>
-
-

Сниппет

- - field($model, 'icon')->textInput(['maxlength' => true]) ?> - - field($model, 'bg')->dropDownList([ - 'light-blue' => 'Светло-синий', - 'aqua' => 'Бирюзовый', - 'green' => 'Зеленый', - 'yellow' => 'Желтый', - 'red' => 'Красный', - 'gray' => 'Серый', - 'navy' => 'Navy', - 'teal' => 'Teal', - 'purple' => 'Фиолетовый', - 'orange' => 'Оранжевый', - 'maroon' => 'Бордовый', - 'black' => 'Черный', - ]) ?> - - field($model, 'class')->textInput(['maxlength' => true]) ?> - - field($model, 'room_id')->dropDownList( - ArrayHelper::map(Room::find()->all(), 'id', 'name') - ) ?> - - field($model, 'sort_order')->input('number') ?> -
- field($model, 'active')->checkbox() ?> - field($model, 'enable_log')->checkbox() ?>
diff --git a/modules/admin/views/item/index.php b/modules/admin/views/item/index.php index 8348c40..35e0aa9 100644 --- a/modules/admin/views/item/index.php +++ b/modules/admin/views/item/index.php @@ -35,14 +35,6 @@ $this->params['in-card'] = false; 'columns' => [ 'id', 'name', - [ - 'attribute' => 'room_id', - 'filter' => Room::getList(), - 'value' => function ($model) { - /** @var $model Item */ - return $model->room->name; - }, - ], [ 'attribute' => 'board_id', 'filter' => Board::getList(), diff --git a/modules/admin/views/item/view.php b/modules/admin/views/item/view.php index 9f00531..59500ab 100644 --- a/modules/admin/views/item/view.php +++ b/modules/admin/views/item/view.php @@ -28,18 +28,13 @@ $this->params['breadcrumbs'][] = $this->title; 'attributes' => [ 'id', 'name', - 'icon', - 'bg', - 'class', ['attribute' => 'board_id', 'value' => $model->board->name], 'pin', 'type', 'default_value', 'update_interval', 'save_history_interval', - ['attribute' => 'room_id', 'value' => $model->room->name], 'url:url', - 'sort_order', ], ]) ?> diff --git a/modules/admin/views/task/_form.php b/modules/admin/views/task/_form.php index d6eea8f..b136cbd 100644 --- a/modules/admin/views/task/_form.php +++ b/modules/admin/views/task/_form.php @@ -36,7 +36,7 @@ if ($model->isNewRecord) {

Выполнить

field($model, 'item_id')->widget(Select2::className(), [ - 'data' => Item::getList(false, true), + 'data' => Item::getList(true), 'options' => [ 'placeholder' => 'Выберите элемент ...', ], diff --git a/modules/admin/views/trigger/_form.php b/modules/admin/views/trigger/_form.php index 4b63270..73034b1 100644 --- a/modules/admin/views/trigger/_form.php +++ b/modules/admin/views/trigger/_form.php @@ -86,7 +86,7 @@ if ($model->isNewRecord) {
field($model, 'item_id')->widget(Select2::className(), [ - 'data' => Item::getList(false, true), + 'data' => Item::getList(true), 'options' => [ 'placeholder' => 'Выберите элемент ...', ], diff --git a/modules/admin/views/user/index.php b/modules/admin/views/user/index.php index d19cca4..efe1d6f 100644 --- a/modules/admin/views/user/index.php +++ b/modules/admin/views/user/index.php @@ -6,7 +6,6 @@ use app\models\User; use yii\helpers\Html; -use yii\grid\GridView; use yii\widgets\Pjax; $this->title = 'Пользователи'; @@ -20,11 +19,9 @@ $this->params['in-card'] = false;
- $dataProvider, 'filterModel' => $searchModel, - 'summaryOptions' => ['class' => 'alert alert-info'], - 'layout' => '{summary}
{items}
{pager}', 'columns' => [ 'id', 'username', diff --git a/modules/api/controllers/ItemController.php b/modules/api/controllers/ItemController.php index a70f9ed..0c128ea 100644 --- a/modules/api/controllers/ItemController.php +++ b/modules/api/controllers/ItemController.php @@ -8,13 +8,15 @@ use app\modules\api\components\WebSocketAPIBridge; use Yii; use yii\base\InvalidParamException; use yii\base\NotSupportedException; -use yii\rest\Controller; +use yii\rest\ActiveController; use yii\web\BadRequestHttpException; use yii\web\NotFoundHttpException; use yii\web\ServerErrorHttpException; -class ItemController extends Controller +class ItemController extends ActiveController { + public $modelClass = 'app\models\Item'; + /** * @inheritdoc */ @@ -29,14 +31,6 @@ class ItemController extends Controller ]; } - /** - * @throws NotSupportedException - */ - public function actionIndex() - { - throw new NotSupportedException(); - } - /** * @param $item_id * @return array diff --git a/modules/api/controllers/RoomController.php b/modules/api/controllers/RoomController.php new file mode 100644 index 0000000..05df537 --- /dev/null +++ b/modules/api/controllers/RoomController.php @@ -0,0 +1,10 @@ +userConnections[$user->id] = $conn; // Prepare Items for User - $itemModels = Item::find() - ->active() - ->all(); + $itemModels = Item::find()->all(); $items = []; foreach ($itemModels as $itemModel) { $itemData = []; $itemData['id'] = $itemModel->id; - $itemData['type'] = $itemModel->type; - $itemData['room_id'] = $itemModel->room_id; + $itemData['type'] = $itemModel->widget->type; + $itemData['value_type'] = $itemModel->widget->value_type; + $itemData['room_id'] = $itemModel->widget->room_id; $itemData['board_id'] = $itemModel->board_id; - $itemData['pin'] = $itemModel->pin; - $itemData['name'] = $itemModel->name; - $itemData['icon'] = $itemModel->icon; - $itemData['bg'] = $itemModel->bg; - $itemData['class'] = $itemModel->class; - $itemData['sort_order'] = $itemModel->sort_order; + $itemData['name'] = $itemModel->widget->getName(); + $itemData['icon'] = $itemModel->widget->icon; + $itemData['html_class'] = $itemModel->widget->html_class; + $itemData['sort_order'] = $itemModel->widget->sort_order; $itemData['value'] = $this->getItemSavedValue($itemModel->id, $itemModel->getDefaultNAValue()); @@ -356,9 +353,9 @@ class CoreServer implements MessageComponentInterface } switch ($data['type']) { - case 'turnON': + case 'turn_on': return $this->handleTurnOn($from, $user, $data); - case 'turnOFF': + case 'turn_off': return $this->handleTurnOff($from, $user, $data); case 'rgb': return $this->handleRgb($from, $user, $data); @@ -410,7 +407,7 @@ class CoreServer implements MessageComponentInterface $this->sendUsers([ 'type' => 'value', 'item_id' => $item->id, - 'item_type' => $item->type, + 'value_type' => $item->widget->type, 'value' => $value, ]); @@ -502,7 +499,7 @@ class CoreServer implements MessageComponentInterface $this->sendUsers([ 'type' => 'value', 'item_id' => $item->id, - 'item_type' => $item->type, + 'value_type' => $item->widget->type, 'value' => $value, ]); @@ -1353,11 +1350,11 @@ class CoreServer implements MessageComponentInterface $this->log("Loading items..."); /** @var Item[] $items */ - $items = Item::find()->active()->all(); + $items = Item::find()->all(); foreach ($items as $item) { if (!$this->hasItemSavedValue($item->id)) { - $this->saveItemValue($item->id, $item->getDefaultValue(), $item->type, false); + $this->saveItemValue($item->id, $item->getDefaultNAValue(), $item->type, false); } } diff --git a/views/layouts/_drawer.php b/views/layouts/_drawer.php index f647f03..3344848 100644 --- a/views/layouts/_drawer.php +++ b/views/layouts/_drawer.php @@ -31,11 +31,15 @@ use yii\bootstrap\Nav; ], '
  • ', [ - 'label' => FA::i('toggle-on fa-fw') . 'Элементы', + 'label' => FA::i('microchip fa-fw') . 'Элементы', 'url' => ['/admin/item/index'], ], [ - 'label' => FA::i('hdd-o fa-fw') . 'Устройства', + 'label' => FA::i('toggle-on fa-fw') . 'Виджеты', + 'url' => ['/admin/item-widget/index'], + ], + [ + 'label' => FA::i('wifi fa-fw') . 'Устройства', 'url' => ['/admin/board/index'], ], [ diff --git a/views/panel/_rgb.php b/views/panel/_rgb.php index b1b6919..14395b8 100644 --- a/views/panel/_rgb.php +++ b/views/panel/_rgb.php @@ -1,19 +1,17 @@
    -
    +
    - icon) ?> +
    - name ?> + getName() ?>
    diff --git a/views/panel/_switch.php b/views/panel/_switch.php index 7e95468..d031417 100644 --- a/views/panel/_switch.php +++ b/views/panel/_switch.php @@ -1,19 +1,17 @@
    -
    +
    - icon) ?> +
    - name ?> + getName() ?>
    diff --git a/views/panel/_variable.php b/views/panel/_variable.php index e9dd93f..bbd2553 100644 --- a/views/panel/_variable.php +++ b/views/panel/_variable.php @@ -1,19 +1,17 @@
    -
    +
    - icon) ?> +
    -
    getDefaultNAValue() ?>
    +
    item->getDefaultNAValue() ?>
    diff --git a/views/panel/index.php b/views/panel/index.php index 8a9b77e..b968728 100644 --- a/views/panel/index.php +++ b/views/panel/index.php @@ -43,23 +43,23 @@ $this->title = 'Панель Управления';
    - getItems()->variables()->active()->all() as $item): ?> + getItemWidgets()->variables()->active()->all() as $widget): ?> render('_variable', [ - 'item' => $item, + 'widget' => $widget, ]) ?>
    - getItems()->switches()->active()->all() as $item): ?> + getItemWidgets()->switches()->active()->all() as $widget): ?> render('_switch', [ - 'item' => $item, + 'widget' => $widget, ]) ?>
    - getItems()->rgb()->all() as $item): ?> + getItemWidgets()->rgb()->all() as $widget): ?> render('_rgb', [ - 'item' => $item, + 'widget' => $widget, ]) ?>
    diff --git a/web/css/md.theme.css b/web/css/md.theme.css index bdac986..5bea8ae 100644 --- a/web/css/md.theme.css +++ b/web/css/md.theme.css @@ -346,22 +346,6 @@ body { user-select: none; } -.popover { - width: 300px; - box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12); - max-width: none; - border-radius: 0; - padding: 0; -} - -.popover-title { - display: none; -} - -.popover-content { - padding: 0; -} - .rgb-widget-form { padding: 10px; } @@ -385,12 +369,6 @@ body { margin: 0; } -@media (min-width: 767px) { - .popover { - width: 500px; - } -} - /* Snackbar fixes */ #snackbar-container { position: fixed; diff --git a/web/css/panel.css b/web/css/panel.css index 84ba4a3..0e81912 100644 --- a/web/css/panel.css +++ b/web/css/panel.css @@ -44,3 +44,22 @@ .control-panel { display: none; } + +/* Popover */ +.popover { + width: 300px; + box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12); + max-width: none; + border-radius: 0; + padding: 0; +} + +.popover-content { + padding: 0; +} + +@media (min-width: 767px) { + .popover { + width: 500px; + } +} diff --git a/web/css/site.css b/web/css/site.css index fa0569c..3c19838 100644 --- a/web/css/site.css +++ b/web/css/site.css @@ -11,6 +11,6 @@ font-style: italic; } -.select2-container--krajee .select2-selection--single { - line-height: 2; +.fontawesome-iconpicker-input { + display: block; } diff --git a/web/js/panel.js b/web/js/panel.js index af5fa83..0dcb1ea 100644 --- a/web/js/panel.js +++ b/web/js/panel.js @@ -48,7 +48,7 @@ function onMessage(e) { saveItemValue(id, value.value); } - updateItemValue(value.id, value.type, value.value); + updateItemValue(value.id, value.type, value.value, value.value_type); } }); @@ -128,7 +128,7 @@ function getSavedItemValue(itemId) { return itemValues[itemId]; } -function updateItemValue(id, type, value) { +function updateItemValue(id, type, value, value_type) { type = parseInt(type); switch (type) { @@ -143,33 +143,37 @@ function updateItemValue(id, type, value) { break; case 20: // Variable - itemSetValue(id, value); - break; - case 21: // Variable Temperature - itemSetValue(id, value + ' °C'); - break; - case 22: // Variable Humidity - itemSetValue(id, value + '%'); - break; - case 25: // Variable boolean - if (Boolean(value)) { - if (value != 'N/A') { - value = 'да'; - } - } else { - value = 'нет'; + if (!value_type || value_type == null) { + return itemSetValue(id, value); } - itemSetValue(id, value); + switch (value_type) { + case 10: // Boolean + if (Boolean(value)) { + if (value != 'N/A') { + value = 'да'; + } + } else { + value = 'нет'; + } - break; - case 26: // Variable boolean door - if (value) { - if (value != 'N/A') { - value = 'открыто'; - } - } else { - value = 'закрыто'; + break; + case 20: // Variable boolean door + if (value) { + if (value != 'N/A') { + value = 'открыто'; + } + } else { + value = 'закрыто'; + } + + break; + case 30: // Celsius + value += ' °C'; + break; + case 40: // Percent + value += '%'; + break; } itemSetValue(id, value); @@ -187,7 +191,7 @@ $(document).ready(function () { var item_id = $this.data('item-id'); send({ - "type": $this.hasClass('off') ? 'turnON' : 'turnOFF', + "type": $this.hasClass('off') ? 'turn_on' : 'turn_off', "item_id": item_id }); });