Compare commits

...

24 Commits

Author SHA1 Message Date
小杨 e7c6ab9e8d Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into yws_dev 2024-12-10 15:34:51 +08:00
小杨 85d06f306a fix:ppt活动添加; 2024-12-10 15:34:46 +08:00
朱浩 656a58693f Merge remote-tracking branch 'origin/main' 2024-12-10 14:20:08 +08:00
zouyf 34cfcf5a6f Merge pull request 'zouyf_dev' (#102) from zouyf_dev into main
Reviewed-on: #102
2024-12-10 11:10:55 +08:00
“zouyf” 9603406a0b 1 2024-12-10 11:09:32 +08:00
“zouyf” 10a7e73c64 Merge branch 'main' into zouyf_dev 2024-12-10 10:59:48 +08:00
“zouyf” 2c238b5706 1 2024-12-10 10:54:21 +08:00
“zouyf” b47feb4a3a 1 2024-12-10 10:46:22 +08:00
朱浩 772b196b31 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/renderer/src/views/prepare/index.vue
2024-12-10 10:44:04 +08:00
zhangxuelin 91e9867b68 Merge pull request 'zxl' (#101) from zxl into main
Reviewed-on: #101
2024-12-10 10:41:08 +08:00
zhangxuelin 80ac4a6e1c Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-10 10:40:21 +08:00
朱浩 757edb0f67 改名AIPPT 2024-12-10 10:40:08 +08:00
“zouyf” c79911cc99 Merge branch 'main' into zouyf_dev 2024-12-10 10:40:07 +08:00
zhangxuelin 1987783fda 添加作业弹窗 2024-12-10 10:40:00 +08:00
“zouyf” 755cfc615a 试题分页查询回顶部 2024-12-10 10:39:39 +08:00
baigl fa776d2a8c Merge pull request 'baigl' (#100) from baigl into main
Reviewed-on: #100
2024-12-10 10:26:52 +08:00
白了个白 122487cf8b ppts习题插入:个人题库 习题截图放到ppts里面转换 2024-12-10 10:24:30 +08:00
白了个白 b7f11c5338 Merge branch 'zouyf_dev' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-10 10:19:06 +08:00
白了个白 c78233a2f4 1 2024-12-10 10:16:07 +08:00
“zouyf” 2e81c706b1 Merge branch 'main' into zouyf_dev 2024-12-10 10:13:00 +08:00
“zouyf” 2360d95f1c pptList试题转图片优化 2024-12-10 10:12:47 +08:00
zhangxuelin f035cf87ea Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl
# Conflicts:
#	src/renderer/src/AixPPTist/src/views/Editor/CanvasTool/index.vue
2024-12-10 09:43:43 +08:00
zhangxuelin e56eb059be 替换上传图片 视频url为线上url 2024-12-10 09:41:59 +08:00
yangws ffd6d6fab9 Merge pull request 'yws_dev' (#99) from yws_dev into main
Reviewed-on: #99
2024-12-09 17:26:08 +08:00
10 changed files with 406 additions and 130 deletions

View File

@ -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)
@ -186,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

View File

@ -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>

View File

@ -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)

View File

@ -30,7 +30,7 @@
<Divider /> <Divider />
<!-- 作业列表 --> <!-- 作业列表 -->
<div class="c-apt-r"> <div class="c-apt-r" v-loading='loadingActive'>
<!-- 显示-作业内容 --> <!-- 显示-作业内容 -->
<template v-for="(item, index) in workList" :key="index"> <template v-for="(item, index) in workList" :key="index">
<div class="item"> <div class="item">
@ -45,9 +45,11 @@
</template> </template>
</div> </div>
<!-- // --> <!-- // -->
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="80%" height="500"> <el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="90%" height="500">
<el-scrollbar height="500"> <el-scrollbar height="550">
<div style="height: 550px;">
<NewClassTsakAssign :currentCourse='currentCourse' @getData="getData" /> <NewClassTsakAssign :currentCourse='currentCourse' @getData="getData" />
</div>
</el-scrollbar> </el-scrollbar>
</el-dialog> </el-dialog>
<!-- 活动引用 --> <!-- 活动引用 -->
@ -142,7 +144,6 @@ const currentCourse = reactive<CurrentCourse>({
worktype: '', worktype: '',
}) })
const dataList = ref<WorkItem[]>([])
const dialogVisible = ref<boolean>(false) const dialogVisible = ref<boolean>(false)
const tasklist_loading = ref<boolean>(false) const tasklist_loading = ref<boolean>(false)
@ -152,11 +153,6 @@ const taskList = ref<WorkItem[]>([])
// //
const activeVisible = ref<boolean>(false) const activeVisible = ref<boolean>(false)
const params = reactive<Params>({
parentid: 14766,
pageSize: 500,
orderby: 'fileidx'
})
const type = ref<WorkType[]>([ const type = ref<WorkType[]>([
{ {
@ -179,6 +175,8 @@ const workList = ref<WorkItem[]>([])
// //
const selectedWorkList = 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 paramData = ref<{ id: number, activityContent: string }>({} as { id: number, activityContent: string })
@ -196,7 +194,6 @@ const formatClassWorkFile = async (postData: WorkItem[]): Promise<void> => {
} }
break; break;
case '习题训练': { case '习题训练': {
console.log(item,'item');
// let workIds = item.quizlist!.map(items => items.id).join(','); // let workIds = item.quizlist!.map(items => items.id).join(',');
// let ress = await listEntpcoursework({ ids: workIds }); // let ress = await listEntpcoursework({ ids: workIds });
// const arr = ress.rows.map((item:{id:number}) => { // const arr = ress.rows.map((item:{id:number}) => {
@ -214,22 +211,19 @@ const formatClassWorkFile = async (postData: WorkItem[]): Promise<void> => {
// item.prevData = JSON.parse(item.workcodes); // item.prevData = JSON.parse(item.workcodes);
} }
} }
const arr = paramData.value.activityContent.split(',') workList.value.push(item)
arr.push(item.id.toString()) loadingActive.value = false
await PPTApi.updateSlide(paramData.value)
addWorkList(item)
} }
await nextTick(); await nextTick();
} }//
//
const addWorkList = (item: WorkItem) => {
workList.value.push(item)
}
//
const handleRemoveDemoActivityClassWork = (item: WorkItem) => { const handleRemoveDemoActivityClassWork = (item: WorkItem) => {
ElMessageBox.confirm('是否确认删除?') ElMessageBox.confirm('是否确认删除?')
.then(() => { .then(() => {
workList.value.splice(workList.value.indexOf(item), 1); workList.value = []
const arr = paramData.value.activityContent.split(',')
const filterArr = arr.filter(itemId => itemId!== item.id.toString())
paramData.value.activityContent = filterArr.join(',')
upDateData()
}) })
.catch(() => { }); .catch(() => { });
} }
@ -269,13 +263,52 @@ const savePPtData = async () => {
ElMessage.warning('请选择活动') ElMessage.warning('请选择活动')
return return
} }
workList.value = []
const arr = selectedWorkList.value.map(item => item.id) const arr = selectedWorkList.value.map(item => item.id)
// //
paramData.value.activityContent = arr.join(',') debugger
await PPTApi.updateSlide(paramData.value) 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(() => {
const curNode = sessionStore.get('subject.curNode') as CourseNode const curNode = sessionStore.get('subject.curNode') as CourseNode
currentCourse.textbookId = curNode.rootid currentCourse.textbookId = curNode.rootid
@ -283,33 +316,12 @@ onMounted(() => {
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: { rows: WorkItem[] }) => {
dataList.value = [...res.rows]
})
objItem.value = workItem.value[slideIndex.value] objItem.value = workItem.value[slideIndex.value]
getCurrentPPtData() getCurrentPPtData()
}) })
watch(() => slideIndex.value, () => { watch(() => slideIndex.value, () => {
getCurrentPPtData() getCurrentPPtData()
}) })
// ppt
const getCurrentPPtData = async () => {
workList.value = []
objItem.value = workItem.value[slideIndex.value]
paramData.value.id = objItem.value.id
if (objItem.value?.activityContent) {
paramData.value.activityContent = objItem.value?.activityContent
const res = await homeworklist({ ids: objItem.value?.activityContent, pageSize: 100 })
await formatClassWorkFile(res.rows)
}
}
//
const getData = async (data: WorkItem) => {
console.log(data, 'data')
await formatClassWorkFile([data])
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.buttonDiv{ .buttonDiv{
@ -375,5 +387,8 @@ const getData = async (data: WorkItem) => {
--el-border-color: var(--current-color); --el-border-color: var(--current-color);
} }
} }
.page .page-resource{
height: 500px !important;
}
} }
</style> </style>

