Explorar o código

reactor:兴唐监听;

zhangchong hai 1 mes
pai
achega
86d2e5ef9e
Modificáronse 3 ficheiros con 368 adicións e 113 borrados
  1. 2 2
      .env.development
  2. 365 91
      src/views/seats/XTHeader.vue
  3. 1 20
      src/views/seats/XTIndex.vue

+ 2 - 2
.env.development

@@ -1,8 +1,8 @@
 # 本地环境
 VITE_MODE_NAME=development
 # socket API
-VITE_API_SOCKET_URL=http://110.188.24.28:50300/hubs/hotline
+VITE_API_SOCKET_URL=http://110.188.24.28:50100/hubs/hotline
 # 基础请求地址
-VITE_API_URL=http://110.188.24.28:50300
+VITE_API_URL=http://110.188.24.28:50100
 # 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
 VITE_STORAGE_NAME=dev

+ 365 - 91
src/views/seats/XTHeader.vue

@@ -120,12 +120,13 @@ import { formatDate } from "@/utils/formatTime";
 import { olaFn } from "@/utils/olaFn";
 import { getNowDateTime } from "@/utils/constants";
 import { callCenterLogout, useGlobalState } from "@/utils/callCenter";
-import { ElMessageBox, FormInstance } from "element-plus";
+import { ElMessage, ElMessageBox, FormInstance } from "element-plus";
 import { Phone, PhoneFilled } from "@element-plus/icons-vue";
 import { useThemeConfig } from "@/stores/themeConfig";
 import { storeToRefs } from "pinia";
 import { getListenExtensionXt } from "api/seats";
 import mittBus from "@/utils/mitt";
+import { useTimeoutFn, useWebSocket } from "@vueuse/core";
 
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
@@ -136,14 +137,281 @@ const props = defineProps({
   },
 });
 const now = useNow(); // 获取当前时间
