3.4.3. Пользовательский компонент Воронка продаж

Особенность этого пользовательского компонента заключается в использовании внешних js библиотек.

Но основе данных, получаемых по специальному апи, необходимо построить воронку следующего вида:

../../_images/funnel_only.png

Для компонента используется библиотека d3-funnel

Html код компонента содержит сдедующий код:

<style>
.chart {
    margin: 0 auto;
    margin-top: 20px;
    margin-bottom: 20px;
    height: 500px;
    width: 450px;
}
</style>
<!-- Funnel container -->
<div class="chart" id="funnel"></div>

Javascript код:

/* global D3Funnel */
const data = {
    normal: [
       ['Первичная регистрация', [0, ''], '#e73a00'],
        ['Квалификация', [0, ''], '#fa6c00'],
        ['Взращивание', [0, ''], '#ffa900'],
        ['Подтверждение интереса', [0, ''], '#ffc500'],
        ['В сделку', [0, ''], '#a6cf00'],
    ]
};
/*параметры воронки*/
const options = {
            chart: {
                width: 450,
                height: 500,
                bottomWidth: 1 / 2,
                curve: {
                    enabled: false,
                },
            },
            block: {
                dynamicHeight: true,
                highlight: true,
                minHeight: 40,

            },
            label: {
                format: '{l}: {v}\n{f}',
            },
            events: {
                click: {
                    block: (d) => {
                    alert('<' + d.label.raw + '> selected.');
},},}}

const chart = new D3Funnel('#funnel');
chart.draw(data.normal, options);

Чтобы отобразить воронку для константных данных, можете поместить компонент на форму и прописать в скрипте следующий код:

setTimeout(function() {
  const data = {
            normal: [
                ['Первичная регистрация', [20, ''], '#e73a00'],
                ['Квалификация', [15, ''], '#fa6c00'],
                ['Взращивание', [8, ''], '#ffa900'],
                ['Подтверждение интереса', [7, ''], '#ffc500'],
                ['В сделку', [5, ''], '#a6cf00'],
            ]
        };
    const options = {
        chart: {
            width: 450,
            height: 500,
            bottomWidth: 1 / 2,
            curve: {
                enabled: false,
            },
        },
        block: {
            dynamicHeight: false,
            highlight: true,
            minHeight: 40,
            },
        label: {
            format: '{l}\n{v} {f}',
        }
    };

    const chart = new D3Funnel('#funnel');
    chart.draw(data.normal, options);
}, 5);

Воронка не будет отображена до тех пор, пока на страницу не будет загружен скрипт d3-funnel. Для подключения библиотеки можно прописать на странице html, куда будет помещен проигрыватель, следующее:

<!-- Required D3 library -->
<script src="d3/dist/d3.v4.js"></script>
<!-- D3Funnel source file -->
<script src="d3/dist/d3-funnel.js"></script>

В текущем случае мы отображаем форму в проигрывателе Synergy, поэтому, чтобы не править страницу Synergy.html, можно подгрузить скрипт с помощью пользовательского компонента и ВМК.

Для этого создаем пользовательский компонент с кодом и названием d3funnel, html код оставляем пустым, в javascript код пишем следующее:

jQuery.loadScript = function (url, callback) {
    jQuery.ajax({
        url: url,
        dataType: 'script',
        success: callback,
        async: true
    });
}

$.loadScript('https://d3js.org/d3.v4.min.js', function(){
    $.loadScript('https://cdn.rawgit.com/jakezatecky/d3-funnel/v1.0.0/dist/d3-funnel.js', function(){
        console.log('d3funnel loaded');
    });
});

Создаем ВМК d3funnel для размещения копмонента на странице Synergy onLoad:

../../_images/d3funnel.png

После можем открыть данные по форме с компонентом Воронка продаж, в результате воронка будет иметь вид:

../../_images/funnel_form_simple.png

Рассмотрим случай, когда данные воронки будут получены по специальному апи, и отрисовка будет производиться по изменению значений компонентов на форме.

В этом случае форма с воронкой используется во внешнем модуле, у которого на странице html встроен проигрыватель форм. Ссылки на скрипты d3-funnel будут прописаны на html странице этого модуля:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">

    <script>
        FORM_PLAYER_URL_PREFIX = window.location.protocol + "//" + window.location.host + "/Synergy/";
    </script>

    <script src="scripts.js" type="text/javascript"></script>

    <!-- Required D3 library -->
    <script src="d3/dist/d3.v4.js"></script>

    <!-- D3Funnel source file -->
    <script src="d3/dist/d3-funnel.js"></script>
    <script src="redips-drag-min.js"></script>

    <link href="index.css" rel="stylesheet"/>
</head>

<body>
<div width="100%" height="100%" id="mngmnt_wait_div" style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; visibility: hidden; z-index: 1000;">
    <table border="0" width="100%" height="100%">
        <tbody><tr>
            <td align="center" valign="middle" id="ww"><img src="images/wait.gif"></td>
        </tr>
        </tbody></table>
</div>
<div style="z-index: 0" class="portal-center">
    <div id="form_player_container">


        <div id="form_player_div" >

        </div>
    </div>
