Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl
This commit is contained in:
commit
1a3598d7c0
|
@ -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/'
|
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
|
||||||
|
|
||||||
# websocket 地址
|
# websocket 地址
|
||||||
|
# VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
||||||
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865'
|
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "aix-win-ws",
|
"name": "aix-win-ws",
|
||||||
"version": "2.5.8",
|
"version": "2.5.9",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "上海交大重庆人工智能研究院",
|
"author": "上海交大重庆人工智能研究院",
|
||||||
|
|
|
@ -14,7 +14,8 @@ export default () => {
|
||||||
const courseId = classcourse?.id // 课堂id
|
const courseId = classcourse?.id // 课堂id
|
||||||
const timgroupid = classcourse?.timgroupid // 群组id
|
const timgroupid = classcourse?.timgroupid // 群组id
|
||||||
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
// 上课状态才-初始化socket
|
||||||
|
if (!ChatWs.ws && !!courseId) ChatWs.init()
|
||||||
// 开课消息
|
// 开课消息
|
||||||
const startCourse = async() => {
|
const startCourse = async() => {
|
||||||
// await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'open' })
|
// await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'open' })
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
export default class gridPic {
|
||||||
|
private static Instance: gridPic | null = null;
|
||||||
|
private gridPicRef: any = null;
|
||||||
|
|
||||||
|
constructor(elRef?: any) {
|
||||||
|
if (elRef) {
|
||||||
|
this.gridPicRef = elRef;
|
||||||
|
}
|
||||||
|
if (!gridPic.Instance) {
|
||||||
|
gridPic.Instance = this;
|
||||||
|
}
|
||||||
|
return gridPic.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init(elRef) {
|
||||||
|
if (elRef) {
|
||||||
|
this.gridPicRef = elRef;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPIc(data) {
|
||||||
|
if (this.gridPicRef && this.gridPicRef.value && typeof this.gridPicRef.value.addPic === 'function') {
|
||||||
|
this.gridPicRef.value.addPic(data);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 静态方法 - 初始化
|
||||||
|
static init(elRef) {
|
||||||
|
if (!gridPic.Instance) {
|
||||||
|
gridPic.Instance = new gridPic(elRef);
|
||||||
|
} else {
|
||||||
|
gridPic.Instance.init(elRef);
|
||||||
|
}
|
||||||
|
return gridPic.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 静态方法 - 打开推图上屏幕
|
||||||
|
static addPIc(data) {
|
||||||
|
if (gridPic.Instance) {
|
||||||
|
return gridPic.Instance.addPIc(data);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -274,6 +274,7 @@ export class PPTApi {
|
||||||
static toRousrceUrl =async (o:any) => {
|
static toRousrceUrl =async (o:any) => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', o)
|
formData.append('file', o)
|
||||||
|
formData.append('ral', true)
|
||||||
const res = await Api_server.Other.uploadFile(formData)
|
const res = await Api_server.Other.uploadFile(formData)
|
||||||
if (res && res.code == 200){
|
if (res && res.code == 200){
|
||||||
const url = res?.url
|
const url = res?.url
|
||||||
|
|
|
@ -132,6 +132,8 @@ export class MsgEnum {
|
||||||
MSG_dz : 'dz',
|
MSG_dz : 'dz',
|
||||||
/** @desc: 疑惑 */
|
/** @desc: 疑惑 */
|
||||||
MSG_yh : 'yh',
|
MSG_yh : 'yh',
|
||||||
|
/** @desc: 推图片上屏 */
|
||||||
|
MSG_pushSreen_ImgList : 'pushSreen_ImgList',
|
||||||
// === 新定义-消息头 ===
|
// === 新定义-消息头 ===
|
||||||
/** @desc: 课程创建-待开课 */
|
/** @desc: 课程创建-待开课 */
|
||||||
MSG_0000: 0x0000,
|
MSG_0000: 0x0000,
|
||||||
|
|
|
@ -12,9 +12,10 @@ import Classcourse from './classcourse' // 课程相关
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
import * as dialogUtils from '@/utils/dialog' // 弹窗-函数
|
import * as dialogUtils from '@/utils/dialog' // 弹窗-函数
|
||||||
import { Homework } from './index' // api-作业相关
|
import { Homework } from './index' // api-作业相关
|
||||||
// import emitter from '@/utils/mitt' //mitt 事件总线
|
import emitter from '@/utils/mitt' //mitt 事件总线
|
||||||
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
||||||
import hooksUpvote from './upvote' // 点赞-工具
|
import hooksUpvote from './upvote' // 点赞-工具
|
||||||
|
import gridPic from './gridPic' // 上屏-工具
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 监听器
|
* @description 监听器
|
||||||
|
@ -98,6 +99,7 @@ export default () => {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
|
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
|
||||||
|
emitter.emit('closegridPic')
|
||||||
const slideIndex = content?.current || 0
|
const slideIndex = content?.current || 0
|
||||||
const type = content?.animation // 上下动作
|
const type = content?.animation // 上下动作
|
||||||
const steps = content?.animationSteps // 动画步骤
|
const steps = content?.animationSteps // 动画步骤
|
||||||
|
@ -128,6 +130,10 @@ export default () => {
|
||||||
case MsgEnum.HEADS.MSG_yh: // 疑惑
|
case MsgEnum.HEADS.MSG_yh: // 疑惑
|
||||||
hooksUpvote.trigger(2)
|
hooksUpvote.trigger(2)
|
||||||
break
|
break
|
||||||
|
case MsgEnum.HEADS.MSG_pushSreen_ImgList: // 推图片上屏
|
||||||
|
const imgArray = content.ImgList.map((obj) => obj.url);
|
||||||
|
emitter.emit('opengridPic',{arr:imgArray})
|
||||||
|
break
|
||||||
case MsgEnum.HEADS.MSG_0010: // 备用
|
case MsgEnum.HEADS.MSG_0010: // 备用
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
@ -142,4 +148,14 @@ export default () => {
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
// setTimeout(async () => {
|
||||||
|
// emitter.emit('opengridPic',{arr:['https://prev.ysaix.com:7868/src/assets/images/homecard4.jpg']})
|
||||||
|
// }, 3000)
|
||||||
|
|
||||||
|
// setTimeout(async () => {
|
||||||
|
// emitter.emit('closegridPic')
|
||||||
|
// }, 6000)
|
||||||
|
// setTimeout(async () => {
|
||||||
|
// emitter.emit('opengridPic',{arr:['https://prev.ysaix.com:7868/src/assets/images/homecard4.jpg','https://prev.ysaix.com:7868/src/assets/images/homecard4.jpg']})
|
||||||
|
// }, 9000)
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
|
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
|
||||||
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
||||||
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
@ -25,6 +26,9 @@ export default () => {
|
||||||
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
||||||
console.log('退出放映状态')
|
console.log('退出放映状态')
|
||||||
ChatWs?.close() // 关闭ws
|
ChatWs?.close() // 关闭ws
|
||||||
|
sessionStore.delete('curr.classcourse') // 清除课堂信息
|
||||||
|
sessionStore.delete('curr.resource') // 清除课件信息
|
||||||
|
sessionStore.delete('curr.isPublic') // 清除公屏状态
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { sessionStore } from '@/utils/store'
|
||||||
import { getSmarttalkPage } from '@/api/file'
|
import { getSmarttalkPage } from '@/api/file'
|
||||||
import * as commUtils from '@/utils/comm.js'
|
import * as commUtils from '@/utils/comm.js'
|
||||||
import { getFileSuffix } from '@/utils/ruoyi.js'
|
import { getFileSuffix } from '@/utils/ruoyi.js'
|
||||||
|
import { PPTApi } from '../../../api'
|
||||||
|
|
||||||
const emit = defineEmits(['insertMaterial', 'close'])
|
const emit = defineEmits(['insertMaterial', 'close'])
|
||||||
|
|
||||||
|
@ -60,73 +61,31 @@ const fileUrl = computed(() => (item) =>{
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// 插入
|
// 插入
|
||||||
const onInsert = async (item) =>{
|
const onInsert = async (item) =>{
|
||||||
|
loading.value = true
|
||||||
const res = await fetch(item.fileFullPath)
|
const res = await fetch(item.fileFullPath)
|
||||||
const bolb = await res.blob()
|
const bolb = await res.blob()
|
||||||
const file = commUtils.blobToFile(bolb, item.fileShowName)
|
const file = commUtils.blobToFile(bolb, item.fileShowName)
|
||||||
|
|
||||||
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
try {
|
||||||
emit('insertMaterial',{ type: 'video', file })
|
const data = await PPTApi.toRousrceUrl(file)
|
||||||
}
|
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
||||||
else{
|
emit('insertMaterial',{ type: 'video', data })
|
||||||
emit('insertMaterial',{ type: 'img', file })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
emit('insertMaterial',{ type: 'img', data })
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
}
|
}
|
||||||
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 = () =>{
|
const onClose = () =>{
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let data = sessionStore.get('subject.curNode')
|
let data = sessionStore.get('subject.curNode')
|
||||||
Object.assign(curNode, data);
|
Object.assign(curNode, data);
|
||||||
|
|
|
@ -281,20 +281,17 @@ const toggleNotesPanel = () => {
|
||||||
// 插入素材
|
// 插入素材
|
||||||
interface MaterialParams {
|
interface MaterialParams {
|
||||||
type: string,
|
type: string,
|
||||||
file: any
|
data: string
|
||||||
}
|
}
|
||||||
const insertMaterial = (item: MaterialParams) =>{
|
const insertMaterial = async (item: MaterialParams) =>{
|
||||||
const { type, file } = item
|
const { type, data } = item
|
||||||
PPTApi.toRousrceUrl(file).then(data=>{
|
if(type == 'video'){
|
||||||
if(type == 'video'){
|
createVideoElement(data)
|
||||||
createVideoElement(data)
|
}
|
||||||
}
|
else{
|
||||||
else{
|
createImageElement(data)
|
||||||
createImageElement(data)
|
}
|
||||||
}
|
materiaVisible.value = false
|
||||||
materiaVisible.value = false
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文生图
|
// 文生图
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible">
|
<Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible">
|
||||||
<template #content>
|
<template #content>
|
||||||
<FileInput accept=".pptist" @change="files => {
|
<!-- <FileInput accept=".pptist" @change="files => {
|
||||||
importSpecificFile(files)
|
importSpecificFile(files)
|
||||||
mainMenuVisible = false
|
mainMenuVisible = false
|
||||||
}">
|
}">
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
}">
|
}">
|
||||||
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
|
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
|
||||||
</FileInput>
|
</FileInput>
|
||||||
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem>
|
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem> -->
|
||||||
<PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</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/issues')">意见反馈</PopoverMenuItem> -->
|
||||||
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
|
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
|
||||||
<PopoverMenuItem @click="mainMenuVisible = false; hotkeyDrawerVisible = true">快捷操作</PopoverMenuItem>
|
<PopoverMenuItem @click="mainMenuVisible = false; hotkeyDrawerVisible = true">快捷操作</PopoverMenuItem>
|
||||||
|
@ -54,9 +54,9 @@
|
||||||
<div class="arrow-btn"><IconDown class="arrow" /></div>
|
<div class="arrow-btn"><IconDown class="arrow" /></div>
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
|
<!-- <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
|
||||||
<IconDownload class="icon" />
|
<IconDownload class="icon" />
|
||||||
</div>
|
</div> -->
|
||||||
<div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`">
|
<div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`">
|
||||||
<el-avatar size="small" :src="avatar" />
|
<el-avatar size="small" :src="avatar" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -88,7 +88,9 @@ import Button from '../../../../components/Button.vue'
|
||||||
import ButtonGroup from '../../../../components/ButtonGroup.vue'
|
import ButtonGroup from '../../../../components/ButtonGroup.vue'
|
||||||
import Popover from '../../../../components/Popover.vue'
|
import Popover from '../../../../components/Popover.vue'
|
||||||
import NumberInput from '../../../../components/NumberInput.vue'
|
import NumberInput from '../../../../components/NumberInput.vue'
|
||||||
|
import { PPTApi } from '../../../../api'
|
||||||
|
import { Console } from 'node:console'
|
||||||
|
import { x64 } from 'crypto-js'
|
||||||
const shapeClipPathOptions = CLIPPATHS
|
const shapeClipPathOptions = CLIPPATHS
|
||||||
const ratioClipOptions = [
|
const ratioClipOptions = [
|
||||||
{
|
{
|
||||||
|
@ -221,10 +223,14 @@ const presetImageClip = (shape: string, ratio = 0) => {
|
||||||
const replaceImage = (files: FileList) => {
|
const replaceImage = (files: FileList) => {
|
||||||
const imageFile = files[0]
|
const imageFile = files[0]
|
||||||
if (!imageFile) return
|
if (!imageFile) return
|
||||||
getImageDataURL(imageFile).then(dataURL => {
|
PPTApi.toRousrceUrl(imageFile).then(data=>{
|
||||||
const props = { src: dataURL }
|
const props = { src: data }
|
||||||
updateImage(props)
|
updateImage(props)
|
||||||
})
|
})
|
||||||
|
// getImageDataURL(imageFile).then(dataURL => {
|
||||||
|
// const props = { src: dataURL }
|
||||||
|
// updateImage(props)
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置图片:清除全部样式
|
// 重置图片:清除全部样式
|
||||||
|
|
|
@ -1,16 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="pptist-screen">
|
<div class="pptist-screen">
|
||||||
<BaseView :changeViewMode="changeViewMode" v-if="viewMode === 'base'" />
|
<BaseView :changeViewMode="changeViewMode" v-if="viewMode === 'base'" />
|
||||||
<PresenterView :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" />
|
<PresenterView :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" />
|
||||||
<!-- 点赞组件 -->
|
<!-- 点赞组件 -->
|
||||||
<upvote-vue ref="upvoteRef" type="2"></upvote-vue>
|
<upvote-vue ref="upvoteRef" type="2"></upvote-vue>
|
||||||
<!-- <div style="z-index: 999;position: absolute;top:10px">
|
<!-- <div style="z-index: 999;position: absolute;top:10px">
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<!-- 推图上屏弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:fullscreen="true"
|
||||||
|
class="gridPicRefdiv"
|
||||||
|
style="overflow: hidden;"
|
||||||
|
:show-close="false"
|
||||||
|
>
|
||||||
|
<grid-pic ref="gridPicRef" style="height:100%;" @clear="clearchidrenPic"></grid-pic>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref } from 'vue'
|
import { onMounted, onUnmounted, ref , nextTick} from 'vue'
|
||||||
import { KEYS } from '../../configs/hotkey'
|
import { KEYS } from '../../configs/hotkey'
|
||||||
import useScreening from '../../hooks/useScreening'
|
import useScreening from '../../hooks/useScreening'
|
||||||
import hooksUpvote from '../../api/upvote' // 点赞-工具
|
import hooksUpvote from '../../api/upvote' // 点赞-工具
|
||||||
|
@ -18,9 +28,13 @@ import hooksUpvote from '../../api/upvote' // 点赞-工具
|
||||||
import BaseView from './BaseView.vue'
|
import BaseView from './BaseView.vue'
|
||||||
import PresenterView from './PresenterView.vue'
|
import PresenterView from './PresenterView.vue'
|
||||||
import upvoteVue from '@/views/tool/components/upvote.vue' // 点赞-子组件
|
import upvoteVue from '@/views/tool/components/upvote.vue' // 点赞-子组件
|
||||||
|
import gridPic from '@/components/grid-pic/index.vue' // 推图上屏弹子组件
|
||||||
|
|
||||||
|
import emitter from '@/utils/mitt' //mitt 事件总线
|
||||||
|
|
||||||
const viewMode = ref<'base' | 'presenter'>('base')
|
const viewMode = ref<'base' | 'presenter'>('base')
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const gridPicRef:any= ref(null)
|
||||||
const changeViewMode = (mode: 'base' | 'presenter') => {
|
const changeViewMode = (mode: 'base' | 'presenter') => {
|
||||||
viewMode.value = mode
|
viewMode.value = mode
|
||||||
}
|
}
|
||||||
|
@ -35,6 +49,23 @@ const keydownListener = (e: KeyboardEvent) => {
|
||||||
if (key === KEYS.ESC) exitScreening()
|
if (key === KEYS.ESC) exitScreening()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clearchidrenPic= ()=> {
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开启推图上屏幕
|
||||||
|
emitter.on('opengridPic', async (data:object)=> {
|
||||||
|
if(gridPicRef.value) gridPicRef.value.clearPic()
|
||||||
|
dialogVisible.value = true
|
||||||
|
await nextTick();
|
||||||
|
gridPicRef.value.addPic(data.arr)
|
||||||
|
});
|
||||||
|
// 关闭推图
|
||||||
|
emitter.on('closegridPic', ()=> {
|
||||||
|
if(!gridPicRef.value) return
|
||||||
|
gridPicRef.value.clearPic()
|
||||||
|
dialogVisible.value = false
|
||||||
|
});
|
||||||
onMounted(() => document.addEventListener('keydown', keydownListener))
|
onMounted(() => document.addEventListener('keydown', keydownListener))
|
||||||
onUnmounted(() => document.removeEventListener('keydown', keydownListener))
|
onUnmounted(() => document.removeEventListener('keydown', keydownListener))
|
||||||
</script>
|
</script>
|
||||||
|
@ -46,4 +77,8 @@ onUnmounted(() => document.removeEventListener('keydown', keydownListener))
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.gridPicRefdiv .el-dialog__body){
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -80,6 +80,15 @@ export function updateClassworkdata(data) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批阅后, 待所有学生都批改完成后自动结束当前作业为[已完成]
|
||||||
|
export function updateClassWorkDataAutoFinish(data) {
|
||||||
|
return request({
|
||||||
|
url: '/education/classworkdata/updAutoFinish',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 修改classwork
|
// 修改classwork
|
||||||
export function updateClasswork(data) {
|
export function updateClasswork(data) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
<draggable handle=".header-btn" :draggable="false" item-key="backgroundColor" v-model="gridPicList" class="grid-pic-wrap" :style="getGrid">
|
<draggable handle=".header-btn" :draggable="false" item-key="backgroundColor" v-model="gridPicList" class="grid-pic-wrap" :style="getGrid">
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
<div class="grid-pic-item" :key="element.backgroundColor" :style="getWH(element,index)">
|
<div class="grid-pic-item" :key="element.backgroundColor" :style="getWH(element,index)">
|
||||||
<div class="delete-btn" @click="gridPicList.splice(index,1)">X</div>
|
<div class="delete-btn" @click="()=>{gridPicList.splice(index,1);if(!gridPicList.length) emits('clear')} ">X</div>
|
||||||
<div class="header-btn"></div>
|
<div class="header-btn"></div>
|
||||||
<ViewerItem :gridPicList="gridPicList" :index="index" :images="element"></ViewerItem>
|
<ViewerItem :gridPicList="gridPicList" :index="index" :images="element"></ViewerItem>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
<div v-if="showToolbar" class="grid-pic-toolbar">
|
<div class="grid-pic-toolbar">
|
||||||
<el-input style="width: 500px" v-model="inputValue" type="text" />
|
<el-input v-if="showToolbar" style="width: 500px" v-model="inputValue" type="text" />
|
||||||
<el-button class="add-btn" @click="pushPic">
|
<el-button v-if="showToolbar" class="add-btn" @click="pushPic">
|
||||||
添加
|
添加
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button class="add-btn" @click="clearPic">
|
<el-button class="add-btn" @click="clearPic">
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
showToolbar: {
|
showToolbar: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// 获取图片样式
|
// 获取图片样式
|
||||||
|
@ -149,20 +149,26 @@
|
||||||
addPic(src)
|
addPic(src)
|
||||||
}
|
}
|
||||||
// 添加图片
|
// 添加图片
|
||||||
const addPic = (src) => {
|
const addPic = (data) => {
|
||||||
if (gridPicList.value.length >= 9) {
|
let list = Array.isArray(data)?data:[data]
|
||||||
|
if (gridPicList.value.length + list.length > 9) {
|
||||||
console.log("超出九个图片")
|
console.log("超出九个图片")
|
||||||
emits('outIndex')
|
emits('outIndex')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!src) {
|
let listArr = [];
|
||||||
console.log("图片链接不能为空")
|
for (let i = 0; i < list.length; i++) {
|
||||||
return;
|
let src = list[i]
|
||||||
|
if (!src) {
|
||||||
|
console.log("图片链接不能为空")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listArr.push({
|
||||||
|
src: src,
|
||||||
|
backgroundColor: getRandomColor()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
gridPicList.value.push({
|
gridPicList.value.push(...listArr)
|
||||||
src: src,
|
|
||||||
backgroundColor: getRandomColor()
|
|
||||||
})
|
|
||||||
inputValue.value = ''
|
inputValue.value = ''
|
||||||
}
|
}
|
||||||
// 清空图片
|
// 清空图片
|
||||||
|
|
|
@ -140,5 +140,8 @@ watch(props.images, (newValue, oldValue) => {
|
||||||
.viewer-item-wrap{
|
.viewer-item-wrap{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
:deep(.viewer-canvas img) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -415,7 +415,7 @@ const onEditSave = async (item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
const onSaveTemp = (item) => {
|
const onSaveTemp = async (item) => {
|
||||||
if (item.answer == '') return
|
if (item.answer == '') return
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -425,7 +425,10 @@ const onSaveTemp = (item) => {
|
||||||
content: item.answer,
|
content: item.answer,
|
||||||
ex1: curNode.id
|
ex1: curNode.id
|
||||||
}
|
}
|
||||||
tempSave(data).then(res => { })
|
const res = await tempSave(data)
|
||||||
|
if(!item.resultId){
|
||||||
|
item.resultId = res.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去掉字符串中的 ### **
|
// 去掉字符串中的 ### **
|
||||||
|
|
|
@ -508,6 +508,11 @@ const backToCenter = () => {
|
||||||
app.scrollToCenter()
|
app.scrollToCenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cancelActiveElement = () =>{
|
||||||
|
app.cancelActiveElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 显示全部
|
// 显示全部
|
||||||
const showFit = () => {
|
const showFit = () => {
|
||||||
let elementList = app.elements.elementList
|
let elementList = app.elements.elementList
|
||||||
|
@ -701,8 +706,6 @@ const getCanvasBlob = async () =>{
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
watch(() => props.data, (newVal) => {
|
watch(() => props.data, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
setCanvasData(newVal)
|
setCanvasData(newVal)
|
||||||
|
@ -838,7 +841,8 @@ defineExpose({
|
||||||
getCanvasJson,
|
getCanvasJson,
|
||||||
getCanvasBase64,
|
getCanvasBase64,
|
||||||
setCanvasData,
|
setCanvasData,
|
||||||
getCanvasBlob
|
getCanvasBlob,
|
||||||
|
cancelActiveElement
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -435,7 +435,7 @@ import useUserStore from '@/store/modules/user'
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
// import { Plus } from '@element-plus/icons-vue'
|
// import { Plus } from '@element-plus/icons-vue'
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
import { updateClassworkeval, updateClassworkdata, getClassworkdata } from '@/api/classTask'
|
import { updateClassworkeval, getClassworkdata, updateClassWorkDataAutoFinish } from '@/api/classTask'
|
||||||
import { getTimeDate } from '@/utils/date'
|
import { getTimeDate } from '@/utils/date'
|
||||||
import ReFilePreview from '@/components/refile-preview/index.vue'
|
import ReFilePreview from '@/components/refile-preview/index.vue'
|
||||||
import { quizStrToList } from '@/utils/comm';
|
import { quizStrToList } from '@/utils/comm';
|
||||||
|
@ -890,7 +890,7 @@ const onSubmit = () => {
|
||||||
updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm;
|
updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm;
|
||||||
};
|
};
|
||||||
// 更新作业批改状态
|
// 更新作业批改状态
|
||||||
updateClassworkdata(formd).then(res => {
|
updateClassWorkDataAutoFinish(formd).then(res => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新题目批改
|
// 更新题目批改
|
||||||
|
|
|
@ -83,6 +83,8 @@ import useUserStore from '@/store/modules/user' // 用户信息
|
||||||
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import KjListItem from '@/views/prepare/container/kj-list-item.vue'
|
import KjListItem from '@/views/prepare/container/kj-list-item.vue'
|
||||||
import FileImage from '@/components/file-image/index.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 {creatAPT, getSmarttalkPage, getModelInfo} from '@/api/file'
|
||||||
import {ArrowDown, Flag, Position} from '@element-plus/icons-vue'
|
import {ArrowDown, Flag, Position} from '@element-plus/icons-vue'
|
||||||
import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile";
|
import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile";
|
||||||
|
@ -94,11 +96,11 @@ import {createWindow, toLinkLeftWeb} from "@/utils/tool";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
|
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
|
||||||
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
||||||
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
|
|
||||||
import msgUtils from "@/plugins/modal";
|
import msgUtils from "@/plugins/modal";
|
||||||
import * as commUtils from "@/utils/comm";
|
import * as commUtils from "@/utils/comm";
|
||||||
import * as Api_server from "@/api/apiService"; // 学科名字文生图
|
import * as Api_server from "@/api/apiService"; // 学科名字文生图
|
||||||
import useClassTaskStore from '@/store/modules/classTask'
|
import useClassTaskStore from '@/store/modules/classTask'
|
||||||
|
import { slidesToImg } from '@/utils/ppt' // ppt相关工具
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore().user // 用户信息
|
const userStore = useUserStore().user // 用户信息
|
||||||
|
@ -278,12 +280,14 @@ const handleFileChange = ()=> {
|
||||||
createAIPPTByFile(file)
|
createAIPPTByFile(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ppt文件转PPT线上数据
|
||||||
const createAIPPTByFile = async (file)=> {
|
const createAIPPTByFile = async (file)=> {
|
||||||
pgDialog.value.visible = true
|
// pgDialog.value.visible = true
|
||||||
pgDialog.value.pg.percentage = 0
|
// pgDialog.value.pg.percentage = 0
|
||||||
const resPptJson = await PPTXFileToJson(file)
|
const resPptJson = await PPTXFileToJson(file)
|
||||||
const { def, slides, ...content } = resPptJson
|
const { def, slides, ...content } = resPptJson
|
||||||
|
// 生成缩略图
|
||||||
|
const thumbnails = await slidesToImg(slides, content.width)
|
||||||
// 转换图片|音频|视频 为线上地址
|
// 转换图片|音频|视频 为线上地址
|
||||||
let completed = 0
|
let completed = 0
|
||||||
const total = slides.length
|
const total = slides.length
|
||||||
|
@ -335,6 +339,7 @@ const createAIPPTByFile = async (file)=> {
|
||||||
entpcourseid: resCourse.id,
|
entpcourseid: resCourse.id,
|
||||||
title: '',
|
title: '',
|
||||||
filetype: 'slide',
|
filetype: 'slide',
|
||||||
|
thumbnails, // 缩略图-列表
|
||||||
slides: resSlides,
|
slides: resSlides,
|
||||||
edituserid: userStore.userId
|
edituserid: userStore.userId
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
<div class="paragraphs">
|
<div class="paragraphs">
|
||||||
{{ outputText }}
|
{{ outputText }}
|
||||||
</div>
|
</div>
|
||||||
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</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">下一步</el-button>
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1" :disabled="!outputText">下一步</el-button>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card v-if="activeStep === 1">
|
<el-card v-if="activeStep === 1">
|
||||||
<div style="padding-bottom: 10px">ppt模板选择</div>
|
<div style="padding-bottom: 10px">ppt模板选择</div>
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
<div>
|
<div>
|
||||||
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
|
<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>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card v-if="activeStep === 2">
|
<el-card v-if="activeStep === 2">
|
||||||
|
@ -177,6 +177,8 @@ const outlineCreatePPT = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
checkProgress();
|
checkProgress();
|
||||||
|
}).finally(()=>{
|
||||||
|
createPPTLoading.value = false
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
<c-form v-bind="classForm">
|
<c-form v-bind="classForm">
|
||||||
<template #item_classid="{prop, form}">
|
<template #item_classid="{prop, form}">
|
||||||
<span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span>
|
<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"
|
<el-option v-for="item in listData.classList" :value="item.id"
|
||||||
:label="`${item.caption} (${item.classstudentcount}人)`" />
|
:label="`${item.caption} (${item.classstudentcount}人)`" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</c-form>
|
</c-form>
|
||||||
|
@ -249,10 +249,10 @@ const getClasscourseList = async type => {
|
||||||
// 创建课程 isPublic 公屏上课
|
// 创建课程 isPublic 公屏上课
|
||||||
const createClasscourse = async (isPublic = false) => {
|
const createClasscourse = async (isPublic = false) => {
|
||||||
const { classid } = classForm.form
|
const { classid } = classForm.form
|
||||||
if (!classid) {
|
// if (!classid) {
|
||||||
ElMessage.warning('请选择班级')
|
// ElMessage.warning('请选择班级')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
dt.loading = true
|
dt.loading = true
|
||||||
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // 课件对象
|
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // 课件对象
|
||||||
const curDate = commUtil.getDateNow('yyyy-MM-dd')
|
const curDate = commUtil.getDateNow('yyyy-MM-dd')
|
||||||
|
@ -372,9 +372,9 @@ const openPublicScreen = (classcourse, isPublic) => {
|
||||||
createWindow('open-win', {
|
createWindow('open-win', {
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
close: () => {
|
close: () => {
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
sessionStore.delete('curr.resource') // 清除缓存
|
||||||
sessionStore.set('curr.classcourse', null) // 清除缓存
|
sessionStore.delete('curr.classcourse') // 清除缓存
|
||||||
sessionStore.set('curr.isPublic', null) // 清除缓存
|
sessionStore.delete('curr.isPublic') // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
visible.value = false // 关闭弹窗
|
visible.value = false // 关闭弹窗
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
|
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
|
||||||
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
|
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item>
|
<!-- <el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item>-->
|
||||||
<el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item>
|
<el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item>
|
||||||
<input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation">
|
<input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation">
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
|
@ -205,13 +205,12 @@ import TreeLog from '@/views/prepare/components/treeLog.vue'
|
||||||
import classStart from './container/class-start.vue' // 预备上课
|
import classStart from './container/class-start.vue' // 预备上课
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
||||||
import * as commUtils from "@/utils/comm";
|
import * as commUtils from "@/utils/comm";
|
||||||
import * as Api_server from "@/api/apiService";
|
|
||||||
import msgUtils from "@/plugins/modal";
|
import msgUtils from "@/plugins/modal";
|
||||||
|
import * as Api_server from "@/api/apiService";
|
||||||
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
||||||
|
import { slidesToImg } from '@/utils/ppt' // ppt相关工具
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
if (!ChatWs.ws) ChatWs.init()
|
||||||
// import Chat from '@/utils/chat' // im 登录初始化
|
|
||||||
// if (!Chat.imChat) Chat.init()
|
|
||||||
|
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
@ -498,11 +497,11 @@ export default {
|
||||||
createWindow('open-win', {
|
createWindow('open-win', {
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
close: () => {
|
close: () => {
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
sessionStore.delete('curr.resource') // 清除缓存
|
||||||
if (type=='edit') {
|
if (type=='edit') {
|
||||||
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
sessionStore.delete('curr.smarttalk') // 清除缓存
|
||||||
this.asyncAllFile() // 刷新资源列表
|
this.asyncAllFile() // 刷新资源列表
|
||||||
} else sessionStore.set('curr.classcourse', null) // 清除缓存
|
} else sessionStore.delete('curr.classcourse') // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -573,8 +572,9 @@ export default {
|
||||||
},500)
|
},500)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
openFilePicker(){
|
async openFilePicker(){
|
||||||
this.$refs.fileInput.click();
|
this.$refs.fileInput.click();
|
||||||
|
// const files = await commUtils.getFiles()
|
||||||
},
|
},
|
||||||
handleFileChange(){
|
handleFileChange(){
|
||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
|
@ -634,6 +634,8 @@ export default {
|
||||||
this.pgDialog.pg.percentage = 0
|
this.pgDialog.pg.percentage = 0
|
||||||
const resPptJson = await PPTXFileToJson(file)
|
const resPptJson = await PPTXFileToJson(file)
|
||||||
const { def, slides, ...content } = resPptJson
|
const { def, slides, ...content } = resPptJson
|
||||||
|
// 生成缩略图
|
||||||
|
const thumbnails = await slidesToImg(slides, content.width)
|
||||||
// 转换图片|音频|视频 为线上地址
|
// 转换图片|音频|视频 为线上地址
|
||||||
let completed = 0
|
let completed = 0
|
||||||
const total = slides.length
|
const total = slides.length
|
||||||
|
@ -686,6 +688,7 @@ export default {
|
||||||
title: '',
|
title: '',
|
||||||
filetype: 'slide',
|
filetype: 'slide',
|
||||||
slides: resSlides,
|
slides: resSlides,
|
||||||
|
thumbnails, // 缩略图
|
||||||
edituserid: this.userStore.userId
|
edituserid: this.userStore.userId
|
||||||
}
|
}
|
||||||
const res_3 = await API_entpcoursefile.batchAddNew(params)
|
const res_3 = await API_entpcoursefile.batchAddNew(params)
|
||||||
|
|
|
@ -93,6 +93,9 @@ emitter.on('onGetMain', (item) => {
|
||||||
const emit = defineEmits([''])
|
const emit = defineEmits([''])
|
||||||
const onSelect = (item) =>{
|
const onSelect = (item) =>{
|
||||||
actId.value = item.id
|
actId.value = item.id
|
||||||
|
item.child.forEach(el =>{
|
||||||
|
el.aiShow = false
|
||||||
|
})
|
||||||
emitter.emit('changeMode', item)
|
emitter.emit('changeMode', item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
|
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
|
||||||
<el-button type="primary">生成大纲</el-button>
|
<el-button type="danger" @click="onCreate">生成PPT</el-button>
|
||||||
<el-button type="danger" @click="pptDialog = true">生成PPT</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-con flex" ref="listRef">
|
<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 msgUtils from '@/plugins/modal'
|
||||||
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
|
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
import { createWindow } from '@/utils/tool' // 消息工具
|
import { createWindow } from '@/utils/tool' // 消息工具
|
||||||
|
import { slidesToImg } from '@/utils/ppt' // ppt相关工具
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const pptDialog = ref(false)
|
const pptDialog = ref(false)
|
||||||
|
@ -136,6 +136,16 @@ emitter.on('changeMode', (item) => {
|
||||||
getTempResult(item.id)
|
getTempResult(item.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const onCreate = () =>{
|
||||||
|
let isAnswer = resultList.value.every(item => !item.answer)
|
||||||
|
if(isAnswer){
|
||||||
|
ElMessage.warning('请先进行研读')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pptDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 一键研读
|
// 一键研读
|
||||||
const getCompletion = async () => {
|
const getCompletion = async () => {
|
||||||
|
@ -196,7 +206,7 @@ const handleCompleteText = async (answer, index) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
const onSaveTemp = (item) => {
|
const onSaveTemp = async (item) => {
|
||||||
if (item.answer == '') return
|
if (item.answer == '') return
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -206,7 +216,11 @@ const onSaveTemp = (item) => {
|
||||||
content: item.answer,
|
content: item.answer,
|
||||||
ex1: curNode.id
|
ex1: curNode.id
|
||||||
}
|
}
|
||||||
tempSave(data).then(res => { })
|
const res = await tempSave(data)
|
||||||
|
|
||||||
|
if(!item.resultId){
|
||||||
|
item.resultId = res.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isWordDialog = ref(false)
|
const isWordDialog = ref(false)
|
||||||
|
@ -258,7 +272,7 @@ const listRef = ref()
|
||||||
// 查询模板结果
|
// 查询模板结果
|
||||||
const isStarted = ref([]);
|
const isStarted = ref([]);
|
||||||
const getTempResult = (id) => {
|
const getTempResult = (id) => {
|
||||||
tempResult({ mainModelId: id }).then(res => {
|
tempResult({ mainModelId: id, pageNum: 1, pageSize: 10000, ex1: curNode.id }).then(res => {
|
||||||
let rows = res.rows
|
let rows = res.rows
|
||||||
if (rows.length > 0) {
|
if (rows.length > 0) {
|
||||||
isStarted.value = new Array(rows.length).fill(true)
|
isStarted.value = new Array(rows.length).fill(true)
|
||||||
|
@ -314,6 +328,7 @@ const prompt = ref('')
|
||||||
|
|
||||||
|
|
||||||
const addAiPPT = async (res) => {
|
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
|
let node = courseObj.node
|
||||||
pptDialog.value = false;
|
pptDialog.value = false;
|
||||||
if (!node) return msgUtils.msgWarning('请选择章节?')
|
if (!node) return msgUtils.msgWarning('请选择章节?')
|
||||||
|
@ -332,6 +347,8 @@ const addAiPPT = async (res) => {
|
||||||
.then(async buffer => {
|
.then(async buffer => {
|
||||||
const resPptJson = await PPTXFileToJson(buffer)
|
const resPptJson = await PPTXFileToJson(buffer)
|
||||||
const { def, slides, ...content } = resPptJson
|
const { def, slides, ...content } = resPptJson
|
||||||
|
// 生成缩略图
|
||||||
|
const thumbnails = await slidesToImg(slides, content.width)
|
||||||
// 转换图片|音频|视频 为线上地址
|
// 转换图片|音频|视频 为线上地址
|
||||||
let completed = 0
|
let completed = 0
|
||||||
const total = slides.length
|
const total = slides.length
|
||||||
|
@ -351,7 +368,7 @@ const addAiPPT = async (res) => {
|
||||||
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
||||||
if (slides.length > 0) {
|
if (slides.length > 0) {
|
||||||
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
|
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)
|
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
|
||||||
if (res_3 && res_3.code == 200) {
|
if (res_3 && res_3.code == 200) {
|
||||||
msgUtils.msgSuccess('生成PPT课件成功')
|
msgUtils.msgSuccess('生成PPT课件成功')
|
||||||
|
|
Loading…
Reference in New Issue