Compare commits

...

30 Commits

Author SHA1 Message Date
“zouyf” 89cba04b8c Merge branch 'main' into zouyf_dev
# Conflicts:
#	src/renderer/src/views/classTask/container/classTask/item-dialog-score.vue
2024-12-25 11:02:19 +08:00
zouyf 9cce9c224c Merge pull request '[作业批改] - 替换自动批改完成' (#179) from zouyf_tmp into main
Reviewed-on: #179
2024-12-25 10:42:58 +08:00
“zouyf” 171dc72ee7 [作业批改] - 替换自动批改完成 2024-12-25 10:33:20 +08:00
“zouyf” dd0160865b Merge branch 'main' into zouyf_dev 2024-12-25 10:09:57 +08:00
lyc 62a419356c Merge pull request 'edit' (#178) from lyc-dev into main 2024-12-24 17:32:25 +08:00
lyc 4b2d13db8e edit 2024-12-24 17:31:56 +08:00
zhengdegang f63bb69919 Merge pull request 'zdg_dev' (#177) from zdg_dev into main
Reviewed-on: #177
2024-12-24 16:08:38 +08:00
zdg b3ffa9bdaa Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-24 16:07:00 +08:00
zdg 5510021566 上课允许不选班级开课 2024-12-24 16:06:53 +08:00
lyc 89e0b2f97c Merge pull request 'edit 框架设计' (#176) from lyc-dev into main 2024-12-24 14:48:25 +08:00
lyc 406e581182 edit 框架设计 2024-12-24 14:47:58 +08:00
lyc ea0e1c91cf Merge pull request 'lyc-dev' (#175) from lyc-dev into main 2024-12-24 14:38:20 +08:00
lyc d4dce61555 Merge branch 'main' into lyc-dev 2024-12-24 14:37:06 +08:00
lyc d6d5d13232 pptList 插入素材 增加loading 2024-12-24 14:32:59 +08:00
zhengdegang 33e38f8992 Merge pull request 'zdg_dev' (#174) from zdg_dev into main
Reviewed-on: #174
2024-12-24 12:05:02 +08:00
zdg 11968879d8 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev
# Conflicts:
#	src/renderer/src/AixPPTist/src/views/Editor/EditorHeader/index.vue
2024-12-24 11:33:49 +08:00
zdg db86299523 ppt缩略图生成 2024-12-24 11:32:52 +08:00
zdg c152a3d3ee aippt生成-缩略图 2024-12-24 11:24:53 +08:00
lyc 9c8872579f Merge pull request 'edit 框架设计' (#173) from lyc-dev into main 2024-12-24 10:21:42 +08:00
lyc 4f32927b49 edit 框架设计 2024-12-24 10:21:13 +08:00
zhangxuelin e132f3927b Merge pull request 'zxl' (#172) from zxl into main
Reviewed-on: #172
2024-12-24 10:07:31 +08:00
朱浩 c290c170d3 报错后及时回转loading按钮 2024-12-24 10:01:34 +08:00
朱浩 3867a9603f 报错后及时回转loading按钮 2024-12-24 09:58:31 +08:00
zhangxuelin f732520d8d Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-24 09:51:31 +08:00
lyc 01fbb9d05c Merge pull request 'lyc-dev' (#171) from lyc-dev into main 2024-12-23 17:02:30 +08:00
lyc 1334becb54 Merge branch 'main' into lyc-dev 2024-12-23 17:01:53 +08:00
lyc c95508ed59 edit 模板 2024-12-23 17:01:40 +08:00
zhangxuelin cf540d73df Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-23 15:26:47 +08:00
zhangxuelin 83d3cd5df8 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-23 09:41:19 +08:00
zhangxuelin 64272467a2 ppist里面不显示导入 2024-12-18 16:08:19 +08:00
16 changed files with 194 additions and 103 deletions

View File

@ -17,6 +17,7 @@ VITE_APP_RES_FILE_PATH = 'https://file.ysaix.com:7868/src/assets/textbook/booktx
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
# websocket 地址
# VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865'

View File

@ -14,7 +14,8 @@ export default () => {
const courseId = classcourse?.id // 课堂id
const timgroupid = classcourse?.timgroupid // 群组id
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
if (!ChatWs.ws) ChatWs.init()
// 上课状态才-初始化socket
if (!ChatWs.ws && !!courseId) ChatWs.init()
// 开课消息
const startCourse = async() => {
// await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'open' })

View File

@ -1,5 +1,6 @@
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
import { sessionStore } from '@/utils/store' // electron-store 状态管理
import ChatWs from '@/plugins/socket' // 聊天socket
export default () => {
@ -25,6 +26,9 @@ export default () => {
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
console.log('退出放映状态')
ChatWs?.close() // 关闭ws
sessionStore.delete('curr.classcourse') // 清除课堂信息
sessionStore.delete('curr.resource') // 清除课件信息
sessionStore.delete('curr.isPublic') // 清除公屏状态
setTimeout(() => {
window.close() // 关闭窗口
}, 1000)

View File

@ -21,6 +21,7 @@ import { sessionStore } from '@/utils/store'
import { getSmarttalkPage } from '@/api/file'
import * as commUtils from '@/utils/comm.js'
import { getFileSuffix } from '@/utils/ruoyi.js'
import { PPTApi } from '../../../api'
const emit = defineEmits(['insertMaterial', 'close'])
@ -60,73 +61,31 @@ const fileUrl = computed(() => (item) =>{
}
})
//
const onInsert = async (item) =>{
loading.value = true
const res = await fetch(item.fileFullPath)
const bolb = await res.blob()
const file = commUtils.blobToFile(bolb, item.fileShowName)
try {
const data = await PPTApi.toRousrceUrl(file)
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
emit('insertMaterial',{ type: 'video', file })
emit('insertMaterial',{ type: 'video', data })
}
else{
emit('insertMaterial',{ type: 'img', file })
emit('insertMaterial',{ type: 'img', data })
}
} finally {
loading.value = false
}
}
const GetUrlParameters = (parameters) => {
let resData = "";
let url = document.location.toString();
let arrUrl = url.split("?");
//
if (arrUrl.length > 1) {
//
let parametersArr = arrUrl[1].split("&");
//
for (let i = 0; i <= parametersArr.length; i++) {
if (parametersArr[i]) {
//
let parameterStr = parametersArr[i].split("=");
if (parameters == parameterStr[0]) {
resData = parameterStr[1];
break;
}
}
}
}
return resData;
}
const proxyToBase64 = (url)=> {
const dourl = GetUrlParameters(url)
console.log(dourl,'dourl')
return
axios({
url: "/api/logo.png",
method: "get",
responseType: "blob",
}).then((res) => {
const reader = new FileReader();
reader.readAsDataURL(res.data);
reader.onload = () => {
console.log(reader.result);
};
});
}
//
const onClose = () =>{
emit('close')
}
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);

View File

@ -281,11 +281,10 @@ const toggleNotesPanel = () => {
//
interface MaterialParams {
type: string,
file: any
data: string
}
const insertMaterial = (item: MaterialParams) =>{
const { type, file } = item
PPTApi.toRousrceUrl(file).then(data=>{
const insertMaterial = async (item: MaterialParams) =>{
const { type, data } = item
if(type == 'video'){
createVideoElement(data)
}
@ -293,8 +292,6 @@ const insertMaterial = (item: MaterialParams) =>{
createImageElement(data)
}
materiaVisible.value = false
})
}
//

View File

@ -3,7 +3,7 @@
<div class="left">
<Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible">
<template #content>
<FileInput accept=".pptist" @change="files => {
<!-- <FileInput accept=".pptist" @change="files => {
importSpecificFile(files)
mainMenuVisible = false
}">
@ -15,7 +15,7 @@
}">
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
</FileInput>
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem>
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem> -->
<PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem>
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> -->
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
@ -54,9 +54,9 @@
<div class="arrow-btn"><IconDown class="arrow" /></div>
</Popover>
</div>
<div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
<!-- <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
<IconDownload class="icon" />
</div>
</div> -->
<div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`">
<el-avatar size="small" :src="avatar" />
</div>

View File

@ -88,6 +88,15 @@ export function updateClassworkdata(data) {
})
}
// 批阅后, 待所有学生都批改完成后自动结束当前作业为[已完成]
export function updateClassWorkDataAutoFinish(data) {
return request({
url: '/education/classworkdata/updAutoFinish',
method: 'put',
data: data
})
}
// 修改classwork
export function updateClasswork(data) {
return request({

View File

@ -415,7 +415,7 @@ const onEditSave = async (item) => {
}
//
const onSaveTemp = (item) => {
const onSaveTemp = async (item) => {
if (item.answer == '') return
const data = {
@ -425,7 +425,10 @@ const onSaveTemp = (item) => {
content: item.answer,
ex1: curNode.id
}
tempSave(data).then(res => { })
const res = await tempSave(data)
if(!item.resultId){
item.resultId = res.data
}
}
// ### **

View File

@ -0,0 +1,87 @@
/**
* ppt 转换为图片
*/
import { h, render, getCurrentInstance } from 'vue'
import { toPng, toJpeg } from 'html-to-image' // 引入html-to-image库
import { PPTXFileToJson } from "@/AixPPTist/src/hooks/useImport"
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
import { useSlidesStore } from '@/AixPPTist/src/store'
// 延时
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
/**
* @description: 渲染组件
* @param {*} node 节点或属性
* @param {*} props 属性
* @param {*} children 子元素
* @param {*} container 容器
*/
const renderComponent = (node, props = {}, children, container) => {
let vNode, body
if (!node) throw new Error('vNode is required')
if (typeof container == 'string') {
if (node == 'slide') {
vNode = h(ThumbnailSlide, props, children)
} else throw new Error('vNode has no corresponding component')
} else {
vNode = h(node, props, children)
}
if (!container) body = document.body // 默认为body
else { // 判断是否为字符串
if (typeof container == 'string') {
body = document.querySelector(container)
} else {
body = container
}
}
return render(vNode, body)
}
/**
* @description: 幻灯片转换为图片
* 提示icon组件找不到是应为 h() 渲染是底层创建的虚拟节点找不到全局组件
* @param {*} slides 幻灯片数据
* @param {*} options 配置 number 为幻灯片宽度 | object 为配置项
* @returns
*/
export const slidesToImg = (slides = [], options) => {
let width, option, ispng = true
if (typeof options =='number'){width = options; option = {}}
else {const { width: w, isPng, ...opt } = options;width = w; ispng=isPng; option = opt}
const slidesStore = useSlidesStore()
!!width && slidesStore.setViewportSize(width) // 设置幻灯片宽度
return new Promise(async(resolve) => {
const instance = getCurrentInstance()
console.log('instance', instance)
const slidesDom = []
for(const slide of slides) {
const props = { class: 'c-thumbnail', slide, size: 120, ...option }
const node = h(ThumbnailSlide, props)
slidesDom.push(node)
}
// 渲染组件到body
const props = { class: 'c-thumbnails', style:{position:'absolute',top:0,left:'-200vw'}}
renderComponent('div', props, slidesDom)
let imgs = []
const toImag = ispng? toPng : toJpeg
for(const slide of slidesDom) {
const img = await toImag(slide.el)
imgs.push(img)
}
// console.log('ppt生成图片: ', imgs)
// console.log('图片已生成,正在卸载组件')
!!width && slidesStore.setViewportSize(1000) // 设置幻灯片宽度-恢复
render(null, document.body) // 卸载组件
resolve(imgs)
})
}
/**
* description: ppt 文件转换为图片
* @param {*} file file 为文件对象| arrayBuffer 为数组
* @param {*} options 配置 number 为幻灯片宽度 | object 为配置项
* @returns
*/
export const pptToImg = async(file, options) => {
const { slides } = await PPTXFileToJson(file)
return slidesToImg(slides, options)
}

View File

@ -435,7 +435,7 @@ import useUserStore from '@/store/modules/user'
import { ref, reactive } from 'vue'
// import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import { updateClassworkeval, updateClassworkdata, getClassworkdata, updateClassworkevalList } from '@/api/classTask'
import { getClassworkdata, updateClassworkevalList, updateClassWorkDataAutoFinish } from '@/api/classTask'
import { getTimeDate } from '@/utils/date'
import ReFilePreview from '@/components/refile-preview/index.vue'
import { quizStrToList } from '@/utils/comm';
@ -890,7 +890,7 @@ const onSubmit = () => {
updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm;
};
//
updateClassworkdata(formd).then(res => {
updateClassWorkDataAutoFinish(formd).then(res => {
})
//

View File

@ -83,6 +83,8 @@ import useUserStore from '@/store/modules/user' // 用户信息
import ChooseTextbook from '@/components/choose-textbook/index.vue'
import KjListItem from '@/views/prepare/container/kj-list-item.vue'
import FileImage from '@/components/file-image/index.vue'
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
import {creatAPT, getSmarttalkPage, getModelInfo} from '@/api/file'
import {ArrowDown, Flag, Position} from '@element-plus/icons-vue'
import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile";
@ -94,11 +96,11 @@ import {createWindow, toLinkLeftWeb} from "@/utils/tool";
import {ElMessage} from "element-plus";
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
import msgUtils from "@/plugins/modal";
import * as commUtils from "@/utils/comm";
import * as Api_server from "@/api/apiService"; //
import useClassTaskStore from '@/store/modules/classTask'
import { slidesToImg } from '@/utils/ppt' // ppt
const router = useRouter()
const userStore = useUserStore().user //
@ -278,12 +280,14 @@ const handleFileChange = ()=> {
createAIPPTByFile(file)
}
}
// pptPPT线
const createAIPPTByFile = async (file)=> {
pgDialog.value.visible = true
pgDialog.value.pg.percentage = 0
// pgDialog.value.visible = true
// pgDialog.value.pg.percentage = 0
const resPptJson = await PPTXFileToJson(file)
const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线
let completed = 0
const total = slides.length
@ -335,6 +339,7 @@ const createAIPPTByFile = async (file)=> {
entpcourseid: resCourse.id,
title: '',
filetype: 'slide',
thumbnails, // -
slides: resSlides,
edituserid: userStore.userId
}

View File

@ -10,8 +10,8 @@
<div class="paragraphs">
{{ outputText }}
</div>
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">{{ outputText ? '重新生成' : '生成大纲' }}</el-button>
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1" :disabled="!outputText">下一步</el-button>
</el-card>
<el-card v-if="activeStep === 1">
<div style="padding-bottom: 10px">ppt模板选择</div>
@ -57,7 +57,7 @@
</el-row>
<div>
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
<el-button style="margin-bottom: 5px;" type="primary" v-loading="createPPTLoading" @click="outlineCreatePPT()">生成PPT</el-button>
<el-button style="margin-bottom: 5px;" type="primary" :loading="createPPTLoading" @click="outlineCreatePPT()">生成PPT</el-button>
</div>
</el-card>
<el-card v-if="activeStep === 2">
@ -177,6 +177,8 @@ const outlineCreatePPT = () => {
};
checkProgress();
}).finally(()=>{
createPPTLoading.value = false
})
};

View File

@ -25,7 +25,7 @@
<c-form v-bind="classForm">
<template #item_classid="{prop, form}">
<span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span>
<el-select v-else v-model="form[prop]" placeholder="请选择班级">
<el-select v-else v-model="form[prop]" placeholder="请选择班级" clearable>
<el-option v-for="item in listData.classList" :value="item.id"
:label="`${item.caption} (${item.classstudentcount}人)`" />
</el-select>
@ -249,10 +249,10 @@ const getClasscourseList = async type => {
// isPublic
const createClasscourse = async (isPublic = false) => {
const { classid } = classForm.form
if (!classid) {
ElMessage.warning('请选择班级')
return
}
// if (!classid) {
// ElMessage.warning('')
// return
// }
dt.loading = true
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value //
const curDate = commUtil.getDateNow('yyyy-MM-dd')
@ -372,9 +372,9 @@ const openPublicScreen = (classcourse, isPublic) => {
createWindow('open-win', {
url: '/pptist', //
close: () => {
sessionStore.set('curr.resource', null) //
sessionStore.set('curr.classcourse', null) //
sessionStore.set('curr.isPublic', null) //
sessionStore.delete('curr.resource') //
sessionStore.delete('curr.classcourse') //
sessionStore.delete('curr.isPublic') //
}
})
visible.value = false //

View File

@ -205,13 +205,12 @@ import TreeLog from '@/views/prepare/components/treeLog.vue'
import classStart from './container/class-start.vue' //
import MsgEnum from '@/plugins/imChat/msgEnum' // im
import * as commUtils from "@/utils/comm";
import * as Api_server from "@/api/apiService";
import msgUtils from "@/plugins/modal";
import * as Api_server from "@/api/apiService";
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
import { slidesToImg } from '@/utils/ppt' // ppt
import ChatWs from '@/plugins/socket' // socket
if (!ChatWs.ws) ChatWs.init()
// import Chat from '@/utils/chat' // im
// if (!Chat.imChat) Chat.init()
const toolStore = useToolState()
const fs = require('fs')
@ -498,11 +497,11 @@ export default {
createWindow('open-win', {
url: '/pptist', //
close: () => {
sessionStore.set('curr.resource', null) //
sessionStore.delete('curr.resource') //
if (type=='edit') {
sessionStore.set('curr.smarttalk', null) //
sessionStore.delete('curr.smarttalk') //
this.asyncAllFile() //
} else sessionStore.set('curr.classcourse', null) //
} else sessionStore.delete('curr.classcourse') //
}
})
},
@ -573,8 +572,9 @@ export default {
},500)
})
},
openFilePicker(){
async openFilePicker(){
this.$refs.fileInput.click();
// const files = await commUtils.getFiles()
},
handleFileChange(){
const file = event.target.files[0];
@ -634,6 +634,8 @@ export default {
this.pgDialog.pg.percentage = 0
const resPptJson = await PPTXFileToJson(file)
const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线
let completed = 0
const total = slides.length
@ -686,6 +688,7 @@ export default {
title: '',
filetype: 'slide',
slides: resSlides,
thumbnails, //
edituserid: this.userStore.userId
}
const res_3 = await API_entpcoursefile.batchAddNew(params)

View File

@ -93,6 +93,9 @@ emitter.on('onGetMain', (item) => {
const emit = defineEmits([''])
const onSelect = (item) =>{
actId.value = item.id
item.child.forEach(el =>{
el.aiShow = false
})
emitter.emit('changeMode', item)
}

View File

@ -14,8 +14,7 @@
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
<el-button type="primary">生成大纲</el-button>
<el-button type="danger" @click="pptDialog = true">生成PPT</el-button>
<el-button type="danger" @click="onCreate">生成PPT</el-button>
</div>
</div>
<div class="right-con flex" ref="listRef">
@ -95,6 +94,7 @@ import * as API_smarttalk from '@/api/file' // 文件相关api
import msgUtils from '@/plugins/modal'
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
import { createWindow } from '@/utils/tool' //
import { slidesToImg } from '@/utils/ppt' // ppt
const userStore = useUserStore()
const pptDialog = ref(false)
@ -136,6 +136,16 @@ emitter.on('changeMode', (item) => {
getTempResult(item.id)
})
const onCreate = () =>{
let isAnswer = resultList.value.every(item => !item.answer)
if(isAnswer){
ElMessage.warning('请先进行研读')
return
}
pptDialog.value = true
}
//
const getCompletion = async () => {
@ -196,7 +206,7 @@ const handleCompleteText = async (answer, index) => {
}
//
const onSaveTemp = (item) => {
const onSaveTemp = async (item) => {
if (item.answer == '') return
const data = {
@ -206,7 +216,11 @@ const onSaveTemp = (item) => {
content: item.answer,
ex1: curNode.id
}
tempSave(data).then(res => { })
const res = await tempSave(data)
if(!item.resultId){
item.resultId = res.data
}
}
const isWordDialog = ref(false)
@ -258,7 +272,7 @@ const listRef = ref()
//
const isStarted = ref([]);
const getTempResult = (id) => {
tempResult({ mainModelId: id }).then(res => {
tempResult({ mainModelId: id, pageNum: 1, pageSize: 10000, ex1: curNode.id }).then(res => {
let rows = res.rows
if (rows.length > 0) {
isStarted.value = new Array(rows.length).fill(true)
@ -314,6 +328,7 @@ const prompt = ref('')
const addAiPPT = async (res) => {
// res = { url: 'https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx' }
let node = courseObj.node
pptDialog.value = false;
if (!node) return msgUtils.msgWarning('请选择章节?')
@ -332,6 +347,8 @@ const addAiPPT = async (res) => {
.then(async buffer => {
const resPptJson = await PPTXFileToJson(buffer)
const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线
let completed = 0
const total = slides.length
@ -351,7 +368,7 @@ const addAiPPT = async (res) => {
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
if (slides.length > 0) {
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
const params = { parentid, filetype: 'slide', title: '', slides: resSlides }
const params = { parentid, filetype: 'slide', title: '', thumbnails, slides: resSlides }
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
if (res_3 && res_3.code == 200) {
msgUtils.msgSuccess('生成PPT课件成功')