本文為您詳細介紹呼叫中心SDK前端接入流程。

在線體驗

如果您已經有SaaS工作臺的賬號,您可以在線體驗,并且完全可以按照這個Demo的方式進行接入。

接入熱線SDK

所有使用${version}的地方,需要替換為真實的版本號。詳細記錄信息,請參見熱線SDK更新記錄

  • 使用非定制UI接入
    • 如果您不需要定制自己的UI,并且您是React體系的項目接入,只需添加以下CDN的資源:
      <link rel="stylesheet" />
      <link rel="stylesheet" />
      <link rel="stylesheet" />
      <script src="http://g.alicdn.com/code/lib/antd/4.x.x/antd.min.js"></script>
      <script src="http://g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.js"></script>
      注意 請確保您的項目中已經有React、ReactDOM、antd的CDN資源,其中antd的版本建議使用4.x系列。
    • 因為構建出的是標準的UMD資源,所以現在可以按照以下方式接入:
      window.HotlineClientUi.renderClient(
          domContainer, //  比如 document.querySelector('#root'),可以替換為任何你想插入的DOM節點。
          props,
      );
    • 如果您使用了webpack,還可以使用以下方式接入:
      // webpack.config.js
      module.exports = {
        //...
        externals: {
          HotlineClient: 'HotlineClientUi'
        }
      };
      
      // in your app or component
      import { HotlineClientUI } from 'HotlineClient';
      window.HotlineClientUi.renderClient(
          domContainer, //  比如 document.querySelector('#root'),可以替換為任何你想插入的DOM節點。
          props,
      )

    上述所有入參的props的內容,請參見HotlineClientUIProps。

  • 使用定制UI接入

    如果您需要定制自己的UI風格,或者需要定制其他UI框架下的組件(比如VUE),可以按照下面的方式來實現:

    1. 引入以下資源:
      <script src="http://g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-fuyun/index.js"></script>
    2. 在自己的代碼中創建一個HotlineClient的實例:
      const { FuYunHotlineClient } = window.HotlineClientFuyun;
      
      const client = new FuYunHotlineClient(config);
    3. 如果您是React體系的項目但是需要定制UI,我們也提供了hooks供您使用:
      // 需要在cdn中添加 <script src="http://g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.js"></script>
      const { useClient } = window.HotlineClientUi;
      const {
        client,           // HotlineClient  實例
        enableState,      // EnableState 使能狀態
        agentContext,     // AgentContext
        callContext,      // CallContext 
        checkIn,          // 上班簽入,可以直接調用
        handleAnswerCall, // 接電話
        handleDial,       // 撥電話
      } = useClient(props);

    其中props的內容請參考HotlineClientUIProps介紹,EnableState內容請參考EnableState。

  • 不需要UI接入
    如果您不需要UI,直接使用API的形式調用,我們也提供了一個扁平化API的版本,只需要引入下面這個CDN地址:
    <script src="http://g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-api/index.js"></script>
    使用方式:
    const getHotlineClientSDK = window.HotlineClientApi.default;
    
    // config: HotlineClientInitConfig
    const SDK = getHotlineClientSDK(config);
    
    console.log(SDK.client); // 獲取client。
    
    console.log(SDK.agent); // 獲取agent。
    
    onsole.log(SDK.call); // 獲取call。
    
    console.log(SDK.enableState); //獲取使能狀態。
    
    // 上班簽入。
    SDK.agentCheckin();
    
    //  下班簽出。
    SDK.agentCheckout();
    
    // 切空閑。
    SDK.agentCheckReady();
    
    // 切小休。
    SDK.agentCheckRestful();
    
    //外呼。
    SDK.dial(calleePhoneNumber: string, callerPhoneNumber?: string);
    
    // 接電話
    SDK.answer();
    
    // 電話保持。
    SDK.hold();
    
    // 電話取回。
    SDK.retrieve();
    
    // 電話轉交。
    SDK.deflect(identifier: DeflectionIdentifier);
    
    // 電話掛斷。
    SDK.hangUp();
    
    // 釋放資源。
    SDK.dispose();
    因為狀態機是維護在后端的,除了由于沒有client、agent或者call導致的報錯外(比如沒有通話直接調掛斷),其余的動作都需要用戶根據enableState當前的狀態判斷是否可以發起,比如發起外呼:1當前如果外呼是否可以發起,API本身不會攔截,應該由狀態進行攔截。

