Compare commits

..

No commits in common. "main" and "2.5.7" have entirely different histories.
main ... 2.5.7

81 changed files with 930 additions and 3548 deletions

View File

@ -17,7 +17,6 @@ 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'

25
.env.yc
View File

@ -1,25 +0,0 @@
# 页面标题
VITE_APP_TITLE = 文枢课堂
# 生产环境配置
VITE_APP_ENV = 'production'
# AIx融合数字管理系统/生产环境
VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
VITE_APP_DOMAIN = 'prev.ysaix.com'
VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
# websocket 地址
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
# 是否显示开发工具
VITE_SHOW_DEV_TOOLS = 'false'

View File

@ -1,25 +0,0 @@
# 页面标题
VITE_APP_TITLE = 实训教学
# 生产环境配置
VITE_APP_ENV = 'production'
# AIx融合数字管理系统/生产环境
VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
VITE_APP_DOMAIN = 'prev.ysaix.com'
VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
# websocket 地址
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
# 是否显示开发工具
VITE_SHOW_DEV_TOOLS = 'false'

View File

@ -1,54 +0,0 @@
appId: com.electron.app.yc
productName: 文枢课堂
directories:
output: dist
buildResources: build
win:
executableName: 文枢课堂
icon: resources/yc-logo.png
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
asarUnpack:
- resources/**
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
artifactName: ${name}-yc-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://prev.ysaix.com:7868/src/assets/smarttalkyc/
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/
# 额外依赖打包到输出目录
extraFiles:
- from: ./node_modules/im_electron_sdk/lib/
to: ./resources
filter:
- '**/*'

View File

@ -1,54 +0,0 @@
appId: com.electron.app.yc2
productName: 实训教学
directories:
output: dist
buildResources: build
win:
executableName: 实训教学
icon: resources/yc-logo.png
files:
- '!**/.vscode/*'
- '!src/*'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
asarUnpack:
- resources/**
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
artifactName: ${name}-ycsx-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://prev.ysaix.com:7868/src/assets/smarttalkycsx/
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/
# 额外依赖打包到输出目录
extraFiles:
- from: ./node_modules/im_electron_sdk/lib/
to: ./resources
filter:
- '**/*'

View File

@ -1,6 +1,6 @@
{ {
"name": "aix-win-ws", "name": "aix-win-ws",
"version": "2.5.9", "version": "2.5.6",
"description": "", "description": "",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "上海交大重庆人工智能研究院", "author": "上海交大重庆人工智能研究院",
@ -16,8 +16,6 @@
"build:dev": "npm run build && electron-builder --win --config ./electron-builder-test.yml", "build:dev": "npm run build && electron-builder --win --config ./electron-builder-test.yml",
"build:test": "electron-vite build --mode test && electron-builder --win --config ./electron-builder.yml", "build:test": "electron-vite build --mode test && electron-builder --win --config ./electron-builder.yml",
"build:prod": "electron-vite build --mode production && electron-builder --win --config ./electron-builder-prod.yml", "build:prod": "electron-vite build --mode production && electron-builder --win --config ./electron-builder-prod.yml",
"build:yc": "electron-vite build --mode yc && electron-builder --win --config ./electron-builder-yc.yml",
"build:yc2": "electron-vite build --mode yc2 && electron-builder --win --config ./electron-builder-yc2.yml",
"build:lt": "electron-vite build --mode lt && electron-builder --win --config ./electron-builder-lt.yml", "build:lt": "electron-vite build --mode lt && electron-builder --win --config ./electron-builder-lt.yml",
"build:mac": "electron-vite build --mode production && electron-builder --mac --config ./electron-builder-prod.yml", "build:mac": "electron-vite build --mode production && electron-builder --mac --config ./electron-builder-prod.yml",
"build:linux": "npm run build && electron-builder --linux" "build:linux": "npm run build && electron-builder --linux"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

View File

@ -7,7 +7,6 @@ import Logger from './logger' // 日志封装
import chat from './chat' // chat封装 import chat from './chat' // chat封装
import Store from './store' // Store封装 import Store from './store' // Store封装
import updateInit from './update' import updateInit from './update'
// 代理 electron/remote // 代理 electron/remote
// 第一步引入remote // 第一步引入remote
import remote from '@electron/remote/main' import remote from '@electron/remote/main'
@ -42,19 +41,19 @@ if(!gotTheLock){
} }
}) })
} }
let logoIco = import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?'../../resources/yc-logo.png':'../../resources/logo2.ico'
//登录窗口 //登录窗口
function createLoginWindow() { function createLoginWindow() {
if (loginWindow) return if (loginWindow) return
loginWindow = new BrowserWindow({ loginWindow = new BrowserWindow({
width: import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?1060:888, width: 888,
height: 520, height: 520,
show: false, show: false,
frame: false, frame: false,
autoHideMenuBar: true, autoHideMenuBar: true,
maximizable: false, maximizable: false,
resizable: false, resizable: false,
icon: join(__dirname, logoIco), icon: join(__dirname, '../../resources/logo2.ico'),
...(process.platform === 'linux' ? { icon } : {}), ...(process.platform === 'linux' ? { icon } : {}),
webPreferences: { webPreferences: {
defaultEncoding: 'utf-8', defaultEncoding: 'utf-8',
@ -96,7 +95,7 @@ function createMainWindow() {
frame: false, // 无边框 frame: false, // 无边框
autoHideMenuBar: true, autoHideMenuBar: true,
maximizable: false, maximizable: false,
icon: join(__dirname, logoIco), icon: join(__dirname, '../../resources/logo2.ico'),
...(process.platform === 'linux' ? { icon } : {}), ...(process.platform === 'linux' ? { icon } : {}),
webPreferences: { webPreferences: {
defaultEncoding: 'utf-8', defaultEncoding: 'utf-8',

View File

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

View File

@ -74,6 +74,8 @@ const initLoad: Function = () => {
!!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// !!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)//
} }
return PPTApi.getSlideList(resource.id) return PPTApi.getSlideList(resource.id)
// PPTApi.updateWorkList()
// return Promise.resolve()
} }
return Promise.resolve() return Promise.resolve()
} }

View File

@ -14,8 +14,7 @@ export default () => {
const courseId = classcourse?.id // 课堂id const courseId = classcourse?.id // 课堂id
const timgroupid = classcourse?.timgroupid // 群组id const timgroupid = classcourse?.timgroupid // 群组id
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理 const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
// 上课状态才-初始化socket if (!ChatWs.ws) ChatWs.init()
if (!ChatWs.ws && !!courseId) ChatWs.init()
// 开课消息 // 开课消息
const startCourse = async() => { const startCourse = async() => {
// await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'open' }) // await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'open' })

View File

@ -1,47 +0,0 @@
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

@ -50,8 +50,6 @@ export class Utils {
}, delay) }, delay)
} }
} }
// 延时
static sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
} }
/** ppt相关后端接口处理 */ /** ppt相关后端接口处理 */
@ -61,7 +59,6 @@ export class PPTApi {
// 获取所有幻灯片列表 isUpdate为true不更新 // 获取所有幻灯片列表 isUpdate为true不更新
static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise<Boolean> { static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise<Boolean> {
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 } const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 }
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params) const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
@ -82,45 +79,25 @@ export class PPTApi {
// 活动列表处理 // 活动列表处理
// const workList = (res.rows || []).map(o => o.activityContent) // const workList = (res.rows || []).map(o => o.activityContent)
const workItem = res.rows ? [...res.rows] : [] const workItem = res.rows ? [...res.rows] : []
// 写入作业列表数据
// slidesStore.setWorkList(workList)
// 获取所有的pptlist的数据 // 获取所有的pptlist的数据
slidesStore.setWorkItem(workItem) slidesStore.setWorkItem(workItem)
// 没有上课时调用-作业列表
if(!classcourse) this.updateWorkList() this.updateWorkList()
// 没有上课时调用-批量更新缩略图
if(!classcourse) {
Utils.sleep(1500).then(() => {
this.batchUpdateThumUrl()
})
}
resolve(true) resolve(true)
} else msgUtils.msgError(res.msg || '获取数据失败');resolve(false) } else msgUtils.msgError(res.msg || '获取数据失败');resolve(false)
}) })
} }
/**
* @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: id, parentid: resource.id,
entpid: userStore.user.deptId, entpid: userStore.user.deptId,
entpcourseid: enpt.id, entpcourseid: enpt.id,
ppttype: 'file', ppttype: 'file',
@ -142,7 +119,7 @@ export class PPTApi {
// msgUtils.msgSuccess('新增成功') // msgUtils.msgSuccess('新增成功')
this.isUpdate = false // 新增后会触发监听,不再更新数据 this.isUpdate = false // 新增后会触发监听,不再更新数据
resolve(true) resolve(true)
} else msgUtils.msgError('新增失败');reject(false) } else msgUtils.msgError('新增失败');resolve(false)
}) })
} }
/** /**
@ -163,17 +140,22 @@ 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) return // 新增-这里不处理 状态管理-处理 if (isAdd) { // 新增的幻灯片(id 为非数字,说明是新增的幻灯片)
// 防抖-更新 const bool = await this.addSlide(currentSlide)
if (!this.isUpdate) return this.isUpdate = true // 下次更新数据 bool && await this.batchUpdateSlides(newData, true) // 批量更新-排序
if (isBatch) { // 批量更新-排序 const resource = sessionStore.get('curr.resource')||{}
this.batchUpdateSlides(newData, true) await PPTApi.getSlideList(resource.id)
} else { // 更新当前页幻灯片 } else { // 防抖-更新
const params = { if (!this.isUpdate) return this.isUpdate = true // 下次更新数据
id: currentSlide.id, if (isBatch) { // 批量更新-排序
datacontent: JSON.stringify(currentSlide), this.batchUpdateSlides(newData, true)
} else { // 更新当前页幻灯片
const params = {
id: currentSlide.id,
datacontent: JSON.stringify(currentSlide),
}
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
} }
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
} }
} }
// 更新幻灯片 isThum 是否更新缩略图 // 更新幻灯片 isThum 是否更新缩略图
@ -250,29 +232,10 @@ export class PPTApi {
}) })
} }
// 批量更新缩略图-异步
static batchUpdateThumUrl() {
return nextTick().then(async () => {
const list = slidesStore.workItem || []
if (!list.length) return
const upList = []
for (const [ind,o] of list.entries()) {
const isCreate = !o.fileurl // 是否创建
if (isCreate) {
const thumUrl = await this.getSlideThumUrl(ind)
upList.push({ id: o.id, fileurl: thumUrl })
}
}
if (!upList.length) return
// 批量更新
return await API_entpcoursefile.batchUpdateNew(upList)
})
}
// thumbnail-slide thumbnail 缩略图 // thumbnail-slide thumbnail 缩略图
static getSlideThumUrl(index?:number): Promise<Boolean> { static getSlideThumUrl(): Promise<Boolean> {
return nextTick().then(async() => { return nextTick().then(async() => {
const slideIndex = index ?? slidesStore.slideIndex const slideIndex = slidesStore.slideIndex
const elements = document.querySelectorAll('.thumbnail-slide') const elements = document.querySelectorAll('.thumbnail-slide')
if (elements.length && slideIndex >= 0) { if (elements.length && slideIndex >= 0) {
const element = elements[slideIndex] const element = elements[slideIndex]
@ -285,7 +248,6 @@ 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

@ -126,14 +126,10 @@ export class MsgEnum {
MSG_homework : 'HOMEWORK', MSG_homework : 'HOMEWORK',
/** @desc: 公屏 - 课堂作业|活动 */ /** @desc: 公屏 - 课堂作业|活动 */
MSG_pushSreen_work : 'pushSreen_work', MSG_pushSreen_work : 'pushSreen_work',
/** @desc: 公屏 - 实验 */
MSG_pushSreen_experiment : 'pushSreen_experiment',
/** @desc: 点赞 */ /** @desc: 点赞 */
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, render } from 'vue' import { watch } 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 状态管理
@ -10,12 +10,10 @@ import { MsgEnum } from './types' // 消息枚举
import ChatWs from '@/plugins/socket' // 聊天socket import ChatWs from '@/plugins/socket' // 聊天socket
import Classcourse from './classcourse' // 课程相关 import Classcourse from './classcourse' // 课程相关
import msgUtils from '@/plugins/modal' // 消息工具 import msgUtils from '@/plugins/modal' // 消息工具
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
@ -99,8 +97,6 @@ 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 // 动画步骤
@ -118,10 +114,6 @@ export default () => {
if (!content.id) return if (!content.id) return
Homework.showHomework(content.id) Homework.showHomework(content.id)
break break
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 打开实验:
if (!content.url) return
dialogUtils.openLink(content.url)
break
case MsgEnum.HEADS.MSG_closed: // 下课: case MsgEnum.HEADS.MSG_closed: // 下课:
close() close()
break break
@ -131,10 +123,6 @@ 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,6 +1,5 @@
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 () => {
@ -26,9 +25,6 @@ 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,8 +148,7 @@ export const useSlidesStore = defineStore('slides', {
this.workItem = list this.workItem = list
}, },
async addSlide(slide: Slide | Slide[]) { 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
@ -157,8 +156,6 @@ 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

@ -21,7 +21,6 @@ import { sessionStore } from '@/utils/store'
import { getSmarttalkPage } from '@/api/file' import { getSmarttalkPage } from '@/api/file'
import * as commUtils from '@/utils/comm.js' import * as commUtils from '@/utils/comm.js'
import { getFileSuffix } from '@/utils/ruoyi.js' import { getFileSuffix } from '@/utils/ruoyi.js'
import { PPTApi } from '../../../api'
const emit = defineEmits(['insertMaterial', 'close']) const emit = defineEmits(['insertMaterial', 'close'])
@ -61,31 +60,73 @@ const fileUrl = computed(() => (item) =>{
} }
}) })
// //
const onInsert = async (item) =>{ const onInsert = async (item) =>{
loading.value = true
const res = await fetch(item.fileFullPath) const res = await fetch(item.fileFullPath)
const bolb = await res.blob() const bolb = await res.blob()
const file = commUtils.blobToFile(bolb, item.fileShowName) const file = commUtils.blobToFile(bolb, item.fileShowName)
try { if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
const data = await PPTApi.toRousrceUrl(file) emit('insertMaterial',{ type: 'video', file })
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){ }
emit('insertMaterial',{ type: 'video', data }) else{
} emit('insertMaterial',{ type: 'img', file })
else{
emit('insertMaterial',{ type: 'img', data })
}
} finally {
loading.value = false
} }
} }
const GetUrlParameters = (parameters) => {
let resData = "";
let url = document.location.toString();
let arrUrl = url.split("?");
//
if (arrUrl.length > 1) {
//
let parametersArr = arrUrl[1].split("&");
//
for (let i = 0; i <= parametersArr.length; i++) {
if (parametersArr[i]) {
//
let parameterStr = parametersArr[i].split("=");
if (parameters == parameterStr[0]) {
resData = parameterStr[1];
break;
}
}
}
}
return resData;
}
const proxyToBase64 = (url)=> {
const dourl = GetUrlParameters(url)
console.log(dourl,'dourl')
return
axios({
url: "/api/logo.png",
method: "get",
responseType: "blob",
}).then((res) => {
const reader = new FileReader();
reader.readAsDataURL(res.data);
reader.onload = () => {
console.log(reader.result);
};
});
}
// //
const onClose = () =>{ const onClose = () =>{
emit('close') emit('close')
} }
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data);

View File

@ -281,17 +281,20 @@ const toggleNotesPanel = () => {
// //
interface MaterialParams { interface MaterialParams {
type: string, type: string,
data: string file: any
} }
const insertMaterial = async (item: MaterialParams) =>{ const insertMaterial = (item: MaterialParams) =>{
const { type, data } = item const { type, file } = item
if(type == 'video'){ PPTApi.toRousrceUrl(file).then(data=>{
createVideoElement(data) if(type == 'video'){
} createVideoElement(data)
else{ }
createImageElement(data) else{
} createImageElement(data)
materiaVisible.value = false }
materiaVisible.value = false
})
} }
// //

View File

@ -3,7 +3,7 @@
<div class="left"> <div class="left">
<Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible"> <Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible">
<template #content> <template #content>
<!-- <FileInput accept=".pptist" @change="files => { <FileInput accept=".pptist" @change="files => {
importSpecificFile(files) importSpecificFile(files)
mainMenuVisible = false mainMenuVisible = false
}"> }">
@ -15,8 +15,8 @@
}"> }">
<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>
@ -54,9 +54,9 @@
<div class="arrow-btn"><IconDown class="arrow" /></div> <div class="arrow-btn"><IconDown class="arrow" /></div>
</Popover> </Popover>
</div> </div>
<!-- <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')"> <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
<IconDownload class="icon" /> <IconDownload class="icon" />
</div> --> </div>
<div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`"> <div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`">
<el-avatar size="small" :src="avatar" /> <el-avatar size="small" :src="avatar" />
</div> </div>

View File

@ -25,12 +25,6 @@
<div style="margin-top: 10px">常规作业</div> <div style="margin-top: 10px">常规作业</div>
</div> </div>
</el-button> </el-button>
<el-button size="small" title="科学实验" text style="height: 54px;margin-left: 0" @click="showDialog('科学实验')">
<div class="buttonDiv">
<svg width="26" height="26" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#646473"><path d="M901.705143 511.926857h-55.954286a8.045714 8.045714 0 0 1-8.045714-8.045714V183.881143H181.686857v656.091428H501.76c4.388571 0 8.045714 3.510857 8.045714 7.899429v56.027429c0 4.388571-3.657143 8.045714-8.045714 8.045714H141.750857a31.963429 31.963429 0 0 1-32.036571-32.036572V143.872c0-17.627429 14.336-31.963429 32.036571-31.963429H877.714286c17.700571 0 32.036571 14.336 32.036571 31.963429V503.954286c0 4.388571-3.657143 8.045714-8.045714 8.045714zM731.428571 911.945143a36.571429 36.571429 0 0 1-36.571428-36.571429v-109.714285H585.142857a36.571429 36.571429 0 0 1 0-73.142858h109.714286v-109.714285a36.571429 36.571429 0 0 1 73.142857 0v109.714285H877.714286a36.571429 36.571429 0 1 1 0 73.142858h-109.714286v109.714285a36.571429 36.571429 0 0 1-36.571429 36.571429z" p-id="22184"></path></svg>
<div style="margin-top: 10px">科学实验</div>
</div>
</el-button>
</div> </div>
<Divider /> <Divider />
@ -163,10 +157,6 @@ const type = ref<WorkType[]>([
{ {
label: '框架梳理', label: '框架梳理',
value: 'primary' value: 'primary'
},
{
label: '科学实验',
value: 'primary'
} }
]) ])

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,14 +221,10 @@ 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
PPTApi.toRousrceUrl(imageFile).then(data=>{ getImageDataURL(imageFile).then(dataURL => {
const props = { src: data } const props = { src: dataURL }
updateImage(props) updateImage(props)
}) })
// getImageDataURL(imageFile).then(dataURL => {
// const props = { src: dataURL }
// updateImage(props)
// })
} }
// //

View File

