Compare commits
77 Commits
8d03c927b9
...
23e59531ea
Author | SHA1 | Date |
---|---|---|
小杨 | 23e59531ea | |
小杨 | 9e021edc67 | |
zouyf | 238f08d9ac | |
“zouyf” | d90b7c695a | |
“zouyf” | f936e726c0 | |
“zouyf” | d07dd4455c | |
zouyf | b319aeb4b2 | |
“zouyf” | 23c397e18a | |
“zouyf” | 78858111bb | |
zhengdegang | 3c6ac1f77d | |
zdg | 97962d591f | |
zdg | 86154148c6 | |
zdg | 44092a21bf | |
“zouyf” | 728ce16c8b | |
小杨 | 5b1d921378 | |
lyc | f2637c7b15 | |
lyc | 93fa916084 | |
lyc | 24d6d5887f | |
朱浩 | 222b0f54f8 | |
朱浩 | e0a56b37ef | |
baigl | 045bc5e198 | |
白了个白 | 464f39dac8 | |
白了个白 | 8e72b50c68 | |
小杨 | 0aa09e9d9a | |
lyc | 97f55ca333 | |
lyc | cb5445f9a9 | |
lyc | 560e6f0e70 | |
“zouyf” | bbe2281781 | |
“zouyf” | 66881b0025 | |
baigl | 4010411c9f | |
“zouyf” | e43c9fd038 | |
白了个白 | da1c80406f | |
白了个白 | e3199b43de | |
朱浩 | a78497b263 | |
朱浩 | 65670af54f | |
zhengdegang | e5be55f12e | |
zdg | 209ab7fafc | |
朱浩 | 87dcd9d5c3 | |
zouyf | 1f96b9b09e | |
小杨 | 0e18d74bb9 | |
小杨 | 399c4b5461 | |
“zouyf” | 35c088c25a | |
“zouyf” | 028eb0f752 | |
zhengdegang | 9a68661fb0 | |
zdg | b28abdff50 | |
zdg | b428260703 | |
lyc | b5f824ceea | |
lyc | d3b3e3bcb5 | |
zhengdegang | dcabb80757 | |
zdg | 53f26d96d4 | |
zdg | 7d7b50fa3e | |
baigl | eae2171c70 | |
白了个白 | 5fe9359d64 | |
白了个白 | be9d33fcd3 | |
lyc | 09e3264ee7 | |
lyc | 7845d9bb1a | |
zhengdegang | 2fb6828154 | |
zdg | 03d1a683be | |
zdg | d542064ee3 | |
朱浩 | 9803c09c43 | |
zhengdegang | 57fdba4578 | |
zdg | 0e5d84fcd2 | |
朱浩 | 7811bbfe3e | |
zhengdegang | 7ddf71c044 | |
zdg | 91ceb712bf | |
zdg | a192640899 | |
zdg | 08a16929f7 | |
lyc | 42e8149443 | |
lyc | 8b429a4174 | |
白了个白 | 23795f2419 | |
白了个白 | ea204de407 | |
白了个白 | a31b8d7376 | |
白了个白 | df474db4a5 | |
白了个白 | 328e623db7 | |
白了个白 | 8ad041e963 | |
lyc | 3ad4391e10 | |
“zouyf” | 7b59d78ce3 |
|
@ -16,4 +16,9 @@ VITE_APP_RES_FILE_PATH = 'https://file.ysaix.com:7868/src/assets/textbook/booktx
|
||||||
|
|
||||||
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
|
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
|
||||||
|
|
||||||
|
# websocket 地址
|
||||||
|
# VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
|
VITE_APP_WS_URL = 'ws://192.168.2.16:7865'
|
||||||
|
|
||||||
|
# 是否显示开发工具
|
||||||
VITE_SHOW_DEV_TOOLS = 'true'
|
VITE_SHOW_DEV_TOOLS = 'true'
|
||||||
|
|
|
@ -18,4 +18,8 @@ VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktx
|
||||||
|
|
||||||
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||||
|
|
||||||
|
# websocket 地址
|
||||||
|
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
|
|
||||||
|
# 是否显示开发工具
|
||||||
VITE_SHOW_DEV_TOOLS = 'false'
|
VITE_SHOW_DEV_TOOLS = 'false'
|
||||||
|
|
|
@ -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/, '')
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
declare module '*.vue' {
|
||||||
|
import { ComponentOptions } from 'vue'
|
||||||
|
const componentOptions: ComponentOptions
|
||||||
|
export default componentOptions
|
||||||
|
}
|
|
@ -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",
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关ap
|
||||||
import { PPTApi } from './api'
|
import { PPTApi } from './api'
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import './api/watcher' // 监听
|
import './api/watcher' // 监听
|
||||||
|
import './api/classcourse' // 课程相关
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const _isPC = isPC()
|
const _isPC = isPC()
|
||||||
|
@ -60,14 +61,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 资源数据
|
||||||
|
@ -89,5 +82,8 @@ const initLoad: Function = () => {
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#app {
|
#app {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
svg, canvas, img, audio, video, iframe {
|
||||||
|
display: unset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* @author zdg
|
||||||
|
* @description 上课相关内容
|
||||||
|
*/
|
||||||
|
import type { Classcourse } from './types'
|
||||||
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
|
import * as useStore from '../store' // pptist-状态管理
|
||||||
|
import { ChatWs } from '@/plugins/socket' // 聊天socket
|
||||||
|
const screenStore = useStore.useScreenStore() // 全屏-状态管理
|
||||||
|
const classcourseStore = useStore.useClasscourseStore() // 课堂信息-状态管理
|
||||||
|
const classcourse: Classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
||||||
|
|
||||||
|
// 如果课堂信息有值,则连接socket
|
||||||
|
if (!!classcourse) {
|
||||||
|
// 连接socket
|
||||||
|
const ws = new ChatWs()
|
||||||
|
console.log('ws- ',ws)
|
||||||
|
// ChatWs.connect(classcourse.id)
|
||||||
|
classcourseStore.setClasscourse(classcourse)
|
||||||
|
}
|
||||||
|
// 打开全屏
|
||||||
|
screenStore.setScreening(!!classcourse)
|
|
@ -4,6 +4,7 @@
|
||||||
* @date 2024-11-26
|
* @date 2024-11-26
|
||||||
*/
|
*/
|
||||||
import { toRaw } from 'vue'
|
import { toRaw } from 'vue'
|
||||||
|
import type { 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 API_smarttalk from '@/api/file' // 相关api
|
||||||
|
@ -135,13 +136,15 @@ export class PPTApi {
|
||||||
id: currentSlide.id,
|
id: currentSlide.id,
|
||||||
datacontent: JSON.stringify(currentSlide),
|
datacontent: JSON.stringify(currentSlide),
|
||||||
}
|
}
|
||||||
Utils.mxThrottle(() => {this.updateSlide(params)}, 1000, 2)
|
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新幻灯片
|
// 更新幻灯片
|
||||||
static updateSlide(data: object): Promise<Boolean> {
|
static updateSlide(data: object): Promise<Boolean> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
|
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
|
||||||
|
console.log(data,'data');
|
||||||
|
console.log(res,'dresata');
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
|
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* @description api 无store循环引用
|
* @description api 无store循环引用
|
||||||
* @author zdg
|
* @author zdg
|
||||||
*/
|
*/
|
||||||
|
import type { 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
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/** 返回-接口类型 */
|
||||||
|
export interface Result {
|
||||||
|
code?: number,
|
||||||
|
msg?: string,
|
||||||
|
data?: any
|
||||||
|
rows?: Array<any>,
|
||||||
|
total?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 课程信息 */
|
||||||
|
export interface Classcourse {
|
||||||
|
id?: number|string, // 课程id
|
||||||
|
coursetitle?: string, // 课程名称
|
||||||
|
coursetype?: string, // 课程类型
|
||||||
|
courseverid?: string, // 课程版本id
|
||||||
|
coursedesc?: string, // 课程描述
|
||||||
|
status?: number, // 课程状态
|
||||||
|
teacherid?: number|string, // 教师id
|
||||||
|
entpcoursefileid?: number|string, // 课程文件id
|
||||||
|
classid?: number|string, // 班级id
|
||||||
|
entpcourseid?: number|string, // 章节中间表id
|
||||||
|
plandate?: string, // 计划时间
|
||||||
|
opendate?: string, // 开课时间
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import { useScreenStore, useSlidesStore } from '../store'
|
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
|
||||||
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const screenStore = useScreenStore()
|
const screenStore = useScreenStore()
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
|
const classcourseStore = useClasscourseStore() // 课堂信息
|
||||||
|
|
||||||
// 进入放映状态(从当前页开始)
|
// 进入放映状态(从当前页开始)
|
||||||
const enterScreening = () => {
|
const enterScreening = () => {
|
||||||
|
@ -19,7 +20,11 @@ export default () => {
|
||||||
|
|
||||||
// 退出放映状态
|
// 退出放映状态
|
||||||
const exitScreening = () => {
|
const exitScreening = () => {
|
||||||
screenStore.setScreening(false)
|
const classcourse = classcourseStore.classcourse
|
||||||
|
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
||||||
|
console.log('退出放映状态')
|
||||||
|
window.close()
|
||||||
|
} else screenStore.setScreening(false)
|
||||||
if (isFullscreen()) exitFullscreen()
|
if (isFullscreen()) exitFullscreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,8 @@ import {
|
||||||
User,
|
User,
|
||||||
Switch,
|
Switch,
|
||||||
More,
|
More,
|
||||||
|
Material,
|
||||||
|
AddPicture
|
||||||
} from '@icon-park/vue-next'
|
} from '@icon-park/vue-next'
|
||||||
|
|
||||||
export interface Icons {
|
export interface Icons {
|
||||||
|
@ -255,6 +257,8 @@ export const icons: Icons = {
|
||||||
IconUser: User,
|
IconUser: User,
|
||||||
IconSwitch: Switch,
|
IconSwitch: Switch,
|
||||||
IconMore: More,
|
IconMore: More,
|
||||||
|
IconMaterial: Material,
|
||||||
|
IconAddPicture: AddPicture
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { Classcourse } from '../api/types'
|
||||||
|
|
||||||
|
export interface ClasscourseState {
|
||||||
|
classcourse: Classcourse
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useClasscourseStore = defineStore('classcourse', {
|
||||||
|
state: (): ClasscourseState => ({
|
||||||
|
classcourse: null, // 课堂信息
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
setClasscourse(classcourse: Classcourse) {
|
||||||
|
this.classcourse = classcourse
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
|
@ -3,6 +3,7 @@ import { useSlidesStore } from './slides'
|
||||||
import { useSnapshotStore } from './snapshot'
|
import { useSnapshotStore } from './snapshot'
|
||||||
import { useKeyboardStore } from './keyboard'
|
import { useKeyboardStore } from './keyboard'
|
||||||
import { useScreenStore } from './screen'
|
import { useScreenStore } from './screen'
|
||||||
|
import { useClasscourseStore } from './classcourse'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useMainStore,
|
useMainStore,
|
||||||
|
@ -10,4 +11,5 @@ export {
|
||||||
useSnapshotStore,
|
useSnapshotStore,
|
||||||
useKeyboardStore,
|
useKeyboardStore,
|
||||||
useScreenStore,
|
useScreenStore,
|
||||||
|
useClasscourseStore,
|
||||||
}
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
<template>
|
||||||
|
<header class="flex material-header">
|
||||||
|
<span>选择素材</span>
|
||||||
|
<i class="iconfont icon-guanbi" @click="onClose"></i>
|
||||||
|
</header>
|
||||||
|
<div class="flex material-list" v-loading="loading">
|
||||||
|
<div class="flex material-item" v-for="item in list" :key="item.id" >
|
||||||
|
<div class="flex">
|
||||||
|
<el-image :src="fileUrl(item)" class="img" />
|
||||||
|
<el-text truncated>{{ item.fileShowName }}</el-text>
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" @click="onInsert(item)">插入</el-button>
|
||||||
|
</div>
|
||||||
|
<el-empty description="暂无素材" v-if="!list.length" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted, computed } from 'vue';
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
import { getSmarttalkPage } from '@/api/file'
|
||||||
|
import { getFileSuffix, urlToBase64 } from '@/utils/ruoyi.js'
|
||||||
|
|
||||||
|
const emit = defineEmits(['insertMaterial', 'close'])
|
||||||
|
|
||||||
|
const curNode = reactive({})
|
||||||
|
let params = {
|
||||||
|
textbookId: '',
|
||||||
|
levelFirstId: '',
|
||||||
|
levelSecondId: null,
|
||||||
|
fileSource: '个人',
|
||||||
|
fileRoot: '备课',
|
||||||
|
orderByColumn: 'uploadTime',
|
||||||
|
isAsc: 'desc',
|
||||||
|
pageSize: 500
|
||||||
|
}
|
||||||
|
|
||||||
|
const suffixAry = [ 'jpeg','jpg','png','gif','mp3','mp4','avi','mov']
|
||||||
|
const videoSuffix = ['mp3','mp4','avi','mov']
|
||||||
|
const list = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const init = () => {
|
||||||
|
loading.value = true
|
||||||
|
getSmarttalkPage(params).then(res => {
|
||||||
|
loading.value = false
|
||||||
|
if(res.rows && res.rows.length){
|
||||||
|
// 过滤出图片和视频
|
||||||
|
list.value = res.rows.filter( item => suffixAry.indexOf(getFileSuffix(item.fileShowName)) != -1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileUrl = computed(() => (item) =>{
|
||||||
|
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
||||||
|
return item.coverPic
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return item.fileFullPath
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 插入
|
||||||
|
const onInsert = async (item) =>{
|
||||||
|
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
||||||
|
emit('insertMaterial',{ type: 'video', data: item.fileFullPath })
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
const base64 = await urlToBase64(item.fileFullPath)
|
||||||
|
emit('insertMaterial',{ type: 'img', data: base64 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const GetUrlParameters = (parameters) => {
|
||||||
|
let resData = "";
|
||||||
|
|
||||||
|
let url = document.location.toString();
|
||||||
|
let arrUrl = url.split("?");
|
||||||
|
// 判断是否有参数
|
||||||
|
if (arrUrl.length > 1) {
|
||||||
|
// 拆分参数字符串
|
||||||
|
let parametersArr = arrUrl[1].split("&");
|
||||||
|
// 循环查找参数
|
||||||
|
for (let i = 0; i <= parametersArr.length; i++) {
|
||||||
|
if (parametersArr[i]) {
|
||||||
|
// 拆分参数的键和值
|
||||||
|
let parameterStr = parametersArr[i].split("=");
|
||||||
|
if (parameters == parameterStr[0]) {
|
||||||
|
resData = parameterStr[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const proxyToBase64 = (url)=> {
|
||||||
|
const dourl = GetUrlParameters(url)
|
||||||
|
console.log(dourl,'dourl')
|
||||||
|
return
|
||||||
|
axios({
|
||||||
|
url: "/api/logo.png",
|
||||||
|
method: "get",
|
||||||
|
responseType: "blob",
|
||||||
|
}).then((res) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(res.data);
|
||||||
|
reader.onload = () => {
|
||||||
|
console.log(reader.result);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
const onClose = () =>{
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
let data = sessionStore.get('subject.curNode')
|
||||||
|
Object.assign(curNode, data);
|
||||||
|
params.textbookId = curNode.rootid
|
||||||
|
if (curNode.parentNode) {
|
||||||
|
params.levelFirstId = curNode.parentNode.id
|
||||||
|
params.levelSecondId = curNode.id
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params.levelFirstId = curNode.id
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.material-header {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.icon-guanbi{
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.material-list{
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 150px;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-item {
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
justify-content: space-between;
|
||||||
|
.img{
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -81,6 +81,9 @@
|
||||||
</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" />
|
||||||
|
<IconMaterial class="handler-item" v-tooltip="'插入素材'" @click="materiaVisible = true"/>
|
||||||
|
<IconAddPicture class="handler-item" v-tooltip="'文生图'" @click="imgVisible = true" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="right-handler">
|
<div class="right-handler">
|
||||||
|
@ -110,6 +113,27 @@
|
||||||
@update="data => { createLatexElement(data); latexEditorVisible = false }"
|
@update="data => { createLatexElement(data); latexEditorVisible = false }"
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
<el-dialog v-model="classWorkTaskVisible" append-to-body :show-close="false" width="70%">
|
||||||
|
<QuestToPPTist
|
||||||
|
class="class-work-task-modal"
|
||||||
|
@close="classWorkTaskVisible = false"
|
||||||
|
@update="data => { onhtml2canvas(data); classWorkTaskVisible = false }"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
<!--插入素材-->
|
||||||
|
<Modal
|
||||||
|
v-model:visible="materiaVisible"
|
||||||
|
:width="880">
|
||||||
|
<MaterialDialog @close="materiaVisible = false" @insertMaterial="insertMaterial"/>
|
||||||
|
</Modal>
|
||||||
|
<!--文生图-->
|
||||||
|
<Modal
|
||||||
|
v-model:visible="imgVisible"
|
||||||
|
:width="1300">
|
||||||
|
<TextCreateImg hasPPt @insertImg="(url: string) => { createImageElement(url); imgVisible = false }" />
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -135,6 +159,9 @@ 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'
|
||||||
|
import MaterialDialog from './MaterialDialog.vue'
|
||||||
|
import TextCreateImg from '@/components/ai-kolors/index.vue'
|
||||||
|
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
|
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
|
||||||
|
@ -172,15 +199,21 @@ 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)
|
||||||
|
const materiaVisible = ref(false)
|
||||||
|
|
||||||
// 绘制文字范围
|
// 绘制文字范围
|
||||||
const drawText = (vertical = false) => {
|
const drawText = (vertical = false) => {
|
||||||
|
@ -227,6 +260,25 @@ const toggleSraechPanel = () => {
|
||||||
const toggleNotesPanel = () => {
|
const toggleNotesPanel = () => {
|
||||||
mainStore.setNotesPanelState(!showNotesPanel.value)
|
mainStore.setNotesPanelState(!showNotesPanel.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 插入素材
|
||||||
|
interface MaterialParams {
|
||||||
|
type: string,
|
||||||
|
data: string
|
||||||
|
}
|
||||||
|
const insertMaterial = (item: MaterialParams) =>{
|
||||||
|
const { type, data } = item
|
||||||
|
if(type == 'video'){
|
||||||
|
createVideoElement(data)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
createImageElement(data)
|
||||||
|
}
|
||||||
|
materiaVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文生图
|
||||||
|
const imgVisible = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -343,6 +395,9 @@ const toggleNotesPanel = () => {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.class-work-task-modal{
|
||||||
|
height: 70vh;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (width <= 1200px) {
|
@media screen and (width <= 1200px) {
|
||||||
.right-handler .text {
|
.right-handler .text {
|
||||||
|
|
|
@ -162,6 +162,10 @@ const setDialogForExport = (type: DialogForExportTypes) => {
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
||||||
|
:deep(svg) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -67,8 +67,6 @@
|
||||||
|
|
||||||
<div class="page-number">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
<div class="page-number">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
||||||
|
|
||||||
<!-- 引入活动的列表页面 -->
|
|
||||||
<Active ref="activeRef" v-show="false"/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -88,7 +86,6 @@ import ThumbnailSlide from '../../../views/components/ThumbnailSlide/index.vue'
|
||||||
import LayoutPool from './LayoutPool.vue'
|
import LayoutPool from './LayoutPool.vue'
|
||||||
import Popover from '../../../components/Popover.vue'
|
import Popover from '../../../components/Popover.vue'
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import Active from '../Toolbar/ElementStylePanel/Active/index.vue'
|
|
||||||
|
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
|
@ -127,7 +124,6 @@ const {
|
||||||
updateSectionTitle,
|
updateSectionTitle,
|
||||||
} = useSectionHandler()
|
} = useSectionHandler()
|
||||||
|
|
||||||
const activeRef = ref()
|
|
||||||
|
|
||||||
// 页面被切换时
|
// 页面被切换时
|
||||||
const thumbnailsRef = ref<InstanceType<typeof Draggable>>()
|
const thumbnailsRef = ref<InstanceType<typeof Draggable>>()
|
||||||
|
@ -151,8 +147,6 @@ watch(() => slideIndex.value, () => {
|
||||||
|
|
||||||
// 切换页面
|
// 切换页面
|
||||||
const changeSlideIndex = (index: number) => {
|
const changeSlideIndex = (index: number) => {
|
||||||
console.log(workItem.value[index],'hasSection');
|
|
||||||
activeRef.value.clickPPTList(workItem.value[index])
|
|
||||||
|
|
||||||
mainStore.setActiveElementIdList([])
|
mainStore.setActiveElementIdList([])
|
||||||
|
|
||||||
|
@ -402,12 +396,17 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
|
:deep(svg) {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.thumbnail-list {
|
.thumbnail-list {
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
border-bottom: 1px solid $borderColor;
|
||||||
}
|
}
|
||||||
.thumbnail-item {
|
.thumbnail-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -486,7 +485,6 @@ const contextmenusThumbnailItem = (): ContextmenuItem[] => {
|
||||||
.page-number {
|
.page-number {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
border-top: 1px solid $borderColor;
|
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
|
@ -32,12 +32,12 @@
|
||||||
<!-- 作业列表 -->
|
<!-- 作业列表 -->
|
||||||
<div class="c-apt-r">
|
<div class="c-apt-r">
|
||||||
<!-- 显示-作业内容 -->
|
<!-- 显示-作业内容 -->
|
||||||
<template v-for="(item, index) in workList">
|
<template v-for="(item, index) in workList" :key="index">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="item-title">
|
<div class="item-title">
|
||||||
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
|
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
|
||||||
<el-tooltip :content="item.title||item.uniquekey" placement="top">
|
<el-tooltip :content="item.evaltitle" placement="top">
|
||||||
<div class="tt">{{item.title||item.uniquekey}}</div>
|
<div class="tt">{{item.evaltitle}}</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-button class="btn-del" type="danger" link @click="handleRemoveDemoActivityClassWork(item)">删除</el-button>
|
<el-button class="btn-del" type="danger" link @click="handleRemoveDemoActivityClassWork(item)">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -45,8 +45,10 @@
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<!-- // 推送作业 -->
|
<!-- // 推送作业 -->
|
||||||
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="80%">
|
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="80%" height="500">
|
||||||
<NewClassTsakAssign :currentCourse='currentCourse'/>
|
<el-scrollbar height="500">
|
||||||
|
<NewClassTsakAssign :currentCourse='currentCourse' @getData="getData" />
|
||||||
|
</el-scrollbar>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 活动引用 -->
|
<!-- 活动引用 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
@ -55,9 +57,9 @@
|
||||||
append-to-body
|
append-to-body
|
||||||
:show-close="false"
|
:show-close="false"
|
||||||
width="40%"
|
width="40%"
|
||||||
@selection-change="handleSelectionChange">
|
>
|
||||||
<el-table :data="taskList" style="width: 100%" height="500">
|
<el-table :data="taskList" style="width: 100%" height="500" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" :selectable="selectable" width="55" />
|
<el-table-column type="selection" width="55" :selectable="selectable"/>
|
||||||
<el-table-column prop="evaltitle" label="活动名称" width="150" />
|
<el-table-column prop="evaltitle" label="活动名称" width="150" />
|
||||||
<el-table-column prop="worktype" label="活动类型" width="120" sortable>
|
<el-table-column prop="worktype" label="活动类型" width="120" sortable>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
@ -68,160 +70,246 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="activeVisible = false">取 消</el-button>
|
<el-button @click="activeVisible = false">取 消</el-button>
|
||||||
<el-button type="primary" @click="save">确 定</el-button>
|
<el-button type="primary" @click="savePPtData">确 定</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, onBeforeMount, defineExpose } from 'vue'
|
import { ref, reactive, onMounted, nextTick, watch } from 'vue'
|
||||||
import Divider from '../../../../../components/Divider.vue'
|
import Divider from '../../../../../components/Divider.vue'
|
||||||
import {listEntpcoursefile} from '@/api/education/entpcoursefile'
|
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
import {homeworklist} from '@/api/teaching/classwork'
|
import { homeworklist } from '@/api/teaching/classwork'
|
||||||
import { processList } from "@/hooks/useProcessList";
|
import { processList } from "@/hooks/useProcessList";
|
||||||
import { listEntpcoursework } from "@/api/classTask/index";
|
import { listEntpcoursework } from "@/api/classTask/index";
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox,ElMessage } from 'element-plus'
|
||||||
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
|
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
const currentCourse = reactive({
|
import { PPTApi } from '../../../../../api/index'
|
||||||
textbookId:0,
|
import { storeToRefs } from 'pinia'
|
||||||
levelFirstId:0,
|
import {useSlidesStore} from '../../../../../store'
|
||||||
levelSecondId:0,
|
const slidesStore = useSlidesStore()
|
||||||
coursetitle:'',
|
const { slides, slideIndex, currentSlide, workItem } = storeToRefs(slidesStore)
|
||||||
node:{},
|
|
||||||
id:1,
|
interface CourseNode {
|
||||||
worktype:'',
|
rootid: number;
|
||||||
})
|
parentNode: { id: number };
|
||||||
const dataList = ref([])
|
id: number;
|
||||||
const dialogVisible = ref(false)
|
itemtitle: string;
|
||||||
const tasklist_loading = ref(false)
|
|
||||||
// 活动列表
|
|
||||||
const taskList = ref([])
|
|
||||||
// 活动引用的弹窗
|
|
||||||
const activeVisible = ref(false)
|
|
||||||
const params = reactive({
|
|
||||||
parentid:14766,
|
|
||||||
pageSize:500,
|
|
||||||
orderby:'fileidx'
|
|
||||||
})
|
|
||||||
const type = ref([
|
|
||||||
{
|
|
||||||
label:'习题训练',
|
|
||||||
value:'danger'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:'课堂展示',
|
|
||||||
value:'success'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:'常规作业',
|
|
||||||
value:'primary'
|
|
||||||
},
|
|
||||||
])
|
|
||||||
// 作业列表
|
|
||||||
const workList = ref([])
|
|
||||||
const selectable = (row,index) => {
|
|
||||||
console.log(row,index,'row,index');
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const clickPPTList = (item) => {
|
interface CurrentCourse {
|
||||||
console.log(item,'点击了')
|
textbookId: number;
|
||||||
workList.value = []
|
levelFirstId: number;
|
||||||
let datacontent = item.datacontent;
|
levelSecondId: number;
|
||||||
let pptJson = "";
|
coursetitle: string;
|
||||||
if(typeof datacontent === 'string') pptJson = JSON.parse(datacontent)
|
node: CourseNode;
|
||||||
if(pptJson&&pptJson[0]&&pptJson[0].classworkList) {
|
id: number;
|
||||||
homeworklist({ids:pptJson[0].classworkList, pageSize: 100}).then( async res => {
|
worktype: string;
|
||||||
await formatClassWorkFile(res.rows)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const formatClassWorkFile = async (postData) => {
|
|
||||||
return new Promise(async (resolve, reject)=>{
|
interface Params {
|
||||||
for (let i = 0; i < postData.length; i++) {
|
parentid: number;
|
||||||
let item = postData[i];
|
pageSize: number;
|
||||||
switch (item.worktype) {
|
orderby: string;
|
||||||
case '框架梳理': {
|
}
|
||||||
}
|
|
||||||
break;
|
interface WorkType {
|
||||||
case '习题训练': {
|
label: string;
|
||||||
item.entpcourseworklistarray = item.entpcourseworklist?JSON.parse('['+item.entpcourseworklist+']'):[];
|
value: string;
|
||||||
let workIds = item.entpcourseworklistarray.map(items=>items.id).join(',')
|
}
|
||||||
let ress = await listEntpcoursework({ids:workIds})
|
|
||||||
processList(ress.rows)
|
interface WorkItem {
|
||||||
item.workShowList = ress.rows
|
status: string;
|
||||||
}
|
activityContent?: string;
|
||||||
break;
|
worktype: string;
|
||||||
case '课堂展示': {
|
quizlist?: { id: number }[];
|
||||||
item.base64 = JSON.parse(item.workcodes).base64
|
workcodes: string;
|
||||||
}
|
base64?: string;
|
||||||
break;
|
prevData?: any;
|
||||||
case '常规作业': {
|
id: number;
|
||||||
item.prevData = JSON.parse(item.workcodes)
|
evaltitle?: string; // 添加 evaltitle 属性
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentCourse = reactive<CurrentCourse>({
|
||||||
|
textbookId: 0,
|
||||||
|
levelFirstId: 0,
|
||||||
|
levelSecondId: 0,
|
||||||
|
coursetitle: '',
|
||||||
|
node: {} as CourseNode,
|
||||||
|
id: 1,
|
||||||
|
worktype: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const dataList = ref<WorkItem[]>([])
|
||||||
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
const tasklist_loading = ref<boolean>(false)
|
||||||
|
|
||||||
|
// 活动列表
|
||||||
|
const taskList = ref<WorkItem[]>([])
|
||||||
|
|
||||||
|
// 活动引用的弹窗
|
||||||
|
const activeVisible = ref<boolean>(false)
|
||||||
|
|
||||||
|
const params = reactive<Params>({
|
||||||
|
parentid: 14766,
|
||||||
|
pageSize: 500,
|
||||||
|
orderby: 'fileidx'
|
||||||
|
})
|
||||||
|
|
||||||
|
const type = ref<WorkType[]>([
|
||||||
|
{
|
||||||
|
label: '习题训练',
|
||||||
|
value: 'danger'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '课堂展示',
|
||||||
|
value: 'success'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '常规作业',
|
||||||
|
value: 'primary'
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
const objItem = ref<any>({})
|
||||||
|
// 作业列表
|
||||||
|
const workList = ref<WorkItem[]>([])
|
||||||
|
|
||||||
|
// 获取所选择的作业列表
|
||||||
|
const selectedWorkList = ref<WorkItem[]>([])
|
||||||
|
|
||||||
|
|
||||||
|
const paramData = ref<{ id: number, activityContent: string }>({} as { id: number, activityContent: string })
|
||||||
|
|
||||||
|
const selectable = (row: WorkItem, index: number): boolean => {
|
||||||
|
return row.status === '10';
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const formatClassWorkFile = async (postData: WorkItem[]): Promise<void> => {
|
||||||
|
for (let i = 0; i < postData.length; i++) {
|
||||||
|
let item = postData[i];
|
||||||
|
switch (item.worktype) {
|
||||||
|
case '框架梳理': {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '习题训练': {
|
||||||
|
console.log(item,'item');
|
||||||
|
// let workIds = item.quizlist!.map(items => items.id).join(',');
|
||||||
|
// let ress = await listEntpcoursework({ ids: workIds });
|
||||||
|
// const arr = ress.rows.map((item:{id:number}) => {
|
||||||
|
// return item.id
|
||||||
|
// })
|
||||||
|
|
||||||
|
// processList(ress.rows);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '课堂展示': {
|
||||||
|
// item.base64 = JSON.parse(item.workcodes).base64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '常规作业': {
|
||||||
|
// item.prevData = JSON.parse(item.workcodes);
|
||||||
}
|
}
|
||||||
workList.value.push(item)
|
|
||||||
}
|
}
|
||||||
resolve()
|
const arr = paramData.value.activityContent.split(',')
|
||||||
})
|
arr.push(item.id.toString())
|
||||||
|
await PPTApi.updateSlide(paramData.value)
|
||||||
|
addWorkList(item)
|
||||||
|
}
|
||||||
|
await nextTick();
|
||||||
|
}
|
||||||
|
// 添加的活动回显到页面上面去
|
||||||
|
const addWorkList = (item: WorkItem) => {
|
||||||
|
workList.value.push(item)
|
||||||
}
|
}
|
||||||
// 删除作业
|
// 删除作业
|
||||||
const handleRemoveDemoActivityClassWork = (item) => {
|
const handleRemoveDemoActivityClassWork = (item: WorkItem) => {
|
||||||
ElMessageBox.confirm('是否确认删除?')
|
ElMessageBox.confirm('是否确认删除?')
|
||||||
.then(function () {
|
.then(() => {
|
||||||
workList.value.splice(workList.value.indexOf(item), 1);
|
workList.value.splice(workList.value.indexOf(item), 1);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取tag的样式
|
// 获取tag的样式
|
||||||
const getTagType = (worktype) => {
|
const getTagType = (worktype: string): string => {
|
||||||
return type.value.find(item => item.label == worktype).value
|
return type.value.find(item => item.label === worktype)!.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取活动引用的列表数据
|
// 获取活动引用的列表数据
|
||||||
const initHomeWork = async()=> {
|
const initHomeWork = async () => {
|
||||||
tasklist_loading.value = true;
|
tasklist_loading.value = true;
|
||||||
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
|
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
|
||||||
taskList.value = res;
|
taskList.value = res;
|
||||||
tasklist_loading.value = false;
|
tasklist_loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选活动引用
|
// 多选活动引用
|
||||||
const handleSelectionChange = (val) => {
|
const handleSelectionChange = (val: WorkItem[]) => {
|
||||||
console.log(val,'多选')
|
selectedWorkList.value = [...val]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开添加作业活动
|
// 打开添加作业活动
|
||||||
const showDialog = (item) => {
|
const showDialog = (item: string) => {
|
||||||
currentCourse.worktype = item
|
currentCourse.worktype = item
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const openList = () => {
|
const openList = () => {
|
||||||
activeVisible.value = true
|
activeVisible.value = true
|
||||||
initHomeWork()
|
initHomeWork()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加活动引用列表作业
|
// 添加活动引用列表作业
|
||||||
const save = () => {
|
const savePPtData = async () => {
|
||||||
console.log('添加了')
|
if (selectedWorkList.value.length === 0) {
|
||||||
|
ElMessage.warning('请选择活动')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const arr = selectedWorkList.value.map(item => item.id)
|
||||||
|
// 应该是新加而不是覆盖
|
||||||
|
paramData.value.activityContent = arr.join(',')
|
||||||
|
await PPTApi.updateSlide(paramData.value)
|
||||||
activeVisible.value = false
|
activeVisible.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// console.log(sessionStore.get('subject.curBook'),'curBook');
|
const curNode = sessionStore.get('subject.curNode') as CourseNode
|
||||||
// console.log(sessionStore.get('subject.subjectTree'),'subjectTree');
|
|
||||||
// console.log(sessionStore.get('subject.bookList'),'bookList');
|
|
||||||
console.log(sessionStore.get('subject.curNode'),'curNode');
|
|
||||||
const curNode = sessionStore.get('subject.curNode')
|
|
||||||
currentCourse.textbookId = curNode.rootid
|
currentCourse.textbookId = curNode.rootid
|
||||||
currentCourse.levelFirstId = curNode.parentNode.id
|
currentCourse.levelFirstId = curNode.parentNode.id
|
||||||
currentCourse.levelSecondId = curNode.id
|
currentCourse.levelSecondId = curNode.id
|
||||||
currentCourse.coursetitle = curNode.itemtitle,
|
currentCourse.coursetitle = curNode.itemtitle
|
||||||
currentCourse.node = curNode
|
currentCourse.node = curNode
|
||||||
listEntpcoursefile(params).then((res) => {
|
listEntpcoursefile(params).then((res: { rows: WorkItem[] }) => {
|
||||||
dataList.value = [...res.rows]
|
dataList.value = [...res.rows]
|
||||||
})
|
})
|
||||||
|
objItem.value = workItem.value[slideIndex.value]
|
||||||
|
getCurrentPPtData()
|
||||||
})
|
})
|
||||||
defineExpose({
|
watch(() => slideIndex.value, () => {
|
||||||
clickPPTList
|
getCurrentPPtData()
|
||||||
})
|
})
|
||||||
|
// 获取当前ppt页的数据
|
||||||
|
const getCurrentPPtData = async () => {
|
||||||
|
workList.value = []
|
||||||
|
objItem.value = workItem.value[slideIndex.value]
|
||||||
|
paramData.value.id = objItem.value.id
|
||||||
|
if (objItem.value?.activityContent) {
|
||||||
|
paramData.value.activityContent = objItem.value?.activityContent
|
||||||
|
const res = await homeworklist({ ids: objItem.value?.activityContent, pageSize: 100 })
|
||||||
|
await formatClassWorkFile(res.rows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收习题训练的值
|
||||||
|
const getData = async (data: WorkItem) => {
|
||||||
|
console.log(data, 'data')
|
||||||
|
await formatClassWorkFile([data])
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.buttonDiv{
|
.buttonDiv{
|
||||||
|
|
|
@ -160,7 +160,7 @@ const topImgPositionStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
left: -left * (100 / width) + '%',
|
left: -left * (100 / width) + '%',
|
||||||
top: -top * (100 / height) + '%',
|
top: -top * (100 / height) + '%',
|
||||||
width: bottomWidth / width * 100 + '%',
|
width: bottomWidth / width * 100 + '%' ,
|
||||||
height: bottomHeight / height * 100 + '%',
|
height: bottomHeight / height * 100 + '%',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -228,6 +228,7 @@ const updateRange = () => {
|
||||||
width: parseInt(topImgPositionStyle.value.width),
|
width: parseInt(topImgPositionStyle.value.width),
|
||||||
height: parseInt(topImgPositionStyle.value.height),
|
height: parseInt(topImgPositionStyle.value.height),
|
||||||
}
|
}
|
||||||
|
console.log('retPosition', retPosition)
|
||||||
|
|
||||||
const widthScale = 100 / retPosition.width
|
const widthScale = 100 / retPosition.width
|
||||||
const heightScale = 100 / retPosition.height
|
const heightScale = 100 / retPosition.height
|
||||||
|
@ -475,7 +476,7 @@ const scaleClipRange = (e: MouseEvent, type: OperateResizeHandlers) => {
|
||||||
isMouseDown = false
|
isMouseDown = false
|
||||||
document.onmousemove = null
|
document.onmousemove = null
|
||||||
document.onmouseup = null
|
document.onmouseup = null
|
||||||
|
console.log('----------------------------------')
|
||||||
updateRange()
|
updateRange()
|
||||||
|
|
||||||
setTimeout(() => isSettingClipRange.value = false, 0)
|
setTimeout(() => isSettingClipRange.value = false, 0)
|
||||||
|
@ -537,6 +538,7 @@ const edgePoints = [
|
||||||
|
|
||||||
img {
|
img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
max-width: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,7 @@ const handleClip = (data: ImageClipedEmitData | null) => {
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
max-width: none !important; // 防止图片被压缩
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.color-mask {
|
.color-mask {
|
||||||
|
|
|
@ -144,8 +144,14 @@ import { convertTextToPicture, getQueue, getPromptId, getPicture, chattoprompt,
|
||||||
import CryptoJS from 'crypto-js'
|
import CryptoJS from 'crypto-js'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
hasPPt: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
ratio: "512",
|
ratio: "512",
|
||||||
|
@ -384,7 +390,7 @@ export default {
|
||||||
urls.push(url0)
|
urls.push(url0)
|
||||||
buttonState.push({
|
buttonState.push({
|
||||||
disabled: false,
|
disabled: false,
|
||||||
text: "插入本课素材资源库",
|
text: this.hasPPt ? '插入' : "插入本课素材资源库",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.skeletonNumber = 0
|
this.skeletonNumber = 0
|
||||||
|
@ -476,6 +482,10 @@ export default {
|
||||||
|
|
||||||
//保存图片到素材库
|
//保存图片到素材库
|
||||||
async saveImage(resultIndex, index, url, resultItem) {
|
async saveImage(resultIndex, index, url, resultItem) {
|
||||||
|
if(this.hasPPt){
|
||||||
|
this.$emit('insertImg', url)
|
||||||
|
return
|
||||||
|
}
|
||||||
this.buttonStates[resultIndex][index].disabled = true;
|
this.buttonStates[resultIndex][index].disabled = true;
|
||||||
this.buttonStates[resultIndex][index].text = "正在保存...";
|
this.buttonStates[resultIndex][index].text = "正在保存...";
|
||||||
const numberIndex = url.indexOf('filename=');
|
const numberIndex = url.indexOf('filename=');
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -35,7 +35,7 @@ const getFileTypeIcon = () => {
|
||||||
txt: 'icon-txt',
|
txt: 'icon-txt',
|
||||||
rar: 'icon-rar',
|
rar: 'icon-rar',
|
||||||
apt: 'icon-A',
|
apt: 'icon-A',
|
||||||
aptist: 'icon-A',
|
aippt: 'icon-A',
|
||||||
}
|
}
|
||||||
if (iconObj[name]) {
|
if (iconObj[name]) {
|
||||||
return '#' + iconObj[name]
|
return '#' + iconObj[name]
|
||||||
|
|
|
@ -26,52 +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">
|
<div class="item-answer">
|
||||||
<TypingEffect :text="item.oldAnswer" :delay="10" :aiShow="item.aiShow" @complete="onSaveTemp(item)" />
|
<TypingEffect v-if="isStarted[index]" :text="item.answer" :delay="10" :aiShow="item.aiShow" @complete="handleCompleteText($event,index)" @updateScroll="scrollToBottom($event,index)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-btn" v-if="item.answer">
|
<div class="ai-btn" v-if="item.answer">
|
||||||
<el-button type="primary" link @click="againResult(index, item)">
|
<el-button type="primary" link @click="againResult(index, item)">
|
||||||
<i class="iconfont icon-ai1"></i>
|
<i class="iconfont icon-ai1"></i>
|
||||||
重新研读
|
重新研读
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" link @click="onAdjust(index, item)">
|
<el-button type="primary" link @click="onAdjust(index, item)">
|
||||||
<i class="iconfont icon-duihua"></i>
|
<i class="iconfont icon-duihua"></i>
|
||||||
AI对话调整
|
AI对话调整
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" link @click="onEdit(index, item)">
|
<el-button type="primary" link @click="onEdit(index, item)">
|
||||||
<i class="iconfont icon-bianji1"></i>
|
<i class="iconfont icon-bianji1"></i>
|
||||||
手动编辑结果
|
手动编辑结果
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-empty v-if="!childTempList.length" description="暂无模板数据" />
|
<el-empty v-if="!childTempList.length" description="暂无模板数据" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--编辑结果-->
|
<!--编辑结果-->
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
</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'
|
||||||
|
@ -146,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 => {
|
||||||
|
@ -161,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(
|
||||||
|
@ -203,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()
|
||||||
}
|
}
|
||||||
|
@ -215,7 +243,7 @@ const removeItem = async (item, isChild) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
editKeyWord(item,!isChild)
|
editKeyWord(item, !isChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,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(
|
||||||
{
|
{
|
||||||
|
@ -260,76 +287,102 @@ 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
|
item.aiShow = true
|
||||||
childTempList.value[index].oldAnswer = ''
|
|
||||||
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
|
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
|
onSaveTemp(item)
|
||||||
item.answer = getResult(answer);
|
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
item.loading = false
|
item.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) => {
|
emitter.on('onSaveAdjust', (item) => {
|
||||||
childTempList.value[curIndex.value].oldAnswer = item
|
childTempList.value[curIndex.value].answer = item
|
||||||
let answer = getResult(item);
|
|
||||||
childTempList.value[curIndex.value].oldAnswer = item
|
|
||||||
childTempList.value[curIndex.value].answer = answer
|
|
||||||
onEditSave(childTempList.value[curIndex.value])
|
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.oldAnswer == '') return
|
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 => { })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分析获取课标对话结果
|
// 去掉字符串中的 ### **
|
||||||
let getResult = (text) => {
|
let getResult = (str) => {
|
||||||
text = text.replace(/^\n\n(.*?)\n\n$/s, '<div>$1</div>');
|
let newStr = str.replace(/#+|(\*\*)/g, '');
|
||||||
text = text.replace(/^\n(.*?)\n$/s, '<p>$1</p>');
|
return newStr
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 操作之后获取字模板
|
// 操作之后获取字模板
|
||||||
|
@ -381,87 +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;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
: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>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="typing-effect">
|
<div class="typing-effect" ref="typingEffectRef">
|
||||||
<!-- <span v-html="displayedText"></span> -->
|
<!-- <span v-html="displayedText"></span> -->
|
||||||
<el-input
|
<el-input
|
||||||
v-model="displayedText"
|
v-model="displayedText"
|
||||||
|
@ -14,11 +14,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue';
|
import { ref, onMounted, watch, nextTick } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
text: {
|
text: {
|
||||||
type: String,
|
type: [String, Object],
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
delay: {
|
delay: {
|
||||||
|
@ -26,35 +26,48 @@ const props = defineProps({
|
||||||
default: 100 // 默认每个字符出现的延迟时间,单位是毫秒
|
default: 100 // 默认每个字符出现的延迟时间,单位是毫秒
|
||||||
},
|
},
|
||||||
aiShow: {
|
aiShow: {
|
||||||
type: [Boolean]
|
type: [Boolean] // 为true 只展示
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const emit = defineEmits(['complete']);
|
const typingEffectRef = ref(null);
|
||||||
|
const emit = defineEmits(['complete', 'updateScroll']);
|
||||||
const displayedText = ref('');
|
const displayedText = ref('');
|
||||||
const index = ref(0);
|
const index = ref(0);
|
||||||
|
|
||||||
const type = () => {
|
const type = async () => {
|
||||||
if(!props.aiShow) return
|
await nextTick()
|
||||||
|
if(!props.aiShow) {
|
||||||
|
displayedText.value = props.text
|
||||||
|
return
|
||||||
|
}
|
||||||
if (index.value <= props.text.length) {
|
if (index.value <= props.text.length) {
|
||||||
displayedText.value += props.text.charAt(index.value);
|
displayedText.value += props.text.charAt(index.value);
|
||||||
index.value++;
|
index.value++;
|
||||||
setTimeout(() => type(), props.delay);
|
setTimeout(() => {
|
||||||
|
type();
|
||||||
|
emit('updateScroll', typingEffectRef.value.clientHeight); // 每次添加新字符后滚动到底部
|
||||||
|
}, props.delay);
|
||||||
} else {
|
} else {
|
||||||
// 当所有字符都显示完毕时,触发 complete 事件
|
// 当所有字符都显示完毕时,触发 complete 事件
|
||||||
emit('complete');
|
emit('complete',displayedText.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
type();
|
resetAndType();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听 props 的变化,以便当传入的 text 或 delay 发生改变时重新开始打字机效果
|
const resetAndType = () =>{
|
||||||
watch([() => props.text, () => props.delay], () => {
|
|
||||||
displayedText.value = '';
|
displayedText.value = '';
|
||||||
index.value = 0;
|
index.value = 0;
|
||||||
type();
|
type();
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// 监听 props 的变化,以便当传入的 text 或 delay 发生改变时重新开始打字机效果
|
||||||
|
watch([() => props.text, () => props.delay], resetAndType);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -36,13 +36,13 @@ export const processList = (row, aloneOption=false) => {
|
||||||
row[i].method = jjj.method
|
row[i].method = jjj.method
|
||||||
row[i].discuss = jjj.discuss
|
row[i].discuss = jjj.discuss
|
||||||
//row[i].discusscollapse = false;
|
//row[i].discusscollapse = false;
|
||||||
if (row[i].examdate !== null && row[i].examdate !== undefined) {
|
if (row[i].examdate && row[i].examdate != "") {
|
||||||
row[i].examdate = row[i].examdate.substring(0, 10)
|
row[i].examdate = row[i].examdate.substring(0, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 具体题型数据结构处理
|
// 具体题型数据结构处理
|
||||||
if (row[i].worktype == '复合题') {
|
if (row[i].worktype == '复合题') {
|
||||||
// 旧类型
|
// 复合题 - 旧格式
|
||||||
if (row[i].title.indexOf('!@#$%') !== -1) {
|
if (row[i].title.indexOf('!@#$%') !== -1) {
|
||||||
// 1.选项解析替换
|
// 1.选项解析替换
|
||||||
const options = JSON.parse(row[i].workdesc)
|
const options = JSON.parse(row[i].workdesc)
|
||||||
|
@ -129,7 +129,9 @@ export const processList = (row, aloneOption=false) => {
|
||||||
|
|
||||||
row[i].workanswerFormat = answer
|
row[i].workanswerFormat = answer
|
||||||
} else {
|
} else {
|
||||||
// 处理[题干显示] - 不再需要处理
|
// 复合题 - 现格式
|
||||||
|
|
||||||
|
// 处理[题干显示] - 不再需要处理(头部已处理)
|
||||||
// row[i].titleFormat = row[i].title; // 仅占位提示
|
// row[i].titleFormat = row[i].title; // 仅占位提示
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,6 +224,7 @@ export const processList = (row, aloneOption=false) => {
|
||||||
row[i].workanswerFormat = workAnswerHtml
|
row[i].workanswerFormat = workAnswerHtml
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
/** 主观题/非基础题(其中主要为第三方的各类解答题) */
|
||||||
row[i].worktype == '主观题' ||
|
row[i].worktype == '主观题' ||
|
||||||
(row[i].worktype !== '单选题' &&
|
(row[i].worktype !== '单选题' &&
|
||||||
row[i].worktype !== '多选题' &&
|
row[i].worktype !== '多选题' &&
|
||||||
|
@ -236,7 +239,7 @@ export const processList = (row, aloneOption=false) => {
|
||||||
row[i].workanswerFormat = JSON.parse(row[i].workanswer)
|
row[i].workanswerFormat = JSON.parse(row[i].workanswer)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 单选题|多选题|填空题|判断题|主观题?(待确认是否归在这里)
|
// 基础题: 单选题|多选题|填空题|判断题|主观题?(待确认是否归在这里)
|
||||||
// 通用选项结构 ['ABC123','ABC123'] | ['ABC123','ABC123'] | [](填空题无选项) | [](判断题无选项)
|
// 通用选项结构 ['ABC123','ABC123'] | ['ABC123','ABC123'] | [](填空题无选项) | [](判断题无选项)
|
||||||
let workDescArr = []
|
let workDescArr = []
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="verson">V{{ version }}</div>
|
<div class="verson">V{{ version }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -87,6 +87,12 @@ const headerMenus = [
|
||||||
icon: 'icon-gongzuotai',
|
icon: 'icon-gongzuotai',
|
||||||
path: '/desktop'
|
path: '/desktop'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '教学实践',
|
||||||
|
id: 4,
|
||||||
|
icon: 'icon-jiaoxueshijian',
|
||||||
|
path: '/prepare'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '资源中心',
|
name: '资源中心',
|
||||||
id: 3,
|
id: 3,
|
||||||
|
@ -126,12 +132,12 @@ const computedregistertype = computed(() => {
|
||||||
if(type==3 && userStore.DeptInfo.register.auditStatus==0){
|
if(type==3 && userStore.DeptInfo.register.auditStatus==0){
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建学校 待审核
|
// 创建学校 待审核
|
||||||
if(type==4 && userStore.DeptInfo.register.auditStatus==0){
|
if(type==4 && userStore.DeptInfo.register.auditStatus==0){
|
||||||
return 3
|
return 3
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
const clickMenu = ({ id, disabled, path }) => {
|
const clickMenu = ({ id, disabled, path }) => {
|
||||||
if (disabled) return
|
if (disabled) return
|
||||||
|
@ -193,7 +199,7 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
.popoverStyle .head-aside{
|
.popoverStyle .head-aside{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -246,7 +252,7 @@ onMounted(() => {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
.user-img{
|
.user-img{
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -312,4 +318,4 @@ onMounted(() => {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
/**
|
||||||
|
* websocket 工具类(im 自己实现)
|
||||||
|
* 单例模式: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
|
||||||
|
* 实现的方法为先判断实例存在与否,如果存在则直接返回,不存在就创建了再返回,这就确保了一个类只有一个实例对象。
|
||||||
|
*/
|
||||||
|
import useUserStore from '@/store/modules/user' // 用户信息
|
||||||
|
|
||||||
|
export class ChatWs {
|
||||||
|
instance = null; // 实例
|
||||||
|
id = null; // 群聊id || 单聊id-用户id(userId)
|
||||||
|
closed = false; // 关闭状态
|
||||||
|
onmessage = null; // 自定义处理
|
||||||
|
errCount = 5; // 重连次数 (ms) 暂时不使用
|
||||||
|
errTime = null; // 重连时间 (ms) 1秒内zhi间内不重连
|
||||||
|
// 类型定义
|
||||||
|
TYPES = {
|
||||||
|
group: 'group', // 群发
|
||||||
|
single: 'single', // 单发
|
||||||
|
beat: 'heart_beat', // 心跳
|
||||||
|
}
|
||||||
|
static base = 'wss://file.ysaix.com:7868'
|
||||||
|
constructor() {
|
||||||
|
if (!ChatWs.instance) {
|
||||||
|
const userStore = useUserStore() // 用户信息
|
||||||
|
const wsBase = import.meta.env.VITE_APP_WS_URL; // ws地址
|
||||||
|
const url = `${wsBase||ChatWs.base}/ws/websocket/${userStore.id}`;
|
||||||
|
this.init(url);
|
||||||
|
ChatWs.instance = this;
|
||||||
|
}
|
||||||
|
return ChatWs.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
init(url) {
|
||||||
|
this.url = url;
|
||||||
|
this.ws = null;
|
||||||
|
const _this = this
|
||||||
|
this.heartCheck = {
|
||||||
|
timeout: 1000 * 10, // 60s
|
||||||
|
timeoutObj: null,
|
||||||
|
serverTimeoutObj: null,
|
||||||
|
reset() {
|
||||||
|
clearTimeout(this.timeoutObj);
|
||||||
|
clearTimeout(this.serverTimeoutObj);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
start() {
|
||||||
|
const self = this;
|
||||||
|
this.timeoutObj = setTimeout(function () {
|
||||||
|
// 这里发送一个心跳,后端收到后,返回一个心跳消息,
|
||||||
|
// onmessage拿到返回的心跳就说明连接正常
|
||||||
|
console.log("websocket-发送心跳")
|
||||||
|
_this.sendMsgBeat();
|
||||||
|
self.serverTimeoutObj = setTimeout(function () {
|
||||||
|
console.log("websocket-心跳响应超时")
|
||||||
|
// 如果超过一定时间还没重置,说明后端主动断开了
|
||||||
|
_this.ws.close(); // 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
|
||||||
|
}, self.timeout);
|
||||||
|
}, this.timeout);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.reconnect();
|
||||||
|
}
|
||||||
|
// 重连
|
||||||
|
reconnect() {
|
||||||
|
const self = this;
|
||||||
|
if (!!this.ws) { // 关闭之前的链接
|
||||||
|
this.ws.close()
|
||||||
|
this.ws = null
|
||||||
|
}
|
||||||
|
this.ws = new WebSocket(this.url);
|
||||||
|
this.ws.onopen = function () {
|
||||||
|
console.log("websocket-连接成功")
|
||||||
|
self.heartCheck.reset().start();
|
||||||
|
};
|
||||||
|
this.ws.onmessage = function (e) {
|
||||||
|
// console.log("websocket-收到消息", e)
|
||||||
|
// 拿到任何消息都说明当前连接是正常的
|
||||||
|
const isBeat = e.data == 'pong'
|
||||||
|
isBeat && self.heartCheck.reset().start();
|
||||||
|
const exts = ['sessionId', 'pong'] // 不处理的消息头
|
||||||
|
const isEmpty = !e.data
|
||||||
|
const isExts = exts.some(item => e.data.includes(item))
|
||||||
|
if (isEmpty && isExts) return;
|
||||||
|
// 自定义处理
|
||||||
|
self.onmessage && self.onmessage(e.data, e);
|
||||||
|
};
|
||||||
|
this.ws.onerror = function (e) {
|
||||||
|
console.log("websocket-连接异常", e)
|
||||||
|
self.connectSocket() // 重连
|
||||||
|
};
|
||||||
|
this.ws.onclose = function (e) {
|
||||||
|
console.log("websocket-连接断开", e)
|
||||||
|
self.connectSocket() // 重连
|
||||||
|
};
|
||||||
|
}
|
||||||
|
connectSocket() {
|
||||||
|
this.heartCheck.reset() // 重置心跳
|
||||||
|
if (self.closed) return; // 关闭状态不重连
|
||||||
|
// if(self.errCount <= 0) return; // 超过重连次数
|
||||||
|
// self.errCount--; // 重连次数减1
|
||||||
|
if (this.errTime) {
|
||||||
|
const nowTime = Date.now();
|
||||||
|
const bool = nowTime - this.errTime < 1000 // 1s内zhi间内不重连
|
||||||
|
if (bool) return; // 1s内不重连
|
||||||
|
}
|
||||||
|
this.errTime = Date.now();
|
||||||
|
// 延时5s 后重连
|
||||||
|
console.log('重连中...')
|
||||||
|
this.sleep(5000).then(_ => {this.reconnect()})
|
||||||
|
}
|
||||||
|
// 发送消息
|
||||||
|
send(msg) {
|
||||||
|
if (!msg) throw new Error("msg is not null")
|
||||||
|
if (!this.ws) throw new Error("ws is not null")
|
||||||
|
if (typeof msg === "object") msg = JSON.stringify(msg)
|
||||||
|
if (!msg.includes('"msg":')) throw new Error("msg 格式错误请重试")
|
||||||
|
this.ws.send(msg)
|
||||||
|
}
|
||||||
|
// 发送消息-带消息头(key)
|
||||||
|
sendMsg(head, content, option = {}) {
|
||||||
|
if (!head) throw new Error("head is not null")
|
||||||
|
if (!content) throw new Error("content is not null")
|
||||||
|
let msg = { head, content, ...option }
|
||||||
|
// 发送消息
|
||||||
|
this.send(this.getMsgObj(msg))
|
||||||
|
}
|
||||||
|
// 发送心跳
|
||||||
|
sendMsgBeat() {
|
||||||
|
// this.send(this.getMsgObj('ping', this.TYPES.beat))
|
||||||
|
this.ws.send('ping')
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 获取消息对象
|
||||||
|
* @param {*} msg 消息内容
|
||||||
|
* @param {*} chatType 群发 group| 单发 single| 心态 heart_beat
|
||||||
|
* @param {*} id 群聊id || 单聊id-用户id(userId)
|
||||||
|
*/
|
||||||
|
getMsgObj(msg, chatType = 'group', id) {
|
||||||
|
if (typeof msg === "object") msg = JSON.stringify(msg)
|
||||||
|
const res = {msg, chatType}
|
||||||
|
// if (!id) throw new Error(`${type=='group'?'群ID':'用户ID'} is not null`)
|
||||||
|
if (chatType == 'group') res.groupId = id || this.id || ''
|
||||||
|
else if (chatType == 'single') res.to = id || this.id || ''
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
// 监听
|
||||||
|
watch(callback) {
|
||||||
|
callback && (this.onmessage = callback);
|
||||||
|
}
|
||||||
|
// 关闭链接
|
||||||
|
close() {
|
||||||
|
this.closed = true;
|
||||||
|
this.ws.close();
|
||||||
|
}
|
||||||
|
// 延时 ms 毫秒
|
||||||
|
sleep(ms){
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 连接socket
|
||||||
|
export const connect = () => new ChatWs()
|
||||||
|
// 默认实例
|
||||||
|
export default new ChatWs()
|
|
@ -258,16 +258,45 @@ export const getFileName = (filename) => {
|
||||||
return filename.replace(/\.[^/.]+$/, "");
|
return filename.replace(/\.[^/.]+$/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除当前选中的教材 章节 相关信息
|
|
||||||
export const clearBookInfo = () =>{
|
/**
|
||||||
//当前选中的教材
|
* 根据图片的url转换对应的base64值
|
||||||
localStorage.removeItem('curBook')
|
* @param { String } url 如:http://xxxx/xxx.png
|
||||||
// 当前选中的节点
|
* @returns base64取值
|
||||||
localStorage.removeItem('curNode')
|
*/
|
||||||
// 所有章节单元数据
|
export const urlToBase64 = (url) => {
|
||||||
localStorage.removeItem('unitList')
|
|
||||||
// 所有教材数据
|
return new Promise((resolve, reject) => {
|
||||||
localStorage.removeItem('subjectList')
|
if (!url) {
|
||||||
// 展开的节点
|
reject('请传入url内容')
|
||||||
localStorage.removeItem('defaultExpandedKeys')
|
}
|
||||||
|
if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(url)) {
|
||||||
|
// 图片地址
|
||||||
|
let image = new Image()
|
||||||
|
// 设置跨域问题
|
||||||
|
image.setAttribute('crossOrigin', 'anonymous')
|
||||||
|
// 图片地址
|
||||||
|
image.src = url +"?v=" + Math.random(); // 处理缓存,fix缓存bug,有缓存,浏览器会报错;
|
||||||
|
image.onload = () => {
|
||||||
|
let canvas = document.createElement('canvas')
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
canvas.width = image.width
|
||||||
|
canvas.height = image.height
|
||||||
|
ctx.drawImage(image, 0, 0, image.width, image.height)
|
||||||
|
|
||||||
|
// 获取图片后缀
|
||||||
|
const ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase()
|
||||||
|
// 转base64
|
||||||
|
const dataUrl = canvas.toDataURL(`image/${ext}`)
|
||||||
|
resolve(dataUrl || '')
|
||||||
|
canvas = null // 清除canvas元素
|
||||||
|
image = null // 清除img元素
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非图片地址
|
||||||
|
reject('非(png/jpe?g/gif/svg等)图片地址');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -208,6 +208,10 @@ export const createWindow = async (type, data) => {
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
}
|
}
|
||||||
|
// pptlist的时候可以选择最大化
|
||||||
|
if (data.url == '/pptist'){
|
||||||
|
defOption.maximizable = true;
|
||||||
|
}
|
||||||
data.isConsole = true // 是否开启控制台
|
data.isConsole = true // 是否开启控制台
|
||||||
data.option = {...defOption, ...option}
|
data.option = {...defOption, ...option}
|
||||||
const win = await toolWindow(type, data)
|
const win = await toolWindow(type, data)
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watch, reactive, getCurrentInstance, nextTick } from 'vue'
|
import { onMounted, ref, watch, reactive, getCurrentInstance, nextTick, defineEmits } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { Plus, Delete } from '@element-plus/icons-vue'
|
import { Plus, Delete } from '@element-plus/icons-vue'
|
||||||
|
@ -156,6 +156,7 @@ const { proxy } = getCurrentInstance()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentCourse: Object,
|
currentCourse: Object,
|
||||||
})
|
})
|
||||||
|
const emits = defineEmits(['getData'])
|
||||||
const isShow = ref(false)
|
const isShow = ref(false)
|
||||||
|
|
||||||
const propsQueryCourseObj = route.query.courseObj;//作业布置的内容对象
|
const propsQueryCourseObj = route.query.courseObj;//作业布置的内容对象
|
||||||
|
@ -460,10 +461,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
await nextTick(); // 确保DOM更新完成
|
await nextTick(); // 确保DOM更新完成
|
||||||
proxy.$refs["classWorkFormRef"].validate(async valid => {
|
proxy.$refs["classWorkFormRef"].validate(async valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
//
|
|
||||||
// const { chapterId } = await useGetHomework(courseObj.node)
|
// const { chapterId } = await useGetHomework(courseObj.node)
|
||||||
// this.entpcourseid = chapterId
|
// this.entpcourseid = chapterId
|
||||||
|
|
||||||
const cform = {
|
const cform = {
|
||||||
id: 0,
|
id: 0,
|
||||||
workdate: classWorkForm.workdate, // //作业类型?web端这里貌似没有这个时间
|
workdate: classWorkForm.workdate, // //作业类型?web端这里貌似没有这个时间
|
||||||
|
@ -507,7 +506,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
|
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
|
||||||
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
|
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
|
||||||
try {
|
try {
|
||||||
addClassworkReturnId(cform).then(() => {
|
addClassworkReturnId(cform).then((res) => {
|
||||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||||
// 重置提交表单
|
// 重置提交表单
|
||||||
classWorkForm.worktype = "课堂展示";
|
classWorkForm.worktype = "课堂展示";
|
||||||
|
@ -519,7 +518,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
// 情况选择的资源缓存
|
// 情况选择的资源缓存
|
||||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
|
classWorkForm.id = res
|
||||||
|
emits('getData',classWorkForm)
|
||||||
boardLoading.value = false
|
boardLoading.value = false
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -531,7 +531,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
||||||
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
|
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
|
||||||
try {
|
try {
|
||||||
addClassworkReturnId(cform).then(() => {
|
addClassworkReturnId(cform).then((res) => {
|
||||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||||
// 重置提交表单
|
// 重置提交表单
|
||||||
classWorkForm.worktype = "常规作业";
|
classWorkForm.worktype = "常规作业";
|
||||||
|
@ -543,7 +543,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
classWorkForm.fileHomeworkList = []; // 常规作业list
|
classWorkForm.fileHomeworkList = []; // 常规作业list
|
||||||
|
classWorkForm.id = res
|
||||||
|
emits('getData',classWorkForm)
|
||||||
fileLoading.value = false
|
fileLoading.value = false
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -574,7 +575,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
console.log(cform,'提交的数据');
|
console.log(cform,'提交的数据');
|
||||||
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
|
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
|
||||||
|
|
||||||
addClassworkReturnId(cform).then(workres => {
|
addClassworkReturnId(cform).then(res => {
|
||||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||||
// 重置提交表单
|
// 重置提交表单
|
||||||
classWorkForm.worktype = "习题训练";
|
classWorkForm.worktype = "习题训练";
|
||||||
|
@ -585,6 +586,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
// 情况选择的资源缓存
|
// 情况选择的资源缓存
|
||||||
classWorkForm.chooseWorkLists = [];
|
classWorkForm.chooseWorkLists = [];
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
|
classWorkForm.id = res
|
||||||
|
emits('getData',classWorkForm)
|
||||||
// refresh the list
|
// refresh the list
|
||||||
//这里分离了,所以不需要更新表单数据了
|
//这里分离了,所以不需要更新表单数据了
|
||||||
// this.getClassWorkAllList();
|
// this.getClassWorkAllList();
|
||||||
|
@ -604,6 +607,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
// // 首页进入的,跳转到作业布置页面
|
// // 首页进入的,跳转到作业布置页面
|
||||||
// router.push({ path: '/classTaskAssign' });
|
// router.push({ path: '/classTaskAssign' });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
<el-form-item label="年份" label-width="70">
|
<el-form-item label="年份" label-width="70">
|
||||||
<el-select v-model="entpCourseWorkQueryParams.yearStr" placeholder="请选择" >
|
<el-select v-model="entpCourseWorkQueryParams.yearStr" placeholder="请选择">
|
||||||
<el-option v-for="(item, index) in entpCourseWorkYearList" :key="index" :label="item.label" :value="item.value"></el-option>
|
<el-option v-for="(item, index) in entpCourseWorkYearList" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -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,6 +118,7 @@
|
||||||
import { Search } from '@element-plus/icons-vue'
|
import { Search } from '@element-plus/icons-vue'
|
||||||
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import html2canvas from 'html2canvas';
|
||||||
|
|
||||||
import { listEntpcoursework, listEntpcourseworkLocal } from '@/api/education/entpCourseWork'
|
import { listEntpcoursework, listEntpcourseworkLocal } from '@/api/education/entpCourseWork'
|
||||||
import { listEvaluationclue } from '@/api/classTask'
|
import { listEvaluationclue } from '@/api/classTask'
|
||||||
|
@ -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'});
|
||||||
|
@ -440,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 => {
|
||||||
|
// 将canvas转换为图像URL
|
||||||
|
const screenshotUrl = canvas.toDataURL('image/png');
|
||||||
|
// 在这里可以将截图保存到本地或上传到服务器
|
||||||
|
// console.log(screenshotUrl);
|
||||||
|
emit('addQuizImgBs64', screenshotUrl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 防抖
|
// 防抖
|
||||||
const debounceQueryData = debounce(() => {
|
const debounceQueryData = debounce(() => {
|
||||||
console.log("防抖 加载数据中...")
|
console.log("防抖 加载数据中...")
|
||||||
|
|
|
@ -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: 100%;
|
||||||
|
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>
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<!-- 习题筛选1 -->
|
<!-- 习题筛选1 -->
|
||||||
<el-row style="width: 100%; height: 50px;">
|
<el-row style="width: 100%; height: 50px;">
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
<div class="page-table" >
|
<div class="page-table" >
|
||||||
<el-table
|
<el-table
|
||||||
:data="workResource.entpCourseWorkList"
|
:data="workResource.entpCourseWorkList"
|
||||||
style="width: 100%; height: calc(100% - 55px);"
|
style="width: 100%; height: calc(100% - 50px);"
|
||||||
v-loading="pageParams.loading"
|
v-loading="pageParams.loading"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" width="60" />
|
<el-table-column type="index" width="60" />
|
||||||
|
@ -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,18 +83,19 @@
|
||||||
</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>
|
||||||
<!-- 分页-->
|
<!-- 分页-->
|
||||||
<div style="height: 55px;">
|
<div style="height: 50px;">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-show="pageParams.total > 0"
|
v-show="pageParams.total > 0"
|
||||||
v-model:page="paginationParams.pageNum"
|
v-model:page="paginationParams.pageNum"
|
||||||
v-model:limit="paginationParams.pageSize"
|
v-model:limit="paginationParams.pageSize"
|
||||||
:total="pageParams.total"
|
:total="pageParams.total"
|
||||||
:style="{ position: 'relative', 'margin-top': '5px' }"
|
:style="{ position: 'relative', 'padding-top': '10px' }"
|
||||||
@change="getPaginationList" />
|
@change="getPaginationList" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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([
|
||||||
|
@ -183,6 +188,7 @@ const workResource = reactive({
|
||||||
}); // 作业资源
|
}); // 作业资源
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
console.log('entpCourseWorkTypeList', entpCourseWorkTypeList);
|
||||||
debounceQueryData(); // 查询习题列表
|
debounceQueryData(); // 查询习题列表
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -427,6 +433,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 => {
|
||||||
|
// 将canvas转换为图像URL
|
||||||
|
const screenshotUrl = canvas.toDataURL('image/png');
|
||||||
|
// 在这里可以将截图保存到本地或上传到服务器
|
||||||
|
// console.log(screenshotUrl);
|
||||||
|
emit('addQuizImgBs64', screenshotUrl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 防抖
|
// 防抖
|
||||||
|
|
|
@ -16,6 +16,16 @@
|
||||||
<el-table-column align="center" prop="worktype" width="100"></el-table-column>
|
<el-table-column align="center" prop="worktype" width="100"></el-table-column>
|
||||||
<el-table-column align="center" prop="worktag" width="120"></el-table-column>
|
<el-table-column align="center" prop="worktag" width="120"></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<!-- 分页-->
|
||||||
|
<div style="height: 48px;">
|
||||||
|
<el-pagination
|
||||||
|
v-show="paginationParams.total > 0"
|
||||||
|
v-model:page="paginationParams.pageNum"
|
||||||
|
v-model:limit="paginationParams.pageSize"
|
||||||
|
:total="paginationParams.total"
|
||||||
|
:style="{ position: 'relative', 'padding': '8px 20px 0 0' }"
|
||||||
|
@change="changePageNum" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 试题详细信息 -->
|
<!-- 试题详细信息 -->
|
||||||
<examDetailsDrawer ref="examDetailsDrawerRef"></examDetailsDrawer>
|
<examDetailsDrawer ref="examDetailsDrawerRef"></examDetailsDrawer>
|
||||||
|
@ -54,11 +64,13 @@ const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
listExamQuestion: {type: Array},
|
listExamQuestion: {type: Array},
|
||||||
loading: {type: Boolean}
|
loading: {type: Boolean},
|
||||||
|
paginationParams: {type: Object},
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeExamInfoDrawer = ref(false);
|
const activeExamInfoDrawer = ref(false);
|
||||||
const activeExam = ref({});
|
const activeExam = ref({});
|
||||||
|
const emit = defineEmits(['updatePageNum'])
|
||||||
|
|
||||||
const showExamAnalyseDrawer = (row) => {
|
const showExamAnalyseDrawer = (row) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
@ -69,13 +81,17 @@ const showExamAnalyseDrawer = (row) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changePageNum = (pageNum) => {
|
||||||
|
emit('updatePageNum', pageNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.table-main {
|
.table-main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: calc(100% - 48px);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
|
|
|
@ -47,10 +47,13 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :style="{'width': (viewportWidth - 400) + 'px','height': (viewportHeight-38) + 'px','overflow-y': 'auto'}">
|
<!-- <div :style="{'width': (viewportWidth - 400) + 'px','height': (viewportHeight-38) + 'px','overflow-y': 'auto'}"> -->
|
||||||
|
<div style="width: 100%; height: 100%; overflow-y: auto; border-radius: 10px;">
|
||||||
<examReview
|
<examReview
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:listExamQuestion="listExamQuestion"
|
:listExamQuestion="listExamQuestion"
|
||||||
|
:paginationParams="paginationParams"
|
||||||
|
@updatePageNum="updatePageNum"
|
||||||
v-if="curTask.viewkey=='真题回顾' "
|
v-if="curTask.viewkey=='真题回顾' "
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -77,12 +80,15 @@ import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import {listEntpcoursework, listEntpcourseworkNew} from '@/api/education/entpCourseWork'
|
import {listEntpcoursework, listEntpcourseworkNew} from '@/api/education/entpCourseWork'
|
||||||
import { processList } from '@/hooks/useProcessList'
|
import { processList } from '@/hooks/useProcessList'
|
||||||
import { JYApiListCT} from "@/utils/examQuestion/jyeoo"
|
import { JYApiListCT} from "@/utils/examQuestion/jyeoo"
|
||||||
|
import useClassTaskStore from '@/store/modules/classTask'
|
||||||
|
|
||||||
import examReview from './container/examReview.vue'
|
import examReview from './container/examReview.vue'
|
||||||
import pointAnalysis from './container/pointAnalysis.vue'
|
import pointAnalysis from './container/pointAnalysis.vue'
|
||||||
import examMocks from './container/examMocks.vue'
|
import examMocks from './container/examMocks.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const classTaskStore = useClassTaskStore();
|
||||||
|
|
||||||
const {proxy} = getCurrentInstance();
|
const {proxy} = getCurrentInstance();
|
||||||
const sourceStore = useResoureStore();
|
const sourceStore = useResoureStore();
|
||||||
const viewportHeight = ref(0);
|
const viewportHeight = ref(0);
|
||||||
|
@ -91,6 +97,11 @@ const viewportWidth = ref(0);
|
||||||
const curNode = ref({});
|
const curNode = ref({});
|
||||||
// 试题集合
|
// 试题集合
|
||||||
const listExamQuestion = ref([]);
|
const listExamQuestion = ref([]);
|
||||||
|
const paginationParams = reactive({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const curTask = reactive({
|
const curTask = reactive({
|
||||||
viewkey: '真题回顾',
|
viewkey: '真题回顾',
|
||||||
|
@ -107,6 +118,22 @@ const listWorkType = ref([{
|
||||||
value: 0,
|
value: 0,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: 翻页
|
||||||
|
* @return: {*}
|
||||||
|
* @param {*} pageNum
|
||||||
|
*/
|
||||||
|
const updatePageNum = (pageNum) => {
|
||||||
|
paginationParams.pageNum = pageNum;
|
||||||
|
queryExamQuestionByParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @desc: 具体获取试题及格式化
|
||||||
|
* @return: {*}
|
||||||
|
* @param {*} params
|
||||||
|
*/
|
||||||
const getCourseWorkList = async (params) => {
|
const getCourseWorkList = async (params) => {
|
||||||
const res = await listEntpcourseworkNew(params);
|
const res = await listEntpcourseworkNew(params);
|
||||||
if(res.data == null) {
|
if(res.data == null) {
|
||||||
|
@ -115,7 +142,14 @@ const getCourseWorkList = async (params) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
listExamQuestion.value = res.data;
|
listExamQuestion.value = res.data;
|
||||||
// queryParams.total = res.total;
|
// 判断获取到的总数
|
||||||
|
const total = parseInt(res.msg)
|
||||||
|
if (!isNaN(total)) {
|
||||||
|
paginationParams.total = total;
|
||||||
|
} else {
|
||||||
|
console.error('无法将 res.msg 转换为数字');
|
||||||
|
paginationParams.total = 0; // 重新设置默认值
|
||||||
|
}
|
||||||
// 格式化试题
|
// 格式化试题
|
||||||
processList(listExamQuestion.value);
|
processList(listExamQuestion.value);
|
||||||
}
|
}
|
||||||
|
@ -132,7 +166,8 @@ const getData = async (data) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
// 1.获取题型
|
// 1.获取题型
|
||||||
getWorkType(data.node);
|
//getWorkType(data.node);
|
||||||
|
listWorkType.value = classTaskStore.entpCourseWorkTypeList;
|
||||||
|
|
||||||
// 2.获取试题集合
|
// 2.获取试题集合
|
||||||
curNode.value = data.node;
|
curNode.value = data.node;
|
||||||
|
@ -166,6 +201,8 @@ const getData = async (data) => {
|
||||||
edusubject: curNode.value.edusubject,
|
edusubject: curNode.value.edusubject,
|
||||||
edustage: curNode.value.edustage,
|
edustage: curNode.value.edustage,
|
||||||
sectionName: curNode.value.itemtitle,
|
sectionName: curNode.value.itemtitle,
|
||||||
|
currentPage: paginationParams.pageNum,
|
||||||
|
pageSize: paginationParams.pageSize,
|
||||||
}
|
}
|
||||||
await getCourseWorkList(params);
|
await getCourseWorkList(params);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -181,6 +218,7 @@ const changeTaskView = (item, key) => {
|
||||||
curTask.viewkey = item;
|
curTask.viewkey = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 目前暂不使用, 题型已通过classTaskStore获取
|
||||||
const getWorkType = async (data) => {
|
const getWorkType = async (data) => {
|
||||||
const selName = `${data.edustage}${data.edusubject}`
|
const selName = `${data.edustage}${data.edusubject}`
|
||||||
const curName = `${curNode.value.edustage}${curNode.value.edusubject}`
|
const curName = `${curNode.value.edustage}${curNode.value.edusubject}`
|
||||||
|
@ -231,6 +269,8 @@ const queryExamQuestionByParams = async () => {
|
||||||
edusubject: curNode.value.edusubject,
|
edusubject: curNode.value.edusubject,
|
||||||
edustage: curNode.value.edustage,
|
edustage: curNode.value.edustage,
|
||||||
sectionName: curNode.value.itemtitle,
|
sectionName: curNode.value.itemtitle,
|
||||||
|
currentPage: paginationParams.pageNum,
|
||||||
|
pageSize: paginationParams.pageSize,
|
||||||
}
|
}
|
||||||
await getCourseWorkList(params);
|
await getCourseWorkList(params);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
|
@ -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,20 @@ const activeIndex = ref(0)
|
||||||
const dataset_id = ref('')
|
const dataset_id = ref('')
|
||||||
|
|
||||||
// 上传成功
|
// 上传成功
|
||||||
const onSuccess = async (response) =>{
|
const onSuccess = async (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 +155,29 @@ 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) => {
|
||||||
|
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 +187,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 +223,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 +236,10 @@ onMounted(() =>{
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #E0EAFF;
|
background: #E0EAFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover .prev-btn {
|
||||||
|
transform: translate(-50%, -50%)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.li-active {
|
.li-active {
|
||||||
|
@ -212,9 +249,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>
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<el-button type="primary" @click="onchange('/model/newClassTaskAssign')">作业管理</el-button>
|
<el-button type="primary" @click="onchange('/model/newClassTaskAssign')">作业管理</el-button>
|
||||||
<el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button>
|
<el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button>
|
||||||
<el-button type="info" @click="onchange('/model/design')">教学框架设计</el-button>
|
<el-button type="info" @click="onchange('/model/design')">教学框架设计</el-button>
|
||||||
<el-button type="success" @click="openPPTist">打开PPTist</el-button>
|
<!-- <el-button type="success" @click="openPPTist">打开PPTist</el-button>-->
|
||||||
<el-button type="info" @click="onchange('/model/examination')">考试分析</el-button>
|
<el-button type="info" @click="onchange('/model/examination')">考试分析</el-button>
|
||||||
<el-button type="primary" v-menus="dt.menus">测试</el-button>
|
<el-button type="primary" v-menus="dt.menus">测试</el-button>
|
||||||
<el-button type="success" @click="onchange('/model/aiKolors')">文生图片</el-button>
|
<el-button type="success" @click="onchange('/model/aiKolors')">文生图片</el-button>
|
||||||
|
@ -52,7 +52,7 @@ 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_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
|
||||||
|
@ -61,7 +61,6 @@ import { sessionStore } from '@/utils/store' // 学科名字文生图
|
||||||
// 组件引入
|
// 组件引入
|
||||||
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import { menusEvent } from '@/plugins/vue3-menus' // 右键菜单
|
import { menusEvent } from '@/plugins/vue3-menus' // 右键菜单
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore() // 用户信息
|
const userStore = useUserStore() // 用户信息
|
||||||
|
|
||||||
|
@ -243,7 +242,7 @@ const HTTP_SERVER_API = (type, params = {}) => {
|
||||||
ppttype: 'file',
|
ppttype: 'file',
|
||||||
title: enpt.coursetitle,
|
title: enpt.coursetitle,
|
||||||
fileurl: '',
|
fileurl: '',
|
||||||
filetype: 'aptist',
|
filetype: 'aippt',
|
||||||
datacontent: '',
|
datacontent: '',
|
||||||
filekey: '',
|
filekey: '',
|
||||||
filetag: '',
|
filetag: '',
|
||||||
|
@ -302,7 +301,7 @@ const handleAll = async(type, row) =>{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'open': { // 打开资源-pptist
|
case 'open': { // 打开资源-pptist
|
||||||
if (row.filetype != 'aptist') return msgUtils.msgWarning('暂不支持该类型文件操作!')
|
if (row.filetype != 'aippt') return msgUtils.msgWarning('暂不支持该类型文件操作!')
|
||||||
sessionStore.set('curr.resource', row) // 缓存当前资源信息
|
sessionStore.set('curr.resource', row) // 缓存当前资源信息
|
||||||
createWindow('open-win', {
|
createWindow('open-win', {
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
|
@ -327,7 +326,7 @@ const handleAll = async(type, row) =>{
|
||||||
// icons 处理 type 代表传递svg
|
// icons 处理 type 代表传递svg
|
||||||
const getIcon = (o, type) => {
|
const getIcon = (o, type) => {
|
||||||
let icon = typeof o == 'string' ? o : o?.filetype
|
let icon = typeof o == 'string' ? o : o?.filetype
|
||||||
if (['aptist'].includes(o?.filetype)) icon = 'pptx'
|
if (['aippt'].includes(o?.filetype)) icon = 'pptx'
|
||||||
if (!!type) { // 其他格式icon
|
if (!!type) { // 其他格式icon
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 'svg': // 返回svg格式
|
case 'svg': // 返回svg格式
|
||||||
|
@ -372,7 +371,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;
|
||||||
|
@ -387,4 +386,4 @@ const getIcon = (o, type) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -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*100/response?.totalPages);
|
||||||
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;
|
|
||||||
//发消息到主进程,携带名称和URL,将URL下载下来后复制到文件列表并上传到服务
|
|
||||||
// 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;
|
||||||
|
@ -265,7 +267,6 @@ function webSocketSend(ws, data) {
|
||||||
|
|
||||||
function result1(resultData) {
|
function result1(resultData) {
|
||||||
let jsonData = JSON.parse(resultData);
|
let jsonData = JSON.parse(resultData);
|
||||||
console.log(jsonData)
|
|
||||||
outputText.value += jsonData.payload.choices.text[0].content;
|
outputText.value += jsonData.payload.choices.text[0].content;
|
||||||
const div = document.querySelector('.paragraphs');
|
const div = document.querySelector('.paragraphs');
|
||||||
if (div) {
|
if (div) {
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- im-chat 聊天组件 -->
|
<!-- im-chat 聊天组件 -->
|
||||||
<im-chat ref="imChatRef" v-if="visible" @change="chatChange" />
|
<!-- <im-chat ref="imChatRef" v-if="visible" @change="chatChange" /> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -90,7 +90,7 @@ import vueQr from 'vue-qr/src/packages/vue-qr.vue' // 插件: 二维码
|
||||||
import imChat from '@/views/tool/components/imChat.vue' // im-chat-子组件
|
import imChat from '@/views/tool/components/imChat.vue' // im-chat-子组件
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息头-相关定义(nuem)
|
import MsgEnum from '@/plugins/imChat/msgEnum' // 消息头-相关定义(nuem)
|
||||||
import * as commUtil from '@/utils/comm' // 工具类-通用
|
import * as commUtil from '@/utils/comm' // 工具类-通用
|
||||||
import { toLinkWeb, getStaticUrl } from '@/utils/tool' // 工具类-主进程相关
|
import { toLinkWeb, createWindow, getStaticUrl, sessionStore } from '@/utils/tool' // 工具类-主进程相关
|
||||||
|
|
||||||
import * as Http_ClassManage from '@/api/classManage' // api接口
|
import * as Http_ClassManage from '@/api/classManage' // api接口
|
||||||
import * as Http_Classcourse from '@/api/teaching/classcourse' // api接口
|
import * as Http_Classcourse from '@/api/teaching/classcourse' // api接口
|
||||||
|
@ -103,7 +103,7 @@ let baseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const visible = ref(false) // 是否打开窗口
|
const visible = ref(false) // 是否打开窗口
|
||||||
const myClassActive = ref({}) // 我的课件:准备上课的APT课件
|
const myClassActive = ref({}) // 我的课件:准备上课的APT课件
|
||||||
const imChatRef = ref(null) // im-chat ref
|
// const imChatRef = ref(null) // im-chat ref
|
||||||
const emit = defineEmits(['close'])
|
const emit = defineEmits(['close'])
|
||||||
const classForm = reactive({ // 班级(左侧):表单数据 表单配置
|
const classForm = reactive({ // 班级(左侧):表单数据 表单配置
|
||||||
form: {}, itemOption: [], option: {}
|
form: {}, itemOption: [], option: {}
|
||||||
|
@ -177,7 +177,7 @@ const initData = () => {
|
||||||
teacherForm.itemOption = [
|
teacherForm.itemOption = [
|
||||||
// { label: '班级', prop: 'classid' },
|
// { label: '班级', prop: 'classid' },
|
||||||
// { label: '上课', prop: 'classcourseid' },
|
// { label: '上课', prop: 'classcourseid' },
|
||||||
{ label: '老师扫码', prop: 'qrUrl', show: false },
|
// { label: '老师扫码', prop: 'qrUrl', show: false },
|
||||||
{ label: '手机登录', prop: 'mobile', show: false },
|
{ label: '手机登录', prop: 'mobile', show: false },
|
||||||
{ label: '故障备用', prop: 'backup', show: false },
|
{ label: '故障备用', prop: 'backup', show: false },
|
||||||
]
|
]
|
||||||
|
@ -257,18 +257,22 @@ const createClasscourse = async () => {
|
||||||
entpcourseid, evalid, coursetitle,
|
entpcourseid, evalid, coursetitle,
|
||||||
plandate: curDate, opendate: curDate
|
plandate: curDate, opendate: curDate
|
||||||
}
|
}
|
||||||
|
// teacherForm.form.classcourseid = 100
|
||||||
teacherForm.form.classcourseid = await Http_Classcourse.addClasscourseReturnId(params)
|
teacherForm.form.classcourseid = await Http_Classcourse.addClasscourseReturnId(params)
|
||||||
dt.loading = false
|
dt.loading = false
|
||||||
// getClasscourseList('update') // 更新列表
|
// getClasscourseList('update') // 更新列表
|
||||||
ElMessage.success('创建课程-成功')
|
let msgEl = ElMessage.success('创建课程-成功')
|
||||||
// 新版-pptList 打开公屏
|
// 新版-pptList 打开公屏
|
||||||
if (myClassActive.value.filetype == 'aptist') {
|
if (myClassActive.value.filetype == 'aippt') {
|
||||||
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
msgEl.close()
|
msgEl.close()
|
||||||
const classcourse = {...params, id: teacherForm.form.classcourseid}
|
msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
||||||
openPublicScreen(classcourse)
|
setTimeout(() => {
|
||||||
}, 1500);
|
msgEl.close()
|
||||||
|
const classcourse = {...params, id: teacherForm.form.classcourseid}
|
||||||
|
openPublicScreen(classcourse)
|
||||||
|
}, 2000);
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 删除课程
|
// 删除课程
|
||||||
|
@ -296,14 +300,23 @@ const removeClasscourse = async () => {
|
||||||
const classTeachingStart = async () => {
|
const classTeachingStart = async () => {
|
||||||
const { classcourseid:id } = teacherForm.form
|
const { classcourseid:id } = teacherForm.form
|
||||||
if (id) { // 开始上课
|
if (id) { // 开始上课
|
||||||
const url = `/teaching/classteaching?classcourseid=${id}&actor=classTeachingOnPublicScreen`
|
// 新版-pptList 打开公屏
|
||||||
toLinkWeb(url) // 跳转web-公屏
|
if (myClassActive.value.filetype == 'aptist') {
|
||||||
visible.value = false // 关闭弹窗
|
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
||||||
handleClose() // 关闭im-chat
|
setTimeout(() => {
|
||||||
|
msgEl.close()
|
||||||
|
openPublicScreen({id})
|
||||||
|
}, 2000);
|
||||||
|
}else {
|
||||||
|
const url = `/teaching/classteaching?classcourseid=${id}&actor=classTeachingOnPublicScreen`
|
||||||
|
toLinkWeb(url) // 跳转web-公屏
|
||||||
|
visible.value = false // 关闭弹窗
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 获取二维码地址
|
// 获取二维码地址
|
||||||
const getQrUrl = async() => {
|
const getQrUrl = async() => {
|
||||||
|
// console.log('获取二维码地址')
|
||||||
const { classcourseid:id } = teacherForm.form
|
const { classcourseid:id } = teacherForm.form
|
||||||
const { userName, userId } = userStore.user
|
const { userName, userId } = userStore.user
|
||||||
if (!id||!userName) return
|
if (!id||!userName) return
|
||||||
|
@ -336,6 +349,7 @@ const getQrUrl = async() => {
|
||||||
|
|
||||||
// 打开公屏
|
// 打开公屏
|
||||||
const openPublicScreen = (classcourse) => {
|
const openPublicScreen = (classcourse) => {
|
||||||
|
console.log('打开公屏', classcourse)
|
||||||
const resource = toRaw(myClassActive.value)
|
const resource = toRaw(myClassActive.value)
|
||||||
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||||
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
||||||
|
@ -346,6 +360,7 @@ const openPublicScreen = (classcourse) => {
|
||||||
sessionStore.set('curr.classcourse', null) // 清除缓存
|
sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
visible.value = false // 关闭弹窗
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定时器监听
|
// 定时器监听
|
||||||
|
@ -386,12 +401,14 @@ watch(() => classForm.form.classid, (val)=> {
|
||||||
// 监听-课程id
|
// 监听-课程id
|
||||||
watch(() => teacherForm.form.classcourseid, (val) => {
|
watch(() => teacherForm.form.classcourseid, (val) => {
|
||||||
const bool = !!val
|
const bool = !!val
|
||||||
|
const isApt = myClassActive.filetype=='apt'
|
||||||
// 获取选中课程-生成二维码地址
|
// 获取选中课程-生成二维码地址
|
||||||
bool && getQrUrl()
|
isApt && bool && getQrUrl()
|
||||||
// 监听课程id,是否显示功能
|
// 监听课程id,是否显示功能
|
||||||
teacherForm.itemOption.forEach(o => {
|
teacherForm.itemOption.forEach(o => {
|
||||||
// 有课程id,触发
|
// 有课程id,触发
|
||||||
if (['qrUrl','backup'].includes(o.prop)) o.show = bool
|
const arr = isApt ? ['qrUrl','backup'] : ['backup']
|
||||||
|
if (arr.includes(o.prop)) o.show = bool
|
||||||
// 课程id为空,触发
|
// 课程id为空,触发
|
||||||
if (['mobile'].includes(o.prop)) o.show = !bool
|
if (['mobile'].includes(o.prop)) o.show = !bool
|
||||||
})
|
})
|
||||||
|
|
|
@ -332,10 +332,6 @@ export default {
|
||||||
const { id, rootid } = sessionStore.get('subject.curNode')
|
const { id, rootid } = sessionStore.get('subject.curNode')
|
||||||
const path="/teaching/aptindex?id="+items.fileId + "&unitId=" + id + "&bookId=" + rootid;
|
const path="/teaching/aptindex?id="+items.fileId + "&unitId=" + id + "&bookId=" + rootid;
|
||||||
let configObj = outLink().getBaseData()
|
let configObj = outLink().getBaseData()
|
||||||
configObj.fullPath = 'https://localhost:7860/'
|
|
||||||
configObj.data.url = 'https://localhost:7860/'
|
|
||||||
configObj.data.domain = 'localhost'
|
|
||||||
console.log(configObj)
|
|
||||||
let fullPath = configObj.fullPath + path
|
let fullPath = configObj.fullPath + path
|
||||||
fullPath = fullPath.replaceAll('//', '/')
|
fullPath = fullPath.replaceAll('//', '/')
|
||||||
// 通知主进程
|
// 通知主进程
|
||||||
|
@ -345,7 +341,7 @@ export default {
|
||||||
cookieData: { ...configObj.data }
|
cookieData: { ...configObj.data }
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
} else if(items.fileFlag === 'aptist') { // aptist 被点击 打开PPT-List 课件
|
} else if(items.fileFlag === 'aippt') { // aippt 被点击 打开PPT-List 课件
|
||||||
return this.$emit('change', 'click', items)
|
return this.$emit('change', 'click', items)
|
||||||
}
|
}
|
||||||
if (!items||!items.fileSuffix) return;
|
if (!items||!items.fileSuffix) return;
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -2,8 +2,20 @@
|
||||||
<div v-loading="isLoading" class="page-resource flex">
|
<div v-loading="isLoading" class="page-resource flex">
|
||||||
<ChooseTextbook @node-click="nodeClick" />
|
<ChooseTextbook @node-click="nodeClick" />
|
||||||
<div class="page-center-wrap">
|
<div class="page-center-wrap">
|
||||||
|
<el-dropdown class="prepare-center-dropdown">
|
||||||
|
<el-button type="primary">
|
||||||
|
新建<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click="createAptFile">新建文枢课件</el-dropdown-item>
|
||||||
|
<el-dropdown-item>AI一键生成</el-dropdown-item>
|
||||||
|
<el-dropdown-item>导入PPT</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
<el-tabs v-model="activeAptTab" style="height: 100%;">
|
<el-tabs v-model="activeAptTab" style="height: 100%;">
|
||||||
<el-tab-pane label="教学课件" name="教学课件" class="prepare-center-jxkj">
|
<el-tab-pane label="文枢课件" name="教学课件" class="prepare-center-jxkj">
|
||||||
<div class="prepare-center-header">
|
<div class="prepare-center-header">
|
||||||
<div class="center-create-btn" style="background-color: rgb(64,158,255)" @click="createAptFile">
|
<div class="center-create-btn" style="background-color: rgb(64,158,255)" @click="createAptFile">
|
||||||
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>创建APT</label></div>
|
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>创建APT</label></div>
|
||||||
|
@ -145,7 +157,7 @@
|
||||||
<!-- <button @click="test">test</button> -->
|
<!-- <button @click="test">test</button> -->
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Check,Plus } from '@element-plus/icons-vue'
|
import {Check, Plus, Position} from '@element-plus/icons-vue'
|
||||||
import Reserv from '@/views/prepare/container/reserv.vue'
|
import Reserv from '@/views/prepare/container/reserv.vue'
|
||||||
import { ArrowDown } from '@element-plus/icons-vue'
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
import PptDialog from '@/views/prepare/container/ppt-dialog.vue'
|
import PptDialog from '@/views/prepare/container/ppt-dialog.vue'
|
||||||
|
@ -180,8 +192,11 @@ import ClassReserv from '@/views/classManage/classReserv.vue'
|
||||||
import TreeLog from '@/views/prepare/components/treeLog.vue'
|
import TreeLog from '@/views/prepare/components/treeLog.vue'
|
||||||
import classStart from './container/class-start.vue' // 预备上课
|
import classStart from './container/class-start.vue' // 预备上课
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
||||||
import Chat from '@/utils/chat' // im 登录初始化
|
// import Chat from '@/utils/chat' // im 登录初始化
|
||||||
if (!Chat.imChat) Chat.init()
|
// if (!Chat.imChat) Chat.init()
|
||||||
|
// import ChatWs from '@/plugins/socket'
|
||||||
|
// console.log('xxxx',ChatWs)
|
||||||
|
// ChatWs.watch((data,e) => console.log('ws', data, e))
|
||||||
|
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
@ -253,11 +268,11 @@ export default {
|
||||||
},
|
},
|
||||||
currentKJFileList() {
|
currentKJFileList() {
|
||||||
// return this.currentFileList.filter((item) => item.fileFlag === 'apt' || item.fileFlag === '课件')
|
// return this.currentFileList.filter((item) => item.fileFlag === 'apt' || item.fileFlag === '课件')
|
||||||
return this.currentFileList.filter((item) => ['apt','aptist','课件'].includes(item.fileFlag))
|
return this.currentFileList.filter((item) => ['apt','aippt','课件'].includes(item.fileFlag))
|
||||||
},
|
},
|
||||||
currentSCFileList() {
|
currentSCFileList() {
|
||||||
// return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '课件')
|
// return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '课件')
|
||||||
return this.currentFileList.filter((item) => !['apt','aptist','课件'].includes(item.fileFlag))
|
return this.currentFileList.filter((item) => !['apt','aippt','课件'].includes(item.fileFlag))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -321,7 +336,7 @@ export default {
|
||||||
if(item.fileFlag === 'apt') {
|
if(item.fileFlag === 'apt') {
|
||||||
this.$refs.calssRef.open(item.fileId, classObj)
|
this.$refs.calssRef.open(item.fileId, classObj)
|
||||||
}
|
}
|
||||||
if(item.fileFlag === 'aptist') {
|
if(item.fileFlag === 'aippt') {
|
||||||
this.$refs.calssRef.open(item.fileId, classObj)
|
this.$refs.calssRef.open(item.fileId, classObj)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -378,8 +393,8 @@ export default {
|
||||||
}, 1000)
|
}, 1000)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'click': { // 点击-打开课件-aptist
|
case 'click': { // 点击-打开课件-aippt
|
||||||
if (row.fileFlag === 'aptist' && !!row.fileId) {
|
if (row.fileFlag === 'aippt' && !!row.fileId) {
|
||||||
const res = await getEntpcoursefile(row.fileId)
|
const res = await getEntpcoursefile(row.fileId)
|
||||||
if (res && res.code === 200) {
|
if (res && res.code === 200) {
|
||||||
sessionStore.set('curr.resource', res.data) // 缓存当前资源信息
|
sessionStore.set('curr.resource', res.data) // 缓存当前资源信息
|
||||||
|
@ -461,6 +476,93 @@ export default {
|
||||||
},500)
|
},500)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
createAIPPT() {
|
||||||
|
listEntpcourse({
|
||||||
|
evalid: this.currentNode.id,
|
||||||
|
edituserid: this.userStore.userId,
|
||||||
|
pageSize: 500
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.rows.length <= 0) return
|
||||||
|
let resCourse = response.rows[0]
|
||||||
|
// 添加
|
||||||
|
let form = {
|
||||||
|
parentid: 0,
|
||||||
|
entpid: this.userStore.deptId,
|
||||||
|
entpcourseid: resCourse.id,
|
||||||
|
ppttype: 'file',
|
||||||
|
title: resCourse.coursetitle,
|
||||||
|
fileurl: '',
|
||||||
|
filetype: 'aippt',
|
||||||
|
datacontent: '',
|
||||||
|
filekey: '',
|
||||||
|
filetag: '',
|
||||||
|
fileidx: 0,
|
||||||
|
dflag: 0,
|
||||||
|
status: '',
|
||||||
|
edituserid: this.userStore.userId
|
||||||
|
}
|
||||||
|
addEntpcoursefileReturnId(form).then((slideid) => {
|
||||||
|
let pagearray = []
|
||||||
|
// 公屏
|
||||||
|
pagearray.push({
|
||||||
|
key: '公屏',
|
||||||
|
title: '公屏页',
|
||||||
|
slidedata: {
|
||||||
|
attrs: { width: 1333, height: 749.8125 },
|
||||||
|
className: 'Stage',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
attrs: {},
|
||||||
|
className: 'Layer',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
attrs: {
|
||||||
|
width: 1333,
|
||||||
|
height: 749.8125,
|
||||||
|
fill: 'white',
|
||||||
|
name: 'fixedbackground',
|
||||||
|
listening: true
|
||||||
|
},
|
||||||
|
className: 'Rect'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加
|
||||||
|
var form = {
|
||||||
|
parentid: slideid,
|
||||||
|
entpid: resCourse.entpid,
|
||||||
|
entpcourseid: resCourse.id,
|
||||||
|
ppttype: 'file',
|
||||||
|
title: '第一页',
|
||||||
|
fileurl: '',
|
||||||
|
filetype: 'slide',
|
||||||
|
datacontent: JSON.stringify(pagearray),
|
||||||
|
filekey: '',
|
||||||
|
filetag: '',
|
||||||
|
fileidx: 0,
|
||||||
|
dflag: 0,
|
||||||
|
status: '',
|
||||||
|
edituserid: this.userStore.userId
|
||||||
|
}
|
||||||
|
addEntpcoursefileReturnId(form).then((res) => {
|
||||||
|
creatAPT({
|
||||||
|
...this.uploadData,
|
||||||
|
fileId: slideid,
|
||||||
|
fileShowName: this.currentNode.itemtitle + '.apt'
|
||||||
|
}).then((res) => {
|
||||||
|
this.currentFileList.unshift(res.resData)
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.$refs['kjItemRef'+res.resData.id][0].openFileWin(res.resData);
|
||||||
|
},500)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
createAptFile() {
|
createAptFile() {
|
||||||
listEntpcourse({
|
listEntpcourse({
|
||||||
evalid: this.currentNode.id,
|
evalid: this.currentNode.id,
|
||||||
|
@ -653,7 +755,7 @@ export default {
|
||||||
for (let i = 0; i < this.currentFileList.length; i++) {
|
for (let i = 0; i < this.currentFileList.length; i++) {
|
||||||
let item = this.currentFileList[i]
|
let item = this.currentFileList[i]
|
||||||
if (item.fileFlag === 'apt') continue;
|
if (item.fileFlag === 'apt') continue;
|
||||||
if (item.fileFlag === 'aptist') continue;
|
if (item.fileFlag === 'aippt') continue;
|
||||||
await asyncLocalFile(item)
|
await asyncLocalFile(item)
|
||||||
}
|
}
|
||||||
this.asyncAllFileVisiable = false
|
this.asyncAllFileVisiable = false
|
||||||
|
@ -872,6 +974,13 @@ export default {
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
position: relative;
|
||||||
|
.prepare-center-dropdown{
|
||||||
|
z-index: 9999;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
.prepare-center-jxkj{
|
.prepare-center-jxkj{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -34,7 +34,6 @@ import {getDept } from '@/api/login'
|
||||||
import { listEvaluation } from '@/api/subject/index'
|
import { listEvaluation } from '@/api/subject/index'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import {ElMessage} from 'element-plus'
|
import {ElMessage} from 'element-plus'
|
||||||
import { clearBookInfo } from '@/utils/ruoyi'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import {listClassmain} from '@/api/classManage/index'
|
import {listClassmain} from '@/api/classManage/index'
|
||||||
//班级列表
|
//班级列表
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-dialog v-model="open" v-bind="dAttrs">
|
||||||
|
<el-progress type="dashboard" v-bind="$attrs.pg" />
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
// 功能说明 弹窗进度条组件
|
||||||
|
import { computed, useAttrs } from 'vue'
|
||||||
|
const attrs = useAttrs()
|
||||||
|
const props = defineProps({
|
||||||
|
visible: { // 是否显示弹窗
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// 数据更新
|
||||||
|
const emit = defineEmits(['update:visible'])
|
||||||
|
// 弹窗显示-双向绑定
|
||||||
|
const open = computed({
|
||||||
|
get: () => props.visible,
|
||||||
|
set: val => emit('update:visible', val)
|
||||||
|
})
|
||||||
|
// 弹窗属性
|
||||||
|
const dAttrs = computed(() => {
|
||||||
|
const attrsNew = { ...attrs }
|
||||||
|
delete attrsNew.pg
|
||||||
|
return attrsNew
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -50,6 +50,7 @@
|
||||||
<EditDialog v-model="isEdit" :item="curItem" />
|
<EditDialog v-model="isEdit" :item="curItem" />
|
||||||
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
||||||
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog"/>
|
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog"/>
|
||||||
|
<progress-dialog v-model:visible="pgDialog.visible" v-bind="pgDialog" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -58,6 +59,7 @@ import { sessionStore } from '@/utils/store'
|
||||||
import emitter from '@/utils/mitt'
|
import emitter from '@/utils/mitt'
|
||||||
import EditDialog from './edit-dialog.vue'
|
import EditDialog from './edit-dialog.vue'
|
||||||
import AdjustDialog from './adjust-dialog.vue'
|
import AdjustDialog from './adjust-dialog.vue'
|
||||||
|
import progressDialog from './progress-dialog.vue'
|
||||||
import { completion, tempResult } from '@/api/mode/index.js'
|
import { completion, tempResult } from '@/api/mode/index.js'
|
||||||
// import { dataSetJson } from '@/utils/comm.js'
|
// import { dataSetJson } from '@/utils/comm.js'
|
||||||
import * as commUtils from '@/utils/comm.js'
|
import * as commUtils from '@/utils/comm.js'
|
||||||
|
@ -68,6 +70,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()
|
||||||
|
@ -76,7 +79,22 @@ const resultList = ref([])
|
||||||
const courseObj = reactive({
|
const courseObj = reactive({
|
||||||
node: null, // 选择的课程节点
|
node: null, // 选择的课程节点
|
||||||
})
|
})
|
||||||
|
const pgDialog = reactive({ // 弹窗-进度条
|
||||||
|
visible: false,
|
||||||
|
title: 'PPT解析中...',
|
||||||
|
width: 300,
|
||||||
|
showClose: false,
|
||||||
|
draggable: true,
|
||||||
|
beforeClose: done => {}, // 阻止-弹窗事件
|
||||||
|
pg: { // 进度条-参数
|
||||||
|
percentage: 0, // 百分比
|
||||||
|
color: [
|
||||||
|
{ color: '#1989fa', percentage: 50 }, // 蓝色
|
||||||
|
{ color: '#e6a23c', percentage: 80 }, // 橙色
|
||||||
|
{ color: '#5cb87a', percentage: 100 }, // 绿色
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
emitter.on('changeMode', (item) => {
|
emitter.on('changeMode', (item) => {
|
||||||
console.log(item, 'item')
|
console.log(item, 'item')
|
||||||
resultList.value = item.child
|
resultList.value = item.child
|
||||||
|
@ -113,7 +131,10 @@ const params = reactive(
|
||||||
|
|
||||||
const addAiPPT = async(res) => {
|
const addAiPPT = async(res) => {
|
||||||
let node = courseObj.node
|
let node = courseObj.node
|
||||||
|
pptDialog.value = false;
|
||||||
if (!node) return msgUtils.msgWarning('请选择章节?')
|
if (!node) return msgUtils.msgWarning('请选择章节?')
|
||||||
|
pgDialog.visible = true
|
||||||
|
pgDialog.pg.percentage = 0
|
||||||
//TODO res中有PPT地址
|
//TODO res中有PPT地址
|
||||||
const params = { evalid: node.id, edituserid: userStore.id, pageSize: 1 }
|
const params = { evalid: node.id, edituserid: userStore.id, pageSize: 1 }
|
||||||
const resEnpt = await HTTP_SERVER_API('getCourseList', params)
|
const resEnpt = await HTTP_SERVER_API('getCourseList', params)
|
||||||
|
@ -128,14 +149,22 @@ const addAiPPT = async(res) => {
|
||||||
const resPptJson = await PPTXFileToJson(buffer)
|
const resPptJson = await PPTXFileToJson(buffer)
|
||||||
const { def, slides, ...content } = resPptJson
|
const { def, slides, ...content } = resPptJson
|
||||||
// 转换图片|音频|视频 为线上地址
|
// 转换图片|音频|视频 为线上地址
|
||||||
|
let completed = 0
|
||||||
|
const total = slides.length
|
||||||
for( let o of slides ) {
|
for( let o of slides ) {
|
||||||
|
completed++
|
||||||
await toRousrceUrl(o)
|
await toRousrceUrl(o)
|
||||||
|
// 设置进度条
|
||||||
|
pgDialog.pg.percentage = Math.floor(completed / total * 100)
|
||||||
}
|
}
|
||||||
// return
|
pgDialog.pg.percentage = 0
|
||||||
|
pgDialog.visible = false
|
||||||
// 生成ppt课件-父级
|
// 生成ppt课件-父级
|
||||||
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 +235,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: 'aippt',
|
||||||
|
fileShowName: node.itemtitle + '.aippt',
|
||||||
|
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('请选择章节?')
|
||||||
|
@ -256,7 +299,7 @@ const getDefParams = (params) => {
|
||||||
ppttype: 'file',
|
ppttype: 'file',
|
||||||
title: enpt.coursetitle,
|
title: enpt.coursetitle,
|
||||||
fileurl: '',
|
fileurl: '',
|
||||||
filetype: 'aptist',
|
filetype: 'aippt',
|
||||||
datacontent: '',
|
datacontent: '',
|
||||||
filekey: '',
|
filekey: '',
|
||||||
filetag: '',
|
filetag: '',
|
||||||
|
@ -298,6 +341,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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue