This commit is contained in:
小杨 2024-12-09 11:16:48 +08:00
commit 5b1d921378
16 changed files with 180 additions and 41 deletions

5
env.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare module '*.vue' {
import { ComponentOptions } from 'vue'
const componentOptions: ComponentOptions
export default componentOptions
}

View File

@ -81,5 +81,8 @@ const initLoad: Function = () => {
<style lang="scss"> <style lang="scss">
#app { #app {
height: 100%; height: 100%;
svg, canvas, img, audio, video, iframe {
display: unset;
}
} }
</style> </style>

View File

@ -125,7 +125,8 @@ import {
User, User,
Switch, Switch,
More, More,
Material Material,
AddPicture
} from '@icon-park/vue-next' } from '@icon-park/vue-next'
export interface Icons { export interface Icons {
@ -256,7 +257,8 @@ export const icons: Icons = {
IconUser: User, IconUser: User,
IconSwitch: Switch, IconSwitch: Switch,
IconMore: More, IconMore: More,
IconMaterial: Material IconMaterial: Material,
IconAddPicture: AddPicture
} }
export default { export default {

View File

@ -11,6 +11,7 @@
</div> </div>
<el-button type="primary" @click="onInsert(item)">插入</el-button> <el-button type="primary" @click="onInsert(item)">插入</el-button>
</div> </div>
<el-empty description="暂无素材" v-if="!list.length" />
</div> </div>
</template> </template>
@ -93,11 +94,9 @@ const GetUrlParameters = (parameters) => {
} }
} }
} }
return resData; return resData;
} }
const proxyToBase64 = (url)=> { const proxyToBase64 = (url)=> {
const dourl = GetUrlParameters(url) const dourl = GetUrlParameters(url)
console.log(dourl,'dourl') console.log(dourl,'dourl')

View File

@ -83,6 +83,7 @@
</Popover> </Popover>
<IconPreviewOpen class="handler-item" v-tooltip="'插入试题'" @click="classWorkTaskVisible = true" /> <IconPreviewOpen class="handler-item" v-tooltip="'插入试题'" @click="classWorkTaskVisible = true" />
<IconMaterial class="handler-item" v-tooltip="'插入素材'" @click="materiaVisible = true"/> <IconMaterial class="handler-item" v-tooltip="'插入素材'" @click="materiaVisible = true"/>
<IconAddPicture class="handler-item" v-tooltip="'文生图'" @click="imgVisible = true" />
</div> </div>
<div class="right-handler"> <div class="right-handler">
@ -121,14 +122,18 @@
@update="data => { onhtml2canvas(data); classWorkTaskVisible = false }" @update="data => { onhtml2canvas(data); classWorkTaskVisible = false }"
/> />
</el-dialog> </el-dialog>
<!--插入素材-->
<Modal <Modal
v-model:visible="materiaVisible" v-model:visible="materiaVisible"
:width="880"> :width="880">
<MaterialDialog @close="materiaVisible = false" @insertMaterial="insertMaterial"/> <MaterialDialog @close="materiaVisible = false" @insertMaterial="insertMaterial"/>
</Modal> </Modal>
<!--文生图-->
<Modal
v-model:visible="imgVisible"
:width="1300">
<TextCreateImg hasPPt @insertImg="(url: string) => { createImageElement(url); imgVisible = false }" />
</Modal>
</div> </div>
</template> </template>
@ -156,6 +161,7 @@ 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 TextCreateImg from '@/components/ai-kolors/index.vue'
const mainStore = useMainStore() const mainStore = useMainStore()
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore) const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
@ -269,8 +275,10 @@ const insertMaterial = (item: MaterialParams) =>{
createImageElement(data) createImageElement(data)
} }
materiaVisible.value = false materiaVisible.value = false
} }
//
const imgVisible = ref(false)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -154,15 +154,13 @@ const topImgWrapperPositionStyle = computed(() => {
const topImgPositionStyle = computed(() => { const topImgPositionStyle = computed(() => {
const bottomWidth = imgPosition.value.width const bottomWidth = imgPosition.value.width
const bottomHeight = imgPosition.value.height const bottomHeight = imgPosition.value.height
console.log("底层图片位置大小(遮罩区域图片)", imgPosition.value)
const { top, left, width, height } = topImgWrapperPosition.value const { top, left, width, height } = topImgWrapperPosition.value
console.log("width", ((bottomWidth / width * 100) - (left * (100 / width))) + '%')
console.log("height", bottomHeight / height * 100 + '%')
return { return {
left: -left * (100 / width) + '%', left: -left * (100 / width) + '%',
top: -top * (100 / height) + '%', top: -top * (100 / height) + '%',
width: ((bottomWidth / width * 100) - (left * (100 / width))) + '%' , width: bottomWidth / width * 100 + '%' ,
height: bottomHeight / height * 100 + '%', height: bottomHeight / height * 100 + '%',
} }
}) })
@ -540,6 +538,7 @@ const edgePoints = [
img { img {
position: absolute; position: absolute;
max-width: none !important;
} }
} }
} }

