diff --git a/electron.vite.config.mjs b/electron.vite.config.mjs index 962bf8f..fb25549 100644 --- a/electron.vite.config.mjs +++ b/electron.vite.config.mjs @@ -33,6 +33,7 @@ export default defineConfig({ proxy: { '/dev-api': { target: 'http://27.128.240.72:7865', + // target: 'https://prev.ysaix.com:7868/prod-api/', // target: 'http://36.134.181.164:7863', // target: 'http://192.168.0.102:7865', changeOrigin: true, diff --git a/package.json b/package.json index 21aff1b..f861a30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aix-win-ws", - "version": "2.5.5", + "version": "2.5.6", "description": "", "main": "./out/main/index.js", "author": "上海交大重庆人工智能研究院", diff --git a/src/renderer/src/AixPPTist/src/App.vue b/src/renderer/src/AixPPTist/src/App.vue index c06919f..74c4b73 100644 --- a/src/renderer/src/AixPPTist/src/App.vue +++ b/src/renderer/src/AixPPTist/src/App.vue @@ -28,8 +28,8 @@ 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 watcher from './api/watcher' // 监听 +import emitter from '@/utils/mitt' //mitt 事件总线 watcher() // 监听启动 const loading = ref(true) const _isPC = isPC() @@ -74,6 +74,8 @@ const initLoad: Function = () => { !!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// 有比例配置项 } return PPTApi.getSlideList(resource.id) + // PPTApi.updateWorkList() + // return Promise.resolve() } return Promise.resolve() } diff --git a/src/renderer/src/AixPPTist/src/api/classcourse.ts b/src/renderer/src/AixPPTist/src/api/classcourse.ts index 30e65e8..e513f3c 100644 --- a/src/renderer/src/AixPPTist/src/api/classcourse.ts +++ b/src/renderer/src/AixPPTist/src/api/classcourse.ts @@ -7,11 +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' // 播放控制 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 // 提示消息对象 @@ -27,17 +29,25 @@ export class Classcourse { load() { console.log('classcourse-load', classcourse) // 打开全屏 - screenStore.setScreening(!!classcourse) + const isCourse = !!classcourse + screenStore.setScreening(isCourse) // 如果课堂信息有值,则连接socket - if (!!classcourse) { + if (isCourse) { // 连接socket if (!ChatWs.ws) ChatWs.init() ChatWs.id = classcourse.timgroupid // 群组id this.classcourse = classcourse // 课堂信息 this.id = classcourse.id // 课堂id // 如果课堂信息有paging,则更新当前页码 - const isPaging = !!classcourse.paging||classcourse.paging==0 + const isPaging = !!classcourse.paging if (isPaging) slidesStore.updateSlideIndex(classcourse.paging) + // 如果课堂信息有paging,则更新动画播放状态 + const isAnim = !!classcourse.cartoonTimes + if (isAnim) { // 动画播放 + for (let i = 0; i <= classcourse.cartoonTimes; i++) { + execPlay.runAnimation(true) // 异步执行动画 + } + } // 课堂信息-状态管理 classcourseStore.setClasscourse(classcourse) // 待上课提示 diff --git a/src/renderer/src/AixPPTist/src/api/index.ts b/src/renderer/src/AixPPTist/src/api/index.ts index 611efb6..685c367 100644 --- a/src/renderer/src/AixPPTist/src/api/index.ts +++ b/src/renderer/src/AixPPTist/src/api/index.ts @@ -3,16 +3,18 @@ * @author zdg * @date 2024-11-26 */ -import { toRaw } from 'vue' +import { toRaw, nextTick } from 'vue' import type { Result } from './types' // 接口类型 import msgUtils from '@/plugins/modal' // 消息工具 import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api import * as API_smarttalk from '@/api/file' // 相关api +import * as API_classwork from '@/api/teaching/classwork' // 相关api import * as useStore from '../store' // pptist-状态管理 import { sessionStore } from '@/utils/store' // electron-store 状态管理 import useUserStore from '@/store/modules/user' // 外部-用户信息 import * as Api_server from '@/api/apiService' // 相关api -import * as commUtils from '@/utils/comm.js' +import * as commUtils from '@/utils/comm.js' // 工具 +import { toPng, toJpeg } from 'html-to-image' // 引入html-to-image库 const slidesStore = useStore.useSlidesStore() const userStore = useUserStore() @@ -55,30 +57,34 @@ export class PPTApi { // 变量 static isUpdate = true // 是否更新数据 - // 获取所有幻灯片列表 - static getSlideList(parentid: (Number | String)): Promise { + // 获取所有幻灯片列表 isUpdate为true不更新 + static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise { return new Promise(async (resolve, reject) => { const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 } const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params) - if (res.code === 200) { - const slides = (res.rows || []).map(o => { - if (!!o.datacontent) { - const json = JSON.parse(o.datacontent) - !!json && (json.id = o.id) - return json - } - // 如果没有数据,默认空白页 - return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}} - }) + if (res.code === 200) { + if(!isUpdate){ + const slides = (res.rows || []).map(o => { + if (!!o.datacontent) { + const json = JSON.parse(o.datacontent) + !!json && (json.id = o.id) + return json + } + // 如果没有数据,默认空白页 + return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}} + }) + // slidesStore.updateSlideIndex(0) // 下标0 为第一页 + slidesStore.setSlides(slides) // 写入数据 + } // 活动列表处理 - const workList = (res.rows || []).map(o => o.activityContent) - const workItem = [...res.rows] - // slidesStore.updateSlideIndex(0) // 下标0 为第一页 - slidesStore.setSlides(slides) // 写入数据 + // const workList = (res.rows || []).map(o => o.activityContent) + const workItem = res.rows ? [...res.rows] : [] // 写入作业列表数据 - slidesStore.setWorkList(workList) + // slidesStore.setWorkList(workList) // 获取所有的pptlist的数据 slidesStore.setWorkItem(workItem) + + this.updateWorkList() resolve(true) } else msgUtils.msgError(res.msg || '获取数据失败');resolve(false) }) @@ -111,7 +117,6 @@ export class PPTApi { data.id = rid slidesStore.updateSlide(data) // msgUtils.msgSuccess('新增成功') - PPTApi.getSlideList(resource.id) this.isUpdate = false // 新增后会触发监听,不再更新数据 resolve(true) } else msgUtils.msgError('新增失败');resolve(false) @@ -132,21 +137,34 @@ export class PPTApi { const currentSlide = toRaw(slidesStore.currentSlide) const isAdd = !/^\d+$/.test(currentSlide.id) // 是否新增 + const currInd = toRaw(slidesStore.slideIndex) // 当前页索引-new + const oldInd = oldData.findIndex(o => o.id == currentSlide.id) // 当前页索引-old + const isBatch = oldVal && oldVal.length && currInd != oldInd // 是否批量更新-排序 if (isAdd) { // 新增的幻灯片(id 为非数字,说明是新增的幻灯片) const bool = await this.addSlide(currentSlide) - bool && this.batchUpdateSlides(newData, true) // 批量更新-排序 + bool && await this.batchUpdateSlides(newData, true) // 批量更新-排序 + const resource = sessionStore.get('curr.resource')||{} + await PPTApi.getSlideList(resource.id) } else { // 防抖-更新 if (!this.isUpdate) return this.isUpdate = true // 下次更新数据 - const params = { - id: currentSlide.id, - datacontent: JSON.stringify(currentSlide), + if (isBatch) { // 批量更新-排序 + this.batchUpdateSlides(newData, true) + } else { // 更新当前页幻灯片 + const params = { + id: currentSlide.id, + datacontent: JSON.stringify(currentSlide), + } + Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2) } - Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2) } } - // 更新幻灯片 - static updateSlide(data: object): Promise { + // 更新幻灯片 isThum 是否更新缩略图 + static updateSlide(data: object, isThum = true): Promise { return new Promise(async (resolve, reject) => { + if (isThum) { // 更新缩略图 + const thumUrl = await this.getSlideThumUrl() + data.base64Code = thumUrl // 更新缩略图 + } const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data) if (res.code === 200) { resolve(true) @@ -190,6 +208,42 @@ export class PPTApi { }) } + // 更新-活动列表 + static async updateWorkList(): Promise { + const resolveData = (resolve, data = []) => { + slidesStore.setWorkList(data) + return resolve() + } + return new Promise(async (resolve, reject) => { + const workItem = slidesStore.workItem // 所有的pptlist的数据-原始数据 + const currentSlide = slidesStore.currentSlide // 当前页幻灯片 + const slideId = currentSlide.id // 当前页幻灯片id + if (!slideId) return resolveData(resolve) + // slide详情获取-作业id + // const res = await API_entpcoursefile.getEntpcoursefile(slideId) + // const workIds = res?.data?.activityContent||'' + // workItem-获取作业id + const workIds = workItem.find(o => o.id == slideId)?.activityContent + if (!workIds) return resolveData(resolve) + // 获取作业列表 + const resW = await API_classwork.homeworklist({ ids: workIds, pageSize: 1000 }) + if (resW && resW.rows) return resolveData(resolve, resW.rows) + else msgUtils.msgError(resW.msg || '更新失败');return resolveData(resolve) + }) + } + + // thumbnail-slide thumbnail 缩略图 + static getSlideThumUrl(): Promise { + return nextTick().then(async() => { + const slideIndex = slidesStore.slideIndex + const elements = document.querySelectorAll('.thumbnail-slide') + if (elements.length && slideIndex >= 0) { + const element = elements[slideIndex] + return await toPng(element) + } + return null + }) + } // 图片|音频|视频 转换为在线地址 static toRousrceUrl =async (o:any) => { const formData = new FormData() @@ -200,8 +254,7 @@ export class PPTApi { url &&(o.src = url) return url } - -} + } } export class Homework{ diff --git a/src/renderer/src/AixPPTist/src/api/store.ts b/src/renderer/src/AixPPTist/src/api/store.ts index 7ec18ea..37591c4 100644 --- a/src/renderer/src/AixPPTist/src/api/store.ts +++ b/src/renderer/src/AixPPTist/src/api/store.ts @@ -7,13 +7,13 @@ import msgUtils from '@/plugins/modal' // 消息工具 import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api export default class { - // 删除幻灯片 - static delSlide(id: string): Promise { - return new Promise(async (resolve, reject) => { - const res: Result = await API_entpcoursefile.delEntpcoursefile(id) - if (res.code === 200) { - resolve(true) - } else msgUtils.msgError(res.msg || '删除失败');resolve(false) - }) - } + // 删除幻灯片 + static delSlide(id: string): Promise { + return new Promise(async (resolve, reject) => { + const res: Result = await API_entpcoursefile.delEntpcoursefile(id) + if (res.code === 200) { + resolve(true) + } else msgUtils.msgError(res.msg || '删除失败');resolve(false) + }) + } } \ 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 aee4d48..f5d91cb 100644 --- a/src/renderer/src/AixPPTist/src/api/watcher.ts +++ b/src/renderer/src/AixPPTist/src/api/watcher.ts @@ -12,6 +12,7 @@ import Classcourse from './classcourse' // 课程相关 import msgUtils from '@/plugins/modal' // 消息工具 import { Homework } from './index' // api-作业相关 import emitter from '@/utils/mitt' //mitt 事件总线 +import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制 /** * @description 监听器 @@ -21,6 +22,7 @@ export default () => { const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理 const resource = sessionStore.get('curr.resource') // apt 资源 const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源 + const execPlay = useExecPlay() // 播放控制 // 监听幻灯片内容变化 watch(() => slidesStore.slides, (newVal, oldVal) => { @@ -33,6 +35,11 @@ export default () => { updatePPT({title: newVal}) }) + // 监听幻灯片下标变化 + watch(() => slidesStore.slideIndex, (newVal, oldVal) => { + PPTApi.updateWorkList() + }) + // 消息监听ws // console.log('监听器已开启', ChatWs) if (!!ChatWs.ws) { @@ -82,8 +89,11 @@ export default () => { } break case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页 - const slideIndex = content.current - slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标 + const slideIndex = content?.current || 0 + const type = content?.animation + if (type === 'Nextsteps') emitter.emit('useExecPlay', 'execNext') // 下一步 + else if (type === 'Previoustep') emitter.emit('useExecPlay', 'turnPrevSlide') // 上一步清空-动画 + else slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标 break case MsgEnum.HEADS.MSG_homework: // 作业|活动-布置 if (!content.classWorkId) return diff --git a/src/renderer/src/AixPPTist/src/store/slides.ts b/src/renderer/src/AixPPTist/src/store/slides.ts index 37ba6b2..d7a3bae 100644 --- a/src/renderer/src/AixPPTist/src/store/slides.ts +++ b/src/renderer/src/AixPPTist/src/store/slides.ts @@ -145,21 +145,16 @@ export const useSlidesStore = defineStore('slides', { setWorkItem(list: Object[]) { this.workItem = list }, - addWorkItem(data: any) { - const id = data?.id - if (!id) return - this.workItem.splice(this.slideIndex + 1, 0, data) - this.slideIndex += 1 - }, addSlide(slide: Slide | Slide[]) { const slides = Array.isArray(slide) ? slide : [slide] for (const slide of slides) { if (slide.sectionTag) delete slide.sectionTag } - this.slides.splice(this.slideIndex, 0, ...slides) + const addIndex = this.slideIndex + 1 + this.slides.splice(addIndex, 0, ...slides) + this.slideIndex = addIndex }, - updateSlide(props: Partial, slideId?: string) { const slideIndex = slideId ? this.slides.findIndex(item => item.id === slideId) : this.slideIndex this.slides[slideIndex] = { ...this.slides[slideIndex], ...props } diff --git a/src/renderer/src/AixPPTist/src/views/Editor/Toolbar/ElementStylePanel/Active/index.vue b/src/renderer/src/AixPPTist/src/views/Editor/Toolbar/ElementStylePanel/Active/index.vue index cddd334..0354fba 100644 --- a/src/renderer/src/AixPPTist/src/views/Editor/Toolbar/ElementStylePanel/Active/index.vue +++ b/src/renderer/src/AixPPTist/src/views/Editor/Toolbar/ElementStylePanel/Active/index.vue @@ -32,22 +32,22 @@
- \ No newline at end of file diff --git a/src/renderer/src/views/teachingDesign/container/left.vue b/src/renderer/src/views/teachingDesign/container/left.vue index ab6f38b..a6d8585 100644 --- a/src/renderer/src/views/teachingDesign/container/left.vue +++ b/src/renderer/src/views/teachingDesign/container/left.vue @@ -2,26 +2,27 @@
教学模式
-
+ +
{{ item.name }} 选择模式
-
- -

- - {{ el.name }} - -

-
- - {{ el.prompt }} - -
-
-
+
+ +

+ + {{ el.name }} + +

+
+ + {{ el.prompt }} + +
+
+
@@ -29,27 +30,34 @@ + \ No newline at end of file