本文為您詳細介紹呼叫中心SDK前端接入流程。
注意 當前版本僅做維護,后續不會繼續迭代。如有需求,請參見熱線SDK接入(新版)。
引用SDK
- SDK cdn assets(umd module)
- SDK Preview Sandbox
https://g.alicdn.com/xspace/phone/0.5.1/index.html#/sample/use-sdk
依賴
- SIM-API:https://g.alicdn.com/crm/sipml-api/0.0.8/SIPml-api.js。
- HTTP:https://g.alicdn.com/xspace/phone/0.5.1/http.js。
啟用渲染撥號盤會自動加載以上依賴。加載后即可獲取SDK實例內容:
const { SoftPhoneSDK } = window
前提條件
初始化前需要完成以下準備工作:
- 必須使用Chrome瀏覽器,版本號為58以上。原因是云呼叫中心的通話是通過webRTC技術實現的,目前Chrome瀏覽器對于webRTC技術的支持是最好的。為了保證您的通話質量及安全性,所以我們做出了這樣的要求。
- 軟電話SDK所嵌入的自有業務系統必須使用HTTPS協議。原因是Chrome在47版本之后,禁止HTTP協議獲取系統麥克風權限,會造成無法正常通話。
- 如果您是在
iframe
標簽內使用軟電話SDK,那么需要為iframe
標簽增加allow="microphone"
屬性,來允許iframe
標簽獲取系統麥克風權限。
接入手冊
狀態流轉
- 藍色為流轉狀態觸發的事件hook,請參見事件回調枚舉。
- 白色為坐席狀態,請參見坐席狀態枚舉。
- 加載SDK初始坐席狀態為-1表示未注冊,需要申請InstanceId BearerToken進行簽入坐席操作。每個坐席原則意義上按1人/位,可能存在設置同一坐席公用。具體流程如下:
- 軟電話類
const { SoftPhone } = window.SoftPhoneSDK; const softPhone = SoftPhone.getInstance(); // softphone follow Singleton Pattern
通過getInstance方法生成唯一實例。
- 實例API
API type description setConfig (config: Partial<SDKConfig> = {}) 注入配置,如下所示 register (eventName: EnumEventName, cb: (eventData: { type: EnumEventName, preConfig: Partial<SDKConfig>, data: any)} => void ) => Canceler 注冊LifeCycle事件返回其注銷方法。 getUIComponent () => React.ElementType 獲取撥號條組件實例,配合APIs.renderComponent 渲染 使用getUIComponent獲取的組件必須使用APIs.renderComponent去掛載,這是因為SDK內部集成了React&ReactDOM,使用外部版本掛載會導致版本不通或者雙副本的問題。
- SDKConfig Options
option type defaultvalue description InstanceId string "" 實例ID,可在阿里云控制臺使用主賬號登錄實例列表獲取https://ccc.console.aliyun.com/AccInstance。 BearerToken string "" bearerToken,通過三方賬號授權置換token中的access_token。 env "online" | "preOnline" 'online' 配置環境。 apiHost "scsp.aliyuncs.com" | "aiccs.aliyuncs.com" | "api.rhinokeen.com" 'scsp.aliyuncs.com' API服務器。 Version string '2020-07-02' POP API版本號。 - scsp.aliyun.com對應版本為
'2020-07-02'
- aiccs.aliyun.com對應版本為
'2019-10-15'
- api.rhinekeen.com無需版本
locale EnumLocale EnumLocale['zh-CN'] 國際化。 isPlugin boolean true 撥號條插件是否支持拖拽, 默認支持。 needDesensitize boolean false 是否對入呼或外呼號碼脫敏展示,默認不脫敏。 autoChangeOnLineTime number 1 自定義話后處理時間,單位為s(秒),為0代表不需要自動切狀態,默認為1s自動結束話后處理。 canChangeStatusByHand boolean false 是否能夠手動切換狀態的能力,默認為false,不展示操作欄&不支持手動更新。 enableVoiceToText Array<'callin' | 'callout'> [] 啟用語音轉文本,該能力需要BU配置支持。 enableServiceSummary boolean false 啟用服務摘要。 disableUI boolean false 是否隱藏UI,默認為false,不隱藏。 cdnPath string //g.alicdn.com 內置資源默認引用CDN域。 - scsp.aliyun.com對應版本為
- Demo
const config = { InstanceId: 'ccc_xp_pre-cn-78v1gnp97002', // 實例id,可在阿里云控制臺實例列表獲取 BearerToken: '', // bearerToken,通過【三方賬號授權】置換token中的access_token env: 'online', // online || preOnline, apiHost: 'api.rhinokeen.com', // scsp.aliyuncs.com || aiccs.aliyuncs.com || api.rhinokeen.com Version: '', // Pop Api 版本號,默認為'2020-07-02'. scsp.aliyun.com對應版本為'2020-07-02';aiccs.aliyun.com對應版本為'2019-10-15';api.rhinekeen.com無需版本 locale: EnumLocale['zh-CN'], isPlugin: true, // 插件是否支持拖拽,默認支持 needDesensitize: false, // 是否對入呼/外呼號碼脫敏展示,默認不脫敏 autoChangeOnLineTime: 1, // 自定義話后處理時間,單位為s,為0代表不需要自動切狀態,默認為1s自動結束話后處理 canChangeStatusByHand: false, // 是否能夠手動切換狀態 disableUI: false // 是否隱藏UI, 默認為false,不隱藏 }; softPhone.setConfig(config); softPhone.register(EnumEventName.actionError, () => { softPhone.setConfig({ BearerToken: 'newBearerToken' // token失效后,此處進行事件注冊,設置新的token }); }); const SoftPhoneUI: React.ElementType<any> = softPhone.getUIComponent(); // if use React Framework, you can render component directly const ExampleApp: React.FC = () => { return ( <SoftPhoneUI /> ); } // if not use React Framework, you can render softphone to specified ElementNode APIs.renderComponent(SoftPhoneUI, document.querySelector('#phone-container'));
- 實例API
- LifeCycle事件注冊
旨在各調度過程中觸發的鉤子,采用訂閱派發的模式進行管理。具體流轉狀態,請參見流轉狀態流程圖。
- 事件回調枚舉
export enum EnumEventName { actionError = 'actionError', // 出錯 actionSuccess = 'actionSuccess', // 撥號盤流程回調 onAgentCheckedin = 'onAgentCheckedin', // 上班簽入成功回調 onAgentCheckedout = 'onAgentCheckedout', // 下班簽出成功回調 onCallComing = 'onCallComing', // 新來電振鈴回調 onCallDialOut = 'onCallDialOut', // 外撥請求中回調 onCallWillAnswer = 'onCallWillAnswer', // 呼入電話執行接聽動作回調 onCallEstablishForCallin = 'onCallEstablishForCallin', // 呼入通話建立完成回調(等同于完成接聽): onCallEstablishForCallout = 'onCallEstablishForCallout', // 呼出通話建立完成回調 onCallWillHangup = 'onCallWillHangup', // 執行掛斷動作回調 onCallDidHangup = 'onCallDidHangup', // 呼入電話掛斷完成回調 onCallOutDidHangup = 'onCallOutDidHangup', // 呼出電話掛斷完成回調 onCallTransferOut = 'onCallTransferOut', // 轉接回調 0.4.16版本新增 onCallHold = 'onCallHold', // 通話保持回調 0.4.16版本新增 onCallRecovery = 'onCallRecovery', // 通話恢復回調 0.4.16版本新增 'actionError.tokenExpired' = 'actionError.tokenExpired', // token失效回調 }
- 注冊監聽Demo
// register action error callback const unRegister = softPhone.register(EnumEventName['actionError.tokenExpired'], (eventData, prevConfig, data) => { // here! your can update BearerToken by softPhone.setConfig({BearerToken: 'xxx'}); const { type, data } = eventData; console.log('[SoftPhone actionError.tokenExpired]',type, data); }); unRegister() // unRegister current actionError.tokenExpired event
eventData字段說明:acid: string // 通話id channelId agentBasicCode: "AgentBusyForCall" // 代理狀態Code agentBasicDesc: "坐席通話忙" // 代理狀態描述 agentCallCode: "AgentCallDialOut" // 撥號狀態Code agentCallDesc: "外撥中" // 撥號狀態描述 aid: string // 在線id ani: string appName: string cmd: string connId: string // 話務Id departmentId: string dnis: string eventTime: string // 事件時間 holdConnId: "" jobId: string // 小二職位id mid: string // memberId? name: string // 會員名稱 status: AgentBarStatus // 坐席狀態AgentBarStatus subSessionId: string // 子會話id supportNewFunction: string time: string
- 事件回調枚舉
- 靜態APIs列表
const APIs = { renderComponent, // 渲染組件到指定節點 doCallOut, // 執行外呼 startWork, // 執行開始上班, 已廢棄,可由agentCheckin替代 agentCheckin, // 執行撥號盤簽入 agentCheckout, // 執行撥號盤簽出 getAgentBarStatus, // 獲取當前撥號盤狀態 callAnswer, // 來電接聽 callHangup, // 電話掛斷 takeWebSocketNotify, // 獲取 websocket 通道實例 }
- 坐席簽入Demo登錄操作,狀態流轉到AgentBarStatus.AgentCheckout。
const { APIs } = window.SoftPhoneSDK; APIs.agentCheckin(); // 是否成功可通過注冊onAgentCheckedin事件來監聽
- 坐席簽出Demo登出操作,狀態流轉到 AgentBarStatus.AgentCheckin。
const { APIs } = window.SoftPhoneSDK; APIs.agentCheckout(); // 是否成功可通過注冊onAgentCheckedout事件來監聽
- 發起呼叫Demo調用外呼能力,外呼成功后執行AgentBarStatus.onCallDialOut,通過返回的eventData.data執行掛斷操作。
const { APIs } = window.SoftPhoneSDK; APIs.doCallOut({ number, // 要呼叫的號碼 onSuccess: this.onSuccess, // 外呼成功接通后的回調,參數為通話信息對象 param: { number, // 要呼叫的號碼 memberId, // 必填, 匿名或未知用戶可傳-1 memberName, // 必填,用戶名稱,未知可傳 '匿名會員' calloutNumber, // 選填, 主叫號碼,如未填則默認為配置的第一個 fromSource: 'other_system_out', // 必填, hotlinebs_out || ticket_out || other_system_out (熱線||工單||其他系統) taskId: this.props.common.taskId, // 如需查動作記錄/服務記錄時, channelId || caseId必傳其中之一 channelId: this.props.channelId, // 會話id 可選 caseId: this.props.common.caseId, // 工單id } })
- 掛斷電話Demo
APIs.callHangup(connId, jobId, acid, aid);
應用場景:呼入不接起掛斷、呼入接起主動掛斷、撥出未接/接起主動掛斷。// 撥入掛斷 softPhone.register(EnumEventName.AgentRinging, (eventData, prevConfig, data) => { const { data: { connId, jobId, acid, aid } } = eventData; APIs.callHangup(connId, jobId, acid, aid); }); // 撥出掛斷 softPhone.register(EnumEventName.AgentCallDialOut, (eventData, prevConfig, data) => { const { data: { connId, jobId, acid, aid } } = eventData; APIs.callHangup(connId, jobId, acid, aid); });
- 接聽來電Demo
softPhone.register(EnumEventName.AgentRinging, (eventData, prevConfig, data) => { // 參數可從 AgentRinging 的事件回調參數里取 const { data: { connId, jobId, acid, aid } } = eventData; APIs.callAnswer(connId, jobId, acid, aid); });
- 獲取坐席狀態Demo回坐席狀態,對應值對應的狀態如下,初始為-1未注冊。
const { APIs } = window.SoftPhoneSDK; const status = await APIs.getAgentBarStatus(); enum AgentBarStatus { AgentCheckout = 1, // 簽出 AgentCheckin = 2, // 簽入 AgentReady = 3, // 空閑 AgentBreak = 4, // 小休 AgentCallRelease = 5, // 通話結束(掛斷的時候) AgentAcw = 6, // 話后處理 AgentRinging = 7, // 振鈴 AgentCallAnswerRequest = 8, // 接聽請求中 AgentCallDialOut = 9, // 撥號請求中 AgentCallInboundEstablish = 10, // 呼入通話 AgentCallOutBoundEstablish = 11, // 呼出通話 AgentCallInternalBoundEstablish = 12, // 內部通話b打給c AgentCallConsultEstablish = 13, // 被動求助通話建立 AgentCallHeld = 14, // 通話保持 AgentCallConferenceWaitAnswer = 16, // 發起三方 AgentCallThirdConsult = 17, // 三方通話中 AgentThirdRetrieveRequest = 18, // 三方取回中 AgentCallConference = 19, // 會議 三方通話狀態 }
- 獲取webSocket通道當某些場景下我們需要定制能力時(e.g.自定義語音轉文本能力),可以直接獲取websocket通道,該對象提供了兩個方法和一個websocket實例。
當前(0.4.16)已定的 sceneType有:type Subscribe = (eventName: string, callback: (msgData: any) => void) => void; type PhoneNotify = { listenerContainer: { [eventName: string]: Array<(msgObj: any) => void>; }; on: Subscribe; off: Subscribe; socket: ReconnectingWebSocket; }; const { APIs } = window.SoftPhoneSDK; const notify: PhoneNotify = APIs.takeWebSocketNotify(); function listenerHotlineMsg(msgData) { // 當通道返回的 data.sceneType === 'hotline-message' 時執行 } notify.on('hotline-message', listenerHotlineMsg); // 執行訂閱 notify.off('hotline-message', listenerHotlineMsg); // 注銷訂閱
hotline-message
熱線消息,表示通話狀態和信息。voice-to-text
語音轉文本,表示推送實時語音同聲傳譯后的文本內容。
- 坐席簽入Demo
- 多語言
- 已支持語言枚舉:
export enum EnumLocale { en = 'en', 'zh-CN' = 'zh-CN', }
- 默認語言:
zh_CN
- 設置語言Demo:
const { SoftPhone, EnumLocale } = window.SoftPhoneSDK; const softPhone = SoftPhone.getInstance(); softPhone.setConfig({ locale: EnumLocale.en, // default = 'zh_CN' });
- 已支持語言枚舉:
- 熱線狀態當我們想對熱線中狀態流轉有更高的定制需求時,e.g.
- 在RTC通道(打開或關閉)時打點。
- 在通話恢復時同步文本語音信息等。
可以先獲取到websocket實例,然后根據msgData.head.agentCallCode
參照EnumWSEventType
枚舉熱線狀態進行定制邏輯處理。具體枚舉:
e.g.export enum EnumWSEventType { // 上班狀態 AgentCheckin = 'AgentCheckin', // 簽入 AgentCheckout = 'AgentCheckout', // 簽出 AgentReady = 'AgentReady', // 空閑 AgentBreak = 'AgentBreak', // 小休 AgentAcw = 'AgentAcw', // 話后處理 // 通話事件監聽 AgentRinging = 'AgentRinging', // 來電 AgentCallInboundEstablish = 'AgentCallInboundEstablish', // 呼入電話建立 AgentCallOutBoundEstablish = 'AgentCallOutBoundEstablish', // 呼出通話建立 AgentCallDialOut = 'AgentCallDialOut', // 撥號呼出 AgentCallAnswerRequest = 'AgentCallAnswerRequest', // 呼入通話執行接聽 AgentCallRelease = 'AgentCallRelease', // 坐席釋放 AgentCallHeld = 'AgentCallHeld', // 通話保持 // 雙步轉 AgentCallConferenceWaitAnswer = 'AgentCallConferenceWaitAnswer', // 三方求助等待應答 AgentCallConference = 'AgentCallConference', // 會議中 AgentCallThirdConsult = 'AgentCallThirdConsult', // 三方求助通話中 AgentThirdRetrieveRequest = 'AgentThirdRetrieveRequest', // 三方取回請求中 AgentCallConsultThirdRetrieveReq = 'AgentCallConsultThirdRetrieveReq', // 三方求助三方取回請求中 AgentCallConsultEstablish = 'AgentCallConsultEstablish', // 三方求助電話建立 AgentCallInternalBoundEstablish = 'AgentCallInternalBoundEstablish', // 內部通話中 // RTC AgentJoinChannel = 'AgentJoinChannel', // 創建 RTC 連接 AgentLeaveChannel = 'AgentLeaveChannel' // 銷毀 RTC 連接 }
const { APIs, EnumWSEventType } = window.SoftPhone; const notify: PhoneNotify = APIs.takeWebSocketNotify; function listenerHotlineMsg(msgData) { // 當通道返回的 data.sceneType === 'hotline-message' 時執行 if(_get(msgData, 'head.agentCallCode') === EnumWSEventType.AgentLeaveChannel) { // dosomething } } takeWebSocketNotify.on('hotline-message', listenerHotlineMsg); // 執行訂閱
完整版Demo
export function APPControll(props: RouterCommonProps) {
const [hash, refresh] = useHash();
const { state: { config } } = useContext(Context); // 配置托管到context
const standWrap = useRef();
useRegisterHooks(props.history); // 注冊鉤子
useInitalIDPToken(hash); // fetch BearerToken assign to `context state` when hash changed
useDeepEffect(() => {
instance.setConfig(config);
// 檢測到過期 regenerator token
const unRegister = instance.register(EnumEventName.actionError, refresh);
// 渲染撥號條
APIs.renderComponent(instance.getUIComponent(), standWrap.current);
// 執行簽入操作
APIs.agentCheckin();
return () => {
APIs.agentCheckout();
unRegister();
};
}, [config]);
return (
<div>
<App />
<div ref={standWrap} className="statusbar" />
</div>
)
}
// e.g. use ReactHooks Synchronization status to Context
function useRegisterHooks(history: RouterCommonProps['history']) {
const { state, dispatch } = useContext(Context);
useEffect(() => {
softPhone.register(EnumEventName.onAgentCheckedin, e => {
safeConsole('成功登錄', e);
dispatch({
type: EnumEventName.onAgentCheckedin,
payload: _get(e, 'data'),
});
});
softPhone.register(EnumEventName.onAgentCheckedout, e => {
safeConsole('成功登出', e);
dispatch({
type: EnumEventName.onAgentCheckedout,
payload: _get(e, 'data'),
});
});
softPhone.register(EnumEventName.onCallDialOut, e => {
safeConsole('外撥請求中', e);
// ...
});
softPhone.register(EnumEventName.onCallComing, e => {
safeConsole('新來電振鈴', e);
// navigation to callpanel page...
// 暫不支持呼入方主動掛斷的事件,繞一下輪詢去偵測是否放開坐席
;(async function() {
while (true) {
await sleep(1000);
const status = await APIs.getAgentBarStatus();
if (status === agmentBarStatus.AgentReady) {
// 處理呼入方主動掛斷邏輯...
return false;
}
}
})();
});
softPhone.register(EnumEventName.onCallWillAnswer, e => {
safeConsole('呼入電話執行接聽動作', e);
});
softPhone.register(EnumEventName.onCallEstablishForCallin, e => {
safeConsole('已接聽來電', e);
});
softPhone.register(EnumEventName.onCallEstablishForCallout, e => {
safeConsole('呼出通話建立完成', e);
});
softPhone.register(EnumEventName.onCallWillHangup, e => {
safeConsole('掛斷回調', e);
// navigation to pre page before callin
});
softPhone.register(EnumEventName.onCallDidHangup, e => {
safeConsole('呼入電話掛斷完成', e);
});
softPhone.register(EnumEventName.onCallOutDidHangup, e => {
safeConsole('呼出電話掛斷完成', e);
});
softPhone.register(EnumEventName.onCallHold, (e) => {
safeConsole('通話保持', e);
});
softPhone.register(EnumEventName.onCallRecovery, () => {
safeConsole('通話恢復');
});
softPhone.register(EnumEventName.onCallTransferOut, () => {
safeConsole('轉交');
});
softPhone.register(EnumEventName['actionError.tokenExpired'], e => {
safeConsole('token失效', e);
// refresh logic...
});
return () => /* hanlder cancel events... */
}, []);
}
版發布記錄
0.5.0
語音轉文本提供呼入呼出可選自開。
0.4.17
- 優化代碼邏輯,移除非必要打印信息(sipml除外)
- 新增拋出三個鉤子(保持、恢復、轉交)
0.4.16
- 新增語音轉文本插件。
- 新增服務摘要插件。
- 新增對外暴露websocket以支持定制功能。
- 在線Demo更新。
0.4.15
新增本地化歸屬
0.4.12
- 新增對外的接聽和掛斷API。
- 新增隱藏UI的配置參數。
0.4.10
- 歸屬地外化多tab不顯示問題修復
- 增加初始化配置參數-autoChangeOnLineTime用來配置話后處理時間(默認為0,不觸發)
- 增加初始化配置參數-canChangeStatusByHand用來配置是否隱藏手動操作狀態欄的能力(默認為false,不需要隱藏)
0.4.9
- 號碼列表支持“號碼組外呼”
- 浮層層級提升至9999
- 撥打電話,上下班等操作提供“同步api”
- 增加“獲取撥號盤狀態”的前端api
- fuyun api token 過期事件修復
- 入呼、外呼歸屬地外化
0.4.7
- 撥號盤內部事件通信優化,棄用
msg-bus
- iconfont更新
0.4.6
Demo頁增加cdnPath
的可配置化
0.4.5
- 增加對后端接口外呼的支持
- 支持在已加載SIPml-api的環境下依舊能夠正常運行
- 修改默認外呼來源為
other_system_out
0.4.4
- 增加雙步轉UI調整
- 測試環境變量修改
0.4.3
- 交互體驗優化
- 增加系統外呼透露
- 增加是否脫敏展現號碼的配置項
- 增加是否可拖動的配置項
- Fuyun和Pop空入參優化
- 轉交邏輯優化,加入咨詢和會議邏輯(暫時隱藏)
- 部分已知bug修復