Compare commits
No commits in common. "main" and "2.5.5" have entirely different histories.
|
@ -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'
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktx
|
||||||
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||||
|
|
||||||
# websocket 地址
|
# websocket 地址
|
||||||
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
|
|
||||||
# 是否显示开发工具
|
# 是否显示开发工具
|
||||||
VITE_SHOW_DEV_TOOLS = 'false'
|
VITE_SHOW_DEV_TOOLS = 'false'
|
||||||
|
|
25
.env.yc
25
.env.yc
|
@ -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'
|
|
25
.env.yc2
25
.env.yc2
|
@ -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'
|
|
|
@ -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:
|
|
||||||
- '**/*'
|
|
|
@ -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:
|
|
||||||
- '**/*'
|
|
|
@ -33,7 +33,6 @@ export default defineConfig({
|
||||||
proxy: {
|
proxy: {
|
||||||
'/dev-api': {
|
'/dev-api': {
|
||||||
target: 'http://27.128.240.72:7865',
|
target: 'http://27.128.240.72:7865',
|
||||||
// target: 'https://prev.ysaix.com:7868/prod-api/',
|
|
||||||
// target: 'http://36.134.181.164:7863',
|
// target: 'http://36.134.181.164:7863',
|
||||||
// target: 'http://192.168.0.102:7865',
|
// target: 'http://192.168.0.102:7865',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "aix-win-ws",
|
"name": "aix-win-ws",
|
||||||
"version": "2.5.9",
|
"version": "2.5.4",
|
||||||
"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"
|
||||||
|
@ -94,8 +92,6 @@
|
||||||
"tinycolor2": "^1.6.0",
|
"tinycolor2": "^1.6.0",
|
||||||
"tinymce": "6.8.3",
|
"tinymce": "6.8.3",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"v-viewer": "^3.0.11",
|
|
||||||
"viewerjs": "^1.11.7",
|
|
||||||
"vite-plugin-electron": "^0.28.8",
|
"vite-plugin-electron": "^0.28.8",
|
||||||
"vue": "^3.4.34",
|
"vue": "^3.4.34",
|
||||||
"vue-cropper": "1.0.3",
|
"vue-cropper": "1.0.3",
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 51 KiB |
|
@ -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',
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -13097,15 +13097,15 @@ const PDFViewerApplication = {
|
||||||
}
|
}
|
||||||
if (isValidSpreadMode(spread)) {
|
if (isValidSpreadMode(spread)) {
|
||||||
//默认双页
|
//默认双页
|
||||||
this.pdfViewer.spreadMode = spread;
|
// this.pdfViewer.spreadMode = spread;
|
||||||
// this.pdfViewer.spreadMode = 1;
|
this.pdfViewer.spreadMode = 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.isInitialViewSet = true;
|
this.isInitialViewSet = true;
|
||||||
this.pdfSidebar?.setInitialView(sidebarView);
|
this.pdfSidebar?.setInitialView(sidebarView);
|
||||||
//默认双页
|
//默认双页
|
||||||
setViewerModes(scrollMode, spreadMode);
|
// setViewerModes(scrollMode, spreadMode);
|
||||||
// setViewerModes(scrollMode, 1);
|
setViewerModes(scrollMode, 1);
|
||||||
if (this.initialBookmark) {
|
if (this.initialBookmark) {
|
||||||
setRotation(this.initialRotation);
|
setRotation(this.initialRotation);
|
||||||
delete this.initialRotation;
|
delete this.initialRotation;
|
||||||
|
|
|
@ -28,9 +28,8 @@ import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||||
import { PPTApi } from './api'
|
import { PPTApi } from './api'
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import watcher from './api/watcher' // 监听
|
import './api/watcher' // 监听
|
||||||
import emitter from '@/utils/mitt' //mitt 事件总线
|
|
||||||
watcher() // 监听启动
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const _isPC = isPC()
|
const _isPC = isPC()
|
||||||
|
|
||||||
|
@ -40,8 +39,8 @@ const slidesStore = useSlidesStore()
|
||||||
const { databaseId } = storeToRefs(mainStore)
|
const { databaseId } = storeToRefs(mainStore)
|
||||||
const { screening } = storeToRefs(useScreenStore())
|
const { screening } = storeToRefs(useScreenStore())
|
||||||
|
|
||||||
if (import.meta.env.MODE === 'development') {
|
if (import.meta.env.MODE !== 'development') {
|
||||||
// window.onbeforeunload = () => false
|
window.onbeforeunload = () => false
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/**
|
|
||||||
* 统一处理消息 发送 避免找不到
|
|
||||||
*/
|
|
||||||
|
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
|
||||||
import { useClasscourseStore } from '../store'
|
|
||||||
import * as API_classcourse from '@/api/teaching/classcourse' // 后端api
|
|
||||||
import { MsgEnum } from './types'
|
|
||||||
// import msgUtils from '@/plugins/modal' // 消息工具
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
|
||||||
const courseId = classcourse?.id // 课堂id
|
|
||||||
const timgroupid = classcourse?.timgroupid // 群组id
|
|
||||||
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
|
||||||
// 上课状态才-初始化socket
|
|
||||||
if (!ChatWs.ws && !!courseId) ChatWs.init()
|
|
||||||
// 开课消息
|
|
||||||
const startCourse = async() => {
|
|
||||||
// await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'open' })
|
|
||||||
ChatWs.sendMsg('open', {id: courseId})
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
// 下课消息
|
|
||||||
const exitCourse = async() => {
|
|
||||||
if(!timgroupid) throw new Error('未获取到群组ID')
|
|
||||||
await API_classcourse.updateClasscourse({ id: courseId, status: 'closed' })
|
|
||||||
return ChatWs.closedCourse(timgroupid)
|
|
||||||
}
|
|
||||||
// 翻页消息
|
|
||||||
const slideFlapping = (msg:object) => {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
const isWs = !!ChatWs.ws && ChatWs.ws.readyState === 1 // 是否有socket连接
|
|
||||||
if(!timgroupid) return reject('未获取到群组ID')
|
|
||||||
else if(!isWs) return reject('信异常,请重试!')
|
|
||||||
const {current: paging, animationSteps: cartoonTimes} = msg || {}
|
|
||||||
const head = MsgEnum.HEADS.MSG_slideFlapping
|
|
||||||
ChatWs.sendMsg(head, msg) // 发送消息
|
|
||||||
API_classcourse.setPaging({ id: courseId, paging, cartoonTimes})
|
|
||||||
// 更新本地缓存
|
|
||||||
sessionStore.set('curr.classcourse.paging', paging)
|
|
||||||
sessionStore.set('curr.classcourse.cartoonTimes', cartoonTimes)
|
|
||||||
classcourseStore.classcourse.paging = paging
|
|
||||||
classcourseStore.classcourse.cartoonTimes = cartoonTimes
|
|
||||||
return resolve(true)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
groupid: timgroupid,
|
|
||||||
classcourse,
|
|
||||||
exitCourse,
|
|
||||||
slideFlapping,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,60 +7,36 @@ import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import * as useStore from '../store' // pptist-状态管理
|
import * as useStore from '../store' // pptist-状态管理
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
import emitter from '@/utils/mitt' //mitt 事件总线
|
|
||||||
import { nextTick } from 'vue'
|
|
||||||
|
|
||||||
const slidesStore = useStore.useSlidesStore() // 幻灯片-状态管理
|
|
||||||
const screenStore = useStore.useScreenStore() // 全屏-状态管理
|
const screenStore = useStore.useScreenStore() // 全屏-状态管理
|
||||||
const classcourseStore = useStore.useClasscourseStore() // 课堂信息-状态管理
|
const classcourseStore = useStore.useClasscourseStore() // 课堂信息-状态管理
|
||||||
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
||||||
const isPublic = sessionStore.get('curr.isPublic') // 是否公屏开课
|
|
||||||
|
|
||||||
export class Classcourse {
|
export class Classcourse {
|
||||||
msgObj:ElMessageBox = null // 提示消息对象
|
msgObj:ElMessageBox = null // 提示消息对象
|
||||||
classcourse:any = null // 课堂信息
|
|
||||||
id: number|string = null // 课堂id
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.load()
|
this.load()
|
||||||
}
|
}
|
||||||
// 延时
|
|
||||||
sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
/**
|
/**
|
||||||
* @description 加载
|
* @description 加载
|
||||||
*/
|
*/
|
||||||
async load() {
|
load() {
|
||||||
console.log('classcourse-load', classcourse)
|
|
||||||
// 打开全屏
|
// 打开全屏
|
||||||
const isCourse = !!classcourse
|
screenStore.setScreening(!!classcourse)
|
||||||
screenStore.setScreening(isCourse)
|
|
||||||
// 如果课堂信息有值,则连接socket
|
// 如果课堂信息有值,则连接socket
|
||||||
if (isCourse) {
|
if (!!classcourse) {
|
||||||
// 连接socket
|
// 连接socket
|
||||||
|
if (!ChatWs.ws) ChatWs.init()
|
||||||
ChatWs.id = classcourse.timgroupid // 群组id
|
ChatWs.id = classcourse.timgroupid // 群组id
|
||||||
if (!ChatWs.ws) {
|
console.log('ws- ', classcourse)
|
||||||
ChatWs.init().then(_ => {
|
|
||||||
isPublic && ChatWs.sendMsg('open', {id: classcourse.id})
|
|
||||||
// isPublic && console.log('socket-开课消息-已发送')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.classcourse = classcourse // 课堂信息
|
|
||||||
this.id = classcourse.id // 课堂id
|
|
||||||
// 如果课堂信息有paging,则更新当前页码
|
|
||||||
const { paging, cartoonTimes } = classcourse
|
|
||||||
const isPaging = !!paging || paging === 0
|
|
||||||
// 如果课堂信息有paging,则更新动画播放状态
|
|
||||||
const isAnim = !!cartoonTimes || cartoonTimes === 0
|
|
||||||
if (isPaging) slidesStore.updateSlideIndex(paging)
|
|
||||||
if (isAnim) slidesStore.updateAnimationIndex(cartoonTimes)
|
|
||||||
// 课堂信息-状态管理
|
|
||||||
classcourseStore.setClasscourse(classcourse)
|
classcourseStore.setClasscourse(classcourse)
|
||||||
// 待上课提示
|
// 待上课提示
|
||||||
if (!classcourse.status) {
|
if (!classcourse.status) {
|
||||||
this.msgObj = {
|
this.msgObj = {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: '系统提示',
|
title: '系统提示',
|
||||||
message: '公屏课堂已准备完毕,等待老师开启课堂...',
|
message: '公屏课堂已准备完毕,请等待老师开启课堂!',
|
||||||
center: true,
|
center: true,
|
||||||
showClose: false,
|
showClose: false,
|
||||||
showCancelButton: false,
|
showCancelButton: false,
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,18 +3,16 @@
|
||||||
* @author zdg
|
* @author zdg
|
||||||
* @date 2024-11-26
|
* @date 2024-11-26
|
||||||
*/
|
*/
|
||||||
import { toRaw, nextTick } from 'vue'
|
import { toRaw } from 'vue'
|
||||||
import type { Result } from './types' // 接口类型
|
import type { Result } from './types' // 接口类型
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||||
import * as API_smarttalk from '@/api/file' // 相关api
|
import * as API_smarttalk from '@/api/file' // 相关api
|
||||||
import * as API_classwork from '@/api/teaching/classwork' // 相关api
|
|
||||||
import * as useStore from '../store' // pptist-状态管理
|
import * as useStore from '../store' // pptist-状态管理
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import useUserStore from '@/store/modules/user' // 外部-用户信息
|
import useUserStore from '@/store/modules/user' // 外部-用户信息
|
||||||
import * as Api_server from '@/api/apiService' // 相关api
|
import * as Api_server from '@/api/apiService' // 相关api
|
||||||
import * as commUtils from '@/utils/comm.js' // 工具
|
import * as commUtils from '@/utils/comm.js'
|
||||||
import { toPng, toJpeg } from 'html-to-image' // 引入html-to-image库
|
|
||||||
const slidesStore = useStore.useSlidesStore()
|
const slidesStore = useStore.useSlidesStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
@ -50,8 +48,6 @@ export class Utils {
|
||||||
}, delay)
|
}, delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 延时
|
|
||||||
static sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ppt相关后端接口处理 */
|
/** ppt相关后端接口处理 */
|
||||||
|
@ -59,68 +55,44 @@ export class PPTApi {
|
||||||
// 变量
|
// 变量
|
||||||
static isUpdate = true // 是否更新数据
|
static isUpdate = true // 是否更新数据
|
||||||
|
|
||||||
// 获取所有幻灯片列表 isUpdate为true不更新
|
// 获取所有幻灯片列表
|
||||||
static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise<Boolean> {
|
static getSlideList(parentid: (Number | String)): 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)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
if(!isUpdate){
|
const slides = (res.rows || []).map(o => {
|
||||||
const slides = (res.rows || []).map(o => {
|
if (!!o.datacontent) {
|
||||||
if (!!o.datacontent) {
|
const json = JSON.parse(o.datacontent)
|
||||||
const json = JSON.parse(o.datacontent)
|
!!json && (json.id = o.id)
|
||||||
!!json && (json.id = o.id)
|
return json
|
||||||
return json
|
}
|
||||||
}
|
// 如果没有数据,默认空白页
|
||||||
// 如果没有数据,默认空白页
|
return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}}
|
||||||
return {id: o.id,elements:[],background:{type:"solid",color:"#fff"}}
|
})
|
||||||
})
|
|
||||||
// slidesStore.updateSlideIndex(0) // 下标0 为第一页
|
|
||||||
slidesStore.setSlides(slides) // 写入数据
|
|
||||||
}
|
|
||||||
// 活动列表处理
|
// 活动列表处理
|
||||||
// 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]
|
||||||
|
// 加入活动后刷新ppt数据内容,不跟换为第一页
|
||||||
|
// slidesStore.updateSlideIndex(0) // 下标0 为第一页
|
||||||
|
slidesStore.setSlides(slides) // 写入数据
|
||||||
|
// 写入作业列表数据
|
||||||
|
slidesStore.setWorkList(workList)
|
||||||
// 获取所有的pptlist的数据
|
// 获取所有的pptlist的数据
|
||||||
slidesStore.setWorkItem(workItem)
|
slidesStore.setWorkItem(workItem)
|
||||||
// 没有上课时调用-作业列表
|
|
||||||
if(!classcourse) 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 +114,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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -160,15 +132,11 @@ export class PPTApi {
|
||||||
|
|
||||||
const currentSlide = toRaw(slidesStore.currentSlide)
|
const currentSlide = toRaw(slidesStore.currentSlide)
|
||||||
const isAdd = !/^\d+$/.test(currentSlide.id) // 是否新增
|
const isAdd = !/^\d+$/.test(currentSlide.id) // 是否新增
|
||||||
const currInd = toRaw(slidesStore.slideIndex) // 当前页索引-new
|
if (isAdd) { // 新增的幻灯片(id 为非数字,说明是新增的幻灯片)
|
||||||
const oldInd = oldData.findIndex(o => o.id == currentSlide.id) // 当前页索引-old
|
const bool = await this.addSlide(currentSlide)
|
||||||
const isBatch = oldVal && oldVal.length && currInd != oldInd // 是否批量更新-排序
|
bool && this.batchUpdateSlides(newData, true) // 批量更新-排序
|
||||||
if (isAdd) return // 新增-这里不处理 状态管理-处理
|
} else { // 防抖-更新
|
||||||
// 防抖-更新
|
if (!this.isUpdate) return this.isUpdate = true // 下次更新数据
|
||||||
if (!this.isUpdate) return this.isUpdate = true // 下次更新数据
|
|
||||||
if (isBatch) { // 批量更新-排序
|
|
||||||
this.batchUpdateSlides(newData, true)
|
|
||||||
} else { // 更新当前页幻灯片
|
|
||||||
const params = {
|
const params = {
|
||||||
id: currentSlide.id,
|
id: currentSlide.id,
|
||||||
datacontent: JSON.stringify(currentSlide),
|
datacontent: JSON.stringify(currentSlide),
|
||||||
|
@ -176,14 +144,12 @@ export class PPTApi {
|
||||||
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
|
Utils.mxThrottle(() => {this.updateSlide(params)}, 200, 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新幻灯片 isThum 是否更新缩略图
|
// 更新幻灯片
|
||||||
static updateSlide(data: object, isThum = true): Promise<Boolean> {
|
static updateSlide(data: object): Promise<Boolean> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
if (isThum) { // 更新缩略图
|
|
||||||
const thumUrl = await this.getSlideThumUrl()
|
|
||||||
data.base64Code = thumUrl // 更新缩略图
|
|
||||||
}
|
|
||||||
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
|
const res: Result = await API_entpcoursefile.updateEntpcoursefileNew(data)
|
||||||
|
console.log(data,'data');
|
||||||
|
console.log(res,'dresata');
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
|
} else msgUtils.msgError(res.msg || '更新失败');resolve(false)
|
||||||
|
@ -226,77 +192,21 @@ export class PPTApi {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新-活动列表
|
|
||||||
static async updateWorkList(): Promise<Boolean> {
|
|
||||||
const resolveData = (resolve, data = []) => {
|
|
||||||
slidesStore.setWorkList(data)
|
|
||||||
return resolve()
|
|
||||||
}
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
const workItem = slidesStore.workItem // 所有的pptlist的数据-原始数据
|
|
||||||
const currentSlide = slidesStore.currentSlide // 当前页幻灯片
|
|
||||||
const slideId = currentSlide.id // 当前页幻灯片id
|
|
||||||
if (!slideId) return resolveData(resolve)
|
|
||||||
// slide详情获取-作业id
|
|
||||||
// const res = await API_entpcoursefile.getEntpcoursefile(slideId)
|
|
||||||
// const workIds = res?.data?.activityContent||''
|
|
||||||
// workItem-获取作业id
|
|
||||||
const workIds = workItem.find(o => o.id == slideId)?.activityContent
|
|
||||||
if (!workIds) return resolveData(resolve)
|
|
||||||
// 获取作业列表
|
|
||||||
const resW = await API_classwork.homeworklist({ ids: workIds, pageSize: 1000 })
|
|
||||||
if (resW && resW.rows) return resolveData(resolve, resW.rows)
|
|
||||||
else msgUtils.msgError(resW.msg || '更新失败');return resolveData(resolve)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量更新缩略图-异步
|
|
||||||
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 缩略图
|
|
||||||
static getSlideThumUrl(index?:number): Promise<Boolean> {
|
|
||||||
return nextTick().then(async() => {
|
|
||||||
const slideIndex = index ?? slidesStore.slideIndex
|
|
||||||
const elements = document.querySelectorAll('.thumbnail-slide')
|
|
||||||
if (elements.length && slideIndex >= 0) {
|
|
||||||
const element = elements[slideIndex]
|
|
||||||
return await toPng(element)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 图片|音频|视频 转换为在线地址
|
// 图片|音频|视频 转换为在线地址
|
||||||
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
|
||||||
url &&(o.src = url)
|
url &&(o.src = url)
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Homework{
|
export class Homework{
|
||||||
static win: null // 作业弹窗
|
|
||||||
// 作业弹窗
|
// 作业弹窗
|
||||||
static async showHomework(id: any) {
|
static async showHomework(id: any) {
|
||||||
let result = await getClassWorkList(id)
|
let result = await getClassWorkList(id)
|
||||||
|
@ -304,14 +214,7 @@ export class Homework{
|
||||||
localStorage.setItem('teachClassWorkItem', JSON.stringify(result[0]));
|
localStorage.setItem('teachClassWorkItem', JSON.stringify(result[0]));
|
||||||
toolStore.isTaskWin=true; // 设置打开批改窗口
|
toolStore.isTaskWin=true; // 设置打开批改窗口
|
||||||
// emit('closeActive')
|
// emit('closeActive')
|
||||||
// 重复打开,先关闭弹窗
|
createWindow('open-taskwin',{url:'/teachClassTask'});
|
||||||
// if (this.win) this.win?.close?.()
|
|
||||||
this.win = await createWindow('open-taskwin',{url:'/teachClassTask'})
|
|
||||||
return this.win;
|
|
||||||
}
|
|
||||||
static closeHomework() {
|
|
||||||
if (this.win) this.win?.close?.()
|
|
||||||
this.win = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default PPTApi
|
export default PPTApi
|
|
@ -7,13 +7,13 @@ import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
// 删除幻灯片
|
// 删除幻灯片
|
||||||
static delSlide(id: string): Promise<Boolean> {
|
static delSlide(id: string): Promise<Boolean> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const res: Result = await API_entpcoursefile.delEntpcoursefile(id)
|
const res: Result = await API_entpcoursefile.delEntpcoursefile(id)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else msgUtils.msgError(res.msg || '删除失败');resolve(false)
|
} else msgUtils.msgError(res.msg || '删除失败');resolve(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -106,8 +106,6 @@ export class MsgEnum {
|
||||||
MSG_anmationclick : 'anmationclick',
|
MSG_anmationclick : 'anmationclick',
|
||||||
/** @desc: 群组创建成功 */
|
/** @desc: 群组创建成功 */
|
||||||
MSG_classcourseopen : 'classcourseopen',
|
MSG_classcourseopen : 'classcourseopen',
|
||||||
/** @desc: 学生提交作业 */
|
|
||||||
MSG_finishHomework : 'finishHomework',
|
|
||||||
/** @desc: 学生的测练结果反馈 */
|
/** @desc: 学生的测练结果反馈 */
|
||||||
MSG_classquizfeedback : 'classquizfeedback',
|
MSG_classquizfeedback : 'classquizfeedback',
|
||||||
/** @desc: 老师端:接收到学生反馈消息-课堂测练中的其他任务 */
|
/** @desc: 老师端:接收到学生反馈消息-课堂测练中的其他任务 */
|
||||||
|
@ -122,18 +120,6 @@ export class MsgEnum {
|
||||||
MSG_classWorkOfPresentDataUpdate : 'classWorkOfPresentDataUpdate',
|
MSG_classWorkOfPresentDataUpdate : 'classWorkOfPresentDataUpdate',
|
||||||
/** @desc: 课堂讲授活动,选择不同的内容 */
|
/** @desc: 课堂讲授活动,选择不同的内容 */
|
||||||
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
||||||
/** @desc: 课堂作业|活动 */
|
|
||||||
MSG_homework : 'HOMEWORK',
|
|
||||||
/** @desc: 公屏 - 课堂作业|活动 */
|
|
||||||
MSG_pushSreen_work : 'pushSreen_work',
|
|
||||||
/** @desc: 公屏 - 实验 */
|
|
||||||
MSG_pushSreen_experiment : 'pushSreen_experiment',
|
|
||||||
/** @desc: 点赞 */
|
|
||||||
MSG_dz : 'dz',
|
|
||||||
/** @desc: 疑惑 */
|
|
||||||
MSG_yh : 'yh',
|
|
||||||
/** @desc: 推图片上屏 */
|
|
||||||
MSG_pushSreen_ImgList : 'pushSreen_ImgList',
|
|
||||||
// === 新定义-消息头 ===
|
// === 新定义-消息头 ===
|
||||||
/** @desc: 课程创建-待开课 */
|
/** @desc: 课程创建-待开课 */
|
||||||
MSG_0000: 0x0000,
|
MSG_0000: 0x0000,
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/**
|
|
||||||
* 点赞组件-相关
|
|
||||||
*/
|
|
||||||
export default class Upvote {
|
|
||||||
instance: any = null // 自身实例
|
|
||||||
upvoteRef: any = null // 点赞组件
|
|
||||||
constructor(elRef?: any) {
|
|
||||||
if(!!elRef) this.upvoteRef = elRef // 点赞组件
|
|
||||||
if (!Upvote.Instance) {
|
|
||||||
Upvote.Instance = this
|
|
||||||
}
|
|
||||||
return Upvote.Instance
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化
|
|
||||||
init(elRef) {
|
|
||||||
if(!!elRef) this.upvoteRef = elRef // 点赞组件
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
// 打开点赞或者疑问 1点赞 2疑问
|
|
||||||
trigger(type) {
|
|
||||||
this.upvoteRef?.value?.trigger?.(type)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
// 静态方法-初始化
|
|
||||||
static init(elRef) {
|
|
||||||
return new Upvote(elRef)
|
|
||||||
}
|
|
||||||
// 静态方法-打开点赞或者疑问 1点赞 2疑问
|
|
||||||
static trigger(type) {
|
|
||||||
return new Upvote().trigger(type)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,143 +10,85 @@ 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' // 弹窗-函数
|
const slidesStore = store.useSlidesStore()
|
||||||
import { Homework } from './index' // api-作业相关
|
const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理
|
||||||
import emitter from '@/utils/mitt' //mitt 事件总线
|
const resource = sessionStore.get('curr.resource') // apt 资源
|
||||||
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源
|
||||||
import hooksUpvote from './upvote' // 点赞-工具
|
|
||||||
import gridPic from './gridPic' // 上屏-工具
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 监听器
|
* @description 监听器
|
||||||
*/
|
*/
|
||||||
export default () => {
|
// 监听幻灯片内容变化
|
||||||
const slidesStore = store.useSlidesStore()
|
watch(() => slidesStore.slides, (newVal, oldVal) => {
|
||||||
const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理
|
PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容
|
||||||
const resource = sessionStore.get('curr.resource') // apt 资源
|
},{ deep: true })
|
||||||
const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源
|
|
||||||
const { execNext, turnPrevSlide } = useExecPlay(false) // 不加载钩子
|
|
||||||
// 监听幻灯片内容变化
|
|
||||||
watch(() => slidesStore.slides, (newVal, oldVal) => {
|
|
||||||
PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容
|
|
||||||
},{ deep: true })
|
|
||||||
|
|
||||||
// 监听标题变化
|
// 监听标题变化
|
||||||
watch(() => slidesStore.title, (newVal, oldVal) => {
|
watch(() => slidesStore.title, (newVal, oldVal) => {
|
||||||
if (oldVal == '未命名演示文稿') return // 初始加载,不需要更新数据
|
if (oldVal == '未命名演示文稿') return // 初始加载,不需要更新数据
|
||||||
updatePPT({title: newVal})
|
updatePPT({title: newVal})
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听幻灯片下标变化
|
// 消息监听ws
|
||||||
watch(() => slidesStore.slideIndex, (newVal, oldVal) => {
|
console.log('监听器已开启', ChatWs)
|
||||||
if (!!Classcourse.id) return // 上课状态,不更新右侧作业列表
|
if (ChatWs.ws) {
|
||||||
PPTApi.updateWorkList() // 更新作业列表
|
ChatWs.watch((msg, e) => {
|
||||||
})
|
try {
|
||||||
// 监听幻灯片下画布尺寸比例变化
|
handleMessage(JSON.parse(msg))
|
||||||
watch(() => slidesStore.viewportRatio, (newVal, oldVal) => {
|
} catch (error) {
|
||||||
const width = slidesStore.viewportSize
|
console.error('socket 解析异常 ', error, e)
|
||||||
const widthandration={width, ratio:newVal}
|
handleMessage(msg)
|
||||||
const data = { id: resource.id, parentContent: JSON.stringify(widthandration)}
|
|
||||||
PPTApi.updateSlide(data)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 消息监听ws
|
|
||||||
// console.log('监听器已开启', ChatWs)
|
|
||||||
if (!!ChatWs.ws) {
|
|
||||||
ChatWs.watch((data, e) => {
|
|
||||||
try {
|
|
||||||
handleMessage(JSON.parse(data)?.msg)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('socket 解析异常 ', error, e)
|
|
||||||
handleMessage(data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新ppt内容
|
|
||||||
const updatePPT = async (data) => {
|
|
||||||
if (!resource) return
|
|
||||||
data.id = resource.id
|
|
||||||
await PPTApi.updateSlide(data) // 更新ppt内容
|
|
||||||
sessionStore.set('curr.resource.title', data.title)
|
|
||||||
// 更新smarttalk内容
|
|
||||||
if (!!smarttalk && !!data.title) {
|
|
||||||
const {id, fileFlag} = smarttalk
|
|
||||||
const params = { id, fileShowName: `${data.title}.${fileFlag}` }
|
|
||||||
await PPTApi.updateSmarttalk(params) // 更新ppt内容
|
|
||||||
sessionStore.set('curr.smarttalk.fileShowName', params.fileShowName)
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ws消息处理
|
// 更新ppt内容
|
||||||
const handleMessage = (msg) => {
|
const updatePPT = async (data) => {
|
||||||
console.log('ws消息处理', msg)
|
if (!resource) return
|
||||||
if (typeof msg === 'object'){
|
data.id = resource.id
|
||||||
const { head, content, ...other } = msg
|
await PPTApi.updateSlide(data) // 更新ppt内容
|
||||||
switch (head) {
|
sessionStore.set('curr.resource.title', data.title)
|
||||||
case MsgEnum.HEADS.MSG_open: // 开课
|
// 更新smarttalk内容
|
||||||
// 课堂信息不一致
|
if (!!smarttalk && !!data.title) {
|
||||||
if (Classcourse.id !== content.id) {
|
const {id, fileFlag} = smarttalk
|
||||||
msgUtils.alertError('老师开课信息异常,请重新进入公屏!')
|
const params = { id, fileShowName: `${data.title}.${fileFlag}` }
|
||||||
.then(() => { // 点击确定按钮,关闭窗口
|
await PPTApi.updateSmarttalk(params) // 更新ppt内容
|
||||||
close()
|
sessionStore.set('curr.smarttalk.fileShowName', params.fileShowName)
|
||||||
})
|
|
||||||
} else { // 正常更新数据
|
|
||||||
classcourseStore.classcourse.status = 'open'
|
|
||||||
sessionStore.set('curr.classcourse.status', 'open')
|
|
||||||
// 更新课堂信息-关闭警告框
|
|
||||||
Classcourse?.msgObj?.onVanish()
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
|
|
||||||
render(null, document.body) //移除弹窗
|
|
||||||
emitter.emit('closegridPic') //如果有推图片窗口 就关闭
|
|
||||||
const slideIndex = content?.current || 0
|
|
||||||
const type = content?.animation // 上下动作
|
|
||||||
const steps = content?.animationSteps // 动画步骤
|
|
||||||
if (type === 'Nextsteps') execNext(true) // 下一步-异步动画
|
|
||||||
else if (type === 'Previoustep') turnPrevSlide() // 上一步清空-动画
|
|
||||||
else slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标
|
|
||||||
// 更新本地缓存
|
|
||||||
sessionStore.set('curr.classcourse.paging', slideIndex)
|
|
||||||
sessionStore.set('curr.classcourse.cartoonTimes', steps)
|
|
||||||
classcourseStore.classcourse.paging = slideIndex
|
|
||||||
classcourseStore.classcourse.cartoonTimes = steps
|
|
||||||
break
|
|
||||||
// case MsgEnum.HEADS.MSG_homework: // 作业|活动-布置 不处理
|
|
||||||
case MsgEnum.HEADS.MSG_pushSreen_work: // 打开-作业|活动
|
|
||||||
if (!content.id) return
|
|
||||||
Homework.showHomework(content.id)
|
|
||||||
break
|
|
||||||
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 打开实验:
|
|
||||||
if (!content.url) return
|
|
||||||
dialogUtils.openLink(content.url)
|
|
||||||
break
|
|
||||||
case MsgEnum.HEADS.MSG_closed: // 下课:
|
|
||||||
close()
|
|
||||||
break
|
|
||||||
case MsgEnum.HEADS.MSG_dz: // 点赞
|
|
||||||
hooksUpvote.trigger(1)
|
|
||||||
break
|
|
||||||
case MsgEnum.HEADS.MSG_yh: // 疑惑
|
|
||||||
hooksUpvote.trigger(2)
|
|
||||||
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: // 备用
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 关闭窗口
|
|
||||||
const close = () => {
|
|
||||||
ChatWs?.close() // 关闭ws
|
|
||||||
setTimeout(() => {
|
|
||||||
window.close() // 关闭窗口
|
|
||||||
}, 1000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ws消息处理
|
||||||
|
const handleMessage = (msg) => {
|
||||||
|
if (typeof msg === 'object'){
|
||||||
|
const { head, content, ...other } = msg
|
||||||
|
switch (head) {
|
||||||
|
case MsgEnum.HEADS.MSG_open: // 开课
|
||||||
|
// 课堂信息不一致
|
||||||
|
if (Classcourse.id !== content.id) {
|
||||||
|
msgUtils.alertError('老师开课信息异常,请重新进入公屏!')
|
||||||
|
.then(() => { // 点击确定按钮,关闭窗口
|
||||||
|
window.close()
|
||||||
|
})
|
||||||
|
} else { // 正常更新数据
|
||||||
|
classcourseStore.classcourse.status = 'open'
|
||||||
|
// 更新课堂信息-关闭警告框
|
||||||
|
Classcourse?.msgObj?.onVanish()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
|
||||||
|
const slideIndex = content.current
|
||||||
|
slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标
|
||||||
|
break
|
||||||
|
case MsgEnum.HEADS.MSG_closed: // 下课:
|
||||||
|
window.close() // 关闭窗口
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log('监听器已开启', Classcourse)
|
||||||
|
// setTimeout(() => {
|
||||||
|
// console.log('关闭弹窗')
|
||||||
|
// // Classcourse.msgObj?.close()
|
||||||
|
// Classcourse?.msgObj?.onVanish()
|
||||||
|
// }, 10 * 1000)
|
|
@ -1,7 +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
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const screenStore = useScreenStore()
|
const screenStore = useScreenStore()
|
||||||
|
@ -25,13 +23,7 @@ export default () => {
|
||||||
const classcourse = classcourseStore.classcourse
|
const classcourse = classcourseStore.classcourse
|
||||||
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
||||||
console.log('退出放映状态')
|
console.log('退出放映状态')
|
||||||
ChatWs?.close() // 关闭ws
|
window.close()
|
||||||
sessionStore.delete('curr.classcourse') // 清除课堂信息
|
|
||||||
sessionStore.delete('curr.resource') // 清除课件信息
|
|
||||||
sessionStore.delete('curr.isPublic') // 清除公屏状态
|
|
||||||
setTimeout(() => {
|
|
||||||
window.close() // 关闭窗口
|
|
||||||
}, 1000)
|
|
||||||
} else screenStore.setScreening(false)
|
} else screenStore.setScreening(false)
|
||||||
if (isFullscreen()) exitFullscreen()
|
if (isFullscreen()) exitFullscreen()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,16 @@ import type { Classcourse } from '../api/types'
|
||||||
|
|
||||||
export interface ClasscourseState {
|
export interface ClasscourseState {
|
||||||
classcourse: Classcourse | any, // 课堂信息
|
classcourse: Classcourse | any, // 课堂信息
|
||||||
isEmit: boolean, // 是否加载监听事件(动画播放)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useClasscourseStore = defineStore('classcourse', {
|
export const useClasscourseStore = defineStore('classcourse', {
|
||||||
state: (): ClasscourseState => ({
|
state: (): ClasscourseState => ({
|
||||||
classcourse: null, // 课堂信息
|
classcourse: null, // 课堂信息
|
||||||
isEmit: false, // 是否加载监听事件(动画播放)
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
setClasscourse(classcourse: Classcourse) {
|
setClasscourse(classcourse: Classcourse) {
|
||||||
this.classcourse = classcourse
|
this.classcourse = classcourse
|
||||||
},
|
},
|
||||||
setIsEmit(isEmit: boolean) {
|
|
||||||
this.isEmit = isEmit
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
|
@ -33,8 +33,7 @@ export interface SlidesState {
|
||||||
slides: Slide[]
|
slides: Slide[]
|
||||||
slideIndex: number
|
slideIndex: number
|
||||||
viewportSize: number
|
viewportSize: number
|
||||||
viewportRatio: number,
|
viewportRatio: number
|
||||||
animationIndex: number, // 不是从0开始
|
|
||||||
workList:Object[],
|
workList:Object[],
|
||||||
workItem:Object[],
|
workItem:Object[],
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,6 @@ export const useSlidesStore = defineStore('slides', {
|
||||||
slideIndex: 0, // 当前页面索引
|
slideIndex: 0, // 当前页面索引
|
||||||
viewportSize: 1000, // 可视区域宽度基数
|
viewportSize: 1000, // 可视区域宽度基数
|
||||||
viewportRatio: 0.5625, // 可视区域比例,默认16:9
|
viewportRatio: 0.5625, // 可视区域比例,默认16:9
|
||||||
animationIndex: 0, // 不是从0开始
|
|
||||||
workList:[],// 活动的列表
|
workList:[],// 活动的列表
|
||||||
workItem:[],// 获取到的所有pptlist
|
workItem:[],// 获取到的所有pptlist
|
||||||
}),
|
}),
|
||||||
|
@ -147,19 +145,48 @@ export const useSlidesStore = defineStore('slides', {
|
||||||
setWorkItem(list: Object[]) {
|
setWorkItem(list: Object[]) {
|
||||||
this.workItem = list
|
this.workItem = list
|
||||||
},
|
},
|
||||||
|
addWorkItem(data: any) {
|
||||||
|
const id = data?.parentid
|
||||||
|
if (!id) return
|
||||||
|
this.workItem.splice(this.slideIndex, 0, data)
|
||||||
|
},
|
||||||
|
|
||||||
async addSlide(slide: Slide | Slide[]) {
|
addSlide(slide: Slide | Slide[]) {
|
||||||
const { PPTApi } = await import('../api/index')
|
const resource = sessionStore.get('curr.resource')||{}
|
||||||
|
const enpt = sessionStore.get('curr.entp')||{}
|
||||||
|
const {id, ...content} = slide
|
||||||
|
const params = {
|
||||||
|
parentid: resource.id,
|
||||||
|
activityContent:null,
|
||||||
|
entpid: userStore.user.deptId,
|
||||||
|
entpcourseid: enpt.id,
|
||||||
|
ppttype: 'file',
|
||||||
|
title: '',
|
||||||
|
fileurl: '',
|
||||||
|
filetype: 'slide',
|
||||||
|
datacontent: JSON.stringify(content),
|
||||||
|
filekey: '',
|
||||||
|
filetag: '',
|
||||||
|
fileidx: 0,
|
||||||
|
dflag: 0,
|
||||||
|
status: '',
|
||||||
|
edituserid: userStore.id,
|
||||||
|
}
|
||||||
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
|
||||||
}
|
}
|
||||||
const addIndex = this.slideIndex + 1
|
API_entpcoursefile.addEntpcoursefileReturnId(params).then((rid:number) => {
|
||||||
this.slides.splice(addIndex, 0, ...slides)
|
if(!!rid){
|
||||||
this.slideIndex = addIndex
|
params.id = rid
|
||||||
// 添加到服务器
|
this.addWorkItem(params)
|
||||||
PPTApi.addSlideServer(slides, this.slides)
|
const addIndex = this.slideIndex + 1
|
||||||
|
this.slides.splice(addIndex, 0, ...slides)
|
||||||
|
this.slideIndex = addIndex
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
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
|
||||||
this.slides[slideIndex] = { ...this.slides[slideIndex], ...props }
|
this.slides[slideIndex] = { ...this.slides[slideIndex], ...props }
|
||||||
|
@ -211,9 +238,6 @@ export const useSlidesStore = defineStore('slides', {
|
||||||
updateSlideIndex(index: number) {
|
updateSlideIndex(index: number) {
|
||||||
this.slideIndex = index
|
this.slideIndex = index
|
||||||
},
|
},
|
||||||
updateAnimationIndex(index: number) {
|
|
||||||
this.animationIndex = index
|
|
||||||
},
|
|
||||||
|
|
||||||
addElement(element: PPTElement | PPTElement[]) {
|
addElement(element: PPTElement | PPTElement[]) {
|
||||||
const elements = Array.isArray(element) ? element : [element]
|
const elements = Array.isArray(element) ? element : [element]
|
||||||
|
|
|
@ -73,54 +73,3 @@ export const svg2File = (svg: string): File => {
|
||||||
const blob = new Blob([svg], { type: 'image/svg+xml' })
|
const blob = new Blob([svg], { type: 'image/svg+xml' })
|
||||||
return new File([blob], `${Date.now()}.svg`, { type: 'image/svg+xml' })
|
return new File([blob], `${Date.now()}.svg`, { type: 'image/svg+xml' })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前的时间
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getTime=()=>{
|
|
||||||
const now = new Date();
|
|
||||||
const year = now.getFullYear();
|
|
||||||
const month = ('0' + (now.getMonth() + 1)).slice(-2);
|
|
||||||
const day = ('0' + now.getDate()).slice(-2);
|
|
||||||
const hours = ('0' + now.getHours()).slice(-2);
|
|
||||||
const minutes = ('0' + now.getMinutes()).slice(-2);
|
|
||||||
const seconds = ('0' + now.getSeconds()).slice(-2);
|
|
||||||
return `${year}-${month}-${day}_${hours}:${minutes}:${seconds}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* base64转图片File
|
|
||||||
* @param {String} base64 图片base64
|
|
||||||
* @param {String} fileName 图片名称| 默认 → myimg
|
|
||||||
* @returns File 返回转换后的file数据类型
|
|
||||||
*/
|
|
||||||
export const base64ToFile = (base64: string, fileName = '试题图片') => {
|
|
||||||
// 将base64按照 , 进行分割 将前缀 与后续内容分隔开
|
|
||||||
let data = base64.split(','),
|
|
||||||
// 利用正则表达式 从前缀中获取图片的类型信息(image/png、image/jpeg、image/webp等)
|
|
||||||
type = data[0].match(/:(.*?);/)[1],
|
|
||||||
// 从图片的类型信息中 获取具体的文件格式后缀(png、jpeg、webp)
|
|
||||||
suffix = type.split('/')[1],
|
|
||||||
// 使用atob()对base64数据进行解码 结果是一个文件数据流 以字符串的格式输出
|
|
||||||
bstr = window.atob(data[1]),
|
|
||||||
// 获取解码结果字符串的长度
|
|
||||||
n = bstr.length,
|
|
||||||
// 根据解码结果字符串的长度创建一个等长的整形数字数组
|
|
||||||
// 但在创建时 所有元素初始值都为 0
|
|
||||||
u8arr = new Uint8Array(n)
|
|
||||||
|
|
||||||
// 将整形数组的每个元素填充为解码结果字符串对应位置字符的UTF-16 编码单元
|
|
||||||
while (n--) {
|
|
||||||
// charCodeAt():获取给定索引处字符对应的 UTF-16 代码单元
|
|
||||||
u8arr[n] = bstr.charCodeAt(n)
|
|
||||||
}
|
|
||||||
const filename = fileName+getTime()
|
|
||||||
// 利用构造函数创建File文件对象
|
|
||||||
// new File(bits, name, options)
|
|
||||||
const file = new File([u8arr], `${filename}.${suffix}`, {
|
|
||||||
type: type
|
|
||||||
})
|
|
||||||
// 返回file
|
|
||||||
return file
|
|
||||||
}
|
|
|
@ -19,9 +19,7 @@
|
||||||
import { ref, reactive, onMounted, computed } from 'vue';
|
import { ref, reactive, onMounted, computed } from 'vue';
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { getSmarttalkPage } from '@/api/file'
|
import { getSmarttalkPage } from '@/api/file'
|
||||||
import * as commUtils from '@/utils/comm.js'
|
import { getFileSuffix, urlToBase64 } 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 +59,70 @@ const fileUrl = computed(() => (item) =>{
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// 插入
|
// 插入
|
||||||
const onInsert = async (item) =>{
|
const onInsert = async (item) =>{
|
||||||
loading.value = true
|
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
||||||
const res = await fetch(item.fileFullPath)
|
emit('insertMaterial',{ type: 'video', data: item.fileFullPath })
|
||||||
const bolb = await res.blob()
|
}
|
||||||
const file = commUtils.blobToFile(bolb, item.fileShowName)
|
else{
|
||||||
|
const base64 = await urlToBase64(item.fileFullPath)
|
||||||
try {
|
emit('insertMaterial',{ type: 'img', data: base64 })
|
||||||
const data = await PPTApi.toRousrceUrl(file)
|
|
||||||
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
|
||||||
emit('insertMaterial',{ type: 'video', data })
|
|
||||||
}
|
|
||||||
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);
|
||||||
|
|
|
@ -114,7 +114,7 @@
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<!--插入试题-->
|
|
||||||
<el-dialog v-model="classWorkTaskVisible" append-to-body :show-close="false" width="70%">
|
<el-dialog v-model="classWorkTaskVisible" append-to-body :show-close="false" width="70%">
|
||||||
<QuestToPPTist
|
<QuestToPPTist
|
||||||
class="class-work-task-modal"
|
class="class-work-task-modal"
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
<Modal
|
<Modal
|
||||||
v-model:visible="imgVisible"
|
v-model:visible="imgVisible"
|
||||||
:width="1300">
|
:width="1300">
|
||||||
<TextCreateImg hasPPt @insertImg="insertImg" />
|
<TextCreateImg hasPPt @insertImg="(url: string) => { createImageElement(url); imgVisible = false }" />
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useMainStore, useSnapshotStore } from '../../../store'
|
import { useMainStore, useSnapshotStore } from '../../../store'
|
||||||
import { getImageDataURL, base64ToFile } from '../../../utils/image'
|
import { getImageDataURL } from '../../../utils/image'
|
||||||
import type { ShapePoolItem } from '../../../configs/shapes'
|
import type { ShapePoolItem } from '../../../configs/shapes'
|
||||||
import type { LinePoolItem } from '../../../configs/lines'
|
import type { LinePoolItem } from '../../../configs/lines'
|
||||||
import useScaleCanvas from '../../../hooks/useScaleCanvas'
|
import useScaleCanvas from '../../../hooks/useScaleCanvas'
|
||||||
|
@ -165,7 +165,6 @@ import { PPTApi } from '../../../api'
|
||||||
import TextCreateImg from '@/components/ai-kolors/index.vue'
|
import TextCreateImg from '@/components/ai-kolors/index.vue'
|
||||||
import { toPng } from 'html-to-image' // 引入html-to-image库
|
import { toPng } from 'html-to-image' // 引入html-to-image库
|
||||||
|
|
||||||
|
|
||||||
const mainStore = useMainStore()
|
const mainStore = useMainStore()
|
||||||
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
|
const { creatingElement, creatingCustomShape, showSelectPanel, showSearchPanel, showNotesPanel } = storeToRefs(mainStore)
|
||||||
const { canUndo, canRedo } = storeToRefs(useSnapshotStore())
|
const { canUndo, canRedo } = storeToRefs(useSnapshotStore())
|
||||||
|
@ -210,14 +209,8 @@ const insertImageElement = (files: FileList) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onhtml2canvas = async (html: HTMLElement) => {
|
const onhtml2canvas = async (html: HTMLElement) => {
|
||||||
const base64Dta = await toPng(html);
|
const ele = await toPng(html);
|
||||||
// base64转图片File
|
createImageElement(ele);
|
||||||
const toFile = base64ToFile(base64Dta)
|
|
||||||
// 上传图片转为线上地址
|
|
||||||
PPTApi.toRousrceUrl(toFile).then(data=>{
|
|
||||||
createImageElement(data)
|
|
||||||
})
|
|
||||||
// createImageElement(ele);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const shapePoolVisible = ref(false)
|
const shapePoolVisible = ref(false)
|
||||||
|
@ -283,7 +276,7 @@ interface MaterialParams {
|
||||||
type: string,
|
type: string,
|
||||||
data: string
|
data: string
|
||||||
}
|
}
|
||||||
const insertMaterial = async (item: MaterialParams) =>{
|
const insertMaterial = (item: MaterialParams) =>{
|
||||||
const { type, data } = item
|
const { type, data } = item
|
||||||
if(type == 'video'){
|
if(type == 'video'){
|
||||||
createVideoElement(data)
|
createVideoElement(data)
|
||||||
|
@ -296,13 +289,6 @@ const insertMaterial = async (item: MaterialParams) =>{
|
||||||
|
|
||||||
// 文生图
|
// 文生图
|
||||||
const imgVisible = ref(false)
|
const imgVisible = ref(false)
|
||||||
const insertImg = async (file: any) =>{
|
|
||||||
PPTApi.toRousrceUrl(file).then(data=>{
|
|
||||||
createImageElement(data)
|
|
||||||
imgVisible.value = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 />
|
||||||
|
@ -38,22 +32,22 @@
|
||||||
<!-- 作业列表 -->
|
<!-- 作业列表 -->
|
||||||
<div class="c-apt-r" v-loading='loadingActive'>
|
<div class="c-apt-r" v-loading='loadingActive'>
|
||||||
<!-- 显示-作业内容 -->
|
<!-- 显示-作业内容 -->
|
||||||
<template v-for="(item, index) in slidesStore.workList" :key="index">
|
<template v-for="(item, index) in workList" :key="index">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="item-title">
|
<div class="item-title">
|
||||||
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
|
<el-tag :type="getTagType(item.worktype) || 'primary'">{{item.worktype}}</el-tag>
|
||||||
<el-tooltip :content="item.uniquekey" placement="top">
|
<el-tooltip :content="item.uniquekey" placement="top">
|
||||||
<div class="tt">{{item.uniquekey}}</div>
|
<div class="tt">{{item.uniquekey}}</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-button class="btn-del" type="danger" link @click="removeWork(item, index)">删除</el-button>
|
<el-button class="btn-del" type="danger" link @click="handleRemoveDemoActivityClassWork(item)">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<!-- // 推送作业 -->
|
<!-- // 推送作业 -->
|
||||||
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="85%" height="500">
|
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="90%" height="500">
|
||||||
<el-scrollbar>
|
<el-scrollbar height="550">
|
||||||
<div style="height: 75vh;">
|
<div style="height: 550px;">
|
||||||
<NewClassTsakAssign :currentCourse='currentCourse' @getData="getData" />
|
<NewClassTsakAssign :currentCourse='currentCourse' @getData="getData" />
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
@ -86,13 +80,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, nextTick, watch } from 'vue'
|
import { ref, reactive, onMounted, nextTick, watch } from 'vue'
|
||||||
import Divider from '../../../../../components/Divider.vue'
|
import Divider from '../../../../../components/Divider.vue'
|
||||||
|
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
|
import { homeworklist } from '@/api/teaching/classwork'
|
||||||
|
import { processList } from "@/hooks/useProcessList";
|
||||||
|
import { listEntpcoursework } from "@/api/classTask/index";
|
||||||
import { ElMessageBox,ElMessage } from 'element-plus'
|
import { ElMessageBox,ElMessage } from 'element-plus'
|
||||||
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
|
import NewClassTsakAssign from '@/views/classTask/newClassTaskAssign/index.vue'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
import { PPTApi } from '../../../../../api/index'
|
import { PPTApi } from '../../../../../api/index'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
import {useSlidesStore} from '../../../../../store'
|
import {useSlidesStore} from '../../../../../store'
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
|
const { slides, slideIndex, currentSlide, workItem } = storeToRefs(slidesStore)
|
||||||
|
|
||||||
interface CourseNode {
|
interface CourseNode {
|
||||||
rootid: number;
|
rootid: number;
|
||||||
parentNode: { id: number };
|
parentNode: { id: number };
|
||||||
|
@ -110,6 +111,12 @@ interface CurrentCourse {
|
||||||
worktype: string;
|
worktype: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Params {
|
||||||
|
parentid: number;
|
||||||
|
pageSize: number;
|
||||||
|
orderby: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface WorkType {
|
interface WorkType {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -160,37 +167,65 @@ const type = ref<WorkType[]>([
|
||||||
label: '常规作业',
|
label: '常规作业',
|
||||||
value: 'primary'
|
value: 'primary'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '框架梳理',
|
|
||||||
value: 'primary'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '科学实验',
|
|
||||||
value: 'primary'
|
|
||||||
}
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const objItem = ref<any>({})
|
||||||
|
// 作业列表
|
||||||
|
const workList = ref<WorkItem[]>([])
|
||||||
|
|
||||||
// 获取所选择的作业列表
|
// 获取所选择的作业列表
|
||||||
const selectedWorkList = ref<WorkItem[]>([])
|
const selectedWorkList = ref<WorkItem[]>([])
|
||||||
// 活动页面的loading框
|
// 活动页面的loading框
|
||||||
const loadingActive = ref<boolean>(false)
|
const loadingActive = ref<boolean>(false)
|
||||||
|
|
||||||
// 选择活动列表
|
|
||||||
|
const paramData = ref<{ id: number, activityContent: string }>({} as { id: number, activityContent: string })
|
||||||
|
|
||||||
const selectable = (row: WorkItem, index: number): boolean => {
|
const selectable = (row: WorkItem, index: number): boolean => {
|
||||||
return row.status === '10';
|
return row.status === '10';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除作业
|
|
||||||
const removeWork = (item: WorkItem, index: number) => {
|
const formatClassWorkFile = async (postData: WorkItem[]): Promise<void> => {
|
||||||
|
for (let i = 0; i < postData.length; i++) {
|
||||||
|
let item = postData[i];
|
||||||
|
switch (item.worktype) {
|
||||||
|
case '框架梳理': {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '习题训练': {
|
||||||
|
// let workIds = item.quizlist!.map(items => items.id).join(',');
|
||||||
|
// let ress = await listEntpcoursework({ ids: workIds });
|
||||||
|
// const arr = ress.rows.map((item:{id:number}) => {
|
||||||
|
// return item.id
|
||||||
|
// })
|
||||||
|
|
||||||
|
// processList(ress.rows);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '课堂展示': {
|
||||||
|
// item.base64 = JSON.parse(item.workcodes).base64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '常规作业': {
|
||||||
|
// item.prevData = JSON.parse(item.workcodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
workList.value.push(item)
|
||||||
|
loadingActive.value = false
|
||||||
|
}
|
||||||
|
await nextTick();
|
||||||
|
}// 删除作业
|
||||||
|
const handleRemoveDemoActivityClassWork = (item: WorkItem) => {
|
||||||
ElMessageBox.confirm('是否确认删除?')
|
ElMessageBox.confirm('是否确认删除?')
|
||||||
.then(async() => {
|
.then(() => {
|
||||||
// 从workList中删除
|
workList.value = []
|
||||||
// slidesStore.workList.splice(index, 1)
|
const arr = paramData.value.activityContent.split(',')
|
||||||
console.log('删除作业', item)
|
const filterArr = arr.filter(itemId => itemId!== item.id.toString())
|
||||||
await upDateData('del', [item.id])
|
paramData.value.activityContent = filterArr.join(',')
|
||||||
ElMessage.success('删除成功')
|
upDateData()
|
||||||
})
|
})
|
||||||
.catch(() => { });
|
.catch(() => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取tag的样式
|
// 获取tag的样式
|
||||||
|
@ -217,7 +252,6 @@ const showDialog = (item: string) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开活动引用列表
|
|
||||||
const openList = () => {
|
const openList = () => {
|
||||||
activeVisible.value = true
|
activeVisible.value = true
|
||||||
initHomeWork()
|
initHomeWork()
|
||||||
|
@ -225,44 +259,65 @@ const openList = () => {
|
||||||
|
|
||||||
// 添加活动引用列表作业
|
// 添加活动引用列表作业
|
||||||
const savePPtData = async () => {
|
const savePPtData = async () => {
|
||||||
if (!selectedWorkList.value.length) {
|
if (selectedWorkList.value.length === 0) {
|
||||||
ElMessage.warning('请选择活动')
|
ElMessage.warning('请选择活动')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const arr = selectedWorkList.value.map(item => item.id)
|
workList.value = []
|
||||||
await upDateData('add', arr)
|
const arr = selectedWorkList.value.map(item => item.id)
|
||||||
activeVisible.value = false
|
// 应该是新加而不是覆盖
|
||||||
|
const existingIds = paramData.value.activityContent ? paramData.value.activityContent.split(',') : []
|
||||||
|
paramData.value.activityContent = Array.from(new Set([...existingIds, ...arr])).join(',')
|
||||||
|
upDateData()
|
||||||
|
activeVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前ppt页的数据
|
||||||
|
const getCurrentPPtData = async () => {
|
||||||
|
workList.value = []
|
||||||
|
objItem.value = workItem.value[slideIndex.value]
|
||||||
|
paramData.value.id = objItem.value.id
|
||||||
|
console.log(paramData.value.id,'paramData.value.id');
|
||||||
|
|
||||||
|
paramData.value.activityContent = objItem.value?.activityContent
|
||||||
|
if (objItem.value?.activityContent) {
|
||||||
|
loadingActive.value = true
|
||||||
|
const res = await homeworklist({ ids: objItem.value?.activityContent, pageSize: 100 })
|
||||||
|
await formatClassWorkFile(res.rows)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 接收习题训练的值
|
// 接收习题训练的值
|
||||||
const getData = async (data: WorkItem) => {
|
const getData = async (data: WorkItem) => {
|
||||||
await upDateData('add', [data.id])
|
workList.value = []
|
||||||
dialogVisible.value = false
|
if(paramData.value.activityContent){
|
||||||
}
|
const arr = paramData.value.activityContent.split(',')
|
||||||
// 更新数据-活动 type add/增加 | del/删除 ids 作业id
|
arr.push(data.id.toString())
|
||||||
const upDateData = (type: string, ids: number[]): Promise<any> => {
|
const unitArr = Array.from(new Set(arr))
|
||||||
return new Promise(async (resolve, reject) => {
|
paramData.value.activityContent = unitArr.join(',')
|
||||||
loadingActive.value = true
|
}else{
|
||||||
// 更新本地数据
|
paramData.value.activityContent = data.id.toString()
|
||||||
let workIds = slidesStore.workList.map((o:any) => o.id)
|
|
||||||
const id = slidesStore.currentSlide.id
|
|
||||||
if (type === 'del') { // 删除
|
|
||||||
workIds = workIds.filter(id => !ids.includes(id))
|
|
||||||
} else { // 增加
|
|
||||||
workIds = Array.from(new Set([...workIds, ...ids]))
|
|
||||||
}
|
}
|
||||||
// 保存到本地
|
upDateData()
|
||||||
const wItem:any = slidesStore.workItem.find((o:any) => o.id === id)
|
dialogVisible.value = false
|
||||||
const workIdsStr = workIds.join(',') // 作业id->字符串
|
}
|
||||||
if (!!wItem) wItem.activityContent = workIdsStr
|
const upDateData = async () => {
|
||||||
const data = { id, activityContent: workIdsStr }
|
await PPTApi.updateSlide(paramData.value)
|
||||||
// 修改数据库
|
loadingActive.value = true
|
||||||
await PPTApi.updateSlide(data, false)
|
const res = await homeworklist({ ids: paramData.value.activityContent, pageSize: 100 })
|
||||||
// 刷新活动列表
|
await formatClassWorkFile(res.rows)
|
||||||
await PPTApi.updateWorkList()
|
const resource = sessionStore.get('curr.resource')
|
||||||
loadingActive.value = false
|
await PPTApi.getSlideList(resource.id)
|
||||||
resolve(true)
|
}
|
||||||
})
|
// 判断是否做操作
|
||||||
|
const objectsAreEqual = (obj1: any[], obj2: any[]) => {
|
||||||
|
const keys1 = Object.keys(obj1);
|
||||||
|
const keys2 = Object.keys(obj2);
|
||||||
|
if (keys1.length !== keys2.length) return false;
|
||||||
|
for (const key of keys1) {
|
||||||
|
if (obj1[key] !== obj2[key]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -272,8 +327,16 @@ onMounted(() => {
|
||||||
currentCourse.levelSecondId = curNode.id
|
currentCourse.levelSecondId = curNode.id
|
||||||
currentCourse.coursetitle = curNode.itemtitle
|
currentCourse.coursetitle = curNode.itemtitle
|
||||||
currentCourse.node = curNode
|
currentCourse.node = curNode
|
||||||
|
objItem.value = workItem.value[slideIndex.value]
|
||||||
|
getCurrentPPtData()
|
||||||
})
|
})
|
||||||
|
watch(() => [workItem.value.length,slideIndex.value], (newVal,oldVal) => {
|
||||||
|
if(!objectsAreEqual(newVal,oldVal))
|
||||||
|
getCurrentPPtData()
|
||||||
|
})
|
||||||
|
// watch(() => workItem.value.length, () => {
|
||||||
|
// getCurrentPPtData()
|
||||||
|
// })
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.buttonDiv{
|
.buttonDiv{
|
||||||
|
|
|
@ -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)
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置图片:清除全部样式
|
// 重置图片:清除全部样式
|
||||||
|
|
|
@ -30,14 +30,18 @@
|
||||||
@close="timerlVisible = false"
|
@close="timerlVisible = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="tools-left" v-if="!classcourse">
|
<div class="tools-left">
|
||||||
<IconLeftTwo class="tool-btn" theme="two-tone" :fill="['#111', '#fff']" @click="execPrev()" />
|
<IconLeftTwo class="tool-btn" theme="two-tone" :fill="['#111', '#fff']" @click="execPrev()" />
|
||||||
<IconRightTwo class="tool-btn" theme="two-tone" :fill="['#111', '#fff']" @click="execNext()" />
|
<IconRightTwo class="tool-btn" theme="two-tone" :fill="['#111', '#fff']" @click="execNext()" />
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 点赞组件 -->
|
||||||
|
<div style="z-index: 999;position: absolute;top:10px">
|
||||||
|
<upvote-vue ref="upvoteRef" type="2"></upvote-vue>
|
||||||
|
</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,22 +51,16 @@
|
||||||
<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" />
|
|
||||||
<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>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref , watchEffect, onMounted, onUnmounted} from 'vue'
|
import { ref , watchEffect} from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useSlidesStore ,useScreenStore, useClasscourseStore} from '../../store'
|
import { useSlidesStore ,useScreenStore} from '../../store'
|
||||||
import type { ContextmenuItem } from '../../components/Contextmenu/types'
|
import type { ContextmenuItem } from '../../components/Contextmenu/types'
|
||||||
import { enterFullscreen } from '../../utils/fullscreen'
|
import { enterFullscreen } from '../../utils/fullscreen'
|
||||||
import useScreening from '../../hooks/useScreening'
|
import useScreening from '../../hooks/useScreening'
|
||||||
|
@ -74,17 +72,14 @@ import ScreenSlideList from './ScreenSlideList.vue'
|
||||||
import SlideThumbnails from './SlideThumbnails.vue'
|
import SlideThumbnails from './SlideThumbnails.vue'
|
||||||
import WritingBoardTool from './WritingBoardTool.vue'
|
import WritingBoardTool from './WritingBoardTool.vue'
|
||||||
import CountdownTimer from './CountdownTimer.vue'
|
import CountdownTimer from './CountdownTimer.vue'
|
||||||
|
import upvoteVue from '@/views/tool/components/upvote.vue' // 点赞-子组件
|
||||||
import emitter from '@/utils/mitt';
|
import emitter from '@/utils/mitt';
|
||||||
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
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { slides, slideIndex } = storeToRefs(useSlidesStore())
|
const { slides, slideIndex } = storeToRefs(useSlidesStore())
|
||||||
const { classcourse, isEmit } = storeToRefs(useClasscourseStore()) // 课堂信息
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
autoPlayTimer,
|
autoPlayTimer,
|
||||||
|
@ -105,20 +100,18 @@ const {
|
||||||
execNext,
|
execNext,
|
||||||
animationIndex,
|
animationIndex,
|
||||||
} = useExecPlay()
|
} = useExecPlay()
|
||||||
|
|
||||||
const { slideWidth, slideHeight } = useSlideSize()
|
const { slideWidth, slideHeight } = useSlideSize()
|
||||||
const { exitScreening } = useScreening()
|
const { exitScreening } = useScreening()
|
||||||
const { fullscreenState, manualExitFullscreen } = useFullscreen()
|
const { fullscreenState, manualExitFullscreen } = useFullscreen()
|
||||||
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 upvoteRef = ref(null)
|
||||||
const iconHide = ref(false) // 工具栏图标是否显示
|
const screenStore =useScreenStore()
|
||||||
const timerId = ref(null) // 定时器id
|
|
||||||
const contextmenus = (): ContextmenuItem[] => {
|
const contextmenus = (): ContextmenuItem[] => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -200,37 +193,11 @@ const contextmenus = (): ContextmenuItem[] => {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
// 工具栏按钮触发
|
// 打开点赞或者疑问 1点赞 2疑问
|
||||||
const toolTrigger = (type:string) => {
|
emitter.on('upvoteTrigger', (type) => {
|
||||||
const curT = Date.now()
|
upvoteRef.value?.trigger(type)
|
||||||
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 () => {
|
|
||||||
// console.log('下课', chat)
|
|
||||||
await chat.exitCourse() // 下课消息
|
|
||||||
exitScreening() // 结束放映
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -287,18 +254,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%;
|
||||||
|
@ -324,9 +279,6 @@ const exitCourse = async () => {
|
||||||
& + .tool-btn {
|
& + .tool-btn {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
&.close{
|
|
||||||
color: #d14424;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.page-number {
|
.page-number {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|
|
@ -10,10 +10,8 @@
|
||||||
<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>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -57,7 +55,7 @@
|
||||||
:class="{ 'active': index === slideIndex }"
|
:class="{ 'active': index === slideIndex }"
|
||||||
v-for="(slide, index) in slides"
|
v-for="(slide, index) in slides"
|
||||||
:key="slide.id"
|
:key="slide.id"
|
||||||
@click="turnSlideTo(index, $event)"
|
@click="turnSlideToIndex(index)"
|
||||||
>
|
>
|
||||||
<ThumbnailSlide :slide="slide" :size="120 / viewportRatio" :visible="index < slidesLoadLimit" />
|
<ThumbnailSlide :slide="slide" :size="120 / viewportRatio" :visible="index < slidesLoadLimit" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -79,10 +77,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Share } from '@icon-park/vue-next' // icon-park 图标库
|
import { computed, nextTick, 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 } from '../../store'
|
||||||
import type { ContextmenuItem } from '../../components/Contextmenu/types'
|
import type { ContextmenuItem } from '../../components/Contextmenu/types'
|
||||||
import { enterFullscreen } from '../../utils/fullscreen'
|
import { enterFullscreen } from '../../utils/fullscreen'
|
||||||
import { parseText2Paragraphs } from '../../utils/textParser'
|
import { parseText2Paragraphs } from '../../utils/textParser'
|
||||||
|
@ -97,16 +94,12 @@ import ScreenSlideList from './ScreenSlideList.vue'
|
||||||
import WritingBoardTool from './WritingBoardTool.vue'
|
import WritingBoardTool from './WritingBoardTool.vue'
|
||||||
import CountdownTimer from './CountdownTimer.vue'
|
import CountdownTimer from './CountdownTimer.vue'
|
||||||
import Divider from '../../components/Divider.vue'
|
import Divider from '../../components/Divider.vue'
|
||||||
import emitter from '@/utils/mitt';
|
|
||||||
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
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { slides, slideIndex, viewportRatio, currentSlide } = storeToRefs(useSlidesStore())
|
const { slides, slideIndex, viewportRatio, currentSlide } = storeToRefs(useSlidesStore())
|
||||||
const { classcourse, isEmit } = storeToRefs(useClasscourseStore()) // 课堂信息
|
|
||||||
|
|
||||||
const slideListWrapRef = ref<HTMLElement>()
|
const slideListWrapRef = ref<HTMLElement>()
|
||||||
const thumbnailsRef = ref<HTMLElement>()
|
const thumbnailsRef = ref<HTMLElement>()
|
||||||
|
@ -124,36 +117,17 @@ const {
|
||||||
turnSlideToId,
|
turnSlideToId,
|
||||||
animationIndex,
|
animationIndex,
|
||||||
} = useExecPlay()
|
} = useExecPlay()
|
||||||
|
|
||||||
const { slideWidth, slideHeight } = useSlideSize(slideListWrapRef)
|
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 remarkFontSize = ref(16)
|
const remarkFontSize = ref(16)
|
||||||
const currentSlideRemark = computed(() => {
|
const currentSlideRemark = computed(() => {
|
||||||
return parseText2Paragraphs(currentSlide.value.remark || '无备注')
|
return parseText2Paragraphs(currentSlide.value.remark || '无备注')
|
||||||
})
|
})
|
||||||
|
|
||||||
// 切换到指定的幻灯片
|
|
||||||
const turnSlideTo = (index: number, e: PointerEvent) => {
|
|
||||||
const preInd = slideIndex.value
|
|
||||||
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 () => {
|
|
||||||
// console.log('下课', chat)
|
|
||||||
await chatApi.exitCourse() // 下课消息
|
|
||||||
exitScreening() // 结束放映
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMousewheelThumbnails = (e: WheelEvent) => {
|
const handleMousewheelThumbnails = (e: WheelEvent) => {
|
||||||
if (!thumbnailsRef.value) return
|
if (!thumbnailsRef.value) return
|
||||||
thumbnailsRef.value.scrollBy(e.deltaY, 0)
|
thumbnailsRef.value.scrollBy(e.deltaY, 0)
|
||||||
|
@ -218,7 +192,6 @@ const contextmenus = (): ContextmenuItem[] => {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -235,7 +208,7 @@ const contextmenus = (): ContextmenuItem[] => {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-right: solid 1px #eee;
|
border-right: solid 1px #eee;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 20px 0;
|
margin: 20px 0;
|
||||||
|
|
||||||
.tool-btn {
|
.tool-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -251,9 +224,6 @@ const contextmenus = (): ContextmenuItem[] => {
|
||||||
&:hover, &.active {
|
&:hover, &.active {
|
||||||
color: $themeColor;
|
color: $themeColor;
|
||||||
}
|
}
|
||||||
&.close{
|
|
||||||
color: #d14424;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
import { onMounted, onUnmounted, ref } from 'vue'
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { throttle } from 'lodash'
|
import { throttle } from 'lodash'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useSlidesStore, useClasscourseStore } from '../../../store'
|
import { useSlidesStore } from '../../../store'
|
||||||
import { KEYS } from '../../../configs/hotkey'
|
import { KEYS } from '../../../configs/hotkey'
|
||||||
import { ANIMATION_CLASS_PREFIX } from '../../../configs/animation'
|
import { ANIMATION_CLASS_PREFIX } from '../../../configs/animation'
|
||||||
import message from '../../../utils/message'
|
import message from '../../../utils/message'
|
||||||
import emitter from '@/utils/mitt';
|
|
||||||
import Chat from '../../../api/chat' // 聊天封装
|
|
||||||
// import ChatWs from '@/plugins/socket' // 聊天socket
|
|
||||||
// import { MsgEnum } from '../../../api/types' // 消息枚举
|
|
||||||
|
|
||||||
export default (isLoader?: boolean = true) => {
|
export default () => {
|
||||||
// isLoader 是否执行 onMounted, onUnmounted
|
|
||||||
const chatApi = Chat()
|
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
const { slides, slideIndex, formatedAnimations } = storeToRefs(slidesStore)
|
||||||
const { slides, slideIndex, formatedAnimations, animationIndex } = storeToRefs(slidesStore)
|
|
||||||
|
|
||||||
// 当前页的元素动画执行到的位置
|
// 当前页的元素动画执行到的位置
|
||||||
// const animationIndex = ref(0)
|
const animationIndex = ref(0)
|
||||||
|
|
||||||
// 动画执行状态
|
// 动画执行状态
|
||||||
const inAnimation = ref(false)
|
const inAnimation = ref(false)
|
||||||
|
@ -26,10 +19,10 @@ export default (isLoader?: boolean = true) => {
|
||||||
// 最小已播放页面索引
|
// 最小已播放页面索引
|
||||||
const playedSlidesMinIndex = ref(slideIndex.value)
|
const playedSlidesMinIndex = ref(slideIndex.value)
|
||||||
|
|
||||||
// 执行元素动画 isAsync 为 true 时,异步执行,否则同步执行
|
// 执行元素动画
|
||||||
const runAnimation = (isAsync: boolean) => {
|
const runAnimation = () => {
|
||||||
// 正在执行动画时,禁止其他新的动画开始
|
// 正在执行动画时,禁止其他新的动画开始
|
||||||
if (inAnimation.value && !isAsync) return
|
if (inAnimation.value) return
|
||||||
|
|
||||||
const { animations, autoNext } = formatedAnimations.value[animationIndex.value]
|
const { animations, autoNext } = formatedAnimations.value[animationIndex.value]
|
||||||
animationIndex.value += 1
|
animationIndex.value += 1
|
||||||
|
@ -76,15 +69,14 @@ export default (isLoader?: boolean = true) => {
|
||||||
elRef.addEventListener('animationend', handleAnimationEnd, { once: true })
|
elRef.addEventListener('animationend', handleAnimationEnd, { once: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isLoader) { // 加载相关钩子
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const firstAnimations = formatedAnimations.value[0]
|
const firstAnimations = formatedAnimations.value[0]
|
||||||
if (firstAnimations && firstAnimations.animations.length) {
|
if (firstAnimations && firstAnimations.animations.length) {
|
||||||
const autoExecFirstAnimations = firstAnimations.animations.every(item => item.trigger === 'auto' || item.trigger === 'meantime')
|
const autoExecFirstAnimations = firstAnimations.animations.every(item => item.trigger === 'auto' || item.trigger === 'meantime')
|
||||||
if (autoExecFirstAnimations) runAnimation()
|
if (autoExecFirstAnimations) runAnimation()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 撤销元素动画,除了将索引前移外,还需要清除动画状态
|
// 撤销元素动画,除了将索引前移外,还需要清除动画状态
|
||||||
const revokeAnimation = () => {
|
const revokeAnimation = () => {
|
||||||
|
@ -129,9 +121,9 @@ export default (isLoader?: boolean = true) => {
|
||||||
// 遇到元素动画时,优先执行动画播放,无动画则执行翻页
|
// 遇到元素动画时,优先执行动画播放,无动画则执行翻页
|
||||||
// 向上播放遇到动画时,仅撤销到动画执行前的状态,不需要反向播放动画
|
// 向上播放遇到动画时,仅撤销到动画执行前的状态,不需要反向播放动画
|
||||||
// 撤回到上一页时,若该页从未播放过(意味着不存在动画状态),需要将动画索引置为最小值(初始状态),否则置为最大值(最终状态)
|
// 撤回到上一页时,若该页从未播放过(意味着不存在动画状态),需要将动画索引置为最小值(初始状态),否则置为最大值(最终状态)
|
||||||
const execPrev = (isAsync: boolean) => {
|
const execPrev = () => {
|
||||||
if (formatedAnimations.value.length && animationIndex.value > 0) {
|
if (formatedAnimations.value.length && animationIndex.value > 0) {
|
||||||
revokeAnimation(isAsync)
|
revokeAnimation()
|
||||||
}
|
}
|
||||||
else if (slideIndex.value > 0) {
|
else if (slideIndex.value > 0) {
|
||||||
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
||||||
|
@ -147,9 +139,9 @@ export default (isLoader?: boolean = true) => {
|
||||||
}
|
}
|
||||||
inAnimation.value = false
|
inAnimation.value = false
|
||||||
}
|
}
|
||||||
const execNext = (isAsync: boolean) => {
|
const execNext = () => {
|
||||||
if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
|
if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
|
||||||
runAnimation(isAsync)
|
runAnimation()
|
||||||
}
|
}
|
||||||
else if (slideIndex.value < slides.value.length - 1) {
|
else if (slideIndex.value < slides.value.length - 1) {
|
||||||
slidesStore.updateSlideIndex(slideIndex.value + 1)
|
slidesStore.updateSlideIndex(slideIndex.value + 1)
|
||||||
|
@ -181,69 +173,51 @@ export default (isLoader?: boolean = true) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鼠标滚动翻页
|
// 鼠标滚动翻页
|
||||||
const mousewheelListener = (e: WheelEvent) => {
|
const mousewheelListener = throttle(function(e: WheelEvent) {
|
||||||
// console.log('mousewheel', e)
|
if (e.deltaY < 0) execPrev()
|
||||||
e.preventDefault() // 阻止默认事件
|
else if (e.deltaY > 0) execNext()
|
||||||
mousewheelListenerThrottle(e)
|
|
||||||
}
|
|
||||||
const mousewheelListenerThrottle = throttle(function(e: WheelEvent) {
|
|
||||||
if (e.deltaY < 0) turning(e, 'prev')
|
|
||||||
else if (e.deltaY > 0) turning(e, 'next')
|
|
||||||
}, 500, { leading: true, trailing: false })
|
}, 500, { leading: true, trailing: false })
|
||||||
|
|
||||||
// 触摸屏上下滑动翻页
|
// 触摸屏上下滑动翻页
|
||||||
const touchInfo = ref<{ x: number; y: number; } | null>(null)
|
const touchInfo = ref<{ x: number; y: number; } | null>(null)
|
||||||
|
|
||||||
const touchStartListener = (e: TouchEvent) => {
|
const touchStartListener = (e: TouchEvent) => {
|
||||||
e.preventDefault() // 阻止默认事件
|
|
||||||
touchInfo.value = {
|
touchInfo.value = {
|
||||||
// x: e.changedTouches[0].pageX,
|
x: e.changedTouches[0].pageX,
|
||||||
// y: e.changedTouches[0].pageY,
|
y: e.changedTouches[0].pageY,
|
||||||
x: e.changedTouches[0].clientX,
|
|
||||||
y: e.changedTouches[0].clientY,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const touchEndListener = (e: TouchEvent) => {
|
const touchEndListener = (e: TouchEvent) => {
|
||||||
if (!touchInfo.value) return
|
if (!touchInfo.value) return
|
||||||
const offsetX = Math.abs(touchInfo.value.x - e.changedTouches[0].clientX)
|
|
||||||
const offsetY = e.changedTouches[0].clientY - touchInfo.value.y
|
const offsetX = Math.abs(touchInfo.value.x - e.changedTouches[0].pageX)
|
||||||
|
const offsetY = e.changedTouches[0].pageY - touchInfo.value.y
|
||||||
|
|
||||||
if ( Math.abs(offsetY) > offsetX && Math.abs(offsetY) > 50 ) {
|
if ( Math.abs(offsetY) > offsetX && Math.abs(offsetY) > 50 ) {
|
||||||
touchInfo.value = null
|
touchInfo.value = null
|
||||||
if (offsetY > 0) turning(e, 'prev')
|
|
||||||
else turning(e, 'next')
|
if (offsetY > 0) execPrev()
|
||||||
}
|
else execNext()
|
||||||
}
|
|
||||||
// 向上翻页/向下翻页
|
|
||||||
const turning = async (e, type) => {
|
|
||||||
e.preventDefault() // 阻止默认事件
|
|
||||||
if (type === 'prev') execPrev()
|
|
||||||
else if (type === 'next') execNext()
|
|
||||||
if (classcourseStore.classcourse) { // 上课中
|
|
||||||
const current = slideIndex.value
|
|
||||||
const animationSteps = animationIndex.value
|
|
||||||
const animation = type == 'next'?'Nextsteps':'Previoustep'
|
|
||||||
const msg = { current, animation, animationSteps}
|
|
||||||
chatApi.slideFlapping(msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 快捷键翻页
|
// 快捷键翻页
|
||||||
const keydownListener = (e: KeyboardEvent) => {
|
const keydownListener = (e: KeyboardEvent) => {
|
||||||
const key = e.key.toUpperCase()
|
const key = e.key.toUpperCase()
|
||||||
|
|
||||||
if (key === KEYS.UP || key === KEYS.LEFT || key === KEYS.PAGEUP) turning(e, 'prev')
|
if (key === KEYS.UP || key === KEYS.LEFT || key === KEYS.PAGEUP) execPrev()
|
||||||
else if (
|
else if (
|
||||||
key === KEYS.DOWN ||
|
key === KEYS.DOWN ||
|
||||||
key === KEYS.RIGHT ||
|
key === KEYS.RIGHT ||
|
||||||
key === KEYS.SPACE ||
|
key === KEYS.SPACE ||
|
||||||
key === KEYS.ENTER ||
|
key === KEYS.ENTER ||
|
||||||
key === KEYS.PAGEDOWN
|
key === KEYS.PAGEDOWN
|
||||||
) turning(e, 'next')
|
) execNext()
|
||||||
}
|
|
||||||
if (isLoader) { // 加载相关钩子
|
|
||||||
onMounted(() => {document.addEventListener('keydown', keydownListener)})
|
|
||||||
onUnmounted(() => {document.removeEventListener('keydown', keydownListener)})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener('keydown', keydownListener))
|
||||||
|
onUnmounted(() => document.removeEventListener('keydown', keydownListener))
|
||||||
|
|
||||||
// 切换到上一张/上一张幻灯片(无视元素的入场动画)
|
// 切换到上一张/上一张幻灯片(无视元素的入场动画)
|
||||||
const turnPrevSlide = () => {
|
const turnPrevSlide = () => {
|
||||||
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
||||||
|
|
|
@ -1,47 +1,25 @@
|
||||||
<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>
|
|
||||||
<!-- <div style="z-index: 999;position: absolute;top:10px">
|
|
||||||
</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 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 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
|
||||||
}
|
}
|
||||||
|
|
||||||
const { exitScreening } = useScreening()
|
const { exitScreening } = useScreening()
|
||||||
const upvoteRef = ref(null)
|
|
||||||
hooksUpvote.init(upvoteRef) // 初始化点赞
|
|
||||||
|
|
||||||
// 快捷键退出放映
|
// 快捷键退出放映
|
||||||
const keydownListener = (e: KeyboardEvent) => {
|
const keydownListener = (e: KeyboardEvent) => {
|
||||||
|
@ -49,23 +27,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 +38,4 @@ onUnmounted(() => document.removeEventListener('keydown', keydownListener))
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.gridPicRefdiv .el-dialog__body){
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
|
@ -10,10 +10,11 @@ export const createChart = ({ headers, data }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 大模型对话
|
// 大模型对话
|
||||||
export const sendChart = (data) => {
|
export const sendChart = ({ headers, data }) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/qf/sendTalk',
|
url: '/qf/sendTalk',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
headers,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -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': '*/*',
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -71,11 +71,3 @@ export const addFileToKj = (id) => {
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getModelInfo = (params) => {
|
|
||||||
return request({
|
|
||||||
url: '/education/llmModel/getModelInfo',
|
|
||||||
method: 'post',
|
|
||||||
params
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -95,23 +95,3 @@ export function getCourseTeachingMsg(id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPaging(data) {
|
|
||||||
return request({
|
|
||||||
url: '/education/classcourse/record/paging',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获取分享码(邀请码)
|
|
||||||
* @param {*} id 课堂id
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function getShareCode(id) {
|
|
||||||
return request({
|
|
||||||
url: '/education/classcourse/refresh/code',
|
|
||||||
method: 'post',
|
|
||||||
data: { id }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4723712 */
|
font-family: "iconfont"; /* Project id 4723712 */
|
||||||
src: url('iconfont.woff2?t=1734337029245') format('woff2'),
|
src: url('iconfont.woff2?t=1733880548695') format('woff2'),
|
||||||
url('iconfont.woff?t=1734337029245') format('woff'),
|
url('iconfont.woff?t=1733880548695') format('woff'),
|
||||||
url('iconfont.ttf?t=1734337029245') format('truetype');
|
url('iconfont.ttf?t=1733880548695') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
|
@ -13,10 +13,6 @@
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-yinle:before {
|
|
||||||
content: "\e6c9";
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-yuyin:before {
|
.icon-yuyin:before {
|
||||||
content: "\e648";
|
content: "\e648";
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,13 +5,6 @@
|
||||||
"css_prefix_text": "icon-",
|
"css_prefix_text": "icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
{
|
|
||||||
"icon_id": "11819186",
|
|
||||||
"name": "音乐",
|
|
||||||
"font_class": "yinle",
|
|
||||||
"unicode": "e6c9",
|
|
||||||
"unicode_decimal": 59081
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"icon_id": "6338162",
|
"icon_id": "6338162",
|
||||||
"name": "语音生成",
|
"name": "语音生成",
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
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 |
|
@ -482,7 +482,10 @@ export default {
|
||||||
|
|
||||||
//保存图片到素材库
|
//保存图片到素材库
|
||||||
async saveImage(resultIndex, index, url, resultItem) {
|
async saveImage(resultIndex, index, url, resultItem) {
|
||||||
|
if(this.hasPPt){
|
||||||
|
this.$emit('insertImg', url)
|
||||||
|
return
|
||||||
|
}
|
||||||
this.buttonStates[resultIndex][index].disabled = true;
|
this.buttonStates[resultIndex][index].disabled = true;
|
||||||
this.buttonStates[resultIndex][index].text = "正在保存...";
|
this.buttonStates[resultIndex][index].text = "正在保存...";
|
||||||
const numberIndex = url.indexOf('filename=');
|
const numberIndex = url.indexOf('filename=');
|
||||||
|
@ -492,7 +495,6 @@ export default {
|
||||||
try {
|
try {
|
||||||
const blob = await this.getImageBlob(`https://ai.ysaix.com:7853/view?filename=${finalPath}&type=temp`);
|
const blob = await this.getImageBlob(`https://ai.ysaix.com:7853/view?filename=${finalPath}&type=temp`);
|
||||||
|
|
||||||
|
|
||||||
const hash = CryptoJS.MD5(blob).toString();
|
const hash = CryptoJS.MD5(blob).toString();
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
@ -500,10 +502,7 @@ export default {
|
||||||
let file = new File([blob], `${resultItem}.png`, {
|
let file = new File([blob], `${resultItem}.png`, {
|
||||||
type: 'image/png'
|
type: 'image/png'
|
||||||
})
|
})
|
||||||
if(this.hasPPt){
|
|
||||||
this.$emit('insertImg', file)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 添加参数
|
// 添加参数
|
||||||
formData.append('md5', hash);
|
formData.append('md5', hash);
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
|
|
@ -1,333 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="book-wrap">
|
|
||||||
<el-scrollbar height="100%">
|
|
||||||
<div class="book-name flex" @click="dialogVisible = true">
|
|
||||||
<span>{{ curBook.data.itemtitle }}</span>
|
|
||||||
<i class="iconfont icon-xiangyou"></i>
|
|
||||||
</div>
|
|
||||||
<div class="book-list" v-loading="treeLoading">
|
|
||||||
<el-tree :data="treeData" accordion :props="defaultProps" node-key="id"
|
|
||||||
:default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current
|
|
||||||
@node-click="handleNodeClick">
|
|
||||||
<template #default="{ node }">
|
|
||||||
<span :title="node.label" class="tree-label">{{ node.label }}</span>
|
|
||||||
</template>
|
|
||||||
</el-tree>
|
|
||||||
</div>
|
|
||||||
</el-scrollbar>
|
|
||||||
</div>
|
|
||||||
<!--弹窗 选择教材-->
|
|
||||||
<el-dialog v-model="dialogVisible" append-to-body :show-close="false" width="550"
|
|
||||||
style="border-radius: 10px; padding: 10px 15px;">
|
|
||||||
<template #header>
|
|
||||||
<div class="choose-book-header flex">
|
|
||||||
<span>切换教材</span>
|
|
||||||
<i class="iconfont icon-guanbi" @click="dialogVisible = false"></i>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="textbook-container">
|
|
||||||
<el-scrollbar height="450px">
|
|
||||||
<div class="textbook-item flex" v-for="item in subjectList" :class="curBook.data.id == item.id ? 'active-item' : ''"
|
|
||||||
:key="item.id" @click="changeBook(item)">
|
|
||||||
<img v-if="item.avartar" :src="item.avartar.indexOf('http') === 0 ? item.avartar : BaseUrl + item.avartar" class="textbook-img" alt="">
|
|
||||||
<div v-else class="textbook-img">
|
|
||||||
<i class="iconfont icon-jiaocaixuanze" style="font-size: 40px;"></i>
|
|
||||||
</div>
|
|
||||||
<span class="book-name">{{ item.itemtitle }}</span>
|
|
||||||
</div>
|
|
||||||
</el-scrollbar>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { onMounted, ref, nextTick, toRaw, reactive } from 'vue';
|
|
||||||
import { cloneDeep } from 'lodash'
|
|
||||||
import { listEvaluation } from '@/api/subject'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
|
||||||
|
|
||||||
const BaseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
|
||||||
// 定义要发送的emit事件
|
|
||||||
const emit = defineEmits(['nodeClick', 'changeBook'])
|
|
||||||
// 章节List
|
|
||||||
const unitList = ref([])
|
|
||||||
const subjectList = ref([])
|
|
||||||
const dialogVisible = ref(false)
|
|
||||||
// 当前教材下面单元内容数据
|
|
||||||
const treeData = ref([])
|
|
||||||
const defaultProps = {
|
|
||||||
children: 'children',
|
|
||||||
label: 'itemtitle',
|
|
||||||
class: 'textbook-tree'
|
|
||||||
}
|
|
||||||
//查当前学科
|
|
||||||
const subjectParams = reactive(
|
|
||||||
{
|
|
||||||
edusubject: '科学',
|
|
||||||
edustage:'小学',
|
|
||||||
itemkey: 'version',
|
|
||||||
orderby: 'orderidx asc',
|
|
||||||
pageSize: 10000
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// 查所有的学科
|
|
||||||
const unitParams = reactive({
|
|
||||||
edusubject:'科学',
|
|
||||||
edustage:'小学',
|
|
||||||
itemgroup: 'textbook',
|
|
||||||
orderby: 'orderidx asc',
|
|
||||||
pageSize: 10000
|
|
||||||
})
|
|
||||||
// 当前选中的教材
|
|
||||||
const curBook = reactive({
|
|
||||||
data: {}
|
|
||||||
})
|
|
||||||
// 当前节点
|
|
||||||
const curNode = reactive({
|
|
||||||
data:{}
|
|
||||||
})
|
|
||||||
const treeLoading = ref(false)
|
|
||||||
// 默认展开的节点
|
|
||||||
const defaultExpandedKeys = ref([])
|
|
||||||
|
|
||||||
//选择教材
|
|
||||||
const changeBook = (data) => {
|
|
||||||
curBook.data = data
|
|
||||||
treeData.value = getTreeData(data.id)
|
|
||||||
//切换教材后默认展开第一个并选中
|
|
||||||
nextTick(() =>{
|
|
||||||
defaultExpandedKeys.value = [treeData.value[0].id]
|
|
||||||
curNode.data = getLastLevelData(treeData.value)[0]
|
|
||||||
handleNodeClick(curNode.data)
|
|
||||||
})
|
|
||||||
// 延迟关闭 视觉上选中
|
|
||||||
setTimeout(() => {
|
|
||||||
dialogVisible.value = false
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
const getLastLevelData = (tree) => {
|
|
||||||
let lastLevelData = [];
|
|
||||||
// 递归函数遍历树形结构
|
|
||||||
function traverseTree(nodes) {
|
|
||||||
nodes.forEach((node) => {
|
|
||||||
// 如果当前节点有子节点,继续遍历
|
|
||||||
if (node.children && node.children.length > 0) {
|
|
||||||
traverseTree(node.children);
|
|
||||||
} else {
|
|
||||||
// 如果没有子节点,说明是最后一层的节点
|
|
||||||
lastLevelData.push(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用递归函数开始遍历
|
|
||||||
traverseTree(tree);
|
|
||||||
|
|
||||||
// 返回最后一层的数据
|
|
||||||
return lastLevelData;
|
|
||||||
}
|
|
||||||
// 根据id 拿到父节点数据
|
|
||||||
const findParentByChildId = (treeData, targetNodeId) => {
|
|
||||||
// 递归查找函数
|
|
||||||
// 遍历树中的每个节点
|
|
||||||
for (let node of treeData) {
|
|
||||||
// 检查当前节点的子节点是否包含目标子节点 ID
|
|
||||||
if (node.children && node.children.some(child => child.id === targetNodeId)) {
|
|
||||||
// 如果当前节点的某个子节点的 ID 匹配目标子节点 ID,则当前节点即为父节点
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
// 如果当前节点没有匹配的子节点,则递归检查当前节点的子节点
|
|
||||||
if (node.children) {
|
|
||||||
let parentNode = findParentByChildId(node.children, targetNodeId);
|
|
||||||
if (parentNode) {
|
|
||||||
return parentNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果未找到匹配的父节点,则返回 null 或者适当的默认值
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const handleNodeClick = (data) => {
|
|
||||||
/**
|
|
||||||
* data : 当前节点数据
|
|
||||||
*/
|
|
||||||
let nodeData = cloneDeep(toRaw(data));
|
|
||||||
|
|
||||||
//增加一个label 之前取的label
|
|
||||||
nodeData.label = nodeData.itemtitle
|
|
||||||
// 父级节点 如果当前是一级节点 父级则为null
|
|
||||||
let parent = {
|
|
||||||
id: nodeData.parentid,
|
|
||||||
label: nodeData.parenttitle,
|
|
||||||
itemtitle: nodeData.parenttitle
|
|
||||||
}
|
|
||||||
const parentNode = nodeData.parentid ? parent : null
|
|
||||||
nodeData.parentNode = parentNode
|
|
||||||
let curData = {
|
|
||||||
textBook: {
|
|
||||||
curBookId: curBook.data.id,
|
|
||||||
curBookName: curBook.data.itemtitle,
|
|
||||||
curBookImg: BaseUrl + curBook.data.avartar,
|
|
||||||
curBookPath: curBook.data.fileurl
|
|
||||||
},
|
|
||||||
node: nodeData
|
|
||||||
}
|
|
||||||
// 本地存储:electron-store
|
|
||||||
emit('nodeClick', curData)
|
|
||||||
}
|
|
||||||
// 单元章节数据转为“树”结构
|
|
||||||
const getTreeData = (bookId) =>{
|
|
||||||
// 根据当前教材的id 查找出对应的章节
|
|
||||||
let data = unitList.value.filter(item => item.rootid == bookId && item.level == 1)
|
|
||||||
data.forEach( item => {
|
|
||||||
item.children = unitList.value.filter( item2 => item2.parentid == item.id && item2.level == 2)
|
|
||||||
})
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onMounted( async () => {
|
|
||||||
treeLoading.value = true
|
|
||||||
try{
|
|
||||||
//获取学科列表
|
|
||||||
const { rows } = await listEvaluation(subjectParams)
|
|
||||||
// 获取所有的教材
|
|
||||||
subjectList.value = rows
|
|
||||||
|
|
||||||
const res = await listEvaluation(unitParams)
|
|
||||||
unitList.value = [...res.rows]
|
|
||||||
// 当前教材
|
|
||||||
curBook.data = rows[0]
|
|
||||||
|
|
||||||
// 章节"树"rows
|
|
||||||
treeData.value = getTreeData(rows[0].id)
|
|
||||||
|
|
||||||
nextTick(() =>{
|
|
||||||
// 默认展开 选中
|
|
||||||
defaultExpandedKeys.value = [treeData.value[0].id]
|
|
||||||
curNode.data = getLastLevelData(treeData.value)[0]
|
|
||||||
handleNodeClick(curNode.data)
|
|
||||||
})
|
|
||||||
|
|
||||||
} finally{
|
|
||||||
treeLoading.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.book-wrap {
|
|
||||||
width: 300px;
|
|
||||||
height: 100%;
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0px 0px 20px 0px rgba(99, 99, 99, 0.06);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.book-name {
|
|
||||||
background-color: #ffffff;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 45px;
|
|
||||||
padding: 0 15px;
|
|
||||||
z-index: 1;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
color: #3b3b3b;
|
|
||||||
cursor: pointer;
|
|
||||||
border-bottom: solid #f4f5f7 1px;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 600;
|
|
||||||
border-radius: 10px 10px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.book-list {
|
|
||||||
padding: 45px 10px 0 10px;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.choose-dialog) {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choose-book-header {
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
.icon-guanbi {
|
|
||||||
font-size: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.textbook-container {
|
|
||||||
.textbook-item {
|
|
||||||
padding: 10px 20px;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.book-name {
|
|
||||||
margin-left: 20px;
|
|
||||||
color: #3b3b3b;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: #f4f7f9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.active-item {
|
|
||||||
background-color: #f4f7f9;
|
|
||||||
|
|
||||||
.book-name {
|
|
||||||
color: #368fff;
|
|
||||||
font-weight: bold
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.textbook-img {
|
|
||||||
width: 55px;
|
|
||||||
height: 70px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-tree-node) {
|
|
||||||
.el-tree-node__content {
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 10px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #eaf3ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-label {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content) {
|
|
||||||
background-color: #eaf3ff !important;
|
|
||||||
color: #409EFF
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="book-wrap">
|
<div class="book-wrap">
|
||||||
<el-scrollbar height="100%">
|
<el-scrollbar height="100%">
|
||||||
<div class="book-name flex" v-if="isStadium() === true"> {{userStore.user.deptName}}</div>
|
<div class="book-name flex" @click="dialogVisible = true">
|
||||||
<div v-else class="book-name flex" @click="dialogVisible = true">
|
|
||||||
<span>{{ curBook.data.itemtitle }}</span>
|
<span>{{ curBook.data.itemtitle }}</span>
|
||||||
<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 }">
|
||||||
|
@ -47,14 +46,8 @@ import { onMounted, ref, nextTick, toRaw, reactive } from 'vue';
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { useGetSubject } from '@/hooks/useGetSubject'
|
import { useGetSubject } from '@/hooks/useGetSubject'
|
||||||
import useUserStore from '@/store/modules/user'
|
|
||||||
const userStore = useUserStore()
|
|
||||||
|
|
||||||
const BaseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
const BaseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
const isStadium = () => {
|
|
||||||
let roles = userStore.user.roles
|
|
||||||
return roles.some(item => item.roleKey === 'stadium')
|
|
||||||
}
|
|
||||||
// 定义要发送的emit事件
|
// 定义要发送的emit事件
|
||||||
const emit = defineEmits(['nodeClick', 'changeBook'])
|
const emit = defineEmits(['nodeClick', 'changeBook'])
|
||||||
let useSubject = null
|
let useSubject = null
|
||||||
|
@ -178,18 +171,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{
|
||||||
|
@ -200,11 +181,7 @@ onMounted( async () => {
|
||||||
curBook.data = sessionStore.get('subject.curBook')
|
curBook.data = sessionStore.get('subject.curBook')
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (subjectList.value) {
|
curBook.data = subjectList.value[0]
|
||||||
curBook.data = subjectList.value[0]
|
|
||||||
}else {
|
|
||||||
curBook.data = {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 章节"树"
|
// 章节"树"
|
||||||
|
|
|
@ -41,7 +41,6 @@ const getFileTypeIcon = () => {
|
||||||
airobot: 'icon-jiqirenfushi', // 数字人生成
|
airobot: 'icon-jiqirenfushi', // 数字人生成
|
||||||
aiimg: 'icon-xiangmuicon_maobishufa', // 文生图片
|
aiimg: 'icon-xiangmuicon_maobishufa', // 文生图片
|
||||||
aidraw: 'icon-meishu-F', // 文生连环画
|
aidraw: 'icon-meishu-F', // 文生连环画
|
||||||
aiyinyue: 'icon-yinle' //文生音乐
|
|
||||||
}
|
}
|
||||||
if (iconObj[name]) {
|
if (iconObj[name]) {
|
||||||
return '#' + iconObj[name]
|
return '#' + iconObj[name]
|
||||||
|
|
|
@ -1,269 +0,0 @@
|
||||||
<!--
|
|
||||||
依赖: vuedraggable、v-viewer
|
|
||||||
属性: showToolbar //是否显示工具栏 默认:false
|
|
||||||
工具栏 添加图片:默认6个测试图片,不输入框添加则添加默认,输入图片链接,展示图片链接的图片
|
|
||||||
清空图片:清空图片
|
|
||||||
事件: clear 清空时触发
|
|
||||||
outIndex 超出九个图片时触发
|
|
||||||
方法: addPic //添加图片
|
|
||||||
参数: src 图片链接
|
|
||||||
clearPic //清空图片
|
|
||||||
参数: 无
|
|
||||||
使用方法: 加载组件后,通过ref调用addPic方法添加图片即可
|
|
||||||
-->
|
|
||||||
<template>
|
|
||||||
<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">
|
|
||||||
<template #item="{ 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="header-btn"></div>
|
|
||||||
<ViewerItem :gridPicList="gridPicList" :index="index" :images="element"></ViewerItem>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</draggable>
|
|
||||||
<div class="grid-pic-toolbar">
|
|
||||||
<el-input v-if="showToolbar" style="width: 500px" v-model="inputValue" type="text" />
|
|
||||||
<el-button v-if="showToolbar" class="add-btn" @click="pushPic">
|
|
||||||
添加
|
|
||||||
</el-button>
|
|
||||||
<el-button class="add-btn" @click="clearPic">
|
|
||||||
清空
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<!-- <el-button style="position:fixed;bottom: 20px;right: 80px;" @click="startPencil">
|
|
||||||
画笔
|
|
||||||
</el-button>-->
|
|
||||||
<!-- <div class="modal-mode">
|
|
||||||
<canvas id="canvas_pic_001" style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;"></canvas>
|
|
||||||
</div>-->
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {ref, computed, onMounted} from 'vue'
|
|
||||||
import Draggable from 'vuedraggable'
|
|
||||||
import ViewerItem from "./viewer-item.vue";
|
|
||||||
// import Fabric from 'fabric';
|
|
||||||
const gridPicList = ref([])
|
|
||||||
const inputValue = ref('')
|
|
||||||
const isShow = ref(false)
|
|
||||||
const emits = defineEmits(['clear','outIndex']);
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
showToolbar: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 获取图片样式
|
|
||||||
const getWH = (item,index)=>{
|
|
||||||
return {
|
|
||||||
backgroundColor: item.backgroundColor,
|
|
||||||
'grid-area': 'a' + index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const picList = [
|
|
||||||
'https://prev.ysaix.com:7868/src/assets/images/homecard4.jpg',
|
|
||||||
'https://prev.ysaix.com:7868/src/assets/images/homecard3.jpg',
|
|
||||||
'https://prev.ysaix.com:7868/src/assets/images/homecard2.jpg',
|
|
||||||
'https://prev.ysaix.com:7868/src/assets/images/homecard1.jpg',
|
|
||||||
'https://prev.ysaix.com:7868/profile/avatar/2024/06/26/blob_20240626135106A001.png',
|
|
||||||
'https://prev.ysaix.com:7868/assets/app_download.b3fb227b.png'
|
|
||||||
]
|
|
||||||
// 获取grid样式
|
|
||||||
const getGrid = computed(() => {
|
|
||||||
switch (gridPicList.value.length) {
|
|
||||||
case 1:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0"`
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a1"`
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a1"
|
|
||||||
"a0 a2"`
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a2"
|
|
||||||
"a1 a3"`
|
|
||||||
}
|
|
||||||
case 5:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a2 a4"
|
|
||||||
"a1 a3 a4"`
|
|
||||||
}
|
|
||||||
case 6:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a2 a4"
|
|
||||||
"a1 a3 a5"`
|
|
||||||
}
|
|
||||||
case 7:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a2 a4"
|
|
||||||
"a0 a2 a4"
|
|
||||||
"a0 a2 a5"
|
|
||||||
"a1 a3 a5"
|
|
||||||
"a1 a3 a6"
|
|
||||||
"a1 a3 a6"`
|
|
||||||
}
|
|
||||||
case 8:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a3 a6"
|
|
||||||
"a0 a3 a6"
|
|
||||||
"a1 a4 a6"
|
|
||||||
"a1 a4 a7"
|
|
||||||
"a2 a5 a7"
|
|
||||||
"a2 a5 a7"`
|
|
||||||
}
|
|
||||||
case 9:
|
|
||||||
return {
|
|
||||||
'grid-template-areas':
|
|
||||||
`"a0 a3 a6"
|
|
||||||
"a1 a4 a7"
|
|
||||||
"a2 a5 a8"`
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
width: '100%',
|
|
||||||
height: '100%'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const pushPic = () => {
|
|
||||||
let src = inputValue.value||picList[gridPicList.value.length]
|
|
||||||
addPic(src)
|
|
||||||
}
|
|
||||||
// 添加图片
|
|
||||||
const addPic = (data) => {
|
|
||||||
let list = Array.isArray(data)?data:[data]
|
|
||||||
if (gridPicList.value.length + list.length > 9) {
|
|
||||||
console.log("超出九个图片")
|
|
||||||
emits('outIndex')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let listArr = [];
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
|
||||||
let src = list[i]
|
|
||||||
if (!src) {
|
|
||||||
console.log("图片链接不能为空")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
listArr.push({
|
|
||||||
src: src,
|
|
||||||
backgroundColor: getRandomColor()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
gridPicList.value.push(...listArr)
|
|
||||||
inputValue.value = ''
|
|
||||||
}
|
|
||||||
// 清空图片
|
|
||||||
const clearPic = () => {
|
|
||||||
gridPicList.value = []
|
|
||||||
emits('clear')
|
|
||||||
}
|
|
||||||
//开始画笔
|
|
||||||
const startPencil = () => {
|
|
||||||
isShow.value = !isShow.value
|
|
||||||
}
|
|
||||||
// 生成随机颜色
|
|
||||||
function getRandomColor() {
|
|
||||||
let r = Math.floor(Math.random() * 256).toString(16);
|
|
||||||
let g = Math.floor(Math.random() * 256).toString(16);
|
|
||||||
let b = Math.floor(Math.random() * 256).toString(16);
|
|
||||||
// 如果生成的十六进制数字只有一位,前面补0
|
|
||||||
r = r.length === 1? '0' + r : r;
|
|
||||||
g = g.length === 1? '0' + g : g;
|
|
||||||
b = b.length === 1? '0' + b : b;
|
|
||||||
return `#${r}${g}${b}`;
|
|
||||||
}
|
|
||||||
/* //初始化画笔
|
|
||||||
const initPend = () => {
|
|
||||||
let canvas = new Fabric.fabric.Canvas('canvas_pic_001',{
|
|
||||||
interactive: false,
|
|
||||||
selection: true,
|
|
||||||
backgroundColor: "rgba(15,15,15,0)"
|
|
||||||
})
|
|
||||||
canvas.defaultCursor = 'default'
|
|
||||||
canvas.setHeight(300)
|
|
||||||
canvas.setWidth(400)
|
|
||||||
canvas.isDrawingMode = true;
|
|
||||||
canvas.freeDrawingBrush = new Fabric.fabric.PencilBrush(canvas)
|
|
||||||
canvas.freeDrawingBrush.width = 1//设置画笔粗细
|
|
||||||
canvas.freeDrawingBrush.color = "red"//设置画笔颜色
|
|
||||||
}*/
|
|
||||||
/*onMounted(() => {
|
|
||||||
initPend()
|
|
||||||
})*/
|
|
||||||
defineExpose({addPic,clearPic})
|
|
||||||
</script>
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.modal-mode{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1001;
|
|
||||||
background-color: rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
.grid-pic-wrap{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: grid;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
.grid-pic-item{
|
|
||||||
//animation: fadeIn 0.5s ease-in-out forwards;
|
|
||||||
background-color: #0a84ff;
|
|
||||||
position: relative;
|
|
||||||
.delete-btn{
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 10px;
|
|
||||||
z-index: 999;
|
|
||||||
&:hover{
|
|
||||||
color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.header-btn{
|
|
||||||
position: absolute;
|
|
||||||
z-index: 998;
|
|
||||||
height: 30px;
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: 1px dotted #ccc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.grid-pic-toolbar{
|
|
||||||
position: fixed;
|
|
||||||
right: 20px;
|
|
||||||
bottom: 20px;
|
|
||||||
display: flex;
|
|
||||||
.add-btn{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,147 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="viewer-item-wrap" :id="'viewer_id'+index">
|
|
||||||
<Viewer @move="move" @moved="moved" @inited="inited" @zoomed="zoomed" :ref="collectRef('viewerRef'+index)" :options="optins" :images="[images.src]" class="images clearfix">
|
|
||||||
<template #default="scope">
|
|
||||||
<div class="viewer-img-box">
|
|
||||||
<img v-for="src in scope.images" :key="index" :src="src" style="display: none">
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Viewer>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import {ref, watch, nextTick, onMounted} from "vue";
|
|
||||||
import { component as Viewer } from 'v-viewer'
|
|
||||||
// import Fabric from 'fabric';
|
|
||||||
import 'viewerjs/dist/viewer.css'
|
|
||||||
const props = defineProps({
|
|
||||||
images: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {}
|
|
||||||
},
|
|
||||||
index: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
gridPicList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
let $viewer = null;
|
|
||||||
const refs = ref([]);
|
|
||||||
//初始化时
|
|
||||||
const inited = (viewer) => {
|
|
||||||
$viewer = viewer
|
|
||||||
}
|
|
||||||
//缩放时
|
|
||||||
const zoomed = (e) => {
|
|
||||||
// setImgStyle()
|
|
||||||
}
|
|
||||||
//移动时
|
|
||||||
const moved = (e) => {
|
|
||||||
// setImgStyle()
|
|
||||||
}
|
|
||||||
const move = (e) => {
|
|
||||||
}
|
|
||||||
const appendCanvasToShow = () => {
|
|
||||||
initImgStyle()
|
|
||||||
}
|
|
||||||
|
|
||||||
const setImgStyle = () => {
|
|
||||||
let item = window.document.getElementById('viewer_id'+props.index)
|
|
||||||
let canvas = item.querySelectorAll('.viewer-canvas')[0]
|
|
||||||
let img = canvas.querySelectorAll('img')[0]
|
|
||||||
let imgStyle = img.getAttribute('style')
|
|
||||||
imgStyle = imgStyle.replace('relative', 'absolute') + 'z-index: 1002';
|
|
||||||
img.style = imgStyle;
|
|
||||||
let canvasNew = canvas.querySelectorAll('canvas')[0]
|
|
||||||
canvasNew.style = imgStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initImgStyle = () => {
|
|
||||||
let item = window.document.getElementById('viewer_id'+props.index)
|
|
||||||
let canvas = item.querySelectorAll('.viewer-canvas')[0]
|
|
||||||
let img = canvas.querySelectorAll('img')[0];
|
|
||||||
let imgStyle = img.getAttribute('style')
|
|
||||||
imgStyle = imgStyle.replace('relative', 'absolute') + 'z-index: 1002';
|
|
||||||
img.style = imgStyle;
|
|
||||||
const canvasNew = document.createElement('canvas');
|
|
||||||
canvasNew.style = imgStyle;
|
|
||||||
canvasNew.id = 'canvas_pic_'+props.index
|
|
||||||
canvas.appendChild(canvasNew);
|
|
||||||
|
|
||||||
initPend()
|
|
||||||
}
|
|
||||||
|
|
||||||
const collectRef = (key) => {
|
|
||||||
return (el) => {
|
|
||||||
refs.value[key] = el;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
//viewer配置
|
|
||||||
const optins = ref({
|
|
||||||
"inline": true,
|
|
||||||
"button": false,
|
|
||||||
"navbar": false,
|
|
||||||
"title": false,
|
|
||||||
"toolbar": false,
|
|
||||||
"tooltip": true,
|
|
||||||
"zoomable": true,
|
|
||||||
"rotatable": true,
|
|
||||||
"movable": true,
|
|
||||||
"scalable": true,
|
|
||||||
"transition": true,
|
|
||||||
"fullscreen": true,
|
|
||||||
"keyboard": true
|
|
||||||
})
|
|
||||||
const initViewers = () => {
|
|
||||||
refs.value['viewerRef'+props.index]?.rebuildViewer()
|
|
||||||
/*setTimeout(()=>{
|
|
||||||
initImgStyle()
|
|
||||||
},300)*/
|
|
||||||
}
|
|
||||||
//初始化画笔
|
|
||||||
const initPend = () => {
|
|
||||||
let canvas = new Fabric.fabric.Canvas('canvas_pic_'+props.index,{
|
|
||||||
interactive: false,
|
|
||||||
selection: true,
|
|
||||||
backgroundColor: "rgba(15,15,15,0)"
|
|
||||||
})
|
|
||||||
canvas.defaultCursor = 'default'
|
|
||||||
canvas.setHeight(300)
|
|
||||||
canvas.setWidth(400)
|
|
||||||
canvas.isDrawingMode = true;
|
|
||||||
canvas.freeDrawingBrush = new Fabric.fabric.PencilBrush(canvas)
|
|
||||||
canvas.freeDrawingBrush.width = 1//设置画笔粗细
|
|
||||||
canvas.freeDrawingBrush.color = "red"//设置画笔颜色
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(props.gridPicList, (newValue, oldValue) => {
|
|
||||||
nextTick(()=>{
|
|
||||||
initViewers()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
watch(props.images, (newValue, oldValue) => {
|
|
||||||
// optins.value.movable = newValue.dragable
|
|
||||||
initPend()
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*onMounted(()=>{
|
|
||||||
setTimeout(()=>{
|
|
||||||
appendCanvasToShow()
|
|
||||||
}, 300)
|
|
||||||
})*/
|
|
||||||
</script>
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.viewer-item-wrap{
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
:deep(.viewer-canvas img) {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -204,11 +204,7 @@ onMounted(async () => {
|
||||||
curBook.data = sessionStore.get('subject.curBook')
|
curBook.data = sessionStore.get('subject.curBook')
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if (subjectList.value) {
|
curBook.data = subjectList.value[0]
|
||||||
curBook.data = subjectList.value[0]
|
|
||||||
}else {
|
|
||||||
curBook.data = {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 章节"树"
|
// 章节"树"
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
<div class="file-list">
|
<div class="file-list">
|
||||||
<el-dropdown @command="changeFile" v-if="type == 3">
|
<el-dropdown @command="changeFile">
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
{{ curFile.fileName }}
|
{{ curFile.fileName }}
|
||||||
<i class="iconfont icon-xiangxia"></i>
|
<i class="iconfont icon-xiangxia"></i>
|
||||||
|
@ -54,12 +54,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
import { ref, reactive, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import { completion, docList } from '@/api/mode/index'
|
import { completion, docList } from '@/api/mode/index'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { dataSetJson } from '@/utils/comm.js'
|
import { dataSetJson } from '@/utils/comm.js'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { sendChart } from '@/api/ai/index'
|
|
||||||
import emitter from '@/utils/mitt';
|
import emitter from '@/utils/mitt';
|
||||||
|
|
||||||
const userInfo = useUserStore().user
|
const userInfo = useUserStore().user
|
||||||
|
@ -72,20 +71,12 @@ const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
return { name: '' }
|
return { name: '11' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1
|
default: 1
|
||||||
},
|
|
||||||
curMode:{
|
|
||||||
type: Number,
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
conversation_id: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: ''
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -109,8 +100,7 @@ const curNode = reactive({})
|
||||||
const params = reactive(
|
const params = reactive(
|
||||||
{
|
{
|
||||||
prompt: '',
|
prompt: '',
|
||||||
dataset_id: '',
|
dataset_id: ''
|
||||||
template: ''
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -118,24 +108,7 @@ const params = reactive(
|
||||||
const getCompletion = async (val) => {
|
const getCompletion = async (val) => {
|
||||||
try {
|
try {
|
||||||
params.prompt = `按照${val}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
params.prompt = `按照${val}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
||||||
params.template = props.item.prompt
|
const { data } = await completion(params)
|
||||||
|
|
||||||
let data = null;
|
|
||||||
// 教学大模型
|
|
||||||
if(props.curMode == 1){
|
|
||||||
const res = await sendChart({
|
|
||||||
content: params.prompt,
|
|
||||||
conversationId: props.conversation_id,
|
|
||||||
stream: false
|
|
||||||
})
|
|
||||||
data = res.data
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
// 知识库模型
|
|
||||||
const res = await completion(params)
|
|
||||||
data = res.data
|
|
||||||
}
|
|
||||||
|
|
||||||
let answer = data.answer
|
let answer = data.answer
|
||||||
msgList.value.push({
|
msgList.value.push({
|
||||||
type: 'robot',
|
type: 'robot',
|
||||||
|
@ -152,6 +125,19 @@ const saveAdjust = (item) =>{
|
||||||
emitter.emit('onSaveAdjust', item.msg)
|
emitter.emit('onSaveAdjust', item.msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modeType = ref('课标')
|
||||||
|
watch(() => props.type, (newVal) => {
|
||||||
|
if (newVal == 1){
|
||||||
|
modeType.value = '课标'
|
||||||
|
}
|
||||||
|
if (newVal == 2){
|
||||||
|
modeType.value = '教材'
|
||||||
|
}
|
||||||
|
if (newVal == 2){
|
||||||
|
modeType.value = '考试'
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { immediate: false })
|
||||||
|
|
||||||
const curFile = reactive({})
|
const curFile = reactive({})
|
||||||
const dataset_id = ref('')
|
const dataset_id = ref('')
|
||||||
|
@ -174,12 +160,11 @@ const changeFile = (val) =>{
|
||||||
params.document_ids = val.docId
|
params.document_ids = val.docId
|
||||||
}
|
}
|
||||||
|
|
||||||
const modeType = ref('')
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let data = sessionStore.get('subject.curNode')
|
let data = sessionStore.get('subject.curNode')
|
||||||
Object.assign(curNode, data);
|
|
||||||
|
|
||||||
modeType.value = props.type == 1 ? '课标' : props.type == 2 ? '教材' : '考试'
|
Object.assign(curNode, data);
|
||||||
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
|
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
|
||||||
params.dataset_id = dataSetJson[jsonKey]
|
params.dataset_id = dataSetJson[jsonKey]
|
||||||
if(props.type == 3){
|
if(props.type == 3){
|
||||||
|
|
|
@ -40,7 +40,7 @@ const props = defineProps({
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1
|
default: 1
|
||||||
},
|
},
|
||||||
item: { // 当前操作的模板
|
item: { // 子模板
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
return { ex3: '' }
|
return { ex3: '' }
|
||||||
|
@ -73,25 +73,23 @@ const loading = ref(false)
|
||||||
const saveAdd = async () => {
|
const saveAdd = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
if (props.item.ex3 == '1') {
|
if (props.item.ex3 == '1') {
|
||||||
let id; // id 为主模板id
|
|
||||||
if (props.item.isAdd) {
|
if (props.item.isAdd) {
|
||||||
id = props.item.id
|
try {
|
||||||
|
// 系统预设模板 copy一份
|
||||||
|
const { msg } = await addKeyWords({ name: form.name, id: props.item.id })
|
||||||
|
emitter.emit('onGetMain')
|
||||||
|
ElMessage.success(msg)
|
||||||
|
mode.value = false
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
// 编辑状态下 item 为子模板 主模板则是item.parentId
|
onAddChildTemp(props.item.parentId)
|
||||||
id = props.item.parentId
|
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
// 系统预设模板 copy一份
|
|
||||||
const { msg } = await addKeyWords({ name: form.name, id })
|
|
||||||
emitter.emit('onGetMain')
|
|
||||||
ElMessage.success(msg)
|
|
||||||
mode.value = false
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (props.item.isAdd) {
|
if (props.item.isAdd) {
|
||||||
onAddChildTemp(props.item.id)
|
onAddChildTemp(props.item.id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, nextTick, reactive } from 'vue'
|
import { ref, onMounted, nextTick } from 'vue'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import PDF from '@/components/PdfJs/index.vue'
|
import PDF from '@/components/PdfJs/index.vue'
|
||||||
import LeftDialog from './left-dialog.vue'
|
import LeftDialog from './left-dialog.vue'
|
||||||
|
|
||||||
const props = defineProps(['type'])
|
const props = defineProps(['curNode', 'type'])
|
||||||
|
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
|
@ -31,13 +31,8 @@ const onClick = () => {
|
||||||
|
|
||||||
// 加载PDF
|
// 加载PDF
|
||||||
const pdfUrl = ref('')
|
const pdfUrl = ref('')
|
||||||
const curNode = reactive({})
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
// 当前节点
|
|
||||||
let nodeData = sessionStore.get('subject.curNode')
|
|
||||||
Object.assign(curNode, nodeData);
|
|
||||||
|
|
||||||
let data = sessionStore.get('subject.curBook')
|
let data = sessionStore.get('subject.curBook')
|
||||||
let fileurl = data.fileurl
|
let fileurl = data.fileurl
|
||||||
if(props.type == 1){
|
if(props.type == 1){
|
||||||
|
|
|
@ -14,10 +14,7 @@
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
<div class="flex">
|
<div>
|
||||||
<el-select v-model="curMode" placeholder="Select" class="mr-4 w-30">
|
|
||||||
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
||||||
</el-select>
|
|
||||||
<el-button type="danger" link :disabled="!(templateList.length)" @click="removeItem(curTemplate, false)">
|
<el-button type="danger" link :disabled="!(templateList.length)" @click="removeItem(curTemplate, false)">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
|
@ -55,8 +52,7 @@
|
||||||
<i class="iconfont icon-ai"></i>
|
<i class="iconfont icon-ai"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-answer">
|
<div class="item-answer">
|
||||||
<TypingEffect v-if="isStarted[index]" :text="item.answer" :delay="10" :aiShow="item.aiShow"
|
<TypingEffect v-if="isStarted[index]" :text="item.answer" :delay="10" :aiShow="item.aiShow" @complete="handleCompleteText($event,index)" @updateScroll="scrollToBottom($event,index)" />
|
||||||
@complete="handleCompleteText($event, index)" @updateScroll="scrollToBottom($event, index)" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-btn" v-if="item.answer">
|
<div class="ai-btn" v-if="item.answer">
|
||||||
|
@ -81,40 +77,24 @@
|
||||||
<!--编辑结果-->
|
<!--编辑结果-->
|
||||||
<EditDialog v-model="isEdit" :item="editItem" />
|
<EditDialog v-model="isEdit" :item="editItem" />
|
||||||
<!--AI 对话调整-->
|
<!--AI 对话调整-->
|
||||||
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" :curMode="curMode" :conversation_id="conversation_id"/>
|
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" />
|
||||||
<!--添加、编辑提示词-->
|
<!--添加、编辑提示词-->
|
||||||
<keywordDialog v-model="isWordDialog" :item="editItem" :modeType="type" />
|
<keywordDialog v-model="isWordDialog" :item="editItem" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
|
import { ref, reactive, onMounted, watch, onUnmounted, nextTick } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { tempSave, completion, modelList, removeChildTemp, tempResult, editTempResult } from '@/api/mode/index'
|
import { tempSave, completion, modelList, removeChildTemp, tempResult, editTempResult } from '@/api/mode/index'
|
||||||
import { createChart, sendChart } from '@/api/ai/index'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import keywordDialog from './keyword-dialog.vue';
|
import keywordDialog from './keyword-dialog.vue';
|
||||||
import AdjustDialog from './adjust-dialog.vue'
|
import AdjustDialog from './adjust-dialog.vue'
|
||||||
import EditDialog from './edit-dialog.vue'
|
import EditDialog from './edit-dialog.vue'
|
||||||
import TypingEffect from '@/components/typing-effect/index.vue'
|
import TypingEffect from '@/components/typing-effect/index.vue'
|
||||||
import useUserStore from '@/store/modules/user'
|
|
||||||
import emitter from '@/utils/mitt';
|
import emitter from '@/utils/mitt';
|
||||||
import { dataSetJson } from '@/utils/comm.js'
|
import { dataSetJson } from '@/utils/comm.js'
|
||||||
import { cloneDeep } from 'lodash'
|
|
||||||
|
|
||||||
const props = defineProps(['type'])
|
const props = defineProps(['curNode', 'type'])
|
||||||
const { user } = useUserStore()
|
|
||||||
|
|
||||||
const curMode = ref(2)
|
|
||||||
const modeOptions = ref([
|
|
||||||
{
|
|
||||||
label: '教学大模型',
|
|
||||||
value: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '知识库模型',
|
|
||||||
value: 2
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
/*****************提示词相关****************/
|
/*****************提示词相关****************/
|
||||||
|
|
||||||
|
@ -157,9 +137,9 @@ const curTemplate = reactive({ name: '', id: '' })
|
||||||
const templateList = ref([])
|
const templateList = ref([])
|
||||||
const childTempList = ref([])
|
const childTempList = ref([])
|
||||||
const getTemplateList = () => {
|
const getTemplateList = () => {
|
||||||
modelList({ createUser: user.userId, model: props.type, type: 1, pageNum: 1, pageSize: 10000, ex1: curNode.edustage, ex2: curNode.edusubject }).then(res => {
|
modelList({ model: props.type, type: 1, pageNum: 1, pageSize: 10000, ex1: curNode.edustage, ex2: curNode.edusubject }).then(res => {
|
||||||
templateList.value = res.rows
|
templateList.value = res.rows
|
||||||
if (res.rows.length > 0) {
|
if(res.rows.length > 0){
|
||||||
Object.assign(curTemplate, res.rows[0]);
|
Object.assign(curTemplate, res.rows[0]);
|
||||||
getChildTemplate()
|
getChildTemplate()
|
||||||
}
|
}
|
||||||
|
@ -169,7 +149,7 @@ const getChildTemplate = () => {
|
||||||
tempLoading.value = true
|
tempLoading.value = true
|
||||||
modelList({ model: props.type, type: 2, parentId: curTemplate.id, ex1: curNode.edustage, ex2: curNode.edusubject }).then(res => {
|
modelList({ model: props.type, type: 2, parentId: curTemplate.id, ex1: curNode.edustage, ex2: curNode.edusubject }).then(res => {
|
||||||
childTempList.value = res.rows
|
childTempList.value = res.rows
|
||||||
if (childTempList.value.length) {
|
if(childTempList.value.length){
|
||||||
childTempList.value.forEach(item => item.answer = '')
|
childTempList.value.forEach(item => item.answer = '')
|
||||||
}
|
}
|
||||||
getTempResult()
|
getTempResult()
|
||||||
|
@ -181,7 +161,7 @@ const isStarted = ref([]);
|
||||||
const listRef = ref()
|
const listRef = ref()
|
||||||
// 查询模板结果
|
// 查询模板结果
|
||||||
const getTempResult = () => {
|
const getTempResult = () => {
|
||||||
tempResult({ mainModelId: curTemplate.id, pageNum: 1, pageSize: 10000, ex1: curNode.id }).then(res => {
|
tempResult({ mainModelId: curTemplate.id, pageNum: 1, pageSize: 10000 }).then(res => {
|
||||||
let rows = res.rows
|
let rows = res.rows
|
||||||
childTempList.value.forEach(item => {
|
childTempList.value.forEach(item => {
|
||||||
rows.forEach(el => {
|
rows.forEach(el => {
|
||||||
|
@ -191,28 +171,28 @@ const getTempResult = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (rows.length > 0) {
|
if(rows.length > 0){
|
||||||
isStarted.value = new Array(rows.length).fill(true)
|
isStarted.value = new Array(rows.length).fill(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollToBottom = (height, index) => {
|
const scrollToBottom = (height,index) =>{
|
||||||
|
|
||||||
if (listRef.value) {
|
if (listRef.value) {
|
||||||
let sum = 0
|
let sum = 0
|
||||||
let listDom = listRef.value.children
|
let listDom = listRef.value.children
|
||||||
|
|
||||||
if (index == 0) {
|
if(index == 0){
|
||||||
// 220 去掉头部
|
// 220 去掉头部
|
||||||
let screenHeight = window.innerHeight - 220
|
let screenHeight = window.innerHeight - 220
|
||||||
if (height > screenHeight) {
|
if(height > screenHeight){
|
||||||
listRef.value.scrollTop = (height - screenHeight + 50)
|
listRef.value.scrollTop = (height - screenHeight + 50)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else{
|
||||||
for (let i = 0; i < index; i++) {
|
for(let i = 0; i < index; i++){
|
||||||
sum += listDom[i].clientHeight
|
sum += listDom[i].clientHeight
|
||||||
}
|
}
|
||||||
listRef.value.scrollTop = sum + height
|
listRef.value.scrollTop = sum + height
|
||||||
|
@ -270,6 +250,7 @@ const removeItem = async (item, isChild) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ai对话调整
|
// Ai对话调整
|
||||||
const curIndex = ref(-1)
|
const curIndex = ref(-1)
|
||||||
const isAdjust = ref(false)
|
const isAdjust = ref(false)
|
||||||
|
@ -287,6 +268,21 @@ const onEdit = (index, item) => {
|
||||||
isEdit.value = true
|
isEdit.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const modeType = ref('课标')
|
||||||
|
watch(() => props.type, (newVal) => {
|
||||||
|
if (newVal == 1) {
|
||||||
|
modeType.value = '课标'
|
||||||
|
}
|
||||||
|
if (newVal == 2) {
|
||||||
|
modeType.value = '教材'
|
||||||
|
}
|
||||||
|
if (newVal == 3) {
|
||||||
|
modeType.value = '考试'
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { immediate: false })
|
||||||
|
|
||||||
// 重新研读
|
// 重新研读
|
||||||
const params = reactive(
|
const params = reactive(
|
||||||
{
|
{
|
||||||
|
@ -294,7 +290,6 @@ const params = reactive(
|
||||||
dataset_id: ''
|
dataset_id: ''
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const prompt = ref('')
|
|
||||||
|
|
||||||
// 重新研读
|
// 重新研读
|
||||||
const isAgain = ref(false)
|
const isAgain = ref(false)
|
||||||
|
@ -303,10 +298,10 @@ const againResult = async (index, item) => {
|
||||||
isStarted.value[index] = false
|
isStarted.value[index] = false
|
||||||
childTempList.value[index].answer = ''
|
childTempList.value[index].answer = ''
|
||||||
|
|
||||||
if (index == 0) {
|
if(index == 0){
|
||||||
listRef.value.scrollTop = 0
|
listRef.value.scrollTop = 0
|
||||||
|
|
||||||
} else {
|
}else{
|
||||||
scrollToBottom(50, index)
|
scrollToBottom(50, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,28 +309,8 @@ const againResult = async (index, item) => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
childTempList.value[index].loading = true
|
childTempList.value[index].loading = true
|
||||||
item.aiShow = true
|
item.aiShow = true
|
||||||
|
params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
||||||
let str = cloneDeep(prompt.value)
|
const { data } = await completion(params)
|
||||||
str = str.replace('{模板标题}',item.name)
|
|
||||||
str = str.replace('{模板内容}',item.prompt)
|
|
||||||
params.prompt = str
|
|
||||||
params.template = item.prompt
|
|
||||||
|
|
||||||
let data = null;
|
|
||||||
// 教学大模型
|
|
||||||
if (curMode.value == 1) {
|
|
||||||
const res = await sendChart({
|
|
||||||
content: params.prompt,
|
|
||||||
conversationId: conversation_id.value,
|
|
||||||
stream: false
|
|
||||||
})
|
|
||||||
data = res.data
|
|
||||||
} else {
|
|
||||||
// 知识库模型
|
|
||||||
const res = await completion(params)
|
|
||||||
data = res.data
|
|
||||||
}
|
|
||||||
|
|
||||||
childTempList.value[index].answer = getResult(data.answer);
|
childTempList.value[index].answer = getResult(data.answer);
|
||||||
isStarted.value[index] = true
|
isStarted.value[index] = true
|
||||||
|
|
||||||
|
@ -343,14 +318,13 @@ const againResult = async (index, item) => {
|
||||||
childTempList.value[index].loading = false
|
childTempList.value[index].loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一键研读
|
// 一键研读
|
||||||
const getCompletion = async () => {
|
const getCompletion = async () => {
|
||||||
isStarted.value = new Array(childTempList.length).fill(false)
|
isStarted.value = new Array(childTempList.length).fill(false)
|
||||||
isStarted.value[0] = true
|
isStarted.value[0] = true
|
||||||
|
|
||||||
childTempList.value.forEach(item => {
|
childTempList.value.forEach(item =>{
|
||||||
if (item.answer) {
|
if(item.answer){
|
||||||
item.answer = ''
|
item.answer = ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -359,27 +333,8 @@ const getCompletion = async () => {
|
||||||
try {
|
try {
|
||||||
item.loading = true
|
item.loading = true
|
||||||
item.aiShow = true
|
item.aiShow = true
|
||||||
let str = cloneDeep(prompt.value)
|
params.prompt = `按照${item.name}的要求,针对${curNode.edustage}${curNode.edusubject}${modeType.value} 对${curNode.itemtitle}进行教学分析`
|
||||||
str = str.replace('{模板标题}',item.name)
|
const { data } = await completion(params)
|
||||||
str = str.replace('{模板内容}',item.prompt)
|
|
||||||
params.prompt = str
|
|
||||||
params.template = item.prompt
|
|
||||||
// 教学大模型
|
|
||||||
let data = null
|
|
||||||
if (curMode.value == 1) {
|
|
||||||
const res = await sendChart({
|
|
||||||
content: params.prompt,
|
|
||||||
conversationId: conversation_id.value,
|
|
||||||
stream: false
|
|
||||||
})
|
|
||||||
data = res.data
|
|
||||||
}
|
|
||||||
// 知识库模型
|
|
||||||
else {
|
|
||||||
const res = await completion(params)
|
|
||||||
data = res.data
|
|
||||||
}
|
|
||||||
|
|
||||||
item.answer = getResult(data.answer)
|
item.answer = getResult(data.answer)
|
||||||
onSaveTemp(item)
|
onSaveTemp(item)
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -388,14 +343,14 @@ const getCompletion = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCompleteText = async (answer, index) => {
|
const handleCompleteText = async (answer, index) =>{
|
||||||
if (index < childTempList.value.length - 1) {
|
if (index < childTempList.value.length - 1) {
|
||||||
isStarted.value[index + 1] = true; // 开始显示下一个文本
|
isStarted.value[index + 1] = true; // 开始显示下一个文本
|
||||||
}
|
}
|
||||||
if (isAgain.value) {
|
if(isAgain.value){
|
||||||
try {
|
try{
|
||||||
await editTempResult({ id: childTempList.value[index].resultId, content: answer })
|
await editTempResult({ id: childTempList.value[index].resultId, content: answer })
|
||||||
} finally {
|
}finally{
|
||||||
isAgain.value = false
|
isAgain.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,20 +370,16 @@ const onEditSave = async (item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
const onSaveTemp = async (item) => {
|
const onSaveTemp = (item) => {
|
||||||
if (item.answer == '') return
|
if (item.answer == '') return
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
mainModelId: curTemplate.id,
|
mainModelId: curTemplate.id,
|
||||||
modelId: item.id,
|
modelId: item.id,
|
||||||
examDocld: '',
|
examDocld: '',
|
||||||
content: item.answer,
|
content: item.answer
|
||||||
ex1: curNode.id
|
|
||||||
}
|
|
||||||
const res = await tempSave(data)
|
|
||||||
if(!item.resultId){
|
|
||||||
item.resultId = res.data
|
|
||||||
}
|
}
|
||||||
|
tempSave(data).then(res => { })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去掉字符串中的 ### **
|
// 去掉字符串中的 ### **
|
||||||
|
@ -447,49 +398,13 @@ emitter.on('onGetMain', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// 创建对话
|
|
||||||
const conversation_id = ref('')
|
|
||||||
const getChartId = () => {
|
|
||||||
createChart({ app_id: '712ff0df-ed6b-470f-bf87-8cfbaf757be5' }).then(res => {
|
|
||||||
localStorage.setItem("conversation_id", res.data.conversation_id);
|
|
||||||
conversation_id.value = res.data.conversation_id;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询prompt 替换
|
|
||||||
const getPrompt = async () => {
|
|
||||||
const { rows } = await modelList({ model: 5 })
|
|
||||||
let str = rows.find(item => item.name.indexOf(modeType.value) != -1).prompt
|
|
||||||
str = str.replace('{学段}', curNode.edustage)
|
|
||||||
str = str.replace('{学科}', curNode.edusubject)
|
|
||||||
let bookV = curNode.roottitle.split('-')[1] + '版本'
|
|
||||||
str = str.replace('{教材版本}', bookV)
|
|
||||||
str = str.replace('{课程名称}', `《${curNode.itemtitle}》`)
|
|
||||||
if(modeType.value == '课标'){
|
|
||||||
str = str.replace('{课标名称}', `${curNode.edustage}${curNode.edusubject}课标`)
|
|
||||||
}
|
|
||||||
prompt.value = str
|
|
||||||
}
|
|
||||||
|
|
||||||
const curNode = reactive({})
|
const curNode = reactive({})
|
||||||
const modeType = ref('')
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let data = sessionStore.get('subject.curNode')
|
let data = sessionStore.get('subject.curNode')
|
||||||
Object.assign(curNode, data);
|
Object.assign(curNode, data);
|
||||||
modeType.value = props.type == 1 ? '课标' : props.type == 2 ? '教材' : '考试'
|
|
||||||
|
|
||||||
getTemplateList()
|
getTemplateList()
|
||||||
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
|
let jsonKey = `${modeType.value}-${data.edustage}-${data.edusubject}`
|
||||||
params.dataset_id = dataSetJson[jsonKey]
|
params.dataset_id = dataSetJson[jsonKey]
|
||||||
// 获取百度千帆会话ID
|
|
||||||
conversation_id.value = localStorage.getItem('conversation_id')
|
|
||||||
if (!conversation_id.value) {
|
|
||||||
getChartId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取prompt
|
|
||||||
getPrompt()
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 解绑
|
// 解绑
|
||||||
|
|
|
@ -2,16 +2,18 @@
|
||||||
<div class="page-template flex">
|
<div class="page-template flex">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<Left :type="type" />
|
<Left :curNode="curNode" :type="type" />
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<Right :type="type" />
|
<Right :curNode="curNode" :type="type" />
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { reactive, onMounted } from 'vue'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
import Left from './container/left.vue'
|
import Left from './container/left.vue'
|
||||||
import Right from './container/right.vue'
|
import Right from './container/right.vue'
|
||||||
|
|
||||||
|
@ -21,6 +23,13 @@ const props = defineProps({
|
||||||
default: 1
|
default: 1
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const curNode = reactive({})
|
||||||
|
onMounted(() =>{
|
||||||
|
let data = sessionStore.get('subject.curNode')
|
||||||
|
Object.assign(curNode, data);
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -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']">
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="blockBox">
|
<div class="blockBox">
|
||||||
<el-button @click="currentType = 'selection'"><el-image :src="pointerImg"
|
<el-button @click="currentType = 'selection'"><el-image src="../../../src/assets/images/mouse-pointer.png"
|
||||||
style="width: 14px; height: 14px; color: silver" /></el-button>
|
style="width: 14px; height: 14px; color: silver" /></el-button>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="type == 'design'">
|
<template v-if="type == 'design'">
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
<!-- 边框粗细 -->
|
<!-- 边框粗细 -->
|
||||||
<div class="blockBox">
|
<div class="blockBox">
|
||||||
<el-dropdown @command="updateStyle('lineWidth', $event)" placement="top">
|
<el-dropdown @command="updateStyle('lineWidth', $event)" placement="top">
|
||||||
<el-button><el-image :src="borderImg"
|
<el-button><el-image src="../../../src/assets/images/borderwidth.png"
|
||||||
style="width: 14px; height: 14px"></el-image></el-button>
|
style="width: 14px; height: 14px"></el-image></el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
|
@ -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 {
|
||||||
|
@ -303,10 +303,6 @@ import {
|
||||||
import Contextmenu from './components/Contextmenu.vue'
|
import Contextmenu from './components/Contextmenu.vue'
|
||||||
import { fontFamilyList, fontSizeList } from './constants'
|
import { fontFamilyList, fontSizeList } from './constants'
|
||||||
|
|
||||||
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 { proxy } = getCurrentInstance()
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -508,7 +504,6 @@ const backToCenter = () => {
|
||||||
app.scrollToCenter()
|
app.scrollToCenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 显示全部
|
// 显示全部
|
||||||
const showFit = () => {
|
const showFit = () => {
|
||||||
let elementList = app.elements.elementList
|
let elementList = app.elements.elementList
|
||||||
|
@ -702,6 +697,8 @@ const getCanvasBlob = async () =>{
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
watch(() => props.data, (newVal) => {
|
watch(() => props.data, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
setCanvasData(newVal)
|
setCanvasData(newVal)
|
||||||
|
@ -713,15 +710,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 +731,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 +778,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 +788,7 @@ defineExpose({
|
||||||
getCanvasJson,
|
getCanvasJson,
|
||||||
getCanvasBase64,
|
getCanvasBase64,
|
||||||
setCanvasData,
|
setCanvasData,
|
||||||
getCanvasBlob,
|
getCanvasBlob
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -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%;
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/**
|
|
||||||
* 无限滚动
|
|
||||||
*/
|
|
||||||
import { nextTick } from 'vue'
|
|
||||||
const mountedHook = async (el, binding) => {
|
|
||||||
console.log(el, binding)
|
|
||||||
const value = binding.value
|
|
||||||
if (typeof value !== 'function') return console.error('v-scroll must be a function')
|
|
||||||
await nextTick()
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
// Hooks for Vue3
|
|
||||||
mounted(el, binding) {
|
|
||||||
mountedHook(el, binding)
|
|
||||||
},
|
|
||||||
// Hooks for Vue2
|
|
||||||
inserted(el, binding) {
|
|
||||||
mountedHook(el, binding)
|
|
||||||
},
|
|
||||||
|
|
||||||
update(el, binding){
|
|
||||||
},
|
|
||||||
updated(el, binding){
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,38 +17,22 @@ export const useGetSubject = async () =>{
|
||||||
|
|
||||||
// 根据学科 + 学段 获取所有单元章节
|
// 根据学科 + 学段 获取所有单元章节
|
||||||
const getSubjectUnit = async () =>{
|
const getSubjectUnit = async () =>{
|
||||||
if(isStadium(userStore.user)) {
|
if(sessionStore.get('subject.unitList')){
|
||||||
//如果是基地人员,直接拿treeData
|
unitList.value = sessionStore.get('subject.unitList')
|
||||||
|
}
|
||||||
|
else{
|
||||||
const unitParams = {
|
const unitParams = {
|
||||||
itemgroup: '基地课程',
|
edusubject,
|
||||||
|
edustage,
|
||||||
|
itemgroup: 'textbook',
|
||||||
orderby: 'orderidx asc',
|
orderby: 'orderidx asc',
|
||||||
entpid: userStore.user.deptId,
|
|
||||||
pageSize: 10000
|
pageSize: 10000
|
||||||
}
|
}
|
||||||
const { rows } = await listEvaluation(unitParams)
|
const { rows } = await listEvaluation(unitParams)
|
||||||
unitList.value = rows
|
unitList.value = rows
|
||||||
}else{
|
sessionStore.set('subject.unitList', rows)
|
||||||
if(sessionStore.get('subject.unitList')){
|
|
||||||
unitList.value = sessionStore.get('subject.unitList')
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
const unitParams = {
|
|
||||||
edusubject,
|
|
||||||
edustage,
|
|
||||||
itemgroup: 'textbook',
|
|
||||||
orderby: 'orderidx asc',
|
|
||||||
pageSize: 10000
|
|
||||||
}
|
|
||||||
const { rows } = await listEvaluation(unitParams)
|
|
||||||
unitList.value = rows
|
|
||||||
sessionStore.set('subject.unitList', rows)
|
|
||||||
}
|
|
||||||
await getSubject()
|
|
||||||
}
|
}
|
||||||
}
|
await getSubject()
|
||||||
const isStadium = (user) => {
|
|
||||||
let roles = user.roles
|
|
||||||
return roles.some(item => item.roleKey === 'stadium')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据学科 + 学段 获取教材
|
// 根据学科 + 学段 获取教材
|
||||||
|
@ -84,9 +68,6 @@ export const useGetSubject = async () =>{
|
||||||
|
|
||||||
// 单元章节数据转为“树”结构
|
// 单元章节数据转为“树”结构
|
||||||
const getTreeData = (bookId) =>{
|
const getTreeData = (bookId) =>{
|
||||||
if (!bookId) {
|
|
||||||
return unitList.value
|
|
||||||
}
|
|
||||||
// 根据当前教材的id 查找出对应的章节
|
// 根据当前教材的id 查找出对应的章节
|
||||||
let data = unitList.value.filter(item => item.rootid == bookId && item.level == 1)
|
let data = unitList.value.filter(item => item.rootid == bookId && item.level == 1)
|
||||||
data.forEach( item => {
|
data.forEach( item => {
|
||||||
|
|
|
@ -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 = ''
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
<el-popover ref="popoverRef" placement="right" trigger="hover" popper-class="popoverStyle" :tabindex="999" >
|
<el-popover ref="popoverRef" placement="right" trigger="hover" popper-class="popoverStyle" :tabindex="999" >
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<el-image class="user-img" :src="userStore.user.avatar ==='/img/avatar-default.jpg' || userStore.user.avatar ==='/images/img-avatar.png' ? defaultUserImg : dev_api + userStore.user.avatar" />
|
<el-image class="user-img" :src="dev_api + userStore.user.avatar" />
|
||||||
<span>{{ userStore.user.nickName }}</span>
|
<span>{{ userStore.user.nickName }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="head-aside">
|
<div class="head-aside">
|
||||||
<ul >
|
<ul >
|
||||||
<li v-if="isStadium() !== true" :class="computedregistertype==1 || computedregistertype==3?'auth-li':'auth-li pointer-events'" @click="onUserTo('/schoolCertification')" >
|
<li :class="computedregistertype==1 || computedregistertype==3?'auth-li':'auth-li pointer-events'" @click="onUserTo('/schoolCertification')" >
|
||||||
<i class="iconfont icon-renzheng-" :style="computedregistertype==4?'color:green;':''"></i>
|
<i class="iconfont icon-renzheng-" :style="computedregistertype==4?'color:green;':''"></i>
|
||||||
<span class="mlr-5" v-if="computedregistertype!=4">学校认证</span>
|
<span class="mlr-5" v-if="computedregistertype!=4">学校认证</span>
|
||||||
<span class="mlr-5" v-else>{{ userStore.DeptInfo.register.schoolName }}</span>
|
<span class="mlr-5" v-else>{{ userStore.DeptInfo.register.schoolName }}</span>
|
||||||
|
@ -19,8 +19,8 @@
|
||||||
</li>
|
</li>
|
||||||
<li v-if="computedregistertype!=4" :class="computedregistertype==1 || computedregistertype==2 ? '':'pointer-events'" @click="onUserTo('/joinSchool')">加入学校</li>
|
<li v-if="computedregistertype!=4" :class="computedregistertype==1 || computedregistertype==2 ? '':'pointer-events'" @click="onUserTo('/joinSchool')">加入学校</li>
|
||||||
<li @click="onUserTo('/profile')">个人中心</li>
|
<li @click="onUserTo('/profile')">个人中心</li>
|
||||||
<li v-if="isStadium() !== true" @click="onUserTo('/schoolManagement')">学校管理</li>
|
<li @click="onUserTo('/schoolManagement')">学校管理</li>
|
||||||
<li v-if="isStadium() !== true" @click="onUserTo('/class')">班级中心</li>
|
<li @click="onUserTo('/class')">班级中心</li>
|
||||||
<li @click="logout">退出登录</li>
|
<li @click="logout">退出登录</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,13 +53,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch , reactive, onMounted, onBeforeMount, computed} from 'vue'
|
import { ref, watch , reactive, onMounted,computed} from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import pkc from "../../../../../package.json"
|
|
||||||
import defaultUserImg from '@/assets/images/img-avatar.png'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
|
import pkc from "../../../../../package.json"
|
||||||
|
|
||||||
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
@ -75,31 +74,19 @@ const version = ref(pkc.version)
|
||||||
|
|
||||||
const popoverRef = ref('')
|
const popoverRef = ref('')
|
||||||
|
|
||||||
//是否是基地人员
|
const headerMenus = [
|
||||||
const isStadium = () => {
|
|
||||||
let user = userStore.user
|
|
||||||
let roles = user.roles
|
|
||||||
return roles.some(item => item.roleKey === 'stadium')
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerMenus = isStadium() ?[{
|
|
||||||
name: '教学实践',
|
|
||||||
id: 6,
|
|
||||||
icon: 'icon-jiaoxueshijian',
|
|
||||||
path: '/prepare'
|
|
||||||
},]:[
|
|
||||||
{
|
{
|
||||||
name: '教学大模型',
|
name: '教学大模型',
|
||||||
id: 1,
|
id: 1,
|
||||||
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,
|
||||||
|
@ -182,9 +169,9 @@ watch(
|
||||||
|
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
|
const hasClass = sessionStore.has('activeClass.id')
|
||||||
if(!!sessionStore.get('curr.classcourse'))return ElMessage.warning('当前正在上课,请先结束上课')
|
const hasTool = sessionStore.get('isToolWin')
|
||||||
|
if (hasClass || hasTool) return ElMessage.warning('当前正在上课,请先结束上课')
|
||||||
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
|
|
|
@ -44,6 +44,7 @@ const breadList = ref([])
|
||||||
watch(
|
watch(
|
||||||
() => router.currentRoute.value,
|
() => router.currentRoute.value,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
|
console.log(newValue)
|
||||||
const { showBread } = newValue.meta
|
const { showBread } = newValue.meta
|
||||||
if (showBread) {
|
if (showBread) {
|
||||||
isShowBack.value = true
|
isShowBack.value = true
|
||||||
|
|
|
@ -16,7 +16,6 @@ import router from './router'
|
||||||
import log from 'electron-log/renderer' // 渲染进程日志-文件记录
|
import log from 'electron-log/renderer' // 渲染进程日志-文件记录
|
||||||
import customComponent from '@/components/common' // 自定义组件
|
import customComponent from '@/components/common' // 自定义组件
|
||||||
import plugins from './plugins' // plugins插件
|
import plugins from './plugins' // plugins插件
|
||||||
import useUserStore from '@/store/modules/user'
|
|
||||||
|
|
||||||
if(process.env.NODE_ENV != 'development') { // 非开发环境,将日志打印到日志文件
|
if(process.env.NODE_ENV != 'development') { // 非开发环境,将日志打印到日志文件
|
||||||
Object.assign(console, log.functions) // 渲染进程日志-控制台替换
|
Object.assign(console, log.functions) // 渲染进程日志-控制台替换
|
||||||
|
@ -24,6 +23,7 @@ if(process.env.NODE_ENV != 'development') { // 非开发环境,将日志打印
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
|
|
||||||
//专为菁优网配置的请求转发
|
//专为菁优网配置的请求转发
|
||||||
app.config.globalProperties.$requestGetJYW = (url,config)=>{
|
app.config.globalProperties.$requestGetJYW = (url,config)=>{
|
||||||
config.params = config.params?config.params:{}
|
config.params = config.params?config.params:{}
|
||||||
|
@ -47,16 +47,3 @@ app.use(router)
|
||||||
.use(Icon)
|
.use(Icon)
|
||||||
.use(Directive)
|
.use(Directive)
|
||||||
.mount('#app')
|
.mount('#app')
|
||||||
|
|
||||||
const isStadium = (user) => {
|
|
||||||
let roles = user.roles
|
|
||||||
return roles.some(item => item.roleKey === 'stadium')
|
|
||||||
}
|
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
if (to.path === '/model/index') {
|
|
||||||
isStadium(useUserStore().user) === true ? next('/prepare') :next()
|
|
||||||
}else {
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
|
@ -80,8 +80,6 @@ export class MsgEnum {
|
||||||
MSG_anmationclick : 'anmationclick',
|
MSG_anmationclick : 'anmationclick',
|
||||||
/** @desc: 群组创建成功 */
|
/** @desc: 群组创建成功 */
|
||||||
MSG_classcourseopen : 'classcourseopen',
|
MSG_classcourseopen : 'classcourseopen',
|
||||||
/** @desc: 学生提交作业 */
|
|
||||||
MSG_finishHomework : 'finishHomework',
|
|
||||||
/** @desc: 学生的测练结果反馈 */
|
/** @desc: 学生的测练结果反馈 */
|
||||||
MSG_classquizfeedback : 'classquizfeedback',
|
MSG_classquizfeedback : 'classquizfeedback',
|
||||||
/** @desc: 老师端:接收到学生反馈消息-课堂测练中的其他任务 */
|
/** @desc: 老师端:接收到学生反馈消息-课堂测练中的其他任务 */
|
||||||
|
@ -96,16 +94,6 @@ export class MsgEnum {
|
||||||
MSG_classWorkOfPresentDataUpdate : 'classWorkOfPresentDataUpdate',
|
MSG_classWorkOfPresentDataUpdate : 'classWorkOfPresentDataUpdate',
|
||||||
/** @desc: 课堂讲授活动,选择不同的内容 */
|
/** @desc: 课堂讲授活动,选择不同的内容 */
|
||||||
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
||||||
/** @desc: 课堂作业|活动 */
|
|
||||||
MSG_homework : 'HOMEWORK',
|
|
||||||
/** @desc: 公屏 - 课堂作业|活动 */
|
|
||||||
MSG_pushSreen_work : 'pushSreen_work',
|
|
||||||
/** @desc: 公屏 - 实验 */
|
|
||||||
MSG_pushSreen_experiment : 'pushSreen_experiment',
|
|
||||||
/** @desc: 点赞 */
|
|
||||||
MSG_dz : 'dz',
|
|
||||||
/** @desc: 疑惑 */
|
|
||||||
MSG_yh : 'yh',
|
|
||||||
// === 新定义-消息头 ===
|
// === 新定义-消息头 ===
|
||||||
/** @desc: 课程创建-待开课 */
|
/** @desc: 课程创建-待开课 */
|
||||||
MSG_0000: 0x0000,
|
MSG_0000: 0x0000,
|
||||||
|
@ -150,4 +138,4 @@ export class MsgEnum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MsgEnum;
|
export { MsgEnum as default }
|
|
@ -28,7 +28,6 @@ export class ChatWs {
|
||||||
const userStore = useUserStore() // 用户信息
|
const userStore = useUserStore() // 用户信息
|
||||||
const wsBase = import.meta.env.VITE_APP_WS_URL; // ws地址
|
const wsBase = import.meta.env.VITE_APP_WS_URL; // ws地址
|
||||||
this.url = `${wsBase||ChatWs.base}/ws/websocket/${userStore.id}`;
|
this.url = `${wsBase||ChatWs.base}/ws/websocket/${userStore.id}`;
|
||||||
this.closed = false; // 关闭状态 防止重连失败
|
|
||||||
// this.init(url);
|
// this.init(url);
|
||||||
}
|
}
|
||||||
ChatWs.instance = this;
|
ChatWs.instance = this;
|
||||||
|
@ -39,7 +38,6 @@ export class ChatWs {
|
||||||
// 初始化
|
// 初始化
|
||||||
init(url) {
|
init(url) {
|
||||||
!!url && (this.url = url);
|
!!url && (this.url = url);
|
||||||
this.closed = false; // 关闭状态 防止重连失败
|
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
const _this = this
|
const _this = this
|
||||||
this.heartCheck = {
|
this.heartCheck = {
|
||||||
|
@ -66,46 +64,43 @@ export class ChatWs {
|
||||||
}, this.timeout);
|
}, this.timeout);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return this.reconnect();
|
this.reconnect();
|
||||||
}
|
}
|
||||||
// 重连
|
// 重连
|
||||||
reconnect() {
|
reconnect() {
|
||||||
return new Promise((resolve, reject) => {
|
const self = this;
|
||||||
const self = this;
|
if (!!this.ws) { // 关闭之前的链接
|
||||||
if (!!this.ws) { // 关闭之前的链接
|
this.ws.close()
|
||||||
this.ws.close()
|
this.ws = null
|
||||||
this.ws = null
|
}
|
||||||
}
|
this.ws = new WebSocket(this.url);
|
||||||
this.ws = new WebSocket(this.url);
|
this.ws.onopen = function () {
|
||||||
this.ws.onopen = function () {
|
console.log("websocket-连接成功")
|
||||||
console.log("websocket-连接成功")
|
self.heartCheck.reset().start();
|
||||||
self.heartCheck.reset().start();
|
};
|
||||||
resolve()
|
this.ws.onmessage = function (e) {
|
||||||
};
|
// console.log("websocket-收到消息", e)
|
||||||
this.ws.onmessage = function (e) {
|
// 拿到任何消息都说明当前连接是正常的
|
||||||
// console.log("websocket-收到消息", e)
|
const isBeat = e.data == 'pong'
|
||||||
// 拿到任何消息都说明当前连接是正常的
|
isBeat && self.heartCheck.reset().start();
|
||||||
const isBeat = e.data == 'pong'
|
const isEmpty = !e.data
|
||||||
isBeat && self.heartCheck.reset().start();
|
const isExts = e.data.includes('sessionId') || e.data == ('pong')
|
||||||
const isEmpty = !e.data
|
if (isEmpty || isExts) return;
|
||||||
const isExts = e.data.includes('sessionId') || e.data == ('pong')
|
// 自定义处理
|
||||||
if (isEmpty || isExts) return;
|
self.onmessage && self.onmessage(e.data, e);
|
||||||
// 自定义处理
|
};
|
||||||
self.onmessage && self.onmessage(e.data, e);
|
this.ws.onerror = function (e) {
|
||||||
};
|
console.log("websocket-连接异常", e)
|
||||||
this.ws.onerror = function (e) {
|
self.connectSocket() // 重连
|
||||||
console.log("websocket-连接异常", e)
|
};
|
||||||
self.connectSocket() // 重连
|
this.ws.onclose = function (e) {
|
||||||
};
|
console.log("websocket-连接断开", e)
|
||||||
this.ws.onclose = function (e) {
|
self.connectSocket() // 重连
|
||||||
console.log("websocket-连接断开", e)
|
};
|
||||||
self.connectSocket() // 重连
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
connectSocket() {
|
connectSocket() {
|
||||||
this.heartCheck.reset() // 重置心跳
|
this.heartCheck.reset() // 重置心跳
|
||||||
if (this.closed) return this.ws = null; // 关闭状态不重连
|
if (self.closed) return; // 关闭状态不重连
|
||||||
// if(self.errCount <= 0) return; // 超过重连次数
|
// if(self.errCount <= 0) return; // 超过重连次数
|
||||||
// self.errCount--; // 重连次数减1
|
// self.errCount--; // 重连次数减1
|
||||||
if (this.errTime) {
|
if (this.errTime) {
|
||||||
|
@ -162,13 +157,6 @@ export class ChatWs {
|
||||||
this.closed = true;
|
this.closed = true;
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
}
|
}
|
||||||
// 下课
|
|
||||||
closedCourse(id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.sendMsg('closed', '下课', null, 'group', id)
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 延时 ms 毫秒
|
// 延时 ms 毫秒
|
||||||
sleep(ms){
|
sleep(ms){
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
|
|
@ -31,11 +31,6 @@ export const constantRoutes = [
|
||||||
component: () => import('@/AixPPTist/src/App.vue'),
|
component: () => import('@/AixPPTist/src/App.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/gridPic',
|
|
||||||
component: () => import('@/components/grid-pic/index.vue'),
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/model',
|
path: '/model',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
@ -88,7 +83,7 @@ export const constantRoutes = [
|
||||||
path: 'questionUpload',
|
path: 'questionUpload',
|
||||||
component: () => import('@/views/classTask/newClassTaskAssign/questionUpload/index.vue'),
|
component: () => import('@/views/classTask/newClassTaskAssign/questionUpload/index.vue'),
|
||||||
name: 'questionUpload',
|
name: 'questionUpload',
|
||||||
meta: { title: '习题上传', showBread: true }
|
meta: { title: '习题上传' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'aiKolors',
|
path: 'aiKolors',
|
||||||
|
@ -106,7 +101,7 @@ const dynamicRoutes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/model/index',
|
redirect: '/desktop',
|
||||||
meta: { title: '教学工作台' },
|
meta: { title: '教学工作台' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,13 +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, // 是否打开习题上传的页面
|
|
||||||
classListIds: [],
|
classListIds: [],
|
||||||
entpCourseWorkTypeList: [
|
entpCourseWorkTypeList: [
|
||||||
{value: 0, label: "不限"},
|
{value: 0, label: "不限"},
|
||||||
|
|
|
@ -395,19 +395,6 @@ export const dataSetJson = {
|
||||||
"课标-高中-英语": "e889fcac9fd011efb22a0242ac140006",
|
"课标-高中-英语": "e889fcac9fd011efb22a0242ac140006",
|
||||||
"课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
"课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
||||||
"课标-高中-地理": "270516829fd111efb13c0242ac140006",
|
"课标-高中-地理": "270516829fd111efb13c0242ac140006",
|
||||||
"课标-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
"课标-高中-政治": "a7df2b01aafd11ef8bb40242ac140002",
|
||||||
"教材-高中-语文": "cee3062a9fcf11efa6910242ac140006",
|
|
||||||
"教材-高中-生物": "fb5d01d59fd011ef9bb90242ac140006",
|
|
||||||
"教材-高中-历史": "f2f6c1fb9fd011ef98740242ac140006",
|
|
||||||
"教材-高中-英语": "e889fcac9fd011efb22a0242ac140006",
|
|
||||||
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
|
||||||
"教材-高中-地理": "270516829fd111efb13c0242ac140006",
|
|
||||||
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
|
||||||
"课标-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
|
||||||
"课标-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
|
||||||
"课标-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
|
||||||
"教材-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
|
||||||
"教材-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
|
||||||
"教材-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
|
||||||
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
||||||
}
|
}
|
|
@ -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',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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(() => {})
|
|
||||||
}
|
|
|
@ -57,31 +57,24 @@ export const resourceFormat = [
|
||||||
// 资源类型
|
// 资源类型
|
||||||
export const resourceType = [
|
export const resourceType = [
|
||||||
{
|
{
|
||||||
id:1,
|
|
||||||
label: '课例库',
|
label: '课例库',
|
||||||
value: "'apt','课件','教案'"
|
value: "'apt','课件','教案'"
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// label: '作业库',
|
label: '作业库',
|
||||||
// value: '作业',
|
value: '作业',
|
||||||
// disabled: true
|
disabled: true
|
||||||
// },
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id:2,
|
|
||||||
label: '素材库',
|
label: '素材库',
|
||||||
value: "'素材'"
|
value: "'素材'"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id:3,
|
label: '习题库',
|
||||||
label: '实验室',
|
value: '习题',
|
||||||
value: "'素材'"
|
disabled: true
|
||||||
},
|
}
|
||||||
// {
|
|
||||||
// label: '习题库',
|
|
||||||
// value: '习题',
|
|
||||||
// disabled: true
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
// 年级划分
|
// 年级划分
|
||||||
export const gradeList = [
|
export const gradeList = [
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -225,7 +225,7 @@ export const createWindow = async (type, data) => {
|
||||||
.filter(k => typeof data[k] === 'function')
|
.filter(k => typeof data[k] === 'function')
|
||||||
.forEach(k => events[k] = data[k])
|
.forEach(k => events[k] = data[k])
|
||||||
eventHandles(type, win, events) // 事件监听处理
|
eventHandles(type, win, events) // 事件监听处理
|
||||||
return win
|
break
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -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,
|
||||||
|
@ -423,19 +422,6 @@ export const toLinkWeb = (path) => {
|
||||||
cookieData: { ...config }
|
cookieData: { ...config }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 外部跳转-web网页
|
|
||||||
* @param {*} url
|
|
||||||
*/
|
|
||||||
export const toLinkLeftWeb = (url) => {
|
|
||||||
// 通知主进程
|
|
||||||
ipcRenderer.send('openWindow', {
|
|
||||||
key: `win-${Date.now()}`,
|
|
||||||
fullPath: url
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 外部跳转-web网页
|
* @description 外部跳转-web网页
|
||||||
* @param {*} path
|
* @param {*} path
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
<!-- <div class="class-reserv-tabs">
|
<!-- <div class="class-reserv-tabs">
|
||||||
<el-segmented v-model="tabActive" block :options="tabOptions" size="large" />
|
<el-segmented v-model="tabActive" block :options="tabOptions" size="large" />
|
||||||
</div>-->
|
</div>-->
|
||||||
<div class="class-reserv-body" v-infinite-scroll="load">
|
<div class="class-reserv-body">
|
||||||
<template v-for="(item, index) in dataList" :key="index">
|
<template v-for="(item, index) in dataList" :key="index">
|
||||||
<!-- <reserv-item
|
<reserv-item
|
||||||
:style="{'background-color': index%2==0?'#f5f5f5':''}"
|
:style="{'background-color': index%2==0?'#f5f5f5':''}"
|
||||||
:item="item"
|
:item="item"
|
||||||
v-if="item.bookImg"
|
v-if="item.bookImg"
|
||||||
@open-edit="reservDialog.openDialog(item)"
|
@open-edit="reservDialog.openDialog(item)"
|
||||||
@delete-reserv="deleteReserv(item)"
|
@delete-reserv="deleteReserv(item)"
|
||||||
@change="(...o) => emit('change', ...o)"
|
@change="(...o) => emit('change', ...o)"
|
||||||
></reserv-item> -->
|
></reserv-item>
|
||||||
<reserv-item-apt
|
<reserv-item-apt
|
||||||
v-if="!item.bookImg"
|
v-if="!item.bookImg"
|
||||||
:style="{'background-color': index%2==0?'#f5f5f5':''}"
|
:style="{'background-color': index%2==0?'#f5f5f5':''}"
|
||||||
|
@ -22,14 +22,13 @@
|
||||||
@change="(...o) => emit('change', ...o)"
|
@change="(...o) => emit('change', ...o)"
|
||||||
></reserv-item-apt>
|
></reserv-item-apt>
|
||||||
</template>
|
</template>
|
||||||
<el-divider v-if="page.isEnd">到底了,没了</el-divider>
|
|
||||||
</div>
|
</div>
|
||||||
<reserv ref="reservDialog"></reserv>
|
<reserv ref="reservDialog"></reserv>
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed, watch, reactive } from 'vue'
|
import { ref, onMounted, computed, watch } from 'vue'
|
||||||
import { getSelfReserv } from '@/api/classManage'
|
import { getSelfReserv } from '@/api/classManage'
|
||||||
import { listClasscourseNew } from '@/api/teaching/classcourse' // api接口
|
import { listClasscourseNew } from '@/api/teaching/classcourse' // api接口
|
||||||
import ReservItem from '@/views/classManage/reserv-item.vue'
|
import ReservItem from '@/views/classManage/reserv-item.vue'
|
||||||
|
@ -37,7 +36,6 @@ import Reserv from '@/views/prepare/container/reserv.vue'
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import ReservItemApt from '@/views/classManage/reserv-item-apt.vue'
|
import ReservItemApt from '@/views/classManage/reserv-item-apt.vue'
|
||||||
import vScroll from '@/directive/scroll' // 指令--滚动
|
|
||||||
// import Chat from '@/utils/chat' // im 登录初始化
|
// import Chat from '@/utils/chat' // im 登录初始化
|
||||||
// if (!Chat.imChat) Chat.init()
|
// if (!Chat.imChat) Chat.init()
|
||||||
|
|
||||||
|
@ -46,12 +44,6 @@ const reservDialog = ref(null)
|
||||||
const tabOptions = ref(['进行中', '已结束'])
|
const tabOptions = ref(['进行中', '已结束'])
|
||||||
const tabActive = ref('进行中')
|
const tabActive = ref('进行中')
|
||||||
const dataList = ref([])
|
const dataList = ref([])
|
||||||
const page = reactive({
|
|
||||||
pageNum: 0, // 页码
|
|
||||||
pageSize: 10, // 每页条数
|
|
||||||
total: 0, // 总条数
|
|
||||||
isEnd: false // 是否加载完
|
|
||||||
})
|
|
||||||
|
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
@ -80,42 +72,21 @@ const deleteReserv = (item) => {
|
||||||
})*/
|
})*/
|
||||||
// 获取数据
|
// 获取数据
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
const { pageNum, pageSize } = page
|
Promise.all([listClasscourseNew({teacherid: userStore.id,evalid: props.curNode.id,pageSize:1000}), getSelfReserv({ex2:props.curNode.id})]).then(([res1,res2])=>{
|
||||||
const params = {
|
let list = res2.data || []
|
||||||
evalid: props.curNode.id,
|
let list2 = res1.rows || []
|
||||||
teacherid: userStore.id,
|
// list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
|
||||||
pageNum, pageSize
|
list = list.concat(list2)
|
||||||
}
|
|
||||||
listClasscourseNew(params)
|
|
||||||
.then((res) => {
|
|
||||||
const list = res.rows || []
|
|
||||||
const total = res.total || 0
|
|
||||||
list.sort((a,b) => { return new Date(b.createTime) - new Date(a.createTime) })
|
list.sort((a,b) => { return new Date(b.createTime) - new Date(a.createTime) })
|
||||||
dataList.value.push(...list)
|
dataList.value = list
|
||||||
page.total = total // 总条数
|
|
||||||
page.isEnd = dataList.value.length == total // 是否结束
|
|
||||||
})
|
})
|
||||||
// aippt+ppt 获取数据
|
|
||||||
// Promise.all([listClasscourseNew({teacherid: userStore.id,evalid: props.curNode.id,pageSize:1000}), getSelfReserv({ex2:props.curNode.id})]).then(([res1,res2])=>{
|
|
||||||
// let list = res2.data || []
|
|
||||||
// let list2 = res1.rows || []
|
|
||||||
// // list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
|
|
||||||
// list = list.concat(list2)
|
|
||||||
// list.sort((a,b) => { return new Date(b.createTime) - new Date(a.createTime) })
|
|
||||||
// dataList.value = list
|
|
||||||
// })
|
|
||||||
/*getSelfReserv().then((res) => {
|
/*getSelfReserv().then((res) => {
|
||||||
const list = res.data || []
|
const list = res.data || []
|
||||||
list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
|
list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
|
||||||
dataList.value = list
|
dataList.value = list
|
||||||
})*/
|
})*/
|
||||||
}
|
}
|
||||||
// 列表加载更多
|
|
||||||
const load = () => {
|
|
||||||
if(page.isEnd) return console.log('已加载完-所有') // 结束
|
|
||||||
page.pageNum++
|
|
||||||
getData()
|
|
||||||
}
|
|
||||||
watch(
|
watch(
|
||||||
() => [dataList,toolStore.isToolWin,props.curNode],
|
() => [dataList,toolStore.isToolWin,props.curNode],
|
||||||
() => {
|
() => {
|
||||||
|
@ -125,14 +96,13 @@ watch(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// getData() // 加载数据
|
getData() // 加载数据
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.class-reserv-wrap {
|
.class-reserv-wrap {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// height: 300px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
//padding: 15px 10px;
|
//padding: 15px 10px;
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="item.status === 'open'">
|
<template v-else-if="item.status === 'open'">
|
||||||
<el-button :disabled="toolStore.isToolWin" size="small" type="primary" @click="startClassR(item)"
|
<el-button :disabled="toolStore.isToolWin" size="small" type="primary" @click="startClassR(item)"
|
||||||
>继续上课</el-button>
|
>继续上课</el-button
|
||||||
|
>
|
||||||
<!--<el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>-->
|
<!--<el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>-->
|
||||||
<el-button :loading="loading" size="small" type="info" @click="endClassR(item)"
|
<el-button :loading="loading" size="small" type="info" @click="endClassR(item)"
|
||||||
>下课{{ loading?'中...':'' }}</el-button>
|
>下课{{ loading?'中...':'' }}</el-button>
|
||||||
|
@ -23,8 +24,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="class-reserv-item-tool" style="width: 50px;">
|
<div class="class-reserv-item-tool" style="width: 50px;">
|
||||||
<!-- <el-button v-if="item.status!='open'" size="small" type="danger" @click="deleteReserv">删除</el-button>-->
|
<!-- <el-button v-if="item.status!='open'" size="small" type="danger" @click="deleteReserv">删除</el-button>-->
|
||||||
<!-- <el-tag>APT</el-tag> -->
|
<el-tag>APT</el-tag>
|
||||||
<el-tag>AIPPT</el-tag>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="min-width: 150px;"><span> 浏览:25955 点赞:26605</span></div>
|
<div style="min-width: 150px;"><span> 浏览:25955 点赞:26605</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,7 +86,6 @@ const chatSend = () => {
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.class-reserv-item {
|
.class-reserv-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -112,7 +111,7 @@ const chatSend = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.class-reserv-item-tool {
|
.class-reserv-item-tool {
|
||||||
margin: 0 7px;
|
margin-left: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
|
@ -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: '提交成功!'
|
||||||
|
|
|
@ -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();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -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>
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
|
@ -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'
|
||||||
|
@ -154,14 +149,10 @@ import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import useClassTaskStore from '@/store/modules/classTask'
|
|
||||||
|
|
||||||
const userStore = useUserStore().user
|
const userStore = useUserStore().user
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
const useClassTaskStores = useClassTaskStore();
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentCourse: Object,
|
currentCourse: Object,
|
||||||
})
|
})
|
||||||
|
@ -198,8 +189,7 @@ const boardLoading = ref(false);
|
||||||
const fileLoading = ref(false); // 常规作业loading
|
const fileLoading = ref(false); // 常规作业loading
|
||||||
|
|
||||||
onMounted(() => {
|
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 // 版本
|
||||||
|
@ -226,28 +216,7 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initHomeWork();
|
initHomeWork();
|
||||||
isInToMyQuestion(); // 如果是上传习题后返回的,跳转到个人题库
|
|
||||||
})
|
})
|
||||||
// 是否进入个人题库
|
|
||||||
const isInToMyQuestion = () => {
|
|
||||||
console.log('isOpenQuestUploadView',useClassTaskStores.isOpenQuestUploadView);
|
|
||||||
if(useClassTaskStores.isOpenQuestUploadView){
|
|
||||||
useClassTaskStores.isOpenQuestUploadView = false;
|
|
||||||
|
|
||||||
currentRow.value.id = 1; // 作业设计
|
|
||||||
activeAptTab.value = "个人题库";
|
|
||||||
//提交内容清空 重置
|
|
||||||
classWorkForm.id = 0;
|
|
||||||
classWorkForm.uniquekey = ""; // 作业唯一标识 作业名称
|
|
||||||
classWorkForm.worktype = "习题训练"; //作业类型
|
|
||||||
classWorkForm.title = ""; // 作业说明
|
|
||||||
classWorkForm.quizlist = []; // 作业习题列表内容
|
|
||||||
classWorkForm.chooseWorkLists = []; // 作业框架梳理list
|
|
||||||
classWorkForm.fileHomeworkList = []; // 常规作业文件列表
|
|
||||||
classWorkForm.whiteboardObj = ""; // 作业资源 - 课堂展示 白板
|
|
||||||
classWorkForm.question = ""; // 作业资源 - 课堂展示 输入的问题
|
|
||||||
}
|
|
||||||
}
|
|
||||||
watch(() => props.currentCourse, (newVal, oldVal) => {
|
watch(() => props.currentCourse, (newVal, oldVal) => {
|
||||||
if(newVal){
|
if(newVal){
|
||||||
courseObj.textbookId = newVal.textbookId // 版本
|
courseObj.textbookId = newVal.textbookId // 版本
|
||||||
|
@ -263,16 +232,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 +240,7 @@ const handleItemClick = (itemName) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRow.value.id = 1; // 作业设计
|
currentRow.value = {id:1}; // 作业设计
|
||||||
/**
|
/**
|
||||||
* 智能推荐?AI设计作业?
|
* 智能推荐?AI设计作业?
|
||||||
* 习题训练: 自主搜题 校本题库 个人题库
|
* 习题训练: 自主搜题 校本题库 个人题库
|
||||||
|
@ -324,7 +283,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 +310,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 +404,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 +495,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 +556,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 +602,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 +641,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 +733,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 +839,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;
|
||||||
|
|
|
@ -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();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import "vue-cropper/dist/index.css";
|
import "vue-cropper/dist/index.css";
|
||||||
import { VueCropper } from "vue-cropper";
|
import { VueCropper } from "vue-cropper";
|
||||||
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick, onUnmounted } from 'vue'
|
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
|
@ -88,8 +88,6 @@ import { useRouter, useRoute } from 'vue-router'
|
||||||
|
|
||||||
import { ocrImg2ExamByManualUpl, ocrImg2ItemByManualUpl } from "@/views/classTask/newClassTaskAssign/questionUpload/ocrImg2ExamQues";
|
import { ocrImg2ExamByManualUpl, ocrImg2ItemByManualUpl } from "@/views/classTask/newClassTaskAssign/questionUpload/ocrImg2ExamQues";
|
||||||
import QuesItem from "@/views/classTask/newClassTaskAssign/questionUpload/quesItem/index.vue";
|
import QuesItem from "@/views/classTask/newClassTaskAssign/questionUpload/quesItem/index.vue";
|
||||||
import useClassTaskStore from '@/store/modules/classTask'
|
|
||||||
|
|
||||||
|
|
||||||
// const Remote = require('@electron/remote')
|
// const Remote = require('@electron/remote')
|
||||||
// const fs = require('fs');
|
// const fs = require('fs');
|
||||||
|
@ -98,9 +96,7 @@ import useUserStore from '@/store/modules/user'
|
||||||
const userStore = useUserStore().user
|
const userStore = useUserStore().user
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance()
|
||||||
const useClassTaskStores = useClassTaskStore();
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -127,7 +123,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
|
||||||
|
@ -155,7 +151,6 @@ const cropOption = reactive({
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
useClassTaskStores.isOpenQuestUploadView = true; // 打开过习题上传界面
|
|
||||||
console.log('propsQueryCourseObj', JSON.parse(propsQueryCourseObj));
|
console.log('propsQueryCourseObj', JSON.parse(propsQueryCourseObj));
|
||||||
if(propsQueryCourseObj&&JSON.parse(propsQueryCourseObj)){
|
if(propsQueryCourseObj&&JSON.parse(propsQueryCourseObj)){
|
||||||
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // 版本
|
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // 版本
|
||||||
|
@ -166,13 +161,7 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
initHomeWork();
|
initHomeWork();
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
|
||||||
// 延迟1s 关闭习题上传界面,作业管理界面需要根据 isOpenQuestUploadView 来进行判断
|
|
||||||
setTimeout(()=>{
|
|
||||||
useClassTaskStores.isOpenQuestUploadView = false; // 关闭习题上传界面
|
|
||||||
console.log('onUnmounted 习题上传');
|
|
||||||
}, 1000)
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 entpcourseid 获取作业列表
|
* 获取 entpcourseid 获取作业列表
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { ElMessageBox, ElMessage } from "element-plus";
|
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 { pyOCRAPI } from "@/api/education/entpcoursework";
|
||||||
import { pyOCRAPI, getOcrContent } from "@/api/education/entpcoursework";
|
|
||||||
import useClassTaskStore from '@/store/modules/classTask'
|
|
||||||
|
|
||||||
|
|
||||||
const EXAM_JUDGED_DICTIONARY = ["正确", "对", "√", "T", "错误", "错", "×", "F"];
|
const EXAM_JUDGED_DICTIONARY = ["正确", "对", "√", "T", "错误", "错", "×", "F"];
|
||||||
|
@ -11,7 +9,7 @@ const baidubceConfig = {
|
||||||
// Header
|
// Header
|
||||||
'Content-Type': "application/x-www-form-urlencoded",
|
'Content-Type': "application/x-www-form-urlencoded",
|
||||||
// 格式
|
// 格式
|
||||||
'Accept': 'application/json',
|
'Accept' : 'application/json',
|
||||||
// id(临时测试)
|
// id(临时测试)
|
||||||
'client_id': "U0DrGBE6X92IXgV6cJMNON8F",
|
'client_id': "U0DrGBE6X92IXgV6cJMNON8F",
|
||||||
// 密钥(临时测试)
|
// 密钥(临时测试)
|
||||||
|
@ -19,10 +17,6 @@ const baidubceConfig = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const {
|
|
||||||
entpCourseWorkTypeList
|
|
||||||
} = useClassTaskStore();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc: [人工录入]中识别[单项]内容
|
* @desc: [人工录入]中识别[单项]内容
|
||||||
|
@ -41,9 +35,9 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
// 识别内容拼接
|
// 识别内容拼接
|
||||||
let ocrTxt = ''
|
let ocrTxt = ''
|
||||||
|
|
||||||
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;
|
||||||
// 识别内容拼接
|
// 识别内容拼接
|
||||||
|
@ -65,7 +59,7 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const tmp = await ocrImg2Json(imgBase64);
|
const tmp = await ocrImg2Json(imgBase64);
|
||||||
if (!tmp?.data) {
|
if(!tmp?.data) {
|
||||||
return examItem;
|
return examItem;
|
||||||
}
|
}
|
||||||
ocrJson = tmp.data.results;
|
ocrJson = tmp.data.results;
|
||||||
|
@ -75,12 +69,12 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ocrJson == '') {
|
if(ocrJson == '') {
|
||||||
ElMessage.error('[人工录入-单项]识别的图片为空, 识别失败, 请检查重试!');
|
ElMessage.error('[人工录入-单项]识别的图片为空, 识别失败, 请检查重试!');
|
||||||
return examItem;
|
return examItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ocrTxt == '') {
|
if(ocrTxt == '') {
|
||||||
ElMessage.error('[人工录入-单项]识别内容拼接失败, 请检查重试!');
|
ElMessage.error('[人工录入-单项]识别内容拼接失败, 请检查重试!');
|
||||||
return examItem;
|
return examItem;
|
||||||
}
|
}
|
||||||
|
@ -102,24 +96,25 @@ export const ocrImg2ItemByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
worktype: '单选题',
|
worktype: '单选题',
|
||||||
params: [],
|
params: [],
|
||||||
}
|
}
|
||||||
mutiParams.arrWorkDesc.forEach(item => {
|
mutiParams.arrWorkDesc.forEach( item => {
|
||||||
const obj = {
|
const obj = {
|
||||||
title: item.title,
|
title: item.title,
|
||||||
workanswer: '',
|
workanswer: '',
|
||||||
checkAnswer: [],
|
checkAnswer: [],
|
||||||
type: item.type,
|
type: item.type,
|
||||||
options: item.options.map(element => { return { text: element.replace(/<br \/>/g, '') } }),
|
options: item.options.map(element => {return {text: element.replace(/<br \/>/g, '')}}),
|
||||||
}
|
}
|
||||||
examItem.params.push(obj);
|
examItem.params.push(obj);
|
||||||
});
|
});
|
||||||
return examItem;
|
return examItem;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (examType.includes('单选题') || examType.includes('多选题')) {
|
else if (examType.includes('单选题') || examType.includes('多选题')) {
|
||||||
/** 单选题/多选题 - 选项 */
|
/** 单选题/多选题 - 选项 */
|
||||||
// 先判断是否存在选项标识, 且存在2个及以上(A.---1.---(1)---(1))
|
// 先判断是否存在选项标识, 且存在2个及以上(A.---1.---(1)---(1))
|
||||||
regex = /\s*[A-H][..。]/g;
|
regex = /\s*[A-H][..。]/g;
|
||||||
const matches = ocrTxt.match(regex);
|
const matches = ocrTxt.match(regex);
|
||||||
if (matches == null || matches.length < 2) {
|
if (matches==null || matches.length < 2){
|
||||||
ElMessage.error('[人工录入-单项]识别[选项]失败, 请检查重试!');
|
ElMessage.error('[人工录入-单项]识别[选项]失败, 请检查重试!');
|
||||||
return examItem;
|
return examItem;
|
||||||
}
|
}
|
||||||
|
@ -147,10 +142,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;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回转换格式后的识别内容
|
// 返回转换格式后的识别内容
|
||||||
|
@ -169,9 +164,9 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
// 识别内容拼接
|
// 识别内容拼接
|
||||||
let ocrTxt = '';
|
let ocrTxt = '';
|
||||||
|
|
||||||
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;
|
||||||
// 识别内容拼接
|
// 识别内容拼接
|
||||||
|
@ -191,7 +186,7 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
// });
|
// });
|
||||||
} else {
|
} else {
|
||||||
const tmp = await ocrImg2Json(imgBase64);
|
const tmp = await ocrImg2Json(imgBase64);
|
||||||
if (!tmp?.data) {
|
if(!tmp?.data) {
|
||||||
return examQues;
|
return examQues;
|
||||||
}
|
}
|
||||||
ocrJson = tmp.data.results;
|
ocrJson = tmp.data.results;
|
||||||
|
@ -200,20 +195,20 @@ export const ocrImg2ExamByManualUpl = async (isLocalTest = false, imgBase64 = ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ocrJson == '') {
|
if(ocrJson == '') {
|
||||||
ElMessage.error('[人工录入-整题]图片识别内容为空, 识别失败, 请重试!');
|
ElMessage.error('[人工录入-整题]图片识别内容为空, 识别失败, 请重试!');
|
||||||
return examQues;
|
return examQues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ocrTxt == '') {
|
if(ocrTxt == '') {
|
||||||
ElMessage.error('[人工录入-整题]识别内容拼接失败, 请重试!');
|
ElMessage.error('[人工录入-整题]识别内容拼接失败, 请重试!');
|
||||||
return examQues;
|
return examQues;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 识别内容转为试题结构
|
// 识别内容转为试题结构
|
||||||
examQues = assembleExam(ocrTxt);
|
examQues = assembleExam(ocrTxt);
|
||||||
if (examQues.err != '') {
|
if(examQues.err != '') {
|
||||||
ElMessage.error(`[人工录入-整题]${examQues.err}, 请重试!`);
|
ElMessage.error(`[人工录入-整题]${examQues.err}, 请重试!`);
|
||||||
examQues = {};
|
examQues = {};
|
||||||
}
|
}
|
||||||
|
@ -231,38 +226,30 @@ const ocrImg2Json = async (urlBase64) => {
|
||||||
ElMessage.error("未检测到截图图片, 请截取图片后再识别");
|
ElMessage.error("未检测到截图图片, 请截取图片后再识别");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const resToken = await bdyAPI_getToken();
|
||||||
let base64Code = urlBase64.split(",")[1];
|
if (resToken.status !== 200) {
|
||||||
const resOcr = await getOcrContent({ base64Code: base64Code });
|
ElMessage.error("百度智能云用户标识有误");
|
||||||
if (resOcr.code !== 200) {
|
|
||||||
ElMessage.error("图片识别错误");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const resToken = await bdyAPI_getToken();
|
const token = resToken.data?.access_token;
|
||||||
// if (resToken.status !== 200) {
|
let base64Code = urlBase64.split(",")[1];
|
||||||
// ElMessage.error("百度智能云用户标识有误");
|
const query = {
|
||||||
// return null;
|
image: base64Code, //图片地址(base64)
|
||||||
// }
|
line_probability: false, //是否返回每行识别结果的置信度。默认为false
|
||||||
|
disp_line_poly: false, //是否返回每行的四角点坐标。默认为false
|
||||||
// const token = resToken.data?.access_token;
|
words_type: 'handprint_mix', //文字类型。 默认:印刷文字识别 = handwring_only:手写文字识别 = handprint_mix: 手写印刷混排识别
|
||||||
// let base64Code = urlBase64.split(",")[1];
|
layout_analysis: false, //是否分析文档版面:包括layout(图、表、标题、段落、目录);attribute(栏、页眉、页脚、页码、脚注)的分析输出
|
||||||
// const query = {
|
recg_long_division: false, //是否检测并识别手写竖式
|
||||||
// image: base64Code, //图片地址(base64)
|
recg_formula: true, //控制是否检测并识别公式,默认为false
|
||||||
// line_probability: false, //是否返回每行识别结果的置信度。默认为false
|
}
|
||||||
// disp_line_poly: false, //是否返回每行的四角点坐标。默认为false
|
|
||||||
// words_type: 'handprint_mix', //文字类型。 默认:印刷文字识别 = handwring_only:手写文字识别 = handprint_mix: 手写印刷混排识别
|
|
||||||
// layout_analysis: false, //是否分析文档版面:包括layout(图、表、标题、段落、目录);attribute(栏、页眉、页脚、页码、脚注)的分析输出
|
|
||||||
// recg_long_division: false, //是否检测并识别手写竖式
|
|
||||||
// recg_formula: true, //控制是否检测并识别公式,默认为false
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// const resOcr = await bdyAPI_getOcrContent(token, base64Code, query);
|
const resOcr = await bdyAPI_getOcrContent(token, base64Code, query);
|
||||||
// if (resOcr.status !== 200) {
|
if (resOcr.status !== 200) {
|
||||||
// ElMessage.error("百度智能云图片识别错误");
|
ElMessage.error("百度智能云图片识别错误");
|
||||||
// return null;
|
return null;
|
||||||
// }
|
}
|
||||||
|
|
||||||
return resOcr;
|
return resOcr;
|
||||||
}
|
}
|
||||||
|
@ -364,7 +351,7 @@ const assembleExam = (eachSub) => {
|
||||||
|
|
||||||
let regex = null;
|
let regex = null;
|
||||||
let titleAndWorkDesc = '',
|
let titleAndWorkDesc = '',
|
||||||
answer = '';
|
answer = '';
|
||||||
|
|
||||||
|
|
||||||
// 获取[题源] - 格式化
|
// 获取[题源] - 格式化
|
||||||
|
@ -383,7 +370,7 @@ const assembleExam = (eachSub) => {
|
||||||
if (!hasAnswer) {
|
if (!hasAnswer) {
|
||||||
// 不存在答案, 仅处理[题干+选项]
|
// 不存在答案, 仅处理[题干+选项]
|
||||||
titleAndWorkDesc = eachSub;
|
titleAndWorkDesc = eachSub;
|
||||||
} else {
|
}else {
|
||||||
// 存在答案, 需处理[题干+选项]和[答案+解析]
|
// 存在答案, 需处理[题干+选项]和[答案+解析]
|
||||||
regex = /(<br \/>?\s*[【\[].*?[】\]])/g;
|
regex = /(<br \/>?\s*[【\[].*?[】\]])/g;
|
||||||
let tmpList = eachSub.split(regex);
|
let tmpList = eachSub.split(regex);
|
||||||
|
@ -393,16 +380,16 @@ 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 = {};
|
||||||
// 将第二部分的内容做key-value绑定 - 键为【分析】、【讨论】、【方法】等. 值为随之分隔的内容
|
// 将第二部分的内容做key-value绑定 - 键为【分析】、【讨论】、【方法】等. 值为随之分隔的内容
|
||||||
for (let i = 1; i < tmpList.length - 1; i = i + 2) {
|
for (let i=1; i<tmpList.length-1; i=i+2){
|
||||||
let key = tmpList[i];
|
let key = tmpList[i];
|
||||||
key = key.replace(/<br \/>|【|】|\[|\]/g, '');
|
key = key.replace(/<br \/>|【|】|\[|\]/g, '');
|
||||||
let value = tmpList[i + 1];
|
let value = tmpList[i+1];
|
||||||
value = value.replace(/^<br \/>+|<br \/>+$/g, '');
|
value = value.replace(/^<br \/>+|<br \/>+$/g, '');
|
||||||
answerAndAnswer[key] = value;
|
answerAndAnswer[key] = value;
|
||||||
}
|
}
|
||||||
|
@ -443,51 +430,48 @@ const assembleExam = (eachSub) => {
|
||||||
|
|
||||||
// [答案] - 初步初始化 --- 根据答案判断试题大分类: 复合题(实际为大题) 或 其他基础题型(单选,多选,填空,判断)
|
// [答案] - 初步初始化 --- 根据答案判断试题大分类: 复合题(实际为大题) 或 其他基础题型(单选,多选,填空,判断)
|
||||||
answer = answerAndAnswer['答案'].trim();
|
answer = answerAndAnswer['答案'].trim();
|
||||||
if (!answer) {
|
if(!answer) {
|
||||||
answer = answerAndAnswer['答案及评分参考'].trim();
|
answer = answerAndAnswer['答案及评分参考'].trim();
|
||||||
answer = answer.replace(/^\d+[\u4e00-\u9fa5][..。]\s*<br \/>/, ''); // 去掉 - 有些开头会有[xx分。]
|
answer = answer.replace(/^\d+[\u4e00-\u9fa5][..。]\s*<br \/>/, ''); // 去掉 - 有些开头会有[xx分。]
|
||||||
}
|
}
|
||||||
// 将多余的空格替换为固定的4个空格
|
// 将多余的空格替换为固定的4个空格
|
||||||
answer = answer.replaceAll("\\s{3,}", " ");
|
answer = answer.replaceAll("\\s{3,}"," ");
|
||||||
if (answer == null | answer == '') {
|
if (answer == null | answer == '') {
|
||||||
subObj.err = '题目缺少[答案]';
|
subObj.err = '题目缺少[答案]';
|
||||||
return subObj;
|
return subObj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 目前暂屏蔽无[复合题], 故所有都算基础题
|
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) {
|
||||||
// 错误信息
|
// 错误信息
|
||||||
if (tmpExam.errMsg !== '') {
|
if(tmpExam.errMsg !== '') {
|
||||||
subObj.err = tmpExam.err;
|
subObj.err = tmpExam.err;
|
||||||
return subObj;
|
return subObj;
|
||||||
}
|
}
|
||||||
|
@ -524,7 +508,7 @@ const processExamSingle = function (titleAndWorkDesc, answer) {
|
||||||
let matcher = null;
|
let matcher = null;
|
||||||
|
|
||||||
/** [判断题]的处理逻辑, resp: -1-未找到 0-*为对应匹配的index */
|
/** [判断题]的处理逻辑, resp: -1-未找到 0-*为对应匹配的index */
|
||||||
let judgedStatus = answer !== '' ? containsExactMatch(answer) : -1;
|
let judgedStatus = answer!=='' ? containsExactMatch(answer) : -1;
|
||||||
|
|
||||||
/** 其他基础题型(单选,多选,填空,判断)的处理逻辑 */
|
/** 其他基础题型(单选,多选,填空,判断)的处理逻辑 */
|
||||||
// 先去掉开头的试题序号
|
// 先去掉开头的试题序号
|
||||||
|
@ -540,7 +524,7 @@ const processExamSingle = function (titleAndWorkDesc, answer) {
|
||||||
answer = answer.replace("<br />", "").trim();
|
answer = answer.replace("<br />", "").trim();
|
||||||
|
|
||||||
// [题型] - 格式化 - 根据答案字符个数区分[单选]或[多选]
|
// [题型] - 格式化 - 根据答案字符个数区分[单选]或[多选]
|
||||||
examSingle.workType = answer === '' ? '单选题' : answer.length == 1 ? "单选题" : "多选题";
|
examSingle.workType = answer==='' ? '单选题' : answer.length == 1 ? "单选题" : "多选题";
|
||||||
|
|
||||||
// 切分题干+选项
|
// 切分题干+选项
|
||||||
regex = /<br \/>*\s*[A-H][..。]/g;
|
regex = /<br \/>*\s*[A-H][..。]/g;
|
||||||
|
@ -551,10 +535,10 @@ const processExamSingle = function (titleAndWorkDesc, answer) {
|
||||||
|
|
||||||
// [选项]-处理 --- ['ABC123','ABC123']
|
// [选项]-处理 --- ['ABC123','ABC123']
|
||||||
for (let i = 1; i < tmpSplit.length; i++) {
|
for (let i = 1; i < tmpSplit.length; i++) {
|
||||||
let option = tmpSplit[i].replace("<br />", "").trim();
|
let option = tmpSplit[i].replace("<br />", "").trim();
|
||||||
//option = option.replace("_", "");
|
//option = option.replace("_", "");
|
||||||
// [选项] - 格式化
|
// [选项] - 格式化
|
||||||
examSingle.arrWorkDesc.push(option);
|
examSingle.arrWorkDesc.push(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
// [题目答案] --- ['0'] | ['0','1']
|
// [题目答案] --- ['0'] | ['0','1']
|
||||||
|
@ -586,7 +570,7 @@ const processExamSingle = function (titleAndWorkDesc, answer) {
|
||||||
examSingle.arrWorkAnswer = answer.split(" ");
|
examSingle.arrWorkAnswer = answer.split(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (judgedStatus != -1) {
|
else if( judgedStatus != -1 ) {
|
||||||
/**
|
/**
|
||||||
* 判断题
|
* 判断题
|
||||||
*/
|
*/
|
||||||
|
@ -609,21 +593,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 !== '') {
|
||||||
|
@ -659,48 +635,48 @@ const processExamMulti = function (titleAndWorkDesc, answer) {
|
||||||
// 先确定当前是以什么形式的小题序号来切分 --- 需要全部独立判断, 避免出现复合题中, 每小题内还包含小题的情况--- 1.回答以下问题 (1)***** (2)******
|
// 先确定当前是以什么形式的小题序号来切分 --- 需要全部独立判断, 避免出现复合题中, 每小题内还包含小题的情况--- 1.回答以下问题 (1)***** (2)******
|
||||||
let cliceSucc = false;
|
let cliceSucc = false;
|
||||||
let arrAnswer = []
|
let arrAnswer = []
|
||||||
if (!cliceSucc) {
|
if(!cliceSucc){
|
||||||
regex = /<br \/>\s*\d+[..。]\s*/;
|
regex = /<br \/>\s*\d+[..。]\s*/;
|
||||||
if (regex.test(titleAndWorkDesc)) {
|
if (regex.test(titleAndWorkDesc)) {
|
||||||
// 再次以答案中的序号同步匹配一次
|
// 再次以答案中的序号同步匹配一次
|
||||||
regex = /^\s*\d+[..。]\s*/;
|
regex = /^\s*\d+[..。]\s*/;
|
||||||
if (answer === '' || regex.test(answer)) {
|
if(answer === '' || regex.test(answer)){
|
||||||
regex = /<br \/>\s*\d+[..。]\s*/g;
|
regex = /<br \/>\s*\d+[..。]\s*/g;
|
||||||
tmpSplit = titleAndWorkDesc.split(regex);
|
tmpSplit = titleAndWorkDesc.split(regex);
|
||||||
if (answer !== '') {
|
if (answer !== '') {
|
||||||
// 存在答案时, 再校验
|
// 存在答案时, 再校验
|
||||||
regex = /^\s*\d+[..。]\s*|<br \/>\s*\d+[..。]\s*|\s+\d+[..。]\s*/g;
|
regex = /^\s*\d+[..。]\s*|<br \/>\s*\d+[..。]\s*|\s+\d+[..。]\s*/g;
|
||||||
arrAnswer = answer.split(regex);
|
arrAnswer = answer.split(regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
cliceSucc = true;
|
cliceSucc = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cliceSucc) {
|
if (!cliceSucc){
|
||||||
regex = /<br \/>\s*(\d+)\s*/;
|
regex = /<br \/>\s*(\d+)\s*/;
|
||||||
if (regex.test(titleAndWorkDesc)) {
|
if (regex.test(titleAndWorkDesc)) {
|
||||||
// 再次以答案中的序号同步匹配一次
|
// 再次以答案中的序号同步匹配一次
|
||||||
regex = /\s*(\d+)\s*/;
|
regex = /\s*(\d+)\s*/;
|
||||||
if (answer === '' || regex.test(answer)) {
|
if(answer === '' || regex.test(answer)){
|
||||||
regex = /<br \/>\s*(\d+)\s*/g;
|
regex = /<br \/>\s*(\d+)\s*/g;
|
||||||
tmpSplit = titleAndWorkDesc.split(regex);
|
tmpSplit = titleAndWorkDesc.split(regex);
|
||||||
if (answer !== '') {
|
if (answer !== '') {
|
||||||
// 存在答案时, 再校验
|
// 存在答案时, 再校验
|
||||||
regex = /^\s*(\d+)\s*|<br \/>\s*(\d+)\s*|\s+(\d+)\s*/g;
|
regex = /^\s*(\d+)\s*|<br \/>\s*(\d+)\s*|\s+(\d+)\s*/g;
|
||||||
arrAnswer = answer.split(regex);
|
arrAnswer = answer.split(regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
cliceSucc = true;
|
cliceSucc = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cliceSucc) {
|
if (!cliceSucc){
|
||||||
regex = /<br \/>\s*\(\d+\)\s*/;
|
regex = /<br \/>\s*\(\d+\)\s*/;
|
||||||
if (regex.test(titleAndWorkDesc)) {
|
if (regex.test(titleAndWorkDesc)) {
|
||||||
// 再次以答案中的序号同步匹配一次
|
// 再次以答案中的序号同步匹配一次
|
||||||
regex = /^\s*\(\d+\)\s*/;
|
regex = /^\s*\(\d+\)\s*/;
|
||||||
if (answer === '' || regex.test(answer)) {
|
if(answer === '' || regex.test(answer)){
|
||||||
regex = /<br \/>\s*\(\d+\)\s*/g;
|
regex = /<br \/>\s*\(\d+\)\s*/g;
|
||||||
tmpSplit = titleAndWorkDesc.split(regex);
|
tmpSplit = titleAndWorkDesc.split(regex);
|
||||||
if (answer !== '') {
|
if (answer !== '') {
|
||||||
|
@ -713,19 +689,19 @@ const processExamMulti = function (titleAndWorkDesc, answer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cliceSucc) {
|
if (!cliceSucc){
|
||||||
examMulti.errMsg = '[复合题]小题与答案序号[不匹配]';
|
examMulti.errMsg = '[复合题]小题与答案序号[不匹配]';
|
||||||
return examMulti;
|
return examMulti;
|
||||||
}
|
}
|
||||||
if (tmpSplit.length < 2) {
|
if (tmpSplit.length < 2){
|
||||||
examMulti.errMsg = '[复合题]题干与小题[切分失败]';
|
examMulti.errMsg = '[复合题]题干与小题[切分失败]';
|
||||||
return examMulti;
|
return examMulti;
|
||||||
}
|
}
|
||||||
if (answer !== '' && arrAnswer.length < 2) {
|
if (answer !== '' && arrAnswer.length < 2){
|
||||||
examMulti.errMsg = '[复合题]答案切分小题失败';
|
examMulti.errMsg = '[复合题]答案切分小题失败';
|
||||||
return examMulti;
|
return examMulti;
|
||||||
}
|
}
|
||||||
if (answer !== '' && tmpSplit.length != arrAnswer.length) {
|
if (answer !== '' && tmpSplit.length != arrAnswer.length){
|
||||||
examMulti.errMsg = '[复合题]小题个数与答案个数[不一致]';
|
examMulti.errMsg = '[复合题]小题个数与答案个数[不一致]';
|
||||||
return examMulti;
|
return examMulti;
|
||||||
}
|
}
|
||||||
|
@ -734,13 +710,13 @@ const processExamMulti = function (titleAndWorkDesc, answer) {
|
||||||
examMulti.title = tmpSplit[0].trim();
|
examMulti.title = tmpSplit[0].trim();
|
||||||
|
|
||||||
// [选项]+[答案] - 逻辑处理
|
// [选项]+[答案] - 逻辑处理
|
||||||
for (let i = 1; i < tmpSplit.length; i++) {
|
for (let i=1; i<tmpSplit.length; i++){
|
||||||
const tmp = tmpSplit[i].trim();
|
const tmp = tmpSplit[i].trim();
|
||||||
// 因arrAnswer[0]对应为分隔出来的首位空数组, 故这里也可直接使用i=1作为下标获取答案
|
// 因arrAnswer[0]对应为分隔出来的首位空数组, 故这里也可直接使用i=1作为下标获取答案
|
||||||
const tmpAnswer = answer === '' ? '' : arrAnswer[i].trim();
|
const tmpAnswer = answer === '' ? '' : arrAnswer[i].trim();
|
||||||
// 单题处理
|
// 单题处理
|
||||||
const tmpExam = processExamSingle(tmp, tmpAnswer);
|
const tmpExam = processExamSingle(tmp, tmpAnswer);
|
||||||
if (tmpExam.errMsg !== '') {
|
if(tmpExam.errMsg !== ''){
|
||||||
examMulti.errMsg = '[复合题]小题解析失败';
|
examMulti.errMsg = '[复合题]小题解析失败';
|
||||||
return examMulti;
|
return examMulti;
|
||||||
}
|
}
|
||||||
|
@ -792,10 +768,10 @@ const containsExactMatch = function (answer) {
|
||||||
answer = answer.replace("_____", "");
|
answer = answer.replace("_____", "");
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (let item of EXAM_JUDGED_DICTIONARY) {
|
for (let item of EXAM_JUDGED_DICTIONARY) {
|
||||||
if (answer === item) {
|
if (answer === item) {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
|
@ -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">(?: )?<\/div><!--EA-->/g, '_____');
|
item.title = item.title.replace(/<!--BA--><div class="quizPutTag" contenteditable="true">(?: )?<\/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{
|
||||||
|
|
|
@ -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();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div style="font-size: 18px; display: flex; flex-wrap: nowrap">
|
<div style="font-size: 18px; display: flex; flex-wrap: nowrap">
|
||||||
<div style="flex: 1">
|
<div style="flex: 1">
|
||||||
{{ classWorkAnalysis.title }}完成情况
|
{{ classWorkAnalysis.title }}完成情况
|
||||||
<el-tag :type="classWorkAnalysis.workclass||'info'" size="large" style="height: 25px">{{
|
<el-tag :type="classWorkAnalysis.workclass" size="large" style="height: 25px">{{
|
||||||
classWorkAnalysis.worktype
|
classWorkAnalysis.worktype
|
||||||
}}</el-tag>
|
}}</el-tag>
|
||||||
</div>
|
</div>
|
||||||
|
@ -162,12 +162,9 @@ import ItemDialogScore from '@/views/classTask/container/classTask/item-dialog-s
|
||||||
import quizStats from '@/views/classTask/container/quizStats.vue'
|
import quizStats from '@/views/classTask/container/quizStats.vue'
|
||||||
import ClassOverview from '@/views/classTask/container/classOverview.vue'
|
import ClassOverview from '@/views/classTask/container/classOverview.vue'
|
||||||
import {sessionStore} from '@/utils/store'
|
import {sessionStore} from '@/utils/store'
|
||||||
// import Chat from '@/utils/chat' // im 登录初始化
|
import Chat from '@/utils/chat' // im 登录初始化
|
||||||
import { Homework } from '@/AixPPTist/src/api/index'
|
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
|
||||||
import { set } from 'lodash'
|
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
const emit = defineEmits(['cle-click'])
|
const emit = defineEmits(['cle-click'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -716,48 +713,27 @@ const closeDialog = () => {
|
||||||
|
|
||||||
// im监听消息回调
|
// im监听消息回调
|
||||||
const msgHandle = (msg) => {
|
const msgHandle = (msg) => {
|
||||||
console.log('socket消息回调', msg)
|
const { type, data } = msg
|
||||||
if (typeof msg === 'object'){
|
switch(type) {
|
||||||
const { head, content, ...other } = msg
|
case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
||||||
switch(head) {
|
{
|
||||||
case MsgEnum.HEADS.MSG_closed: // 下课:
|
(data||[]).forEach(o => {
|
||||||
Homework.win = null
|
const msgArr = o?.message_elem_array||[]
|
||||||
window.close() // 关闭窗口
|
msgArr.forEach(info => {
|
||||||
break
|
const msgType = info?.elem_type // 消息类型 TIMElemType
|
||||||
case MsgEnum.HEADS.MSG_finishHomework: // 跟新作业:
|
const msgData = !!info.text_elem_content ? JSON.parse(info.text_elem_content)||'' : ''
|
||||||
console.log('更新作业', head, content)
|
// 处理学生端反馈得消息
|
||||||
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
//console.log('msgData->', msgData);
|
||||||
openDialog(data, false);
|
if (msgData.msgKey == "finishHomework"){
|
||||||
break
|
// 刷新
|
||||||
case MsgEnum.HEADS.MSG_slideFlapping: // 切换页面
|
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
||||||
console.log('切换页面-关闭窗口')
|
//console.log('data->', data);
|
||||||
Homework.win = null
|
openDialog(data, false);
|
||||||
window.close() // 关闭窗口
|
}
|
||||||
break
|
})
|
||||||
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 实验:
|
})
|
||||||
Homework.win = null
|
}
|
||||||
window.close() // 关闭窗口
|
break
|
||||||
break
|
|
||||||
// case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
|
||||||
// {
|
|
||||||
// (data||[]).forEach(o => {
|
|
||||||
// const msgArr = o?.message_elem_array||[]
|
|
||||||
// msgArr.forEach(info => {
|
|
||||||
// const msgType = info?.elem_type // 消息类型 TIMElemType
|
|
||||||
// const msgData = !!info.text_elem_content ? JSON.parse(info.text_elem_content)||'' : ''
|
|
||||||
// // 处理学生端反馈得消息
|
|
||||||
// //console.log('msgData->', msgData);
|
|
||||||
// if (msgData.msgKey == "finishHomework"){
|
|
||||||
// // 刷新
|
|
||||||
// const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
|
||||||
// //console.log('data->', data);
|
|
||||||
// openDialog(data, false);
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,22 +750,11 @@ onMounted(() => {
|
||||||
isReloadTimer();
|
isReloadTimer();
|
||||||
|
|
||||||
// im监听消息
|
// im监听消息
|
||||||
if (ChatWs.ws) {
|
if (!Chat.imChat) {
|
||||||
console.log('socket监听消息')
|
Chat.init(true, true, msgHandle);
|
||||||
ChatWs.watch((msg, e) => {
|
} else {
|
||||||
try {
|
Chat.listenMsg(msgHandle);
|
||||||
msgHandle(JSON.parse(msg)?.msg)
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('socket 解析异常 ', error, e)
|
|
||||||
msgHandle(msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// if (!Chat.imChat) {
|
|
||||||
// Chat.init(true, true, msgHandle);
|
|
||||||
// } else {
|
|
||||||
// Chat.listenMsg(msgHandle);
|
|
||||||
// }
|
|
||||||
})
|
})
|
||||||
const isReloadTimer = () =>{
|
const isReloadTimer = () =>{
|
||||||
clearInterval(reloadTimer.value) // 关闭定时器
|
clearInterval(reloadTimer.value) // 关闭定时器
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue