Преглед изворни кода

新增sip手动外呼功能

peicj пре 4 недеља
родитељ
комит
2a933859a9

+ 9 - 0
src/api/aiSipCall/aiSipCallGateway.js

@@ -9,6 +9,15 @@ export function listAiSipCallGateway(query) {
   })
 }
 
+// 查询aiSIP外呼网关列表
+export function remoteList(data) {
+  return request({
+    url: '/company/aiSipCall/gateway/remoteList',
+    method: 'post',
+    data: data
+  })
+}
+
 // 查询aiSIP外呼网关详细
 export function getAiSipCallGateway(id) {
   return request({

+ 8 - 0
src/api/aiSipCall/aiSipCallOutboundCdr.js

@@ -8,6 +8,14 @@ export function listOutboundCdr(query) {
     params: query
   })
 }
+// 查询远程aiSIP手动外呼通话记录列表
+export function remoteList(data) {
+  return request({
+    url: '/company/aiSipCall/outboundCdr/remoteList',
+    method: 'post',
+    data: data
+  })
+}
 
 // 查询aiSIP手动外呼通话记录详细
 export function getOutboundCdr(id) {

+ 8 - 0
src/api/aiSipCall/aiSipCallPhone.js

@@ -8,6 +8,14 @@ export function listAiSipCallPhone(query) {
     params: query
   })
 }
+// 查询远程aiSIP外呼通话记录列表
+export function remoteList(data) {
+  return request({
+    url: '/company/aiSipCall/phone/remoteList',
+    method: 'post',
+    data: data
+  })
+}
 
 // 查询aiSIP外呼通话记录详细
 export function getAiSipCallPhone(id) {

+ 4 - 3
src/api/aiSipCall/aiSipCallUser.js

@@ -68,9 +68,10 @@ export function getUnBindExtnum(query) {
 }
 
 // 查询aiSIP工具条基础配置参数
-export function getToolbarBasicParam(extNum) {
+export function getToolbarBasicParam(data) {
   return request({
-    url: '/company/aiSipCall/aiSipCallUser/getToolbarBasicParam/' + extNum,
-    method: 'get'
+    url: '/company/aiSipCall/aiSipCallUser/getToolbarBasicParam',
+    method: 'post',
+    data: data
   })
 }

+ 1871 - 1866
src/assets/callCenterPhoneBarSdk/ccPhoneBarSocket.js

@@ -8,1912 +8,1917 @@
 import $ from './jquery-1.11.0.js';
 
 function _phoneBarObserver(){
-	if(!(this instanceof _phoneBarObserver)){
-		return new _phoneBarObserver();
-	}
-	this.listeners = {}
+  if(!(this instanceof _phoneBarObserver)){
+    return new _phoneBarObserver();
+  }
+  this.listeners = {}
 };
 _phoneBarObserver.prototype = {
-	on: function (key, callback) { this.addListener(key, callback); },
-	off: function (key, callback) { this.removeListener(key, callback); },
-	addListener: function (key, callback) {
-		if(!this.listeners[key]) {
-			this.listeners[key] = [];
-		}
-		this.listeners[key].push(callback);
-	},
-	removeListener: function (key, callback) {
-		if(this.listeners[key]) {
-			if(callback) {
-				const index = this.listeners[key].indexOf(callback);
-				if (index > -1) {
-					this.listeners[key].splice(index, 1);
-				}
-			}else {
-				this.listeners[key] = [];
-			}
-		}
-	},
-	notifyAll: function (key, info) {
-		if(!this.listeners[key]) return;
-		for (var i = 0; i < this.listeners[key].length; i++) {
-			if (typeof this.listeners[key][i] === 'function') {
-				this.listeners[key][i](info);
-			}
-		}
-	},
-	make: function (o) {
-		for (var i in this) {
-			o[i] = this[i];
-			o.listeners = {}
-		}
-	}
+  on: function (key, callback) { this.addListener(key, callback); },
+  off: function (key, callback) { this.removeListener(key, callback); },
+  addListener: function (key, callback) {
+    if(!this.listeners[key]) {
+      this.listeners[key] = [];
+    }
+    this.listeners[key].push(callback);
+  },
+  removeListener: function (key, callback) {
+    if(this.listeners[key]) {
+      if(callback) {
+        const index = this.listeners[key].indexOf(callback);
+        if (index > -1) {
+          this.listeners[key].splice(index, 1);
+        }
+      }else {
+        this.listeners[key] = [];
+      }
+    }
+  },
+  notifyAll: function (key, info) {
+    if(!this.listeners[key]) return;
+    for (var i = 0; i < this.listeners[key].length; i++) {
+      if (typeof this.listeners[key][i] === 'function') {
+        this.listeners[key][i](info);
+      }
+    }
+  },
+  make: function (o) {
+    for (var i in this) {
+      o[i] = this[i];
+      o.listeners = {}
+    }
+  }
 };
 
 //呼叫中心websocket通信对象
 "use strict";
 function ccPhoneBarSocket() {
-	var observer = new _phoneBarObserver();
-	observer.make(this);
-	var _cc = this;
-	var ws = null;
-	var wsuri = null;
-	var isConnected = false;
-	/* 通话已建立 */
-	var callConnected = false;
-	/*
-	 *  是否可以发送视频通话邀请;
-	 */
-	var canSendVideoReInvite = false;
-	/**
-	 * 是否开启了坐席状态列表订阅
-	 * @type {boolean}
-	 */
-	this.subscribeAgentListStarted = false;
-	this.iframe = null;
-	this.callConfig = {
-		 // 使用默认的UI,还是使用自定义的UI
-		'useDefaultUi': false,
-		//呼叫控制服务器地址
-		'ipccServer': '129.28.164.235:8443',
-		//是否启用websocket安全连接
-		'enableWss' : false,
-		//语音编码
-		'callCodec' : 'pcma',
-		//是否发送心跳数据
-		'enableHeartBeat' : true,
-		//送心跳数据的时间间隔; 秒;
-		'heartBeatIntervalSecs' : 16,
-		// 工具条外呼时: 软电话和外呼通话,使用相同的语音编码,避免转码,从而提高性能;
-		// 但是!: 如果客户端是网页电话,且外呼线路使用g729编码时,该参数需要设置为false,
-		// 因为网页电话不支持g729编码; [此时会产生语音编码的转码]
-		'useSameAudioCodeForOutbound' : true,
-		// 令牌
-		'loginToken' : '',
-
-		 // 网关列表, 如果是注册模式: 网关地址参数则填写为网关名称;
-		 // 安全起见,生产环境,需要把该参数加密为base64格式;
-		'gatewayList' : [
-			{
-				uuid         :  '01',
-				updateTime         :  1675953810492,
-				gatewayAddr  : '113.207.68.30:5543;external', // 网关地址 + 外呼环境[可选参数,默认为external];
-				callerNumber : '02386990208',    // 主叫号码
-				calleePrefix : '',       // 被叫前缀
-				priority     : 1,        // 优先级
-				concurrency  : 1000,       // 并发数
-				register     : false,    // 是否注册模式
-				audioCodec   : 'g711'    // 语音编码,可用选择项 g711、g729
-			}
-		],
-
-	    'gatewayEncrypted' : false,
-
-		 // 分机注册配置;
-		 //Freeswitch服务器地址
-		 'fsServer' : '129.28.164.235:5060',
-		 // 分机账户
-		 'extnum' : '1001',
-		 // 工号
-		 'opnum' : 'admin',
-		 //业务组编号
-		 'groupId' : '1',
-		 //全部业务组列表
-		 'groups' : null,
-		 //全部坐席人员列表
-		 'agentList' : null,
-		 'extPassword': '0406f9d44bb8fe195a1ee2557bbeebf7',  // 分机密码
-		 'phoneType': 'EyeBeam',         // 电话类型
-		 'webPhoneUrl' : 'None',
-
-		 // 客户端软电话代理配置信息
-		 'localHostProxyVersion' : 'v20221130_1736',  // 本地代理软件的版本信息
-		 'localHostProxyPort' : 8888    // 本地代理软件端口;
-	};
-
-	/**
-	 * 在指定html对象后追加新元素
-	 * @param newElement
-	 * @param targetElement
-	 */
-	this.insertAfter = function(newElement,targetElement)
-	{
-		var parent = targetElement.parentNode;
-		if(parent.lastChild === targetElement)
-		{
-			parent.appendChild(newElement);
-		}else{
-			parent.insertBefore(newElement,targetElement.nextSibling);
-		}
-	};
-
-	this.trim = function (str) {
-		return str.replace(/^\s\s*/,'').replace(/\s\s*$/, '');
-	};
-    this.getIsConnected = function(){
-    	return isConnected;
+  var observer = new _phoneBarObserver();
+  observer.make(this);
+  var _cc = this;
+  var ws = null;
+  var wsuri = null;
+  var isConnected = false;
+  /* 通话已建立 */
+  var callConnected = false;
+  /*
+   *  是否可以发送视频通话邀请;
+   */
+  var canSendVideoReInvite = false;
+  /**
+   * 是否开启了坐席状态列表订阅
+   * @type {boolean}
+   */
+  this.subscribeAgentListStarted = false;
+  this.iframe = null;
+  this.callConfig = {
+    // 使用默认的UI,还是使用自定义的UI
+    'useDefaultUi': false,
+    //呼叫控制服务器地址
+    'ipccServer': 'sip.ylrzcloud.com',
+    //是否启用websocket安全连接
+    'enableWss' : true,
+    //语音编码
+    'callCodec' : 'pcma',
+    //是否发送心跳数据
+    'enableHeartBeat' : true,
+    //送心跳数据的时间间隔; 秒;
+    'heartBeatIntervalSecs' : 16,
+    // 工具条外呼时: 软电话和外呼通话,使用相同的语音编码,避免转码,从而提高性能;
+    // 但是!: 如果客户端是网页电话,且外呼线路使用g729编码时,该参数需要设置为false,
+    // 因为网页电话不支持g729编码; [此时会产生语音编码的转码]
+    'useSameAudioCodeForOutbound' : true,
+    // 令牌
+    'loginToken' : '',
+
+    // 网关列表, 如果是注册模式: 网关地址参数则填写为网关名称;
+    // 安全起见,生产环境,需要把该参数加密为base64格式;
+    'gatewayList' : [
+      {
+        uuid         :  '01',
+        updateTime         :  1675953810492,
+        gatewayAddr  : '113.207.68.30:5543;external', // 网关地址 + 外呼环境[可选参数,默认为external];
+        callerNumber : '02386990208',    // 主叫号码
+        calleePrefix : '',       // 被叫前缀
+        priority     : 1,        // 优先级
+        concurrency  : 1000,       // 并发数
+        register     : false,    // 是否注册模式
+        audioCodec   : 'g711'    // 语音编码,可用选择项 g711、g729
+      }
+    ],
+
+    'gatewayEncrypted' : false,
+
+    // 分机注册配置;
+    //Freeswitch服务器地址
+    'fsServer' : '129.28.164.235:5060',
+    // 分机账户
+    'extnum' : '1001',
+    // 工号
+    'opnum' : 'admin',
+    //业务组编号
+    'groupId' : '1',
+    //全部业务组列表
+    'groups' : null,
+    //全部坐席人员列表
+    'agentList' : null,
+    'extPassword': '0406f9d44bb8fe195a1ee2557bbeebf7',  // 分机密码
+    'phoneType': 'EyeBeam',         // 电话类型
+    'webPhoneUrl' : 'None',
+
+    // 客户端软电话代理配置信息
+    'localHostProxyVersion' : 'v20221130_1736',  // 本地代理软件的版本信息
+    'localHostProxyPort' : 8888    // 本地代理软件端口;
+  };
+
+  /**
+   * 在指定html对象后追加新元素
+   * @param newElement
+   * @param targetElement
+   */
+  this.insertAfter = function(newElement,targetElement)
+  {
+    var parent = targetElement.parentNode;
+    if(parent.lastChild === targetElement)
+    {
+      parent.appendChild(newElement);
+    }else{
+      parent.insertBefore(newElement,targetElement.nextSibling);
+    }
+  };
+
+  this.trim = function (str) {
+    return str.replace(/^\s\s*/,'').replace(/\s\s*$/, '');
+  };
+  this.getIsConnected = function(){
+    return isConnected;
+  };
+  /**
+   *  获取通话状态
+   * @returns {boolean} true通话中,false通话未建立;
+   */
+  this.getCallConnected = function(){
+    return callConnected;
+  };
+  /**
+   *  设置通话状态;
+   * @param value true通话中,false通话未建立
+   * @returns {*}
+   */
+  this.setCallConnected = function(value){
+    callConnected = value;
+  };
+
+  /**
+   *  设置一个标志,指示是否可以发起视频通话;
+   * 仅限通话为音频通话且通话已经接通时方可允许发起视频邀请;
+   * @param value
+   */
+  this.setCanSendVideoReInvite = function(value){
+    canSendVideoReInvite = value;
+  };
+
+  /**
+   *  设置一个标志,指示是否可以发起视频通话;
+   * @param value
+   */
+  this.getCanSendVideoReInvite = function(){
+    return 	canSendVideoReInvite;
+  };
+
+  this.setHeartbeat = function()
+  {
+    setInterval(function(){
+      //如果启用了心跳,而且用户已经登录上线,则发送心跳数据
+      if(_cc.callConfig.enableHeartBeat && _cc.getIsConnected()){
+        console.debug("try to send heartbeat.");
+        var heartBeat = {};
+        heartBeat.action="setHearBeat";
+        heartBeat.body = "{}";
+        _cc.sendMsg(heartBeat);
+      }
+    }, _cc.callConfig.heartBeatIntervalSecs * 1000);
+  };
+
+  this.loadScript = function(destUrl, callbackFunc){
+    var script = document.createElement("script");
+    script.type = "text/javascript";
+    script.src = destUrl;
+    if(null != callbackFunc){
+      script.onload=function(){callbackFunc();}
+    }
+    document.getElementsByTagName('head')[0].appendChild(script);
+  };
+
+  // 初始化websocket连接参数
+  this.initConfig = function(config) {
+    //把config中的属性全部拷贝到callConfig中;
+    for(var element in config) {
+      this.callConfig[element] = config[element];
+    }
+
+    var _loginToken = this.callConfig["loginToken"];
+    if(typeof(_loginToken) == "undefined" && _loginToken === "") {
+      alert("电话工具条:无法获取 loginToken!");
+      return;
+    }
+
+    console.log("callConfig:", JSON.stringify(this.callConfig));
+    //线上enableWss: true 本地调试为false
+    if(_cc.callConfig.enableWss){
+      wsuri = 'wss://' + this.callConfig.ipccServer +
+        '/call-center/websocketServer?' +
+        '&loginToken=' + this.callConfig.loginToken;
+    }else{
+      wsuri = 'ws://129.28.164.235:1081/call-center/websocketServer?' +
+        '&loginToken=' + this.callConfig.loginToken;
+    }
+    console.log("ipccServer url: " + wsuri);
+    var ipccServerIpAddr = this.callConfig.ipccServer.split(":");
+    if(this.callConfig.enableWss &&  this.checkIP(ipccServerIpAddr)){
+      var tipsError = "ERROR! 启用了wss之后,必须使用域名访问websocketServer! " + this.callConfig.ipccServer;
+      console.log(tipsError);
+      alert(tipsError);
+    }
+    if(this.callConfig.enableHeartBeat) {
+      _cc.setHeartbeat();
+    }
+
+    //var downLoadUrl = "http://192.168.66.71:81/soft/callcenter-soft/LocalHostProxy/LocalHostProxy-" +
+    _cc.callConfig["localHostProxyVersion"] + ".zip";
+    //console.log("客户端代理软件的下载地址:", downLoadUrl);
+    //this.createIframe("http://127.0.0.1:8888/getVersion");
+
+    if(_cc.callConfig["useDefaultUi"]){
+      this.initPhoneBarUI();
+    }
+  };
+
+  //检测ip地址是否合法;
+  this.checkIP = function (ip)
+  {
+    var re =  /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/ ;
+    return re.test(ip);
+  };
+
+  //断开到呼叫控制服务器的连接
+  this.disconnect = function(){
+    // 检查 WebSocket 是否存在且连接正常
+    if (!ws || ws.readyState !== WebSocket.OPEN) {
+      console.log('WebSocket 未连接或已关闭,无需发送断开指令');
+      return;
+    }
+    var cmdInfo = {};
+    cmdInfo.action="setAgentStatus";
+    cmdInfo.body = {"cmd" : "disconnect", "args" : { "msg" : "disconnection opt triggered by js client." } };
+    ws.send(JSON.stringify(cmdInfo));
+    // 立即关闭 WebSocket 连接
+    ws.close();
+  };
+
+  /**
+   *  获取当前坐席登录的分机号码
+   * @returns {string|*}
+   */
+  this.getExtNum = function(){
+    return this.callConfig.extnum;
+  };
+
+  /**
+   *  获取当前坐席登录的工号
+   * @returns {string|*}
+   */
+  this.getOpNum = function(){
+    return this.callConfig.opnum;
+  };
+
+  /**
+   *  获取当前坐席的业务组编号
+   * @returns {string|*}
+   */
+  this.getGroupId = function(){
+    return this.callConfig.groupId;
+  };
+
+
+  /**
+   *  获取全部业务组列表
+   * @returns {string|*}
+   */
+  this.getGroups = function(){
+    return  JSON.parse(JSON.stringify(this.callConfig.groups));
+  };
+
+  this.findAgentByOpNum  = function (opnum){
+    if(_cc.callConfig.agentList == null) return null;
+
+    for (var key in _cc.callConfig.agentList) {
+      let item = _cc.callConfig.agentList[key];
+      if(item["opnum"] === opnum){
+        //add _arrayIndex property to record index
+        item["_arrayIndex"] = key;
+        return item;
+      }
+    }
+    return null;
+  };
+
+  this.updateAgentList = function (agentList) {
+    for (var key in agentList) {
+      let item = agentList[key];
+      var existItem = this.findAgentByOpNum(item["opnum"]);
+      if(existItem != null){
+        var newStatus = item["agentStatus"];
+        var oldStatus = existItem["agentStatus"];
+        var logoutTime = item["logoutTime"];
+        if(logoutTime > 0){
+          //删除元素
+          console.info("delete offline user",item["opnum"], "index=", key);
+          _cc.callConfig.agentList.splice(existItem["_arrayIndex"], 1);
+          continue;
+        }
+        if(newStatus != oldStatus){
+          existItem["agentStatus"] = newStatus;
+        }
+      }else{
+        if(_cc.callConfig.agentList != null) {
+          _cc.callConfig.agentList.push(item);
+        }
+      }
+    }
+  };
+
+  //连接到呼叫控制服务器
+  this.connect = function() {
+    // 如果已经在连接中,直接返回
+    if (ws && ws.readyState === WebSocket.CONNECTING) {
+      console.log('[connect] WebSocket 正在连接中,请勿重复操作');
+      return;
+    }
+
+    // 先关闭旧的连接,避免重复登录
+    if (ws) {
+      console.log('[connect] 检测到旧连接存在,先关闭旧连接');
+      try {
+        ws.close();
+      } catch(e) {
+        console.error('[connect] 关闭旧连接失败:', e);
+      }
+      ws = null;
+    }
+
+    if ('WebSocket' in window)
+      ws = new WebSocket(wsuri);
+    else {
+      console.log('您的浏览器不支持 websocket,您无法使用本页面的功能!');
+      return;
+    }
+    //收到消息
+    ws.onmessage = function(evt) {
+      console.log("recv msg from websocket server: ", evt.data);
+      var msg = JSON.parse(evt.data);
+      console.log("parsed json data:", msg);
+      var resp_status = msg["status"];
+      switch(resp_status) {
+        case 200:
+          isConnected = true;
+          _cc.callConfig.extnum = msg.object["extnum"];
+          _cc.callConfig.opnum = msg.object["opnum"];
+          _cc.callConfig.groupId = msg.object["groupId"];
+          _cc.callConfig.groups = msg.object["groups"];
+          console.log('ipcc 连接成功.', 'connected_ipcc_server');
+          // WebSocket 连接成功后自动设置为置忙状态,以便可以外呼
+          _cc.setStatus(ccPhoneBarSocket.agentStatusEnum.busy);
+          _cc.notifyAll(ccPhoneBarSocket.eventList.ws_connected, msg);
+          break;
+        default:
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.caller_hangup) ||
+            parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.CONFERENCE_MODERATOR_HANGUP)) {
+            _cc.setCallConnected(false);
+            _cc.setCanSendVideoReInvite(false);
+            _cc.callConfig.agentList = null;
+            _cc.unSubscribeAgentList();
+            // 重置呼叫标志
+            _cc.isCalling = false;
+            console.log("caller_hangup")
+          }
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_hangup)) {
+            // 重置呼叫标志
+            _cc.isCalling = false;
+          }
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_answered)) {
+            _cc.setCallConnected(true);
+            console.log("callee_answered")
+          }
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.new_inbound_call)) {
+            _cc.setCallConnected(true);
+            console.log("new_inbound_call")
+          }
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.caller_answered) ||
+            parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_answered)) {
+            if (msg["object"]["callType"] === "audio") {
+              _cc.setCanSendVideoReInvite(true);
+              _cc.notifyAll(ccPhoneBarSocket.eventList.on_audio_call_connected, "audio call connected.")
+              console.log("current callType is audio.")
+            }
+            if (msg["object"]["callType"] === "video") {
+              _cc.setCanSendVideoReInvite(false);
+              _cc.notifyAll(ccPhoneBarSocket.eventList.on_video_call_connected, "video call connected.")
+              console.log("current callType is video.")
+            }
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_hold)) {
+            _cc.changeUiOnHold();
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_unhold)) {
+            _cc.changeUiOnUnHold();
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_on_hold_hangup)) {
+            _cc.changeUiOnUnHold();
+            $("#holdBtn").removeClass('on');
+            $("#callStatus").text("保持的通话已挂机.");
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_call_wait)) {
+            $("#stopCallWait").show();
+            $("#doConsultationBtn").hide();
+            $("#callStatus").text("客户电话等待中.");
+            _cc.showTransferAreaUI();
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_off_call_wait)) {
+            $("#stopCallWait").hide();
+            $("#transferCallWait").hide();
+            _cc.hideTransferAreaUI();
+            $("#callStatus").text("等待的电话已接回.");
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.inner_consultation_start)) {
+            $("#callStatus").text("咨询已开始.");
+            $("#transferCallWait").show();
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.inner_consultation_stop)) {
+            $("#callStatus").text("咨询已结束.");
+            $("#transferCallWait").hide();
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_on_call_wait_hangup)) {
+            $("#stopCallWait").hide();
+            $("#transferCallWait").hide();
+            $("#callStatus").text("等待的客户已挂机.");
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.inner_consultation_start)) {
+            $("#holdBtn").removeClass('on');
+            $("#hangUpBtn").removeClass('on');
+            $("#transferBtn").removeClass('on');
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.transfer_call_success)) {
+            var extNum = msg["object"]["callee"];
+            if(extNum === _cc.getExtNum()) {
+              $("#holdBtn").addClass('on');
+              $("#hangUpBtn").addClass('on');
+              $("#transferBtn").addClass('on');
+            }
+
+          }
+
+          if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.agent_status_data_changed)) {
+            if(_cc.subscribeAgentListStarted) {
+              if (_cc.callConfig.agentList == null) {
+                _cc.callConfig.agentList = JSON.parse(msg.object);
+              }else{
+                // 更新列表;
+                _cc.updateAgentList(JSON.parse(msg.object));
+              }
+            }
+          }
+          _cc.notifyAll(resp_status, msg);
+          break;
+      }
+    };
+    //关闭连接时触发
+    ws.onclose = function(evt) {
+      isConnected = false;
+      _cc.notifyAll(ccPhoneBarSocket.eventList.ws_disconnected, "ipccserver 连接断开.");
+      console.log("ipcc连接断开.", "disconnected");
+      console.log(evt);
+      ws.close();
     };
