青岛网站设计建设,国外免费服务器平台,个人如何在企业网站做实名认证,怎么样建立学校网站先把封装好的地址安上#xff08;非本人封装#xff09;#xff1a;webrtc-webphone: 基于JsSIP开发的webrtc软电话
jssip中文文档#xff1a;jssip中文开发文档#xff08;完整版#xff09; - 简书
jssip使用文档#xff1a;#xff08;我没有运行过#xff0c;但…先把封装好的地址安上非本人封装webrtc-webphone: 基于JsSIP开发的webrtc软电话
jssip中文文档jssip中文开发文档完整版 - 简书
jssip使用文档我没有运行过但是他写的很清楚反正比我好jssipwebrtcfreeswitch实现电话网页及遇到的488状态码问题_freeswitch 488_weixin_39715323的博客-CSDN博客
正常使用由于web限制应该在https上使用但是http也不是不可以我放到下一篇文章了这就说怎么使用
我这用的是webrtcjssip
webrtc-webphone已经实现了我的需求所以我没有使用原生jssip
特主要实现的功能有注册拨叫接听保持恢复
我的项目中需要静音指我不能说话通话人可以讲话
所以我将hold保持和unhold恢复改成了mute和unmute 下面是完整代码和方法说明
1.init注册citbarconfig中需要使用ip地址、端口号、extNo拨号人、extPwd密码
2.handleAgentBarBtnClick通话状态更改 makecall拨号 hangup挂断 hold静音 unhold取消静音
3.onbeforeunload 通话中刷新对讲群组中没有退出导致群组中有多个同一个人
4.beforeDestroy切换页面后没有退出群组刷新不走这个方法
注意
1.不要重复拨号状态卡住后就能同一个设备对话了bug
2.如果想切换页面还能通话就不要beforeDestroy但是在其他页面在回来时会导致状态不一致而且容易出现卡状态所以我将通话操作放在index最顶层里面
templatediv classtopdiv stylepadding: 0 30px;div styledisplay: flex;padding-top: 3px;!-- 设备树插件 --organizationTree reforganizationTree/organizationTreediv stylewidth:77vw;height:80vh; margin-top: 5px;div classphoto_date styleposition:relativediv styledisplay:flex;min-width:30%div classtext_type photo_deviceName v-showgroupName styletext-align: center;{{groupName}}/divdiv classtext_type :classmeetingStatus2? meetingName1: meetingNamestylewidth: 125px;text-align: center;{{meetingStatus2?meetingName:meetingName1}}/div/divdiv styleposition: absolute;right: 0; v-showcreateByuserNamediv v-showmeetingStatus2 classbtn_type photo_meeting_btn clickmeetingAllstyleposition:absolute; right:135px;width: 140px;height: 35px;line-height: 35px;邀请全部成员/divdiv classbg_btn_type photo_meeting_btn clickmeetingstyleposition:absolute; right:0;width: 125px;height: 35px;line-height: 35px;{{meetingStatus1?开始会议:结束会议}}/div/div/divdiv classdiv classdeviceList_titlediv classdeviceList_title_text stylewidth:15%名称/divdiv classdeviceList_title_text stylewidth:15%imei/divdiv classdeviceList_title_text stylewidth:15%类型/divdiv classdeviceList_title_text stylewidth:15%状态/divdiv classdeviceList_title_text stylewidth:15%会议状态/divdiv classdeviceList_title_text stylewidth:24%操作/div!-- div classdeviceList_title_text操作/div --/divdiv v-showdeviceList classdeviceListdiv classdeviceList_list :classitem.iditemId?deviceList_list1:v-for(item,index) in deviceList :keyitem.id mouseovermouseover(item.id)mouseleavemouseout()!-- el-tooltip :contentitem.name placementbottom effectlight --div classdeviceList_title_text stylewidth:15%{{item.devName}}/div!-- /el-tooltip --div classdeviceList_title_text stylewidth:15%{{item.imei}}/divdiv classdeviceList_title_text stylewidth:15%{{item.devTypeName}}/divdiv classdeviceList_title_text stylewidth:15%{{dictionary(item.devStatus,dev_status,item.imei)}}/divdiv classdeviceList_title_text stylewidth:15%{{dictionary(item.memberStatus,meeting_member_status)}}/divdiv stylewidth:24%;div v-ifmeetingStatus2div v-ifitem.imei createByitem.imei userNamediv v-ifitem.devStatus3||item.devStatus4||item.devStatus5||item.devStatus1div stylewidth:100%;justify-content: center; classdeviceList_operatediv classdeviceList_title_text1 clickspeak(request)v-ifitem.memberStatus!3item.memberStatus!1item.memberStatus!4item.memberStatus!5div开始发言/div/divdiv classdeviceList_title_text1 clickspeak(request) v-ifitem.memberStatus3div结束发言/div/divdiv classdeviceList_title_text1 clickoutMeeting v-ifitem.memberStatus2离开会议/divdiv classdeviceList_title_text1 clickinMeeting v-ifitem.memberStatus1进入会议/div/div/div/divdiv v-ifitem.imei ! createBydiv v-ifitem.devStatus3||item.devStatus4||item.devStatus5||item.devStatus1div stylewidth:100%;justify-content: center; classdeviceList_operatev-showcreateByuserNameisInOrOutMeetingdeviceList[0].memberStatus2div classdeviceList_title_text1 clickspeak(call,item.imei,start)v-ifitem.memberStatus!3item.memberStatus!1item.memberStatus!4item.memberStatus!5div点名发言/div/divdiv classdeviceList_title_text1 clickspeak(call,item.imei,end)v-ifitem.memberStatus3div结束发言/div/divdiv classdeviceList_title_text1 clickinOrOut(out,item.imei)v-ifitem.memberStatus2请离会议/divdiv classdeviceList_title_text1 clickinOrOut(in,item.imei)v-ifitem.memberStatus1拉入会议/div/div/div/div/div/div/div/div/div/div/div/div/div/template
scriptimport Header from ../home/header/index;import Footer from ../home/footer/index;import webSocketClass from /utils/webSocket;import { postWarnStatus } from /api/AlarmRecord;import organizationTree from ./deviceTree/organizationTreeimport { devicetree } from /api/system/deviceTree;import { timestampToTime } from ../../../utils/time.jsimport { addGroup, delGroup, getGroup, listGroup, updateGroup, updateMeetingStatus, selectDeviceGroupDetailList, deviceRequestTalking, inOrOutMeeting } from /api/system/group;import { listData } from /api/system/dict/data;import Ctibar from ./AgentBar/ctibar.js;var audio document.getElementById(audio);var constraints {audio: true,video: true,mandatory: {maxWidth: 640,maxHeight: 360}};URL window.URL || window.webkitURL;var eventHandlers {progress: function (e) {console.log(call is in progress);},failed: function (e) {console.log(call failed: , e);},ended: function (e) {console.log(call ended : , e);},confirmed: function (e) {console.log(call confirmed);}};export default {dicts: [warn_type],components: {Header,Footer,organizationTree},data() {return {// 以下群组isGroup: false,createBy: ,isInOrOutMeeting: false,isSpeak: false,itemId: ,meetingStatus: ,groupDetail: {},isMike: false,deviceList: null,meetingName1: 会议未开始,meetingName: 会议中,groupName: ,dataList: null,userId: JSON.parse(sessionStorage.getItem(userInfo)).userId,userName: JSON.parse(sessionStorage.getItem(userInfo)).userName,// 查询参数queryParams: {pageNum: 1,pageSize: 10,deptId: null,planName: null,status: null,},total: 0,deviceTreeList: [],title: ,num: 1,groupId: ,dictionaryList: [],websocket: null,//初始化SDK所需要的配置config: {host: 39.152.2.103,port: 5066,proto: false,extNo: ,extPwd: 20181231,autoRegister: true,debug: true,//stunServer: stun.1.google.com, 可自行修改使用stun服务器地址stateEventListener: this.stateEventListener},//坐席分机号agentNo: ,//客户号码customerNo: ,//拨号弹窗showDial: false,//转接弹窗showTransferDial: false,//转接号码transNum: ,numList: [1, 2, 3, 4, 5, 6, 7, 8, 9, *, 0, #,],agentStatus: DISCONNECTED,statusMap: {CONNECTED: 已连接,DISCONNECTED: 网络断开,REGISTERED: 已注册,UNREGISTERED: 未注册,REGISTER_FAILED: 注册失败,IN_CALL: 通话中,INCOMING_CALL: 来电振铃,OUTGOING_CALL: 外呼振铃,HOLD: 保持中,CALL_END: 通话结束},timer: null,timerString: 00:00:00,outNum: ,isHold: true};},computed: {classObject() {const bool1 this.alarmArr.length 1;const bool2 this.alarmArr.length 1;return {tanchuangbox: true,tanchuangbox-height-multi: bool1,tanchuangbox-height-single: bool2,};},},mounted() {this.init()},methods: {// 以下群组inMeeting() {this.loadingFun()var body {devImei: this.userName,flag: in,groupId: this.groupId,}inOrOutMeeting(body).then(response {if (response.data.success) {} else {this.$modal.msgError(response.data.message);}this.loading.close();},error {this.loading.close();});},outMeeting() {this.loadingFun()var body {devImei: this.userName,flag: out,groupId: this.groupId,}inOrOutMeeting(body).then(response {if (response.data.message 已离开) {} else {this.$modal.msgError(response.data.message);}this.loading.close();},error {this.loading.close();});},inOrOut(flag, devImei) {this.loadingFun()var body {devImei: devImei,flag: flag,groupId: this.groupId,}inOrOutMeeting(body).then(response {console.log(123123123, response)if (response.data.success) {this.$modal.msgSuccess(response.data.message);} else {this.$modal.msgError(response.data.message);}this.loading.close();},error {this.loading.close();});},loadingFun() {this.loading this.$loading({lock: true,text: Loading,spinner: el-icon-loading,background: rgba(0, 0, 0, 0.7)});},speak(type, devImei, flag) {this.loadingFun()var flagg if (type request) {flagg !this.isSpeak ? start : enddevImei this.userName} else {flagg flag}var body {devImei: devImei,flag: flagg,groupId: this.groupId,type: type,}deviceRequestTalking(body).then(response {if (response.data.success) {if (type request) {}this.$modal.msgSuccess(response.data.message);//恢复发言} else {this.$modal.msgError(response.data.message);this.hold()}this.loading.close();},error {this.loading.close();});},// 1、进入元素mouseover(index) {this.itemId index},// 4、离开元素mouseout() {this.itemId },ws() {console.log({groupId: this.groupId })this.websocket.webSocketSendMsg({groupId: this.groupId })},devStatus(devStatus) {for (const i in this.deviceList) {if (this.deviceList[i].devStatus devStatus) {this.deviceList[i].devStatus devStatus}}},dictionary(e, type, imei) {for (const i in this.dictionaryList) {if (this.createBy imei e 4) {return 在线}if (this.dictionaryList[i].dictValue e this.dictionaryList[i].dictType type) {return this.dictionaryList[i].dictLabel}}},handleAdd() {// this.reset();// this.open true;this.title 添加群组;},tableRowClassName({ row, rowIndex }) {return photo;},rowClass({ row, rowIndex }) {return text-align: center;background-color: #1A1D30;color: #fff},meetingAll() {var meetingStatusAll 2var params {groupId: this.groupId,meetingStatus: meetingStatusAll}updateMeetingStatus(params).then(response {if (response.code 200) {this.$modal.msgSuccess(response.msg);} else {this.$modal.msgError(response.msg);}});},meeting() {this.loadingFun()if (this.deviceList ! null) {console.log(meetingStatusmeetingStatus, this.meetingStatus)var params {groupId: this.groupId,meetingStatus: this.meetingStatus 1 ? 2 : 1}updateMeetingStatus(params).then(response {setTimeout(() {if (response.code 200) {if (this.meetingStatus 1) {if (sessionStorage.getItem(groupId) this.groupId) {this.handleAgentBarBtnClick(hangup)sessionStorage.setItem(groupId, )}this.isInOrOutMeeting falsethis.isHold truethis.loading.close()}}}, 5000);});}},//孙组件向父组件传递数据wsMeetingStatus(isInterface) {console.log(isMeeting状态, isInterface)this.meetingStatus isInterface},groupDeviceItemClick(item) {// this.handleAgentBarBtnClick(hangup)this.isSpeak falsethis.deviceList []this.groupId item.idthis.meetingStatus item.meetingStatusthis.groupName item.groupNamethis.createBy item.createBythis.item itemvar params { groupInfoId: item.id, pageNum: 0, pageSize: 0, }selectDeviceGroupDetailList(params).then(response {this.deviceList response.rowsthis.total this.deviceList.lengththis.ws()if (this.deviceList[0].memberStatus 3 this.deviceList[0].imei this.userName) {this.isSpeak true;}if (this.deviceList[0].memberStatus 2 this.deviceList[0].imei this.userName) {if (sessionStorage.getItem(groupId) this.groupId) {this.isInOrOutMeeting truereturn}if (sessionStorage.getItem(groupId)) {} else {this.call()}}});},onClickDialOutside(event) {console.log(event)this.showDial false},onClickTransDialOutside(event) {this.showTransferDial false;},handleAgentBarBtnClick(name) {console.log(name 当前)if (name login) {this.login();} else if (name logout) {this.logout();} else if (name answer) {this.answer();} else if (name hangup) {this.hangup();} else if (name makecall) {this.makeCall(9* this.groupId)} else if (name hold) {this.hold();} else if (name unhold) {this.unhold();} else if (name transfer) {this.transfer(this.transNum)}},login() {this.init()Ctibar.register()},logout() {Ctibar.unregister()},makeCall(phone) {if (phone || phone undefined) {console.error(无效的号码请重新输入);return}Ctibar.makecall(phone);},hold() {Ctibar.hold();},unhold() {Ctibar.unhold();},answer() {Ctibar.answer();},hangup() {Ctibar.hangup();},transfer(phone) {console.info(触发转接, phone)Ctibar.transfer(phone);},//外呼拨号盘handleDialBtnClick(val) {this.outNum val;this.$refs.outNumInput.focus();},//转接拨号盘handleTransDialBtnClick(val) {this.transNum val;this.$refs.transNumInput.focus();},//参数为时间差秒数返回这两个时间差并格式化computeTimeDiff(diff) {diff Math.round(diff / 1000);let hour Math.floor(diff / 3600).toString().padStart(2, 0);let min Math.floor((diff - hour * 3600) / 60).toString().padStart(2, 0);let sec (diff % 60).toString().padStart(2, 0);return hour : min : sec;},//重置时间restoreTime(origin) {clearInterval(this.timer);this.timerString 00:00:00;this.timer setInterval(() {this.timerString this.computeTimeDiff(new Date().getTime() - origin);}, 1000);},//状态变更回调stateEventListener(event, data) {//debug使用console.log(当前event为: event , 当前data为: JSON.stringify(data))this.agentStatus eventlet origin new Date().getTime();switch (event) {case CONNECTED:this.agentNo data.localAgentthis.restoreTime(origin);break;case DISCONNECTED:this.restoreTime(origin);break;case UNREGISTERED:this.restoreTime(origin);break;case OUTGOING_CALL:this.customerNo data.otherLegNumber;this.restoreTime(origin);break;case INCOMING_CALL:this.customerNo data.otherLegNumber;//播放来电振铃音this.playRingMedia();this.restoreTime(origin);break;case IN_CALL:this.stopPlayRingMedia();this.restoreTime(origin);// this.timer setInterval(() {// }, 1000);console.log(当前是否hold, this.isHold)if (this.isHold) {setTimeout(() {this.handleAgentBarBtnClick(hold)this.isHold false// 方法区}, 500);}break;case CALL_END:this.stopPlayRingMedia();//挂机铃声this.playHangupMedia()this.restoreTime(origin);break;default:}},//播放挂机铃声playHangupMedia() {const _this this;var hangupAudio document.getElementById(hangupMediaAudioId)if (!hangupAudio) {hangupAudio document.createElement(audio);hangupAudio.id hangupMediaAudioId;hangupAudio.hidden true;hangupAudio.src wav/hangup.wavdocument.body.appendChild(hangupAudio);}hangupAudio.play();},//播放来电振铃playRingMedia() {const _this this;_this.stopPlayRingMedia();var ringAudio document.getElementById(ringMediaAudioId)if (!ringAudio) {ringAudio document.createElement(audio);ringAudio.id ringMediaAudioId;ringAudio.hidden true;ringAudio.src wav/ring.wav;ringAudio.loop loop;document.body.appendChild(ringAudio);}ringAudio.play();},//停止播放来电振铃stopPlayRingMedia() {const _this this;var ringAudio document.getElementById(ringMediaAudioId);if (ringAudio) {document.body.removeChild(ringAudio);}},//初始化方法init() {this.config.extNo this.userNameif (sessionStorage.getItem(freeSwitchWs) ! null) {this.config.host sessionStorage.getItem(freeSwitchWs).split(:)[0]this.config.port sessionStorage.getItem(freeSwitchWs).split(:)[1]}Ctibar.initSDK(this.config)let url /ws/ this.userId /group/device/push;this.websocket new webSocketClass(url)this.websocket.getWebSocketMsg(evt {// 客户端接收服务端返回的数据var data JSON.parse(evt.data);console.log(websocket返回的数据123, data);switch (data.flag) {case group://会议状态this.$refs.organizationTree.setGroupList(data, this.groupId)console.log(websocket返回的数据123, data);breakcase memberStatus://成员状态for (const i in this.deviceList) {console.log(123123132, data.member);if (this.deviceList[i].imei data.member) {this.deviceList[i].devStatus data.memberStatus;}}breakcase memberMeetingStatus://成员会议状态for (const i in this.deviceList) {if (this.deviceList[i].imei data.member) {this.deviceList[i].memberStatus data.memberMeetingStatus;}}if (this.groupId data.groupId this.userName data.member this.createBy data.member) {if (data.memberMeetingStatus 3) {this.isSpeak true;this.unhold()console.log(数据this.isInOrOutMeeting1111, this.isSpeak)} else {this.isSpeak false;this.hold()}}if (data.memberMeetingStatus 4) {this.loading.close()}if (!this.isInOrOutMeeting this.groupId data.groupId this.userName data.member this.createBy data.member data.memberMeetingStatus 2) {this.hold()if (sessionStorage.getItem(groupId) sessionStorage.getItem(groupId) ! this.groupId) {} else {console.log(this.isInOrOutMeeting1111, data.memberMeetingStatus)this.call()}}if (this.createBy data.member data.memberMeetingStatus 1 this.userName data.member) {this.handleAgentBarBtnClick(hangup)sessionStorage.setItem(groupId, )this.isInOrOutMeeting falsethis.isSpeak falsethis.isHold true}break}})},setGroup(group) {this.isGroup group},call() {this.handleAgentBarBtnClick(makecall)sessionStorage.setItem(groupId, this.groupId)this.isInOrOutMeeting trueif (this.deviceList[0].imei ! this.createBy) {// this.groupDeviceItemClick(this.item)}var that thiswindow.onbeforeunload (e) {console.log(this.isInOrOutMeeting, that.isInOrOutMeeting)if (that.isInOrOutMeeting) {that.handleAgentBarBtnClick(hangup)sessionStorage.setItem(groupId, )that.websocket.closeSocket()window.onbeforeunload null}}this.loading.close()this.isInOrOutMeeting truethis.isHold true}},beforeDestroy() { //进行监听销毁console.log(1231232131232132131,, this.isInOrOutMeeting)if (this.isInOrOutMeeting) {this.handleAgentBarBtnClick(hangup)sessionStorage.setItem(groupId, )this.websocket.closeSocket()window.onbeforeunload null}},};
/script