Compare commits

..

49 Commits

Author SHA1 Message Date
zhengdegang dcabb80757 Merge pull request 'zdg_dev' (#87) from zdg_dev into main
Reviewed-on: #87
2024-12-05 09:47:15 +08:00
zdg 53f26d96d4 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-05 09:44:51 +08:00
zdg 7d7b50fa3e 类型定义 2024-12-05 09:44:45 +08:00
baigl eae2171c70 Merge pull request 'baigl' (#86) from baigl into main
Reviewed-on: #86
2024-12-04 17:31:51 +08:00
白了个白 5fe9359d64 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-04 17:30:30 +08:00
白了个白 be9d33fcd3 pptist: canvasTool 里面 新增插入试题 2024-12-04 17:30:01 +08:00
lyc 09e3264ee7 Merge pull request 'edit' (#85) from lyc-dev into main 2024-12-04 17:16:34 +08:00
lyc 7845d9bb1a edit 2024-12-04 17:15:20 +08:00
zhengdegang 2fb6828154 Merge pull request 'zdg_dev' (#84) from zdg_dev into main
Reviewed-on: #84
2024-12-04 17:09:39 +08:00
zdg 03d1a683be Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-04 17:08:57 +08:00
zdg d542064ee3 ppt生成课堂备课 2024-12-04 17:08:51 +08:00
zhengdegang 57fdba4578 Merge pull request 'ppt生产' (#83) from zdg_dev into main
Reviewed-on: #83
2024-12-04 16:42:25 +08:00
zdg 0e5d84fcd2 ppt生产 2024-12-04 16:41:38 +08:00
朱浩 7811bbfe3e s生成PPT 2024-12-04 16:28:52 +08:00
zhengdegang 7ddf71c044 Merge pull request 'zdg_dev' (#82) from zdg_dev into main
Reviewed-on: #82
2024-12-04 15:46:59 +08:00
zdg 91ceb712bf 异常修复 2024-12-04 15:45:45 +08:00
zdg a192640899 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-04 15:42:38 +08:00
zdg 08a16929f7 还原本地测试代码 2024-12-04 15:32:56 +08:00
lyc 42e8149443 Merge pull request 'lyc-dev' (#81) from lyc-dev into main 2024-12-04 15:14:22 +08:00
lyc 8b429a4174 edit 2024-12-04 15:13:53 +08:00
白了个白 23795f2419 Merge branch 'yws_dev' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-04 15:09:05 +08:00
白了个白 ea204de407 1 2024-12-04 15:05:48 +08:00
白了个白 a31b8d7376 pptist:canvastool 新增 插入习题按钮 2024-12-04 14:58:47 +08:00
小杨 8d03c927b9 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into yws_dev 2024-12-04 14:58:02 +08:00
小杨 edabc0336f add:新增pptlist活动列表; 2024-12-04 14:57:56 +08:00
白了个白 df474db4a5 1 2024-12-04 14:38:28 +08:00
白了个白 328e623db7 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-04 14:36:53 +08:00
白了个白 8ad041e963 1 2024-12-04 14:34:25 +08:00
zhengdegang c22b360e0f Merge pull request 'zdg_dev' (#80) from zdg_dev into main
Reviewed-on: #80
2024-12-04 14:34:14 +08:00
zdg 3b851887ca Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-04 14:33:30 +08:00
zdg e6333e49f0 更新ppt 2024-12-04 14:33:08 +08:00
CYS cee81102da Merge pull request '文生图' (#79) from cys_dev into main
Reviewed-on: #79
2024-12-04 10:29:19 +08:00
cys 59bc2fba86 Merge branch 'cys_dev' 2024-12-04 10:27:45 +08:00
lyc 3ad4391e10 edit 模板 2024-12-03 10:11:51 +08:00
zouyf 051aa6bd56 Merge pull request 'zouyf_dev' (#78) from zouyf_dev into main
Reviewed-on: #78
2024-12-02 17:29:44 +08:00
“zouyf” 330a9acddb 避免多次点击 2024-12-02 17:25:10 +08:00
“zouyf” 90dff4d5c7 Merge branch 'main' into zouyf_dev 2024-12-02 16:36:12 +08:00
baigl e64311e8a4 Merge pull request 'baigl' (#77) from baigl into main
Reviewed-on: #77
2024-12-02 15:36:13 +08:00
白了个白 7c304650ad Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-02 15:35:13 +08:00
lyc 1a267e5696 Merge pull request 'lyc-dev' (#76) from lyc-dev into main 2024-12-02 14:25:30 +08:00
lyc cd6ca2e4e7 最大最小化icon 2024-12-02 14:24:02 +08:00
“zouyf” 99c90bf9a3 Merge branch 'main' into zouyf_dev 2024-12-02 10:44:51 +08:00
白了个白 40053c6c79 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-02 10:19:30 +08:00
“zouyf” c3620a11ee 1 2024-11-28 14:17:32 +08:00
lyc 7b4e54cb16 edit 2024-11-27 17:31:54 +08:00
白了个白 eb428eaddf Merge branch 'zouyf_dev' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-11-27 16:58:39 +08:00
“zouyf” e30e3fd42d Merge branch 'main' into zouyf_dev 2024-11-27 16:58:18 +08:00
“zouyf” 81f704b2a5 1 2024-11-27 15:48:22 +08:00
白了个白 944dff1b00 1 2024-11-27 14:15:00 +08:00
47 changed files with 1909 additions and 312 deletions

View File

@ -34,7 +34,7 @@ export default defineConfig({
'/dev-api': { '/dev-api': {
target: 'http://27.128.240.72:7865', target: 'http://27.128.240.72:7865',
// target: 'http://36.134.181.164:7863', // target: 'http://36.134.181.164:7863',
// target: 'http://192.168.2.52:7863', // target: 'http://192.168.0.102:7865',
changeOrigin: true, changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '') rewrite: (p) => p.replace(/^\/dev-api/, '')
}, },

View File

@ -57,6 +57,7 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"hfmath": "^0.0.2", "hfmath": "^0.0.2",
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",
"html2canvas": "^1.4.1",
"im_electron_sdk": "^8.0.5904", "im_electron_sdk": "^8.0.5904",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",

View File

@ -8,7 +8,7 @@
http-equiv="Content-Security-Policy" http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/> --> /> -->
<meta http-equiv="Content-Security-Policy" content="connect-src * blob: data:; default-src 'self'; script-src 'self' 'unsafe-eval' http://www.wiris.net 'unsafe-inline'; style-src 'self' 'unsafe-inline' http://www.wiris.net; media-src * blob:;img-src * 'self' data: blob:;font-src 'self' http://www.wiris.net;" /> <meta http-equiv="Content-Security-Policy" content="connect-src * blob: data:; default-src 'self' https://wzyzoss.eos-chongqing-3.cmecloud.cn/; script-src 'self' 'unsafe-eval' http://www.wiris.net 'unsafe-inline'; style-src 'self' 'unsafe-inline' http://www.wiris.net; media-src * blob:;img-src * 'self' data: blob:;font-src 'self' http://www.wiris.net;" />
</head> </head>

View File

@ -60,14 +60,6 @@ window.addEventListener('unload', () => {
const newDiscardedDB = JSON.stringify(discardedDBList) const newDiscardedDB = JSON.stringify(discardedDBList)
localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB) localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB)
}) })
/** 接口类型 */
interface Result {
code?: number,
msg?: string,
data?: any
rows?: Array<any>,
total?: number
}
// //
const initLoad: Function = () => { const initLoad: Function = () => {
// ppt // ppt

View File

@ -4,8 +4,10 @@
* @date 2024-11-26 * @date 2024-11-26
*/ */
import { toRaw } from 'vue' import { toRaw } from 'vue'
import { Result } from '@/types' // 接口类型
import msgUtils from '@/plugins/modal' // 消息工具 import msgUtils from '@/plugins/modal' // 消息工具
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
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' // 外部-用户信息
@ -53,7 +55,8 @@ 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)
if (res.code === 200) { console.log(res.rows,'res.rows');
if (res.code === 200) {
const slides = (res.rows || []).map(o => { const slides = (res.rows || []).map(o => {
if (!!o.datacontent) { if (!!o.datacontent) {
const json = JSON.parse(o.datacontent) const json = JSON.parse(o.datacontent)
@ -63,8 +66,15 @@ export class PPTApi {
// 如果没有数据,默认空白页 // 如果没有数据,默认空白页
return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}} return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}}
}) })
// 活动列表处理
const workList = (res.rows || []).map(o => o.activityContent)
const workItem = [...res.rows]
slidesStore.updateSlideIndex(0) // 下标0 为第一页 slidesStore.updateSlideIndex(0) // 下标0 为第一页
slidesStore.setSlides(slides) // 写入数据 slidesStore.setSlides(slides) // 写入数据
// 写入作业列表数据
slidesStore.setWorkList(workList)
// 获取所有的pptlist的数据
slidesStore.setWorkItem(workItem)
resolve(true) resolve(true)
} else msgUtils.msgError(res.msg || '获取数据失败');resolve(false) } else msgUtils.msgError(res.msg || '获取数据失败');resolve(false)
}) })
@ -166,6 +176,14 @@ export class PPTApi {
} else msgUtils.msgError(res.msg || '删除失败');resolve(false) } else msgUtils.msgError(res.msg || '删除失败');resolve(false)
}) })
} }
// 更新-备课资源 标题
static updateSmarttalk(data: object): Promise<Boolean> {
return API_smarttalk.updateSmarttalk(data).then(res => {
if (res.code === 200) return true
else msgUtils.msgError(res.msg || '更新失败');return false
})
}
} }
export default PPTApi export default PPTApi

View File

@ -2,6 +2,7 @@
* @description api store循环引用 * @description api store循环引用
* @author zdg * @author zdg
*/ */
import { Result } from '@/types' // 接口类型
import msgUtils from '@/plugins/modal' // 消息工具 import msgUtils from '@/plugins/modal' // 消息工具
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api

View File

@ -0,0 +1,8 @@
/** 返回-接口类型 */
export interface Result {
code?: number,
msg?: string,
data?: any
rows?: Array<any>,
total?: number
}

View File

@ -7,7 +7,8 @@ import { PPTApi } from './index'
import * as store from '../store' import * as store from '../store'
import { sessionStore } from '@/utils/store' // electron-store 状态管理 import { sessionStore } from '@/utils/store' // electron-store 状态管理
const slidesStore = store.useSlidesStore() const slidesStore = store.useSlidesStore()
const resource = sessionStore.get('curr.resource') const resource = sessionStore.get('curr.resource') // apt 资源
const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源
/** /**
* @description * @description
*/ */
@ -28,4 +29,11 @@ const updatePPT = async (data) => {
data.id = resource.id data.id = resource.id
await PPTApi.updateSlide(data) // 更新ppt内容 await PPTApi.updateSlide(data) // 更新ppt内容
sessionStore.set('curr.resource.title', data.title) sessionStore.set('curr.resource.title', data.title)
// 更新smarttalk内容
if (!!smarttalk && !!data.title) {
const {id, fileFlag} = smarttalk
const params = { id, fileShowName: `${data.title}.${fileFlag}` }
await PPTApi.updateSmarttalk(params) // 更新ppt内容
sessionStore.set('curr.smarttalk.fileShowName', params.fileShowName)
}
} }

View File