View File

@ -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);
} }

View File

@ -157,6 +157,7 @@ const props = defineProps({
currentCourse: Object, currentCourse: Object,
}) })
const emits = defineEmits(['getData']) const emits = defineEmits(['getData'])
// ppt
const isShow = ref(false) const isShow = ref(false)
const propsQueryCourseObj = route.query.courseObj;// const propsQueryCourseObj = route.query.courseObj;//
@ -490,11 +491,13 @@ const handleClassWorkFormQuizRemove = (index) =>{
// [] newWorkSpaceEdit true // [] newWorkSpaceEdit true
if(isShow.value === false){
if(classWorkForm.id != '' ) {// id if(classWorkForm.id != '' ) {// id
editWork(cform); // editWork(cform); //
return; return;
} }
}
if (classWorkForm.worktype === "课堂展示") { if (classWorkForm.worktype === "课堂展示") {
boardLoading.value = true boardLoading.value = true
@ -596,7 +599,12 @@ const handleClassWorkFormQuizRemove = (index) =>{
} }
console.log('该清空左侧列表数据了'); console.log('该清空左侧列表数据了');
// //
debugger
if(isShow.value){
currentRow.value = {id:1};
}else{
currentRow.value = {id:0}; currentRow.value = {id:0};
}
initHomeWork(); initHomeWork();

View File

@ -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) {
// canvasURL emit('addQuizImgBs64', targetElement);
const screenshotUrl = canvas.toDataURL('image/png'); }
// // html2canvas(targetElement).then(canvas => {
// console.log(screenshotUrl); // // canvasURL
emit('addQuizImgBs64', screenshotUrl); // const screenshotUrl = canvas.toDataURL('image/png');
}); // //
// // console.log(screenshotUrl);
// emit('addQuizImgBs64', screenshotUrl);
// });
} }
// //

View File

@ -62,6 +62,7 @@
:data="workResource.entpCourseWorkList" :data="workResource.entpCourseWorkList"
style="width: 100%; height: calc(100% - 50px);" 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" >
@ -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'
@ -396,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);
} }
@ -439,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) {
// canvasURL emit('addQuizImgBs64', targetElement);
const screenshotUrl = canvas.toDataURL('image/png'); }
// // html2canvas(targetElement).then(canvas => {
// console.log(screenshotUrl); // // canvasURL
emit('addQuizImgBs64', screenshotUrl); // const screenshotUrl = canvas.toDataURL('image/png');
}); // //
// // console.log(screenshotUrl);
// emit('addQuizImgBs64', screenshotUrl);
// });
} }

View File

@ -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 {

View File

@ -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,6 +202,12 @@ 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'
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()
// import Chat from '@/utils/chat' // im // import Chat from '@/utils/chat' // im
// if (!Chat.imChat) Chat.init() // if (!Chat.imChat) Chat.init()
// import ChatWs from '@/plugins/socket' // import ChatWs from '@/plugins/socket'
@ -201,7 +217,6 @@ import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
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: {
@ -257,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: {
@ -476,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,
@ -502,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(()=>{