</div>

<div id="message" class="hidden">
    <span id="message_text"></span>
</div>

</body>
</html>

Помещаем компонент на форму:

../../_images/funnel_form_edit.png

В скрипте компонента на форме прописываем основную логику: получение данных для формирования воронки, функцию отрисовки воронки.

/*установливаем ширину*/
var width = $(window).width() - 325;
$(view.container[0]).css('width', (width) + 'px');

/*идентификаторы компонентов, значения которых участивуют в формировании параметров для получения данных воронки*/
var crm_form_funnel_events = 'crm_form_funnel_events';
var crm_form_funnel_show_free_leads = 'crm_form_funnel_show_free_leads';
var crm_form_funnel_users = 'crm_form_funnel_users';
var crm_form_funnel_period = 'crm_form_funnel_period';
var crm_form_funnel_start_date = 'crm_form_funnel_start_date';
var crm_form_funnel_finish_date = 'crm_form_funnel_finish_date';
var crm_form_funnel_status = 'crm_form_funnel_status';
var crm_form_funnel_cost = 'crm_form_funnel_cost';
var crm_form_funnel_comission = 'crm_form_funnel_comission';

model.playerModel.isFunnel = false;
view.setVisible(false);
model.playerModel.firstShow = true;

/* определяем функцию перерисовки воронки;
   функция используется в скриптах компонентов, идентификаторы которых определены выше,
   в событии изменения значения
  */
model.playerModel.redraw = function (modeChange) {
    if (model.playerModel.firstShow) {
        return;
    }

    if (!model.playerModel.invisible) {
        width = $(window).width();
    } else {
        width = $(window).width() - 325
    }
    $(view.container[0]).css('width', (width) + 'px');

    var events = model.playerModel.getModelWithId(crm_form_funnel_events);
    var showFreeLeads = model.playerModel.getModelWithId(crm_form_funnel_show_free_leads);
    var users = model.playerModel.getModelWithId(crm_form_funnel_users);
    var periodType = model.playerModel.getModelWithId(crm_form_funnel_period);
    var startDate = model.playerModel.getModelWithId(crm_form_funnel_start_date);
    var finishDate = model.playerModel.getModelWithId(crm_form_funnel_finish_date);
    var status = model.playerModel.getModelWithId(crm_form_funnel_status);

    /*форморирование запроса для получения данных воронки*/
    var factUrl = window.location.origin + "/crm/rest/api/funnel/getData";
    var params = {
        events: events.getValue(),
        users: users.getKey(),
        periodType: periodType.getValue()[0],
        startDate: startDate.getValue(),
        finishDate: finishDate.getValue(),
        status: status.getValue()[0],
        locale: AS.OPTIONS.locale
    };
    if (periodType.getValue()[0] === 'custom' && (startDate.getValue() === null || finishDate.getValue() === null )) {
        return;
    }
    params.showFreeLeads = showFreeLeads.getValue() !== null;
    params.loadLeads = !model.playerModel.isFunnel;
    AS.SERVICES.showWaitWindow();
    /*отправка запроса*/
    var pFact = jQuery.ajax({
        url: factUrl,
        type: "POST",
        beforeSend: AS.FORMS.ApiUtils.addAuthHeader,
        data: params,
        dataType: "text"
    });

    jQuery.when(pFact).then(function (data) {
        if (model.playerModel.isFunnel) {
            model.playerModel.drawFunnel(JSON.parse(data));
            model.playerModel.canbanDrawn = false;
            model.playerModel.funnelDrawn = true;
        } else {
            model.playerModel.drawCanban(JSON.parse(data));
            model.playerModel.funnelDrawn = false;
            model.playerModel.canbanDrawn = true;
        }

        AS.SERVICES.hideWaitWindow();
    });
};

/*отрисовка воронки на основе переданных данных data*/
model.playerModel.drawFunnel = function(data) {
    view.playerView.calcDim();
    var v = [];
    /* global D3Funnel */
    var budget = 0;
    var commission = 0;
    data.forEach(function (object) {
        var t = [];
        t.push(object.name);
        var tt = [];
        tt.push((object.count + "").replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 '));
        tt.push(object.percent);
        t.push(tt);
        t.push(object.color);
        v.push(t);
        budget = budget + object.budget;
        commission = commission + object.commission;
    });

    view.playerView.getViewWithId(crm_form_funnel_cost).container.children()[0].textContent = (budget + "").replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 ');
    view.playerView.getViewWithId(crm_form_funnel_comission).container.children()[0].textContent = (Math.round(commission) + "").replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 ');
    const options = {
        chart: {
            width: 450,
            height: 500,
            bottomWidth: 1 / 2,
            curve: {
                enabled: false,
            },
        },
        block: {
            dynamicHeight: false,
            highlight: true,
            minHeight: 40,

        },
        label: {
            format: '{l}\n{v} {f}',
        }
    }
}

    const chart = new D3Funnel('#funnel');
    chart.draw(v, options);
};

В итоге получается следующая форма, которую можно отобразить во вшешнем модуле:

../../_images/funnel_form.png