,
total?: number
+}
+
+/** 课程信息 */
+export interface Classcourse {
+ id?: number|string, // 课程id
+ coursetitle?: string, // 课程名称
+ coursetype?: string, // 课程类型
+ courseverid?: string, // 课程版本id
+ coursedesc?: string, // 课程描述
+ status?: number, // 课程状态
+ teacherid?: number|string, // 教师id
+ entpcoursefileid?: number|string, // 课程文件id
+ classid?: number|string, // 班级id
+ entpcourseid?: number|string, // 章节中间表id
+ plandate?: string, // 计划时间
+ opendate?: string, // 开课时间
}
\ 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 dd7d66b..e8cc32a 100644
--- a/src/renderer/src/AixPPTist/src/hooks/useScreening.ts
+++ b/src/renderer/src/AixPPTist/src/hooks/useScreening.ts
@@ -1,9 +1,10 @@
-import { useScreenStore, useSlidesStore } from '../store'
+import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
export default () => {
const screenStore = useScreenStore()
const slidesStore = useSlidesStore()
+ const classcourseStore = useClasscourseStore() // 课堂信息
// 进入放映状态(从当前页开始)
const enterScreening = () => {
@@ -19,7 +20,11 @@ export default () => {
// 退出放映状态
const exitScreening = () => {
- screenStore.setScreening(false)
+ const classcourse = classcourseStore.classcourse
+ if (!!classcourse) { //DOTO 有课堂,执行退相关操作
+ console.log('退出放映状态')
+ window.close()
+ } else screenStore.setScreening(false)
if (isFullscreen()) exitFullscreen()
}
diff --git a/src/renderer/src/AixPPTist/src/plugins/icon.ts b/src/renderer/src/AixPPTist/src/plugins/icon.ts
index 2bffc0e..bc6e035 100644
--- a/src/renderer/src/AixPPTist/src/plugins/icon.ts
+++ b/src/renderer/src/AixPPTist/src/plugins/icon.ts
@@ -125,7 +125,8 @@ import {
User,
Switch,
More,
- Material
+ Material,
+ AddPicture
} from '@icon-park/vue-next'
export interface Icons {
@@ -256,7 +257,8 @@ export const icons: Icons = {
IconUser: User,
IconSwitch: Switch,
IconMore: More,
- IconMaterial: Material
+ IconMaterial: Material,
+ IconAddPicture: AddPicture
}
export default {
diff --git a/src/renderer/src/AixPPTist/src/store/classcourse.ts b/src/renderer/src/AixPPTist/src/store/classcourse.ts
new file mode 100644
index 0000000..7abd3fe
--- /dev/null
+++ b/src/renderer/src/AixPPTist/src/store/classcourse.ts
@@ -0,0 +1,18 @@
+import { defineStore } from 'pinia'
+import type { Classcourse } from '../api/types'
+
+export interface ClasscourseState {
+ classcourse: Classcourse
+}
+
+export const useClasscourseStore = defineStore('classcourse', {
+ state: (): ClasscourseState => ({
+ classcourse: null, // 课堂信息
+ }),
+
+ actions: {
+ setClasscourse(classcourse: Classcourse) {
+ this.classcourse = classcourse
+ },
+ },
+})
\ No newline at end of file
diff --git a/src/renderer/src/AixPPTist/src/store/index.ts b/src/renderer/src/AixPPTist/src/store/index.ts
index 1ed4f2f..fe0cf22 100644
--- a/src/renderer/src/AixPPTist/src/store/index.ts
+++ b/src/renderer/src/AixPPTist/src/store/index.ts
@@ -3,6 +3,7 @@ import { useSlidesStore } from './slides'
import { useSnapshotStore } from './snapshot'
import { useKeyboardStore } from './keyboard'
import { useScreenStore } from './screen'
+import { useClasscourseStore } from './classcourse'
export {
useMainStore,
@@ -10,4 +11,5 @@ export {
useSnapshotStore,
useKeyboardStore,
useScreenStore,
+ useClasscourseStore,
}
\ No newline at end of file
diff --git a/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MaterialDialog.vue b/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MaterialDialog.vue
index 8295fe0..dd648a3 100644
--- a/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MaterialDialog.vue
+++ b/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MaterialDialog.vue
@@ -11,6 +11,7 @@
插入
+
@@ -93,11 +94,9 @@ const GetUrlParameters = (parameters) => {
}
}
}
-
return resData;
}
-
const proxyToBase64 = (url)=> {
const dourl = GetUrlParameters(url)
console.log(dourl,'dourl')
diff --git a/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/index.vue b/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/index.vue
index 9f03ff0..f83291b 100644
--- a/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/index.vue
+++ b/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/index.vue
@@ -83,6 +83,7 @@
+
@@ -121,14 +122,18 @@
@update="data => { onhtml2canvas(data); classWorkTaskVisible = false }"
/>
-
+
-
-
+
+
+ { createImageElement(url); imgVisible = false }" />
+
@@ -157,6 +162,8 @@ import PopoverMenuItem from '../../../components/PopoverMenuItem.vue'
import QuestToPPTist from '@/views/classTask/newClassTaskAssign/questToPPTist/index.vue'
import MaterialDialog from './MaterialDialog.vue'
import { PPTApi } from '../../../api'
+import TextCreateImg from '@/components/ai-kolors/index.vue'
+
const mainStore = useMainStore()
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
const { canUndo, canRedo } = storeToRefs(useSnapshotStore())
@@ -276,8 +283,10 @@ const insertMaterial = (item: MaterialParams) =>{
createImageElement(data)
}
materiaVisible.value = false
-
}
+
+// 文生图
+const imgVisible = ref(false)
\ No newline at end of file
+
diff --git a/src/renderer/src/plugins/socket/index.js b/src/renderer/src/plugins/socket/index.js
new file mode 100644
index 0000000..968ac53
--- /dev/null
+++ b/src/renderer/src/plugins/socket/index.js
@@ -0,0 +1,164 @@
+/**
+ * websocket 工具类(im 自己实现)
+* 单例模式: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
+* 实现的方法为先判断实例存在与否,如果存在则直接返回,不存在就创建了再返回,这就确保了一个类只有一个实例对象。
+*/
+import useUserStore from '@/store/modules/user' // 用户信息
+
+export class ChatWs {
+ instance = null; // 实例
+ id = null; // 群聊id || 单聊id-用户id(userId)
+ closed = false; // 关闭状态
+ onmessage = null; // 自定义处理
+ errCount = 5; // 重连次数 (ms) 暂时不使用
+ errTime = null; // 重连时间 (ms) 1秒内zhi间内不重连
+ // 类型定义
+ TYPES = {
+ group: 'group', // 群发
+ single: 'single', // 单发
+ beat: 'heart_beat', // 心跳
+ }
+ static base = 'wss://file.ysaix.com:7868'
+ constructor() {
+ if (!ChatWs.instance) {
+ const userStore = useUserStore() // 用户信息
+ const wsBase = import.meta.env.VITE_APP_WS_URL; // ws地址
+ const url = `${wsBase||ChatWs.base}/ws/websocket/${userStore.id}`;
+ this.init(url);
+ ChatWs.instance = this;
+ }
+ return ChatWs.instance;
+ }
+
+ // 初始化
+ init(url) {
+ this.url = url;
+ this.ws = null;
+ const _this = this
+ this.heartCheck = {
+ timeout: 1000 * 10, // 60s
+ timeoutObj: null,
+ serverTimeoutObj: null,
+ reset() {
+ clearTimeout(this.timeoutObj);
+ clearTimeout(this.serverTimeoutObj);
+ return this;
+ },
+ start() {
+ const self = this;
+ this.timeoutObj = setTimeout(function () {
+ // 这里发送一个心跳,后端收到后,返回一个心跳消息,
+ // onmessage拿到返回的心跳就说明连接正常
+ console.log("websocket-发送心跳")
+ _this.sendMsgBeat();
+ self.serverTimeoutObj = setTimeout(function () {
+ console.log("websocket-心跳响应超时")
+ // 如果超过一定时间还没重置,说明后端主动断开了
+ _this.ws.close(); // 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
+ }, self.timeout);
+ }, this.timeout);
+ },
+ };
+ 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 exts = ['sessionId', 'pong'] // 不处理的消息头
+ const isEmpty = !e.data
+ const isExts = exts.some(item => e.data.includes(item))
+ 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(self.errCount <= 0) return; // 超过重连次数
+ // self.errCount--; // 重连次数减1
+ if (this.errTime) {
+ const nowTime = Date.now();
+ const bool = nowTime - this.errTime < 1000 // 1s内zhi间内不重连
+ if (bool) return; // 1s内不重连
+ }
+ this.errTime = Date.now();
+ // 延时5s 后重连
+ console.log('重连中...')
+ this.sleep(5000).then(_ => {this.reconnect()})
+ }
+ // 发送消息
+ send(msg) {
+ if (!msg) throw new Error("msg is not null")
+ if (!this.ws) throw new Error("ws is not null")
+ if (typeof msg === "object") msg = JSON.stringify(msg)
+ if (!msg.includes('"msg":')) throw new Error("msg 格式错误请重试")
+ this.ws.send(msg)
+ }
+ // 发送消息-带消息头(key)
+ sendMsg(head, content, option = {}) {
+ if (!head) throw new Error("head is not null")
+ if (!content) throw new Error("content is not null")
+ let msg = { head, content, ...option }
+ // 发送消息
+ this.send(this.getMsgObj(msg))
+ }
+ // 发送心跳
+ sendMsgBeat() {
+ // this.send(this.getMsgObj('ping', this.TYPES.beat))
+ this.ws.send('ping')
+ }
+ /**
+ * @description 获取消息对象
+ * @param {*} msg 消息内容
+ * @param {*} chatType 群发 group| 单发 single| 心态 heart_beat
+ * @param {*} id 群聊id || 单聊id-用户id(userId)
+ */
+ getMsgObj(msg, chatType = 'group', id) {
+ if (typeof msg === "object") msg = JSON.stringify(msg)
+ const res = {msg, chatType}
+ // if (!id) throw new Error(`${type=='group'?'群ID':'用户ID'} is not null`)
+ if (chatType == 'group') res.groupId = id || this.id || ''
+ else if (chatType == 'single') res.to = id || this.id || ''
+ return res
+ }
+ // 监听
+ watch(callback) {
+ callback && (this.onmessage = callback);
+ }
+ // 关闭链接
+ close() {
+ this.closed = true;
+ this.ws.close();
+ }
+ // 延时 ms 毫秒
+ sleep(ms){
+ return new Promise(resolve => setTimeout(resolve, ms))
+ }
+}
+// 连接socket
+export const connect = () => new ChatWs()
+// 默认实例
+export default new ChatWs()
\ No newline at end of file
diff --git a/src/renderer/src/utils/tool.js b/src/renderer/src/utils/tool.js
index a89be59..02aeae2 100644
--- a/src/renderer/src/utils/tool.js
+++ b/src/renderer/src/utils/tool.js
@@ -208,6 +208,10 @@ export const createWindow = async (type, data) => {
autoHideMenuBar: true,
maximizable: false,
}
+ // pptlist的时候可以选择最大化
+ if (data.url == '/pptist'){
+ defOption.maximizable = true;
+ }
data.isConsole = true // 是否开启控制台
data.option = {...defOption, ...option}
const win = await toolWindow(type, data)
diff --git a/src/renderer/src/views/classTask/newClassTaskAssign/index.vue b/src/renderer/src/views/classTask/newClassTaskAssign/index.vue
index b1a52f2..577a881 100644
--- a/src/renderer/src/views/classTask/newClassTaskAssign/index.vue
+++ b/src/renderer/src/views/classTask/newClassTaskAssign/index.vue
@@ -126,7 +126,7 @@