View File

@ -183,6 +183,7 @@ const handleClip = (data: ImageClipedEmitData | null) => {
} }
img { img {
position: absolute; position: absolute;
max-width: none !important; //
} }
} }
.color-mask { .color-mask {

View File

@ -144,8 +144,14 @@ import { convertTextToPicture, getQueue, getPromptId, getPicture, chattoprompt,
import CryptoJS from 'crypto-js' import CryptoJS from 'crypto-js'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
export default { export default {
props: {
hasPPt: {
type: Boolean,
default: false
}
},
data() { data() {
return { return {
form: { form: {
ratio: "512", ratio: "512",
@ -384,7 +390,7 @@ export default {
urls.push(url0) urls.push(url0)
buttonState.push({ buttonState.push({
disabled: false, disabled: false,
text: "插入本课素材资源库", text: this.hasPPt ? '插入' : "插入本课素材资源库",
}) })
} }
this.skeletonNumber = 0 this.skeletonNumber = 0
@ -476,6 +482,10 @@ export default {
// //
async saveImage(resultIndex, index, url, resultItem) { async saveImage(resultIndex, index, url, resultItem) {
if(this.hasPPt){
this.$emit('insertImg', url)
return
}
this.buttonStates[resultIndex][index].disabled = true; this.buttonStates[resultIndex][index].disabled = true;
this.buttonStates[resultIndex][index].text = "正在保存..."; this.buttonStates[resultIndex][index].text = "正在保存...";
const numberIndex = url.indexOf('filename='); const numberIndex = url.indexOf('filename=');

View File

@ -35,7 +35,7 @@ const getFileTypeIcon = () => {
txt: 'icon-txt', txt: 'icon-txt',
rar: 'icon-rar', rar: 'icon-rar',
apt: 'icon-A', apt: 'icon-A',
aptist: 'icon-A', aippt: 'icon-A',
} }
if (iconObj[name]) { if (iconObj[name]) {
return '#' + iconObj[name] return '#' + iconObj[name]

View File

@ -48,7 +48,7 @@
</div> </div>
<div class="verson">V{{ version }}</div> <div class="verson">V{{ version }}</div>
</div> </div>
</div> </div>
</template> </template>
@ -87,6 +87,12 @@ const headerMenus = [
icon: 'icon-gongzuotai', icon: 'icon-gongzuotai',
path: '/desktop' path: '/desktop'
}, },
{
name: '教学实践',
id: 4,
icon: 'icon-jiaoxueshijian',
path: '/prepare'
},
{ {
name: '资源中心', name: '资源中心',
id: 3, id: 3,
@ -126,12 +132,12 @@ const computedregistertype = computed(() => {
if(type==3 && userStore.DeptInfo.register.auditStatus==0){ if(type==3 && userStore.DeptInfo.register.auditStatus==0){
return 2 return 2
} }
// //
if(type==4 && userStore.DeptInfo.register.auditStatus==0){ if(type==4 && userStore.DeptInfo.register.auditStatus==0){
return 3 return 3
} }
}) })
const clickMenu = ({ id, disabled, path }) => { const clickMenu = ({ id, disabled, path }) => {
if (disabled) return if (disabled) return
@ -193,7 +199,7 @@ onMounted(() => {
} }
.popoverStyle .head-aside{ .popoverStyle .head-aside{
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -246,7 +252,7 @@ onMounted(() => {
align-items: center; align-items: center;
font-size: 12px; font-size: 12px;
.user-img{ .user-img{
width: 56px; width: 56px;
height: 56px; height: 56px;
border-radius: 50%; border-radius: 50%;
cursor: pointer; cursor: pointer;
@ -312,4 +318,4 @@ onMounted(() => {
font-size: 18px; font-size: 18px;
font-weight: 800; font-weight: 800;
} }
</style> </style>

View File

@ -10,7 +10,7 @@
<el-button type="primary" @click="onchange('/model/newClassTaskAssign')">作业管理</el-button> <el-button type="primary" @click="onchange('/model/newClassTaskAssign')">作业管理</el-button>
<el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button> <el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button>
<el-button type="info" @click="onchange('/model/design')">教学框架设计</el-button> <el-button type="info" @click="onchange('/model/design')">教学框架设计</el-button>
<el-button type="success" @click="openPPTist">打开PPTist</el-button> <!-- <el-button type="success" @click="openPPTist">打开PPTist</el-button>-->
<el-button type="info" @click="onchange('/model/examination')">考试分析</el-button> <el-button type="info" @click="onchange('/model/examination')">考试分析</el-button>
<el-button type="primary" v-menus="dt.menus">测试</el-button> <el-button type="primary" v-menus="dt.menus">测试</el-button>
<el-button type="success" @click="onchange('/model/aiKolors')">文生图片</el-button> <el-button type="success" @click="onchange('/model/aiKolors')">文生图片</el-button>
@ -230,7 +230,7 @@ const HTTP_SERVER_API = (type, params = {}) => {
ppttype: 'file', ppttype: 'file',
title: enpt.coursetitle, title: enpt.coursetitle,
fileurl: '', fileurl: '',
filetype: 'aptist', filetype: 'aippt',
datacontent: '', datacontent: '',
filekey: '', filekey: '',
filetag: '', filetag: '',
@ -287,7 +287,7 @@ const handleAll = async(type, row) =>{
break; break;
} }
case 'open': { // -pptist case 'open': { // -pptist
if (row.filetype != 'aptist') return msgUtils.msgWarning('暂不支持该类型文件操作!') if (row.filetype != 'aippt') return msgUtils.msgWarning('暂不支持该类型文件操作!')
sessionStore.set('curr.resource', row) // sessionStore.set('curr.resource', row) //
createWindow('open-win', { createWindow('open-win', {
url: '/pptist', // url: '/pptist', //
@ -312,7 +312,7 @@ const handleAll = async(type, row) =>{
// icons type svg // icons type svg
const getIcon = (o, type) => { const getIcon = (o, type) => {
let icon = typeof o == 'string' ? o : o?.filetype let icon = typeof o == 'string' ? o : o?.filetype
if (['aptist'].includes(o?.filetype)) icon = 'pptx' if (['aippt'].includes(o?.filetype)) icon = 'pptx'
if (!!type) { // icon if (!!type) { // icon
switch(type) { switch(type) {
case 'svg': // svg case 'svg': // svg

View File

@ -158,7 +158,7 @@ const outlineCreatePPT = () => {
const checkProgress = () => { const checkProgress = () => {
getProgressV2(res.sid).then(response => { getProgressV2(res.sid).then(response => {
percentage.value = Math.round(response?.donePages/response?.totalPages)*100; percentage.value = Math.round(response?.donePages*100/response?.totalPages);
if (response.pptStatus === "done") { if (response.pptStatus === "done") {
emit('addSuccess',{...res,url:response.pptUrl}) emit('addSuccess',{...res,url:response.pptUrl})
ElMessage.success("生成成功"); ElMessage.success("生成成功");
@ -267,7 +267,6 @@ function webSocketSend(ws, data) {
function result1(resultData) { function result1(resultData) {
let jsonData = JSON.parse(resultData); let jsonData = JSON.parse(resultData);
console.log(jsonData)
outputText.value += jsonData.payload.choices.text[0].content; outputText.value += jsonData.payload.choices.text[0].content;
const div = document.querySelector('.paragraphs'); const div = document.querySelector('.paragraphs');
if (div) { if (div) {

View File

@ -262,7 +262,7 @@ const createClasscourse = async () => {
// getClasscourseList('update') // // getClasscourseList('update') //
ElMessage.success('创建课程-成功') ElMessage.success('创建课程-成功')
// -pptList // -pptList
if (myClassActive.value.filetype == 'aptist') { if (myClassActive.value.filetype == 'aippt') {
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0}) const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
setTimeout(() => { setTimeout(() => {
msgEl.close() msgEl.close()

View File

@ -341,7 +341,7 @@ export default {
cookieData: { ...configObj.data } cookieData: { ...configObj.data }
}) })
return return
} else if(items.fileFlag === 'aptist') { // aptist PPT-List } else if(items.fileFlag === 'aippt') { // aippt PPT-List
return this.$emit('change', 'click', items) return this.$emit('change', 'click', items)
} }
if (!items||!items.fileSuffix) return; if (!items||!items.fileSuffix) return;

View File

@ -2,8 +2,20 @@
<div v-loading="isLoading" class="page-resource flex"> <div v-loading="isLoading" class="page-resource flex">
<ChooseTextbook @node-click="nodeClick" /> <ChooseTextbook @node-click="nodeClick" />
<div class="page-center-wrap"> <div class="page-center-wrap">
<el-dropdown class="prepare-center-dropdown">
<el-button type="primary">
新建<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="createAptFile">新建文枢课件</el-dropdown-item>
<el-dropdown-item>AI一键生成</el-dropdown-item>
<el-dropdown-item>导入PPT</el-dropdown-item>
</el-dropdown-menu>
</template>
</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>
@ -145,7 +157,7 @@
<!-- <button @click="test">test</button> --> <!-- <button @click="test">test</button> -->
</template> </template>
<script setup> <script setup>
import { Check,Plus } from '@element-plus/icons-vue' 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'
@ -253,11 +265,11 @@ export default {
}, },
currentKJFileList() { currentKJFileList() {
// return this.currentFileList.filter((item) => item.fileFlag === 'apt' || item.fileFlag === '') // return this.currentFileList.filter((item) => item.fileFlag === 'apt' || item.fileFlag === '')
return this.currentFileList.filter((item) => ['apt','aptist','课件'].includes(item.fileFlag)) return this.currentFileList.filter((item) => ['apt','aippt','课件'].includes(item.fileFlag))
}, },
currentSCFileList() { currentSCFileList() {
// return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '') // return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '')
return this.currentFileList.filter((item) => !['apt','aptist','课件'].includes(item.fileFlag)) return this.currentFileList.filter((item) => !['apt','aippt','课件'].includes(item.fileFlag))
} }
}, },
@ -321,7 +333,7 @@ export default {
if(item.fileFlag === 'apt') { if(item.fileFlag === 'apt') {
this.$refs.calssRef.open(item.fileId, classObj) this.$refs.calssRef.open(item.fileId, classObj)
} }
if(item.fileFlag === 'aptist') { if(item.fileFlag === 'aippt') {
this.$refs.calssRef.open(item.fileId, classObj) this.$refs.calssRef.open(item.fileId, classObj)
} }
}, },
@ -378,8 +390,8 @@ export default {
}, 1000) }, 1000)
break break
} }
case 'click': { // --aptist case 'click': { // --aippt
if (row.fileFlag === 'aptist' && !!row.fileId) { if (row.fileFlag === 'aippt' && !!row.fileId) {
const res = await getEntpcoursefile(row.fileId) const res = await getEntpcoursefile(row.fileId)
if (res && res.code === 200) { if (res && res.code === 200) {
sessionStore.set('curr.resource', res.data) // sessionStore.set('curr.resource', res.data) //
@ -461,6 +473,93 @@ export default {
},500) },500)
}) })
}, },
createAIPPT() {
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: '',
filekey: '',
filetag: '',
fileidx: 0,
dflag: 0,
status: '',
edituserid: this.userStore.userId
}
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 = {
parentid: slideid,
entpid: resCourse.entpid,
entpcourseid: resCourse.id,
ppttype: 'file',
title: '第一页',
fileurl: '',
filetype: 'slide',
datacontent: JSON.stringify(pagearray),
filekey: '',
filetag: '',
fileidx: 0,
dflag: 0,
status: '',
edituserid: this.userStore.userId
}
addEntpcoursefileReturnId(form).then((res) => {
creatAPT({
...this.uploadData,
fileId: slideid,
fileShowName: this.currentNode.itemtitle + '.apt'
}).then((res) => {
this.currentFileList.unshift(res.resData)
setTimeout(()=>{
this.$refs['kjItemRef'+res.resData.id][0].openFileWin(res.resData);
},500)
})
})
})
})
},
createAptFile() { createAptFile() {
listEntpcourse({ listEntpcourse({
evalid: this.currentNode.id, evalid: this.currentNode.id,
@ -653,7 +752,7 @@ export default {
for (let i = 0; i < this.currentFileList.length; i++) { for (let i = 0; i < this.currentFileList.length; i++) {
let item = this.currentFileList[i] let item = this.currentFileList[i]
if (item.fileFlag === 'apt') continue; if (item.fileFlag === 'apt') continue;
if (item.fileFlag === 'aptist') continue; if (item.fileFlag === 'aippt') continue;
await asyncLocalFile(item) await asyncLocalFile(item)
} }
this.asyncAllFileVisiable = false this.asyncAllFileVisiable = false
@ -872,6 +971,13 @@ export default {
margin: 0 5px; margin: 0 5px;
border-radius: 10px; border-radius: 10px;
background-color: white; background-color: white;
position: relative;
.prepare-center-dropdown{
z-index: 9999;
position: absolute;
right: 10px;
top: 4px;
}
.prepare-center-jxkj{ .prepare-center-jxkj{
height: 100%; height: 100%;
display: flex; display: flex;

View File

@ -131,6 +131,7 @@ const params = reactive(
const addAiPPT = async(res) => { const addAiPPT = async(res) => {
let node = courseObj.node let node = courseObj.node
pptDialog.value = false;
if (!node) return msgUtils.msgWarning('请选择章节?') if (!node) return msgUtils.msgWarning('请选择章节?')
pgDialog.visible = true pgDialog.visible = true
pgDialog.pg.percentage = 0 pgDialog.pg.percentage = 0
@ -238,8 +239,8 @@ const HTTP_SERVER_API = (type, params = {}) => {
const node = courseObj.node || {} const node = courseObj.node || {}
const def = { const def = {
fileId: '', // id - Entpcoursefile id fileId: '', // id - Entpcoursefile id
fileFlag: 'aptist', fileFlag: 'aippt',
fileShowName: node.itemtitle + '.aptist', fileShowName: node.itemtitle + '.aippt',
textbookId: node.rootid, textbookId: node.rootid,
levelFirstId: node.parentid||node.id, levelFirstId: node.parentid||node.id,
levelSecondId: node.parentid && node.id, levelSecondId: node.parentid && node.id,
@ -298,7 +299,7 @@ const getDefParams = (params) => {
ppttype: 'file', ppttype: 'file',
title: enpt.coursetitle, title: enpt.coursetitle,
fileurl: '', fileurl: '',
filetype: 'aptist', filetype: 'aippt',
datacontent: '', datacontent: '',
filekey: '', filekey: '',
filetag: '', filetag: '',