import io from 'socket.io-client'; const address: any = import.meta.env.VITE_APP_BASE_API; const token: any = localStorage.getItem('token'); const myInfo: any = localStorage.getItem('userInfo'); let socket: any = {}; //ws实例对象 let timerManager: any = {}; //计时器管理 let parameter: any = {}; //参数 let testTime: number = 0; //默认时长 let userInfo: any = JSON.parse(myInfo); //用户信息 let beatTime: number = 10000; //心跳频率 let loading: any = null; //遮罩层 let version: string = ''; //ws接口版本v2表示单ws多项目 let examStateList: any = []; //当前状态码 let testList: any = []; //区列表 let wkList: any = []; //工作站列表 export const initWs = (data: any, callback: any) => { examStateList = []; //当前状态码 testList = []; //区列表 wkList = []; //工作站列表 loading = ElLoading.service({ text: '正在初始化,请稍候', background: 'rgba(0, 0, 0, 0.8)', customClass: `sports ${data.parameter.project}` }); parameter = data.parameter; testTime = data.testTime; version = data.version || ''; testList = data.parameter.area.split(','); examStateList = testList.map((item: any) => { let examId = `${parameter.project}_${item}`; let obj = { examState: 0, examId: examId, beatNumber: 0 }; return obj; }); socket = io(address + '/midexam', { transports: ['websocket', 'polling'], query: { Authorization: token, sysuuid: token } }); let loadingTime = setTimeout(() => { //30秒还在0状态就算超时 let list = examStateList.filter((item: any) => { return item.examState == 0; }); //考虑到多开只有一个在线也有效的 if (list.length == testList.length) { clearTimeout(loadingTime); callback({ cmd: 'disconnect_request', data: { message: 'WS连接超时' } }); } }, 20000); socket.on('connect', (e: any) => { callback({ cmd: 'mySid', data: { sid: socket.id.replace('/midexam#', '') } }); if (testList.length > 1) { //单WS多区 testList.forEach((item: any) => { let examId = `${parameter.project}_${item}`; getExamStarts(examId); getNetWork(examId, (e: any) => { if (!e.status) { callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: '工作站未响应' } }); } }); }); } else { //单WS单区 let examId = parameter.examId; getExamStarts(); getNetWork(examId, (e: any) => { if (!e.status) { callback({ cmd: 'disconnect_request', exam_id: examId, data: { message: '工作站未响应' } }); } }); } }); socket.on('msg2frontend', (e: any) => { callback(e); //实时状态 if (e.cmd === 'exam_status') { let index = examStateList.findIndex((item: any) => { return item.examId == e.exam_id; }); if (index != -1) { examStateList[index].examState = e.data; examStateList[index].beatNumber = examStateList[index].beatNumber + 1; } } //工作站状态 if (e.cmd === 'init_result') { if (e.status == 666) { let data = { wk_id: e.data.wk_id, examId: e.exam_id }; wkList.push(data); } } //测试违规 if (e.cmd === 'warning_result') { } //后端播报语音 if (e.cmd === 'return_audio_msg') { } //错误提示 if (e.cmd === 'info_result') { } //错误提示 if (e.cmd === 'error_result') { } //测试中违规提示 if (e.cmd === 'warning_notify') { } //断线状态 if (e.cmd === 'disconnect_request') { if (testList.length == 1) { getExit(); //let examId = e?.exam_id || ''; //getExit(examId); } } //状态变更 if (e.cmd === 'set_exam_state') { let index = examStateList.findIndex((item: any) => { return item.examId == e.exam_id; }); if (index != -1) { examStateList[index].examState = e.data; } if (e.data == 3) { //关闭遮罩层 loading?.close(); clearTimeout(loadingTime); } } //新建测试后返回信息,获取result_id if (e.cmd === 'open_one_test_ack') { } //人脸识别状态 if (e.cmd === 'face_check_result') { } //测试结束结果 if (e.cmd === 'oneresult') { } //结果生成完成(视频图片) if (e.cmd === 'static_urls_finished') { } //选择学生或测试结束后返回的数据 if (e.cmd === 'result_info') { } }); socket.on('disconnect', (e: any) => { callback(e); getExit(); }); }; /** * 发送命令 * @param type发送类型:v2版是单WS多人的项目 * msgfrom_frontend:测试中命令交互, * get_exam_status:心跳, * exam_ends:结束测试, * fe_reconnect:重连, * task_starts:开启工作站, * exam_starts:开启测试, * join_exam_room:加入房间, * @param data发送数据: * msgfrom_frontend发送cmd的参: * open_one_test:创建测试将由3转40, * start_face_recognition:开始人脸识别将由40转41, * stop_face_recognition:停止人脸识别将由41转43, * face_confirm_only:人脸确认即将测试, * start_one_test:开始测试将由43转42, * finish_one_test:正在测试中结束并下一次将由42转6转3, * close_one_test:中断任何阶段将由42、43、41、40转3, * suspend_face_recognition_channels:工作站识别的短跑,某道识别到了人就停止某道的识别, * resume_face_recognition_channels:工作站识别的短跑,重新开启某一道的识别, * next_test:, * result_info:, * @param callback回调函数 */ export const sendMessage = (type: string, data: any, callback?: () => void) => { if (socket.connected) { callback = callback || function () {}; //版本2就拼接进去 if (version == 'v2') { type = type + '_' + version; } socket.emit(type, JSON.stringify(data), callback); } }; /** * 连接成功 */ const getExamStarts = (data?: any) => { let examId = data ? data : parameter.examId; sendMessage( 'exam_starts', { data: 'start_' + examId, class_id: parameter.classes, exam_type: parameter.standard, gesture: parameter.gesture, demo: parameter.demo, test_time: testTime }, () => {} ); }; /** * 创建测试 */ export const openOneTest = (data?: any) => { return new Promise((resolve, reject) => { let examId = data ? data : parameter.examId; let index = examStateList.findIndex((item: any) => { return item.examId == examId; }); sendMessage('msgfrom_frontend', { data: { cmd: 'open_one_test', exam_id: examId } }); let timer1 = setInterval(() => { if (examStateList[index].examState == 40) { clearInterval(timer1); clearTimeout(timer2); resolve({ data: examStateList[index].examState }); } }, 250); let timer2 = setTimeout(() => { if (examStateList[index].examState == 3) { clearInterval(timer1); clearTimeout(timer2); reject({ cmd: 'disconnect_request', exam_id: examId, data: { message: '超时:open_one_test' } }); } }, 30000); }); }; /** * 开始人脸识别 */ export const startFace = (data?: any) => { return new Promise((resolve, reject) => { let examId = data ? data : parameter.examId; let index = examStateList.findIndex((item: any) => { return item.examId == examId; }); sendMessage('msgfrom_frontend', { data: { cmd: 'start_face_recognition', exam_id: examId } }); let timer1 = setInterval(() => { if (examStateList[index].examState == 41) { clearInterval(timer1); clearTimeout(timer2); resolve({ data: examStateList[index].examState }); } }, 250); let timer2 = setTimeout(() => { if (examStateList[index].examState == 40) { clearInterval(timer1); clearTimeout(timer2); reject({ cmd: 'disconnect_request', exam_id: examId, data: { message: '超时:start_face_recognition' } }); } }, 30000); }); }; /** * 停止人脸识别 */ export const stopFace = (data?: any) => { return new Promise((resolve, reject) => { let examId = data ? data : parameter.examId; let index = examStateList.findIndex((item: any) => { return item.examId == examId; }); sendMessage('msgfrom_frontend', { data: { cmd: 'stop_face_recognition', exam_id: examId } }); let timer1 = setInterval(() => { if (examStateList[index].examState == 43) { clearInterval(timer1); clearTimeout(timer2); resolve({ data: examStateList[index].examState }); } }, 250); let timer2 = setTimeout(() => { if (examStateList[index].examState == 41) { clearInterval(timer1); clearTimeout(timer2); reject({ cmd: 'disconnect_request', exam_id: examId, data: { message: '超时:stop_face_recognition' } }); } }, 30000); }); }; /** * 确认并提交人脸 */ export const faceConfirmOnly = (data: any, callback?: any) => { let examId = data.exam_id ? data.exam_id : parameter.examId; let myData = null; if (Array.isArray(data)) { //数组类型 myData = { cmd: 'face_confirm_only', data }; } else { //对象类型 myData = { cmd: 'face_confirm_only', exam_id: examId, result_id: data.result_id, student_id: data.student_id, gender: data.gender }; } sendMessage( 'msgfrom_frontend', { data: myData }, () => { callback(); } ); }; /** * 开始测试 */ export const startOneTest = (data?: any, callback?: any) => { let examId = data ? data : parameter.examId; sendMessage( 'msgfrom_frontend', { data: { cmd: 'start_one_test', exam_id: examId } }, () => { callback(); } ); }; /** * 停止测试 */ export const finishOneTest = (data?: any) => { return new Promise((resolve, reject) => { let examId = data ? data : parameter.examId; let index = examStateList.findIndex((item: any) => { return item.examId == examId; }); sendMessage('msgfrom_frontend', { data: { cmd: 'finish_one_test', exam_id: examId } }); let timer1 = setInterval(() => { if (examStateList[index].examState == 3) { clearInterval(timer1); clearTimeout(timer2); resolve({ data: examStateList[index].examState }); } }, 250); let timer2 = setTimeout(() => { if (examStateList[index].examState == 42) { clearInterval(timer1); clearTimeout(timer2); reject({ cmd: 'disconnect_request', exam_id: examId, data: { message: '超时:finish_one_test' } }); } }, 60000); }); }; /** * 关闭测试测试 */ export const closeOneTest = (data?: any) => { return new Promise((resolve, reject) => { let examId = data ? data : parameter.examId; let index = examStateList.findIndex((item: any) => { return item.examId == examId; }); sendMessage('msgfrom_frontend', { data: { cmd: 'close_one_test', exam_id: examId } }); let timer1 = setInterval(() => { if (examStateList[index].examState == 3) { clearInterval(timer1); clearTimeout(timer2); resolve({ data: examStateList[index].examState }); } }, 250); let timer2 = setTimeout(() => { if (examStateList[index].examState != 3) { clearInterval(timer1); clearTimeout(timer2); reject({ cmd: 'disconnect_request', exam_id: examId, data: { message: '超时:close_one_test' } }); } }, 30000); }); }; /** * 某道识别到了人就停止某道的识别 */ export const suspendFaceRecognitionChannels = (data: any) => { let track = data; sendMessage('msgfrom_frontend', { data: { cmd: 'suspend_face_recognition_channels', track: track } }); }; /** * 某道重新开始识别 */ export const resumeFaceRecognitionChannels = (data: any) => { let track = data; sendMessage('msgfrom_frontend', { data: { cmd: 'resume_face_recognition_channels', track: track } }); }; /** * 心跳 */ export const getNetWork = (data: any, callback?: any) => { timerManager[data] = setInterval(() => { let obj = wkList.find((item: any) => { return item.examId == data; }); if (obj == undefined) { return false; } let wk_id = obj.wk_id; let examId = data ? data : parameter.examId; sendMessage( 'get_exam_status', { exam_id: examId, wk_id: wk_id, school_id: userInfo.school_id || null }, () => { //如果心跳停止了就退出去 let index = examStateList.findIndex((item: any) => { return item.examId == examId; }); if (index == -1) { return false; } let beforBeatNumber = JSON.parse(JSON.stringify(examStateList[index].beatNumber)); setTimeout(() => { //5秒后验证是否有变 if (beforBeatNumber == examStateList[index].beatNumber) { //异常 callback({ status: false }); } else { //正常 callback({ status: true }); } }, 5000); } ); }, beatTime); }; /** * 关闭项目 */ export const examEnds = () => { getExit(); }; /** * 退出 */ const getExit = (data?: any) => { //关闭遮罩层 loading?.close(); //通知工作站关闭 if (testList.length > 1 && !data) { //单WS多区 examStateList.forEach((item: any) => { let examId = item.examId; sendMessage('exam_ends', { data: 'end_' + examId, class_id: parameter.classes }); }); //清除计时器 getClearTimer(); //如果正在连接就关闭 if (socket?.connected) { socket?.close(); } } else { //单WS单区 let examId = data ? data : parameter.examId; sendMessage('exam_ends', { data: 'end_' + examId, class_id: parameter.classes }); if (!data) { //清除计时器 getClearTimer(); //如果正在连接就关闭 if (socket?.connected) { socket?.close(); } } } }; /** * 清空定时任务 */ const getClearTimer = () => { for (let key in timerManager) { if (timerManager.hasOwnProperty(key)) { clearInterval(timerManager[key]); timerManager[key] = null; } } };