+    ws.onopen = function(evt) {
+      console.log("ipccserver websocket onopen...");
+    };
+  };
+
+  //发送消息给呼叫控制服务器
+  this.sendMsg = function(jsonObject) {
+    console.debug("ws.send:", jsonObject);
+    ws.send(JSON.stringify(jsonObject));
+  };
+
+  this.changeUiOnHold = function() {
+    $("#holdBtnLi").hide();
+    $("#unHoldBtnLi").show();
+    $("#unHoldBtn").addClass('on');
+  };
+
+  this.changeUiOnUnHold = function() {
+    $("#holdBtnLi").show();
+    $("#holdBtn").addClass('on');
+    $("#unHoldBtnLi").hide();
+  };
+
+  this.hideTransferAreaUI = function(){
+    var transferArea = document.getElementById("transfer_area");
+    transferArea.style.display = "none";
+  };
+
+  this.showTransferAreaUI = function(){
+    var transferArea = document.getElementById("transfer_area");
+    transferArea.style.display = "block";
+  };
+
+  /**
+   *  设置状态为空闲
+   */
+  this.setStatusFree = function(){
+    this.setStatus(ccPhoneBarSocket.agentStatusEnum.free);
+  };
+
+  /**
+   *  设置状态为忙碌
+   */
+  this.setStatusBusy = function(){
+    this.setStatus(ccPhoneBarSocket.agentStatusEnum.busy);
+  };
+
+  ccPhoneBarSocket.utils = {
+
     /**
-     *  获取通话状态
-     * @returns {boolean} true通话中,false通话未建立;
+     * 读取 URL 中的指定查询参数值
+     * @param {string} paramName - 要获取的参数名称
+     * @returns {string|null} 返回参数值,如果不存在则返回 null
      */
-    this.getCallConnected = function(){
-        return callConnected;
-    };
+    getQueryParam :	function (paramName) {
+      const url = window.location.href; // 获取当前页面 URL
+      const params = new URLSearchParams(new URL(url).search); // 创建 URLSearchParams 对象
+      return params.get(paramName); // 获取指定参数值
+    }
+  };
+
+  /**
+   *  座席状态枚举;
+   * @type {{rest: number, calling: number, busy: number, free: number, justLogin: number, meeting: number, train: number}}
+   */
+  ccPhoneBarSocket.agentStatusEnum = {
+
     /**
-     *  设置通话状态;
-     * @param value true通话中,false通话未建立
-     * @returns {*}
+     *  刚刚上线,尚未就绪中;
      */
-    this.setCallConnected = function(value){
-        callConnected = value;
-    };
+    "justLogin" : 1,
 
-	/**
-	 *  设置一个标志,指示是否可以发起视频通话;
-	 * 仅限通话为音频通话且通话已经接通时方可允许发起视频邀请;
-	 * @param value
-	 */
-	this.setCanSendVideoReInvite = function(value){
-		canSendVideoReInvite = value;
-	};
-
-	/**
-	 *  设置一个标志,指示是否可以发起视频通话;
-	 * @param value
-	 */
-	this.getCanSendVideoReInvite = function(){
-	    return 	canSendVideoReInvite;
-	};
-
-	this.setHeartbeat = function()
-	{
-		setInterval(function(){
-			//如果启用了心跳,而且用户已经登录上线,则发送心跳数据
-			if(_cc.callConfig.enableHeartBeat && _cc.getIsConnected()){
-				console.debug("try to send heartbeat.");
-				var heartBeat = {};
-				heartBeat.action="setHearBeat";
-				heartBeat.body = "{}";
-				_cc.sendMsg(heartBeat);
-			}
-		}, _cc.callConfig.heartBeatIntervalSecs * 1000);
-	};
-
-	this.loadScript = function(destUrl, callbackFunc){
-		var script = document.createElement("script");
-        script.type = "text/javascript";
-        script.src = destUrl;
-		if(null != callbackFunc){
-		   script.onload=function(){callbackFunc();}
-		}
-		document.getElementsByTagName('head')[0].appendChild(script);
-	};
-
-    // 初始化websocket连接参数
-	this.initConfig = function(config) {
-		//把config中的属性全部拷贝到callConfig中;
-		for(var element in config) {
-			this.callConfig[element] = config[element];
-		}
-
-		var _loginToken = this.callConfig["loginToken"];
-		if(typeof(_loginToken) == "undefined" && _loginToken === "") {
-			alert("电话工具条:无法获取 loginToken!");
-			return;
-		}
-
-	    console.log("callConfig:", JSON.stringify(this.callConfig));
-	    wsuri = 'ws://' + this.callConfig.ipccServer +
-	    			'/call-center/websocketServer?' +
-			'&loginToken=' + this.callConfig.loginToken;
-
-	    console.log("ipccServer ws url: " + wsuri);
-	    var ipccServerIpAddr = this.callConfig.ipccServer.split(":");
-	    if(this.callConfig.enableWss &&  this.checkIP(ipccServerIpAddr)){
-	    	var tipsError = "ERROR! 启用了wss之后,必须使用域名访问websocketServer! " + this.callConfig.ipccServer;
-	    	console.log(tipsError);
-	    	alert(tipsError);
-		}
-	    if(this.callConfig.enableHeartBeat) {
-			_cc.setHeartbeat();
-		}
-
-		//var downLoadUrl = "http://192.168.66.71:81/soft/callcenter-soft/LocalHostProxy/LocalHostProxy-" +
-							  _cc.callConfig["localHostProxyVersion"] + ".zip";
-		//console.log("客户端代理软件的下载地址:", downLoadUrl);
-        //this.createIframe("http://127.0.0.1:8888/getVersion");
-
-        if(_cc.callConfig["useDefaultUi"]){
-			this.initPhoneBarUI();
-		}
-	};
-
-	//检测ip地址是否合法;
-	this.checkIP = function (ip)
-	{
-	    var re =  /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/ ;
-	    return re.test(ip);
-	};
-
-	//断开到呼叫控制服务器的连接
-	this.disconnect = function(){
-		// 检查 WebSocket 是否存在且连接正常
-		if (!ws || ws.readyState !== WebSocket.OPEN) {
-			console.log('WebSocket 未连接或已关闭,无需发送断开指令');
-			return;
-		}
-		var cmdInfo = {};
-		cmdInfo.action="setAgentStatus";
-		cmdInfo.body = {"cmd" : "disconnect", "args" : { "msg" : "disconnection opt triggered by js client." } };
-		ws.send(JSON.stringify(cmdInfo));
-		// 立即关闭 WebSocket 连接
-		ws.close();
-	};
-
-	/**
-	 *  获取当前坐席登录的分机号码
-	 * @returns {string|*}
-	 */
-	this.getExtNum = function(){
-		return this.callConfig.extnum;
-	};
-
-	/**
-	 *  获取当前坐席登录的工号
-	 * @returns {string|*}
-	 */
-	this.getOpNum = function(){
-		return this.callConfig.opnum;
-	};
-
-	/**
-	 *  获取当前坐席的业务组编号
-	 * @returns {string|*}
-	 */
-	this.getGroupId = function(){
-		return this.callConfig.groupId;
-	};
-
-
-	/**
-	 *  获取全部业务组列表
-	 * @returns {string|*}
-	 */
-	this.getGroups = function(){
-		return  JSON.parse(JSON.stringify(this.callConfig.groups));
-	};
-
-    this.findAgentByOpNum  = function (opnum){
-    	if(_cc.callConfig.agentList == null) return null;
-
-		for (var key in _cc.callConfig.agentList) {
-			let item = _cc.callConfig.agentList[key];
-            if(item["opnum"] === opnum){
-            	//add _arrayIndex property to record index
-            	item["_arrayIndex"] = key;
-            	return item;
-			}
-		}
-		return null;
-	};
-
-	this.updateAgentList = function (agentList) {
-		for (var key in agentList) {
-			let item = agentList[key];
-            var existItem = this.findAgentByOpNum(item["opnum"]);
-            if(existItem != null){
-				var newStatus = item["agentStatus"];
-				var oldStatus = existItem["agentStatus"];
-				var logoutTime = item["logoutTime"];
-				if(logoutTime > 0){
-					//删除元素
-					console.info("delete offline user",item["opnum"], "index=", key);
-					_cc.callConfig.agentList.splice(existItem["_arrayIndex"], 1);
-					continue;
-				}
-				if(newStatus != oldStatus){
-					existItem["agentStatus"] = newStatus;
-				}
-			}else{
-				if(_cc.callConfig.agentList != null) {
-					_cc.callConfig.agentList.push(item);
-				}
-			}
-		}
-	};
-
-	//连接到呼叫控制服务器
-	this.connect = function() {
-		// 如果已经在连接中,直接返回
-		if (ws && ws.readyState === WebSocket.CONNECTING) {
-			console.log('[connect] WebSocket 正在连接中,请勿重复操作');
-			return;
-		}
-		
-		// 先关闭旧的连接,避免重复登录
-		if (ws) {
-			console.log('[connect] 检测到旧连接存在,先关闭旧连接');
-			try {
-				ws.close();
-			} catch(e) {
-				console.error('[connect] 关闭旧连接失败:', e);
-			}
-			ws = null;
-		}
-			
-		if ('WebSocket' in window)
-			ws = new WebSocket(wsuri);
-		else {
-			console.log('您的浏览器不支持 websocket,您无法使用本页面的功能!');
-			return;
-		}
-		//收到消息
-		ws.onmessage = function(evt) {
-			console.log("recv msg from websocket server: ", evt.data);
-			var msg = JSON.parse(evt.data);
-			console.log("parsed json data:", msg);
-			var resp_status = msg["status"];
-			switch(resp_status) {
-				case 200:
-					isConnected = true;
-					_cc.callConfig.extnum = msg.object["extnum"];
-					_cc.callConfig.opnum = msg.object["opnum"];
-					_cc.callConfig.groupId = msg.object["groupId"];
-					_cc.callConfig.groups = msg.object["groups"];
-					console.log('ipcc 连接成功.', 'connected_ipcc_server');
-					// WebSocket 连接成功后自动设置为置忙状态,以便可以外呼
-					_cc.setStatus(ccPhoneBarSocket.agentStatusEnum.busy);
-					_cc.notifyAll(ccPhoneBarSocket.eventList.ws_connected, msg);
-					break;
-				default:
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.caller_hangup) ||
-						parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.CONFERENCE_MODERATOR_HANGUP)) {
-						_cc.setCallConnected(false);
-						_cc.setCanSendVideoReInvite(false);
-						_cc.callConfig.agentList = null;
-						_cc.unSubscribeAgentList();
-						// 重置呼叫标志
-						_cc.isCalling = false;
-						console.log("caller_hangup")
-					}
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_hangup)) {
-						// 重置呼叫标志
-						_cc.isCalling = false;
-					}
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_answered)) {
-						_cc.setCallConnected(true);
-						console.log("callee_answered")
-					}
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.new_inbound_call)) {
-						_cc.setCallConnected(true);
-						console.log("new_inbound_call")
-					}
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.caller_answered) ||
-						parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_answered)) {
-						if (msg["object"]["callType"] === "audio") {
-							_cc.setCanSendVideoReInvite(true);
-							_cc.notifyAll(ccPhoneBarSocket.eventList.on_audio_call_connected, "audio call connected.")
-							console.log("current callType is audio.")
-						}
-						if (msg["object"]["callType"] === "video") {
-							_cc.setCanSendVideoReInvite(false);
-							_cc.notifyAll(ccPhoneBarSocket.eventList.on_video_call_connected, "video call connected.")
-							console.log("current callType is video.")
-						}
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_hold)) {
-						_cc.changeUiOnHold();
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_unhold)) {
-						_cc.changeUiOnUnHold();
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_on_hold_hangup)) {
-						_cc.changeUiOnUnHold();
-						$("#holdBtn").removeClass('on');
-						$("#callStatus").text("保持的通话已挂机.");
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_call_wait)) {
-						$("#stopCallWait").show();
-						$("#doConsultationBtn").hide();
-						$("#callStatus").text("客户电话等待中.");
-						_cc.showTransferAreaUI();
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_channel_off_call_wait)) {
-						$("#stopCallWait").hide();
-                        $("#transferCallWait").hide();
-						_cc.hideTransferAreaUI();
-						$("#callStatus").text("等待的电话已接回.");
-					}
-
-                    if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.inner_consultation_start)) {
-                        $("#callStatus").text("咨询已开始.");
-                        $("#transferCallWait").show();
-                    }
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.inner_consultation_stop)) {
-						$("#callStatus").text("咨询已结束.");
-						$("#transferCallWait").hide();
-					}
-
-                    if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.customer_on_call_wait_hangup)) {
-						$("#stopCallWait").hide();
-                        $("#transferCallWait").hide();
-						$("#callStatus").text("等待的客户已挂机.");
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.inner_consultation_start)) {
-						$("#holdBtn").removeClass('on');
-						$("#hangUpBtn").removeClass('on');
-						$("#transferBtn").removeClass('on');
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.transfer_call_success)) {
-						var extNum = msg["object"]["callee"];
-						if(extNum === _cc.getExtNum()) {
-							$("#holdBtn").addClass('on');
-							$("#hangUpBtn").addClass('on');
-							$("#transferBtn").addClass('on');
-						}
-
-					}
-
-					if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.agent_status_data_changed)) {
-						if(_cc.subscribeAgentListStarted) {
-							if (_cc.callConfig.agentList == null) {
-								_cc.callConfig.agentList = JSON.parse(msg.object);
-							}else{
-								// 更新列表;
-                                _cc.updateAgentList(JSON.parse(msg.object));
-							}
-						}
-					}
-					_cc.notifyAll(resp_status, msg);
-					break;
-			}
-		};
-		//关闭连接时触发
-		ws.onclose = function(evt) {
-			isConnected = false;
-			_cc.notifyAll(ccPhoneBarSocket.eventList.ws_disconnected, "ipccserver 连接断开.");
-			console.log("ipcc连接断开.", "disconnected");
-			console.log(evt);
-			ws.close();
-		};
-		ws.onopen = function(evt) {
-			console.log("ipccserver websocket onopen...");
-		};
-	};
-
-	//发送消息给呼叫控制服务器
-	this.sendMsg = function(jsonObject) {
-		console.debug("ws.send:", jsonObject);
-		ws.send(JSON.stringify(jsonObject));
-	};
-
-	this.changeUiOnHold = function() {
-		$("#holdBtnLi").hide();
-		$("#unHoldBtnLi").show();
-		$("#unHoldBtn").addClass('on');
-	};
-
-	this.changeUiOnUnHold = function() {
-		$("#holdBtnLi").show();
-		$("#holdBtn").addClass('on');
-		$("#unHoldBtnLi").hide();
-	};
-
-	this.hideTransferAreaUI = function(){
-		var transferArea = document.getElementById("transfer_area");
-		transferArea.style.display = "none";
-	};
-
-	this.showTransferAreaUI = function(){
-		var transferArea = document.getElementById("transfer_area");
-		transferArea.style.display = "block";
-	};
-
-	/**
-	 *  设置状态为空闲
-	 */
-	this.setStatusFree = function(){
-		this.setStatus(ccPhoneBarSocket.agentStatusEnum.free);
-	};
-
-	/**
-	 *  设置状态为忙碌
-	 */
-	this.setStatusBusy = function(){
-		this.setStatus(ccPhoneBarSocket.agentStatusEnum.busy);
-	};
-
-	ccPhoneBarSocket.utils = {
-
-		/**
-		 * 读取 URL 中的指定查询参数值
-		 * @param {string} paramName - 要获取的参数名称
-		 * @returns {string|null} 返回参数值,如果不存在则返回 null
-		 */
-		getQueryParam :	function (paramName) {
-			const url = window.location.href; // 获取当前页面 URL
-			const params = new URLSearchParams(new URL(url).search); // 创建 URLSearchParams 对象
-			return params.get(paramName); // 获取指定参数值
-		}
-	};
-
-	/**
-	 *  座席状态枚举;
-	 * @type {{rest: number, calling: number, busy: number, free: number, justLogin: number, meeting: number, train: number}}
-	 */
-	ccPhoneBarSocket.agentStatusEnum = {
-
-		/**
-		 *  刚刚上线,尚未就绪中;
-		 */
-		"justLogin" : 1,
-
-		/**
-		 * 空闲
-		 */
-		"free"  :  2,
-
-		/**
-		* 忙碌
-		*/
-		"busy"  :  3,
-
-		/**
-		 * 小休
-		 */
-		"busy_rest"  :  31,
-
-		/**
-		 * 线下会议
-		 */
-		"busy_meeting"  :  32,
-
-		/**
-		 * 培训
-		 */
-		"busy_training"  :  33,
-
-		/**
-		 * 通话中
-		 */
-		"incall" : 4,
-
-		/**
-		 * 话后处理,填写表单中
-		 */
-		"fill_form" : 5,
-
-		/**
-		 * 电话会议中
-		 */
-		"conference"  :  6
-	};
-
-	//定义视频level-id
-	ccPhoneBarSocket.videoLevels = {
-		"Smooth" :  { "levelId" : "42e00b",  "description" : "流畅"  },
-		"Smooth2" :  { "levelId" : "42e00c",  "description" : "流畅+"  },
-		"Smooth3" :  { "levelId" : "42e00d",  "description" : "流畅++"  },
-		"Clear" : { "levelId" : "42e014",  "description" : "清晰"  },
-		"Clear2" :  { "levelId" : "42e015",  "description" : "清晰+"  },
-		"Clear3" :  { "levelId" : "42e016",  "description" : "清晰++"  },
-		"HD" :   { "levelId" : "42e01e",  "description" : "高清"  },
-		"HD2" :  { "levelId" : "42e01f",  "description" : "高清+"  }
-	};
-
-
-	/**
-	 * 系统事件列表;
-	 * @type {{}}
-	 */
-	ccPhoneBarSocket.eventList = {
-		// 当音频通话已建立
-		"on_audio_call_connected" : "100",
-		"on_video_call_connected" : "101",
-
-		// websocketServer连接成功
-		"ws_connected": "200",
-		// 当前用户已在其他设备登录;
-		"user_login_on_other_device" : "201",
-		// 用户下线
-		"ws_disconnected" : "202",
-		// 通话状态发生改变 [监听的数据]
-		"call_session_status_data_changed" : "203",
-        // 坐席状态列表发生改变
-        "agent_status_data_changed" : "205",
-		//请求参数错误
-		"request_args_error" : "400",
-
-		// unauthorized
-		"unauthorized" : "401",
-
-		//服务器内部错误
-		"server_error" : "500",
-		// 语音编码不匹配
-		"server_error_audio_codec_not_match" : "501",
-		// 主叫接通
-		"caller_answered" : "600",
-		//  主叫挂断
-		"caller_hangup" : "601",
-		// 主叫忙; 上一通电话未挂机
-		"caller_busy" : "602",
-		//主叫未登录
-        "caller_not_login" : "603",
-		//主叫应答超时
-		"caller_respond_timeout" : "604",
-		// 被叫接通
-		"callee_answered" : "605",
-        // 被叫挂断
-		"callee_hangup" : "606",
-		//被叫振铃
-        "callee_ringing" : "607",
-		// 座席状态改变
-		"status_changed" : "608",
-		// 一个完整的外呼任务结束: [可能尝试了一个或多个网关]
-		"outbound_finished" : "611",
-
-		// 预测外呼,分配的来电;
-		"PREDICTIVE_CALL_INBOUND" : "612",
-
-         // ACD队列分配的新来电
-		"new_inbound_call" : "613",
-
-         // 当前业务组实时排队人数
-		"acd_group_queue_number" : "615",
-
-
-		/**
-		 * 收到转接的来电请求
-		 */
-		"transfer_call_recv" :  616,
-
-		/**
-		 * 锁定坐席失败
-		 */
-		"lock_agent_fail" :  617,
-
-		/**
-		 * 通话已经转接成功
-		 */
-		"transfer_call_success" :  618,
-
-		/**
-		 * 产生asr语音识别结果
-		 */
-		"asr_result_generate" :  619,
-
-		/**
-		 * ASR语音识别流程结束(坐席侧)
-		 */
-		"asr_process_end_agent" :  620,
-
-		/**
-		 * ASR语音识别流程结束(客户侧)
-		 */
-		"asr_process_end_customer" :  621,
-
-		"asr_process_started" : 622,
-
-		/**
-		 * customer call session hold.
-		 */
-		"customer_channel_hold" : 623,
-
-		/**
-		 * customer call session unHold.
-		 */
-		"customer_channel_unhold" : 624,
-
-		/**
-		 * customer call session on hold is hangup.
-		 */
-		"customer_on_hold_hangup" : 625,
-
-		"inner_consultation_request" : 626,
-
-		/**
-		 * customer call session on call-wait.
-		 */
-		"customer_channel_call_wait" : 627,
-
-		/**
-		 * customer call session off call-wait.
-		 */
-		"customer_channel_off_call_wait" : 628,
-
-		/**
-		 * customer call session on call-wait is hangup.
-		 */
-		"customer_on_call_wait_hangup" : 629,
-
-		/**
-		 *  extension on line event
-		 */
-		"extension_on_line" : 630,
-
-		/**
-		 * extension off line event
-		 */
-		"extension_off_line" : 631,
-
-        /**
-         * Notify the agent that the call consultation has started.
-         */
-        "inner_consultation_start" : 632,
-
-        /**
-         *  Notify the agent that the call consultation has stopped.
-         */
-        "inner_consultation_stop" : 633,
-
-
-	    /**
-		* 多人电话会议,重复的被叫 ,
-		*/
-		"conference_repeat_callee"  :  660 ,
-
-		 /**
-		 * 多人电话会议,呼叫成员超时 ,
-		 */
-		 "CONFERENCE_CALL_MODERATOR_TIMEOUT"  :  661 ,
-
-		/**
-		 * 多人电话会议,成员接通 ,
-		 */
-		"CONFERENCE_MEMBER_ANSWERED"  :  662 ,
-
-
-		/**
-		 * 多人电话会议,成员挂机 ,
-		 */
-		"CONFERENCE_MEMBER_HANGUP"  :  663 ,
-
-		/**
-		 * 多人电话会议,成员禁言成功 ,
-		 */
-		"CONFERENCE_MEMBER_MUTED_SUCCESS"  :  666 ,
-
-
-		/**
-		 * 多人电话会议,成员禁言失败 ,
-		 */
-		"CONFERENCE_MEMBER_MUTED_FAILED"  : 665  ,
-
-		/**
-		 * 多人电话会议,成员解除禁言成功 ,
-		 */
-		"CONFERENCE_MEMBER_UNMUTED_SUCCESS"  :  667 ,
-
-
-		/**
-		 * 多人电话会议,成员解除禁言失败 ,
-		 */
-		"CONFERENCE_MEMBER_UNMUTED_FAILED"  : 668  ,
-
-		/**
-		 * 多人电话会议,会议成员不存在,无法执行相关操作:
-		 */
-		"CONFERENCE_MEMBER_NOT_EXISTS"  : "669"  ,
-
-		/**
-		 * 多人电话会议,主持人重置会议 ,
-		 */
-		"CONFERENCE_MODERATOR_RESET"  : "670"  ,
-
-		/**
-		 * 多人电话会议,主持人接通 ,
-		 */
-		"CONFERENCE_MODERATOR_ANSWERED"  : "671"  ,
-
-
-		/**
-		 * 多人电话会议,主持人挂机,会议结束 ,
-		 */
-		"CONFERENCE_MODERATOR_HANGUP"  : "672",
-
-		/*
-		 * 成员视频禁用成功
-		 */
-		"CONFERENCE_MEMBER_VMUTED_SUCCESS" : "674",
-
-		/*
-		 * 成员解除视频禁用成功
-		 */
-		"CONFERENCE_MEMBER_UnVMUTED_SUCCESS" : "676",
-
-		/**
-		 * 多人电话会议,成员解除视频禁用失败;
-		 */
-		"CONFERENCE_MEMBER_UnVMUTED_FAILED"  : "677",
-
-		/**
-		 * 成功把通话转接到多人视频会议
-		 */
-		"CONFERENCE_TRANSFER_SUCCESS_FROM_EXISTED_CALL"  :  "678",
-
-		/**
-		 *  outbound start event
-		 */
-		"OUTBOUND_START" : "679"
-	};
-
-	this.createIframe = function(src){
-        var _iframe = document.createElement("iframe");
-        _iframe.style.width = '0';
-        _iframe.style.height = '0';
-        _iframe.style.margin = '0';
-        _iframe.style.padding = '0';
-        _iframe.style.overflow = 'hidden';
-        _iframe.style.border = 'none';
-        _iframe.src = src;
-        document.body.appendChild(_iframe);
-        _cc.iframe = _iframe;
-    };
+    /**
+     * 空闲
+     */
+    "free"  :  2,
 
