Commit cf61be32 authored by Kulya's avatar Kulya 😊

first routeng added

parent 883eebf7
...@@ -90,6 +90,21 @@ die(); ...@@ -90,6 +90,21 @@ die();
function doCommandAjax($cmd,$r){ function doCommandAjax($cmd,$r){
switch ($cmd) { switch ($cmd) {
case 'removeInroute':
return removeInroute($r);
break;
case 'saveInroute':
return saveInroute($r);
break;
case 'loadDestinationsList':
return loadDestinationsList($r);
break;
case 'loadTrunksList':
return loadTrunksList($r);
break;
case 'loadInroutesList':
return loadInroutesList($r);
break;
case 'saveAudioFile': case 'saveAudioFile':
return saveAudioFile($r); return saveAudioFile($r);
break; break;
...@@ -108,6 +123,9 @@ function doCommandAjax($cmd,$r){ ...@@ -108,6 +123,9 @@ function doCommandAjax($cmd,$r){
case 'addNewQueue': case 'addNewQueue':
return addNewQueue($r); return addNewQueue($r);
break; break;
case 'saveQueue':
return saveQueue($r);
break;
case 'getQueue': case 'getQueue':
return getQueue($r['queue']); return getQueue($r['queue']);
break; break;
...@@ -149,6 +167,239 @@ function doCommandAjax($cmd,$r){ ...@@ -149,6 +167,239 @@ function doCommandAjax($cmd,$r){
function removeInroute($r=[]){
if( empty($r["extension"]) || empty($r["cidnum"]) )
{
return ["error"=>"Мало данных"];
}
$extension = ( $r["extension"] == "Все" ) ? "" : $r["extension"];
$cidnum = ( $r["cidnum"] == "Все" ) ? "" : $r["cidnum"];
$db = \FreePBX::Database();
$sql = "DELETE FROM incoming WHERE cidnum = '".$cidnum."' AND extension = '".$extension."'";
$res = $db->query($sql);
exec("fwconsole reload");
return true;
}
function saveInroute($r=[]){
/*
extension // did
cidnum
mohclass
destination
delay_answer // 0
description
*/
// "app-blackhole,hangup,1",
// "ext-local,vms1098,1",
// timeconditions,1,1
// from-did-direct,2424,1
// ext-queues,99999,1
// ext-group,99998,1
if(
empty($r["extension"]) ||
empty($r["cidnum"]) ||
empty($r["destination"])
)
{
return ["error"=>"Мало данных"];
}
$destination = '';
if(!empty($r["destination_code"])){
if($r["destination"] == "ext-queues"){
$destination = $r["destination"].','.$r["destination_code"].',1';
}
if($r["destination"] == "from-did-direct"){
$destination = $r["destination"].','.$r["destination_code"].',1';
}
if($r["destination"] == "timeconditions"){
$destination = $r["destination"].',1,1';
}
}
elseif($r["destination"] == "timeconditions"){
$destination = $r["destination_code"].',1,1';
}
elseif($r["destination"] == "hangup"){
$destination = 'app-blackhole,hangup,1';
}
elseif($r["destination"] == "vm"){
$destination = 'ext-local,vms1098,1';
}
if(empty($destination)){
return ["error" => "Направление не верная"];
}
$did_vars = [
"extension" => ( $r["extension"] == "Все" ) ? "" : $r["extension"],
"cidnum" => ( $r["cidnum"] == "Все" ) ? "" : $r["cidnum"],
"mohclass" => "default",
"destination" => $destination,
"delay_answer" => 0,
"description" => (!empty($r["description"])) ? $r["description"] : "",
];
$res = \FreePBX::Core()->createUpdateDID($did_vars);
if(!empty($res)){
exec("fwconsole reload");
}
return ["query"=>$r, "ardid"=>$did_vars, "save_res" => $res];
}
function loadDestinationsList($r=[]){
$destTitle = [];
$destTitle["from-did-direct"] = 'Внут.номер';
$destTitle["ext-queues"] = 'Очередь';
// $destTitle["ext-group"] = 'Группа';
$destTitle["timeconditions"] = 'Правила по времени';
$destTitle["vm"] = 'Голосовая почта';
$destTitle["hangup"] = 'Завершить звонок';
return $destTitle;
}
function loadInroutesList($r=[]){
$arInroutes = [];
$db = \FreePBX::Database();
$sql = "SELECT * FROM incoming ORDER BY extension,cidnum";
$ob = $db->query($sql,\PDO::FETCH_ASSOC);
if($ob->rowCount()){
$dbInroutes = $ob->fetchAll();
}
foreach($dbInroutes as $route){
$arDest = explode(",",$route['destination']);
$destTitle = '';
if(!empty($arDest[0]) && $arDest[0]=="from-did-direct"){
$destTitle = 'Внут.номер';
}
if(!empty($arDest[0]) && $arDest[0]=="ext-queues"){
$destTitle = 'Очередь';
}
if(!empty($arDest[0]) && $arDest[0]=="ext-group"){
$destTitle = 'Группа';
}
if(!empty($arDest[0]) && $arDest[0]=="timeconditions"){
$destTitle = 'Правила по времени';
}
$arInroutes[] = [
// 'id' => $route[''],
'name' => $route['description'],
'route_cid' => (!empty($route['cidnum'])) ? $route['cidnum'] : "Все",
'route_did' => (!empty($route['extension'])) ? $route['extension'] : "Все",
'route_goto' => $destTitle." (".$arDest[1].")",
'route_goto_code' => $route['destination'],
'route_moh' => $route['mohclass']
];
}
$arHeaders = [
'name' => 'Название',
'route_cid' => 'Кто звонит',
'route_did' => 'Куда звонит',
'route_goto' => 'Назначение',
'route_moh' => 'Мелодия в ожидании',
];
$arReturn = [
'headers' => $arHeaders,
'datas' => $arInroutes,
];
return $arReturn;
}
function loadTrunksList($r=[]){
// TODO: $assoc default to true, eventually..
//outcid keepcid maxchans
// $trunks = \FreePBX::Core()->listTrunks();
$db = \FreePBX::Database();
$sql = "SELECT `trunkid` , `tech` , `outcid`, `name`, `keepcid`, `maxchans`, `channelid` , `disabled` FROM `trunks` ORDER BY `trunkid`";
$ob = $db->query($sql,\PDO::FETCH_ASSOC);
$dbTrunks = [];
if($ob->rowCount()){
$dbTrunks = $ob->fetchAll();
}
// $unique_trunks = array();
// foreach ($trunks as $trunk) {
// $trunk_id = "OUT_".$trunk['trunkid'];
// $disabled = $trunk['disabled'];
// if($disabled=="off"){ continue; }
// $tech = strtoupper($trunk['tech']);
// switch ($tech) {
// case 'IAX':
// $dialstring = 'IAX2/'.$trunk['channelid'];
// break;
// case 'CUSTOM':
// $dialstring = 'AMP:'.$trunk['channelid'];
// break;
// default:
// $dialstring = $tech.'/'.$trunk['channelid'];
// break;
// }
// $unique_trunks[] = array($trunk_id, $dialstring, $disabled);
// }
// $arTrunks = array();
foreach ($dbTrunks as $trunk) {
$arTrunks[$trunk["trunkid"]] = [
'id' => $trunk["trunkid"],
'type' => $trunk["tech"],
'name' => $trunk["name"],
'number' => (!empty($trunk["outcid"])) ? $trunk["outcid"] : "_",
'maxchannels' => (!empty($trunk["maxchans"])) ? $trunk["maxchans"] : "-",
'status' => (!empty($trunk["disabled"]) && $trunk["disabled"]=="on") ? "On" : "Off",
// 'globalvar' => $trunk[0], //OUT_4
];
}
$arHeaders = [
'id' => 'ID',
'name' => 'Название',
'type' => 'Тип',
'number' => 'Номер',
'maxchannels' => 'Максимум линий',
'status' => 'Статус',
];
$arReturn = [
'headers' => $arHeaders,
'datas' => $arTrunks,
'test' => $rawTest,
];
return $arReturn;
}
function restartWork(){ function restartWork(){
return true; return true;
} }
...@@ -385,6 +636,10 @@ function saveQueue($data,$r=true){ ...@@ -385,6 +636,10 @@ function saveQueue($data,$r=true){
if(empty($goto)) { if(empty($goto)) {
$goto = (!empty($oQueue["goto"])) ? $oQueue["goto"] : "app-blackhole,hangup,1"; $goto = (!empty($oQueue["goto"])) ? $oQueue["goto"] : "app-blackhole,hangup,1";
} }
$strategy = (!empty($data["strategy"])) ? $data["strategy"] : false;
if(empty($strategy) && !empty($oQueue["strategy"])) { $strategy = $oQueue["strategy"]; } else {$strategy = 'ringall';}
$agentannounce_id = (!empty($data["agentannounce_id"])) ? $data["agentannounce_id"] : (!empty($oQueue["agentannounce_id"])) ? $oQueue["agentannounce_id"] : NULL; $agentannounce_id = (!empty($data["agentannounce_id"])) ? $data["agentannounce_id"] : (!empty($oQueue["agentannounce_id"])) ? $oQueue["agentannounce_id"] : NULL;
$joinannounce_id = (!empty($data["joinannounce_id"])) ? $data["joinannounce_id"] : (!empty($oQueue["joinannounce_id"])) ? $oQueue["joinannounce_id"] : NULL; $joinannounce_id = (!empty($data["joinannounce_id"])) ? $data["joinannounce_id"] : (!empty($oQueue["joinannounce_id"])) ? $oQueue["joinannounce_id"] : NULL;
$maxwait = (!empty($data["maxwait"])) ? $data["maxwait"] : (!empty($oQueue["maxwait"])) ? $oQueue["maxwait"] : ""; $maxwait = (!empty($data["maxwait"])) ? $data["maxwait"] : (!empty($oQueue["maxwait"])) ? $oQueue["maxwait"] : "";
...@@ -399,7 +654,7 @@ function saveQueue($data,$r=true){ ...@@ -399,7 +654,7 @@ function saveQueue($data,$r=true){
$fields[] = [$account,'maxlen',(!empty($oQueue["maxlen"])) ? $oQueue["maxlen"] : '0',0]; $fields[] = [$account,'maxlen',(!empty($oQueue["maxlen"])) ? $oQueue["maxlen"] : '0',0];
$fields[] = [$account,'joinempty',(!empty($oQueue["joinempty"])) ? $oQueue["joinempty"] : 'yes',0]; $fields[] = [$account,'joinempty',(!empty($oQueue["joinempty"])) ? $oQueue["joinempty"] : 'yes',0];
$fields[] = [$account,'leavewhenempty',(!empty($oQueue["leavewhenempty"])) ? $oQueue["leavewhenempty"] : 'no',0]; $fields[] = [$account,'leavewhenempty',(!empty($oQueue["leavewhenempty"])) ? $oQueue["leavewhenempty"] : 'no',0];
$fields[] = [$account,'strategy',(!empty($oQueue["strategy"])) ? $oQueue["strategy"] : 'ringall',0]; $fields[] = [$account,'strategy',$strategy,0];
$fields[] = [$account,'timeout',(!empty($oQueue["timeout"])) ? $oQueue["timeout"] : '15',0]; $fields[] = [$account,'timeout',(!empty($oQueue["timeout"])) ? $oQueue["timeout"] : '15',0];
$fields[] = [$account,'retry',(!empty($oQueue["retry"])) ? $oQueue["retry"] : '5',0]; $fields[] = [$account,'retry',(!empty($oQueue["retry"])) ? $oQueue["retry"] : '5',0];
$fields[] = [$account,'wrapuptime',(!empty($oQueue["wrapuptime"])) ? $oQueue["wrapuptime"] : '0',0]; $fields[] = [$account,'wrapuptime',(!empty($oQueue["wrapuptime"])) ? $oQueue["wrapuptime"] : '0',0];
......
<?php namespace AloVoice; ?>
<style>
.alv_table_lines .nowrp {
white-space: nowrap;
}
.loadingline{
display:none;
}
</style>
<center>
<h3 class="h3 card-body">Входящие звонки</h3>
<div class="loadingline"></div>
<a href="#" onClick="addNewinRoute()" id="inroute_add_button" class="btn btn-primary title_line_button"><i class="fa fa-plus"></i> Добавить </a>
</center>
<br/>
<table class="table" id="stats_block_table">
<thead>
<tr id="inroutes_table_header"></tr>
</thead>
<tbody id="inroutes_table_body"> </tbody>
</table>
<script>
var delOneDid = function(cid,did,me){
if(typeof me != 'undefined'){
$(me).html('<i class="fa fa-spinner fa-spin"></i> Удаление...');
}
doAloVoiceCmd('removeInroute', {"cidnum":cid,"extension":did}, function(res) {
console.log("--== DEL inROUTE RES:",res);
$("#inroutes-tab").click();
});
};
var loadAlVOperators = function(destination_code){
$("#destination_code_container").html('<span>Загрузка...</span>');
loadAloVoiceInfo("alovoice_get_operators_nums",function(operators){
$("#destination_code_container").html('');
$("#destination_code_container").append('<select id="inrt_destination_code" class="form-control inrouteinp"></select>');
$.each( operators, function( num, operator ) {
var selexttxt = (typeof destination_code != 'undefined' && destination_code==num) ? ' selected' : '';
$("#inrt_destination_code").append( '<option value="'+num+'"'+selexttxt+'>'+num+' - '+operator.NAME+' '+operator.LAST_NAME+'</option>' );
});
});
}
var loadAlVQueues = function(destination_code){
$("#destination_code_container").html('<span>Загрузка...</span>');
loadAloVoiceInfo("alovoice_get_allqueues",function(queues){
console.log("--== Loaded All QUEUEs:",queues);
$("#destination_code_container").html('');
$("#destination_code_container").append('<select id="inrt_destination_code" class="form-control inrouteinp"></select>');
$.each( queues, function( queue, strategy ) {
var selexttxt = (typeof destination_code != 'undefined' && destination_code==queue) ? ' selected' : '';
$("#inrt_destination_code").append( '<option value="'+queue+'"'+selexttxt+'>'+queue+' - '+strategy+'</option>' );
});
});
}
var route_destination_change = function(me){
var route_dest = $(me).val();
console.log("--== Changed dest: ", route_dest);
if(route_dest=="from-did-direct"){
loadAlVOperators();
}
if(route_dest=="ext-queues"){
loadAlVQueues();
}
if(route_dest=="timeconditions"){
$("#destination_code_container").html("");
}
if(route_dest=="hangup"){
$("#destination_code_container").html("");
}
}
var addNewinRoute = function(vars){
console.log("Begin adding inRoute ........");
var nowTime = Math.round(new Date().getTime()/1000);
var description = (typeof vars != 'undefined' && typeof vars.description != 'undefined' && vars.description.length > 2) ? vars.description : 'Все '+nowTime;
var extension = (typeof vars != 'undefined' && typeof vars.extension != 'undefined' && vars.extension.length) ? vars.extension : 'Все';
var cidnum = (typeof vars != 'undefined' && typeof vars.cidnum != 'undefined' && vars.cidnum.length) ? vars.cidnum : 'Все';
var mohclass = (typeof vars != 'undefined' && typeof vars.mohclass != 'undefined' && vars.mohclass.length) ? vars.mohclass : 'default';
var destination = (typeof vars != 'undefined' && typeof vars.destination != 'undefined' && vars.destination.length) ? vars.destination : 'default';
var destination_code = (typeof vars != 'undefined' && typeof vars.destination_code != 'undefined') ? vars.destination_code : '';
doAloVoiceCmd('loadDestinationsList', {}, function(dests) {
console.log("--===Loaded Dests:",dests);
var allDestsTxt = '<option value="">Выберите направление...</option>';
$.each( dests, function( key, value ) {
var seltxt = (destination==value) ? ' selected' : '';
allDestsTxt += '<option value="'+key+'"'+seltxt+'>'+value+'</option>';
});
aloModal({
label: "Добавить входящий маршрут",
body: '<form>'
+'<div class="form-group">'
+'<input type="text" class="form-control inrouteinp" id="inrt_description" placeholder="Введите названия" value="'+description+'">'
+'</div>'
+'<div class="form-row">'
+'<div class="col form-group">'
+'<label>Звонок на: (DID)</label>'
+'<input type="text" class="form-control inrouteinp" id="inrt_extension" value="'+extension+'">'
+'</div>'
+'<div class="col form-group">'
+'<label>Кто звонит (CallerID)</label>'
+'<input type="text" class="form-control inrouteinp" id="inrt_cidnum" value="'+cidnum+'">'
+'</div>'
+'</div>'
+'<div class="form-group">'
+'<label>Мелодия в ожидании</label>'
+'<input type="text" class="form-control inrouteinp" id="inrt_mohclass" value="'+mohclass+'" disabled>'
+'</div>'
+'<div class="form-group">'
+'<label>Направление</label>'
+'<select class="form-control inrouteinp" id="inrt_destination" onChange="route_destination_change(this)">'+allDestsTxt+'</select>'
+'</div>'
+'<div class="form-group" id="destination_code_container"></div>'
// +'<div class="form-group">'
// +'<label for="alv_sound_file" class="btn btn-primary afilelabel">Выберите файл записи - *.mp3</label>'
// +'<input type="file" class="sound-file-input myfileinput" id="alv_sound_file" name="alv_sound_file" required accept=".mp3" onChange="doUpload(this)">'
// +'</div>'
+'</form>',
btn: "Сохранить",
nohide: true,
callback: function(){
var saveElements = {};
saveElements["cmd"] = "saveInroute";
$(".inrouteinp").each(function(){
var inRouteInpId = $(this).attr('id');
var inRouteInpCode = inRouteInpId.substr(5);
var inRouteInpVal = $(this).val();
saveElements[inRouteInpCode] = inRouteInpVal;
});
console.log("TEST saveElements: ", saveElements);
$("#alvModalFooter").html('<i class="fa fa-spinner fa-spin"></i> Сохранение...');
// $("#modalCloseBtn").attr("disabled",true);
// $("#alvModalSendBtn").attr("disabled",true);
loadAloVoiceInfo(saveElements,function(res){
console.log("Save RES: ",res);
$('#alvModal').modal('hide');
$("#inroutes-tab").click();
});
}
});
});
};
var afterLoadPage = function(){
var isHeadered = false;
var inroutesUpdate = function(){
doAloVoiceCmd('loadInroutesList', {}, function(res) {
console.log("AloVoice Trunks RES:",res);
if(!isHeadered){
if(typeof res.headers != 'undefined' ){
isHeadered = true;
$("#inroutes_table_header").html('');
$.each( res.headers, function( key, value ) {
console.log("Each Header:",key, value);
$("#inroutes_table_header").append('<th id="hd_'+key+'">'+value+'</th>');
});
}
}
if(typeof res.datas != 'undefined' ){
$("#inroutes_table_body").html('');
$.each( res.datas, function( irkey, inroute ) {
console.log("Each Trunk:",inroute);
/*
'name' => 'Название',
'route_cid' => 'Кто звонит',
'route_did' => 'Куда звонит',
'route_goto' => 'Назначение',
'route_moh' => 'Мелодия в ожидании',
*/
var lineHTML = '<tr class="alv_table_lines" id="inroute_'+irkey+'_" data-cid="'+inroute.route_cid+'" data-did="'+inroute.route_cid+'">'
+'<td class="nowrp" > <span>'+inroute.name+'</span></td>'
+'<td class="nowrp" > <b>'+inroute.route_cid+'</b></td>'
+'<td class="nowrp" >'+inroute.route_did +'</td>'
+'<td class="nowrp" >'+inroute.route_goto +'</td>'
+'<td class="nowrp" >'+inroute.route_moh +'</td>'
+'<td class="nowrp" ><a href="#" onClick="delOneDid(\''+inroute.route_cid+'\',\''+inroute.route_did+'\',this);"><i class="fa fa-trash"></i> Удалить</a></td>'
+'</tr>';
$("#inroutes_table_body").append(lineHTML);
});
}
//setTimeout(donglesUpdate,100000);
});
}
inroutesUpdate();
};
</script>
\ No newline at end of file
...@@ -4,6 +4,70 @@ ...@@ -4,6 +4,70 @@
$().ready(() => { $().ready(() => {
window.getAllStrateges = function () {
return [
{
title: "Звонят все",
value: "ringall",
select: true
},
{
title: "Линейный",
value: "linear",
},
{
title: "Самому не занятому",
value: "leastrecent",
},
{
title: "Случайному",
value: "random",
},
// {
// title: lng.strategy.rrmemory,
// value: "rrmemory",
// },
// {
// title: lng.strategy.rrordered,
// value: "rrordered",
// },
// {
// title: lng.strategy.wrandom,
// value: "wrandom",
// }
];
}
window.getAllGotos = function () {
var result = [
// {
// title: "Не выбрано",
// value: "",
// },
{
title: "Завершить звонок",
value: "app-blackhole,hangup,1",
select: true
},
{
title: "Голосовая почта",
value: "ext-local,vms1098,1",
},
];
// res = res.map(function(d) {
// return {
// title: "Очередь: " + d[0],
// value: "ext-queues," + d[0] + ",1",
// };
// });
// result = [...result, ...res];
return result;
}
feather.replace() feather.replace()
setWindowFunction('removeAgent', removeAgent) setWindowFunction('removeAgent', removeAgent)
...@@ -11,38 +75,75 @@ $().ready(() => { ...@@ -11,38 +75,75 @@ $().ready(() => {
setWindowFunction('addAgent', addAgent) setWindowFunction('addAgent', addAgent)
$('#queues_add').on('click', function () { $('#queues_add').on('click', function () {
var currGoto = '';
var gotosOpts = '';
window.getAllGotos().forEach(function(elm){
var seltxt = (elm.select) ? " seleted" : "";
gotosOpts += '<option value="'+elm.value+'"'+seltxt+'>'+elm.title+'</option>';
});
var strategyOpts = '';
window.getAllStrateges().forEach(function(elm){
var seltxt = (elm.select) ? " seleted" : "";
strategyOpts += '<option value="'+elm.value+'"'+seltxt+'>'+elm.title+'</option>';
});
swal.fire({ swal.fire({
title: 'Введите номер очереди', title: 'Введите номер очереди',
input: 'text', showCancelButton: true,
inputAttributes: { cancelButtonText: 'Отмена',
autocapitalize: 'off', preConfirm: () => {
placeholder: 'Номер очереди', var queuenum = $('#add_queue_inp').val();
id: 'add_queue_inp', var final_destination = $('#final_destination').val();
}, var queue_strategy = $('#queue_strategy').val();
preConfirm: (val) => { var queuenum = queuenum.replace(/\D+/g, '');
if (!val) {
Swal.showValidationMessage( console.log("Queue Params:",queuenum, final_destination, queue_strategy );
`Введите номер очереди`
)
return false; if (queuenum && (queuenum < 6000 || queuenum > 6999)) {
}
if (val.replace(/\d+/g, '')) {
Swal.showValidationMessage( Swal.showValidationMessage(
`Некорректный номер очереди` `Некорректный номер очереди! <br>требуется от 6000 до 6999`
) )
return false; return false;
} }
return true;
}, },
showCancelButton: true, html: ''
cancelButtonText: 'Отмена',
+'<input id="add_queue_inp" class="swal2-input row mx-0" type="text">'
+'<div class="row"></div>'
+'<h2 class="swal2-title">Направление при не ответе: </h2> '
+'<select id="final_destination" class="swal2-select row mx-0">'
+gotosOpts
+'</select>'
+'<h2 class="swal2-title">Правила приёма звонок: </h2> '
+'<select id="queue_strategy" class="swal2-select row mx-0">'
+strategyOpts
+'</select>'
,
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
var val = $('#add_queue_inp').val(); uiLoading();
var queuenum = $('#add_queue_inp').val();
var final_destination = $('#final_destination').val();
var queue_strategy = $('#queue_strategy').val();
console.log("Queue SAVEing Params:",queuenum, final_destination, queue_strategy );
doAloVoiceCmd('saveQueue', {
account: queuenum,
goto: final_destination,
strategy: queue_strategy
}, function() {
uiLoadingEnd();
// alert(queuenum + ' успешно добавлен! ' + queue);
});
if (val) {
addNewQueue(val);
}
} }
}); });
}) })
...@@ -142,8 +243,11 @@ $().ready(() => { ...@@ -142,8 +243,11 @@ $().ready(() => {
window.uiLoadingEnd = function () { window.uiLoadingEnd = function () {
$('.app-loading').remove(); $('.app-loading').remove();
$("#queues-tab").click();
} }
window.addNewQueue = function (queue) { window.addNewQueue = function (queue) {
uiLoading(); uiLoading();
doAloVoiceCmd('addNewQueue', { doAloVoiceCmd('addNewQueue', {
...@@ -154,15 +258,24 @@ $().ready(() => { ...@@ -154,15 +258,24 @@ $().ready(() => {
}); });
} }
window.removeQueue = function (queue) { window.removeQueue = function (queue) {
swal.fire({
title: 'Удалить очередь '+ queue,
html: "Вы точно хотите удалить очередь: "+queue,
// backdrop: 'rgb(0 0 0 / 0%)'
showCancelButton: true,
cancelButtonText: 'Отмена',
confirmButtonText: 'удалить',
}).then(function (result) {
console.log("Test Remove Queue confirming: ", result.isConfirmed);
if (result.isConfirmed) {
uiLoading(); uiLoading();
doAloVoiceCmd('removeQueue', { doAloVoiceCmd('removeQueue', {queue:queue}, function() {
queue: queue,
}, function() {
uiLoadingEnd(); uiLoadingEnd();
$('[queue-nav]:first').trigger('click');
alert('Очередь ' + queue + ' удалена');
}); });
} }
});
}
function createMembersList (list) { function createMembersList (list) {
var div = $('<form class="" style="max-height: 300px;max-height: calc(60vh - 100px);" />'); var div = $('<form class="" style="max-height: 300px;max-height: calc(60vh - 100px);" />');
......
/**
* @var feather
*/
$().ready(() => {
window.getAllGotos = function () {
var result = [
// {
// title: "Не выбрано",
// value: "",
// },
{
title: "Завершить звонок",
value: "app-blackhole,hangup,1",
select: true
},
{
title: "Голосовая почта",
value: "ext-local,vms1098,1",
},
];
// res = res.map(function(d) {
// return {
// title: "Очередь: " + d[0],
// value: "ext-queues," + d[0] + ",1",
// };
// });
// result = [...result, ...res];
return result;
}
feather.replace()
setWindowFunction('removeAgent', removeAgent)
setWindowFunction('toggltAgentDnd', toggltAgentDnd)
setWindowFunction('addAgent', addAgent)
$('#queues_add').on('click', function () {
var currGoto = '';
var gotosOpts = '';
window.getAllGotos().forEach(function(elm){
var seltxt = (elm.select) ? " seleted" : "";
gotosOpts += '<option value="'+elm.value+'"'+seltxt+'>'+elm.title+'</option>';
});
swal.fire({
title: 'Введите номер очереди',
// input: 'text',
// inputAttributes: {
// autocapitalize: 'off',
// placeholder: 'Номер очереди',
// id: 'add_queue_inp',
// },
// preConfirm: (val) => {
// if (!val) {
// Swal.showValidationMessage(
// `Введите номер очереди`
// )
// return false;
// }
// if (val.replace(/\d+/g, '')) {
// Swal.showValidationMessage(
// `Некорректный номер очереди`
// )
// return false;
// }
// return true;
// },
showCancelButton: true,
cancelButtonText: 'Отмена',
preConfirm: () => {
var queuenum = $('#add_queue_inp').val();
var queue_final_destination = $('#queue_final_destination').val();
var queuenum = queuenum.replace(/\D+/g, '');
console.log("Queue Params:",queuenum, queuenum.length, queue_final_destination );
if (queuenum && (queuenum < 6000 || queuenum > 6999)) {
Swal.showValidationMessage(
`Некорректный номер очереди! <br>требуется от 6000 до 6999`
)
return false;
}
},
html: ''
+'<input id="add_queue_inp" class="swal2-input row mx-0" type="text">'
+'<div class="row"></div>'
+'<h2 class="swal2-title">Направление при не ответе: </h2> '
+'<select id="queue_final_destination" class="swal2-select row mx-0">'
+gotosOpts
+'</select>'
,
}).then((result) => {
if (result.isConfirmed) {
if (val) {
addNewQueue(val);
}
}
});
})
/**
* if there is no function under key {key} add it to window
* @param {String} key
* @param {Function} func
* @returns {void}
*/
function setWindowFunction(key, func) {
if (typeof window[key] !== 'function') {
window[key] = func
}
}
/**
* remove agent from queue
* @param {String} agentId
* @returns {void}
*/
function removeAgent (agentId, queue) {
uiLoading();
const agent = window.Queues.agents.get(agentId);
if (!agent) {
console.warn(agentId + ' is not defined');
return;
}
doAloVoiceCmd('delMemeberQueue', {
queue: queue,
member: agent.number
}, function() {
uiLoadingEnd();
alert(agent.number + ' удален из очереди ' + queue);
});
}
window.addAgentToQueue = function (queue) {
var list = getCurrentUsersAr(queue);
var el = createMembersList(list);
swal.fire({
title: 'Добавить в '+ queue,
html: el,
// backdrop: 'rgb(0 0 0 / 0%)'
showCancelButton: true,
cancelButtonText: 'Отмена',
confirmButtonText: 'Добавить',
didOpen: function () {
$('[name="add_member"]').on('change', function () {
var target = '[for="' + this.id+ '"]';
if ($(this).is(':checked')) {
$(target).addClass('btn-success').removeClass('btn-light');
} else {
$(target).removeClass('btn-success').addClass('btn-light');
}
})
}
}).then(function (result) {
if (result.isConfirmed) {
// $('[name="add_member"]:checked').each(function () {
// var value = $(this).val();
// if (!value) {
// return;
// }
// addAgent(value, queue);
// });
uiLoading();
addMember($('[name="add_member"]:checked'), 0);
}
});
function addMember (elements, index) {
if (elements.length-1 < index) {
uiLoadingEnd();
return;
}
var el = elements[index];
if (!el) {
return;
}
// return
addAgent(el.value, queue, function () {
addMember(elements, index+1);
});
}
}
window.uiLoading = function () {
$('body').append(`<div class="app-loading d-flex align-items-center justify-content-center">${feather.icons['loader'].toSvg({class: 'app-loading__icon'})}</div>`);
}
window.uiLoadingEnd = function () {
$('.app-loading').remove();
}
window.addNewQueue = function (queue) {
uiLoading();
doAloVoiceCmd('addNewQueue', {
number: queue,
}, function() {
uiLoadingEnd();
alert('Очередь ' + queue + ' добавлена');
});
}
window.removeQueue = function (queue) {
swal.fire({
title: 'Удалить очередь '+ queue,
html: "Вы точно хотите удалить очередь: "+queue,
// backdrop: 'rgb(0 0 0 / 0%)'
showCancelButton: true,
cancelButtonText: 'Отмена',
confirmButtonText: 'удалить',
}).then(function (result) {
console.log("Test Remove Queue confirming: ", result.isConfirmed);
if (result.isConfirmed) {
uiLoading();
addMember($('[name="add_member"]:checked'), 0);
}
});
}
function createMembersList (list) {
var div = $('<form class="" style="max-height: 300px;max-height: calc(60vh - 100px);" />');
// div.append('');
$.each(list, function (none, data) {
div.append(`<div class="mb-2">
<label class="d-block btn btn-light py-2 mb-0" for="member_${data.number}" style="cursor: pointer;">
<span class="mr-4">${data.number} </span>
<span>${data.fullname}</span>
</label>
<input name="add_member"
type="checkbox"
id="member_${data.number}"
value="${data.number}"
style="display: none;">
</div>`);
});
return div.get(0);
}
function getCurrentUsersAr (queue) {
var result = [];
var queueMembers, allMembers, queueData;
if (!window.Queues && !window.Queues.data) {
return result;
}
queueData = window.Queues.data.queues[queue];
allMembers = window.Queues.data.agents || {};
if (!queueData) {
return result;
}
queueMembers = queueData.QueueMember || {};
$.each(allMembers, function (number, data) {
if (number in queueMembers) {
return;
}
result.push(data);
});
return result;
}
function addAgent (number, queue, success) {
doAloVoiceCmd('addMemeberQueue', {
queue: queue,
member: number
}, function() {
alert(number + ' добавлен в очередь ' + queue);
if (typeof success === 'function') {
success();
}
});
}
/**
* toggle agent dnd status
* @param {String} agentId
* @returns {void}
*/
function toggltAgentDnd (number) {
if (!number) {
return;
}
uiLoading();
loadAloVoiceInfo({
restmethod:'alovoice_dnd_toggle',
number: number,
// status:'off'
}, function (r) {
console.warn("RES:", r);
uiLoadingEnd();
if (r.status === 'on') {
alert(number + ' DND включен');
} else {
alert(number + ' DND выключен');
}
});
}
})
function getQuesue() {
/**
* @class Quesue
* @param {{
* data: {
* agents: Array
* },
* locale: Object,
* params: Object,
* target: Object
* }} data
*/
function Quesue(data) {
const self = this
this.data = this._toCurrentAgentData(data.data)
// this.target = data.target
this.locale = data.locale
this.params = data.params
this.__setAgents(data.data.agents)
this.$target = {}
$.each(data.target, function(key, value) {
self.$target[key] = $(value)
})
this.footerActivePill = 0
this._conf = {
calls: {
keys: {
ivr: ['ivr'],
in: ['Incom'],
out: ["Out", "Outlines"],
}
}
}
}
Quesue.prototype = {
/**
*
*/
init() {
const data = this.data
this._channels = this._getCurrentQueuesCalls(data.channels)
this.$target.agents.append(
this.renderQueuesBar(Object.keys(data.queues))
)
this.$target.queues.html(
this.renderChannelsBar(this._channels)
)
this.$target.agents.append(
this.agentsController(data.queues)
)
return true
},
getAgentQueue(number) {
// this.data
var result = '';
if (!this.data.queues) {
return result;
}
$.each(this.data.queues, function (key, data) {
if (data.QueueMember && number in data.QueueMember) {
result = key;
}
});
return result;
},
/**
* update ques data
* @param {Object} newData
* @returns {Boolean}
*/
update(newData) {
newData = this._toCurrentAgentData(newData)
const self = this
const prevData = this.data;
this._channels = this._getCurrentQueuesCalls(newData.channels)
this.channels = newData.channels
this.__setAgents(newData.agents)
this.data = newData
$.each(prevData.queues, (index, value) => {
// get current data
if (newData.queues[index]) {
const data = self.__getUpdateResult(
value.QueueMember, newData.queues[index].QueueMember
)
self._update(data, index)
} else {
$(`[queue-nav="${index}"`).remove();
$(`[data-queue-number="${index}"`).remove();
}
})
this.$target.queues.html(
this.renderChannelsBar(this._channels)
)
return true
},
_toCurrentAgentData(data) {
var agents = {};
Object.entries(data.agents).map(function(arr) {
var key = arr[0], value = arr[1];
if (value.connect && value.status === 'off') {
value.status = 'free'
}
agents[key] = value
})
data.agents = agents
return data
},
/**
* uppdate queue
* @private
* @param {Object} data queue data
* @param {Number|String} queue queue number
* @returns
*/
_update(data, queue) {
const self = this
const nav = $(`[queue-nav='${queue}']`).get(0)
if (Array.isArray(data.new) && data.new.length) {
this._updateAddNew(data.new, queue)
}
if (Array.isArray(data.remove) && data.remove.length) {
this._updateRemove(data.remove, queue)
}
if (Array.isArray(data.data) && data.data.length) {
this._updateData(data.data, queue)
}
if (!nav) {
const $target = $(`#queues__container`)
const navs = $(`[queue-nav]`).length
$target.append(
self.quesusItemView({
index: navs,
value: queue,
isActive: false
})
)
$(`#queues_tab_content`).append(
self.agentsContainer({
data: data,
index: navs,
isActive: false,
queue: queue
})
)
}
return true
},
/**
* Adds a new agent to the queue
* @private _updateAddNew
* @param {Array} data - Array of users
* @param {String} queue - queue number
* @returns {void}
*/
_updateAddNew(data, queue) {
const self = this;
const $target = $(`[data-queue-number="${queue}"] .row:first .add_agent_div`)
if ($target.length) {
$target.before(
data.map(d => {
const agent = self.agents.get(d.number)
return self.agentsView({
data: agent,
params: d
})
})
)
}
},
/**
* remove agent from the queue
* @private _updateRemove
* @param {Array} data - Array of users
* @param {String} queue - queue number
* @returns {void}
*/
_updateRemove(data, queue) {
const $target = $(`[data-queue-number="${queue}"]`)
if ($target.length) {
data.map(d => $target.find(`[data-queue-agent=${d.number}]`).remove())
}
},
/**
* updates the queue data
* @private _updateData
* @param {Array} data - Array of users
* @param {String} queue - queue number
* @returns {void}
*/
_updateData(data, queue) {
const self = this
const $target = $(`[data-queue-number="${queue}"]`)
if ($target.length) {
data.map(d => {
// const agent = self.agents.get(d.name)
const agent = self.agents.get(d.number)
if (!agent) {
return
}
const call = this._getAgentCall(agent.number, agent.status) || {}
const $el = $target.find(`[data-queue-agent=${agent.number}]`)
if(typeof self.channels.Incom != 'undefined' && typeof self.channels.Incom[agent.number] != 'undefined'){
inCall = self.channels.Incom[agent.number];
}
if(typeof self.channels.Out != 'undefined' && typeof self.channels.Out[agent.number] != 'undefined'){
outCall = self.channels.Out[agent.number];
}
$el.children().css('background-color', self._getAgentStatusColor(agent.status));
$el.find('[data-agent="name"]').html(agent.name)
$el.find('[data-agent="status"]').html(self._getAgentStatusValue(agent, call))
$el.find('[data-agent="buttons"]').html(self._getAgentButtons(agent, d))
return true
})
}
},
/**
* returns an object with elements to remove, update, add
* @param {Array} oldData
* @param {Array} newData
* @returns {Object}
*/
__getUpdateResult(oldData, newData) {
let result = {
new: [], // add elements
remove: [], // remove elements
data: [] // update elements
}
if (!(typeof oldData === "object" && typeof newData === 'object')) {
return result
}
return ({
data: getUpdates(newData, oldData),
new: getNews(newData, oldData),
remove: getRemoves(newData, oldData)
});
function getUpdates (newData, curretData) {
var result = [];
$.each(newData, function (key, data) {
if (curretData[key]) {
result.push(data);
}
});
return result;
}
function getNews (newData, curretData) {
var result = [];
$.each(newData, function (key, data) {
if (!curretData[key]) {
result.push(data);
}
});
return result;
}
function getRemoves (newData, curretData) {
var result = [];
$.each(curretData, function (key, data) {
if (!newData[key]) {
result.push(data);
}
});
return result;
}
},
/**
* render queues bar to target
* @param {JQElement} target
* @param {Array} data - array with queues and agents
* @returns
*/
renderQueuesBar(data) {
if(!Array.isArray(data)) {
console.error("Typeof data isn't Array")
return ''
}
const self = this
const view = $(`<nav class="row">
<div class="col-2">${this.locale.queues}</div>
<div class="col-10">
<ul class="nav nav-pills mr-auto" id="queues__container"></ul>
</div>
</nav>`)
const cont = view.find(".nav-pills")
cont.append(
data.map((value, index) => {
return self.quesusItemView({
index: index,
value: value,
isActive: isActive(index)
})
})
)
return view
function isActive (i) {
return i === self.footerActivePill
}
},
/**
* render call queue bar
* @param {Object} data
*/
renderChannelsBar(data) {
const self = this
const view = $(`<div class="bg-light p-2">
<div class="text-center">
<h5>${this.locale.channelsTitle}</h5>
</div>
</div>`);
const cont = $(`<div></div>`);
if (typeof data === "object") {
$.each(data, (key, d) => {
cont.append(
self.callQueueSection(d.title, d.data)
)
})
}
view.append(cont)
return view
},
/**
* render channel observer NO_USED
* @param {JQElement} target
* @param {Object} data
*/
renderObservers(target, data) {
const view = $(`<div class="p-1 bg-light">
<div class="text-center font-weight-bold">
${data.TEXT}
</div>
</div>`);
const cont = $(`<div></div>`);
// cont.append(
// this.observersController(data.DATAS)
// )
target.append(
view.append(
cont.append(
this.observersController(data.DATAS)
)
)
)
},
/**
* render queue agents container with agens
* @param {JQElement} target
* @param {Object} data
*/
agentsController(data) {
const self = this
const keys = Object.keys(data)
// craete tab container
const tabVont = $(`<div class="tab-content" id="queues_tab_content"></div>`)
tabVont.append(
keys.map((key, index) => self.agentsContainer({
data: data[key].QueueMember,
index: index,
isActive: isActive(index),
queue: key
}))
)
return tabVont
function isActive (i) {
return i === self.footerActivePill
}
},
/**
* @param {Object} param0
* @returns {String|HTMLElement}
*/
agentsContainer({data, index, isActive, queue}) {
const self = this
const view = $(`<div class="tab-pane ${isActive ? "active" : ""}" role="tabpanel" id="${index}" data-queue-number="${queue}"></div>`)
const cont = $(`<div class="row"></div>`)
if (typeof data !== "object" || !Object.keys(data).length) {
return view.append(cont.html(
self.addAgentView(queue)
))
}
const elems = []
$.each(data, (index, params) => {
const agent = self.agents.get(params.number)
if (!agent) {
return ''
}
elems.push(
self.agentsView({
data: agent,
params: params,
index: index
})
)
})
view.append(
cont.append(
elems, self.addAgentView(queue)
),
)
return view;
},
/**
* template for agent
* @param {Object} param0
* @returns {String|HTMLElement}
*/
agentsView({data, params, index}) {
const self = this
const call = this._getAgentCall(data.number, data.status) || {}
const view = `<div class="col-4 p-2" style="position: relative;" data-queue-agent="${data.number}" title="${data.connect} ${data.useragent} ${data.secret}">
<div class="row align-items-center m-0 px-2 py-1 rounded h-100" style="background: ${this._getAgentStatusColor(data.status)}">
${discription(data.name)}
</div>
<div data-agent="buttons">
${this._getAgentButtons(data, params).join('')}
</div>
</div>`
return view;
function discription(name) {
const view = `<div class="col-12 p-0">
<p class="m-0" data-agent="name">${name}</p>
<p class="m-0" data-agent="status">${self._getAgentStatusValue(data, call)}</p>
</div>`;
return view;
}
function callData(call) {
if (!call) {
return ''
}
const view = `<div class="col-12 p-0">
<p class="m-0" data-agent="phone">${call.phone1}</p>
</div>`;
return view;
}
},
addAgentView(queue) {
const view = `<div class="col-4 p-2 add_agent_div" style="position: relative;" >
<button type="button"
class="d-flex align-items-center justify-content-center btn btn-light w-100"
style="height: 56px"
onclick="window.addAgentToQueue('${queue}')"
data-queue="${queue}">
${feather.icons.plus.toSvg()} Добавить агента</button>
</div>`
return view;
},
/**
* @private _getAgentStatusValue
* @param {Object} agent
* @param {Object} call
* @returns {String}
*/
_getAgentStatusValue(agent, call) {
let value = [
this._getAgentStatusText(agent.status),
`<br> <span>${call.phone1 || ""} ${call.duration || ""} </span>`
]
return value.join('')
},
/**
* @private
* @param {} param0
* @returns {HTMLElement}
*/
_getAgentButtons(agent, params) {
const className = "queues_agent_icon rounded-circle d-flex align-icemt-center"
let result = [
`<button type="button" class="${className} bg-white text-danger mr-4"
title="Удалить из очереди"
onclick="window.removeAgent('${agent.id}', '${params.queue}')"
>${feather.icons['trash'].toSvg({class: "w-100 h-100"})}</button>`,
]
if (agent.dnd === 'Y') {
result.push(`<button type="button" class="${className} bg-white"
onclick="window.toggltAgentDnd('${agent.number}')"
title="Выключить DND">${feather.icons['phone-missed'].toSvg({class: "w-100 h-100"})}</button>`)
} else {
result.push(`<button type="button" class="${className} bg-white"
onclick="window.toggltAgentDnd('${agent.number}')"
title="Включить DND">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
}
// switch (agent.status) {
// case 'off':
// result.push(`<button type="button" class="${className} bg-white" onclick
// title="off">${feather.icons['phone-missed'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// case 'free':
// result.push(`<button type="button" class="${className} bg-white" onclick
// title="2">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// case 'dnd':
// result.push(`<button type="button" class="${className} bg-white"
// onclick="window.toggltAgentDnd('${agent.number}')"
// title="3">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// case 'incring':
// result.push(`<button type="button" class="${className} bg-white" onclick
// title="4">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// case 'inccall':
// result.push(`<button type="button" class="${className} bg-white" onclick
// title="5">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// case 'outring':
// result.push(`<button type="button" class="${className} bg-white" onclick
// title="6">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// case 'outcall':
// result.push(`<button type="button" class="${className} bg-white" onclick
// title="7">${feather.icons['phone-incoming'].toSvg({class: "w-100 h-100"})}</button>`)
// break
// }
return result
},
/**
* retorns status color
* @param {Number} status
* @returns {Object}
*/
_getAgentStatusColor(status) {
const stcolor = this.params.agents.statuscolor
return stcolor[status] || '#CCCCCC'
},
_getAgentCall(agentId, status) {
const self = this
let result
getCall.bind(this)
switch (status) {
case "incring":
case "inccall":
result = getCall(agentId, "in")
break
case "outring":
case "outcall":
result = getCall(agentId, "out")
break
}
if (result) {
result = this._getCurrentCallData(result)
}
return result
function getCall(agentId, key) {
const calls = self._channels[key].data
let result
$.each(calls, (none, call) => {
if (call._agentNumber !== agentId) {
return
}
result = call
})
return result
}
},
_getAgentStatusText(status) {
const stcode = this.params.agents.statuscode
return stcode[status] || '-----'
},
/**
* template for queues bar item
* @param {Object} param0
* @returns {String|HTMLElement}
*/
quesusItemView({
index,
isActive,
value
}) {
const self = this
const view = $(`<li class="nav-item">
<a class="nav-link ${isActive ? "active" : ""}" href="#${index}" data-toggle="pill" aria-expanded="${isActive}" queue-nav="${value}">
${value}
<button type="button" class="ml-1 align-middle text-danger" onclick="window.removeQueue('${value}')">
${feather.icons['trash'].toSvg({
width: '18px',
height: '18px'
})}
</button>
</a>
</li>`)
view.on("click", function () {
const $el = $(this);
const parent = $el.parent();
self.footerActivePill = index;
})
return view;
},
/**
*
* @param {Object} data
* @returns {String|HTMLElement}
*/
callQueueSection(title, data) {
const self = this
const view = $(`<div class="mb-3">
<div class="text-center font-weight-bold">${title}</div>
</div>`)
const cont = $(`<div></div>`)
view.append(
cont.append(
self.queuesController(data)
)
)
return view
},
/**
*
* @param {Object} data
* @returns {Array}
*/
queuesController(data) {
const self = this
if(!Array.isArray(data)) {
return ''
}
if(data.length === 0) {
return `<p class="text-center">${this.locale.queuesEmpty}</p>`
}
return data.map((d, i) => {
const current = self._getCurrentCallData(d)
return self.queueCallView(current, i+1)
})
},
/**
*
* @param {Object} data
* @returns {String|HTMLElement}
*/
queueCallView(data, key) {
const view = $(`<div class="row align-items-center p-1 m-0 mt-1"
style="background: ${data.bgColor}">
${keyView(key)} ${phoneView(data.phone1)}${phoneView(data.phone2)} ${timeView(data.duration)}
</div>`)
function keyView(val="") {
const view = `<div class="col-1 p-0">${val}</div>`
return view
}
function titleView(title="", info="") {
const view = `<div class="col-auto p-0"> ${title} <span>${info}</spam> </div>`;
return view
}
function phoneView(phone="") {
const view = `<div class="col-4 p-0">${phone}</div>`
return view
}
function phoneToView(phone="") {
if(!phone.length){ return "";}
const view = ` <div class="col-4 p-0">${phone}</div>`
return view
}
function timeView(duration="") {
const view = `<div class="col-2 p-1 bg-light rounded d-flex justify-content-center ml-auto">${duration.substr(-5)}</div>`
return view
}
return view
},
/**
* Takes call data and converts it to a standard form
* @param {Object} data
* @returns {Object}
*/
_getCurrentCallData(data) {
let result = {
queue: "",
phone1: "",
phone2: "",
duration: "",
}
// console.log("CHECK: ", "_getCurrentCallData", data);
switch (data._type) {
case "ivr":
// IVR
result.phone1 = data.calleridnum // номер звонящего
result.phone2 = data.language // внутренний номер агента
//result.queue = "" //data.queue_number // номер очереди агента
break
case "incom":
// входящий выхов
result.phone1 = data.calleridnum // номер звонящего
result.phone2 = (data._agentNumber) ? data._agentNumber : data.connectedlinenum // внутренний номер агента
result.queue = data.queue_number // номер очереди агента
break
case "out":
// исходящий выхов
result.phone1 = data.outnum // исходящий номер
result.phone2 = data._agentNumber || data.calleridnum // || data.connectedlinenum // внутренний номер агента || номер
result.queue = data.queue_number // номер очереди агента
break
case "outlines":
// внутренний входящий номер
result.phone1 = data.calleridnum // номер
result.phone2 = data._agentNumber || data.calleridnum // внутренний номер агента || номер
// result.queue = data.queue_number // номер очереди агента
break
}
result.duration = data.duration
// console.log("CallRES: ",result);
return result
},
_getCurrentQueuesCalls(data) {
let result = {
ivr: {
title: 'IVR',
data: []
},
in: {
title: 'Входящие',
data: []
},
out: {
title: 'Исходящие',
data: []
}
}
setData("ivr", this._conf.calls.keys.ivr)
setData("in", this._conf.calls.keys.in)
setData("out", this._conf.calls.keys.out)
return result
function setData(mainKey, args) {
$.each(args, (none, key) => {
const k = key.toLocaleLowerCase()
$.each(data[key], (phone, value) => {
if (k === 'outlines') {
if (value.channelstate == 5) {
return
}
}
value = $.extend({}, value)
value._agentNumber = phone
value._type = key.toLocaleLowerCase()
result[mainKey].data.push(value)
})
})
}
},
/**
*
* @param {Array} data
* @returns {Array} array with html elements
*/
observersController(data) {
const self = this
if(!Array.isArray(data)) {
return ''
}
return data.map(d => {
return self.observerView(d)
})
},
/**
* tempalte for observers
* @param {Object} data
* @returns {String|HTMLElement}
*/
observerView(data) {
const {
IMG,
USER
} = data;
const view = `<div class="row align-items-center m-0 mt-2 p-1">
<div class="col-2">
<img src="${IMG}"
class="w-100 rounded-circle">
</div>
<div class="col-8">
<p class="m-0">${USER}</p>
</div>
</div>`;
return view;
},
/**
*
* @private __setAgents
* @param {Array} agents
* @returns {Map}
*/
__setAgents(agents) {
let map = new Map()
$.each(agents, function(i, agent) {
map.set(agent.number, agent)
})
this.agents = map
return map
}
}
return Quesue
}
...@@ -76,8 +76,8 @@ var afterLoadPage = function(){ ...@@ -76,8 +76,8 @@ var afterLoadPage = function(){
*/ */
var trunksUpdate = function(){ var trunksUpdate = function(){
//if(updatingTm == true){ return; } doAloVoiceCmd('loadTrunksList', {}, function(res) {
loadAloVoiceInfo("alovoice_trunks_list",function(res){
console.log("AloVoice Trunks RES:",res); console.log("AloVoice Trunks RES:",res);
if(!isHeadered){ if(!isHeadered){
...@@ -109,7 +109,7 @@ var afterLoadPage = function(){ ...@@ -109,7 +109,7 @@ var afterLoadPage = function(){
+'<td>'+trunk.number+'</td>' +'<td>'+trunk.number+'</td>'
+'<td>'+trunk.maxchannels+'</td>' +'<td>'+trunk.maxchannels+'</td>'
+'<td>'+status+'</td>' +'<td>'+status+'</td>'
+'<td class="nowrp" ><a href="#" onClick="updateOneTrunk(\''+trunk.id+'\');"><i class="fa fa-money"></i> Проверить</a></td>' +'<td class="nowrp" ><a href="#" onClick="updateOneTrunk(\''+trunk.id+'\');"><i class="fa fa-money"></i> Настройки</a></td>'
+'</tr>'; +'</tr>';
$("#alvtrunks_table_body").append(lineHTML); $("#alvtrunks_table_body").append(lineHTML);
...@@ -118,6 +118,48 @@ var afterLoadPage = function(){ ...@@ -118,6 +118,48 @@ var afterLoadPage = function(){
//setTimeout(donglesUpdate,100000); //setTimeout(donglesUpdate,100000);
}); });
// loadAloVoiceInfo("alovoice_trunks_list",function(res){
// console.log("AloVoice Trunks RES:",res);
// if(!isHeadered){
// if(typeof res.headers != 'undefined' ){
// isHeadered = true;
// $("#alvtrunks_table_header").html('');
// $.each( res.headers, function( key, value ) {
// console.log("Each Header:",key, value);
// $("#alvtrunks_table_header").append('<th id="hd_'+key+'">'+value+'</th>');
// });
// }
// }
// if(typeof res.datas != 'undefined' ){
// $("#alvtrunks_table_body").html('');
// $.each( res.datas, function( tkey, trunk ) {
// console.log("Each Trunk:",trunk);
// /*var statusLine = (val.datas[2]=="free") ? '<span style="color:green;">'+val.datas[2]+'</span>' : val.datas[2];
// var statusLine = (statusLine=="dialing") ? '<span style="color:yellow;">'+statusLine+'</span>' : statusLine;
// var statusLine = (statusLine=="outgoing") ? '<span style="color:blue;">'+statusLine+'</span>' : statusLine;
// //var statusLine = (val.datas[2]=="dialing") ? '<span style="color:yellow;">'+val.datas[2]+'</span>' : val.datas[2];
// */
// let status = (trunk.status == 'On') ? '<span class="active_tg_status badge badge-success">Активный</span>' : '<span class="off_tg_status badge badge-secondary">Выключен</span>';
// var lineHTML = '<tr class="alv_table_lines" id="trk_line_'+trunk.id+'" data-device="'+trunk.type+'" data-numcode="'+trunk.name+'">'
// +'<td class="nowrp" > <span>'+trunk.id+'</span></td>'
// +'<td class="nowrp" > <b>'+trunk.name+'</b></td>'
// +'<td class="nowrp" >'+trunk.type +'</td>'
// +'<td>'+trunk.number+'</td>'
// +'<td>'+trunk.maxchannels+'</td>'
// +'<td>'+status+'</td>'
// +'<td class="nowrp" ><a href="#" onClick="updateOneTrunk(\''+trunk.id+'\');"><i class="fa fa-money"></i> Проверить</a></td>'
// +'</tr>';
// $("#alvtrunks_table_body").append(lineHTML);
// });
// }
// //setTimeout(donglesUpdate,100000);
// });
} }
trunksUpdate(); trunksUpdate();
......
...@@ -189,7 +189,45 @@ class AloVoiceActions ...@@ -189,7 +189,45 @@ class AloVoiceActions
return false; return false;
} }
public function getAlovoiceOperators(){ public function getAlovoiceOperatorsNums($r=false){
$bxOnlineUsers = BxRest::call("user.get",array(
'UF_PHONE_INNER' => '_%',
//'IS_ONLINE' => 'Y',
));
$bxPhoneUsers = array();
if(!empty($bxOnlineUsers["result"])){
foreach($bxOnlineUsers["result"] as $bxonUser){
$bxPhoneUsers[$bxonUser["UF_PHONE_INNER"]] = $bxonUser;
}
}
return $bxPhoneUsers;
}
public function getAlovoiceAllQueues($r=false){
$arQueues = [];
$doCmds = $this->runAsteriskAction([
'queues' => new \PAMI\Message\Action\QueueStatusAction(),
]);
if(!empty($doCmds['queues'])){
$QueueStatusEvents = $doCmds['queues']->getEvents();
foreach( $QueueStatusEvents as $qevnt){
$qKeys = $qevnt->getKeys();
if(!empty($qKeys["queue"]) && $qKeys["queue"] != "default"){
$arQueues[$qKeys["queue"]] = $qKeys["strategy"];
// $arQueues[$qKeys["queue"]] = $qKeys;
// $arQueues[] = $qKeys["queue"];
}
}
}
return $arQueues;
}
public function getAlovoiceOperators($r=false){
$doCmds = $this->runAsteriskAction([ $doCmds = $this->runAsteriskAction([
'dnds' => new \PAMI\Message\Action\CommandAction('database show DND'), 'dnds' => new \PAMI\Message\Action\CommandAction('database show DND'),
......
...@@ -1189,6 +1189,7 @@ class AloVoiceConnector ...@@ -1189,6 +1189,7 @@ class AloVoiceConnector
"dashboard" => array( "name" => "АлоВойс", "perms" => "all"), "dashboard" => array( "name" => "АлоВойс", "perms" => "all"),
"queues" => array( "name" => "Звонки", "perms" => "all"), "queues" => array( "name" => "Звонки", "perms" => "all"),
// "chdongles" => array( "name" => "GSM линии", "perms" => "admin"), // "chdongles" => array( "name" => "GSM линии", "perms" => "admin"),
"inroutes" => array( "name" => "Входящие", "perms" => "admin"),
"trunks" => array( "name" => "Линии", "perms" => "admin"), "trunks" => array( "name" => "Линии", "perms" => "admin"),
"peers" => array( "name" => "Внут.номера", "perms" => "admin"), "peers" => array( "name" => "Внут.номера", "perms" => "admin"),
// "stats" => array( "name" => "Статистика агентов", "perms" => "all"), // "stats" => array( "name" => "Статистика агентов", "perms" => "all"),
......
...@@ -1436,9 +1436,19 @@ sessid: 40512ed0288d707e78dc4f7ef25214ef ...@@ -1436,9 +1436,19 @@ sessid: 40512ed0288d707e78dc4f7ef25214ef
return $alvActions->doDndToggle($r); return $alvActions->doDndToggle($r);
} }
private function alovoice_get_operators_nums($r=false) {
$alvActions = new AloVoiceActions($this->config);
return $alvActions->getAlovoiceOperatorsNums($r);
}
private function alovoice_get_allqueues($r=false) {
$alvActions = new AloVoiceActions($this->config);
return $alvActions->getAlovoiceAllQueues($r);
}
private function alovoice_get_operators($r=false) { private function alovoice_get_operators($r=false) {
$alvActions = new AloVoiceActions($this->config); $alvActions = new AloVoiceActions($this->config);
return $alvActions->getAlovoiceOperators(); return $alvActions->getAlovoiceOperators($r);
} }
private function alovoice_peers_list($r=false) { private function alovoice_peers_list($r=false) {
...@@ -1478,7 +1488,7 @@ sessid: 40512ed0288d707e78dc4f7ef25214ef ...@@ -1478,7 +1488,7 @@ sessid: 40512ed0288d707e78dc4f7ef25214ef
return $alvActions->getAlovoiceSounds(); return $alvActions->getAlovoiceSounds();
} }
private function alovoice_trunks_list($r=false) { private function alovoice_lines_list($r=false) {
$alvActions = new AloVoiceActions($this->config); $alvActions = new AloVoiceActions($this->config);
return $alvActions->getAlovoiceTrunks(); return $alvActions->getAlovoiceTrunks();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment