| 
					
				 | 
			
			
				@@ -0,0 +1,927 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import TUICallEngine, { EVENT, MEDIA_TYPE, AUDIO_PLAYBACK_DEVICE, STATUS } from 'tuicall-engine-wx'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { BellContext } from './serve/bellContext'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { throttle, isTabBarPage, tabBarConfig } from './utils/commom'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { THROTTLE_TIME } from './utils/constants'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 组件旨在跨终端维护一个通话状态管理机,以事件发布机制驱动上层进行管理,并通过API调用进行状态变更。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 组件设计思路将UI和状态管理分离。您可以通过修改`component`文件夹下的文件,适配您的业务场景, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 在UI展示上,您可以通过属性的方式,将上层的用户头像,名称等数据传入组件内部,`static`下的icon和默认头像图片, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 只是为了展示基础的效果,您需要根据业务场景进行修改。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export const PREFIX = 'TUICallKit'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const version = '1.4.4'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let INVITER_BELL_FILEPATH = 'TUICallKit/TUICallKit/static/phone_dialing.mp3'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let INVITEE_BELL_FILEPATH = 'TUICallKit/TUICallKit/static/phone_ringing.mp3'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 记录组件是否初始化完成 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let tuiCallInitReady = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 是否需要隐藏 tabBar 页面 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let shouldHideTabBar = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Component({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  properties: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    config: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: Object, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      value: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        sdkAppID: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userID: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userSig: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tim: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    backgroundMute: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: Boolean, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      value: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  data: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    callStatus: STATUS.IDLE,   // idle、calling、connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    isSponsor: false,          // 呼叫者身份 true为呼叫者 false为被叫者 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pusher: {},                // TRTC 本地流 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    playerList: [],            // TRTC 远端流 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    playerProcess: {},         // 经过处理的的远端流(多人通话) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    isGroup: false,            // 是否为多人通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    remoteUsers: [],           // 未排序的通话列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    allUsers: [],              // 排序后的通话列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    sponsor: '',               // 主叫方 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    screen: 'pusher',          // 视屏通话中,显示大屏幕的流(只限1v1聊天 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    soundMode: AUDIO_PLAYBACK_DEVICE.SPEAKER,  // 声音模式 听筒/扬声器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    showToatTime: 0,           // 弹窗时长 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ownUserId: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    callingBell: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    bellFilePath: '',          // 被叫方铃声地址 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  methods: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    initialUI() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 收起键盘 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.hideKeyboard(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 隐藏 tabBar 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (shouldHideTabBar) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.hideTabBar(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 新的邀请回调事件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async handleNewInvitationReceived(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.initialUI(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.checkRunPlatform(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.config.type = event.data.inviteData.callType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.callingBell.setBellSrc(this.data.bellFilePath || INVITEE_BELL_FILEPATH); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.callingBell.play(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 判断是否为多人通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (event.data.isFromGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          isGroup: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          sponsor: event.data.sponsor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 将主叫方和被叫列表合并在一起 组成全部通话人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const newList = [...event.data.inviteeList, event.data.sponsor]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 获取用户信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.getUserProfile(newList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.getUserProfile([event.data.sponsor]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        config: this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        callStatus: STATUS.CALLING, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isSponsor: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 用户接听 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleUserAccept(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 主叫方则唤起通话页面 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.isSponsor()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callStatus: STATUS.CONNECTED, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 远端用户进入通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleUserEnter(res) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const newList = this.data.allUsers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 多人通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 改变远端用户信息中的isEnter属性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let i = 0;i < newList.length;i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (newList[i].userID === res.data.userID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            newList[i].isEnter = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        playerList: res.playerList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        allUsers: newList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 远端用户离开通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleUserLeave(res) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 多人通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: `${this.getUserNickName(res.data.userID)}离开通话`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deleteUsers(this.data.allUsers, res.data.userID); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        playerList: res.data.playerList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 用户数据更新 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleUserUpdate(res) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.handleNetStatus(res.data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const newplayer = {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const newres = res.data.playerList; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 多人通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 处理远端流 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let i = 0;i < newres.length;i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const  { userID } = newres[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          newplayer[userID] = newres[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pusher: res.data.pusher, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        playerList: res.data.playerList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        playerProcess: newplayer, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 判断网络状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleNetStatus(data) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (data.pusher.netQualityLevel > 4) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: '您当前网络不佳', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      data.playerList.map((item) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (item.netStatus.netQualityLevel > 4) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const name = data.playerList.length > 1 ? item.nick : '对方'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            title: `${name}当前网络不佳`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return item; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 用户拒绝 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleInviteeReject(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deleteUsers(this.data.allUsers, event.data.invitee); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: `${this.getUserNickName(event.data.invitee)}已拒绝`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 用户不在线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleNoResponse(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deleteUsers(this.data.allUsers, event.data.timeoutUserList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: `${event.data.timeoutUserList}无应答`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 获取用户昵称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getUserNickName(userId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { remoteUsers } = this.data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const userObj = remoteUsers.find(item => item.userID === userId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return userObj.nick ? userObj.nick : userObj.userID; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 用户忙线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleLineBusy(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deleteUsers(this.data.allUsers, event.data.invitee); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.showToast(this.getUserNickName(event.data.invitee)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    showToast(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        showToatTime: this.data.showToatTime + THROTTLE_TIME, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      setTimeout(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: `${event}忙线中`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, this.data.showToatTime); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 用户取消 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleCallingCancel(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (event.data.invitee !== this.data.config.userID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: `${this.getUserNickName(event.data.invitee)}取消通话`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 通话超时未应答 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleCallingTimeout(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 若是自身未应答 则不弹窗 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (this.data.config.userID === event.data.timeoutUserList[0]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const newList = this.deleteUsers(this.data.allUsers, event.data.timeoutUserList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          allUsers: newList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.playerList.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: `${event.data.timeoutUserList[0]}超时无应答`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleCallingUser(userIDList) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const remoteUsers = [...this.data.remoteUsers]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const userProfile = remoteUsers.filter(item => userIDList.some(userItem => `${userItem}` === item.userID)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        remoteUsers: remoteUsers.filter(item => userIDList.some(userItem => userItem !== item.userID)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let nick = ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let i = 0; i < userProfile.length; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        nick += `${userProfile[i].nick}、`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return nick.slice(0, -1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 通话结束 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleCallingEnd(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: '通话结束', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        duration: 800, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // SDK Ready 回调 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleSDKReady() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 呼叫需在sdk ready之后 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 被踢下线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleKickedOut() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: '您已被踢下线', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 切换通话模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleCallMode(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.config.type = event.data.type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setSoundMode(AUDIO_PLAYBACK_DEVICE.EAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        config: this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleError(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { code, message } = event.data || {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.warn(`${PREFIX} errorCode: ${code}, errorMessage: ${message}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 删除用户列表操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    deleteUsers(usersList, userID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 若userID不是数组,则将其转换为数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!Array.isArray(userID)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userID = [userID]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const list = usersList.filter(item => !userID.includes(item.userID)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        allUsers: list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 增加用户列表操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addUsers(usersList, userID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 若userID不是数组,则将其转换为数组 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!Array.isArray(userID)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userID = [userID]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const newList = [...usersList, ...userID]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return newList; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 增加 tsignaling 事件监听 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    _addTSignalingEvent() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.ERROR, this.handleError, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 被邀请通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.INVITED, this.handleNewInvitationReceived, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户接听 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.USER_ACCEPT, this.handleUserAccept, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户进入通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.USER_ENTER, this.handleUserEnter, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户离开通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.USER_LEAVE, this.handleUserLeave, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户更新数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.USER_UPDATE, this.handleUserUpdate, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户拒绝通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.REJECT, this.handleInviteeReject, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户无响应 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.NO_RESP, this.handleNoResponse, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户忙线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.LINE_BUSY, this.handleLineBusy, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 通话被取消 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.CALLING_CANCEL, this.handleCallingCancel, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 通话超时未应答 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.CALLING_TIMEOUT, this.handleCallingTimeout, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 通话结束 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.CALL_END, this.handleCallingEnd, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // SDK Ready 回调 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.SDK_READY, this.handleSDKReady, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 被踢下线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.KICKED_OUT, this.handleKickedOut, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 切换通话模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.CALL_MODE, this.handleCallMode, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 自己发送消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.on(EVENT.MESSAGE_SENT_BY_ME, this.messageSentByMe, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 取消 tsignaling 事件监听 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    _removeTSignalingEvent() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.ERROR, this.handleError); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 被邀请通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.INVITED, this.handleNewInvitationReceived); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户接听 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.USER_ACCEPT, this.handleUserAccept); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户进入通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.USER_ENTER, this.handleUserEnter); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户离开通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.USER_LEAVE, this.handleUserLeave); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户更新数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.USER_UPDATE, this.handleUserUpdate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户拒绝通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.REJECT, this.handleInviteeReject); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户无响应 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.NO_RESP, this.handleNoResponse); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 用户忙线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.LINE_BUSY, this.handleLineBusy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 通话被取消 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.CALLING_CANCEL, this.handleCallingCancel); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 通话超时未应答 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.CALLING_TIMEOUT, this.handleCallingTimeout); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 通话结束 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.CALL_END, this.handleCallingEnd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // SDK Ready 回调 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.SDK_READY, this.handleSDKReady); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 被踢下线 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.KICKED_OUT, this.handleKickedOut); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 切换通话模式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.CALL_MODE, this.handleCallMode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 自己发送消息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.off(EVENT.MESSAGE_SENT_BY_ME, this.messageSentByMe); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * C2C邀请通话,被邀请方会收到的回调 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 如果当前处于通话中,可以调用该函数以邀请第三方进入通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Object} params 呼叫参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {String} params.userID 被邀请方 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Number} params.type 0-未知,1-语音通话,2-视频通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Number} params.roomID 数字房间号, 范围 1~2147483647 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {String=} params.userData 扩展字段: 用于在邀请信令中增加扩展信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    call: throttle(async function (params) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.initialUI(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.callStatus !== STATUS.IDLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.checkRunPlatform(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.config.type = params.type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 检查设备权限 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const deviceMap = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        microphone: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        camera: params.type === MEDIA_TYPE.VIDEO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const hasDevicePermission = await wx.$TUICallEngine.deviceCheck(deviceMap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const callStatus = hasDevicePermission ? STATUS.CALLING : STATUS.IDLE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        callStatus, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isSponsor: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        config: this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.getUserProfile([params.userID]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.warn(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.call({ userID: params.userID, type: params.type, roomID: params.roomID, userData: params.userData }).then(async (res) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (res) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            callStatus: STATUS.CALLING, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pusher: res.pusher, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.data.callingBell.setBellSrc(INVITER_BELL_FILEPATH); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.data.callingBell.play(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.setSoundMode(this.data.config.type === MEDIA_TYPE.AUDIO ? AUDIO_PLAYBACK_DEVICE.EAR : AUDIO_PLAYBACK_DEVICE.SPEAKER); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .catch((error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (error.code === -1002) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            wx.showModal({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              title: 'error', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              content: error.message, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              showCancel: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          throw new Error(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, THROTTLE_TIME), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * IM群组邀请通话,被邀请方会收到的回调 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 如果当前处于通话中,可以继续调用该函数继续邀请他人进入通话,同时正在通话的用户会收到的回调 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Object} params 呼叫参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Array<String>} params.userIDList 邀请列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Number} params.type 1-语音通话,2-视频通话 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {String} params.groupID IM群组ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {Number} params.roomID 数字房间号, 范围 1~2147483647 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param {String=} params.userData 扩展字段: 用于在邀请信令中增加扩展信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    groupCall: throttle(async function (params) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 判断是否存在groupID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!params.groupID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showToast({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: '群ID为空', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.initialUI(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.callStatus !== STATUS.IDLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.checkRunPlatform(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.data.config.type = params.type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 检查设备权限 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const deviceMap = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        microphone: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        camera: params.type === MEDIA_TYPE.VIDEO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const hasDevicePermission = await wx.$TUICallEngine.deviceCheck(deviceMap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const callStatus = hasDevicePermission ? STATUS.CALLING : STATUS.IDLE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        callStatus, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isSponsor: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isGroup: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        sponsor: this.data.config.userID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        config: this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 将自身的userID插入到邀请列表中,组成完整的用户信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const list = JSON.parse(JSON.stringify(params.userIDList)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      list.unshift(this.data.config.userID); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 获取用户信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.getUserProfile(list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.warn(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.groupCall({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userIDList: params.userIDList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: params.type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        groupID: params.groupID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        roomID: params.roomID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        userData: params.userData, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).then(async (res) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (res) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.data.config.type = params.type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pusher: res.pusher, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            callStatus: STATUS.CALLING, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.data.callingBell.setBellSrc(INVITER_BELL_FILEPATH); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.data.callingBell.play(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .catch((error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (error.code === -1002) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            wx.showModal({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              title: 'error', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              content: error.message, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              showCancel: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          throw new Error(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, THROTTLE_TIME), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 当您作为被邀请方收到 {@link TRTCCallingDelegate#onInvited } 的回调时,可以调用该函数接听来电 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    accept: throttle(async function () { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.accept().then((res) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (res) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            pusher: res.pusher, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            callStatus: STATUS.CONNECTED, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 多人通话需要对自身位置进行修正,将其放到首位 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            const newList = this.data.allUsers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (let i = 0;i < newList.length;i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              if (newList[i].userID === this.data.config.userID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                newList[i].isEnter = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                [newList[i], newList[0]] = [newList[0], newList[i]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              allUsers: newList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .catch((error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.error(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, THROTTLE_TIME), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 当您作为被邀请方收到的回调时,可以调用该函数拒绝来电 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    reject: throttle(async function () { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.reject().then((res) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell && this.data.callingBell.stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .catch((error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.error(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, THROTTLE_TIME), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    messageSentByMe(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const message = event.data.data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.triggerEvent('sendMessage', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        message, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // xml层,是否开启扬声器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setSoundMode(type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        soundMode: wx.$TUICallEngine.selectAudioPlaybackDevice(type), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // xml层,挂断 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hangup: throttle(async function () { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await wx.$TUICallEngine.hangup(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.error(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, THROTTLE_TIME), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //  切换大小屏 (仅支持1v1聊天) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    toggleViewSize(event) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // FIXME _toggleViewSize 不应该为TUICallEngine的方法 后续修改 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        screen: wx.$TUICallEngine._toggleViewSize(event), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 数据重置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    reset() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (shouldHideTabBar) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showTabBar(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        callStatus: STATUS.IDLE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isSponsor: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isGroup: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        soundMode: AUDIO_PLAYBACK_DEVICE.SPEAKER, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pusher: {}, // TRTC 本地流 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        playerList: [], // TRTC 远端流 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        showToatTime: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 呼叫中的事件处理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async handleCallingEvent(data) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { name, event } = data.detail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      switch (name) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'accept': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.setSoundMode(this.data.config.type === MEDIA_TYPE.AUDIO ? AUDIO_PLAYBACK_DEVICE.EAR : AUDIO_PLAYBACK_DEVICE.SPEAKER); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.accept(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'hangup': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.hangup(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'reject': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.reject(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'toggleSwitchCamera': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine.switchCamera(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'switchAudioCall': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine.switchCallMediaType(MEDIA_TYPE.AUDIO).then((res) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.data.config.type = MEDIA_TYPE.AUDIO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.setSoundMode(AUDIO_PLAYBACK_DEVICE.EAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              config: this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherErrorHandler': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.pusherErrorHandler(event.errMsg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 通话中的事件处理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async handleConnectedEvent(data) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { name, event } = data.detail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      switch (name) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'toggleViewSize': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.toggleViewSize(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherNetStatus': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._pusherNetStatus(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'playNetStatus': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._playNetStatus(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherStateChangeHandler': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._pusherStateChangeHandler(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherAudioVolumeNotify': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._pusherAudioVolumeNotify(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'playerStateChange': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._playerStateChange(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'playerAudioVolumeNotify': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._playerAudioVolumeNotify(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherAudioHandler': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._pusherAudioHandler(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'hangup': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.hangup(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'toggleSoundMode': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.setSoundMode(this.data.soundMode === AUDIO_PLAYBACK_DEVICE.EAR ? AUDIO_PLAYBACK_DEVICE.SPEAKER : AUDIO_PLAYBACK_DEVICE.EAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherVideoHandler': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine._pusherVideoHandler(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'toggleSwitchCamera': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine.switchCamera(event); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'switchAudioCall': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.$TUICallEngine.switchCallMediaType(MEDIA_TYPE.AUDIO).then((res) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.data.config.type = MEDIA_TYPE.AUDIO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              config: this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.setSoundMode(AUDIO_PLAYBACK_DEVICE.EAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'pusherErrorHandler': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.pusherErrorHandler(event.errMsg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理 pusher 中的异常问题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pusherErrorHandler(code) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      switch (code) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'fail:access denied': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          wx.showModal({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            title: '权限提示', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            content: '当前小程序 appid 不具备 <live-pusher> 和 <live-player> 的使用权限,您将无法正常使用实时通话能力,请使用企业小程序账号申请权限后再进行开发体验', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            showCancel: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 设置用户的头像、昵称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setSelfInfo(nickName, avatar) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return wx.$TUICallEngine.setSelfInfo(nickName, avatar); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 获取用户资料 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async getUserProfile(userList) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const imResponse = await this.getTim().getUserProfile({ userIDList: userList }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 修正用户资料 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.modifyUser(imResponse.data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 修正用户资料 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    modifyUser(userIDList) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { sponsor } = this.data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.isGroup) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 多人通话需要将呼叫者放到第一位 isEnter的作用是区分用户是否进入房间 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (let i = 0;i < userIDList.length;i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 主叫方的标志位设置成true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (userIDList[i].userID === sponsor) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            userIDList[i].isEnter = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 对主叫方位置进行修正 将其放到首位 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [userIDList[i], userIDList[0]] = [userIDList[0], userIDList[i]]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          // 其他用户默认未进入房间 设置为false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            userIDList[i].isEnter = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          allUsers: userIDList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        remoteUsers: userIDList, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 获取 tim 实例 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getTim() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return wx.$TUICallEngine.getTim(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 设置日志级别,低于 level 的日志将不会输出 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setLogLevel(leave) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wx.$TUICallEngine.setLogLevel(leave); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 初始化TUICallKit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async init(params) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (tuiCallInitReady) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tuiCallInitReady = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 关于 tabBar 页面的特化逻辑 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.handleTabBarLogic(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 兼容从config和init中传值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { sdkAppID, tim, userID, userSig, SDKAppID } = { ...this.data.config, ...params }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ownUserId: userID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        config: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ...this.data.config, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          sdkAppID: sdkAppID || SDKAppID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          userID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          userSig, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 取消全局监听 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (wx.$globalCallSign) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.$CallManagerInstance.removeEngineInvite(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setUniBellFilePath(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!this.data.callingBell) {  // 创建铃声实例 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const bellContext = new BellContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callingBell: bellContext, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!wx.$TUICallEngine) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.$TUICallEngine = TUICallEngine.createInstance({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          tim, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          sdkAppID: sdkAppID || SDKAppID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        _addTSignalingEvent 需要在 init 之前,回调才能正常触发 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tap:https://tapd.woa.com/20396022/prong/stories/view/1020396022885781069 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this._addTSignalingEvent(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await wx.$TUICallEngine.init({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            userID, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            userSig, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          tuiCallInitReady = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          throw new Error(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 用于全局监听进入 TUICallKit 页面中绑定上当前页面的监听。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this._addTSignalingEvent(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`${PREFIX} init Ready!`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 销毁 TUICallEngine 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async destroyed() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!wx.$TUICallEngine || !tuiCallInitReady) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tuiCallInitReady = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this._removeTSignalingEvent(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 全局监听模式下,离开页面需要重新绑定全局监听,但不卸载 TUICallEngine 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (wx.$globalCallSign) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 处理异常退出 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (this.getCallStatus() !== STATUS.IDLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.handleExceptionExit(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.$CallManagerInstance.addEngineInvite(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 非全局监听模式下,离开页面需要卸载 TUICallEngine 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.$TUICallEngine.destroyInstance(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.$TUICallEngine = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.callingBell) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.data.callingBell.destroyInstance(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          callingBell: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`${PREFIX} destroyed OK!`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      以下两种情况需要全部符合,则需要隐藏 tabBar 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      1.用户当前处于 tabBar 页面, isTabBar 为 true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      2.用户没有使用了自定义 tabBar, isCustomTabBar 为 fales 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleTabBarLogic() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const isTabBar = isTabBarPage(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const isCustomTabBar = tabBarConfig().custom || false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      shouldHideTabBar = isTabBar && !isCustomTabBar; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 检测运行时环境 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    checkRunPlatform() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const systemInfo = wx.getSystemInfoSync(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (systemInfo.platform === 'devtools') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 当前运行在微信开发者工具里 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        wx.showModal({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          icon: 'none', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: '运行环境提醒', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          content: '微信开发者工具不支持原生推拉流组件(即 <live-pusher> 和 <live-player> 标签),请使用真机调试或者扫码预览。', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          showCancel: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 运行在 uniapp 小程序需要修改铃声地址 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setUniBellFilePath() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 防止用户退出再进入,在地址前重复拼接 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (INVITER_BELL_FILEPATH.indexOf('wxcomponents') !== -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // comType 用于 Vue2 的判断,wxcomponents 用于 Vue3 的判断 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.dataset.comType === 'wx' || this.is.indexOf('wxcomponents') !== -1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        INVITER_BELL_FILEPATH = `wxcomponents/${INVITER_BELL_FILEPATH}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        INVITEE_BELL_FILEPATH = `wxcomponents/${INVITEE_BELL_FILEPATH}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 自定义铃声 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setCallingBell(filePath) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 如需恢复默认铃声,filePath 传空即可 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bellFilePath: filePath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理用户异常退出的情况,处理了右滑退出,以及返回退出的情况。 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async handleExceptionExit() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 在呼叫状态下,被叫调用 reject,主叫调用 hangup 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.getCallStatus() === STATUS.CALLING) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (this.isSponsor()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.hangup(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.reject(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 在通话状态下,统一调用 hangup 接口 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.getCallStatus() === STATUS.CONNECTED) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.hangup(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getCallStatus() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return this.data.callStatus; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    isSponsor() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return this.data.isSponsor; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 生命周期方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lifetimes: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    created() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    attached() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ready() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`${PREFIX} SDK Version: ${version}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async detached() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await this.destroyed(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    error() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pageLifetimes: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async show() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.data.config.sdkAppID) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.init(this.data.config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async hide() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.getCallStatus() === STATUS.IDLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.destroyed(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    resize() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 |