SDK接入常見問題

  • 怎么訂閱事件?
    熱線中基本上每一個動作(比如狀態切換、電話狀態變更等)都會對應一些事件,為了保證所有后端的事件都完整的傳遞給上層應用,我們在HotlineClient的實例上提供了完整的事件監聽功能,您可以按照這樣的方式從client上發起監聽:
    client.on('eventName', (data: EventData) => {})

    其中eventName可以是HotlineSystemEvents和HotlineCustomEvents中任意的一個key,正如命名所指,HotlineSystemEvents推送的都是后端直接給到的事件信息,而HotlineCustomEvents是SDK系統中自己觸發的事件。

    目前所有的EventData都是HotlineSocketEventData。

  • 使用過程中會不會有環境問題?

    會的,目前我們只支持Chrome瀏覽器64版本以上的環境,我們提供了完整的環境檢測工具,包括網絡檢測、麥克風檢測和遠端音頻播放流程檢測。

  • 以UI形式接入環境檢測工具
    首先,一定需要以帶UI的形式使用,然后加入下面的2個CDN:
    <link rel="stylesheet" />
    <script src="http://g.alicdn.com/hotline-client/hotline-client-sdk/1.0.1/hotline-client-check-tools/index.js"></script>
    現在你只需要將openCheckTool設置為true即可。
  • 是否可以用npm的形式接入?

    考慮到一些依賴需要單獨處理的問題,建議使用CDN的形式接入。

術語表

術語詳細說明,請參見下表:
術語 說明
Client 即HotlineClient的實例,可以通過create的方式獲取,如果直接以UI形式接入,可以通過onClientOnline回調的方式獲取。
Agent 即AgentContext的實例,client調用login之后可以拿到,如果以UI形式接入,可以通過onAgentOnline回調的方式獲取。
Call 即CallContext的實例,agent調用dial(外呼)或者振鈴的時候,可以從幾個特殊事件中可以獲取到。
  • 系統外呼事件
    外呼事件觸發的時候會有callContext:
    client.on('SystemCallDialOut', (dialOutCallContext) => {console.log(dialOutCallContext)})
  • 系統振鈴事件
    系統振鈴事件觸發會有callContext:
    client.on('SystemCallRinging',(ringingCallContext) => {console.log(ringingCallContext) });
  • 斷線重連(用戶主動刷新瀏覽器)事件
    系統斷線重連事件觸發會有CallContext:
    // status 當前斷線重連的狀態。
    client.on('AgentCallReconnect',(status, callContext) => {console.log(status, callContext) });
EnableState 狀態使能類表示在當前的坐席狀態下是否允許一些操作的使用,比如在一通話務中,是否可以掛斷,是否可以轉接等等完全由這個“使能類”來定義,類型定義,請參見:HotlineClientEnableState。

