|
@@ -10,7 +10,7 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="btn">
|
|
|
- <!-- 签出 -->
|
|
|
+ <!-- 签入 -->
|
|
|
<template v-if="telStatusInfo.isDutyOn">
|
|
|
<!-- 签出可用 -->
|
|
|
<div
|
|
@@ -127,24 +127,24 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
- <!-- 事后处理和取消事后处理 可用-->
|
|
|
+ <!-- 话后整理和取消话后整理中 可用-->
|
|
|
<template v-if="telStatusInfo.isDutyOn && activeArr.includes('TalkingDeal')">
|
|
|
<div
|
|
|
class="item active"
|
|
|
@click="onControlClick(telStatusInfo.isTalkingDeal ? 'unTalkingDeal' : 'TalkingDeal')"
|
|
|
@mouseenter="onHover('talkingDealSrc', 'phoneControls/talkingDeal_white.png')"
|
|
|
- :title="telStatusInfo.isTalkingDeal ? '取消事后处理' : '事后处理'"
|
|
|
+ :title="telStatusInfo.isTalkingDeal ? '取消话后整理' : '话后整理'"
|
|
|
@mouseleave="onHover('talkingDealSrc', 'phoneControls/talkingDeal_blue.png')"
|
|
|
>
|
|
|
<img :src="state.talkingDealSrc" alt="" />
|
|
|
- <span>{{ telStatusInfo.isTalkingDeal ? '取消事后处理' : '事后处理' }}</span>
|
|
|
+ <span>{{ telStatusInfo.isTalkingDeal ? '取消话后整理' : '话后整理' }}</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
- <!-- 事后处理不可用 -->
|
|
|
+ <!-- 话后整理中不可用 -->
|
|
|
<template v-else>
|
|
|
- <div class="item disabled" title="事后处理">
|
|
|
+ <div class="item disabled" title="话后整理">
|
|
|
<img :src="getImageUrl('phoneControls/talkingDeal_grey.png')" alt="" />
|
|
|
- <span>事后处理</span>
|
|
|
+ <span>话后整理</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -169,7 +169,7 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
- <!-- 三方会议 可用(两个通话 一个取消保持 一个保持 才能使用三方通话) -->
|
|
|
+ <!-- 三方会议 可用(当前处于通话中)-->
|
|
|
<template v-if="telStatusInfo.isDutyOn && activeArr.includes('conference')">
|
|
|
<div
|
|
|
class="item active"
|
|
@@ -182,6 +182,34 @@
|
|
|
<span>三方会议</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
+ <!-- 三方会议并且处于三方会议中 -->
|
|
|
+ <template v-else-if="telStatusInfo.isDutyOn && activeArr.includes('conference') && onCallArr.length === 2">
|
|
|
+ <el-popover
|
|
|
+ :width="130 * onCallArr.length"
|
|
|
+ :offset="0"
|
|
|
+ v-model:visible="threeWayVisible"
|
|
|
+ trigger="hover"
|
|
|
+ popper-class="hangup-popover"
|
|
|
+ >
|
|
|
+ <template #reference>
|
|
|
+ <div
|
|
|
+ class="item active"
|
|
|
+ @mouseenter="onHover('conferenceSrc', 'phoneControls/conference_white.png')"
|
|
|
+ title="三方会议"
|
|
|
+ @mouseleave="onHover('conferenceSrc', 'phoneControls/conference_blue.png')"
|
|
|
+ >
|
|
|
+ <img :src="state.holdSrc" alt="" />
|
|
|
+ <span>三方会议({{ onCallArr.length }})</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="hangup-container">
|
|
|
+ <div class="hangup-item" v-for="(item, index) in onCallArr" :key="index">
|
|
|
+ <p class="hangup-item-phoneNumber">{{ item.number }}</p>
|
|
|
+ <el-button size="small" @click="kickOut(item)" class="default-button">踢出</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </template>
|
|
|
<!-- 三方会议 不可用 -->
|
|
|
<template v-else>
|
|
|
<div class="item disabled" title="三方会议">
|
|
@@ -218,9 +246,13 @@
|
|
|
<!-- 签入弹窗 -->
|
|
|
<el-dialog v-model="state.dutyDialogVisible" draggable title="签入" width="500px" :show-close="false">
|
|
|
<el-form :model="state.dutyForm" label-width="80px" ref="dutyFormRef">
|
|
|
- <el-form-item label="分机" prop="telNo" :rules="[{ required: true, message: '请选择需要签入的分机', trigger: 'change' }]">
|
|
|
+ <el-form-item label="分机" prop="telNo" :rules="[{ required: true, message: '请选择需要签入的分机', trigger: 'change' }]" v-if="AppConfigInfo.isNeedTelNo">
|
|
|
<el-select-v2 v-model="state.dutyForm.telNo" :options="state.telsList" placeholder="选择要签入的分机" filterable class="w100" />
|
|
|
</el-form-item>
|
|
|
+ <!-- 是否需要输入分机密码 -->
|
|
|
+ <el-form-item label="分机密码" prop="password" :rules="[{ required: true, message: '请输入分机密码', trigger: 'blur' }]" v-if="AppConfigInfo.isTelNeedVerify">
|
|
|
+ <el-input v-model="state.dutyForm.password" placeholder="请输入分机密码"/>
|
|
|
+ </el-form-item>
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
<span class="dialog-footer">
|
|
@@ -236,13 +268,13 @@
|
|
|
ref="dialogRestRef"
|
|
|
draggable
|
|
|
title="小休申请"
|
|
|
- :width="AppConfigInfo.IsRestApproval ? '60%' : '500px'"
|
|
|
+ :width="AppConfigInfo.isRestApproval ? '60%' : '500px'"
|
|
|
@mouseup="mouseup"
|
|
|
:style="'transform: ' + state.transform + ';'"
|
|
|
@opend="restFormOpened"
|
|
|
>
|
|
|
<!-- 需要审核 -->
|
|
|
- <template v-if="AppConfigInfo.IsRestApproval">
|
|
|
+ <template v-if="AppConfigInfo.isRestApproval">
|
|
|
<el-form :model="state.restForm" label-width="100px" ref="restFormRef">
|
|
|
<el-row :gutter="10">
|
|
|
<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
|
|
@@ -390,7 +422,27 @@
|
|
|
</el-dialog>
|
|
|
|
|
|
<!-- 三方通话弹窗 -->
|
|
|
-
|
|
|
+ <el-dialog v-model="state.threeWayDialogVisible" draggable title="三方会议" width="450px">
|
|
|
+ <el-form :model="state.threeWayForm" label-width="120px" ref="threeWayFormRef">
|
|
|
+ <el-form-item label="三方通话号码" prop="telNo" :rules="[{ required: true, message: '请选择或输入三方通话号码', trigger: 'blur' }]">
|
|
|
+ <el-select-v2
|
|
|
+ v-model="state.threeWayForm.telNo"
|
|
|
+ :options="state.telsList"
|
|
|
+ placeholder="请选择或输入三方通话号码"
|
|
|
+ filterable
|
|
|
+ class="w100"
|
|
|
+ allow-create
|
|
|
+ default-first-option
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="state.threeWayDialogVisible = false" class="default-button" :loading="state.loading">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="clickOnThreeWay(threeWayFormRef)" :loading="state.loading">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts" name="telControl">
|
|
@@ -405,13 +457,11 @@ import { formatDuration } from '/@/utils/formatTime';
|
|
|
import { commonEnum } from '/@/utils/constants';
|
|
|
import other from '/@/utils/other';
|
|
|
import { workflowStepOptions } from '/@/api/system/workflow';
|
|
|
-import { restFlowStart, restFlowDel, restFlowStartWex, getTelList, telRestProcess, telRestAdd, telRestBaseData } from '/@/api/public/wex';
|
|
|
+import {restFlowStart, restFlowDel, restFlowStartWex, getTelList, telRestProcess, telRestAdd, telRestBaseData, dutyOff, dutyOn} from '/@/api/public/wex';
|
|
|
import { auth } from '/@/utils/authFunction';
|
|
|
-import { VoiceInterfaceObject } from '/@/utils/PhoneScript';
|
|
|
import signalR from '/@/utils/signalR';
|
|
|
import { Local } from '/@/utils/storage';
|
|
|
import { ola } from '/@/utils/ola_api';
|
|
|
-
|
|
|
// 引入组件
|
|
|
const CommonAdvice = defineAsyncComponent(() => import('/@/components/CommonAdvice/index.vue')); // 常用意见
|
|
|
const AnnexList = defineAsyncComponent(() => import('/@/components/AnnexList/index.vue'));
|
|
@@ -466,13 +516,11 @@ const state = reactive<any>({
|
|
|
handleId: '', // 流程处理ID
|
|
|
transform: 'translate(0px, 0px)',
|
|
|
fileList: [], // 文件上传列表
|
|
|
- metingDialogVisible: false, // 三方会议弹窗
|
|
|
- metingForm: {
|
|
|
+ threeWayDialogVisible: false, // 三方会议弹窗
|
|
|
+ threeWayForm: {
|
|
|
// 三方会议表单
|
|
|
- metingId: '', // 三方会议ID
|
|
|
- phoneNo: '', // 三方会议号码
|
|
|
+ telNo: null, // 三方会议号码
|
|
|
},
|
|
|
- groupName: '', //坐席组名称
|
|
|
});
|
|
|
|
|
|
const useTelStatusStore = useTelStatus();
|
|
@@ -509,10 +557,6 @@ const removeTimer = () => {
|
|
|
};
|
|
|
// 监听消息
|
|
|
const signalRStart = () => {
|
|
|
- signalR.SR.on('Send', (data: any) => {
|
|
|
- // 加入分组成功
|
|
|
- console.log(data, '加入分组成功');
|
|
|
- });
|
|
|
signalR.SR.on('RestApplyPass', (data: any) => {
|
|
|
// 小休审批通过消息
|
|
|
console.log(data, '小休审批通过消息');
|
|
@@ -529,7 +573,7 @@ const activeArr = computed(() => {
|
|
|
ring: ['hangup'], //振铃中
|
|
|
onCall: ['hangup', 'hold', 'transfer', 'evaluate','conference'], // 单个通话中
|
|
|
onHold: ['hangup', 'hold', 'transfer', 'evaluate'], // 保持中
|
|
|
- onTalkingDeal: ['dutyOff', 'rest', 'outbound', 'callForwarding', 'TalkingDeal'], // 事后处理中
|
|
|
+ onTalkingDeal: ['dutyOff', 'rest', 'outbound', 'callForwarding', 'TalkingDeal'], // 话后整理中
|
|
|
onTransferSuccess: ['hangup', 'conference'], // 转接成功
|
|
|
onConference: ['hangup'], // 三方会议中 只能挂断
|
|
|
};
|
|
@@ -548,7 +592,7 @@ const currentStatusText = computed(() => {
|
|
|
ring: '振铃中',
|
|
|
onHold: '保持中',
|
|
|
onCall: '通话中',
|
|
|
- onTalkingDeal: '事后处理',
|
|
|
+ onTalkingDeal: '整理中',
|
|
|
onConference: '会议中',
|
|
|
onTransferSuccess: '转接成功',
|
|
|
};
|
|
@@ -561,21 +605,23 @@ const RestApplyPassFn = (data: any) => {
|
|
|
message: '小休审批通过,开始小休',
|
|
|
type: 'success',
|
|
|
});
|
|
|
- VoiceInterfaceObject.SetBusy(data); //设置忙碌
|
|
|
+ //不需要审核直接开始小休
|
|
|
+ ola.go_break(state.restForm.reason); //设置忙碌
|
|
|
};
|
|
|
// 查询所有分机
|
|
|
-const getTelsLists = async (object?: object) => {
|
|
|
+const getTelsLists = async () => {
|
|
|
state.loading = true;
|
|
|
try {
|
|
|
- const res: any = await getTelList(object);
|
|
|
- state.telsList = res?.data ?? [];
|
|
|
+ const res: any = await getTelList();
|
|
|
+ state.telsList = res?.result ?? [];
|
|
|
state.telsList = state.telsList.map((item: any) => ({
|
|
|
- value: item.device,
|
|
|
- label: item.device,
|
|
|
+ value: item.telNo,
|
|
|
+ label: item.telNo,
|
|
|
+ queue: item.description === '默认' ? '10010' : item.description,
|
|
|
...item,
|
|
|
}));
|
|
|
state.loading = false;
|
|
|
- return Promise.resolve(state.telsList);
|
|
|
+ return state.telsList;
|
|
|
} catch (err) {
|
|
|
console.log(err);
|
|
|
state.loading = false;
|
|
@@ -616,12 +662,12 @@ const onControlClick = (val: string) => {
|
|
|
if (!auth('public:seat:unHold')) ElMessage.error('抱歉,您没有取消保持权限!');
|
|
|
else onUnHold();
|
|
|
break;
|
|
|
- case 'TalkingDeal': //事后处理
|
|
|
- if (!auth('public:seat:TalkingDeal')) ElMessage.error('抱歉,您没有事后处理权限!');
|
|
|
+ case 'TalkingDeal': //话后整理
|
|
|
+ if (!auth('public:seat:TalkingDeal')) ElMessage.error('抱歉,您没有话后整理权限!');
|
|
|
else onTalkingDeal();
|
|
|
break;
|
|
|
- case 'unTalkingDeal': // 取消事后处理
|
|
|
- if (!auth('public:seat:unTalkingDeal')) ElMessage.error('抱歉,您没有取消事后处理权限!');
|
|
|
+ case 'unTalkingDeal': // 取消话后整理
|
|
|
+ if (!auth('public:seat:unTalkingDeal')) ElMessage.error('抱歉,您没有取消话后整理权限!');
|
|
|
else unTalkingDeal();
|
|
|
break;
|
|
|
case 'transfer': //转接
|
|
@@ -641,77 +687,168 @@ const onControlClick = (val: string) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 当前分机对象
|
|
|
-const ola_object = {
|
|
|
- ola_extn: '1001', //分机hao
|
|
|
- ola_password: '!@#123Qw', //分机密码
|
|
|
- queues: '10010', //队列
|
|
|
+//签入
|
|
|
+const dutyFormRef = ref<RefType>();
|
|
|
+const onDutyFn = async () => {
|
|
|
+ if(AppConfigInfo.value.isNeedTelNo || AppConfigInfo.value.isTelNeedVerify){ // 需要选择分机号或者输入密码 打开弹窗选择分机号
|
|
|
+ dutyFormRef.value?.resetFields();
|
|
|
+ state.dutyDialogVisible = true;
|
|
|
+ }else{
|
|
|
+ ElMessageBox.confirm(`确定要签入,是否继续?`, '提示', {
|
|
|
+ confirmButtonText: '确认',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ draggable: true,
|
|
|
+ cancelButtonClass: 'default-button',
|
|
|
+ autofocus: false,
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ state.loading = true;
|
|
|
+ dutyOn({}).then((res:any)=>{
|
|
|
+ currentTel.value.password = res.result.telPwd;
|
|
|
+ currentTel.value.telNo = res.result.telNo;
|
|
|
+ currentTel.value.queue = res.result.description === '默认' ? '10010' : res.result.description;
|
|
|
+ // 不需要选择分机号和密码 直接签入
|
|
|
+ currentTel.value = state.telsList.find((item: any) => item.value === userInfos.value.defaultTelNo);
|
|
|
+ websocket_connect(); //开启消息监听
|
|
|
+ state.loading = false;
|
|
|
+
|
|
|
+ }).catch(()=>{
|
|
|
+ }).finally(()=>{
|
|
|
+ state.loading = false;
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ state.loading = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+// 确认签入
|
|
|
+const currentTel = ref<any>({});
|
|
|
+const clickOnDuty = (formEl: FormInstance | undefined) => {
|
|
|
+ if (!formEl) return;
|
|
|
+ formEl.validate((valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+ state.loading = true;
|
|
|
+ if(AppConfigInfo.value.isNeedTelNo && AppConfigInfo.value.isTelNeedVerify){ // 需要分机和密码
|
|
|
+ currentTel.value = state.telsList.find((item: any) => item.value === state.dutyForm.telNo);
|
|
|
+ currentTel.value.password = state.dutyForm.password;
|
|
|
+ const request = {
|
|
|
+ telId:currentTel.value.id,
|
|
|
+ telNo:state.dutyForm.telNo,
|
|
|
+ telPwd:state.dutyForm.password,
|
|
|
+ queue: currentTel.value.description,
|
|
|
+ }
|
|
|
+ dutyOn(request).then(()=>{
|
|
|
+ currentTel.value.password = state.dutyForm.password;
|
|
|
+ currentTel.value.telNo = state.dutyForm.telNo;
|
|
|
+ currentTel.value.queue = currentTel.value.description === '默认' ? '10010' : currentTel.value.description;
|
|
|
+ websocket_connect(); //开启消息监听
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyDialogVisible = false;
|
|
|
+ }).catch(()=>{
|
|
|
+ }).finally(()=>{
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyDialogVisible = false;
|
|
|
+ })
|
|
|
+ }else if(AppConfigInfo.value.isNeedTelNo){ //需要分机
|
|
|
+ currentTel.value = state.telsList.find((item: any) => item.value === state.dutyForm.telNo);
|
|
|
+ currentTel.value.description = currentTel.value.description === '默认' ? '10010' : currentTel.value.description;
|
|
|
+ const request = {
|
|
|
+ telId:currentTel.value.id,
|
|
|
+ telNo:currentTel.value.telNo,
|
|
|
+ telPwd: currentTel.value.password,
|
|
|
+ queue: currentTel.value.description,
|
|
|
+ }
|
|
|
+ dutyOn(request).then(()=>{
|
|
|
+ websocket_connect(); //开启消息监听
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyDialogVisible = false;
|
|
|
+ }).catch(()=>{
|
|
|
+ }).finally(()=>{
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyDialogVisible = false;
|
|
|
+ })
|
|
|
+ }else if(AppConfigInfo.value.isTelNeedVerify){// 需要密码
|
|
|
+ dutyOn({telPwd:state.dutyForm.password}).then((res:any)=>{
|
|
|
+ currentTel.value.password = state.dutyForm.password;
|
|
|
+ currentTel.value.telNo = res.result.telNo;
|
|
|
+ currentTel.value.queue = res.result.description === '默认' ? '10010' : res.result.description;
|
|
|
+ websocket_connect(); //开启消息监听
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyDialogVisible = false;
|
|
|
+ }).catch(()=>{
|
|
|
+ }).finally(()=>{
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyDialogVisible = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+ });
|
|
|
};
|
|
|
+
|
|
|
// 链接呼叫中心
|
|
|
const websocket_connect = () => {
|
|
|
- ola.onConnect = onConnect;
|
|
|
- ola.onClose = onClose;
|
|
|
- ola.onMessage = onMessage;
|
|
|
- ola.connect(import.meta.env.VITE_CALLCENTER_SOCKET_URL, ola_object.ola_extn, ola_object.ola_password);
|
|
|
+ if(ola.ws) { // 如果已经连接 则先关闭
|
|
|
+ ola.close();
|
|
|
+ }
|
|
|
+ ola.onConnect = onConnect;
|
|
|
+ ola.onClose = onClose;
|
|
|
+ ola.onMessage = onMessage;
|
|
|
+ ola.connect(import.meta.env.VITE_CALLCENTER_SOCKET_URL, currentTel.value.telNo, currentTel.value.password);
|
|
|
};
|
|
|
// 呼叫中心链接
|
|
|
const onConnect = () => {
|
|
|
- ola.subscribe('ola.agent.' + ola_object.ola_extn);
|
|
|
- ola.subscribe('ola.caller.' + ola_object.ola_extn);
|
|
|
- ola.get_agent_state(ola_object.ola_extn);
|
|
|
+ ola.subscribe('ola.agent.' + currentTel.value.telNo);
|
|
|
+ ola.subscribe('ola.caller.' + currentTel.value.telNo);
|
|
|
+ ola.get_agent_state(currentTel.value.telNo);
|
|
|
|
|
|
- callCenterLogin();
|
|
|
-};
|
|
|
-// 呼叫中心登录
|
|
|
-const callCenterLogin = () => {
|
|
|
- ola.logout(ola_object.ola_extn); //连接之后,先登出一次,防止其他地方已经登陆
|
|
|
- let array_ola_queue: EmptyArrayType = []; // 队列
|
|
|
- if (ola_object.queues) {
|
|
|
- let array = ola_object.queues.split(',');
|
|
|
- for (let i = 0; i < array.length; i++) {
|
|
|
- array_ola_queue[i] = array[i];
|
|
|
- }
|
|
|
- ola.login(array_ola_queue, ola_object.ola_extn, { type: 'onhook' });
|
|
|
- }
|
|
|
+ ola.logout(currentTel.value.telNo); //连接之后,先登出一次,防止其他地方已经登陆
|
|
|
+ let array_ola_queue: EmptyArrayType = []; // 队列
|
|
|
+ if (currentTel.value.queue) {
|
|
|
+ let array = currentTel.value.queue.split(',');
|
|
|
+ for (let i = 0; i < array.length; i++) {
|
|
|
+ array_ola_queue[i] = array[i];
|
|
|
+ }
|
|
|
+ ola.login(array_ola_queue, currentTel.value.telNo, { type: 'onhook' });
|
|
|
+ }
|
|
|
};
|
|
|
// 呼叫中心消息
|
|
|
const onMessage = (event: any) => {
|
|
|
- const data = JSON.parse(event.data);
|
|
|
- console.log('onMessage', data);
|
|
|
- if (data.event_type == 'agent_state') {
|
|
|
- // 坐席状态
|
|
|
- if (data.state == 'login') {
|
|
|
- // 签入
|
|
|
- // 设置分机号和坐席组
|
|
|
- useTelStatusStore.setCallInfo({ telsNo: ola_object.ola_extn });
|
|
|
- // 设置签入状态
|
|
|
- useTelStatusStore.setDutyState(true);
|
|
|
- // 设置电话状态
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
- setTimeout(() => {
|
|
|
- // 设置示闲状态
|
|
|
- ola.go_ready();
|
|
|
- }, 1000);
|
|
|
- console.log('已签入');
|
|
|
- } else if (data.state == 'logout') {
|
|
|
- // 签出
|
|
|
- state.loading = true;
|
|
|
- // 重置所有状态
|
|
|
- useTelStatusStore.resetState();
|
|
|
- state.loading = false;
|
|
|
- console.log('已签出');
|
|
|
- } else if (data.state == 'ready') {
|
|
|
- // 示闲中
|
|
|
- // 设置休息状态 设置未正常状态
|
|
|
- useTelStatusStore.setRest(RestStates.unRest);
|
|
|
- // 设置话机状态 结束休息改为签入状态
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
- console.log('示闲中');
|
|
|
- } else if (data.state == 'unready') {
|
|
|
- // 示忙中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.rest);
|
|
|
- useTelStatusStore.setRest(RestStates.resting);
|
|
|
- /*if (AppConfigInfo.value.IsRestApproval) {
|
|
|
+ const data = JSON.parse(event.data);
|
|
|
+ console.log('onMessage', data);
|
|
|
+ if (data.event_type == 'agent_state') {
|
|
|
+ // 坐席状态
|
|
|
+ if (data.state == 'login') {
|
|
|
+ // 签入
|
|
|
+ // 设置分机号和坐席组
|
|
|
+ useTelStatusStore.setCallInfo({ telsNo: currentTel.value.telNo });
|
|
|
+ state.loading = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ // 设置示闲状态
|
|
|
+ ola.go_ready();
|
|
|
+ }, 1000);
|
|
|
+ console.log('已签入');
|
|
|
+ } else if (data.state == 'logout') {
|
|
|
+ // 签出
|
|
|
+ // 重置所有状态
|
|
|
+ useTelStatusStore.resetState();
|
|
|
+ console.log('已签出');
|
|
|
+ } else if (data.state == 'ready') {
|
|
|
+ // 设置签入状态
|
|
|
+ useTelStatusStore.setDutyState(true);
|
|
|
+ // 示闲中
|
|
|
+ // 设置休息状态 设置未正常状态
|
|
|
+ useTelStatusStore.setRest(RestStates.unRest);
|
|
|
+ // 设置话机状态 结束休息改为签入状态
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
+ state.loading = false;
|
|
|
+ ElMessage.success('签入成功!');
|
|
|
+ console.log('示闲中');
|
|
|
+ } else if (data.state == 'unready') {
|
|
|
+ // 示忙中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.rest);
|
|
|
+ useTelStatusStore.setRest(RestStates.resting);
|
|
|
+ /*if (AppConfigInfo.value.isRestApproval) {
|
|
|
// 如果小休需要审核
|
|
|
telRestProcess()
|
|
|
.then((res: any) => {
|
|
@@ -744,124 +881,123 @@ const onMessage = (event: any) => {
|
|
|
|
|
|
});
|
|
|
}*/
|
|
|
- break_reason(data.private_data);
|
|
|
- console.log('示忙中');
|
|
|
- } else if (data.state == 'acw') {
|
|
|
- // 话后整理中
|
|
|
- const time: number = AppConfigInfo.value.TalkingDealTime * 1000; // 事后处理时间
|
|
|
- ElNotification({
|
|
|
- title: '自动开启事后处理成功',
|
|
|
- message: `${AppConfigInfo.value.TalkingDealTime}秒后自动结束事后处理,或者手动结束事后处理`,
|
|
|
- type: 'success',
|
|
|
- duration: time,
|
|
|
- });
|
|
|
- // 设置事后处理
|
|
|
- useTelStatusStore.setTalkingDeal(true);
|
|
|
- // 设置话机状态 设置为事后处理中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.onTalkingDeal);
|
|
|
- setTimeout(() => {
|
|
|
- // 设置事后处理
|
|
|
- useTelStatusStore.setTalkingDeal(false);
|
|
|
- // 设置话机状态 取消事后处理修改为空闲状态
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
- ola.go_ready(); // 示闲
|
|
|
- }, time);
|
|
|
- console.log('话后整理中');
|
|
|
- } else if (data.state == 'busy') {
|
|
|
+ break_reason(data.private_data);
|
|
|
+ console.log('示忙中');
|
|
|
+ } else if (data.state == 'acw') {
|
|
|
+ // 话后整理中
|
|
|
+ const time: number = AppConfigInfo.value.talkingDealTime * 1000; // 话后整理时间
|
|
|
+ ElNotification({
|
|
|
+ title: '自动开启话后整理成功',
|
|
|
+ message: `${time/1000}秒后自动结束话后整理,或者手动结束话后整理`,
|
|
|
+ type: 'success',
|
|
|
+ duration: time,
|
|
|
+ });
|
|
|
+ // 设置话后整理
|
|
|
+ useTelStatusStore.setTalkingDeal(true);
|
|
|
+ // 设置话机状态 设置为话后整理中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.onTalkingDeal);
|
|
|
+ setTimeout(() => {
|
|
|
+ // 设置话后整理
|
|
|
+ useTelStatusStore.setTalkingDeal(false);
|
|
|
+ // 设置话机状态 取消话后整理修改为空闲状态
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
+ ola.go_ready(); // 示闲
|
|
|
+ }, time);
|
|
|
+ console.log('话后整理中');
|
|
|
+ } else if (data.state == 'busy') {
|
|
|
|
|
|
- } else {
|
|
|
- console.log(data.state, '其他状态');
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ console.log(data.state, '其他状态');
|
|
|
+ }
|
|
|
|
|
|
- if (data.state == 'busy') {
|
|
|
+ if (data.state == 'busy') {
|
|
|
holdStatus(data.private_data); //处理保持
|
|
|
- if (data.call_direction == 'outbound') {
|
|
|
- // 呼出
|
|
|
- if (data.private_data == 'calling') {
|
|
|
- // 拨号中
|
|
|
- // 设置电话状态 振铃中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.ring);
|
|
|
- console.log('呼出拨号中');
|
|
|
- } else if (data.private_data == 'answered') {
|
|
|
- //振铃中
|
|
|
- if (data.other_answered == false) {
|
|
|
- // 设置电话状态 振铃中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.ring);
|
|
|
- console.log('呼出振铃中');
|
|
|
- } else if (data.other_answered == true) {
|
|
|
- // 通话中
|
|
|
+ if (data.call_direction == 'outbound') {
|
|
|
+ // 呼出
|
|
|
+ if (data.private_data == 'calling') {
|
|
|
+ // 拨号中
|
|
|
+ // 设置电话状态 振铃中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.ring);
|
|
|
+ console.log('呼出拨号中');
|
|
|
+ } else if (data.private_data == 'answered') {
|
|
|
+ //振铃中
|
|
|
+ if (data.other_answered == false) {
|
|
|
+ // 设置电话状态 振铃中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.ring);
|
|
|
+ console.log('呼出振铃中');
|
|
|
+ } else if (data.other_answered == true) {
|
|
|
+ // 通话中
|
|
|
// 开始计时
|
|
|
startTime();
|
|
|
- // 设置电话状态 通话中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.onCall);
|
|
|
- console.log('呼出通话中');
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 呼入
|
|
|
- if (data.private_data == 'ring') {
|
|
|
- // 设置电话状态 振铃中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.ring);
|
|
|
- console.log('呼入振铃中');
|
|
|
- } else if (data.private_data == 'answered') {
|
|
|
+ // 设置电话状态 通话中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.onCall);
|
|
|
+ console.log('呼出通话中');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 呼入
|
|
|
+ if (data.private_data == 'ring') {
|
|
|
+ // 设置电话状态 振铃中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.ring);
|
|
|
+ console.log('呼入振铃中');
|
|
|
+ } else if (data.private_data == 'answered') {
|
|
|
// 开始计时
|
|
|
startTime();
|
|
|
- // 设置电话状态 通话中
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.onCall);
|
|
|
- console.log('呼入通话中');
|
|
|
- }
|
|
|
- }
|
|
|
- } else if (data.old_state == 'busy') {
|
|
|
- //挂机后系统可以返回两种状态:acw 话后整理状态 ready 示闲状态,如果不需要acw,可以联系我们后台修改配置,如果需要保留,如果需要再次
|
|
|
- //拨打电话的话,需要手动点击示闲按钮
|
|
|
+ // 设置电话状态 通话中
|
|
|
+ useTelStatusStore.setPhoneControlState(TelStates.onCall);
|
|
|
+ console.log('呼入通话中');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (data.old_state == 'busy') {
|
|
|
+ //挂机后系统可以返回两种状态:acw 话后整理状态 ready 示闲状态,如果不需要acw,可以联系我们后台修改配置,如果需要保留,如果需要再次
|
|
|
+ //拨打电话的话,需要手动点击示闲按钮
|
|
|
|
|
|
- // 设置电话状态
|
|
|
- useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
- // 结束计时
|
|
|
- removeTimer();
|
|
|
- console.log('已挂机');
|
|
|
- }
|
|
|
- } else if (data.event_type == 'agent_caller_state') {
|
|
|
- //通话状态
|
|
|
- // special feature, never mind
|
|
|
- if (data.action == 'in') {
|
|
|
- console.log('呼入', data.caller.cid_number, data.caller.uuid);
|
|
|
- // ola.take_call(data.caller.uuid);
|
|
|
- } else {
|
|
|
- console.log('呼出', data.caller.uuid);
|
|
|
- }
|
|
|
- } else if (data.event_type == 'command/reply') {
|
|
|
- // 其他消息
|
|
|
- // console.log('command/reply', data);
|
|
|
- }
|
|
|
+ // 结束计时
|
|
|
+ removeTimer();
|
|
|
+ console.log('已挂机');
|
|
|
+ }
|
|
|
+ } else if (data.event_type == 'agent_caller_state') {
|
|
|
+ //通话状态
|
|
|
+ // special feature, never mind
|
|
|
+ if (data.action == 'in') {
|
|
|
+ console.log('呼入', data.caller.cid_number, data.caller.uuid);
|
|
|
+ // ola.take_call(data.caller.uuid);
|
|
|
+ } else {
|
|
|
+ console.log('呼出', data.caller.uuid);
|
|
|
+ }
|
|
|
+ } else if (data.event_type == 'command/reply') {
|
|
|
+ // 其他消息
|
|
|
+ // console.log('command/reply', data);
|
|
|
+ }
|
|
|
};
|
|
|
// 呼叫中心链接关闭
|
|
|
const onClose = () => {
|
|
|
- ElMessage.error('呼叫中心断开链接');
|
|
|
+ console.log('呼叫中心断开链接')
|
|
|
+ // ElMessage.error('呼叫中心断开链接');
|
|
|
};
|
|
|
// 小休原因
|
|
|
const restReason = ref(''); // 小休原因
|
|
|
const break_reason = (reason: string) => {
|
|
|
- switch (reason) {
|
|
|
- case 'away':
|
|
|
- restReason.value = '外出中';
|
|
|
- break;
|
|
|
- case 'rest':
|
|
|
- restReason.value = '休息中';
|
|
|
- break;
|
|
|
- case 'conference':
|
|
|
- restReason.value = '会议中';
|
|
|
- break;
|
|
|
- case 'train':
|
|
|
- restReason.value = '培训中';
|
|
|
- break;
|
|
|
- case 'eat':
|
|
|
- restReason.value = '用餐中';
|
|
|
- break;
|
|
|
- default:
|
|
|
- restReason.value = '休息中';
|
|
|
- break;
|
|
|
- }
|
|
|
+ switch (reason) {
|
|
|
+ case 'away':
|
|
|
+ restReason.value = '外出中';
|
|
|
+ break;
|
|
|
+ case 'rest':
|
|
|
+ restReason.value = '休息中';
|
|
|
+ break;
|
|
|
+ case 'conference':
|
|
|
+ restReason.value = '会议中';
|
|
|
+ break;
|
|
|
+ case 'train':
|
|
|
+ restReason.value = '培训中';
|
|
|
+ break;
|
|
|
+ case 'eat':
|
|
|
+ restReason.value = '用餐中';
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ restReason.value = '休息中';
|
|
|
+ break;
|
|
|
+ }
|
|
|
};
|
|
|
// 保持状态处理
|
|
|
const holdStatus = (holdStatus:string)=>{
|
|
@@ -883,30 +1019,6 @@ const holdStatus = (holdStatus:string)=>{
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
-//签入
|
|
|
-const dutyFormRef = ref<RefType>();
|
|
|
-const onDutyFn = async () => {
|
|
|
- websocket_connect();
|
|
|
- /*dutyFormRef.value?.resetFields();
|
|
|
- // 获取所有分机列表(未签入的)
|
|
|
- const list = await getTelsLists({ sigin: 0 });
|
|
|
- const isDefaultTelNo = list.some((item: any) => item.value === userInfos.value.defaultTelNo);
|
|
|
- if (isDefaultTelNo) {
|
|
|
- // 如果默认分机号是空闲的,就默认选中
|
|
|
- state.dutyForm.telNo = userInfos.value.defaultTelNo;
|
|
|
- }
|
|
|
- state.dutyDialogVisible = true;*/
|
|
|
-};
|
|
|
-// 确认签入
|
|
|
-const clickOnDuty = (formEl: FormInstance | undefined) => {
|
|
|
- if (!formEl) return;
|
|
|
- formEl.validate((valid: boolean) => {
|
|
|
- if (!valid) return;
|
|
|
- state.loading = true;
|
|
|
- // {telNo:state.dutyForm.telNo}
|
|
|
- websocket_connect(); //开启消息监听
|
|
|
- });
|
|
|
-};
|
|
|
// 签出
|
|
|
const offDutyFn = () => {
|
|
|
ElMessageBox.confirm(`确定要签出,是否继续?`, '提示', {
|
|
@@ -919,11 +1031,18 @@ const offDutyFn = () => {
|
|
|
})
|
|
|
.then(() => {
|
|
|
state.loading = true;
|
|
|
- ola.logout(ola_object.ola_extn); //签出
|
|
|
- // 重置所有状态
|
|
|
- useTelStatusStore.resetState();
|
|
|
- state.loading = false;
|
|
|
- state.dutyOnSrc = getImageUrl('phoneControls/dutyOn_blue.png'); //签入图片
|
|
|
+ dutyOff().then(()=>{
|
|
|
+ ola.logout(currentTel.value.telNo); //签出
|
|
|
+ ola.close();
|
|
|
+ // 重置所有状态
|
|
|
+ useTelStatusStore.resetState();
|
|
|
+ state.loading = false;
|
|
|
+ state.dutyOnSrc = getImageUrl('phoneControls/dutyOn_blue.png'); //签入图片
|
|
|
+ state.loading = false;
|
|
|
+ }).catch(()=>{
|
|
|
+ }).finally(()=>{
|
|
|
+ state.loading = false;
|
|
|
+ })
|
|
|
})
|
|
|
.catch(() => {
|
|
|
state.loading = false;
|
|
@@ -949,7 +1068,7 @@ const onHangup = () => {
|
|
|
// 小休
|
|
|
const restFormRef = ref<RefType>(); //小休表单
|
|
|
const onRest = async () => {
|
|
|
- if (AppConfigInfo.value.IsRestApproval) {
|
|
|
+ if (AppConfigInfo.value.isRestApproval) {
|
|
|
// 如果小休需要审核
|
|
|
// 查询流程节点参数
|
|
|
const res: any = await restFlowStart();
|
|
@@ -996,7 +1115,7 @@ const clickOnRest = (formEl: FormInstance | undefined) => {
|
|
|
formEl.validate((valid: boolean) => {
|
|
|
if (!valid) return;
|
|
|
state.loading = true;
|
|
|
- if (AppConfigInfo.value.IsRestApproval) {
|
|
|
+ if (AppConfigInfo.value.isRestApproval) {
|
|
|
//如果需要审核
|
|
|
state.restForm.additions = state.fileList;
|
|
|
let submitObj = other.deepClone(state.restForm);
|
|
@@ -1097,11 +1216,11 @@ const onUnHold = () => {
|
|
|
})
|
|
|
.catch(() => {});
|
|
|
};
|
|
|
-// 事后处理(系统默认进入)
|
|
|
+// 话后整理(系统默认进入)
|
|
|
const onTalkingDeal = () => {};
|
|
|
-// 取消事后处理
|
|
|
+// 取消话后整理
|
|
|
const unTalkingDeal = () => {
|
|
|
- ElMessageBox.confirm(`确定要取消事后处理,是否继续?`, '提示', {
|
|
|
+ ElMessageBox.confirm(`确定要取消话后整理,是否继续?`, '提示', {
|
|
|
confirmButtonText: '确认',
|
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning',
|
|
@@ -1111,9 +1230,9 @@ const unTalkingDeal = () => {
|
|
|
})
|
|
|
.then(() => {
|
|
|
state.loading = true;
|
|
|
- // 设置事后处理
|
|
|
+ // 设置话后整理
|
|
|
useTelStatusStore.setTalkingDeal(false);
|
|
|
- // 设置话机状态 取消事后处理修改为空闲状态
|
|
|
+ // 设置话机状态 取消话后整理修改为空闲状态
|
|
|
useTelStatusStore.setPhoneControlState(TelStates.dutyOn);
|
|
|
ola.go_ready(); // 示闲
|
|
|
state.loading = false;
|
|
@@ -1126,9 +1245,7 @@ const onTransfer = () => {
|
|
|
// 重置表单
|
|
|
transferFormRef.value?.resetFields();
|
|
|
// 获取所有分机列表
|
|
|
- getTelsLists().then(() => {
|
|
|
- state.transferDialogVisible = true;
|
|
|
- });
|
|
|
+ state.transferDialogVisible = true;
|
|
|
};
|
|
|
// 确认转接
|
|
|
const clickOnTransfer = (formEl: FormInstance | undefined) => {
|
|
@@ -1141,28 +1258,51 @@ const clickOnTransfer = (formEl: FormInstance | undefined) => {
|
|
|
};
|
|
|
// 三方会议开始
|
|
|
const onConference = () => {
|
|
|
- ElMessageBox.confirm(`确定确定要开启三方会议,是否继续?`, '提示', {
|
|
|
- confirmButtonText: '确认',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning',
|
|
|
- draggable: true,
|
|
|
- cancelButtonClass: 'default-button',
|
|
|
- autofocus: false,
|
|
|
- })
|
|
|
- .then(() => {
|
|
|
- VoiceInterfaceObject.Dtmf('0'); // 开启dtmf 三方通话
|
|
|
- })
|
|
|
- .catch(() => {});
|
|
|
+ // 重置表单
|
|
|
+ transferFormRef.value?.resetFields();
|
|
|
+ // 获取所有分机列表
|
|
|
+ state.threeWayDialogVisible = true;
|
|
|
+};
|
|
|
+// 三方会议确定
|
|
|
+const onCallArr = ref<EmptyArrayType>([
|
|
|
+ {
|
|
|
+ number:"2121"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ number:"1001"
|
|
|
+ },
|
|
|
+]); // 三方会议选中的分机
|
|
|
+const threeWayVisible = ref(false); // 三方会议弹窗
|
|
|
+const threeWayFormRef = ref<RefType>(); // 三方会议表单
|
|
|
+const clickOnThreeWay = (formEl: FormInstance | undefined) => {
|
|
|
+ if (!formEl) return;
|
|
|
+ formEl.validate((valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+ // ola.conference(state.conferenceForm.telNo); //三方会议
|
|
|
+ state.threeWayDialogVisible = false;
|
|
|
+ });
|
|
|
};
|
|
|
+const kickOut = (item:any)=>{
|
|
|
+ ElMessageBox.confirm(`确定确定要踢出${item.number},并恢复通话,是否继续?`, '提示', {
|
|
|
+ confirmButtonText: '确认',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ draggable: true,
|
|
|
+ cancelButtonClass: 'default-button',
|
|
|
+ autofocus: false,
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ // state.threeWayDialogVisible = true;
|
|
|
+ })
|
|
|
+ .catch(() => {});
|
|
|
+}
|
|
|
// 外呼
|
|
|
const outboundFormRef = ref<RefType>(); //外呼
|
|
|
const onOutbound = () => {
|
|
|
// 重置表单
|
|
|
outboundFormRef.value?.resetFields();
|
|
|
// 获取所有分机列表
|
|
|
- getTelsLists().then(() => {
|
|
|
- state.outboundDialogVisible = true;
|
|
|
- });
|
|
|
+ state.outboundDialogVisible = true;
|
|
|
};
|
|
|
// 外呼保存
|
|
|
const clickOnOutbound = (formEl: FormInstance | undefined) => {
|
|
@@ -1177,11 +1317,20 @@ const clickOnOutbound = (formEl: FormInstance | undefined) => {
|
|
|
}, 300);
|
|
|
});
|
|
|
};
|
|
|
-onMounted(() => {
|
|
|
+onMounted(async () => {
|
|
|
signalRStart(); //开启消息监听
|
|
|
+ const telList = await getTelsLists(); // 查询所有分机
|
|
|
if (telStatusInfo.value.telsNo) {
|
|
|
- // 有分机号
|
|
|
- websocket_connect(); // 链接呼叫中心
|
|
|
+ dutyOn({}).then(()=>{
|
|
|
+ // 有分机号
|
|
|
+ currentTel.value = telList.find((item: any) => item.value === telStatusInfo.value.telsNo);
|
|
|
+ websocket_connect(); //开启消息监听
|
|
|
+ state.loading = false;
|
|
|
+ }).catch(()=>{
|
|
|
+ }).finally(()=>{
|
|
|
+ state.loading = false;
|
|
|
+ })
|
|
|
+
|
|
|
}
|
|
|
});
|
|
|
</script>
|
|
@@ -1262,3 +1411,23 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
+<style lang="scss">
|
|
|
+.el-popover.hangup-popover {
|
|
|
+ .hangup-container {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: nowrap;
|
|
|
+ .hangup-item {
|
|
|
+ text-align: center;
|
|
|
+ width: 120px;
|
|
|
+ border-right: 1px solid var(--el-border-color-darker);
|
|
|
+ &:last-child {
|
|
|
+ border-right: 0;
|
|
|
+ }
|
|
|
+ &-phoneNumber {
|
|
|
+ padding-top: 4px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|