-    this.openSoftPhone = function (){
-		//打开软电话
-		var softPhoneUrl = "http://127.0.0.1:" + _cc.callConfig["localHostProxyPort"] +
-		                   "/autoSetExtension?server=" + encodeURIComponent(_cc.callConfig["fsServer"].split(':')[0]) +
-						   "&port=" + _cc.callConfig["fsServer"].split(':')[1] +
-						   "&extnum=" + _cc.callConfig["extnum"] +
-						   "&pass=" + encodeURIComponent(_cc.callConfig["extPassword"]) +
-						   "&phoneType=" + _cc.callConfig["phoneType"] +
-						   "&version=" + encodeURIComponent(_cc.callConfig["localHostProxyVersion"]) +
-						   "&webPhoneUrl=" + encodeURIComponent(_cc.callConfig["webPhoneUrl"]) +
-						   "";
-	  console.log("softPhoneUrl:", softPhoneUrl);
-      _cc.iframe.src = softPhoneUrl;
-	};
-
-	/**
-	 * 设置座席状态
-	 * @param status  agentStatusEnum
-	 */
-	this.setStatus = function (status) {
-		var cmdInfo = {};
-		cmdInfo.action="setAgentStatus";
-		cmdInfo.body = {"cmd" : "setStatus", "args" : { "status" : status } };
-		ws.send(JSON.stringify(cmdInfo));
-	};
-
-	//注销登录;
-	this.logOff = function () {
-		var cmdInfo = {};
-		cmdInfo.action="setAgentStatus";
-		cmdInfo.body = {"cmd" : "disconnect", "args" : { "cause": "disconnect request from js client." }  };
-		ws.send(JSON.stringify(cmdInfo));
-	};
-
-	/**
-	 *  在咨询失败的情况下使用该按钮,接回处于等待中的电话
-	 */
-	this.stopCallWaitBtnClickUI = function () {
-		var cmd = {};
-		cmd.action="callWait";
-		cmd.body = {"cmd" : "stop", "args" : {} };
-		ws.send(JSON.stringify(cmd));
-	};
+    /**
+     * 忙碌
+     */
+    "busy"  :  3,
 
     /**
-     * 在咨询成功的情况下使用该按钮,把电话转接给专家坐席。
+     * 小休
      */
-	this.transferCallWaitBtnClickUI = function () {
-        this.callControl("transferCallWait", {})
-    };
+    "busy_rest"  :  31,
 
-	this.consultationBtnClickUI = function () {
-        let transferType = "outer";
-        let phoneNumber = $("#externalPhoneNumber").val().trim();
-        if (phoneNumber === "") {
-			transferType = "inner";
-            var groupId = $("#transfer_to_groupIds").val();
-            if ($.trim(groupId) == "") {
-                alert("请选择业务组!");
-                $("#transfer_to_groupIds").focus();
-                return;
-            }
-            var member = $("#transfer_to_member").val();
-            if ($.trim(member) == "") {
-                alert("请选择要咨询的坐席成员!");
-                $("#transfer_to_member").focus();
-                return;
-            }
+    /**
+     * 线下会议
+     */
+    "busy_meeting"  :  32,
 
-            var selectText = $('#transfer_to_member option:selected').text();
-            if (selectText.indexOf("空闲") == -1) {
-                alert("请选择空闲的坐席成员!");
-                $("#transfer_to_member").focus();
-                return;
-            }
+    /**
+     * 培训
+     */
+    "busy_training"  :  33,
 
-            if (member == this.getOpNum()) {
-                alert("不能咨询自己,请选择其他坐席成员!");
-                return;
-            }
-            phoneNumber = member;
-        }
-        this.callControl("consultation", {"to": phoneNumber, "transferType": transferType});
+    /**
+     * 通话中
+     */
+    "incall" : 4,
 
-    };
+    /**
+     * 话后处理,填写表单中
+     */
+    "fill_form" : 5,
 
-	/**
-	 *  处理通话转接按钮点击事件
-	 */
-	this.transferBtnClickUI = function() {
-	    let transferType = "outer";
-	    let phoneNumber = $("#externalPhoneNumber").val().trim();
-        if(phoneNumber === "") {
-            transferType = "inner";
-            var groupId = $("#transfer_to_groupIds").val();
-            if ($.trim(groupId) === "") {
-                alert("请选择转接的业务组!");
-                $("#transfer_to_groupIds").focus();
-                return;
-            }
-            var member = $("#transfer_to_member").val();
-            if ($.trim(member) === "") {
-                alert("请选择转接的坐席成员!");
-                $("#transfer_to_member").focus();
-                return;
-            }
+    /**
+     * 电话会议中
+     */
+    "conference"  :  6
+  };
+
+  //定义视频level-id
+  ccPhoneBarSocket.videoLevels = {
+    "Smooth" :  { "levelId" : "42e00b",  "description" : "流畅"  },
+    "Smooth2" :  { "levelId" : "42e00c",  "description" : "流畅+"  },
+    "Smooth3" :  { "levelId" : "42e00d",  "description" : "流畅++"  },
+    "Clear" : { "levelId" : "42e014",  "description" : "清晰"  },
+    "Clear2" :  { "levelId" : "42e015",  "description" : "清晰+"  },
+    "Clear3" :  { "levelId" : "42e016",  "description" : "清晰++"  },
+    "HD" :   { "levelId" : "42e01e",  "description" : "高清"  },
+    "HD2" :  { "levelId" : "42e01f",  "description" : "高清+"  }
+  };
+
+
+  /**
+   * 系统事件列表;
+   * @type {{}}
+   */
+  ccPhoneBarSocket.eventList = {
+    // 当音频通话已建立
+    "on_audio_call_connected" : "100",
+    "on_video_call_connected" : "101",
+
+    // websocketServer连接成功
+    "ws_connected": "200",
+    // 当前用户已在其他设备登录;
+    "user_login_on_other_device" : "201",
+    // 用户下线
+    "ws_disconnected" : "202",
+    // 通话状态发生改变 [监听的数据]
+    "call_session_status_data_changed" : "203",
+    // 坐席状态列表发生改变
+    "agent_status_data_changed" : "205",
+    //请求参数错误
+    "request_args_error" : "400",
+
+    // unauthorized
+    "unauthorized" : "401",
+
+    //服务器内部错误
+    "server_error" : "500",
+    // 语音编码不匹配
+    "server_error_audio_codec_not_match" : "501",
+    // 主叫接通
+    "caller_answered" : "600",
+    //  主叫挂断
+    "caller_hangup" : "601",
+    // 主叫忙; 上一通电话未挂机
+    "caller_busy" : "602",
+    //主叫未登录
+    "caller_not_login" : "603",
+    //主叫应答超时
+    "caller_respond_timeout" : "604",
+    // 被叫接通
+    "callee_answered" : "605",
+    // 被叫挂断
+    "callee_hangup" : "606",
+    //被叫振铃
+    "callee_ringing" : "607",
+    // 座席状态改变
+    "status_changed" : "608",
+    // 一个完整的外呼任务结束: [可能尝试了一个或多个网关]
+    "outbound_finished" : "611",
+
+    // 预测外呼,分配的来电;
+    "PREDICTIVE_CALL_INBOUND" : "612",
+
+    // ACD队列分配的新来电
+    "new_inbound_call" : "613",
+
+    // 当前业务组实时排队人数
+    "acd_group_queue_number" : "615",
 
-            var selectText = $('#transfer_to_member option:selected').text();
-            if (selectText.indexOf("空闲") === -1) {
-                alert("请选择空闲的坐席成员!");
-                $("#transfer_to_member").focus();
-                return;
-            }
-            if (member === this.getOpNum()) {
-                alert("不能转给自己,请选择其他坐席成员!");
-                return;
-            }
-            phoneNumber = member;
-        }
-        this.transferCall(phoneNumber, transferType);
-	};
-
-	/**
-	 *  处理通话转接
-     *  @param userCodeOrPhone 工号或者电话号码
-     *  @param transferType 转接类型:工号还是外部号码(inner or outer)
-	 */
-	this.transferCall = function(userCodeOrPhone, transferType) {
-	    if(transferType === "inner") {
-            if (userCodeOrPhone !== this.getOpNum()) {
-                this.callControl("transferCall", {"to": userCodeOrPhone, "transferType" : "inner" })
-            } else {
-                console.error("cant not transfer call to yourself.")
-            }
-        }else{
-            this.callControl("transferCall", {"to": userCodeOrPhone, "transferType" : "outer" })
-        }
-	};
-
-	//挂机
-	this.hangup = function() {
-		this.callControl("endSession", {})
-	};
-
-	// 呼叫控制相关操作;
-	this.callControl = function(action, argsObject){
-		var sessionControl = {};
-		sessionControl.action="call";
-		sessionControl.body = {"cmd" : action, "args" : argsObject };
-		ws.send(JSON.stringify(sessionControl));
-	};
-
-	this.checkCallConfirmed = function () {
-		if(!_cc.getIsConnected()){
-			console.log('请先上线.');
-			return false;
-		}
-		if(!_cc.getCallConnected()){
-			console.log('当前没有通话.');
-			return false;
-		}
-		return true;
-	};
-
-	/**
-	 *  send and play mp4 video file.
-	 */
-	this.sendVideoFile = function (mp4FilePath) {
-		if(!_cc.checkCallConfirmed()){
-			return false;
-		}
-		if(typeof(mp4FilePath) == "undefined" || mp4FilePath.trim().length === 0){
-			console.log("Parameter mp4FilePath is missing!")
-			return false;
-		}
-		this.callControl(
-			"playMp4File",
-			{ "mp4FilePath" : mp4FilePath }
-		);
-		return true;
-	};
-
-	/**
-	 *  发起视频通话邀请
-	 */
-	this.reInviteVideoCall = function(){
-        if(!_cc.checkCallConfirmed()){
-        	return false;
-		}
-		if(!_cc.getCanSendVideoReInvite()){
-			console.log('cant not send video reInvite. ',
-				'Precondition is:  Call is connected and  callType is audio.');
-			return false;
-		}
-		this.callControl(
-			"reInviteVideo",
-			{}
-		);
-		return true;
-	};
-
-	/**
-	 *  发起外呼
-	 * @param phoneNumber 被叫号码
-	 * @param callType 通话类型:视频通话、音频通话
-	 * @param videoLevel 视频通话的profile-level-id
-	 */
-	this.call = function(phoneNumber, callType, videoLevel){
-		// 防止重复调用
-		if(_cc.isCalling) {
-			console.log('正在呼叫中,请勿重复操作');
-			return;
-		}
-		
-		if(typeof(videoLevel) == "undefined" || videoLevel.trim().length === 0){
-			videoLevel = ccPhoneBarSocket.videoLevels.HD.levelId;
-			console.log("auto default set videoLevel=", videoLevel);
-		}
-		if(typeof(callType) == "undefined" || callType.trim().length === 0){
-			callType = "audio";
-			console.log("auto default set callType=", callType);
-		}
-
-		console.log("call config videoLevel=" + videoLevel + ", callType=" + callType);
-
-		if(phoneNumber==null || phoneNumber.length===0) {
-			console.log('请输入外呼号码!');
-			return;
-		}
-		if(phoneNumber.trim().length < 3){
-			alert('请输入正确格式的外呼号码!');
-			return;
-		}
-		if(!_cc.getIsConnected()){
-			console.log('请先上线.');
-			return;
-		}
-		let outboundInfo = {
-			"gatewayList": _cc.callConfig.gatewayList,
-			'destPhone': phoneNumber,
-			'gatewayEncrypted' : _cc.callConfig.gatewayEncrypted,
-			'useSameAudioCodeForOutbound' : _cc.callConfig.useSameAudioCodeForOutbound,
-			'callType' :  callType,
-			'videoLevel' : videoLevel
-		};
-		this.callControl(
-			"startSession",
-			outboundInfo
-		);
-		// 设置呼叫标志
-		_cc.isCalling = true;
-	};
-
-	this.callEx = function(phoneNumber){
-		if(phoneNumber == null || phoneNumber.length === 0) {
-			console.log('请输入外呼号码!');
-			return;
-		}
-		if(!_cc.getIsConnected()){
-			_cc.connect();
-			_cc.on(ccPhoneBarSocket.eventList.ws_connected, function(){
-				_cc.off(ccPhoneBarSocket.eventList.ws_connected); //取消事件订阅
-				_cc.call(phoneNumber);
-			});
-			return;
-		}
-		_cc.call(phoneNumber);
-	 };
-
-
-	/************************  以下是网页工具条ui代码   ************************/
-
-	/**
-	 *  根据服务器响应状态码去查找action
-	 * @param code
-	 * @returns {string}
-	 */
-	ccPhoneBarSocket.findItemByCode = function(code){
-		for(var item in ccPhoneBarSocket.eventListWithTextInfo ){
-			if(ccPhoneBarSocket.eventListWithTextInfo[item].code === code){
-				return ccPhoneBarSocket.eventListWithTextInfo[item];
-			}
-		}
-	};
-
-	/**
-	 *  服务器响应状态枚举值;
-	 */
-	  ccPhoneBarSocket.eventListWithTextInfo = {
-		"ws_connected": { "code": 200,  msg:"已签入",
-			btn_text:[{id:"#onLineBtn",name:"签出"}],
-			enabled_btn:['#setFree','#callBtn','#onLineBtn', '#consultationBtn']
-		},
-		"ws_disconnected": { "code" : 202, msg:"服务器连接断开",
-			btn_text:[{id:"#onLineBtn",name:"签入"}],
-			enabled_btn:['#onLineBtn']
-		},
-		"user_login_on_other_device": { "code" : 201, msg:"用户已在其他设备登录",
-			btn_text:[{id:"#onLineBtn",name:"签入"}],
-			enabled_btn:['#onLineBtn']
-		},
-		"request_args_error":{ "code" : 400, msg:"客户端请求参数错误",
-			btn_text:[],
-			enabled_btn:[]
-		},
-		"server_error":{ "code" : 500, msg:"服务器内部错误",
-			btn_text:[],
-			enabled_btn:[]
-		},
-		"caller_answered":{ "code" : 600, msg:"分机已接通",
-			btn_text:[],
-			enabled_btn:['#resetStatus', '#hangUpBtn', '#transferBtn', '#holdBtn', '#consultationBtn']
-		},
-		"caller_hangup":{ "code" : 601, msg:"分机已挂断",
-			btn_text:[],
-			enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn' ]
-		},
-		"caller_busy":{ "code" : 602, msg:"分机忙,上一通电话未挂断",
-			btn_text:[],
-			enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn']
-		},
-		"caller_not_login":{ "code" : 603, msg:"分机未登录,请检查",
-			btn_text:[],
-			enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn']
-		},
-		"caller_respond_timeout":{ "code" : 604, msg:"分机未应答超时,请重新打开分机",
-			btn_text:[],
-			enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn']
-		},
-		"callee_answered":{ "code" : 605, msg:"被叫已接通",
-			btn_text:[],
-			enabled_btn:['#resetStatus', '#hangUpBtn', '#transferBtn', '#holdBtn', '#consultationBtn' ]
-		},
-		"callee_hangup":{ "code" : 606, msg:"通话结束",
-			btn_text:[],
-			enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree' , '#consultationBtn']
-		},
-		"callee_ringing":{ "code" : 607, msg:"被叫振铃中",
-			btn_text:[],
-			enabled_btn:['#resetStatus', '#hangUpBtn', '#transferBtn', '#consultationBtn']
-		},
-		"status_changed":{ "code" : 608, msg:"状态已改变",
-			btn_text:[],
-			enabled_btn:[ ]
-		},
-		"free":{ "code" : 0, msg:"空闲中",
-			btn_text:[],
-			enabled_btn:['#setBusy','#onLineBtn', '#consultationBtn']
-		},
-		"busy":{ "code" : 1, msg:"忙碌",
-			btn_text:[],
-			enabled_btn:['#setFree', '#onLineBtn',  '#callBtn', '#consultationBtn']  //  '#transferBtn'
-		},
-		"customer_channel_hold" : { "code" : 623, msg:"通话已保持.",
-			btn_text:[],
-			enabled_btn:['#setFree',  '#callBtn', '#unHoldBtn', '#consultationBtn' ]
-		},
-	   "customer_channel_unhold" : { "code" : 624, msg:"通话已接回.",
-			  btn_text:[],
-			  enabled_btn:[ '#hangUpBtn', '#holdBtn' ]
-		}
-	};
-
-	ccPhoneBarSocket.phone_buttons = ['#setFree', '#setBusy', '#callBtn','#hangUpBtn' , '#resetStatus' ,'#onLineBtn', '#transferBtn', '#holdBtn', '#unHoldBtn', '#consultationBtn'];
-
-	// 更新状态显示
-	this.updatePhoneBar = function (msg, status_key) {
-		if(!_cc.callConfig.useDefaultUi){
-			console.log("callConfig.useDefaultUi = false , 已禁用默认ui工具条按钮.");
-			return;
-		}
-
-		if (msg) {
-			$("#callStatus").text(msg.msg);
-		}
-		var status_info = ccPhoneBarSocket.findItemByCode(status_key);
-		if (!status_info) {
-			return;
-		}
-
-		if(status_info.code === ccPhoneBarSocket.eventListWithTextInfo.status_changed.code){
-			if(msg.object.status === ccPhoneBarSocket.agentStatusEnum.free){
-				status_info = ccPhoneBarSocket.eventListWithTextInfo.free;
-			}else{
-				status_info = ccPhoneBarSocket.eventListWithTextInfo.busy;
-			}
-		}
-		// 判断当前是否为状态改变的事件;
-		// 显示预设的消息;
-		var msgSet = status_info.msg;
-
-		if(msgSet && msgSet.length > 0){
-			$("#callStatus").text(msgSet);
-		}
-
-		var btn_text = status_info.btn_text;
-		var enabled_btn = status_info.enabled_btn;
-		if (btn_text) {
-			$.each(btn_text, function (i, d) {
-				$(d.id).next().text(d.name);
-			});
-		}
-
-		if (enabled_btn.length === 0) {
-			return;
-		}
-
-		var all_btn = ccPhoneBarSocket.phone_buttons;
-		for (var i in all_btn) {
-			var idx = $.inArray(all_btn[i], enabled_btn);
-			if (idx < 0) {
-				$(all_btn[i]).removeClass('on');
-			} else {
-				$(enabled_btn[idx]).addClass('on');
-			}
-		}
-	};
-
-	/**
-	 *  初始化电话工具条ui按钮;
-	 */
-	this.initPhoneBarUI = function () {
-
-		window.onbeforeunload = function () {
-			if (!confirm('关闭网页将导致您无法接听电话,确定要关闭吗 ?')) return false;
-		};
-
-		$("#unHoldBtnLi").hide();
-
-		if(!_cc.callConfig.useDefaultUi){
-			console.log("callConfig.useDefaultUi = false , 已禁用默认ui工具条按钮.");
-			return;
-		}
-
-        $('#conferenceBtn').on('click', function () {
-                if(!_cc.getIsConnected()){
-                    console.log('请先上线.');
-                    return;
-                }
-                var confObjId = document.getElementById("conference_area");
-                if(confObjId.style.display === "block"){
-					confObjId.style.display = "none";
-				}else{
-					confObjId.style.display = "block";
-				}
-
-        });
-
-		$('#callBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				var destPhone = $.trim($("#ccphoneNumber").val());
-				var videoLevel = document.getElementById("videoLevelSelect").value;
-				var callType = document.forms[0].callType.value;
-				_cc.call(destPhone, callType,  videoLevel);
-			}
-		});
-		$('#setFree').on('click', function () {
-			if ($(this).hasClass('on')) {
-				_cc.setStatus(ccPhoneBarSocket.agentStatusEnum.free);
-			}
-		});
-		$('#setBusy').on('click', function () {
-			if ($(this).hasClass('on')) {
-				_cc.setStatus(ccPhoneBarSocket.agentStatusEnum.busy);
-			}
-		});
-
-		$('#setBusySubList').on('change', function () {
-			 let itemValue = $('#setBusySubList').val();
-			 console.log('set busy subStatus', itemValue);
-			 _cc.setStatus(itemValue);
-		});
-
-		$('#hangUpBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				_cc.hangup();
-			}
-		});
-
-		$('#holdBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				_cc.holdCall();
-			}
-		});
-
-		$('#unHoldBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				_cc.unHoldCall();
-			}
-		});
-
-		$("#doTransferBtn").hide();
-		
-		/**
-		 * 填充业务组选项
-		 * 注意:该函数仅用于原始 HTML 版本,Vue + Element UI 版本中由 Vue 组件自行处理
-		 */
-		function populateGroupIdOptions() {
-			var groups = _cc.callConfig.groups;
-			if (groups) {
-				var selectObj = document.getElementById("transfer_to_groupIds");
-				if (selectObj) {
-					// 检查是否为原生 select 元素
-					if (selectObj.tagName.toLowerCase() === 'select') {
-						// 清空现有选项(保留第一个"请选择")
-						var firstOption = selectObj.options[0];
-						selectObj.innerHTML = '';
-						selectObj.add(firstOption);
-						
-						// 添加业务组选项
-						for (var i = 0; i < groups.length; i++) {
-							var group = groups[i];
-							var option = document.createElement("option");
-							option.value = group.groupId;
-							option.text = group.bizGroupName;
-							selectObj.add(option);
-						}
-						
-						// 默认选中第一个
-						if (groups.length > 0 && selectObj.options.length > 1) {
-							selectObj.selectedIndex = 1;
-						}
-					}
-					// 如果是 el-select 组件,则不处理,由 Vue 数据绑定自动更新
-				}
-			}
-		}
-		
-		$('#transferBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				if(!_cc.getIsConnected()){
-					console.log('请先上线.');
-					return;
-				}
-				var transferArea = document.getElementById("transfer_area");
-				if(transferArea.style.display === "block"){
-					transferArea.style.display = "none";
-					_cc.unSubscribeAgentList();
-					$("#doTransferBtn").hide();
-					$("#doConsultationBtn").hide();
-				}else{
-					transferArea.style.display = "block";
-					populateGroupIdOptions();
-					// 不再自动订阅坐席状态列表,由外部控制
-					// _cc.subscribeAgentList();
-					$("#doTransferBtn").show();
-					$("#doConsultationBtn").hide();
-				}
-			}
-		});
-
-        $("#stopCallWait").hide();
-        $("#transferCallWait").hide();
-		$("#doConsultationBtn").hide();
-		$('#consultationBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				if(!_cc.getIsConnected()){
-					console.log('请先上线.');
-					return;
-				}
-				var transferArea = document.getElementById("transfer_area");
-				if(transferArea.style.display === "block"){
-					transferArea.style.display = "none";
-					_cc.unSubscribeAgentList();
-					$("#doConsultationBtn").hide();
-					$("#doTransferBtn").hide();
-				}else{
-					transferArea.style.display = "block";
-					populateGroupIdOptions();
-					// 不再自动订阅坐席状态列表,由外部控制
-					// _cc.subscribeAgentList();
-					$("#doConsultationBtn").show();
-					$("#doTransferBtn").hide();
-				}
-			}
-		});
-
-		$('#onLineBtn').on('click', function () {
-			if ($(this).hasClass('on')) {
-				if (_cc.getIsConnected()) {
-					_cc.disconnect();
-				} else {
-					_cc.connect();
-				}
-			}else {
-				alert('当前不允许签出!');
-			}
-		});
-
-		$('#resetStatus').on('click', function () {
-			window.onbeforeunload = null;
-			location.reload();
-		});
-
-		//拨号文本框;收到键盘回车事件之后立即拨号
-		$("#ccphoneNumber").keydown(function (e) {
-			var curKey = e.which;
-			if (curKey === 13) {
-				var destPhone = $.trim($("#ccphoneNumber").val());
-				var videoLevel = document.getElementById("videoLevelSelect").value;
-				var callType = document.forms[0].callType.value;
-				_cc.call(destPhone,callType, videoLevel);
-				return false;
-			}
-		});
-
-		//ESC按键挂机功能支持
-		$(document).keyup(function (e) {
-			var key = e.which;
-			if (key === 27) {
-				console.log('按下了ESC键, 即将发送挂机指令.');
-				if(_cc.getIsConnected()){
-					if(_cc.callConfig["useDefaultUi"]) {
-						if ($('#hangUpBtn').hasClass('on')) {
-							_cc.hangup();
-						}
-					}else{
-						_cc.hangup();
-					}
-				}
-			}
-		});
-	};
-
-	/**
-	 *  保持通话
-	 */
-	this.holdCall = function(){
-		var cmd = {};
-		cmd.action="callHold";
-		cmd.body = {"cmd" : "hold", "args" : {} };
-		ws.send(JSON.stringify(cmd));
-	};
-
-	/**
-	 *  接回保持的通话
-	 */
-	this.unHoldCall = function(){
-		var cmd = {};
-		cmd.action="callHold";
-		cmd.body = {"cmd" : "unhold", "args" : {} };
-		ws.send(JSON.stringify(cmd));
-	};
-
-	/**
-	 *  订阅坐席状态列表
-	 */
-	this.subscribeAgentList = function(){
-		var cmd = {};
-		cmd.action="pollAgentList";
-		cmd.body = {"cmd" : "subscribe", "args" : {} };
-		ws.send(JSON.stringify(cmd));
-		_cc.subscribeAgentListStarted = true;
-	};
-
-	/**
-	 *  取消订阅坐席状态列表
-	 */
-	this.unSubscribeAgentList = function(){
-		if(_cc.subscribeAgentListStarted) {
-			_cc.subscribeAgentListStarted = false;
-			_cc.callConfig.agentList = null;
-			var cmd = {};
-			cmd.action = "pollAgentList";
-			cmd.body = {"cmd": "unSubscribe", "args": {}};
-			ws.send(JSON.stringify(cmd));
-		}
-	};
-
-	/*************************  以下是电话会议相关  ***************************/
-
-	/**
-	 *  启动会议; 仅限使用默认UI场景下使用;
-	 */
-	this.conferenceStartBtnUI = function(customerName){
-		var callType = document.getElementById("conf_call_type").value;
-		var confTemplate = document.getElementById("conf_template").value;
-		var layOut = document.getElementById("conf_layout").value;
-
-		_cc.setStatusBusy();
-
-		// 禁用外呼按钮
-		$("#callBtn").removeClass('on');
-
-		// 禁用置闲按钮
-		$("#setFree").removeClass('on');
-
-		// 禁用签出按钮
-		$("#onLineBtn").removeClass('on');
-
-		document.getElementById("startConference").setAttribute("disabled", "true");
-
-		if(_cc.getCallConnected()) {
-			let tips = "是否把当前通话转换为会议 ?";
-			console.log(tips);
-			if(confirm(tips)) {
-				_cc.transferToConference(layOut, confTemplate, callType, customerName);
-			}else{
-				document.getElementById("startConference").removeAttribute("disabled");
-			}
-		}else {
-			_cc.conferenceStart(layOut, confTemplate, callType);
-		}
-	};
-
-	/**
-	 *  添加会议成员; 仅限使用默认UI场景下使用;
-	 */
-	this.conferenceAddMemberBtnUI = function (reInvite, memberPhoneParam,  memberNameParam) {
-		var memberName = "";
-		var memberPhone = "";
-		var memberCallType = $.trim(document.getElementById("member_call_type").value);
-		var memberVideoLevel = $.trim(document.getElementById("member_video_level").value);
-
-		if(reInvite === 0) {
-			memberName = $("#member_name").val();
-			memberPhone = $("#member_phone").val();
-			if (memberName.length === 0 || $.trim(memberName) === "") {
-				alert('请填写参会者姓名!');
-				return;
-			}
-			if (memberPhone.length === 0 || $.trim(memberPhone) === "") {
-				alert('请填写参会者手机号!');
-				return;
-			}
-
-			memberName = $.trim(memberName);
-			memberPhone = $.trim(memberPhone);
-			// 使用会员成员html模版添加新成员
-			var templateObj = document.getElementById("conf_member_template");
-
-			var existMember = document.getElementById("conf_member_" + memberPhone) != null;
-			if (existMember) {
-				alert('会议成员已经存在,请不要重复添加!');
-				return;
-			}
-
-			var memberHtmlItem = templateObj.innerHTML;
-			memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_name}", "gm"), memberName);
-			memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_phone}", "gm"), memberPhone);
-			memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_status}", "gm"), "即将呼叫");
-
-			var li = document.createElement("li");
-			li.setAttribute("id", "conf_member_" + memberPhone);
-			li.setAttribute("class", "conf_member_item_row");
-			li.innerHTML = memberHtmlItem;
-
-			_cc.insertAfter(li, templateObj);
-
-			$("#member_name").val('');
-			$("#member_phone").val('');
-		}else{
-			memberName = memberNameParam;
-			memberPhone = memberPhoneParam;
-		}
-
-		// 隐藏 mute及 vmute按钮
-		var memberItemId = "#conf_member_" + memberPhone;
-		$(".conf_mute", $(memberItemId)).find("img").hide();
-		$(".conf_vmute", $(memberItemId)).find("img").hide();
-		$(".conf_re_invite", $(memberItemId)).hide();
-		$(".conf_status", $(memberItemId)).html("即将呼叫");
-
-		_cc.conferenceAddMembers( [
-			{"name": memberName, "phone": memberPhone, "callType" : memberCallType,  "videoLevel": memberVideoLevel}
-		]);
-	};
-
-	/**
-	 *  从现有通话添加会议成员;
-	 */
-	this.conferenceAddMemberFromExistCall = function (memberName, memberPhone) {
-		if (memberName.length === 0 || $.trim(memberName) === "") {
-			alert('请填写参会者姓名!');
-			return;
-		}
-		if (memberPhone.length === 0 || $.trim(memberPhone) === "") {
-			alert('请填写参会者手机号!');
-			return;
-		}
-		memberName = $.trim(memberName);
-		memberPhone = $.trim(memberPhone);
-
-		// 使用html模版添加新成员
-		var templateObj = document.getElementById("conf_member_template");
-		var existMember = document.getElementById("conf_member_" + memberPhone) != null;
-		if (existMember) {
-			alert('会议成员已经存在,请不要重复添加!');
-			return;
-		}
-
-		var memberHtmlItem = templateObj.innerHTML;
-		memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_name}", "gm"), memberName);
-		memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_phone}", "gm"), memberPhone);
-		memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_status}", "gm"), "即将呼叫");
-		var li = document.createElement("li");
-		li.setAttribute("id", "conf_member_" + memberPhone);
-		li.setAttribute("class", "conf_member_item_row");
-		li.innerHTML = memberHtmlItem;
-		_cc.insertAfter(li, templateObj);
-
-		// 隐藏 mute及 vmute按钮
-		var memberItemId = "#conf_member_" + memberPhone;
-		$(".conf_mute", $(memberItemId)).find("img").show();
-		$(".conf_vmute", $(memberItemId)).find("img").show();
-		$(".conf_re_invite", $(memberItemId)).hide();
-		$(".conf_status", $(memberItemId)).html("通话中").css("color", "green");
-	};
-
-	/**
-	 *  通话转为会议
-	 * @param layOut
-	 * @param confTemplate
-	 * @param callType
-	 * @param customerName
-	 */
-	this.transferToConference = function (layOut, confTemplate, callType, customerName) {
-		console.log("try to transferToConference: ", layOut, confTemplate, callType, customerName);
-		_cc.callControl(
-			"transferToConference",
-			{
-				"layOut": layOut,
-				'callType': callType,
-				'confTemplate': confTemplate,
-				'customerName' : customerName
-			}
-		);
-	};
-
-
-	/**
-	 *  主持人启动电话会议
-	 * @param layOut 会议布局
-	 * @param confTemplate 会议模版
-	 * @param callType 会议类型
-	 */
-	this.conferenceStart = function(layOut, confTemplate, callType) {
-		console.log("正常发起多方通话");
-		var cmd = {};
-		cmd.action = "conference";
-		cmd.body = {"method": "startconf", "args": {
-				"layOut": layOut,
-				'callType': callType,
-				'confTemplate': confTemplate
-			}};
-		ws.send(JSON.stringify(cmd));
-	};
-
-
-	/**
-	 *  VMute会议成员(不显示视频);
-	 **/
-	this.conferenceVMuteMember = function(members) {
-		// single phone
-		if(typeof(members) === "string") {
-			this.conferenceControl("vmute",
-				[
-					{"phone": members}
-				]
-			);
-		}else{
-			// multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
-			this.conferenceControl("vmute", members);
-		}
-	};
-
-
-	/**
-	 *  UnVMute会议成员(显示视频);
-	 **/
-	this.conferenceUnVMuteMember = function(members) {
-		// single phone
-		if(typeof(members) === "string") {
-			this.conferenceControl("unvmute",
-				[
-					{"phone": members}
-				]
-			);
-		}else{
-			// multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
-			this.conferenceControl("unvmute", members);
-		}
-	};
-
-	/**
-	 *  禁言会议成员
-	 **/
-	this.conferenceMuteMember = function(members) {
-		// single phone
-		if(typeof(members) === "string") {
-			this.conferenceControl("mute",
-				[
-					{"phone": members}
-				]
-			);
-		}else{
-			// multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
-			this.conferenceControl("mute", members);
-		}
-	};
-
-	/**
-	 *  解禁会议成员
-	 **/
-	this.conferenceUnMuteMember = function(members) {
-		// single phone
-		if(typeof(members) === "string") {
-			this.conferenceControl("unmute",
-				[
-					{"phone": members}
-				]
-			);
-		}else{
-			// multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
-			this.conferenceControl("unmute", members);
-		}
-	};
-
-	/**
-	 *  增加会议成员
-	 **/
-	this.conferenceAddMembers = function(members) {
-		this.conferenceControl("add", members)
-	};
-
-
-	/**
-	 *  移除会议成员
-	 **/
-	this.conferenceRemoveMembers = function(members) {
-		// single phone
-		if(typeof(members) === "string") {
-			var memberItemObj = $("#conf_member_" + members);
-			if($(".conf_status", memberItemObj).text() === "通话中") {
-				this.conferenceControl("remove",
-					[
-						{"phone": members}
-					]
-				);
-			}
-			memberItemObj.remove();
-		}else{
-			// multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
-			this.conferenceControl("remove", members);
-		}
-	};
-
-	/**
-	 *  结束电话会议
-	 **/
-	this.conferenceEnd = function() {
-		this.conferenceControl("endconf", [])
-	};
-
-
-	/**
-	 *  电话会议控制相关操作
-	 * @param action 操作
-	 * @param phoneList 会议成员
-	 */
-	this.conferenceControl = function (action, phoneList) {
-		var cmd = {};
-		cmd.action = "conference";
-		cmd.body = { "method": action, "memberList": phoneList };
-		ws.send(JSON.stringify(cmd));
-	};
-
-    /*************************  以下是通话监听相关  ***************************/
 
     /**
-     *   拉取监听的通话列表
+     * 收到转接的来电请求
      */
