Compare commits

..

72 Commits

Author SHA1 Message Date
zhangxuelin 2463feb0b7 Merge pull request 'zxl' (#190) from zxl into main
Reviewed-on: #190
2024-12-26 17:25:27 +08:00
zhangxuelin d866f546bc Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-26 16:49:31 +08:00
baigl 991bbd179f Merge pull request 'baigl' (#189) from baigl into main
Reviewed-on: #189
2024-12-26 16:29:10 +08:00
白了个白 bf39850d2f Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-26 16:28:06 +08:00
白了个白 0f51892d96 课堂展示:白板bug修复 2024-12-26 16:27:39 +08:00
zhengdegang 2224de7144 Merge pull request 'zdg_dev' (#188) from zdg_dev into main
Reviewed-on: #188
2024-12-26 16:08:17 +08:00
zdg 14cf608c62 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-26 16:07:34 +08:00
zdg eca310928e 修复模版新增 异常 2024-12-26 16:07:27 +08:00
zhangxuelin 35e63e3587 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-26 15:15:49 +08:00
zhengdegang 52f9a1493d Merge pull request 'zdg_dev' (#187) from zdg_dev into main
Reviewed-on: #187
2024-12-26 15:15:32 +08:00
zdg 0acde1952c Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-26 15:14:28 +08:00
zdg 719693bf63 1.分享邀请码
2.优化ppt上课
2024-12-26 15:14:22 +08:00
zhangxuelin 1999104ee4 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-26 14:49:54 +08:00
zhangxuelin 65643279ce 切换幻灯片关闭弹窗 2024-12-26 14:49:40 +08:00
baigl 53ccb2236e Merge pull request 'baigl' (#185) from baigl into main
Reviewed-on: #185
2024-12-26 14:20:33 +08:00
白了个白 00119e4a49 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-26 14:18:47 +08:00
白了个白 4bbe89ed31 课堂展示:画布选中物品,移除优化 2024-12-26 14:18:12 +08:00
zhangxuelin 49e16c458f Merge pull request '1' (#184) from zxl into main
Reviewed-on: #184
2024-12-26 14:13:31 +08:00
zhangxuelin 5fb447d5e6 1 2024-12-26 14:12:47 +08:00
yangws 9aa17ed786 Merge pull request 'fix:头像的样式问题;' (#183) from yws_dev into main
Reviewed-on: #183
2024-12-26 10:40:29 +08:00
小杨 2a7fbc3577 fix:头像的样式问题; 2024-12-26 10:40:07 +08:00
白了个白 ccbafea3d4 Merge branch 'zouyf_dev' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-26 10:26:19 +08:00
白了个白 1f9111a89d 课堂展示:画布拖选问题修复 2024-12-26 10:25:54 +08:00
“zouyf” be78520410 Merge branch 'main' into zouyf_dev 2024-12-26 10:08:10 +08:00
“zouyf” 4b935b9110 1 2024-12-25 17:30:42 +08:00
zhangxuelin d0cbb5cbcd Merge pull request 'zxl' (#182) from zxl into main
Reviewed-on: #182
2024-12-25 17:30:13 +08:00
zhangxuelin 5686669563 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-25 17:29:43 +08:00
zhangxuelin eb7d6df355 添加推图片上屏 2024-12-25 17:29:34 +08:00
白了个白 1a3598d7c0 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-12-25 17:26:45 +08:00
白了个白 2fdd997c5e 1 2024-12-25 17:26:14 +08:00
lyc 960ab581c3 Merge pull request 'edit' (#181) from lyc-dev into main 2024-12-25 17:25:11 +08:00
“zouyf” 96e01ae711 Merge branch 'main' into zouyf_dev 2024-12-25 17:04:50 +08:00
“zouyf” d8c4876119 [科学实验] - 更新作业学段学科回显 2024-12-25 17:04:29 +08:00
zhangxuelin ae839825d4 Merge pull request 'zxl' (#180) from zxl into main
Reviewed-on: #180
2024-12-25 16:56:38 +08:00
zhangxuelin ef670dee99 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-25 16:55:47 +08:00
朱浩 c81f393715 宫格插件 2024-12-25 14:38:29 +08:00
zhangxuelin 06bb6284c4 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-25 13:39:31 +08:00
朱浩 b5caa7ba80 Merge remote-tracking branch 'origin/main' 2024-12-25 12:04:41 +08:00
朱浩 53ff508635 宫格插件 2024-12-25 12:04:27 +08:00
“zouyf” d9a0f2f8c3 1 2024-12-25 11:20:18 +08:00
“zouyf” 89cba04b8c Merge branch 'main' into zouyf_dev
# Conflicts:
#	src/renderer/src/views/classTask/container/classTask/item-dialog-score.vue
2024-12-25 11:02:19 +08:00
zouyf 9cce9c224c Merge pull request '[作业批改] - 替换自动批改完成' (#179) from zouyf_tmp into main
Reviewed-on: #179
2024-12-25 10:42:58 +08:00
“zouyf” 171dc72ee7 [作业批改] - 替换自动批改完成 2024-12-25 10:33:20 +08:00
zhangxuelin c2750e3da6 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-25 10:27:02 +08:00
zhangxuelin 5550ca570c no message 2024-12-25 10:25:07 +08:00
“zouyf” dd0160865b Merge branch 'main' into zouyf_dev 2024-12-25 10:09:57 +08:00
“zouyf” ff0dd3600c 1 2024-12-25 10:06:03 +08:00
lyc 62a419356c Merge pull request 'edit' (#178) from lyc-dev into main 2024-12-24 17:32:25 +08:00
zhangxuelin ab9bad467a Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl
# Conflicts:
#	src/renderer/src/AixPPTist/src/views/Editor/EditorHeader/index.vue
2024-12-24 16:08:48 +08:00
zhengdegang f63bb69919 Merge pull request 'zdg_dev' (#177) from zdg_dev into main
Reviewed-on: #177
2024-12-24 16:08:38 +08:00
zdg b3ffa9bdaa Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zdg_dev 2024-12-24 16:07:00 +08:00
zdg 5510021566 上课允许不选班级开课 2024-12-24 16:06:53 +08:00
lyc 89e0b2f97c Merge pull request 'edit 框架设计' (#176) from lyc-dev into main 2024-12-24 14:48:25 +08:00
lyc ea0e1c91cf Merge pull request 'lyc-dev' (#175) from lyc-dev into main 2024-12-24 14:38:20 +08:00
zhangxuelin a366d5d4d6 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-12-24 11:24:01 +08:00
zhangxuelin e0ec22c3ac 替换照片改为线上url 2024-12-24 11:23:52 +08:00
“zouyf” 63b8a0d5c6 Merge branch 'main' into zouyf_dev 2024-12-23 15:28:49 +08:00
“zouyf” f6b08169b6 Merge branch 'main' into zouyf_dev 2024-12-23 10:11:48 +08:00
“zouyf” af60c5cc17 Merge branch 'baigl' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zouyf_dev 2024-12-20 14:49:02 +08:00
“zouyf” e67756192a Merge branch 'main' into zouyf_dev 2024-12-20 14:48:30 +08:00
“zouyf” 73d4ee03ba Merge branch 'main' into zouyf_dev 2024-12-20 14:08:27 +08:00
“zouyf” 8863e05a1a Merge branch 'main' into zouyf_dev 2024-12-20 11:18:03 +08:00
“zouyf” debd5e1942 Merge branch 'main' into zouyf_dev 2024-12-20 10:27:19 +08:00
“zouyf” c8b8c21875 Merge branch 'main' into zouyf_dev 2024-12-19 15:51:19 +08:00
“zouyf” c8729a7008 [试题上传] - 兼容优化菁优网题型 2024-12-19 15:51:06 +08:00
“zouyf” 2bdac6e2ea Merge branch 'main' into zouyf_dev 2024-12-18 10:31:46 +08:00
“zouyf” 058509b29c 1 2024-12-18 10:31:20 +08:00
“zouyf” 9a2a55c62b 1 2024-12-16 17:30:00 +08:00
“zouyf” 19efe185c5 Merge branch 'main' into zouyf_dev 2024-12-16 17:14:22 +08:00
“zouyf” 78ecf6ea55 [查询试题] - 单元查询优化 2024-12-16 17:13:56 +08:00
“zouyf” cccf109499 Merge branch 'main' into zouyf_dev 2024-12-13 10:12:14 +08:00
“zouyf” 4a0e9b0b84 批改作业 2024-12-13 10:11:33 +08:00
41 changed files with 761 additions and 282 deletions

View File

@ -17,6 +17,7 @@ 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 地址 # websocket 地址
# VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868' VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865' # VITE_APP_WS_URL = 'ws://192.168.2.16:7865'

View File

@ -1,6 +1,6 @@
{ {
"name": "aix-win-ws", "name": "aix-win-ws",
"version": "2.5.8", "version": "2.5.9",
"description": "", "description": "",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "上海交大重庆人工智能研究院", "author": "上海交大重庆人工智能研究院",

View File

@ -0,0 +1,47 @@
export default class gridPic {
private static Instance: gridPic | null = null;
private gridPicRef: any = null;
constructor(elRef?: any) {
if (elRef) {
this.gridPicRef = elRef;
}
if (!gridPic.Instance) {
gridPic.Instance = this;
}
return gridPic.Instance;
}
// 初始化
init(elRef) {
if (elRef) {
this.gridPicRef = elRef;
}
return this;
}
addPIc(data) {
if (this.gridPicRef && this.gridPicRef.value && typeof this.gridPicRef.value.addPic === 'function') {
this.gridPicRef.value.addPic(data);
}
return this;
}
// 静态方法 - 初始化
static init(elRef) {
if (!gridPic.Instance) {
gridPic.Instance = new gridPic(elRef);
} else {
gridPic.Instance.init(elRef);
}
return gridPic.Instance;
}
// 静态方法 - 打开推图上屏幕
static addPIc(data) {
if (gridPic.Instance) {
return gridPic.Instance.addPIc(data);
}
return null;
}
}

View File

@ -97,14 +97,30 @@ export class PPTApi {
}) })
} }
/**
* @description slide
* @param slides
* @param slideAll
* @returns
*/
static async addSlideServer(slides: object[], slideAll: object[]) {
const resource = sessionStore.get('curr.resource')||{}
for(const slide of slides){
slide.id = resource.id // 覆盖默认随机id
await this.addSlide(slide)
}
await this.batchUpdateSlides(slideAll, true) // 批量更新-排序
return PPTApi.getSlideList(resource.id) // 更新幻灯片列表以及活动相关
}
// 新增幻灯片 // 新增幻灯片
static addSlide(data: object): Promise<Boolean> { static addSlide(data: object): Promise<Boolean> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const enpt = sessionStore.get('curr.entp')||{} const enpt = sessionStore.get('curr.entp')||{}
const resource = sessionStore.get('curr.resource')||{} // const resource = sessionStore.get('curr.resource')||{}
const {id, ...content} = data const {id, ...content} = data
const params = { const params = {
parentid: resource.id, parentid: id,
entpid: userStore.user.deptId, entpid: userStore.user.deptId,
entpcourseid: enpt.id, entpcourseid: enpt.id,
ppttype: 'file', ppttype: 'file',
@ -126,7 +142,7 @@ export class PPTApi {
// msgUtils.msgSuccess('新增成功') // msgUtils.msgSuccess('新增成功')
this.isUpdate = false // 新增后会触发监听,不再更新数据 this.isUpdate = false // 新增后会触发监听,不再更新数据
resolve(true) resolve(true)
} else msgUtils.msgError('新增失败');resolve(false) } else msgUtils.msgError('新增失败');reject(false)
}) })
} }
/** /**
@ -147,12 +163,8 @@ export class PPTApi {
const currInd = toRaw(slidesStore.slideIndex) // 当前页索引-new const currInd = toRaw(slidesStore.slideIndex) // 当前页索引-new
const oldInd = oldData.findIndex(o => o.id == currentSlide.id) // 当前页索引-old const oldInd = oldData.findIndex(o => o.id == currentSlide.id) // 当前页索引-old
const isBatch = oldVal && oldVal.length && currInd != oldInd // 是否批量更新-排序 const isBatch = oldVal && oldVal.length && currInd != oldInd // 是否批量更新-排序
if (isAdd) { // 新增的幻灯片(id 为非数字,说明是新增的幻灯片) if (isAdd) return // 新增-这里不处理 状态管理-处理
const bool = await this.addSlide(currentSlide) // 防抖-更新
bool && await this.batchUpdateSlides(newData, true) // 批量更新-排序
const resource = sessionStore.get('curr.resource')||{}
await PPTApi.getSlideList(resource.id)
} else { // 防抖-更新
if (!this.isUpdate) return this.isUpdate = true // 下次更新数据 if (!this.isUpdate) return this.isUpdate = true // 下次更新数据
if (isBatch) { // 批量更新-排序 if (isBatch) { // 批量更新-排序
this.batchUpdateSlides(newData, true) this.batchUpdateSlides(newData, true)
@ -164,7 +176,6 @@ export class PPTApi {
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2) Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
} }
} }
}
// 更新幻灯片 isThum 是否更新缩略图 // 更新幻灯片 isThum 是否更新缩略图
static updateSlide(data: object, isThum = true): Promise<Boolean> { static updateSlide(data: object, isThum = true): Promise<Boolean> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
@ -274,6 +285,7 @@ export class PPTApi {
static toRousrceUrl =async (o:any) => { static toRousrceUrl =async (o:any) => {
const formData = new FormData() const formData = new FormData()
formData.append('file', o) formData.append('file', o)
formData.append('ral', true)
const res = await Api_server.Other.uploadFile(formData) const res = await Api_server.Other.uploadFile(formData)
if (res && res.code == 200){ if (res && res.code == 200){
const url = res?.url const url = res?.url

View File

@ -132,6 +132,8 @@ export class MsgEnum {
MSG_dz : 'dz', MSG_dz : 'dz',
/** @desc: 疑惑 */ /** @desc: 疑惑 */
MSG_yh : 'yh', MSG_yh : 'yh',
/** @desc: 推图片上屏 */
MSG_pushSreen_ImgList : 'pushSreen_ImgList',
// === 新定义-消息头 === // === 新定义-消息头 ===
/** @desc: 课程创建-待开课 */ /** @desc: 课程创建-待开课 */
MSG_0000: 0x0000, MSG_0000: 0x0000,

View File

@ -2,7 +2,7 @@
* @description * @description
*/ */
import { watch } from 'vue' import { watch, render } from 'vue'
import { PPTApi } from './index' import { PPTApi } from './index'
import * as store from '../store' import * as store from '../store'
import { sessionStore } from '@/utils/store' // electron-store 状态管理 import { sessionStore } from '@/utils/store' // electron-store 状态管理
@ -12,9 +12,10 @@ import Classcourse from './classcourse' // 课程相关
import msgUtils from '@/plugins/modal' // 消息工具 import msgUtils from '@/plugins/modal' // 消息工具
import * as dialogUtils from '@/utils/dialog' // 弹窗-函数 import * as dialogUtils from '@/utils/dialog' // 弹窗-函数
import { Homework } from './index' // api-作业相关 import { Homework } from './index' // api-作业相关
// import emitter from '@/utils/mitt' //mitt 事件总线 import emitter from '@/utils/mitt' //mitt 事件总线
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制 import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
import hooksUpvote from './upvote' // 点赞-工具 import hooksUpvote from './upvote' // 点赞-工具
import gridPic from './gridPic' // 上屏-工具
/** /**
* @description * @description
@ -98,6 +99,8 @@ export default () => {
} }
break break
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页 case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
render(null, document.body) //移除弹窗
emitter.emit('closegridPic') //如果有推图片窗口 就关闭
const slideIndex = content?.current || 0 const slideIndex = content?.current || 0
const type = content?.animation // 上下动作 const type = content?.animation // 上下动作
const steps = content?.animationSteps // 动画步骤 const steps = content?.animationSteps // 动画步骤
@ -128,6 +131,10 @@ export default () => {
case MsgEnum.HEADS.MSG_yh: // 疑惑 case MsgEnum.HEADS.MSG_yh: // 疑惑
hooksUpvote.trigger(2) hooksUpvote.trigger(2)
break break
case MsgEnum.HEADS.MSG_pushSreen_ImgList: // 推图片上屏
const imgArray = content.ImgList.map((obj) => obj.url);
emitter.emit('opengridPic',{arr:imgArray}) // 打开推图片上屏窗口
break
case MsgEnum.HEADS.MSG_0010: // 备用 case MsgEnum.HEADS.MSG_0010: // 备用
break break
default: default:

View File

@ -1,5 +1,6 @@
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store' import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen' import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
import { sessionStore } from '@/utils/store' // electron-store 状态管理
import ChatWs from '@/plugins/socket' // 聊天socket import ChatWs from '@/plugins/socket' // 聊天socket
export default () => { export default () => {
@ -25,6 +26,9 @@ export default () => {
if (!!classcourse) { //DOTO 有课堂,执行退相关操作 if (!!classcourse) { //DOTO 有课堂,执行退相关操作
console.log('退出放映状态') console.log('退出放映状态')
ChatWs?.close() // 关闭ws ChatWs?.close() // 关闭ws
sessionStore.delete('curr.classcourse') // 清除课堂信息
sessionStore.delete('curr.resource') // 清除课件信息
sessionStore.delete('curr.isPublic') // 清除公屏状态
setTimeout(() => { setTimeout(() => {
window.close() // 关闭窗口 window.close() // 关闭窗口
}, 1000) }, 1000)

View File

@ -148,7 +148,8 @@ export const useSlidesStore = defineStore('slides', {
this.workItem = list this.workItem = list
}, },
addSlide(slide: Slide | Slide[]) { async addSlide(slide: Slide | Slide[]) {
const { PPTApi } = await import('../api/index')
const slides = Array.isArray(slide) ? slide : [slide] const slides = Array.isArray(slide) ? slide : [slide]
for (const slide of slides) { for (const slide of slides) {
if (slide.sectionTag) delete slide.sectionTag if (slide.sectionTag) delete slide.sectionTag
@ -156,6 +157,8 @@ export const useSlidesStore = defineStore('slides', {
const addIndex = this.slideIndex + 1 const addIndex = this.slideIndex + 1
this.slides.splice(addIndex, 0, ...slides) this.slides.splice(addIndex, 0, ...slides)
this.slideIndex = addIndex this.slideIndex = addIndex
// 添加到服务器
PPTApi.addSlideServer(slides, this.slides)
}, },
updateSlide(props: Partial<Slide>, slideId?: string) { updateSlide(props: Partial<Slide>, slideId?: string) {
const slideIndex = slideId ? this.slides.findIndex(item => item.id === slideId) : this.slideIndex const slideIndex = slideId ? this.slides.findIndex(item => item.id === slideId) : this.slideIndex

View File

@ -16,7 +16,7 @@
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem> <PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
</FileInput> </FileInput>
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem> --> <PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem> -->
<PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem> <!-- <PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem> -->
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> --> <!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> -->
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> --> <!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
<PopoverMenuItem @click="mainMenuVisible = false; hotkeyDrawerVisible = true">快捷操作</PopoverMenuItem> <PopoverMenuItem @click="mainMenuVisible = false; hotkeyDrawerVisible = true">快捷操作</PopoverMenuItem>

View File

@ -88,7 +88,7 @@ import Button from '../../../../components/Button.vue'
import ButtonGroup from '../../../../components/ButtonGroup.vue' import ButtonGroup from '../../../../components/ButtonGroup.vue'
import Popover from '../../../../components/Popover.vue' import Popover from '../../../../components/Popover.vue'
import NumberInput from '../../../../components/NumberInput.vue' import NumberInput from '../../../../components/NumberInput.vue'
import { PPTApi } from '../../../../api'
const shapeClipPathOptions = CLIPPATHS const shapeClipPathOptions = CLIPPATHS
const ratioClipOptions = [ const ratioClipOptions = [
{ {
@ -221,10 +221,14 @@ const presetImageClip = (shape: string, ratio = 0) => {
const replaceImage = (files: FileList) => { const replaceImage = (files: FileList) => {
const imageFile = files[0] const imageFile = files[0]
if (!imageFile) return if (!imageFile) return
getImageDataURL(imageFile).then(dataURL => { PPTApi.toRousrceUrl(imageFile).then(data=>{
const props = { src: dataURL } const props = { src: data }
updateImage(props) updateImage(props)
}) })
// getImageDataURL(imageFile).then(dataURL => {
// const props = { src: dataURL }
// updateImage(props)
// })
} }
// //

View File

@ -47,8 +47,9 @@
<IconListView class="tool-btn" v-tooltip="'演讲者视图'" @click="changeViewMode('presenter')" /> <IconListView class="tool-btn" v-tooltip="'演讲者视图'" @click="changeViewMode('presenter')" />
<IconOffScreenOne class="tool-btn" v-tooltip="'退出全屏'" v-if="fullscreenState" @click="manualExitFullscreen()" /> <IconOffScreenOne class="tool-btn" v-tooltip="'退出全屏'" v-if="fullscreenState" @click="manualExitFullscreen()" />
<IconFullScreenOne class="tool-btn" v-tooltip="'进入全屏'" v-else @click="enterFullscreen()" /> <IconFullScreenOne class="tool-btn" v-tooltip="'进入全屏'" v-else @click="enterFullscreen()" />
<IconPower class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" /> <IconPower class="tool-btn" v-if="!classcourse" v-tooltip="'结束放映'" @click="exitScreening()" />
<IconPower class="tool-btn close" v-if="chat.groupid" v-tooltip="'结束课堂'" @click="exitCourse()" /> <IconPower class="tool-btn" v-else v-tooltip="'结束课堂'" @click="exitCourse()" size="30" fill="#d0021b" strokeLinecap="butt" />
<Share class="tool-btn" v-if="classcourse" v-tooltip="'分享'" @click="ShareCode()" />
</div> </div>
<div :class="['tools-icon',{opacity:iconHide}]" @click.stop="toolTrigger('icon')"> <div :class="['tools-icon',{opacity:iconHide}]" @click.stop="toolTrigger('icon')">
<circle-double-down v-if="rightToolsVisible" theme="outline" size="30" fill="#409EFF"/> <circle-double-down v-if="rightToolsVisible" theme="outline" size="30" fill="#409EFF"/>
@ -75,7 +76,8 @@ import WritingBoardTool from './WritingBoardTool.vue'
import CountdownTimer from './CountdownTimer.vue' import CountdownTimer from './CountdownTimer.vue'
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
import Chat from '../../api/chat' // import Chat from '../../api/chat' //
import { CircleDoubleDown, CircleDoubleUp } from '@icon-park/vue-next' // icon-park import { CircleDoubleDown, CircleDoubleUp, Share } from '@icon-park/vue-next' // icon-park
import { ShareCode } from '@/utils/ppt' // ppt
const props = defineProps<{ const props = defineProps<{
changeViewMode: (mode: 'base' | 'presenter') => void changeViewMode: (mode: 'base' | 'presenter') => void
@ -198,7 +200,7 @@ const contextmenus = (): ContextmenuItem[] => {
}, },
] ]
} }
//
const toolTrigger = (type:string) => { const toolTrigger = (type:string) => {
const curT = Date.now() const curT = Date.now()
if (curT - timer.value < 200) return if (curT - timer.value < 200) return

View File

@ -10,9 +10,10 @@
<IconOffScreenOne class="tool-icon" v-else /> <IconOffScreenOne class="tool-icon" v-else />
<span>{{ fullscreenState ? '退出全屏' : '全屏' }}</span> <span>{{ fullscreenState ? '退出全屏' : '全屏' }}</span>
</div> </div>
<div class="tool-btn" @click="ShareCode()"><Share class="tool-icon" /><span>分享</span></div>
<Divider class="divider" /> <Divider class="divider" />
<div class="tool-btn" @click="exitScreening()"><IconPower class="tool-icon" /><span>结束放映</span></div> <div class="tool-btn" v-if="!classcourse" @click="exitScreening()"><IconPower class="tool-icon" /><span>结束放映</span></div>
<div class="tool-btn close" @click="exitCourse()" v-if="chat.groupid"><IconPower class="tool-icon" /><span>结束课堂</span></div> <div class="tool-btn" v-else @click="exitCourse()" size="30" fill="#d0021b" strokeLinecap="butt"><IconPower class="tool-icon" /><span>结束课堂</span></div>
</div> </div>
<div class="content"> <div class="content">
@ -78,6 +79,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Share } from '@icon-park/vue-next' // icon-park
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue' import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useSlidesStore, useClasscourseStore } from '../../store' import { useSlidesStore, useClasscourseStore } from '../../store'
@ -97,6 +99,7 @@ import CountdownTimer from './CountdownTimer.vue'
import Divider from '../../components/Divider.vue' import Divider from '../../components/Divider.vue'
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
import Chat from '../../api/chat' // import Chat from '../../api/chat' //
import { ShareCode } from '@/utils/ppt' // ppt
const props = defineProps<{ const props = defineProps<{
changeViewMode: (mode: 'base' | 'presenter') => void changeViewMode: (mode: 'base' | 'presenter') => void
@ -125,7 +128,7 @@ const { slideWidth, slideHeight } = useSlideSize(slideListWrapRef)
const { exitScreening } = useScreening() const { exitScreening } = useScreening()
const { slidesLoadLimit } = useLoadSlides() const { slidesLoadLimit } = useLoadSlides()
const { fullscreenState, manualExitFullscreen } = useFullscreen() const { fullscreenState, manualExitFullscreen } = useFullscreen()
const chat:any = Chat() // const chatApi:any = Chat() //
const remarkFontSize = ref(16) const remarkFontSize = ref(16)
const currentSlideRemark = computed(() => { const currentSlideRemark = computed(() => {
@ -134,15 +137,20 @@ const currentSlideRemark = computed(() => {
// //
const turnSlideTo = (index: number, e: PointerEvent) => { const turnSlideTo = (index: number, e: PointerEvent) => {
// const preInd = slideIndex.value
console.log('课堂信息', classcourse, index)
if (!!classcourse.value) return
turnSlideToIndex(index) turnSlideToIndex(index)
if (!!classcourse.value) {//
if (preInd == index) return
const animationSteps = 0
const animation = index > preInd?'Nextsteps':'Previoustep'
const msg = { current:index, animation, animationSteps}
chatApi.slideFlapping(msg)
}
} }
// //
const exitCourse = async () => { const exitCourse = async () => {
// console.log('', chat) // console.log('', chat)
await chat.exitCourse() // await chatApi.exitCourse() //
exitScreening() // exitScreening() //
} }

View File

@ -6,11 +6,21 @@
<upvote-vue ref="upvoteRef" type="2"></upvote-vue> <upvote-vue ref="upvoteRef" type="2"></upvote-vue>
<!-- <div style="z-index: 999;position: absolute;top:10px"> <!-- <div style="z-index: 999;position: absolute;top:10px">
</div> --> </div> -->
<!-- 推图上屏弹窗 -->
<el-dialog
v-model="dialogVisible"
:fullscreen="true"
class="gridPicRefdiv"
style="overflow: hidden;"
:show-close="false"
>
<grid-pic ref="gridPicRef" style="height:100%;" @clear="clearchidrenPic"></grid-pic>
</el-dialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue' import { onMounted, onUnmounted, ref , nextTick} from 'vue'
import { KEYS } from '../../configs/hotkey' import { KEYS } from '../../configs/hotkey'
import useScreening from '../../hooks/useScreening' import useScreening from '../../hooks/useScreening'
import hooksUpvote from '../../api/upvote' // - import hooksUpvote from '../../api/upvote' // -
@ -18,9 +28,13 @@ import hooksUpvote from '../../api/upvote' // 点赞-工具
import BaseView from './BaseView.vue' import BaseView from './BaseView.vue'
import PresenterView from './PresenterView.vue' import PresenterView from './PresenterView.vue'
import upvoteVue from '@/views/tool/components/upvote.vue' // - import upvoteVue from '@/views/tool/components/upvote.vue' // -
import gridPic from '@/components/grid-pic/index.vue' //
import emitter from '@/utils/mitt' //mitt 线
const viewMode = ref<'base' | 'presenter'>('base') const viewMode = ref<'base' | 'presenter'>('base')
const dialogVisible = ref(false)
const gridPicRef:any= ref(null)
const changeViewMode = (mode: 'base' | 'presenter') => { const changeViewMode = (mode: 'base' | 'presenter') => {
viewMode.value = mode viewMode.value = mode
} }
@ -35,6 +49,23 @@ const keydownListener = (e: KeyboardEvent) => {
if (key === KEYS.ESC) exitScreening() if (key === KEYS.ESC) exitScreening()
} }
const clearchidrenPic= ()=> {
dialogVisible.value = false
}
//
emitter.on('opengridPic', async (data:object)=> {
if(gridPicRef.value) gridPicRef.value.clearPic()
dialogVisible.value = true
await nextTick();
gridPicRef.value.addPic(data.arr)
});
//
emitter.on('closegridPic', ()=> {
if(!gridPicRef.value) return
gridPicRef.value.clearPic()
dialogVisible.value = false
});
onMounted(() => document.addEventListener('keydown', keydownListener)) onMounted(() => document.addEventListener('keydown', keydownListener))
onUnmounted(() => document.removeEventListener('keydown', keydownListener)) onUnmounted(() => document.removeEventListener('keydown', keydownListener))
</script> </script>
@ -46,4 +77,8 @@ onUnmounted(() => document.removeEventListener('keydown', keydownListener))
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
:deep(.gridPicRefdiv .el-dialog__body){
height: 100% !important;
}
</style> </style>

View File

@ -71,6 +71,14 @@ export function updateClassworkeval(data) {
}) })
} }
export function updateClassworkevalList(data) {
return request({
url: '/education/classworkeval/updateList',
method: 'put',
data: data
})
}
// 修改classworkdata // 修改classworkdata
export function updateClassworkdata(data) { export function updateClassworkdata(data) {
return request({ return request({
@ -80,6 +88,15 @@ export function updateClassworkdata(data) {
}) })
} }
// 批阅后, 待所有学生都批改完成后自动结束当前作业为[已完成]
export function updateClassWorkDataAutoFinish(data) {
return request({
url: '/education/classworkdata/updAutoFinish',
method: 'put',
data: data
})
}
// 修改classwork // 修改classwork
export function updateClasswork(data) { export function updateClasswork(data) {
return request({ return request({

View File

@ -136,3 +136,17 @@ export function getJYPath(url,config) {
params: config.params params: config.params
}) })
} }
/**
* @desc: 百度识图转发
* @return: {*}
* @param {*} data
*/
export function getOcrContent(data) {
return request({
url: '/ocr/exam',
method: 'post',
data: data
})
}

View File

@ -102,4 +102,16 @@ export function setPaging(data) {
data data
}) })
} }
/**
* 获取分享码(邀请码)
* @param {*} id 课堂id
* @returns
*/
export function getShareCode(id) {
return request({
url: '/education/classcourse/refresh/code',
method: 'post',
data: { id }
})
}

View File

@ -7,7 +7,7 @@
<i class="iconfont icon-xiangyou"></i> <i class="iconfont icon-xiangyou"></i>
</div> </div>
<div class="book-list" v-loading="treeLoading"> <div class="book-list" v-loading="treeLoading">
<el-tree :data="treeData" accordion :props="defaultProps" node-key="id" <el-tree :data="treeData" accordion :props="defaultProps" node-key="id" :render-content="renderContent"
:default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current :default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<template #default="{ node }"> <template #default="{ node }">
@ -178,6 +178,18 @@ const handleNodeClick = (data) => {
sessionStore.set('subject.curNode', nodeData) sessionStore.set('subject.curNode', nodeData)
emit('nodeClick', curData) emit('nodeClick', curData)
} }
const renderContent = (h, { node, data, store }) => {
return h(
'span',
{
style: {
color: data.bookId==''||data.bookId=='0' ? '#A5B3CA' : 'black',
},
},
node.label
);
}
onMounted( async () => { onMounted( async () => {
treeLoading.value = true treeLoading.value = true
try{ try{

View File

@ -16,15 +16,15 @@
<draggable handle=".header-btn" :draggable="false" item-key="backgroundColor" v-model="gridPicList" class="grid-pic-wrap" :style="getGrid"> <draggable handle=".header-btn" :draggable="false" item-key="backgroundColor" v-model="gridPicList" class="grid-pic-wrap" :style="getGrid">
<template #item="{ element, index }"> <template #item="{ element, index }">
<div class="grid-pic-item" :key="element.backgroundColor" :style="getWH(element,index)"> <div class="grid-pic-item" :key="element.backgroundColor" :style="getWH(element,index)">
<div class="delete-btn" @click="gridPicList.splice(index,1)">X</div> <div class="delete-btn" @click="()=>{gridPicList.splice(index,1);if(!gridPicList.length) emits('clear')} ">X</div>
<div class="header-btn"></div> <div class="header-btn"></div>
<ViewerItem :gridPicList="gridPicList" :index="index" :images="element"></ViewerItem> <ViewerItem :gridPicList="gridPicList" :index="index" :images="element"></ViewerItem>
</div> </div>
</template> </template>
</draggable> </draggable>
<div v-if="showToolbar" class="grid-pic-toolbar"> <div class="grid-pic-toolbar">
<el-input style="width: 500px" v-model="inputValue" type="text" /> <el-input v-if="showToolbar" style="width: 500px" v-model="inputValue" type="text" />
<el-button class="add-btn" @click="pushPic"> <el-button v-if="showToolbar" class="add-btn" @click="pushPic">
添加 添加
</el-button> </el-button>
<el-button class="add-btn" @click="clearPic"> <el-button class="add-btn" @click="clearPic">
@ -53,7 +53,7 @@
const props = defineProps({ const props = defineProps({
showToolbar: { showToolbar: {
type: Boolean, type: Boolean,
default: true default: false
} }
}) })
// //
@ -149,20 +149,26 @@
addPic(src) addPic(src)
} }
// //
const addPic = (src) => { const addPic = (data) => {
if (gridPicList.value.length >= 9) { let list = Array.isArray(data)?data:[data]
if (gridPicList.value.length + list.length > 9) {
console.log("超出九个图片") console.log("超出九个图片")
emits('outIndex') emits('outIndex')
return return
} }
let listArr = [];
for (let i = 0; i < list.length; i++) {
let src = list[i]
if (!src) { if (!src) {
console.log("图片链接不能为空") console.log("图片链接不能为空")
return; return;
} }
gridPicList.value.push({ listArr.push({
src: src, src: src,
backgroundColor: getRandomColor() backgroundColor: getRandomColor()
}) })
}
gridPicList.value.push(...listArr)
inputValue.value = '' inputValue.value = ''
} }
// //

View File

@ -140,5 +140,8 @@ watch(props.images, (newValue, oldValue) => {
.viewer-item-wrap{ .viewer-item-wrap{
width: 100%; width: 100%;
height: 100%; height: 100%;
:deep(.viewer-canvas img) {
display: block !important;
}
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="whiteboart-container" :style="{ height: height + 'px' }"> <div class="whiteboart-container" :style="{ height: height + 'px' }">
<div class="canvasBox" ref="box"></div> <div class="canvasBox" ref="box" @mouseenter.capture="handleMouseEnter" @mouseleave.capture="handleMouseLeave"></div>
<div class="footerLeft" @click.stop <div class="footerLeft" @click.stop
:style="type == 'design' ? ['top: 10px', 'justify-content: space-between'] : ['bottom: 10px', 'justify-content: center']"> :style="type == 'design' ? ['top: 10px', 'justify-content: space-between'] : ['bottom: 10px', 'justify-content: center']">
@ -278,7 +278,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, watch, toRaw, nextTick, computed, reactive, defineProps, defineEmits } from 'vue' import { onMounted, onBeforeUnmount, ref, getCurrentInstance, watch, toRaw, nextTick, computed, reactive, defineProps, defineEmits } from 'vue'
import TinyWhiteboard from 'whiteboard_lyc' import TinyWhiteboard from 'whiteboard_lyc'
import ColorPicker from './components/ColorPicker.vue' import ColorPicker from './components/ColorPicker.vue'
import { import {
@ -305,6 +305,7 @@ import { fontFamilyList, fontSizeList } from './constants'
const borderImg = new URL('../../../src/assets/images/borderwidth.png', import.meta.url).href const borderImg = new URL('../../../src/assets/images/borderwidth.png', import.meta.url).href
const pointerImg = new URL('../../../src/assets/images/mouse-pointer.png', import.meta.url).href const pointerImg = new URL('../../../src/assets/images/mouse-pointer.png', import.meta.url).href
const { proxy } = getCurrentInstance()
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -507,10 +508,6 @@ const backToCenter = () => {
app.scrollToCenter() app.scrollToCenter()
} }
const cancelActiveElement = () =>{
app.cancelActiveElement()
}
// //
const showFit = () => { const showFit = () => {
@ -716,6 +713,13 @@ watch(() => props.data, (newVal) => {
// dom // dom
onMounted(() => { onMounted(() => {
init();
})
/**
* 初始化画布内容
*/
const init = () => {
// //
app = new TinyWhiteboard({ app = new TinyWhiteboard({
container: box.value, container: box.value,
@ -737,6 +741,7 @@ onMounted(() => {
}) })
// //
app.on('activeElementChange', element => { app.on('activeElementChange', element => {
console.log('点击元素 监听 activeElementChange-----------')
if (activeElement.value) { if (activeElement.value) {
activeElement.value.off('elementRotateChange', onElementRotateChange) activeElement.value.off('elementRotateChange', onElementRotateChange)
} }
@ -784,7 +789,39 @@ onMounted(() => {
app.resize() app.resize()
}, 300) }, 300)
}) })
}) }
const isMyCanvas = ref(false); //
const handleKeyDown=(event)=> {
// console.log(':', event.key);
// console.log(isMyCanvas.value,'??????????')
if(isMyCanvas.value == false){
event.stopPropagation();
// console.log(':', event.key);
}
}
/**
* 鼠标进入事件
*/
const handleMouseEnter = () => {
console.log('进入白板')
isMyCanvas.value = true;
document.addEventListener('keydown', handleKeyDown, true);
}
/**
* 课堂展示-鼠标离开白板监听事件该事件是避免选中状态在其他地方点击后退删除等事件会删除白板内选中的元素
*/
const handleMouseLeave = () => {
console.log('离开白板')
// --
app.cancelActiveElement()
//
isMyCanvas.value = false;
//
document.addEventListener('keydown', handleKeyDown, true);
};
// //
defineExpose({ defineExpose({
@ -795,7 +832,6 @@ defineExpose({
getCanvasBase64, getCanvasBase64,
setCanvasData, setCanvasData,
getCanvasBlob, getCanvasBlob,
cancelActiveElement
}) })
</script> </script>

View File

@ -1,5 +1,7 @@
import { listEntpcoursework,getEvaluationclue } from '@/api/classTask'; import { listEntpcoursework,getEvaluationclue } from '@/api/classTask';
import { processList } from '@/hooks/useProcessList'; import { processList } from '@/hooks/useProcessList';
import useClassTaskStore from '@/store/modules/classTask'
const useClassTaskStores = useClassTaskStore();
const isJson = (str) => { const isJson = (str) => {
if (typeof str == 'string') { if (typeof str == 'string') {
@ -114,6 +116,14 @@ export const editListItem = (row, courseObj) => {
} }
else if (row.worktype == '科学实验') { else if (row.worktype == '科学实验') {
if(isJson(row.workcodes)){ if(isJson(row.workcodes)){
// 同步更新实验内部的科目信息
if (row.worktag && row.worktag.indexOf('-') > -1){
const eduInfo = row.worktag.split('-');
useClassTaskStores.experimentObj.edustage = eduInfo[0];
useClassTaskStores.experimentObj.edusubject = eduInfo[1];
useClassTaskStores.experimentObj.updateEduInfo = row.worktag;
}
// 更新科学实验内容
classtaskObj.fileHomeworkList = JSON.parse(row.workcodes); classtaskObj.fileHomeworkList = JSON.parse(row.workcodes);
// //
// console.log('科学实验', classtaskObj); // console.log('科学实验', classtaskObj);

View File

@ -299,21 +299,28 @@ export const processList = (row, aloneOption=false) => {
if(!aloneOption && j%2== 0){ if(!aloneOption && j%2== 0){
tmp += '</div>'; tmp += '</div>';
} }
row[i].workdescFormat = tmp row[i].workdescFormat = tmp;
// 处理[答案显示] - 转换ABCD // 处理[答案显示] - 转换ABCD
let arr2Char = workAnswerArr let arr2Char = workAnswerArr
.map((item) => { .map((item) => {
return String.fromCharCode(65 + Number(item)) return String.fromCharCode(65 + Number(item))
}) })
.join('') .join('');
row[i].workanswerFormat = arr2Char row[i].workanswerFormat = arr2Char;
} else if (row[i].worktype == '填空题') { } else if (row[i].worktype == '填空题') {
// 处理[选项显示] - 填空题中无选项, 故置空 // 处理[选项显示] - 填空题中无选项, 故置空
row[i].workdescFormat = '' row[i].workdescFormat = '';
// 处理[答案显示] - 逗号连接 // 处理[答案显示] - 逗号连接
row[i].workanswerFormat = workAnswerArr.join('、')
// 当[答案显示]为 [<div] 开头时,不再需逗号连接(一般为自主上传, 当前答案每个自带div标签)
let linkChar = '、';
if (workAnswerArr.length != 0 && workAnswerArr[0].indexOf('<div') == 0) {
linkChar = '';
}
row[i].workanswerFormat = workAnswerArr.join(linkChar);
} else if (row[i].worktype == '判断题') { } else if (row[i].worktype == '判断题') {
// 处理[选项显示] - 判断题中无选项, 故置空 // 处理[选项显示] - 判断题中无选项, 故置空
row[i].workdescFormat = '' row[i].workdescFormat = ''

View File

@ -7,8 +7,9 @@ const useClassTaskStore = defineStore('classTask',{
state: () => ({ state: () => ({
experimentObj:{ experimentObj:{
edustage: '小学', // 教育阶段 edustage: '小学', // 教育阶段
edusubject: '', // 学科 edusubject: '数学', // 学科
experimentList: [], // 实验科目列表 experimentList: [], // 实验科目列表
updateEduInfo: '小学-数学', //实际需上传的学段+学科信息(用于上传及回显实验内的学段学科)
}, },
isOpenQuestUploadView: false, // 是否打开习题上传的页面 isOpenQuestUploadView: false, // 是否打开习题上传的页面
classListIds: [], classListIds: [],

View File

@ -6,6 +6,10 @@ import { toPng, toJpeg } from 'html-to-image' // 引入html-to-image库
import { PPTXFileToJson } from "@/AixPPTist/src/hooks/useImport" import { PPTXFileToJson } from "@/AixPPTist/src/hooks/useImport"
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue' import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
import { useSlidesStore } from '@/AixPPTist/src/store' import { useSlidesStore } from '@/AixPPTist/src/store'
import * as ElementPlus from 'element-plus'
import { sessionStore } from '@/utils/store' // electron-store 状态管理
import * as Http_Classcourse from '@/api/teaching/classcourse' // api接口
// 延时 // 延时
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
@ -85,3 +89,43 @@ export const pptToImg = async(file, options) => {
const { slides } = await PPTXFileToJson(file) const { slides } = await PPTXFileToJson(file)
return slidesToImg(slides, options) return slidesToImg(slides, options)
} }
/**
* 课堂-分享码
*/
export const ShareCode = async(code, cb) => {
let shareCode
if (typeof code =='string') shareCode = code
else { // 自动获取邀请码
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
if (!classcourse) return ElementPlus.ElMessage.warning('没有课堂信息')
const isRefresh = typeof code == 'boolean' && code // 是否刷新邀请码
shareCode = classcourse.shareCode
if (!shareCode || isRefresh) { // 获取邀请码
const res = await Http_Classcourse.getShareCode(classcourse.id)
shareCode = res.msg
// 更新邀请码
sessionStore.set('curr.classcourse.shareCode', shareCode)
}
}
const msg = h('div', [
h('h1', [`我的邀请码:`, h('b',{style:{color:'#F56C6C',fontSize:'1.5em'}}, shareCode)]),
h('div', {style:{color:'#E6A23C',fontSize:'13px'}}, `该邀请码1小时内有效请在学生端填写邀请码后即可进入课堂。`)
])
return ElementPlus.ElMessageBox.alert(msg, '分享课程', {
confirmButtonText: '更新',
cancelButtonText: '关闭',
showCancelButton: true,
beforeClose: (action, instance, done) => {
if (action =='confirm') { // 更新
if (!!cb) { // 回调
cb({ h, instance, action, done }, done) && done()
} else { // 默认更新
ShareCode(true)
done()
}
} else done()
}
}).catch(() => {})
}

View File

@ -435,7 +435,7 @@ import useUserStore from '@/store/modules/user'
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
// import { Plus } from '@element-plus/icons-vue' // import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import { updateClassworkeval, updateClassworkdata, getClassworkdata } from '@/api/classTask' import { getClassworkdata, updateClassworkevalList, updateClassWorkDataAutoFinish } from '@/api/classTask'
import { getTimeDate } from '@/utils/date' import { getTimeDate } from '@/utils/date'
import ReFilePreview from '@/components/refile-preview/index.vue' import ReFilePreview from '@/components/refile-preview/index.vue'
import { quizStrToList } from '@/utils/comm'; import { quizStrToList } from '@/utils/comm';
@ -890,12 +890,12 @@ const onSubmit = () => {
updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm; updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm;
}; };
// //
updateClassworkdata(formd).then(res => { updateClassWorkDataAutoFinish(formd).then(res => {
}) })
// //
classWorkFormScore.teacherRating && const queryList = [];
classWorkFormScore.teacherRating.map((item, index) => { classWorkFormScore.teacherRating && classWorkFormScore.teacherRating.map((item, index) => {
const queryParams = { const queryParams = {
id: item.id, id: item.id,
teacherRating: item.score, // teacherRating: item.score, //
@ -903,13 +903,32 @@ const onSubmit = () => {
teacherremark: classWorkFormScore.teacherremark, // teacherremark: classWorkFormScore.teacherremark, //
timestamp: getTimeDate() // timestamp: getTimeDate() //
} }
console.log(queryParams) queryList.push(queryParams)
updateClassworkeval(queryParams).then((res) => { })
//console.log('queryList->', queryList)
updateClassworkevalList(queryList).then((res) => {
// if(res.code == 200){ // if(res.code == 200){
// //
// } // }
}) })
})
//
// classWorkFormScore.teacherRating &&
// classWorkFormScore.teacherRating.map((item, index) => {
// const queryParams = {
// id: item.id,
// teacherRating: item.score, //
// rating: classWorkFormScore.rating, //
// teacherremark: classWorkFormScore.teacherremark, //
// timestamp: getTimeDate() //
// }
// console.log(queryParams)
// updateClassworkeval(queryParams).then((res) => {
// // if(res.code == 200){
// //
// // }
// })
// })
ElMessage({ ElMessage({
type: 'success', type: 'success',
message: '提交成功!' message: '提交成功!'

View File

@ -55,6 +55,7 @@
<el-col :span="11"> <el-col :span="11">
<el-form-item label="知识点" label-width="70"> <el-form-item label="知识点" label-width="70">
<el-cascader <el-cascader
disabled
v-model="entpCourseWorkQueryParams.point" v-model="entpCourseWorkQueryParams.point"
clearable clearable
style="width: 100%" style="width: 100%"
@ -172,7 +173,7 @@
<!-- 非习题训练常规作业 --> <!-- 非习题训练常规作业 -->
<div v-if="classWorkForm.worktype!='习题训练'"> <div v-if="classWorkForm.worktype!='习题训练'">
<div :style="{ 'overflow': 'auto'}"> <div :style="{ 'overflow': 'auto'}">
<template v-if="classWorkForm.worktype!='常规作业'"> <!-- <template v-if="classWorkForm.worktype!='常规作业'">
<template v-for="(item, index) in workResource.teachResourceList" :key="item"> <template v-for="(item, index) in workResource.teachResourceList" :key="item">
<div v-if="item.worktype==classWorkForm.worktype" style="border-bottom: 1px dotted;display: flex;justify-content: space-between;"> <div v-if="item.worktype==classWorkForm.worktype" style="border-bottom: 1px dotted;display: flex;justify-content: space-between;">
<div style="margin-bottom: 5px; padding-left: 15px;display: flex;flex-direction: row;align-items: center;"> <div style="margin-bottom: 5px; padding-left: 15px;display: flex;flex-direction: row;align-items: center;">
@ -193,7 +194,7 @@
</div> </div>
</div> </div>
</template> </template>
</template> </template> -->
<template v-if="classWorkForm.worktype =='常规作业'"> <template v-if="classWorkForm.worktype =='常规作业'">
<div v-loading="fileLoading" class="upload-homework"> <div v-loading="fileLoading" class="upload-homework">
<FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/> <FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
@ -285,6 +286,7 @@ import { updateClasswork, listEvaluationclue, listClassworkeval,delClassworkeval
import { listEvaluation } from '@/api/subject' import { listEvaluation } from '@/api/subject'
import { listEntpcoursefile } from '@/api/education/entpcoursefile' import { listEntpcoursefile } from '@/api/education/entpcoursefile'
import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint"; import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
import { isJson } from "@/utils/comm";
import { useGetHomework } from '@/hooks/useGetHomework' import { useGetHomework } from '@/hooks/useGetHomework'
@ -459,12 +461,13 @@ const client = new Apis('/paht');
*/ */
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const evalId = props.bookobj.levelSecondId=='' ? props.bookobj.levelFirstId : props.bookobj.levelSecondId;
const queryForm = { const queryForm = {
// //
currentPage: paginationParams.pageNum, currentPage: paginationParams.pageNum,
pageSize: paginationParams.pageSize, pageSize: paginationParams.pageSize,
// //
eid: props.bookobj.levelSecondId, eid: evalId, // id
sectionName: props.bookobj.coursetitle, sectionName: props.bookobj.coursetitle,
edusubject: userStore.edusubject, edusubject: userStore.edusubject,
edustage: userStore.edustage, edustage: userStore.edustage,
@ -557,10 +560,13 @@ const getQueryFromEvaluationclue = () => {
} }
if (clueres.rows[i].childlist != '') { if (clueres.rows[i].childlist != '') {
clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']'); const tmpJson = '['+clueres.rows[i].childlist+']';
if (isJson(tmpJson)){
clueres.rows[i].childArray = JSON.parse(tmpJson);
for (var j=0; j<clueres.rows[i].childArray.length; j++) { for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, ''); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
} }
}
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
} }
@ -990,6 +996,8 @@ const initPageParams = () => {
onMounted(async() => { onMounted(async() => {
//
getEntpCourseWorkPointList();
}) })
// const refreshData = () => { // const refreshData = () => {
@ -1016,9 +1024,9 @@ const debounceQueryData = debounce(() => {
// //
handleQueryFromEntpCourseWork(0); handleQueryFromEntpCourseWork(0);
// //
getQueryFromEvaluationclue(); //getQueryFromEvaluationclue();
// //
getEntpCourseWorkPointList(); //getEntpCourseWorkPointList();
}, 1000); }, 1000);
watch(() => props.propsformobj.uniquekey, (newVal) => { watch(() => props.propsformobj.uniquekey, (newVal) => {
@ -1027,8 +1035,20 @@ watch(() => props.propsformobj.uniquekey, (newVal) => {
classWorkForm.uniquekey = props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):''; // classWorkForm.uniquekey = props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):''; //
} }
}) })
watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
//watch(() => props.bookobj.levelSecondId, async (newVal, oldVal) => {
watch([
() => props.bookobj.levelFirstId,
() => props.bookobj.levelSecondId
], ([newLevelSecondId, newLevelFirstId], [oldLevelSecondId, oldLevelFirstId]) => {
console.log(props.bookobj,'课程选择') console.log(props.bookobj,'课程选择')
// , ,
if (props.bookobj.levelSecondId == '') {
workResource.entpCourseWorkList = [];
return;
}
debounceQueryData(); debounceQueryData();
}) })

View File

@ -36,16 +36,24 @@ const props = defineProps({
}) })
const value = ref('') const value = ref('')
const updateLabel = (val) => {
value.value = val;
}
const onSelectOption = (option) => {
classTaskStore.updateEduInfo = `${classTaskStore.edustage}-${classTaskStore.edusubject}`;
console.log('updateEduInfo->', classTaskStore.updateEduInfo);
console.log(option,'选择的实验课-------')
emit('selectItem', classTaskStore.experimentList.filter(item => item.label === option)[0])
}
onMounted(() => { onMounted(() => {
}) })
const onSelectOption = (option) => { defineExpose({
console.log(option,'选择的实验课-------') updateLabel
emit('selectItem', classTaskStore.experimentList.filter(item => item.label === option)[0]) })
}
</script> </script>
<style scoped> <style scoped>

View File

@ -56,7 +56,7 @@ const subjectList = ref([])
const chooseGrade= ref({}) const chooseGrade= ref({})
const expList = ref([]) // const expList = ref([]) //
const checkList = ref([])// const checkList = ref([])//
const isLoaded = ref(false);
// //
const getSubject = () => { const getSubject = () => {
@ -80,8 +80,15 @@ const getSubject = () => {
}) })
}) })
console.log(subjectList,'subjectList'); console.log(subjectList,'subjectList');
// //
handleUserEduStage(useClassTaskStore().experimentObj.edustage) const edusubject = useClassTaskStore().experimentObj.edusubject;
handleUserEduStage(useClassTaskStore().experimentObj.edustage);
// , , .
useClassTaskStore().experimentObj.edusubject = edusubject;
// []
isLoaded.value = true;
//console.log('----');
} }
// //
const isExpList = (edusubject) => { const isExpList = (edusubject) => {
@ -108,7 +115,8 @@ const isExpList = (edusubject) => {
// //
const handleUserEduStage = (item) => { const handleUserEduStage = (item) => {
// userStore.edustage = item // userStore.edustage = item
useClassTaskStore().experimentObj.edustage = item useClassTaskStore().experimentObj.edustage = item;
// //
expList.value = [] expList.value = []
if(item === '小学'){ if(item === '小学'){
@ -117,10 +125,11 @@ const handleUserEduStage = (item) => {
const newSubjectList = subjectList.value.filter(item => item.edustage === '小学'); const newSubjectList = subjectList.value.filter(item => item.edustage === '小学');
for(let i in newSubjectList){ for(let i in newSubjectList){
const name = newSubjectList[i].itemtitle const name = newSubjectList[i].itemtitle
if(isExpList(name)){ if(isExpList(name) && useClassTaskStore().experimentObj.edusubject===name){
useClassTaskStore().experimentObj.edusubject = name; //useClassTaskStore().experimentObj.edusubject = name;
// //
handleUserEduSubject(name) handleUserEduSubject(name)
break;
} }
} }
}else if(item === '初中'){ }else if(item === '初中'){
@ -129,10 +138,11 @@ const handleUserEduStage = (item) => {
const newSubjectList = subjectList.value.filter(item => item.edustage === '初中'); const newSubjectList = subjectList.value.filter(item => item.edustage === '初中');
for(let i in newSubjectList){ for(let i in newSubjectList){
const name = newSubjectList[i].itemtitle const name = newSubjectList[i].itemtitle
if(isExpList(name)){ if(isExpList(name) && useClassTaskStore().experimentObj.edusubject===name){
useClassTaskStore().experimentObj.edusubject = name; //useClassTaskStore().experimentObj.edusubject = name;
// //
handleUserEduSubject(name) handleUserEduSubject(name)
break;
} }
} }
}else if(item === '高中'){ }else if(item === '高中'){
@ -141,10 +151,11 @@ const handleUserEduStage = (item) => {
const newSubjectList = subjectList.value.filter(item => item.edustage === '高中'); const newSubjectList = subjectList.value.filter(item => item.edustage === '高中');
for(let i in newSubjectList){ for(let i in newSubjectList){
const name = newSubjectList[i].itemtitle const name = newSubjectList[i].itemtitle
if(isExpList(name)){ if(isExpList(name) && useClassTaskStore().experimentObj.edusubject===name){
useClassTaskStore().experimentObj.edusubject = name; //useClassTaskStore().experimentObj.edusubject = name;
// //
handleUserEduSubject(name) handleUserEduSubject(name)
break;
} }
} }
} }
@ -177,10 +188,59 @@ const handleUserEduSubject = (item) => {
// emit('experlist',checkList.value) // emit('experlist',checkList.value)
} }
const updateCheckList = async () => {
try {
await waitForSubjectData();
//console.log('-------', );
//console.log('experimentObj-> ', useClassTaskStore().experimentObj);
//
const edustage = useClassTaskStore().experimentObj.edustage;
if(edustage === '小学'){
chooseGrade.value = jsonData.data.primary
}else if(edustage === '初中'){
chooseGrade.value = jsonData.data.junior
}else if(edustage === '高中'){
chooseGrade.value = jsonData.data.senior
}
expList.value = chooseGrade.value
const edusubject = useClassTaskStore().experimentObj.edusubject;
handleUserEduSubject(edusubject);
} catch (error) {
console.error(error);
}
}
const waitForSubjectData = () => {
return new Promise((resolve, reject) => {
let timeoutId;
let intervalId;
const checkIsLoaded = () => {
if (isLoaded.value) {
clearInterval(intervalId);
clearTimeout(timeoutId);
resolve();
}
};
intervalId = setInterval(checkIsLoaded, 100);
timeoutId = setTimeout(() => {
clearInterval(intervalId);
reject(new Error('该作业-等待[科学实验]学科学段初始化超时'));
}, 5000);
});
};
onMounted(() => { onMounted(() => {
getSubject() getSubject()
}) })
defineExpose({
updateCheckList
})
</script> </script>
<style scoped> <style scoped>
.custom-button { .custom-button {

View File

@ -3,10 +3,10 @@
<div class="activeExp-header"> <div class="activeExp-header">
<div class="infomation" v-if="isStadium() !== true" > <div class="infomation" v-if="isStadium() !== true" >
<!-- <selectClass v-if="!isSubject" @experlist="getExperimentList" /> --> <!-- <selectClass v-if="!isSubject" @experlist="getExperimentList" /> -->
<selectClass v-if="!isSubject" /> <selectClass ref="selectClassRef"/>
</div> </div>
<div> <div>
<selectExperiment @selectItem="getExperimentListItem" /> <selectExperiment ref="selectExperimentRef" @selectItem="getExperimentListItem" />
</div> </div>
</div> </div>
<div ref="mainDiv" class="activeExp-main" style="overflow: auto"> <div ref="mainDiv" class="activeExp-main" style="overflow: auto">
@ -44,6 +44,8 @@ const props = defineProps({
// //
// const experimentList = ref([]); // const experimentList = ref([]);
const activeExp = ref({}); const activeExp = ref({});
const selectExperimentRef = ref();
const selectClassRef = ref();
const isStadium = () => { const isStadium = () => {
let roles = userStore.roles let roles = userStore.roles
@ -82,6 +84,13 @@ const getExperimentListItem = (val) => {
watch(() => props.expObj.fileurl, (newVal, oldVal) => { watch(() => props.expObj.fileurl, (newVal, oldVal) => {
console.log(props.expObj,'科学实验科目') console.log(props.expObj,'科学实验科目')
activeExp.value = props.expObj; activeExp.value = props.expObj;
//
nextTick(() => {
selectClassRef.value.updateCheckList();
selectExperimentRef.value.updateLabel(props.expObj.label);
})
}) })
</script> </script>

View File

@ -68,7 +68,6 @@
</div> </div>
<div v-if="(currentRow.worktype == '课堂展示' || classWorkForm.worktype == '课堂展示') && currentRow.id>0" class="page-center"> <div v-if="(currentRow.worktype == '课堂展示' || classWorkForm.worktype == '课堂展示') && currentRow.id>0" class="page-center">
<div v-loading="boardLoading" class="board-wrap" style="height: 100%; flex: 1; overflow: hidden;"> <div v-loading="boardLoading" class="board-wrap" style="height: 100%; flex: 1; overflow: hidden;">
<!-- <whiteboard v-if="isShowBoard" ref="boardref" :height="mainHeight - 150" :isShowSave="false" :data="whiteboardObj"/> -->
<whiteboard ref="boardref" height="100%" width="100%" :isShowSave="false" :data="classWorkForm.whiteboardObj" /> <whiteboard ref="boardref" height="100%" width="100%" :isShowSave="false" :data="classWorkForm.whiteboardObj" />
</div> </div>
</div> </div>
@ -600,7 +599,8 @@ const handleClassWorkFormQuizRemove = (index) =>{
} }
else if(classWorkForm.worktype === "科学实验"){ else if(classWorkForm.worktype === "科学实验"){
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验的课程!'}); if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验的课程!'});
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); cform.worktag = useClassTaskStores.experimentObj.updateEduInfo; // , [-]
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); //
cform.entpcourseworklist = JSON.stringify([{'id':-3, 'score': '10'}]); cform.entpcourseworklist = JSON.stringify([{'id':-3, 'score': '10'}]);
try { try {
console.log(cform,'科学实验') console.log(cform,'科学实验')
@ -807,12 +807,14 @@ const editWork = async (cform) =>{
else if (classWorkForm.worktype=='科学实验') { //TODO fileHomeworkList else if (classWorkForm.worktype=='科学实验') { //TODO fileHomeworkList
// 1. (, ) // 1. (, )
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
cform.worktag = useClassTaskStores.experimentObj.updateEduInfo;
} }
// 3. // 3.
let res = await updateClasswork(cform); let res = await updateClasswork(cform);
if (res.code == 200) { if (res.code == 200) {
ElMessage.success('更新成功'); ElMessage.success('更新成功');
taskList.value = []
// //
if(isShow.value){ if(isShow.value){
currentRow.value.id = 1; currentRow.value.id = 1;

View File

@ -129,6 +129,7 @@ import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import QuesItem from "@/views/classTask/newClassTaskAssign/questionUpload/quesItem/index.vue"; import QuesItem from "@/views/classTask/newClassTaskAssign/questionUpload/quesItem/index.vue";
import { useHandleData } from "@/hooks/useHandleData"; import { useHandleData } from "@/hooks/useHandleData";
import { processList } from '@/hooks/useProcessList'; import { processList } from '@/hooks/useProcessList';
import { isJson } from "@/utils/comm";
import { debounce } from '@/utils/comm' import { debounce } from '@/utils/comm'
@ -254,6 +255,7 @@ function Apis(key) {
const client = new Apis('/paht'); const client = new Apis('/paht');
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const evalId = props.bookobj.levelSecondId=='' ? props.bookobj.levelFirstId : props.bookobj.levelSecondId;
const queryForm = { const queryForm = {
// //
worktype: entpCourseWorkQueryParams.worktype.label, worktype: entpCourseWorkQueryParams.worktype.label,
@ -266,7 +268,7 @@ const t = function(name, time) {
// //
edustage: userStore.edustage, // this.userStore.edustage, edustage: userStore.edustage, // this.userStore.edustage,
edusubject: userStore.edusubject, // this.userStore.edusubject, edusubject: userStore.edusubject, // this.userStore.edusubject,
eid: props.bookobj.levelSecondId, // this.activeParams.lession.id, eid: evalId, // id
status: "1", status: "1",
editUserId: userStore.userId, editUserId: userStore.userId,
//orderby: 'concat(worktype,timestamp) DESC', //orderby: 'concat(worktype,timestamp) DESC',
@ -326,10 +328,13 @@ const handleQueryFromEntpCourseWork= async (queryType) => {
} }
//console.log("clueres.rows[i].childlist",clueres.rows[i].childlist); //console.log("clueres.rows[i].childlist",clueres.rows[i].childlist);
if (clueres.rows[i].childlist != '') { if (clueres.rows[i].childlist != '') {
clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']'); const tmpJson = '['+clueres.rows[i].childlist+']';
if (isJson(tmpJson)){
clueres.rows[i].childArray = JSON.parse(tmpJson);
for (var j=0; j<clueres.rows[i].childArray.length; j++) { for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, ''); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
} }
}
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
} }
@ -482,8 +487,16 @@ const debounceQueryData = debounce(() => {
}, 1000); }, 1000);
watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => { watch([
() => props.bookobj.levelFirstId,
() => props.bookobj.levelSecondId
], ([newLevelSecondId, newLevelFirstId], [oldLevelSecondId, oldLevelFirstId]) => {
console.log(props.bookobj,'课程选择') console.log(props.bookobj,'课程选择')
// , ,
if (props.bookobj.levelSecondId == '') {
workResource.entpCourseWorkList = [];
return;
}
debounceQueryData(); debounceQueryData();
}) })

View File

@ -43,7 +43,7 @@
</div> </div>
<!-- orc 使用说明 --> <!-- orc 使用说明 -->
<div class="import-manual-explain"> <div class="import-manual-explain">
<p>orc 使用说明</p> <p>orc 使用说明填空题暂无法整题识别</p>
<p>1本地浏览 </p> <p>1本地浏览 </p>
<p>2获取剪贴板图片 </p> <p>2获取剪贴板图片 </p>
<p>3整题识别可识别整张图片自动填充到对应内容 </p> <p>3整题识别可识别整张图片自动填充到对应内容 </p>
@ -127,7 +127,7 @@ const courseObj = reactive({
const activeAptTab = ref("人工录入"); const activeAptTab = ref("人工录入");
// false - api true - json // false - api true - json
const OCR_WORK_TEST = false; const OCR_WORK_TEST = true;
// [] // []
const cropOption = reactive({ const cropOption = reactive({
img: '', // url , base64, blob img: '', // url , base64, blob

View File

@ -2,7 +2,8 @@ import { ElMessageBox, ElMessage } from "element-plus";
import qs from "qs"; import qs from "qs";
import axios from 'axios' import axios from 'axios'
import request from '@/utils/request' import request from '@/utils/request'
import { pyOCRAPI } from "@/api/education/entpcoursework"; import { pyOCRAPI, getOcrContent } from "@/api/education/entpcoursework";
import useClassTaskStore from '@/store/modules/classTask'
const EXAM_JUDGED_DICTIONARY = ["正确", "对", "√", "T", "错误", "错", "×", "F"]; const EXAM_JUDGED_DICTIONARY = ["正确", "对", "√", "T", "错误", "错", "×", "F"];
@ -17,13 +18,10 @@ const baidubceConfig = {
'client_secret': 'oWb0M0YWMmZPMQIhIUkJX99ddr7h61qf', 'client_secret': 'oWb0M0YWMmZPMQIhIUkJX99ddr7h61qf',
}; };
export function getOcrContent(data) {
return request({ const {
url: '/ocr/exam', entpCourseWorkTypeList
method: 'post', } = useClassTaskStore();
data: data
})
}
/** /**
@ -45,7 +43,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
if (isLocalTest) { if (isLocalTest) {
// 临时本地测试json格式跟百度ocr一致 // 临时本地测试json格式跟百度ocr一致
const response = await fetch('/cropImgTest/single.json'); const response = await fetch('/cropImgTest/single2.json');
const resOcr = await response.json(); const resOcr = await response.json();
ocrJson = resOcr.results; ocrJson = resOcr.results;
// 识别内容拼接 // 识别内容拼接
@ -115,7 +113,6 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
examItem.params.push(obj); examItem.params.push(obj);
}); });
return examItem; return examItem;
} }
else if (examType.includes('单选题') || examType.includes('多选题')) { else if (examType.includes('单选题') || examType.includes('多选题')) {
/** 单选题/多选题 - 选项 */ /** 单选题/多选题 - 选项 */
@ -150,10 +147,10 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
} }
else if (curItem === 'workanswer') { else if (curItem === 'workanswer') {
// 该类型下只做[主观题]和[复合题]的处理 // 该类型下只做[主观题]和[复合题]的处理
if (examType.includes('主观题')) {
ocrTxt = ocrTxt.replace(/<br \/>/g, ''); ocrTxt = ocrTxt.replace(/<br \/>/g, '');
examItem = ocrTxt; examItem = ocrTxt;
} } else {
examItem = ocrTxt;
} }
// 返回转换格式后的识别内容 // 返回转换格式后的识别内容
@ -174,7 +171,7 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = ''
if (isLocalTest) { if (isLocalTest) {
// 临时本地测试json格式跟百度ocr一致 // 临时本地测试json格式跟百度ocr一致
const response = await fetch('/cropImgTest/single.json'); const response = await fetch('/cropImgTest/single1.json');
const resOcr = await response.json(); const resOcr = await response.json();
ocrJson = resOcr.results; ocrJson = resOcr.results;
// 识别内容拼接 // 识别内容拼接
@ -234,12 +231,14 @@ const ocrImg2Json = async (urlBase64) => {
ElMessage.error("未检测到截图图片, 请截取图片后再识别"); ElMessage.error("未检测到截图图片, 请截取图片后再识别");
return null; return null;
} }
let base64Code = urlBase64.split(",")[1]; let base64Code = urlBase64.split(",")[1];
const resOcr = await getOcrContent({ base64Code: base64Code }); const resOcr = await getOcrContent({ base64Code: base64Code });
if (resOcr.code !== 200) { if (resOcr.code !== 200) {
ElMessage.error("图片识别错误"); ElMessage.error("图片识别错误");
return null; return null;
} }
// const resToken = await bdyAPI_getToken(); // const resToken = await bdyAPI_getToken();
// if (resToken.status !== 200) { // if (resToken.status !== 200) {
// ElMessage.error("百度智能云用户标识有误"); // ElMessage.error("百度智能云用户标识有误");
@ -394,8 +393,8 @@ const assembleExam = (eachSub) => {
} }
// 第一部分[题干-选项] 处理 // 第一部分[题干-选项] 处理
titleAndWorkDesc = tmpList[0]; titleAndWorkDesc = tmpList[0];
// 将4个以上连续的下划线统一替换为5个 // 将3个以上连续的下划线统一替换为5个
titleAndWorkDesc = titleAndWorkDesc.replace(/_{4,}/g, '_____'); titleAndWorkDesc = titleAndWorkDesc.replace(/_{3,}/g, '_____');
// 第二部分[分析-答案] 处理 // 第二部分[分析-答案] 处理
let answerAndAnswer = {}; let answerAndAnswer = {};
@ -456,32 +455,35 @@ const assembleExam = (eachSub) => {
} }
} }
let tmpExam = null; // 目前暂屏蔽无[复合题], 故所有都算基础题
if (answer === '') { let tmpExam = processExamSingle(titleAndWorkDesc, answer);
/**
* 基础题型 - [单选题] [多选题] [填空题] [判断题] [主观题] // let tmpExam = null;
*/ // if (answer === '') {
tmpExam = processExamSingle(titleAndWorkDesc, answer); // /**
} // * 基础题型 - [单选题] [多选题] [填空题] [判断题] [主观题]
else { // */
// 匹配是否存在 1. 1 (1)的存在, 题目与答案都存在则说明题型为复合题(嵌套题) // tmpExam = processExamSingle(titleAndWorkDesc, answer);
regex = /^(\d+[..。]|\(\d+\)|\d+)/; // }
let answerFind = regex.test(answer); // else {
regex = /(\d+[..。]|\(\d+\)|\d+)/; // // 匹配是否存在 1. 1 (1)的存在, 题目与答案都存在则说明题型为复合题(嵌套题)
let titleFind = regex.test(titleAndWorkDesc); // regex = /^(\d+[..。]|\(\d+\)|\d+)/;
if (titleFind && answerFind) { // let answerFind = regex.test(answer);
/** // regex = /(\d+[..。]|\(\d+\)|\d+)/;
* [复合题] - 处理逻辑 // let titleFind = regex.test(titleAndWorkDesc);
*/ // if (titleFind && answerFind) {
tmpExam = processExamMulti(titleAndWorkDesc, answer); // /**
} // * [复合题] - 处理逻辑
else { // */
/** // tmpExam = processExamMulti(titleAndWorkDesc, answer);
* 基础题型 - [单选题] [多选题] [填空题] [判断题] [主观题] // }
*/ // else {
tmpExam = processExamSingle(titleAndWorkDesc, answer); // /**
} // * 基础题型 - [单选题] [多选题] [填空题] [判断题] [主观题]
} // */
// tmpExam = processExamSingle(titleAndWorkDesc, answer);
// }
// }
if (tmpExam) { if (tmpExam) {
// 错误信息 // 错误信息
@ -607,13 +609,21 @@ const processExamSingle = function (titleAndWorkDesc, answer) {
* 主观题 * 主观题
*/ */
// [题型] - 格式化 // [题型] - 格式化
examSingle.workType = "主观题"; const flagDict = ['单选题', '多选题', '判断题', '填空题'];
const another = entpCourseWorkTypeList.filter(item => !flagDict.includes(item.label));
if (another.length > 0) {
examSingle.workType = another[another.length-1].label;
// [题干]-格式化 // [题干]-格式化
examSingle.title = titleAndWorkDesc; examSingle.title = titleAndWorkDesc;
}
// [选项] - 格式化 --- 主观题无选项 // examSingle.workType = "主观题";
//examSingle.arrWorkDesc = [];
// // [题干]-格式化
// examSingle.title = titleAndWorkDesc;
// // [选项] - 格式化 --- 主观题无选项
// //examSingle.arrWorkDesc = [];
// [题目答案] - 处理 --- ['qweasd123'] // [题目答案] - 处理 --- ['qweasd123']
if (answer !== '') { if (answer !== '') {

View File

@ -8,7 +8,7 @@
<el-form ref="questFormRef" :model="questForm" :rules="MainRules" label-width="80px"> <el-form ref="questFormRef" :model="questForm" :rules="MainRules" label-width="80px">
<el-form-item label="题型" prop="worktype"> <el-form-item label="题型" prop="worktype">
<el-select v-model="questForm.worktype" placeholder="请选择题型" style="width:20%" :disabled="questForm.id==0?false:true"> <el-select v-model="questForm.worktype" placeholder="请选择题型" style="width:20%" :disabled="questForm.id==0?false:true">
<el-option v-for="item in fromOptions.type" :key="item.value" :label="item.label" :value="item.label"></el-option> <el-option v-for="item in fromOptions.type" :key="item.value" :label="item.label" :value="item.label" :disabled="item.label=='不限'"></el-option>
</el-select> </el-select>
<el-tag v-if="questForm.worktype=='填空题'" type="danger" style=" margin-left: 10px ">温馨提示填空题题目的填空位置下划线请连续输入3-10个 _ <el-tag v-if="questForm.worktype=='填空题'" type="danger" style=" margin-left: 10px ">温馨提示填空题题目的填空位置下划线请连续输入3-10个 _
符号eg今天___好日子</el-tag> 符号eg今天___好日子</el-tag>
@ -103,7 +103,7 @@
</div> </div>
<!-- 多选题 --> <!-- 多选题 -->
<div v-if="questForm.worktype=='多选题'" class="questForm-item-cover"> <div v-else-if="questForm.worktype=='多选题'" class="questForm-item-cover">
<div v-for="(item,index) in questForm.list" :key='index'> <div v-for="(item,index) in questForm.list" :key='index'>
<el-form-item <el-form-item
:label=Options(1,index) :label=Options(1,index)
@ -134,7 +134,7 @@
</div> </div>
<!-- 填空题 --> <!-- 填空题 -->
<div v-if="questForm.worktype=='填空题'" class="questForm-item-cover"> <div v-else-if="questForm.worktype=='填空题'" class="questForm-item-cover">
<div v-for="(item,index) in questForm.list" :key='index'> <div v-for="(item,index) in questForm.list" :key='index'>
<el-form-item :label=Options(3,index) :prop="`list.${index}.text`" <el-form-item :label=Options(3,index) :prop="`list.${index}.text`"
:rules="{required: true, message: '填空选项不能为空', trigger: 'blur'}"> :rules="{required: true, message: '填空选项不能为空', trigger: 'blur'}">
@ -157,7 +157,7 @@
</div> </div>
<!-- 判断题 --> <!-- 判断题 -->
<div v-if="questForm.worktype=='判断题'" class="questForm-item-cover"> <div v-else-if="questForm.worktype=='判断题'" class="questForm-item-cover">
<div v-for="(item,index) in questForm.list" :key='index'> <div v-for="(item,index) in questForm.list" :key='index'>
<el-form-item <el-form-item
v-if="index==0" v-if="index==0"
@ -176,7 +176,7 @@
</div> </div>
<!-- 主观题 --> <!-- 主观题 -->
<div v-if="questForm.worktype.indexOf('主观题') != -1" class="questForm-item-cover"> <div v-else-if="questForm.worktype.indexOf('主观题') != -1" class="questForm-item-cover">
<el-form-item label="答案"> <el-form-item label="答案">
<Tinymce v-model="questForm.workanswer" :upFileParams="{ <Tinymce v-model="questForm.workanswer" :upFileParams="{
lessionId: lessionid, lessionId: lessionid,
@ -239,7 +239,7 @@
<!-- 复合题 --> <!-- 复合题 -->
<div v-if="questForm.worktype=='复合题'" class="questForm-item-cover"> <div v-else-if="questForm.worktype=='复合题'" class="questForm-item-cover">
<el-form-item label="单项题型" :prop="worktype"> <el-form-item label="单项题型" :prop="worktype">
<el-select v-model="questForm.mulList.worktype" placeholder="请选择题型" style="width:20%"> <el-select v-model="questForm.mulList.worktype" placeholder="请选择题型" style="width:20%">
<!-- <el-option key="1" label="单选题" value="单选题"></el-option> --> <!-- <el-option key="1" label="单选题" value="单选题"></el-option> -->
@ -350,6 +350,19 @@
</div> </div>
</div> </div>
<!-- 非统一标准名称的解答题 -->
<div v-else class="questForm-item-cover">
<el-form-item label="答案">
<Tinymce v-model="questForm.workanswer" :upFileParams="{
lessionId: lessionid,
fileAlias: '单题上传',
}" />
</el-form-item>
<div class="item-cropper-btn">
<el-button v-show="isCropper" circle @click="cropperFormItem('workanswer')"><el-icon><Search /></el-icon></el-button>
</div>
</div>
<!-- 答案分析 --> <!-- 答案分析 -->
<div class="questForm-item-cover"> <div class="questForm-item-cover">
<el-form-item label="答案分析" prop="method"> <el-form-item label="答案分析" prop="method">
@ -623,8 +636,9 @@ onMounted(() => {
// //
if (entpCourseWorkTypeList.length>0) { if (entpCourseWorkTypeList.length>0) {
const flagDict = ['单选题', '多选题', '判断题', '填空题']; //const flagDict = ['', '', '', ''];
fromOptions.type = entpCourseWorkTypeList.filter(item => flagDict.includes(item.label)); //fromOptions.type = entpCourseWorkTypeList.filter(item => flagDict.includes(item.label));
fromOptions.type = entpCourseWorkTypeList
} }
if (entpCourseWorkGroupList.length>0) { if (entpCourseWorkGroupList.length>0) {
fromOptions.flag = entpCourseWorkGroupList; fromOptions.flag = entpCourseWorkGroupList;
@ -748,8 +762,8 @@ const resetForm = () =>{
const updateForm= async(item, submitIndex=0, submitType=1) =>{ const updateForm= async(item, submitIndex=0, submitType=1) =>{
console.log(item,'item'); console.log(item,'item');
// []1 // []1
if (!item.hasOwnProperty('stutus')) { if (!item.hasOwnProperty('status')) {
item.stutus = '1'; item.status = '1';
} }
// [], // [],
if (!item.hasOwnProperty('evalnodeid')) { if (!item.hasOwnProperty('evalnodeid')) {
@ -765,7 +779,6 @@ const updateForm= async(item, submitIndex=0, submitType=1) =>{
// 线线() // 线线()
item.title = item.title.replace(/<!--BA--><div class="quizPutTag" contenteditable="true">(?:&nbsp;)?<\/div><!--EA-->/g, '_____'); item.title = item.title.replace(/<!--BA--><div class="quizPutTag" contenteditable="true">(?:&nbsp;)?<\/div><!--EA-->/g, '_____');
if(item.worktype == '复合题') { if(item.worktype == '复合题') {
// [] // []
newList = [{text:""}]; newList = [{text:""}];
@ -902,11 +915,14 @@ const updateForm= async(item, submitIndex=0, submitType=1) =>{
}], }],
}, },
]; ];
newList = [];
//
newList = [{text:""}];
// [] // []
item.worktype = item.worktype.replace(/\(主观题\)/g, ''); //item.worktype = item.worktype.replace(/\(\)/g, '');
item.worktype = `${item.worktype}(主观题)`; //item.worktype = `${item.worktype}()`;
// //
// //
if(isJson(item.workanswer)){ if(isJson(item.workanswer)){
@ -1008,9 +1024,8 @@ const updateForm= async(item, submitIndex=0, submitType=1) =>{
lessionid.value = props.bookobj.levelSecondId? props.bookobj.levelSecondId : props.bookobj.levelFirstId; lessionid.value = props.bookobj.levelSecondId? props.bookobj.levelSecondId : props.bookobj.levelFirstId;
console.log('lessionid', lessionid.value); console.log('lessionid', lessionid.value);
// //
if( props.bookobj.node.edustage == '高中' && (props.bookobj.node.edusubject == '语文' || props.bookobj.node.edusubject == '英语') ){ if( props.bookobj.node.edusubject == '语文' || props.bookobj.node.edusubject == '英语' ){
const res = await listEvaluation({ edusubject: props.bookobj.node.edusubject, edustage: props.bookobj.node.edustage, itemkey: "subject", pageSize: 10 }); const res = await listEvaluation({ edusubject: props.bookobj.node.edusubject, edustage: props.bookobj.node.edustage, itemkey: "subject", pageSize: 10 });
const id = res.rows[0]?.id; const id = res.rows[0]?.id;
if (id) { if (id) {
@ -1083,6 +1098,7 @@ const updateForm= async(item, submitIndex=0, submitType=1) =>{
// status = 1, // status = 1,
// } // }
// emit('update-exam-single', updateStatus); // emit('update-exam-single', updateStatus);
console.log('updateFormone->', questForm)
}; };
const updateFormone=(item, submitIndex, submitType, formdataitem)=>{ const updateFormone=(item, submitIndex, submitType, formdataitem)=>{
@ -1437,14 +1453,9 @@ const submitForm=(formName) =>{
//param.workdesc = questForm.list.map(item => item.text).join('#&'); //param.workdesc = questForm.list.map(item => item.text).join('#&');
param.workdesc = JSON.stringify(questForm.list.map(item => item.text)); param.workdesc = JSON.stringify(questForm.list.map(item => item.text));
// [][] //
if (questForm.worktype === '单选题' || questForm.worktype === '多选题') {
//param.workanswer = questForm.checkAnswer.map(item => item).join('#&');
param.workanswer = JSON.stringify(questForm.checkAnswer);
}
// []
if(questForm.worktype === '复合题') { if(questForm.worktype === '复合题') {
// []
let workdesc = []; let workdesc = [];
let answer = []; let answer = [];
// 1.: (, 使form.title) // 1.: (, 使form.title)
@ -1501,9 +1512,33 @@ const submitForm=(formName) =>{
param.workdesc = JSON.stringify(workdesc); param.workdesc = JSON.stringify(workdesc);
param.workanswer = JSON.stringify(answer); param.workanswer = JSON.stringify(answer);
} }
else if (questForm.worktype === '单选题' || questForm.worktype === '多选题') {
// [][]
//param.workanswer = questForm.checkAnswer.map(item => item).join('#&');
param.workanswer = JSON.stringify(questForm.checkAnswer);
}
// [] "<div></div>#&<div></div>".replace(/<[^>]*>/g, "")
else if(questForm.worktype === '填空题'){
//
//param.workanswer = questForm.list.map(item => item.text).join('#&').replace(/<[^>]*>/g, "");
// [] ([] [][()], ) //
if(questForm.worktype.indexOf('主观题') !== -1) { param.workdesc = '';
param.workanswer = JSON.stringify(questForm.list.map(item => item.text));
}
// []
else if(questForm.worktype === '判断题'){
//
//param.workanswer = questForm.list.map(item => item.text).join('#&').replace(/<[^>]*>/g, "");
//
param.workdesc = '';
param.workanswer = JSON.stringify(questForm.checkAnswer);
}
else if(questForm.worktype.indexOf('主观题') !== -1) {
// warn: [] ([] [][()], )
// //
param.workdesc = ''; // param.workdesc = ''; //
// workanswer // workanswer
@ -1533,27 +1568,16 @@ const submitForm=(formName) =>{
// param.workdesc = ''; // // param.workdesc = ''; //
// param.workanswer = JSON.stringify(answer).replace(/<[^>]*>/g, ""); // param.workanswer = JSON.stringify(answer).replace(/<[^>]*>/g, "");
} }
else {
// [] "<div></div>#&<div></div>".replace(/<[^>]*>/g, "") // (), [], ocr
if(questForm.worktype === '填空题'){ param.workdesc = ''; //
// // workanswer
//param.workanswer = questForm.list.map(item => item.text).join('#&').replace(/<[^>]*>/g, ""); if (questForm.workanswer && questForm.workanswer != '') {
param.workanswer = JSON.stringify([questForm.workanswer]);
// }
param.workdesc = '';
param.workanswer = JSON.stringify(questForm.list.map(item => item.text));
} }
// []
if(questForm.worktype === '判断题'){
//
//param.workanswer = questForm.list.map(item => item.text).join('#&').replace(/<[^>]*>/g, "");
//
param.workdesc = '';
param.workanswer = JSON.stringify(questForm.checkAnswer);
}
// , (3) // , (3)
if (questForm.submitType === 3) { if (questForm.submitType === 3) {
@ -1703,37 +1727,40 @@ const myMessageShow=(title, msg, status)=>{
* @return: {*} * @return: {*}
* @param {*} list * @param {*} list
*/ */
const updateKnowledgePoint = (list) => { const formatKnowledgePoint = (list) => {
list.forEach(item => { list.forEach(item => {
if (item.title && item.title != '') { if (item.title && item.title != '') {
item.knowTitle = item.title; item.knowTitle = item.title;
} }
if (item.children && Array.isArray(item.children)) { if (item.children && Array.isArray(item.children)) {
updateKnowledgePoint(item.children); formatKnowledgePoint(item.children);
} }
}); });
return list; return list;
}; };
watch(() => props.bookobj.levelSecondId, async (newVal, oldVal) => { watch([
() => props.bookobj.levelFirstId,
() => props.bookobj.levelSecondId
], async([newLevelSecondId, newLevelFirstId], [oldLevelSecondId, oldLevelFirstId]) => {
console.log(props.bookobj,'课程选择') console.log(props.bookobj,'课程选择')
// props.bookobj.levelSecondId? props.bookobj.levelSecondId : props.bookobj.levelFirstId // props.bookobj.levelSecondId? props.bookobj.levelSecondId : props.bookobj.levelFirstId
lessionid.value = props.bookobj.levelSecondId? props.bookobj.levelSecondId : props.bookobj.levelFirstId; lessionid.value = props.bookobj.levelSecondId!='' ? props.bookobj.levelSecondId : props.bookobj.levelFirstId;
/** /**
* 格式化知识点: 分两种情况 * 格式化知识点: 分两种情况
* 1. 语文/英语: 获取学科下的所有知识点(该学科对应无章节与知识点绑定, 故只获取全知识点) * 1. 语文/英语: 获取学科下的所有知识点(该学科对应无章节与知识点绑定, 故只获取全知识点)
* 2. 其他: 获取当前章节下的所有知识点 * 2. 其他: 获取当前章节下的所有知识点
*/ */
let id = props.bookobj.levelSecondId; let id = lessionid.value;
if( props.bookobj.node.edustage == '高中' && (props.bookobj.node.edusubject == '语文' || props.bookobj.node.edusubject == '英语') ){ if( props.bookobj.node.edusubject == '语文' || props.bookobj.node.edusubject == '英语'){
id = props.bookobj.node.rootid; id = props.bookobj.node.rootid;
const res = await listEvaluation({ edusubject: props.bookobj.node.edusubject, edustage: props.bookobj.node.edustage, itemkey: "subject", pageSize: 10 }); const res = await listEvaluation({ edusubject: props.bookobj.node.edusubject, edustage: props.bookobj.node.edustage, itemkey: "subject", pageSize: 10 });
id = res.rows[0]?.id; id = res.rows[0]?.id;
if (id) { if (id) {
listKnowlegepointFormat({evalId: id, pageNum: 1, pageSize: 5000,}).then(res => { listKnowlegepointFormat({evalId: id, pageNum: 1, pageSize: 5000,}).then(res => {
//console.log('listKnowlegepointFormat->', res.rows); //console.log('listKnowlegepointFormat->', res.rows);
curKnowledgePointList.value = updateKnowledgePoint(res.rows); curKnowledgePointList.value = formatKnowledgePoint(res.rows);
}); });
} }
}else{ }else{

View File

@ -117,6 +117,8 @@ import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
import { getBindlist } from '@/api/education/knowledgePoint' import { getBindlist } from '@/api/education/knowledgePoint'
import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue' import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import { processList } from '@/hooks/useProcessList' import { processList } from '@/hooks/useProcessList'
import { isJson } from "@/utils/comm";
import { useGetHomework } from '@/hooks/useGetHomework' import { useGetHomework } from '@/hooks/useGetHomework'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import {throttle,debounce } from '@/utils/comm' import {throttle,debounce } from '@/utils/comm'
@ -190,6 +192,8 @@ const workResource = reactive({
onMounted(() => { onMounted(() => {
console.log('entpCourseWorkTypeList', entpCourseWorkTypeList); console.log('entpCourseWorkTypeList', entpCourseWorkTypeList);
// ()
getEntpCourseWorkPointList();
debounceQueryData(); // debounceQueryData(); //
}) })
@ -235,12 +239,13 @@ function Apis(key) {
const client = new Apis('/paht'); const client = new Apis('/paht');
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const evalId = props.bookobj.levelSecondId=='' ? props.bookobj.levelFirstId : props.bookobj.levelSecondId;
const queryForm = { const queryForm = {
// //
currentPage: paginationParams.pageNum, currentPage: paginationParams.pageNum,
pageSize: paginationParams.pageSize, pageSize: paginationParams.pageSize,
// //
eid: props.bookobj.levelSecondId, eid: evalId, // id
sectionName: props.bookobj.coursetitle, sectionName: props.bookobj.coursetitle,
edusubject: userStore.edusubject, edusubject: userStore.edusubject,
edustage: userStore.edustage, edustage: userStore.edustage,
@ -329,10 +334,13 @@ const handleQueryFromEntpCourseWork= async (queryType) => {
} }
//console.log("clueres.rows[i].childlist",clueres.rows[i].childlist); //console.log("clueres.rows[i].childlist",clueres.rows[i].childlist);
if (clueres.rows[i].childlist != '') { if (clueres.rows[i].childlist != '') {
clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']'); const tmpJson = '['+clueres.rows[i].childlist+']';
if (isJson(tmpJson)){
clueres.rows[i].childArray = JSON.parse(tmpJson);
for (var j=0; j<clueres.rows[i].childArray.length; j++) { for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, ''); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
} }
}
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
} }
@ -460,19 +468,29 @@ const captureScreenshot = (id) => {
// //
const debounceQueryData = debounce(() => { const debounceQueryData = debounce(() => {
console.log("防抖 加载数据中...") console.log("防抖 加载数据中...")
console.log(props.bookobj,'课程选择')
// //
initPageParams(); initPageParams();
// //
handleQueryFromEntpCourseWork(0); handleQueryFromEntpCourseWork(0);
// //
getQueryFromEvaluationclue(); //getQueryFromEvaluationclue();
// //
getEntpCourseWorkPointList(); //getEntpCourseWorkPointList();
}, 1000); }, 1000);
//watch(() => props.bookobj.levelSecondId, async (newVal, oldVal) => {
watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => { watch([
() => props.bookobj.levelFirstId,
() => props.bookobj.levelSecondId
], ([newLevelSecondId, newLevelFirstId], [oldLevelSecondId, oldLevelFirstId]) => {
console.log(props.bookobj,'课程选择') console.log(props.bookobj,'课程选择')
// , ,
if (props.bookobj.levelSecondId == '') {
workResource.entpCourseWorkList = [];
return;
}
debounceQueryData(); debounceQueryData();
}) })

View File

@ -58,10 +58,10 @@ import { useGetSubject } from '@/hooks/useGetSubject'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import useUserStore from '@/store/modules/user' // import useUserStore from '@/store/modules/user'
import useClassTaskStore from '@/store/modules/classTask' // import useClassTaskStore from '@/store/modules/classTask'
const userStore = useUserStore() // const userStore = useUserStore()
const classTaskStore = useClassTaskStore(); // const classTaskStore = useClassTaskStore();
const router = useRouter() const router = useRouter()
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
@ -217,7 +217,7 @@ onMounted(async ()=>{
chartInstance = echarts.init(chartDom.value) chartInstance = echarts.init(chartDom.value)
// //
await classTaskStore.initJYInfo(userStore.user); //await classTaskStore.initJYInfo(userStore.user);
const option = { const option = {

View File

@ -410,8 +410,8 @@ const changeBook = async(data) => {
let cata = parseCataByNode(data.node) let cata = parseCataByNode(data.node)
currentNode.value = data.node currentNode.value = data.node
uploadData.value.levelFirstId = cata[0] uploadData.value.levelFirstId = cata[0]
uploadData.value.levelSecondId = cata[1] uploadData.value.levelSecondId = cata[1] ?? ''
uploadData.value.levelThirdId = cata[2] uploadData.value.levelThirdId = cata[2] ?? ''
uploadData.value.textbookId = data.textBook.curBookId uploadData.value.textbookId = data.textBook.curBookId
getModelInfo({cataid: currentNode.value.id}).then(res=>{ getModelInfo({cataid: currentNode.value.id}).then(res=>{
console.log(res) console.log(res)

View File

@ -25,7 +25,7 @@
<c-form v-bind="classForm"> <c-form v-bind="classForm">
<template #item_classid="{prop, form}"> <template #item_classid="{prop, form}">
<span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span> <span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span>
<el-select v-else v-model="form[prop]" placeholder="请选择班级"> <el-select v-else v-model="form[prop]" placeholder="请选择班级" clearable>
<el-option v-for="item in listData.classList" :value="item.id" <el-option v-for="item in listData.classList" :value="item.id"
:label="`${item.caption} (${item.classstudentcount}人)`" /> :label="`${item.caption} (${item.classstudentcount}人)`" />
</el-select> </el-select>
@ -60,8 +60,8 @@
<template #item_mobile> <template #item_mobile>
<div> <div>
<div v-if="myClassActive.filetype=='apt'">开始新的课堂需要点击先创建课堂才能显示手机二维码</div> <div v-if="myClassActive.filetype=='apt'">开始新的课堂需要点击先创建课堂才能显示手机二维码</div>
<div v-else>开始新的课堂需要点击先创建课堂</div> <div v-else>开始新的课堂</div>
<el-button type="warning" :loading="dt.loading" @click="createClasscourse()">创建课堂</el-button> <!-- <el-button type="warning" :loading="dt.loading" @click="createClasscourse()">创建课堂</el-button> -->
<el-button type="success" @click="createClasscourse(true)">公屏上课</el-button> <el-button type="success" @click="createClasscourse(true)">公屏上课</el-button>
</div> </div>
</template> </template>
@ -139,6 +139,8 @@ onMounted(() => {
* @param classObj 课程对象-用于继续上课 * @param classObj 课程对象-用于继续上课
*/ */
const open = async (id, classObj) => { const open = async (id, classObj) => {
dt.loading = false
dt.loadingDel = false
visible.value = true visible.value = true
if (id) { if (id) {
// //
@ -167,6 +169,8 @@ const handleClose = async () => {
// await chat?.logout() // await chat?.logout()
// chat = null // chat = null
dt.ctCourse = null dt.ctCourse = null
dt.loading = false
dt.loadingDel = false
emit('close') emit('close')
} }
// - // -
@ -249,10 +253,10 @@ const getClasscourseList = async type => {
// isPublic // isPublic
const createClasscourse = async (isPublic = false) => { const createClasscourse = async (isPublic = false) => {
const { classid } = classForm.form const { classid } = classForm.form
if (!classid) { // if (!classid) {
ElMessage.warning('请选择班级') // ElMessage.warning('')
return // return
} // }
dt.loading = true dt.loading = true
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // const { entpcourseid, evalid, id, coursetitle } = myClassActive.value //
const curDate = commUtil.getDateNow('yyyy-MM-dd') const curDate = commUtil.getDateNow('yyyy-MM-dd')
@ -264,7 +268,7 @@ const createClasscourse = async (isPublic = false) => {
} }
// teacherForm.form.classcourseid = 100 // teacherForm.form.classcourseid = 100
teacherForm.form.classcourseid = await Http_Classcourse.addClasscourseReturnId(params) teacherForm.form.classcourseid = await Http_Classcourse.addClasscourseReturnId(params)
dt.loading = false .finally(() => {dt.loading = false})
// getClasscourseList('update') // // getClasscourseList('update') //
let msgEl = ElMessage.success('创建课程-成功') let msgEl = ElMessage.success('创建课程-成功')
// -pptList // -pptList
@ -372,9 +376,9 @@ const openPublicScreen = (classcourse, isPublic) => {
createWindow('open-win', { createWindow('open-win', {
url: '/pptist', // url: '/pptist', //
close: () => { close: () => {
sessionStore.set('curr.resource', null) // sessionStore.delete('curr.resource') //
sessionStore.set('curr.classcourse', null) // sessionStore.delete('curr.classcourse') //
sessionStore.set('curr.isPublic', null) // sessionStore.delete('curr.isPublic') //
} }
}) })
visible.value = false // visible.value = false //

View File

@ -10,7 +10,7 @@
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item> <el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item> <el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
<el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item> <!-- <el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item>-->
<el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item> <el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item>
<input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation"> <input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation">
</el-dropdown-menu> </el-dropdown-menu>
@ -449,6 +449,7 @@ export default {
} }
case 'click': { // --aippt case 'click': { // --aippt
if (row.fileFlag === 'aippt' && !!row.fileId) { if (row.fileFlag === 'aippt' && !!row.fileId) {
sessionStore.delete('curr.classcourse') //
const res = await getEntpcoursefile(row.fileId) const res = await getEntpcoursefile(row.fileId)
if (res && res.code === 200) { if (res && res.code === 200) {
this.openPublicScreen('edit', res.data, row) // - this.openPublicScreen('edit', res.data, row) // -
@ -497,11 +498,11 @@ export default {
createWindow('open-win', { createWindow('open-win', {
url: '/pptist', // url: '/pptist', //
close: () => { close: () => {
sessionStore.set('curr.resource', null) // sessionStore.delete('curr.resource') //
if (type=='edit') { if (type=='edit') {
sessionStore.set('curr.smarttalk', null) // sessionStore.delete('curr.smarttalk') //
this.asyncAllFile() // this.asyncAllFile() //
} else sessionStore.set('curr.classcourse', null) // } else sessionStore.delete('curr.classcourse') //
} }
}) })
}, },

View File

@ -206,7 +206,7 @@ export default {
width: 200px; width: 200px;
height: 200px; height: 200px;
position: relative; position: relative;
left: 150px; left: 100px;
overflow: hidden; overflow: hidden;
border-radius: 50%; border-radius: 50%;
} }

View File

@ -6,6 +6,7 @@
append-to-body append-to-body
@opened="modalOpened" @opened="modalOpened"
@close="closeDialog" @close="closeDialog"
width="100px"
> >
<CropperImage <CropperImage
ref="cropper" ref="cropper"