Пользовательский компонент *Воронка продаж* ------------------------------------------- Особенность этого пользовательского компонента заключается в использовании внешних js библиотек. Но основе данных, получаемых по специальному апи, необходимо построить воронку следующего вида: .. figure:: ../../_static/img/forms/cmp/funnel_only.png :scale: 100% Для компонента используется библиотека `d3-funnel `_ Html код компонента содержит сдедующий код: .. code-block:: xml
Javascript код: .. code-block:: js /* 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); Чтобы отобразить воронку для константных данных, можете поместить компонент на форму и прописать в скрипте следующий код: .. code-block:: js 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, куда будет помещен проигрыватель, следующее: .. code-block:: xml В текущем случае мы отображаем форму в проигрывателе Synergy, поэтому, чтобы не править страницу Synergy.html, можно подгрузить скрипт с помощью пользовательского компонента и ВМК. Для этого создаем пользовательский компонент с кодом и названием d3funnel, html код оставляем пустым, в javascript код пишем следующее: .. code-block:: js 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: .. figure:: ../../_static/img/forms/cmp/d3funnel.png :scale: 100% После можем открыть данные по форме с компонентом *Воронка продаж*, в результате воронка будет иметь вид: .. figure:: ../../_static/img/forms/cmp/funnel_form_simple.png :scale: 100% Рассмотрим случай, когда данные воронки будут получены по специальному апи, и отрисовка будет производиться по изменению значений компонентов на форме. В этом случае форма с воронкой используется во внешнем модуле, у которого на странице html встроен проигрыватель форм. Ссылки на скрипты d3-funnel будут прописаны на html странице этого модуля: .. code-block:: xml
Помещаем компонент на форму: .. figure:: ../../_static/img/forms/cmp/funnel_form_edit.png :scale: 100% В скрипте компонента на форме прописываем основную логику: получение данных для формирования воронки, функцию отрисовки воронки. .. code-block:: js /*установливаем ширину*/ 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); }; В итоге получается следующая форма, которую можно отобразить во вшешнем модуле: .. figure:: ../../_static/img/forms/cmp/funnel_form.png :scale: 100%