-const state = reactive({
+const state = reactive<any>({
   dutyDialogVisible: false,
-  dutyForm: {
+  dutyForm: <any>{
     currentTel: null,
   },
   loading: false,
   telsList: [],
 });
+
+const m_strUserNo = ref(""); // 分机号码
+const m_strUserName = ref(""); // 用户名称
+const m_strJobNum = ref("1"); // 坐席工号
+const m_strSkillId = ref("99"); // 技能组
+const m_strLevel = ref("1"); // 优先级别
+const m_strGroup = ref("1"); // 分组ID
+const m_strCompanyId = ref(""); // 企业编码
+const m_bLogin = ref(false); // 登录状态
+const m_strTelState = ref("0"); // 当前状态
+const m_strIsMonitor = ref("1"); // 是否监控分机 1-是监控分机
+const m_IsHold = ref(false); // 是否保持
+
+const globalState = useGlobalState(); // 全局变量
+// 发送消息
+const e_TelSendMsg = (strObj: Object) => {
+  // 客户端当前时间
+  const strMsg = JSON.stringify(strObj);
+  console.log(`${getNowDateTime()} 发送消息:`, strMsg, wsRef.value.status);
+  if (wsRef.value.ws?.readyState === 1) {
+    // 已经链接并且可以通讯,则发放文本消息
+    wsRef.value.send(strMsg);
+  } else {
+    ElMessage.error("请先签入");
+  }
+};
+
+// ws实例对象
+const wsRef = ref();
+const initWs = () => {
+  wsRef.value = useWebSocket(themeConfig.value.callCenterSocketUrl, {
+    heartbeat: {
+      message: JSON.stringify({
+        Action: "ReqHealthCheck",
+        Param: { Extension: m_strUserNo.value },
+      }),
+      interval: 5000,
+      pongTimeout: 5000,
+    },
+    autoReconnect: {
+      delay: 2000,
+    }, // 自动重连
+    immediate: true, // 是否立即链接
+    onMessage: e_TelMsgReceive, // 消息接收
+    onError: e_websocketError, // 错误
+    onDisconnected: e_websocketClose, // 断开
+    onConnected: e_websocketOpen, // 链接成功
+  });
+};
+// 消息接收
+const e_TelMsgReceive = (ws: any, restMsg: any) => {
+  console.log(`${getNowDateTime()} 接收消息:${restMsg.data}`);
+  if (restMsg.data) {
+    const data = eval("(" + restMsg.data + ")");
+    if (data) {
+      // 方法
+      const strAction = data.Action;
+      switch (strAction) {
+        // 登录返回值
+        case "ResAgentLogin":
+          retSignIn(data);
+          break;
+        // 示闲
+        case "ResAgentIdle":
+          break;
+        // 示忙
+        case "ResAgentBusy":
+          break;
+        // 外呼状态
+        case "ResMakeCall":
+          break;
+        // 保持
+        case "ResHoldCall":
+          break;
+        // 取消保持
+        case "ResRetrieve":
+          break;
+        // 咨询内线
+        case "ResConsultInline":
+          break;
+        // 咨询外线
+        case "ResConsultOutline":
+          break;
+        // 咨询群组
+        case "ResConsultSkillGroup":
+          break;
+        // 咨询转移
+        case "ResTransfer":
+          break;
+        // 三方会议
+        case "ResConference":
+          break;
+        // 三方会议
+        case "ResMonConf":
+          break;
+      }
+      // 事件
+      const strEvent = data.Event;
+      switch (strEvent) {
+        // 签出事件
+        case "EvtLogout":
+          retSignOut();
+          break;
+        // 呼入振铃事件
+        case "EvtCallAlerting":
+          break;
+        // 应答事件
+        case "EvtCallAnswer":
+          break;
+        // 挂机事件
+        case "EvtHangup":
+          break;
+        // 状态
+        case "EvtSeatState":
+          evtSeatState(data);
+          break;
+        // 队列等待
+        case "EvtAcdInfo":
+          break;
+        // 语音识别结果通知事件
+        case "EvtRecognize":
+          break;
+
+        // 转三方接通状态
+        case "EvtDispatchState":
+          break;
+
+        // 签出事件
+        case "ResStopMonitor":
+          retSignOut();
+          break;
+
+        case "ResError": // 异常
+          // 异常处理
+          retResError(data);
+          break;
+        // 呼出接通事件
+        case "EvtOutCalling":
+          break;
+        // 签出事件
+        case "EvtQuit":
+          retSignOut();
+          break;
+      }
+    }
+  }
+};
+const evtSeatState = (data: any) => {
+  if (m_strIsMonitor.value == "1") {
+    // 推送分机信息
+    const pushExt = data.Param.Extension || "";
+    if (pushExt !== m_strUserNo.value) {
+      // 如果分机实时推送的分机信息和当前登录分机不一致,则表明当前登录分机为监控分机,开启了状态监控功能
+      // 1.不属于当前分机的状态,则不改变当前分机电话条状态
+      // 2.调整其他分机大屏监控状态
+      const pushState = GetTelState(data.Param.State);
+      if (pushState) {
+        // 修改后台数据
+        console.log(pushExt, pushState);
+        // SetMonitorState(pushExt, pushState);
+      }
+      mittBus.emit("monitorInfoTel", data.Param);
+      return;
+    }
+  }
+  // 状态 0:闲 1:忙 2:会议 3:登出 4:呼入 5:呼出 6:咨询 7:其他 8:通话
+  const strState = data.Param.State;
+  switch (strState) {
+    // 空闲
+    case "0":
+      break;
+    // 示忙
+    case "1":
+      break;
+    case "2":
+      break;
+    // 登出
+    case "3":
+      // 附加签出方法(用户分机分离调用业务系统签出);
+      break;
+    // 通话振铃
+    case "4":
+      break;
+    // 通话振铃
+    case "5":
+      break;
+    // 咨询
+    case "6":
+      break;
+    // 其他
+    case "7":
+      break;
+    // 接通
+    case "8":
+      break;
+    case "9": // 工单整理
+      break;
+  }
+};
+// 获取分机状态
+const GetTelState = (strState: any) => {
+  let strResult = "";
+  switch (strState) {
+    // 空闲
+    case "0":
+      strResult = "200";
+      break;
+    // 示忙
+    case "1":
+      strResult = "201";
+      break;
+    case "2":
+      break;
+    // 登出
+    case "3":
+      strResult = "0";
+      break;
+    // 通话振铃
+    case "4":
+      strResult = "302"; // 默认呼入振铃
+      break;
+    // 通话振铃
+    case "5":
+      strResult = "302"; // 默认呼出振铃
+      break;
+    // 咨询
+    case "6":
+      break;
+    // 其他
+    case "7":
+      break;
+    // 接通
+    case "8":
+      strResult = "301";
+      break;
+    case "9": // 工单整理
+      strResult = "900";
+      break;
+  }
+  return strResult;
+};
+// ws链接开启成功
+const e_websocketOpen = () => {
+  /*  if (userAlreadyLogin.value) {
+    // 检查到用户已经登录需要先签出 再签入
+    sendSignOut();
+    useTimeoutFn(() => {
+      sendSignIn();
+    }, 500);
+
+  //   {"Action" : "ReqStateMonitor", "Param":  { "MonitorId":""}}
+  } else {
+    if (m_strUserNo.value && m_strSkillId.value) sendSignIn();
+  }*/
+  sendSignIn(); // 签入
+};
+// 链接关闭
+const e_websocketClose = () => {
+  globalState.callCenterIsSignIn = false; // 签出状态
+  console.log(`${getNowDateTime()} 呼叫中心链接关闭`);
+};
+// 链接错误
+const e_websocketError = () => {
+  globalState.callCenterWs = null;
+  globalState.callCenterIsSignIn = false; // 签出状态
+  console.log(`${getNowDateTime()} 呼叫中心链接错误`);
+};
 // 签入
 const signIn = () => {
   if (!globalState.callCenterIsSignIn) {
@@ -158,18 +426,68 @@ const clickOnDuty = (formEl: FormInstance | undefined) => {
   if (!formEl) return;
   formEl.validate((valid: boolean) => {
     if (!valid) return;
-    const currentPhone: any = state.telsList.find(
-      (item: any) => item.telNo === state.dutyForm.currentTel
-    );
-    globalState.currentTel = {
-      telNo: currentPhone.telNo,
-      telGroup: currentPhone.queue,
-      jobNum: currentPhone.TelNo,
-    };
-    websocket_connect(currentPhone.telNo, currentPhone.telPwd);
+    m_strUserNo.value = state.dutyForm.currentTel;
+    m_strJobNum.value = state.dutyForm.currentTel; // 默认取用户工号
+    initWs();
     state.dutyDialogVisible = false;
   });
 };
+/*
+* 登录
+* ReqAgentLogin - 登录方法名
+* JobNum - 工号
+* Name - 姓名
+* Extension - 分机号
+* SkillId - 技能组
+* Level - 为要设置的级别,分为9个级别,从高到低分别为0-8;同一技能组中级别越高的坐席优先被分配
+* Role - 角色,保留,不做设置
+* GroupName - 技能组名称
+* OrgId - 组织ID
+* 返回内容:
+{“Action”:”ResAgentLogin”,”Param”:{“Result”:}}
+Result: 3:分机错误 7:已登录 0:登录成功
+ */
+const sendSignIn = () => {
+  globalState.callCenterWs = wsRef.value;
+  const sendObj = {
+    Action: "ReqAgentLogin",
+    Param: {
+      JobNum: m_strJobNum.value,
+      Name: m_strUserName.value,
+      Extension: m_strUserNo.value,
+      SkillId: m_strSkillId.value,
+      Level: m_strLevel.value,
+      Role: "",
+      GroupName: m_strGroup.value,
+      OrgId: m_strCompanyId.value,
+    },
+  };
+  // 发送请求
+  e_TelSendMsg(sendObj);
+  console.log(`${getNowDateTime()} 呼叫中心发起签入`);
+};
+// 签入消息回调
+const retSignIn = (data: any) => {
+  if (data.Param.Result === "0") {
+    // 登录成功
+    m_bLogin.value = true;
+
+    // 登录成功
+    globalState.callCenterIsSignIn = true; // 签入状态
+
+    console.log(`${getNowDateTime()} 呼叫中心签入成功回调`);
+  } else if (data.Param.Result === "3") {
+    // 分机错误
+    ElMessage.error("分机错误");
+    wsRef.value.close();
+    // 分机错误
+  } else if (data.Param.Result === "7") {
+    // 已经处于登录状态
+    // 先签出再签入
+    wsRef.value.close();
+    ElMessage.error("当前分机已经签入");
+  }
+};
 // 签出
 const signOut = () => {
   ElMessageBox.confirm(`签出后无法监听和插话,确定签出?`, "提示", {
@@ -181,90 +499,48 @@ const signOut = () => {
     autofocus: false,
   })
     .then(async () => {
-      callCenterLogout();
+      sendSignOut();
     })
     .catch(() => {});
 };
-const globalState = useGlobalState();
-const olaRef = ref();
-const websocket_connect = (telNo: string, telPwd: string) => {
-  olaRef.value = olaFn(themeConfig.value.callCenterSocketUrl, {
-    username: telNo,
-    password: telPwd,
-    onConnected: onConnected, // 连接成功
-    onDisconnected: onDisconnected, // 断开链接
-    onMessage: onMessage, // 接收消息
-    onError: onError, // 错误
-    autoReconnect: {
-      delay: 2000,
-      // retries: 10,
-    }, // 自动重连
-    heartbeat: {
-      message: JSON.stringify({ cmd: "ping" }),
-      interval: 5000,
-      // pongTimeout: 1000,
+/*
+ * 签出
+ * ReqAgentLogout - 签出方法名称
+ * Extension - 分机号码
+ */
+const sendSignOut = () => {
+  const objMsg = {
+    Action: "ReqAgentLogout",
+    Param: {
+      Extension: m_strUserNo.value,
     },
-  });
-  console.log(`${getNowDateTime()}:开始链接呼叫中心`);
+  };
+  // 发送请求
+  e_TelSendMsg(objMsg);
 };
-// 呼叫中心链接成功
-const onConnected = () => {
-  olaRef.value.logout(globalState.currentTel.telNo); //连接之后,先登出一次,防止其他地方已经登陆
-  let array_ola_queue = []; // 队列
-  // 普通模式
-  let array = globalState.currentTel.telGroup.split(",");
-  for (let i = 0; i < array.length; i++) {
-    array_ola_queue[i] = array[i];
-  }
-  olaRef.value.login(array_ola_queue, globalState.currentTel.telNo, {
-    type: "onhook",
-  });
-  globalState.callCenterWs = olaRef.value;
-  console.log(`${getNowDateTime()}:呼叫中心链接成功`);
-};
-// 呼叫中心链接关闭
-const onDisconnected = (event: any) => {
-  globalState.callCenterWs = null;
-  console.log(`${getNowDateTime()}:呼叫中心断开链接`, event);
-};
-// 呼叫中心链接错误
-const onError = (ws: any, e: any) => {
+/*
+ * 签出事件
+ */
+const retSignOut = () => {
+  // 登出成功
+  m_strTelState.value = "0";
+  m_bLogin.value = false;
   globalState.callCenterIsSignIn = false; // 签出状态
-  console.log(`${getNowDateTime()}:呼叫中心链接错误`, e);
+  globalState.callCenterWs = null;
+  wsRef.value.close();
+  console.log(`${getNowDateTime()} 呼叫中心签出回调`);
 };
-// 呼叫中心消息
-const onMessage = async (event: any) => {
-  const data = JSON.parse(event);
-  // console.log(`${getNowDateTime()}:接收呼叫中心消息`, event);
-  if (data.event_type == "agent_state") {
-    switch (data.state) {
-      case "login": // 签入消息回调
-        globalState.callCenterIsSignIn = true; // 签入状态
-        setTimeout(() => {
-          // 设置示闲状态
-          olaRef.value.go_ready();
-        }, 300);
-        console.log(
-          `${getNowDateTime()}:接收消息:呼叫中心:已签入,当前分机:${
-            globalState.currentTel.telNo
-          }`
-        );
-        break;
-      case "logout": // 签出消息回调
-        globalState.callCenterIsSignIn = false; // 签出状态
-        console.log(`${getNowDateTime()}:接收消息:呼叫中心:已签出`);
-        break;
-      case "acw": // 话后整理回到
-        // 调用示闲
-        olaRef.value.go_ready(); // 示闲
-        console.log(`${getNowDateTime()}:接收消息:呼叫中心:已示闲`);
-        break;
-      case "unready": // 示忙消息回调
-        // 调用示闲
-        olaRef.value.go_ready(); // 示闲
-        console.log(`${getNowDateTime()}:接收消息:呼叫中心:已示闲`);
-        break;
-    }
+/**
+ * 异常处理
+ * @param {any} data
+ */
+const retResError = (data: any) => {
+  if (data.Param.Result == "99") {
+    // 掉线
+
+    globalState.callCenterWs = null;
+    ElMessage.error("连接已断开");
+    // 自动签入
   }
 };
 // 空闲数量
@@ -336,11 +612,9 @@ onMounted(() => {
     const item = seatsList.value.find(
       (item: any) => item.Extension === data.Extension
     );
-    item.loading = true;
     if (item) {
       setTimeout(() => {
         item.State = data.State;
-        item.loading = false;
       }, 500);
     }
   });

+ 1 - 20
src/views/seats/XTIndex.vue

@@ -59,7 +59,6 @@ const m_IsMonListen = ref("0"); // 监控状态 0-未监听;1-监控成功;2
 const m_strTelState = ref("0"); // 当前状态
 
 const globalState = useGlobalState(); // 全局变量
-const userAlreadyLogin = ref(false);
 // 发送消息
 const e_TelSendMsg = (strObj: Object) => {
   // 客户端当前时间
@@ -100,7 +99,7 @@ const initWs = () => {
 };
 // 消息接收
 const e_TelMsgReceive = (ws: any, restMsg: any) => {
-  console.log(`${getNowDateTime()} 接收消息:${restMsg.data}`);
+  console.log(`${getNowDateTime()} 分机监听 接收消息:${restMsg.data}`);
   if (restMsg.data) {
     const data = eval("(" + restMsg.data + ")");
     if (data) {
@@ -359,17 +358,6 @@ const sendMonitor = () => {
 };
 // ws链接开启成功
 const e_websocketOpen = () => {
-  /*  if (userAlreadyLogin.value) {
-    // 检查到用户已经登录需要先签出 再签入
-    sendSignOut();
-    useTimeoutFn(() => {
-      sendSignIn();
-    }, 500);
-
-  //   {"Action" : "ReqStateMonitor", "Param":  { "MonitorId":""}}
-  } else {
-    if (m_strUserNo.value && m_strSkillId.value) sendSignIn();
-  }*/
   sendMonitor(); // 开启监控
 };
 // 链接关闭
@@ -435,14 +423,11 @@ const retSignIn = (data: any) => {
   } else if (data.Param.Result === "3") {
     // 分机错误
     ElMessage.error("分机错误");
-    userAlreadyLogin.value = false; // 将登录状态重置
     wsRef.value.close();
     // 分机错误
   } else if (data.Param.Result === "7") {
     // 已经处于登录状态
     // 先签出再签入
-    /* sendSignOut();
-    userAlreadyLogin.value = false; // 将登录状态重置*/
     wsRef.value.close();
     ElMessage.error("当前分机已经签入");
   }
@@ -509,10 +494,6 @@ const retSignOut = () => {
   globalState.callCenterIsSignIn = false; // 签出状态
   globalState.callCenterWs = null;
   wsRef.value.close();
-  // 如果用户没有登录 关闭ws
-  if (!userAlreadyLogin.value) {
-    wsRef.value.close();
-  }
   console.log(`${getNowDateTime()} 呼叫中心签出回调`);
 };
 /**