-    this.callMonitorDataPull = function (){
-        var cmd = {};
-        cmd.action = "monitorData";
-        cmd.body = {};
-        ws.send(JSON.stringify(cmd));
-    };
+    "transfer_call_recv" :  616,
 
-	/**
-	 *   拉取排队中的电话列表
-	 */
-	this.inboundCallQueuePull = function (){
-		var cmd = {};
-		cmd.action = "inboundMonitorData";
-		cmd.body = {};
-		ws.send(JSON.stringify(cmd));
-	};
-
-    // 构造通话监听参数
-    this.monitorControl = function(action, argsObject){
-        var sessionControl = {};
-        sessionControl.action="callMonitor";
-        sessionControl.body = {"cmd" : action, "args" : argsObject };
-        ws.send(JSON.stringify(sessionControl));
-    };
+    /**
+     * 锁定坐席失败
+     */
+    "lock_agent_fail" :  617,
 
     /**
-     * 通话监听
-     * @param { 通话id } callId
-     * @returns
+     * 通话已经转接成功
      */
-    this.callMonitorStart = function(callId){
-        if(callId == null || callId.length === 0) {
-            console.log('请提供待监听电话的 callId !');
-            return;
-        }
+    "transfer_call_success" :  618,
 
-        if(!_cc.getIsConnected()){
-            console.log('请先上线.');
-            return;
-        }
+    /**
+     * 产生asr语音识别结果
+     */
+    "asr_result_generate" :  619,
 
-        this.monitorControl(
-            "startMonitoring",
-            {
-                'callSpyId': callId
-            }
-        );
+    /**
+     * ASR语音识别流程结束(坐席侧)
+     */
+    "asr_process_end_agent" :  620,
+
+    /**
+     * ASR语音识别流程结束(客户侧)
+     */
+    "asr_process_end_customer" :  621,
+
+    "asr_process_started" : 622,
+
+    /**
+     * customer call session hold.
+     */
+    "customer_channel_hold" : 623,
+
+    /**
+     * customer call session unHold.
+     */
+    "customer_channel_unhold" : 624,
+
+    /**
+     * customer call session on hold is hangup.
+     */
+    "customer_on_hold_hangup" : 625,
+
+    "inner_consultation_request" : 626,
+
+    /**
+     * customer call session on call-wait.
+     */
+    "customer_channel_call_wait" : 627,
+
+    /**
+     * customer call session off call-wait.
+     */
+    "customer_channel_off_call_wait" : 628,
+
+    /**
+     * customer call session on call-wait is hangup.
+     */
+    "customer_on_call_wait_hangup" : 629,
+
+    /**
+     *  extension on line event
+     */
+    "extension_on_line" : 630,
+
+    /**
+     * extension off line event
+     */
+    "extension_off_line" : 631,
+
+    /**
+     * Notify the agent that the call consultation has started.
+     */
+    "inner_consultation_start" : 632,
+
+    /**
+     *  Notify the agent that the call consultation has stopped.
+     */
+    "inner_consultation_stop" : 633,
+
+
+    /**
+     * 多人电话会议,重复的被叫 ,
+     */
+    "conference_repeat_callee"  :  660 ,
+
+    /**
+     * 多人电话会议,呼叫成员超时 ,
+     */
+    "CONFERENCE_CALL_MODERATOR_TIMEOUT"  :  661 ,
+
+    /**
+     * 多人电话会议,成员接通 ,
+     */
+    "CONFERENCE_MEMBER_ANSWERED"  :  662 ,
+
+
+    /**
+     * 多人电话会议,成员挂机 ,
+     */
+    "CONFERENCE_MEMBER_HANGUP"  :  663 ,
+
+    /**
+     * 多人电话会议,成员禁言成功 ,
+     */
+    "CONFERENCE_MEMBER_MUTED_SUCCESS"  :  666 ,
+
+
+    /**
+     * 多人电话会议,成员禁言失败 ,
+     */
+    "CONFERENCE_MEMBER_MUTED_FAILED"  : 665  ,
+
+    /**
+     * 多人电话会议,成员解除禁言成功 ,
+     */
+    "CONFERENCE_MEMBER_UNMUTED_SUCCESS"  :  667 ,
+
+
+    /**
+     * 多人电话会议,成员解除禁言失败 ,
+     */
+    "CONFERENCE_MEMBER_UNMUTED_FAILED"  : 668  ,
+
+    /**
+     * 多人电话会议,会议成员不存在,无法执行相关操作:
+     */
+    "CONFERENCE_MEMBER_NOT_EXISTS"  : "669"  ,
+
+    /**
+     * 多人电话会议,主持人重置会议 ,
+     */
+    "CONFERENCE_MODERATOR_RESET"  : "670"  ,
+
+    /**
+     * 多人电话会议,主持人接通 ,
+     */
+    "CONFERENCE_MODERATOR_ANSWERED"  : "671"  ,
+
+
+    /**
+     * 多人电话会议,主持人挂机,会议结束 ,
+     */
+    "CONFERENCE_MODERATOR_HANGUP"  : "672",
+
+    /*
+     * 成员视频禁用成功
+     */
+    "CONFERENCE_MEMBER_VMUTED_SUCCESS" : "674",
+
+    /*
+     * 成员解除视频禁用成功
+     */
+    "CONFERENCE_MEMBER_UnVMUTED_SUCCESS" : "676",
+
+    /**
+     * 多人电话会议,成员解除视频禁用失败;
+     */
+    "CONFERENCE_MEMBER_UnVMUTED_FAILED"  : "677",
+
+    /**
+     * 成功把通话转接到多人视频会议
+     */
+    "CONFERENCE_TRANSFER_SUCCESS_FROM_EXISTED_CALL"  :  "678",
+
+    /**
+     *  outbound start event
+     */
+    "OUTBOUND_START" : "679"
+  };
+
+  this.createIframe = function(src){
+    var _iframe = document.createElement("iframe");
+    _iframe.style.width = '0';
+    _iframe.style.height = '0';
+    _iframe.style.margin = '0';
+    _iframe.style.padding = '0';
+    _iframe.style.overflow = 'hidden';
+    _iframe.style.border = 'none';
+    _iframe.src = src;
+    document.body.appendChild(_iframe);
+    _cc.iframe = _iframe;
+  };
+
+  this.openSoftPhone = function (){
+    //打开软电话
+    var softPhoneUrl = "http://127.0.0.1:" + _cc.callConfig["localHostProxyPort"] +
+      "/autoSetExtension?server=" + encodeURIComponent(_cc.callConfig["fsServer"].split(':')[0]) +
+      "&port=" + _cc.callConfig["fsServer"].split(':')[1] +
+      "&extnum=" + _cc.callConfig["extnum"] +
+      "&pass=" + encodeURIComponent(_cc.callConfig["extPassword"]) +
+      "&phoneType=" + _cc.callConfig["phoneType"] +
+      "&version=" + encodeURIComponent(_cc.callConfig["localHostProxyVersion"]) +
+      "&webPhoneUrl=" + encodeURIComponent(_cc.callConfig["webPhoneUrl"]) +
+      "";
+    console.log("softPhoneUrl:", softPhoneUrl);
+    _cc.iframe.src = softPhoneUrl;
+  };
+
+  /**
+   * 设置座席状态
+   * @param status  agentStatusEnum
+   */
+  this.setStatus = function (status) {
+    var cmdInfo = {};
+    cmdInfo.action="setAgentStatus";
+    cmdInfo.body = {"cmd" : "setStatus", "args" : { "status" : status } };
+    ws.send(JSON.stringify(cmdInfo));
+  };
+
+  //注销登录;
+  this.logOff = function () {
+    var cmdInfo = {};
+    cmdInfo.action="setAgentStatus";
+    cmdInfo.body = {"cmd" : "disconnect", "args" : { "cause": "disconnect request from js client." }  };
+    ws.send(JSON.stringify(cmdInfo));
+  };
+
+  /**
+   *  在咨询失败的情况下使用该按钮,接回处于等待中的电话
+   */
+  this.stopCallWaitBtnClickUI = function () {
+    var cmd = {};
+    cmd.action="callWait";
+    cmd.body = {"cmd" : "stop", "args" : {} };
+    ws.send(JSON.stringify(cmd));
+  };
+
+  /**
+   * 在咨询成功的情况下使用该按钮,把电话转接给专家坐席。
+   */
+  this.transferCallWaitBtnClickUI = function () {
+    this.callControl("transferCallWait", {})
+  };
+
+  this.consultationBtnClickUI = function () {
+    let transferType = "outer";
+    let phoneNumber = $("#externalPhoneNumber").val().trim();
+    if (phoneNumber === "") {
+      transferType = "inner";
+      var groupId = $("#transfer_to_groupIds").val();
+      if ($.trim(groupId) == "") {
+        alert("请选择业务组!");
+        $("#transfer_to_groupIds").focus();
+        return;
+      }
+      var member = $("#transfer_to_member").val();
+      if ($.trim(member) == "") {
+        alert("请选择要咨询的坐席成员!");
+        $("#transfer_to_member").focus();
+        return;
+      }
+
+      var selectText = $('#transfer_to_member option:selected').text();
+      if (selectText.indexOf("空闲") == -1) {
+        alert("请选择空闲的坐席成员!");
+        $("#transfer_to_member").focus();
+        return;
+      }
+
+      if (member == this.getOpNum()) {
+        alert("不能咨询自己,请选择其他坐席成员!");
+        return;
+      }
+      phoneNumber = member;
+    }
+    this.callControl("consultation", {"to": phoneNumber, "transferType": transferType});
+
+  };
+
+  /**
+   *  处理通话转接按钮点击事件
+   */
+  this.transferBtnClickUI = function() {
+    let transferType = "outer";
+    let phoneNumber = $("#externalPhoneNumber").val().trim();
+    if(phoneNumber === "") {
+      transferType = "inner";
+      var groupId = $("#transfer_to_groupIds").val();
+      if ($.trim(groupId) === "") {
+        alert("请选择转接的业务组!");
+        $("#transfer_to_groupIds").focus();
+        return;
+      }
+      var member = $("#transfer_to_member").val();
+      if ($.trim(member) === "") {
+        alert("请选择转接的坐席成员!");
+        $("#transfer_to_member").focus();
+        return;
+      }
+
+      var selectText = $('#transfer_to_member option:selected').text();
+      if (selectText.indexOf("空闲") === -1) {
+        alert("请选择空闲的坐席成员!");
+        $("#transfer_to_member").focus();
+        return;
+      }
+      if (member === this.getOpNum()) {
+        alert("不能转给自己,请选择其他坐席成员!");
+        return;
+      }
+      phoneNumber = member;
+    }
+    this.transferCall(phoneNumber, transferType);
+  };
+
+  /**
+   *  处理通话转接
+   *  @param userCodeOrPhone 工号或者电话号码
+   *  @param transferType 转接类型:工号还是外部号码(inner or outer)
+   */
+  this.transferCall = function(userCodeOrPhone, transferType) {
+    if(transferType === "inner") {
+      if (userCodeOrPhone !== this.getOpNum()) {
+        this.callControl("transferCall", {"to": userCodeOrPhone, "transferType" : "inner" })
+      } else {
+        console.error("cant not transfer call to yourself.")
+      }
+    }else{
+      this.callControl("transferCall", {"to": userCodeOrPhone, "transferType" : "outer" })
+    }
+  };
+
+  //挂机
+  this.hangup = function() {
+    this.callControl("endSession", {})
+  };
+
+  // 呼叫控制相关操作;
+  this.callControl = function(action, argsObject){
+    var sessionControl = {};
+    sessionControl.action="call";
+    sessionControl.body = {"cmd" : action, "args" : argsObject };
+    ws.send(JSON.stringify(sessionControl));
+  };
+
+  this.checkCallConfirmed = function () {
+    if(!_cc.getIsConnected()){
+      console.log('请先上线.');
+      return false;
+    }
+    if(!_cc.getCallConnected()){
+      console.log('当前没有通话.');
+      return false;
+    }
+    return true;
+  };
+
+  /**
+   *  send and play mp4 video file.
+   */
+  this.sendVideoFile = function (mp4FilePath) {
+    if(!_cc.checkCallConfirmed()){
+      return false;
+    }
+    if(typeof(mp4FilePath) == "undefined" || mp4FilePath.trim().length === 0){
+      console.log("Parameter mp4FilePath is missing!")
+      return false;
+    }
+    this.callControl(
+      "playMp4File",
+      { "mp4FilePath" : mp4FilePath }
+    );
+    return true;
+  };
+
+  /**
+   *  发起视频通话邀请
+   */
+  this.reInviteVideoCall = function(){
+    if(!_cc.checkCallConfirmed()){
+      return false;
+    }
+    if(!_cc.getCanSendVideoReInvite()){
+      console.log('cant not send video reInvite. ',
+        'Precondition is:  Call is connected and  callType is audio.');
+      return false;
+    }
+    this.callControl(
+      "reInviteVideo",
+      {}
+    );
+    return true;
+  };
+
+  /**
+   *  发起外呼
+   * @param phoneNumber 被叫号码
+   * @param callType 通话类型:视频通话、音频通话
+   * @param videoLevel 视频通话的profile-level-id
+   */
+  this.call = function(phoneNumber, callType, videoLevel){
+    // 防止重复调用
+    if(_cc.isCalling) {
+      console.log('正在呼叫中,请勿重复操作');
+      return;
+    }
+
+    if(typeof(videoLevel) == "undefined" || videoLevel.trim().length === 0){
+      videoLevel = ccPhoneBarSocket.videoLevels.HD.levelId;
+      console.log("auto default set videoLevel=", videoLevel);
+    }
+    if(typeof(callType) == "undefined" || callType.trim().length === 0){
+      callType = "audio";
+      console.log("auto default set callType=", callType);
+    }
+
+    console.log("call config videoLevel=" + videoLevel + ", callType=" + callType);
+
+    if(phoneNumber==null || phoneNumber.length===0) {
+      console.log('请输入外呼号码!');
+      return;
+    }
+    if(phoneNumber.trim().length < 3){
+      alert('请输入正确格式的外呼号码!');
+      return;
+    }
+    if(!_cc.getIsConnected()){
+      console.log('请先上线.');
+      return;
+    }
+    let outboundInfo = {
+      "gatewayList": _cc.callConfig.gatewayList,
+      'destPhone': phoneNumber,
+      'gatewayEncrypted' : _cc.callConfig.gatewayEncrypted,
+      'useSameAudioCodeForOutbound' : _cc.callConfig.useSameAudioCodeForOutbound,
+      'callType' :  callType,
+      'videoLevel' : videoLevel
+    };
+    this.callControl(
+      "startSession",
+      outboundInfo
+    );
+    // 设置呼叫标志
+    _cc.isCalling = true;
+  };
+
+  this.callEx = function(phoneNumber){
+    if(phoneNumber == null || phoneNumber.length === 0) {
+      console.log('请输入外呼号码!');
+      return;
+    }
+    if(!_cc.getIsConnected()){
+      _cc.connect();
+      _cc.on(ccPhoneBarSocket.eventList.ws_connected, function(){
+        _cc.off(ccPhoneBarSocket.eventList.ws_connected); //取消事件订阅
+        _cc.call(phoneNumber);
+      });
+      return;
+    }
+    _cc.call(phoneNumber);
+  };
+
+
+  /************************  以下是网页工具条ui代码   ************************/
+
+  /**
+   *  根据服务器响应状态码去查找action
+   * @param code
+   * @returns {string}
+   */
+  ccPhoneBarSocket.findItemByCode = function(code){
+    for(var item in ccPhoneBarSocket.eventListWithTextInfo ){
+      if(ccPhoneBarSocket.eventListWithTextInfo[item].code === code){
+        return ccPhoneBarSocket.eventListWithTextInfo[item];
+      }
+    }
+  };
+
+  /**
+   *  服务器响应状态枚举值;
+   */
+  ccPhoneBarSocket.eventListWithTextInfo = {
+    "ws_connected": { "code": 200,  msg:"已签入",
+      btn_text:[{id:"#onLineBtn",name:"签出"}],
+      enabled_btn:['#setFree','#callBtn','#onLineBtn', '#consultationBtn']
+    },
+    "ws_disconnected": { "code" : 202, msg:"服务器连接断开",
+      btn_text:[{id:"#onLineBtn",name:"签入"}],
+      enabled_btn:['#onLineBtn']
+    },
+    "user_login_on_other_device": { "code" : 201, msg:"用户已在其他设备登录",
+      btn_text:[{id:"#onLineBtn",name:"签入"}],
+      enabled_btn:['#onLineBtn']
+    },
+    "request_args_error":{ "code" : 400, msg:"客户端请求参数错误",
+      btn_text:[],
+      enabled_btn:[]
+    },
+    "server_error":{ "code" : 500, msg:"服务器内部错误",
+      btn_text:[],
+      enabled_btn:[]
+    },
+    "caller_answered":{ "code" : 600, msg:"分机已接通",
+      btn_text:[],
+      enabled_btn:['#resetStatus', '#hangUpBtn', '#transferBtn', '#holdBtn', '#consultationBtn']
+    },
+    "caller_hangup":{ "code" : 601, msg:"分机已挂断",
+      btn_text:[],
+      enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn' ]
+    },
+    "caller_busy":{ "code" : 602, msg:"分机忙,上一通电话未挂断",
+      btn_text:[],
+      enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn']
+    },
+    "caller_not_login":{ "code" : 603, msg:"分机未登录,请检查",
+      btn_text:[],
+      enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn']
+    },
+    "caller_respond_timeout":{ "code" : 604, msg:"分机未应答超时,请重新打开分机",
+      btn_text:[],
+      enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree', '#consultationBtn']
+    },
+    "callee_answered":{ "code" : 605, msg:"被叫已接通",
+      btn_text:[],
+      enabled_btn:['#resetStatus', '#hangUpBtn', '#transferBtn', '#holdBtn', '#consultationBtn' ]
+    },
+    "callee_hangup":{ "code" : 606, msg:"通话结束",
+      btn_text:[],
+      enabled_btn:['#onLineBtn', '#resetStatus', '#callBtn', '#setFree' , '#consultationBtn']
+    },
+    "callee_ringing":{ "code" : 607, msg:"被叫振铃中",
+      btn_text:[],
+      enabled_btn:['#resetStatus', '#hangUpBtn', '#transferBtn', '#consultationBtn']
+    },
+    "status_changed":{ "code" : 608, msg:"状态已改变",
+      btn_text:[],
+      enabled_btn:[ ]
+    },
+    "free":{ "code" : 0, msg:"空闲中",
+      btn_text:[],
+      enabled_btn:['#setBusy','#onLineBtn', '#consultationBtn']
+    },
+    "busy":{ "code" : 1, msg:"忙碌",
+      btn_text:[],
+      enabled_btn:['#setFree', '#onLineBtn',  '#callBtn', '#consultationBtn']  //  '#transferBtn'
+    },
+    "customer_channel_hold" : { "code" : 623, msg:"通话已保持.",
+      btn_text:[],
+      enabled_btn:['#setFree',  '#callBtn', '#unHoldBtn', '#consultationBtn' ]
+    },
+    "customer_channel_unhold" : { "code" : 624, msg:"通话已接回.",
+      btn_text:[],
+      enabled_btn:[ '#hangUpBtn', '#holdBtn' ]
+    }
+  };
+
+  ccPhoneBarSocket.phone_buttons = ['#setFree', '#setBusy', '#callBtn','#hangUpBtn' , '#resetStatus' ,'#onLineBtn', '#transferBtn', '#holdBtn', '#unHoldBtn', '#consultationBtn'];
+
+  // 更新状态显示
+  this.updatePhoneBar = function (msg, status_key) {
+    if(!_cc.callConfig.useDefaultUi){
+      console.log("callConfig.useDefaultUi = false , 已禁用默认ui工具条按钮.");
+      return;
+    }
+
+    if (msg) {
+      $("#callStatus").text(msg.msg);
+    }
+    var status_info = ccPhoneBarSocket.findItemByCode(status_key);
+    if (!status_info) {
+      return;
+    }
+
+    if(status_info.code === ccPhoneBarSocket.eventListWithTextInfo.status_changed.code){
+      if(msg.object.status === ccPhoneBarSocket.agentStatusEnum.free){
+        status_info = ccPhoneBarSocket.eventListWithTextInfo.free;
+      }else{
+        status_info = ccPhoneBarSocket.eventListWithTextInfo.busy;
+      }
+    }
+    // 判断当前是否为状态改变的事件;
+    // 显示预设的消息;
+    var msgSet = status_info.msg;
+
+    if(msgSet && msgSet.length > 0){
+      $("#callStatus").text(msgSet);
+    }
+
+    var btn_text = status_info.btn_text;
+    var enabled_btn = status_info.enabled_btn;
+    if (btn_text) {
+      $.each(btn_text, function (i, d) {
+        $(d.id).next().text(d.name);
+      });
+    }
+
+    if (enabled_btn.length === 0) {
+      return;
+    }
+
+    var all_btn = ccPhoneBarSocket.phone_buttons;
+    for (var i in all_btn) {
+      var idx = $.inArray(all_btn[i], enabled_btn);
+      if (idx < 0) {
+        $(all_btn[i]).removeClass('on');
+      } else {
+        $(enabled_btn[idx]).addClass('on');
+      }
+    }
+  };
+
+  /**
+   *  初始化电话工具条ui按钮;
+   */
+  this.initPhoneBarUI = function () {
+
+    window.onbeforeunload = function () {
+      if (!confirm('关闭网页将导致您无法接听电话,确定要关闭吗 ?')) return false;
     };
 
+    $("#unHoldBtnLi").hide();
+
+    if(!_cc.callConfig.useDefaultUi){
+      console.log("callConfig.useDefaultUi = false , 已禁用默认ui工具条按钮.");
+      return;
+    }
+
+    $('#conferenceBtn').on('click', function () {
+      if(!_cc.getIsConnected()){
+        console.log('请先上线.');
+        return;
+      }
+      var confObjId = document.getElementById("conference_area");
+      if(confObjId.style.display === "block"){
+        confObjId.style.display = "none";
+      }else{
+        confObjId.style.display = "block";
+      }
+
+    });
+
+    $('#callBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        var destPhone = $.trim($("#ccphoneNumber").val());
+        var videoLevel = document.getElementById("videoLevelSelect").value;
+        var callType = document.forms[0].callType.value;
+        _cc.call(destPhone, callType,  videoLevel);
+      }
+    });
+    $('#setFree').on('click', function () {
+      if ($(this).hasClass('on')) {
+        _cc.setStatus(ccPhoneBarSocket.agentStatusEnum.free);
+      }
+    });
+    $('#setBusy').on('click', function () {
+      if ($(this).hasClass('on')) {
+        _cc.setStatus(ccPhoneBarSocket.agentStatusEnum.busy);
+      }
+    });
+
+    $('#setBusySubList').on('change', function () {
+      let itemValue = $('#setBusySubList').val();
+      console.log('set busy subStatus', itemValue);
+      _cc.setStatus(itemValue);
+    });
+
+    $('#hangUpBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        _cc.hangup();
+      }
+    });
+
+    $('#holdBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        _cc.holdCall();
+      }
+    });
+
+    $('#unHoldBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        _cc.unHoldCall();
+      }
+    });
+
+    $("#doTransferBtn").hide();
 
     /**
-     * 结束监听
+     * 填充业务组选项
+     * 注意:该函数仅用于原始 HTML 版本,Vue + Element UI 版本中由 Vue 组件自行处理
      */
