From 5d6c946e0814f86b13cbf6a0a4fe2b1485a2cea8 Mon Sep 17 00:00:00 2001 From: zdg Date: Mon, 16 Dec 2024 17:49:04 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/AixPPTist/src/api/chat.ts | 23 +++++++++++++++++++ src/renderer/src/AixPPTist/src/api/index.ts | 10 +++++++- src/renderer/src/AixPPTist/src/api/watcher.ts | 1 + .../AixPPTist/src/views/Screen/BaseView.vue | 11 +++++++++ .../src/views/Screen/PresenterView.vue | 10 ++++++++ src/renderer/src/plugins/socket/index.js | 3 --- src/renderer/src/utils/tool.js | 2 +- .../src/views/classTask/teachClassTask.vue | 7 +++++- 8 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/renderer/src/AixPPTist/src/api/chat.ts diff --git a/src/renderer/src/AixPPTist/src/api/chat.ts b/src/renderer/src/AixPPTist/src/api/chat.ts new file mode 100644 index 0000000..92a5806 --- /dev/null +++ b/src/renderer/src/AixPPTist/src/api/chat.ts @@ -0,0 +1,23 @@ +/** + * 统一处理消息 发送 避免找不到 + */ + +import ChatWs from '@/plugins/socket' // 聊天socket +import { sessionStore } from '@/utils/store' // electron-store 状态管理 + +export default () => { + const classcourse = sessionStore.get('curr.classcourse') // 课堂信息 + const timgroupid = classcourse?.timgroupid // 群组id + if (!ChatWs.ws) ChatWs.init() + // 下课消息 + const exitCourse = async() => { + if(!timgroupid) throw new Error('未获取到群组ID') + await updateClasscourse({ id: classcourse.id, status: 'closed' }) + return ChatWs.closedCourse(timgroupid) + } + return { + exitCourse, + classcourse, + groupid: timgroupid, + } +} \ No newline at end of file diff --git a/src/renderer/src/AixPPTist/src/api/index.ts b/src/renderer/src/AixPPTist/src/api/index.ts index 685c367..203ba3e 100644 --- a/src/renderer/src/AixPPTist/src/api/index.ts +++ b/src/renderer/src/AixPPTist/src/api/index.ts @@ -258,6 +258,7 @@ export class PPTApi { } export class Homework{ + static win: null // 作业弹窗 // 作业弹窗 static async showHomework(id: any) { let result = await getClassWorkList(id) @@ -265,7 +266,14 @@ export class Homework{   localStorage.setItem('teachClassWorkItem', JSON.stringify(result[0]));   toolStore.isTaskWin=true; // 设置打开批改窗口 //   emit('closeActive') -   createWindow('open-taskwin',{url:'/teachClassTask'}); + // 重复打开,先关闭弹窗 + // if (this.win) this.win?.close?.() + this.win = await createWindow('open-taskwin',{url:'/teachClassTask'}) +  return this.win; + } + static closeHomework() { + if (this.win) this.win?.close?.() + this.win = null } } export default PPTApi \ No newline at end of file diff --git a/src/renderer/src/AixPPTist/src/api/watcher.ts b/src/renderer/src/AixPPTist/src/api/watcher.ts index f5d91cb..d4cea21 100644 --- a/src/renderer/src/AixPPTist/src/api/watcher.ts +++ b/src/renderer/src/AixPPTist/src/api/watcher.ts @@ -122,4 +122,5 @@ export default () => { window.close() // 关闭窗口 }, 1000) } + } diff --git a/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue b/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue index ae2add1..c8ef0b3 100644 --- a/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue +++ b/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue @@ -52,6 +52,7 @@ + @@ -74,6 +75,7 @@ import WritingBoardTool from './WritingBoardTool.vue' import CountdownTimer from './CountdownTimer.vue' import upvoteVue from '@/views/tool/components/upvote.vue' // 点赞-子组件 import emitter from '@/utils/mitt'; +import Chat from '../../api/chat' // 聊天 const props = defineProps<{ changeViewMode: (mode: 'base' | 'presenter') => void @@ -103,6 +105,7 @@ const { const { slideWidth, slideHeight } = useSlideSize() const { exitScreening } = useScreening() const { fullscreenState, manualExitFullscreen } = useFullscreen() +const chat:any = Chat() // 聊天室 const rightToolsVisible = ref(false) const writingBoardToolVisible = ref(false) @@ -192,6 +195,14 @@ const contextmenus = (): ContextmenuItem[] => { }, ] } + +// 下课 +const exitCourse = async () => { + // console.log('下课', chat) + await chat.exitCourse() // 下课消息 + exitScreening() // 结束放映 +} + // 打开点赞或者疑问 1点赞 2疑问 emitter.on('upvoteTrigger', (type) => { upvoteRef.value?.trigger(type) diff --git a/src/renderer/src/AixPPTist/src/views/Screen/PresenterView.vue b/src/renderer/src/AixPPTist/src/views/Screen/PresenterView.vue index 4d2076d..aabc72a 100644 --- a/src/renderer/src/AixPPTist/src/views/Screen/PresenterView.vue +++ b/src/renderer/src/AixPPTist/src/views/Screen/PresenterView.vue @@ -12,6 +12,7 @@
结束放映
+
结束课堂
@@ -94,6 +95,7 @@ import ScreenSlideList from './ScreenSlideList.vue' import WritingBoardTool from './WritingBoardTool.vue' import CountdownTimer from './CountdownTimer.vue' import Divider from '../../components/Divider.vue' +import Chat from '../../api/chat' // 聊天 const props = defineProps<{ changeViewMode: (mode: 'base' | 'presenter') => void @@ -122,12 +124,20 @@ const { slideWidth, slideHeight } = useSlideSize(slideListWrapRef) const { exitScreening } = useScreening() const { slidesLoadLimit } = useLoadSlides() const { fullscreenState, manualExitFullscreen } = useFullscreen() +const chat:any = Chat() // 聊天室 const remarkFontSize = ref(16) const currentSlideRemark = computed(() => { return parseText2Paragraphs(currentSlide.value.remark || '无备注') }) +// 下课 +const exitCourse = async () => { + // console.log('下课', chat) + await chat.exitCourse() // 下课消息 + exitScreening() // 结束放映 +} + const handleMousewheelThumbnails = (e: WheelEvent) => { if (!thumbnailsRef.value) return thumbnailsRef.value.scrollBy(e.deltaY, 0) diff --git a/src/renderer/src/plugins/socket/index.js b/src/renderer/src/plugins/socket/index.js index 5e9870f..5d9cd6c 100644 --- a/src/renderer/src/plugins/socket/index.js +++ b/src/renderer/src/plugins/socket/index.js @@ -167,9 +167,6 @@ export class ChatWs { return new Promise((resolve, reject) => { this.sendMsg('closed', '下课', null, 'group', id) resolve() - // setTimeout(() => { - // this.close() // 关闭链接 - // }, 1000); }) } // 延时 ms 毫秒 diff --git a/src/renderer/src/utils/tool.js b/src/renderer/src/utils/tool.js index 02aeae2..9673f11 100644 --- a/src/renderer/src/utils/tool.js +++ b/src/renderer/src/utils/tool.js @@ -225,7 +225,7 @@ export const createWindow = async (type, data) => { .filter(k => typeof data[k] === 'function') .forEach(k => events[k] = data[k]) eventHandles(type, win, events) // 事件监听处理 - break + return win } default: break diff --git a/src/renderer/src/views/classTask/teachClassTask.vue b/src/renderer/src/views/classTask/teachClassTask.vue index 3db91ae..83b5ec9 100644 --- a/src/renderer/src/views/classTask/teachClassTask.vue +++ b/src/renderer/src/views/classTask/teachClassTask.vue @@ -163,8 +163,10 @@ import quizStats from '@/views/classTask/container/quizStats.vue' import ClassOverview from '@/views/classTask/container/classOverview.vue' import {sessionStore} from '@/utils/store' // import Chat from '@/utils/chat' // im 登录初始化 +import { Homework } from '@/AixPPTist/src/api/index' import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举 import ChatWs from '@/plugins/socket' // 聊天socket +import { set } from 'lodash' if (!ChatWs.ws) ChatWs.init() const { proxy } = getCurrentInstance() const emit = defineEmits(['cle-click']) @@ -719,14 +721,17 @@ const msgHandle = (msg) => { const { head, content, ...other } = msg switch(head) { case MsgEnum.HEADS.MSG_closed: // 下课: + Homework.win = null window.close() // 关闭窗口 break case MsgEnum.HEADS.MSG_finishHomework: // 跟新作业: + console.log('更新作业', head, content) const data = JSON.parse(localStorage.getItem('teachClassWorkItem')); openDialog(data, false); break case MsgEnum.HEADS.MSG_slideFlapping: // 切换页面 console.log('切换页面-关闭窗口') + Homework.win = null window.close() // 关闭窗口 break // case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[] @@ -769,7 +774,7 @@ onMounted(() => { console.log('socket监听消息') ChatWs.watch((msg, e) => { try { - msgHandle(JSON.parse(msg)) + msgHandle(JSON.parse(msg)?.msg) } catch (error) { console.error('socket 解析异常 ', error, e) msgHandle(msg) From d6dfe966c07995a02b0f9d3c975e33b7c4492177 Mon Sep 17 00:00:00 2001 From: zhangxuelin <959231531@qq.com> Date: Tue, 17 Dec 2024 10:26:41 +0800 Subject: [PATCH 2/8] =?UTF-8?q?pptist=20=E6=AF=94=E4=BE=8B=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/AixPPTist/src/api/watcher.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/AixPPTist/src/api/watcher.ts b/src/renderer/src/AixPPTist/src/api/watcher.ts index f5d91cb..236c0e8 100644 --- a/src/renderer/src/AixPPTist/src/api/watcher.ts +++ b/src/renderer/src/AixPPTist/src/api/watcher.ts @@ -23,7 +23,6 @@ export default () => { const resource = sessionStore.get('curr.resource') // apt 资源 const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源 const execPlay = useExecPlay() // 播放控制 - // 监听幻灯片内容变化 watch(() => slidesStore.slides, (newVal, oldVal) => { PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容 @@ -39,7 +38,14 @@ export default () => { watch(() => slidesStore.slideIndex, (newVal, oldVal) => { PPTApi.updateWorkList() }) - + // 监听幻灯片下画布尺寸比例变化 + watch(() => slidesStore.viewportRatio, (newVal, oldVal) => { + const width = slidesStore.viewportSize + const widthandration={width, ratio:newVal} + const data = { id: resource.id, parentContent: JSON.stringify(widthandration)} + PPTApi.updateSlide(data) + }) + // 消息监听ws // console.log('监听器已开启', ChatWs) if (!!ChatWs.ws) { From c01a29bf3fa72977d0e392db436a02cbdf7bda72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E4=BA=86=E4=B8=AA=E7=99=BD?= <543593352@qq.com> Date: Tue, 17 Dec 2024 17:20:30 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E4=B9=A0=E9=A2=98=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=EF=BC=9A=E6=89=AB=E6=8F=8F=E8=AF=86=E5=88=ABurl=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../questionUpload/ocrImg2ExamQues.js | 196 ++++++++++-------- 1 file changed, 105 insertions(+), 91 deletions(-) diff --git a/src/renderer/src/views/classTask/newClassTaskAssign/questionUpload/ocrImg2ExamQues.js b/src/renderer/src/views/classTask/newClassTaskAssign/questionUpload/ocrImg2ExamQues.js index 5e72245..b3a8c7a 100644 --- a/src/renderer/src/views/classTask/newClassTaskAssign/questionUpload/ocrImg2ExamQues.js +++ b/src/renderer/src/views/classTask/newClassTaskAssign/questionUpload/ocrImg2ExamQues.js @@ -1,6 +1,7 @@ import { ElMessageBox, ElMessage } from "element-plus"; import qs from "qs"; import axios from 'axios' +import request from '@/utils/request' import { pyOCRAPI } from "@/api/education/entpcoursework"; @@ -9,13 +10,20 @@ const baidubceConfig = { // Header 'Content-Type': "application/x-www-form-urlencoded", // 格式 - 'Accept' : 'application/json', + 'Accept': 'application/json', // id(临时测试) 'client_id': "U0DrGBE6X92IXgV6cJMNON8F", // 密钥(临时测试) 'client_secret': 'oWb0M0YWMmZPMQIhIUkJX99ddr7h61qf', }; +export function getOcrContent(data) { + return request({ + url: '/ocr/exam', + method: 'post', + data: data + }) +} /** @@ -34,8 +42,8 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' let regex = null; // 识别内容拼接 let ocrTxt = '' - - if(isLocalTest) { + + if (isLocalTest) { // 临时本地测试(json格式跟百度ocr一致) const response = await fetch('/cropImgTest/single.json'); const resOcr = await response.json(); @@ -59,7 +67,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' } else { const tmp = await ocrImg2Json(imgBase64); - if(!tmp?.data) { + if (!tmp?.data) { return examItem; } ocrJson = tmp.data.results; @@ -69,12 +77,12 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' }); } - if(ocrJson == '') { + if (ocrJson == '') { ElMessage.error('[人工录入-单项]识别的图片为空, 识别失败, 请检查重试!'); return examItem; } - if(ocrTxt == '') { + if (ocrTxt == '') { ElMessage.error('[人工录入-单项]识别内容拼接失败, 请检查重试!'); return examItem; } @@ -87,7 +95,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' ocrTxt = ocrTxt.replace(regex, '').replace(/
/g, ''); examItem = ocrTxt; } - else if (curItem === 'workdesc') { + else if (curItem === 'workdesc') { // 该类型下无需[判断题]和[主观题]处理 if (examType.includes('复合题')) { // 因[题目+选项]分离正则匹配需要, 故需开头手动拼一个
@@ -96,13 +104,13 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' worktype: '单选题', params: [], } - mutiParams.arrWorkDesc.forEach( item => { + mutiParams.arrWorkDesc.forEach(item => { const obj = { title: item.title, workanswer: '', checkAnswer: [], type: item.type, - options: item.options.map(element => {return {text: element.replace(/
/g, '')}}), + options: item.options.map(element => { return { text: element.replace(/
/g, '') } }), } examItem.params.push(obj); }); @@ -114,7 +122,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' // 先判断是否存在选项标识, 且存在2个及以上(A.---1.---(1)---(1)) regex = /\s*[A-H][..。]/g; const matches = ocrTxt.match(regex); - if (matches==null || matches.length < 2){ + if (matches == null || matches.length < 2) { ElMessage.error('[人工录入-单项]识别[选项]失败, 请检查重试!'); return examItem; } @@ -138,7 +146,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = '' examItem.push(obj); return examItem; } - + } else if (curItem === 'workanswer') { // 该类型下只做[主观题]和[复合题]的处理 @@ -163,8 +171,8 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = '' let ocrJson = ''; // 识别内容拼接 let ocrTxt = ''; - - if(isLocalTest) { + + if (isLocalTest) { // 临时本地测试(json格式跟百度ocr一致) const response = await fetch('/cropImgTest/single.json'); const resOcr = await response.json(); @@ -173,7 +181,7 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = '' ocrJson.forEach(ele => { ocrTxt += `${ele.words.word}
`; }); - + //-------------------------------------------------------------- // 备用ocr识别服务 (python的一个识别服务) // const response = await ocrImgPyJson(imgBase64); @@ -186,7 +194,7 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = '' // }); } else { const tmp = await ocrImg2Json(imgBase64); - if(!tmp?.data) { + if (!tmp?.data) { return examQues; } ocrJson = tmp.data.results; @@ -195,20 +203,20 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = '' }); } - if(ocrJson == '') { + if (ocrJson == '') { ElMessage.error('[人工录入-整题]图片识别内容为空, 识别失败, 请重试!'); return examQues; } - - if(ocrTxt == '') { + + if (ocrTxt == '') { ElMessage.error('[人工录入-整题]识别内容拼接失败, 请重试!'); return examQues; } // 识别内容转为试题结构 examQues = assembleExam(ocrTxt); - if(examQues.err != '') { + if (examQues.err != '') { ElMessage.error(`[人工录入-整题]${examQues.err}, 请重试!`); examQues = {}; } @@ -226,30 +234,36 @@ const ocrImg2Json = async (urlBase64) => { ElMessage.error("未检测到截图图片, 请截取图片后再识别"); return null; } - const resToken = await bdyAPI_getToken(); - if (resToken.status !== 200) { - ElMessage.error("百度智能云用户标识有误"); - return null; - } - - const token = resToken.data?.access_token; let base64Code = urlBase64.split(",")[1]; - const query = { - image: base64Code, //图片地址(base64) - line_probability: false, //是否返回每行识别结果的置信度。默认为false - disp_line_poly: false, //是否返回每行的四角点坐标。默认为false - words_type: 'handprint_mix', //文字类型。 默认:印刷文字识别 = handwring_only:手写文字识别 = handprint_mix: 手写印刷混排识别 - layout_analysis: false, //是否分析文档版面:包括layout(图、表、标题、段落、目录);attribute(栏、页眉、页脚、页码、脚注)的分析输出 - recg_long_division: false, //是否检测并识别手写竖式 - recg_formula: true, //控制是否检测并识别公式,默认为false - } - - - const resOcr = await bdyAPI_getOcrContent(token, base64Code, query); - if (resOcr.status !== 200) { - ElMessage.error("百度智能云图片识别错误"); + const resOcr = await getOcrContent({ base64Code: base64Code }); + if (resOcr.code !== 200) { + ElMessage.error("图片识别错误"); return null; } + // const resToken = await bdyAPI_getToken(); + // if (resToken.status !== 200) { + // ElMessage.error("百度智能云用户标识有误"); + // return null; + // } + + // const token = resToken.data?.access_token; + // let base64Code = urlBase64.split(",")[1]; + // const query = { + // image: base64Code, //图片地址(base64) + // line_probability: false, //是否返回每行识别结果的置信度。默认为false + // disp_line_poly: false, //是否返回每行的四角点坐标。默认为false + // words_type: 'handprint_mix', //文字类型。 默认:印刷文字识别 = handwring_only:手写文字识别 = handprint_mix: 手写印刷混排识别 + // layout_analysis: false, //是否分析文档版面:包括layout(图、表、标题、段落、目录);attribute(栏、页眉、页脚、页码、脚注)的分析输出 + // recg_long_division: false, //是否检测并识别手写竖式 + // recg_formula: true, //控制是否检测并识别公式,默认为false + // } + + + // const resOcr = await bdyAPI_getOcrContent(token, base64Code, query); + // if (resOcr.status !== 200) { + // ElMessage.error("百度智能云图片识别错误"); + // return null; + // } return resOcr; } @@ -264,7 +278,7 @@ const ocrImgPyJson = async (urlBase64) => { ElMessage.error("未检测到截图图片, 请截取图片后再识别"); return null; } - + const resOcr = await pyOCRAPI(urlBase64); if (resOcr.status !== 200) { ElMessage.error("图片识别错误"); @@ -351,7 +365,7 @@ const assembleExam = (eachSub) => { let regex = null; let titleAndWorkDesc = '', - answer = ''; + answer = ''; // 获取[题源] - 格式化 @@ -361,7 +375,7 @@ const assembleExam = (eachSub) => { subObj.worktag = workTag[0].replace(/^\d*[..。]/g, ''); subObj.worktag = subObj.worktag.replace('(', '(').replace(')', ')'); } - + // 去掉开头的序号和题源 eachSub = eachSub.replace(regex, ''); // 先判断是否存在答案 @@ -370,7 +384,7 @@ const assembleExam = (eachSub) => { if (!hasAnswer) { // 不存在答案, 仅处理[题干+选项] titleAndWorkDesc = eachSub; - }else { + } else { // 存在答案, 需处理[题干+选项]和[答案+解析] regex = /(
?\s*[【\[].*?[】\]])/g; let tmpList = eachSub.split(regex); @@ -386,10 +400,10 @@ const assembleExam = (eachSub) => { // 第二部分[分析-答案] 处理 let answerAndAnswer = {}; // 将第二部分的内容做key-value绑定 - 键为【分析】、【讨论】、【方法】等. 值为随之分隔的内容 - for (let i=1; i|【|】|\[|\]/g, ''); - let value = tmpList[i+1]; + let value = tmpList[i + 1]; value = value.replace(/^
+|
+$/g, ''); answerAndAnswer[key] = value; } @@ -430,12 +444,12 @@ const assembleExam = (eachSub) => { // [答案] - 初步初始化 --- 根据答案判断试题大分类: 复合题(实际为大题) 或 其他基础题型(单选,多选,填空,判断) answer = answerAndAnswer['答案'].trim(); - if(!answer) { + if (!answer) { answer = answerAndAnswer['答案及评分参考'].trim(); answer = answer.replace(/^\d+[\u4e00-\u9fa5][..。]\s*
/, ''); // 去掉 - 有些开头会有[xx分。] } // 将多余的空格替换为固定的4个空格 - answer = answer.replaceAll("\\s{3,}"," "); + answer = answer.replaceAll("\\s{3,}", " "); if (answer == null | answer == '') { subObj.err = '题目缺少[答案]'; return subObj; @@ -455,7 +469,7 @@ const assembleExam = (eachSub) => { let answerFind = regex.test(answer); regex = /(\d+[..。]|\(\d+\)|(\d+))/; let titleFind = regex.test(titleAndWorkDesc); - if(titleFind && answerFind){ + if (titleFind && answerFind) { /** * [复合题] - 处理逻辑 */ @@ -471,7 +485,7 @@ const assembleExam = (eachSub) => { if (tmpExam) { // 错误信息 - if(tmpExam.errMsg !== '') { + if (tmpExam.errMsg !== '') { subObj.err = tmpExam.err; return subObj; } @@ -484,7 +498,7 @@ const assembleExam = (eachSub) => { subObj.workanswer = JSON.stringify(tmpExam.arrWorkAnswer); } } - + return subObj; } @@ -508,7 +522,7 @@ const processExamSingle = function (titleAndWorkDesc, answer) { let matcher = null; /** [判断题]的处理逻辑, resp: -1-未找到 0-*为对应匹配的index */ - let judgedStatus = answer!=='' ? containsExactMatch(answer) : -1; + let judgedStatus = answer !== '' ? containsExactMatch(answer) : -1; /** 其他基础题型(单选,多选,填空,判断)的处理逻辑 */ // 先去掉开头的试题序号 @@ -524,7 +538,7 @@ const processExamSingle = function (titleAndWorkDesc, answer) { answer = answer.replace("
", "").trim(); // [题型] - 格式化 - 根据答案字符个数区分[单选]或[多选] - examSingle.workType = answer==='' ? '单选题' : answer.length == 1 ? "单选题" : "多选题"; + examSingle.workType = answer === '' ? '单选题' : answer.length == 1 ? "单选题" : "多选题"; // 切分题干+选项 regex = /
*\s*[A-H][..。]/g; @@ -535,12 +549,12 @@ const processExamSingle = function (titleAndWorkDesc, answer) { // [选项]-处理 --- ['ABC123','ABC123'] for (let i = 1; i < tmpSplit.length; i++) { - let option = tmpSplit[i].replace("
", "").trim(); - //option = option.replace("_", ""); - // [选项] - 格式化 - examSingle.arrWorkDesc.push(option); + let option = tmpSplit[i].replace("
", "").trim(); + //option = option.replace("_", ""); + // [选项] - 格式化 + examSingle.arrWorkDesc.push(option); } - + // [题目答案] --- ['0'] | ['0','1'] if (answer !== '') { // 答案为空时, 置空后直接返回 @@ -570,7 +584,7 @@ const processExamSingle = function (titleAndWorkDesc, answer) { examSingle.arrWorkAnswer = answer.split(" "); } } - else if( judgedStatus != -1 ) { + else if (judgedStatus != -1) { /** * 判断题 */ @@ -635,48 +649,48 @@ const processExamMulti = function (titleAndWorkDesc, answer) { // 先确定当前是以什么形式的小题序号来切分 --- 需要全部独立判断, 避免出现复合题中, 每小题内还包含小题的情况--- 1.回答以下问题 (1)***** (2)****** let cliceSucc = false; let arrAnswer = [] - if(!cliceSucc){ + if (!cliceSucc) { regex = /
\s*\d+[..。]\s*/; if (regex.test(titleAndWorkDesc)) { // 再次以答案中的序号同步匹配一次 regex = /^\s*\d+[..。]\s*/; - if(answer === '' || regex.test(answer)){ - regex = /
\s*\d+[..。]\s*/g; - tmpSplit = titleAndWorkDesc.split(regex); - if (answer !== '') { - // 存在答案时, 再校验 - regex = /^\s*\d+[..。]\s*|
\s*\d+[..。]\s*|\s+\d+[..。]\s*/g; - arrAnswer = answer.split(regex); - } + if (answer === '' || regex.test(answer)) { + regex = /
\s*\d+[..。]\s*/g; + tmpSplit = titleAndWorkDesc.split(regex); + if (answer !== '') { + // 存在答案时, 再校验 + regex = /^\s*\d+[..。]\s*|
\s*\d+[..。]\s*|\s+\d+[..。]\s*/g; + arrAnswer = answer.split(regex); + } - cliceSucc = true; + cliceSucc = true; } } } - if (!cliceSucc){ + if (!cliceSucc) { regex = /
\s*(\d+)\s*/; if (regex.test(titleAndWorkDesc)) { // 再次以答案中的序号同步匹配一次 regex = /\s*(\d+)\s*/; - if(answer === '' || regex.test(answer)){ - regex = /
\s*(\d+)\s*/g; - tmpSplit = titleAndWorkDesc.split(regex); - if (answer !== '') { - // 存在答案时, 再校验 - regex = /^\s*(\d+)\s*|
\s*(\d+)\s*|\s+(\d+)\s*/g; - arrAnswer = answer.split(regex); - } + if (answer === '' || regex.test(answer)) { + regex = /
\s*(\d+)\s*/g; + tmpSplit = titleAndWorkDesc.split(regex); + if (answer !== '') { + // 存在答案时, 再校验 + regex = /^\s*(\d+)\s*|
\s*(\d+)\s*|\s+(\d+)\s*/g; + arrAnswer = answer.split(regex); + } - cliceSucc = true; + cliceSucc = true; } } } - if (!cliceSucc){ + if (!cliceSucc) { regex = /
\s*\(\d+\)\s*/; if (regex.test(titleAndWorkDesc)) { // 再次以答案中的序号同步匹配一次 regex = /^\s*\(\d+\)\s*/; - if(answer === '' || regex.test(answer)){ + if (answer === '' || regex.test(answer)) { regex = /
\s*\(\d+\)\s*/g; tmpSplit = titleAndWorkDesc.split(regex); if (answer !== '') { @@ -689,19 +703,19 @@ const processExamMulti = function (titleAndWorkDesc, answer) { } } } - if (!cliceSucc){ + if (!cliceSucc) { examMulti.errMsg = '[复合题]小题与答案序号[不匹配]'; return examMulti; } - if (tmpSplit.length < 2){ + if (tmpSplit.length < 2) { examMulti.errMsg = '[复合题]题干与小题[切分失败]'; return examMulti; } - if (answer !== '' && arrAnswer.length < 2){ + if (answer !== '' && arrAnswer.length < 2) { examMulti.errMsg = '[复合题]答案切分小题失败'; return examMulti; } - if (answer !== '' && tmpSplit.length != arrAnswer.length){ + if (answer !== '' && tmpSplit.length != arrAnswer.length) { examMulti.errMsg = '[复合题]小题个数与答案个数[不一致]'; return examMulti; } @@ -710,13 +724,13 @@ const processExamMulti = function (titleAndWorkDesc, answer) { examMulti.title = tmpSplit[0].trim(); // [选项]+[答案] - 逻辑处理 - for (let i=1; i Date: Tue, 17 Dec 2024 17:20:53 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E7=AE=A1=E7=90=86?= =?UTF-8?q?=EF=BC=9A=E4=B9=A0=E9=A2=98=E4=B8=8A=E4=BC=A0=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/router/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/router/index.js b/src/renderer/src/router/index.js index 470b3b9..7c1b13a 100644 --- a/src/renderer/src/router/index.js +++ b/src/renderer/src/router/index.js @@ -83,7 +83,7 @@ export const constantRoutes = [ path: 'questionUpload', component: () => import('@/views/classTask/newClassTaskAssign/questionUpload/index.vue'), name: 'questionUpload', - meta: { title: '习题上传' } + meta: { title: '习题上传', showBread: true } }, { path: 'aiKolors', From 0d38a1209478e55ace242a736f166db21f0b45df Mon Sep 17 00:00:00 2001 From: zdg Date: Tue, 17 Dec 2024 17:34:47 +0800 Subject: [PATCH 5/8] ppt --- src/renderer/src/AixPPTist/src/api/chat.ts | 3 +- .../src/AixPPTist/src/api/classcourse.ts | 29 ++++++--- src/renderer/src/AixPPTist/src/api/watcher.ts | 7 ++- .../AixPPTist/src/views/Screen/BaseView.vue | 60 +++++++++++-------- .../src/views/Screen/PresenterView.vue | 19 ++++-- .../src/views/Screen/hooks/useExecPlay.ts | 22 +++++-- .../src/views/classManage/reserv-item-apt.vue | 6 +- 7 files changed, 95 insertions(+), 51 deletions(-) diff --git a/src/renderer/src/AixPPTist/src/api/chat.ts b/src/renderer/src/AixPPTist/src/api/chat.ts index 92a5806..6cf016e 100644 --- a/src/renderer/src/AixPPTist/src/api/chat.ts +++ b/src/renderer/src/AixPPTist/src/api/chat.ts @@ -4,6 +4,7 @@ import ChatWs from '@/plugins/socket' // 聊天socket import { sessionStore } from '@/utils/store' // electron-store 状态管理 +import * as API_classcourse from '@/api/teaching/classcourse' // 后端api export default () => { const classcourse = sessionStore.get('curr.classcourse') // 课堂信息 @@ -12,7 +13,7 @@ export default () => { // 下课消息 const exitCourse = async() => { if(!timgroupid) throw new Error('未获取到群组ID') - await updateClasscourse({ id: classcourse.id, status: 'closed' }) + await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'closed' }) return ChatWs.closedCourse(timgroupid) } return { diff --git a/src/renderer/src/AixPPTist/src/api/classcourse.ts b/src/renderer/src/AixPPTist/src/api/classcourse.ts index e513f3c..7e7e3c3 100644 --- a/src/renderer/src/AixPPTist/src/api/classcourse.ts +++ b/src/renderer/src/AixPPTist/src/api/classcourse.ts @@ -7,13 +7,13 @@ import { sessionStore } from '@/utils/store' // electron-store 状态管理 import * as useStore from '../store' // pptist-状态管理 import ChatWs from '@/plugins/socket' // 聊天socket import msgUtils from '@/plugins/modal' // 消息工具 -import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制 +import emitter from '@/utils/mitt' //mitt 事件总线 +import { nextTick } from 'vue' const slidesStore = useStore.useSlidesStore() // 幻灯片-状态管理 const screenStore = useStore.useScreenStore() // 全屏-状态管理 const classcourseStore = useStore.useClasscourseStore() // 课堂信息-状态管理 const classcourse = sessionStore.get('curr.classcourse') // 课堂信息 -const execPlay = useExecPlay() // 播放控制 export class Classcourse { msgObj:ElMessageBox = null // 提示消息对象 @@ -23,10 +23,12 @@ export class Classcourse { constructor() { this.load() } + // 延时 + sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) /** * @description 加载 */ - load() { + async load() { console.log('classcourse-load', classcourse) // 打开全屏 const isCourse = !!classcourse @@ -39,13 +41,22 @@ export class Classcourse { this.classcourse = classcourse // 课堂信息 this.id = classcourse.id // 课堂id // 如果课堂信息有paging,则更新当前页码 - const isPaging = !!classcourse.paging - if (isPaging) slidesStore.updateSlideIndex(classcourse.paging) + const { paging } = classcourse + const isPaging = !!paging || paging === 0 + if (isPaging) { + console.log('更新当前页码', paging) + await this.sleep(200) + emitter.emit('useExecPlay', {key:'turnSlideToIndex', paging}) + await this.sleep(1000) // 如果课堂信息有paging,则更新动画播放状态 - const isAnim = !!classcourse.cartoonTimes - if (isAnim) { // 动画播放 - for (let i = 0; i <= classcourse.cartoonTimes; i++) { - execPlay.runAnimation(true) // 异步执行动画 + const isAnim = !!classcourse.cartoonTimes + if (isAnim) { // 动画播放 + console.log('动画播放1', classcourse) + for (let i = 0; i < classcourse.cartoonTimes; i++) { + console.log('动画播放2', i) + // 异步执行动画 + emitter.emit('useExecPlay', {key:'execNext', isAsync:true}) + } } } // 课堂信息-状态管理 diff --git a/src/renderer/src/AixPPTist/src/api/watcher.ts b/src/renderer/src/AixPPTist/src/api/watcher.ts index d4cea21..ef9f65f 100644 --- a/src/renderer/src/AixPPTist/src/api/watcher.ts +++ b/src/renderer/src/AixPPTist/src/api/watcher.ts @@ -37,7 +37,8 @@ export default () => { // 监听幻灯片下标变化 watch(() => slidesStore.slideIndex, (newVal, oldVal) => { - PPTApi.updateWorkList() + if (!!Classcourse.id) return // 上课状态,不更新右侧作业列表 + PPTApi.updateWorkList() // 更新作业列表 }) // 消息监听ws @@ -91,7 +92,8 @@ export default () => { case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页 const slideIndex = content?.current || 0 const type = content?.animation - if (type === 'Nextsteps') emitter.emit('useExecPlay', 'execNext') // 下一步 + // if (type === 'Nextsteps') emitter.emit('useExecPlay', 'execNext') // 下一步 + if (type === 'Nextsteps') emitter.emit('useExecPlay', {key:'execNext', isAsync:true}) // 下一步 else if (type === 'Previoustep') emitter.emit('useExecPlay', 'turnPrevSlide') // 上一步清空-动画 else slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标 break @@ -122,5 +124,4 @@ export default () => { window.close() // 关闭窗口 }, 1000) } - } diff --git a/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue b/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue index c8ef0b3..fc4940a 100644 --- a/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue +++ b/src/renderer/src/AixPPTist/src/views/Screen/BaseView.vue @@ -52,7 +52,7 @@ - +
@@ -61,7 +61,7 @@