]);
}
+ public function actionUpdateName($id)
+ {
+ Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+ $model = $this->findModel($id);
+ if (!$model) {
+ return ['success'=>false,'message'=>'Не найдено'];
+ }
+ $model->load(Yii::$app->request->post(), '');
+ if ($model->save()) {
+ return ['success'=>true,'data'=>['name'=>$model->name]];
+ }
+ return ['success'=>false,'message'=>current($model->getFirstErrors()) ?: 'Ошибка сохранения'];
+ }
+
+ public function actionCreateChild($parent_id)
+ {
+ Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+ $child = new MatrixType();
+ $child->load(Yii::$app->request->post(), '');
+ $child->parent_id = (int)$parent_id;
+
+ if ($child->save()) {
+ return ['success'=>true,'data'=>['id'=>$child->id, 'name'=>$child->name]];
+ }
+ return ['success'=>false,'message'=>current($child->getFirstErrors()) ?: 'Ошибка создания'];
+ }
+
+ public function actionToggleActive()
+ {
+ Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+ $id = Yii::$app->request->post('id');
+ $active = Yii::$app->request->post('active');
+
+ $model = $this->findModel($id);
+ if (!$model) {
+ return ['success' => false, 'message' => 'Не найдено'];
+ }
+
+ $model->active = (int)$active;
+ if ($model->save(false)) {
+ return ['success' => true];
+ }
+ return ['success' => false, 'message' => 'Не удалось сохранить'];
+ }
/**
* Deletes an existing MatrixType model.
* If deletion is successful, the browser will be redirected to the 'index' page.
--- /dev/null
+<?php
+
+use yii\db\Migration;
+
+class m250905_090045_add_parentid_active_fields_to_matrix_type_table extends Migration
+{
+ const TABLE_NAME = 'erp24.matrix_type';
+ /**
+ * {@inheritdoc}
+ */
+ public function safeUp()
+ {
+ $table = $this->db->schema->getTableSchema(self::TABLE_NAME);
+ if ($table === null) {
+ return;
+ }
+
+ if (!$this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('parent_id')) {
+ $this->addColumn(
+ self::TABLE_NAME,
+ 'parent_id',
+ $this->integer()->null()->comment('id записи родителя')
+ );
+ }
+ if (!$this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('active')) {
+ $this->addColumn(
+ self::TABLE_NAME,
+ 'active',
+ $this->tinyInteger()->notNull()->defaultValue(1)->comment('активность')
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function safeDown()
+ {
+ if ($this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('parent_id')) {
+ $this->dropColumn(self::TABLE_NAME, 'parent_id');
+ }
+ if ($this->db->schema->getTableSchema(self::TABLE_NAME, true)->getColumn('active')) {
+ $this->dropColumn(self::TABLE_NAME, 'active');
+ }
+ }
+
+ /*
+ // Use up()/down() to run migration code without a transaction.
+ public function up()
+ {
+
+ }
+
+ public function down()
+ {
+ echo "m250905_090045_add_parentid_active_fields_to_matrix_type_table cannot be reverted.\n";
+
+ return false;
+ }
+ */
+}
* This is the model class for table "erp24.matrix_type".
*
* @property int $id
+ * @property int|null $parent_id id родительской категории - null - корневая
+ * @property int $active активность (0,1) по умолчанию - 1 - активная запись
* @property string $name
* @property int $created_by
* @property string $created_at
{
return [
[['name'], 'filter', 'filter' => 'trim'],
- [['name'], 'unique', 'targetAttribute' => ['name'], 'message' => 'Имя матрицы уже используется'],
[['name'], 'required'],
- [['created_by', 'updated_by'], 'integer'],
+ [['created_by', 'updated_by', 'active', 'parent_id'], 'integer'],
[['created_at', 'updated_at'], 'safe'],
[['name'], 'string', 'max' => 255],
+ // Уникальность имени в рамках одной группы
+ [
+ ['name', 'parent_id'],
+ 'unique',
+ 'targetAttribute' => ['name', 'parent_id'],
+ 'message' => 'Подгруппа с таким названием уже существует в этой группе.',
+ ],
+
+ // Уникальность имени для групп (без parent_id)
+ [
+ 'name',
+ 'unique',
+ 'targetAttribute' => 'name',
+ 'filter' => ['parent_id' => null],
+ 'message' => 'Группа с таким названием уже существует.',
+ ],
];
}
return [
'id' => 'ID',
'name' => 'Название типа матрицы',
+ 'parent_id' => 'Родительская категория',
+ 'active' => 'Активность',
'created_by' => 'ИД создателя',
'created_at' => 'Дата создания',
'updated_by' => 'ИД редактировавшего',
<?php
+use leandrogehlen\treegrid\TreeGrid;
use yii\helpers\Html;
use yii\grid\GridView;
+use yii\helpers\Url;
/* @var $this yii\web\View */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Типы матриц';
$this->params['breadcrumbs'][] = $this->title;
+$this->registerJsFile('/js/matrix-type/index.js', ['position' => \yii\web\View::POS_END]);
?>
<div class="matrix-type-index p-3">
<?= Html::a('Создать новый тип матрицы', ['create'], ['class' => 'btn btn-success']) ?>
</p>
- <?= GridView::widget([
+<!-- --><?php //= GridView::widget([
+// 'dataProvider' => $dataProvider,
+// 'filterModel' => null,
+// 'columns' => [
+// 'id',
+// 'name',
+// 'created_at',
+// 'updated_at',
+// [
+// 'class' => 'yii\grid\ActionColumn',
+// 'template' => '{update} {delete}',
+// ],
+// ],
+// ]); ?>
+
+ <?=
+ TreeGrid::widget([
'dataProvider' => $dataProvider,
- 'filterModel' => null,
+ 'keyColumnName' => 'id',
+ 'showOnEmpty' => FALSE,
+ 'parentColumnName' => 'parent_id',
'columns' => [
- 'id',
- 'name',
- 'created_at',
- 'updated_at',
+
+ //'name',
+ [
+ 'attribute' => 'name',
+ 'format' => 'raw',
+ 'value' => function ($model) {
+ $id = (int)$model->id;
+ $editModalId = "editModal-$id";
+ $createModalId = "createModal-$id";
+
+ $editUrl = Url::to(['matrix-type/update-name', 'id' => $id]);
+ $createUrl = Url::to(['matrix-type/create-child', 'parent_id' => $id]);
+
+ ob_start(); ?>
+
+ <div class="d-inline-block">
+ <div class="d-flex justify-content-start align-items-center">
+
+ <button type="button"
+ class="btn btn-outline-primary"
+ data-bs-toggle="modal"
+ data-bs-target="#<?= $editModalId ?>">
+ <span id="nameLabel-<?= $id ?>"><?= Html::encode($model->name) ?></span>
+ <i class="fa fa-pencil ms-2 "></i>
+ </button>
+
+ <button type="button"
+ class="btn btn-sm"
+ data-bs-toggle="modal"
+ data-bs-target="#<?= $createModalId ?>"
+ aria-label="Добавить">
+ <i class="fa fa-plus"></i>
+ </button>
+ </div>
+ </div>
+
+
+ <div class="modal fade" id="<?= $editModalId ?>" tabindex="-1" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h5 class="modal-title">Редактировать название</h5>
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"><i class="fa fa-times"></i></button>
+ </div>
+ <form class="ajax-form" data-action="<?= $editUrl ?>" data-success="rename" data-id="<?= $id ?>">
+ <div class="modal-body">
+ <div class="mb-3">
+ <label class="form-label">Название</label>
+ <input type="text" name="name" class="form-control" value="<?= Html::encode($model->name) ?>" required>
+ </div>
+ <div class="alert alert-danger d-none js-form-error"></div>
+ </div>
+
+ <div class="modal-footer">
+
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отменить</button>
+ <button type="submit" class="btn btn-primary">Сохранить</button>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+
+
+ <div class="modal fade" id="<?= $createModalId ?>" tabindex="-1" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h5 class="modal-title">Новый пункт (дочерний)</h5>
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"><i class="fa fa-times"></i></button>
+ </div>
+ <form class="ajax-form" data-action="<?= $createUrl ?>" data-success="created" data-parent-id="<?= $id ?>">
+ <div class="modal-body">
+ <input type="hidden" name="parent_id" value="<?= $id ?>">
+ <div class="mb-3">
+ <label class="form-label">Название</label>
+ <input type="text" name="name" class="form-control" required>
+ </div>
+ <div class="alert alert-danger d-none js-form-error"></div>
+ </div>
+
+ <div class="modal-footer">
+
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отменить</button>
+ <button type="submit" class="btn btn-success">Создать</button>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+
+
+ <?php
+ return ob_get_clean();
+ },
+ ],
[
- 'class' => 'yii\grid\ActionColumn',
- 'template' => '{update} {delete}',
+ 'attribute' => 'active',
+ 'format' => 'raw',
+ 'value' => function ($model) {
+ return \yii\helpers\Html::checkbox(
+ 'active[' . $model->id . ']',
+ $model->active == 1,
+ [
+ 'class' => 'js-toggle-active',
+ 'data-id' => $model->id,
+ ]
+ );
+ },
+ 'contentOptions' => ['class' => 'text-center', 'style' => 'width:80px; min-width:50px; '],
],
- ],
- ]); ?>
+
+ ['class' => 'yii\grid\ActionColumn',
+ 'template' => '{delete}',
+ 'contentOptions' => ['class' => 'text-center', 'style' => 'width:80px; min-width:50px; '],
+ 'buttons' => [
+ 'delete' => function ($url, $model, $key)
+ {
+ return Html::a('<span class="fa fa-times"></span>',
+ $url,
+ [
+ 'title' => "Удалить",
+ 'data' => [
+ 'method' => 'post',
+ 'confirm' => 'Вы уверены, что хотите удалить этот элемент?',
+ ]
+ ]);
+ },
+ ]
+ ]
+ ]
+ ]);
+ ?>
</div>
--- /dev/null
+(function(){
+ function setError(form, msg){
+ var $box = $(form).find('.js-form-error');
+ if(!$box.length) return;
+ if(!msg){ $box.addClass('d-none').text(''); return; }
+ $box.removeClass('d-none').text(msg);
+ }
+
+ $(document).on('submit', '.ajax-form', function(e){
+ e.preventDefault();
+ var $form = $(this);
+ setError($form[0], null);
+
+ var action = $form.data('action');
+ var mode = $form.data('success');
+ var id = $form.data('id');
+ var parentId = $form.data('parent-id');
+
+ var dataArr = $form.serializeArray();
+
+
+ dataArr.push({
+ name: yii.getCsrfParam(),
+ value: yii.getCsrfToken()
+ });
+
+ if (id && !$form.find('[name="id"]').length) {
+ dataArr.push({name: 'id', value: id});
+ }
+ if (parentId && !$form.find('[name="parent_id"]').length) {
+ dataArr.push({name: 'parent_id', value: parentId});
+ }
+
+ var $submitBtn = $form.find('button[type="submit"]').prop('disabled', true);
+
+ $.ajax({
+ url: action,
+ type: 'POST',
+ data: $.param(dataArr),
+ dataType: 'json',
+ headers: { 'X-Requested-With':'XMLHttpRequest' },
+ success: function(json){
+ if (!json || json.success !== true) {
+ setError($form[0], (json && json.message) ? json.message : 'Ошибка сохранения');
+ return;
+ }
+
+ if (mode === 'rename') {
+ var label = document.getElementById('nameLabel-' + id);
+ var newName = (json.data && json.data.name) ? json.data.name : $form.find('[name="name"]').val();
+ if (label && newName) { label.textContent = newName; }
+ } else if (mode === 'created') {
+ if ($.pjax) {
+ $.pjax.reload({container:'#pjaxtable', async:false});
+ } else {
+ location.reload();
+ }
+ }
+
+ // закрыть модалку
+ var modalEl = $form.closest('.modal')[0];
+ if (modalEl) {
+ var modal = bootstrap.Modal.getInstance(modalEl) || new bootstrap.Modal(modalEl);
+ modal.hide();
+ $form[0].reset();
+ setError($form[0], null);
+ }
+ },
+ error: function(){
+ setError($form[0], 'Сеть/сервер недоступен');
+ },
+ complete: function(){
+ $submitBtn.prop('disabled', false);
+ }
+ });
+ });
+
+ $(document).on('change', '.js-toggle-active', function () {
+ var checkbox = $(this);
+ var id = checkbox.data('id');
+ var active = checkbox.is(':checked') ? 1 : 0;
+
+ $.ajax({
+ url: '/matrix-type/toggle-active',
+ type: 'POST',
+ data: {
+ id: id,
+ active: active,
+ _csrf: yii.getCsrfToken()
+ },
+ success: function (res) {
+ if (!res.success) {
+ alert('Ошибка: ' + res.message);
+ checkbox.prop('checked', !active);
+ }
+ },
+ error: function () {
+ alert('Ошибка сервера');
+ checkbox.prop('checked', !active);
+ }
+ });
+ });
+})();