]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Восстановили views/charts-for-management/index.php origin/bug_smirnov_2025_01_10_charts_for_management_index
authorAlexander Smirnov <fredeom@mail.ru>
Fri, 10 Jan 2025 07:14:14 +0000 (10:14 +0300)
committerAlexander Smirnov <fredeom@mail.ru>
Fri, 10 Jan 2025 07:14:14 +0000 (10:14 +0300)
erp24/views/charts-for-management/index.php [new file with mode: 0644]

diff --git a/erp24/views/charts-for-management/index.php b/erp24/views/charts-for-management/index.php
new file mode 100644 (file)
index 0000000..90030e7
--- /dev/null
@@ -0,0 +1,1061 @@
+<?php
+
+use kartik\select2\Select2;
+use yii\helpers\Html;
+use yii\helpers\Json;
+use yii\web\View;
+
+/**
+ * @var $this View
+ * @var $access []
+ */
+
+$default_start_date = date('Y-m-d', strtotime('-13 day'));
+$default_end_date = date('Y-m-d', time());
+
+$select_mode_json = [];
+
+foreach ($access as $chart_name => $access_chart) {
+    foreach ($access_chart['mode_level'] as $key => $item) {
+        $select_mode_json[$chart_name][] = ['id' => $key, 'text' => $item];
+    }
+
+}
+
+$select_shift_json = [];
+
+foreach ($access as $chart_name => $access_chart) {
+    foreach ($access_chart['mode_shift'] as $key => $item) {
+        $select_shift_json[$chart_name][] = ['id' => $key, 'text' => $item];
+    }
+
+}
+
+$select_mode_json = Json::encode($select_mode_json);
+$select_shift_json = Json::encode($select_shift_json);
+
+$this->registerCss(<<<CSS
+.apexcharts-toolbar {
+  display: flex !important;
+}
+CSS);
+
+$this->registerJsFile('/js/charts/apexcharts.js', ['position' => \yii\web\View::POS_END]);
+
+$this->registerJs(<<<JS
+
+    //region Настроки чартов
+    let default_chart_options = {
+        series: [],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'line',
+            height: 500,
+            stacked: false
+        },
+        colors: ['red', 'blue'],
+        dataLabels: {
+            enabled: false
+        },
+        stroke: {
+            width: [4, 4, 4]
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100
+        },
+       xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        markers: {
+            size: 4
+        },
+        yaxis: [{
+            labels: {
+                formatter: function (val, index) {
+                    return (val / 1000).toFixed(2) + ' тыс.';
+                }
+            }
+        }]
+    };
+
+    let count_sales_chart_options = {
+        series:[],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'bar',
+            height: 600,
+            stacked: true,
+            toolbar: {
+                show: true
+            },
+            zoom: {
+                enabled: true
+            }
+        },
+        responsive: [{
+            breakpoint: 480,
+            options: {
+                legend: {
+                    position: 'bottom',
+                    horizontalAlign: 'center',
+                    height: 100,
+                },
+            }
+        }],
+       xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        yaxis: [{
+            labels: {
+                formatter: function (val, index) {
+                    return val + ' шт.';
+                }
+            }
+        }],
+        fill: {
+            opacity: 1
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100,
+        },
+    };
+    
+    let count_sales_percent_chart_options = {
+        series:[],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'bar',
+            height: 600,
+            stacked: true,
+            stackType: '100%',
+            toolbar: {
+                show: true
+            },
+            zoom: {
+                enabled: true
+            }
+        },
+        responsive: [{
+            breakpoint: 480,
+            options: {
+                legend: {
+                    position: 'bottom',
+                    horizontalAlign: 'center',
+                    height: 100,
+                },
+            }
+        }],
+       xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        yaxis: [{
+            labels: {
+                show: false,
+                formatter: function (val, index) {
+                    return val + ' шт.';
+                }
+            }
+        }],
+        fill: {
+            opacity: 1
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100,
+        },
+    };
+    
+    let matrix_sales_chart_options = {
+        series: [],
+        chart: {
+            type: 'bar',
+            height: 600,
+            locales: [ru],
+            defaultLocale: 'ru',
+            stacked: true,
+            toolbar: {
+                show: true
+            },
+            zoom: {
+                enabled: true
+            }
+        },
+        responsive: [{
+            breakpoint: 480,
+            options: {
+                legend: {
+                    position: 'bottom',
+                    offsetX: -10,
+                    offsetY: 0
+                }
+            }
+        }],
+        plotOptions: {
+            bar: {
+                horizontal: false,
+                dataLabels: {
+                    total: {
+                        formatter: function (val, index) {
+                            return (val / 1000).toFixed(2) + ' тыс.';
+                        },
+                        enabled: true,
+                        style: {
+                            fontSize: '10px',
+                            fontWeight: 400
+                        }
+                    },
+                }
+            },
+        },
+        xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        yaxis: [{
+            labels: {
+                formatter: function (val, index) {
+                    return (val / 1000).toFixed(2) + ' тыс.';
+                }
+            }
+        }],
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100,
+        },
+        fill: {
+            opacity: 1
+        }
+    };
+    
+    let count_sales_in_hour_chart_options = {
+        series: [],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'bar',
+            height: 600
+        },
+        plotOptions: {
+            bar: {
+                borderRadius: 4,
+                horizontal: true,
+            }
+        },
+        dataLabels: {
+            enabled: false
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 40,
+        },
+        yaxis: [{
+            labels: {
+                formatter: function (val, index) {
+                    return parseFloat(val).toFixed(2);
+                }
+            }
+        }],
+        xaxis: {
+            categories: [
+                '8 ч.',
+                '9 ч.',
+                '10 ч.',
+                '11 ч.',
+                '12 ч.',
+                '13 ч.',
+                '14 ч.',
+                '15 ч.',
+                '16 ч.',
+                '17 ч.',
+                '18 ч.',
+                '19 ч.',
+                '20 ч.',
+                '21 ч.',
+                '22 ч.',
+                '23 ч.',
+                '0 ч.',
+                '1 ч.',
+                '2 ч.',
+                '3 ч.',
+                '4 ч.',
+                '5 ч.',
+                '6 ч.',
+                '7 ч.'
+            ],
+        }
+    
+    };
+    
+    let fot_chart_options = {
+        series:[],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'line',
+            height: 500,
+            stacked: false
+        },
+        colors: ['red', 'blue'],
+        dataLabels: {
+            enabled: false
+        },
+        stroke: {
+            width: [4, 4, 4]
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100,
+        },
+        xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        markers: {
+            size: 4
+        },
+        yaxis: [{
+            labels: {
+                formatter: function (val, index) {
+                    return parseFloat(val).toFixed(2) + ' %';
+                }
+            }
+        }],
+    };
+    
+    let one_admin_sales_chart_options = {
+        series:[],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'line',
+            height: 500,
+            stacked: false,
+        },
+        dataLabels: {
+            enabled: false
+        },
+        stroke: {
+            width: [4, 4, 4]
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100,
+        },
+        xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        markers: {
+            size: 4
+        },
+        yaxis: [{
+            labels: {
+                formatter: function (val, index) {
+                    return parseFloat(val).toFixed(2) + ' р.';
+                }
+            }
+        }],
+    };
+    
+    let write_offs_chart_options = {
+        series:[],
+        chart: {
+            locales: [ru],
+            defaultLocale: 'ru',
+            type: 'line',
+            height: 500,
+            stacked: false,
+        },
+        dataLabels: {
+            enabled: false
+        },
+        stroke: {
+            width: [4, 4, 4]
+        },
+        legend: {
+            position: 'bottom',
+            horizontalAlign: 'center',
+            height: 100,
+        },
+        xaxis: {
+            'type': 'text',
+            'categories': [],
+            'title': {
+                'text': 'Дата'
+            }
+        },
+        markers: {
+            size: 4
+        },
+        yaxis: [
+            {
+                labels: {
+                    align: 'left',
+                    formatter: function (val, index) {
+                        return parseFloat(val).toFixed(2) + ' р.';
+                    }
+                }
+            
+            },
+            {
+                min: 0,
+                max: 100,
+                opposite: true,
+                labels: {
+                    align: 'right',
+                    formatter: function (val, index) {
+                        return parseFloat(val).toFixed(2) + ' %';
+                    }
+                }
+            },
+            {
+                labels: {
+                    show: false,
+                    formatter: function (val, index) {
+                        return parseFloat(val).toFixed(2) + ' %';
+                    }
+                }
+            }
+        ]  
+    };
+    
+    let radio_chart_options = {
+        series:[0],
+        chart: {
+            type: 'radialBar',
+            offsetY: -20,
+            sparkline: {
+                enabled: true
+            }
+        },
+        plotOptions: {
+            radialBar: {
+                startAngle: -90,
+                endAngle: 90,
+                track: {
+                    background: "#e7e7e7",
+                    strokeWidth: '97%',
+                    margin: 5, // margin is in pixels
+                    dropShadow: {
+                        enabled: true,
+                        top: 2,
+                        left: 0,
+                        color: '#999',
+                        opacity: 1,
+                        blur: 2
+                    }
+                },
+                dataLabels: {
+                    name: {
+                        show: false
+                    },
+                    value: {
+                        offsetY: -2,
+                        fontSize: '22px'
+                    }
+                }
+            }
+        },
+        grid: {
+            padding: {
+                top: -10
+            }
+        },
+        fill: {
+            type: 'gradient',
+            gradient: {
+                shade: 'light',
+                shadeIntensity: 0.4,
+                inverseColors: false,
+                opacityFrom: 1,
+                opacityTo: 1,
+                stops: [0, 50, 53, 91]
+            },
+        },
+        labels: ['Average Results'],
+    };
+    //endregion
+    
+    let charts_options = {
+        'default_chart_options': default_chart_options,
+        'count_sales_chart_options': count_sales_chart_options,
+        'count_sales_percent_chart_options': count_sales_percent_chart_options,
+        'matrix_sales_chart_options': matrix_sales_chart_options,
+        'count_sales_in_hour_chart_options': count_sales_in_hour_chart_options,
+        'fot_chart_options': fot_chart_options,
+        'one_admin_sales_options': one_admin_sales_chart_options,
+        'write_offs_chart_options': write_offs_chart_options,
+        'radio_chart_options': radio_chart_options,
+    }
+
+    let stores_in_cluster_array = [];
+    
+    let count_chart_on_attribute = [];
+    
+    let mode_default = JSON.parse('$select_mode_json');
+    
+    let shift_default = JSON.parse('$select_shift_json');
+    
+    let default_date_start = '$default_start_date';
+    let default_date_end = '$default_end_date'
+    
+    function DateChanges (attribute) {
+        let attribute_split_DOM = attribute.split('-');
+        let atribut_group_name = attribute_split_DOM[0];
+        let postfix = attribute_split_DOM[1];
+        let id = attribute_split_DOM[2];
+        
+        let date_start_input = $('input[id="date-start-' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+        let date_end_input = $('input[id="date-end-' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+        
+        let date_start = date_start_input.val();
+        let date_end = date_end_input.val();
+        
+        let information_row = $('div[id*="information-row-' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+        information_row.html('');
+        
+        if (date_start === "" || date_end === "" || new Date(date_start) > new Date(date_end) || (new Date(date_end) > new Date() && atribut_group_name === 'fot')) {
+            information_row.html('<p>Ошибка валидации:<br> Дата начала должна быть больше даты окончания выборки!<br>Даты должны быть заполнены!<br> Дата окончания не может быть больше текущей даты!</p>');
+            if (atribut_group_name === 'fot') {
+                information_row.append('<br> Дата окончания не может быть больше текущей даты!')
+            }
+            
+            $('button[id*="update"][id*="' + attribute + '"][attribute*="' + attribute + '"]').prop('disabled', true);
+            return;
+        }
+        $('button[id*="update"][id*="' + attribute + '"][attribute*="' + attribute + '"]').prop('disabled', false);
+        UpdateSelectorsDate (date_start, date_end, atribut_group_name, postfix, id);
+    }
+    
+    function ModeChanges (attribute, value) {
+        let attribute_split_DOM = attribute.split('-');
+        let atribut_group_name = attribute_split_DOM[0];
+        let postfix = attribute_split_DOM[1];
+        let id = attribute_split_DOM[2];
+        
+        let cluster_select = $('[id*="cluster-select"][attribute="' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+        let store_select = $('[id*="store-select"][attribute="' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+        
+        switch (parseInt(value)) {
+            case 0:
+              
+              cluster_select.val(null);
+              cluster_select.prop('disabled', true);
+              cluster_select.trigger('change');
+              
+              store_select.val(null);
+              store_select.empty();
+              store_select.prop('disabled', true);
+              store_select.trigger('change');
+              
+          break;
+          case 1:
+              
+              cluster_select.val(null);
+              cluster_select.prop('disabled', true);
+              cluster_select.trigger('change');
+              
+              store_select.val(null);
+              store_select.empty();
+              store_select.prop('disabled', true);
+              store_select.trigger('change');
+              
+          break;
+          case 2:
+              cluster_select.val(null);
+              cluster_select.prop('disabled', false);
+              cluster_select.trigger('change');
+              
+              store_select.val(null);
+              store_select.empty();
+              store_select.prop('disabled', true);
+              store_select.trigger('change');
+              
+          break;
+          case 3:
+              cluster_select.val(null);
+              cluster_select.prop('disabled', false);
+              cluster_select.trigger('change');
+              
+              store_select.val(null);
+              store_select.empty();
+              store_select.prop('disabled', false);
+              store_select.trigger('change');
+              
+          break;
+        }
+    }
+    
+    function ClusterChanges (attribute, value) {
+        let attribute_split_DOM = attribute.split('-');
+        let atribut_group_name = attribute_split_DOM[0];
+        let postfix = attribute_split_DOM[1];
+        let id = attribute_split_DOM[2];
+        
+        let store_select = $('[id*="store-select-' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+        
+        store_select.empty();
+        
+        store_select.select2({
+            data: [stores_in_cluster_array[attribute][value]],
+            placeholder: 'Выберите магазин',
+            minimumResultsForSearch: -1
+        });
+        
+        store_select.val(null);
+        
+        store_select.trigger('change');
+    }
+    
+    function UpdateClick (attribute_DOM) {
+        let attribute_split_DOM = attribute_DOM.split('-');
+        let atribut_group_name = attribute_split_DOM[0];
+        let postfix = attribute_split_DOM[1];
+        let id = attribute_split_DOM[2];
+        
+        let date_start = $('input[id*="date-start"][id*="' + attribute_DOM + '"]').val();
+        let date_end = $('input[id*="date-end"][id*="' + attribute_DOM + '"]').val();
+        let mode = $('select[id*="mode-select"][id*="' + attribute_DOM + '"]').val();
+        let cluster = $('select[id*="cluster-select"][id*="' + attribute_DOM + '"]').val();
+        let store = $('select[id*="store-select"][id*="' + attribute_DOM + '"]').val();
+        let shift = $('select[id*="shift-select"][id*="' + attribute_DOM + '"]').val();
+        
+        if (date_start > date_end) {
+            return;
+        }
+        
+        $('button[id*="update"][id*="' + attribute_DOM + '"][attribute*="' + attribute_DOM + '"]').prop('disabled', true);
+        
+        var csrfToken = $('meta[name="csrf-token"]').attr("content");
+        
+        let data = {
+            date_start: date_start,
+            date_end: date_end,
+            mode: mode,
+            cluster: cluster,
+            store: store,
+            attribute: atribut_group_name,
+            shift: shift,
+            _csrf : csrfToken
+        }
+        
+        $.ajax({
+            url: '/charts-for-management/get-data-ajax',
+            method: 'POST',
+            dataType: 'json',
+            data: data,
+            success: function(data) {
+                ChartUpdate (data.data_answer.attribute, data.chart_opts, atribut_group_name, postfix, id);
+                $('button[id*="update"][id*="' + attribute_DOM + '"][attribute*="' + attribute_DOM + '"]').trigger('update_series');
+            }
+        });
+    }
+    
+    function ChartUpdate (data, options, atribut_group_name, postfix, id = '') {
+        
+        let data_view = [];
+                    
+        Object.keys(data).forEach((index) => {
+            data_view.push(data[index]);
+        });
+        
+        ApexCharts.exec((atribut_group_name + '-' + postfix + ((id !== '') ? ('-' + id) : '')), 'updateSeries', data_view, false, true);
+        
+        if (options !== null) {
+            ApexCharts.exec((atribut_group_name + '-' + postfix + ((id !== '') ? ('-' + id) : '')), 'updateOptions', options);
+        }
+    }
+    
+    function CreateChart (chart_type, atribut_group_name, postfix, id = '') {
+        charts_options[chart_type].chart.id = (atribut_group_name + '-' + postfix + ((id !== '') ? ('-' + id) : ''))
+        let chart = new ApexCharts(document.querySelector("#chart-panel-" + atribut_group_name + '-' + postfix + ((id !== '') ? ('-' + id) : '')), charts_options[chart_type]);
+        chart.render();
+        
+    }
+
+    $('input[id*="date-start"], input[id*="date-end"]').on('change', function() {
+        let attribute_DOM = this.attributes.attribute.value;
+        
+        DateChanges (attribute_DOM);
+    });
+    
+    function UpdateSelectorsDate (date_start, date_end, atribut_group_name, postfix, id = undefined) {
+        let dates = {
+            date_start: date_start,
+            date_end: date_end  
+        };
+        
+        let stores_step;
+        let clusters;
+        let stores_in_cluster;
+        
+        $.ajax({
+            url: '/charts-for-management/get-control-data-ajax',
+            method: 'POST',
+            dataType: 'json',
+            data: dates,
+            success: function(answer) {
+                let cluster_select = $('[id*="cluster-select-' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+                let store_select = $('[id*="store-select-' + atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '') + '"]');
+                
+                stores_step = answer.stores_step;
+                clusters = answer.clusters;
+                console.log(clusters);
+                stores_in_cluster = answer.stores_in_cluster;
+                 console.log(stores_in_cluster);
+                //TODO Костыль
+                if (atribut_group_name === 'write_offs') {
+                    Object.keys(stores_in_cluster).forEach((cluster_id) => {
+                        Object.keys(stores_in_cluster[cluster_id]['children']).forEach((key) => {
+                            if (stores_in_cluster[cluster_id]['children'][key].id == 4 ) {
+                                stores_in_cluster[cluster_id]['children'][key].text = 'Аэродромная + Доставка'
+                            }
+                        })
+                    })
+                   
+                }
+                
+                stores_in_cluster_array[atribut_group_name + ((postfix !== undefined) ? ('-' + postfix) : '') + ((id !== undefined) ? ('-' + id) : '')] = stores_in_cluster;
+                
+                
+                cluster_select.select2({
+                    data: clusters,
+                    placeholder: 'Выберите куст',
+                    minimumResultsForSearch: -1,
+                });
+                
+                cluster_select.val(null);
+                
+                cluster_select.trigger('change');
+                
+                store_select.val(null);
+                store_select.empty();
+                store_select.trigger('change');
+            }
+        });
+    }
+
+    $('select[id*="mode-select"]').on('change', function() {
+        let attribute = this.attributes.attribute.value;
+        
+        ModeChanges (attribute, this.value)
+    })
+    
+    $('select[id*="cluster-select"]').on('change', function() {
+        if (this.value === null || this.value === '') {
+            return;
+        }
+        
+        let attribute = this.attributes.attribute.value;
+        
+        ClusterChanges (attribute, this.value);
+    });
+    
+    $('#update-controls').on('click', function() {
+        
+        let date_start = $('input[id*="date-start"][id*="main"]').val();
+        let date_end = $('input[id*="date-end"][id*="main"]').val();
+        let mode = $('select[id*="mode-select"][id*="main"]').val();
+        let cluster = $('select[id*="cluster-select"][id*="main"]').val();
+        let store = $('select[id*="store-select"][id*="main"]').val();
+        let shift = $('select[id*="shift-select"][id*="main"]').val()
+        
+        $('input[id*="date-start"][id*="default"]').val(date_start);
+        $('input[id*="date-end"][id*="default"]').val(date_end).trigger('change');
+        
+        setTimeout(function() {
+            $('select[id*="mode-select"][id*="default"]').val(mode).trigger('change');
+            $('select[id*="cluster-select"][id*="default"]').val(cluster).trigger('change');
+            $('select[id*="store-select"][id*="default"]').val(store).trigger('change');
+            $('select[id*="shift-select"][id*="default"]').val(shift).trigger('change');
+        }, 1000 / (5));
+        
+        setTimeout(function() {
+          $('button[id*="update"][id*="default-chart"]').trigger('click');
+        }, 1000/(5))
+    });
+    
+    $('#date-start-main').val(default_date_start);
+    $('#date-end-main').val(default_date_end).trigger('change');
+    
+    $('#mode-select-main').trigger('change');
+    
+    $('button[id="update-controls"][attribute="main"]').trigger('click');
+    
+    $('button[id*="update"]:not([attribute*="main"])').on('click', function() {
+        let attribute_DOM = this.attributes.attribute.value;
+        
+        UpdateClick (attribute_DOM);
+    });
+    
+    $('button[id*="update"]:not([attribute*="main"])').on('update_series', function() {
+        
+        let attribute_DOM = this.attributes.attribute.value;
+        let attribute_split_DOM = attribute_DOM.split('-');
+        let atribut_group_name = attribute_split_DOM[0];
+        let postfix = attribute_split_DOM[1];
+        let id = attribute_split_DOM[2];
+        
+        $('button[id*="update"][id*="' + attribute_DOM + '"][attribute*="' + attribute_DOM + '"]').prop('disabled', false);
+    });
+JS
+);
+?>
+
+<div class="p-8">
+    <h1>
+        Показатели компании
+    </h1>
+    <div id="panel-charts-main" style="min-width: 200px">
+        <h4>Общая форма</h4>
+        <div id="control-charts-main" attribute="main">
+            <div class="" id="inputs-row-main">
+                <hr class="my-2 border-white" style="mix-blend-mode: difference">
+                <div class="mt-2" id="information-row-main" attribute="main">
+                </div>
+                <div class="mt-2 d-flex flex-row justify-content-between" id="date-row-main"
+                     attribute="main">
+                    <?= Html::input(
+                        'date',
+                        null,
+                        '',
+                        [
+                            'class' => 'w-40',
+                            'id' => 'date-start-main',
+                            'attribute' => 'main'
+                        ]
+                    ) ?>
+                    <?= Html::input(
+                        'date',
+                        null,
+                        '',
+                        [
+                            'class' => 'w-40',
+                            'id' => 'date-end-main',
+                            'attribute' => 'main'
+                        ]
+                    ) ?>
+                </div>
+                <div class="my-2 d-flex flex-row justify-content-between" id="data-row-main"
+                     attribute="main">
+                    <div class="w-30 mw-30">
+                        <?= Select2::widget([
+                            'name' => '',
+                            //'value' => 1,
+                            'data' => $access['main']['mode_level'],
+                            'options' => [
+                                'id' => 'mode-select-main',
+                                'style' => 'width:100%',
+                                'attribute' => 'main'
+                            ],
+                            'pluginOptions' => [
+                                'allowClear' => true,
+                                'minimumResultsForSearch' => -1
+                            ],
+                        ]) ?>
+                    </div>
+                    <div class="w-30 mw-30">
+                        <?= Select2::widget([
+                            'name' => '',
+                            'data' => [],
+                            'options' => [
+                                'placeholder' => 'Выберите куст',
+                                'id' => 'cluster-select-main',
+                                'attribute' => 'main',
+                                'style' => 'width:100%',
+                            ],
+                            'pluginOptions' => [
+                                'allowClear' => true,
+                                'minimumResultsForSearch' => -1
+                            ],
+                        ]) ?>
+                    </div>
+                    <div class="w-30 mw-30">
+                        <?= Select2::widget([
+                            'name' => '',
+                            'data' => [],
+                            'options' => [
+                                'placeholder' => 'Выберите магазин',
+                                'id' => 'store-select-main',
+                                'style' => 'width:100%',
+                                'attribute' => 'main'
+                            ],
+                            'pluginOptions' => [
+                                'allowClear' => true,
+                                'minimumResultsForSearch' => -1
+                            ],
+                        ]) ?>
+                    </div>
+                </div>
+                <div class="my-2 d-flex flex-row justify-content-between" id="shift-row-main"
+                     attribute="main">
+                    <div class="w-100 mw-100">
+                        <?= Select2::widget([
+                            'name' => '',
+                            'value' => (isset($access['main']['mode_shift'][3]) ? 3 : ((isset($access['main']['mode_shift'][1])) ? 1 : 2)),
+                            'data' => $access['main']['mode_shift'],
+                            'options' => [
+                                'placeholder' => '',
+                                'id' => 'shift-select-main',
+                                'style' => 'width:100%',
+                                'attribute' => 'main',
+
+                            ],
+                            'pluginOptions' => [
+                                'allowClear' => true,
+                                'minimumResultsForSearch' => -1,
+                            ],
+                        ]) ?>
+                    </div>
+                </div>
+                <div class="d-flex flex-row justify-content-between" id="button-row-main"
+                     attribute="main">
+                    <button class="btn btn-danger disabled" style="opacity: 0;" id="joke-main">-</button>
+                    <button class="btn btn-success" id="update-controls"
+                            attribute="main">Обновить
+                    </button>
+                </div>
+                <hr class="my-2 border-white" style="mix-blend-mode: difference">
+            </div>
+        </div>
+    </div>
+    <div class="row">
+        <div class="mt-2 row">
+            <?php if ($access['plan_completed_this_day']['visible']): ?>
+                <div class="col">
+                    <?= $this->render('radial-chart', [
+                        'attribute_name' => 'plan_completed_this_day',
+                        'title' => 'Выполнение плана на текущий день',
+                        'chart_type' => 'radio_chart_options',
+                        'access' => $access['plan_completed_this_day']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <?php if ($access['plan_completed_this_month']['visible']): ?>
+                <div class="col">
+                    <?= $this->render('radial-chart', [
+                        'attribute_name' => 'plan_completed_this_month',
+                        'title' => 'Выполнение плана на конец месяца',
+                        'chart_type' => 'radio_chart_options',
+                        'access' => $access['plan_completed_this_month']
+                    ]) ?>
+                </div>
+                <div class="w-100"></div>
+            <?php endif; ?>
+            <?php if ($access['sales']['visible']): ?>
+                <div class="col">
+                    <?= $this->render('chart', [
+                        'attribute_name' => 'sales',
+                        'title' => 'Продажи',
+                        'chart_type' => 'default_chart_options',
+                        'access' => $access['sales']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <?php if ($access['avg_sales_value']['visible']): ?>
+                <div class="col">
+                    <?= $this->render('chart', [
+                        'attribute_name' => 'avg_sales_value',
+                        'title' => 'Средний чек',
+                        'chart_type' => 'default_chart_options',
+                        'access' => $access['avg_sales_value']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <div class="w-100"></div>
+            <?php if ($access['fot']['visible']): ?>
+                <div class="col">
+                    <?= $this->render('chart', [
+                        'attribute_name' => 'fot',
+                        'title' => 'Доля ФОТ',
+                        'chart_type' => 'fot_chart_options',
+                        'access' => $access['fot']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <?php if ($access['sales_sum_on_admin']['visible']): ?>
+                <div class="col">
+                    <?= $this->render('chart', [
+                        'attribute_name' => 'sales_sum_on_admin',
+                        'title' => 'Продажи на сотрудника',
+                        'chart_type' => 'one_admin_sales_options',
+                        'access' => $access['sales_sum_on_admin']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <div class="w-100"></div>
+            <?php if ($access['user_bonus']['visible']): ?>
+                <div class="col-12">
+                    <?= $this->render('users_bonus-chart', [
+                        'attribute_name' => 'user_bonus',
+                        'title' => 'Пользователи бонусной программы',
+                        'chart_type' => 'count_sales_chart_options',
+                        'access' => $access['user_bonus']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <div class="col-12">
+                <?= $this->render('chart', [
+                    'attribute_name' => 'matrix_sales_sum',
+                    'title' => 'Продажи матрицы',
+                    'chart_type' => 'matrix_sales_chart_options',
+                    'access' => $access['matrix_sales_sum']
+                ]) ?>
+            </div>
+            <?php if ($access['count_sales_in_hour']['visible']): ?>
+                <div class="col-12">
+                    <?= $this->render('chart', [
+                        'attribute_name' => 'count_sales_in_hour',
+                        'title' => 'Продажи в час',
+                        'chart_type' => 'count_sales_in_hour_chart_options',
+                        'access' => $access['count_sales_in_hour']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+            <?php if ($access['write_offs']['visible']): ?>
+                <div class="col-12">
+                    <?= $this->render('write_offs-chart', [
+                        'attribute_name' => 'write_offs',
+                        'title' => 'Списания',
+                        'chart_type' => 'write_offs_chart_options',
+                        'access' => $access['write_offs']
+                    ]) ?>
+                </div>
+            <?php endif; ?>
+        </div>
+    </div>
+</div>
+