@ -36,8 +36,8 @@
</div> </div>
<div <div
class="tools-right" :class="{ 'visible': rightToolsVisible }" class="tools-right" :class="{ 'visible': rightToolsVisible }"
@mouseleave="toolTrigger('leave')" @mouseleave="rightToolsVisible = false"
@mouseenter="toolTrigger('enter')" @mouseenter="rightToolsVisible = true"
> >
<div class="content"> <div class="content">
<div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div> <div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
@ -47,13 +47,8 @@
<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-if="!classcourse" v-tooltip="'结束放映'" @click="exitScreening()" /> <IconPower class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
<IconPower class="tool-btn" v-else v-tooltip="'结束课堂'" @click="exitCourse()" size="30" fill="#d0021b" strokeLinecap="butt" /> <IconPower class="tool-btn close" v-if="chat.groupid" v-tooltip="'结束课堂'" @click="exitCourse()" />
<Share class="tool-btn" v-if="classcourse" v-tooltip="'分享'" @click="ShareCode()" />
</div>
<div :class="['tools-icon',{opacity:iconHide}]" @click.stop="toolTrigger('icon')">
<circle-double-down v-if="rightToolsVisible" theme="outline" size="30" fill="#409EFF"/>
<circle-double-up v-else="!rightToolsVisible" theme="outline" size="30" fill="#E6A23C"/>
</div> </div>
</div> </div>
</div> </div>
@ -76,8 +71,6 @@ 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, 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
@ -110,15 +103,12 @@ const { exitScreening } = useScreening()
const { fullscreenState, manualExitFullscreen } = useFullscreen() const { fullscreenState, manualExitFullscreen } = useFullscreen()
const chat:any = Chat() // const chat:any = Chat() //
const screenStore =useScreenStore()
const rightToolsVisible = ref(false) const rightToolsVisible = ref(false)
const writingBoardToolVisible = ref(false) const writingBoardToolVisible = ref(false)
const timerlVisible = ref(false) const timerlVisible = ref(false)
const slideThumbnailModelVisible = ref(false) const slideThumbnailModelVisible = ref(false)
const laserPen = ref(false) const laserPen = ref(false)
const timer = ref(0) // const screenStore =useScreenStore()
const iconHide = ref(false) //
const timerId = ref(null) // id
const contextmenus = (): ContextmenuItem[] => { const contextmenus = (): ContextmenuItem[] => {
return [ return [
{ {
@ -200,31 +190,7 @@ const contextmenus = (): ContextmenuItem[] => {
}, },
] ]
} }
//
const toolTrigger = (type:string) => {
const curT = Date.now()
if (curT - timer.value < 200) return
iconHide.value = false //
if (timerId.value) clearTimeout(timerId.value) //
switch (type) {
case 'icon': //
timer.value = curT
rightToolsVisible.value = !rightToolsVisible.value
break
case 'enter': //
timer.value = curT
rightToolsVisible.value = true
break
case 'leave': //
rightToolsVisible.value = false
break
default:
break
}
timerId.value = setTimeout(() => { //
iconHide.value = true //
}, 2000)
}
// //
const exitCourse = async () => { const exitCourse = async () => {
// console.log('', chat) // console.log('', chat)
@ -287,18 +253,6 @@ const exitCourse = async () => {
top: -66px; top: -66px;
} }
.tools-icon{
position: absolute;
right: 8px;
top: -35px;
z-index: 1;
cursor: pointer;
transition: opacity $transitionDelay;
&.opacity{
opacity: .35;
}
}
.content { .content {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

@ -10,10 +10,9 @@
<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" v-if="!classcourse" @click="exitScreening()"><IconPower class="tool-icon" /><span>结束放映</span></div> <div class="tool-btn" @click="exitScreening()"><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 class="tool-btn close" @click="exitCourse()" v-if="chat.groupid"><IconPower class="tool-icon" /><span>结束课堂</span></div>
</div> </div>
<div class="content"> <div class="content">
@ -79,7 +78,6 @@
</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'
@ -99,7 +97,6 @@ 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
@ -128,7 +125,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 chatApi:any = Chat() // const chat:any = Chat() //
const remarkFontSize = ref(16) const remarkFontSize = ref(16)
const currentSlideRemark = computed(() => { const currentSlideRemark = computed(() => {
@ -137,20 +134,15 @@ 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 chatApi.exitCourse() // await chat.exitCourse() //
exitScreening() // exitScreening() //
} }

View File

@ -1,26 +1,16 @@
<template> <template>
<div class="pptist-screen"> <div class="pptist-screen">
<BaseView :changeViewMode="changeViewMode" v-if="viewMode === 'base'" /> <BaseView :changeViewMode="changeViewMode" v-if="viewMode === 'base'" />
<PresenterView :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" /> <PresenterView :changeViewMode="changeViewMode" v-else-if="viewMode === 'presenter'" />
<!-- 点赞组件 --> <!-- 点赞组件 -->
<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 , nextTick} from 'vue' import { onMounted, onUnmounted, ref } 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' // -
@ -28,13 +18,9 @@ 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
} }
@ -49,23 +35,6 @@ 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>
@ -77,8 +46,4 @@ 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

@ -2,8 +2,6 @@ import axios from 'axios'
import request from '@/utils/request' import request from '@/utils/request'
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
let rootPath = import.meta.env.VITE_APP_ENV === 'production' ? 'https://ai.ysaix.com:7864' : ''
// 文生图片 // 文生图片
export function convertTextToPicture(data) { export function convertTextToPicture(data) {
return axios({ return axios({
@ -44,7 +42,7 @@ export function getPicture(data) {
// 大模型对话生成prompt模板 // 大模型对话生成prompt模板
export function chattoprompt(dataset_id,prompt) { export function chattoprompt(dataset_id,prompt) {
return axios({ return axios({
url: rootPath + '/api/v1/parse/docs', url: '/api/v1/parse/docs',
method: 'post', method: 'post',
headers: { headers: {
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm', 'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
@ -70,7 +68,7 @@ export function textSensitiveWord(data) {
// 图片上传资源库 // 图片上传资源库
export function uploadPicture(data) { export function uploadPicture(data) {
return axios({ return axios({
url: import.meta.env.VITE_APP_BASE_API + '/smarttalk/file/upload', url: '/dev-api/smarttalk/file/upload',
method: 'post', method: 'post',
headers: { headers: {
'Accept': '*/*', 'Accept': '*/*',

View File

@ -71,14 +71,6 @@ 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({
@ -88,15 +80,6 @@ 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,17 +136,3 @@ 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,16 +102,4 @@ 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 }
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 KiB

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" :render-content="renderContent" <el-tree :data="treeData" accordion :props="defaultProps" node-key="id"
: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,18 +178,6 @@ 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

@ -1,42 +1,24 @@
<!--
依赖 vuedraggablev-viewer
属性: showToolbar // false
工具栏 添加图片默认6个测试图片不输入框添加则添加默认输入图片链接展示图片链接的图片
清空图片清空图片
事件: clear 清空时触发
outIndex 超出九个图片时触发
方法 addPic //
参数 src 图片链接
clearPic //
参数
使用方法 加载组件后通过ref调用addPic方法添加图片即可
-->
<template> <template>
<div style="position: relative;height: 100%;width: 100%;"> <div style="position: relative;height: 100%;width: 100%;">
<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);if(!gridPicList.length) emits('clear')} ">X</div> <div class="delete-btn" @click="gridPicList.splice(index,1)">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 class="grid-pic-toolbar"> <el-input style="position:fixed;bottom: 20px;right: 180px;width: 1000px" v-model="inputValue" type="text" />
<el-input v-if="showToolbar" style="width: 500px" v-model="inputValue" type="text" /> <el-button class="add-btn" @click="addPic">
<el-button v-if="showToolbar" class="add-btn" @click="pushPic"> 添加
添加 </el-button>
</el-button> <el-button style="position:fixed;bottom: 20px;right: 80px;" @click="startPencil">
<el-button class="add-btn" @click="clearPic">
清空
</el-button>
</div>
<!-- <el-button style="position:fixed;bottom: 20px;right: 80px;" @click="startPencil">
画笔 画笔
</el-button>--> </el-button>
<!-- <div class="modal-mode"> <div class="modal-mode">
<canvas id="canvas_pic_001" style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;"></canvas> <canvas id="canvas_pic_001" style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;"></canvas>
</div>--> </div>
</div> </div>
</template> </template>
@ -44,18 +26,10 @@
import {ref, computed, onMounted} from 'vue' import {ref, computed, onMounted} from 'vue'
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import ViewerItem from "./viewer-item.vue"; import ViewerItem from "./viewer-item.vue";
// import Fabric from 'fabric'; import Fabric from 'fabric';
const gridPicList = ref([]) const gridPicList = ref([])
const inputValue = ref('') const inputValue = ref('')
const isShow = ref(false) const isShow = ref(false)
const emits = defineEmits(['clear','outIndex']);
const props = defineProps({
showToolbar: {
type: Boolean,
default: false
}
})
// //
const getWH = (item,index)=>{ const getWH = (item,index)=>{
return { return {
@ -144,38 +118,21 @@
} }
}) })
const pushPic = () => {
let src = inputValue.value||picList[gridPicList.value.length]
addPic(src)
}
// //
const addPic = (data) => { const addPic = () => {
let list = Array.isArray(data)?data:[data] if (gridPicList.value.length >= 9) {
if (gridPicList.value.length + list.length > 9) {
console.log("超出九个图片")
emits('outIndex')
return return
} }
let listArr = []; let src = inputValue.value||picList[gridPicList.value.length]
for (let i = 0; i < list.length; i++) { if (!src) {
let src = list[i] return;
if (!src) {
console.log("图片链接不能为空")
return;
}
listArr.push({
src: src,
backgroundColor: getRandomColor()
})
} }
gridPicList.value.push(...listArr) gridPicList.value.push({
src: src,
backgroundColor: getRandomColor()
})
inputValue.value = '' inputValue.value = ''
} }
//
const clearPic = () => {
gridPicList.value = []
emits('clear')
}
// //
const startPencil = () => { const startPencil = () => {
isShow.value = !isShow.value isShow.value = !isShow.value
@ -191,7 +148,7 @@
b = b.length === 1? '0' + b : b; b = b.length === 1? '0' + b : b;
return `#${r}${g}${b}`; return `#${r}${g}${b}`;
} }
/* //初始化画 //
const initPend = () => { const initPend = () => {
let canvas = new Fabric.fabric.Canvas('canvas_pic_001',{ let canvas = new Fabric.fabric.Canvas('canvas_pic_001',{
interactive: false, interactive: false,
@ -205,11 +162,10 @@
canvas.freeDrawingBrush = new Fabric.fabric.PencilBrush(canvas) canvas.freeDrawingBrush = new Fabric.fabric.PencilBrush(canvas)
canvas.freeDrawingBrush.width = 1// canvas.freeDrawingBrush.width = 1//
canvas.freeDrawingBrush.color = "red"// canvas.freeDrawingBrush.color = "red"//
}*/ }
/*onMounted(() => { onMounted(() => {
initPend() initPend()
})*/ })
defineExpose({addPic,clearPic})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.modal-mode{ .modal-mode{
@ -248,13 +204,10 @@
} }
} }
} }
.grid-pic-toolbar{ .add-btn{
position: fixed; position: fixed;
right: 20px; right: 20px;
bottom: 20px; bottom: 20px;
display: flex;
.add-btn{
}
} }
@keyframes fadeIn { @keyframes fadeIn {
from { from {

View File

@ -12,7 +12,7 @@
<script setup> <script setup>
import {ref, watch, nextTick, onMounted} from "vue"; import {ref, watch, nextTick, onMounted} from "vue";
import { component as Viewer } from 'v-viewer' import { component as Viewer } from 'v-viewer'
// import Fabric from 'fabric'; import Fabric from 'fabric';
import 'viewerjs/dist/viewer.css' import 'viewerjs/dist/viewer.css'
const props = defineProps({ const props = defineProps({
images: { images: {
@ -36,13 +36,16 @@ const inited = (viewer) => {
} }
// //
const zoomed = (e) => { const zoomed = (e) => {
// setImgStyle() setImgStyle()
// console.log('zoomed', e)
} }
// //
const moved = (e) => { const moved = (e) => {
// setImgStyle() setImgStyle()
// console.log('moved',e)
} }
const move = (e) => { const move = (e) => {
// console.log('move', e)
} }
const appendCanvasToShow = () => { const appendCanvasToShow = () => {
initImgStyle() initImgStyle()
@ -89,7 +92,7 @@ const optins = ref({
"tooltip": true, "tooltip": true,
"zoomable": true, "zoomable": true,
"rotatable": true, "rotatable": true,
"movable": true, "movable": false,
"scalable": true, "scalable": true,
"transition": true, "transition": true,
"fullscreen": true, "fullscreen": true,
@ -97,9 +100,9 @@ const optins = ref({
}) })
const initViewers = () => { const initViewers = () => {
refs.value['viewerRef'+props.index]?.rebuildViewer() refs.value['viewerRef'+props.index]?.rebuildViewer()
/*setTimeout(()=>{ setTimeout(()=>{
initImgStyle() initImgStyle()
},300)*/ },300)
} }
// //
const initPend = () => { const initPend = () => {
@ -130,18 +133,15 @@ watch(props.images, (newValue, oldValue) => {
}); });
*/ */
/*onMounted(()=>{ onMounted(()=>{
setTimeout(()=>{ setTimeout(()=>{
appendCanvasToShow() appendCanvasToShow()
}, 300) }, 300)
})*/ })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.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

@ -83,7 +83,7 @@
<!--AI 对话调整--> <!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" :curMode="curMode" :conversation_id="conversation_id"/> <AdjustDialog v-model="isAdjust" :type="type" :item="editItem" :curMode="curMode" :conversation_id="conversation_id"/>
<!--添加编辑提示词--> <!--添加编辑提示词-->
<keywordDialog v-model="isWordDialog" :item="editItem" :modeType="type" /> <keywordDialog v-model="isWordDialog" :item="editItem" />
</template> </template>
<script setup> <script setup>
@ -104,7 +104,7 @@ import { cloneDeep } from 'lodash'
const props = defineProps(['type']) const props = defineProps(['type'])
const { user } = useUserStore() const { user } = useUserStore()
const curMode = ref(2) const curMode = ref(1)
const modeOptions = ref([ const modeOptions = ref([
{ {
label: '教学大模型', label: '教学大模型',
@ -415,7 +415,7 @@ const onEditSave = async (item) => {
} }
// //
const onSaveTemp = async (item) => { const onSaveTemp = (item) => {
if (item.answer == '') return if (item.answer == '') return
const data = { const data = {
@ -425,10 +425,7 @@ const onSaveTemp = async (item) => {
content: item.answer, content: item.answer,
ex1: curNode.id ex1: curNode.id
} }
const res = await tempSave(data) tempSave(data).then(res => { })
if(!item.resultId){
item.resultId = res.data
}
} }
// ### ** // ### **

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" @mouseenter.capture="handleMouseEnter" @mouseleave.capture="handleMouseLeave"></div> <div class="canvasBox" ref="box"></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, onBeforeUnmount, ref, getCurrentInstance, watch, toRaw, nextTick, computed, reactive, defineProps, defineEmits } from 'vue' import { onMounted, ref, 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,7 +305,6 @@ 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: {
@ -508,7 +507,6 @@ const backToCenter = () => {
app.scrollToCenter() app.scrollToCenter()
} }
// //
const showFit = () => { const showFit = () => {
let elementList = app.elements.elementList let elementList = app.elements.elementList
@ -702,6 +700,8 @@ const getCanvasBlob = async () =>{
}) })
} }
watch(() => props.data, (newVal) => { watch(() => props.data, (newVal) => {
if (newVal) { if (newVal) {
setCanvasData(newVal) setCanvasData(newVal)
@ -713,15 +713,8 @@ watch(() => props.data, (newVal) => {
// dom // dom
onMounted(() => { onMounted(() => {
init(); //
}) app = new TinyWhiteboard({
/**
* 初始化画布内容
*/
const init = () => {
//
app = new TinyWhiteboard({
container: box.value, container: box.value,
drawType: currentType.value, drawType: currentType.value,
state: { state: {
@ -741,7 +734,6 @@ const init = () => {
}) })
// //
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)
} }
@ -789,39 +781,7 @@ const init = () => {
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({
@ -831,7 +791,7 @@ defineExpose({
getCanvasJson, getCanvasJson,
getCanvasBase64, getCanvasBase64,
setCanvasData, setCanvasData,
getCanvasBlob, getCanvasBlob
}) })
</script> </script>

View File

@ -38,7 +38,6 @@ const closeWindow = () => {
ElMessageBox.confirm('确认退出系统吗?', '提示', { ElMessageBox.confirm('确认退出系统吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
customClass: 'login-close-tool',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
userStore.logOut().then(() => { userStore.logOut().then(() => {
@ -55,11 +54,7 @@ onMounted(() =>{
}) })
</script> </script>
<style>
.login-close-tool {
-webkit-app-region: no-drag;
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
.header-tool { .header-tool {
width: 100%; width: 100%;

View File

@ -1,7 +1,5 @@
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') {
@ -34,7 +32,7 @@ export const editListItem = (row, courseObj) => {
worktype: '', // 设计中的作业类型 worktype: '', // 设计中的作业类型
quizlist: [], // 设计中的试题列表 quizlist: [], // 设计中的试题列表
chooseWorkLists: [],// 设计中的框架梳理list chooseWorkLists: [],// 设计中的框架梳理list
fileHomeworkList: [],//TODO 暂时共用这个字段(新增了 科学实验) 设计中的常规作业list fileHomeworkList: [],// 设计中的常规作业list
whiteboardObj: '',// 设计中的课堂展示对象 whiteboardObj: '',// 设计中的课堂展示对象
question: '', // 设计中的[课堂展示]的问题 question: '', // 设计中的[课堂展示]的问题
}; };
@ -114,24 +112,6 @@ export const editListItem = (row, courseObj) => {
return resolve(classtaskObj); return resolve(classtaskObj);
} }
} }
else if (row.worktype == '科学实验') {
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);
//
// console.log('科学实验', classtaskObj);
// 更新默认的科学实验( 学段 学科 以及实验科目)
console.log('科学实验', classtaskObj);
return resolve(classtaskObj);
}
}
} }
}); });
} }

View File

@ -87,15 +87,13 @@ const getHomeWorkList = async () => {
// } else // } else
// 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加 // 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加
if (res.rows[i].worktype == '课堂展示') { if (res.rows[i].worktype == '课堂展示') {
res.rows[i].workclass = 'success'; res.rows[i].workclass = 'primary';
} else if (res.rows[i].worktype == '框架梳理') { } else if (res.rows[i].worktype == '框架梳理') {
res.rows[i].workclass = 'warning'; res.rows[i].workclass = 'warning';
} else if (res.rows[i].worktype == '常规作业') { } else if (res.rows[i].worktype == '常规作业') {
res.rows[i].workclass = 'info'; res.rows[i].workclass = 'info';
} else if (res.rows[i].worktype == '习题训练') { } else if (res.rows[i].worktype == '习题训练') {
res.rows[i].workclass = 'danger'; res.rows[i].workclass = 'danger';
} else if (res.rows[i].worktype == '科学实验') {
res.rows[i].workclass = 'primary';
} else { } else {
res.rows[i].workclass = 'primary'; res.rows[i].workclass = 'primary';
} }

View File

@ -299,28 +299,21 @@ 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

@ -84,7 +84,7 @@ const isStadium = () => {
const headerMenus = isStadium() ?[{ const headerMenus = isStadium() ?[{
name: '教学实践', name: '教学实践',
id: 6, id: 4,
icon: 'icon-jiaoxueshijian', icon: 'icon-jiaoxueshijian',
path: '/prepare' path: '/prepare'
},]:[ },]:[
@ -94,12 +94,12 @@ const headerMenus = isStadium() ?[{
icon: 'icon-shouye', icon: 'icon-shouye',
path: '/model/index' path: '/model/index'
}, },
// { {
// name: '', name: '教学工作台',
// id: 2, id: 2,
// icon: 'icon-gongzuotai', icon: 'icon-gongzuotai',
// path: '/desktop' path: '/desktop'
// }, },
{ {
name: '教学实践', name: '教学实践',
id: 4, id: 4,

View File

@ -100,8 +100,6 @@ export class MsgEnum {
MSG_homework : 'HOMEWORK', MSG_homework : 'HOMEWORK',
/** @desc: 公屏 - 课堂作业|活动 */ /** @desc: 公屏 - 课堂作业|活动 */
MSG_pushSreen_work : 'pushSreen_work', MSG_pushSreen_work : 'pushSreen_work',
/** @desc: 公屏 - 实验 */
MSG_pushSreen_experiment : 'pushSreen_experiment',
/** @desc: 点赞 */ /** @desc: 点赞 */
MSG_dz : 'dz', MSG_dz : 'dz',
/** @desc: 疑惑 */ /** @desc: 疑惑 */

View File

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

View File

@ -403,11 +403,5 @@ export const dataSetJson = {
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006", "教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
"教材-高中-地理": "270516829fd111efb13c0242ac140006", "教材-高中-地理": "270516829fd111efb13c0242ac140006",
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005", "教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
"课标-小学-科学": "935cfec8bf6a11ef98950242ac140006",
"课标-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
"课标-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
"教材-小学-科学": "935cfec8bf6a11ef98950242ac140006",
"教材-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
"教材-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm" "鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
} }

View File

@ -1,49 +0,0 @@
/**
* 弹窗-函数
*/
import { h, render } from 'vue'
import { ElDialog } from 'element-plus'
// 打开弹窗-函数
export const openDialog = (option, content) => {
let vNode
const body = document.body
const dOpts = {
modelValue: true,
width: 800,
height: 600,
title: '添加-超连接',
draggable: true,
'onUpdate:modelValue': val => {
if (vNode && !val) render(null, body)
},
...option
}
vNode = h(ElDialog, dOpts, {
default: typeof content == 'function' ? content(h) : content
})
render(vNode, body)
}
// 打开链接
export const openLink = (option, title) => {
// https://phet.colorado.edu/sims/html/number-play/latest/number-play_zh_CN.html
const isStr = typeof option == 'string'
const opt = isStr ? {} : option
const url = isStr ? option : option?.url || option?.src || option?.href
const titleNew = isStr? title||'实验室' : option?.title || '添加-超连接'
openDialog({
title: titleNew,
...opt
}, (h) => {
return h('iframe', {
src: url,
width: '100%',
style: {
height: 'calc(80vh - 75px)',
},
scrolling: 'no',
frameborder: '0',
})
})
}

View File

@ -1,734 +0,0 @@
{
"title": "实验",
"data": {
"primary":[
{
"label": "数量比较",
"fileurl": "https://phet.colorado.edu/sims/html/number-compare/latest/number-compare_zh_CN.html",
"subject": "math"
},
{
"label": "数字游戏",
"fileurl": "https://phet.colorado.edu/sims/html/number-play/latest/number-play_zh_CN.html",
"subject": "math"
},
{
"label": "数轴:距离",
"fileurl": "https://phet.colorado.edu/sims/html/number-line-distance/latest/number-line-distance_zh_CN.html",
"subject": "math"
},
{
"label": "比率和比例",
"fileurl": "https://phet.colorado.edu/sims/html/ratio-and-proportion/latest/ratio-and-proportion_zh_CN.html",
"subject": "math"
},
{
"label": "数轴:运算",
"fileurl": "https://phet.colorado.edu/sims/html/number-line-operations/latest/number-line-operations_zh_CN.html",
"subject": "math"
},
{
"label": "数轴:整数",
"fileurl": "https://phet.colorado.edu/sims/html/number-line-integers/latest/number-line-integers_zh_CN.html",
"subject": "math"
},
{
"label": "向量的和:等式",
"fileurl": "https://phet.colorado.edu/sims/html/vector-addition-equations/latest/vector-addition-equations_zh_CN.html",
"subject": "math"
},
{
"label": "向量相加",
"fileurl": "https://phet.colorado.edu/sims/html/vector-addition/latest/vector-addition_zh_CN.html",
"subject": "math"
},
{
"label": "曲线拟合",
"fileurl": "https://phet.colorado.edu/sims/html/curve-fitting/latest/curve-fitting_zh_CN.html",
"subject": "math"
},
{
"label": "分数:带分数",
"fileurl": "https://phet.colorado.edu/sims/html/fractions-mixed-numbers/latest/fractions-mixed-numbers_zh_CN.html",
"subject": "math"
},
{
"label": "分数:入门",
"fileurl": "https://phet.colorado.edu/sims/html/fractions-intro/latest/fractions-intro_zh_CN.html",
"subject": "math"
},
{
"label": "构建一个分数",
"fileurl": "https://phet.colorado.edu/sims/html/build-a-fraction/latest/build-a-fraction_zh_CN.html",
"subject": "math"
},
{
"label": "分数:等式",
"fileurl": "https://phet.colorado.edu/sims/html/fractions-equality/latest/fractions-equality_zh_CN.html",
"subject": "math"
},
{
"label": "单位价格",
"fileurl": "https://phet.colorado.edu/sims/html/unit-rates/latest/unit-rates_zh_CN.html",
"subject": "math"
},
{
"label": "获得一个10",
"fileurl": "https://phet.colorado.edu/sims/html/make-a-ten/latest/make-a-ten_zh_CN.html",
"subject": "math"
},
{
"label": "木棒的计算问题",
"fileurl": "https://www.netpad.net.cn/resource_web/course/?pack_id=6dc2ab05-cb06-4716-92ca-e00fb89ad1e6#/20808",
"subject": "math"
},
{
"label": "几何光学",
"fileurl": "https://phet.colorado.edu/sims/html/geometric-optics/latest/geometric-optics_zh_CN.html",
"subject": "physics"
},
{
"label": "密度",
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
"subject": "physics"
},
{
"label": "能量滑板竞技场: 基础",
"fileurl": "https://phet.colorado.edu/sims/html/energy-skate-park-basics/latest/energy-skate-park-basics_zh_CN.html",
"subject": "physics"
},
{
"label": "法拉第定律",
"fileurl": "https://phet.colorado.edu/sims/html/faradays-law/latest/faradays-law_zh_CN.html",
"subject": "physics"
},
{
"label": "绳波",
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
"subject": "physics"
},
{
"label": "光的混合",
"fileurl": "https://phet.colorado.edu/sims/html/color-vision/latest/color-vision_zh_CN.html",
"subject": "physics"
},
{
"label": "平衡探究实验",
"fileurl": "https://phet.colorado.edu/sims/html/balancing-act/latest/balancing-act_zh_CN.html",
"subject": "physics"
},
{
"label": "受到压力",
"fileurl": "https://phet.colorado.edu/sims/html/under-pressure/latest/under-pressure_zh_CN.html",
"subject": "physics"
},
{
"label": "摩擦力",
"fileurl": "https://phet.colorado.edu/sims/html/friction/latest/friction_zh_CN.html",
"subject": "physics"
},
{
"label": "力和运动:基础",
"fileurl": "https://phet.colorado.edu/sims/html/forces-and-motion-basics/latest/forces-and-motion-basics_zh_CN.html",
"subject": "physics"
},
{
"label": "静电电压",
"fileurl": "https://phet.colorado.edu/sims/html/john-travoltage/latest/john-travoltage_zh_CN.html",
"subject": "physics"
},
{
"label": "万有引力实验",
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab/latest/gravity-force-lab_zh_CN.html",
"subject": "physics"
},
{
"label": "气球和静电(摩擦起电)",
"fileurl": "https://phet.colorado.edu/sims/html/balloons-and-static-electricity/latest/balloons-and-static-electricity_zh_CN.html",
"subject": "physics"
},
{
"label": "密度",
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
"subject": "biology"
},
{
"label": "基因表达基础",
"fileurl": "https://phet.colorado.edu/sims/html/gene-expression-essentials/latest/gene-expression-essentials_zh_CN.html",
"subject": "biology"
},
{
"label": "密度",
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
"subject": "sciences"
},
{
"label": "PH值",
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale/latest/ph-scale_zh_CN.html",
"subject": "sciences"
},
{
"label": "密度",
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
"subject": "chemistry"
},
{
"label": "创造一个分子",
"fileurl": "https://phet.colorado.edu/sims/html/build-a-molecule/latest/build-a-molecule_zh_CN.html",
"subject": "chemistry"
},
{
"label": "扩散",
"fileurl": "https://phet.colorado.edu/sims/html/diffusion/latest/diffusion_zh_CN.html",
"subject": "chemistry"
}
],
"junior": [
{
"label": "二项分布弹珠台几率",
"fileurl": "https://phet.colorado.edu/sims/html/plinko-probability/latest/plinko-probability_zh_CN.html",
"subject": "math"
},
{
"label": "建立方程",
"fileurl": "https://phet.colorado.edu/sims/html/function-builder/latest/function-builder_zh_CN.html",
"subject": "math"
},
{
"label": "三角函数之旅",
"fileurl": "https://phet.colorado.edu/sims/html/trig-tour/latest/trig-tour_zh_CN.html",
"subject": "math"
},
{
"label": "四则运算",
"fileurl": "https://phet.colorado.edu/sims/html/arithmetic/latest/arithmetic_zh_CN.html",
"subject": "math"
},
{
"label": "二次函数图像",
"fileurl": "https://phet.colorado.edu/sims/html/graphing-quadratics/latest/graphing-quadratics_zh_CN.html",
"subject": "math"
},
{
"label": "质量和弹簧",
"fileurl": "https://phet.colorado.edu/sims/html/masses-and-springs/latest/masses-and-springs_zh_CN.html",
"subject": "math"
},
{
"label": "等式探索:两个变量",
"fileurl": "https://phet.colorado.edu/sims/html/equality-explorer-two-variables/latest/equality-explorer-two-variables_zh_CN.html",
"subject": "math"
},
{
"label": "等式探索:基础",
"fileurl": "https://phet.colorado.edu/sims/html/equality-explorer-basics/latest/equality-explorer-basics_zh_CN.html",
"subject": "math"
},
{
"label": "等式探索",
"fileurl": "https://phet.colorado.edu/sims/html/equality-explorer/latest/equality-explorer_zh_CN.html",
"subject": "math"
},
{
"label": "面积模型代数",
"fileurl": "https://phet.colorado.edu/sims/html/area-model-algebra/latest/area-model-algebra_zh_CN.html",
"subject": "math"
},
{
"label": "面积模型:小数",
"fileurl": "https://phet.colorado.edu/sims/html/area-model-decimals/latest/area-model-decimals_zh_CN.html",
"subject": "math"
},
{
"label": "面积模型乘法",
"fileurl": "https://phet.colorado.edu/sims/html/area-model-multiplication/latest/area-model-multiplication_zh_CN.html",
"subject": "math"
},
{
"label": "面积模型入门",
"fileurl": "https://phet.colorado.edu/sims/html/area-model-introduction/latest/area-model-introduction_zh_CN.html",
"subject": "math"
},
{
"label": "钟摆实验",
"fileurl": "https://phet.colorado.edu/sims/html/pendulum-lab/latest/pendulum-lab_zh_CN.html",
"subject": "math"
},
{
"label": "斜抛运动",
"fileurl": "https://phet.colorado.edu/sims/html/projectile-motion/latest/projectile-motion_zh_CN.html",
"subject": "math"
},
{
"label": "表达式变换",
"fileurl": "https://phet.colorado.edu/sims/html/expression-exchange/latest/expression-exchange_zh_CN.html",
"subject": "math"
},
{
"label": "电路建设工具包:交流",
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-ac/latest/circuit-construction-kit-ac_zh_CN.html",
"subject": "physics"
},
{
"label": "交流虚拟实验室",
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-ac-virtual-lab/latest/circuit-construction-kit-ac-virtual-lab_zh_CN.html",
"subject": "physics"
},
{
"label": "碰撞实验室",
"fileurl": "https://phet.colorado.edu/sims/html/collision-lab/latest/collision-lab_zh_CN.html",
"subject": "physics"
},
{
"label": "能量滑板竞技场",
"fileurl": "https://phet.colorado.edu/sims/html/energy-skate-park/latest/energy-skate-park_zh_CN.html",
"subject": "physics"
},
{
"label": "向量相加",
"fileurl": "https://phet.colorado.edu/sims/html/vector-addition/latest/vector-addition_zh_CN.html",
"subject": "physics"
},
{
"label": "曲线拟合",
"fileurl": "https://phet.colorado.edu/sims/html/curve-fitting/latest/curve-fitting_zh_CN.html",
"subject": "physics"
},
{
"label": "引力实验室:基础",
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab-basics/latest/gravity-force-lab-basics_zh_CN.html",
"subject": "physics"
},
{
"label": "波动入门",
"fileurl": "https://phet.colorado.edu/sims/html/waves-intro/latest/waves-intro_zh_CN.html",
"subject": "physics"
},
{
"label": "扩散",
"fileurl": "https://phet.colorado.edu/sims/html/diffusion/latest/diffusion_zh_CN.html",
"subject": "physics"
},
{
"label": "气体基础",
"fileurl": "https://phet.colorado.edu/sims/html/gases-intro/latest/gases-intro_zh_CN.html",
"subject": "physics"
},
{
"label": "气体性质",
"fileurl": "https://phet.colorado.edu/sims/html/gas-properties/latest/gas-properties_zh_CN.html",
"subject": "physics"
},
{
"label": "质量与弹簧:基础",
"fileurl": "https://phet.colorado.edu/sims/html/masses-and-springs-basics/latest/masses-and-springs-basics_zh_CN.html",
"subject": "physics"
},
{
"label": "黑体辐射",
"fileurl": "https://phet.colorado.edu/sims/html/blackbody-spectrum/latest/blackbody-spectrum_zh_CN.html",
"subject": "physics"
},
{
"label": "能量的形式和转换",
"fileurl": "https://phet.colorado.edu/sims/html/energy-forms-and-changes/latest/energy-forms-and-changes_zh_CN.html",
"subject": "physics"
},
{
"label": "波的干涉",
"fileurl": "https://phet.colorado.edu/sims/html/wave-interference/latest/wave-interference_zh_CN.html",
"subject": "physics"
},
{
"label": "库仑定律",
"fileurl": "https://phet.colorado.edu/sims/html/coulombs-law/latest/coulombs-law_zh_CN.html",
"subject": "physics"
},
{
"label": "质量和弹簧",
"fileurl": "https://phet.colorado.edu/sims/html/masses-and-springs/latest/masses-and-springs_zh_CN.html",
"subject": "physics"
},
{
"label": "电容器实验:基础",
"fileurl": "https://phet.colorado.edu/sims/html/capacitor-lab-basics/latest/capacitor-lab-basics_zh_CN.html",
"subject": "physics"
},
{
"label": "电路组建实验:直流虚拟实验室",
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-dc-virtual-lab/latest/circuit-construction-kit-dc-virtual-lab_zh_CN.html",
"subject": "physics"
},
{
"label": "电路组建实验:直流",
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-dc/latest/circuit-construction-kit-dc_zh_CN.html",
"subject": "physics"
},
{
"label": "钟摆实验",
"fileurl": "https://phet.colorado.edu/sims/html/pendulum-lab/latest/pendulum-lab_zh_CN.html",
"subject": "physics"
},
{
"label": "斜抛运动",
"fileurl": "https://phet.colorado.edu/sims/html/projectile-motion/latest/projectile-motion_zh_CN.html",
"subject": "physics"
},
{
"label": "物质状态:基础",
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter-basics/latest/states-of-matter-basics_zh_CN.html",
"subject": "physics"
},
{
"label": "物质状态",
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter/latest/states-of-matter_zh_CN.html",
"subject": "physics"
},
{
"label": "重力和轨道",
"fileurl": "https://phet.colorado.edu/sims/html/gravity-and-orbits/latest/gravity-and-orbits_zh_CN.html",
"subject": "physics"
},
{
"label": "分子与光",
"fileurl": "https://phet.colorado.edu/sims/html/molecules-and-light/latest/molecules-and-light_zh_CN.html",
"subject": "physics"
},
{
"label": "PH值",
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale/latest/ph-scale_zh_CN.html",
"subject": "biology"
},
{
"label": "光的混合",
"fileurl": "https://phet.colorado.edu/sims/html/color-vision/latest/color-vision_zh_CN.html",
"subject": "biology"
},
{
"label": "自然选择",
"fileurl": "https://phet.colorado.edu/sims/html/natural-selection/latest/natural-selection_zh_CN.html",
"subject": "biology"
},
{
"label": "受到压力",
"fileurl": "https://phet.colorado.edu/sims/html/under-pressure/latest/under-pressure_zh_CN.html",
"subject": "sciences"
},
{
"label": "万有引力实验",
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab/latest/gravity-force-lab_zh_CN.html",
"subject": "sciences"
},
{
"label": "气球和静电(摩擦起电)",
"fileurl": "https://phet.colorado.edu/sims/html/balloons-and-static-electricity/latest/balloons-and-static-electricity_zh_CN.html",
"subject": "sciences"
},
{
"label": "气体基础",
"fileurl": "https://phet.colorado.edu/sims/html/gases-intro/latest/gases-intro_zh_CN.html",
"subject": "chemistry"
},
{
"label": "气体性质",
"fileurl": "https://phet.colorado.edu/sims/html/gas-properties/latest/gas-properties_zh_CN.html",
"subject": "chemistry"
},
{
"label": "黑体辐射",
"fileurl": "https://phet.colorado.edu/sims/html/blackbody-spectrum/latest/blackbody-spectrum_zh_CN.html",
"subject": "chemistry"
},
{
"label": "能量的形式和转换",
"fileurl": "https://phet.colorado.edu/sims/html/energy-forms-and-changes/latest/energy-forms-and-changes_zh_CN.html",
"subject": "chemistry"
},
{
"label": "库仑定律",
"fileurl": "https://phet.colorado.edu/sims/html/coulombs-law/latest/coulombs-law_zh_CN.html",
"subject": "chemistry"
},
{
"label": "分子极性",
"fileurl": "https://phet.colorado.edu/sims/html/molecule-polarity/latest/molecule-polarity_zh_CN.html",
"subject": "chemistry"
},
{
"label": "物质状态:基础",
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter-basics/latest/states-of-matter-basics_zh_CN.html",
"subject": "chemistry"
},
{
"label": "物质状态",
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter/latest/states-of-matter_zh_CN.html",
"subject": "chemistry"
},
{
"label": "原子的相互作用",
"fileurl": "https://phet.colorado.edu/sims/html/atomic-interactions/latest/atomic-interactions_zh_CN.html",
"subject": "chemistry"
},
{
"label": "卢瑟福散射",
"fileurl": "https://phet.colorado.edu/sims/html/rutherford-scattering/latest/rutherford-scattering_zh_CN.html",
"subject": "chemistry"
},
{
"label": "原子的相互作用",
"fileurl": "https://phet.colorado.edu/sims/html/atomic-interactions/latest/atomic-interactions_zh_CN.html",
"subject": "chemistry"
}
],
"senior": [
{
"label": "一次线性函数的拟合",
"fileurl": "https://phet.colorado.edu/sims/html/least-squares-regression/latest/least-squares-regression_zh_CN.html",
"subject": "math"
},
{
"label": "区域建造者",
"fileurl": "https://phet.colorado.edu/sims/html/area-builder/latest/area-builder_zh_CN.html",
"subject": "math"
},
{
"label": "绳波",
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
"subject": "math"
},
{
"label": "直线图形",
"fileurl": "https://phet.colorado.edu/sims/html/graphing-lines/latest/graphing-lines_zh_CN.html",
"subject": "math"
},
{
"label": "分数配对",
"fileurl": "https://phet.colorado.edu/sims/html/fraction-matcher/latest/fraction-matcher_zh_CN.html",
"subject": "math"
},
{
"label": "平衡探究实验",
"fileurl": "https://phet.colorado.edu/sims/html/balancing-act/latest/balancing-act_zh_CN.html",
"subject": "math"
},
{
"label": "绘图:斜率与截距",
"fileurl": "https://phet.colorado.edu/sims/html/graphing-slope-intercept/latest/graphing-slope-intercept_zh_CN.html",
"subject": "math"
},
{
"label": "函数构造器:基础",
"fileurl": "https://phet.colorado.edu/sims/html/function-builder-basics/latest/function-builder-basics_zh_CN.html",
"subject": "math"
},
{
"label": "比例游乐场",
"fileurl": "https://phet.colorado.edu/sims/html/proportion-playground/latest/proportion-playground_zh_CN.html",
"subject": "math"
},
{
"label": "二项分布弹珠台几率",
"fileurl": "https://phet.colorado.edu/sims/html/plinko-probability/latest/plinko-probability_zh_CN.html",
"subject": "physics"
},
{
"label": "原子的相互作用",
"fileurl": "https://phet.colorado.edu/sims/html/atomic-interactions/latest/atomic-interactions_zh_CN.html",
"subject": "physics"
},
{
"label": "电荷与电场",
"fileurl": "https://phet.colorado.edu/sims/html/charges-and-fields/latest/charges-and-fields_zh_CN.html",
"subject": "physics"
},
{
"label": "卢瑟福散射",
"fileurl": "https://phet.colorado.edu/sims/html/rutherford-scattering/latest/rutherford-scattering_zh_CN.html",
"subject": "physics"
},
{
"label": "光的折射",
"fileurl": "https://phet.colorado.edu/sims/html/bending-light/latest/bending-light_zh_CN.html",
"subject": "physics"
},
{
"label": "胡克定律",
"fileurl": "https://phet.colorado.edu/sims/html/hookes-law/latest/hookes-law_zh_CN.html",
"subject": "physics"
},
{
"label": "部分电路欧姆定律",
"fileurl": "https://phet.colorado.edu/sims/html/ohms-law/latest/ohms-law_zh_CN.html",
"subject": "physics"
},
{
"label": "电线的电阻",
"fileurl": "https://phet.colorado.edu/sims/html/resistance-in-a-wire/latest/resistance-in-a-wire_zh_CN.html",
"subject": "physics"
},
{
"label": "原子模型",
"fileurl": "https://phet.colorado.edu/sims/html/build-an-atom/latest/build-an-atom_zh_CN.html",
"subject": "physics"
},
{
"label": "分子极性",
"fileurl": "https://phet.colorado.edu/sims/html/molecule-polarity/latest/molecule-polarity_zh_CN.html",
"subject": "biology"
},
{
"label": "神经元",
"fileurl": "https://phet.colorado.edu/sims/html/neuron/latest/neuron_zh_CN.html",
"subject": "biology"
},
{
"label": "引力实验室:基础",
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab-basics/latest/gravity-force-lab-basics_zh_CN.html",
"subject": "sciences"
},
{
"label": "波动入门",
"fileurl": "https://phet.colorado.edu/sims/html/waves-intro/latest/waves-intro_zh_CN.html",
"subject": "sciences"
},
{
"label": "扩散",
"fileurl": "https://phet.colorado.edu/sims/html/diffusion/latest/diffusion_zh_CN.html",
"subject": "sciences"
},
{
"label": "气体基础",
"fileurl": "https://phet.colorado.edu/sims/html/gases-intro/latest/gases-intro_zh_CN.html",
"subject": "sciences"
},
{
"label": "气体性质",
"fileurl": "https://phet.colorado.edu/sims/html/gas-properties/latest/gas-properties_zh_CN.html",
"subject": "sciences"
},
{
"label": "分子与光",
"fileurl": "https://phet.colorado.edu/sims/html/molecules-and-light/latest/molecules-and-light_zh_CN.html",
"subject": "sciences"
},
{
"label": "绳波",
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
"subject": "sciences"
},
{
"label": "黑体辐射",
"fileurl": "https://phet.colorado.edu/sims/html/blackbody-spectrum/latest/blackbody-spectrum_zh_CN.html",
"subject": "sciences"
},
{
"label": "波的干涉",
"fileurl": "https://phet.colorado.edu/sims/html/wave-interference/latest/wave-interference_zh_CN.html",
"subject": "sciences"
},
{
"label": "重力和轨道",
"fileurl": "https://phet.colorado.edu/sims/html/gravity-and-orbits/latest/gravity-and-orbits_zh_CN.html",
"subject": "sciences"
},
{
"label": "同位素和原子的质量",
"fileurl": "https://phet.colorado.edu/sims/html/isotopes-and-atomic-mass/latest/isotopes-and-atomic-mass_zh_CN.html",
"subject": "chemistry"
},
{
"label": "分子与光",
"fileurl": "https://phet.colorado.edu/sims/html/molecules-and-light/latest/molecules-and-light_zh_CN.html",
"subject": "chemistry"
},
{
"label": "分子形状",
"fileurl": "https://phet.colorado.edu/sims/html/molecule-shapes/latest/molecule-shapes_zh_CN.html",
"subject": "chemistry"
},
{
"label": "分子形状:基础",
"fileurl": "https://phet.colorado.edu/sims/html/molecule-shapes-basics/latest/molecule-shapes-basics_zh_CN.html",
"subject": "chemistry"
},
{
"label": "反应物,生成物及未反应物",
"fileurl": "https://phet.colorado.edu/sims/html/reactants-products-and-leftovers/latest/reactants-products-and-leftovers_zh_CN.html",
"subject": "chemistry"
},
{
"label": "pH值:基础",
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale-basics/latest/ph-scale-basics_zh_CN.html",
"subject": "chemistry"
},
{
"label": "绳波",
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
"subject": "chemistry"
},
{
"label": "PH值",
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale/latest/ph-scale_zh_CN.html",
"subject": "chemistry"
},
{
"label": "配平化学方程式",
"fileurl": "https://phet.colorado.edu/sims/html/balancing-chemical-equations/latest/balancing-chemical-equations_zh_CN.html",
"subject": "chemistry"
},
{
"label": "酸碱溶度",
"fileurl": "https://phet.colorado.edu/sims/html/acid-base-solutions/latest/acid-base-solutions_zh_CN.html",
"subject": "chemistry"
},
{
"label": "浓度",
"fileurl": "https://phet.colorado.edu/sims/html/concentration/latest/concentration_zh_CN.html",
"subject": "chemistry"
},
{
"label": "气球和静电(摩擦起电)",
"fileurl": "https://phet.colorado.edu/sims/html/balloons-and-static-electricity/latest/balloons-and-static-electricity_zh_CN.html",
"subject": "chemistry"
},
{
"label": "比尔定律实验",
"fileurl": "https://phet.colorado.edu/sims/html/beers-law-lab/latest/beers-law-lab_zh_CN.html",
"subject": "chemistry"
},{
"label": "摩尔浓度",
"fileurl": "https://phet.colorado.edu/sims/html/molarity/latest/molarity_zh_CN.html",
"subject": "chemistry"
},
{
"label": "原子模型",
"fileurl": "https://phet.colorado.edu/sims/html/build-an-atom/latest/build-an-atom_zh_CN.html",
"subject": "chemistry"
}
]
}
}

View File

@ -1,131 +0,0 @@
/**
* ppt 转换为图片
*/
import { h, render, getCurrentInstance } from 'vue'
import { toPng, toJpeg } from 'html-to-image' // 引入html-to-image库
import { PPTXFileToJson } from "@/AixPPTist/src/hooks/useImport"
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
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))
/**
* @description: 渲染组件
* @param {*} node 节点或属性
* @param {*} props 属性
* @param {*} children 子元素
* @param {*} container 容器
*/
const renderComponent = (node, props = {}, children, container) => {
let vNode, body
if (!node) throw new Error('vNode is required')
if (typeof container == 'string') {
if (node == 'slide') {
vNode = h(ThumbnailSlide, props, children)
} else throw new Error('vNode has no corresponding component')
} else {
vNode = h(node, props, children)
}
if (!container) body = document.body // 默认为body
else { // 判断是否为字符串
if (typeof container == 'string') {
body = document.querySelector(container)
} else {
body = container
}
}
return render(vNode, body)
}
/**
* @description: 幻灯片转换为图片
* 提示icon组件找不到是应为 h() 渲染是底层创建的虚拟节点找不到全局组件
* @param {*} slides 幻灯片数据
* @param {*} options 配置 number 为幻灯片宽度 | object 为配置项
* @returns
*/
export const slidesToImg = (slides = [], options) => {
let width, option, ispng = true
if (typeof options =='number'){width = options; option = {}}
else {const { width: w, isPng, ...opt } = options;width = w; ispng=isPng; option = opt}
const slidesStore = useSlidesStore()
!!width && slidesStore.setViewportSize(width) // 设置幻灯片宽度
return new Promise(async(resolve) => {
const instance = getCurrentInstance()
console.log('instance', instance)
const slidesDom = []
for(const slide of slides) {
const props = { class: 'c-thumbnail', slide, size: 120, ...option }
const node = h(ThumbnailSlide, props)
slidesDom.push(node)
}
// 渲染组件到body
const props = { class: 'c-thumbnails', style:{position:'absolute',top:0,left:'-200vw'}}
renderComponent('div', props, slidesDom)
let imgs = []
const toImag = ispng? toPng : toJpeg
for(const slide of slidesDom) {
const img = await toImag(slide.el)
imgs.push(img)
}
// console.log('ppt生成图片: ', imgs)
// console.log('图片已生成,正在卸载组件')
!!width && slidesStore.setViewportSize(1000) // 设置幻灯片宽度-恢复
render(null, document.body) // 卸载组件
resolve(imgs)
})
}
/**
* description: ppt 文件转换为图片
* @param {*} file file 为文件对象| arrayBuffer 为数组
* @param {*} options 配置 number 为幻灯片宽度 | object 为配置项
* @returns
*/
export const pptToImg = async(file, options) => {
const { slides } = await PPTXFileToJson(file)
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

@ -9,7 +9,7 @@ export const asyncLocalFile = (item) => {
if (isAsync === true) { if (isAsync === true) {
item.async = 'on' item.async = 'on'
if (type === 'down') { if (type === 'down') {
// console.log(item) console.log(item)
ipcRenderer.send('download-file-default', { ipcRenderer.send('download-file-default', {
url: item.fileFullPath, url: item.fileFullPath,
fileName: item.fileNewName fileName: item.fileNewName

View File

@ -248,11 +248,10 @@ export function toolWindow(type, {url, isConsole, isWeb=true, option={}}) {
const devUrl = `${BaseUrl}${url}` const devUrl = `${BaseUrl}${url}`
const buildUrl = path.join(__dirname, 'index.html') const buildUrl = path.join(__dirname, 'index.html')
const urlAll = isDev ? devUrl : buildUrl const urlAll = isDev ? devUrl : buildUrl
let logoIco = import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?'/resources/yc-logo.png':'/resources/logo2.ico'
return new Promise(async(resolve) => { return new Promise(async(resolve) => {
const config = { const config = {
width, height, width, height,
icon: path.join(appPath, logoIco), icon: path.join(appPath, '/resources/logo2.ico'),
webPreferences: { webPreferences: {
preload: path.join(API.preloadPath, '/index.js'), preload: path.join(API.preloadPath, '/index.js'),
sandbox: false, sandbox: false,

View File

@ -154,14 +154,14 @@ const getClassWorkList = async () => {
// ---------------------------------------------- // ----------------------------------------------
// UI // UI
if (list[i].worktype == '课堂展示') { if (list[i].worktype == '学习目标定位') {
list[i].workclass = 'success' list[i].workclass = 'success'
list[i].workcodesList = JSON.parse(list[i].workcodes) list[i].workcodesList = JSON.parse(list[i].workcodes)
} else if (list[i].worktype == '科学实验') { } else if (list[i].worktype == '教材研读') {
list[i].workclass = 'primary' list[i].workclass = 'primary'
} else if (list[i].worktype == '框架梳理') { } else if (list[i].worktype == '框架梳理') {
list[i].workclass = 'warning' list[i].workclass = 'warning'
} else if (list[i].worktype == '常规作业') { } else if (list[i].worktype == '学科定位') {
list[i].workclass = 'info' list[i].workclass = 'info'
} else if (list[i].worktype == '习题训练') { } else if (list[i].worktype == '习题训练') {
list[i].workclass = 'danger' list[i].workclass = 'danger'

View File

@ -437,15 +437,13 @@ const queryPushRecords = (row) => {
// } else // } else
// TODO // TODO
if (res.rows[i].worktype == '课堂展示') { if (res.rows[i].worktype == '课堂展示') {
res.rows[i].workclass = 'success'; res.rows[i].workclass = 'primary';
} else if (res.rows[i].worktype == '框架梳理') { } else if (res.rows[i].worktype == '框架梳理') {
res.rows[i].workclass = 'warning'; res.rows[i].workclass = 'warning';
} else if (res.rows[i].worktype == '常规作业') { } else if (res.rows[i].worktype == '常规作业') {
res.rows[i].workclass = 'info'; res.rows[i].workclass = 'info';
} else if (res.rows[i].worktype == '习题训练') { } else if (res.rows[i].worktype == '习题训练') {
res.rows[i].workclass = 'danger'; res.rows[i].workclass = 'danger';
} else if (res.rows[i].worktype == '科学实验') {
res.rows[i].workclass = 'primary';
} else { } else {
res.rows[i].workclass = 'primary'; res.rows[i].workclass = 'primary';
} }

View File

@ -141,8 +141,7 @@
v-if=" v-if="
dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '常规作业' ||
dialogProps.studentObj.worktype == '课堂展示' || dialogProps.studentObj.worktype == '课堂展示' ||
dialogProps.studentObj.worktype == '框架梳理' || dialogProps.studentObj.worktype == '框架梳理'
dialogProps.studentObj.worktype == '科学实验'
" "
> >
<div v-for="(stuItem, sIndex) in dialogProps.studentQuizAllList" :key="stuItem.id"> <div v-for="(stuItem, sIndex) in dialogProps.studentQuizAllList" :key="stuItem.id">
@ -158,8 +157,7 @@
v-if=" v-if="
dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '常规作业' ||
dialogProps.studentObj.worktype == '课堂展示' || dialogProps.studentObj.worktype == '课堂展示' ||
dialogProps.studentObj.worktype == '框架梳理' || dialogProps.studentObj.worktype == '框架梳理'
dialogProps.studentObj.worktype == '科学实验'
" "
> >
<!-- 文件内容格式mp3/mp4/doc/docx/excel/pdf/ppt/pptx/jpg/jpeg/gif/png/txt -> <!-- 文件内容格式mp3/mp4/doc/docx/excel/pdf/ppt/pptx/jpg/jpeg/gif/png/txt ->
@ -212,13 +210,7 @@
<!-- 学生答题展示 --> <!-- 学生答题展示 -->
<div v-if="feedContentList.length > 0"> <div v-if="feedContentList.length > 0">
<div <div v-if="dialogProps.studentObj.worktype == '常规作业' && stuItem.rightanswer != ''&& stuItem.rightanswer != null">
v-if="
(dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '科学实验') &&
stuItem.rightanswer != '' &&
stuItem.rightanswer != null
"
>
<!-- 常规作业学生有的会答复 --> <!-- 常规作业学生有的会答复 -->
<p style="padding: 10px 0;text-align: left;">学生答复内容</p> <p style="padding: 10px 0;text-align: left;">学生答复内容</p>
<div style="padding: 0 20px;text-align: left;">{{stuItem.rightanswer}}</div> <div style="padding: 0 20px;text-align: left;">{{stuItem.rightanswer}}</div>
@ -435,7 +427,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 { getClassworkdata, updateClassworkevalList, updateClassWorkDataAutoFinish } from '@/api/classTask' import { updateClassworkeval, updateClassworkdata, getClassworkdata } 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';
@ -708,34 +700,30 @@ const acceptParams = async (params) => {
}) })
} else { } else {
// //
if (params.studentObj.worktype == '常规作业' || params.studentObj.worktype == '科学实验') { if (params.studentObj.worktype == '常规作业') {
if(params.studentObj.worktype == '常规作业'){ try {
try { // datacontent TODO
// datacontent TODO const res = await getClassworkdata(params.studentObj.id);
const res = await getClassworkdata(params.studentObj.id); if(res.data.datacontent != ''){
if(res.data.datacontent != ''){ const teachWorkFileList = JSON.parse(res.data.datacontent);
const teachWorkFileList = JSON.parse(res.data.datacontent); console.log(teachWorkFileList, '老师filelist-------------')
console.log(teachWorkFileList, '老师filelist-------------') teachWorkFileList &&
teachWorkFileList && teachWorkFileList.forEach((item) => {
teachWorkFileList.forEach((item) => { if (
if ( item.name.indexOf('jpg') > -1 ||
item.name.indexOf('jpg') > -1 || item.name.indexOf('jpeg') > -1 ||
item.name.indexOf('jpeg') > -1 || item.name.indexOf('png') > -1
item.name.indexOf('png') > -1 ) {
) { teachImageList.value.push(item)
teachImageList.value.push(item) } else {
} else { teachFileList.value.push(item)
teachFileList.value.push(item) }
} })
}) teacherFeedContentList.value.push(teachWorkFileList)
teacherFeedContentList.value.push(teachWorkFileList)
}
} catch (error) {
console.error('Invalid JSON:', error)
} }
}else{
// TODO 2024-12-20 } catch (error) {
console.error('Invalid JSON:', error)
} }
params.studentQuizAllList.forEach((item) => { params.studentQuizAllList.forEach((item) => {
@ -890,45 +878,26 @@ const onSubmit = () => {
updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm; updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm;
}; };
// //
updateClassWorkDataAutoFinish(formd).then(res => { updateClassworkdata(formd).then(res => {
}) })
// //
const queryList = []; classWorkFormScore.teacherRating &&
classWorkFormScore.teacherRating && classWorkFormScore.teacherRating.map((item, index) => { classWorkFormScore.teacherRating.map((item, index) => {
const queryParams = { const queryParams = {
id: item.id, id: item.id,
teacherRating: item.score, // teacherRating: item.score, //
rating: classWorkFormScore.rating, // rating: classWorkFormScore.rating, //
teacherremark: classWorkFormScore.teacherremark, // teacherremark: classWorkFormScore.teacherremark, //
timestamp: getTimeDate() // timestamp: getTimeDate() //
} }
queryList.push(queryParams) console.log(queryParams)
}) updateClassworkeval(queryParams).then((res) => {
//console.log('queryList->', queryList) // if(res.code == 200){
updateClassworkevalList(queryList).then((res) => { //
// 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,7 +55,6 @@
<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%"
@ -173,7 +172,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;">
@ -194,7 +193,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']"/>
@ -286,7 +285,6 @@ 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'
@ -461,13 +459,12 @@ 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: evalId, // id eid: props.bookobj.levelSecondId,
sectionName: props.bookobj.coursetitle, sectionName: props.bookobj.coursetitle,
edusubject: userStore.edusubject, edusubject: userStore.edusubject,
edustage: userStore.edustage, edustage: userStore.edustage,
@ -560,12 +557,9 @@ const getQueryFromEvaluationclue = () => {
} }
if (clueres.rows[i].childlist != '') { if (clueres.rows[i].childlist != '') {
const tmpJson = '['+clueres.rows[i].childlist+']'; clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
if (isJson(tmpJson)){ for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray = JSON.parse(tmpJson); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
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, '');
}
} }
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
@ -996,8 +990,6 @@ const initPageParams = () => {
onMounted(async() => { onMounted(async() => {
//
getEntpCourseWorkPointList();
}) })
// const refreshData = () => { // const refreshData = () => {
@ -1024,9 +1016,9 @@ const debounceQueryData = debounce(() => {
// //
handleQueryFromEntpCourseWork(0); handleQueryFromEntpCourseWork(0);
// //
//getQueryFromEvaluationclue(); getQueryFromEvaluationclue();
// //
//getEntpCourseWorkPointList(); getEntpCourseWorkPointList();
}, 1000); }, 1000);
watch(() => props.propsformobj.uniquekey, (newVal) => { watch(() => props.propsformobj.uniquekey, (newVal) => {
@ -1035,20 +1027,8 @@ 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

@ -29,15 +29,14 @@ import { ElMessage } from 'element-plus'
const emit = defineEmits(['itemClick']) const emit = defineEmits(['itemClick'])
const items = shallowRef([ const items = shallowRef([
{ title: '自主搜题', description: '上千万高质量习题资源,历届考试真题,每道题均有习题解析', icon: '#icon-soutibao-',type:'danger' }, { title: '自主搜题', description: '上千万高质量习题资源,历届考试真题,每道题均有习题解析', icon: '#icon-soutibao-',type:'primary' },
// { title: '', description: '', icon: '#icon-soutibao-',type:'danger' }, { title: '校本题库', description: '本校公共题库资源。', icon: '#icon-soutibao-',type:'primary' },
{ title: '个人题库', description: '老师上传维护自己的个人题库。', icon: '#icon-soutibao-',type:'danger' }, { title: '个人题库', description: '老师上传维护自己的个人题库。', icon: '#icon-soutibao-',type:'primary' },
// { title: '', description: '', icon: '#icon-tubiao_wuxing-',type:'primary' }, { title: '智能推荐', description: '通过对学生的薄弱知识点分析,推送不同难度的习题进行强化训练。', icon: '#icon-tubiao_wuxing-',type:'primary' },
{ title: '课堂展示', description: '通过课堂白板绘制作业,提升学生的创作思维能力。', icon: '#icon-huaban',type:'success' }, { title: '课堂展示', description: '通过课堂白板绘制作业,提升学生的创作思维能力。', icon: '#icon-huaban',type:'danger' },
{ title: '常规作业', description: '推送pdf、视频、音频、图片学生可以拍照上传。', icon: '#icon-zhaoxiangji',type:'info' }, { title: '常规作业', description: '推送pdf、视频、音频、图片学生可以拍照上传。', icon: '#icon-zhaoxiangji',type:'danger' },
// { title: 'AI', description: 'AI', icon: '#icon-jiqiren_o',type:'danger' }, { title: 'AI设计作业', description: '通过AI助手根据课标、教材、考试等分析结果智能创建作业。', icon: '#icon-jiqiren_o',type:'danger' },
{ title: '习题上传', description: '自己上传个人题库。', icon: '#icon-shangchuan',type:'danger' }, { title: '习题上传', description: '自己上传个人题库。', icon: '#icon-shangchuan',type:'danger' },
{ title: '科学实验', description: '学生完成虚拟仿真实验,并提交实验结果。', icon: '#icon-shangchuan',type:'primary' },
]); ]);
const handleClick = (item) => { const handleClick = (item) => {

View File

@ -1,62 +0,0 @@
<template>
<div style="display: flex;">
<el-select
v-model="value"
placeholder="请选择实验课程"
size="large"
style="width: 240px"
@change="onSelectOption"
>
<el-option
v-for="item in classTaskStore.experimentList"
:key="item.value"
:label="item.label"
:value="item.label"
/>
</el-select>
</div>
</template>
<script setup>
import useUserStore from '@/store/modules/user'
import {ArrowDown} from '@element-plus/icons-vue'
import { onMounted,ref } from 'vue';
import useClassTaskStore from '@/store/modules/classTask'
const userStore = useUserStore().user
const subjectList = ref([])
const classTaskStore = useClassTaskStore().experimentObj
// emit
let emit = defineEmits(['selectItem'])
const props = defineProps({
list: {
type: Array,
default: () => ([])
},
})
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(() => {
})
defineExpose({
updateLabel
})
</script>
<style scoped>
</style>

View File

@ -1,259 +0,0 @@
<template>
<div style="display: flex;">
<div style="margin-left: 15px">
<el-dropdown @command="handleUserEduStage">
<span class="el-dropdown-link">
<el-button class="custom-button" type="default" round >{{ useClassTaskStore().experimentObj.edustage }}
<el-icon><ArrowDown /></el-icon>
</el-button>
</span>
<template #dropdown>
<el-dropdown-menu>
<!-- <el-dropdown-item command="幼儿园">幼儿园</el-dropdown-item> -->
<el-dropdown-item command="小学">小学</el-dropdown-item>
<el-dropdown-item command="初中">初中</el-dropdown-item>
<el-dropdown-item command="高中">高中</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div style="margin-left: 15px">
<el-dropdown @command="handleUserEduSubject">
<span class="el-dropdown-link">
<el-button class="custom-button" type="default" round>{{ useClassTaskStore().experimentObj.edusubject }}
<el-icon><ArrowDown /></el-icon>
</el-button>
</span>
<template #dropdown>
<el-dropdown-menu>
<template v-for="(item, index) in subjectList">
<el-dropdown-item v-if="item.edustage == useClassTaskStore().experimentObj.edustage && isExpList(item.itemtitle)" :command="item.itemtitle">{{
item.itemtitle }}</el-dropdown-item>
</template>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script setup>
import useUserStore from '@/store/modules/user'
import {ArrowDown} from '@element-plus/icons-vue'
import { onMounted,ref } from 'vue';
import { listEvaluation } from '@/api/subject/index'
import jsonData from "@/utils/phetData.json";
import useClassTaskStore from '@/store/modules/classTask'
const userStore = useUserStore().user
// emit
// let emit = defineEmits(['experlist'])
// const expObj = ref({
// edustage: useClassTaskStore().experimentObj.edustage,
// edusubject: useClassTaskStore().experimentObj.edusubject,
// })
const subjectList = ref([])
const chooseGrade= ref({})
const expList = ref([]) //
const checkList = ref([])//
const isLoaded = ref(false);
//
const getSubject = () => {
//
// if(!userStore.subject) return
// listEvaluation({ itemkey: 'subject', pageSize: 500 }).then((res) => {
// const arr = userStore.subject.split(',')
// subjectList.value = res.rows.filter(item => arr.includes(String(item.id))).map(items => items)
// console.log(subjectList,'subjectList');
// })
// list
const edustageList = ['小学','初中','高中'];
const subList = ['数学','物理','化学','生物','科学'];
edustageList.forEach((item) => {
subList.forEach((subItems) => {
subjectList.value.push({
edustage: item,
edusubject: subItems,
itemtitle: subItems
})
})
})
console.log(subjectList,'subjectList');
//
const edusubject = useClassTaskStore().experimentObj.edusubject;
handleUserEduStage(useClassTaskStore().experimentObj.edustage);
// , , .
useClassTaskStore().experimentObj.edusubject = edusubject;
// []
isLoaded.value = true;
//console.log('----');
}
//
const isExpList = (edusubject) => {
let list = [];
switch (edusubject){
case '数学':
list = expList.value.filter(item => item.subject === 'math')
break;
case '物理':
list = expList.value.filter(item => item.subject === 'physics')
break;
case '化学':
checkList.value = expList.value.filter(item => item.subject === 'chemistry')
break;
case '生物':
list = expList.value.filter(item => item.subject === 'biology')
break;
case '科学':
list = expList.value.filter(item => item.subject === 'sciences')
break;
}
return list.length > 0
}
//
const handleUserEduStage = (item) => {
// userStore.edustage = item
useClassTaskStore().experimentObj.edustage = item;
//
expList.value = []
if(item === '小学'){
chooseGrade.value = jsonData.data.primary
expList.value = chooseGrade.value
const newSubjectList = subjectList.value.filter(item => item.edustage === '小学');
for(let i in newSubjectList){
const name = newSubjectList[i].itemtitle
if(isExpList(name) && useClassTaskStore().experimentObj.edusubject===name){
//useClassTaskStore().experimentObj.edusubject = name;
//
handleUserEduSubject(name)
break;
}
}
}else if(item === '初中'){
chooseGrade.value = jsonData.data.junior
expList.value = chooseGrade.value
const newSubjectList = subjectList.value.filter(item => item.edustage === '初中');
for(let i in newSubjectList){
const name = newSubjectList[i].itemtitle
if(isExpList(name) && useClassTaskStore().experimentObj.edusubject===name){
//useClassTaskStore().experimentObj.edusubject = name;
//
handleUserEduSubject(name)
break;
}
}
}else if(item === '高中'){
chooseGrade.value = jsonData.data.senior
expList.value = chooseGrade.value
const newSubjectList = subjectList.value.filter(item => item.edustage === '高中');
for(let i in newSubjectList){
const name = newSubjectList[i].itemtitle
if(isExpList(name) && useClassTaskStore().experimentObj.edusubject===name){
//useClassTaskStore().experimentObj.edusubject = name;
//
handleUserEduSubject(name)
break;
}
}
}
}
//
const handleUserEduSubject = (item) => {
// userStore.edusubject = item;
useClassTaskStore().experimentObj.edusubject = item;
console.log(item,'选择的学科-------')
checkList.value = []
switch (item){
case '数学':
checkList.value = expList.value.filter(item => item.subject === 'math')
break;
case '物理':
checkList.value = expList.value.filter(item => item.subject === 'physics')
break;
case '化学':
checkList.value = expList.value.filter(item => item.subject === 'chemistry')
break;
case '生物':
checkList.value = expList.value.filter(item => item.subject === 'biology')
break;
case '科学':
checkList.value = expList.value.filter(item => item.subject === 'sciences')
break;
}
console.log(checkList.value,'checkList')
useClassTaskStore().experimentObj.experimentList = 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(() => {
getSubject()
})
defineExpose({
updateCheckList
})
</script>
<style scoped>
.custom-button {
width: auto;
border: 1px solid rgb(59, 130, 246);
outline: none;
outline-offset: none;
padding: 0 24px;
}
.custom-button i {
margin-left: 8px; /* 调整图标与文字之间的间距 */
}
</style>

View File

@ -1,114 +0,0 @@
<template>
<div class="experiment-page">
<div class="activeExp-header">
<div class="infomation" v-if="isStadium() !== true" >
<!-- <selectClass v-if="!isSubject" @experlist="getExperimentList" /> -->
<selectClass ref="selectClassRef"/>
</div>
<div>
<selectExperiment ref="selectExperimentRef" @selectItem="getExperimentListItem" />
</div>
</div>
<div ref="mainDiv" class="activeExp-main" style="overflow: auto">
<div v-if="!activeExp.fileurl"><el-empty description="暂无学科实验"></el-empty></div>
<iframe v-else :src="activeExp.fileurl" ref="myuunity" width="100%" height="100%" scrolling="no" frameborder="0"></iframe>
<!-- <phet/>-->
</div>
</div>
</template>
<script setup>
import { Search } from '@element-plus/icons-vue'
//import html2canvas from 'html2canvas';
import { onMounted, ref, watch, reactive, getCurrentInstance, nextTick } from 'vue'
import useUserStore from '@/store/modules/user'
import useClassTaskStore from '@/store/modules/classTask'
import selectClass from './components/selectClass.vue' //
import selectExperiment from './components/experimentList.vue' //
// emit
let emit = defineEmits(['clickExpObj'])
const { proxy } = getCurrentInstance()
const userStore = useUserStore().user
const props = defineProps({
bookobj: {
type: Object,
default: () => ({})
},
expObj: {
type: Object,
default: () => ({})
}
})
//
// const experimentList = ref([]);
const activeExp = ref({});
const selectExperimentRef = ref();
const selectClassRef = ref();
const isStadium = () => {
let roles = userStore.roles
return roles.some(item => item.roleKey === 'stadium')
}
// const mainLeftBarHeight = ref(0);
onMounted(() => {
// var mainLeftBar = document.getElementById("mainLeftBar");
// mainLeftBarHeight.value = document.documentElement.clientHeight-50-mainLeftBar.offsetParent.offsetTop - 10;
// getDivHeight()
// window.addEventListener('resize', getDivHeight)
})
// const getDivHeight = () => {
// const screenheight = window.innerHeight;
// proxy.$refs.mainDiv.style.height = screenheight-140 > 320 ? screenheight-140+'px' : 320+'px';
// console.log("height", proxy.$refs.mainDiv.style.height);
// // 704 +
// // mainDiv ref="mainDiv"
// }
//
// const getExperimentList = (val) => {
// console.log(val,'list')
// // experimentList.value = val;
// }
//
const getExperimentListItem = (val) => {
console.log(val,'选择的实验课程信息')
activeExp.value = val;
emit('clickExpObj', val)
}
//
watch(() => props.expObj.fileurl, (newVal, oldVal) => {
console.log(props.expObj,'科学实验科目')
activeExp.value = props.expObj;
//
nextTick(() => {
selectClassRef.value.updateCheckList();
selectExperimentRef.value.updateLabel(props.expObj.label);
})
})
</script>
<style scoped lang="scss">
.experiment-page {
height: 100%;
display: flex;
flex-direction: column;
.activeExp-header {
display: flex;
justify-content: space-between;
}
.activeExp-main{
flex: auto;
}
}
</style>

View File

@ -58,9 +58,9 @@
<el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst"> <el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst">
<SearchQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd" /> <SearchQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd" />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk"> <el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk">
<SchoolQuestion /> <SchoolQuestion />
</el-tab-pane> --> </el-tab-pane>
<el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst"> <el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst">
<MyQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd"/> <MyQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd"/>
</el-tab-pane> </el-tab-pane>
@ -68,7 +68,8 @@
</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 ref="boardref" height="100%" width="100%" :isShowSave="false" :data="classWorkForm.whiteboardObj" /> <!-- <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"/>
</div> </div>
</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">
@ -76,11 +77,6 @@
<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']"/>
</div> </div>
</div> </div>
<div v-if="(currentRow.worktype == '科学实验' || classWorkForm.worktype == '科学实验')&& currentRow.id>0" class="page-center">
<div class="experiment-homework">
<ExperimentQuestion :expObj="classWorkForm.fileHomeworkList&&classWorkForm.fileHomeworkList[0]" @clickExpObj="getExpObj" />
</div>
</div>
<div v-if="currentRow.id>0 " class="page-right"> <div v-if="currentRow.id>0 " class="page-right">
<div class="prepare-top" > <div class="prepare-top" >
@ -144,7 +140,6 @@ import { editListItem } from '@/hooks/useClassTask'
import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue' import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue'
import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue' import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue'
import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue' import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue'
import ExperimentQuestion from "@/views/classTask/newClassTaskAssign/experimentQuestion/index.vue";
import whiteboard from '@/components/whiteboard/whiteboard.vue' import whiteboard from '@/components/whiteboard/whiteboard.vue'
import FileUpload from "@/components/FileUpload/index.vue"; import FileUpload from "@/components/FileUpload/index.vue";
import Right from './Right/index.vue' import Right from './Right/index.vue'
@ -199,7 +194,7 @@ const fileLoading = ref(false); // 常规作业loading
onMounted(() => { onMounted(() => {
console.log("----onMounted-------") console.log("----onMounted-------")
currentRow.value.id = 0 currentRow.value = {id:0};
if(propsQueryCourseObj){ if(propsQueryCourseObj){
if(JSON.parse(propsQueryCourseObj)){ if(JSON.parse(propsQueryCourseObj)){
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj //
@ -234,7 +229,7 @@ const isInToMyQuestion = () => {
if(useClassTaskStores.isOpenQuestUploadView){ if(useClassTaskStores.isOpenQuestUploadView){
useClassTaskStores.isOpenQuestUploadView = false; useClassTaskStores.isOpenQuestUploadView = false;
currentRow.value.id = 1; // currentRow.value = {id:1}; //
activeAptTab.value = "个人题库"; activeAptTab.value = "个人题库";
// //
classWorkForm.id = 0; classWorkForm.id = 0;
@ -263,16 +258,6 @@ watch(() => props.currentCourse, (newVal, oldVal) => {
} }
console.log(newVal,'newval'); console.log(newVal,'newval');
},{deep:true}) },{deep:true})
// ------------
const getExpObj = (obj)=>{
// obj:{
// fileurl: "https://phet.colorado.edu/sims/html/number-compare/latest/number-compare_zh_CN.html"
// label: ""
// subject: "math"
// }
classWorkForm.fileHomeworkList = [obj];
}
//------------ //------------
const handleItemClick = (itemName) => { const handleItemClick = (itemName) => {
console.log('itemName', itemName); console.log('itemName', itemName);
@ -281,7 +266,7 @@ const handleItemClick = (itemName) => {
return; return;
} }
currentRow.value.id = 1; // currentRow.value = {id:1}; //
/** /**
* 智能推荐AI设计作业 * 智能推荐AI设计作业
* 习题训练 自主搜题 校本题库 个人题库 * 习题训练 自主搜题 校本题库 个人题库
@ -324,7 +309,7 @@ const initHomeWork = async()=> {
const handleNewAllClass = () => { const handleNewAllClass = () => {
taskTable.value.setCurrentRow({});// taskTable.value.setCurrentRow({});//
currentRow.value.id = 0; // currentRow.value = {id:0}; //
//-------- //--------
classWorkForm.id = 0; classWorkForm.id = 0;
classWorkForm.uniquekey = ""; // classWorkForm.uniquekey = ""; //
@ -351,7 +336,7 @@ const handleDelete =() => {
return delClasswork(ids.join(',')); return delClasswork(ids.join(','));
}).then(() => { }).then(() => {
taskTable.value.setCurrentRow({});// taskTable.value.setCurrentRow({});//
currentRow.value.id = 0; // currentRow.value = {id:0}; //
taskList.value = []; taskList.value = [];
// initHomeWork(); // initHomeWork();
setTimeout(() => { setTimeout(() => {
@ -445,7 +430,7 @@ const handleCurrentChange = (val) => {
console.log(val,'???????????') console.log(val,'???????????')
if(val && val.id >0 ) { if(val && val.id >0 ) {
currentRow.value.id = 1; currentRow.value = val;
classWorkForm.worktype = val.worktype; // classWorkForm.worktype = val.worktype; //
editListItem(val, courseObj).then((obj) => { editListItem(val, courseObj).then((obj) => {
if(obj){ if(obj){
@ -536,7 +521,7 @@ const handleClassWorkFormQuizRemove = (index) =>{
if(isShow.value === false){ if(isShow.value === false){
if(classWorkForm.id != '' ) {// id if(classWorkForm.id != '' ) {// id
editWork(cform); // editWork(cform); //
return; return;
} }
} }
@ -597,33 +582,6 @@ const handleClassWorkFormQuizRemove = (index) =>{
fileLoading.value = false fileLoading.value = false
} }
} }
else if(classWorkForm.worktype === "科学实验"){
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验的课程!'});
cform.worktag = useClassTaskStores.experimentObj.updateEduInfo; // , [-]
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); //
cform.entpcourseworklist = JSON.stringify([{'id':-3, 'score': '10'}]);
try {
console.log(cform,'科学实验')
addClassworkReturnId(cform).then((res) => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "科学实验";
classWorkForm.uniquekey = ''; // props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = []; // list
classWorkForm.whiteboardObj = ''; // ? //
classWorkForm.fileHomeworkList = []; // list
classWorkForm.id = res
emits('getData',classWorkForm)
// TODO
})
} finally{
//
}
}
else { else {
// //
var ll = []; var ll = [];
@ -670,9 +628,9 @@ const handleClassWorkFormQuizRemove = (index) =>{
console.log('该清空左侧列表数据了'); console.log('该清空左侧列表数据了');
// //
if(isShow.value){ if(isShow.value){
currentRow.value.id = 1; currentRow.value = {id:1};
}else{ }else{
currentRow.value.id = 0; currentRow.value = {id:0};
} }
initHomeWork(); initHomeWork();
@ -709,10 +667,7 @@ const editWork = async (cform) =>{
}else{ }else{
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请上传常规作业附件!'}); if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请上传常规作业附件!'});
} }
}else if( classWorkForm.worktype == '科学实验') { }else {
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验科目!'});
}
else {
if (classWorkForm.chooseWorkLists.length == 0) { if (classWorkForm.chooseWorkLists.length == 0) {
// //
ElMessage.error('请先添加作业资源!'); ElMessage.error('请先添加作业资源!');
@ -804,23 +759,13 @@ const editWork = async (cform) =>{
// 1. (, ) // 1. (, )
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
} }
else if (classWorkForm.worktype=='科学实验') { //TODO fileHomeworkList
// 1. (, )
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){ currentRow.value = {id:0};
currentRow.value.id = 1;
}else{
currentRow.value.id = 0;
}
initHomeWork(); initHomeWork();
// // // //
// router.back() // router.back()
@ -920,11 +865,6 @@ const editWork = async (cform) =>{
padding: 20px; padding: 20px;
box-sizing: border-box; box-sizing: border-box;
} }
.experiment-homework{
padding: 15px;
height: 100%;
}
} }
.page-right { .page-right {
overflow: hidden; overflow: hidden;

View File

@ -129,7 +129,6 @@ 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'
@ -255,7 +254,6 @@ 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,
@ -268,7 +266,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: evalId, // id eid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
status: "1", status: "1",
editUserId: userStore.userId, editUserId: userStore.userId,
//orderby: 'concat(worktype,timestamp) DESC', //orderby: 'concat(worktype,timestamp) DESC',
@ -328,12 +326,9 @@ 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 != '') {
const tmpJson = '['+clueres.rows[i].childlist+']'; clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
if (isJson(tmpJson)){ for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray = JSON.parse(tmpJson); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
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, '');
}
} }
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
@ -487,16 +482,8 @@ const debounceQueryData = debounce(() => {
}, 1000); }, 1000);
watch([ watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
() => 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

@ -6,9 +6,9 @@
<el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst"> <el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst">
<SearchQuestion :bookobj="courseObj" :isHtml2canvas="true" @addQuizImgBs64="handleaddQuizImgBs64" /> <SearchQuestion :bookobj="courseObj" :isHtml2canvas="true" @addQuizImgBs64="handleaddQuizImgBs64" />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk"> <el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk">
<SchoolQuestion /> <SchoolQuestion />
</el-tab-pane> --> </el-tab-pane>
<el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst"> <el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst">
<MyQuestion :bookobj="courseObj" :isHtml2canvas="true" @addQuizImgBs64="handleaddQuizImgBs64"/> <MyQuestion :bookobj="courseObj" :isHtml2canvas="true" @addQuizImgBs64="handleaddQuizImgBs64"/>
</el-tab-pane> </el-tab-pane>

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 = true; const OCR_WORK_TEST = false;
// [] // []
const cropOption = reactive({ const cropOption = reactive({
img: '', // url , base64, blob img: '', // url , base64, blob

View File

@ -2,8 +2,7 @@ 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, getOcrContent } from "@/api/education/entpcoursework"; import { pyOCRAPI } from "@/api/education/entpcoursework";
import useClassTaskStore from '@/store/modules/classTask'
const EXAM_JUDGED_DICTIONARY = ["正确", "对", "√", "T", "错误", "错", "×", "F"]; const EXAM_JUDGED_DICTIONARY = ["正确", "对", "√", "T", "错误", "错", "×", "F"];
@ -18,10 +17,13 @@ const baidubceConfig = {
'client_secret': 'oWb0M0YWMmZPMQIhIUkJX99ddr7h61qf', 'client_secret': 'oWb0M0YWMmZPMQIhIUkJX99ddr7h61qf',
}; };
export function getOcrContent(data) {
const { return request({
entpCourseWorkTypeList url: '/ocr/exam',
} = useClassTaskStore(); method: 'post',
data: data
})
}
/** /**
@ -43,7 +45,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
if (isLocalTest) { if (isLocalTest) {
// 临时本地测试json格式跟百度ocr一致 // 临时本地测试json格式跟百度ocr一致
const response = await fetch('/cropImgTest/single2.json'); const response = await fetch('/cropImgTest/single.json');
const resOcr = await response.json(); const resOcr = await response.json();
ocrJson = resOcr.results; ocrJson = resOcr.results;
// 识别内容拼接 // 识别内容拼接
@ -113,6 +115,7 @@ 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('多选题')) {
/** 单选题/多选题 - 选项 */ /** 单选题/多选题 - 选项 */
@ -147,10 +150,10 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
} }
else if (curItem === 'workanswer') { else if (curItem === 'workanswer') {
// 该类型下只做[主观题]和[复合题]的处理 // 该类型下只做[主观题]和[复合题]的处理
ocrTxt = ocrTxt.replace(/<br \/>/g, ''); if (examType.includes('主观题')) {
examItem = ocrTxt; ocrTxt = ocrTxt.replace(/<br \/>/g, '');
} else { examItem = ocrTxt;
examItem = ocrTxt; }
} }
// 返回转换格式后的识别内容 // 返回转换格式后的识别内容
@ -171,7 +174,7 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = ''
if (isLocalTest) { if (isLocalTest) {
// 临时本地测试json格式跟百度ocr一致 // 临时本地测试json格式跟百度ocr一致
const response = await fetch('/cropImgTest/single1.json'); const response = await fetch('/cropImgTest/single.json');
const resOcr = await response.json(); const resOcr = await response.json();
ocrJson = resOcr.results; ocrJson = resOcr.results;
// 识别内容拼接 // 识别内容拼接
@ -231,14 +234,12 @@ 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("百度智能云用户标识有误");
@ -393,8 +394,8 @@ const assembleExam = (eachSub) => {
} }
// 第一部分[题干-选项] 处理 // 第一部分[题干-选项] 处理
titleAndWorkDesc = tmpList[0]; titleAndWorkDesc = tmpList[0];
// 将3个以上连续的下划线统一替换为5个 // 将4个以上连续的下划线统一替换为5个
titleAndWorkDesc = titleAndWorkDesc.replace(/_{3,}/g, '_____'); titleAndWorkDesc = titleAndWorkDesc.replace(/_{4,}/g, '_____');
// 第二部分[分析-答案] 处理 // 第二部分[分析-答案] 处理
let answerAndAnswer = {}; let answerAndAnswer = {};
@ -455,35 +456,32 @@ const assembleExam = (eachSub) => {
} }
} }
// 目前暂屏蔽无[复合题], 故所有都算基础题 let tmpExam = null;
let tmpExam = processExamSingle(titleAndWorkDesc, answer); if (answer === '') {
/**
// let tmpExam = null; * 基础题型 - [单选题] [多选题] [填空题] [判断题] [主观题]
// if (answer === '') { */
// /** tmpExam = processExamSingle(titleAndWorkDesc, answer);
// * 基础题型 - [单选题] [多选题] [填空题] [判断题] [主观题] }
// */ else {
// tmpExam = processExamSingle(titleAndWorkDesc, answer); // 匹配是否存在 1. 1 (1)的存在, 题目与答案都存在则说明题型为复合题(嵌套题)
// } regex = /^(\d+[..。]|\(\d+\)|\d+)/;
// else { let answerFind = regex.test(answer);
// // 匹配是否存在 1. 1 (1)的存在, 题目与答案都存在则说明题型为复合题(嵌套题) regex = /(\d+[..。]|\(\d+\)|\d+)/;
// regex = /^(\d+[..。]|\(\d+\)|\d+)/; let titleFind = regex.test(titleAndWorkDesc);
// let answerFind = regex.test(answer); if (titleFind && answerFind) {
// 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) {
// 错误信息 // 错误信息
@ -609,21 +607,13 @@ const processExamSingle = function (titleAndWorkDesc, answer) {
* 主观题 * 主观题
*/ */
// [题型] - 格式化 // [题型] - 格式化
const flagDict = ['单选题', '多选题', '判断题', '填空题']; examSingle.workType = "主观题";
const another = entpCourseWorkTypeList.filter(item => !flagDict.includes(item.label));
if (another.length > 0) {
examSingle.workType = another[another.length-1].label;
// [题干]-格式化
examSingle.title = titleAndWorkDesc;
}
// examSingle.workType = "主观题"; // [题干]-格式化
examSingle.title = titleAndWorkDesc;
// // [题干]-格式化 // [选项] - 格式化 --- 主观题无选项
// examSingle.title = titleAndWorkDesc; //examSingle.arrWorkDesc = [];
// // [选项] - 格式化 --- 主观题无选项
// //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" :disabled="item.label=='不限'"></el-option> <el-option v-for="item in fromOptions.type" :key="item.value" :label="item.label" :value="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-else-if="questForm.worktype=='多选题'" class="questForm-item-cover"> <div v-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-else-if="questForm.worktype=='填空题'" class="questForm-item-cover"> <div v-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-else-if="questForm.worktype=='判断题'" class="questForm-item-cover"> <div v-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-else-if="questForm.worktype.indexOf('主观题') != -1" class="questForm-item-cover"> <div v-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-else-if="questForm.worktype=='复合题'" class="questForm-item-cover"> <div v-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,19 +350,6 @@
</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">
@ -636,9 +623,8 @@ 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;
@ -762,8 +748,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('status')) { if (!item.hasOwnProperty('stutus')) {
item.status = '1'; item.stutus = '1';
} }
// [], // [],
if (!item.hasOwnProperty('evalnodeid')) { if (!item.hasOwnProperty('evalnodeid')) {
@ -779,6 +765,7 @@ 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:""}];
@ -915,14 +902,11 @@ 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)){
@ -1024,8 +1008,9 @@ 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.edusubject == '语文' || props.bookobj.node.edusubject == '英语' ){ if( props.bookobj.node.edustage == '高中' && (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) {
@ -1098,7 +1083,6 @@ 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)=>{
@ -1453,9 +1437,14 @@ 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)
@ -1512,33 +1501,9 @@ 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, "");
// // [] ([] [][()], )
param.workdesc = ''; if(questForm.worktype.indexOf('主观题') !== -1) {
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
@ -1568,16 +1533,27 @@ const submitForm=(formName) =>{
// param.workdesc = ''; // // param.workdesc = ''; //
// param.workanswer = JSON.stringify(answer).replace(/<[^>]*>/g, ""); // param.workanswer = JSON.stringify(answer).replace(/<[^>]*>/g, "");
} }
else {
// (), [], ocr // [] "<div></div>#&<div></div>".replace(/<[^>]*>/g, "")
param.workdesc = ''; // if(questForm.worktype === '填空题'){
// workanswer //
if (questForm.workanswer && questForm.workanswer != '') { //param.workanswer = questForm.list.map(item => item.text).join('#&').replace(/<[^>]*>/g, "");
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) {
@ -1727,40 +1703,37 @@ const myMessageShow=(title, msg, status)=>{
* @return: {*} * @return: {*}
* @param {*} list * @param {*} list
*/ */
const formatKnowledgePoint = (list) => { const updateKnowledgePoint = (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)) {
formatKnowledgePoint(item.children); updateKnowledgePoint(item.children);
} }
}); });
return list; return list;
}; };
watch([ watch(() => props.bookobj.levelSecondId, async (newVal, oldVal) => {
() => 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 = lessionid.value; let id = props.bookobj.levelSecondId;
if( props.bookobj.node.edusubject == '语文' || props.bookobj.node.edusubject == '英语'){ if( props.bookobj.node.edustage == '高中' && (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 = formatKnowledgePoint(res.rows); curKnowledgePointList.value = updateKnowledgePoint(res.rows);
}); });
} }
}else{ }else{

View File

@ -117,8 +117,6 @@ 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'
@ -192,8 +190,6 @@ const workResource = reactive({
onMounted(() => { onMounted(() => {
console.log('entpCourseWorkTypeList', entpCourseWorkTypeList); console.log('entpCourseWorkTypeList', entpCourseWorkTypeList);
// ()
getEntpCourseWorkPointList();
debounceQueryData(); // debounceQueryData(); //
}) })
@ -239,33 +235,32 @@ function Apis(key) {
const client = new Apis('/paht'); const client = new Apis('/paht');
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const 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, //
// //
// worktype: entpCourseWorkQueryParams.worktype.label,
worktype: entpCourseWorkQueryParams.worktype.label, workTypeId: entpCourseWorkQueryParams.worktype.value,
workTypeId: entpCourseWorkQueryParams.worktype.value, //
// workgroup: entpCourseWorkQueryParams.workgroup,
workgroup: entpCourseWorkQueryParams.workgroup, //
// yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'', //
// thirdId: entpCourseWorkQueryParams.point&&entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[0]:'',
thirdId: entpCourseWorkQueryParams.point&&entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[0]:'', //
// keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
} }
const entpcourseworkres = listEntpcourseworkNew(queryForm); const entpcourseworkres = listEntpcourseworkNew(queryForm);
resolve(entpcourseworkres); resolve(entpcourseworkres);
}) })
} }
const handleQueryFromEntpCourseWork= async (queryType) => { const handleQueryFromEntpCourseWork= async (queryType) => {
@ -334,12 +329,9 @@ 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 != '') {
const tmpJson = '['+clueres.rows[i].childlist+']'; clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
if (isJson(tmpJson)){ for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray = JSON.parse(tmpJson); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
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, '');
}
} }
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
@ -468,29 +460,19 @@ 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([ watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
() => 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

@ -721,23 +721,19 @@ const msgHandle = (msg) => {
const { head, content, ...other } = msg const { head, content, ...other } = msg
switch(head) { switch(head) {
case MsgEnum.HEADS.MSG_closed: // : case MsgEnum.HEADS.MSG_closed: // :
Homework.win = null Homework.win = null
window.close() // window.close() //
break break
case MsgEnum.HEADS.MSG_finishHomework: // : case MsgEnum.HEADS.MSG_finishHomework: // :
console.log('更新作业', head, content) console.log('更新作业', head, content)
const data = JSON.parse(localStorage.getItem('teachClassWorkItem')); const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
openDialog(data, false); openDialog(data, false);
break break
case MsgEnum.HEADS.MSG_slideFlapping: // case MsgEnum.HEADS.MSG_slideFlapping: //
console.log('切换页面-关闭窗口') console.log('切换页面-关闭窗口')
Homework.win = null Homework.win = null
window.close() // window.close() //
break break
case MsgEnum.HEADS.MSG_pushSreen_experiment: // :
Homework.win = null
window.close() //
break
// case 'TIMAddRecvNewMsgCallback': // data=[] // case 'TIMAddRecvNewMsgCallback': // data=[]
// { // {
// (data||[]).forEach(o => { // (data||[]).forEach(o => {

View File

@ -59,10 +59,10 @@ const getHomework = async () => {
homeworkList.value = rows || []; homeworkList.value = rows || [];
homeworkList.value.forEach((item) => { homeworkList.value.forEach((item) => {
// UI // UI
if (item.worktype == '课堂展示') { if (item.worktype == '学习目标定位') {
item.workclass = 'success' item.workclass = 'success'
item.workcodesList = JSON.parse(item.workcodes) item.workcodesList = JSON.parse(item.workcodes)
} else if (item.worktype == '科学实验') { } else if (item.worktype == '教材研读') {
item.workclass = 'primary' item.workclass = 'primary'
} else if (item.worktype == '框架梳理') { } else if (item.worktype == '框架梳理') {
item.workclass = 'warning' item.workclass = 'warning'

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

@ -1,427 +0,0 @@
<template>
<div class="login-container">
<div class="box-item desc">
<div class="welcome">
<p>欢迎登录 {{ homeTitle }}</p>
</div>
<img class="welcome-img" :src="leftBg2" />
</div>
<div class="box-item login" v-if="isRegister">
<WindowTools :is-has-max="false" />
<div class="login-title">账号登录</div>
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
<el-form-item prop="username">
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item prop="password" style="margin-bottom: 15px">
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
</el-form-item>
<div class="flex mb-5">
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
<!-- <el-checkbox >阅读并同意xxx</el-checkbox> -->
</div>
<el-form-item>
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
</div>
</el-form>
</div>
<div class="box-item login" v-else>
<WindowTools :is-has-max="false" />
<div class="login-title">账号注册</div>
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
<el-form-item label="手机号" prop="username">
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="验证码" prop="smsCode" style="display: flex">
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
</el-form-item>
<el-form-item label="密码" prop="password" >
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item>
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 返回登录 </a>
</div>
</el-form>
</div>
</div>
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
:close-on-press-escape="false" align-center>
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
status="success" />
</el-dialog>
<el-dialog
v-model="isImg"
title="人机验证"
width="500"
style=" -webkit-app-region: no-drag;"
>
<span>根据图片回答相关问题1</span>
<div style="display: flex;align-items: center;;margin-top:30px">
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
</div>
<div style="display: flex;justify-content: center;margin-top:30px">
<el-button type="primary" @click="sbmitImg">确定</el-button>
</div>
</el-dialog>
<!--选择学科-->
<SelectSubject v-model="isSubject" :login-data="loginForm" />
<!--注册弹框-->
<Register ref="RegModel"></Register>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { encrypt, decrypt } from '@/utils/jsencrypt'
import useUserStore from '@/store/modules/user'
import leftBg2 from '@/assets/images/login/left-bg2.png'
import WindowTools from '@/components/window-tools/index.vue'
import SelectSubject from '@/components/select-subject/index.vue'
import Register from './components/Register.vue'
import { sessionStore } from '@/utils/store'
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
const { session } = require('@electron/remote')
const downloadProp = ref(0)
const showDownLoading = ref(false)
const { ipcRenderer } = window.electron || {}
const formRef = ref()
const userStore = useUserStore()
const btnLoading = ref(false)
const isSubject = ref(false)
const RegModel = ref(false)
const isRegister = ref(true)
const ruleFormRef = ref(null)
const codeName=ref('发送验证码')
const timer=ref(null)
const isImg=ref(false)
const isPeopleImg=ref(null)
const type=ref(1) // 1 2
const resImg = reactive({ imgData: {} });
//
const loginForm = reactive({
username: '',
password: '',
rememberMe: false
})
//
const ruleForm = reactive({
})
//
const rules = reactive({
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
})
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
ipcRenderer.on('update-app-progress', (e, prop) => {
downloadProp.value = prop
showDownLoading.value = prop !== 100
})
const gotoreRegister=()=>{
codeName.value='发送验证码'
if(timer.value){
clearInterval(timer.value);
}
isRegister.value=false
}
//
const refreshImg=()=>{
getCodeImg().then(res=>{
isPeopleImg.value='data:image/jpg;base64,'+res.img
resImg.imgData=res
})
}
//
const sbmitImg=()=>{
if(ruleForm.imgCode){
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
const { username:username,imgCode:code } = ruleForm
const params = {
username, code,
uuid: resImg.imgData.uuid,
source:4
}
sendcode(params).then(res=>{
if(res.code==200){
ElMessage.success('短信发送成功')
ruleForm.Code=res.data
isImg.value=false
codeName.value=60
timer.value=setInterval(()=>{
codeName.value--
if(codeName.value==0){
codeName.value='发送验证码'
clearInterval(timer.value);
}
},1000)
}
})
}else{
ElMessage.error('请根据图片输入验证码')
}
//
}
//
const sendyzm=()=>{
if(ruleForm.username){
const pattern = /^1[3-9]\d{9}$/;
if( pattern.test(ruleForm.username) ){
getCodeImg().then(res=>{
if(res.code==200){
ruleForm.imgCode=null
isPeopleImg.value='data:image/jpg;base64,'+res.img
isImg.value=true
resImg.imgData=res
// codeName.value=60
// timer.value=setInterval(()=>{
// codeName.value--
// if(codeName.value==0){
// codeName.value=''
// clearInterval(timer.value);
// }
// },1000)
}else{
ElMessage.error(res.msg)
}
})
}else{
ElMessage.error('请输入正确的手机号码')
}
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
// console.log('res->', res)
// })
}else{
ElMessage.error('请输入手机号码')
}
}
//
const RegisterModel = type => {
RegModel.value.OpenModel(type)
}
//
const submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
btnLoading.value = true
// cookie
if (loginForm.rememberMe) {
await setCookie('username', loginForm.username)
await setCookie('password', encrypt(loginForm.password))
await setCookie('rememberMe', loginForm.rememberMe.toString())
} else {
//
await session.defaultSession.clearStorageData({
origin: curWinUrl,
storages: ['cookies']
})
}
try {
await userStore.login(loginForm)
await userStore.getInfo()
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
ElMessage.success('登录成功')
ipcRenderer && ipcRenderer.send('openMainWindow')
} else {
isSubject.value = true
}
} finally {
btnLoading.value = false
}
}
})
}
const isStadium = (user) => {
let roles = user.roles
return roles.some(item => item.roleKey === 'stadium')
}
const getCookie = async () => {
const username = (await getCookieDetail('username'))[0]
const password = (await getCookieDetail('password'))[0]
const rememberMe = (await getCookieDetail('rememberMe'))[0]
loginForm.username = username ? username.value : loginForm.username
loginForm.password = password ? decrypt(password.value) : loginForm.password
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
}
// cookie
const getCookieDetail = (name) => {
return session.defaultSession.cookies.get({ url: curWinUrl, name })
}
// cookie
const setCookie = (name, value) => {
// 30
let Days = 30
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
const cookie = {
url: curWinUrl,
name,
value,
expirationDate: times
}
return session.defaultSession.cookies.set(cookie)
}
const gotoLogin = () => {
codeName.value='发送验证码'
if (timer.value){
clearInterval(timer.value);
}
if (ruleFormRef.value) ruleFormRef.value.resetFields()
isRegister.value = true
}
//
const RegisterForm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
instructorregister(ruleForm).then(res=>{
if(res.code==200){
ElMessage.success('您已注册成功')
if (ruleFormRef.value) ruleFormRef.value.resetFields()
gotoLogin()
}else{
ElMessage.error(res.msg)
}
})
console.log('submit!')
} else {
console.log('error submit!', fields)
}
})
}
onMounted(() => {
localStorage.clear()
sessionStore.set('subject', {
bookList: null,
curBook: null,
curNode: null,
defaultExpandedKeys: [],
subjectTree: []
})
getCookie()
})
</script>
<style lang="scss" scoped>
.login-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
-webkit-app-region: drag;
.box-item {
width: 444px;
height: 520px;
&.desc {
background: #ffffff;
border-radius: 12px 0px 0px 12px;
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
padding: 23px 25px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
background-color: #003b94;
}
&.login {
background: #ffffff;
border-radius: 0px 12px 12px 0px;
padding: 34px 42px;
position: relative;
}
.welcome {
padding-top: 35px;
p {
color: #ffffff;
line-height: 25px;
letter-spacing: 0.26px;
text-align: center;
font-weight: 700;
font-size: 26px;
}
}
.welcome-img {
margin-top: 20px;
width: 350px;
height: 350px;
}
.login-title {
font-size: 20px;
text-align: center;
color: #1e1e1e;
margin-bottom: 35px;
margin-top: 50px;
}
.login-form {
-webkit-app-region: no-drag;
.captcha-input {
width: 60%;
}
.captcha-img {
cursor: pointer;
}
}
.btn {
width: 350px;
height: 50px;
border-radius: 4px;
font-size: 16px;
font-weight: 700;
text-align: center;
color: #ffffff;
line-height: 50px;
cursor: pointer;
}
}
}
.header-tool {
position: absolute;
right: 0;
top: 0;
-webkit-app-region: no-drag;
span {
padding: 5px 10px;
cursor: pointer;
}
}
.el-form-item {
margin-bottom: 40px;
}
</style>

View File

@ -1,13 +1,427 @@
<template> <template>
<ycLogin v-if="buildMode === 'yc'||buildMode === 'yc2'"> <div class="login-container">
</ycLogin> <div class="box-item desc">
<defultLogin v-else> <div class="welcome">
</defultLogin> <p>欢迎登录 {{ homeTitle }}</p>
</div>
<img class="welcome-img" :src="leftBg2" />
</div>
<div class="box-item login" v-if="isRegister">
<WindowTools :is-has-max="false" />
<div class="login-title">账号登录</div>
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
<el-form-item prop="username">
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item prop="password" style="margin-bottom: 15px">
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
</el-form-item>
<div class="flex mb-5">
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
<!-- <el-checkbox >阅读并同意xxx</el-checkbox> -->
</div>
<el-form-item>
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
</div>
</el-form>
</div>
<div class="box-item login" v-else>
<WindowTools :is-has-max="false" />
<div class="login-title">账号注册</div>
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
<el-form-item label="手机号" prop="username">
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="验证码" prop="smsCode" style="display: flex">
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
</el-form-item>
<el-form-item label="密码" prop="password" >
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item>
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 返回登录 </a>
</div>
</el-form>
</div>
</div>
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
:close-on-press-escape="false" align-center>
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
status="success" />
</el-dialog>
<el-dialog
v-model="isImg"
title="人机验证"
width="500"
style=" -webkit-app-region: no-drag;"
>
<span>根据图片回答相关问题1</span>
<div style="display: flex;align-items: center;;margin-top:30px">
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
</div>
<div style="display: flex;justify-content: center;margin-top:30px">
<el-button type="primary" @click="sbmitImg">确定</el-button>
</div>
</el-dialog>
<!--选择学科-->
<SelectSubject v-model="isSubject" :login-data="loginForm" />
<!--注册弹框-->
<Register ref="RegModel"></Register>
</template> </template>
<script setup> <script setup>
import ycLogin from './yc-login.vue' import { onMounted, reactive, ref } from 'vue'
import defultLogin from './defult-login.vue' import { ElMessage } from 'element-plus'
const buildMode = import.meta.env.MODE import { encrypt, decrypt } from '@/utils/jsencrypt'
import useUserStore from '@/store/modules/user'
import leftBg2 from '@/assets/images/login/left-bg2.png'
import WindowTools from '@/components/window-tools/index.vue'
import SelectSubject from '@/components/select-subject/index.vue'
import Register from './components/Register.vue'
import { sessionStore } from '@/utils/store'
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
const { session } = require('@electron/remote')
const downloadProp = ref(0)
const showDownLoading = ref(false)
const { ipcRenderer } = window.electron || {}
const formRef = ref()
const userStore = useUserStore()
const btnLoading = ref(false)
const isSubject = ref(false)
const RegModel = ref(false)
const isRegister = ref(true)
const ruleFormRef = ref(null)
const codeName=ref('发送验证码')
const timer=ref(null)
const isImg=ref(false)
const isPeopleImg=ref(null)
const type=ref(1) // 1 2
const resImg = reactive({ imgData: {} });
//
const loginForm = reactive({
username: '',
password: '',
rememberMe: false
})
//
const ruleForm = reactive({
})
//
const rules = reactive({
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
})
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
ipcRenderer.on('update-app-progress', (e, prop) => {
downloadProp.value = prop
showDownLoading.value = prop !== 100
})
const gotoreRegister=()=>{
codeName.value='发送验证码'
if(timer.value){
clearInterval(timer.value);
}
isRegister.value=false
}
//
const refreshImg=()=>{
getCodeImg().then(res=>{
isPeopleImg.value='data:image/jpg;base64,'+res.img
resImg.imgData=res
})
}
//
const sbmitImg=()=>{
if(ruleForm.imgCode){
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
const { username:username,imgCode:code } = ruleForm
const params = {
username, code,
uuid: resImg.imgData.uuid,
source:4
}
sendcode(params).then(res=>{
if(res.code==200){
ElMessage.success('短信发送成功')
ruleForm.Code=res.data
isImg.value=false
codeName.value=60
timer.value=setInterval(()=>{
codeName.value--
if(codeName.value==0){
codeName.value='发送验证码'
clearInterval(timer.value);
}
},1000)
}
})
}else{
ElMessage.error('请根据图片输入验证码')
}
//
}
//
const sendyzm=()=>{
if(ruleForm.username){
const pattern = /^1[3-9]\d{9}$/;
if( pattern.test(ruleForm.username) ){
getCodeImg().then(res=>{
if(res.code==200){
ruleForm.imgCode=null
isPeopleImg.value='data:image/jpg;base64,'+res.img
isImg.value=true
resImg.imgData=res
// codeName.value=60
// timer.value=setInterval(()=>{
// codeName.value--
// if(codeName.value==0){
// codeName.value=''
// clearInterval(timer.value);
// }
// },1000)
}else{
ElMessage.error(res.msg)
}
})
}else{
ElMessage.error('请输入正确的手机号码')
}
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
// console.log('res->', res)
// })
}else{
ElMessage.error('请输入手机号码')
}
}
//
const RegisterModel = type => {
RegModel.value.OpenModel(type)
}
//
const submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
btnLoading.value = true
// cookie
if (loginForm.rememberMe) {
await setCookie('username', loginForm.username)
await setCookie('password', encrypt(loginForm.password))
await setCookie('rememberMe', loginForm.rememberMe.toString())
} else {
//
await session.defaultSession.clearStorageData({
origin: curWinUrl,
storages: ['cookies']
})
}
try {
await userStore.login(loginForm)
await userStore.getInfo()
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
ElMessage.success('登录成功')
ipcRenderer && ipcRenderer.send('openMainWindow')
} else {
isSubject.value = true
}
} finally {
btnLoading.value = false
}
}
})
}
const isStadium = (user) => {
let roles = user.roles
return roles.some(item => item.roleKey === 'stadium')
}
const getCookie = async () => {
const username = (await getCookieDetail('username'))[0]
const password = (await getCookieDetail('password'))[0]
const rememberMe = (await getCookieDetail('rememberMe'))[0]
loginForm.username = username ? username.value : loginForm.username
loginForm.password = password ? decrypt(password.value) : loginForm.password
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
}
// cookie
const getCookieDetail = (name) => {
return session.defaultSession.cookies.get({ url: curWinUrl, name })
}
// cookie
const setCookie = (name, value) => {
// 30
let Days = 30
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
const cookie = {
url: curWinUrl,
name,
value,
expirationDate: times
}
return session.defaultSession.cookies.set(cookie)
}
const gotoLogin = () => {
codeName.value='发送验证码'
if (timer.value){
clearInterval(timer.value);
}
if (ruleFormRef.value) ruleFormRef.value.resetFields()
isRegister.value = true
}
//
const RegisterForm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
instructorregister(ruleForm).then(res=>{
if(res.code==200){
ElMessage.success('您已注册成功')
if (ruleFormRef.value) ruleFormRef.value.resetFields()
gotoLogin()
}else{
ElMessage.error(res.msg)
}
})
console.log('submit!')
} else {
console.log('error submit!', fields)
}
})
}
onMounted(() => {
localStorage.clear()
sessionStore.set('subject', {
bookList: null,
curBook: null,
curNode: null,
defaultExpandedKeys: [],
subjectTree: []
})
getCookie()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.login-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
-webkit-app-region: drag;
.box-item {
width: 444px;
height: 520px;
&.desc {
background: #ffffff;
border-radius: 12px 0px 0px 12px;
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
padding: 23px 25px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
background-color: #003b94;
}
&.login {
background: #ffffff;
border-radius: 0px 12px 12px 0px;
padding: 34px 42px;
position: relative;
}
.welcome {
padding-top: 35px;
p {
color: #ffffff;
line-height: 25px;
letter-spacing: 0.26px;
text-align: center;
font-weight: 700;
font-size: 26px;
}
}
.welcome-img {
margin-top: 20px;
width: 350px;
height: 350px;
}
.login-title {
font-size: 20px;
text-align: center;
color: #1e1e1e;
margin-bottom: 35px;
margin-top: 50px;
}
.login-form {
-webkit-app-region: no-drag;
.captcha-input {
width: 60%;
}
.captcha-img {
cursor: pointer;
}
}
.btn {
width: 350px;
height: 50px;
border-radius: 4px;
font-size: 16px;
font-weight: 700;
text-align: center;
color: #ffffff;
line-height: 50px;
cursor: pointer;
}
}
}
.header-tool {
position: absolute;
right: 0;
top: 0;
-webkit-app-region: no-drag;
span {
padding: 5px 10px;
cursor: pointer;
}
}
.el-form-item {
margin-bottom: 40px;
}
</style> </style>

View File

@ -1,463 +0,0 @@
<template>
<div class="login-container">
<div class="login-yc">
<img class="welcome-img" :src="buildMode === 'yc2'?leftBg2:leftBg1" />
</div>
<div class="box-item login" v-if="isRegister">
<WindowTools :is-has-max="false" />
<div style="display: flex;justify-content: center;"><img class="title-logo" :src="yclogo" /></div>
<div class="login-title">永川中小学</div>
<div class="login-title2">{{buildMode === 'yc2'?'虚拟仿真AI实训教学管理系统':'人工智能赋能科学素养与劳动技能系统'}}</div>
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
<el-form-item prop="username">
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item prop="password" style="margin-bottom: 15px">
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
</el-form-item>
<div class="flex mb-5">
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
<!-- <el-checkbox >阅读并同意xxx</el-checkbox> -->
</div>
<el-form-item style="margin-bottom: 20px">
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
</div>
<div class="title-bottom">
重庆市永川区教育委员会
</div>
</el-form>
</div>
<div class="box-item login" v-else>
<WindowTools :is-has-max="false" />
<div class="login-title">账号注册</div>
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
<el-form-item label="手机号" prop="username">
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="验证码" prop="smsCode" style="display: flex">
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
</el-form-item>
<el-form-item label="密码" prop="password" >
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item>
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 返回登录 </a>
</div>
</el-form>
</div>
</div>
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
:close-on-press-escape="false" align-center>
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
status="success" />
</el-dialog>
<el-dialog
v-model="isImg"
title="人机验证"
width="500"
style=" -webkit-app-region: no-drag;"
>
<span>根据图片回答相关问题1</span>
<div style="display: flex;align-items: center;;margin-top:30px">
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
</div>
<div style="display: flex;justify-content: center;margin-top:30px">
<el-button type="primary" @click="sbmitImg">确定</el-button>
</div>
</el-dialog>
<!--选择学科-->
<SelectSubject v-model="isSubject" :login-data="loginForm" />
<!--注册弹框-->
<Register ref="RegModel"></Register>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { encrypt, decrypt } from '@/utils/jsencrypt'
import useUserStore from '@/store/modules/user'
import WindowTools from '@/components/window-tools/index.vue'
import SelectSubject from '@/components/select-subject/index.vue'
import Register from './components/Register.vue'
import { sessionStore } from '@/utils/store'
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
import yclogo from '@/assets/images/login/yc-logo.png'
import leftBg1 from '@/assets/images/login/ycpeitu.png'
import leftBg2 from '@/assets/images/login/ycpeitu2.jpg'
const { session } = require('@electron/remote')
const buildMode = import.meta.env.MODE
const downloadProp = ref(0)
const showDownLoading = ref(false)
const { ipcRenderer } = window.electron || {}
const formRef = ref()
const userStore = useUserStore()
const btnLoading = ref(false)
const isSubject = ref(false)
const RegModel = ref(false)
const isRegister = ref(true)
const ruleFormRef = ref(null)
const codeName=ref('发送验证码')
const timer=ref(null)
const isImg=ref(false)
const isPeopleImg=ref(null)
const type=ref(1) // 1 2
const resImg = reactive({ imgData: {} });
//
const loginForm = reactive({
username: '',
password: '',
rememberMe: false
})
//
const ruleForm = reactive({
})
//
const rules = reactive({
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
})
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
ipcRenderer.on('update-app-progress', (e, prop) => {
downloadProp.value = prop
showDownLoading.value = prop !== 100
})
const gotoreRegister=()=>{
codeName.value='发送验证码'
if(timer.value){
clearInterval(timer.value);
}
isRegister.value=false
}
//
const refreshImg=()=>{
getCodeImg().then(res=>{
isPeopleImg.value='data:image/jpg;base64,'+res.img
resImg.imgData=res
})
}
//
const sbmitImg=()=>{
if(ruleForm.imgCode){
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
const { username:username,imgCode:code } = ruleForm
const params = {
username, code,
uuid: resImg.imgData.uuid,
source:4
}
sendcode(params).then(res=>{
if(res.code==200){
ElMessage.success('短信发送成功')
ruleForm.Code=res.data
isImg.value=false
codeName.value=60
timer.value=setInterval(()=>{
codeName.value--
if(codeName.value==0){
codeName.value='发送验证码'
clearInterval(timer.value);
}
},1000)
}
})
}else{
ElMessage.error('请根据图片输入验证码')
}
//
}
//
const sendyzm=()=>{
if(ruleForm.username){
const pattern = /^1[3-9]\d{9}$/;
if( pattern.test(ruleForm.username) ){
getCodeImg().then(res=>{
if(res.code==200){
ruleForm.imgCode=null
isPeopleImg.value='data:image/jpg;base64,'+res.img
isImg.value=true
resImg.imgData=res
// codeName.value=60
// timer.value=setInterval(()=>{
// codeName.value--
// if(codeName.value==0){
// codeName.value=''
// clearInterval(timer.value);
// }
// },1000)
}else{
ElMessage.error(res.msg)
}
})
}else{
ElMessage.error('请输入正确的手机号码')
}
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
// console.log('res->', res)
// })
}else{
ElMessage.error('请输入手机号码')
}
}
//
const RegisterModel = type => {
RegModel.value.OpenModel(type)
}
//
const submitForm = async (formEl) => {
if (!formEl) return
await formEl.validate(async (valid) => {
if (valid) {
btnLoading.value = true
// cookie
if (loginForm.rememberMe) {
await setCookie('username', loginForm.username)
await setCookie('password', encrypt(loginForm.password))
await setCookie('rememberMe', loginForm.rememberMe.toString())
} else {
//
await session.defaultSession.clearStorageData({
origin: curWinUrl,
storages: ['cookies']
})
}
try {
await userStore.login(loginForm)
await userStore.getInfo()
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
ElMessage.success('登录成功')
ipcRenderer && ipcRenderer.send('openMainWindow')
} else {
isSubject.value = true
}
} finally {
btnLoading.value = false
}
}
})
}
const isStadium = (user) => {
let roles = user.roles
return roles.some(item => item.roleKey === 'stadium')
}
const getCookie = async () => {
const username = (await getCookieDetail('username'))[0]
const password = (await getCookieDetail('password'))[0]
const rememberMe = (await getCookieDetail('rememberMe'))[0]
loginForm.username = username ? username.value : loginForm.username
loginForm.password = password ? decrypt(password.value) : loginForm.password
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
}
// cookie
const getCookieDetail = (name) => {
return session.defaultSession.cookies.get({ url: curWinUrl, name })
}
// cookie
const setCookie = (name, value) => {
// 30
let Days = 30
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
const cookie = {
url: curWinUrl,
name,
value,
expirationDate: times
}
return session.defaultSession.cookies.set(cookie)
}
const gotoLogin = () => {
codeName.value='发送验证码'
if (timer.value){
clearInterval(timer.value);
}
if (ruleFormRef.value) ruleFormRef.value.resetFields()
isRegister.value = true
}
//
const RegisterForm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
instructorregister(ruleForm).then(res=>{
if(res.code==200){
ElMessage.success('您已注册成功')
if (ruleFormRef.value) ruleFormRef.value.resetFields()
gotoLogin()
}else{
ElMessage.error(res.msg)
}
})
console.log('submit!')
} else {
console.log('error submit!', fields)
}
})
}
onMounted(() => {
localStorage.clear()
sessionStore.set('subject', {
bookList: null,
curBook: null,
curNode: null,
defaultExpandedKeys: [],
subjectTree: []
})
getCookie()
})
</script>
<style lang="scss" scoped>
.login-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
-webkit-app-region: drag;
.login-yc{
width: 100%;
height: 100%;
img{
width: 100%;
height: 100%;
}
}
.box-item {
width: 370px;
height: 520px;
&.desc {
background: #ffffff;
border-radius: 12px 0px 0px 12px;
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
padding: 23px 25px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
background-color: #003b94;
}
&.login {
background: #ffffff;
border-radius: 0px 12px 12px 0px;
padding: 34px 42px;
position: relative;
.title-logo{
width: 50px;
}
}
.welcome {
padding-top: 35px;
p {
color: #ffffff;
line-height: 25px;
letter-spacing: 0.26px;
text-align: center;
font-weight: 700;
font-size: 26px;
}
}
.welcome-img {
margin-top: 20px;
width: 350px;
height: 350px;
}
.login-title {
font-size: 20px;
text-align: center;
color: #1e1e1e;
margin-bottom: 35px;
margin-top: 50px;
}
.login-title {
font-size: 20px;
text-align: center;
color: #1e1e1e;
margin-bottom: 10px;
margin-top: 5px;
font-width: bold;
}
.login-title2 {
margin-bottom: 20px;
}
.login-form {
-webkit-app-region: no-drag;
.captcha-input {
width: 60%;
}
.captcha-img {
cursor: pointer;
}
.title-bottom{
text-align: center;
width: 100%;
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
}
}
.btn {
width: 350px;
height: 50px;
border-radius: 4px;
font-size: 16px;
font-weight: 700;
text-align: center;
color: #ffffff;
line-height: 50px;
cursor: pointer;
}
}
}
.header-tool {
position: absolute;
right: 0;
top: 0;
-webkit-app-region: no-drag;
span {
padding: 5px 10px;
cursor: pointer;
}
}
.el-form-item {
margin-bottom: 40px;
}
</style>

View File

@ -83,8 +83,6 @@ import useUserStore from '@/store/modules/user' // 用户信息
import ChooseTextbook from '@/components/choose-textbook/index.vue' import ChooseTextbook from '@/components/choose-textbook/index.vue'
import KjListItem from '@/views/prepare/container/kj-list-item.vue' import KjListItem from '@/views/prepare/container/kj-list-item.vue'
import FileImage from '@/components/file-image/index.vue' import FileImage from '@/components/file-image/index.vue'
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
import {creatAPT, getSmarttalkPage, getModelInfo} from '@/api/file' import {creatAPT, getSmarttalkPage, getModelInfo} from '@/api/file'
import {ArrowDown, Flag, Position} from '@element-plus/icons-vue' import {ArrowDown, Flag, Position} from '@element-plus/icons-vue'
import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile"; import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile";
@ -96,17 +94,14 @@ import {createWindow, toLinkLeftWeb} from "@/utils/tool";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport"; import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
import * as API_entpcoursefile from "@/api/education/entpcoursefile"; import * as API_entpcoursefile from "@/api/education/entpcoursefile";
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
import msgUtils from "@/plugins/modal"; import msgUtils from "@/plugins/modal";
import * as commUtils from "@/utils/comm"; import * as commUtils from "@/utils/comm";
import * as Api_server from "@/api/apiService"; // import * as Api_server from "@/api/apiService"; //
import useClassTaskStore from '@/store/modules/classTask'
import { slidesToImg } from '@/utils/ppt' // ppt
const router = useRouter() const router = useRouter()
const userStore = useUserStore().user // const userStore = useUserStore().user //
const currentNode = ref({}) const currentNode = ref({})
const refs = ref([]); const refs = ref([]);
const classTaskStore = useClassTaskStore();
const collectRef = (key) => { const collectRef = (key) => {
return (el) => { return (el) => {
@ -280,14 +275,12 @@ const handleFileChange = ()=> {
createAIPPTByFile(file) createAIPPTByFile(file)
} }
} }
// pptPPT线
const createAIPPTByFile = async (file)=> { const createAIPPTByFile = async (file)=> {
// pgDialog.value.visible = true pgDialog.value.visible = true
// pgDialog.value.pg.percentage = 0 pgDialog.value.pg.percentage = 0
const resPptJson = await PPTXFileToJson(file) const resPptJson = await PPTXFileToJson(file)
const { def, slides, ...content } = resPptJson const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线 // || 线
let completed = 0 let completed = 0
const total = slides.length const total = slides.length
@ -339,7 +332,6 @@ const createAIPPTByFile = async (file)=> {
entpcourseid: resCourse.id, entpcourseid: resCourse.id,
title: '', title: '',
filetype: 'slide', filetype: 'slide',
thumbnails, // -
slides: resSlides, slides: resSlides,
edituserid: userStore.userId edituserid: userStore.userId
} }
@ -410,8 +402,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)
@ -521,9 +513,7 @@ const changeClass = async (type, row, other) => {
} }
// //
onMounted(async () => { onMounted(() => {
//
await classTaskStore.initJYInfo(userStore);
}) })
</script> </script>

View File

@ -10,8 +10,8 @@
<div class="paragraphs"> <div class="paragraphs">
{{ outputText }} {{ outputText }}
</div> </div>
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">{{ outputText ? '重新生成' : '生成大纲' }}</el-button> <el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1" :disabled="!outputText">下一步</el-button> <el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
</el-card> </el-card>
<el-card v-if="activeStep === 1"> <el-card v-if="activeStep === 1">
<div style="padding-bottom: 10px">ppt模板选择</div> <div style="padding-bottom: 10px">ppt模板选择</div>
@ -57,7 +57,7 @@
</el-row> </el-row>
<div> <div>
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button> <el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 0">上一步</el-button>
<el-button style="margin-bottom: 5px;" type="primary" :loading="createPPTLoading" @click="outlineCreatePPT()">生成PPT</el-button> <el-button style="margin-bottom: 5px;" type="primary" v-loading="createPPTLoading" @click="outlineCreatePPT()">生成PPT</el-button>
</div> </div>
</el-card> </el-card>
<el-card v-if="activeStep === 2"> <el-card v-if="activeStep === 2">
@ -177,8 +177,6 @@ const outlineCreatePPT = () => {
}; };
checkProgress(); checkProgress();
}).finally(()=>{
createPPTLoading.value = false
}) })
}; };

View File

@ -25,9 +25,9 @@
<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="请选择班级" clearable> <el-select v-else v-model="form[prop]" placeholder="请选择班级">
<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>
</template> </template>
</c-form> </c-form>
@ -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,8 +139,6 @@ 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) {
// //
@ -169,8 +167,6 @@ 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')
} }
// - // -
@ -253,10 +249,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')
@ -268,7 +264,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)
.finally(() => {dt.loading = false}) dt.loading = false
// getClasscourseList('update') // // getClasscourseList('update') //
let msgEl = ElMessage.success('创建课程-成功') let msgEl = ElMessage.success('创建课程-成功')
// -pptList // -pptList
@ -376,9 +372,9 @@ const openPublicScreen = (classcourse, isPublic) => {
createWindow('open-win', { createWindow('open-win', {
url: '/pptist', // url: '/pptist', //
close: () => { close: () => {
sessionStore.delete('curr.resource') // sessionStore.set('curr.resource', null) //
sessionStore.delete('curr.classcourse') // sessionStore.set('curr.classcourse', null) //
sessionStore.delete('curr.isPublic') // sessionStore.set('curr.isPublic', null) //
} }
}) })
visible.value = false // visible.value = false //

View File

@ -126,17 +126,11 @@
<span>下载</span> <span>下载</span>
</el-button> </el-button>
</div> </div>
<!-- <div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item"> <div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
<el-button text @click="adToKj(item)"> <el-button text @click="adToKj(item)">
<i class="iconfont icon-jiahao"></i> <i class="iconfont icon-jiahao"></i>
<span>加入课件</span> <span>加入课件</span>
</el-button> </el-button>
</div>-->
<div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
<el-button text @click="importPPT(item)">
<i class="iconfont icon-jiahao"></i>
<span>导入PPT</span>
</el-button>
</div> </div>
<div class="item-popover-item"> <div class="item-popover-item">
<el-button text @click="moveSmarttalkFun(item)"> <el-button text @click="moveSmarttalkFun(item)">
@ -187,7 +181,7 @@ export default {
} }
} }
}, },
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null,'on-importPPT': null }, emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null },
data() { data() {
return { return {
listenList: [], listenList: [],
@ -223,9 +217,6 @@ export default {
}) })
.catch(() => {}) .catch(() => {})
}, },
importPPT(item) {
this.$emit('on-importPPT', item)
},
downloadFile(item) { downloadFile(item) {
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName) ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
}, },

View File

@ -99,7 +99,6 @@
@on-delete="deleteTalk" @on-delete="deleteTalk"
@on-set="openSet" @on-set="openSet"
@on-delhomework="delhomework" @on-delhomework="delhomework"
@on-importPPT="importPPT"
@on-filearg="isOpenHomework = true" @on-filearg="isOpenHomework = true"
> >
<el-checkbox v-if="!item.uniquekey" label="" :value="item" /> <el-checkbox v-if="!item.uniquekey" label="" :value="item" />
@ -195,7 +194,7 @@ import outLink from '@/utils/linkConfig'
import { createWindow, sessionStore, getAppInstallUrl, ipcMsgSend } from '@/utils/tool' import { createWindow, sessionStore, getAppInstallUrl, ipcMsgSend } from '@/utils/tool'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { delClasswork, listEntpcourse } from '@/api/teaching/classwork' import { delClasswork, listEntpcourse } from '@/api/teaching/classwork'
import { updateClasscourse, getClasscourse } from '@/api/teaching/classcourse' import { updateClasscourse } from '@/api/teaching/classcourse'
import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage' import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage'
import { useGetHomework } from '@/hooks/useGetHomework' import { useGetHomework } from '@/hooks/useGetHomework'
import { editListItem } from '@/hooks/useClassTask' import { editListItem } from '@/hooks/useClassTask'
@ -205,12 +204,13 @@ import TreeLog from '@/views/prepare/components/treeLog.vue'
import classStart from './container/class-start.vue' // import classStart from './container/class-start.vue' //
import MsgEnum from '@/plugins/imChat/msgEnum' // im import MsgEnum from '@/plugins/imChat/msgEnum' // im
import * as commUtils from "@/utils/comm"; import * as commUtils from "@/utils/comm";
import msgUtils from "@/plugins/modal";
import * as Api_server from "@/api/apiService"; import * as Api_server from "@/api/apiService";
import msgUtils from "@/plugins/modal";
import * as API_entpcoursefile from "@/api/education/entpcoursefile"; import * as API_entpcoursefile from "@/api/education/entpcoursefile";
import { slidesToImg } from '@/utils/ppt' // ppt
import ChatWs from '@/plugins/socket' // socket import ChatWs from '@/plugins/socket' // socket
if (!ChatWs.ws) ChatWs.init() if (!ChatWs.ws) ChatWs.init()
// import Chat from '@/utils/chat' // im
// if (!Chat.imChat) Chat.init()
const toolStore = useToolState() const toolStore = useToolState()
const fs = require('fs') const fs = require('fs')
@ -389,13 +389,12 @@ export default {
if (res.code == 200) { if (res.code == 200) {
const resource = res.data const resource = res.data
if (resource.filetype != 'aippt') this.$refs.calssRef.open(aptFileId, row) if (resource.filetype != 'aippt') this.$refs.calssRef.open(aptFileId, row)
else { // aippt else {
if (!!sessionStore.get('curr.classcourse')) return ElMessage.warning('公屏已打开,请勿重复操作') if (!!sessionStore.get('curr.classcourse')) return ElMessage.warning('公屏已打开,请勿重复操作')
const { data:classcourse } = await getClasscourse(row.id) //
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0}) const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
setTimeout(()=>{ setTimeout(()=>{
msgEl.close() msgEl.close()
this.openPublicScreen('class', resource, classcourse||row) // - this.openPublicScreen('class', resource, row) // -
}, 2000) }, 2000)
} }
} else ElMessage.error(res.msg||'获取课件信息失败') } else ElMessage.error(res.msg||'获取课件信息失败')
@ -449,7 +448,6 @@ 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) // -
@ -498,11 +496,11 @@ export default {
createWindow('open-win', { createWindow('open-win', {
url: '/pptist', // url: '/pptist', //
close: () => { close: () => {
sessionStore.delete('curr.resource') // sessionStore.set('curr.resource', null) //
if (type=='edit') { if (type=='edit') {
sessionStore.delete('curr.smarttalk') // sessionStore.set('curr.smarttalk', null) //
this.asyncAllFile() // this.asyncAllFile() //
} else sessionStore.delete('curr.classcourse') // } else sessionStore.set('curr.classcourse', null) //
} }
}) })
}, },
@ -556,15 +554,6 @@ export default {
progDownFile(e, num) { progDownFile(e, num) {
this.downloadNum = num this.downloadNum = num
}, },
importPPT(item) {
let _this = this;
fetch(item.fileFullPath)
.then(res => res.arrayBuffer())
.then(buffer => {
let name = item.fileShowName.substring(0, item.fileShowName.lastIndexOf('.')) + '.aippt'
_this.createAIPPTByFile(buffer, name)
})
},
createFile() { createFile() {
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => { creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
this.currentFileList.unshift(res.resData) this.currentFileList.unshift(res.resData)
@ -573,9 +562,8 @@ export default {
},500) },500)
}) })
}, },
async openFilePicker(){ openFilePicker(){
this.$refs.fileInput.click(); this.$refs.fileInput.click();
// const files = await commUtils.getFiles()
}, },
handleFileChange(){ handleFileChange(){
const file = event.target.files[0]; const file = event.target.files[0];
@ -584,7 +572,7 @@ export default {
console.log('文件名:', file.name); console.log('文件名:', file.name);
console.log('文件类型:', file.type); console.log('文件类型:', file.type);
console.log('文件大小:', file.size); console.log('文件大小:', file.size);
this.createAIPPTByFile(file, this.currentNode.itemtitle + '.aippt') this.createAIPPTByFile(file)
} }
}, },
async toRousrceUrl(o) { async toRousrceUrl(o) {
@ -630,13 +618,11 @@ export default {
} }
} }
}, },
async createAIPPTByFile(file,fileShowName) { async createAIPPTByFile(file) {
this.pgDialog.visible = true this.pgDialog.visible = true
this.pgDialog.pg.percentage = 0 this.pgDialog.pg.percentage = 0
const resPptJson = await PPTXFileToJson(file) const resPptJson = await PPTXFileToJson(file)
const { def, slides, ...content } = resPptJson const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线 // || 线
let completed = 0 let completed = 0
const total = slides.length const total = slides.length
@ -678,7 +664,7 @@ export default {
...this.uploadData, ...this.uploadData,
fileId: slideid, fileId: slideid,
fileFlag: 'aippt', fileFlag: 'aippt',
fileShowName: fileShowName fileShowName: this.currentNode.itemtitle + '.aippt'
}).then(async (res) => { }).then(async (res) => {
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide)) const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
@ -689,7 +675,6 @@ export default {
title: '', title: '',
filetype: 'slide', filetype: 'slide',
slides: resSlides, slides: resSlides,
thumbnails, //
edituserid: this.userStore.userId edituserid: this.userStore.userId
} }
const res_3 = await API_entpcoursefile.batchAddNew(params) const res_3 = await API_entpcoursefile.batchAddNew(params)

View File

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

View File

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

View File

@ -93,9 +93,6 @@ emitter.on('onGetMain', (item) => {
const emit = defineEmits(['']) const emit = defineEmits([''])
const onSelect = (item) =>{ const onSelect = (item) =>{
actId.value = item.id actId.value = item.id
item.child.forEach(el =>{
el.aiShow = false
})
emitter.emit('changeMode', item) emitter.emit('changeMode', item)
} }

View File

@ -14,7 +14,8 @@
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button> <el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
<el-button type="danger" @click="onCreate">生成PPT</el-button> <el-button type="primary">生成大纲</el-button>
<el-button type="danger" @click="pptDialog = true">生成PPT</el-button>
</div> </div>
</div> </div>
<div class="right-con flex" ref="listRef"> <div class="right-con flex" ref="listRef">
@ -91,10 +92,7 @@ import * as API_entpcourse from '@/api/education/entpcourse' // 相关api
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api import * as API_entpcoursefile from '@/api/education/entpcoursefile' // api
import * as Api_server from '@/api/apiService' // api import * as Api_server from '@/api/apiService' // api
import * as API_smarttalk from '@/api/file' // api import * as API_smarttalk from '@/api/file' // api
import msgUtils from '@/plugins/modal' import msgUtils from '@/plugins/modal' //
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
import { createWindow } from '@/utils/tool' //
import { slidesToImg } from '@/utils/ppt' // ppt
const userStore = useUserStore() const userStore = useUserStore()
const pptDialog = ref(false) const pptDialog = ref(false)
@ -119,7 +117,7 @@ const pgDialog = reactive({ // 弹窗-进度条
} }
}) })
const curMode = ref(2) const curMode = ref(1)
const modeOptions = ref([ const modeOptions = ref([
{ {
label: '教学大模型', label: '教学大模型',
@ -136,16 +134,6 @@ emitter.on('changeMode', (item) => {
getTempResult(item.id) getTempResult(item.id)
}) })
const onCreate = () =>{
let isAnswer = resultList.value.every(item => !item.answer)
if(isAnswer){
ElMessage.warning('请先进行研读')
return
}
pptDialog.value = true
}
// //
const getCompletion = async () => { const getCompletion = async () => {
@ -206,7 +194,7 @@ const handleCompleteText = async (answer, index) => {
} }
// //
const onSaveTemp = async (item) => { const onSaveTemp = (item) => {
if (item.answer == '') return if (item.answer == '') return
const data = { const data = {
@ -216,11 +204,7 @@ const onSaveTemp = async (item) => {
content: item.answer, content: item.answer,
ex1: curNode.id ex1: curNode.id
} }
const res = await tempSave(data) tempSave(data).then(res => { })
if(!item.resultId){
item.resultId = res.data
}
} }
const isWordDialog = ref(false) const isWordDialog = ref(false)
@ -272,7 +256,7 @@ const listRef = ref()
// //
const isStarted = ref([]); const isStarted = ref([]);
const getTempResult = (id) => { const getTempResult = (id) => {
tempResult({ mainModelId: id, pageNum: 1, pageSize: 10000, ex1: curNode.id }).then(res => { tempResult({ mainModelId: id }).then(res => {
let rows = res.rows let rows = res.rows
if (rows.length > 0) { if (rows.length > 0) {
isStarted.value = new Array(rows.length).fill(true) isStarted.value = new Array(rows.length).fill(true)
@ -328,7 +312,6 @@ const prompt = ref('')
const addAiPPT = async (res) => { const addAiPPT = async (res) => {
// res = { url: 'https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx' }
let node = courseObj.node let node = courseObj.node
pptDialog.value = false; pptDialog.value = false;
if (!node) return msgUtils.msgWarning('请选择章节?') if (!node) return msgUtils.msgWarning('请选择章节?')
@ -347,8 +330,6 @@ const addAiPPT = async (res) => {
.then(async buffer => { .then(async buffer => {
const resPptJson = await PPTXFileToJson(buffer) const resPptJson = await PPTXFileToJson(buffer)
const { def, slides, ...content } = resPptJson const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线 // || 线
let completed = 0 let completed = 0
const total = slides.length const total = slides.length
@ -365,20 +346,13 @@ const addAiPPT = async (res) => {
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params) const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
if (!!parentid ?? null) { // if (!!parentid ?? null) { //
// -Smarttalk // -Smarttalk
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid }) HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
if (slides.length > 0) { if (slides.length > 0) {
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide)) const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
const params = { parentid, filetype: 'slide', title: '', thumbnails, slides: resSlides } const params = { parentid, filetype: 'slide', title: '', slides: resSlides }
const res_3 = await HTTP_SERVER_API('batchAddNew', params) const res_3 = await HTTP_SERVER_API('batchAddNew', params)
if (res_3 && res_3.code == 200) { if (res_3 && res_3.code == 200) {
msgUtils.msgSuccess('生成PPT课件成功') msgUtils.msgSuccess('生成PPT课件成功')
//TODO
const res = await getEntpcoursefile(parentid)
if (res && res.code === 200) {
openPublicScreen('edit', res.data, smarttalk.resData) // -
} else {
ElMessage.warning(res.msg||'文件获取异常!')
}
} else { } else {
msgUtils.msgWarning('生成PPT课件失败') msgUtils.msgWarning('生成PPT课件失败')
} }
@ -387,20 +361,7 @@ const addAiPPT = async (res) => {
}) })
} }
const openPublicScreen = (type, resource, currData)=> {
sessionStore.set('curr.resource', resource) //
if (type=='edit') sessionStore.set('curr.smarttalk', currData) // smarttalk
else sessionStore.set('curr.classcourse', currData) //
createWindow('open-win', {
url: '/pptist', //
close: () => {
sessionStore.set('curr.resource', null) //
if (type=='edit') {
sessionStore.set('curr.smarttalk', null) //
} else sessionStore.set('curr.classcourse', null) //
}
})
}
const isEdit = ref(false) const isEdit = ref(false)
// //
const curIndex = ref(-1) const curIndex = ref(-1)

View File

@ -81,10 +81,10 @@ export const getClassWorkList = async (id) => {
// ---------------------------------------------- // ----------------------------------------------
// 处理任务类型的UI // 处理任务类型的UI
if (list[i].worktype == '课堂展示') { if (list[i].worktype == '学习目标定位') {
list[i].workclass = 'success' list[i].workclass = 'success'
list[i].workcodesList = JSON.parse(list[i].workcodes) list[i].workcodesList = JSON.parse(list[i].workcodes)
} else if (list[i].worktype == '科学实验') { } else if (list[i].worktype == '教材研读') {
list[i].workclass = 'primary' list[i].workclass = 'primary'
} else if (list[i].worktype == '框架梳理') { } else if (list[i].worktype == '框架梳理') {
list[i].workclass = 'warning' list[i].workclass = 'warning'