diff --git a/electron-builder-prod.yml b/electron-builder-prod.yml
index 4eea1f2..022b89a 100644
--- a/electron-builder-prod.yml
+++ b/electron-builder-prod.yml
@@ -6,11 +6,11 @@ directories:
win:
executableName: 文枢课堂
icon: resources/logo2.ico
- target:
- - target: nsis
- arch:
- - x64
- - ia32
+# target:
+# - target: nsis
+# arch:
+# - x64
+# - ia32
files:
- '!**/.vscode/*'
- '!src/*'
diff --git a/electron-builder-yc.yml b/electron-builder-yc.yml
index 6ed8ad7..fca9e1c 100644
--- a/electron-builder-yc.yml
+++ b/electron-builder-yc.yml
@@ -6,11 +6,11 @@ directories:
win:
executableName: 永川中小学AI教学系统
icon: resources/yc-logo.png
- target:
- - target: nsis
- arch:
- - x64
- - ia32
+# target:
+# - target: nsis
+# arch:
+# - x64
+# - ia32
files:
- '!**/.vscode/*'
- '!src/*'
diff --git a/electron-builder-yc2.yml b/electron-builder-yc2.yml
index ce77b6d..11a9d00 100644
--- a/electron-builder-yc2.yml
+++ b/electron-builder-yc2.yml
@@ -6,11 +6,11 @@ directories:
win:
executableName: 实训教学
icon: resources/yc-logo.png
- target:
- - target: nsis
- arch:
- - x64
- - ia32
+# target:
+# - target: nsis
+# arch:
+# - x64
+# - ia32
files:
- '!**/.vscode/*'
- '!src/*'
diff --git a/electron-builder-yy.yml b/electron-builder-yy.yml
index 46a0498..46c02de 100644
--- a/electron-builder-yy.yml
+++ b/electron-builder-yy.yml
@@ -6,11 +6,11 @@ directories:
win:
executableName: 育人酉数平台
icon: resources/yy-logo.png
- target:
- - target: nsis
- arch:
- - x64
- - ia32
+# target:
+# - target: nsis
+# arch:
+# - x64
+# - ia32
files:
- '!**/.vscode/*'
- '!src/*'
diff --git a/electron-builder.yml b/electron-builder.yml
index a974581..9d7caf6 100644
--- a/electron-builder.yml
+++ b/electron-builder.yml
@@ -13,11 +13,11 @@ asarUnpack:
win:
executableName: AIx
icon: resources/logo2.ico
- target:
- - target: nsis
- arch:
- - x64
- - ia32
+# target:
+# - target: nsis
+# arch:
+# - x64
+# - ia32
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
diff --git a/package.json b/package.json
index 0815835..d95a19e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "aix-win-ws",
- "version": "2.5.16",
+ "version": "2.5.18",
"description": "",
"main": "./out/main/index.js",
"author": "上海交大重庆人工智能研究院",
@@ -44,7 +44,7 @@
"@vue-office/excel": "^1.7.11",
"@vue-office/pdf": "^2.0.2",
"@vueuse/core": "^10.11.0",
- "aix-plugins-aitools": "^1.1.5",
+ "aix-plugins-aitools": "^1.1.10",
"animate.css": "^4.1.1",
"circular-json": "^0.5.9",
"clipboard": "^2.0.11",
@@ -141,4 +141,4 @@
"vue-tsc": "^1.8.25",
"windicss": "^3.5.6"
}
-}
+}
\ No newline at end of file
diff --git a/resources/yy-logo.png b/resources/yy-logo.png
index d64abf0..9ac092f 100644
Binary files a/resources/yy-logo.png and b/resources/yy-logo.png differ
diff --git a/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MediaInput.vue b/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MediaInput.vue
index c08635b..e28307d 100644
--- a/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MediaInput.vue
+++ b/src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/MediaInput.vue
@@ -94,7 +94,7 @@ const insertImageElementaudio = (files: FileList) => {
const imageFile = files[0]
if (!imageFile) return
PPTApi.toRousrceUrl(imageFile).then(data=>{
- videoSrc.value=data
+ audioSrc.value=data
insertAudio()
})
diff --git a/src/renderer/src/AixPPTist/src/views/Screen/ScreenSlideList.vue b/src/renderer/src/AixPPTist/src/views/Screen/ScreenSlideList.vue
index 1b0b4c7..4b69c8a 100644
--- a/src/renderer/src/AixPPTist/src/views/Screen/ScreenSlideList.vue
+++ b/src/renderer/src/AixPPTist/src/views/Screen/ScreenSlideList.vue
@@ -80,6 +80,7 @@ provide(injectKeySlideScale, scale)
position: relative;
width: 100%;
height: 100%;
+ overflow: hidden;
}
.slide-item {
position: absolute;
diff --git a/src/renderer/src/AixPPTist/src/views/Screen/hooks/useExecPlay.ts b/src/renderer/src/AixPPTist/src/views/Screen/hooks/useExecPlay.ts
index abccbfd..49c6ba7 100644
--- a/src/renderer/src/AixPPTist/src/views/Screen/hooks/useExecPlay.ts
+++ b/src/renderer/src/AixPPTist/src/views/Screen/hooks/useExecPlay.ts
@@ -198,7 +198,7 @@ export default (isLoader?: boolean = true) => {
const touchInfo = ref<{ x: number; y: number; } | null>(null)
const touchStartListener = (e: TouchEvent) => {
- e.preventDefault() // 阻止默认事件
+ // e.preventDefault() // 阻止默认事件
touchInfo.value = {
// x: e.changedTouches[0].pageX,
// y: e.changedTouches[0].pageY,
@@ -208,6 +208,7 @@ export default (isLoader?: boolean = true) => {
}
const touchEndListener = (e: TouchEvent) => {
if (!touchInfo.value) return
+ // window.scrollTo(0, 0) // 滚动到顶部
const offsetX = Math.abs(touchInfo.value.x - e.changedTouches[0].clientX)
const offsetY = e.changedTouches[0].clientY - touchInfo.value.y
if ( Math.abs(offsetY) > offsetX && Math.abs(offsetY) > 50 ) {
diff --git a/src/renderer/src/assets/images/login/yy-logo.png b/src/renderer/src/assets/images/login/yy-logo.png
index d64abf0..0686bea 100644
Binary files a/src/renderer/src/assets/images/login/yy-logo.png and b/src/renderer/src/assets/images/login/yy-logo.png differ
diff --git a/src/renderer/src/components/template-study/container/right.vue b/src/renderer/src/components/template-study/container/right.vue
index e2cba23..a0efe23 100644
--- a/src/renderer/src/components/template-study/container/right.vue
+++ b/src/renderer/src/components/template-study/container/right.vue
@@ -23,7 +23,7 @@
- 添加提示词
+ {{curTemplate.ex3 === '1' ? '复制并创建个人模板' : '添加提示词'}}
一键研读
@@ -120,6 +120,10 @@ const modeOptions = ref([
label: '知识库模型',
value: 2,
disabled: false
+ },
+ {
+ label: 'deepseek模型',
+ value: 3
}
])
@@ -134,7 +138,7 @@ const modeOptions = ref([
const isWordDialog = ref(false)
const editItem = reactive({})
const onAdd = () => {
-
+ console.log(curTemplate)
Object.assign(editItem, curTemplate)
editItem.isAdd = true
isWordDialog.value = true
@@ -333,6 +337,9 @@ const againResult = async (index, item) => {
})
data = res.data
} else {
+ if (curMode.value == 3) {
+ params.llm = 'deepseek-r1:8b'
+ }
// 知识库模型
const res = await completion(params)
data = res.data
@@ -381,6 +388,9 @@ const getCompletion = async () => {
}
// 知识库模型
else {
+ if (curMode.value == 3) {
+ params.llm = 'deepseek-r1:8b'
+ }
const res = await completion(params)
data = res.data
}
@@ -439,6 +449,7 @@ const onSaveTemp = async (item) => {
// 去掉字符串中的 ### **
let getResult = (str) => {
let newStr = str.replace(/#+|(\*\*)/g, '');
+ newStr = newStr.replace(/[\s\S]*?<\/think>/g, '');
return newStr
}
@@ -485,8 +496,8 @@ onMounted(() => {
getTemplateList()
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
-
-
+
+
params.dataset_id = dataSetJson[jsonKey]
if(!params.dataset_id){
curMode.value = 1
diff --git a/src/renderer/src/components/typing-effect/index.vue b/src/renderer/src/components/typing-effect/index.vue
index 2438ce0..d707a45 100644
--- a/src/renderer/src/components/typing-effect/index.vue
+++ b/src/renderer/src/components/typing-effect/index.vue
@@ -40,9 +40,22 @@ const type = async () => {
displayedText.value = props.text
return
}
+ //限制多久内打印完ms
+ let allLength = props.text.length
+ let allTime = 3000
+ let addIndex = allLength/(allTime/props.delay);
+ //一次添加5个字符
+ for (let i = 0; i < addIndex; i++) {
+ if (index.value <= allLength) {
+ displayedText.value += props.text.charAt(index.value);
+ index.value++;
+ } else {
+ break;
+ }
+ }
if (index.value <= props.text.length) {
- displayedText.value += props.text.charAt(index.value);
- index.value++;
+ // displayedText.value += props.text.charAt(index.value);
+ // index.value++;
setTimeout(() => {
type();
emit('updateScroll', typingEffectRef.value.clientHeight); // 每次添加新字符后滚动到底部
@@ -74,4 +87,4 @@ watch([() => props.text, () => props.delay], resetAndType);
:deep(.el-textarea__inner:hover){
box-shadow: none;
}
-
\ No newline at end of file
+
diff --git a/src/renderer/src/layout/components/Aside.vue b/src/renderer/src/layout/components/Aside.vue
index ecc7566..8aa998e 100644
--- a/src/renderer/src/layout/components/Aside.vue
+++ b/src/renderer/src/layout/components/Aside.vue
@@ -23,7 +23,7 @@
加入学校
个人中心
- 学校管理
+ 学校管理
班级中心
退出登录
@@ -65,7 +65,7 @@ import pkc from "../../../../../package.json"
import defaultUserImg from '@/assets/images/img-avatar.png'
import { sessionStore } from '@/utils/store'
import {toLinkLeftWeb} from "@/utils/tool"
-
+import { checkRole } from '@/utils/permission'
const { ipcRenderer } = window.electron || {}
const dev_api = ref(import.meta.env.VITE_APP_BASE_API)
@@ -86,6 +86,7 @@ const defaultImg = ['/img/avatar-default.jpg','/images/img-avatar.png','/src/ass
//是否是基地人员
const isStadium = () => {
+ console.log('isStadium',userStore.roles )
let user = userStore.user
let roles = user.roles
return roles.some(item => item.roleKey === 'stadium')
diff --git a/src/renderer/src/main.js b/src/renderer/src/main.js
index b4e79b2..7d7c36d 100644
--- a/src/renderer/src/main.js
+++ b/src/renderer/src/main.js
@@ -25,7 +25,7 @@ import log from 'electron-log/renderer' // 渲染进程日志-文件记录
import customComponent from '@/components/common' // 自定义组件
import plugins from './plugins' // plugins插件
import useUserStore from '@/store/modules/user'
-import aiAudio from 'aix-plugins-aitools' // 文字转语音插件
+import aiTools from 'aix-plugins-aitools' // 文字转语音插件
import '../../../node_modules/aix-plugins-aitools/aitools.css'
@@ -91,7 +91,7 @@ app.use(router)
.use(plugins)
.use(Icon)
.use(Directive)
- .use(aiAudio)
+ .use(aiTools)
.use(VMdEditor)
.mount('#app')
diff --git a/src/renderer/src/utils/permission.js b/src/renderer/src/utils/permission.js
new file mode 100644
index 0000000..93fee87
--- /dev/null
+++ b/src/renderer/src/utils/permission.js
@@ -0,0 +1,51 @@
+import useUserStore from '@/store/modules/user'
+
+/**
+ * 字符权限校验
+ * @param {Array} value 校验值
+ * @returns {Boolean}
+ */
+export function checkPermi(value) {
+ if (value && value instanceof Array && value.length > 0) {
+ const permissions = useUserStore().permissions
+ const permissionDatas = value
+ const all_permission = "*:*:*";
+
+ const hasPermission = permissions.some(permission => {
+ return all_permission === permission || permissionDatas.includes(permission)
+ })
+
+ if (!hasPermission) {
+ return false
+ }
+ return true
+ } else {
+ console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
+ return false
+ }
+}
+
+/**
+ * 角色权限校验
+ * @param {Array} value 校验值
+ * @returns {Boolean}
+ */
+export function checkRole(value) {
+ if (value && value instanceof Array && value.length > 0) {
+ const roles = useUserStore().roles
+ const permissionRoles = value
+ const super_admin = "admin";
+
+ const hasRole = roles.some(role => {
+ return super_admin === role || permissionRoles.includes(role)
+ })
+
+ if (!hasRole) {
+ return false
+ }
+ return true
+ } else {
+ console.error(`need roles! Like checkRole="['admin','editor']"`)
+ return false
+ }
+}
\ No newline at end of file
diff --git a/src/renderer/src/utils/tool.js b/src/renderer/src/utils/tool.js
index a83cbd1..9ba4abc 100644
--- a/src/renderer/src/utils/tool.js
+++ b/src/renderer/src/utils/tool.js
@@ -222,9 +222,11 @@ export const createWindow = async (type, data) => {
if (import.meta.env.VITE_SHOW_DEV_TOOLS === 'true') win.webContents.openDevTools() // 打开调试工具
let events = {} // 事件处理函数对象
Object.keys(data)
- .filter(k => typeof data[k] === 'function')
+ .filter(k => typeof data[k] === 'function' && k!=='success')
.forEach(k => events[k] = data[k])
eventHandles(type, win, events) // 事件监听处理
+ // 创建成功后触发回调
+ data.success && data.success(win)
return win
}
default:
@@ -306,9 +308,9 @@ const eventHandles = (type, win, events) => {
// 监听主窗口-关闭事件
mainWin.once('close', () => {winPdf=null;win.destroy();})
win.on('closed', () => {
- if(!!onClosed) onClosed() // 自定义关闭事件
- if(!!closed) closed() // 自定义关闭事件
- if(!!close) close() // 自定义关闭事件
+ if(!!onClosed) onClosed(win) // 自定义关闭事件
+ if(!!closed) closed(win) // 自定义关闭事件
+ if(!!close) close(win) // 自定义关闭事件
win = null
wins_tool = null
winChild=null
diff --git a/src/renderer/src/views/mindMap/index.vue b/src/renderer/src/views/mindMap/index.vue
index 976a0b3..0a56894 100644
--- a/src/renderer/src/views/mindMap/index.vue
+++ b/src/renderer/src/views/mindMap/index.vue
@@ -1,267 +1,91 @@
-
+
diff --git a/src/renderer/src/views/mindMap/index_old.vue b/src/renderer/src/views/mindMap/index_old.vue
new file mode 100644
index 0000000..976a0b3
--- /dev/null
+++ b/src/renderer/src/views/mindMap/index_old.vue
@@ -0,0 +1,267 @@
+
+
+
+
+
+
+
diff --git a/src/renderer/src/views/mindMap/mindMapAITools.vue b/src/renderer/src/views/mindMap/mindMapAITools.vue
new file mode 100644
index 0000000..0926386
--- /dev/null
+++ b/src/renderer/src/views/mindMap/mindMapAITools.vue
@@ -0,0 +1,246 @@
+
+
+
+
+
+
+
+
diff --git a/src/renderer/src/views/model/index.vue b/src/renderer/src/views/model/index.vue
index 70bafe7..fb4da79 100644
--- a/src/renderer/src/views/model/index.vue
+++ b/src/renderer/src/views/model/index.vue
@@ -288,14 +288,17 @@ const createAIPPT = () => {
})
})
}
-
+const isPgDialogClose = ref(false) // 弹窗-进度条-是否关闭
const pgDialog = ref({ // 弹窗-进度条
visible: false,
title: 'PPT解析中...',
width: 300,
- showClose: false,
+ showClose: true,
draggable: true,
- beforeClose: done => {}, // 阻止-弹窗事件
+ beforeClose: done => { // 弹窗关闭前回调
+ isPgDialogClose.value = true
+ done()
+ },
pg: { // 进度条-参数
percentage: 0, // 百分比
color: [
@@ -316,20 +319,26 @@ const openFilePicker = () =>{
const handleFileChange = ()=> {
const file = event.target.files[0];
+ fileInput.value.value = ''
if (file) {
- console.log(file);
createAIPPTByFile(file)
}
}
// ppt文件转PPT线上数据
const createAIPPTByFile = async (file)=> {
+ isPgDialogClose.value = false // 默认没有关闭
pgDialog.value.visible = true
pgDialog.value.pg.percentage = 0
+ const closePgDialog = () => {
+ pgDialog.value.pg.percentage = 0
+ pgDialog.value.visible = false
+ }
pptMedia = {} // 清空媒体数据
const resPptJson = await PPTXFileToJson(file).catch(() => {
ElMessageBox.alert('PPT文件转换失败!请点击素材右侧...下载文件后打开另存为PPTX文件格式再进行导入!')
pgDialog.value.visible = false
})
+ if(isPgDialogClose.value) return closePgDialog() // 弹窗关闭了,终止进行
const { def, slides, ...content } = resPptJson
// 生成缩略图
const thumbnails = await slidesToImg(slides, content.width)
@@ -337,13 +346,13 @@ const createAIPPTByFile = async (file)=> {
let completed = 0
const total = slides.length
for( let o of slides ) {
+ if(isPgDialogClose.value) return closePgDialog() // 弹窗关闭了,终止进行
completed++
await toRousrceUrl(o)
// 设置进度条
pgDialog.value.pg.percentage = Math.floor(completed / total * 100)
}
- pgDialog.value.pg.percentage = 0
- pgDialog.value.visible = false
+ closePgDialog() // 关闭进度条弹窗
listEntpcourse({
evalid: currentNode.value.id,
edituserid: userStore.userId,
@@ -429,17 +438,23 @@ const toRousrceUrl = async (o) => {
if (!!o.src) { // 如果有src就转换
const isBase64 = /^data:image\/(\w+);base64,/.test(o.src)
const isBlobUrl = /^blob:/.test(o.src)
- let onLineUrl = '' // 线上地址
- if (!!o.zipPath) onLineUrl = pptMedia[o.zipPath] || '' // 是否已上传过
+ let onLineUrl = '', typeExt = '' // 线上地址|文件后缀
+ if (!!o.zipPath) {
+ onLineUrl = pptMedia[o.zipPath] || '' // 是否已上传过
+ typeExt = o.zipPath.split('.').pop()
+ }
if (onLineUrl) o.src = onLineUrl // 已存在线上地址直接赋值
else { // 不存在重新上传
if (isBase64) { // 相同资源处理
- const url = await getOnlineFileUrl(o.src)
+ if(!typeExt) typeExt = 'png'
+ const url = await getOnlineFileUrl(o.src, typeExt)
+ url &&(o.src = url)
url && o.zipPath && (pptMedia[o.zipPath] = url) // 缓存
} else if (isBlobUrl) { // 视频和音频
+ if(!typeExt) typeExt = o.type=='video'?'mp4':'mp3'
const res = await fetch(o.src)
const blob = await res.blob()
- const url = await getOnlineFileUrl(blob, o.type=='video'?'mp4':'mp3')
+ const url = await getOnlineFileUrl(blob, typeExt)
URL.revokeObjectURL(o.src) // 释放内存
url &&(o.src = url)
url && o.zipPath && (pptMedia[o.zipPath] = url) // 缓存
@@ -564,13 +579,38 @@ const changeClass = async (type, row, other) => {
switch(type) {
case 'click': { // 点击-打开课件-aippt
if (row.fileFlag === 'aippt' && !!row.fileId) {
+ const id = Number(row.fileId)
+ const openFileIds = sessionStore.get('curr.openFileIds')||[] // 已打开课件列表id
+ const isHasOpen = openFileIds.includes(id) // 是否已打开
+ if (isHasOpen) return ElMessage.warning('该课件已打开!')
const res = await getEntpcoursefile(row.fileId)
if (res && res.code === 200) {
+ openFileIds.push(id) // 课堂资源缓存-允许打开多个
+ sessionStore.set('curr.openFileIds', openFileIds) // 更新窗口课件列表id
sessionStore.set('curr.resource', res.data) // 缓存当前资源信息
sessionStore.set('curr.smarttalk', row) // 缓存当前文件smarttalk
createWindow('open-win', {
url: '/pptist', // 窗口关闭时,清除缓存
- close: () => {
+ success: (win) => { // 窗口打开成功
+ const map = sessionStore.get('curr.winMap') || {}
+ map[win.id] = id // 将当前窗口id和课件id进行关联
+ sessionStore.set('curr.winMap', map)
+ },
+ close: (win) => {
+ const openFileIds = sessionStore.get('curr.openFileIds')||[] // 已打开课件列表id
+ const map = sessionStore.get('curr.winMap') || {}
+ const resourceId = map[win.id] // 当前窗口关联的课件id
+ if (resourceId){
+ const ind = openFileIds.findIndex(id => id == resourceId) // 是否存在打开的课件
+ if (ind >= 0) { // 存在打开的课件
+ openFileIds.splice(ind, 1) // 删除关联课件
+ if (openFileIds.length) sessionStore.set('curr.openFileIds', openFileIds) // 更新窗口课件列表
+ else sessionStore.delete('curr.openFileIds') // 清除缓存
+ delete map[win.id] // 删除 当前窗口课件关联
+ if(Object.keys(map).length) sessionStore.set('curr.winMap', map) // 更新窗口课件关联
+ else sessionStore.delete('curr.winMap') // 清除缓存
+ }
+ }
sessionStore.delete('curr.resource') // 清除缓存
sessionStore.delete('curr.smarttalk') // 清除缓存
getSmarttalkPage({
diff --git a/src/renderer/src/views/prepare/index.vue b/src/renderer/src/views/prepare/index.vue
index 8a9d5c6..da54074 100644
--- a/src/renderer/src/views/prepare/index.vue
+++ b/src/renderer/src/views/prepare/index.vue
@@ -274,13 +274,17 @@ export default {
treelogRef:null,
// 获取当前章节对应的课程信息 Entpcourse
entp: null,
+ isPgDialogClose: false, // 关闭进度条弹窗
pgDialog: { // 弹窗-进度条
visible: false,
title: 'PPT解析中...',
width: 300,
- showClose: false,
+ showClose: true,
draggable: true,
- beforeClose: done => {}, // 阻止-弹窗事件
+ beforeClose: done => { // 弹窗关闭前回调
+ this.isPgDialogClose = true
+ done()
+ },
pg: { // 进度条-参数
percentage: 0, // 百分比
color: [
@@ -453,6 +457,9 @@ export default {
}
case 'click': { // 点击-打开课件-aippt
if (row.fileFlag === 'aippt' && !!row.fileId) {
+ const openFileIds = sessionStore.get('curr.openFileIds')||[] // 已打开课件列表id
+ const isHasOpen = openFileIds.includes(Number(row.fileId)) // 是否已打开
+ if (isHasOpen) return ElMessage.warning('该课件已打开!')
sessionStore.delete('curr.classcourse') // 清除上课相关信息
const res = await getEntpcoursefile(row.fileId)
if (res && res.code === 200) {
@@ -496,12 +503,37 @@ export default {
* @param {object} currData 当前数据 type: edit/class 备课信息 | 课堂信息
*/
openPublicScreen(type, resource, currData) {
+ const openFileIds = sessionStore.get('curr.openFileIds')||[]
+ const isNoOpen = !openFileIds.includes(Number(resource.id)) // 是否不存在
+ if (isNoOpen) {
+ openFileIds.push(resource.id) // 课堂资源缓存-允许打开多个
+ sessionStore.set('curr.openFileIds', openFileIds) // 更新窗口课件列表id
+ }
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
if (type=='edit') sessionStore.set('curr.smarttalk', currData) // 缓存当前文件smarttalk
else sessionStore.set('curr.classcourse', currData) // 缓存当前当前上课
createWindow('open-win', {
url: '/pptist', // 窗口关闭时,清除缓存
- close: () => {
+ success: (win) => { // 窗口打开成功
+ const map = sessionStore.get('curr.winMap') || {}
+ map[win.id] = resource.id // 将当前窗口id和课件id进行关联
+ sessionStore.set('curr.winMap', map)
+ },
+ close: (win) => {
+ const openFileIds = sessionStore.get('curr.openFileIds')||[] // 课件列表
+ const map = sessionStore.get('curr.winMap') || {}
+ const resourceId = map[win.id] // 当前窗口关联的课件id
+ if (resourceId){
+ const ind = openFileIds.findIndex(id => id == resourceId) // 是否存在打开的课件
+ if (ind >= 0) { // 存在打开的课件
+ openFileIds.splice(ind, 1) // 删除关联课件
+ if (openFileIds.length) sessionStore.set('curr.openFileIds', openFileIds) // 更新窗口课件列表
+ else sessionStore.delete('curr.openFileIds') // 清除缓存
+ delete map[win.id] // 删除 当前窗口课件关联
+ if(Object.keys(map).length) sessionStore.set('curr.winMap', map) // 更新窗口课件关联
+ else sessionStore.delete('curr.winMap') // 清除缓存
+ }
+ }
sessionStore.delete('curr.resource') // 清除缓存
if (type=='edit') {
sessionStore.delete('curr.smarttalk') // 清除缓存
@@ -584,6 +616,7 @@ export default {
},
handleFileChange(){
const file = event.target.files[0];
+ this.$refs.fileInput.value = ''
if (file) {
console.log(file);
console.log('文件名:', file.name);
@@ -620,17 +653,23 @@ export default {
if (!!o.src) { // 如果有src就转换
const isBase64 = /^data:image\/(\w+);base64,/.test(o.src)
const isBlobUrl = /^blob:/.test(o.src)
- let onLineUrl = '' // 线上地址
- if (!!o.zipPath) onLineUrl = this.pptMedia[o.zipPath] || '' // 是否已上传过
+ let onLineUrl = '', typeExt = '' // 线上地址|文件后缀
+ if (!!o.zipPath) {
+ onLineUrl = this.pptMedia[o.zipPath] || '' // 是否已上传过
+ typeExt = o.zipPath.split('.').pop()
+ }
if (onLineUrl) o.src = onLineUrl // 已存在线上地址直接赋值
else { // 不存在重新上传
if (isBase64) { // 相同资源处理
- const url = await this.getOnlineFileUrl(o.src)
+ if(!typeExt) typeExt = 'png'
+ const url = await this.getOnlineFileUrl(o.src, typeExt)
+ url &&(o.src = url)
url && o.zipPath && (this.pptMedia[o.zipPath] = url) // 缓存
} else if (isBlobUrl) { // 视频和音频
+ if(!typeExt) typeExt = o.type=='video'?'mp4':'mp3'
const res = await fetch(o.src)
const blob = await res.blob()
- const url = await this.getOnlineFileUrl(blob, o.type=='video'?'mp4':'mp3')
+ const url = await this.getOnlineFileUrl(blob, typeExt)
URL.revokeObjectURL(o.src) // 释放内存
url &&(o.src = url)
url && o.zipPath && (this.pptMedia[o.zipPath] = url) // 缓存
@@ -659,14 +698,20 @@ export default {
}
},
async createAIPPTByFile(file,fileShowName) {
+ this.isPgDialogClose = false // 默认不关闭
this.pgDialog.visible = true
this.pgDialog.pg.percentage = 0
+ const closePgDialog = () => {
+ this.pgDialog.pg.percentage = 0
+ this.pgDialog.visible = false
+ }
this.pptMedia = {} // 清空媒体数据
const resPptJson = await PPTXFileToJson(file).catch(() => {
ElMessageBox.alert('PPT文件转换失败!请点击素材右侧...下载文件后打开另存为PPTX文件格式再进行导入!')
this.pgDialog.visible = false
})
if (!resPptJson) return
+ if(this.isPgDialogClose) return closePgDialog() // 弹窗关闭了,终止进行
const { def, slides, ...content } = resPptJson
// 生成缩略图
const thumbnails = await slidesToImg(slides, content.width)
@@ -674,13 +719,13 @@ export default {
let completed = 0
const total = slides.length
for( let o of slides ) {
+ if(this.isPgDialogClose) return closePgDialog() // 弹窗关闭了,终止进行
completed++
await this.toRousrceUrl(o)
// 设置进度条
this.pgDialog.pg.percentage = Math.floor(completed / total * 100)
}
- this.pgDialog.pg.percentage = 0
- this.pgDialog.visible = false
+ closePgDialog() // 关闭进度条弹窗
listEntpcourse({
evalid: this.currentNode.id,
edituserid: this.userStore.userId,