3.4.3. Пользовательский компонент Воронка продаж¶
Особенность этого пользовательского компонента заключается в использовании внешних js библиотек.
Но основе данных, получаемых по специальному апи, необходимо построить воронку следующего вида:
Для компонента используется библиотека 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:
После можем открыть данные по форме с компонентом Воронка продаж, в результате воронка будет иметь вид:
Рассмотрим случай, когда данные воронки будут получены по специальному апи, и отрисовка будет производиться по изменению значений компонентов на форме.
В этом случае форма с воронкой используется во внешнем модуле, у которого на странице 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>
Помещаем компонент на форму:
В скрипте компонента на форме прописываем основную логику: получение данных для формирования воронки, функцию отрисовки воронки.
/*установливаем ширину*/
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);
};
В итоге получается следующая форма, которую можно отобразить во вшешнем модуле: