From 13b1a895a4f89e72bfaa0815ce3b1d2625e29a3e Mon Sep 17 00:00:00 2001 From: zdg Date: Wed, 11 Dec 2024 17:16:55 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E4=B8=8A=E8=AF=BE=20socket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/AixPPTist/src/App.vue | 5 +- .../src/AixPPTist/src/api/classcourse.ts | 9 +- src/renderer/src/AixPPTist/src/api/types.ts | 2 + src/renderer/src/AixPPTist/src/api/watcher.ts | 166 ++++++++++-------- .../src/AixPPTist/src/hooks/useScreening.ts | 6 +- src/renderer/src/plugins/imChat/msgEnum.js | 2 + src/renderer/src/plugins/socket/index.js | 77 ++++---- .../src/views/classManage/reserv-item-apt.vue | 5 +- src/renderer/src/views/prepare/index.vue | 13 +- 9 files changed, 166 insertions(+), 119 deletions(-) diff --git a/src/renderer/src/AixPPTist/src/App.vue b/src/renderer/src/AixPPTist/src/App.vue index 7cb504f..c6f4071 100644 --- a/src/renderer/src/AixPPTist/src/App.vue +++ b/src/renderer/src/AixPPTist/src/App.vue @@ -27,8 +27,9 @@ import msgUtils from '@/plugins/modal' // 消息工具 import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api import { PPTApi } from './api' import { sessionStore } from '@/utils/store' // electron-store 状态管理 -import './api/watcher' // 监听 - +// import './api/watcher' // 监听 +import watcher from './api/watcher' // 监听 +watcher() // 监听启动 const loading = ref(true) const _isPC = isPC() diff --git a/src/renderer/src/AixPPTist/src/api/classcourse.ts b/src/renderer/src/AixPPTist/src/api/classcourse.ts index e78a19d..da4a566 100644 --- a/src/renderer/src/AixPPTist/src/api/classcourse.ts +++ b/src/renderer/src/AixPPTist/src/api/classcourse.ts @@ -14,6 +14,8 @@ const classcourse = sessionStore.get('curr.classcourse') // 课堂信息 export class Classcourse { msgObj:ElMessageBox = null // 提示消息对象 + classcourse:any = null // 课堂信息 + id: number|string = null // 课堂id constructor() { this.load() @@ -22,6 +24,7 @@ export class Classcourse { * @description 加载 */ load() { + console.log('classcourse-load', classcourse) // 打开全屏 screenStore.setScreening(!!classcourse) // 如果课堂信息有值,则连接socket @@ -30,13 +33,15 @@ export class Classcourse { if (!ChatWs.ws) ChatWs.init() ChatWs.id = classcourse.timgroupid // 群组id console.log('ws- ', classcourse) - classcourseStore.setClasscourse(classcourse) + this.classcourse = classcourse // 课堂信息 + this.id = classcourse.id // 课堂id + classcourseStore.setClasscourse(classcourse) // 课堂信息-状态管理 // 待上课提示 if (!classcourse.status) { this.msgObj = { type: 'success', title: '系统提示', - message: '公屏课堂已准备完毕,请等待老师开启课堂!', + message: '公屏课堂已准备完毕,等待老师开启课堂...', center: true, showClose: false, showCancelButton: false, diff --git a/src/renderer/src/AixPPTist/src/api/types.ts b/src/renderer/src/AixPPTist/src/api/types.ts index 26881e9..c8ba828 100644 --- a/src/renderer/src/AixPPTist/src/api/types.ts +++ b/src/renderer/src/AixPPTist/src/api/types.ts @@ -120,6 +120,8 @@ export class MsgEnum { MSG_classWorkOfPresentDataUpdate : 'classWorkOfPresentDataUpdate', /** @desc: 课堂讲授活动,选择不同的内容 */ MSG_classlecturePagesrc : 'classlecturePagesrc', + /** @desc: 课堂作业|活动 */ + MSG_homework : 'homework', // === 新定义-消息头 === /** @desc: 课程创建-待开课 */ MSG_0000: 0x0000, diff --git a/src/renderer/src/AixPPTist/src/api/watcher.ts b/src/renderer/src/AixPPTist/src/api/watcher.ts index ff14229..b2dd96c 100644 --- a/src/renderer/src/AixPPTist/src/api/watcher.ts +++ b/src/renderer/src/AixPPTist/src/api/watcher.ts @@ -10,85 +10,103 @@ import { MsgEnum } from './types' // 消息枚举 import ChatWs from '@/plugins/socket' // 聊天socket import Classcourse from './classcourse' // 课程相关 import msgUtils from '@/plugins/modal' // 消息工具 -const slidesStore = store.useSlidesStore() -const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理 -const resource = sessionStore.get('curr.resource') // apt 资源 -const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源 +import { Homework } from './index' // api-作业相关 + /** * @description 监听器 */ -// 监听幻灯片内容变化 -watch(() => slidesStore.slides, (newVal, oldVal) => { - PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容 -},{ deep: true }) - -// 监听标题变化 -watch(() => slidesStore.title, (newVal, oldVal) => { - if (oldVal == '未命名演示文稿') return // 初始加载,不需要更新数据 - updatePPT({title: newVal}) -}) - -// 消息监听ws -console.log('监听器已开启', ChatWs) -if (ChatWs.ws) { - ChatWs.watch((msg, e) => { - try { - handleMessage(JSON.parse(msg)) - } catch (error) { - console.error('socket 解析异常 ', error, e) - handleMessage(msg) - } +export default () => { + const slidesStore = store.useSlidesStore() + const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理 + const resource = sessionStore.get('curr.resource') // apt 资源 + const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源 + window.test = slidesStore + // 监听幻灯片内容变化 + watch(() => slidesStore.slides, (newVal, oldVal) => { + PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容 + },{ deep: true }) + + // 监听标题变化 + watch(() => slidesStore.title, (newVal, oldVal) => { + if (oldVal == '未命名演示文稿') return // 初始加载,不需要更新数据 + updatePPT({title: newVal}) }) -} - -// 更新ppt内容 -const updatePPT = async (data) => { - if (!resource) return - data.id = resource.id - await PPTApi.updateSlide(data) // 更新ppt内容 - sessionStore.set('curr.resource.title', data.title) - // 更新smarttalk内容 - if (!!smarttalk && !!data.title) { - const {id, fileFlag} = smarttalk - const params = { id, fileShowName: `${data.title}.${fileFlag}` } - await PPTApi.updateSmarttalk(params) // 更新ppt内容 - sessionStore.set('curr.smarttalk.fileShowName', params.fileShowName) + + // 消息监听ws + // console.log('监听器已开启', ChatWs) + if (!!ChatWs.ws) { + ChatWs.watch((data, e) => { + try { + handleMessage(JSON.parse(data)?.msg) + } catch (error) { + console.error('socket 解析异常 ', error, e) + handleMessage(data) + } + }) } -} - -// ws消息处理 -const handleMessage = (msg) => { - if (typeof msg === 'object'){ - const { head, content, ...other } = msg - switch (head) { - case MsgEnum.HEADS.MSG_open: // 开课 - // 课堂信息不一致 - if (Classcourse.id !== content.id) { - msgUtils.alertError('老师开课信息异常,请重新进入公屏!') - .then(() => { // 点击确定按钮,关闭窗口 - window.close() - }) - } else { // 正常更新数据 - classcourseStore.classcourse.status = 'open' - // 更新课堂信息-关闭警告框 - Classcourse?.msgObj?.onVanish() - } - break - case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页 - const slideIndex = content.current - slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标 - break - case MsgEnum.HEADS.MSG_closed: // 下课: - window.close() // 关闭窗口 - break - default: - break + + // 更新ppt内容 + const updatePPT = async (data) => { + if (!resource) return + data.id = resource.id + await PPTApi.updateSlide(data) // 更新ppt内容 + sessionStore.set('curr.resource.title', data.title) + // 更新smarttalk内容 + if (!!smarttalk && !!data.title) { + const {id, fileFlag} = smarttalk + const params = { id, fileShowName: `${data.title}.${fileFlag}` } + await PPTApi.updateSmarttalk(params) // 更新ppt内容 + sessionStore.set('curr.smarttalk.fileShowName', params.fileShowName) } } + + // ws消息处理 + const handleMessage = (msg) => { + console.log('ws消息处理', msg) + if (typeof msg === 'object'){ + const { head, content, ...other } = msg + switch (head) { + case MsgEnum.HEADS.MSG_open: // 开课 + // 课堂信息不一致 + if (Classcourse.id !== content.id) { + msgUtils.alertError('老师开课信息异常,请重新进入公屏!') + .then(() => { // 点击确定按钮,关闭窗口 + close() + }) + } else { // 正常更新数据 + classcourseStore.classcourse.status = 'open' + sessionStore.set('curr.classcourse.status', 'open') + // 更新课堂信息-关闭警告框 + Classcourse?.msgObj?.onVanish() + } + break + case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页 + const slideIndex = content.current + slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标 + break + case MsgEnum.HEADS.MSG_homework: // 作业|活动-布置 + if (!content.id) return + Homework.showHomework(content.id) + break + case MsgEnum.HEADS.MSG_closed: // 下课: + close() + break + case MsgEnum.HEADS.MSG_0001: // 点赞 + break + case MsgEnum.HEADS.MSG_0002: // 疑惑 + break + case MsgEnum.HEADS.MSG_0010: // 备用 + break + default: + break + } + } + } + // 关闭窗口 + const close = () => { + ChatWs?.close() // 关闭ws + setTimeout(() => { + window.close() // 关闭窗口 + }, 1000) + } } -// console.log('监听器已开启', Classcourse) -// setTimeout(() => { -// console.log('关闭弹窗') -// // Classcourse.msgObj?.close() -// Classcourse?.msgObj?.onVanish() -// }, 10 * 1000) \ No newline at end of file diff --git a/src/renderer/src/AixPPTist/src/hooks/useScreening.ts b/src/renderer/src/AixPPTist/src/hooks/useScreening.ts index e8cc32a..979b8c4 100644 --- a/src/renderer/src/AixPPTist/src/hooks/useScreening.ts +++ b/src/renderer/src/AixPPTist/src/hooks/useScreening.ts @@ -1,5 +1,6 @@ import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store' import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen' +import ChatWs from '@/plugins/socket' // 聊天socket export default () => { const screenStore = useScreenStore() @@ -23,7 +24,10 @@ export default () => { const classcourse = classcourseStore.classcourse if (!!classcourse) { //DOTO 有课堂,执行退相关操作 console.log('退出放映状态') - window.close() + ChatWs?.close() // 关闭ws + setTimeout(() => { + window.close() // 关闭窗口 + }, 1000) } else screenStore.setScreening(false) if (isFullscreen()) exitFullscreen() } diff --git a/src/renderer/src/plugins/imChat/msgEnum.js b/src/renderer/src/plugins/imChat/msgEnum.js index d685406..b509800 100644 --- a/src/renderer/src/plugins/imChat/msgEnum.js +++ b/src/renderer/src/plugins/imChat/msgEnum.js @@ -94,6 +94,8 @@ export class MsgEnum { MSG_classWorkOfPresentDataUpdate : 'classWorkOfPresentDataUpdate', /** @desc: 课堂讲授活动,选择不同的内容 */ MSG_classlecturePagesrc : 'classlecturePagesrc', + /** @desc: 课堂作业|活动 */ + MSG_homework : 'homework', // === 新定义-消息头 === /** @desc: 课程创建-待开课 */ MSG_0000: 0x0000, diff --git a/src/renderer/src/plugins/socket/index.js b/src/renderer/src/plugins/socket/index.js index e5d3289..5e9870f 100644 --- a/src/renderer/src/plugins/socket/index.js +++ b/src/renderer/src/plugins/socket/index.js @@ -28,6 +28,7 @@ export class ChatWs { const userStore = useUserStore() // 用户信息 const wsBase = import.meta.env.VITE_APP_WS_URL; // ws地址 this.url = `${wsBase||ChatWs.base}/ws/websocket/${userStore.id}`; + this.closed = false; // 关闭状态 防止重连失败 // this.init(url); } ChatWs.instance = this; @@ -38,6 +39,7 @@ export class ChatWs { // 初始化 init(url) { !!url && (this.url = url); + this.closed = false; // 关闭状态 防止重连失败 this.ws = null; const _this = this this.heartCheck = { @@ -64,43 +66,46 @@ export class ChatWs { }, this.timeout); }, }; - this.reconnect(); + return this.reconnect(); } // 重连 reconnect() { - const self = this; - if (!!this.ws) { // 关闭之前的链接 - this.ws.close() - this.ws = null - } - this.ws = new WebSocket(this.url); - this.ws.onopen = function () { - console.log("websocket-连接成功") - self.heartCheck.reset().start(); - }; - this.ws.onmessage = function (e) { - // console.log("websocket-收到消息", e) - // 拿到任何消息都说明当前连接是正常的 - const isBeat = e.data == 'pong' - isBeat && self.heartCheck.reset().start(); - const isEmpty = !e.data - const isExts = e.data.includes('sessionId') || e.data == ('pong') - if (isEmpty || isExts) return; - // 自定义处理 - self.onmessage && self.onmessage(e.data, e); - }; - this.ws.onerror = function (e) { - console.log("websocket-连接异常", e) - self.connectSocket() // 重连 - }; - this.ws.onclose = function (e) { - console.log("websocket-连接断开", e) - self.connectSocket() // 重连 - }; + return new Promise((resolve, reject) => { + const self = this; + if (!!this.ws) { // 关闭之前的链接 + this.ws.close() + this.ws = null + } + this.ws = new WebSocket(this.url); + this.ws.onopen = function () { + console.log("websocket-连接成功") + self.heartCheck.reset().start(); + resolve() + }; + this.ws.onmessage = function (e) { + // console.log("websocket-收到消息", e) + // 拿到任何消息都说明当前连接是正常的 + const isBeat = e.data == 'pong' + isBeat && self.heartCheck.reset().start(); + const isEmpty = !e.data + const isExts = e.data.includes('sessionId') || e.data == ('pong') + if (isEmpty || isExts) return; + // 自定义处理 + self.onmessage && self.onmessage(e.data, e); + }; + this.ws.onerror = function (e) { + console.log("websocket-连接异常", e) + self.connectSocket() // 重连 + }; + this.ws.onclose = function (e) { + console.log("websocket-连接断开", e) + self.connectSocket() // 重连 + }; + }) } connectSocket() { this.heartCheck.reset() // 重置心跳 - if (self.closed) return; // 关闭状态不重连 + if (this.closed) return this.ws = null; // 关闭状态不重连 // if(self.errCount <= 0) return; // 超过重连次数 // self.errCount--; // 重连次数减1 if (this.errTime) { @@ -157,6 +162,16 @@ export class ChatWs { this.closed = true; this.ws.close(); } + // 下课 + closedCourse(id) { + return new Promise((resolve, reject) => { + this.sendMsg('closed', '下课', null, 'group', id) + resolve() + // setTimeout(() => { + // this.close() // 关闭链接 + // }, 1000); + }) + } // 延时 ms 毫秒 sleep(ms){ return new Promise(resolve => setTimeout(resolve, ms)) diff --git a/src/renderer/src/views/classManage/reserv-item-apt.vue b/src/renderer/src/views/classManage/reserv-item-apt.vue index 55a2a51..18caf2a 100644 --- a/src/renderer/src/views/classManage/reserv-item-apt.vue +++ b/src/renderer/src/views/classManage/reserv-item-apt.vue @@ -14,9 +14,8 @@ 上课(APP)