Merge branch 'main' into lyc-dev
This commit is contained in:
commit
7e9ac2bf74
|
@ -16,4 +16,9 @@ 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 地址
|
||||||
|
# VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
|
VITE_APP_WS_URL = 'ws://192.168.2.16:7865'
|
||||||
|
|
||||||
|
# 是否显示开发工具
|
||||||
VITE_SHOW_DEV_TOOLS = 'true'
|
VITE_SHOW_DEV_TOOLS = 'true'
|
||||||
|
|
|
@ -18,4 +18,8 @@ VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktx
|
||||||
|
|
||||||
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||||
|
|
||||||
|
# websocket 地址
|
||||||
|
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
|
|
||||||
|
# 是否显示开发工具
|
||||||
VITE_SHOW_DEV_TOOLS = 'false'
|
VITE_SHOW_DEV_TOOLS = 'false'
|
||||||
|
|
|
@ -28,6 +28,7 @@ import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关ap
|
||||||
import { PPTApi } from './api'
|
import { PPTApi } from './api'
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import './api/watcher' // 监听
|
import './api/watcher' // 监听
|
||||||
|
import './api/classcourse' // 课程相关
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const _isPC = isPC()
|
const _isPC = isPC()
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* @author zdg
|
||||||
|
* @description 上课相关内容
|
||||||
|
*/
|
||||||
|
import type { Classcourse } from './types'
|
||||||
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
|
import * as useStore from '../store' // pptist-状态管理
|
||||||
|
import { ChatWs } from '@/plugins/socket' // 聊天socket
|
||||||
|
const screenStore = useStore.useScreenStore() // 全屏-状态管理
|
||||||
|
const classcourseStore = useStore.useClasscourseStore() // 课堂信息-状态管理
|
||||||
|
const classcourse: Classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
||||||
|
|
||||||
|
// 如果课堂信息有值,则连接socket
|
||||||
|
if (!!classcourse) {
|
||||||
|
// 连接socket
|
||||||
|
const ws = new ChatWs()
|
||||||
|
console.log('ws- ',ws)
|
||||||
|
// ChatWs.connect(classcourse.id)
|
||||||
|
classcourseStore.setClasscourse(classcourse)
|
||||||
|
}
|
||||||
|
// 打开全屏
|
||||||
|
screenStore.setScreening(!!classcourse)
|
|
@ -11,10 +11,15 @@ import * as API_smarttalk from '@/api/file' // 相关api
|
||||||
import * as useStore from '../store' // pptist-状态管理
|
import * as useStore from '../store' // pptist-状态管理
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import useUserStore from '@/store/modules/user' // 外部-用户信息
|
import useUserStore from '@/store/modules/user' // 外部-用户信息
|
||||||
|
import * as Api_server from '@/api/apiService' // 相关api
|
||||||
|
import * as commUtils from '@/utils/comm.js'
|
||||||
const slidesStore = useStore.useSlidesStore()
|
const slidesStore = useStore.useSlidesStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
import { getClassWorkList,getStudentClassWorkData } from '@/views/tool/createHomework'
|
||||||
|
import {createWindow} from '@/utils/tool'
|
||||||
|
import { useToolState } from '@/store/modules/tool'
|
||||||
|
const toolStore = useToolState()
|
||||||
/** 工具类 */
|
/** 工具类 */
|
||||||
export class Utils {
|
export class Utils {
|
||||||
static mxData: any = {
|
static mxData: any = {
|
||||||
|
@ -55,7 +60,6 @@ export class PPTApi {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 }
|
const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 }
|
||||||
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
|
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
|
||||||
console.log(res.rows,'res.rows');
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const slides = (res.rows || []).map(o => {
|
const slides = (res.rows || []).map(o => {
|
||||||
if (!!o.datacontent) {
|
if (!!o.datacontent) {
|
||||||
|
@ -69,7 +73,8 @@ export class PPTApi {
|
||||||
// 活动列表处理
|
// 活动列表处理
|
||||||
const workList = (res.rows || []).map(o => o.activityContent)
|
const workList = (res.rows || []).map(o => o.activityContent)
|
||||||
const workItem = [...res.rows]
|
const workItem = [...res.rows]
|
||||||
slidesStore.updateSlideIndex(0) // 下标0 为第一页
|
// 加入活动后刷新ppt数据内容,不跟换为第一页
|
||||||
|
// slidesStore.updateSlideIndex(0) // 下标0 为第一页
|
||||||
slidesStore.setSlides(slides) // 写入数据
|
slidesStore.setSlides(slides) // 写入数据
|
||||||
// 写入作业列表数据
|
// 写入作业列表数据
|
||||||
slidesStore.setWorkList(workList)
|
slidesStore.setWorkList(workList)
|
||||||
|
@ -136,13 +141,15 @@ export class PPTApi {
|
||||||
id: currentSlide.id,
|
id: currentSlide.id,
|
||||||
datacontent: JSON.stringify(currentSlide),
|
datacontent: JSON.stringify(currentSlide),
|
||||||
}
|
}
|
||||||
Utils.mxThrottle(() => {this.updateSlide(params)}, 1000, 2)
|
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新幻灯片
|
// 更新幻灯片
|
||||||
static updateSlide(data: object): Promise<Boolean> {
|
static updateSlide(data: object): Promise<Boolean> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
|
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
|
||||||
|
console.log(data,'data');
|
||||||
|
console.log(res,'dresata');
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
|
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
|
||||||
|
@ -184,6 +191,30 @@ export class PPTApi {
|
||||||
else msgUtils.msgError(res.msg || '更新失败');return false
|
else msgUtils.msgError(res.msg || '更新失败');return false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 图片|音频|视频 转换为在线地址
|
||||||
|
static toRousrceUrl =async (o:any) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', o)
|
||||||
|
const res = await Api_server.Other.uploadFile(formData)
|
||||||
|
if (res && res.code == 200){
|
||||||
|
const url = res?.url
|
||||||
|
url &&(o.src = url)
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Homework{
|
||||||
|
// 作业弹窗
|
||||||
|
static async showHomework(id: any) {
|
||||||
|
let result = await getClassWorkList(id)
|
||||||
|
result = await getStudentClassWorkData()
|
||||||
|
localStorage.setItem('teachClassWorkItem', JSON.stringify(result[0]));
|
||||||
|
toolStore.isTaskWin=true; // 设置打开批改窗口
|
||||||
|
// emit('closeActive')
|
||||||
|
createWindow('open-taskwin',{url:'/teachClassTask'});
|
||||||
|
}
|
||||||
|
}
|
||||||
export default PPTApi
|
export default PPTApi
|
|
@ -6,3 +6,19 @@ export interface Result {
|
||||||
rows?: Array<any>,
|
rows?: Array<any>,
|
||||||
total?: number
|
total?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 课程信息 */
|
||||||
|
export interface Classcourse {
|
||||||
|
id?: number|string, // 课程id
|
||||||
|
coursetitle?: string, // 课程名称
|
||||||
|
coursetype?: string, // 课程类型
|
||||||
|
courseverid?: string, // 课程版本id
|
||||||
|
coursedesc?: string, // 课程描述
|
||||||
|
status?: number, // 课程状态
|
||||||
|
teacherid?: number|string, // 教师id
|
||||||
|
entpcoursefileid?: number|string, // 课程文件id
|
||||||
|
classid?: number|string, // 班级id
|
||||||
|
entpcourseid?: number|string, // 章节中间表id
|
||||||
|
plandate?: string, // 计划时间
|
||||||
|
opendate?: string, // 开课时间
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import { useScreenStore, useSlidesStore } from '../store'
|
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
|
||||||
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const screenStore = useScreenStore()
|
const screenStore = useScreenStore()
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
|
const classcourseStore = useClasscourseStore() // 课堂信息
|
||||||
|
|
||||||
// 进入放映状态(从当前页开始)
|
// 进入放映状态(从当前页开始)
|
||||||
const enterScreening = () => {
|
const enterScreening = () => {
|
||||||
|
@ -19,7 +20,11 @@ export default () => {
|
||||||
|
|
||||||
// 退出放映状态
|
// 退出放映状态
|
||||||
const exitScreening = () => {
|
const exitScreening = () => {
|
||||||
screenStore.setScreening(false)
|
const classcourse = classcourseStore.classcourse
|
||||||
|
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
||||||
|
console.log('退出放映状态')
|
||||||
|
window.close()
|
||||||
|
} else screenStore.setScreening(false)
|
||||||
if (isFullscreen()) exitFullscreen()
|
if (isFullscreen()) exitFullscreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { Classcourse } from '../api/types'
|
||||||
|
|
||||||
|
export interface ClasscourseState {
|
||||||
|
classcourse: Classcourse
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useClasscourseStore = defineStore('classcourse', {
|
||||||
|
state: (): ClasscourseState => ({
|
||||||
|
classcourse: null, // 课堂信息
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
setClasscourse(classcourse: Classcourse) {
|
||||||
|
this.classcourse = classcourse
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
|
@ -3,6 +3,7 @@ import { useSlidesStore } from './slides'
|
||||||
import { useSnapshotStore } from './snapshot'
|
import { useSnapshotStore } from './snapshot'
|
||||||
import { useKeyboardStore } from './keyboard'
|
import { useKeyboardStore } from './keyboard'
|
||||||
import { useScreenStore } from './screen'
|
import { useScreenStore } from './screen'
|
||||||
|
import { useClasscourseStore } from './classcourse'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useMainStore,
|
useMainStore,
|
||||||
|
@ -10,4 +11,5 @@ export {
|
||||||
useSnapshotStore,
|
useSnapshotStore,
|
||||||
useKeyboardStore,
|
useKeyboardStore,
|
||||||
useScreenStore,
|
useScreenStore,
|
||||||
|
useClasscourseStore,
|
||||||
}
|
}
|
|
@ -7,19 +7,44 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<template v-if="type === 'video'">
|
<template v-if="type === 'video'">
|
||||||
<Input v-model:value="videoSrc" placeholder="请输入视频地址,e.g. https://xxx.mp4"></Input>
|
<el-tabs :tab-position="'left'" class="demo-tabs" v-model="tabvalue">
|
||||||
<div class="btns">
|
<el-tab-pane label="常规" >
|
||||||
|
<Input v-model:value="videoSrc" style="width:100%" placeholder="请输入视频地址,e.g. https://xxx.mp4"></Input>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="上传" >
|
||||||
|
<FileInput accept="video/*" @change="files => insertImageElementvideo(files)">
|
||||||
|
<div class="updivs">+点击上传视频</div>
|
||||||
|
</FileInput>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="btns" v-if="tabvalue=='0'">
|
||||||
<Button @click="emit('close')" style="margin-right: 10px;">取消</Button>
|
<Button @click="emit('close')" style="margin-right: 10px;">取消</Button>
|
||||||
<Button type="primary" @click="insertVideo()">确认</Button>
|
<Button type="primary" @click="insertVideo()">确认</Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="type === 'audio'">
|
<template v-if="type === 'audio'">
|
||||||
<Input v-model:value="audioSrc" placeholder="请输入音频地址,e.g. https://xxx.mp3"></Input>
|
<el-tabs :tab-position="'left'" class="demo-tabs" v-model="tabvalue1">
|
||||||
<div class="btns">
|
<el-tab-pane label="常规" >
|
||||||
|
<Input v-model:value="audioSrc" style="width:100%" placeholder="请输入音频地址,e.g. https://xxx.mp3"></Input>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="上传" >
|
||||||
|
<FileInput accept="audio/*" @change="files => insertImageElementaudio(files)">
|
||||||
|
<div class="updivs">+点击上传音频</div>
|
||||||
|
</FileInput>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<div class="btns" v-if="tabvalue1=='0'">
|
||||||
<Button @click="emit('close')" style="margin-right: 10px;">取消</Button>
|
<Button @click="emit('close')" style="margin-right: 10px;">取消</Button>
|
||||||
<Button type="primary" @click="insertAudio()">确认</Button>
|
<Button type="primary" @click="insertAudio()">确认</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -30,6 +55,8 @@ import message from '../../../utils/message'
|
||||||
import Tabs from '../../../components/Tabs.vue'
|
import Tabs from '../../../components/Tabs.vue'
|
||||||
import Input from '../../../components/Input.vue'
|
import Input from '../../../components/Input.vue'
|
||||||
import Button from '../../../components/Button.vue'
|
import Button from '../../../components/Button.vue'
|
||||||
|
import FileInput from '../../../components/FileInput.vue'
|
||||||
|
import { PPTApi } from '../../../api'
|
||||||
|
|
||||||
type TypeKey = 'video' | 'audio'
|
type TypeKey = 'video' | 'audio'
|
||||||
interface TabItem {
|
interface TabItem {
|
||||||
|
@ -45,9 +72,33 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
const type = ref<TypeKey>('video')
|
const type = ref<TypeKey>('video')
|
||||||
|
|
||||||
const videoSrc = ref('https://mazwai.com/videvo_files/video/free/2019-01/small_watermarked/181004_04_Dolphins-Whale_06_preview.webm')
|
const videoSrc = ref('')
|
||||||
const audioSrc = ref('https://freesound.org/data/previews/614/614107_11861866-lq.mp3')
|
const audioSrc = ref('')
|
||||||
|
// https://freesound.org/data/previews/614/614107_11861866-lq.mp3
|
||||||
|
const tabvalue = ref('0')
|
||||||
|
const tabvalue1 = ref('0')
|
||||||
|
|
||||||
|
const insertImageElementvideo = (files: FileList) => {
|
||||||
|
console.log('files', files)
|
||||||
|
const imageFile = files[0]
|
||||||
|
if (!imageFile) return
|
||||||
|
PPTApi.toRousrceUrl(imageFile).then(data=>{
|
||||||
|
videoSrc.value=data
|
||||||
|
insertVideo()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertImageElementaudio = (files: FileList) => {
|
||||||
|
console.log('files', files)
|
||||||
|
const imageFile = files[0]
|
||||||
|
if (!imageFile) return
|
||||||
|
PPTApi.toRousrceUrl(imageFile).then(data=>{
|
||||||
|
videoSrc.value=data
|
||||||
|
insertAudio()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
const tabs: TabItem[] = [
|
const tabs: TabItem[] = [
|
||||||
{ key: 'video', label: '视频' },
|
{ key: 'video', label: '视频' },
|
||||||
{ key: 'audio', label: '音频' },
|
{ key: 'audio', label: '音频' },
|
||||||
|
@ -74,4 +125,33 @@ const insertAudio = () => {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
.updivs{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.demo-tabs{
|
||||||
|
:deep(.el-tabs__content){
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
div{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep( .el-tabs__item.is-active) {
|
||||||
|
color: #d14424;
|
||||||
|
}
|
||||||
|
:deep( .el-tabs__item:hover) {
|
||||||
|
color: #d14424;
|
||||||
|
}
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
background-color: #d14424;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -161,7 +161,9 @@ import Popover from '../../../components/Popover.vue'
|
||||||
import PopoverMenuItem from '../../../components/PopoverMenuItem.vue'
|
import PopoverMenuItem from '../../../components/PopoverMenuItem.vue'
|
||||||
import QuestToPPTist from '@/views/classTask/newClassTaskAssign/questToPPTist/index.vue'
|
import QuestToPPTist from '@/views/classTask/newClassTaskAssign/questToPPTist/index.vue'
|
||||||
import MaterialDialog from './MaterialDialog.vue'
|
import MaterialDialog from './MaterialDialog.vue'
|
||||||
|
import { PPTApi } from '../../../api'
|
||||||
import TextCreateImg from '@/components/ai-kolors/index.vue'
|
import TextCreateImg from '@/components/ai-kolors/index.vue'
|
||||||
|
import { toPng } from 'html-to-image' // 引入html-to-image库
|
||||||
|
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
|
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
|
||||||
|
@ -194,13 +196,21 @@ const {
|
||||||
} = useCreateElement()
|
} = useCreateElement()
|
||||||
|
|
||||||
const insertImageElement = (files: FileList) => {
|
const insertImageElement = (files: FileList) => {
|
||||||
|
console.log('files', files)
|
||||||
const imageFile = files[0]
|
const imageFile = files[0]
|
||||||
if (!imageFile) return
|
if (!imageFile) return
|
||||||
getImageDataURL(imageFile).then(dataURL => createImageElement(dataURL))
|
// 上传图片转为线上地址
|
||||||
|
PPTApi.toRousrceUrl(imageFile).then(data=>{
|
||||||
|
createImageElement(data)
|
||||||
|
})
|
||||||
|
// getImageDataURL(imageFile).then(dataURL => {
|
||||||
|
// createImageElement(dataURL)
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onhtml2canvas = (imgbs64: string) => {
|
const onhtml2canvas = async (html: HTMLElement) => {
|
||||||
createImageElement(imgbs64)
|
const ele = await toPng(html);
|
||||||
|
createImageElement(ele);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shapePoolVisible = ref(false)
|
const shapePoolVisible = ref(false)
|
||||||
|
|
|
@ -162,6 +162,10 @@ const setDialogForExport = (type: DialogForExportTypes) => {
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
||||||
|
:deep(svg) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -67,8 +67,6 @@
|
||||||
|
|
||||||
<div class="page-number">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
<div class="page-number">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
||||||
|
|
||||||
<!-- 引入活动的列表页面 -->
|
|
||||||
<Active ref="activeRef" v-show="false"/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -88,7 +86,6 @@ import ThumbnailSlide from '../../../views/components/ThumbnailSlide/index.vue'
|
||||||
import LayoutPool from './LayoutPool.vue'
|
import LayoutPool from './LayoutPool.vue'
|
||||||
import Popover from '../../../components/Popover.vue'
|
import Popover from '../../../components/Popover.vue'
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import Active from '../Toolbar/ElementStylePanel/Active/index.vue'
|
|
||||||
|
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
|
@ -127,7 +124,6 @@ const {
|
||||||
updateSectionTitle,
|
updateSectionTitle,
|
||||||
} = useSectionHandler()
|
} = useSectionHandler()
|
||||||
|
|
||||||
const activeRef = ref()
|
|
||||||
|
|
||||||
// 页面被切换时
|
// 页面被切换时
|
||||||
const thumbnailsRef = ref<InstanceType<typeof Draggable>>()
|
const thumbnailsRef = ref<InstanceType<typeof Draggable>>()
|
||||||
|
@ -151,8 +147,6 @@ watch(() => slideIndex.value, () => {
|
||||||
|
|
||||||
// 切换页面
|
// 切换页面
|
||||||
const changeSlideIndex = (index: number) => {
|
const changeSlideIndex = (index: number) => {
|
||||||
console.log(workItem.value[index],'hasSection');
|
|
||||||
activeRef.value.clickPPTList(workItem.value[index])
|
|
||||||
|
|
||||||
mainStore.setActiveElementIdList([])
|
mainStore.setActiveElementIdList([])
|
||||||
|
|
||||||
|
@ -402,12 +396,17 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
|
:deep(svg) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.thumbnail-list {
|
.thumbnail-list {
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
border-bottom: 1px solid $borderColor;
|
||||||
}
|
}
|
||||||
.thumbnail-item {
|
.thumbnail-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -486,7 +485,6 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
||||||
.page-number {
|
.page-number {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
border-top: 1px solid $borderColor;
|
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
|
@ -30,14 +30,14 @@
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<!-- 作业列表 -->
|
<!-- 作业列表 -->
|
||||||
<div class="c-apt-r">
|
<div class="c-apt-r" v-loading='loadingActive'>
|
||||||
<!-- 显示-作业内容 -->
|
<!-- 显示-作业内容 -->
|
||||||
<template v-for="(item, index) in workList">
|
<template v-for="(item, index) in workList" :key="index">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="item-title">
|
<div class="item-title">
|
||||||
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
|
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
|
||||||
<el-tooltip :content="item.title||item.uniquekey" placement="top">
|
<el-tooltip :content="item.evaltitle" placement="top">
|
||||||
<div class="tt">{{item.title||item.uniquekey}}</div>
|
<div class="tt">{{item.evaltitle}}</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-button class="btn-del" type="danger" link @click="handleRemoveDemoActivityClassWork(item)">删除</el-button>
|
<el-button class="btn-del" type="danger" link @click="handleRemoveDemoActivityClassWork(item)">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -45,8 +45,12 @@
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<!-- // 推送作业 -->
|
<!-- // 推送作业 -->
|
||||||
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="80%">
|
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="90%" height="500">
|
||||||
<NewClassTsakAssign :currentCourse='currentCourse'/>
|
<el-scrollbar height="550">
|
||||||
|
<div style="height: 550px;">
|
||||||
|
<NewClassTsakAssign :currentCourse='currentCourse' @getData="getData" />
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 活动引用 -->
|
<!-- 活动引用 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
@ -55,9 +59,9 @@
|
||||||
append-to-body
|
append-to-body
|
||||||
:show-close="false"
|
:show-close="false"
|
||||||
width="40%"
|
width="40%"
|
||||||
@selection-change="handleSelectionChange">
|
>
|
||||||
<el-table :data="taskList" style="width: 100%" height="500">
|
<el-table :data="taskList" style="width: 100%" height="500" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" :selectable="selectable" width="55" />
|
<el-table-column type="selection" width="55" :selectable="selectable"/>
|
||||||
<el-table-column prop="evaltitle" label="活动名称" width="150" />
|
<el-table-column prop="evaltitle" label="活动名称" width="150" />
|
||||||
<el-table-column prop="worktype" label="活动类型" width="120" sortable>
|
<el-table-column prop="worktype" label="活动类型" width="120" sortable>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
@ -68,159 +72,254 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="activeVisible = false">取 消</el-button>
|
<el-button @click="activeVisible = false">取 消</el-button>
|
||||||
<el-button type="primary" @click="save">确 定</el-button>
|
<el-button type="primary" @click="savePPtData">确 定</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, onBeforeMount, defineExpose } from 'vue'
|
import { ref, reactive, onMounted, nextTick, watch } from 'vue'
|
||||||
import Divider from '../../../../../components/Divider.vue'
|
import Divider from '../../../../../components/Divider.vue'
|
||||||
import {listEntpcoursefile} from '@/api/education/entpcoursefile'
|
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
import {homeworklist} from '@/api/teaching/classwork'
|
import { homeworklist } from '@/api/teaching/classwork'
|
||||||
import { processList } from "@/hooks/useProcessList";
|
import { processList } from "@/hooks/useProcessList";
|
||||||
import { listEntpcoursework } from "@/api/classTask/index";
|
import { listEntpcoursework } from "@/api/classTask/index";
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox,ElMessage } from 'element-plus'
|
||||||
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
|
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
const currentCourse = reactive({
|
import { PPTApi } from '../../../../../api/index'
|
||||||
textbookId:0,
|
import { storeToRefs } from 'pinia'
|
||||||
levelFirstId:0,
|
import {useSlidesStore} from '../../../../../store'
|
||||||
levelSecondId:0,
|
const slidesStore = useSlidesStore()
|
||||||
coursetitle:'',
|
const { slides, slideIndex, currentSlide, workItem } = storeToRefs(slidesStore)
|
||||||
node:{},
|
|
||||||
id:1,
|
interface CourseNode {
|
||||||
worktype:'',
|
rootid: number;
|
||||||
})
|
parentNode: { id: number };
|
||||||
const dataList = ref([])
|
id: number;
|
||||||
const dialogVisible = ref(false)
|
itemtitle: string;
|
||||||
const tasklist_loading = ref(false)
|
|
||||||
// 活动列表
|
|
||||||
const taskList = ref([])
|
|
||||||
// 活动引用的弹窗
|
|
||||||
const activeVisible = ref(false)
|
|
||||||
const params = reactive({
|
|
||||||
parentid:14766,
|
|
||||||
pageSize:500,
|
|
||||||
orderby:'fileidx'
|
|
||||||
})
|
|
||||||
const type = ref([
|
|
||||||
{
|
|
||||||
label:'习题训练',
|
|
||||||
value:'danger'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:'课堂展示',
|
|
||||||
value:'success'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:'常规作业',
|
|
||||||
value:'primary'
|
|
||||||
},
|
|
||||||
])
|
|
||||||
// 作业列表
|
|
||||||
const workList = ref([])
|
|
||||||
const selectable = (row,index) => {
|
|
||||||
console.log(row,index,'row,index');
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const clickPPTList = (item) => {
|
interface CurrentCourse {
|
||||||
console.log(item,'点击了')
|
textbookId: number;
|
||||||
workList.value = []
|
levelFirstId: number;
|
||||||
let datacontent = item.datacontent;
|
levelSecondId: number;
|
||||||
let pptJson = "";
|
coursetitle: string;
|
||||||
if(typeof datacontent === 'string') pptJson = JSON.parse(datacontent)
|
node: CourseNode;
|
||||||
if(pptJson&&pptJson[0]&&pptJson[0].classworkList) {
|
id: number;
|
||||||
homeworklist({ids:pptJson[0].classworkList, pageSize: 100}).then( async res => {
|
worktype: string;
|
||||||
await formatClassWorkFile(res.rows)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const formatClassWorkFile = async (postData) => {
|
|
||||||
return new Promise(async (resolve, reject)=>{
|
interface Params {
|
||||||
for (let i = 0; i < postData.length; i++) {
|
parentid: number;
|
||||||
let item = postData[i];
|
pageSize: number;
|
||||||
switch (item.worktype) {
|
orderby: string;
|
||||||
case '框架梳理': {
|
}
|
||||||
}
|
|
||||||
break;
|
interface WorkType {
|
||||||
case '习题训练': {
|
label: string;
|
||||||
item.entpcourseworklistarray = item.entpcourseworklist?JSON.parse('['+item.entpcourseworklist+']'):[];
|
value: string;
|
||||||
let workIds = item.entpcourseworklistarray.map(items=>items.id).join(',')
|
}
|
||||||
let ress = await listEntpcoursework({ids:workIds})
|
|
||||||
processList(ress.rows)
|
interface WorkItem {
|
||||||
item.workShowList = ress.rows
|
status: string;
|
||||||
}
|
activityContent?: string;
|
||||||
break;
|
worktype: string;
|
||||||
case '课堂展示': {
|
quizlist?: { id: number }[];
|
||||||
item.base64 = JSON.parse(item.workcodes).base64
|
workcodes: string;
|
||||||
}
|
base64?: string;
|
||||||
break;
|
prevData?: any;
|
||||||
case '常规作业': {
|
id: number;
|
||||||
item.prevData = JSON.parse(item.workcodes)
|
evaltitle?: string; // 添加 evaltitle 属性
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentCourse = reactive<CurrentCourse>({
|
||||||
|
textbookId: 0,
|
||||||
|
levelFirstId: 0,
|
||||||
|
levelSecondId: 0,
|
||||||
|
coursetitle: '',
|
||||||
|
node: {} as CourseNode,
|
||||||
|
id: 1,
|
||||||
|
worktype: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
const tasklist_loading = ref<boolean>(false)
|
||||||
|
|
||||||
|
// 活动列表
|
||||||
|
const taskList = ref<WorkItem[]>([])
|
||||||
|
|
||||||
|
// 活动引用的弹窗
|
||||||
|
const activeVisible = ref<boolean>(false)
|
||||||
|
|
||||||
|
|
||||||
|
const type = ref<WorkType[]>([
|
||||||
|
{
|
||||||
|
label: '习题训练',
|
||||||
|
value: 'danger'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '课堂展示',
|
||||||
|
value: 'success'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '常规作业',
|
||||||
|
value: 'primary'
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const objItem = ref<any>({})
|
||||||
|
// 作业列表
|
||||||
|
const workList = ref<WorkItem[]>([])
|
||||||
|
|
||||||
|
// 获取所选择的作业列表
|
||||||
|
const selectedWorkList = ref<WorkItem[]>([])
|
||||||
|
// 活动页面的loading框
|
||||||
|
const loadingActive = ref<boolean>(false)
|
||||||
|
|
||||||
|
|
||||||
|
const paramData = ref<{ id: number, activityContent: string }>({} as { id: number, activityContent: string })
|
||||||
|
|
||||||
|
const selectable = (row: WorkItem, index: number): boolean => {
|
||||||
|
return row.status === '10';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const formatClassWorkFile = async (postData: WorkItem[]): Promise<void> => {
|
||||||
|
for (let i = 0; i < postData.length; i++) {
|
||||||
|
let item = postData[i];
|
||||||
|
switch (item.worktype) {
|
||||||
|
case '框架梳理': {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '习题训练': {
|
||||||
|
// let workIds = item.quizlist!.map(items => items.id).join(',');
|
||||||
|
// let ress = await listEntpcoursework({ ids: workIds });
|
||||||
|
// const arr = ress.rows.map((item:{id:number}) => {
|
||||||
|
// return item.id
|
||||||
|
// })
|
||||||
|
|
||||||
|
// processList(ress.rows);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '课堂展示': {
|
||||||
|
// item.base64 = JSON.parse(item.workcodes).base64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '常规作业': {
|
||||||
|
// item.prevData = JSON.parse(item.workcodes);
|
||||||
}
|
}
|
||||||
workList.value.push(item)
|
|
||||||
}
|
}
|
||||||
resolve()
|
workList.value.push(item)
|
||||||
})
|
loadingActive.value = false
|
||||||
}
|
}
|
||||||
// 删除作业
|
await nextTick();
|
||||||
const handleRemoveDemoActivityClassWork = (item) => {
|
}// 删除作业
|
||||||
|
const handleRemoveDemoActivityClassWork = (item: WorkItem) => {
|
||||||
ElMessageBox.confirm('是否确认删除?')
|
ElMessageBox.confirm('是否确认删除?')
|
||||||
.then(function () {
|
.then(() => {
|
||||||
workList.value.splice(workList.value.indexOf(item), 1);
|
workList.value = []
|
||||||
})
|
const arr = paramData.value.activityContent.split(',')
|
||||||
.catch(() => {});
|
const filterArr = arr.filter(itemId => itemId!== item.id.toString())
|
||||||
|
paramData.value.activityContent = filterArr.join(',')
|
||||||
|
upDateData()
|
||||||
|
})
|
||||||
|
.catch(() => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取tag的样式
|
// 获取tag的样式
|
||||||
const getTagType = (worktype) => {
|
const getTagType = (worktype: string): string => {
|
||||||
return type.value.find(item => item.label == worktype).value
|
return type.value.find(item => item.label === worktype)!.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取活动引用的列表数据
|
// 获取活动引用的列表数据
|
||||||
const initHomeWork = async()=> {
|
const initHomeWork = async () => {
|
||||||
tasklist_loading.value = true;
|
tasklist_loading.value = true;
|
||||||
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
|
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
|
||||||
taskList.value = res;
|
taskList.value = res;
|
||||||
tasklist_loading.value = false;
|
tasklist_loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选活动引用
|
// 多选活动引用
|
||||||
const handleSelectionChange = (val) => {
|
const handleSelectionChange = (val: WorkItem[]) => {
|
||||||
console.log(val,'多选')
|
selectedWorkList.value = [...val]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开添加作业活动
|
// 打开添加作业活动
|
||||||
const showDialog = (item) => {
|
const showDialog = (item: string) => {
|
||||||
currentCourse.worktype = item
|
currentCourse.worktype = item
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const openList = () => {
|
const openList = () => {
|
||||||
activeVisible.value = true
|
activeVisible.value = true
|
||||||
initHomeWork()
|
initHomeWork()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加活动引用列表作业
|
// 添加活动引用列表作业
|
||||||
const save = () => {
|
const savePPtData = async () => {
|
||||||
console.log('添加了')
|
if (selectedWorkList.value.length === 0) {
|
||||||
|
ElMessage.warning('请选择活动')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
workList.value = []
|
||||||
|
const arr = selectedWorkList.value.map(item => item.id)
|
||||||
|
// 应该是新加而不是覆盖
|
||||||
|
const existingIds = paramData.value.activityContent ? paramData.value.activityContent.split(',') : []
|
||||||
|
paramData.value.activityContent = Array.from(new Set([...existingIds, ...arr])).join(',')
|
||||||
|
upDateData()
|
||||||
activeVisible.value = false
|
activeVisible.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取当前ppt页的数据
|
||||||
|
const getCurrentPPtData = async () => {
|
||||||
|
workList.value = []
|
||||||
|
objItem.value = workItem.value[slideIndex.value]
|
||||||
|
paramData.value.id = objItem.value.id
|
||||||
|
paramData.value.activityContent = objItem.value?.activityContent
|
||||||
|
if (objItem.value?.activityContent) {
|
||||||
|
loadingActive.value = true
|
||||||
|
const res = await homeworklist({ ids: objItem.value?.activityContent, pageSize: 100 })
|
||||||
|
await formatClassWorkFile(res.rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收习题训练的值
|
||||||
|
const getData = async (data: WorkItem) => {
|
||||||
|
workList.value = []
|
||||||
|
if(paramData.value.activityContent){
|
||||||
|
const arr = paramData.value.activityContent.split(',')
|
||||||
|
arr.push(data.id.toString())
|
||||||
|
const unitArr = Array.from(new Set(arr))
|
||||||
|
paramData.value.activityContent = unitArr.join(',')
|
||||||
|
}else{
|
||||||
|
paramData.value.activityContent = data.id.toString()
|
||||||
|
}
|
||||||
|
upDateData()
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
const upDateData = async () => {
|
||||||
|
await PPTApi.updateSlide(paramData.value)
|
||||||
|
loadingActive.value = true
|
||||||
|
const res = await homeworklist({ ids: paramData.value.activityContent, pageSize: 100 })
|
||||||
|
await formatClassWorkFile(res.rows)
|
||||||
|
const resource = sessionStore.get('curr.resource')
|
||||||
|
await PPTApi.getSlideList(resource.id)
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// console.log(sessionStore.get('subject.curBook'),'curBook');
|
const curNode = sessionStore.get('subject.curNode') as CourseNode
|
||||||
// console.log(sessionStore.get('subject.subjectTree'),'subjectTree');
|
|
||||||
// console.log(sessionStore.get('subject.bookList'),'bookList');
|
|
||||||
console.log(sessionStore.get('subject.curNode'),'curNode');
|
|
||||||
const curNode = sessionStore.get('subject.curNode')
|
|
||||||
currentCourse.textbookId = curNode.rootid
|
currentCourse.textbookId = curNode.rootid
|
||||||
currentCourse.levelFirstId = curNode.parentNode.id
|
currentCourse.levelFirstId = curNode.parentNode.id
|
||||||
currentCourse.levelSecondId = curNode.id
|
currentCourse.levelSecondId = curNode.id
|
||||||
currentCourse.coursetitle = curNode.itemtitle,
|
currentCourse.coursetitle = curNode.itemtitle
|
||||||
currentCourse.node = curNode
|
currentCourse.node = curNode
|
||||||
listEntpcoursefile(params).then((res) => {
|
objItem.value = workItem.value[slideIndex.value]
|
||||||
dataList.value = [...res.rows]
|
getCurrentPPtData()
|
||||||
})
|
|
||||||
})
|
})
|
||||||
defineExpose({
|
watch(() => slideIndex.value, () => {
|
||||||
clickPPTList
|
getCurrentPPtData()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@ -287,5 +386,8 @@ defineExpose({
|
||||||
--el-border-color: var(--current-color);
|
--el-border-color: var(--current-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.page .page-resource{
|
||||||
|
height: 500px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -0,0 +1,164 @@
|
||||||
|
/**
|
||||||
|
* websocket 工具类(im 自己实现)
|
||||||
|
* 单例模式: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
|
||||||
|
* 实现的方法为先判断实例存在与否,如果存在则直接返回,不存在就创建了再返回,这就确保了一个类只有一个实例对象。
|
||||||
|
*/
|
||||||
|
import useUserStore from '@/store/modules/user' // 用户信息
|
||||||
|
|
||||||
|
export class ChatWs {
|
||||||
|
instance = null; // 实例
|
||||||
|
id = null; // 群聊id || 单聊id-用户id(userId)
|
||||||
|
closed = false; // 关闭状态
|
||||||
|
onmessage = null; // 自定义处理
|
||||||
|
errCount = 5; // 重连次数 (ms) 暂时不使用
|
||||||
|
errTime = null; // 重连时间 (ms) 1秒内zhi间内不重连
|
||||||
|
// 类型定义
|
||||||
|
TYPES = {
|
||||||
|
group: 'group', // 群发
|
||||||
|
single: 'single', // 单发
|
||||||
|
beat: 'heart_beat', // 心跳
|
||||||
|
}
|
||||||
|
static base = 'wss://file.ysaix.com:7868'
|
||||||
|
constructor() {
|
||||||
|
if (!ChatWs.instance) {
|
||||||
|
const userStore = useUserStore() // 用户信息
|
||||||
|
const wsBase = import.meta.env.VITE_APP_WS_URL; // ws地址
|
||||||
|
const url = `${wsBase||ChatWs.base}/ws/websocket/${userStore.id}`;
|
||||||
|
this.init(url);
|
||||||
|
ChatWs.instance = this;
|
||||||
|
}
|
||||||
|
return ChatWs.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init(url) {
|
||||||
|
this.url = url;
|
||||||
|
this.ws = null;
|
||||||
|
const _this = this
|
||||||
|
this.heartCheck = {
|
||||||
|
timeout: 1000 * 10, // 60s
|
||||||
|
timeoutObj: null,
|
||||||
|
serverTimeoutObj: null,
|
||||||
|
reset() {
|
||||||
|
clearTimeout(this.timeoutObj);
|
||||||
|
clearTimeout(this.serverTimeoutObj);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
start() {
|
||||||
|
const self = this;
|
||||||
|
this.timeoutObj = setTimeout(function () {
|
||||||
|
// 这里发送一个心跳,后端收到后,返回一个心跳消息,
|
||||||
|
// onmessage拿到返回的心跳就说明连接正常
|
||||||
|
console.log("websocket-发送心跳")
|
||||||
|
_this.sendMsgBeat();
|
||||||
|
self.serverTimeoutObj = setTimeout(function () {
|
||||||
|
console.log("websocket-心跳响应超时")
|
||||||
|
// 如果超过一定时间还没重置,说明后端主动断开了
|
||||||
|
_this.ws.close(); // 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
|
||||||
|
}, self.timeout);
|
||||||
|
}, this.timeout);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.reconnect();
|
||||||
|
}
|
||||||
|
// 重连
|
||||||
|
reconnect() {
|
||||||
|
const self = this;
|
||||||
|
if (!!this.ws) { // 关闭之前的链接
|
||||||
|
this.ws.close()
|
||||||
|
this.ws = null
|
||||||
|
}
|
||||||
|
this.ws = new WebSocket(this.url);
|
||||||
|
this.ws.onopen = function () {
|
||||||
|
console.log("websocket-连接成功")
|
||||||
|
self.heartCheck.reset().start();
|
||||||
|
};
|
||||||
|
this.ws.onmessage = function (e) {
|
||||||
|
// console.log("websocket-收到消息", e)
|
||||||
|
// 拿到任何消息都说明当前连接是正常的
|
||||||
|
const isBeat = e.data == 'pong'
|
||||||
|
isBeat && self.heartCheck.reset().start();
|
||||||
|
const exts = ['sessionId', 'pong'] // 不处理的消息头
|
||||||
|
const isEmpty = !e.data
|
||||||
|
const isExts = exts.some(item => e.data.includes(item))
|
||||||
|
if (isEmpty && isExts) return;
|
||||||
|
// 自定义处理
|
||||||
|
self.onmessage && self.onmessage(e.data, e);
|
||||||
|
};
|
||||||
|
this.ws.onerror = function (e) {
|
||||||
|
console.log("websocket-连接异常", e)
|
||||||
|
self.connectSocket() // 重连
|
||||||
|
};
|
||||||
|
this.ws.onclose = function (e) {
|
||||||
|
console.log("websocket-连接断开", e)
|
||||||
|
self.connectSocket() // 重连
|
||||||
|
};
|
||||||
|
}
|
||||||
|
connectSocket() {
|
||||||
|
this.heartCheck.reset() // 重置心跳
|
||||||
|
if (self.closed) return; // 关闭状态不重连
|
||||||
|
// if(self.errCount <= 0) return; // 超过重连次数
|
||||||
|
// self.errCount--; // 重连次数减1
|
||||||
|
if (this.errTime) {
|
||||||
|
const nowTime = Date.now();
|
||||||
|
const bool = nowTime - this.errTime < 1000 // 1s内zhi间内不重连
|
||||||
|
if (bool) return; // 1s内不重连
|
||||||
|
}
|
||||||
|
this.errTime = Date.now();
|
||||||
|
// 延时5s 后重连
|
||||||
|
console.log('重连中...')
|
||||||
|
this.sleep(5000).then(_ => {this.reconnect()})
|
||||||
|
}
|
||||||
|
// 发送消息
|
||||||
|
send(msg) {
|
||||||
|
if (!msg) throw new Error("msg is not null")
|
||||||
|
if (!this.ws) throw new Error("ws is not null")
|
||||||
|
if (typeof msg === "object") msg = JSON.stringify(msg)
|
||||||
|
if (!msg.includes('"msg":')) throw new Error("msg 格式错误请重试")
|
||||||
|
this.ws.send(msg)
|
||||||
|
}
|
||||||
|
// 发送消息-带消息头(key)
|
||||||
|
sendMsg(head, content, option = {}) {
|
||||||
|
if (!head) throw new Error("head is not null")
|
||||||
|
if (!content) throw new Error("content is not null")
|
||||||
|
let msg = { head, content, ...option }
|
||||||
|
// 发送消息
|
||||||
|
this.send(this.getMsgObj(msg))
|
||||||
|
}
|
||||||
|
// 发送心跳
|
||||||
|
sendMsgBeat() {
|
||||||
|
// this.send(this.getMsgObj('ping', this.TYPES.beat))
|
||||||
|
this.ws.send('ping')
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 获取消息对象
|
||||||
|
* @param {*} msg 消息内容
|
||||||
|
* @param {*} chatType 群发 group| 单发 single| 心态 heart_beat
|
||||||
|
* @param {*} id 群聊id || 单聊id-用户id(userId)
|
||||||
|
*/
|
||||||
|
getMsgObj(msg, chatType = 'group', id) {
|
||||||
|
if (typeof msg === "object") msg = JSON.stringify(msg)
|
||||||
|
const res = {msg, chatType}
|
||||||
|
// if (!id) throw new Error(`${type=='group'?'群ID':'用户ID'} is not null`)
|
||||||
|
if (chatType == 'group') res.groupId = id || this.id || ''
|
||||||
|
else if (chatType == 'single') res.to = id || this.id || ''
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
// 监听
|
||||||
|
watch(callback) {
|
||||||
|
callback && (this.onmessage = callback);
|
||||||
|
}
|
||||||
|
// 关闭链接
|
||||||
|
close() {
|
||||||
|
this.closed = true;
|
||||||
|
this.ws.close();
|
||||||
|
}
|
||||||
|
// 延时 ms 毫秒
|
||||||
|
sleep(ms){
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 连接socket
|
||||||
|
export const connect = () => new ChatWs()
|
||||||
|
// 默认实例
|
||||||
|
export default new ChatWs()
|
|
@ -208,6 +208,10 @@ export const createWindow = async (type, data) => {
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
}
|
}
|
||||||
|
// pptlist的时候可以选择最大化
|
||||||
|
if (data.url == '/pptist'){
|
||||||
|
defOption.maximizable = true;
|
||||||
|
}
|
||||||
data.isConsole = true // 是否开启控制台
|
data.isConsole = true // 是否开启控制台
|
||||||
data.option = {...defOption, ...option}
|
data.option = {...defOption, ...option}
|
||||||
const win = await toolWindow(type, data)
|
const win = await toolWindow(type, data)
|
||||||
|
|
|
@ -949,11 +949,11 @@ const showExamAnalyseDrawer = (row) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const getPaginationList = ( page, limit ) => {
|
const getPaginationList = async ( page, limit ) => {
|
||||||
paginationParams.pageNum = page;
|
paginationParams.pageNum = page;
|
||||||
paginationParams.pageSize = limit;
|
paginationParams.pageSize = limit;
|
||||||
//console.log(page, limit)
|
//console.log(page, limit)
|
||||||
handleQueryFromEntpCourseWork(0);
|
await handleQueryFromEntpCourseWork(0);
|
||||||
// 重置滚动条至顶部
|
// 重置滚动条至顶部
|
||||||
tableRef.value.setScrollTop(0);
|
tableRef.value.setScrollTop(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watch, reactive, getCurrentInstance, nextTick } from 'vue'
|
import { onMounted, ref, watch, reactive, getCurrentInstance, nextTick, defineEmits } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { Plus, Delete } from '@element-plus/icons-vue'
|
import { Plus, Delete } from '@element-plus/icons-vue'
|
||||||
|
@ -156,6 +156,8 @@ const { proxy } = getCurrentInstance()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentCourse: Object,
|
currentCourse: Object,
|
||||||
})
|
})
|
||||||
|
const emits = defineEmits(['getData'])
|
||||||
|
// 这个代表的是是否从ppt里面添加的作业
|
||||||
const isShow = ref(false)
|
const isShow = ref(false)
|
||||||
|
|
||||||
const propsQueryCourseObj = route.query.courseObj;//作业布置的内容对象
|
const propsQueryCourseObj = route.query.courseObj;//作业布置的内容对象
|
||||||
|
@ -460,10 +462,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
await nextTick(); // 确保DOM更新完成
|
await nextTick(); // 确保DOM更新完成
|
||||||
proxy.$refs["classWorkFormRef"].validate(async valid => {
|
proxy.$refs["classWorkFormRef"].validate(async valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
//
|
|
||||||
// const { chapterId } = await useGetHomework(courseObj.node)
|
// const { chapterId } = await useGetHomework(courseObj.node)
|
||||||
// this.entpcourseid = chapterId
|
// this.entpcourseid = chapterId
|
||||||
|
|
||||||
const cform = {
|
const cform = {
|
||||||
id: 0,
|
id: 0,
|
||||||
workdate: classWorkForm.workdate, // //作业类型?web端这里貌似没有这个时间
|
workdate: classWorkForm.workdate, // //作业类型?web端这里貌似没有这个时间
|
||||||
|
@ -491,12 +491,14 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
|
|
||||||
|
|
||||||
// 当前为[编辑]状态下点进来得处理 newWorkSpaceEdit true 为编辑状态
|
// 当前为[编辑]状态下点进来得处理 newWorkSpaceEdit true 为编辑状态
|
||||||
if(classWorkForm.id != '' ) {// 编辑状态 有id
|
if(isShow.value === false){
|
||||||
|
if(classWorkForm.id != '' ) {// 编辑状态 有id
|
||||||
editWork(cform); // 编辑作业
|
editWork(cform); // 编辑作业
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (classWorkForm.worktype === "课堂展示") {
|
if (classWorkForm.worktype === "课堂展示") {
|
||||||
boardLoading.value = true
|
boardLoading.value = true
|
||||||
let canvasJson = proxy.$refs.boardref.getCanvasJson()
|
let canvasJson = proxy.$refs.boardref.getCanvasJson()
|
||||||
|
@ -507,7 +509,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
|
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
|
||||||
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
|
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
|
||||||
try {
|
try {
|
||||||
addClassworkReturnId(cform).then(() => {
|
addClassworkReturnId(cform).then((res) => {
|
||||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||||
// 重置提交表单
|
// 重置提交表单
|
||||||
classWorkForm.worktype = "课堂展示";
|
classWorkForm.worktype = "课堂展示";
|
||||||
|
@ -519,7 +521,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
// 情况选择的资源缓存
|
// 情况选择的资源缓存
|
||||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
|
classWorkForm.id = res
|
||||||
|
emits('getData',classWorkForm)
|
||||||
boardLoading.value = false
|
boardLoading.value = false
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -531,7 +534,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
||||||
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
|
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
|
||||||
try {
|
try {
|
||||||
addClassworkReturnId(cform).then(() => {
|
addClassworkReturnId(cform).then((res) => {
|
||||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||||
// 重置提交表单
|
// 重置提交表单
|
||||||
classWorkForm.worktype = "常规作业";
|
classWorkForm.worktype = "常规作业";
|
||||||
|
@ -543,7 +546,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
classWorkForm.fileHomeworkList = []; // 常规作业list
|
classWorkForm.fileHomeworkList = []; // 常规作业list
|
||||||
|
classWorkForm.id = res
|
||||||
|
emits('getData',classWorkForm)
|
||||||
fileLoading.value = false
|
fileLoading.value = false
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -574,7 +578,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
console.log(cform,'提交的数据');
|
console.log(cform,'提交的数据');
|
||||||
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
|
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
|
||||||
|
|
||||||
addClassworkReturnId(cform).then(workres => {
|
addClassworkReturnId(cform).then(res => {
|
||||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||||
// 重置提交表单
|
// 重置提交表单
|
||||||
classWorkForm.worktype = "习题训练";
|
classWorkForm.worktype = "习题训练";
|
||||||
|
@ -585,6 +589,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
// 情况选择的资源缓存
|
// 情况选择的资源缓存
|
||||||
classWorkForm.chooseWorkLists = [];
|
classWorkForm.chooseWorkLists = [];
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
|
classWorkForm.id = res
|
||||||
|
emits('getData',classWorkForm)
|
||||||
// refresh the list
|
// refresh the list
|
||||||
//这里分离了,所以不需要更新表单数据了
|
//这里分离了,所以不需要更新表单数据了
|
||||||
// this.getClassWorkAllList();
|
// this.getClassWorkAllList();
|
||||||
|
@ -593,7 +599,11 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
}
|
}
|
||||||
console.log('该清空左侧列表数据了');
|
console.log('该清空左侧列表数据了');
|
||||||
// 清空左侧 选中的布置列表 并刷新列表
|
// 清空左侧 选中的布置列表 并刷新列表
|
||||||
currentRow.value = {id:0};
|
if(isShow.value){
|
||||||
|
currentRow.value = {id:1};
|
||||||
|
}else{
|
||||||
|
currentRow.value = {id:0};
|
||||||
|
}
|
||||||
initHomeWork();
|
initHomeWork();
|
||||||
|
|
||||||
|
|
||||||
|
@ -604,6 +614,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
// // 首页进入的,跳转到作业布置页面
|
// // 首页进入的,跳转到作业布置页面
|
||||||
// router.push({ path: '/classTaskAssign' });
|
// router.push({ path: '/classTaskAssign' });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
:data="workResource.entpCourseWorkList"
|
:data="workResource.entpCourseWorkList"
|
||||||
style="width: 100%; height: calc(100% - 55px);"
|
style="width: 100%; height: calc(100% - 55px);"
|
||||||
v-loading="pageParams.loading"
|
v-loading="pageParams.loading"
|
||||||
|
ref="tableRef"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" width="60" />
|
<el-table-column type="index" width="60" />
|
||||||
<el-table-column align="left" >
|
<el-table-column align="left" >
|
||||||
|
@ -118,7 +119,7 @@
|
||||||
import { Search } from '@element-plus/icons-vue'
|
import { Search } from '@element-plus/icons-vue'
|
||||||
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import html2canvas from 'html2canvas';
|
// import html2canvas from 'html2canvas';
|
||||||
|
|
||||||
import { listEntpcoursework, listEntpcourseworkLocal } from '@/api/education/entpCourseWork'
|
import { listEntpcoursework, listEntpcourseworkLocal } from '@/api/education/entpCourseWork'
|
||||||
import { listEvaluationclue } from '@/api/classTask'
|
import { listEvaluationclue } from '@/api/classTask'
|
||||||
|
@ -364,11 +365,15 @@ const showExamAnalyseDrawer = (row) => {
|
||||||
proxy.$refs.examDetailsDrawerRef.acceptParams(activeParams);
|
proxy.$refs.examDetailsDrawerRef.acceptParams(activeParams);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const getPaginationList = ( page, limit ) => {
|
|
||||||
|
const tableRef = ref();
|
||||||
|
const getPaginationList = async ( page, limit ) => {
|
||||||
paginationParams.pageNum = page;
|
paginationParams.pageNum = page;
|
||||||
paginationParams.pageSize = limit;
|
paginationParams.pageSize = limit;
|
||||||
console.log(page, limit)
|
console.log(page, limit)
|
||||||
handleQueryFromEntpCourseWork(0);
|
await handleQueryFromEntpCourseWork(0);
|
||||||
|
// 重置滚动条至顶部
|
||||||
|
tableRef.value.setScrollTop(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 单题上传弹出框----纠错修改框 */
|
/** 单题上传弹出框----纠错修改框 */
|
||||||
|
@ -453,13 +458,16 @@ const handleDelete = async(item, index) => {
|
||||||
*/
|
*/
|
||||||
const captureScreenshot = (id) => {
|
const captureScreenshot = (id) => {
|
||||||
const targetElement = document.getElementById('screenshot-target-' + id);
|
const targetElement = document.getElementById('screenshot-target-' + id);
|
||||||
html2canvas(targetElement).then(canvas => {
|
if (targetElement) {
|
||||||
// 将canvas转换为图像URL
|
emit('addQuizImgBs64', targetElement);
|
||||||
const screenshotUrl = canvas.toDataURL('image/png');
|
}
|
||||||
// 在这里可以将截图保存到本地或上传到服务器
|
// html2canvas(targetElement).then(canvas => {
|
||||||
// console.log(screenshotUrl);
|
// // 将canvas转换为图像URL
|
||||||
emit('addQuizImgBs64', screenshotUrl);
|
// const screenshotUrl = canvas.toDataURL('image/png');
|
||||||
});
|
// // 在这里可以将截图保存到本地或上传到服务器
|
||||||
|
// // console.log(screenshotUrl);
|
||||||
|
// emit('addQuizImgBs64', screenshotUrl);
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 防抖
|
// 防抖
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<!-- 习题筛选1 -->
|
<!-- 习题筛选1 -->
|
||||||
<el-row style="width: 100%; height: 50px;">
|
<el-row style="width: 100%; height: 50px;">
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
|
@ -60,8 +60,9 @@
|
||||||
<div class="page-table" >
|
<div class="page-table" >
|
||||||
<el-table
|
<el-table
|
||||||
:data="workResource.entpCourseWorkList"
|
:data="workResource.entpCourseWorkList"
|
||||||
style="width: 100%; height: calc(100% - 55px);"
|
style="width: 100%; height: calc(100% - 50px);"
|
||||||
v-loading="pageParams.loading"
|
v-loading="pageParams.loading"
|
||||||
|
ref="tableRef"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" width="60" />
|
<el-table-column type="index" width="60" />
|
||||||
<el-table-column align="left" >
|
<el-table-column align="left" >
|
||||||
|
@ -89,13 +90,13 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<!-- 分页-->
|
<!-- 分页-->
|
||||||
<div style="height: 55px;">
|
<div style="height: 50px;">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-show="pageParams.total > 0"
|
v-show="pageParams.total > 0"
|
||||||
v-model:page="paginationParams.pageNum"
|
v-model:page="paginationParams.pageNum"
|
||||||
v-model:limit="paginationParams.pageSize"
|
v-model:limit="paginationParams.pageSize"
|
||||||
:total="pageParams.total"
|
:total="pageParams.total"
|
||||||
:style="{ position: 'relative', 'margin-top': '5px' }"
|
:style="{ position: 'relative', 'padding-top': '10px' }"
|
||||||
@change="getPaginationList" />
|
@change="getPaginationList" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,7 +106,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Search } from '@element-plus/icons-vue'
|
import { Search } from '@element-plus/icons-vue'
|
||||||
import html2canvas from 'html2canvas';
|
//import html2canvas from 'html2canvas';
|
||||||
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
||||||
|
|
||||||
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
|
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
|
||||||
|
@ -188,6 +189,7 @@ const workResource = reactive({
|
||||||
}); // 作业资源
|
}); // 作业资源
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
console.log('entpCourseWorkTypeList', entpCourseWorkTypeList);
|
||||||
debounceQueryData(); // 查询习题列表
|
debounceQueryData(); // 查询习题列表
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -395,11 +397,15 @@ const showExamAnalyseDrawer = (row) => {
|
||||||
proxy.$refs.examDetailsDrawerRef.acceptParams(activeParams);
|
proxy.$refs.examDetailsDrawerRef.acceptParams(activeParams);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const getPaginationList = ( page, limit ) => {
|
|
||||||
|
const tableRef = ref();
|
||||||
|
const getPaginationList = async ( page, limit ) => {
|
||||||
paginationParams.pageNum = page;
|
paginationParams.pageNum = page;
|
||||||
paginationParams.pageSize = limit;
|
paginationParams.pageSize = limit;
|
||||||
console.log(page, limit)
|
console.log(page, limit)
|
||||||
handleQueryFromEntpCourseWork(0);
|
await handleQueryFromEntpCourseWork(0);
|
||||||
|
// 重置滚动条至顶部
|
||||||
|
tableRef.value.setScrollTop(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -438,13 +444,16 @@ const getPaginationList = ( page, limit ) => {
|
||||||
*/
|
*/
|
||||||
const captureScreenshot = (id) => {
|
const captureScreenshot = (id) => {
|
||||||
const targetElement = document.getElementById('screenshot-target-' + id);
|
const targetElement = document.getElementById('screenshot-target-' + id);
|
||||||
html2canvas(targetElement).then(canvas => {
|
if (targetElement) {
|
||||||
// 将canvas转换为图像URL
|
emit('addQuizImgBs64', targetElement);
|
||||||
const screenshotUrl = canvas.toDataURL('image/png');
|
}
|
||||||
// 在这里可以将截图保存到本地或上传到服务器
|
// html2canvas(targetElement).then(canvas => {
|
||||||
// console.log(screenshotUrl);
|
// // 将canvas转换为图像URL
|
||||||
emit('addQuizImgBs64', screenshotUrl);
|
// const screenshotUrl = canvas.toDataURL('image/png');
|
||||||
});
|
// // 在这里可以将截图保存到本地或上传到服务器
|
||||||
|
// // console.log(screenshotUrl);
|
||||||
|
// emit('addQuizImgBs64', screenshotUrl);
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ import { sessionStore } from '@/utils/store' // 学科名字文生图
|
||||||
// 组件引入
|
// 组件引入
|
||||||
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import { menusEvent } from '@/plugins/vue3-menus' // 右键菜单
|
import { menusEvent } from '@/plugins/vue3-menus' // 右键菜单
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore() // 用户信息
|
const userStore = useUserStore() // 用户信息
|
||||||
|
|
||||||
|
@ -197,6 +196,19 @@ const getResourceList = async () => {
|
||||||
// 统一HTTP处理
|
// 统一HTTP处理
|
||||||
const HTTP_SERVER_API = (type, params = {}) => {
|
const HTTP_SERVER_API = (type, params = {}) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case 'addSmarttalk': { // 获取课程
|
||||||
|
const def = {
|
||||||
|
fileId: '', // 文件id - Entpcoursefile 对应id
|
||||||
|
fileFlag: 'aptist',
|
||||||
|
fileShowName: courseObj.coursetitle + '.aptist',
|
||||||
|
textbookId: courseObj.textbookId,
|
||||||
|
levelFirstId: courseObj.levelFirstId,
|
||||||
|
levelSecondId: courseObj.levelSecondId,
|
||||||
|
fileSource: '个人',
|
||||||
|
fileRoot: '备课'
|
||||||
|
}
|
||||||
|
return API_smarttalk.creatAPT({...def, ...params})
|
||||||
|
}
|
||||||
case 'addEntpcourse': { // 添加课程
|
case 'addEntpcourse': { // 添加课程
|
||||||
const node = courseObj.node || {}
|
const node = courseObj.node || {}
|
||||||
if (!node) return msgUtils.msgWarning('请选择章节?')
|
if (!node) return msgUtils.msgWarning('请选择章节?')
|
||||||
|
@ -279,6 +291,8 @@ const handleAll = async(type, row) =>{
|
||||||
}
|
}
|
||||||
// 生成ppt课件-子级(slide)
|
// 生成ppt课件-子级(slide)
|
||||||
await HTTP_SERVER_API('addEntpcoursefile', params)
|
await HTTP_SERVER_API('addEntpcoursefile', params)
|
||||||
|
// 生成备课资源-Smarttalk
|
||||||
|
await HTTP_SERVER_API('addSmarttalk',{fileId: id})
|
||||||
// 刷新资源列表
|
// 刷新资源列表
|
||||||
await getResourceList()
|
await getResourceList()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- im-chat 聊天组件 -->
|
<!-- im-chat 聊天组件 -->
|
||||||
<im-chat ref="imChatRef" v-if="visible" @change="chatChange" />
|
<!-- <im-chat ref="imChatRef" v-if="visible" @change="chatChange" /> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -90,7 +90,7 @@ import vueQr from 'vue-qr/src/packages/vue-qr.vue' // 插件: 二维码
|
||||||
import imChat from '@/views/tool/components/imChat.vue' // im-chat-子组件
|
import imChat from '@/views/tool/components/imChat.vue' // im-chat-子组件
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息头-相关定义(nuem)
|
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息头-相关定义(nuem)
|
||||||
import * as commUtil from '@/utils/comm' // 工具类-通用
|
import * as commUtil from '@/utils/comm' // 工具类-通用
|
||||||
import { toLinkWeb, getStaticUrl } from '@/utils/tool' // 工具类-主进程相关
|
import { toLinkWeb, createWindow, getStaticUrl, sessionStore } from '@/utils/tool' // 工具类-主进程相关
|
||||||
|
|
||||||
import * as Http_ClassManage from '@/api/classManage' // api接口
|
import * as Http_ClassManage from '@/api/classManage' // api接口
|
||||||
import * as Http_Classcourse from '@/api/teaching/classcourse' // api接口
|
import * as Http_Classcourse from '@/api/teaching/classcourse' // api接口
|
||||||
|
@ -103,7 +103,7 @@ let baseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const visible = ref(false) // 是否打开窗口
|
const visible = ref(false) // 是否打开窗口
|
||||||
const myClassActive = ref({}) // 我的课件:准备上课的APT课件
|
const myClassActive = ref({}) // 我的课件:准备上课的APT课件
|
||||||
const imChatRef = ref(null) // im-chat ref
|
// const imChatRef = ref(null) // im-chat ref
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
const classForm = reactive({ // 班级(左侧):表单数据 表单配置
|
const classForm = reactive({ // 班级(左侧):表单数据 表单配置
|
||||||
form: {}, itemOption: [], option: {}
|
form: {}, itemOption: [], option: {}
|
||||||
|
@ -177,7 +177,7 @@ const initData = () => {
|
||||||
teacherForm.itemOption = [
|
teacherForm.itemOption = [
|
||||||
// { label: '班级', prop: 'classid' },
|
// { label: '班级', prop: 'classid' },
|
||||||
// { label: '上课', prop: 'classcourseid' },
|
// { label: '上课', prop: 'classcourseid' },
|
||||||
{ label: '老师扫码', prop: 'qrUrl', show: false },
|
// { label: '老师扫码', prop: 'qrUrl', show: false },
|
||||||
{ label: '手机登录', prop: 'mobile', show: false },
|
{ label: '手机登录', prop: 'mobile', show: false },
|
||||||
{ label: '故障备用', prop: 'backup', show: false },
|
{ label: '故障备用', prop: 'backup', show: false },
|
||||||
]
|
]
|
||||||
|
@ -257,18 +257,22 @@ const createClasscourse = async () => {
|
||||||
entpcourseid, evalid, coursetitle,
|
entpcourseid, evalid, coursetitle,
|
||||||
plandate: curDate, opendate: curDate
|
plandate: curDate, opendate: curDate
|
||||||
}
|
}
|
||||||
|
// teacherForm.form.classcourseid = 100
|
||||||
teacherForm.form.classcourseid = await Http_Classcourse.addClasscourseReturnId(params)
|
teacherForm.form.classcourseid = await Http_Classcourse.addClasscourseReturnId(params)
|
||||||
dt.loading = false
|
dt.loading = false
|
||||||
// getClasscourseList('update') // 更新列表
|
// getClasscourseList('update') // 更新列表
|
||||||
ElMessage.success('创建课程-成功')
|
let msgEl = ElMessage.success('创建课程-成功')
|
||||||
// 新版-pptList 打开公屏
|
// 新版-pptList 打开公屏
|
||||||
if (myClassActive.value.filetype == 'aippt') {
|
if (myClassActive.value.filetype == 'aippt') {
|
||||||
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
msgEl.close()
|
msgEl.close()
|
||||||
const classcourse = {...params, id: teacherForm.form.classcourseid}
|
msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
||||||
openPublicScreen(classcourse)
|
setTimeout(() => {
|
||||||
}, 1500);
|
msgEl.close()
|
||||||
|
const classcourse = {...params, id: teacherForm.form.classcourseid}
|
||||||
|
openPublicScreen(classcourse)
|
||||||
|
}, 2000);
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 删除课程
|
// 删除课程
|
||||||
|
@ -296,14 +300,23 @@ const removeClasscourse = async () => {
|
||||||
const classTeachingStart = async () => {
|
const classTeachingStart = async () => {
|
||||||
const { classcourseid:id } = teacherForm.form
|
const { classcourseid:id } = teacherForm.form
|
||||||
if (id) { // 开始上课
|
if (id) { // 开始上课
|
||||||
const url = `/teaching/classteaching?classcourseid=${id}&actor=classTeachingOnPublicScreen`
|
// 新版-pptList 打开公屏
|
||||||
toLinkWeb(url) // 跳转web-公屏
|
if (myClassActive.value.filetype == 'aptist') {
|
||||||
visible.value = false // 关闭弹窗
|
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
||||||
handleClose() // 关闭im-chat
|
setTimeout(() => {
|
||||||
|
msgEl.close()
|
||||||
|
openPublicScreen({id})
|
||||||
|
}, 2000);
|
||||||
|
}else {
|
||||||
|
const url = `/teaching/classteaching?classcourseid=${id}&actor=classTeachingOnPublicScreen`
|
||||||
|
toLinkWeb(url) // 跳转web-公屏
|
||||||
|
visible.value = false // 关闭弹窗
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 获取二维码地址
|
// 获取二维码地址
|
||||||
const getQrUrl = async() => {
|
const getQrUrl = async() => {
|
||||||
|
// console.log('获取二维码地址')
|
||||||
const { classcourseid:id } = teacherForm.form
|
const { classcourseid:id } = teacherForm.form
|
||||||
const { userName, userId } = userStore.user
|
const { userName, userId } = userStore.user
|
||||||
if (!id||!userName) return
|
if (!id||!userName) return
|
||||||
|
@ -336,6 +349,7 @@ const getQrUrl = async() => {
|
||||||
|
|
||||||
// 打开公屏
|
// 打开公屏
|
||||||
const openPublicScreen = (classcourse) => {
|
const openPublicScreen = (classcourse) => {
|
||||||
|
console.log('打开公屏', classcourse)
|
||||||
const resource = toRaw(myClassActive.value)
|
const resource = toRaw(myClassActive.value)
|
||||||
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||||
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
||||||
|
@ -346,6 +360,7 @@ const openPublicScreen = (classcourse) => {
|
||||||
sessionStore.set('curr.classcourse', null) // 清除缓存
|
sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
visible.value = false // 关闭弹窗
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定时器监听
|
// 定时器监听
|
||||||
|
@ -386,12 +401,14 @@ watch(() => classForm.form.classid, (val)=> {
|
||||||
// 监听-课程id
|
// 监听-课程id
|
||||||
watch(() => teacherForm.form.classcourseid, (val) => {
|
watch(() => teacherForm.form.classcourseid, (val) => {
|
||||||
const bool = !!val
|
const bool = !!val
|
||||||
|
const isApt = myClassActive.filetype=='apt'
|
||||||
// 获取选中课程-生成二维码地址
|
// 获取选中课程-生成二维码地址
|
||||||
bool && getQrUrl()
|
isApt && bool && getQrUrl()
|
||||||
// 监听课程id,是否显示功能
|
// 监听课程id,是否显示功能
|
||||||
teacherForm.itemOption.forEach(o => {
|
teacherForm.itemOption.forEach(o => {
|
||||||
// 有课程id,触发
|
// 有课程id,触发
|
||||||
if (['qrUrl','backup'].includes(o.prop)) o.show = bool
|
const arr = isApt ? ['qrUrl','backup'] : ['backup']
|
||||||
|
if (arr.includes(o.prop)) o.show = bool
|
||||||
// 课程id为空,触发
|
// 课程id为空,触发
|
||||||
if (['mobile'].includes(o.prop)) o.show = !bool
|
if (['mobile'].includes(o.prop)) o.show = !bool
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
{{ item.async === 'on' ? '同步中' : '' }}
|
{{ item.async === 'on' ? '同步中' : '' }}
|
||||||
</div>
|
</div>
|
||||||
<template v-if="item.fileFlag ==='课件'">|</template>
|
<template v-if="item.fileFlag ==='课件'">|</template>
|
||||||
<div style="width: 70px">访问 100</div>
|
<!-- <div style="width: 70px">访问 100</div>
|
||||||
|
|
|
|
||||||
<div style="width: 70px">引用 50</div>
|
<div style="width: 70px">引用 50</div>
|
||||||
|
|
|
|
||||||
|
@ -49,6 +49,16 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
">点赞 20</div>
|
">点赞 20</div>
|
||||||
|
|-->
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
flex: 1;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 200px;
|
||||||
|
">{{formatDate(item.createTime, 'yyyy-MM-dd hh:mm:ss')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="prepare-body-main-item-btn">
|
<div class="prepare-body-main-item-btn">
|
||||||
|
@ -107,6 +117,7 @@ import { endClass, getSelfReserv } from '@/api/classManage'
|
||||||
import { listEntpcourse } from '@/api/teaching/classwork'
|
import { listEntpcourse } from '@/api/teaching/classwork'
|
||||||
import { createWindow } from '@/utils/tool'
|
import { createWindow } from '@/utils/tool'
|
||||||
import { defineExpose } from 'vue'
|
import { defineExpose } from 'vue'
|
||||||
|
import {formatDate} from '@/utils/comm'
|
||||||
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -8,15 +8,16 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="createAptFile">新建文枢课件</el-dropdown-item>
|
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
|
||||||
<el-dropdown-item>AI一键生成</el-dropdown-item>
|
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
|
||||||
<el-dropdown-item>导入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">
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
<el-tabs v-model="activeAptTab" style="height: 100%;">
|
<el-tabs v-model="activeAptTab" style="height: 100%;">
|
||||||
<el-tab-pane label="文枢课件" name="教学课件" class="prepare-center-jxkj">
|
<el-tab-pane label="文枢课件" name="教学课件" class="prepare-center-jxkj">
|
||||||
<div class="prepare-center-header">
|
<!-- <div class="prepare-center-header">
|
||||||
<div class="center-create-btn" style="background-color: rgb(64,158,255)" @click="createAptFile">
|
<div class="center-create-btn" style="background-color: rgb(64,158,255)" @click="createAptFile">
|
||||||
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>创建APT</label></div>
|
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>创建APT</label></div>
|
||||||
<div class="create-btn-info">智能交互课件</div>
|
<div class="create-btn-info">智能交互课件</div>
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>生成PPT</label></div>
|
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>生成PPT</label></div>
|
||||||
<div class="create-btn-info">试验版</div>
|
<div class="create-btn-info">试验版</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>-->
|
||||||
<div class="prepare-center-body">
|
<div class="prepare-center-body">
|
||||||
<kj-list-item
|
<kj-list-item
|
||||||
v-for="(item, index) in currentKJFileList"
|
v-for="(item, index) in currentKJFileList"
|
||||||
|
@ -152,6 +153,7 @@
|
||||||
<!-- 上课配置 -->
|
<!-- 上课配置 -->
|
||||||
<class-start ref="calssRef" @close="closeChange"/>
|
<class-start ref="calssRef" @close="closeChange"/>
|
||||||
<PptDialog @add-success="addAiPPT" :currentNode="currentNode" :uploadData="uploadData" v-model="pptDialog"/>
|
<PptDialog @add-success="addAiPPT" :currentNode="currentNode" :uploadData="uploadData" v-model="pptDialog"/>
|
||||||
|
<progress-dialog v-model:visible="pgDialog.visible" v-bind="pgDialog" />
|
||||||
<!-- 章节弹窗 -->
|
<!-- 章节弹窗 -->
|
||||||
<TreeLog ref="treelogRef"/>
|
<TreeLog ref="treelogRef"/>
|
||||||
<!-- <button @click="test">test</button> -->
|
<!-- <button @click="test">test</button> -->
|
||||||
|
@ -161,8 +163,16 @@ import {Check, Plus, Position} from '@element-plus/icons-vue'
|
||||||
import Reserv from '@/views/prepare/container/reserv.vue'
|
import Reserv from '@/views/prepare/container/reserv.vue'
|
||||||
import { ArrowDown } from '@element-plus/icons-vue'
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
import PptDialog from '@/views/prepare/container/ppt-dialog.vue'
|
import PptDialog from '@/views/prepare/container/ppt-dialog.vue'
|
||||||
|
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
const router = useRouter()
|
||||||
|
const aiTOPPT = ()=> {
|
||||||
|
router.push({path: '/model/design'})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
|
||||||
|
|
||||||
const Remote = require('@electron/remote')
|
const Remote = require('@electron/remote')
|
||||||
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import uploadDialog from '@/components/upload-dialog/index.vue'
|
import uploadDialog from '@/components/upload-dialog/index.vue'
|
||||||
|
@ -192,13 +202,21 @@ import ClassReserv from '@/views/classManage/classReserv.vue'
|
||||||
import TreeLog from '@/views/prepare/components/treeLog.vue'
|
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 Chat from '@/utils/chat' // im 登录初始化
|
import Chat from '@/utils/chat'
|
||||||
|
import * as commUtils from "@/utils/comm";
|
||||||
|
import * as Api_server from "@/api/apiService";
|
||||||
|
import msgUtils from "@/plugins/modal";
|
||||||
|
import * as API_entpcoursefile from "@/api/education/entpcoursefile"; // im 登录初始化
|
||||||
if (!Chat.imChat) Chat.init()
|
if (!Chat.imChat) Chat.init()
|
||||||
|
// import Chat from '@/utils/chat' // im 登录初始化
|
||||||
|
// if (!Chat.imChat) Chat.init()
|
||||||
|
// import ChatWs from '@/plugins/socket'
|
||||||
|
// console.log('xxxx',ChatWs)
|
||||||
|
// ChatWs.watch((data,e) => console.log('ws', data, e))
|
||||||
|
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Prepare',
|
name: 'Prepare',
|
||||||
components: {
|
components: {
|
||||||
|
@ -254,7 +272,23 @@ export default {
|
||||||
// 打开章节的弹窗
|
// 打开章节的弹窗
|
||||||
treelogRef:null,
|
treelogRef:null,
|
||||||
// 获取当前章节对应的课程信息 Entpcourse
|
// 获取当前章节对应的课程信息 Entpcourse
|
||||||
entp: null
|
entp: null,
|
||||||
|
pgDialog: { // 弹窗-进度条
|
||||||
|
visible: false,
|
||||||
|
title: 'PPT解析中...',
|
||||||
|
width: 300,
|
||||||
|
showClose: false,
|
||||||
|
draggable: true,
|
||||||
|
beforeClose: done => {}, // 阻止-弹窗事件
|
||||||
|
pg: { // 进度条-参数
|
||||||
|
percentage: 0, // 百分比
|
||||||
|
color: [
|
||||||
|
{ color: '#1989fa', percentage: 50 }, // 蓝色
|
||||||
|
{ color: '#e6a23c', percentage: 80 }, // 橙色
|
||||||
|
{ color: '#5cb87a', percentage: 100 }, // 绿色
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -473,6 +507,117 @@ export default {
|
||||||
},500)
|
},500)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
openFilePicker(){
|
||||||
|
this.$refs.fileInput.click();
|
||||||
|
},
|
||||||
|
handleFileChange(){
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
console.log(file);
|
||||||
|
console.log('文件名:', file.name);
|
||||||
|
console.log('文件类型:', file.type);
|
||||||
|
console.log('文件大小:', file.size);
|
||||||
|
this.createAIPPTByFile(file)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async toRousrceUrl(o) {
|
||||||
|
if (!!o.src) { // 如果有src就转换
|
||||||
|
const isBase64 = /^data:image\/(\w+);base64,/.test(o.src)
|
||||||
|
const isBlobUrl = /^blob:/.test(o.src)
|
||||||
|
console.log('isBase64', o, isBase64)
|
||||||
|
if (isBase64) {
|
||||||
|
const bolb = commUtils.base64ToBlob(o.src)
|
||||||
|
const fileName = Date.now() + '.png'
|
||||||
|
const file = commUtils.blobToFile(bolb, fileName)
|
||||||
|
// o.src = fileName
|
||||||
|
// console.log('file', file)
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
const res = await Api_server.Other.uploadFile(formData)
|
||||||
|
if (res && res.code == 200){
|
||||||
|
const url = res?.url
|
||||||
|
url &&(o.src = url)
|
||||||
|
}
|
||||||
|
} else if (isBlobUrl) { // 视频和音频
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (o?.background?.image) await this.toRousrceUrl(o.background.image)
|
||||||
|
if (o?.elements) o.elements.forEach(async o => {await this.toRousrceUrl(o)})
|
||||||
|
},
|
||||||
|
async createAIPPTByFile(file) {
|
||||||
|
this.pgDialog.visible = true
|
||||||
|
this.pgDialog.pg.percentage = 0
|
||||||
|
const resPptJson = await PPTXFileToJson(file)
|
||||||
|
const { def, slides, ...content } = resPptJson
|
||||||
|
// 转换图片|音频|视频 为线上地址
|
||||||
|
let completed = 0
|
||||||
|
const total = slides.length
|
||||||
|
for( let o of slides ) {
|
||||||
|
completed++
|
||||||
|
await this.toRousrceUrl(o)
|
||||||
|
// 设置进度条
|
||||||
|
this.pgDialog.pg.percentage = Math.floor(completed / total * 100)
|
||||||
|
}
|
||||||
|
this.pgDialog.pg.percentage = 0
|
||||||
|
this.pgDialog.visible = false
|
||||||
|
listEntpcourse({
|
||||||
|
evalid: this.currentNode.id,
|
||||||
|
edituserid: this.userStore.userId,
|
||||||
|
pageSize: 500
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.rows.length <= 0) return
|
||||||
|
let resCourse = response.rows[0]
|
||||||
|
// 添加
|
||||||
|
let form = {
|
||||||
|
parentid: 0,
|
||||||
|
entpid: this.userStore.deptId,
|
||||||
|
entpcourseid: resCourse.id,
|
||||||
|
ppttype: 'file',
|
||||||
|
title: resCourse.coursetitle,
|
||||||
|
fileurl: '',
|
||||||
|
filetype: 'aippt',
|
||||||
|
datacontent: '',
|
||||||
|
parentContent: JSON.stringify(content),
|
||||||
|
filekey: '',
|
||||||
|
filetag: '',
|
||||||
|
fileidx: 0,
|
||||||
|
dflag: 0,
|
||||||
|
status: '',
|
||||||
|
edituserid: this.userStore.userId
|
||||||
|
}
|
||||||
|
addEntpcoursefileReturnId(form).then((slideid) => {
|
||||||
|
creatAPT({
|
||||||
|
...this.uploadData,
|
||||||
|
fileId: slideid,
|
||||||
|
fileFlag: 'aippt',
|
||||||
|
fileShowName: this.currentNode.itemtitle + '.aippt'
|
||||||
|
}).then(async (res) => {
|
||||||
|
|
||||||
|
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
|
||||||
|
let params = {
|
||||||
|
parentid: slideid,
|
||||||
|
entpid: resCourse.entpid,
|
||||||
|
entpcourseid: resCourse.id,
|
||||||
|
title: '',
|
||||||
|
filetype: 'slide',
|
||||||
|
slides: resSlides,
|
||||||
|
edituserid: this.userStore.userId
|
||||||
|
}
|
||||||
|
const res_3 = await API_entpcoursefile.batchAddNew(params)
|
||||||
|
if (res_3 && res_3.code == 200) {
|
||||||
|
msgUtils.msgSuccess('导入PPT课件成功')
|
||||||
|
this.currentFileList.unshift(res.resData)
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.$refs['kjItemRef'+res.resData.id][0].openFileWin(res.resData);
|
||||||
|
},500)
|
||||||
|
} else {
|
||||||
|
msgUtils.msgWarning('导入PPT课件失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
createAIPPT() {
|
createAIPPT() {
|
||||||
listEntpcourse({
|
listEntpcourse({
|
||||||
evalid: this.currentNode.id,
|
evalid: this.currentNode.id,
|
||||||
|
@ -499,57 +644,22 @@ export default {
|
||||||
edituserid: this.userStore.userId
|
edituserid: this.userStore.userId
|
||||||
}
|
}
|
||||||
addEntpcoursefileReturnId(form).then((slideid) => {
|
addEntpcoursefileReturnId(form).then((slideid) => {
|
||||||
let pagearray = []
|
|
||||||
// 公屏
|
|
||||||
pagearray.push({
|
|
||||||
key: '公屏',
|
|
||||||
title: '公屏页',
|
|
||||||
slidedata: {
|
|
||||||
attrs: { width: 1333, height: 749.8125 },
|
|
||||||
className: 'Stage',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
attrs: {},
|
|
||||||
className: 'Layer',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
attrs: {
|
|
||||||
width: 1333,
|
|
||||||
height: 749.8125,
|
|
||||||
fill: 'white',
|
|
||||||
name: 'fixedbackground',
|
|
||||||
listening: true
|
|
||||||
},
|
|
||||||
className: 'Rect'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 添加
|
// 添加
|
||||||
var form = {
|
var form = {
|
||||||
parentid: slideid,
|
parentid: slideid,
|
||||||
entpid: resCourse.entpid,
|
entpid: resCourse.entpid,
|
||||||
entpcourseid: resCourse.id,
|
entpcourseid: resCourse.id,
|
||||||
ppttype: 'file',
|
|
||||||
title: '第一页',
|
title: '第一页',
|
||||||
fileurl: '',
|
|
||||||
filetype: 'slide',
|
filetype: 'slide',
|
||||||
datacontent: JSON.stringify(pagearray),
|
datacontent: '{"elements":[],"background":{"type":"solid","color":"#fff"}}',
|
||||||
filekey: '',
|
|
||||||
filetag: '',
|
|
||||||
fileidx: 0,
|
|
||||||
dflag: 0,
|
|
||||||
status: '',
|
|
||||||
edituserid: this.userStore.userId
|
edituserid: this.userStore.userId
|
||||||
}
|
}
|
||||||
addEntpcoursefileReturnId(form).then((res) => {
|
addEntpcoursefileReturnId(form).then((res) => {
|
||||||
creatAPT({
|
creatAPT({
|
||||||
...this.uploadData,
|
...this.uploadData,
|
||||||
fileId: slideid,
|
fileId: slideid,
|
||||||
fileShowName: this.currentNode.itemtitle + '.apt'
|
fileFlag: 'aippt',
|
||||||
|
fileShowName: this.currentNode.itemtitle + '.aippt'
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
this.currentFileList.unshift(res.resData)
|
this.currentFileList.unshift(res.resData)
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
|
|
|
@ -34,7 +34,6 @@ import {getDept } from '@/api/login'
|
||||||
import { listEvaluation } from '@/api/subject/index'
|
import { listEvaluation } from '@/api/subject/index'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import {ElMessage} from 'element-plus'
|
import {ElMessage} from 'element-plus'
|
||||||
import { clearBookInfo } from '@/utils/ruoyi'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import {listClassmain} from '@/api/classManage/index'
|
import {listClassmain} from '@/api/classManage/index'
|
||||||
//班级列表
|
//班级列表
|
||||||
|
|
Loading…
Reference in New Issue