類型定義

  • Client相關
    • HotlineClient
      interface HotlineClient {
        /**
         * 獲取此熱線客戶端的上下文對象。
         */
        readonly context: HotlineClientContext;
      
        /**
         * 發起登錄。
         *
         * {@return 一個坐席上下文對象}。
         */
        login(): Promise<AgentContext>;
        /**
         * 更新token。
         */
        updateToken(token: string): void;
      }
    • FuYunHotlineClient
      class FuYunHotlineClient implements HotlineClient {
          /**
         * ...
         */
      }
    • HotlineClientContext
      /**
       * 表示熱線 client 的上下文對象
       */
      export interface HotlineClientContext {
        /**
         * 獲取此 client 上的配置信息。
         */
        readonly config: HotlineClientInitConfig;
      
        /**
         * 獲取此 client 上的熱線服務。
         */
        readonly hotlineService: HotlineService;
      }
    • HotlineClientInitConfig
      /**
       * 提供 {@link HotlineClient} 初始化參數的描述。
       */
      export interface HotlineClientInitConfig {
        instanceId: string; // 實例 id
        token: string; // token
      }
    • HotlineClientUIProps
      /**
       * HotlineClientUIProps 定義。
       */
      export type HotlineClientUIProps = {
        /**
         * 初始化 Client 需要的參數。
         */
        config?: HotlineClientInitConfig;
      
        /**
         * 是否支持拖拽。默認為 false。
         */
        draggable?: boolean;
      
        /**
         * 拖拽相關的配置。具體可以參考 https://www.n****.com/package/react-draggable 
         * 的 DraggableProps
         */
        draggableProps?: Partial<DraggableProps>;
      
        /**
         * 是否打開檢測工具。默認是關閉的。
         */
        openCheckTool?: boolean;
      
        /**
         * 電話號碼是否加密,(脫敏),默認是 false。
         */
        isPhoneNumberEncrypted?: boolean;
      
        onClientOnline?: (client: HotlineClient) => void;
      
        onAgentOnline?: (agent: AgentContext) => void;
      
        onCallContextChange?: (callContext: CallContext) => void;
      
        onLoginError?: (error: Error) => void;
      };
    • HotlineClientEnableState
      export interface HotlineClientEnableState {
        /**
         * 狀態。
         */
        status: AgentStatus;
      
        /**
         * 可簽出。
         */
        checkoutEnable: boolean;
      
        /**
         * 可簽入。
         */
        checkinEnable: boolean;
      
        /**
         * 可空閑。(繼續工作)
         */
        readyEnable: boolean;
      
        /**
         * 可小休。
         */
        breakEnable: boolean;
      
        /**
         * 可培訓。
         */
        trainEnable: boolean;
      
        /**
         * 可接電話。
         */
        callAnswerEnable: boolean;
      
        /**
         * 可掛電話。
         */
        callHangupEnable: boolean;
      
        /**
         * 可撥號。
         */
        callDialEnable: boolean;
      
        /**
         * 電話可保持。
         */
        callHoldEnable: boolean;
      
        /**
         * 電話可取回。
         *
         * 保持 + 轉接。
         */
        callRetrieveEnable: boolean;
      
        /**
         * 電話可轉接。
         */
        callDeflectEnable: boolean;
      }
  • Agent相關
    AgentContext
    /**
     * 表示坐席的接口定義。
     */
    export interface AgentContext extends Disposable {
      /**
       * 坐席發起簽入。
       */
      checkIn(): Promise<unknown>;
    
      /**
       * 坐席發起簽出。
       */
      checkOut(): Promise<unknown>;
    
      /**
       * 坐席發起小休。
       */
      doRest(): Promise<unknown>;
    
      /**
       * 坐席切到在線。
       */
      checkReady(): Promise<unknown>;
    
      /**
       * 坐席發起撥號。
       * @param calleePhoneNumber 被叫號碼。
       * @param callerPhoneNumber 主叫號碼。
       */
      dial(calleePhoneNumber: string, callerPhoneNumber?: string): Promise<CallContext>;
    
      /**
       * 坐席接電話。
       * @param params 接電話需要的身份信息。
       */
      answer(params?: CallIdentity): Promise<unknow>;
    }
  • Call相關
    • CallContext
      /**
       * 表示通話上下文的結構體。
       */
      export interface CallContext extends EventEmitter<HotlineConnectionEvents>, Disposable {
        /**
         * 獲取此通話的標識信息。
         */
        readonly identity: CallIdentity;
      
        /**
         * 獲取此通話的方向。
         */
        readonly callDirection: CallDirection;
      
        /**
         * 獲取此通話的呼叫方身份。
         */
        readonly caller: CallerIdentity;
      
        /**
         * 獲取此通話的被呼叫方身份。
         */
        readonly callee: CallerIdentity;
      
        /**
         * 掛斷此通話。
         */
        hangUp(): Promise<unknown>;
      
        /**
         * 轉接此通話。
         * @param identifier 轉接需要的標識符。
         *
         * 根據 DeflectionIdentifier 的 deflectionType 來確認是否需要返回一個可取回的通話。
         */
        deflect(identifier: DeflectionIdentifier): void;
      
        /**
         * 保持此通話。
         */
        hold(): Promise<unknown>;
      
        /**
         * 表示取回此通話。
         */
        retrieve(): Promise<unknown>;
      }
    • CallIdentity
      /**
       * 表示通話身份的結構體。
       */
      export interface CallIdentity {
        /**
         * 獲取此通話的 acId。
         */
        readonly acId: string;
      
        /**
         * 獲取此通話的連接 Id。
         */
        readonly connId: string;
      
        /**
         * 獲取此通話被保持時的連接 Id。
         */
        readonly holdConnId?: string;
      
        /**
         * 獲取此通話的 jobId。
         */
        readonly jobId: string;
      }
    • CallDirection
      /**
       * 表示通話方向的枚舉,如呼入或呼出。
       */
      export enum CallDirection {
        /**
         * 表示呼入。
         */
        Incoming,
      
        /**
         * 表示呼出。
         */
        Outgoing,
      }
  • Event事件相關
    • HotlineSystemEvents
      /**
       * 后端推送的事件。
       */
      export interface HotlineSystemEvents<EventData> {
        AgentCheckin: (data: EventData) => void; // 坐席簽入
        AgentReady: (data: EventData) => void; // 坐席進入空閑(在線)狀態
        AgentCallDialOut: (data: EventData) => void; // 坐席正在外呼事件
        AgentJoinChannel: (data: EventData) => void; // RTC 建立,坐席加入聊天
        AgentLeaveChannel: (data: EventData) => void; // RTC 斷開,坐席離開聊天
        AgentCheckout: (data: EventData) => void; // 坐席簽出事件
        AgentBreak: (data: EventData) => void; // 坐席小休事件
        AgentAcw: (data: EventData) => void; // 坐席進入話后處理事件
        AgentRinging: (data: EventData) => void; // 坐席振鈴
        // AgentCallRelease: (data: EventData) => void; // 通話結束,商業化場景暫時沒有
        AgentCallAnswerRequest: (data: EventData) => void; // FIXME: 待確認
        AgentCallInboundEstablish: (data: EventData) => void; // 入呼通道建立事件
        AgentCallOutBoundEstablish: (data: EventData) => void; // 外呼通道建立事件
        AgentCallConferenceWaitAnswer: (data: EventData) => void; // 雙步轉等待第三方接聽事件
        AgentCallHeld: (data: EventData) => void; // 通話保持事件
      }
    • HotlineCustomEvents
      export interface HotlineCustomEvents<EventData> {  
      AgentStatusChange: (data: EventData) => void;               // 坐席狀態變更事件  
      EnableStateChange: (data: HotlineClientEnableState) => void;// 使能類變更事件。  
      CallVoiceText: (data: EventData) => void;                   // 通話語音文本事件  
      AgentReconnect: (status: AgentStatus) => void;              // 坐席斷線重連消息。  
      AgentCallReconnect: (status: AgentStatus, callContext: CallContext) => void; // 通話斷線重連消息。  
      BeforeCallHold: () => void;                                 // 電話保持動作被觸發前觸發。  
      AfterCallHold: () => void;                                  // 電話保持成功后觸發。  
      BeforeCallDeflect: () => void;                              // 電話轉交動作被觸發前觸發。  
      BeforeCallHangup: () => void;                               // 電話掛斷動作被觸發前觸發。  
      AfterCallHangup: () => void;                                // 電話掛斷成功后觸發。  
      BeforeCallAnswer: () => void;                               // 電話接起動作被觸發前觸發。  
      AfterCallAnswer: () => void;                                // 電話接起成功后觸發。  
      BeforeCallDial: () => void;                                 // 電話撥號動作被觸發前觸發。  
      AfterCallDial: () => void;                                  // 電話撥號成功后觸發。  
      BeforeCallRetrieve: () => void;                             // 電話取回動作被觸發前觸發。  
      AfterCallRetrieve: () => void;                              // 電話取回成功后觸發。  
      UnHandleEvent: (data: EventData) => void;                   // 異常兜底。
      TokenExpired: () => void;                                   // Token過期事件。  
      SystemCallRinging: (call: CallContext) => void;             // 帶話務上下文的系統振鈴事件。  
      SystemCallDialOut: (call: CallContext) => void;             // 帶話務上下文的系統外呼事件。
      }
    • HotlineSocketEventData
      /**
       * 熱線 socket 消息體
       */
      export interface HotlineSocketEventData {
        eventName: string;
        buId?: number;
        departmentId?: number;
        enumIconType?: string;
        enumSceneType?: string;
        gmtCreate?: number;
        head: HotlineSocketHeadData;
        isPersistent?: boolean;
        sceneType?: string;
        senderId?: number;
        senderType?: string;
        userId?: number;
        uuid?: string;
        content: string;
      }
      
      export interface HotlineSocketHeadData {
        agentBasicCode?: AgentBasicCode;
        agentBasicDesc?: string;
        agentCallCode?: AgentCallCode;
        agentCallDesc?: string;
        aid?: string;
        appName?: string;
        cmd?: string;
        departmentId?: string;
        mid?: string;
        name?: string;
        supportNewFunction?: string;
        time?: string;
        tk?: string;
        xspaceHotline?: string;
        jobId?: string;
        connId?: string;
        holdConnId?: string;
        acid?: string;
        dnis?: string;
        ani?: string;
      }
  • 其他類型說明
    DeflectionIdentifier
    export interface DeflectionIdentifier {
      isSingleTransfer?: boolean; // true 是單步轉,false 是雙步轉,默認是 true
      isTransferSkillGroup?: boolean; // 是否轉接給技能組。
      isTransferPhone?: boolean; // 是否轉接給電話號。
      caller?: string; // 轉接到電話的主叫號碼。
      callee?: string; // 轉接到電話的被叫號碼。
      skillGroupId?: string; // 轉接的技能組 id
    }