Parcourir la source

reactor:ws消息日志和demo;

zhangchong il y a 10 mois
Parent
commit
1d647536b9

+ 50 - 21
src/layout/navBars/breadcrumb/telControl.vue

@@ -316,6 +316,7 @@
 					placeholder="选择要签入的分机"
 					filterable
 					class="w100"
+					:height="650"
 				/>
 			</el-form-item>
 			<!-- 是否需要填写分机密码 -->
@@ -465,6 +466,7 @@
 						label: 'dicDataName',
 						value: 'dicDataValue',
 					}"
+					:height="800"
 				/>
 			</el-form-item>
 		</el-form>
@@ -492,6 +494,7 @@
 						label: 'telNo',
 						value: 'telNo',
 					}"
+					:height="800"
 				/>
 			</el-form-item>
 		</el-form>
@@ -519,6 +522,7 @@
 						label: 'dicDataName',
 						value: 'dicDataValue',
 					}"
+					:height="800"
 				/>
 			</el-form-item>
 		</el-form>
@@ -842,7 +846,7 @@ const onConnect = () => {
 	pingTimer.value = setInterval(() => {
 		ola.ping();
 	}, 5000);
-
+  Local.set('currentTel', currentTel.value.telNo);
 	ola.logout(currentTel.value.telNo); //连接之后,先登出一次,防止其他地方已经登陆
 	let array_ola_queue: EmptyArrayType = []; // 队列
 	if (currentTel.value.telModel === 2) {
@@ -858,13 +862,21 @@ const onConnect = () => {
 			array_ola_queue[i] = array[i];
 		}
 	}
-	Local.set('telNo', currentTel.value.telNo);
-	console.log(currentTel.value.telNo, '当前话机');
 	ola.login(array_ola_queue, currentTel.value.telNo, { type: 'onhook' });
 	if (currentTel.value.telModel != 2) {
 		// 普通模式才链接语音助手
 		connectVoiceAssistant(currentTel.value.telNo); // 坐席助手开启
 	}
+
+	const name: string = `天润分机号:${currentTel.value.telNo}的websocket链接成功`;
+	const remark: string = `天润websocket 链接成功:分机模式:${currentTel.value.telModel}`;
+	const request = {
+		creationTime: new Date(),
+		name,
+		remark,
+		executeUrl: import.meta.env.VITE_CALLCENTER_SOCKET_URL,
+	};
+	submitLogFn(request);
 };
 // 业务系统发送消息
 const sendMsg = (msg: any) => {
@@ -1197,7 +1209,7 @@ const onMessage = async (event: any) => {
 								telGuid: data.other_accept,
 								transfer: data.gateway, // 转接来源(如12345,12333)
 								telArea: '',
-                identityType:data.app_data.dtmf_his // 按键接收(1:市民 2:企业 3:智能应答)
+								identityType: data.app_data.dtmf_his, // 按键接收(1:市民 2:企业 3:智能应答)
 							},
 							params: {
 								callId: data.other_accept, // 通话唯一ID
@@ -1241,17 +1253,7 @@ const onMessage = async (event: any) => {
 	}
 };
 // 记录日志
-const submitLogFn = async (event: any) => {
-	const telsNo = Local.get('telNo');
-	const name: string = `分机号:${telsNo}的websocket断开链接`;
-	const remark: string = `websocket 断开: 错误code:${event.code}, 错误原因:${event.reason}, 是否正常断开:${event.wasClean}`;
-	console.log(name, remark, event);
-	const request = {
-		creationTime: new Date(),
-		name,
-		remark,
-		executeUrl: import.meta.env.VITE_CALLCENTER_SOCKET_URL,
-	};
+const submitLogFn = async (request: any) => {
 	try {
 		await submitLog(request);
 		Local.remove('telNo');
@@ -1268,7 +1270,16 @@ const onClose = async (event: any) => {
 		// 签入状态需要重连
 		await reConnect(); // 重新链接呼叫中心
 	}
-	await submitLogFn(event);
+	const currentTel = Local.get('currentTel');
+	const name: string = `天润分机号:${currentTel}的websocket断开链接`;
+	const remark: string = `天润websocket 断开: 错误code:${event.code}, 错误原因:${event.reason}, 是否正常断开:${event.wasClean}`;
+	const request = {
+		creationTime: new Date(),
+		name,
+		remark,
+		executeUrl: import.meta.env.VITE_CALLCENTER_SOCKET_URL,
+	};
+	await submitLogFn(request);
 };
 // 重新链接呼叫中心
 const reconnectTimeout = ref(); // 重连定时器
@@ -1894,6 +1905,15 @@ const connectVoiceAssistant = async (telNo: string) => {
 			socket.value.send({ id: '', type: 1, from: uid, to: 'sys', timestamps: new Date().getTime(), body: result.userName });
 			console.log('坐席辅助连接成功');
 			ElMessage.success('坐席辅助连接成功');
+			const name: string = `捷通华声的websocket链接成功`;
+			const remark: string = `捷通华声的websocket链接成功`;
+			const request = {
+				creationTime: new Date(),
+				name,
+				remark,
+				executeUrl: import.meta.env.VITE_VOICE_ASSISTANT_SOCKET_URL,
+			};
+			submitLogFn(request);
 		});
 		socket.value.on('message', wsReceive);
 	} catch (err) {
@@ -1908,6 +1928,15 @@ const seatAssistOff = () => {
 		socket.value.close();
 		socket.value = null;
 	}
+	const name: string = `捷通华声的websocket链接断开`;
+	const remark: string = `捷通华声的websocket链接断开`;
+	const request = {
+		creationTime: new Date(),
+		name,
+		remark,
+		executeUrl: import.meta.env.VITE_VOICE_ASSISTANT_SOCKET_URL,
+	};
+	submitLogFn(request);
 };
 // 推送消息
 const wsReceive = (message: any) => {
@@ -2043,10 +2072,10 @@ onMounted(async () => {
 	await getTodayWaitNumFn(); // 查询今日等待数量
 	// 加入分组
 	await signalR.joinGroup('CallCenter');
-  signalR.SR.on('ToDayWaitNum', (data: number) => {
+	signalR.SR.on('ToDayWaitNum', (data: number) => {
 		todayWait.value = data;
 	});
-  signalR.SR.on('CurrentWaitNum', (data: number) => {
+	signalR.SR.on('CurrentWaitNum', (data: number) => {
 		currentWait.value = data;
 	});
 });
@@ -2058,9 +2087,9 @@ watch(
 	{ immediate: true }
 );
 onBeforeUnmount(() => {
-  signalR.SR.off('RestApplyPass');
-  signalR.SR.off('ToDayWaitNum');
-  signalR.SR.off('CurrentWaitNum');
+	signalR.SR.off('RestApplyPass');
+	signalR.SR.off('ToDayWaitNum');
+	signalR.SR.off('CurrentWaitNum');
 	if (ola.ws) ola.close();
 });
 </script>

+ 4 - 0
src/theme/element.scss

@@ -391,3 +391,7 @@
 .el-select-dropdown__option-item.hover {
 	background-color: var(--el-fill-color-darker) !important;
 }
+//  下拉框滚动条高度
+.el-select-dropdown__wrap{
+	max-height: 600px !important;
+}

+ 29 - 3
src/utils/signalR.ts

@@ -1,12 +1,20 @@
 // 官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.2&tabs=visual-studio
 import * as signalR from '@microsoft/signalr';
 import { Cookie, Local } from '@/utils/storage';
-import mittBus from '@/utils/mitt';
+import { submitLog } from "@/api/public/log";
+// 记录日志
+const submitLogFn = async (request: any) => {
+	try {
+		await submitLog(request);
+	} catch (error) {
+		console.log(error);
+	}
+};
 export default {
 	// signalR对象
 	SR: null as any,
 	// 失败连接重试次数
-	failNum: 5,
+	failNum: 99,
 	baseUrl: import.meta.env.VITE_API_SOCKET_URL,
 	init() {
 		const token = Cookie.get('token');
@@ -19,6 +27,15 @@ export default {
 		this.SR = connection;
 		// 断线重连
 		connection.onclose(async () => {
+			const name: string = `业务系统的websocket断开链接`;
+			const remark: string = `业务系统的websocket断开链接`;
+			const request = {
+				creationTime: new Date(),
+				name,
+				remark,
+				executeUrl: import.meta.env.VITE_API_SOCKET_URL,
+			};
+			await submitLogFn(request);
 			console.log('业务系统signal当前链接状态:', connection.state);
 			// 建议用户重新刷新浏览器
 			await this.start();
@@ -42,7 +59,7 @@ export default {
 		});
 		// 服务端推送消息
 		connection.on('SeatState', (message: any) => {
-			console.log(`座席状态:${message}`);
+			console.log(`座席状态:${JSON.stringify(message)}`);
 		});
 		// 服务端推送消息
 		connection.on('RestApplyPass', (message: any) => {
@@ -75,6 +92,15 @@ export default {
 			//使用async和await 或 promise的then 和catch 处理来自服务端的异常
 			await this.SR.start();
 			console.log('业务系统signal当前链接状态:', this.SR.state);
+			const name: string = `业务系统的websocket链接成功`;
+			const remark: string = `业务系统的websocket断开链接`;
+			const request = {
+				creationTime: new Date(),
+				name,
+				remark,
+				executeUrl: import.meta.env.VITE_API_SOCKET_URL,
+			};
+			await submitLogFn(request);
 			return Promise.resolve();
 		} catch (error: any) {
 			this.failNum--;

+ 177 - 5
src/views/tels/smartRecord/index.vue

@@ -1,6 +1,6 @@
 <template>
 	<div class="tels-smart-record-container layout-pd">
-		<el-card shadow="never">
+		<!--		<el-card shadow="never">
 			<el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="20px">
 				<el-row :gutter="10">
 					<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
@@ -48,15 +48,68 @@
 				v-model:page-size="state.queryParams.pagesize"
 				:key="Math.random()"
 			>
-				<!-- 表格操作 -->
+				&lt;!&ndash; 表格操作 &ndash;&gt;
 				<template #operation="{ row }">
 					<el-button type="primary" @click="onPlaySoundRecording(row)" title="播放录音" link v-if="row.recordUrl">播放录音</el-button>
 					<el-button link type="primary" @click="onDownload(row)" title="下载录音" v-if="row.recordUrl"> 下载录音 </el-button>
 				</template>
 			</ProTable>
 		</el-card>
-		<!-- 播放录音 -->
-		<play-record ref="playRecordRef" />
+		&lt;!&ndash; 播放录音 &ndash;&gt;
+		<play-record ref="playRecordRef" />-->
+		<el-card>
+			<div id="ola">
+				<el-form :model="state.testForm" @submit.native.prevent>
+					<el-row :gutter="10">
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+							<el-form-item prop="serIp" label="服务器ip:">
+								<el-input v-model="state.testForm.serIp" placeholder="例如:114.114.114.114" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+							<el-form-item prop="serPort" label="服务器端口:">
+								<el-input v-model="state.testForm.serPort" placeholder="例如:29003" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+							<el-form-item prop="queue" label="队列:">
+								<el-input v-model="state.testForm.queue" placeholder="例如:10010" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+							<el-form-item prop="callNumber" label="分机:">
+								<el-input v-model="state.testForm.agent" placeholder="例如:1001" clearable />
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
+							<el-form-item prop="agentPwd" label="分机密码:">
+								<el-input v-model="state.testForm.agentPwd" placeholder="例如:!@#123Qw" clearable />
+							</el-form-item>
+						</el-col>
+						<el-divider>
+							<span class="ss_title">连接状态:{{ wsStatus }}</span>
+
+							<el-button @click="wsConnect" type="primary" class="ml10" v-if="showConnect">连接</el-button>
+						</el-divider>
+						<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+							<div class="mb10">签入状态:{{ olaStatus }}</div>
+							<el-button @click="login" type="primary">签入</el-button>
+							<el-button @click="logout" type="primary">签出</el-button>
+							<el-button @click="ready" type="primary">示闲</el-button>
+							<el-button @click="unReady" type="primary">示忙</el-button>
+							<el-button @click="hold" type="primary">保持</el-button>
+							<el-button @click="unHold" type="primary">取消保持</el-button>
+							<el-button @click="hangup" type="primary">挂机</el-button>
+						</el-col>
+						<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+							<el-form-item label="JSON数据">
+								{{jsonData}}
+							</el-form-item>
+						</el-col>
+					</el-row>
+				</el-form>
+			</div>
+		</el-card>
 	</div>
 </template>
 
@@ -70,6 +123,8 @@ import { shortcuts } from '@/utils/constants';
 import other from '@/utils/other';
 import { fileDownload } from '@/api/public/file';
 import { jthsRecord } from '@/api/todo/voiceAssistant';
+import { ola } from '@/utils/ola_api';
+import { forceLogout } from "@/api/tels/extension";
 
 // 引入组件
 const PlayRecord = defineAsyncComponent(() => import('@/views/tels/callLog/component/Play-record.vue')); // 播放录音
@@ -102,6 +157,13 @@ const state = reactive({
 	callDirection: [],
 	onState: [],
 	endByOptions: [],
+	testForm: {
+		serIp: '222.213.23.229',
+		serPort: '29003',
+		queue: '10010',
+		agent: '1100',
+		agentPwd: '!@#123Qw',
+	},
 });
 const ruleFormRef = ref<FormInstance>(); // 表单ref
 const searchCol = ref(true); // 展开/收起
@@ -192,6 +254,116 @@ const onDownload = (row: any) => {
 		.catch(() => {});
 };
 onMounted(() => {
-	queryList();
+	// queryList();
 });
+const wsStatus = ref('Disconnected');
+const jsonData = ref('');
+const showConnect = ref(true);
+// 链接ws
+const wsConnect = () => {
+	const websocket_url = 'ws://' + state.testForm.serIp + ':' + state.testForm.serPort + '/ola_socket';
+	console.log('----00000-----');
+	ola.onConnect = onConnect;
+	console.log('-----11111----');
+	ola.onClose = onClose;
+	ola.onMessage = onMessage;
+	ola.connect(websocket_url, state.testForm.agent, state.testForm.agentPwd);
+};
+const onConnect = () => {
+	console.log('-----222222----');
+	console.log('websocket connected!');
+	ola._extn = state.testForm.agent;
+	showConnect.value = false;
+	wsStatus.value = 'Connected';
+	ola.subscribe('ola.agent.' + state.testForm.agent);
+	ola.subscribe('ola.caller.' + state.testForm.agent);
+	ola.get_agent_state(state.testForm.agent);
+	//连接之后,先登出一次,防止其他地方已经登陆
+	ola.logout();
+	login();
+};
+const login = () => {
+	let array_ola_queue: EmptyArrayType = []; // 队列
+	if (state.testForm.queue != '') {
+		const array = state.testForm.queue.split(',');
+		for (let i = 0; i < array.length; i++) {
+			array_ola_queue[i] = array[i];
+		}
+		ola.login(array_ola_queue, state.testForm.agent, { type: 'onhook' });
+	}
+};
+const logout = () => {
+	ola.logout();
+	olaStatus.value = '未签入';
+};
+const onClose = () => {
+	console.log('websocket closed!');
+	wsStatus.value = 'Disconnected';
+	showConnect.value = true;
+};
+const olaStatus = ref('');
+const onMessage = (evt: any) => {
+	const data = JSON.parse(evt.data);
+	if (data.event_type === 'agent_state') {
+		jsonData.value = evt.data;
+		if (data.state == 'login') {
+			olaStatus.value = '已签入';
+		} else if (data.state == 'logout') {
+			olaStatus.value = '未签入';
+		} else if (data.state == 'ready') {
+			olaStatus.value = '示闲中';
+		} else if (data.state == 'unready') {
+			olaStatus.value = '示忙中';
+		} else if (data.state == 'acw') {
+			olaStatus.value = '话后整理中';
+		} else if (data.state == 'busy') {
+			olaStatus.value = '通话中';
+		} else {
+			olaStatus.value = data.state;
+		}
+
+		if (data.state == 'busy') {
+			if (data.call_direction == 'outbound') {
+				if (data.private_data == 'calling') {
+					olaStatus.value = '拨号中';
+				} else if (data.private_data == 'answered') {
+					if (data.other_answered == false) {
+						olaStatus.value = '振铃中';
+					} else if (data.other_answered == true) {
+						olaStatus.value = '通话中';
+					}
+				}
+			} else {
+				if (data.private_data == 'ring') {
+					olaStatus.value = '振铃中';
+				} else if (data.private_data == 'answered') {
+					olaStatus.value = '通话中';
+				}
+			}
+		} else if (data.old_state == 'busy') {
+			//挂机后系统可以返回两种状态:acw 话后整理状态 ready 示闲状态,如果不需要acw,可以联系我们后台修改配置,如果需要保留,如果需要再次
+			//拨打电话的话,需要手动点击示闲按钮
+			alert('已挂机');
+			olaStatus.value = '已挂机';
+		}
+	} else if (data.event_type == 'agent_caller_state') {
+	} else if (data.event_type == 'command/reply') {
+	}
+};
+const ready = () => {
+	ola.go_ready();
+};
+const unReady = () => {
+	ola.go_break('');
+};
+const hold = () => {
+	ola.hold();
+};
+const unHold = () => {
+	ola.unhold();
+};
+const hangup = () => {
+	ola.hangup();
+};
+
 </script>