-    this.callMonitorEnd = function(){
-        if(!_cc.getIsConnected()){
-            console.log('请先上线.');
-            return;
+    function populateGroupIdOptions() {
+      var groups = _cc.callConfig.groups;
+      if (groups) {
+        var selectObj = document.getElementById("transfer_to_groupIds");
+        if (selectObj) {
+          // 检查是否为原生 select 元素
+          if (selectObj.tagName.toLowerCase() === 'select') {
+            // 清空现有选项(保留第一个"请选择")
+            var firstOption = selectObj.options[0];
+            selectObj.innerHTML = '';
+            selectObj.add(firstOption);
+
+            // 添加业务组选项
+            for (var i = 0; i < groups.length; i++) {
+              var group = groups[i];
+              var option = document.createElement("option");
+              option.value = group.groupId;
+              option.text = group.bizGroupName;
+              selectObj.add(option);
+            }
+
+            // 默认选中第一个
+            if (groups.length > 0 && selectObj.options.length > 1) {
+              selectObj.selectedIndex = 1;
+            }
+          }
+          // 如果是 el-select 组件,则不处理,由 Vue 数据绑定自动更新
         }
+      }
+    }
 
-        this.monitorControl(
-            "endMonitoring",{}
+    $('#transferBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        if(!_cc.getIsConnected()){
+          console.log('请先上线.');
+          return;
+        }
+        var transferArea = document.getElementById("transfer_area");
+        if(transferArea.style.display === "block"){
+          transferArea.style.display = "none";
+          _cc.unSubscribeAgentList();
+          $("#doTransferBtn").hide();
+          $("#doConsultationBtn").hide();
+        }else{
+          transferArea.style.display = "block";
+          populateGroupIdOptions();
+          // 不再自动订阅坐席状态列表,由外部控制
+          // _cc.subscribeAgentList();
+          $("#doTransferBtn").show();
+          $("#doConsultationBtn").hide();
+        }
+      }
+    });
+
+    $("#stopCallWait").hide();
+    $("#transferCallWait").hide();
+    $("#doConsultationBtn").hide();
+    $('#consultationBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        if(!_cc.getIsConnected()){
+          console.log('请先上线.');
+          return;
+        }
+        var transferArea = document.getElementById("transfer_area");
+        if(transferArea.style.display === "block"){
+          transferArea.style.display = "none";
+          _cc.unSubscribeAgentList();
+          $("#doConsultationBtn").hide();
+          $("#doTransferBtn").hide();
+        }else{
+          transferArea.style.display = "block";
+          populateGroupIdOptions();
+          // 不再自动订阅坐席状态列表,由外部控制
+          // _cc.subscribeAgentList();
+          $("#doConsultationBtn").show();
+          $("#doTransferBtn").hide();
+        }
+      }
+    });
+
+    $('#onLineBtn').on('click', function () {
+      if ($(this).hasClass('on')) {
+        if (_cc.getIsConnected()) {
+          _cc.disconnect();
+        } else {
+          _cc.connect();
+        }
+      }else {
+        alert('当前不允许签出!');
+      }
+    });
+
+    $('#resetStatus').on('click', function () {
+      window.onbeforeunload = null;
+      location.reload();
+    });
+
+    //拨号文本框;收到键盘回车事件之后立即拨号
+    $("#ccphoneNumber").keydown(function (e) {
+      var curKey = e.which;
+      if (curKey === 13) {
+        var destPhone = $.trim($("#ccphoneNumber").val());
+        var videoLevel = document.getElementById("videoLevelSelect").value;
+        var callType = document.forms[0].callType.value;
+        _cc.call(destPhone,callType, videoLevel);
+        return false;
+      }
+    });
+
+    //ESC按键挂机功能支持
+    $(document).keyup(function (e) {
+      var key = e.which;
+      if (key === 27) {
+        console.log('按下了ESC键, 即将发送挂机指令.');
+        if(_cc.getIsConnected()){
+          if(_cc.callConfig["useDefaultUi"]) {
+            if ($('#hangUpBtn').hasClass('on')) {
+              _cc.hangup();
+            }
+          }else{
+            _cc.hangup();
+          }
+        }
+      }
+    });
+  };
+
+  /**
+   *  保持通话
+   */
+  this.holdCall = function(){
+    var cmd = {};
+    cmd.action="callHold";
+    cmd.body = {"cmd" : "hold", "args" : {} };
+    ws.send(JSON.stringify(cmd));
+  };
+
+  /**
+   *  接回保持的通话
+   */
+  this.unHoldCall = function(){
+    var cmd = {};
+    cmd.action="callHold";
+    cmd.body = {"cmd" : "unhold", "args" : {} };
+    ws.send(JSON.stringify(cmd));
+  };
+
+  /**
+   *  订阅坐席状态列表
+   */
+  this.subscribeAgentList = function(){
+    var cmd = {};
+    cmd.action="pollAgentList";
+    cmd.body = {"cmd" : "subscribe", "args" : {} };
+    ws.send(JSON.stringify(cmd));
+    _cc.subscribeAgentListStarted = true;
+  };
+
+  /**
+   *  取消订阅坐席状态列表
+   */
+  this.unSubscribeAgentList = function(){
+    if(_cc.subscribeAgentListStarted) {
+      _cc.subscribeAgentListStarted = false;
+      _cc.callConfig.agentList = null;
+      var cmd = {};
+      cmd.action = "pollAgentList";
+      cmd.body = {"cmd": "unSubscribe", "args": {}};
+      ws.send(JSON.stringify(cmd));
+    }
+  };
+
+  /*************************  以下是电话会议相关  ***************************/
+
+  /**
+   *  启动会议; 仅限使用默认UI场景下使用;
+   */
+  this.conferenceStartBtnUI = function(customerName){
+    var callType = document.getElementById("conf_call_type").value;
+    var confTemplate = document.getElementById("conf_template").value;
+    var layOut = document.getElementById("conf_layout").value;
+
+    _cc.setStatusBusy();
+
+    // 禁用外呼按钮
+    $("#callBtn").removeClass('on');
+
+    // 禁用置闲按钮
+    $("#setFree").removeClass('on');
+
+    // 禁用签出按钮
+    $("#onLineBtn").removeClass('on');
+
+    document.getElementById("startConference").setAttribute("disabled", "true");
+
+    if(_cc.getCallConnected()) {
+      let tips = "是否把当前通话转换为会议 ?";
+      console.log(tips);
+      if(confirm(tips)) {
+        _cc.transferToConference(layOut, confTemplate, callType, customerName);
+      }else{
+        document.getElementById("startConference").removeAttribute("disabled");
+      }
+    }else {
+      _cc.conferenceStart(layOut, confTemplate, callType);
+    }
+  };
+
+  /**
+   *  添加会议成员; 仅限使用默认UI场景下使用;
+   */
+  this.conferenceAddMemberBtnUI = function (reInvite, memberPhoneParam,  memberNameParam) {
+    var memberName = "";
+    var memberPhone = "";
+    var memberCallType = $.trim(document.getElementById("member_call_type").value);
+    var memberVideoLevel = $.trim(document.getElementById("member_video_level").value);
+
+    if(reInvite === 0) {
+      memberName = $("#member_name").val();
+      memberPhone = $("#member_phone").val();
+      if (memberName.length === 0 || $.trim(memberName) === "") {
+        alert('请填写参会者姓名!');
+        return;
+      }
+      if (memberPhone.length === 0 || $.trim(memberPhone) === "") {
+        alert('请填写参会者手机号!');
+        return;
+      }
+
+      memberName = $.trim(memberName);
+      memberPhone = $.trim(memberPhone);
+      // 使用会员成员html模版添加新成员
+      var templateObj = document.getElementById("conf_member_template");
+
+      var existMember = document.getElementById("conf_member_" + memberPhone) != null;
+      if (existMember) {
+        alert('会议成员已经存在,请不要重复添加!');
+        return;
+      }
+
+      var memberHtmlItem = templateObj.innerHTML;
+      memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_name}", "gm"), memberName);
+      memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_phone}", "gm"), memberPhone);
+      memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_status}", "gm"), "即将呼叫");
+
+      var li = document.createElement("li");
+      li.setAttribute("id", "conf_member_" + memberPhone);
+      li.setAttribute("class", "conf_member_item_row");
+      li.innerHTML = memberHtmlItem;
+
+      _cc.insertAfter(li, templateObj);
+
+      $("#member_name").val('');
+      $("#member_phone").val('');
+    }else{
+      memberName = memberNameParam;
+      memberPhone = memberPhoneParam;
+    }
+
+    // 隐藏 mute及 vmute按钮
+    var memberItemId = "#conf_member_" + memberPhone;
+    $(".conf_mute", $(memberItemId)).find("img").hide();
+    $(".conf_vmute", $(memberItemId)).find("img").hide();
+    $(".conf_re_invite", $(memberItemId)).hide();
+    $(".conf_status", $(memberItemId)).html("即将呼叫");
+
+    _cc.conferenceAddMembers( [
+      {"name": memberName, "phone": memberPhone, "callType" : memberCallType,  "videoLevel": memberVideoLevel}
+    ]);
+  };
+
+  /**
+   *  从现有通话添加会议成员;
+   */
+  this.conferenceAddMemberFromExistCall = function (memberName, memberPhone) {
+    if (memberName.length === 0 || $.trim(memberName) === "") {
+      alert('请填写参会者姓名!');
+      return;
+    }
+    if (memberPhone.length === 0 || $.trim(memberPhone) === "") {
+      alert('请填写参会者手机号!');
+      return;
+    }
+    memberName = $.trim(memberName);
+    memberPhone = $.trim(memberPhone);
+
+    // 使用html模版添加新成员
+    var templateObj = document.getElementById("conf_member_template");
+    var existMember = document.getElementById("conf_member_" + memberPhone) != null;
+    if (existMember) {
+      alert('会议成员已经存在,请不要重复添加!');
+      return;
+    }
+
+    var memberHtmlItem = templateObj.innerHTML;
+    memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_name}", "gm"), memberName);
+    memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_phone}", "gm"), memberPhone);
+    memberHtmlItem = memberHtmlItem.replace(new RegExp("{member_status}", "gm"), "即将呼叫");
+    var li = document.createElement("li");
+    li.setAttribute("id", "conf_member_" + memberPhone);
+    li.setAttribute("class", "conf_member_item_row");
+    li.innerHTML = memberHtmlItem;
+    _cc.insertAfter(li, templateObj);
+
+    // 隐藏 mute及 vmute按钮
+    var memberItemId = "#conf_member_" + memberPhone;
+    $(".conf_mute", $(memberItemId)).find("img").show();
+    $(".conf_vmute", $(memberItemId)).find("img").show();
+    $(".conf_re_invite", $(memberItemId)).hide();
+    $(".conf_status", $(memberItemId)).html("通话中").css("color", "green");
+  };
+
+  /**
+   *  通话转为会议
+   * @param layOut
+   * @param confTemplate
+   * @param callType
+   * @param customerName
+   */
+  this.transferToConference = function (layOut, confTemplate, callType, customerName) {
+    console.log("try to transferToConference: ", layOut, confTemplate, callType, customerName);
+    _cc.callControl(
+      "transferToConference",
+      {
+        "layOut": layOut,
+        'callType': callType,
+        'confTemplate': confTemplate,
+        'customerName' : customerName
+      }
+    );
+  };
+
+
+  /**
+   *  主持人启动电话会议
+   * @param layOut 会议布局
+   * @param confTemplate 会议模版
+   * @param callType 会议类型
+   */
+  this.conferenceStart = function(layOut, confTemplate, callType) {
+    console.log("正常发起多方通话");
+    var cmd = {};
+    cmd.action = "conference";
+    cmd.body = {"method": "startconf", "args": {
+        "layOut": layOut,
+        'callType': callType,
+        'confTemplate': confTemplate
+      }};
+    ws.send(JSON.stringify(cmd));
+  };
+
+
+  /**
+   *  VMute会议成员(不显示视频);
+   **/
+  this.conferenceVMuteMember = function(members) {
+    // single phone
+    if(typeof(members) === "string") {
+      this.conferenceControl("vmute",
+        [
+          {"phone": members}
+        ]
+      );
+    }else{
+      // multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
+      this.conferenceControl("vmute", members);
+    }
+  };
+
+
+  /**
+   *  UnVMute会议成员(显示视频);
+   **/
+  this.conferenceUnVMuteMember = function(members) {
+    // single phone
+    if(typeof(members) === "string") {
+      this.conferenceControl("unvmute",
+        [
+          {"phone": members}
+        ]
+      );
+    }else{
+      // multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
+      this.conferenceControl("unvmute", members);
+    }
+  };
+
+  /**
+   *  禁言会议成员
+   **/
+  this.conferenceMuteMember = function(members) {
+    // single phone
+    if(typeof(members) === "string") {
+      this.conferenceControl("mute",
+        [
+          {"phone": members}
+        ]
+      );
+    }else{
+      // multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
+      this.conferenceControl("mute", members);
+    }
+  };
+
+  /**
+   *  解禁会议成员
+   **/
+  this.conferenceUnMuteMember = function(members) {
+    // single phone
+    if(typeof(members) === "string") {
+      this.conferenceControl("unmute",
+        [
+          {"phone": members}
+        ]
+      );
+    }else{
+      // multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
+      this.conferenceControl("unmute", members);
+    }
+  };
+
+  /**
+   *  增加会议成员
+   **/
+  this.conferenceAddMembers = function(members) {
+    this.conferenceControl("add", members)
+  };
+
+
+  /**
+   *  移除会议成员
+   **/
+  this.conferenceRemoveMembers = function(members) {
+    // single phone
+    if(typeof(members) === "string") {
+      var memberItemObj = $("#conf_member_" + members);
+      if($(".conf_status", memberItemObj).text() === "通话中") {
+        this.conferenceControl("remove",
+          [
+            {"phone": members}
+          ]
         );
-    };
+      }
+      memberItemObj.remove();
+    }else{
+      // multiple phones array, e.g.: [  {"phone": '15005600321'}, {"phone": '15005600323'} ]
+      this.conferenceControl("remove", members);
+    }
+  };
+
+  /**
+   *  结束电话会议
+   **/
+  this.conferenceEnd = function() {
+    this.conferenceControl("endconf", [])
+  };
+
+
+  /**
+   *  电话会议控制相关操作
+   * @param action 操作
+   * @param phoneList 会议成员
+   */
+  this.conferenceControl = function (action, phoneList) {
+    var cmd = {};
+    cmd.action = "conference";
+    cmd.body = { "method": action, "memberList": phoneList };
+    ws.send(JSON.stringify(cmd));
+  };
+
+  /*************************  以下是通话监听相关  ***************************/
+
+  /**
+   *   拉取监听的通话列表
+   */
+  this.callMonitorDataPull = function (){
+    var cmd = {};
+    cmd.action = "monitorData";
+    cmd.body = {};
+    ws.send(JSON.stringify(cmd));
+  };
+
+  /**
+   *   拉取排队中的电话列表
+   */
+  this.inboundCallQueuePull = function (){
+    var cmd = {};
+    cmd.action = "inboundMonitorData";
+    cmd.body = {};
+    ws.send(JSON.stringify(cmd));
+  };
+
+  // 构造通话监听参数
+  this.monitorControl = function(action, argsObject){
+    var sessionControl = {};
+    sessionControl.action="callMonitor";
+    sessionControl.body = {"cmd" : action, "args" : argsObject };
+    ws.send(JSON.stringify(sessionControl));
+  };
+
+  /**
+   * 通话监听
+   * @param { 通话id } callId
+   * @returns
+   */
+  this.callMonitorStart = function(callId){
+    if(callId == null || callId.length === 0) {
+      console.log('请提供待监听电话的 callId !');
+      return;
+    }
+
+    if(!_cc.getIsConnected()){
+      console.log('请先上线.');
+      return;
+    }
+
+    this.monitorControl(
+      "startMonitoring",
+      {
+        'callSpyId': callId
+      }
+    );
+  };
+
+
+  /**
+   * 结束监听
+   */
+  this.callMonitorEnd = function(){
+    if(!_cc.getIsConnected()){
+      console.log('请先上线.');
+      return;
+    }
+
+    this.monitorControl(
+      "endMonitoring",{}
+    );
+  };
 
 }
 