@ -31,6 +31,8 @@ export interface SlidesState {
slideIndex: number slideIndex: number
viewportSize: number viewportSize: number
viewportRatio: number viewportRatio: number
workList:Object[],
workItem:Object[],
} }
export const useSlidesStore = defineStore('slides', { export const useSlidesStore = defineStore('slides', {
@ -41,6 +43,8 @@ export const useSlidesStore = defineStore('slides', {
slideIndex: 0, // 当前页面索引 slideIndex: 0, // 当前页面索引
viewportSize: 1000, // 可视区域宽度基数 viewportSize: 1000, // 可视区域宽度基数
viewportRatio: 0.5625, // 可视区域比例默认16:9 viewportRatio: 0.5625, // 可视区域比例默认16:9
workList:[],// 活动的列表
workItem:[],// 获取到的所有pptlist
}), }),
getters: { getters: {
@ -131,6 +135,13 @@ export const useSlidesStore = defineStore('slides', {
setSlides(slides: Slide[]) { setSlides(slides: Slide[]) {
this.slides = slides this.slides = slides
}, },
// 更新活动列表
setWorkList(list: Object[]) {
this.workList = list
},
setWorkItem(list: Object[]) {
this.workItem = list
},
addSlide(slide: Slide | Slide[]) { addSlide(slide: Slide | Slide[]) {
const slides = Array.isArray(slide) ? slide : [slide] const slides = Array.isArray(slide) ? slide : [slide]

View File

@ -6,4 +6,5 @@ export const enum ToolbarStates {
SLIDE_DESIGN = 'slideDesign', SLIDE_DESIGN = 'slideDesign',
SLIDE_ANIMATION = 'slideAnimation', SLIDE_ANIMATION = 'slideAnimation',
MULTI_POSITION = 'multiPosition', MULTI_POSITION = 'multiPosition',
EL_ACTIVE = 'elActive',
} }

View File

@ -81,6 +81,7 @@
</template> </template>
<IconVideoTwo class="handler-item" v-tooltip="'插入音视频'" /> <IconVideoTwo class="handler-item" v-tooltip="'插入音视频'" />
</Popover> </Popover>
<IconPreviewOpen class="handler-item" v-tooltip="'插入试题'" @click="classWorkTaskVisible = true" />
</div> </div>
<div class="right-handler"> <div class="right-handler">
@ -110,6 +111,18 @@
@update="data => { createLatexElement(data); latexEditorVisible = false }" @update="data => { createLatexElement(data); latexEditorVisible = false }"
/> />
</Modal> </Modal>
<Modal
v-model:visible="classWorkTaskVisible"
:width="880"
>
<QuestToPPTist
class="class-work-task-modal"
@close="classWorkTaskVisible = false"
@update="data => { onhtml2canvas(data); classWorkTaskVisible = false }"
/>
</Modal>
</div> </div>
</template> </template>
@ -135,6 +148,7 @@ import Modal from '../../../components/Modal.vue'
import Divider from '../../../components/Divider.vue' import Divider from '../../../components/Divider.vue'
import Popover from '../../../components/Popover.vue' 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'
const mainStore = useMainStore() const mainStore = useMainStore()
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore) const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
@ -172,12 +186,17 @@ const insertImageElement = (files: FileList) => {
getImageDataURL(imageFile).then(dataURL => createImageElement(dataURL)) getImageDataURL(imageFile).then(dataURL => createImageElement(dataURL))
} }
const onhtml2canvas = (imgbs64: string) => {
createImageElement(imgbs64)
}
const shapePoolVisible = ref(false) const shapePoolVisible = ref(false)
const linePoolVisible = ref(false) const linePoolVisible = ref(false)
const chartPoolVisible = ref(false) const chartPoolVisible = ref(false)
const tableGeneratorVisible = ref(false) const tableGeneratorVisible = ref(false)
const mediaInputVisible = ref(false) const mediaInputVisible = ref(false)
const latexEditorVisible = ref(false) const latexEditorVisible = ref(false)
const classWorkTaskVisible = ref(false)
const textTypeSelectVisible = ref(false) const textTypeSelectVisible = ref(false)
const shapeMenuVisible = ref(false) const shapeMenuVisible = ref(false)
const moreVisible = ref(false) const moreVisible = ref(false)
@ -343,6 +362,9 @@ const toggleNotesPanel = () => {
font-size: 13px; font-size: 13px;
} }
} }
.class-work-task-modal{
height: 80vh;
}
@media screen and (width <= 1200px) { @media screen and (width <= 1200px) {
.right-handler .text { .right-handler .text {

View File

@ -66,6 +66,9 @@
</Draggable> </Draggable>
<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>
@ -85,12 +88,13 @@ 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()
const keyboardStore = useKeyboardStore() const keyboardStore = useKeyboardStore()
const { selectedSlidesIndex: _selectedSlidesIndex, thumbnailsFocus } = storeToRefs(mainStore) const { selectedSlidesIndex: _selectedSlidesIndex, thumbnailsFocus } = storeToRefs(mainStore)
const { slides, slideIndex, currentSlide } = storeToRefs(slidesStore) const { slides, slideIndex, currentSlide, workList, workItem } = storeToRefs(slidesStore)
const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore) const { ctrlKeyState, shiftKeyState } = storeToRefs(keyboardStore)
const { slidesLoadLimit } = useLoadSlides() const { slidesLoadLimit } = useLoadSlides()
@ -123,6 +127,8 @@ const {
updateSectionTitle, updateSectionTitle,
} = useSectionHandler() } = useSectionHandler()
const activeRef = ref()
// //
const thumbnailsRef = ref<InstanceType<typeof Draggable>>() const thumbnailsRef = ref<InstanceType<typeof Draggable>>()
watch(() => slideIndex.value, () => { watch(() => slideIndex.value, () => {
@ -145,6 +151,9 @@ 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([])
if (slideIndex.value === index) return if (slideIndex.value === index) return

View File

@ -0,0 +1,291 @@
<template>
<div>
<div style="display: flex;flex-wrap: wrap;">
<el-button size="small" title="活动引用" text style="height: 54px" @click="openList()">
<div class="buttonDiv">
<svg width="26" height="26" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#646473"><path d="M133.36576 308.12842667v407.74314666c0 96.39253333 78.31552 174.76266667 174.76266667 174.76266667h407.74314666c96.39253333 0 174.76266667-78.31552 174.76266667-174.76266667V308.12842667c0-96.39253333-78.31552-174.76266667-174.76266667-174.76266667H308.12842667a174.87189333 174.87189333 0 0 0-174.76266667 174.76266667zM75.09333333 308.12842667A233.19893333 233.19893333 0 0 1 308.12842667 75.09333333h407.74314666A233.19893333 233.19893333 0 0 1 948.90666667 308.12842667v407.74314666A233.19893333 233.19893333 0 0 1 715.87157333 948.90666667H308.12842667A233.19893333 233.19893333 0 0 1 75.09333333 715.87157333V308.12842667z m706.9696 192.07509333c0 24.46677333-5.67978667 48.22357333-16.98474666 71.21578667-11.35957333 22.99221333-26.76053333 43.52682667-46.25749334 61.54922666-19.44234667 18.0224-42.05226667 32.44032-67.61130666 43.25376a207.20298667 207.20298667 0 0 1-81.21002667 16.16554667h-26.54208c-10.37653333 0-21.62688 0.10922667-33.64181333 0.27306667-12.01493333 0.21845333-23.86602667 0.32768-35.66250667 0.32768h-31.9488c-13.1072 0-23.53834667 1.25610667-31.23882667 3.71370666-7.70048 2.51221333-11.35957333 7.91893333-10.92266666 16.16554667 0 6.22592-0.10922667 13.38026667-0.32768 21.46304-0.21845333 8.08277333-0.32768 15.45557333-0.32768 22.06378667 0 10.81344-3.16757333 17.74933333-9.50272 20.86229333-6.33514667 3.11296-14.7456 0.92842667-25.12213334-6.5536-10.92266667-7.42741333-23.37450667-16.27477333-37.41013333-26.43285333a36528.56490667 36528.56490667 0 0 0-126.42986667-91.09504c-10.37653333-7.42741333-15.72864-14.47253333-15.94709333-21.13536-0.27306667-6.60821333 4.36906667-13.65333333 13.9264-21.13536 9.93962667-7.48202667 21.62688-16.27477333 34.95253333-26.43285334 13.38026667-10.15808 27.30666667-20.58922667 41.83381334-31.40266666l42.81685333-31.67573334c14.03562667-10.37653333 26.48746667-19.71541333 37.41013333-28.01664 11.74186667-9.12042667 21.62688-12.61568 29.4912-10.54037333 7.97354667 2.07530667 11.96032 8.73813333 11.96032 19.87925333 0 3.2768 0.10922667 7.3728 0.32768 12.12416a2794.40042667 2794.40042667 0 0 1 1.69301334 43.85450667c0 7.86432 2.62144 12.72490667 7.80970666 14.58176 5.24288 1.85685333 12.34261333 2.83989333 21.40842667 2.83989333 20.42538667-0.43690667 43.30837333-0.65536 68.64896-0.65536h70.66965333c10.43114667 0 20.86229333-2.18453333 31.29344-6.5536 10.37653333-4.36906667 19.93386667-10.10346667 28.56277334-17.36704 8.57429333-7.26357333 15.61941333-15.67402667 21.02613333-25.17674666 5.46133333-9.55733333 8.192-19.6608 8.192-30.47424v-43.52682667c0-16.60245333-0.10922667-32.65877333-0.32768-48.22357333a2840.00256 2840.00256 0 0 1-0.38229333-40.68693334V341.6064c0-9.12042667 3.05834667-16.65706667 9.17504-22.66453333 6.11669333-6.00746667 13.81717333-10.59498667 23.10144-13.70794667 9.28426667-3.11296 19.38773333-4.64213333 30.25578666-4.64213333 10.92266667 0 20.97152 1.41994667 30.25578667 4.36906666 9.28426667 2.83989333 16.98474667 7.09973333 23.10144 12.72490667 6.11669333 5.57056 9.17504 12.56106667 9.17504 20.80768v46.03904c0 10.75882667 0.10922667 22.28224 0.32768 34.51562667 0.27306667 12.23338667 0.38229333 23.92064 0.38229333 35.11637333V500.20352z" p-id="7882"></path></svg>
<div style="margin-top: 10px">活动引用</div>
</div>
</el-button>
<el-button size="small" title="习题训练" text style="height: 54px" @click="showDialog('习题训练')">
<div class="buttonDiv">
<svg width="26" height="26" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#646473"><path d="M473.6 204.8c21.2 0 38.4 17.2 38.4 38.4s-17.2 38.4-38.4 38.4H243.2c-21.2 0-38.4-17.2-38.4-38.4s17.2-38.4 38.4-38.4h230.4z m-51.2 153.6c21.2 0 38.4 17.2 38.4 38.4s-17.2 38.4-38.4 38.4H243.2c-21.2 0-38.4-17.2-38.4-38.4s17.2-38.4 38.4-38.4h179.2zM371.2 512c21.2 0 38.4 17.2 38.4 38.4s-17.2 38.4-38.4 38.4h-128c-21.2 0-38.4-17.2-38.4-38.4S222 512 243.2 512h128z m192-384H153.6c-12.6 0-23 9.1-25.2 21l-0.4 4.6v512c0 12.6 9.1 23 21 25.2l4.6 0.4h257.1c-0.7-8.5-1.1-17-1.1-25.6 0-124 73.5-230.8 179.2-279.4V153.6c0-12.6-9.1-23-21-25.2l-4.6-0.4zM768 460.8H665.6v153.6H512v102.4h153.6v153.6H768V716.8h153.6V614.4H768V460.8zM563.2 51.2c56.6 0 102.4 45.8 102.4 102.4v209c16.6-2.8 33.7-4.2 51.2-4.2 169.7 0 307.2 137.5 307.2 307.2S886.5 972.8 716.8 972.8c-133.7 0-247.5-85.5-289.7-204.8H153.6C97 768 51.2 722.2 51.2 665.6v-512C51.2 97 97 51.2 153.6 51.2h409.6z" p-id="13225"></path></svg>
<div style="margin-top: 10px">习题训练</div>
</div>
</el-button>
<el-button size="small" title="课堂展示" text style="height: 54px" @click="showDialog('课堂展示')">
<div class="buttonDiv">
<svg width="26" height="26" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#646473"><path d="M741.75298 604.605763l3.836774 0.697596 17.43988 3.767014c154.656857 35.089039 260.133252 103.732407 260.133252 194.070985 0 88.455072-101.360583 156.261326-251.134274 191.838682l-9.068737 2.092785-17.370121 3.836774-17.788678 3.487976c-23.927515 4.39485-48.831664 8.092104-74.642686 11.022004l-19.462907 2.023026-24.69487 2.092786-5.022685 0.348797-20.090742 1.325431-10.18489 0.488317-10.25465 0.418557-20.579058 0.697595c-10.324409 0.209279-20.788337 0.348798-31.322025 0.348798l-15.695892-0.139519-15.556373-0.279038-20.648818-0.627836-10.18489-0.418557-10.18489-0.488317-20.160501-1.325431-9.975612-0.697595-19.741944-1.743988a1100.665713 1100.665713 0 0 1-75.968118-9.905852l-18.137475-3.139178-17.788678-3.487976-17.37012-3.767014C105.406635 961.983786 0 893.410178 0 803.141358c0-88.594591 101.360583-156.261326 251.134273-191.9782l8.998979-2.092785 17.43988-3.767014 3.767014-0.697596v93.756796l-10.952245 2.581102-15.207575 3.906533-14.6495 4.046052-13.951904 4.185572c-75.340282 23.857756-121.660604 61.946454-121.660603 89.989781 0 27.206213 43.250903 61.527897 114.196335 85.036855l7.394509 2.371824 14.021663 4.255331 14.6495 4.046052 15.207575 3.906533c8.580421 2.092786 17.43988 4.115812 26.578377 5.999319l13.951904 2.790381 17.021323 3.139178 8.7897 1.39519 17.788678 2.790381 9.068737 1.255672 18.556033 2.302064 14.161182 1.604469 14.370462 1.39519 19.532665 1.53471a1139.731044 1139.731044 0 0 0 142.867498 1.255671l19.881463-1.255671 19.532666-1.53471c8.580421-0.767355 17.021323-1.674228 25.392466-2.581102l12.417194-1.53471 18.276995-2.441583 17.858437-2.790381 8.71994-1.39519 17.091082-3.139178c9.417535-1.813748 18.486273-3.697255 27.415492-5.720281l13.11479-3.069419 15.207575-3.906533 14.649499-4.046052 13.951904-4.185572c75.340282-23.857756 121.590844-59.365352 121.590845-87.408679 0-27.206213-43.250903-64.178759-114.196335-87.617957l-7.39451-2.371824-14.021663-4.255331-14.649499-4.115811-15.207576-3.836774-10.952245-2.581102V604.605763zM451.204578 588.072757l121.660604 69.82928-131.078139 86.153008 9.417535-155.982288z m280.921589-484.131072l121.660603 69.82928-257.552149 443.810069-121.590844-69.899039 257.48239-443.74031zM842.904285 6.278357l40.530281 23.22992a46.459841 46.459841 0 0 1 17.160842 63.690442l-23.439198 40.321003L755.565365 63.620683l23.36944-40.321003a46.948157 46.948157 0 0 1 63.96948-17.021323z" p-id="59383"></path></svg>
<div style="margin-top: 10px">课堂展示</div>
</div>
</el-button>
<el-button size="small" title="常规作业" text style="height: 54px;margin-left: 0" @click="showDialog('常规作业')">
<div class="buttonDiv">
<svg width="26" height="26" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#646473"><path d="M901.705143 511.926857h-55.954286a8.045714 8.045714 0 0 1-8.045714-8.045714V183.881143H181.686857v656.091428H501.76c4.388571 0 8.045714 3.510857 8.045714 7.899429v56.027429c0 4.388571-3.657143 8.045714-8.045714 8.045714H141.750857a31.963429 31.963429 0 0 1-32.036571-32.036572V143.872c0-17.627429 14.336-31.963429 32.036571-31.963429H877.714286c17.700571 0 32.036571 14.336 32.036571 31.963429V503.954286c0 4.388571-3.657143 8.045714-8.045714 8.045714zM731.428571 911.945143a36.571429 36.571429 0 0 1-36.571428-36.571429v-109.714285H585.142857a36.571429 36.571429 0 0 1 0-73.142858h109.714286v-109.714285a36.571429 36.571429 0 0 1 73.142857 0v109.714285H877.714286a36.571429 36.571429 0 1 1 0 73.142858h-109.714286v109.714285a36.571429 36.571429 0 0 1-36.571429 36.571429z" p-id="22184"></path></svg>
<div style="margin-top: 10px">常规作业</div>
</div>
</el-button>
</div>
<Divider />
<!-- 作业列表 -->
<div class="c-apt-r">
<!-- 显示-作业内容 -->
<template v-for="(item, index) in workList">
<div class="item">
<div class="item-title">
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
<el-tooltip :content="item.title||item.uniquekey" placement="top">
<div class="tt">{{item.title||item.uniquekey}}</div>
</el-tooltip>
<el-button class="btn-del" type="danger" link @click="handleRemoveDemoActivityClassWork(item)">删除</el-button>
</div>
</div>
</template>
</div>
<!-- // -->
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="80%">
<NewClassTsakAssign :currentCourse='currentCourse'/>
</el-dialog>
<!-- 活动引用 -->
<el-dialog
v-loading="tasklist_loading"
v-model="activeVisible"
append-to-body
:show-close="false"
width="40%"
@selection-change="handleSelectionChange">
<el-table :data="taskList" style="width: 100%" height="500">
<el-table-column type="selection" :selectable="selectable" width="55" />
<el-table-column prop="evaltitle" label="活动名称" width="150" />
<el-table-column prop="worktype" label="活动类型" width="120" sortable>
<template #default="scope">
<el-tag :type="getTagType(scope.row.worktype) || 'primary'">{{ scope.row.worktype }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="timestamp" label="创建时间" sortable/>
</el-table>
<template #footer>
<el-button @click="activeVisible = false"> </el-button>
<el-button type="primary" @click="save"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, onBeforeMount, defineExpose } from 'vue'
import Divider from '../../../../../components/Divider.vue'
import {listEntpcoursefile} from '@/api/education/entpcoursefile'
import {homeworklist} from '@/api/teaching/classwork'
import { processList } from "@/hooks/useProcessList";
import { listEntpcoursework } from "@/api/classTask/index";
import { ElMessageBox } from 'element-plus'
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
import { sessionStore } from '@/utils/store'
import { useGetHomework } from '@/hooks/useGetHomework'
const currentCourse = reactive({
textbookId:0,
levelFirstId:0,
levelSecondId:0,
coursetitle:'',
node:{},
id:1,
worktype:'',
})
const dataList = ref([])
const dialogVisible = ref(false)
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) => {
console.log(item,'点击了')
workList.value = []
let datacontent = item.datacontent;
let pptJson = "";
if(typeof datacontent === 'string') pptJson = JSON.parse(datacontent)
if(pptJson&&pptJson[0]&&pptJson[0].classworkList) {
homeworklist({ids:pptJson[0].classworkList, pageSize: 100}).then( async res => {
await formatClassWorkFile(res.rows)
})
}
}
const formatClassWorkFile = async (postData) => {
return new Promise(async (resolve, reject)=>{
for (let i = 0; i < postData.length; i++) {
let item = postData[i];
switch (item.worktype) {
case '框架梳理': {
}
break;
case '习题训练': {
item.entpcourseworklistarray = item.entpcourseworklist?JSON.parse('['+item.entpcourseworklist+']'):[];
let workIds = item.entpcourseworklistarray.map(items=>items.id).join(',')
let ress = await listEntpcoursework({ids:workIds})
processList(ress.rows)
item.workShowList = ress.rows
}
break;
case '课堂展示': {
item.base64 = JSON.parse(item.workcodes).base64
}
break;
case '常规作业': {
item.prevData = JSON.parse(item.workcodes)
}
}
workList.value.push(item)
}
resolve()
})
}
//
const handleRemoveDemoActivityClassWork = (item) => {
ElMessageBox.confirm('是否确认删除?')
.then(function () {
workList.value.splice(workList.value.indexOf(item), 1);
})
.catch(() => {});
}
// tag
const getTagType = (worktype) => {
return type.value.find(item => item.label == worktype).value
}
//
const initHomeWork = async()=> {
tasklist_loading.value = true;
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
taskList.value = res;
tasklist_loading.value = false;
}
//
const handleSelectionChange = (val) => {
console.log(val,'多选')
}
//
const showDialog = (item) => {
currentCourse.worktype = item
dialogVisible.value = true
}
const openList = () => {
activeVisible.value = true
initHomeWork()
}
//
const save = () => {
console.log('添加了')
activeVisible.value = false
}
onMounted(() => {
// console.log(sessionStore.get('subject.curBook'),'curBook');
// 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.levelFirstId = curNode.parentNode.id
currentCourse.levelSecondId = curNode.id
currentCourse.coursetitle = curNode.itemtitle,
currentCourse.node = curNode
listEntpcoursefile(params).then((res) => {
dataList.value = [...res.rows]
})
})
defineExpose({
clickPPTList
})
</script>
<style scoped lang="scss">
.buttonDiv{
margin-top: 4px;
display: flex;
align-items: center;
justify-content: space-between;
flex-direction: column;
}
// (apt)-
.c-apt-r{
flex:1;
overflow: auto;
.item{
position: relative;
margin-top: 5px;
.item-title{
display: flex;
align-items: center;
.tt{
flex: 1;
padding-left: 10px;
cursor: default;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 13px;
color: #606266;
}
.btn-del{
margin-right: 10px;
}
}
.item-body{
position: relative;
border: 1px solid silver;
padding: 10px;
background: #fff;
border-radius: 3px;
margin: 5px 10px;
cursor: default;
&:hover{
border-color: var(--el-color-primary);
.el-text{
--el-text-color: var(--el-color-primary);
}
.el-tag{
--el-tag-bg-color: var(--el-color-primary);
--el-tag-border-color: var(--el-color-primary);
--el-tag-text-color: var(--el-color-white);
}
}
.c-icon-info{
position: absolute;
top: -5px;
right: -5px;
}
}
.item-divider{
margin: 5px 0;
margin-left: 10px;
width: calc(100% - 20px);
--el-border-color: var(--current-color);
}
}
}
</style>

View File

@ -25,6 +25,8 @@ import SlideDesignPanel from './SlideDesignPanel.vue'
import SlideAnimationPanel from './SlideAnimationPanel.vue' import SlideAnimationPanel from './SlideAnimationPanel.vue'
import MultiPositionPanel from './MultiPositionPanel.vue' import MultiPositionPanel from './MultiPositionPanel.vue'
import SymbolPanel from './SymbolPanel.vue' import SymbolPanel from './SymbolPanel.vue'
//
import SymbolActivePanel from './ElementStylePanel/Active/index.vue'
import Tabs from '../../../components/Tabs.vue' import Tabs from '../../../components/Tabs.vue'
interface ElementTabs { interface ElementTabs {
@ -54,6 +56,7 @@ const slideTabs = [
{ label: '设计', key: ToolbarStates.SLIDE_DESIGN }, { label: '设计', key: ToolbarStates.SLIDE_DESIGN },
{ label: '切换', key: ToolbarStates.SLIDE_ANIMATION }, { label: '切换', key: ToolbarStates.SLIDE_ANIMATION },
{ label: '动画', key: ToolbarStates.EL_ANIMATION }, { label: '动画', key: ToolbarStates.EL_ANIMATION },
{ label: '活动', key: ToolbarStates.EL_ACTIVE },
] ]
const multiSelectTabs = [ const multiSelectTabs = [
{ label: '样式', key: ToolbarStates.EL_STYLE }, { label: '样式', key: ToolbarStates.EL_STYLE },
@ -86,6 +89,7 @@ const currentPanelComponent = computed(() => {
[ToolbarStates.SLIDE_ANIMATION]: SlideAnimationPanel, [ToolbarStates.SLIDE_ANIMATION]: SlideAnimationPanel,
[ToolbarStates.MULTI_POSITION]: MultiPositionPanel, [ToolbarStates.MULTI_POSITION]: MultiPositionPanel,
[ToolbarStates.SYMBOL]: SymbolPanel, [ToolbarStates.SYMBOL]: SymbolPanel,
[ToolbarStates.EL_ACTIVE]: SymbolActivePanel,//
} }
return panelMap[toolbarState.value] || null return panelMap[toolbarState.value] || null
}) })

View File

@ -0,0 +1,81 @@
import axios from 'axios'
import request from '@/utils/request'
import { getToken } from "@/utils/auth";
// 文生图片
export function convertTextToPicture(data) {
return axios({
url: 'https://ai.ysaix.com:7853/prompt',
method: 'post',
headers: {
'Content-Type': 'application/json',
'Accept': '*/*'
},
data: data
})
}
// 获取任务列表
export function getQueue() {
return axios({
url: `https://ai.ysaix.com:7853/queue`,
method: 'get',
})
}
// 获取生图任务id
export function getPromptId(id) {
return axios({
url: `https://ai.ysaix.com:7853/history/${id}`,
method: 'get',
})
}
// 获取生成图片路径
export function getPicture(data) {
return axios({
url: 'https://ai.ysaix.com:7853/view',
method: 'get',
params: data
})
}
// 大模型对话生成prompt模板
export function chattoprompt(dataset_id,prompt) {
return axios({
url: '/api/v1/parse/docs',
method: 'post',
headers: {
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
},
data: {
'dataset_id': dataset_id,
'prompt': prompt
}
})
}
// prompt敏感词校验
export function textSensitiveWord(data) {
return request({
url: '/verify/text',
method: 'post',
data: {
'text' : data
}
})
}
// 图片上传资源库
export function uploadPicture(data) {
return axios({
url: '/dev-api/smarttalk/file/upload',
method: 'post',
headers: {
'Accept': '*/*',
'Content-Type': 'multipart/form-data',
'Authorization': "Bearer " + getToken()
},
data: data
})
}

View File

@ -9,6 +9,16 @@ export function listEntpcoursework(query) {
}) })
} }
// 查询entpcoursework列表
export function listEntpcourseworkLocal(query) {
return request({
url: '/education/entpcoursework/local/list',
method: 'get',
params: query
})
}
// 查询entpcoursework详细 // 查询entpcoursework详细
export function getEntpcoursework(id) { export function getEntpcoursework(id) {
return request({ return request({

View File

@ -0,0 +1,627 @@
<template>
<div>
<el-row :gutter="40" style="height:auto">
<el-col :span="8">
<div>
<div style="text-align: left">反面提示词</div>
<br>
<el-input v-model="formData.prompt[12].inputs.negative_prompt" placeholder="试试在这里输入你不想其进入图画的词"
type="textarea"></el-input>
</div>
<br>
<div>
<div style="text-align: left">可选提示词</div>
<br>
<div style="font-size: 14px;text-align: left">风格特点</div>
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="(prompt, index) in promptOption1" :key="index" :label="prompt" :value="prompt" />
</el-checkbox-group>
</div>
<div>
<div style="font-size: 14px;text-align: left">主体对象</div>
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="(prompt, index) in promptOption2" :key="index" :label="prompt" :value="prompt" />
</el-checkbox-group>
</div>
<div>
<div style="font-size: 14px;text-align: left">场景</div>
<el-checkbox-group v-model="checkList">
<el-checkbox v-for="(prompt, index) in promptOption3" :key="index" :label="prompt" :value="prompt" />
</el-checkbox-group>
</div>
<div style="text-align: right">
<el-button type="primary" @click="addCheckListToPrompt">添加</el-button>
<el-button type="primary" @click="deletePrompt">清空</el-button>
</div>
<!-- 具体参数相关内容 -->
<el-form label-position="top" size="small">
<el-form-item label="图片尺寸" style=" margin-bottom: 0px">
<el-row class="ratio-options" :gutter="10" style="margin-bottom: -15px;margin-top: -25px">
<el-col v-for="ratio in ratioOptions" :key="ratio.value" :span="4">
<el-button :type="form.ratio === ratio.value ? 'primary' : 'default'" @click="setRatio(ratio.value)"
class="ratio-option" block>
{{ ratio.label }}
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="图片比例" style=" margin-bottom: 0px">
<el-row class="ratio-options" :gutter="10" style="margin-bottom: -15px;margin-top: -25px">
<el-col v-for="ratio in ratioOptions2" :key="ratio.value" :span="4">
<el-button :type="form.ratios2 === ratio.value ? 'primary' : 'default'" @click="setRatio2(ratio.value)"
class="ratio-option" block>
{{ ratio.label }}
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="图片数量" style=" margin-bottom: 0px">
<el-row style="margin-bottom: -15px;margin-top: -25px">
<el-button style="width: 10%" :type="num_picture === 1 ? 'primary' : 'default'" @click="changePicture(1)">
1
</el-button>
<el-button style="width: 10%" :type="num_picture === 2 ? 'primary' : 'default'" @click="changePicture(2)">
2
</el-button>
<el-button style="width: 10%" :type="num_picture === 3 ? 'primary' : 'default'" @click="changePicture(3)">
3
</el-button>
<el-button style="width: 10%" :type="num_picture === 4 ? 'primary' : 'default'" @click="changePicture(4)">
4
</el-button>
</el-row>
</el-form-item>
<el-form-item label="随机种子">
<el-slider v-model="formData.prompt[14].inputs.seed" :min="1" :max="10000000" show-input />
</el-form-item>
<el-form-item label="cfg (数值越高,生图过程与提示词越相关)">
<el-slider v-model="formData.prompt[14].inputs.cfg" :max="20" show-input />
</el-form-item>
</el-form>
</el-col>
<el-col :span="16">
<div
:style="{ height: divHeight + 'px', 'overflow-y': 'auto', 'margin-bottom': '10px', 'background-color': '#f5f5f5', 'padding': '10px' }">
<div v-for="(resultItem, resultIndex) in resultList" :key="resultIndex">
<div style="display: flex; flex-wrap: wrap; justify-content: flex-end;">
<el-card style="max-width: 50%; margin-right: 10px; display: inline-block;background-color: lightblue;">
<div>
<p style="word-wrap: break-word; overflow-wrap: break-word;text-align: left">{{ resultItem }}</p>
</div>
</el-card>
</div>
<el-row :gutter="10" justify="center">
<el-col :span="6" v-for="(url, index) in pictureurl[resultIndex]" :key="index">
<el-card style="margin-bottom: 5%;height:95%">
<el-image style="width: 100%;" fit="cover" :src="url" :preview-src-list="pictureurl"
:initial-index="index" class="equal-size-image"></el-image>
<div style="text-align: center; margin-top: 15px">
<el-button :disabled="buttonStates[resultIndex][index].disabled" size="small" type="primary"
@click="saveImage(resultIndex, index, url, resultItem)">{{ buttonStates[resultIndex][index].text
}}</el-button>
</div>
</el-card>
</el-col>
</el-row>
</div>
<el-row :gutter="10" justify="center">
<el-col v-if="pictureLoading" :span="6" v-for="n in generateArray(this.skeletonNumber)" :key="n">
<el-card>
<el-skeleton class="custom-skeleton-item" animated>
<template #template>
<el-skeleton-item variant="image" class="custom-skeleton-item"></el-skeleton-item>
</template>
</el-skeleton>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" justify="center">
<el-col :span="12">
<el-card v-for="(item, index) in resultData" :key="index"
style="display: flex;flex-direction: column;align-items: center;margin-bottom: 10px" justify="center"
@click="handleCardClick(item)" :class="{ 'card-hover': !pictureLoading }">
<p style="word-wrap: break-word; overflow-wrap: break-word;">{{ item }}</p>
</el-card>
</el-col>
</el-row>
</div>
<div style="text-align: center">
<el-input style="width: 70%;" v-model="promptData" placeholder="试试输入你心中的画面,尽量描述具体点哦,可以按照这个格式来写: 提示词=主体+风格+场景"
type="textarea">
</el-input>
<el-button type="primary" :disabled="pictureLoading" @click="fetchData">
{{ !pictureLoading ? "生成图片" : "请等待" }}
</el-button>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { convertTextToPicture, getQueue, getPromptId, getPicture, chattoprompt, textSensitiveWord, uploadPicture } from "@/api/aiGeneratedImage/index.js";
import CryptoJS from 'crypto-js'
import { useRoute } from 'vue-router'
export default {
data() {
return {
form: {
ratio: "512",
ratios2: "1/1",
},
ratioOptions: [
{ value: "512", label: "512" },
{ value: "768", label: "768" },
{ value: "1024", label: "1024" },
{ value: "1280", label: "1280" },
{ value: "2048", label: "2048" },
],
ratioOptions2: [
{ value: "1/1", label: "1:1" },
{ value: "4/3", label: "4:3" },
{ value: "3/4", label: "3:4" },
{ value: "9/16", label: "9:16" },
{ value: "16/9", label: "16:9" },
],
//
imageData: {
imageUrls: [],
prompt: [],
time: [],
id: [],
},
promptOption1: ["赛博朋克", "水墨风", "莫奈风格", "二次元", "中国风", "写实风格", "水彩风格", "工笔画", "素描风", "未来主义", "超现实主义", "映像派"],
promptOption2: ["男生", "女生", "老年人", "船舶", "蝴蝶", "狮子", "兔子", "飞机", "中年人", "大树", "长江", "坦克"],
promptOption3: ["雨林", "沙漠", "湖泊", "天空", "城市", "乡村", "太空", "教室"],
promptData: "",
//
formData: {
client_id: "533ef3a3-39c0-4e39-9ced-37d290f371f8",
prompt: {
3: {
inputs: {
images: ["10", 0],
},
class_type: "PreviewImage",
_meta: {
title: "Preview Image",
},
},
6: {
inputs: {
model: "Kwai-Kolors/Kolors",
precision: "fp16",
},
class_type: "DownloadAndLoadKolorsModel",
_meta: {
title: "(Down)load Kolors Model",
},
},
10: {
inputs: {
samples: ["14", 0],
vae: ["11", 0],
},
class_type: "VAEDecode",
_meta: {
title: "VAE Decode",
},
},
11: {
inputs: {
vae_name: "sdxl.vae.safetensors",
},
class_type: "VAELoader",
_meta: {
title: "Load VAE",
},
},
12: {
inputs: {
prompt: "",
negative_prompt: "",
num_images_per_prompt: 1,
chatglm3_model: ["13", 0],
},
class_type: "KolorsTextEncode",
_meta: {
title: "Kolors Text Encode",
},
},
13: {
inputs: {
precision: "quant8",
},
class_type: "DownloadAndLoadChatGLM3",
_meta: {
title: "(Down)load ChatGLM3 Model",
},
},
14: {
inputs: {
width: 1024,
height: 1024,
seed: 1000102404233412,
steps: 25,
cfg: 5,
scheduler: "EulerDiscreteScheduler",
denoise_strength: 1,
kolors_model: ["6", 0],
kolors_embeds: ["12", 0],
},
class_type: "KolorsSampler",
_meta: {
title: "Kolors Sampler",
},
},
},
},
picture: {
filename: "",
type: "temp",
subfolder: "",
preview: "",
channel: "",
},
buttonStates: [], //
resultList: [],
pictureurl: [],
percentage: 50,
num_picture: 1,
skeletonNumber: 0,
cfg_value: 5,
pictureLoading: false,
QueueNumber: 0, //
userIdInComponent: '',
activeName: '1',
checkList: [], //prompt
totalData: 0,
// deleteImageSrc: deletebutton,
timer: null,
isTimerPaused: false,
resultData: [],
divHeight: 0,
dataset_id: '',
courseName: '',
levelFirstId: '',
levelSecondId: '',
textbookId: '',
};
},
methods: {
//
generateArray(length) {
return Array.from({ length }, (_, index) => index);
},
//
Randomseed() {
this.formData.prompt[14].inputs.seed = Math.floor(
Math.random() * 10000001
);
},
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
},
//
async fetchData() {
// prompt
if (this.promptData == "") {
this.$message.error("prompt不能为空");
return;
}
const prompt = this.promptData
//
await textSensitiveWord(prompt)
this.setRatio(this.form.ratio)
this.changeSize()
this.resultList.push(this.promptData)
this.skeletonNumber = this.num_picture
const skeletonItemNumber = this.num_picture
// const userId = this.userIdInComponent
// const model = 'kolors'
// prompt
let temp = "";
if (skeletonItemNumber > 1) {
for (let i = 1; i < skeletonItemNumber; i++) {
temp += "|" + this.promptData;
}
this.formData.prompt[12].inputs.prompt = this.promptData + temp;
} else {
this.formData.prompt[12].inputs.prompt = this.promptData;
}
// json
const transformedData = {
client_id: this.formData.client_id,
prompt: Object.fromEntries(
Object.entries(this.formData.prompt).map(([key, value]) => [
key,
{
inputs: value.inputs,
class_type: value.class_type,
_meta: value._meta,
},
])
),
};
const jsonData = JSON.stringify(transformedData, null, 2);
//
try {
this.pictureLoading = true;
const response = await convertTextToPicture(jsonData); //
const pictureId = response.data.prompt_id;
const queue_Number = response.data.number
let queue;
do {
queue = await getQueue(); //
if (this.hasId(queue, pictureId)) {
this.QueueNumber = queue_Number - queue.data.queue_running[0][0] //
await this.sleep(500);
}
} while (this.hasId(queue, pictureId));
const pictureData = await getPromptId(pictureId); //id
const jsonString = JSON.parse(pictureData.request.responseText);
const urls = []
const buttonState = [];
for (let i = 0; i < skeletonItemNumber; i++) {
this.picture.filename = jsonString[pictureId].outputs[3].images[i].filename;
const pictureURL = await getPicture(this.picture); //url
const url0 = pictureURL.request.responseURL;
urls.push(url0)
buttonState.push({
disabled: false,
text: "插入本课素材资源库",
})
}
this.skeletonNumber = 0
this.pictureurl.push(urls)
this.buttonStates.push(buttonState)
this.pictureLoading = false;
} catch (error) {
this.pictureLoading = false;
console.error("Error fetching data:", error);
}
},
//
hasId(obj, id) {
if (typeof obj !== "object" || obj === null) {
return false;
}
if (Object.values(obj).includes(id)) {
return true;
}
return Object.values(obj).some((value) => this.hasId(value, id));
},
setRatio(ratio) {
this.form.ratio = ratio;
switch (ratio) {
case "512":
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height = 512;
break;
case "768":
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height = 768;
break;
case "1024":
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height = 1024;
break;
case "1280":
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height = 1280;
break;
case "2048":
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height = 2048;
break;
default:
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height = 512;
}
},
setRatio2(ratio) {
this.form.ratios2 = ratio;
},
changeSize() {
const a = this.form.ratios2
if (a == "1/1") {
this.formData.prompt[14].inputs.width = this.formData.prompt[14].inputs.height
} else if (a == "4/3") {
this.formData.prompt[14].inputs.height = (this.formData.prompt[14].inputs.width) * 3 / 4
} else if (a == "3/4") {
this.formData.prompt[14].inputs.width = (this.formData.prompt[14].inputs.height) * 3 / 4
} else if (a == "9/16") {
this.formData.prompt[14].inputs.width = (this.formData.prompt[14].inputs.height) * 9 / 16
} else {
this.formData.prompt[14].inputs.height = (this.formData.prompt[14].inputs.width) * 9 / 16
}
},
changePicture(num) {
this.num_picture = num;
},
//
async createPrompt() {
const dataset_id = this.dataset_id
const courseName = this.courseName
const prompt = `结合${courseName}给我三句详细的提示词用于生成图片以1.2.3的形式`
const response = await chattoprompt(dataset_id, prompt)
const resultData = response.data.answer
const promptData = []
for (let i = 1; i <= 3; i++) {
const startIndex = resultData.indexOf(`${i}.`) + `${i}.`.length;
const endIndex = resultData.indexOf("。", startIndex);
promptData.push(resultData.substring(startIndex, endIndex).trim());
}
this.resultData = promptData
},
handleCardClick(item) {
this.promptData = item
this.fetchData()
},
//
async saveImage(resultIndex, index, url, resultItem) {
this.buttonStates[resultIndex][index].disabled = true;
this.buttonStates[resultIndex][index].text = "正在保存...";
const numberIndex = url.indexOf('filename=');
const path = url.substring(numberIndex + 9);
const pngIndex = path.indexOf('.png');
const finalPath = path.substring(0, pngIndex + 4);
try {
const blob = await this.getImageBlob(`https://ai.ysaix.com:7853/view?filename=${finalPath}&type=temp`);
const hash = CryptoJS.MD5(blob).toString();
const formData = new FormData();
let file = new File([blob], `${resultItem}.png`, {
type: 'image/png'
})
//
formData.append('md5', hash);
formData.append('file', file);
formData.append('textbookId', this.textbookId);
formData.append('levelFirstId', this.levelFirstId);
formData.append('levelSecondId', this.levelSecondId);
formData.append('fileSource', '个人');
formData.append('fileRoot', '备课');
formData.append('fileShowName', `${resultItem}.png`);
formData.append('fileFlag', '素材');
const responsedata = uploadPicture(formData);
responsedata.then((response) => {
if (response.data && response.data.code === 200) {
//
this.buttonStates[resultIndex][index].text = "已保存";
this.buttonStates[resultIndex][index].disabled = true;
}
}).catch((error) => {
console.error(error);
this.buttonStates[resultIndex][index].disabled = false;
this.buttonStates[resultIndex][index].text = "插入本课素材资源库";
});
} catch (error) {
console.error(error);
}
},
getImageBlob(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(`图片获取失败,状态码:${this.status}`));
}
};
xhr.onerror = function () {
reject(new Error('图片获取发生网络错误'));
};
xhr.send();
});
},
// convertImageToBase64(url) {
// return request({
// url: '/common/convertImageToBase64',
// method: 'get',
// params: {
// url: url
// }
// })
// },
// handleSaveImage(url) {
// this.convertImageToBase64(url).then(res => {
// this.$emit("saveImage", res)
// }, err => {
// this.$message.error(err);
// })
// },
//prompt
addCheckListToPrompt() {
const joinedString = this.checkList.join(',');
this.promptData = ''
this.promptData += joinedString;
},
//prompt
deletePrompt() {
this.promptData = '',
this.checkList = []
},
},
mounted() {
const route = useRoute();
this.dataset_id = route.query.datasetId;
this.courseName = route.query.coursetitle;
this.levelFirstId = route.query.levelFirstId;
this.levelSecondId = route.query.levelSecondId;
this.textbookId = route.query.textbookId;
this.createPrompt()
this.Randomseed();
this.divHeight = window.innerHeight * 0.80;
window.addEventListener('resize', () => {
this.divHeight = window.innerHeight * 0.85;
});
},
beforeDestroy() {
window.removeEventListener('resize', () => {
this.divHeight = window.innerHeight * 0.85;
});
}
};
</script>
<style scoped>
.el-row {
padding: 20px
}
.count-option,
.ratio-option {
width: 100%;
}
.custom-skeleton-item {
width: 100%;
height: 200px;
}
.time-display p {
font-size: 9px;
}
.equal-size-image img {
position: absolute;
top: 0;
}
.card-hover:hover {
background-color: #f0f0f0;
cursor: pointer;
}
.disabled-cursor {
cursor: not-allowed !important;
}
</style>

View File

@ -142,13 +142,19 @@ const handleNodeClick = (data) => {
//label label //label label
nodeData.label = nodeData.itemtitle nodeData.label = nodeData.itemtitle
// null let parentNode
let parent = { // children
id: nodeData.parentid, if(nodeData.children){
label: nodeData.parenttitle, //
itemtitle: nodeData.parenttitle parentNode = null
} }
const parentNode = nodeData.parentid ? parent : null else{
parentNode = {
id: nodeData.parentid,
label: nodeData.parenttitle,
itemtitle: nodeData.parenttitle
}
}
nodeData.parentNode = parentNode nodeData.parentNode = parentNode
let curData = { let curData = {
textBook: { textBook: {

View File

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

View File

@ -41,7 +41,7 @@
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click.stop="cloneDialog(ruleFormRef)">取消</el-button> <el-button @click.stop="cloneDialog(ruleFormRef)">取消</el-button>
<el-button type="primary" @click.stop="onSubmit(ruleFormRef)"> 确定 </el-button> <el-button :loading="setLoading" type="primary" @click.stop="onSubmit(ruleFormRef)"> 确定 </el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="isDialog" :show-close="false" width="800" destroy-on-close> <el-dialog v-model="isDialog" :show-close="false" width="800" append-to-body destroy-on-close>
<template #header> <template #header>
<div class="custom-header flex"> <div class="custom-header flex">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
@ -105,11 +105,9 @@ const getCompletion = async (val) => {
} }
const saveAdjust = (item) =>{ const saveAdjust = (item) =>{
isDialog.value = false isDialog.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
emitter.on('saveAdjust', item.msg) emitter.emit('onSaveAdjust', item.msg)
} }
const modeType = ref('课标') const modeType = ref('课标')

View File

@ -26,51 +26,52 @@
</div> </div>
</div> </div>
<!--List--> <!--List-->
<div class="container-right-list"> <div class="container-right-list" ref="listRef">
<template v-for="(item, index) in childTempList"> <template v-for="(item, index) in childTempList">
<div class="template-item" v-loading="item.loading"> <div class="template-item" v-loading="item.loading">
<div class="item-header"> <div class="item-header">
<div> <div>
<span class="blue">#</span>{{ item.name }} <span class="blue">#</span>{{ item.name }}
</div> </div>
<el-popover placement="bottom-end" trigger="hover" popper-class="template-custom-popover"> <el-popover placement="bottom-end" trigger="hover" popper-class="template-custom-popover">
<template #reference> <template #reference>
<el-button link type="primary"> <el-button link type="primary">
<i class="iconfont icon-shenglvehao"></i></el-button> <i class="iconfont icon-shenglvehao"></i></el-button>
</template> </template>
<template #default> <template #default>
<el-button type="primary" link @click="editKeyWord(item)">编辑</el-button> <el-button type="primary" link @click="editKeyWord(item)">编辑</el-button>
<el-button type="primary" link @click="removeItem(item, true)">移除</el-button> <el-button type="primary" link @click="removeItem(item, true)">移除</el-button>
</template> </template>
</el-popover> </el-popover>
</div> </div>
<div class="item-text"> <div class="item-text">
{{ item.prompt }} {{ item.prompt }}
</div> </div>
<div class="item-text text-answer" v-if="item.answer"> <div class="item-text text-answer" v-if="item.answer">
<div class="item-icon"> <div class="item-icon">
<i class="iconfont icon-ai"></i> <i class="iconfont icon-ai"></i>
</div> </div>
<div class="item-answer" v-html="item.answer"></div> <div class="item-answer">
</div> <TypingEffect v-if="isStarted[index]" :text="item.answer" :delay="10" :aiShow="item.aiShow" @complete="handleCompleteText($event,index)" @updateScroll="scrollToBottom($event,index)" />
<div class="ai-btn" v-if="item.answer"> </div>
<el-button type="primary" link @click="againResult(index, item)"> </div>
<i class="iconfont icon-ai1"></i> <div class="ai-btn" v-if="item.answer">
重新研读 <el-button type="primary" link @click="againResult(index, item)">
</el-button> <i class="iconfont icon-ai1"></i>
<el-button type="primary" link @click="onAdjust(index, item)"> 重新研读
<i class="iconfont icon-duihua"></i> </el-button>
AI对话调整 <el-button type="primary" link @click="onAdjust(index, item)">
</el-button> <i class="iconfont icon-duihua"></i>
<el-button type="primary" link @click="onEdit(index, item)"> AI对话调整
<i class="iconfont icon-bianji1"></i> </el-button>
手动编辑结果 <el-button type="primary" link @click="onEdit(index, item)">
</el-button> <i class="iconfont icon-bianji1"></i>
</div> 手动编辑结果
</div> </el-button>
</div>
</template> </div>
<el-empty v-if="!childTempList.length" description="暂无模板数据" /> </template>
<el-empty v-if="!childTempList.length" description="暂无模板数据" />
</div> </div>
</div> </div>
<!--编辑结果--> <!--编辑结果-->
@ -82,13 +83,14 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, watch, onUnmounted } from 'vue' import { ref, reactive, onMounted, watch, onUnmounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { tempSave, completion, modelList, removeChildTemp, tempResult, editTempResult } from '@/api/mode/index' import { tempSave, completion, modelList, removeChildTemp, tempResult, editTempResult } from '@/api/mode/index'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import keywordDialog from './keyword-dialog.vue'; import keywordDialog from './keyword-dialog.vue';
import AdjustDialog from './adjust-dialog.vue' import AdjustDialog from './adjust-dialog.vue'
import EditDialog from './edit-dialog.vue' import EditDialog from './edit-dialog.vue'
import TypingEffect from '@/components/typing-effect/index.vue'
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
import { dataSetJson } from '@/utils/comm.js' import { dataSetJson } from '@/utils/comm.js'
@ -109,7 +111,6 @@ const onAdd = () => {
isAdd.value = true isAdd.value = true
Object.assign(editItem, curTemplate) Object.assign(editItem, curTemplate)
isWordDialog.value = true isWordDialog.value = true
} }
const editKeyWord = (item, val) => { const editKeyWord = (item, val) => {
@ -145,14 +146,16 @@ const getChildTemplate = () => {
tempLoading.value = true tempLoading.value = true
modelList({ model: props.type, type: 2, parentId: curTemplate.id }).then(res => { modelList({ model: props.type, type: 2, parentId: curTemplate.id }).then(res => {
childTempList.value = res.rows childTempList.value = res.rows
if(childTempList.value.length){
childTempList.value.forEach(item => item.answer = '')
}
getTempResult() getTempResult()
}).finally(() => { }).finally(() => {
tempLoading.value = false tempLoading.value = false
}) })
} }
const isStarted = ref([]);
const listRef = ref()
// //
const getTempResult = () => { const getTempResult = () => {
tempResult({ mainModelId: curTemplate.id, pageNum: 1, pageSize: 10000 }).then(res => { tempResult({ mainModelId: curTemplate.id, pageNum: 1, pageSize: 10000 }).then(res => {
@ -160,14 +163,40 @@ const getTempResult = () => {
childTempList.value.forEach(item => { childTempList.value.forEach(item => {
rows.forEach(el => { rows.forEach(el => {
if (item.id == el.modelId) { if (item.id == el.modelId) {
item.answer = el.content item.answer = getResult(el.content)
item.resultId = el.id item.resultId = el.id
} }
}) })
}) })
if(rows.length > 0){
isStarted.value = new Array(rows.length).fill(true)
}
}) })
} }
const scrollToBottom = (height,index) =>{
if (listRef.value) {
let sum = 0
let listDom = listRef.value.children
if(index == 0){
// 220
let screenHeight = window.innerHeight - 220
if(height > screenHeight){
listRef.value.scrollTop = (height - screenHeight + 50)
}
}
else{
for(let i = 0; i < index; i++){
sum += listDom[i].clientHeight
}
listRef.value.scrollTop = sum + height
}
}
}
// //
const changeTemplate = (val) => { const changeTemplate = (val) => {
ElMessageBox.confirm( ElMessageBox.confirm(
@ -202,11 +231,11 @@ const removeItem = async (item, isChild) => {
).then(() => { ).then(() => {
removeChildTemp(item.id).then(res => { removeChildTemp(item.id).then(res => {
ElMessage.success('操作成功') ElMessage.success('操作成功')
if(isChild){ if (isChild) {
// //
getChildTemplate() getChildTemplate()
} }
else{ else {
// //
getTemplateList() getTemplateList()
} }
@ -214,7 +243,7 @@ const removeItem = async (item, isChild) => {
}) })
} }
else { else {
editKeyWord(item,!isChild) editKeyWord(item, !isChild)
} }
} }
@ -239,19 +268,18 @@ const onEdit = (index, item) => {
const modeType = ref('课标') const modeType = ref('课标')
watch(() => props.type, (newVal) => { watch(() => props.type, (newVal) => {
if (newVal == 1){ if (newVal == 1) {
modeType.value = '课标' modeType.value = '课标'
} }
if (newVal == 2){ if (newVal == 2) {
modeType.value = '教材' modeType.value = '教材'
} }
if (newVal == 2){ if (newVal == 3) {
modeType.value = '考试' modeType.value = '考试'
} }
}, { immediate: false }) }, { immediate: false })
// //
const params = reactive( const params = reactive(
{ {
@ -259,30 +287,52 @@ const params = reactive(
dataset_id: '' dataset_id: ''
} }
) )
// //
const isAgain = ref(false)
const againResult = async (index, item) => { const againResult = async (index, item) => {
isAgain.value = true
isStarted.value[index] = false
childTempList.value[index].answer = ''
if(index == 0){
listRef.value.scrollTop = 0
}else{
scrollToBottom(50, index)
}
try { try {
await nextTick()
childTempList.value[index].loading = true childTempList.value[index].loading = true
item.aiShow = true
params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value}${curNode.itemtitle}进行教学分析` params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value}${curNode.itemtitle}进行教学分析`
const { data } = await completion(params) const { data } = await completion(params)
let answer = data.answer childTempList.value[index].answer = getResult(data.answer);
childTempList.value[index].oldAnswer = answer isStarted.value[index] = true
childTempList.value[index].answer = getResult(answer);
onEditSave(item)
} finally { } finally {
childTempList.value[index].loading = false childTempList.value[index].loading = false
} }
} }
// //
const getCompletion = async () => { const getCompletion = async () => {
isStarted.value = new Array(childTempList.length).fill(false)
isStarted.value[0] = true
childTempList.value.forEach(item =>{
if(item.answer){
item.answer = ''
}
})
for (let item of childTempList.value) { for (let item of childTempList.value) {
try { try {
item.loading = true item.loading = true
item.aiShow = true
params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value}${curNode.itemtitle}进行教学分析` params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value}${curNode.itemtitle}进行教学分析`
const { data } = await completion(params) const { data } = await completion(params)
let answer = data.answer item.answer = getResult(data.answer)
item.oldAnswer = answer
item.answer = getResult(answer);
onSaveTemp(item) onSaveTemp(item)
} finally { } finally {
item.loading = false item.loading = false
@ -290,44 +340,49 @@ const getCompletion = async () => {
} }
} }
const handleCompleteText = async (answer, index) =>{
if (index < childTempList.value.length - 1) {
isStarted.value[index + 1] = true; //
}
if(isAgain.value){
try{
await editTempResult({ id: childTempList.value[index].resultId, content: answer })
}finally{
isAgain.value = false
}
}
}
//
emitter.on('onSaveAdjust', (item) => {
childTempList.value[curIndex.value].answer = item
onEditSave(childTempList.value[curIndex.value])
})
// //
const onEditSave = async (item) =>{ const onEditSave = async (item) => {
const { res } = await editTempResult({id: item.resultId, content: item.oldAnswer}) const { res } = await editTempResult({ id: item.resultId, content: item.answer })
ElMessage.success(res) ElMessage.success(res)
getChildTemplate() getChildTemplate()
} }
// //
const onSaveTemp = (item) => { const onSaveTemp = (item) => {
if (item.answer == '') return
const data = { const data = {
mainModelId: curTemplate.id, mainModelId: curTemplate.id,
modelId: item.id, modelId: item.id,
examDocld: '', examDocld: '',
content: item.oldAnswer content: item.answer
} }
tempSave(data).then(res => { tempSave(data).then(res => { })
console.log(res)
})
} }
// ### **
let getResult = (str) => {
// let newStr = str.replace(/#+|(\*\*)/g, '');
emitter.on('saveAdjust', (item) => { return newStr
childTempList.value[curIndex.value].oldAnswer = item
let answer = getResult(item);
childTempList.value[curIndex.value].answer = answer
})
//
let getResult = (text) => {
text = text.replace(/^\n\n(.*?)\n\n$/s, '<div>$1</div>');
text = text.replace(/^\n(.*?)\n$/s, '<p>$1</p>');
text = text.replace(/\*\*(.*?)\*\*/g, "<div class='text-tit'>$1</div>");
text = text.replace(/(\d+\..*?)\n/g, "<div class='text-num'>$1</div>\n");
return text
} }
// //
@ -351,8 +406,9 @@ onMounted(() => {
// //
onUnmounted(() => { onUnmounted(() => {
emitter.off('onGetMain');
emitter.off('onGetChild'); emitter.off('onGetChild');
emitter.off('saveAdjust'); emitter.off('onSaveAdjust');
}) })
</script> </script>
@ -378,86 +434,85 @@ onUnmounted(() => {
padding: 5px 15px; padding: 5px 15px;
box-sizing: border-box; box-sizing: border-box;
.template-item {
background: #fff;
padding: 10px;
margin-top: 10px;
border-radius: 5px;
.template-item { .item-header {
background: #fff; display: flex;
padding: 10px; align-items: center;
margin-top: 10px; font-size: 16px;
border-radius: 5px; font-weight: bold;
color: #000;
justify-content: space-between;
.item-header { .blue {
display: flex; font-size: 22px;
align-items: center;
font-size: 16px;
font-weight: bold;
color: #000;
justify-content: space-between;
.blue {
font-size: 22px;
color: #409eff;
margin-right: 5px;
}
}
.item-text {
display: flex;
margin-top: 10px;
font-size: 14px;
text-align: left;
color: #606266;
.item-icon {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #F6F6F6;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.item-answer {
flex-direction: column;
padding-top: 5px;
:deep(.text-tit) {
font-weight: bold;
margin: 10px 0;
}
:deep(.text-num) {
padding-left: 2em;
}
}
}
.text-answer {
color: #409eff; color: #409eff;
} margin-right: 5px;
.ai-btn {
margin-top: 10px;
display: flex;
justify-content: flex-end;
.iconfont {
margin-right: 3px;
}
:deep(.el-button) {
font-size: 13px;
}
.icon-ai1 {
font-size: 18px;
}
} }
} }
.item-text {
display: flex;
margin-top: 10px;
font-size: 14px;
text-align: left;
color: #606266;
.item-icon {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #F6F6F6;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.item-answer {
flex-direction: column;
padding-top: 5px;
width: 100%;
:deep(.text-tit) {
font-weight: bold;
margin: 10px 0;
}
:deep(.text-num) {
padding-left: 2em;
}
}
}
.text-answer {
color: #409eff;
}
.ai-btn {
margin-top: 10px;
display: flex;
justify-content: flex-end;
.iconfont {
margin-right: 3px;
}
:deep(.el-button) {
font-size: 13px;
}
.icon-ai1 {
font-size: 18px;
}
}
}
} }
} }
</style> </style>

View File

@ -284,23 +284,23 @@ const init = reactive({
formData.append("filetype", "image"); formData.append("filetype", "image");
formData.append("suffix", "image"); formData.append("suffix", "image");
formData.append("status", '1'); formData.append("status", '1');
if(userStore.deptId && userStore.deptId != null){ if(userStore.deptId != null){
formData.append("entpid", userStore.deptId); formData.append("entpid", userStore.deptId);
} }
if(userStore.userId && userStore.userId != null){ if(userStore.userId != null){
formData.append("userid", userStore.userId); formData.append("userid", userStore.userId);
} }
if(userStore.edudegree && userStore.edudegree != null){ if(userStore.edudegree && userStore.edudegree != ''){
let edudegree = userStore.edudegree.toString(); let edudegree = userStore.edudegree.toString();
if(edudegree != '' && edudegree.indexOf('年级') == -1){ if(edudegree != '' && edudegree.indexOf('年级') == -1){
edudegree += '年级'; edudegree += '年级';
} }
formData.append("edudegree", edudegree); formData.append("edudegree", edudegree);
} }
if(userStore.edusubject && userStore.edusubject != null){ if(userStore.edusubject && userStore.edusubject != ''){
formData.append("edusubject", userStore.edusubject); formData.append("edusubject", userStore.edusubject);
} }
if(userStore.edustage && userStore.edustage != null){ if(userStore.edustage && userStore.edustage != ''){
formData.append("edustage", userStore.edustage); formData.append("edustage", userStore.edustage);
} }
if(props.upFileParams?.hasOwnProperty('lessionId')){ if(props.upFileParams?.hasOwnProperty('lessionId')){

View File

@ -0,0 +1,80 @@
<template>
<div class="typing-effect" ref="typingEffectRef">
<!-- <span v-html="displayedText"></span> -->
<el-input
v-model="displayedText"
:autosize="{ minRows: 2 }"
type="textarea"
readonly
resize="none"
style="width: 100%;"
input-style="border:none;outline: none;box-shadow:none;color:000;fontSize:15px"
/>
</div>
</template>
<script setup>
import { ref, onMounted, watch, nextTick } from 'vue';
const props = defineProps({
text: {
type: [String, Object],
required: true
},
delay: {
type: Number,
default: 100 //
},
aiShow: {
type: [Boolean] // true
}
});
const typingEffectRef = ref(null);
const emit = defineEmits(['complete', 'updateScroll']);
const displayedText = ref('');
const index = ref(0);
const type = async () => {
await nextTick()
if(!props.aiShow) {
displayedText.value = props.text
return
}
if (index.value <= props.text.length) {
displayedText.value += props.text.charAt(index.value);
index.value++;
setTimeout(() => {
type();
emit('updateScroll', typingEffectRef.value.clientHeight); //
}, props.delay);
} else {
// complete
emit('complete',displayedText.value);
}
};
onMounted(() => {
resetAndType();
});
const resetAndType = () =>{
displayedText.value = '';
index.value = 0;
type();
}
// props 便 text delay
watch([() => props.text, () => props.delay], resetAndType);
</script>
<style scoped>
.typing-effect {
font-family: monospace;
}
:deep(.el-textarea__inner:hover){
box-shadow: none;
}
</style>

View File

@ -8,9 +8,10 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, onMounted } from 'vue'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const Remote = require('@electron/remote')
const userStore = useUserStore() const userStore = useUserStore()
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
@ -47,6 +48,11 @@ const closeWindow = () => {
}) })
}).catch(() => { }); }).catch(() => { });
} }
onMounted(() =>{
isMaxSize.value = Remote.getCurrentWindow().isMaximized()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -8,6 +8,7 @@
<el-breadcrumb :separator-icon="ArrowRight"> <el-breadcrumb :separator-icon="ArrowRight">
<el-breadcrumb-item v-for="item in breadList"> {{ item.title }} </el-breadcrumb-item> <el-breadcrumb-item v-for="item in breadList"> {{ item.title }} </el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
<span class="ml-5">{{ curNode.itemtitle }}</span>
</div> </div>
<div class="header-center" v-else> <div class="header-center" v-else>
AI文枢{{ version }} AI文枢{{ version }}
@ -20,11 +21,13 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { ArrowRight } from '@element-plus/icons-vue' import { ArrowRight } from '@element-plus/icons-vue'
import WindowTools from '@/components/window-tools/index.vue' import WindowTools from '@/components/window-tools/index.vue'
import pkc from "../../../../../package.json" import pkc from "../../../../../package.json"
import { sessionStore } from '@/utils/store'
const version = ref(pkc.version) const version = ref(pkc.version)
// //
@ -33,6 +36,8 @@ const onBack = () => {
router.go(-1) router.go(-1)
} }
const curNode = reactive({itemtitle: ''})
// //
const isShowBack = ref(false) const isShowBack = ref(false)
const breadList = ref([]) const breadList = ref([])
@ -44,7 +49,8 @@ watch(
if (path.includes('/model') && path !== ('/model/index')) { if (path.includes('/model') && path !== ('/model/index')) {
isShowBack.value = true isShowBack.value = true
breadList.value = newValue.matched.map(item => item.meta) breadList.value = newValue.matched.map(item => item.meta)
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data)
} }
else { else {
isShowBack.value = false isShowBack.value = false

View File

@ -85,6 +85,12 @@ export const constantRoutes = [
name: 'questionUpload', name: 'questionUpload',
meta: { title: '习题上传' } meta: { title: '习题上传' }
}, },
{
path: 'aiKolors',
component: () => import('@/components/ai-kolors/index.vue'),
name: 'aiKolors',
meta: { title: '文生图片' }
},
] ]
}, },

View File

@ -16,14 +16,11 @@ const useClassTaskStore = defineStore('classTask',{
{value: 6, label: "复合题"}, {value: 6, label: "复合题"},
], // 习题查询条件 - 题型 ], // 习题查询条件 - 题型
entpCourseWorkGroupList: [{ entpCourseWorkGroupList: [{
Key: -1, Key: 0,
Value: '不限', Value: '不限',
}, { }, {
Key: 1, Key: 1,
Value: '真题', Value: '真题',
}, {
Key: 0,
Value: '非真题',
} }
], // 习题查询条件 - 题源 ], // 习题查询条件 - 题源
entpCourseWorkYearList: [ entpCourseWorkYearList: [

View File

@ -395,5 +395,6 @@ export const dataSetJson = {
"课标-高中-英语": "e889fcac9fd011efb22a0242ac140006", "课标-高中-英语": "e889fcac9fd011efb22a0242ac140006",
"课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006", "课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
"课标-高中-地理": "270516829fd111efb13c0242ac140006", "课标-高中-地理": "270516829fd111efb13c0242ac140006",
"课标-高中-政治": "a7df2b01aafd11ef8bb40242ac140002",
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm" "鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="page"> <div class="page">
<div class="page-top"> <div class="page-top" v-if="!isShow">
<div class="page-top-left"> <div class="page-top-left">
<el-button type="danger" :icon="Delete" @click="handleDelete">删除</el-button> <el-button type="danger" :icon="Delete" @click="handleDelete">删除</el-button>
<el-button type="success" @click="handleTaskAssignToAllClass()">批量推送</el-button> <el-button type="success" @click="handleTaskAssignToAllClass()">批量推送</el-button>
@ -10,7 +10,7 @@
</div> </div>
</div> </div>
<div class="page-resource"> <div class="page-resource">
<div class="page-left"> <div class="page-left" v-if="!isShow">
<el-table <el-table
ref="taskTable" ref="taskTable"
v-loading="tasklist_loading" v-loading="tasklist_loading"
@ -154,7 +154,9 @@ const route = useRoute();
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const props = defineProps({ const props = defineProps({
currentCourse: Object,
}) })
const isShow = ref(false)
const propsQueryCourseObj = route.query.courseObj;// const propsQueryCourseObj = route.query.courseObj;//
const courseObj = reactive({ const courseObj = reactive({
@ -186,16 +188,48 @@ const fileLoading = ref(false); // 常规作业loading
onMounted(() => { onMounted(() => {
currentRow.value = {id:0}; currentRow.value = {id:0};
console.log('propsQueryCourseObj', JSON.parse(propsQueryCourseObj)); if(propsQueryCourseObj){
if(propsQueryCourseObj&&JSON.parse(propsQueryCourseObj)){ if(JSON.parse(propsQueryCourseObj)){
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj //
courseObj.levelFirstId = JSON.parse(propsQueryCourseObj).levelFirstId // courseObj.levelFirstId = JSON.parse(propsQueryCourseObj).levelFirstId //
courseObj.levelSecondId = JSON.parse(propsQueryCourseObj).levelSecondId // courseObj.levelSecondId = JSON.parse(propsQueryCourseObj).levelSecondId //
courseObj.coursetitle = JSON.parse(propsQueryCourseObj).coursetitle // (/) courseObj.coursetitle = JSON.parse(propsQueryCourseObj).coursetitle // (/)
courseObj.node = JSON.parse(propsQueryCourseObj).node; // courseObj.node = JSON.parse(propsQueryCourseObj).node; //
}
}else{
if(props.currentCourse){
courseObj.textbookId = props.currentCourse.textbookId //
courseObj.levelFirstId = props.currentCourse.levelFirstId //
courseObj.levelSecondId = props.currentCourse.levelSecondId //
courseObj.coursetitle = props.currentCourse.coursetitle // (/)
courseObj.node = props.currentCourse.node; //
classWorkForm.worktype = props.currentCourse.worktype
currentRow.value = {
id:props.currentCourse.id,
worktype:props.currentCourse.worktype
}
isShow.value = true;
}else{
isShow.value = false;
}
} }
initHomeWork(); initHomeWork();
}) })
watch(() => props.currentCourse, (newVal, oldVal) => {
if(newVal){
courseObj.textbookId = newVal.textbookId //
courseObj.levelFirstId = newVal.levelFirstId //
courseObj.levelSecondId = newVal.levelSecondId //
courseObj.coursetitle = newVal.coursetitle // (/)
courseObj.node = newVal.node; //
classWorkForm.worktype = newVal.worktype
currentRow.value = {
id:props.currentCourse.id,
worktype:props.currentCourse.worktype
}
}
console.log(newVal,'newval');
},{deep:true})
//------------ //------------
const handleItemClick = (itemName) => { const handleItemClick = (itemName) => {
console.log('itemName', itemName); console.log('itemName', itemName);

View File

@ -40,7 +40,7 @@
<el-button @click="handleQueryParamFromEntpCourseWork(1)"><el-icon><Search /></el-icon> </el-button> <el-button @click="handleQueryParamFromEntpCourseWork(1)"><el-icon><Search /></el-icon> </el-button>
</el-col> </el-col>
<el-col :span="5"> <el-col :span="5">
<el-button type="primary" @click="goToQuestUpload()">添加习题</el-button> <el-button v-if="!props.isHtml2canvas" type="primary" @click="goToQuestUpload()">添加习题</el-button>
</el-col> </el-col>
</el-row> </el-row>
<!-- 习题表格 --> <!-- 习题表格 -->
@ -58,9 +58,9 @@
</div> </div>
</template> </template>
<template #default="scope"> <template #default="scope">
<div @click="showExamAnalyseDrawer(scope.row)"> <div @click="showExamAnalyseDrawer(scope.row)" :id=" `screenshot-target-${scope.row.id}` " style="padding: 5px;">
<div style="overflow: hidden; text-overflow: ellipsis" v-html="scope.row.titleFormat"></div> <div style="overflow: hidden; text-overflow: ellipsis; padding: 2px;" v-html="scope.row.titleFormat"></div>
<div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px;" v-html="scope.row.workdescFormat"></div> <div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px; padding: 2px;" v-html="scope.row.workdescFormat"></div>
<el-col :span="24" style="display: flex"> <el-col :span="24" style="display: flex">
<div style="font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.entpname }} {{ scope.row.editusername }}</div> <div style="font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.entpname }} {{ scope.row.editusername }}</div>
<div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.worktag }}</div> <div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.worktag }}</div>
@ -70,7 +70,8 @@
</el-table-column> </el-table-column>
<el-table-column width="100"> <el-table-column width="100">
<template #default="scope"> <template #default="scope">
<div> <el-button v-if="props.isHtml2canvas" type="primary" @click="captureScreenshot(scope.row.id)">选取该题</el-button>
<div v-else>
<el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button> <el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button>
<div style="padding: 2px;"></div> <div style="padding: 2px;"></div>
<el-button type="warning" @click="handleImportSingleDlg(scope.row)">纠错</el-button> <el-button type="warning" @click="handleImportSingleDlg(scope.row)">纠错</el-button>
@ -117,8 +118,9 @@
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 { listEntpcoursework } from '@/api/education/entpCourseWork' import { listEntpcoursework, listEntpcourseworkLocal } from '@/api/education/entpCourseWork'
import { listEvaluationclue } from '@/api/classTask' import { listEvaluationclue } from '@/api/classTask'
import { delEntpcoursework, updateEntpcoursework } from "@/api/education/entpCourseWork"; import { delEntpcoursework, updateEntpcoursework } from "@/api/education/entpCourseWork";
@ -136,7 +138,7 @@ const router = useRouter()
// emit // emit
const emit = defineEmits(['addQuiz']) let emit = defineEmits(['addQuiz', 'addQuizImgBs64'])
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const userStore = useUserStore().user const userStore = useUserStore().user
const { const {
@ -150,6 +152,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
isHtml2canvas: {//
type: Boolean,
default: () => false
},
}) })
const knowledgePointProps = ref({value: 'thirdId', label: 'title'}); const knowledgePointProps = ref({value: 'thirdId', label: 'title'});
@ -247,31 +253,32 @@ function Apis(key) {
const client = new Apis('/paht'); const client = new Apis('/paht');
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const queryForm = { const queryForm = {
// //
worktype: entpCourseWorkQueryParams.worktype.label == '不限' ? '' : entpCourseWorkQueryParams.worktype.label, worktype: entpCourseWorkQueryParams.worktype.label,
// TODO web // TODO web
// workgroup: entpCourseWorkQueryParams.workgroup, workgroup: entpCourseWorkQueryParams.workgroup,
// TODO web // TODO web
// yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'', yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
// //
title: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'', keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
//
edustage: userStore.edustage, // this.userStore.edustage,
edusubject: userStore.edusubject, // this.userStore.edusubject,
eid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
status: "1",
editUserId: userStore.userId,
//orderby: 'concat(worktype,timestamp) DESC',
// //
pageNum: paginationParams.pageNum, pageNum: paginationParams.pageNum,
pageSize: paginationParams.pageSize, pageSize: paginationParams.pageSize,
// }
edustage: userStore.edustage, // this.userStore.edustage, //const entpcourseworkres = listEntpcoursework(queryForm);
edusubject: userStore.edusubject, // this.userStore.edusubject, const entpcourseworkres = listEntpcourseworkLocal(queryForm);
evalid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
status: "1",
edituserid: userStore.userId,
orderby: 'concat(worktype,timestamp) DESC',
} resolve(entpcourseworkres);
const entpcourseworkres = listEntpcoursework(queryForm);
resolve(entpcourseworkres);
}) })
} }
const handleQueryFromEntpCourseWork= async (queryType) => { const handleQueryFromEntpCourseWork= async (queryType) => {
@ -439,6 +446,22 @@ const handleDelete = async(item, index) => {
// ElMessage('') // ElMessage('')
// } // }
}; };
/**
* 把该题区域id 获取为截屏区域
* @param id 试题id
*/
const captureScreenshot = (id) => {
const targetElement = document.getElementById('screenshot-target-' + id);
html2canvas(targetElement).then(canvas => {
// canvasURL
const screenshotUrl = canvas.toDataURL('image/png');
//
// console.log(screenshotUrl);
emit('addQuizImgBs64', screenshotUrl);
});
}
// //
const debounceQueryData = debounce(() => { const debounceQueryData = debounce(() => {
console.log("防抖 加载数据中...") console.log("防抖 加载数据中...")

View File

@ -0,0 +1,115 @@
<template>
<div class="page">
<div class="page-resource">
<div class="page-center">
<el-tabs v-model="activeAptTab" style="height: 100%;">
<el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst">
<SearchQuestion :bookobj="courseObj" :isHtml2canvas="true" @addQuizImgBs64="handleaddQuizImgBs64" />
</el-tab-pane>
<el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk">
<SchoolQuestion />
</el-tab-pane>
<el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst">
<MyQuestion :bookobj="courseObj" :isHtml2canvas="true" @addQuizImgBs64="handleaddQuizImgBs64"/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, watch, reactive, getCurrentInstance, nextTick } from 'vue'
import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue'
import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue'
import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue'
import { sessionStore } from '@/utils/store'
import { useRouter, useRoute } from 'vue-router'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
const emit = defineEmits(['update']);
const courseObj = reactive({
// : id,id,id,
textbookId: '',
levelFirstId: '',
levelSecondId: '',
coursetitle:'',
node: null, //
//
})
const activeAptTab = ref("自主搜题");
onMounted(() => {
const curNode = sessionStore.get('subject.curNode')
courseObj.textbookId = curNode.rootid
courseObj.levelFirstId = curNode.parentNode.id
courseObj.levelSecondId = curNode.id
courseObj.coursetitle = curNode.itemtitle,
courseObj.node = curNode
})
const handleaddQuizImgBs64 = (quizbs64) => {
emit('update', quizbs64)
}
defineExpose({
})
</script>
<style scoped lang="scss">
.page {
height: 100%;
.page-resource {
user-select: none;
height: calc(100% - 55px);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
flex: 1;
:deep(.el-tabs__nav) {
.el-tabs__item{
font-weight: bold;
font-size: 18px;
}
}
}
.page-center{
flex: 1;
//min-width: calc(100% - 675px);
height: 100%;
padding: 0 5px;
margin: 0 5px;
overflow: hidden;
border-radius: 10px;
background-color: white;
.prepare-center-zzst{
height: 100%;
display: flex;
flex-direction: column;
}
.prepare-center-xbtk{
height: 100%;
}
.prepare-center-grst{
height: 100%;
}
.upload-homework{
padding: 20px;
box-sizing: border-box;
}
}
}
</style>

View File

@ -152,7 +152,7 @@
</el-form-item> </el-form-item>
</div> </div>
<div class="item-cropper-btn"> <div class="item-cropper-btn">
<el-button v-show="isCropper" circle @click="cropperFormItem('workdesc')"></el-button> <el-button v-show="isCropper" circle @click="cropperFormItem('workdesc')"><el-icon><Search /></el-icon></el-button>
</div> </div>
</div> </div>
@ -252,8 +252,7 @@
<el-tag v-else type="danger" style=" margin-left: 10px ">温馨提示这里 - 号删除的是最后一道题目哟</el-tag> <el-tag v-else type="danger" style=" margin-left: 10px ">温馨提示这里 - 号删除的是最后一道题目哟</el-tag>
</el-form-item> </el-form-item>
<div class="item-cropper-btn-multi"> <div class="item-cropper-btn-multi">
<!-- <el-button v-show="isCropper" circle icon="Search" @click="cropperFormItem('workdesc')"></el-button> --> <el-button v-show="isCropper" circle @click="cropperFormItem('workdesc')"><el-icon><Search /></el-icon></el-button>
<el-button v-show="isCropper" circle @click="cropperFormItem('workdesc')">识别</el-button>
</div> </div>

View File

@ -71,9 +71,9 @@
</div> </div>
</template> </template>
<template #default="scope"> <template #default="scope">
<div @click="showExamAnalyseDrawer(scope.row)"> <div @click="showExamAnalyseDrawer(scope.row)" :id=" `screenshot-target-${scope.row.id}` " style="padding: 5px;">
<div style="overflow: hidden; text-overflow: ellipsis" v-html="scope.row.titleFormat"></div> <div style="overflow: hidden; text-overflow: ellipsis; padding: 2px;" v-html="scope.row.titleFormat"></div>
<div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px;" v-html="scope.row.workdescFormat"></div> <div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px; padding: 2px;" v-html="scope.row.workdescFormat"></div>
<el-col :span="24" style="display: flex"> <el-col :span="24" style="display: flex">
<div style="font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.entpname }} {{ scope.row.editusername }}</div> <div style="font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.entpname }} {{ scope.row.editusername }}</div>
<div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.worktag }}</div> <div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ scope.row.worktag }}</div>
@ -83,7 +83,8 @@
</el-table-column> </el-table-column>
<el-table-column align="left" width="100"> <el-table-column align="left" width="100">
<template #default="scope"> <template #default="scope">
<el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button> <el-button v-if="props.isHtml2canvas" type="primary" @click="captureScreenshot(scope.row.id)">选取该题</el-button>
<el-button v-else type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -104,7 +105,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 { 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'
@ -122,7 +123,7 @@ import useUserStore from '@/store/modules/user'
import useClassTaskStore from '@/store/modules/classTask' import useClassTaskStore from '@/store/modules/classTask'
// emit // emit
const emit = defineEmits(['addQuiz']) let emit = defineEmits(['addQuiz', 'addQuizImgBs64'])
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const userStore = useUserStore().user const userStore = useUserStore().user
const { const {
@ -136,6 +137,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
isHtml2canvas: {//
type: Boolean,
default: () => false
},
}) })
const entpCourseWorkPointList = ref([ const entpCourseWorkPointList = ref([
@ -427,6 +432,20 @@ const getPaginationList = ( page, limit ) => {
// ElMessage('') // ElMessage('')
// } // }
}; };
/**
* 把该题区域id 获取为截屏区域
* @param id 试题id
*/
const captureScreenshot = (id) => {
const targetElement = document.getElementById('screenshot-target-' + id);
html2canvas(targetElement).then(canvas => {
// canvasURL
const screenshotUrl = canvas.toDataURL('image/png');
//
// console.log(screenshotUrl);
emit('addQuizImgBs64', screenshotUrl);
});
}
// //

View File

@ -113,7 +113,7 @@ const getConversation = (val) => {
const getCompletion = async (val) => { const getCompletion = async (val) => {
try { try {
params.prompt = `根据${curNode.edustage}${curNode.edusubject},分析${props.item.name}${val}` params.prompt = `按照${val}的要求,针对${curNode.edustage}${curNode.edusubject}考试 对${curNode.itemtitle}进行教学分析`
const { data } = await completion(params) const { data } = await completion(params)
let answer = data.answer let answer = data.answer
msgList.value.push({ msgList.value.push({
@ -133,8 +133,6 @@ const saveAdjust = (item) =>{
} }
const curFile = reactive({}) const curFile = reactive({})
const dataset_id = ref('') const dataset_id = ref('')
const fileList = ref([]) const fileList = ref([])
@ -143,15 +141,15 @@ const getList = () =>{
userId: userInfo.userId, userId: userInfo.userId,
dataset_id: dataset_id.value dataset_id: dataset_id.value
}).then( res =>{ }).then( res =>{
fileList.value = [{fileId: '',fileName: '选择文件', id:-1},...res.rows] fileList.value = res.rows
Object.assign(curFile, fileList.value[0]) Object.assign(curFile, fileList.value[0])
params.document_ids = fileList.value[0].docId
}) })
} }
emitter.on('curFile', (item) =>{ emitter.on('curFile', (item) =>{
changeFile(item) changeFile(item)
}) })
const changeFile = (val) =>{ const changeFile = (val) =>{
Object.assign(curFile, val); Object.assign(curFile, val);
params.document_ids = val.docId params.document_ids = val.docId
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="isDialog" :show-close="false" width="900" destroy-on-close> <el-dialog v-model="isDialog" :show-close="false" width="900" append-to-body destroy-on-close>
<template #header> <template #header>
<div class="custom-header flex"> <div class="custom-header flex">
<span>选择{{ title }}</span> <span>选择{{ title }}</span>
@ -15,8 +15,10 @@
</div> </div>
<div class="content-list"> <div class="content-list">
<ul> <ul>
<li v-for="(item, index) in fileList" :class="activeIndex == index ? 'li-active' : ''" @click="clickItem(index, item)"> <li v-for="(item, index) in fileList" :class="activeIndex == index ? 'li-active' : ''"
@click="clickItem(index, item)">
<el-image class="img" :src="url" /> <el-image class="img" :src="url" />
<el-button type="primary" class="prev-btn" @click.stop="onPrevItem(item)">预览</el-button>
<el-text truncated>{{ item.fileName }}</el-text> <el-text truncated>{{ item.fileName }}</el-text>
</li> </li>
</ul> </ul>
@ -24,8 +26,8 @@
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-upload class="upload-demo" :action="uploadFileUrl" :limit="1" :show-file-list="false" <el-upload class="upload-demo" :action="uploadFileUrl" :limit="1" :show-file-list="false" :headers="headers"
:headers="headers" :on-success="onSuccess"> :on-success="onSuccess">
<el-button type="primary">上传</el-button> <el-button type="primary">上传</el-button>
</el-upload> </el-upload>
<div> <div>
@ -37,6 +39,31 @@
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="prevVisible" fullscreen :show-close="false" class="prev-dialog">
<template #header>
<div class="custom-header flex">
<span>预览</span>
<i class="iconfont icon-guanbi" @click="prevVisible = false"></i>
</div>
</template>
<div style="height: calc(100vh - 120px);">
<template v-if="getFileSuffix(prevItem.fileUrl) == 'pdf'">
<iframe :src="prevItem.fileUrl"
frameborder="0" width="100%" height="100%"></iframe>
</template>
<template v-else>
<el-image :src="prevItem.fileUrl" style="height:100%"/>
</template>
</div>
<template #footer>
<div class="dialog-footer">
<div></div>
<el-button type="primary" @click="prevVisible = false">
关闭
</el-button>
</div>
</template>
</el-dialog>
</template> </template>
<script setup> <script setup>
@ -47,6 +74,7 @@ import { sessionStore } from '@/utils/store'
import { dataSetJson } from '@/utils/comm.js' import { dataSetJson } from '@/utils/comm.js'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { getFileSuffix } from '@/utils/ruoyi.js'
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
const userInfo = useUserStore().user const userInfo = useUserStore().user
@ -56,6 +84,7 @@ const headers = ref({ Authorization: "Bearer " + getToken() });
const url = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F11044b08-04c1-41a0-a453-1fd20b58a614%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1732953359&t=7ab1d1b3a903db85b1149914407aea35' const url = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F11044b08-04c1-41a0-a453-1fd20b58a614%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1732953359&t=7ab1d1b3a903db85b1149914407aea35'
const isDialog = defineModel() const isDialog = defineModel()
const prevVisible = ref(false)
const props = defineProps({ const props = defineProps({
modeType: { modeType: {
@ -99,21 +128,21 @@ const activeIndex = ref(0)
const dataset_id = ref('') const dataset_id = ref('')
// //
const onSuccess = async (response) =>{ const onSuccess = async (response) => {
console.log(response,'response') console.log(response, 'response')
let data = { let data = {
url: response.url, url: response.url,
dataset_id: dataset_id.value dataset_id: dataset_id.value
} }
const res = await completion(data) const res = await completion(data)
if(res.data.code != 200) return if (res.data.code != 200) return
let docData = { let docData = {
fileUrl: response.url, fileUrl: response.url,
fileId: response.file.id, fileId: response.file.id,
fileName: response.file.fileName, fileName: response.file.fileName,
filesize: response.file.fileSize, filesize: response.file.fileSize,
datasetId: dataset_id.value, datasetId: dataset_id.value,
docId: res.data.document_id, docId: res.data.document_id,
edustage: curNode.edustage, edustage: curNode.edustage,
edusubject: curNode.edusubject edusubject: curNode.edusubject
@ -127,25 +156,32 @@ const curNode = reactive({})
const fileList = ref([]) const fileList = ref([])
const curFile = reactive({}) const curFile = reactive({})
const getList = () =>{ const getList = () => {
docList({ docList({
userId: userInfo.userId, userId: userInfo.userId,
dataset_id: dataset_id.value dataset_id: dataset_id.value
}).then( res =>{ }).then(res => {
fileList.value = [...res.rows] fileList.value = [...res.rows]
Object.assign(curFile, fileList.value[0]) Object.assign(curFile, fileList.value[0])
}) })
} }
const clickItem = (index, item) => { const clickItem = (index, item) => {
activeIndex.value = index activeIndex.value = index
Object.assign(curFile, item) Object.assign(curFile, item)
emitter.emit('curFile',item) emitter.emit('curFile', item)
}
const prevItem = reactive({})
const onPrevItem = (item) => {
console.log(item)
Object.assign(prevItem, item)
prevVisible.value = true
} }
onMounted(() =>{ onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data);
@ -155,7 +191,6 @@ onMounted(() =>{
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.custom-header { .custom-header {
justify-content: space-between; justify-content: space-between;
@ -192,9 +227,11 @@ onMounted(() =>{
overflow: hidden; overflow: hidden;
margin-right: 20px; margin-right: 20px;
margin-bottom: 10px; margin-bottom: 10px;
position: relative;
overflow: hidden;
.img { .img {
width: 100px; width: 100%;
height: 130px; height: 130px;
border: solid #ccc 1px; border: solid #ccc 1px;
margin-bottom: 10px; margin-bottom: 10px;
@ -203,6 +240,10 @@ onMounted(() =>{
&:hover { &:hover {
background: #E0EAFF; background: #E0EAFF;
} }
&:hover .prev-btn {
transform: translate(-50%, -50%)
}
} }
.li-active { .li-active {
@ -212,9 +253,20 @@ onMounted(() =>{
} }
} }
} }
.dialog-footer{
.dialog-footer {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.prev-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) translateY(-110px);
/* 按钮初始位置在容器外 */
transition: transform 0.3s ease-in-out;
/* 设置过渡效果 */
}
</style> </style>

View File

@ -51,7 +51,7 @@ watch(() => props.item.answer, (newVal) => {
const emit = defineEmits(['saveEdit']) const emit = defineEmits(['saveEdit'])
const onSave = () =>{ const onSave = () =>{
editTempResult({id: props.item.reultId, content: textarea.value}).then( res =>{ editTempResult({id: props.item.resultId, content: textarea.value}).then( res =>{
isDialog.value = false isDialog.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
emit('saveEdit', textarea.value) emit('saveEdit', textarea.value)

View File

@ -14,8 +14,14 @@ const pdfUrl = ref('')
onMounted(async () =>{ onMounted(async () =>{
await nextTick() await nextTick()
const { fileurl } = sessionStore.get('subject.curBook')
pdfUrl.value = import.meta.env.VITE_APP_RES_FILE_PATH + fileurl.replace('.txt','.pdf') let data = sessionStore.get('subject.curBook')
let fileurl = data.fileurl
if(fileurl == ''){
fileurl = `${data.edustage}-${data.edusubject}-课标.txt`
}
pdfUrl.value = import.meta.env.VITE_APP_RES_FILE_PATH + fileurl.replace('.txt', '.pdf')
}) })
</script> </script>

View File

@ -67,7 +67,7 @@ import AdjustDialog from './adjust-dialog.vue'
import keywordDialog from './keyword-dialog.vue'; import keywordDialog from './keyword-dialog.vue';
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { tempSave, completion, modelList, removeChildTemp, tempResult } from '@/api/mode/index' import { tempSave, completion, modelList, removeChildTemp, tempResult, editTempResult } from '@/api/mode/index'
import { dataSetJson } from '@/utils/comm.js' import { dataSetJson } from '@/utils/comm.js'
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
@ -109,7 +109,7 @@ const getTempResult = () => {
rows.forEach(el => { rows.forEach(el => {
if (item.id == el.modelId) { if (item.id == el.modelId) {
item.answer = el.content item.answer = el.content
item.reultId = el.id item.resultId = el.id
} }
}) })
}) })
@ -143,7 +143,6 @@ const getCompletion = async () => {
for (let item of childTempList.value) { for (let item of childTempList.value) {
try { try {
item.loading = true item.loading = true
// params.prompt = `${curNode.edustage}${curNode.edusubject}${item.prompt}`
params.prompt = `按照${item.prompt}的要求,针对${curNode.edustage}${curNode.edusubject}考试 对${curNode.itemtitle}进行教学分析` params.prompt = `按照${item.prompt}的要求,针对${curNode.edustage}${curNode.edusubject}考试 对${curNode.itemtitle}进行教学分析`
const { data } = await completion(params) const { data } = await completion(params)
let answer = data.answer let answer = data.answer
@ -175,16 +174,24 @@ const onSaveTemp = (item) => {
const againResult = async (index, item) => { const againResult = async (index, item) => {
try { try {
childTempList.value[index].loading = true childTempList.value[index].loading = true
params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标,提炼出${item.name}` params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}考试 对${curNode.itemtitle}进行教学分析`
const { data } = await completion(params) const { data } = await completion(params)
let answer = data.answer let answer = data.answer
childTempList.value[index].oldAnswer = answer childTempList.value[index].oldAnswer = answer
childTempList.value[index].answer = getResult(answer); childTempList.value[index].answer = getResult(answer);
onEditSave(childTempList.value[index])
} finally { } finally {
childTempList.value[index].loading = false childTempList.value[index].loading = false
} }
} }
//
const onEditSave = async (item) =>{
const { res } = await editTempResult({id: item.resultId, content: item.oldAnswer})
ElMessage.success(res)
getChildTemplate()
}
// //
let getResult = (text) => { let getResult = (text) => {

View File

@ -13,6 +13,7 @@
<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>
</div> </div>
</div> </div>
</div> </div>
@ -51,9 +52,12 @@ import { useRouter } from 'vue-router'
import { Plus, Refresh, Upload, Files, UploadFilled } from '@element-plus/icons-vue' import { Plus, Refresh, Upload, Files, UploadFilled } from '@element-plus/icons-vue'
import useUserStore from '@/store/modules/user' // import useUserStore from '@/store/modules/user' //
import msgUtils from '@/plugins/modal' // import msgUtils from '@/plugins/modal' //
import { createWindow, sessionStore } from '@/utils/tool' // import { createWindow } from '@/utils/tool' //
import * as API_smarttalk from '@/api/file' // api
import * as API_entpcourse from '@/api/education/entpcourse' // api import * as API_entpcourse from '@/api/education/entpcourse' // api
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api
import { dataSetJson } from '@/utils/comm' // id
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' //
@ -156,6 +160,21 @@ const onchange = (path) => {
if (path == '/model/newClassTaskAssign') { if (path == '/model/newClassTaskAssign') {
// //
router.push({ path, query: { courseObj: JSON.stringify(courseObj) } }) router.push({ path, query: { courseObj: JSON.stringify(courseObj) } })
} else if (path == '/model/aiKolors') {
// ai
let subjectdata = sessionStore.get('subject.curNode')
let datasubject = `课标-${subjectdata.edustage}-${subjectdata.edusubject}`
console.log(subjectdata)
router.push({
path,
query: {
datasetId: dataSetJson[datasubject],
coursetitle: courseObj.coursetitle,
levelFirstId: subjectdata.parentid,
levelSecondId: subjectdata.id,
textbookId: subjectdata.rootid,
}
});
} else { } else {
router.push(path) router.push(path)
} }
@ -338,7 +357,7 @@ const getIcon = (o, type) => {
justify-content: flex-start; justify-content: flex-start;
.el-button { .el-button {
flex: 1 1 15%; flex: 1 1 15%;
max-width: 15%; max-width: 15%;
min-width: 15%; min-width: 15%;
box-sizing: border-box; box-sizing: border-box;
@ -353,4 +372,4 @@ const getIcon = (o, type) => {
} }
} }
} }
</style> </style>

View File

@ -57,11 +57,11 @@
</el-row> </el-row>
<div> <div>
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button> <el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
<el-button style="margin-bottom: 5px;" type="primary" @click="outlineCreatePPT()">生成PPT</el-button> <el-button style="margin-bottom: 5px;" type="primary" v-loading="createPPTLoading" @click="outlineCreatePPT()">生成PPT</el-button>
</div> </div>
</el-card> </el-card>
<el-card v-if="activeStep === 2"> <el-card v-if="activeStep === 2">
<el-progress :percentage="30" type="circle" v-if="percentage === 30"></el-progress> <el-progress :percentage="percentage" type="circle"></el-progress>
</el-card> </el-card>
</div> </div>
</div> </div>
@ -79,6 +79,7 @@ import {
import CryptoJS from "crypto-js" import CryptoJS from "crypto-js"
import { getSignature } from "@/utils/index.js"; import { getSignature } from "@/utils/index.js";
import {sessionStore} from "@/utils/store";
let appId = "01ec9aa3"; let appId = "01ec9aa3";
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy"; let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
@ -98,8 +99,8 @@ let secondArray = ref([]); //大纲的文字部分
const backGroundList = ref([]); const backGroundList = ref([]);
let subjectdata = sessionStore.get('subject.curNode')
const inputTheme = ref("高中语文《沁园春雪》的授课课件"); // const inputTheme = ref(subjectdata.edustage + subjectdata.edusubject + "《" + subjectdata.itemtitle + "》的授课课件"); //
const inputRequire = ref("") // const inputRequire = ref("") //
const activeStep = ref(0); // const activeStep = ref(0); //
const combined = ref('') // ppt const combined = ref('') // ppt
@ -109,6 +110,8 @@ const status = ref("init");
const percentage = ref(0); const percentage = ref(0);
const createPPTLoading = ref(false);
const getBackgrounds = () => { const getBackgrounds = () => {
treeData.value = []; treeData.value = [];
getBackGroundV2().then((res) => { getBackGroundV2().then((res) => {
@ -126,6 +129,8 @@ const outlineData = ref({
// templateId: 'auto', // ppt // templateId: 'auto', // ppt
author: 'AIX平台', author: 'AIX平台',
isFigure: false, // isFigure: false, //
search: true,
language: "cn"
} }
) )
@ -145,20 +150,17 @@ function updateStagingData(role, newData) {
const outlineCreatePPT = () => { const outlineCreatePPT = () => {
const newOutlineData = { ...outlineData.value, }; const newOutlineData = { ...outlineData.value, };
newOutlineData.query = outputText.value; newOutlineData.query = outputText.value;
createPPTLoading.value = true;
createPPTV2(newOutlineData).then((res) => { createPPTV2(newOutlineData).then((res) => {
console.log(res, "正在生成中"); console.log(res, "正在生成中");
createPPTLoading.value = false;
activeStep.value = 2 activeStep.value = 2
const checkProgress = () => { const checkProgress = () => {
getProgressV2(res.sid).then((response) => { getProgressV2(res.sid).then(response => {
percentage.value = response.process; percentage.value = Math.round(response?.donePages/response?.totalPages)*100;
if (response && response.pptUrl && response.pptUrl.length > 4) { if (response.pptStatus === "done") {
console.log('PPT',response) emit('addSuccess',{...res,url:response.pptUrl})
// window.location.href = response.data.pptUrl;
//URLURL
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
emit('addSuccess',res)
ElMessage.success("生成成功"); ElMessage.success("生成成功");
} else { } else {
const sleepTime = 2000; const sleepTime = 2000;

View File

@ -59,14 +59,16 @@
<!-- 手机登录 --> <!-- 手机登录 -->
<template #item_mobile> <template #item_mobile>
<div> <div>
<div>开始新的课堂需要点击先创建课堂才能显示手机二维码</div> <div v-if="myClassActive.filetype=='apt'">开始新的课堂需要点击先创建课堂才能显示手机二维码</div>
<div v-else>开始新的课堂需要点击先创建课堂</div>
<el-button type="warning" :loading="dt.loading" @click="createClasscourse">创建课堂</el-button> <el-button type="warning" :loading="dt.loading" @click="createClasscourse">创建课堂</el-button>
</div> </div>
</template> </template>
<!-- 故障备用 --> <!-- 故障备用 -->
<template #item_backup> <template #item_backup>
<div> <div>
<div>如果手机扫码后进入课堂但本页面没自动跳转请点击下面按钮</div> <div v-if="myClassActive.filetype=='apt'">如果手机扫码后进入课堂但本页面没自动跳转请点击下面按钮</div>
<div v-else>本页面没自动跳转请点击下面按钮</div>
<el-button type="primary" plain @click="classTeachingStart">开始上课</el-button> <el-button type="primary" plain @click="classTeachingStart">开始上课</el-button>
</div> </div>
</template> </template>
@ -81,7 +83,7 @@
<script setup> <script setup>
// //
import { onMounted, reactive, ref, watchEffect, watch, nextTick } from 'vue' // vue import { onMounted, reactive, ref, watchEffect, watch, nextTick, toRaw } from 'vue' // vue
import { Refresh } from '@element-plus/icons-vue' import { Refresh } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus' // ui: import { ElMessage, ElMessageBox } from 'element-plus' // ui:
import vueQr from 'vue-qr/src/packages/vue-qr.vue' // : import vueQr from 'vue-qr/src/packages/vue-qr.vue' // :
@ -149,9 +151,9 @@ const open = async (id, classObj) => {
teacherForm.form.classcourseid = classObj.id teacherForm.form.classcourseid = classObj.id
} }
// im-chat // im-chat
nextTick(async() => { // nextTick(async() => {
chat = await imChatRef.value?.initImChat() // chat = await imChatRef.value?.initImChat()
}) // })
} }
} }
// //
@ -259,7 +261,15 @@ const createClasscourse = async () => {
dt.loading = false dt.loading = false
// getClasscourseList('update') // // getClasscourseList('update') //
ElMessage.success('创建课程-成功') ElMessage.success('创建课程-成功')
// -pptList
if (myClassActive.value.filetype == 'aptist') {
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
setTimeout(() => {
msgEl.close()
const classcourse = {...params, id: teacherForm.form.classcourseid}
openPublicScreen(classcourse)
}, 1500);
}
} }
// //
const removeClasscourse = async () => { const removeClasscourse = async () => {
@ -323,6 +333,21 @@ const getQrUrl = async() => {
} }
teacherForm.form.qrUrl = baseUrl + qrCodeUrl teacherForm.form.qrUrl = baseUrl + qrCodeUrl
} }
//
const openPublicScreen = (classcourse) => {
const resource = toRaw(myClassActive.value)
sessionStore.set('curr.resource', resource) //
sessionStore.set('curr.classcourse', classcourse) //
createWindow('open-win', {
url: '/pptist', //
close: () => {
sessionStore.set('curr.resource', null) //
sessionStore.set('curr.classcourse', null) //
}
})
}
// //
// ================== ======================= // ================== =======================

View File

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

View File

@ -13,7 +13,7 @@
</template> </template>
<script setup> <script setup>
import AiPptist from './ai-pptist.vue'; import AiPptist from './ai-pptistV2.vue';
const model = defineModel() const model = defineModel()
const emit = defineEmits(['addSuccess']) const emit = defineEmits(['addSuccess'])
const props = defineProps({ const props = defineProps({

View File

@ -175,8 +175,9 @@ import { updateClasscourse } from '@/api/teaching/classcourse'
import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage' import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage'
import { useGetHomework } from '@/hooks/useGetHomework' import { useGetHomework } from '@/hooks/useGetHomework'
import { editListItem } from '@/hooks/useClassTask' import { editListItem } from '@/hooks/useClassTask'
import { addEntpcoursefileReturnId } from '@/api/education/entpcoursefile' import { addEntpcoursefileReturnId, getEntpcoursefile } from '@/api/education/entpcoursefile'
import ClassReserv from '@/views/classManage/classReserv.vue' import ClassReserv from '@/views/classManage/classReserv.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' // im
@ -239,7 +240,9 @@ export default {
activeClass: null, activeClass: null,
pptDialog: false, pptDialog: false,
// //
treelogRef:null treelogRef:null,
// Entpcourse
entp: null
} }
}, },
computed: { computed: {
@ -249,10 +252,12 @@ 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))
}, },
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))
} }
}, },
@ -305,8 +310,8 @@ export default {
// //
startClass(item, classObj) { startClass(item, classObj) {
// () // ()
const id = sessionStore.has('activeClass.id') ? sessionStore.get('activeClass.id') : null // const id = sessionStore.has('activeClass.id') ? sessionStore.get('activeClass.id') : null
if (id && id == item.id) return ElMessage.warning('当前正在上课,请勿重复操作') // if (id && id == item.id) return ElMessage.warning('')
// -store // -store
sessionStore.set('activeClass', item) sessionStore.set('activeClass', item)
this.activeClass = item this.activeClass = item
@ -316,6 +321,9 @@ 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') {
this.$refs.calssRef.open(item.fileId, classObj)
}
}, },
// -apt // -apt
async changeClass(type, row, other) { async changeClass(type, row, other) {
@ -370,6 +378,28 @@ export default {
}, 1000) }, 1000)
break break
} }
case 'click': { // --aptist
if (row.fileFlag === 'aptist' && !!row.fileId) {
const res = await getEntpcoursefile(row.fileId)
if (res && res.code === 200) {
sessionStore.set('curr.resource', res.data) //
sessionStore.set('curr.smarttalk', row) // smarttalk
createWindow('open-win', {
url: '/pptist', //
close: () => {
sessionStore.set('curr.resource', null) //
sessionStore.set('curr.smarttalk', null) //
this.asyncAllFile() //
}
})
} else {
ElMessage.warning(res.msg||'文件获取异常!')
}
return
}
ElMessage.warning('该功能暂未开放!')
break
}
default: default:
break break
} }
@ -623,6 +653,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;
await asyncLocalFile(item) await asyncLocalFile(item)
} }
this.asyncAllFileVisiable = false this.asyncAllFileVisiable = false
@ -651,6 +682,11 @@ export default {
toolStore.curSubjectNode.querySearch = this.uploadData toolStore.curSubjectNode.querySearch = this.uploadData
this.initHomeWork() this.initHomeWork()
await this.asyncAllFile() await this.asyncAllFile()
//
const params = { evalid: this.currentNode.id, edituserid: this.userStore.userId, pageSize: 1 }
const res = await listEntpcourse(params)
this.entp = res?.rows?.[0] || null
sessionStore.set('curr.entp', this.entp) //
}, },
// //
async initHomeWork() { async initHomeWork() {

View File

@ -5,7 +5,7 @@
<div class="info"> <div class="info">
<div class="info-name">{{ state.user.nickName }}</div> <div class="info-name">{{ state.user.nickName }}</div>
<div class="infomation"> <div class="infomation">
<selectClass/> <selectClass v-if="!isSubject"/>
</div> </div>
</div> </div>
</div> </div>
@ -46,8 +46,10 @@ const state = reactive({
postGroup: {} postGroup: {}
}) })
const isSubject = ref(false)
async function getUser() { async function getUser() {
getUserProfile().then((response) => { getUserProfile().then((response) => {
isSubject.value = response.roleGroup.indexOf('场馆管理员') != -1
// response.data.avatar = import.meta.env.VITE_APP_BASE_API + response.data.avatar // response.data.avatar = import.meta.env.VITE_APP_BASE_API + response.data.avatar
Object.assign(state.user,response.data) Object.assign(state.user,response.data)
state.roleGroup = response.roleGroup state.roleGroup = response.roleGroup

View File

@ -68,6 +68,7 @@ import {PPTXFileToJson} from '@/AixPPTist/src/hooks/useImport' // ppt转json
import * as API_entpcourse from '@/api/education/entpcourse' // api import * as API_entpcourse from '@/api/education/entpcourse' // api
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api
import * as Api_server from '@/api/apiService' // api import * as Api_server from '@/api/apiService' // api
import * as API_smarttalk from '@/api/file' // api
import msgUtils from '@/plugins/modal' // import msgUtils from '@/plugins/modal' //
const userStore = useUserStore() const userStore = useUserStore()
@ -136,6 +137,8 @@ const addAiPPT = async(res) => {
const p_params = {parentContent: JSON.stringify(content)} const p_params = {parentContent: JSON.stringify(content)}
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params) const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
if (!!parentid??null) { // if (!!parentid??null) { //
// -Smarttalk
HTTP_SERVER_API('addSmarttalk',{fileId: parentid})
if (slides.length > 0) { if (slides.length > 0) {
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide)) const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
const params = {parentid, filetype: 'slide', title: '', slides: resSlides } const params = {parentid, filetype: 'slide', title: '', slides: resSlides }
@ -206,6 +209,20 @@ emitter.on('changeResult', (item) => {
// HTTP // HTTP
const HTTP_SERVER_API = (type, params = {}) => { const HTTP_SERVER_API = (type, params = {}) => {
switch (type) { switch (type) {
case 'addSmarttalk': { //
const node = courseObj.node || {}
const def = {
fileId: '', // id - Entpcoursefile id
fileFlag: 'aptist',
fileShowName: node.itemtitle + '.aptist',
textbookId: node.rootid,
levelFirstId: node.parentid||node.id,
levelSecondId: node.parentid && node.id,
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('请选择章节?')
@ -298,6 +315,7 @@ const toRousrceUrl = async(o) => {
const curNode = reactive({}) const curNode = reactive({})
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
console.log('data', sessionStore)
Object.assign(curNode, data); Object.assign(curNode, data);
courseObj.node = data courseObj.node = data