<template> <div class="ivr-div"> <ivr-btn :show="!signStatus" icon="qianru" @click="login">签入</ivr-btn> <ivr-btn :show="signStatus" icon="qianchu" @click="logout">签出</ivr-btn> <ivr-btn :show="!holdStatus" :disabled="(!signStatus)||(!isInCall)||(isInCall&&holdStatus)" icon="baochi" @click="hold">保持</ivr-btn> <ivr-btn :show="isInCall&&holdStatus" :disabled="isInCall&&!holdStatus" icon="baochi" @click="unhold">解除保持</ivr-btn> <ivr-btn :show="true" :disabled="(!signStatus)||(signStatus&&isInCall)" icon="hujiao" @click="dialIn">内呼</ivr-btn> <ivr-btn :show="true" :disabled="(!signStatus)||(signStatus&&isInCall)" icon="duiwaihujiao" @click="dialOut">外呼</ivr-btn> <ivr-btn :show="true" :disabled="!(isInCall&&isInComing)" icon="hujiao" @click="transferDial">转接</ivr-btn> <ivr-btn :disabled="!isInCall" icon="guaji" @click="hangup">挂机</ivr-btn> <ivr-btn :disabled="!(isInCall&&isInComing)" icon="hy" @click="meeting">会议</ivr-btn> <ivr-btn :show="!btnStatus.btnIdle" :disabled="btnStatus.btnIdle" icon="xiaoxiu" @click="onidle">退出示忙</ivr-btn> <ivr-btn :show="btnStatus.btnIdle" :disabled="btnStatus.btnBusy" icon="shimang" @click="onbusy">示忙</ivr-btn> <!--<ivr-btn :show="!btnStatus.btnQuitWorkState" :disabled="btnStatus.btnWorkState" icon="icon-work" @click="quitWorkState">退出工作态</ivr-btn>--> <!--<ivr-btn :show="!btnStatus.btnWorkState" :disabled="btnStatus.btnQuitWorkState" icon="icon-work" @click="goWorkState">进入工作态</ivr-btn>--> <div class="state-show"> <div>来电号码:<span class="highlight">{{ number }}</span></div> <div>通话时间:<span class="highlight">{{ time | timeFilter }}</span><span class="highlight">{{ callStatus | windowTextFilter }}</span></div> </div> <!--软键盘--> <keyboard ref="keyboard" @call="dial"/> <!--选择分机--> <choose-exten ref="chooseexten" :exten-list="extenList" @finish="finishChooseExten"/> <!--选择坐席--> <choose-seats ref="chooseseats" :seat-list="extensionList" :self="nowExten" @call="dial"/> <!--外呼状态栏--> <el-dialog :title="statusText" :visible.sync="statusShow" width="30%" append-to-body> <span>{{ callStatus }}</span><span class="dot">...</span> </el-dialog> <!--新建事件页面--> <el-dialog :visible.sync="showAddCase" :close-on-click-modal="false" :close-on-press-escape="false" title="新建事件" width="1200px" custom-class="addcase-dialog" top="60px" append-to-body> <left-call-bar :tel="currentNumber" :hold-status="holdStatus" @click="click"/> <div style="display: inline-block; width:1070px;"> <create-case ref="addcase" @cancel="closeCreateDialog"/> </div> </el-dialog> </div> </template> <script> import Keyboard from './keyboard' import IvrBtn from './ivrBtn' import CreateCase from '@/views/caseManage/createCase' import { getToday } from '@/utils/dateutils' import ChooseSeats from './chooseSeats' import { getProject } from '@/utils/baseConfig' import { seatReport } from '@/api/call' import ChooseExten from './chooseExten' import { mapState } from 'vuex' import LeftCallBar from '../../../components/cti/LeftCallBar' export default { name: 'IvrBar', components: { LeftCallBar, ChooseExten, ChooseSeats, CreateCase, IvrBtn, Keyboard }, data() { return { debug: true, // 是否开启debug模式 nowExten: '', // 当前使用的分机号 extenList: [], // 待选分机列表 agentName: this.$store.getters.seat, // 坐席号 userId: this.$store.getters.id, // 用户id deptid: this.$store.getters.deptId, // 部门编号 deptName: this.$store.getters.deptName, // 部门名称 seatsList: [], // 坐席列表 heartbeatInterval: 0, // 心跳interval heartbeatCount: 0, // 心跳heartbeat count heartbeatID: 0, // 心跳heartbeat id // webSocket: this.$store.state.ivr.websocket, // ws btnStatus: { btnLogin: false, // 签入 btnLogOut: true, // 签出 btnHold: true, // 保持 btnUnhold: true, // 解除保持 btnHangUp: true, // 挂机 btnDialOut: true, // 外呼 btnDialIn: true, // 内呼 btnTransfer: true, // 转接 btnBusy: true, // 示忙 btnIdle: true, // 示闲 btnMeeting: true, // 会议/三方通话 btnWorkState: false, // 进入工作态 btnQuitWorkState: true // 退出工作态 }, status: '', // 签入状态:已连接,已签入,未签入 holdStatus: false, // 保持状态 currentNumber: '', // 当前接入号码 busy: '', // 坐席忙碌状态 :忙碌,'', 另一坐席已登录 call: '', // 通话状态 isInComing: false, // 是否来电 // reg: '', // 话机状态 number: '', // 通话号码 diaStatus: '', // 拨号状态 statusText: '', // 拨号状态标题 statusDetailText: '', // 拨号状态详情 statusShow: false, // 拨号的状态显示 time: 0, // 来电计时,单位:秒 timeInterval: null, threeWayPhone: '', // 三方通话电话号码 ip: getProject().ws_ip, // websocket Ip port: getProject().ws_port, // webSocket Port showAddCase: false, // 是否显示新建案卷的弹窗 notify: null // 来电通知 } }, computed: { ...mapState({ exten: state => state.user.exten, // 用户绑定的分机号 wsStatus: state => state.ivr.wsStatus, signStatus: state => state.ivr.signStatus, // 签入签出状态 callStatus: state => state.ivr.callStatus, isInCall: state => state.ivr.isInCall, isInComming: state => state.ivr.isInComming, extensionList: state => state.ivr.extensionList, reg: state => state.ivr.reg, webSocket: state => state.ivr.webSocket, websocketObj: state => state.ivr.websocketObj }), timeFormat() { // 将时间格式化为时分秒样式 const h = Math.floor(this.time / 3600) const m = Math.floor((this.time - h * 3600) / 60) const s = this.time - h * 3600 - m * 60 const str = ('0' + h).slice(-2) + ':' + ('0' + m).slice(-2) + ':' + ('0' + s).slice(-2) return str } }, filters: { // 呼叫时间过滤器 timeFilter(val) { const h = Math.floor(val / 3600) const m = Math.floor((val - h * 3600) / 60) const s = val - h * 3600 - m * 60 const str = ('0' + h).slice(-2) + ':' + ('0' + m).slice(-2) + ':' + ('0' + s).slice(-2) return str }, // 弹窗内文字 windowTextFilter(val) { if (val) { if (val === '呼入振铃') { return '呼入振铃' } else if (val === '外呼振铃' || val === '外呼准备' || val === '开始拨号') { return '呼叫中' } else if (val === '通话结束' || val === '空闲') { return '空闲中' } else { return '通话中' } } else { return '空闲中' } } }, watch: { // busy(val) { // // 忙碌状态为不忙时,示忙按钮允许点,示闲不允许 // if (val === '') { // this.btnStatus.btnBusy = false // this.btnStatus.btnIdle = true // } else if (val === '忙碌') { // this.btnStatus.btnBusy = true // this.btnStatus.btnIdle = false // } // }, // wsStatus(val) { // 监控ws连接状态 // if (val) { // 如果wsStatus==true // if (!this.signStatus) { // 如果还没有签入 // this.btnStatus.btnLogin = false // } else { // this.btnStatus.btnLogin = true // } // } else { // this.btnStatus.btnLogin = true // } // }, signStatus(val) { // 监控签入状态 console.log('sign status Change:' + val) if (val) { // 已签入 this.onLoginSuccess() } else { this.logoutSuccess() } }, callStatus(val) { // 通话状态 console.log(val) if (val === '通话结束') { // 通话结束 this.callOver() } else if (val === '外呼通话' || val === '呼入通话' || val === '自动外呼接入') { this.startCall() } }, reg(val) { if (val === 'incomming answered') { // 接听呼入 this.incommingAnswerd() } else if (val === 'holding') { // 状态为保持 this.holdStatus = true this.btnStatus.btnHold = true this.btnStatus.btnUnhold = false } else if (val === 'unholding') { // 状态为解除保持 this.holdStatus = false this.btnStatus.btnHold = false this.btnStatus.btnUnhold = true } else if (val === 'incomming ringing') { // 来电振铃 this.notify = this.$notify({ title: '未接来电', message: this.websocketObj.number, duration: 100000 }) } else if (val === 'outbound ringing') { // 外呼振铃后的操作 this.onOutBoundRinging() } else if (val === 'outbound answered') { // 外呼接通,允许保持,挂断 this.onOutBoundAnswered() } else if (val === 'hangup') { // 挂断, 保持和解除保持不好用,其他均可 this.btnStatus.btnDialOut = false this.btnStatus.btnDialIn = false this.btnStatus.btnHold = true this.btnStatus.btnUnhold = true this.btnStatus.btnBusy = false this.btnStatus.btnIdle = true this.btnStatus.btnMeeting = false this.btnStatus.btnHangUp = false } } }, created() { this.initSocket() }, methods: { // 初始化Socket,ok initSocket() { if ('WebSocket' in window) { console.log('您的浏览器支持Websocket!') this.$store.dispatch('initWebSocket') } else { this.$message.error('您的浏览器不支持Websocket!请更换浏览器!') } }, // 坐席签入,ok login() { // 先判断websocket状态 if (this.wsStatus) { // 如果没有绑定的分机号,需要先输入分机号,有分机号直接签入 if (!this.exten) { this.$prompt('请输入分机号', '提示', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(({ value }) => { this.nowExten = value this.doLogin() }) } else { // 获取分机号, this.extenList = this.exten.split(',') if (this.extenList.length > 1) { // 打开选择分机号弹窗 this.$refs.chooseexten.initDialog() } else { this.nowExten = this.exten this.doLogin() } } } else { this.$message.error('websocket连接状态异常,请刷新页面') } }, // 结束选择分机号 finishChooseExten(exten) { this.nowExten = exten this.doLogin() }, // websocket执行签入操作 doLogin() { // 传入分机号和坐席名称 const { userId, deptid, deptName, nowExten, agentName } = this this.$store.dispatch('signin', { userId, deptid, deptName, nowExten, agentName }) }, // 签入成功后按钮的操作 onLoginSuccess() { this.onidle() this.btnStatus.btnLogin = true // 签入按钮不显示 this.btnStatus.btnLogOut = false this.btnStatus.btnDialOut = false this.btnStatus.btnDialIn = false this.btnStatus.btnHold = false this.btnStatus.btnUnhold = true this.btnStatus.btnBusy = false this.btnStatus.btnIdle = true // 置闲不显示 this.btnStatus.btnMeeting = true this.btnStatus.btnHangUp = true this.btnStatus.btnTransfer = true // 转接不可用 this.status = '已签入' this.call = '空闲' // 通知后台已签入 this.sendRecord('1', '签入') }, // 坐席签出 logout() { this.$confirm( '确认签出吗?', '确认操作', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ).then(() => { this.$store.dispatch('signout') }) }, logoutSuccess() { this.status = '未签入' this.$message.success('签出成功') // 处理按钮状态 this.btnStatus.btnLogin = false this.btnStatus.btnLogOut = true this.btnStatus.btnDialOut = true this.btnStatus.btnDialIn = true this.btnStatus.btnTransfer = true this.btnStatus.btnHold = true this.btnStatus.btnUnhold = true this.btnStatus.btnBusy = false this.btnStatus.btnIdle = true this.btnStatus.btnMeeting = true this.btnStatus.btnHangUp = true // 通知后台已签入 this.sendRecord('1', '签出') }, // 外呼,ok dialOut() { if (this.judgeStatus()) { if (!this.isInCall) { this.$refs.keyboard.initDialog('out') } else { this.$message.warning('已在通话中') } } }, // 内呼,ok dialIn() { if (this.judgeStatus()) { // 如果在通话中,不允许内呼 if (!this.isInCall) { this.getExtentionList() this.$refs.chooseseats.initDialog('in') } else { this.$message.warning('已在通话中') } } }, // 转接,ok transferDial() { if (this.judgeStatus()) { // 判断坐席状态 if (this.judgeCallStatus()) { // 判断通话状态 if (this.isInComing) { // 判断是否外接电话 this.getExtentionList() this.$refs.keyboard.initDialog('transfer') } else { this.$message.warning('只有外接电话才允许转接') } } } }, // 获取已登录坐席列表,ok getExtentionList() { const params = { type: 'agent' } this.$store.dispatch('getExtensionList', params) }, // 拨号 dial(type, tel) { if (type === 'meeting') { // 三方通话 this.goMeeting(tel) } else if (type === 'transfer') { // 转移 this.goTransfer(tel) } else if (type === 'out') { // 外呼 this.statusShow = true this.statusText = '呼叫中...' this.statusDetailText = '呼叫中' this.$store.dispatch('dial', tel) } else { // 内呼 this.statusShow = true this.statusText = '呼叫中...' this.statusDetailText = '呼叫中' this.$store.dispatch('dial', tel) } }, // 直接去转接 goTransfer(tel) { this.$store.dispatch('transfer', tel) }, // 示忙 onbusy() { if (this.judgeStatus()) { // 已签入且不在通话中 if (!this.isInCall) { this.$store.dispatch('onbusy') this.btnStatus.btnBusy = true this.btnStatus.btnIdle = false this.sendRecord('4', '置忙') } } }, // 示闲 onidle() { if (this.judgeStatus()) { // 已签入且不在通话中 if (!this.isInCall) { this.$store.dispatch('onidle') this.btnStatus.btnBusy = false this.btnStatus.btnIdle = true this.sendRecord('4', '置闲') } } }, // 挂机 hangup() { if (this.judgeStatus()) { // 判断坐席状态, if (this.judgeCallStatus()) { // 判断通话状态 this.$store.dispatch('hangup') } } }, // 保持 hold() { if (this.judgeStatus()) { // 判断坐席状态 if (this.judgeCallStatus()) { // 判断通话状态 this.$store.dispatch('hold') this.sendRecord('3', '进入保持') } } }, // 解除保持 unhold() { if (this.judgeStatus()) { this.$store.dispatch('unhold') this.sendRecord('3', '解除保持') } }, // 通话开始 startCall() { const that = this this.number = this.websocketObj.number // 开始通话后3s弹窗消失 if (this.statusShow) { setTimeout(function() { that.statusShow = false }, 3000) } // 开启计时器 this.time = 0 this.timeInterval = setInterval(function() { that.time += 1 }, 1000) }, // 通话结束 callOver() { this.btnStatus.btnTransfer = true this.btnStatus.btnHangUp = true // 结束计时器 if (this.timeInterval) { this.$message.info('通话结束') clearInterval(this.timeInterval) this.timeInterval = null this.time = 0 this.number = '' } // 如果还显示着弹窗,关闭弹窗 if (this.statusShow) { this.statusShow = false } // 如果是来电,进入工作态 // if (this.isInComing) { // this.goWorkState() // } }, // 处理接通来电之后 incommingAnswerd() { const object = this.websocketObj this.isInComing = true if (this.notify) { this.notify.close() // 关闭来电提醒 } // 处理按钮显示问题 this.btnStatus.btnDialOut = true this.btnStatus.btnDialIn = true this.btnStatus.btnHold = false this.btnStatus.btnUnhold = true // this.btnStatus.btnBusy = false // this.btnStatus.btnIdle = true this.btnStatus.btnMeeting = true this.btnStatus.btnHangUp = false this.btnStatus.btnTransfer = false // 判断是不是内呼,内呼则不弹出新建工单页面 // if (!this.judgeInsideNumber()) { // 弹出新建工单窗口 this.showAddCase = true const data = { callid: object.callid, number: object.number, dialStartStamp: getToday('yyyy-MM-dd HH:mm:ss') } this.currentNumber = object.number console.log(data) const that = this setTimeout(function() { that.$refs['addcase'].initData(data) }, 500) // } }, // 新建事件完毕调用 closeCreateDialog() { this.showAddCase = false // 关闭弹窗 }, // 进入工作态 goWorkState() { // this.$message.info('已进入工作态') this.btnStatus.btnWorkState = true this.btnStatus.btnQuitWorkState = false this.sendRecord('2', '进入工作态') this.onbusy() // 置忙 }, // 退出工作态 quitWorkState() { // this.$message.info('已退出工作态') this.btnStatus.btnWorkState = false this.btnStatus.btnQuitWorkState = true this.sendRecord('2', '退出工作态') this.onidle() // 置闲 }, // 点击会议,打开会议弹窗 meeting() { if (this.judgeStatus()) { // 判断坐席状态 if (this.judgeCallStatus()) { // 判断通话状态 if (this.isInComing) { this.getExtentionList() this.$refs.chooseseats.initDialog('meeting') } else { this.$message.warning('只有外接电话才允许三方通话') } } } }, // 开启三方通话 goMeeting(tel) { this.$store.dispatch('meeting', tel) }, // 外呼振铃的操作 onOutBoundRinging() { // 除了挂断其他不允许点 this.btnStatus.btnDialOut = true this.btnStatus.btnDialIn = true this.btnStatus.btnHold = true this.btnStatus.btnUnhold = true this.btnStatus.btnBusy = true this.btnStatus.btnIdle = true this.btnStatus.btnMeeting = true this.btnStatus.btnHangUp = false }, // 外呼接听后的操作 , 允许保持,允许挂断,其余均不允许 onOutBoundAnswered() { this.btnStatus.btnHold = false this.btnStatus.btnHangUp = false this.btnStatus.btnTransfer = true this.btnStatus.btnDialOut = true this.btnStatus.btnDialIn = true this.btnStatus.btnUnhold = true this.btnStatus.btnBusy = true this.btnStatus.btnIdle = true this.btnStatus.btnMeeting = true }, // 获取坐席列表,存到seatsList handleExtensionList(object) { if (object.success) { const test = object.resultText const index = test.indexOf(',') if (index > 0) { const messageList = test.split(',') console.log(messageList.length) for (let i = 0; i < messageList.length; i++) { const tList = messageList[i].split('|') const seat = { exten: tList[0], name: tList[1], loginId: tList[2], sector: tList[3], group: tList[4], state: tList[5], busy: tList[6] } this.seatsList.push(seat) } } } }, // 显示错误信息 showError(message) { this.$message.error(message) }, // 判断坐席状态 judgeStatus() { if (this.signStatus) { return true } else { this.$message.warning('请先签入呼叫平台') return false } }, // 判断通话状态 judgeCallStatus() { if (this.isInCall) { return true } else { this.$message.warning('未在通话中') return false } }, judgeInsideNumber(number) { if (number.length > 4) { return false } else { return true } }, // 向后台写记录 sendRecord(type, recordName) { seatReport(type, recordName) }, click(method) { switch (method) { case 'hangup': this.hangup() break case 'hold': this.hold() break case 'unhold': this.unhold() break case 'transfer': this.transferDial() break case 'meeting': this.meeting() break default: break } } } } </script> <style rel="stylesheet/scss" lang="scss" scoped> .ivr-div{ position: fixed; top:0px; left:240px; padding-top: 10px; .el-button--default{ width:50px; display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background-color:transparent; border-style:none; color: #ffffff; -webkit-appearance: none; text-align: center; -webkit-box-sizing: border-box; box-sizing: border-box; outline: none; margin: 0; -webkit-transition: .1s; transition: .1s; font-weight: 500; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; padding: 3px 3px; font-size: 12px; .ivr-icon{ width: 100%; text-align: center; display: block; font-size: 25px; margin-bottom: 2px; } } .el-button.is-disabled, .el-button.is-disabled:hover, .el-button.is-disabled:focus{ color: #e1e1e1; .ivr-icon{ color: #e1e1e1 !important; } } .state-show{ display: inline-block; width:200px; margin-left: 20px; border:1px solid #409EFF; color:#ffffff; font-size:12px; line-height: 17px; padding:5px 5px; height: 45px; box-sizing: border-box; transform: translate(0, -8px); } .highlight{ font-size:13px; font-weight: 600; color:#00ffff; padding-left: 5px; } } </style> <style rel="stylesheet/scss" lang="scss" > .addcase-dialog{ .el-dialog__body{ display: flex; justify-content: space-between; } } .dot { font-family: simsun; } :root .dot { display: inline-block; width: 1.5em; vertical-align: bottom; overflow: hidden; } @-webkit-keyframes dot { 0% { width: 0; margin-right: 1.5em; } 33% { width: .5em; margin-right: 1em; } 66% { width: 1em; margin-right: .5em; } 100% { width: 1.5em; margin-right: 0;} } .dot { -webkit-animation: dot 3s infinite step-start; } @keyframes dot { 0% { width: 0; margin-right: 1.5em; } 33% { width: .5em; margin-right: 1em; } 66% { width: 1em; margin-right: .5em; } 100% { width: 1.5em; margin-right: 0;} } .dot { animation: dot 3s infinite step-start; } </style>