+ 18 - 1
src/assets/callCenterPhoneBarSdk/constants.js

@@ -346,5 +346,22 @@ export const DefaultConfig = {
   groupId: '1',// 业务组 id
   extPassword: '0406f9d44bb8fe195a1ee2557bbeebf7',
   skillLevel: 9,//技能等级
-  ipccServerUrl: '129.28.164.235:1081',
+  ipccServerUrl: 'sip.ylrzcloud.com',
+
+  // 功能开关配置
+  featureSwitches: {
+    //基础外呼
+    call: true,         // 外呼
+    hold: true,         // 保持
+    hangup: true,       // 挂机
+    reset: true,        // 强置
+    signInOut: true,     // 签出签入
+
+    //进阶功能
+    setBusy: false,      // 置忙-可外呼
+    setFree: false,      // 置闲-可接呼入的电话
+    transfer: false,     // 转接
+    consultation: false, // 咨询
+    conference: false,   // 会议
+  }
 };

+ 78 - 78
src/views/aiSipCall/aiSipCallBizGroup.vue

@@ -44,49 +44,49 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="primary"-->
-<!--          plain-->
-<!--          icon="el-icon-plus"-->
-<!--          size="mini"-->
-<!--          @click="handleAdd"-->
-<!--          v-hasPermi="['company:aiSipCall:bizGroup:add']"-->
-<!--        >新增</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="success"-->
-<!--          plain-->
-<!--          icon="el-icon-edit"-->
-<!--          size="mini"-->
-<!--          :disabled="single"-->
-<!--          @click="handleUpdate"-->
-<!--          v-hasPermi="['company:aiSipCall:bizGroup:edit']"-->
-<!--        >修改</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="danger"-->
-<!--          plain-->
-<!--          icon="el-icon-delete"-->
-<!--          size="mini"-->
-<!--          :disabled="multiple"-->
-<!--          @click="handleDelete"-->
-<!--          v-hasPermi="['company:aiSipCall:bizGroup:remove']"-->
-<!--        >删除</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="warning"-->
-<!--          plain-->
-<!--          icon="el-icon-download"-->
-<!--          size="mini"-->
-<!--          :loading="exportLoading"-->
-<!--          @click="handleExport"-->
-<!--          v-hasPermi="['company:aiSipCall:bizGroup:export']"-->
-<!--        >导出</el-button>-->
-<!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="primary"-->
+      <!--          plain-->
+      <!--          icon="el-icon-plus"-->
+      <!--          size="mini"-->
+      <!--          @click="handleAdd"-->
+      <!--          v-hasPermi="['company:aiSipCall:bizGroup:add']"-->
+      <!--        >新增</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="success"-->
+      <!--          plain-->
+      <!--          icon="el-icon-edit"-->
+      <!--          size="mini"-->
+      <!--          :disabled="single"-->
+      <!--          @click="handleUpdate"-->
+      <!--          v-hasPermi="['company:aiSipCall:bizGroup:edit']"-->
+      <!--        >修改</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="danger"-->
+      <!--          plain-->
+      <!--          icon="el-icon-delete"-->
+      <!--          size="mini"-->
+      <!--          :disabled="multiple"-->
+      <!--          @click="handleDelete"-->
+      <!--          v-hasPermi="['company:aiSipCall:bizGroup:remove']"-->
+      <!--        >删除</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="warning"-->
+      <!--          plain-->
+      <!--          icon="el-icon-download"-->
+      <!--          size="mini"-->
+      <!--          :loading="exportLoading"-->
+      <!--          @click="handleExport"-->
+      <!--          v-hasPermi="['company:aiSipCall:bizGroup:export']"-->
+      <!--        >导出</el-button>-->
+      <!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -98,22 +98,22 @@
       <el-table-column label="备注" align="center" prop="notes" />
       <el-table-column label="远程技能组ID" align="center" prop="remoteGroupId" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-<!--        <template slot-scope="scope">-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-edit"-->
-<!--            @click="handleUpdate(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:bizGroup:edit']"-->
-<!--          >修改</el-button>-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-delete"-->
-<!--            @click="handleDelete(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:bizGroup:remove']"-->
-<!--          >删除</el-button>-->
-<!--        </template>-->
+        <!--        <template slot-scope="scope">-->
+        <!--          <el-button-->
+        <!--            size="mini"-->
+        <!--            type="text"-->
+        <!--            icon="el-icon-edit"-->
+        <!--            @click="handleUpdate(scope.row)"-->
+        <!--            v-hasPermi="['company:aiSipCall:bizGroup:edit']"-->
+        <!--          >修改</el-button>-->
+        <!--          <el-button-->
+        <!--            size="mini"-->
+        <!--            type="text"-->
+        <!--            icon="el-icon-delete"-->
+        <!--            @click="handleDelete(scope.row)"-->
+        <!--            v-hasPermi="['company:aiSipCall:bizGroup:remove']"-->
+        <!--          >删除</el-button>-->
+        <!--        </template>-->
       </el-table-column>
     </el-table>
 
