]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Фикс по маппингу
authorfomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 17 Apr 2026 07:26:57 +0000 (10:26 +0300)
committerfomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 17 Apr 2026 07:26:57 +0000 (10:26 +0300)
erp24/views/product-mapping/index.php
erp24/web/js/product-mapping/index.js [new file with mode: 0644]

index f346b785b5304dd8c0199eb72353f6c0063066b7..70b27b093cbcc2cdd138d97adf38bde9f7062802 100644 (file)
@@ -109,249 +109,19 @@ use yii\widgets\LinkPager;
 </div>
 
 <?php
-$createFormUrl = Url::to(['/product-mapping/create-form']);
-$updateFormUrl = Url::to(['/product-mapping/update-form']);
-$createUrl = Url::to(['/product-mapping/create']);
-$updateUrl = Url::to(['/product-mapping/update']);
-$deleteUrl = Url::to(['/product-mapping/delete']);
-$indexUrl = Url::to(['/product-mapping/index']);
-$analyticsUrl = Url::to(['/product-mapping/analytics']);
-$cascadeUrl = Url::to(['/product-mapping/cascade-filters']);
-$exportUrl = Url::to(['/product-mapping/export']);
-
-$js = <<<JS
-(function() {
-    var pmModal = new bootstrap.Modal(document.getElementById('pm-modal'));
-    var editingId = null;
-    var searchTimer = null;
-    var loaderHtml = '<div class="text-center p-4"><i class="fa fa-spinner fa-spin fa-2x text-secondary"></i></div>';
-
-    function collectFilters() {
-        var params = {};
-        $('.pm-filter').each(function() {
-            var \$el = $(this);
-            var name = \$el.attr('name');
-            if (!name) return;
-            if (\$el.is(':checkbox')) {
-                if (\$el.is(':checked')) {
-                    params[name] = '1';
-                }
-            } else {
-                var v = \$el.val();
-                if (v !== '' && v !== null) {
-                    params[name] = v;
-                }
-            }
-        });
-        params['per-page'] = $('#pm-per-page').val();
-        return params;
-    }
-
-    function reloadList(extraParams) {
-        var params = collectFilters();
-        if (extraParams) {
-            \$.extend(params, extraParams);
-        }
-        var \$tab = $('#tab-mappings');
-        \$tab.html('<div class="text-muted p-4 text-center"><i class="fa fa-spinner fa-spin me-2"></i>Загрузка...</div>');
-        \$.get('{$indexUrl}', params, function(html) {
-            \$tab.html(html);
-        });
-    }
-
-    function reloadAnalytics() {
-        var params = collectFilters();
-        delete params['per-page'];
-        \$.get('{$analyticsUrl}', params, function(data) {
-            \$.each(data, function(field, value) {
-                $('[data-analytics-field="' + field + '"]').text(value);
-            });
-        }, 'json');
-    }
-
-    // ========= ФИЛЬТРЫ =========
-
-    // Смена фильтров — reload списка
-    $(document).on('change', '.pm-filter', function() {
-        var name = $(this).attr('name');
-
-        // Каскадное обновление категорий
-        if (name === 'category') {
-            var category = $(this).val();
-            $('#pm-filter-subcategory').html('<option value="">Все</option>').prop('disabled', !category);
-            $('#pm-filter-species').html('<option value="">Все</option>').prop('disabled', true);
-            if (category) {
-                \$.get('{$cascadeUrl}', {category: category}, function(data) {
-                    var html = '<option value="">Все</option>';
-                    \$.each(data.subcategories, function(_, sub) {
-                        html += '<option value="' + sub + '">' + sub + '</option>';
-                    });
-                    $('#pm-filter-subcategory').html(html).prop('disabled', false);
-                }, 'json');
-            }
-        } else if (name === 'subcategory') {
-            var cat = $('#pm-filter-category').val();
-            var sub = $(this).val();
-            $('#pm-filter-species').html('<option value="">Все</option>').prop('disabled', !sub);
-            if (cat && sub) {
-                \$.get('{$cascadeUrl}', {category: cat, subcategory: sub}, function(data) {
-                    var html = '<option value="">Все</option>';
-                    \$.each(data.species, function(_, sp) {
-                        html += '<option value="' + sp + '">' + sp + '</option>';
-                    });
-                    $('#pm-filter-species').html(html).prop('disabled', false);
-                }, 'json');
-            }
-        }
-
-        // Для поиска по названию — debounce
-        if (name === 'search') return;
-
-        reloadList({page: 1});
-    });
-
-    // Поиск — с debounce 400мс
-    $(document).on('input', 'input[name="search"].pm-filter', function() {
-        clearTimeout(searchTimer);
-        searchTimer = setTimeout(function() {
-            reloadList({page: 1});
-        }, 400);
-    });
-
-    // Сброс фильтров
-    $(document).on('click', '#pm-filter-reset', function() {
-        $('.pm-filter').each(function() {
-            var \$el = $(this);
-            if (\$el.is(':checkbox')) {
-                \$el.prop('checked', false);
-            } else if (\$el.is('select')) {
-                \$el.val('');
-            } else {
-                \$el.val('');
-            }
-        });
-        reloadList({page: 1});
-    });
-
-    // Смена per-page
-    $('#pm-per-page').on('change', function() {
-        reloadList({page: 1});
-    });
-
-    // Экспорт в .xlsx — редирект с текущими фильтрами
-    $(document).on('click', '#pm-export-btn', function() {
-        var params = collectFilters();
-        delete params['per-page'];
-        var qs = $.param(params);
-        window.location.href = '{$exportUrl}' + (qs ? '?' + qs : '');
-    });
-
-    // Пагинация — перехват ссылок
-    $(document).on('click', '.pm-pager a', function(e) {
-        e.preventDefault();
-        var href = $(this).attr('href');
-        var pageMatch = href.match(/[?&]page=(\d+)/);
-        var page = pageMatch ? pageMatch[1] : 1;
-        reloadList({page: page});
-    });
-
-    // ========= МОДАЛКА МАППИНГА =========
-
-    $(document).on('click', '.btn-pm-add', function() {
-        var \$btn = $(this);
-        if (\$btn.prop('disabled')) return;
-        \$btn.prop('disabled', true);
-        editingId = null;
-        var guid = \$btn.data('product-guid');
-        $('#pm-modal-title').text('Добавить поставщика');
-        $('#pm-modal-body').html(loaderHtml);
-        pmModal.show();
-        \$.get('{$createFormUrl}', {product_guid: guid}, function(html) {
-            $('#pm-modal-body').html(html);
-        }).always(function() {
-            \$btn.prop('disabled', false);
-        });
-    });
-
-    $(document).on('click', '.btn-pm-edit', function(e) {
-        e.preventDefault();
-        var \$btn = $(this);
-        if (\$btn.prop('disabled')) return;
-        \$btn.prop('disabled', true);
-        editingId = \$btn.data('id');
-        $('#pm-modal-title').text('Редактировать маппинг');
-        $('#pm-modal-body').html(loaderHtml);
-        pmModal.show();
-        \$.get('{$updateFormUrl}', {id: editingId}, function(html) {
-            $('#pm-modal-body').html(html);
-        }).always(function() {
-            \$btn.prop('disabled', false);
-        });
-    });
-
-    $(document).on('click', '#btn-mapping-save', function() {
-        var \$form = $('#mapping-form');
-        var url = editingId ? '{$updateUrl}?id=' + editingId : '{$createUrl}';
-
-        \$form.find('.is-invalid').removeClass('is-invalid');
-        \$form.find('.invalid-feedback').remove();
-
-        \$.ajax({
-            url: url,
-            type: 'POST',
-            data: \$form.serialize(),
-            dataType: 'json',
-            success: function(resp) {
-                if (resp.success) {
-                    pmModal.hide();
-                    reloadList();
-                } else if (resp.errors) {
-                    \$.each(resp.errors, function(field, messages) {
-                        var \$input = \$form.find('[name="ProductMapping[' + field + ']"]');
-                        if (!\$input.length) {
-                            \$input = \$form.find('[name="ProductMapping[' + field + '][]"]');
-                        }
-                        \$input.addClass('is-invalid');
-                        \$input.after('<div class="invalid-feedback">' + messages[0] + '</div>');
-                    });
-                }
-            },
-            error: function() { alert('Ошибка сервера'); }
-        });
-    });
-
-    $(document).on('click', '.btn-pm-delete', function(e) {
-        e.preventDefault();
-        var id = $(this).data('id');
-        var name = $(this).data('name');
-
-        if (!confirm('Удалить маппинг на поставщика "' + name + '"?')) {
-            return;
-        }
-
-        \$.ajax({
-            url: '{$deleteUrl}?id=' + id,
-            type: 'POST',
-            data: {_csrf: yii.getCsrfToken()},
-            dataType: 'json',
-            success: function(resp) {
-                if (resp.success) {
-                    reloadList();
-                } else {
-                    alert(resp.message || 'Ошибка удаления');
-                }
-            },
-            error: function() { alert('Ошибка сервера'); }
-        });
-    });
-
-    // Очистка ошибок при вводе
-    $(document).on('input change', '#mapping-form input, #mapping-form select', function() {
-        $(this).removeClass('is-invalid');
-        $(this).next('.invalid-feedback').remove();
-    });
-})();
-JS;
-
-$this->registerJs($js);
+$this->registerJs('window.pmCfg = ' . \yii\helpers\Json::encode([
+    'urls' => [
+        'createForm' => Url::to(['/product-mapping/create-form']),
+        'updateForm' => Url::to(['/product-mapping/update-form']),
+        'create'     => Url::to(['/product-mapping/create']),
+        'update'     => Url::to(['/product-mapping/update']),
+        'delete'     => Url::to(['/product-mapping/delete']),
+        'index'      => Url::to(['/product-mapping/index']),
+        'analytics'  => Url::to(['/product-mapping/analytics']),
+        'cascade'    => Url::to(['/product-mapping/cascade-filters']),
+        'export'     => Url::to(['/product-mapping/export']),
+    ],
+]) . ';');
+
+$this->registerJsFile('/js/product-mapping/index.js', ['position' => \yii\web\View::POS_END]);
 ?>
