| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317 |
- /*
- * 呼叫中心电话工具条
- * author: easycallcenter365@126.com
- * 2025-04-08
- * 修改:增强断开清理,优化重连状态,修复isCalling死锁
- */
- import $ from './jquery-1.11.0.js';
- function _phoneBarObserver() {
- 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) {
- var keys = [key];
- if (key != null && String(key) !== key) keys.push(String(key));
- keys.forEach(function(keyName) {
- if (keyName == null || !this.listeners[keyName]) return;
- for (var i = 0; i < this.listeners[keyName].length; i++) {
- if (typeof this.listeners[keyName][i] === 'function') {
- this.listeners[keyName][i](info);
- }
- }
- }, this);
- },
- make: function(o) {
- for (var i in this) {
- o[i] = this[i];
- o.listeners = {};
- }
- }
- };
- "use strict";
- function ccPhoneBarSocket() {
- var observer = new _phoneBarObserver();
- observer.make(this);
- var _cc = this;
- var ws = null;
- var wsuri = null;
- var _connectPending = false;
- var _sendQueue = [];
- var _kickedByOtherDevice = false;
- var _everConnected = false;
- var _reconnectSeq = 0;
- var _reconnectAttemptAt = 0;
- var _reconnect201RetryCount = 0;
- var _staleCloseTimer = null;
- var MAX_201_RETRY = 5;
- var CONNECT_RACE_WINDOW_MS = 12000;
- var STALE_CLOSE_DELAY_MS = 400;
- var RECOVERING_CALL_CLEAR_MS = 5000;
- var RETRY_201_BASE_MS = 400;
- var RETRY_201_STEP_MS = 300;
- var isConnected = false;
- var callConnected = false;
- var canSendVideoReInvite = false;
- this.subscribeAgentListStarted = false;
- this.iframe = null;
- this.isCalling = false; // 防止重复外呼
- this._intentionalDisconnect = false;
- this.resetOutboundLock = function() {
- this.isCalling = false;
- };
- this._activeCallUuid = null;
- this._recoveringCall = false;
- this._suppressSessionNotFound = false;
- this.setActiveCallUuid = function(uuid) {
- if (uuid) this._activeCallUuid = String(uuid);
- };
- this.getActiveCallUuid = function() {
- return this._activeCallUuid;
- };
- this.clearActiveCallUuid = function() {
- this._activeCallUuid = null;
- this._recoveringCall = false;
- };
- this._captureCallUuid = function(msg) {
- if (msg && msg.object && msg.object.uuid) {
- this.setActiveCallUuid(msg.object.uuid);
- }
- };
- this.restoreCallSession = function() {
- if (!this._activeCallUuid) return;
- if (!ws || ws.readyState !== WebSocket.OPEN) return;
- console.log('[IPCC] 重连后恢复本地通话状态 uuid=', this._activeCallUuid);
- this._recoveringCall = true;
- callConnected = true;
- };
- this.callConfig = {
- 'useDefaultUi': false,
- 'ipccServer': 'sip.ylrzcloud.com',
- 'enableWss': true,
- 'callCodec': 'pcma',
- 'enableHeartBeat': true,
- 'heartBeatIntervalSecs': 16,
- 'useSameAudioCodeForOutbound': true,
- 'loginToken': '',
- 'gatewayList': [{
- uuid: '01',
- updateTime: 1675953810492,
- gatewayAddr: '113.207.68.30:5543;external',
- callerNumber: '02386990208',
- calleePrefix: '',
- priority: 1,
- concurrency: 1000,
- register: false,
- audioCodec: 'g711'
- }],
- 'gatewayEncrypted': false,
- 'fsServer': '129.28.164.235:5060',
- 'groupId': '1',
- 'groups': null,
- 'agentList': null,
- 'phoneType': 'EyeBeam',
- 'webPhoneUrl': 'None',
- 'localHostProxyVersion': 'v20221130_1736',
- 'localHostProxyPort': 8888
- };
- 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; };
- this.getCallConnected = function() { return callConnected; };
- this.setCallConnected = function(value) { callConnected = value; };
- this.setCanSendVideoReInvite = function(value) { canSendVideoReInvite = value; };
- this.getCanSendVideoReInvite = function() { return canSendVideoReInvite; };
- this.heartbeatTimer = null;
- // 与 phone-bar-ex.html 一致:status 200 / 重连后重置心跳定时器
- this.setHeartbeat = function() {
- if (this.heartbeatTimer) {
- clearInterval(this.heartbeatTimer);
- this.heartbeatTimer = null;
- }
- if (!_cc.callConfig.enableHeartBeat) return;
- var intervalSec = _cc.callConfig.heartBeatIntervalSecs || 16;
- this.heartbeatTimer = setInterval(function() {
- if (!_cc.callConfig.enableHeartBeat) return;
- if (!_cc.getIsConnected()) return;
- if (!ws || ws.readyState !== WebSocket.OPEN) {
- console.warn('[heartbeat] WebSocket未连接,停止心跳');
- if (_cc.heartbeatTimer) {
- clearInterval(_cc.heartbeatTimer);
- _cc.heartbeatTimer = null;
- }
- return;
- }
- console.debug('[heartbeat] 发送心跳');
- try {
- _cc.sendMsg({ action: 'setHearBeat', body: '{}' });
- } catch (e) {
- console.error('[heartbeat] 发送心跳失败:', e);
- if (_cc.heartbeatTimer) {
- clearInterval(_cc.heartbeatTimer);
- _cc.heartbeatTimer = null;
- }
- }
- }, intervalSec * 1000);
- console.log('[heartbeat] 心跳已启动,间隔:', intervalSec, '秒');
- };
- 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);
- };
- this.initConfig = function(config) {
- 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));
- 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) this.setHeartbeat();
- if (_cc.callConfig["useDefaultUi"]) this.initPhoneBarUI();
- };
- 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() {
- if (callConnected) {
- console.warn('[disconnect] 通话进行中,拒绝断开 IPPC 连接');
- return;
- }
- _cc._performDisconnect();
- };
- /** 强制断开(清理/切线路时使用,忽略通话态) */
- this.forceDisconnect = function() {
- callConnected = false;
- _cc._activeCallUuid = null;
- _cc._recoveringCall = false;
- _cc._performDisconnect();
- };
- this._performDisconnect = function() {
- console.log('[disconnect] 开始断开IPCC连接');
- this._intentionalDisconnect = true;
- if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; }
- if (!ws || ws.readyState !== WebSocket.OPEN) {
- if (ws) {
- ws.onmessage = null;
- ws.onclose = null;
- ws.onopen = null;
- ws.onerror = null;
- ws.close();
- ws = null;
- }
- isConnected = false;
- _connectPending = false;
- this.isCalling = false;
- return;
- }
- try {
- ws.onmessage = null;
- ws.onclose = null;
- ws.onopen = null;
- ws.onerror = null;
- var cmdInfo = {};
- cmdInfo.action = "setAgentStatus";
- cmdInfo.body = { "cmd": "disconnect", "args": { "msg": "disconnection opt triggered by js client." } };
- _cc.sendMsg(cmdInfo);
- console.log('[disconnect] 已发送断开指令');
- } catch(e) { console.error('[disconnect] 发送断开指令失败:', e); }
- try { ws.close(); } catch(e) { console.error('[disconnect] 关闭WebSocket失败:', e); }
- ws = null;
- isConnected = false;
- _connectPending = false;
- this.isCalling = false;
- console.log('[disconnect] IPCC连接已完全断开');
- };
- /** 断开并等待 WebSocket 关闭,避免同 token 新连接与旧会话冲突导致 201 */
- this.disconnectAndWait = function(timeoutMs) {
- timeoutMs = timeoutMs || 2000;
- var _ccRef = this;
- return new Promise(function(resolve) {
- if (callConnected) {
- console.warn('[disconnectAndWait] 通话进行中,跳过断开');
- resolve(false);
- return;
- }
- var finished = false;
- function done() {
- if (finished) return;
- finished = true;
- _ccRef._intentionalDisconnect = true;
- _connectPending = false;
- isConnected = false;
- _ccRef.isCalling = false;
- resolve(true);
- }
- var timer = setTimeout(done, timeoutMs);
- if (_ccRef.heartbeatTimer) {
- clearInterval(_ccRef.heartbeatTimer);
- _ccRef.heartbeatTimer = null;
- }
- if (!ws) {
- clearTimeout(timer);
- done();
- return;
- }
- var closing = ws;
- var state = closing.readyState;
- if (state === WebSocket.CLOSED) {
- ws = null;
- clearTimeout(timer);
- done();
- return;
- }
- try {
- closing.onmessage = null;
- closing.onopen = null;
- closing.onerror = null;
- closing.onclose = function() {
- if (ws === closing) ws = null;
- clearTimeout(timer);
- done();
- };
- if (state === WebSocket.OPEN) {
- try {
- closing.send(JSON.stringify({
- action: "setAgentStatus",
- body: { cmd: "disconnect", args: { msg: "disconnection opt triggered by js client." } }
- }));
- } catch (e) {}
- }
- closing.close();
- } catch (e) {
- if (ws === closing) ws = null;
- clearTimeout(timer);
- done();
- }
- });
- };
- this.getExtNum = function() { return this.callConfig.extnum; };
- this.getOpNum = function() { return this.callConfig.opnum; };
- this.getGroupId = function() { return this.callConfig.groupId; };
- 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) {
- 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);
- }
- }
- };
- function _isCurrentSocket(socket) {
- return ws === socket;
- }
- function _safeSendOnSocket(socket, jsonObject) {
- if (_kickedByOtherDevice) {
- console.warn('[sendMsg] 账号已在其他设备登录,拒绝发送');
- return false;
- }
- if (!socket) return false;
- var state = socket.readyState;
- if (state === WebSocket.OPEN) {
- try {
- socket.send(JSON.stringify(jsonObject));
- return true;
- } catch (e) {
- console.error('[sendMsg] 发送失败:', e);
- return false;
- }
- }
- if (state === WebSocket.CONNECTING && socket === ws) {
- _sendQueue.push(jsonObject);
- return true;
- }
- console.warn('[sendMsg] WebSocket 未就绪, readyState=', state);
- return false;
- }
- function _flushSendQueue(socket) {
- if (!_isCurrentSocket(socket) || socket.readyState !== WebSocket.OPEN) return;
- while (_sendQueue.length) {
- try {
- socket.send(JSON.stringify(_sendQueue.shift()));
- } catch (e) {
- console.error('[sendMsg] 刷新发送队列失败:', e);
- break;
- }
- }
- }
- this.resetKickedState = function() {
- _kickedByOtherDevice = false;
- _reconnect201RetryCount = 0;
- };
- this._handleKickedByOtherDevice = function(msg, sourceSocket) {
- if (sourceSocket && ws && ws !== sourceSocket) {
- if (isConnected && ws.readyState === WebSocket.OPEN) {
- console.warn('[IPCC] 已有有效连接,忽略过期连接的201');
- try {
- sourceSocket.onmessage = null;
- sourceSocket.onclose = null;
- sourceSocket.close();
- } catch (e) {}
- return;
- }
- }
- if (isConnected && ws && ws.readyState === WebSocket.OPEN && (!sourceSocket || sourceSocket === ws)) {
- console.error('[IPCC] 当前连接收到201,确认被踢下线');
- }
- console.error('[IPCC] 用户已在其他设备登录(201),停止重连');
- _kickedByOtherDevice = true;
- _connectPending = false;
- _cc._intentionalDisconnect = true;
- isConnected = false;
- _sendQueue = [];
- if (_cc.heartbeatTimer) { clearInterval(_cc.heartbeatTimer); _cc.heartbeatTimer = null; }
- _cc.notifyAll(ccPhoneBarSocket.eventList.user_login_on_other_device, msg);
- var closing = sourceSocket || ws;
- if (closing) {
- try {
- closing.onmessage = null;
- closing.onclose = null;
- closing.onopen = null;
- closing.onerror = null;
- closing.close();
- } catch (e) {}
- if (ws === closing) ws = null;
- }
- };
- function _scheduleOpenAfterStale(mySeq, delayMs) {
- if (_staleCloseTimer) clearTimeout(_staleCloseTimer);
- _staleCloseTimer = setTimeout(function() {
- _staleCloseTimer = null;
- if (mySeq !== _reconnectSeq || _kickedByOtherDevice) {
- _connectPending = false;
- return;
- }
- _createWebSocketConnection();
- }, delayMs);
- }
- this.connect = function() {
- console.log('[connect] 开始建立IPCC WebSocket连接');
- if (_kickedByOtherDevice) {
- console.warn('[connect] 已在其他设备登录,停止重连');
- return;
- }
- if (ws && ws.readyState === WebSocket.OPEN) {
- if (callConnected) {
- console.log('[connect] WebSocket 已连接且通话中,跳过重连');
- return;
- }
- console.log('[connect] WebSocket 已连接,无需重复连接');
- _connectPending = false;
- return;
- }
- if (ws && ws.readyState === WebSocket.CONNECTING) {
- console.log('[connect] WebSocket 正在连接中,请勿重复操作');
- return;
- }
- if (_connectPending) {
- console.log('[connect] 连接任务已排队,跳过重复 connect');
- return;
- }
- _connectPending = true;
- _reconnectAttemptAt = Date.now();
- _reconnectSeq++;
- var mySeq = _reconnectSeq;
- this._intentionalDisconnect = false;
- if (ws) {
- console.log('[connect] 检测到旧连接,等待关闭后再建连, readyState:', ws.readyState);
- var stale = ws;
- isConnected = false;
- _sendQueue = [];
- try {
- stale.onmessage = null;
- stale.onopen = null;
- stale.onerror = null;
- stale.onclose = function(evt) {
- if (ws === stale) ws = null;
- console.log('[connect] 旧连接已关闭, code=', evt && evt.code);
- if (mySeq !== _reconnectSeq) {
- _connectPending = false;
- return;
- }
- _scheduleOpenAfterStale(mySeq, STALE_CLOSE_DELAY_MS);
- };
- if (stale.readyState === WebSocket.OPEN || stale.readyState === WebSocket.CONNECTING) {
- stale.close();
- } else if (ws === stale) {
- ws = null;
- _scheduleOpenAfterStale(mySeq, 400);
- }
- } catch (e) {
- console.error('[connect] 关闭旧连接失败:', e);
- if (ws === stale) ws = null;
- _scheduleOpenAfterStale(mySeq, STALE_CLOSE_DELAY_MS);
- }
- return;
- }
- _scheduleOpenAfterStale(mySeq, 100);
- };
- this.reconnect = function() {
- this.connect();
- };
- function _createWebSocketConnection() {
- console.log('[connect] 开始创建新的WebSocket连接');
- if (!('WebSocket' in window)) {
- _connectPending = false;
- console.log('您的浏览器不支持 websocket,您无法使用本页面的功能!');
- return;
- }
- var socket = new WebSocket(wsuri);
- ws = socket;
- _sendQueue = [];
- socket.onmessage = function(evt) {
- if (!_isCurrentSocket(socket)) return;
- 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:
- _everConnected = true;
- _connectPending = false;
- _reconnect201RetryCount = 0;
- 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');
- _cc.notifyAll(ccPhoneBarSocket.eventList.ws_connected, msg);
- if (callConnected || _cc._activeCallUuid) {
- _cc.restoreCallSession();
- setTimeout(function() {
- if (_cc.getIsConnected()) _cc._recoveringCall = false;
- }, RECOVERING_CALL_CLEAR_MS);
- } else {
- _safeSendOnSocket(socket, {
- action: "setAgentStatus",
- body: { cmd: "setStatus", args: { status: ccPhoneBarSocket.agentStatusEnum.busy } }
- });
- }
- _cc.setHeartbeat();
- break;
- default:
- if (parseInt(resp_status) === 201) {
- if (isConnected && ws && ws !== socket && ws.readyState === WebSocket.OPEN) {
- console.warn('[IPCC] 有效连接已建立,忽略迟到的201');
- try { socket.close(); } catch (e) {}
- return;
- }
- var isConnectRace = (Date.now() - _reconnectAttemptAt < CONNECT_RACE_WINDOW_MS) &&
- _reconnect201RetryCount < MAX_201_RETRY;
- if (isConnectRace && _isCurrentSocket(socket)) {
- _reconnect201RetryCount++;
- console.warn('[IPCC] 连接竞态201,第', _reconnect201RetryCount, '次自动重试');
- _connectPending = false;
- isConnected = false;
- try {
- socket.onmessage = null;
- socket.onclose = null;
- socket.onopen = null;
- socket.onerror = null;
- socket.close();
- } catch (e) {}
- if (ws === socket) ws = null;
- setTimeout(function() {
- if (!_kickedByOtherDevice && !(isConnected && ws && ws.readyState === WebSocket.OPEN)) {
- _cc.connect();
- }
- }, RETRY_201_BASE_MS + _reconnect201RetryCount * RETRY_201_STEP_MS);
- return;
- }
- _cc._handleKickedByOtherDevice(msg, socket);
- return;
- }
- _cc._captureCallUuid(msg);
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.asr_result_generate)) {
- _cc._recoveringCall = false;
- }
- var hangupCode = parseInt(resp_status);
- var isHangupEvent = hangupCode === parseInt(ccPhoneBarSocket.eventList.caller_hangup) ||
- hangupCode === parseInt(ccPhoneBarSocket.eventList.callee_hangup) ||
- hangupCode === parseInt(ccPhoneBarSocket.eventList.CONFERENCE_MODERATOR_HANGUP);
- if (isHangupEvent) {
- _cc.notifyAll(resp_status, msg);
- }
- if (parseInt(resp_status) === 400) {
- var errText = (msg["msg"] || "").toString();
- if (errText.indexOf("method not support") >= 0) {
- console.debug('[SDK] 服务端不支持的方法,已忽略:', errText);
- break;
- }
- if (errText.indexOf("通话不存在") >= 0 || errText.indexOf("不存在") >= 0) {
- if (_cc._suppressSessionNotFound || !_cc.getCallConnected()) {
- console.debug('[SDK] 挂机后会话已不存在,已忽略:', errText);
- } else {
- console.warn('[SDK] 服务端无通话会话:', errText);
- _cc.notifyAll('call_session_not_found', msg);
- }
- } else {
- _cc.isCalling = false;
- console.log('[SDK] 请求参数错误, status: 400', errText);
- }
- } else if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.server_error)) {
- _cc.isCalling = false;
- console.log('[SDK] 发生错误,已重置 isCalling = false, status:', resp_status);
- }
- 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;
- _cc.clearActiveCallUuid();
- console.log("caller_hangup");
- }
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.caller_answered)) {
- // 外呼:600=分机已接通,客户仍在振铃;桥接期需标记通话活跃,避免误判挂机
- _cc.setCallConnected(true);
- }
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_hangup)) {
- _cc.isCalling = false;
- _cc.setCallConnected(false);
- _cc.clearActiveCallUuid();
- }
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.extension_off_line)) {
- _cc.isCalling = false;
- if (_cc.getCallConnected()) {
- _cc.setCallConnected(false);
- _cc.clearActiveCallUuid();
- }
- }
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_answered)) {
- _cc.setCallConnected(true);
- _cc._recoveringCall = false;
- console.log("callee_answered");
- }
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.OUTBOUND_START)) {
- _cc.setCallConnected(true);
- }
- if (parseInt(resp_status) === parseInt(ccPhoneBarSocket.eventList.callee_busy)) {
- console.warn("callee_busy or rejected");
- _cc.isCalling = false;
- }
- 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));
- }
- }
- if (!isHangupEvent) {
- _cc.notifyAll(resp_status, msg);
- }
- break;
- }
- };
- socket.onclose = function(evt) {
- if (!_isCurrentSocket(socket)) {
- console.log('[onclose] 忽略已作废连接的关闭事件');
- return;
- }
- console.log('[onclose] IPCC WebSocket关闭事件触发');
- console.log('[onclose] evt.code:', evt.code, ', evt.reason:', evt.reason, ', evt.wasClean:', evt.wasClean);
- const intentional = _cc._intentionalDisconnect || _kickedByOtherDevice;
- _cc._intentionalDisconnect = false;
- _connectPending = false;
- isConnected = false;
- _sendQueue = [];
- if (_cc.heartbeatTimer) { clearInterval(_cc.heartbeatTimer); _cc.heartbeatTimer = null; }
- ws = null;
- if (_kickedByOtherDevice) {
- console.log('[onclose] 其他设备登录导致断开');
- return;
- }
- if (!callConnected && !_cc._activeCallUuid) {
- _cc.isCalling = false;
- }
- if (intentional || (evt.wasClean && evt.code === 1000)) {
- console.log('[onclose] 主动/正常关闭,不触发异常断开事件');
- } else {
- console.warn('[onclose] 异常断开,通知前端');
- _cc.notifyAll(ccPhoneBarSocket.eventList.ws_disconnected, "ipccserver 连接断开.");
- }
- console.log('[onclose] 连接状态已更新');
- };
- socket.onerror = function(evt) {
- if (!_isCurrentSocket(socket)) return;
- console.warn('[onerror] IPCC WebSocket 错误', evt);
- };
- socket.onopen = function(evt) {
- if (!_isCurrentSocket(socket)) return;
- console.log('ipccserver websocket onopen...');
- _flushSendQueue(socket);
- };
- }
- this.sendMsg = function(jsonObject) {
- console.debug("ws.send:", jsonObject);
- return _safeSendOnSocket(ws, 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"); if (transferArea) transferArea.style.display = "none"; };
- this.showTransferAreaUI = function() { var transferArea = document.getElementById("transfer_area"); if (transferArea) transferArea.style.display = "block"; };
- this.setStatusFree = function() { this.setStatus(ccPhoneBarSocket.agentStatusEnum.free); };
- this.setStatusBusy = function() { this.setStatus(ccPhoneBarSocket.agentStatusEnum.busy); };
- ccPhoneBarSocket.utils = {
- getQueryParam: function(paramName) {
- const url = window.location.href;
- const params = new URLSearchParams(new URL(url).search);
- return params.get(paramName);
- }
- };
- ccPhoneBarSocket.agentStatusEnum = {
- "justLogin": 1, "free": 2, "busy": 3, "busy_rest": 31,
- "busy_meeting": 32, "busy_training": 33, "incall": 4, "fill_form": 5, "conference": 6
- };
- 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": "高清+" }
- };
- ccPhoneBarSocket.eventList = {
- "on_audio_call_connected": "100", "on_video_call_connected": "101", "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": "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",
- "callee_busy": "609", "outbound_finished": "611", "PREDICTIVE_CALL_INBOUND": "612",
- "new_inbound_call": "613", "acd_group_queue_number": "615", "transfer_call_recv": 616,
- "lock_agent_fail": 617, "transfer_call_success": 618, "asr_result_generate": 619,
- "asr_process_end_agent": 620, "asr_process_end_customer": 621, "asr_process_started": 622,
- "customer_channel_hold": 623, "customer_channel_unhold": 624, "customer_on_hold_hangup": 625,
- "inner_consultation_request": 626, "customer_channel_call_wait": 627, "customer_channel_off_call_wait": 628,
- "customer_on_call_wait_hangup": 629, "extension_on_line": 630, "extension_off_line": 631,
- "inner_consultation_start": 632, "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": "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;
- };
- this.setStatus = function(status) {
- this.sendMsg({
- action: "setAgentStatus",
- body: { cmd: "setStatus", args: { status: status } }
- });
- };
- this.logOff = function() {
- this.sendMsg({
- action: "setAgentStatus",
- body: { cmd: "disconnect", args: { cause: "disconnect request from js client." } }
- });
- };
- this.stopCallWaitBtnClickUI = function() {
- this.sendMsg({
- action: "callWait",
- body: { cmd: "stop", args: {} }
- });
- };
- 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);
- };
- 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() {
- var args = {};
- if (_cc._activeCallUuid) args.uuid = _cc._activeCallUuid;
- _cc._suppressSessionNotFound = true;
- setTimeout(function() { _cc._suppressSessionNotFound = false; }, 4000);
- var sent = this.callControl("endSession", args);
- this.isCalling = false;
- if (sent !== false) {
- setTimeout(function() {
- _cc.setCallConnected(false);
- _cc.clearActiveCallUuid();
- }, 200);
- } else {
- _cc.setCallConnected(false);
- _cc.clearActiveCallUuid();
- }
- };
- this.callControl = function(action, argsObject) {
- if (!ws || ws.readyState !== WebSocket.OPEN) {
- console.warn('[callControl] WebSocket 未连接, cmd=', action);
- return false;
- }
- var sessionControl = {};
- sessionControl.action = "call";
- sessionControl.body = { "cmd": action, "args": argsObject || {} };
- return this.sendMsg(sessionControl);
- };
- this.checkCallConfirmed = function() {
- if (!_cc.getIsConnected()) { console.log('请先上线.'); return false; }
- if (!_cc.getCallConnected()) { console.log('当前没有通话.'); return false; }
- return true;
- };
- 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.'); return false; }
- this.callControl("reInviteVideo", {});
- return true;
- };
- this.call = function(phoneNumber, callType, videoLevel) {
- if (this.isCalling) {
- console.warn('[SDK] 正在呼叫中,请勿重复操作 (isCalling=true)');
- return false;
- }
- 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);
- }
- if (phoneNumber == null || phoneNumber.length === 0) { console.log('请输入外呼号码!'); return false; }
- if (phoneNumber.trim().length < 3) { alert('请输入正确格式的外呼号码!'); return false; }
- if (!_cc.getIsConnected()) { console.log('请先上线.'); return false; }
- let outboundInfo = {
- "gatewayList": _cc.callConfig.gatewayList,
- "destPhone": phoneNumber,
- "gatewayEncrypted": _cc.callConfig.gatewayEncrypted,
- "useSameAudioCodeForOutbound": _cc.callConfig.useSameAudioCodeForOutbound,
- "callType": callType,
- "videoLevel": videoLevel
- };
- this.callControl("startSession", outboundInfo);
- this.isCalling = true;
- return 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工具条相关方法(仅当 useDefaultUi=true 时使用,不影响核心功能)
- 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'] },
- "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) {
- if ($.inArray(all_btn[i], enabled_btn) < 0) $(all_btn[i]).removeClass('on');
- else $(enabled_btn[$.inArray(all_btn[i], enabled_btn)]).addClass('on');
- }
- };
- 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(); _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();
- function populateGroupIdOptions() {
- var groups = _cc.callConfig.groups;
- if (groups) {
- var selectObj = document.getElementById("transfer_to_groupIds");
- if (selectObj && 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;
- }
- }
- }
- $('#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();
- $("#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();
- $("#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) {
- if (e.which === 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;
- }
- });
- $(document).keyup(function(e) {
- if (e.which === 27) {
- console.log('按下了ESC键, 即将发送挂机指令.');
- if (_cc.getIsConnected()) {
- if (_cc.callConfig["useDefaultUi"]) { if ($('#hangUpBtn').hasClass('on')) _cc.hangup(); }
- else _cc.hangup();
- }
- }
- });
- };
- this.holdCall = function() {
- this.sendMsg({ action: "callHold", body: { cmd: "hold", args: {} } });
- };
- this.unHoldCall = function() {
- this.sendMsg({ action: "callHold", body: { cmd: "unhold", args: {} } });
- };
- this.subscribeAgentList = function() {
- this.sendMsg({ action: "pollAgentList", body: { cmd: "subscribe", args: {} } });
- _cc.subscribeAgentListStarted = true;
- };
- this.unSubscribeAgentList = function() {
- if (_cc.subscribeAgentListStarted) {
- _cc.subscribeAgentListStarted = false;
- _cc.callConfig.agentList = null;
- this.sendMsg({ action: "pollAgentList", body: { cmd: "unSubscribe", args: {} } });
- }
- };
- // 会议相关方法(保持不变)
- 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 = "是否把当前通话转换为会议 ?";
- if (confirm(tips)) _cc.transferToConference(layOut, confTemplate, callType, customerName);
- else document.getElementById("startConference").removeAttribute("disabled");
- } else _cc.conferenceStart(layOut, confTemplate, callType);
- };
- this.conferenceAddMemberBtnUI = function(reInvite, memberPhoneParam, memberNameParam) {
- var memberName = "", memberPhone = "", memberCallType = $.trim(document.getElementById("member_call_type").value), 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);
- var templateObj = document.getElementById("conf_member_template");
- if (document.getElementById("conf_member_" + memberPhone) != null) { 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; }
- 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);
- var templateObj = document.getElementById("conf_member_template");
- if (document.getElementById("conf_member_" + memberPhone) != null) { 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);
- 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");
- };
- 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 });
- };
- this.conferenceStart = function(layOut, confTemplate, callType) {
- this.sendMsg({
- action: "conference",
- body: { method: "startconf", args: { layOut: layOut, callType: callType, confTemplate: confTemplate } }
- });
- };
- this.conferenceVMuteMember = function(members) { this.conferenceControl("vmute", typeof members === "string" ? [{ "phone": members }] : members); };
- this.conferenceUnVMuteMember = function(members) { this.conferenceControl("unvmute", typeof members === "string" ? [{ "phone": members }] : members); };
- this.conferenceMuteMember = function(members) { this.conferenceControl("mute", typeof members === "string" ? [{ "phone": members }] : members); };
- this.conferenceUnMuteMember = function(members) { this.conferenceControl("unmute", typeof members === "string" ? [{ "phone": members }] : members); };
- this.conferenceAddMembers = function(members) { this.conferenceControl("add", members); };
- this.conferenceRemoveMembers = function(members) {
- if (typeof members === "string") {
- var memberItemObj = $("#conf_member_" + members);
- if ($(".conf_status", memberItemObj).text() === "通话中") this.conferenceControl("remove", [{ "phone": members }]);
- memberItemObj.remove();
- } else this.conferenceControl("remove", members);
- };
- this.conferenceEnd = function() { this.conferenceControl("endconf", []); };
- this.conferenceControl = function(action, phoneList) {
- this.sendMsg({
- action: "conference",
- body: { method: action, memberList: phoneList }
- });
- };
- this.callMonitorDataPull = function() {
- this.sendMsg({ action: "monitorData", body: {} });
- };
- this.inboundCallQueuePull = function() {
- this.sendMsg({ action: "inboundMonitorData", body: {} });
- };
- this.monitorControl = function(action, argsObject) {
- this.sendMsg({
- action: "callMonitor",
- body: { cmd: action, args: argsObject }
- });
- };
- 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", {}); };
- }
- export default ccPhoneBarSocket;
|