@@ -281,30 +281,30 @@ export default {
     handleDelete(row) {
       const groupIds = row.groupId || this.ids;
       this.$confirm('是否确认删除aiSIP外呼技能组编号为"' + groupIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delAiSipCallBizGroup(groupIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delAiSipCallBizGroup(groupIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有aiSIP外呼技能组数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportAiSipCallBizGroup(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAiSipCallBizGroup(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 97 - 97
src/views/aiSipCall/aiSipCallLlmAgentAccount.vue

@@ -32,49 +32,49 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="primary"-->
-<!--          plain-->
-<!--          icon="el-icon-plus"-->
-<!--          size="mini"-->
-<!--          @click="handleAdd"-->
-<!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:add']"-->
-<!--        >新增</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="success"-->
-<!--          plain-->
-<!--          icon="el-icon-edit"-->
-<!--          size="mini"-->
-<!--          :disabled="single"-->
-<!--          @click="handleUpdate"-->
-<!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:edit']"-->
-<!--        >修改</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="danger"-->
-<!--          plain-->
-<!--          icon="el-icon-delete"-->
-<!--          size="mini"-->
-<!--          :disabled="multiple"-->
-<!--          @click="handleDelete"-->
-<!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:remove']"-->
-<!--        >删除</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="warning"-->
-<!--          plain-->
-<!--          icon="el-icon-download"-->
-<!--          size="mini"-->
-<!--          :loading="exportLoading"-->
-<!--          @click="handleExport"-->
-<!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:export']"-->
-<!--        >导出</el-button>-->
-<!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="primary"-->
+      <!--          plain-->
+      <!--          icon="el-icon-plus"-->
+      <!--          size="mini"-->
+      <!--          @click="handleAdd"-->
+      <!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:add']"-->
+      <!--        >新增</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="success"-->
+      <!--          plain-->
+      <!--          icon="el-icon-edit"-->
+      <!--          size="mini"-->
+      <!--          :disabled="single"-->
+      <!--          @click="handleUpdate"-->
+      <!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:edit']"-->
+      <!--        >修改</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="danger"-->
+      <!--          plain-->
+      <!--          icon="el-icon-delete"-->
+      <!--          size="mini"-->
+      <!--          :disabled="multiple"-->
+      <!--          @click="handleDelete"-->
+      <!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:remove']"-->
+      <!--        >删除</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="warning"-->
+      <!--          plain-->
+      <!--          icon="el-icon-download"-->
+      <!--          size="mini"-->
+      <!--          :loading="exportLoading"-->
+      <!--          @click="handleExport"-->
+      <!--          v-hasPermi="['company:aiSipCall:llmAgentAccount:export']"-->
+      <!--        >导出</el-button>-->
+      <!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -84,20 +84,20 @@
       <el-table-column label="实现类" align="center" prop="providerClassName" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-edit"-->
-<!--            @click="handleUpdate(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:llmAgentAccount:edit']"-->
-<!--          >修改</el-button>-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-delete"-->
-<!--            @click="handleDelete(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:llmAgentAccount:remove']"-->
-<!--          >删除</el-button>-->
+          <!--          <el-button-->
+          <!--            size="mini"-->
+          <!--            type="text"-->
+          <!--            icon="el-icon-edit"-->
+          <!--            @click="handleUpdate(scope.row)"-->
+          <!--            v-hasPermi="['company:aiSipCall:llmAgentAccount:edit']"-->
+          <!--          >修改</el-button>-->
+          <!--          <el-button-->
+          <!--            size="mini"-->
+          <!--            type="text"-->
+          <!--            icon="el-icon-delete"-->
+          <!--            @click="handleDelete(scope.row)"-->
+          <!--            v-hasPermi="['company:aiSipCall:llmAgentAccount:remove']"-->
+          <!--          >删除</el-button>-->
         </template>
       </el-table-column>
     </el-table>
@@ -138,28 +138,28 @@
 
 
 
-<!--        <el-form-item label="大模型类型,枚举值:LlmAccount, CozeAccount" prop="accountEntity">-->
-<!--          <el-input v-model="form.accountEntity" placeholder="请输入大模型类型,枚举值:LlmAccount, CozeAccount" />-->
-<!--        </el-form-item>-->
+        <!--        <el-form-item label="大模型类型,枚举值:LlmAccount, CozeAccount" prop="accountEntity">-->
+        <!--          <el-input v-model="form.accountEntity" placeholder="请输入大模型类型,枚举值:LlmAccount, CozeAccount" />-->
+        <!--        </el-form-item>-->
 
-<!--        <el-form-item label="打断关键词列表" prop="interruptKeywords">-->
-<!--          <el-input v-model="form.interruptKeywords" type="textarea" placeholder="请输入内容" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="打断忽略关键字列表" prop="interruptIgnoreKeywords">-->
-<!--          <el-input v-model="form.interruptIgnoreKeywords" type="textarea" placeholder="请输入内容" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="客户意向提示词" prop="intentionTips">-->
-<!--          <el-input v-model="form.intentionTips" type="textarea" placeholder="请输入内容" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="一个用于启动向人工座席转移的单位数字代码。" prop="transferManualDigit">-->
-<!--          <el-input v-model="form.transferManualDigit" placeholder="请输入一个用于启动向人工座席转移的单位数字代码。" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="知识库分类ID" prop="kbCatId">-->
-<!--          <el-input v-model="form.kbCatId" placeholder="请输入知识库分类ID" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="远程大模型ID" prop="remoteLlmAgentAccountId">-->
-<!--          <el-input v-model="form.remoteLlmAgentAccountId" placeholder="请输入远程大模型ID" />-->
-<!--        </el-form-item>-->
+        <!--        <el-form-item label="打断关键词列表" prop="interruptKeywords">-->
+        <!--          <el-input v-model="form.interruptKeywords" type="textarea" placeholder="请输入内容" />-->
+        <!--        </el-form-item>-->
+        <!--        <el-form-item label="打断忽略关键字列表" prop="interruptIgnoreKeywords">-->
+        <!--          <el-input v-model="form.interruptIgnoreKeywords" type="textarea" placeholder="请输入内容" />-->
+        <!--        </el-form-item>-->
+        <!--        <el-form-item label="客户意向提示词" prop="intentionTips">-->
+        <!--          <el-input v-model="form.intentionTips" type="textarea" placeholder="请输入内容" />-->
+        <!--        </el-form-item>-->
+        <!--        <el-form-item label="一个用于启动向人工座席转移的单位数字代码。" prop="transferManualDigit">-->
+        <!--          <el-input v-model="form.transferManualDigit" placeholder="请输入一个用于启动向人工座席转移的单位数字代码。" />-->
+        <!--        </el-form-item>-->
+        <!--        <el-form-item label="知识库分类ID" prop="kbCatId">-->
+        <!--          <el-input v-model="form.kbCatId" placeholder="请输入知识库分类ID" />-->
+        <!--        </el-form-item>-->
+        <!--        <el-form-item label="远程大模型ID" prop="remoteLlmAgentAccountId">-->
+        <!--          <el-input v-model="form.remoteLlmAgentAccountId" placeholder="请输入远程大模型ID" />-->
+        <!--        </el-form-item>-->
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -330,30 +330,30 @@ export default {
     handleDelete(row) {
       const ids = row.id || this.ids;
       this.$confirm('是否确认删除aiSIP外呼大模型编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delAiSipCallLlmAgentAccount(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delAiSipCallLlmAgentAccount(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有aiSIP外呼大模型数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportAiSipCallLlmAgentAccount(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAiSipCallLlmAgentAccount(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

Разлика између датотеке није приказан због своје велике величине
+ 1997 - 2064
src/views/aiSipCall/aiSipCallManualOutbound.vue


+ 84 - 76
src/views/aiSipCall/aiSipCallOutboundCar.vue

@@ -31,7 +31,7 @@
           style="width: 150px"
         />
       </el-form-item>
-      <el-form-item label="通话时长">
+      <el-form-item label="通话分钟">
         <div class="time-range">
           <el-input-number v-model="queryParams.timeLenStart" :min="0" placeholder="最小值" size="small"
                            style="width: 130px"/>
@@ -75,28 +75,28 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          :loading="exportLoading"
-          @click="handleExport"
-          v-hasPermi="['company:aiSipCall:outboundCdr:export']"
-        >导出</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleManualPull"
-          v-hasPermi="['company:aiSipCall:outboundCdr:manualPull']"
-        >同步今天数据
-        </el-button>
-      </el-col>
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="warning"-->
+      <!--          plain-->
+      <!--          icon="el-icon-download"-->
+      <!--          size="mini"-->
+      <!--          :loading="exportLoading"-->
+      <!--          @click="handleExport"-->
+      <!--          v-hasPermi="['company:aiSipCall:outboundCdr:export']"-->
+      <!--        >导出</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="warning"-->
+      <!--          plain-->
+      <!--          icon="el-icon-download"-->
+      <!--          size="mini"-->
+      <!--          @click="handleManualPull"-->
+      <!--          v-hasPermi="['company:aiSipCall:outboundCdr:manualPull']"-->
+      <!--        >同步今天数据-->
+      <!--        </el-button>-->
+      <!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -119,28 +119,28 @@
       <el-table-column label="纯通时长" align="center" prop="timeLenValidStr" />
       <el-table-column label="挂断原因" align="center" prop="hangupCause" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-<!--        <template slot-scope="scope">-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-video-play"-->
-<!--            @click="playVoice(scope.row.recordFilename)"-->
-<!--            v-hasPermi="['company:aiSipCall:phone:downloadVoice']"-->
-<!--            v-if="scope.row.recordFilename"-->
-<!--            style="color: #409EFF;"-->
-<!--          >播放-->
-<!--          </el-button>-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-download"-->
-<!--            @click="downloadVoice(scope.row.recordFilename)"-->
-<!--            v-hasPermi="['company:aiSipCall:phone:downloadVoice']"-->
-<!--            v-if="scope.row.recordFilename"-->
-<!--            style="color: #67C23A;"-->
-<!--          >下载-->
-<!--          </el-button>-->
-<!--        </template>-->
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-video-play"
+            @click="playVoice(scope.row.wavFileUrl)"
+            v-hasPermi="['company:aiSipCall:phone:downloadVoice']"
+            v-if="scope.row.wavFileUrl"
+            style="color: #409EFF;"
+          >播放
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-download"
+            @click="downloadVoice(scope.row.wavFileUrl)"
+            v-hasPermi="['company:aiSipCall:phone:downloadVoice']"
+            v-if="scope.row.wavFileUrl"
+            style="color: #67C23A;"
+          >下载
+          </el-button>
+        </template>
       </el-table-column>
     </el-table>
 
@@ -156,7 +156,7 @@
 </template>
 
 <script>
-import { listOutboundCdr, getOutboundCdr, delOutboundCdr, addOutboundCdr, updateOutboundCdr, exportOutboundCdr,manualPull } from "@/api/aiSipCall/aiSipCallOutboundCdr";
+import { listOutboundCdr, getOutboundCdr, delOutboundCdr, addOutboundCdr, updateOutboundCdr, exportOutboundCdr,manualPull,remoteList } from "@/api/aiSipCall/aiSipCallOutboundCdr";
 
 export default {
   name: "OutboundCdr",
@@ -190,11 +190,11 @@ export default {
       queryParams: {
         pageNum: 1,
         pageSize: 10,
+        timeLenStart: undefined,
+        timeLenEnd: undefined,
+        callType: '03',
         caller: null,
         opnum: null,
-        timeLenStart: null,
-        timeLenEnd: null,
-
         startTimeStart: null,
         startTimeEnd: null,
         answeredTimeStart: null,
@@ -206,7 +206,6 @@ export default {
         answeredTime: null,
         endTime: null,
         uuid: null,
-        callType: null,
         timeLen: null,
         timeLenValid: null,
         recordFilename: null,
@@ -227,8 +226,8 @@ export default {
     getTodayStart() {
       const now = new Date();
       return now.getFullYear() + '-' +
-             String(now.getMonth() + 1).padStart(2, '0') + '-' +
-             String(now.getDate()).padStart(2, '0') + ' 00:00:00';
+        String(now.getMonth() + 1).padStart(2, '0') + '-' +
+        String(now.getDate()).padStart(2, '0') + ' 00:00:00';
     },
     handleManualPull(){
       manualPull().then(response => {
@@ -243,7 +242,7 @@ export default {
     /** 查询aiSIP手动外呼通话记录列表 */
     getList() {
       this.loading = true;
-      listOutboundCdr(this.queryParams).then(response => {
+      remoteList(this.queryParams).then(response => {
         this.outboundCdrList = response.rows;
         this.total = response.total;
         this.loading = false;
@@ -257,15 +256,24 @@ export default {
     // 表单重置
     reset() {
       this.form = {
-        id: null,
+        pageNum: 1,
+        pageSize: 10,
+        callType: '03',
         caller: null,
         opnum: null,
+        timeLenStart: null,
+        timeLenEnd: null,
+        startTimeStart: null,
+        startTimeEnd: null,
+        answeredTimeStart: null,
+        answeredTimeEnd: null,
+        endTimeStart: this.getTodayStart(),
+        endTimeEnd: null,
         callee: null,
         startTime: null,
         answeredTime: null,
         endTime: null,
         uuid: null,
-        callType: null,
         timeLen: null,
         timeLenValid: null,
         recordFilename: null,
@@ -283,8 +291,8 @@ export default {
     resetQuery() {
       this.queryParams.startTimeStart = null;
       this.queryParams.startTimeEnd = null;
-      this.queryParams.timeLenStart = null;
-      this.queryParams.timeLenEnd = null;
+      this.queryParams.timeLenStart = undefined;
+      this.queryParams.timeLenEnd = undefined;
       this.queryParams.answeredTimeStart = null;
       this.queryParams.answeredTimeEnd = null;
       this.queryParams.endTimeStart = this.getTodayStart();
@@ -340,30 +348,30 @@ export default {
     handleDelete(row) {
       const ids = row.id || this.ids;
       this.$confirm('是否确认删除aiSIP手动外呼通话记录编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delOutboundCdr(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delOutboundCdr(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有aiSIP手动外呼通话记录数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportOutboundCdr(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportOutboundCdr(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
 
 

+ 28 - 35
src/views/aiSipCall/aiSipCallPhone.vue

@@ -87,27 +87,27 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          :loading="exportLoading"
-          @click="handleExport"
-          v-hasPermi="['company:aiSipCall:phone:export']"
-        >导出</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-sync"
-          size="mini"
-          @click="handleManualPull"
-          v-hasPermi="['company:aiSipCall:phone:manualPull']"
-        >同步今天数据</el-button>
-      </el-col>
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="primary"-->
+      <!--          plain-->
+      <!--          icon="el-icon-download"-->
+      <!--          size="mini"-->
+      <!--          :loading="exportLoading"-->
+      <!--          @click="handleExport"-->
+      <!--          v-hasPermi="['company:aiSipCall:phone:export']"-->
+      <!--        >导出</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="warning"-->
+      <!--          plain-->
+      <!--          icon="el-icon-sync"-->
+      <!--          size="mini"-->
+      <!--          @click="handleManualPull"-->
+      <!--          v-hasPermi="['company:aiSipCall:phone:manualPull']"-->
+      <!--        >同步今天数据</el-button>-->
+      <!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -168,7 +168,8 @@ import {
   exportAiSipCallPhone,
   getAiSipCallPhone,
   updateAiSipCallPhone,
-  manualPull
+  manualPull,
+  remoteList
 } from "@/api/aiSipCall/aiSipCallPhone";
 import {listAiSipCallTask} from "../../api/aiSipCall/aiSipCallTask";
 
@@ -224,6 +225,7 @@ export default {
         callEndTime: null,
         timeLen: null,
         validTimeLen: null,
+        callType: '02',
         uuid: null,
         connectedTime: null,
         hangupCause: null,
@@ -270,18 +272,8 @@ export default {
     getTodayStart() {
       const now = new Date();
       return now.getFullYear() + '-' +
-             String(now.getMonth() + 1).padStart(2, '0') + '-' +
-             String(now.getDate()).padStart(2, '0') + ' 00:00:00';
-    },
-    // 获取当前时间(yyyy-MM-dd HH:mm:ss)
-    getCurrentTime() {
-      const now = new Date();
-      return now.getFullYear() + '-' +
-             String(now.getMonth() + 1).padStart(2, '0') + '-' +
-             String(now.getDate()).padStart(2, '0') + ' ' +
-             String(now.getHours()).padStart(2, '0') + ':' +
-             String(now.getMinutes()).padStart(2, '0') + ':' +
-             String(now.getSeconds()).padStart(2, '0');
+        String(now.getMonth() + 1).padStart(2, '0') + '-' +
+        String(now.getDate()).padStart(2, '0') + ' 00:00:00';
     },
     handleManualPull(){
       manualPull().then(response => {
@@ -387,7 +379,7 @@ export default {
     /** 查询 aiSIP 外呼通话记录列表 */
     getList() {
       this.loading = true;
-      listAiSipCallPhone(this.queryParams).then(response => {
+      remoteList(this.queryParams).then(response => {
         this.aiSipCallList = response.rows || [];
         this.total = response.total || 0;
         this.loading = false;
@@ -420,6 +412,7 @@ export default {
         callEndTime: null,
         timeLen: null,
         validTimeLen: null,
+        callType: '02',
         uuid: null,
         connectedTime: null,
         hangupCause: null,

+ 204 - 189
src/views/aiSipCall/aiSipCallTask.vue

@@ -25,12 +25,16 @@
           <el-option label="停止外呼" value="0" />
         </el-select>
       </el-form-item>
-      <el-form-item label="创建时间">
-        <el-date-picker v-model="queryParams.createTimeStart" size="small" style="width: 180px"
-                        value-format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="开始时间"/>
-        <span style="margin: 0 8px">-</span>
-        <el-date-picker v-model="queryParams.createTimeEnd" size="small" style="width: 180px"
-                        value-format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="结束时间"/>
+      <el-form-item label="音色" prop="voiceCode">
+        <el-select v-model="queryParams.voiceCode" placeholder="请选择音色" clearable size="small">
+          <el-option label="全部" value="" />
+          <el-option
+            v-for="(item, index) in voiceSourceList"
+            :key="'query-' + item.voiceCode + '-' + index"
+            :label="item.voiceName"
+            :value="item.voiceCode"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item label="外呼线路" prop="gatewayId">
         <el-select v-model="queryParams.gatewayId" placeholder="请选择外呼线路" clearable size="small">
@@ -43,16 +47,12 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="音色" prop="voiceSource">
-        <el-select v-model="queryParams.voiceSource" placeholder="请选择音色" clearable size="small">
-          <el-option label="全部" value="" />
-          <el-option
-            v-for="(item, index) in voiceSourceList"
-            :key="'query-' + item.voiceCode + '-' + index"
-            :label="item.voiceName"
-            :value="item.voiceCode"
-          />
-        </el-select>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="queryParams.createTimeStart" size="small" style="width: 180px"
+                        value-format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="开始时间"/>
+        <span style="margin: 0 8px">-</span>
+        <el-date-picker v-model="queryParams.createTimeEnd" size="small" style="width: 180px"
+                        value-format="yyyy-MM-dd HH:mm:ss" type="datetime" placeholder="结束时间"/>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -72,37 +72,37 @@
         >新增</el-button>
       </el-col>
       <el-col :span="1.5">
-      <el-button
-        type="primary"
-        plain
-        icon="el-icon-plus"
-        size="mini"
-        @click="downloadCallTemplate"
-        v-hasPermi="['company:aiSipCall:task:download:template']"
-      >下载外呼模板</el-button>
-    </el-col>
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="success"-->
-<!--          plain-->
-<!--          icon="el-icon-edit"-->
-<!--          size="mini"-->
-<!--          :disabled="single"-->
-<!--          @click="handleUpdate"-->
-<!--          v-hasPermi="['company:aiSipCall:task:edit']"-->
-<!--        >修改</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="danger"-->
-<!--          plain-->
-<!--          icon="el-icon-delete"-->
-<!--          size="mini"-->
-<!--          :disabled="multiple"-->
-<!--          @click="handleDelete"-->
-<!--          v-hasPermi="['company:aiSipCall:task:remove']"-->
-<!--        >删除</el-button>-->
-<!--      </el-col>-->
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="downloadCallTemplate"
+          v-hasPermi="['company:aiSipCall:task:download:template']"
+        >下载外呼模板</el-button>
+      </el-col>
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="success"-->
+      <!--          plain-->
+      <!--          icon="el-icon-edit"-->
+      <!--          size="mini"-->
+      <!--          :disabled="single"-->
+      <!--          @click="handleUpdate"-->
+      <!--          v-hasPermi="['company:aiSipCall:task:edit']"-->
+      <!--        >修改</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="danger"-->
+      <!--          plain-->
+      <!--          icon="el-icon-delete"-->
+      <!--          size="mini"-->
+      <!--          :disabled="multiple"-->
+      <!--          @click="handleDelete"-->
+      <!--          v-hasPermi="['company:aiSipCall:task:remove']"-->
+      <!--        >删除</el-button>-->
+      <!--      </el-col>-->
       <el-col :span="1.5">
         <el-button
           type="warning"
@@ -144,25 +144,30 @@
       </el-table-column>
       <el-table-column label="音色" align="center" prop="voiceCode">
         <template slot-scope="scope">
-        <span v-for="(item, index) in voiceSourceList" v-if="scope.row.voiceCode === item.voiceCode" :key="'table-' + item.voiceCode + '-' + index">{{ item.voiceName }}</span>
-      </template>
+          <span v-for="(item, index) in voiceSourceList" v-if="scope.row.voiceCode === item.voiceCode" :key="'table-' + item.voiceCode + '-' + index">{{ item.voiceName }}</span>
+        </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" />
-<!--      <el-table-column label="总名单量" align="center" prop="phoneCount" />-->
-<!--      <el-table-column label="未拨打" align="center" prop="noCallCount" />-->
-<!--      <el-table-column label="已拨打" align="center" prop="callCount" />-->
-<!--      <el-table-column label="接通量" align="center" prop="connectCount" />-->
-<!--      <el-table-column label="接通率" align="center" prop="realConnectRate" />-->
-      <el-table-column label="远程任务ID" align="center" prop="remoteBatchId" />
+      <el-table-column label="总名单量" align="center" prop="phoneCount" />
+      <el-table-column label="未拨打" align="center" prop="noCallCount" />
+      <el-table-column label="已拨打" align="center" prop="callCount" />
+      <el-table-column label="接通量" align="center" prop="connectCount" />
+      <el-table-column label="未接量" align="center" prop="noConnectCount" />
+      <el-table-column label="接通率" align="center">
+        <template slot-scope="scope">
+          {{ formatConnectRate(scope.row.realConnectRate) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="远程ID" align="center" prop="remoteBatchId" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-edit"-->
-<!--            @click="handleUpdate(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:task:edit']"-->
-<!--          >修改</el-button>-->
+          <!--          <el-button-->
+          <!--            size="mini"-->
+          <!--            type="text"-->
+          <!--            icon="el-icon-edit"-->
+          <!--            @click="handleUpdate(scope.row)"-->
+          <!--            v-hasPermi="['company:aiSipCall:task:edit']"-->
+          <!--          >修改</el-button>-->
           <el-button
             size="mini"
             type="text"
@@ -184,13 +189,13 @@
             @click="handleImportData(scope.row.batchId)"
             v-hasPermi="['company:aiSipCall:task:commonImportExcel']"
           >导入外呼模板</el-button>
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-delete"-->
-<!--            @click="handleDelete(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:task:remove']"-->
-<!--          >删除</el-button>-->
+          <!--          <el-button-->
+          <!--            size="mini"-->
+          <!--            type="text"-->
+          <!--            icon="el-icon-delete"-->
+          <!--            @click="handleDelete(scope.row)"-->
+          <!--            v-hasPermi="['company:aiSipCall:task:remove']"-->
+          <!--          >删除</el-button>-->
         </template>
       </el-table-column>
     </el-table>
@@ -211,10 +216,10 @@
         </el-form-item>
         <el-form-item label="任务类型" prop="taskType">
           <el-select v-model="form.taskType" placeholder="请选择任务类型" clearable>
-<!--            <el-option label="纯人工预测外呼" value="0" />-->
+            <!--            <el-option label="纯人工预测外呼" value="0" />-->
             <el-option label="AI外呼" value="1" />
-<!--            <el-option label="语音通知" value="2" />-->
-<!--            <el-option label="IVR外呼" value="3" />-->
+            <!--            <el-option label="语音通知" value="2" />-->
+            <!--            <el-option label="IVR外呼" value="3" />-->
           </el-select>
         </el-form-item>
 
@@ -349,7 +354,7 @@
 
 <script>
 import { downloadTemplateByType,listAiSipCallTask, getAiSipCallTask, delAiSipCallTask, addAiSipCallTask, updateAiSipCallTask, exportAiSipCallTask, startTask, stopTask,commonImportExcel } from "@/api/aiSipCall/aiSipCallTask";
-import {listAiSipCallGateway} from "../../api/aiSipCall/aiSipCallGateway";
+import {remoteList} from "../../api/aiSipCall/aiSipCallGateway";
 import {listAiSipCallVoiceTtsAliyun} from "../../api/aiSipCall/aiSipCallVoiceTtsAliyun";
 import {listAiSipCallLlmAgentAccount } from "@/api/aiSipCall/aiSipCallLlmAgentAccount";
 import { listAiSipCallBizGroup } from "@/api/aiSipCall/aiSipCallBizGroup";
@@ -361,6 +366,7 @@ export default {
       loading: true,
       // 导出遮罩层
       exportLoading: false,
+      //新增和修改使用
       gatewayList: [],
       voiceSourceList: [],
       // 按厂商分类的音色列表
@@ -495,7 +501,7 @@ export default {
         ],
         aiTransferGatewayDestNumber: [
           { validator: (rule, value, callback) => {
-             if (this.form.aiTransferType === 'gateway' && !value) {
+              if (this.form.aiTransferType === 'gateway' && !value) {
                 callback(new Error('转接号码不能为空'));
               } else {
                 callback();
@@ -504,7 +510,7 @@ export default {
         ],
         conntectRate: [
           { validator: (rule, value, callback) => {
-            if (this.form.taskType === '0' && !value) {
+              if (this.form.taskType === '0' && !value) {
                 callback(new Error('预估接通率不能为空'));
               } else {
                 callback();
@@ -513,7 +519,7 @@ export default {
         ],
         avgRingTimeLen: [
           { validator: (rule, value, callback) => {
-            if (this.form.taskType === '0' && !value) {
+              if (this.form.taskType === '0' && !value) {
                 callback(new Error('平均振铃时长不能为空'));
               } else {
                 callback();
@@ -522,7 +528,7 @@ export default {
         ],
         avgCallTalkTimeLen: [
           { validator: (rule, value, callback) => {
-            if (this.form.taskType === '0' && !value) {
+              if (this.form.taskType === '0' && !value) {
                 callback(new Error('平均通话时长不能为空'));
               } else {
                 callback();
@@ -531,7 +537,7 @@ export default {
         ],
         avgCallEndProcessTimeLen: [
           { validator: (rule, value, callback) => {
-            if (this.form.taskType === '0' && !value) {
+              if (this.form.taskType === '0' && !value) {
                 callback(new Error('平均事后处理时长不能为空'));
               } else {
                 callback();
@@ -540,7 +546,7 @@ export default {
         ],
         playTimes: [
           { validator: (rule, value, callback) => {
-            if (this.form.taskType === '2' && !value) {
+              if (this.form.taskType === '2' && !value) {
                 callback(new Error('播放次数不能为空'));
               } else {
                 callback();
@@ -551,31 +557,31 @@ export default {
     };
   },
   created() {
-    //获取所有网关
-    listAiSipCallGateway().then(response => {
-     this.gatewayList = response.rows;
-    })
+    // 获取网关列表
+    remoteList({ pageNum:1, pageSize: 500,params:{purposes: [2, 3]} }).then(response => {
+      this.gatewayList = response.rows || [];
+    });
     //获取所有音色并按厂商分类
     listAiSipCallVoiceTtsAliyun({voiceEnabled: 1}).then(response => {
       const allVoices = response.rows || [];
       // voiceSourceList 使用所有音色
       this.voiceSourceList = allVoices;
       // 按 voiceSource 分类
-     this.voiceCodeLists.chinatelecom_tts = allVoices.filter(item => item.voiceSource === 'chinatelecom_tts');
-     this.voiceCodeLists.doubao_vcl_tts = allVoices.filter(item => item.voiceSource === 'doubao_vcl_tts');
-     this.voiceCodeLists.aliyun_tts = allVoices.filter(item => item.voiceSource === 'aliyun_tts');
+      this.voiceCodeLists.chinatelecom_tts = allVoices.filter(item => item.voiceSource === 'chinatelecom_tts');
+      this.voiceCodeLists.doubao_vcl_tts = allVoices.filter(item => item.voiceSource === 'doubao_vcl_tts');
+      this.voiceCodeLists.aliyun_tts = allVoices.filter(item => item.voiceSource === 'aliyun_tts');
     })
     //获取所有大模型底座
     listAiSipCallLlmAgentAccount().then(response => {
-     this.llmAgentAccountList = response.rows;
+      this.llmAgentAccountList = response.rows;
     })
     // 获取所有业务组
     listAiSipCallBizGroup().then(response => {
-     this.bizGroupList = response.rows;
+      this.bizGroupList = response.rows;
     })
 
 
-   this.getList();
+    this.getList();
   },
   methods: {
     downloadCallTemplate(){
@@ -633,11 +639,11 @@ export default {
     },
     // 表单重置
     reset() {
-     this.form = {
+      this.form = {
         batchId: null,
         groupId: null,
-       createTimeStart: null,
-       createTimeEnd: null,
+        createTimeStart: null,
+        createTimeEnd: null,
         batchName: null,
         ifcall: null,
         rate: null,
@@ -664,7 +670,7 @@ export default {
         remoteBatchId: null,
         aiTransferExtNumber: null
       };
-     this.resetForm("form");
+      this.resetForm("form");
     },
     /** 搜索按钮操作 */
     handleQuery() {
@@ -684,71 +690,71 @@ export default {
     },
     /** 新增按钮操作 */
     handleAdd() {
-    this.reset();
-    this.open = true;
-    this.title = "添加 aiSIP 外呼任务";
+      this.reset();
+      this.open = true;
+      this.title = "添加 aiSIP 外呼任务";
       // 默认选中 AI 外呼
-    this.form.taskType = "1";
+      this.form.taskType = "1";
       // 默认自动停止
-    this.form.autoStop = "1";
+      this.form.autoStop = "1";
       // 默认选中第一个外呼线路
-    if (this.gatewayList && this.gatewayList.length > 0) {
-      this.form.gatewayId = this.gatewayList[0].id;
+      if (this.gatewayList && this.gatewayList.length > 0) {
+        this.form.gatewayId = this.gatewayList[0].id;
       }
       // 默认选中第一个大模型底座
-    if (this.llmAgentAccountList && this.llmAgentAccountList.length > 0) {
-      this.form.llmAccountId = this.llmAgentAccountList[0].id;
+      if (this.llmAgentAccountList && this.llmAgentAccountList.length > 0) {
+        this.form.llmAccountId = this.llmAgentAccountList[0].id;
       }
       // 默认选中第一个 TTS 厂商
-    this.form.voiceSource = "chinatelecom_tts";
+      this.form.voiceSource = "chinatelecom_tts";
       // 根据选中的 TTS 厂商设置默认音色
-    this.$nextTick(() => {
-      if (this.voiceCodeLists.chinatelecom_tts && this.voiceCodeLists.chinatelecom_tts.length > 0) {
-        this.form.voiceCode = this.voiceCodeLists.chinatelecom_tts[0].voiceCode;
+      this.$nextTick(() => {
+        if (this.voiceCodeLists.chinatelecom_tts && this.voiceCodeLists.chinatelecom_tts.length > 0) {
+          this.form.voiceCode = this.voiceCodeLists.chinatelecom_tts[0].voiceCode;
         }
       });
       // 默认选中第一个 ASR 厂商
-    this.form.asrProvider = "chinatelecom";
+      this.form.asrProvider = "chinatelecom";
       // 默认选中第一个转人工方式
-    this.form.aiTransferType = "acd";
+      this.form.aiTransferType = "acd";
       // 根据转人工方式设置默认业务组
-    this.$nextTick(() => {
-      if (this.bizGroupList && this.bizGroupList.length > 0) {
-        this.form.groupId = this.bizGroupList[0].groupId;
+      this.$nextTick(() => {
+        if (this.bizGroupList && this.bizGroupList.length > 0) {
+          this.form.groupId = this.bizGroupList[0].groupId;
         }
       });
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
-   this.reset();
+      this.reset();
       const batchId = row.batchId || this.ids
       getAiSipCallTask(batchId).then(response => {
-     this.form = response.data;
+        this.form = response.data;
         // 如果有 voiceSource,设置对应的音色列表
-     if (this.form.voiceSource) {
+        if (this.form.voiceSource) {
           // 不需要重新请求,直接使用已加载的数据
         }
-     this.open = true;
-     this.title = "修改 aiSIP 外呼任务";
+        this.open = true;
+        this.title = "修改 aiSIP 外呼任务";
         // 如果是纯人工预测外呼,设置默认的并发相关字段
-      if (this.form.taskType === '0') {
-        if (!this.form.conntectRate) {
-          this.form.conntectRate = '80';
+        if (this.form.taskType === '0') {
+          if (!this.form.conntectRate) {
+            this.form.conntectRate = '80';
           }
-        if (!this.form.avgRingTimeLen) {
-          this.form.avgRingTimeLen = '30';
+          if (!this.form.avgRingTimeLen) {
+            this.form.avgRingTimeLen = '30';
           }
-        if (!this.form.avgCallTalkTimeLen) {
-          this.form.avgCallTalkTimeLen = '60';
+          if (!this.form.avgCallTalkTimeLen) {
+            this.form.avgCallTalkTimeLen = '60';
           }
-        if (!this.form.avgCallEndProcessTimeLen) {
-          this.form.avgCallEndProcessTimeLen = '30';
+          if (!this.form.avgCallEndProcessTimeLen) {
+            this.form.avgCallEndProcessTimeLen = '30';
           }
         }
         // 如果是语音通知,设置默认播放次数
-      if (this.form.taskType === '2') {
-        if (!this.form.playTimes) {
-          this.form.playTimes = '1';
+        if (this.form.taskType === '2') {
+          if (!this.form.playTimes) {
+            this.form.playTimes = '1';
           }
         }
       });
@@ -777,30 +783,30 @@ export default {
     handleDelete(row) {
       const batchIds = row.batchId || this.ids;
       this.$confirm('是否确认删除aiSIP外呼任务编号为"' + batchIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delAiSipCallTask(batchIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delAiSipCallTask(batchIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有 aiSIP 外呼任务数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportAiSipCallTask(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAiSipCallTask(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
     /** 导入数据按钮操作 */
     handleImportData(batchId) {
@@ -812,7 +818,7 @@ export default {
 
       input.onchange = (event) => {
         const files = event.target.files;
-       if (!files || files.length === 0) {
+        if (!files || files.length === 0) {
           return;
         }
 
@@ -820,19 +826,19 @@ export default {
 
         // 验证文件类型
         const isExcelOrCSV = file.type === 'application/vnd.ms-excel' ||
-                            file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
-                            file.type === 'text/csv' ||
-                            file.name.endsWith('.xlsx') ||
-                            file.name.endsWith('.xls') ||
-                            file.name.endsWith('.csv');
+          file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
+          file.type === 'text/csv' ||
+          file.name.endsWith('.xlsx') ||
+          file.name.endsWith('.xls') ||
+          file.name.endsWith('.csv');
         const isLt100M = file.size / 1024 / 1024 < 100;
 
-       if (!isExcelOrCSV) {
-         this.msgError('只能上传 xlsx/xls/csv 文件!');
+        if (!isExcelOrCSV) {
+          this.msgError('只能上传 xlsx/xls/csv 文件!');
           return;
         }
-       if (!isLt100M) {
-         this.msgError('上传文件大小不能超过 100MB!');
+        if (!isLt100M) {
+          this.msgError('上传文件大小不能超过 100MB!');
           return;
         }
 
@@ -842,14 +848,14 @@ export default {
         formData.append('file', file);
 
         commonImportExcel(formData).then(response => {
-         if (response.code === 200) {
-           this.msgSuccess('导入成功');
-           this.getList();
+          if (response.code === 200) {
+            this.msgSuccess('导入成功');
+            this.getList();
           } else {
-           this.msgError(response.msg || '导入失败');
+            this.msgError(response.msg || '导入失败');
           }
         }).catch(error => {
-         this.msgError('导入失败:' + error.message);
+          this.msgError('导入失败:' + error.message);
         });
       };
 
@@ -859,7 +865,7 @@ export default {
     },
     // 获取当前选中厂商的音色列表
     getCurrentVoiceCodeList() {
-     if (!this.form.voiceSource) {
+      if (!this.form.voiceSource) {
         return [];
       }
       return this.voiceCodeLists[this.form.voiceSource] || [];
@@ -867,50 +873,50 @@ export default {
     // 处理 TTS 厂商变化
     handleVoiceSourceChange() {
       // 清空已选音色
-   this.form.voiceCode = null;
+      this.form.voiceCode = null;
       // 默认选中当前厂商的第一个音色
-    this.$nextTick(() => {
+      this.$nextTick(() => {
         const currentList = this.voiceCodeLists[this.form.voiceSource];
-      if (currentList && currentList.length > 0) {
-        this.form.voiceCode = currentList[0].voiceCode;
+        if (currentList && currentList.length > 0) {
+          this.form.voiceCode = currentList[0].voiceCode;
         }
       });
     },
     // 处理转人工方式变化
     handleAiTransferTypeChange() {
-     if (this.form.aiTransferType === 'extension') {
+      if (this.form.aiTransferType === 'extension') {
         // 选中转分机时,清空业务组
-       this.form.groupId = null;
+        this.form.groupId = null;
       } else if (this.form.aiTransferType === 'acd' || this.form.aiTransferType === 'gateway') {
         // 选中电话排队或转外部网关时,清空转接分机
-       this.form.aiTransferExtNumber = null;
+        this.form.aiTransferExtNumber = null;
       }
     },
     // 处理文件变化
     handleFileChange(event) {
       const files = event.target.files;
-     if (!files || files.length === 0) {
-       return;
+      if (!files || files.length === 0) {
+        return;
       }
 
       const file = files[0];
 
       // 验证文件类型
       const isExcelOrCSV = file.type === 'application/vnd.ms-excel' ||
-                          file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
-                          file.type === 'text/csv' ||
-                          file.name.endsWith('.xlsx') ||
-                          file.name.endsWith('.xls') ||
-                          file.name.endsWith('.csv');
+        file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
+        file.type === 'text/csv' ||
+        file.name.endsWith('.xlsx') ||
+        file.name.endsWith('.xls') ||
+        file.name.endsWith('.csv');
       const isLt100M = file.size / 1024 / 1024 < 100;
 
-     if (!isExcelOrCSV) {
-       this.msgError('只能上传 xlsx/xls/csv 文件!');
-       return;
+      if (!isExcelOrCSV) {
+        this.msgError('只能上传 xlsx/xls/csv 文件!');
+        return;
       }
-     if (!isLt100M) {
-       this.msgError('上传文件大小不能超过 100MB!');
-       return;
+      if (!isLt100M) {
+        this.msgError('上传文件大小不能超过 100MB!');
+        return;
       }
 
       // 创建 FormData 对象并调用接口
@@ -920,17 +926,26 @@ export default {
 
       // 调用 importExcel 接口
       commonImportExcel(formData).then(response => {
-       if (response.code === 200) {
-         this.msgSuccess('导入成功');
-         this.uploadOpen = false;
-         this.getList();
+        if (response.code === 200) {
+          this.msgSuccess('导入成功');
+          this.uploadOpen = false;
+          this.getList();
         } else {
-         this.msgError(response.msg || '导入失败');
+          this.msgError(response.msg || '导入失败');
         }
       }).catch(error => {
-       this.msgError('导入失败:' + error.message);
+        this.msgError('导入失败:' + error.message);
       });
     },
+    // 格式化接通率显示
+    formatConnectRate(rate) {
+      // 如果为空或为 0,返回 0.00%
+      if (!rate || rate === 0 || rate === '0') {
+        return '0.00%';
+      }
+      // 否则保留两位小数并添加%
+      return parseFloat(rate).toFixed(2) + '%';
+    },
 
   }
 };

+ 81 - 38
src/views/aiSipCall/aiSipCallUser.vue

@@ -51,7 +51,7 @@
           size="mini"
           :disabled="single"
           @click="handleUpdate"
-          v-hasPermi="['aiSipCallUser:aiSipCallUser:edit']"
+          v-hasPermi="['company:aiSipCallUser:aiSipCallUser:edit']"
         >修改
         </el-button>
       </el-col>
@@ -63,7 +63,7 @@
       <!--          size="mini"-->
       <!--          :disabled="multiple"-->
       <!--          @click="handleDelete"-->
-      <!--          v-hasPermi="['aiSipCallUser:aiSipCallUser:remove']"-->
+      <!--          v-hasPermi="['company:aiSipCallUser:aiSipCallUser:remove']"-->
       <!--        >删除</el-button>-->
       <!--      </el-col>-->
       <el-col :span="1.5">
@@ -74,7 +74,7 @@
           size="mini"
           :loading="exportLoading"
           @click="handleExport"
-          v-hasPermi="['aiSipCallUser:aiSipCallUser:export']"
+          v-hasPermi="['company:aiSipCallUser:aiSipCallUser:export']"
         >导出
         </el-button>
       </el-col>
@@ -83,11 +83,11 @@
 
     <el-table border v-loading="loading" :data="aiSipCallUserList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center"/>
-<!--      <el-table-column label="用户ID" align="center" prop="userId"/>-->
+      <!--      <el-table-column label="用户ID" align="center" prop="userId"/>-->
       <el-table-column label="登录账号" align="center" prop="loginName"/>
       <el-table-column label="用户姓名" align="center" prop="userName"/>
       <el-table-column label="手机号码" align="center" prop="phonenumber"/>
-<!--      <el-table-column label="用户邮箱" align="center" prop="email"/>-->
+      <!--      <el-table-column label="用户邮箱" align="center" prop="email"/>-->
       <el-table-column label="用户性别" align="center" prop="sex">
         <template slot-scope="scope">
           <span v-if="scope.row.sex == '0'">男</span>
@@ -104,6 +104,11 @@
         </template>
       </el-table-column>
       <el-table-column label="绑定分机号" align="center" prop="extNum"/>
+      <el-table-column label="绑定网关" align="center" prop="gatewayIds">
+        <template slot-scope="scope">
+          <span>{{ getGatewayNames(scope.row.gatewayIds) }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="备注" align="center" prop="remark"/>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@@ -113,7 +118,7 @@
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
-            v-hasPermi="['aiSipCallUser:aiSipCallUser:edit']"
+            v-hasPermi="['company:aiSipCall:aiSipCallUser:edit']"
           >修改
           </el-button>
           <!--          <el-button-->
@@ -121,7 +126,7 @@
           <!--            type="text"-->
           <!--            icon="el-icon-delete"-->
           <!--            @click="handleDelete(scope.row)"-->
-          <!--            v-hasPermi="['aiSipCallUser:aiSipCallUser:remove']"-->
+          <!--            v-hasPermi="['company:aiSipCallUser:aiSipCallUser:remove']"-->
           <!--          >删除</el-button>-->
         </template>
       </el-table-column>
@@ -178,6 +183,16 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="网关" prop="gatewayIds">
+          <el-select v-model="selectedGateways" placeholder="请选择网关" multiple collapse-tags>
+            <el-option
+              v-for="item in gateways"
+              :key="item.id"
+              :label="item.gwDesc"
+              :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"/>
         </el-form-item>
@@ -200,6 +215,7 @@ import {
   exportAiSipCallUser,
   getUnBindExtnum
 } from "@/api/aiSipCall/aiSipCallUser";
+import {remoteList} from "../../api/aiSipCall/aiSipCallGateway";
 
 export default {
   name: "AiSipCallUser",
@@ -223,6 +239,10 @@ export default {
       aiSipCallUserList: [],
       // 分机号码下拉选项
       extNumOptions: [],
+      //网关列表
+      gateways: [],
+      // 选中的网关
+      selectedGateways: [],
       // 是否显示弹出层
       open: false,
       // 查询参数
@@ -286,10 +306,18 @@ export default {
           this.form.sex = Number(this.form.sex);
           // 修改时将密码设置为 null,不显示密码输入框
           this.form.password = null;
+          // 如果有网关字符串,分割为数组并转换为数字类型
+          if (this.form.gatewayIds) {
+            this.selectedGateways = this.form.gatewayIds.split(',').map(id => Number(id));
+          }
           // 获取最新的未绑定分机号列表
           getUnBindExtnum().then(res => {
             this.extNumOptions = res.data || [];
           });
+          // 获取网关列表
+          remoteList({ pageNum:1, pageSize: 500,params:{purposes: [1, 3]} }).then(response => {
+            this.gateways = response.rows || [];
+          });
           this.open = true;
           // 显示具体的员工姓名
           const employeeName = this.form.userName || '未知角色';
@@ -318,17 +346,29 @@ export default {
         this.extNumOptions = response.data || [];
       });
 
+      // 获取网关列表
+      remoteList({ pageNum:1, pageSize: 500,params:{purposes: [1, 3]} }).then(response => {
+        this.gateways = response.rows || [];
+      });
+
       this.open = true;
       // 显示具体的员工姓名
       const employeeName = nickName || '未知员工';
       this.title = `添加 sip 外呼角色 - ${employeeName}`;
     },
-    /** 查询sip用户信息列表 */
+    /** 查询 sip 用户信息列表 */
     getList() {
       this.loading = true;
-      listAiSipCallUser(this.queryParams).then(response => {
-        this.aiSipCallUserList = response.rows;
-        this.total = response.total;
+      // 先获取网关列表
+      remoteList({ pageNum:1, pageSize: 500,params:{purposes: [1, 3]} }).then(response => {
+        this.gateways = response.rows || [];
+        // 再获取用户列表
+        listAiSipCallUser(this.queryParams).then(response => {
+          this.aiSipCallUserList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        });
+      }).catch(() => {
         this.loading = false;
       });
     },
@@ -340,31 +380,9 @@ export default {
     // 表单重置
     reset() {
       this.form = {
-        userId: null,
-        deptId: null,
-        loginName: null,
-        userName: null,
-        userType: null,
-        email: null,
-        phonenumber: null,
-        sex: 0,
-        avatar: null,
-        password: '123456',
-        salt: null,
-        status: 0,
-        delFlag: null,
-        loginIp: null,
-        loginDate: null,
-        pwdUpdateDate: null,
-        createBy: null,
-        createTime: null,
-        updateBy: null,
-        updateTime: null,
-        remark: null,
-        logo: null,
-        companyUserId: null,
-        extNum: null
+        password: '123456'
       };
+      this.selectedGateways = [];
       this.passwordVisible = false;
       this.resetForm("form");
     },
@@ -401,12 +419,20 @@ export default {
         this.form.sex = Number(this.form.sex);
         // 修改时将密码设置为 null,不显示密码输入框
         this.form.password = null;
+        // 如果有网关字符串,分割为数组并转换为数字类型
+        if (this.form.gatewayIds) {
+          this.selectedGateways = this.form.gatewayIds.split(',').map(id => Number(id));
+        }
         // 获取最新的未绑定分机号列表
         getUnBindExtnum().then(res => {
           this.extNumOptions = res.data || [];
         });
-        this.open = true;
-        this.title = "修改 sip 用户信息";
+        // 获取网关列表
+        remoteList({ pageNum:1, pageSize: 500,params:{purposes: [1, 3]} }).then(response => {
+          this.gateways = response.rows || [];
+          this.open = true;
+          this.title = "修改 sip 用户信息";
+        });
       });
     },
     // 切换密码显示/隐藏
@@ -417,6 +443,9 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
+          // 将选中的网关数组用逗号拼接成字符串
+          this.form.gatewayIds = this.selectedGateways.join(',');
+
           if (this.form.userId != null) {
             updateAiSipCallUser(this.form).then(response => {
               this.msgSuccess("修改成功");
@@ -455,7 +484,7 @@ export default {
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有 sip用户信息数据项?', "警告", {
+      this.$confirm('是否确认导出所有 sip 用户信息数据项?', "警告", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning"
@@ -468,6 +497,20 @@ export default {
       }).catch(() => {
       })
     },
+    /** 根据网关 IDs 获取网关名称 */
+    getGatewayNames(gatewayIds) {
+      if (!gatewayIds) {
+        return '';
+      }
+      const ids = gatewayIds.split(',').map(id => Number(id));
+      const names = ids
+        .map(id => {
+          const gateway = this.gateways.find(gw => gw.id === id);
+          return gateway ? gateway.gwDesc : '';
+        })
+        .filter(name => name);
+      return names.join(', ');
+    }
   }
 };
 </script>

+ 87 - 87
src/views/aiSipCall/aiSipCallVoiceTtsAliyun.vue

@@ -19,15 +19,15 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-<!--      <el-form-item label="是否启用" prop="voiceEnabled">-->
-<!--        <el-input-->
-<!--          v-model="queryParams.voiceEnabled"-->
-<!--          placeholder="请输入是否启用"-->
-<!--          clearable-->
-<!--          size="small"-->
-<!--          @keyup.enter.native="handleQuery"-->
-<!--        />-->
-<!--      </el-form-item>-->
+      <!--      <el-form-item label="是否启用" prop="voiceEnabled">-->
+      <!--        <el-input-->
+      <!--          v-model="queryParams.voiceEnabled"-->
+      <!--          placeholder="请输入是否启用"-->
+      <!--          clearable-->
+      <!--          size="small"-->
+      <!--          @keyup.enter.native="handleQuery"-->
+      <!--        />-->
+      <!--      </el-form-item>-->
       <el-form-item label="声音源" prop="voiceSource">
         <el-select
           v-model="queryParams.voiceSource"
@@ -48,49 +48,49 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="primary"-->
-<!--          plain-->
-<!--          icon="el-icon-plus"-->
-<!--          size="mini"-->
-<!--          @click="handleAdd"-->
-<!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:add']"-->
-<!--        >新增</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="success"-->
-<!--          plain-->
-<!--          icon="el-icon-edit"-->
-<!--          size="mini"-->
-<!--          :disabled="single"-->
-<!--          @click="handleUpdate"-->
-<!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:edit']"-->
-<!--        >修改</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="danger"-->
-<!--          plain-->
-<!--          icon="el-icon-delete"-->
-<!--          size="mini"-->
-<!--          :disabled="multiple"-->
-<!--          @click="handleDelete"-->
-<!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:remove']"-->
-<!--        >删除</el-button>-->
-<!--      </el-col>-->
-<!--      <el-col :span="1.5">-->
-<!--        <el-button-->
-<!--          type="warning"-->
-<!--          plain-->
-<!--          icon="el-icon-download"-->
-<!--          size="mini"-->
-<!--          :loading="exportLoading"-->
-<!--          @click="handleExport"-->
-<!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:export']"-->
-<!--        >导出</el-button>-->
-<!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="primary"-->
+      <!--          plain-->
+      <!--          icon="el-icon-plus"-->
+      <!--          size="mini"-->
+      <!--          @click="handleAdd"-->
+      <!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:add']"-->
+      <!--        >新增</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="success"-->
+      <!--          plain-->
+      <!--          icon="el-icon-edit"-->
+      <!--          size="mini"-->
+      <!--          :disabled="single"-->
+      <!--          @click="handleUpdate"-->
+      <!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:edit']"-->
+      <!--        >修改</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="danger"-->
+      <!--          plain-->
+      <!--          icon="el-icon-delete"-->
+      <!--          size="mini"-->
+      <!--          :disabled="multiple"-->
+      <!--          @click="handleDelete"-->
+      <!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:remove']"-->
+      <!--        >删除</el-button>-->
+      <!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="warning"-->
+      <!--          plain-->
+      <!--          icon="el-icon-download"-->
+      <!--          size="mini"-->
+      <!--          :loading="exportLoading"-->
+      <!--          @click="handleExport"-->
+      <!--          v-hasPermi="['company:aiSipCall:voiceTtsAliyun:export']"-->
+      <!--        >导出</el-button>-->
+      <!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -102,22 +102,22 @@
       <el-table-column label="声音源" align="center" prop="voiceSource" />
       <el-table-column label="远程音色ID" align="center" prop="remoteVoiceTtsAliyunId" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-<!--        <template slot-scope="scope">-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-edit"-->
-<!--            @click="handleUpdate(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:voiceTtsAliyun:edit']"-->
-<!--          >修改</el-button>-->
-<!--          <el-button-->
-<!--            size="mini"-->
-<!--            type="text"-->
-<!--            icon="el-icon-delete"-->
-<!--            @click="handleDelete(scope.row)"-->
-<!--            v-hasPermi="['company:aiSipCall:voiceTtsAliyun:remove']"-->
-<!--          >删除</el-button>-->
-<!--        </template>-->
+        <!--        <template slot-scope="scope">-->
+        <!--          <el-button-->
+        <!--            size="mini"-->
+        <!--            type="text"-->
+        <!--            icon="el-icon-edit"-->
+        <!--            @click="handleUpdate(scope.row)"-->
+        <!--            v-hasPermi="['company:aiSipCall:voiceTtsAliyun:edit']"-->
+        <!--          >修改</el-button>-->
+        <!--          <el-button-->
+        <!--            size="mini"-->
+        <!--            type="text"-->
+        <!--            icon="el-icon-delete"-->
+        <!--            @click="handleDelete(scope.row)"-->
+        <!--            v-hasPermi="['company:aiSipCall:voiceTtsAliyun:remove']"-->
+        <!--          >删除</el-button>-->
+        <!--        </template>-->
       </el-table-column>
     </el-table>
 
@@ -304,30 +304,30 @@ export default {
     handleDelete(row) {
       const ids = row.id || this.ids;
       this.$confirm('是否确认删除aiSIP外呼阿里云音色编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delAiSipCallVoiceTtsAliyun(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delAiSipCallVoiceTtsAliyun(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有aiSIP外呼阿里云音色数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportAiSipCallVoiceTtsAliyun(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAiSipCallVoiceTtsAliyun(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 11 - 1
src/views/company/companyUser/index.vue

@@ -297,6 +297,8 @@
               <el-button v-if="scope.row.userType !== '00'" size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['company:user:edit']">修改</el-button>
               <el-button v-if="scope.row.userType !== '00'" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['company:user:remove']">删除</el-button>
               <el-button size="mini" type="text" icon="el-icon-key" @click="handleResetPwd(scope.row)" v-hasPermi="['company:user:resetPwd']">重置密码</el-button>
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="checkBindSipCallUser(scope.row)" v-if="scope.row.aiSipCallUserId==null">绑定sip角色</el-button>
+              <el-button size="mini" type="text" icon="el-icon-search" @click="checkChangeSipCallUser(scope.row)" v-if="scope.row.aiSipCallUserId">修改sip角色</el-button>
             </template>
           </el-table-column>
         </el-table>
@@ -698,7 +700,7 @@
     <el-dialog :title="doctor.title" :visible.sync="doctor.open" width="800px" append-to-body>
       <selectDoctor ref="selectDoctor" @bindCompanyUserDoctorId="bindCompanyUserDoctorId"></selectDoctor>
     </el-dialog>
-
+    <ai-sip-call-user ref="aiSipCallUser" v-show="false" @refreshParentData="getList" />
   </div>
 </template>
 
@@ -966,6 +968,14 @@ export default {
     });
   },
   methods: {
+    checkBindSipCallUser(row){
+
+      this.$refs.aiSipCallUser.handleAddCompanyUserOnSip(row.userName,row.nickName,row.userId);
+
+    },
+    checkChangeSipCallUser(row){
+      this.$refs.aiSipCallUser.handleUpdateById(row.aiSipCallUserId);
+    },
     //用户绑定cidserver服务器
     handleBindCidServer(row){
       let param = {

Неке датотеке нису приказане због велике количине промена