diff --git a/erp24/web/js/product-mapping/index.js b/erp24/web/js/product-mapping/index.js
new file mode 100644 (file)
index 0000000..0995582
--- /dev/null
@@ -0,0 +1,243 @@
+/* global bootstrap, yii */
+(function () {
+    var cfg = window.pmCfg;
+    if (!cfg) return;
+
+    // Снимаем все предыдущие обработчики этого модуля с document,
+    // чтобы предотвратить накопление при каждом reloadList().
+    var NS = '.pmapping';
+    $(document).off(NS);
+
+    var pmModal = new bootstrap.Modal(document.getElementById('pm-modal'));
+    var editingId = null;
+    var searchTimer = null;
+    var loaderHtml = '<div class="text-center p-4"><i class="fa fa-spinner fa-spin fa-2x text-secondary"></i></div>';
+
+    function collectFilters() {
+        var params = {};
+        $('.pm-filter').each(function () {
+            var $el = $(this);
+            var name = $el.attr('name');
+            if (!name) return;
+            if ($el.is(':checkbox')) {
+                if ($el.is(':checked')) {
+                    params[name] = '1';
+                }
+            } else {
+                var v = $el.val();
+                if (v !== '' && v !== null) {
+                    params[name] = v;
+                }
+            }
+        });
+        params['per-page'] = $('#pm-per-page').val();
+        return params;
+    }
+
+    function reloadList(extraParams) {
+        var params = collectFilters();
+        if (extraParams) {
+            $.extend(params, extraParams);
+        }
+        var $tab = $('#tab-mappings');
+        $tab.html('<div class="text-muted p-4 text-center"><i class="fa fa-spinner fa-spin me-2"></i>Загрузка...</div>');
+        $.get(cfg.urls.index, params, function (html) {
+            $tab.html(html);
+        });
+    }
+
+    function reloadAnalytics() {
+        var params = collectFilters();
+        delete params['per-page'];
+        $.get(cfg.urls.analytics, params, function (data) {
+            $.each(data, function (field, value) {
+                $('[data-analytics-field="' + field + '"]').text(value);
+            });
+        }, 'json');
+    }
+
+    // ========= ФИЛЬТРЫ =========
+
+    $(document).on('change' + NS, '.pm-filter', function () {
+        var name = $(this).attr('name');
+
+        if (name === 'category') {
+            var category = $(this).val();
+            $('#pm-filter-subcategory').html('<option value="">Все</option>').prop('disabled', !category);
+            $('#pm-filter-species').html('<option value="">Все</option>').prop('disabled', true);
+            if (category) {
+                $.get(cfg.urls.cascade, {category: category}, function (data) {
+                    var html = '<option value="">Все</option>';
+                    $.each(data.subcategories, function (_, sub) {
+                        html += '<option value="' + sub + '">' + sub + '</option>';
+                    });
+                    $('#pm-filter-subcategory').html(html).prop('disabled', false);
+                }, 'json');
+            }
+            reloadList({page: 1});
+            return;
+        }
+
+        if (name === 'subcategory') {
+            var cat = $('#pm-filter-category').val();
+            var sub = $(this).val();
+            $('#pm-filter-species').html('<option value="">Все</option>').prop('disabled', !sub);
+            if (cat && sub) {
+                $.get(cfg.urls.cascade, {category: cat, subcategory: sub}, function (data) {
+                    var html = '<option value="">Все</option>';
+                    $.each(data.species, function (_, sp) {
+                        html += '<option value="' + sp + '">' + sp + '</option>';
+                    });
+                    $('#pm-filter-species').html(html).prop('disabled', false);
+                }, 'json');
+            }
+            reloadList({page: 1});
+            return;
+        }
+
+        if (name === 'search') return;
+
+        reloadList({page: 1});
+    });
+
+    // Поиск — с debounce 400мс
+    $(document).on('input' + NS, 'input[name="search"].pm-filter', function () {
+        clearTimeout(searchTimer);
+        searchTimer = setTimeout(function () {
+            reloadList({page: 1});
+        }, 400);
+    });
+
+    // Сброс фильтров
+    $(document).on('click' + NS, '#pm-filter-reset', function () {
+        $('.pm-filter').each(function () {
+            var $el = $(this);
+            if ($el.is(':checkbox')) {
+                $el.prop('checked', false);
+            } else if ($el.is('select')) {
+                $el.val('');
+            } else {
+                $el.val('');
+            }
+        });
+        reloadList({page: 1});
+    });
+
+    // Смена per-page
+    $('#pm-per-page').on('change', function () {
+        reloadList({page: 1});
+    });
+
+    // Экспорт в .xlsx — редирект с текущими фильтрами
+    $(document).on('click' + NS, '#pm-export-btn', function () {
+        var params = collectFilters();
+        delete params['per-page'];
+        var qs = $.param(params);
+        window.location.href = cfg.urls.export + (qs ? '?' + qs : '');
+    });
+
+    // Пагинация — перехват ссылок
+    $(document).on('click' + NS, '.pm-pager a', function (e) {
+        e.preventDefault();
+        var href = $(this).attr('href');
+        var pageMatch = href.match(/[?&]page=(\d+)/);
+        var page = pageMatch ? pageMatch[1] : 1;
+        reloadList({page: page});
+    });
+
+    // ========= МОДАЛКА МАППИНГА =========
+
+    $(document).on('click' + NS, '.btn-pm-add', function () {
+        var $btn = $(this);
+        if ($btn.prop('disabled')) return;
+        $btn.prop('disabled', true);
+        editingId = null;
+        var guid = $btn.data('product-guid');
+        $('#pm-modal-title').text('Добавить поставщика');
+        $('#pm-modal-body').html(loaderHtml);
+        pmModal.show();
+        $.get(cfg.urls.createForm, {product_guid: guid}, function (html) {
+            $('#pm-modal-body').html(html);
+        }).always(function () {
+            $btn.prop('disabled', false);
+        });
+    });
+
+    $(document).on('click' + NS, '.btn-pm-edit', function (e) {
+        e.preventDefault();
+        var $btn = $(this);
+        if ($btn.prop('disabled')) return;
+        $btn.prop('disabled', true);
+        editingId = $btn.data('id');
+        $('#pm-modal-title').text('Редактировать маппинг');
+        $('#pm-modal-body').html(loaderHtml);
+        pmModal.show();
+        $.get(cfg.urls.updateForm, {id: editingId}, function (html) {
+            $('#pm-modal-body').html(html);
+        }).always(function () {
+            $btn.prop('disabled', false);
+        });
+    });
+
+    $(document).on('click' + NS, '#btn-mapping-save', function () {
+        var $form = $('#mapping-form');
+        var url = editingId ? cfg.urls.update + '?id=' + editingId : cfg.urls.create;
+
+        $form.find('.is-invalid').removeClass('is-invalid');
+        $form.find('.invalid-feedback').remove();
+
+        $.ajax({
+            url: url,
+            type: 'POST',
+            data: $form.serialize(),
+            dataType: 'json',
+            success: function (resp) {
+                if (resp.success) {
+                    pmModal.hide();
+                    reloadList();
+                } else if (resp.errors) {
+                    $.each(resp.errors, function (field, messages) {
+                        var $input = $form.find('[name="ProductMapping[' + field + ']"]');
+                        if (!$input.length) {
+                            $input = $form.find('[name="ProductMapping[' + field + '][]"]');
+                        }
+                        $input.addClass('is-invalid');
+                        $input.after('<div class="invalid-feedback">' + messages[0] + '</div>');
+                    });
+                }
+            },
+            error: function () { alert('Ошибка сервера'); }
+        });
+    });
+
+    $(document).on('click' + NS, '.btn-pm-delete', function (e) {
+        e.preventDefault();
+        var id = $(this).data('id');
+        var name = $(this).data('name');
+
+        if (!confirm('Удалить маппинг на поставщика "' + name + '"?')) {
+            return;
+        }
+
+        $.ajax({
+            url: cfg.urls.delete + '?id=' + id,
+            type: 'POST',
+            data: {_csrf: yii.getCsrfToken()},
+            dataType: 'json',
+            success: function (resp) {
+                if (resp.success) {
+                    reloadList();
+                } else {
+                    alert(resp.message || 'Ошибка удаления');
+                }
+            },
+            error: function () { alert('Ошибка сервера'); }
+        });
+    });
+
+    // Очистка ошибок при вводе
+    $(document).on('input change' + NS, '#mapping-form input, #mapping-form select', function () {
+        $(this).removeClass('is-invalid');
+        $(this).next('.invalid-feedback').remove();
+    });
+}());