Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl
This commit is contained in:
commit
83d3cd5df8
|
@ -0,0 +1,25 @@
|
||||||
|
# 页面标题
|
||||||
|
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'
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 页面标题
|
||||||
|
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'
|
|
@ -0,0 +1,54 @@
|
||||||
|
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:
|
||||||
|
- '**/*'
|
|
@ -0,0 +1,54 @@
|
||||||
|
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:
|
||||||
|
- '**/*'
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "aix-win-ws",
|
"name": "aix-win-ws",
|
||||||
"version": "2.5.6",
|
"version": "2.5.8",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "上海交大重庆人工智能研究院",
|
"author": "上海交大重庆人工智能研究院",
|
||||||
|
@ -16,6 +16,8 @@
|
||||||
"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"
|
||||||
|
@ -92,6 +94,8 @@
|
||||||
"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.
After Width: | Height: | Size: 51 KiB |
|
@ -7,6 +7,7 @@ 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'
|
||||||
|
@ -41,19 +42,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: 888,
|
width: import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?1060: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, '../../resources/logo2.ico'),
|
icon: join(__dirname, logoIco),
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
defaultEncoding: 'utf-8',
|
defaultEncoding: 'utf-8',
|
||||||
|
@ -95,7 +96,7 @@ function createMainWindow() {
|
||||||
frame: false, // 无边框
|
frame: false, // 无边框
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
icon: join(__dirname, '../../resources/logo2.ico'),
|
icon: join(__dirname, logoIco),
|
||||||
...(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:; 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:; 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;" />
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -74,8 +74,6 @@ const initLoad: Function = () => {
|
||||||
!!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// 有比例配置项
|
!!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// 有比例配置项
|
||||||
}
|
}
|
||||||
return PPTApi.getSlideList(resource.id)
|
return PPTApi.getSlideList(resource.id)
|
||||||
// PPTApi.updateWorkList()
|
|
||||||
// return Promise.resolve()
|
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,21 +4,51 @@
|
||||||
|
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
|
import { useClasscourseStore } from '../store'
|
||||||
import * as API_classcourse from '@/api/teaching/classcourse' // 后端api
|
import * as API_classcourse from '@/api/teaching/classcourse' // 后端api
|
||||||
|
import { MsgEnum } from './types'
|
||||||
|
// import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
||||||
|
const courseId = classcourse?.id // 课堂id
|
||||||
const timgroupid = classcourse?.timgroupid // 群组id
|
const timgroupid = classcourse?.timgroupid // 群组id
|
||||||
|
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
if (!ChatWs.ws) 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() => {
|
const exitCourse = async() => {
|
||||||
if(!timgroupid) throw new Error('未获取到群组ID')
|
if(!timgroupid) throw new Error('未获取到群组ID')
|
||||||
await API_classcourse.updateClasscourse({ id: classcourse.id, status: 'closed' })
|
await API_classcourse.updateClasscourse({ id: courseId, status: 'closed' })
|
||||||
return ChatWs.closedCourse(timgroupid)
|
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 {
|
return {
|
||||||
exitCourse,
|
|
||||||
classcourse,
|
|
||||||
groupid: timgroupid,
|
groupid: timgroupid,
|
||||||
|
classcourse,
|
||||||
|
exitCourse,
|
||||||
|
slideFlapping,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@ 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 // 提示消息对象
|
||||||
|
@ -36,8 +37,13 @@ export class Classcourse {
|
||||||
// 如果课堂信息有值,则连接socket
|
// 如果课堂信息有值,则连接socket
|
||||||
if (isCourse) {
|
if (isCourse) {
|
||||||
// 连接socket
|
// 连接socket
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
|
||||||
ChatWs.id = classcourse.timgroupid // 群组id
|
ChatWs.id = classcourse.timgroupid // 群组id
|
||||||
|
if (!ChatWs.ws) {
|
||||||
|
ChatWs.init().then(_ => {
|
||||||
|
isPublic && ChatWs.sendMsg('open', {id: classcourse.id})
|
||||||
|
// isPublic && console.log('socket-开课消息-已发送')
|
||||||
|
})
|
||||||
|
}
|
||||||
this.classcourse = classcourse // 课堂信息
|
this.classcourse = classcourse // 课堂信息
|
||||||
this.id = classcourse.id // 课堂id
|
this.id = classcourse.id // 课堂id
|
||||||
// 如果课堂信息有paging,则更新当前页码
|
// 如果课堂信息有paging,则更新当前页码
|
||||||
|
@ -46,7 +52,7 @@ export class Classcourse {
|
||||||
// 如果课堂信息有paging,则更新动画播放状态
|
// 如果课堂信息有paging,则更新动画播放状态
|
||||||
const isAnim = !!cartoonTimes || cartoonTimes === 0
|
const isAnim = !!cartoonTimes || cartoonTimes === 0
|
||||||
if (isPaging) slidesStore.updateSlideIndex(paging)
|
if (isPaging) slidesStore.updateSlideIndex(paging)
|
||||||
if (isAnim) slidesStore.updateAnimationIndex(cartoonTimes+1)
|
if (isAnim) slidesStore.updateAnimationIndex(cartoonTimes)
|
||||||
// 课堂信息-状态管理
|
// 课堂信息-状态管理
|
||||||
classcourseStore.setClasscourse(classcourse)
|
classcourseStore.setClasscourse(classcourse)
|
||||||
// 待上课提示
|
// 待上课提示
|
||||||
|
|
|
@ -50,6 +50,8 @@ export class Utils {
|
||||||
}, delay)
|
}, delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 延时
|
||||||
|
static sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ppt相关后端接口处理 */
|
/** ppt相关后端接口处理 */
|
||||||
|
@ -59,6 +61,7 @@ export class PPTApi {
|
||||||
|
|
||||||
// 获取所有幻灯片列表 isUpdate为true不更新
|
// 获取所有幻灯片列表 isUpdate为true不更新
|
||||||
static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise<Boolean> {
|
static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise<Boolean> {
|
||||||
|
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 }
|
const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 }
|
||||||
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
|
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
|
||||||
|
@ -79,12 +82,16 @@ export class PPTApi {
|
||||||
// 活动列表处理
|
// 活动列表处理
|
||||||
// const workList = (res.rows || []).map(o => o.activityContent)
|
// const workList = (res.rows || []).map(o => o.activityContent)
|
||||||
const workItem = res.rows ? [...res.rows] : []
|
const workItem = res.rows ? [...res.rows] : []
|
||||||
// 写入作业列表数据
|
|
||||||
// slidesStore.setWorkList(workList)
|
|
||||||
// 获取所有的pptlist的数据
|
// 获取所有的pptlist的数据
|
||||||
slidesStore.setWorkItem(workItem)
|
slidesStore.setWorkItem(workItem)
|
||||||
|
// 没有上课时调用-作业列表
|
||||||
this.updateWorkList()
|
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)
|
||||||
})
|
})
|
||||||
|
@ -232,10 +239,29 @@ export class PPTApi {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量更新缩略图-异步
|
||||||
|
static batchUpdateThumUrl() {
|
||||||
|
return nextTick().then(async () => {
|
||||||
|
const list = slidesStore.workItem || []
|
||||||
|
if (!list.length) return
|
||||||
|
const upList = []
|
||||||
|
for (const [ind,o] of list.entries()) {
|
||||||
|
const isCreate = !o.fileurl // 是否创建
|
||||||
|
if (isCreate) {
|
||||||
|
const thumUrl = await this.getSlideThumUrl(ind)
|
||||||
|
upList.push({ id: o.id, fileurl: thumUrl })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!upList.length) return
|
||||||
|
// 批量更新
|
||||||
|
return await API_entpcoursefile.batchUpdateNew(upList)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// thumbnail-slide thumbnail 缩略图
|
// thumbnail-slide thumbnail 缩略图
|
||||||
static getSlideThumUrl(): Promise<Boolean> {
|
static getSlideThumUrl(index?:number): Promise<Boolean> {
|
||||||
return nextTick().then(async() => {
|
return nextTick().then(async() => {
|
||||||
const slideIndex = slidesStore.slideIndex
|
const slideIndex = index ?? slidesStore.slideIndex
|
||||||
const elements = document.querySelectorAll('.thumbnail-slide')
|
const elements = document.querySelectorAll('.thumbnail-slide')
|
||||||
if (elements.length && slideIndex >= 0) {
|
if (elements.length && slideIndex >= 0) {
|
||||||
const element = elements[slideIndex]
|
const element = elements[slideIndex]
|
||||||
|
|
|
@ -124,6 +124,10 @@ export class MsgEnum {
|
||||||
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
||||||
/** @desc: 课堂作业|活动 */
|
/** @desc: 课堂作业|活动 */
|
||||||
MSG_homework : 'HOMEWORK',
|
MSG_homework : 'HOMEWORK',
|
||||||
|
/** @desc: 公屏 - 课堂作业|活动 */
|
||||||
|
MSG_pushSreen_work : 'pushSreen_work',
|
||||||
|
/** @desc: 公屏 - 实验 */
|
||||||
|
MSG_pushSreen_experiment : 'pushSreen_experiment',
|
||||||
/** @desc: 点赞 */
|
/** @desc: 点赞 */
|
||||||
MSG_dz : 'dz',
|
MSG_dz : 'dz',
|
||||||
/** @desc: 疑惑 */
|
/** @desc: 疑惑 */
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { MsgEnum } from './types' // 消息枚举
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
import Classcourse from './classcourse' // 课程相关
|
import Classcourse from './classcourse' // 课程相关
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
|
import * as dialogUtils from '@/utils/dialog' // 弹窗-函数
|
||||||
import { Homework } from './index' // api-作业相关
|
import { Homework } from './index' // api-作业相关
|
||||||
// import emitter from '@/utils/mitt' //mitt 事件总线
|
// import emitter from '@/utils/mitt' //mitt 事件总线
|
||||||
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
||||||
|
@ -23,7 +24,7 @@ export default () => {
|
||||||
const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理
|
const classcourseStore = store.useClasscourseStore() // 课堂信息-状态管理
|
||||||
const resource = sessionStore.get('curr.resource') // apt 资源
|
const resource = sessionStore.get('curr.resource') // apt 资源
|
||||||
const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源
|
const smarttalk = sessionStore.get('curr.smarttalk') // 备课资源
|
||||||
const { execNext, turnPrevSlide } = useExecPlay()
|
const { execNext, turnPrevSlide } = useExecPlay(false) // 不加载钩子
|
||||||
// 监听幻灯片内容变化
|
// 监听幻灯片内容变化
|
||||||
watch(() => slidesStore.slides, (newVal, oldVal) => {
|
watch(() => slidesStore.slides, (newVal, oldVal) => {
|
||||||
PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容
|
PPTApi.updateSlides(newVal, oldVal) // 更新幻灯片内容
|
||||||
|
@ -98,14 +99,25 @@ export default () => {
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
|
case MsgEnum.HEADS.MSG_slideFlapping: // 幻灯片翻页
|
||||||
const slideIndex = content?.current || 0
|
const slideIndex = content?.current || 0
|
||||||
const type = content?.animation
|
const type = content?.animation // 上下动作
|
||||||
|
const steps = content?.animationSteps // 动画步骤
|
||||||
if (type === 'Nextsteps') execNext(true) // 下一步-异步动画
|
if (type === 'Nextsteps') execNext(true) // 下一步-异步动画
|
||||||
else if (type === 'Previoustep') turnPrevSlide() // 上一步清空-动画
|
else if (type === 'Previoustep') turnPrevSlide() // 上一步清空-动画
|
||||||
else slidesStore.updateSlideIndex(slideIndex) // 更新幻灯片下标
|
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
|
break
|
||||||
case MsgEnum.HEADS.MSG_homework: // 作业|活动-布置
|
// case MsgEnum.HEADS.MSG_homework: // 作业|活动-布置 不处理
|
||||||
if (!content.classWorkId) return
|
case MsgEnum.HEADS.MSG_pushSreen_work: // 打开-作业|活动
|
||||||
Homework.showHomework(content.classWorkId)
|
if (!content.id) return
|
||||||
|
Homework.showHomework(content.id)
|
||||||
|
break
|
||||||
|
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 打开实验:
|
||||||
|
if (!content.url) return
|
||||||
|
dialogUtils.openLink(content.url)
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_closed: // 下课:
|
case MsgEnum.HEADS.MSG_closed: // 下课:
|
||||||
close()
|
close()
|
||||||
|
@ -130,4 +142,4 @@ export default () => {
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,6 +25,12 @@
|
||||||
<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 />
|
||||||
|
@ -157,6 +163,10 @@ const type = ref<WorkType[]>([
|
||||||
{
|
{
|
||||||
label: '框架梳理',
|
label: '框架梳理',
|
||||||
value: 'primary'
|
value: 'primary'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '科学实验',
|
||||||
|
value: 'primary'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="tools-right" :class="{ 'visible': rightToolsVisible }"
|
class="tools-right" :class="{ 'visible': rightToolsVisible }"
|
||||||
@mouseleave="rightToolsVisible = false"
|
@mouseleave="toolTrigger('leave')"
|
||||||
@mouseenter="rightToolsVisible = true"
|
@mouseenter="toolTrigger('enter')"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
@ -50,6 +50,10 @@
|
||||||
<IconPower class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
|
<IconPower class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
|
||||||
<IconPower class="tool-btn close" v-if="chat.groupid" v-tooltip="'结束课堂'" @click="exitCourse()" />
|
<IconPower class="tool-btn close" v-if="chat.groupid" v-tooltip="'结束课堂'" @click="exitCourse()" />
|
||||||
</div>
|
</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>
|
||||||
</template>
|
</template>
|
||||||
|
@ -71,6 +75,7 @@ import WritingBoardTool from './WritingBoardTool.vue'
|
||||||
import CountdownTimer from './CountdownTimer.vue'
|
import CountdownTimer from './CountdownTimer.vue'
|
||||||
import emitter from '@/utils/mitt';
|
import emitter from '@/utils/mitt';
|
||||||
import Chat from '../../api/chat' // 聊天
|
import Chat from '../../api/chat' // 聊天
|
||||||
|
import { CircleDoubleDown, CircleDoubleUp } from '@icon-park/vue-next' // icon-park 图标库
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
changeViewMode: (mode: 'base' | 'presenter') => void
|
changeViewMode: (mode: 'base' | 'presenter') => void
|
||||||
|
@ -103,12 +108,15 @@ const { exitScreening } = useScreening()
|
||||||
const { fullscreenState, manualExitFullscreen } = useFullscreen()
|
const { fullscreenState, manualExitFullscreen } = useFullscreen()
|
||||||
const chat:any = Chat() // 聊天室
|
const chat:any = Chat() // 聊天室
|
||||||
|
|
||||||
|
const screenStore =useScreenStore()
|
||||||
const rightToolsVisible = ref(false)
|
const rightToolsVisible = ref(false)
|
||||||
const writingBoardToolVisible = ref(false)
|
const writingBoardToolVisible = ref(false)
|
||||||
const timerlVisible = ref(false)
|
const timerlVisible = ref(false)
|
||||||
const slideThumbnailModelVisible = ref(false)
|
const slideThumbnailModelVisible = ref(false)
|
||||||
const laserPen = ref(false)
|
const laserPen = ref(false)
|
||||||
const screenStore =useScreenStore()
|
const timer = ref(0) // 记录操作时间
|
||||||
|
const iconHide = ref(false) // 工具栏图标是否显示
|
||||||
|
const timerId = ref(null) // 定时器id
|
||||||
const contextmenus = (): ContextmenuItem[] => {
|
const contextmenus = (): ContextmenuItem[] => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -191,6 +199,30 @@ const contextmenus = (): ContextmenuItem[] => {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toolTrigger = (type:string) => {
|
||||||
|
const curT = Date.now()
|
||||||
|
if (curT - timer.value < 200) return
|
||||||
|
iconHide.value = false // 显示图标按钮
|
||||||
|
if (timerId.value) clearTimeout(timerId.value) // 清除定时器
|
||||||
|
switch (type) {
|
||||||
|
case 'icon': // 点击图标
|
||||||
|
timer.value = curT
|
||||||
|
rightToolsVisible.value = !rightToolsVisible.value
|
||||||
|
break
|
||||||
|
case 'enter': // 移入
|
||||||
|
timer.value = curT
|
||||||
|
rightToolsVisible.value = true
|
||||||
|
break
|
||||||
|
case 'leave': // 移出
|
||||||
|
rightToolsVisible.value = false
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
timerId.value = setTimeout(() => { // 定时器
|
||||||
|
iconHide.value = true // 隐藏图标按钮
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
// 下课
|
// 下课
|
||||||
const exitCourse = async () => {
|
const exitCourse = async () => {
|
||||||
// console.log('下课', chat)
|
// console.log('下课', chat)
|
||||||
|
@ -253,6 +285,18 @@ 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%;
|
||||||
|
|
|
@ -6,8 +6,13 @@ 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 emitter from '@/utils/mitt';
|
||||||
|
import Chat from '../../../api/chat' // 聊天封装
|
||||||
|
// import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
|
// import { MsgEnum } from '../../../api/types' // 消息枚举
|
||||||
|
|
||||||
export default () => {
|
export default (isLoader?: boolean = true) => {
|
||||||
|
// isLoader 是否执行 onMounted, onUnmounted
|
||||||
|
const chatApi = Chat()
|
||||||
const slidesStore = useSlidesStore()
|
const slidesStore = useSlidesStore()
|
||||||
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
const classcourseStore = useClasscourseStore() // 课堂信息-状态管理
|
||||||
const { slides, slideIndex, formatedAnimations, animationIndex } = storeToRefs(slidesStore)
|
const { slides, slideIndex, formatedAnimations, animationIndex } = storeToRefs(slidesStore)
|
||||||
|
@ -71,14 +76,15 @@ export default () => {
|
||||||
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 = () => {
|
||||||
|
@ -142,7 +148,6 @@ export default () => {
|
||||||
inAnimation.value = false
|
inAnimation.value = false
|
||||||
}
|
}
|
||||||
const execNext = (isAsync: boolean) => {
|
const execNext = (isAsync: boolean) => {
|
||||||
console.log('execNext', isAsync)
|
|
||||||
if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
|
if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
|
||||||
runAnimation(isAsync)
|
runAnimation(isAsync)
|
||||||
}
|
}
|
||||||
|
@ -178,8 +183,7 @@ export default () => {
|
||||||
// 鼠标滚动翻页
|
// 鼠标滚动翻页
|
||||||
const mousewheelListener = (e: WheelEvent) => {
|
const mousewheelListener = (e: WheelEvent) => {
|
||||||
// console.log('mousewheel', e)
|
// console.log('mousewheel', e)
|
||||||
// 课堂信息存在时,不允许翻页
|
e.preventDefault() // 阻止默认事件
|
||||||
if (!!classcourseStore.classcourse) e.preventDefault()
|
|
||||||
mousewheelListenerThrottle(e)
|
mousewheelListenerThrottle(e)
|
||||||
}
|
}
|
||||||
const mousewheelListenerThrottle = throttle(function(e: WheelEvent) {
|
const mousewheelListenerThrottle = throttle(function(e: WheelEvent) {
|
||||||
|
@ -210,12 +214,17 @@ export default () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 向上翻页/向下翻页
|
// 向上翻页/向下翻页
|
||||||
const turning = (e, type) => {
|
const turning = async (e, type) => {
|
||||||
e.preventDefault() // 阻止默认事件
|
e.preventDefault() // 阻止默认事件
|
||||||
// 课堂信息存在时,不允许翻页
|
|
||||||
if (!!classcourseStore.classcourse) return
|
|
||||||
if (type === 'prev') execPrev()
|
if (type === 'prev') execPrev()
|
||||||
else if (type === 'next') execNext()
|
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) => {
|
||||||
|
@ -230,10 +239,11 @@ export default () => {
|
||||||
key === KEYS.PAGEDOWN
|
key === KEYS.PAGEDOWN
|
||||||
) turning(e, 'next')
|
) turning(e, 'next')
|
||||||
}
|
}
|
||||||
|
if (isLoader) { // 加载相关钩子
|
||||||
onMounted(() => {document.addEventListener('keydown', keydownListener)})
|
onMounted(() => {document.addEventListener('keydown', keydownListener)})
|
||||||
onUnmounted(() => {document.removeEventListener('keydown', keydownListener)})
|
onUnmounted(() => {document.removeEventListener('keydown', keydownListener)})
|
||||||
|
}
|
||||||
|
|
||||||
// 切换到上一张/上一张幻灯片(无视元素的入场动画)
|
// 切换到上一张/上一张幻灯片(无视元素的入场动画)
|
||||||
const turnPrevSlide = () => {
|
const turnPrevSlide = () => {
|
||||||
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
slidesStore.updateSlideIndex(slideIndex.value - 1)
|
||||||
|
|
|
@ -2,6 +2,8 @@ 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({
|
||||||
|
@ -42,7 +44,7 @@ export function getPicture(data) {
|
||||||
// 大模型对话生成prompt模板
|
// 大模型对话生成prompt模板
|
||||||
export function chattoprompt(dataset_id,prompt) {
|
export function chattoprompt(dataset_id,prompt) {
|
||||||
return axios({
|
return axios({
|
||||||
url: '/api/v1/parse/docs',
|
url: rootPath + '/api/v1/parse/docs',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
|
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
|
||||||
|
@ -68,7 +70,7 @@ export function textSensitiveWord(data) {
|
||||||
// 图片上传资源库
|
// 图片上传资源库
|
||||||
export function uploadPicture(data) {
|
export function uploadPicture(data) {
|
||||||
return axios({
|
return axios({
|
||||||
url: '/dev-api/smarttalk/file/upload',
|
url: import.meta.env.VITE_APP_BASE_API + '/smarttalk/file/upload',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': '*/*',
|
'Accept': '*/*',
|
||||||
|
|
|
@ -95,3 +95,11 @@ export function getCourseTeachingMsg(id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setPaging(data) {
|
||||||
|
return request({
|
||||||
|
url: '/education/classcourse/record/paging',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
After Width: | Height: | Size: 520 KiB |
|
@ -0,0 +1,333 @@
|
||||||
|
<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>
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
<!--
|
||||||
|
依赖: 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)">X</div>
|
||||||
|
<div class="header-btn"></div>
|
||||||
|
<ViewerItem :gridPicList="gridPicList" :index="index" :images="element"></ViewerItem>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
<div v-if="showToolbar" class="grid-pic-toolbar">
|
||||||
|
<el-input style="width: 500px" v-model="inputValue" type="text" />
|
||||||
|
<el-button 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: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 获取图片样式
|
||||||
|
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 = (src) => {
|
||||||
|
if (gridPicList.value.length >= 9) {
|
||||||
|
console.log("超出九个图片")
|
||||||
|
emits('outIndex')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!src) {
|
||||||
|
console.log("图片链接不能为空")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gridPicList.value.push({
|
||||||
|
src: src,
|
||||||
|
backgroundColor: getRandomColor()
|
||||||
|
})
|
||||||
|
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>
|
|
@ -0,0 +1,144 @@
|
||||||
|
<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%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -59,6 +59,7 @@ 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
|
||||||
|
@ -77,6 +78,14 @@ const props = defineProps({
|
||||||
type: {
|
type: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1
|
default: 1
|
||||||
|
},
|
||||||
|
curMode:{
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
conversation_id: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -100,7 +109,8 @@ const curNode = reactive({})
|
||||||
const params = reactive(
|
const params = reactive(
|
||||||
{
|
{
|
||||||
prompt: '',
|
prompt: '',
|
||||||
dataset_id: ''
|
dataset_id: '',
|
||||||
|
template: ''
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -108,7 +118,24 @@ 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}进行教学分析`
|
||||||
const { data } = await completion(params)
|
params.template = props.item.prompt
|
||||||
|
|
||||||
|
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',
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
<!--编辑结果-->
|
<!--编辑结果-->
|
||||||
<EditDialog v-model="isEdit" :item="editItem" />
|
<EditDialog v-model="isEdit" :item="editItem" />
|
||||||
<!--AI 对话调整-->
|
<!--AI 对话调整-->
|
||||||
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" />
|
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" :curMode="curMode" :conversation_id="conversation_id"/>
|
||||||
<!--添加、编辑提示词-->
|
<!--添加、编辑提示词-->
|
||||||
<keywordDialog v-model="isWordDialog" :item="editItem" />
|
<keywordDialog v-model="isWordDialog" :item="editItem" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -104,7 +104,7 @@ import { cloneDeep } from 'lodash'
|
||||||
const props = defineProps(['type'])
|
const props = defineProps(['type'])
|
||||||
const { user } = useUserStore()
|
const { user } = useUserStore()
|
||||||
|
|
||||||
const curMode = ref(1)
|
const curMode = ref(2)
|
||||||
const modeOptions = ref([
|
const modeOptions = ref([
|
||||||
{
|
{
|
||||||
label: '教学大模型',
|
label: '教学大模型',
|
||||||
|
@ -205,7 +205,7 @@ const scrollToBottom = (height, index) => {
|
||||||
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)
|
||||||
|
@ -240,7 +240,7 @@ const changeTemplate = (val) => {
|
||||||
const removeItem = async (item, isChild) => {
|
const removeItem = async (item, isChild) => {
|
||||||
/**
|
/**
|
||||||
* item: 当前操作的模板
|
* item: 当前操作的模板
|
||||||
* isChild: 子模板中的移除为 true
|
* isChild: 子模板中的移除为 true
|
||||||
*/
|
*/
|
||||||
if (item.ex3 != '1') {
|
if (item.ex3 != '1') {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
|
@ -320,10 +320,10 @@ const againResult = async (index, item) => {
|
||||||
str = str.replace('{模板内容}',item.prompt)
|
str = str.replace('{模板内容}',item.prompt)
|
||||||
params.prompt = str
|
params.prompt = str
|
||||||
params.template = item.prompt
|
params.template = item.prompt
|
||||||
|
|
||||||
let data = null;
|
let data = null;
|
||||||
// 教学大模型
|
// 教学大模型
|
||||||
if (mode.value == 1) {
|
if (curMode.value == 1) {
|
||||||
const res = await sendChart({
|
const res = await sendChart({
|
||||||
content: params.prompt,
|
content: params.prompt,
|
||||||
conversationId: conversation_id.value,
|
conversationId: conversation_id.value,
|
||||||
|
@ -606,4 +606,4 @@ onUnmounted(() => {
|
||||||
width: 110px !important;
|
width: 110px !important;
|
||||||
min-width: 110px !important;
|
min-width: 110px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="blockBox">
|
<div class="blockBox">
|
||||||
<el-button @click="currentType = 'selection'"><el-image src="../../../src/assets/images/mouse-pointer.png"
|
<el-button @click="currentType = 'selection'"><el-image :src="pointerImg"
|
||||||
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="../../../src/assets/images/borderwidth.png"
|
<el-button><el-image :src="borderImg"
|
||||||
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>
|
||||||
|
@ -303,6 +303,9 @@ 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 props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|
|
@ -38,6 +38,7 @@ 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(() => {
|
||||||
|
@ -54,7 +55,11 @@ 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%;
|
||||||
|
@ -81,4 +86,4 @@ onMounted(() =>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/**
|
||||||
|
* 无限滚动
|
||||||
|
*/
|
||||||
|
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){
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ export const editListItem = (row, courseObj) => {
|
||||||
worktype: '', // 设计中的作业类型
|
worktype: '', // 设计中的作业类型
|
||||||
quizlist: [], // 设计中的试题列表
|
quizlist: [], // 设计中的试题列表
|
||||||
chooseWorkLists: [],// 设计中的框架梳理list
|
chooseWorkLists: [],// 设计中的框架梳理list
|
||||||
fileHomeworkList: [],// 设计中的常规作业list
|
fileHomeworkList: [],//TODO 暂时共用这个字段(新增了 科学实验) 设计中的常规作业list
|
||||||
whiteboardObj: '',// 设计中的课堂展示对象
|
whiteboardObj: '',// 设计中的课堂展示对象
|
||||||
question: '', // 设计中的[课堂展示]的问题
|
question: '', // 设计中的[课堂展示]的问题
|
||||||
};
|
};
|
||||||
|
@ -58,7 +58,7 @@ export const editListItem = (row, courseObj) => {
|
||||||
|
|
||||||
|
|
||||||
if (row.worktype == '框架梳理') {
|
if (row.worktype == '框架梳理') {
|
||||||
// 框架梳理对应只有一个内容
|
// 框架梳理对应只有一个内容
|
||||||
getEvaluationclue(listCourseWork[0].id).then(res => {
|
getEvaluationclue(listCourseWork[0].id).then(res => {
|
||||||
if ( res.data==null || res.data==undefined ) {
|
if ( res.data==null || res.data==undefined ) {
|
||||||
return ;
|
return ;
|
||||||
|
@ -112,6 +112,16 @@ export const editListItem = (row, courseObj) => {
|
||||||
return resolve(classtaskObj);
|
return resolve(classtaskObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (row.worktype == '科学实验') {
|
||||||
|
if(isJson(row.workcodes)){
|
||||||
|
classtaskObj.fileHomeworkList = JSON.parse(row.workcodes);
|
||||||
|
//
|
||||||
|
// console.log('科学实验', classtaskObj);
|
||||||
|
// 更新默认的科学实验( 学段 学科 以及实验科目)
|
||||||
|
console.log('科学实验', classtaskObj);
|
||||||
|
return resolve(classtaskObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,8 @@ const getHomeWorkList = async () => {
|
||||||
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 = 'danger';
|
||||||
} else {
|
} else {
|
||||||
res.rows[i].workclass = 'primary';
|
res.rows[i].workclass = 'primary';
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,9 @@ import { ref, watch , reactive, onMounted, onBeforeMount, 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 { sessionStore } from '@/utils/store'
|
|
||||||
import pkc from "../../../../../package.json"
|
import pkc from "../../../../../package.json"
|
||||||
import defaultUserImg from '@/assets/images/img-avatar.png'
|
import defaultUserImg from '@/assets/images/img-avatar.png'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
|
||||||
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
@ -84,7 +84,7 @@ const isStadium = () => {
|
||||||
|
|
||||||
const headerMenus = isStadium() ?[{
|
const headerMenus = isStadium() ?[{
|
||||||
name: '教学实践',
|
name: '教学实践',
|
||||||
id: 4,
|
id: 6,
|
||||||
icon: 'icon-jiaoxueshijian',
|
icon: 'icon-jiaoxueshijian',
|
||||||
path: '/prepare'
|
path: '/prepare'
|
||||||
},]:[
|
},]:[
|
||||||
|
@ -94,12 +94,12 @@ const headerMenus = isStadium() ?[{
|
||||||
icon: 'icon-shouye',
|
icon: 'icon-shouye',
|
||||||
path: '/model/index'
|
path: '/model/index'
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: '教学工作台',
|
// name: '教学工作台',
|
||||||
id: 2,
|
// id: 2,
|
||||||
icon: 'icon-gongzuotai',
|
// icon: 'icon-gongzuotai',
|
||||||
path: '/desktop'
|
// path: '/desktop'
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
name: '教学实践',
|
name: '教学实践',
|
||||||
id: 4,
|
id: 4,
|
||||||
|
@ -182,9 +182,9 @@ watch(
|
||||||
|
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
const hasClass = sessionStore.has('activeClass.id')
|
|
||||||
const hasTool = sessionStore.get('isToolWin')
|
if(!!sessionStore.get('curr.classcourse'))return ElMessage.warning('当前正在上课,请先结束上课')
|
||||||
if (hasClass || hasTool) return ElMessage.warning('当前正在上课,请先结束上课')
|
|
||||||
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
|
|
|
@ -24,7 +24,6 @@ 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:{}
|
||||||
|
|
|
@ -98,6 +98,10 @@ export class MsgEnum {
|
||||||
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
MSG_classlecturePagesrc : 'classlecturePagesrc',
|
||||||
/** @desc: 课堂作业|活动 */
|
/** @desc: 课堂作业|活动 */
|
||||||
MSG_homework : 'HOMEWORK',
|
MSG_homework : 'HOMEWORK',
|
||||||
|
/** @desc: 公屏 - 课堂作业|活动 */
|
||||||
|
MSG_pushSreen_work : 'pushSreen_work',
|
||||||
|
/** @desc: 公屏 - 实验 */
|
||||||
|
MSG_pushSreen_experiment : 'pushSreen_experiment',
|
||||||
/** @desc: 点赞 */
|
/** @desc: 点赞 */
|
||||||
MSG_dz : 'dz',
|
MSG_dz : 'dz',
|
||||||
/** @desc: 疑惑 */
|
/** @desc: 疑惑 */
|
||||||
|
|
|
@ -31,6 +31,11 @@ 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,
|
||||||
|
|
|
@ -5,6 +5,11 @@ import { JYApiListCT, JYApiListOriginYear, JYApiListSO} from "@/utils/examQuesti
|
||||||
|
|
||||||
const useClassTaskStore = defineStore('classTask',{
|
const useClassTaskStore = defineStore('classTask',{
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
experimentObj:{
|
||||||
|
edustage: '小学', // 教育阶段
|
||||||
|
edusubject: '', // 学科
|
||||||
|
experimentList: [], // 实验科目列表
|
||||||
|
},
|
||||||
isOpenQuestUploadView: false, // 是否打开习题上传的页面
|
isOpenQuestUploadView: false, // 是否打开习题上传的页面
|
||||||
classListIds: [],
|
classListIds: [],
|
||||||
entpCourseWorkTypeList: [
|
entpCourseWorkTypeList: [
|
||||||
|
|
|
@ -49,10 +49,10 @@ export function blobToFile(blob, fileName, contentType) {
|
||||||
/**
|
/**
|
||||||
* @description 计算两点直线距离 (获取直径)
|
* @description 计算两点直线距离 (获取直径)
|
||||||
* (欧几里得距离公式): [ \text{distance} = \sqrt{(x2 - x1)^2 + (y2 - y1)^2} ]
|
* (欧几里得距离公式): [ \text{distance} = \sqrt{(x2 - x1)^2 + (y2 - y1)^2} ]
|
||||||
* @param {*} x1
|
* @param {*} x1
|
||||||
* @param {*} y1
|
* @param {*} y1
|
||||||
* @param {*} x2
|
* @param {*} x2
|
||||||
* @param {*} y2
|
* @param {*} y2
|
||||||
*/
|
*/
|
||||||
export function getDistance(x1,y1,x2,y2) {
|
export function getDistance(x1,y1,x2,y2) {
|
||||||
return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2))
|
return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2))
|
||||||
|
@ -62,10 +62,10 @@ export function getRadius(x1,y1,x2,y2) { return getDistance(x1,y1,x2,y2) / 2 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算某个值在总数中所占的百分比。
|
* 计算某个值在总数中所占的百分比。
|
||||||
*
|
*
|
||||||
* 此函数用于根据给定的值和总数,计算该值占总数的百分比。它还支持指定百分比的小数位数。
|
* 此函数用于根据给定的值和总数,计算该值占总数的百分比。它还支持指定百分比的小数位数。
|
||||||
* 如果计算结果小于0,则返回0;如果大于100,则返回100,以确保百分比的合理范围。
|
* 如果计算结果小于0,则返回0;如果大于100,则返回100,以确保百分比的合理范围。
|
||||||
*
|
*
|
||||||
* @param {number} v - 待计算的值。
|
* @param {number} v - 待计算的值。
|
||||||
* @param {number} total - 总数。
|
* @param {number} total - 总数。
|
||||||
* @param {number} [step=2] - 百分比的小数位数,默认为2。
|
* @param {number} [step=2] - 百分比的小数位数,默认为2。
|
||||||
|
@ -76,7 +76,7 @@ export function getPercent(v, total, step=2) {
|
||||||
!total && (total = 1)
|
!total && (total = 1)
|
||||||
// 计算百分比,保留指定的小数位,并转换为数字类型
|
// 计算百分比,保留指定的小数位,并转换为数字类型
|
||||||
let res = (v / total * 100).toFixed(step)-0
|
let res = (v / total * 100).toFixed(step)-0
|
||||||
|
|
||||||
// 确保百分比在0到100之间
|
// 确保百分比在0到100之间
|
||||||
return res < 0 ? 0 : res > 100 ? 100 : res
|
return res < 0 ? 0 : res > 100 ? 100 : res
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ export function getPercent(v, total, step=2) {
|
||||||
* @param {*} start 前面保留几位 默认 3位
|
* @param {*} start 前面保留几位 默认 3位
|
||||||
* @param {*} end 后面保留几位 默认 3位
|
* @param {*} end 后面保留几位 默认 3位
|
||||||
* @param {*} rstr 替换字符 默认 ****
|
* @param {*} rstr 替换字符 默认 ****
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function phoneHideFormat(phone, start = 3, end = 4, rstr = '****') {
|
export function phoneHideFormat(phone, start = 3, end = 4, rstr = '****') {
|
||||||
// const reg = /^(\d{3})\d*(\d{4})$/
|
// const reg = /^(\d{3})\d*(\d{4})$/
|
||||||
|
@ -101,8 +101,8 @@ export function phoneHideFormat(phone, start = 3, end = 4, rstr = '****') {
|
||||||
// ============= 习题工具--相关 ===================
|
// ============= 习题工具--相关 ===================
|
||||||
/**
|
/**
|
||||||
* @description 将字符串转换为数组
|
* @description 将字符串转换为数组
|
||||||
* @param {*} str
|
* @param {*} str
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function quizStrToList(str = '') {
|
export function quizStrToList(str = '') {
|
||||||
if (!str) return []
|
if (!str) return []
|
||||||
|
@ -175,8 +175,8 @@ export const validateUrl = (url) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 时间 秒 转化 时分秒
|
* @description 时间 秒 转化 时分秒
|
||||||
* @param {*} seconds
|
* @param {*} seconds
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function formatTime(seconds) {
|
export function formatTime(seconds) {
|
||||||
seconds = parseInt(seconds) // 转换整数
|
seconds = parseInt(seconds) // 转换整数
|
||||||
|
@ -188,9 +188,9 @@ export function formatTime(seconds) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 时间格式化
|
* @description 时间格式化
|
||||||
* @param {*} time
|
* @param {*} time
|
||||||
* @param {*} fmt
|
* @param {*} fmt
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function formatDate(time, fmt = 'yyyy-MM-dd') {
|
export function formatDate(time, fmt = 'yyyy-MM-dd') {
|
||||||
let date
|
let date
|
||||||
|
@ -300,7 +300,7 @@ export function getDateStr1(num, fmt = 'yyyy-MM-dd hh:mm:ss') {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取当前 0:0:0:0 时间
|
* 获取当前 0:0:0:0 时间
|
||||||
* @param {*} [fmt] 格式 'yyyy-MM-dd hh:mm:ss'
|
* @param {*} [fmt] 格式 'yyyy-MM-dd hh:mm:ss'
|
||||||
*/
|
*/
|
||||||
export function getDateNow(fmt) {
|
export function getDateNow(fmt) {
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
|
@ -339,9 +339,9 @@ export function timeToStr(time,str = '时分秒', isPad = false) {
|
||||||
* debounce(() => {
|
* debounce(() => {
|
||||||
console.log('Input event handled');
|
console.log('Input event handled');
|
||||||
}, 300);
|
}, 300);
|
||||||
* @param {*} func
|
* @param {*} func
|
||||||
* @param {*} wait
|
* @param {*} wait
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function debounce(func, wait) {
|
export function debounce(func, wait) {
|
||||||
let timeout;
|
let timeout;
|
||||||
|
@ -358,9 +358,9 @@ export function debounce(func, wait) {
|
||||||
* throttle(() => {
|
* throttle(() => {
|
||||||
console.log('Scroll event handled');
|
console.log('Scroll event handled');
|
||||||
}, 300);
|
}, 300);
|
||||||
* @param {*} func
|
* @param {*} func
|
||||||
* @param {*} wait
|
* @param {*} wait
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function throttle(func, wait) {
|
export function throttle(func, wait) {
|
||||||
let lastTime = 0;
|
let lastTime = 0;
|
||||||
|
@ -376,7 +376,7 @@ export function throttle(func, wait) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 大模型对话dataset_id
|
* 大模型对话dataset_id
|
||||||
*/
|
*/
|
||||||
export const dataSetJson = {
|
export const dataSetJson = {
|
||||||
|
@ -403,5 +403,11 @@ export const dataSetJson = {
|
||||||
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
||||||
"教材-高中-地理": "270516829fd111efb13c0242ac140006",
|
"教材-高中-地理": "270516829fd111efb13c0242ac140006",
|
||||||
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
||||||
|
"课标-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
||||||
|
"课标-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
||||||
|
"课标-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
||||||
|
"教材-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
||||||
|
"教材-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
||||||
|
"教材-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
||||||
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 弹窗-函数
|
||||||
|
*/
|
||||||
|
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',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,734 @@
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,24 +57,31 @@ 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: "'素材'"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '习题库',
|
id:3,
|
||||||
value: '习题',
|
label: '实验室',
|
||||||
disabled: true
|
value: "'素材'"
|
||||||
}
|
},
|
||||||
|
// {
|
||||||
|
// 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
|
||||||
|
|
|
@ -248,10 +248,11 @@ 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, '/resources/logo2.ico'),
|
icon: path.join(appPath, logoIco),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(API.preloadPath, '/index.js'),
|
preload: path.join(API.preloadPath, '/index.js'),
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
|
|
|
@ -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">
|
<div class="class-reserv-body" v-infinite-scroll="load">
|
||||||
<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,13 +22,14 @@
|
||||||
@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 } from 'vue'
|
import { ref, onMounted, computed, watch, reactive } 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'
|
||||||
|
@ -36,6 +37,7 @@ 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()
|
||||||
|
|
||||||
|
@ -44,6 +46,12 @@ 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()
|
||||||
|
@ -72,21 +80,42 @@ const deleteReserv = (item) => {
|
||||||
})*/
|
})*/
|
||||||
// 获取数据
|
// 获取数据
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
Promise.all([listClasscourseNew({teacherid: userStore.id,evalid: props.curNode.id,pageSize:1000}), getSelfReserv({ex2:props.curNode.id})]).then(([res1,res2])=>{
|
const { pageNum, pageSize } = page
|
||||||
let list = res2.data || []
|
const params = {
|
||||||
let list2 = res1.rows || []
|
evalid: props.curNode.id,
|
||||||
// list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
|
teacherid: userStore.id,
|
||||||
list = list.concat(list2)
|
pageNum, pageSize
|
||||||
|
}
|
||||||
|
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 = list
|
dataList.value.push(...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],
|
||||||
() => {
|
() => {
|
||||||
|
@ -96,13 +125,14 @@ 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;
|
||||||
|
|
|
@ -141,7 +141,8 @@
|
||||||
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">
|
||||||
|
@ -157,7 +158,8 @@
|
||||||
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 ->
|
||||||
|
@ -210,7 +212,13 @@
|
||||||
|
|
||||||
<!-- 学生答题展示 -->
|
<!-- 学生答题展示 -->
|
||||||
<div v-if="feedContentList.length > 0">
|
<div v-if="feedContentList.length > 0">
|
||||||
<div v-if="dialogProps.studentObj.worktype == '常规作业' && stuItem.rightanswer != ''&& stuItem.rightanswer != null">
|
<div
|
||||||
|
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>
|
||||||
|
@ -700,30 +708,34 @@ const acceptParams = async (params) => {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 学生回答
|
// 学生回答
|
||||||
if (params.studentObj.worktype == '常规作业') {
|
if (params.studentObj.worktype == '常规作业' || params.studentObj.worktype == '科学实验') {
|
||||||
try {
|
if(params.studentObj.worktype == '常规作业'){
|
||||||
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
try {
|
||||||
const res = await getClassworkdata(params.studentObj.id);
|
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
||||||
if(res.data.datacontent != ''){
|
const res = await getClassworkdata(params.studentObj.id);
|
||||||
const teachWorkFileList = JSON.parse(res.data.datacontent);
|
if(res.data.datacontent != ''){
|
||||||
console.log(teachWorkFileList, '老师filelist-------------')
|
const teachWorkFileList = JSON.parse(res.data.datacontent);
|
||||||
teachWorkFileList &&
|
console.log(teachWorkFileList, '老师filelist-------------')
|
||||||
teachWorkFileList.forEach((item) => {
|
teachWorkFileList &&
|
||||||
if (
|
teachWorkFileList.forEach((item) => {
|
||||||
item.name.indexOf('jpg') > -1 ||
|
if (
|
||||||
item.name.indexOf('jpeg') > -1 ||
|
item.name.indexOf('jpg') > -1 ||
|
||||||
item.name.indexOf('png') > -1
|
item.name.indexOf('jpeg') > -1 ||
|
||||||
) {
|
item.name.indexOf('png') > -1
|
||||||
teachImageList.value.push(item)
|
) {
|
||||||
} else {
|
teachImageList.value.push(item)
|
||||||
teachFileList.value.push(item)
|
} else {
|
||||||
}
|
teachFileList.value.push(item)
|
||||||
})
|
}
|
||||||
teacherFeedContentList.value.push(teachWorkFileList)
|
})
|
||||||
}
|
teacherFeedContentList.value.push(teachWorkFileList)
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Invalid JSON:', error)
|
console.error('Invalid JSON:', error)
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// TODO 科学实验 老师布置的活动 暂时不在批改中显示 2024-12-20
|
||||||
}
|
}
|
||||||
|
|
||||||
params.studentQuizAllList.forEach((item) => {
|
params.studentQuizAllList.forEach((item) => {
|
||||||
|
|
|
@ -30,13 +30,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:'primary' },
|
{ title: '自主搜题', description: '上千万高质量习题资源,历届考试真题,每道题均有习题解析', icon: '#icon-soutibao-',type:'primary' },
|
||||||
{ title: '校本题库', description: '本校公共题库资源。', icon: '#icon-soutibao-',type:'primary' },
|
// { title: '校本题库', description: '本校公共题库资源。', icon: '#icon-soutibao-',type:'primary' },
|
||||||
{ title: '个人题库', description: '老师上传维护自己的个人题库。', icon: '#icon-soutibao-',type:'primary' },
|
{ 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:'danger' },
|
{ title: '课堂展示', description: '通过课堂白板绘制作业,提升学生的创作思维能力。', icon: '#icon-huaban',type:'danger' },
|
||||||
{ title: '常规作业', description: '推送pdf、视频、音频、图片,学生可以拍照上传。', icon: '#icon-zhaoxiangji',type:'danger' },
|
{ 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:'danger' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleClick = (item) => {
|
const handleClick = (item) => {
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<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('')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSelectOption = (option) => {
|
||||||
|
console.log(option,'选择的实验课-------')
|
||||||
|
emit('selectItem', classTaskStore.experimentList.filter(item => item.label === option)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
<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 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');
|
||||||
|
// 默认读取一个学科
|
||||||
|
handleUserEduStage(useClassTaskStore().experimentObj.edustage)
|
||||||
|
}
|
||||||
|
// 展示有 实验科目的学科
|
||||||
|
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;
|
||||||
|
// 更改学科默认与学科下的实验科目
|
||||||
|
handleUserEduSubject(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}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;
|
||||||
|
// 更改学科默认与学科下的实验科目
|
||||||
|
handleUserEduSubject(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}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;
|
||||||
|
// 更改学科默认与学科下的实验科目
|
||||||
|
handleUserEduSubject(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 选择学科
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getSubject()
|
||||||
|
})
|
||||||
|
</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>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
<template>
|
||||||
|
<div class="experiment-page">
|
||||||
|
<div class="activeExp-header">
|
||||||
|
<div class="infomation" v-if="isStadium() !== true" >
|
||||||
|
<!-- <selectClass v-if="!isSubject" @experlist="getExperimentList" /> -->
|
||||||
|
<selectClass v-if="!isSubject" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<selectExperiment @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 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;
|
||||||
|
})
|
||||||
|
|
||||||
|
</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>
|
||||||
|
@ -77,6 +77,11 @@
|
||||||
<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" >
|
||||||
|
@ -140,6 +145,7 @@ 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'
|
||||||
|
@ -194,7 +200,7 @@ const fileLoading = ref(false); // 常规作业loading
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
console.log("----onMounted-------")
|
console.log("----onMounted-------")
|
||||||
currentRow.value = {id:0};
|
currentRow.value.id = 0
|
||||||
if(propsQueryCourseObj){
|
if(propsQueryCourseObj){
|
||||||
if(JSON.parse(propsQueryCourseObj)){
|
if(JSON.parse(propsQueryCourseObj)){
|
||||||
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // 版本
|
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // 版本
|
||||||
|
@ -229,7 +235,7 @@ const isInToMyQuestion = () => {
|
||||||
if(useClassTaskStores.isOpenQuestUploadView){
|
if(useClassTaskStores.isOpenQuestUploadView){
|
||||||
useClassTaskStores.isOpenQuestUploadView = false;
|
useClassTaskStores.isOpenQuestUploadView = false;
|
||||||
|
|
||||||
currentRow.value = {id:1}; // 作业设计
|
currentRow.value.id = 1; // 作业设计
|
||||||
activeAptTab.value = "个人题库";
|
activeAptTab.value = "个人题库";
|
||||||
//提交内容清空 重置
|
//提交内容清空 重置
|
||||||
classWorkForm.id = 0;
|
classWorkForm.id = 0;
|
||||||
|
@ -258,6 +264,16 @@ 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);
|
||||||
|
@ -266,7 +282,7 @@ const handleItemClick = (itemName) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRow.value = {id:1}; // 作业设计
|
currentRow.value.id = 1; // 作业设计
|
||||||
/**
|
/**
|
||||||
* 智能推荐?AI设计作业?
|
* 智能推荐?AI设计作业?
|
||||||
* 习题训练: 自主搜题 校本题库 个人题库
|
* 习题训练: 自主搜题 校本题库 个人题库
|
||||||
|
@ -309,7 +325,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 = ""; // 作业唯一标识 作业名称
|
||||||
|
@ -336,7 +352,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(() => {
|
||||||
|
@ -430,7 +446,7 @@ const handleCurrentChange = (val) => {
|
||||||
|
|
||||||
console.log(val,'???????????')
|
console.log(val,'???????????')
|
||||||
if(val && val.id >0 ) {
|
if(val && val.id >0 ) {
|
||||||
currentRow.value = val;
|
currentRow.value.id = 1;
|
||||||
classWorkForm.worktype = val.worktype; //作业类型
|
classWorkForm.worktype = val.worktype; //作业类型
|
||||||
editListItem(val, courseObj).then((obj) => {
|
editListItem(val, courseObj).then((obj) => {
|
||||||
if(obj){
|
if(obj){
|
||||||
|
@ -582,6 +598,32 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
||||||
fileLoading.value = false
|
fileLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(classWorkForm.worktype === "科学实验"){
|
||||||
|
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验的课程!'});
|
||||||
|
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 = [];
|
||||||
|
@ -628,9 +670,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();
|
||||||
|
|
||||||
|
@ -667,7 +709,10 @@ 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 {
|
}else if( classWorkForm.worktype == '科学实验') {
|
||||||
|
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('请先添加作业资源!');
|
||||||
|
@ -759,13 +804,21 @@ 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);
|
||||||
|
}
|
||||||
|
|
||||||
// 3.更新作业任务本身
|
// 3.更新作业任务本身
|
||||||
let res = await updateClasswork(cform);
|
let res = await updateClasswork(cform);
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
ElMessage.success('更新成功');
|
ElMessage.success('更新成功');
|
||||||
// 清空左侧 选中的布置列表 并刷新列表
|
// 清空左侧 选中的布置列表 并刷新列表
|
||||||
currentRow.value = {id:0};
|
if(isShow.value){
|
||||||
|
currentRow.value.id = 1;
|
||||||
|
}else{
|
||||||
|
currentRow.value.id = 0;
|
||||||
|
}
|
||||||
initHomeWork();
|
initHomeWork();
|
||||||
// // 返回上一页
|
// // 返回上一页
|
||||||
// router.back()
|
// router.back()
|
||||||
|
@ -865,6 +918,11 @@ 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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -721,19 +721,23 @@ const msgHandle = (msg) => {
|
||||||
const { head, content, ...other } = msg
|
const { head, content, ...other } = msg
|
||||||
switch(head) {
|
switch(head) {
|
||||||
case MsgEnum.HEADS.MSG_closed: // 下课:
|
case MsgEnum.HEADS.MSG_closed: // 下课:
|
||||||
Homework.win = null
|
Homework.win = null
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_finishHomework: // 跟新作业:
|
case MsgEnum.HEADS.MSG_finishHomework: // 跟新作业:
|
||||||
console.log('更新作业', head, content)
|
console.log('更新作业', head, content)
|
||||||
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
||||||
openDialog(data, false);
|
openDialog(data, false);
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_slideFlapping: // 切换页面
|
case MsgEnum.HEADS.MSG_slideFlapping: // 切换页面
|
||||||
console.log('切换页面-关闭窗口')
|
console.log('切换页面-关闭窗口')
|
||||||
Homework.win = null
|
Homework.win = null
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
break
|
break
|
||||||
|
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 实验:
|
||||||
|
Homework.win = null
|
||||||
|
window.close() // 关闭窗口
|
||||||
|
break
|
||||||
// case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
// case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
||||||
// {
|
// {
|
||||||
// (data||[]).forEach(o => {
|
// (data||[]).forEach(o => {
|
||||||
|
|
|
@ -0,0 +1,427 @@
|
||||||
|
<template>
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="box-item desc">
|
||||||
|
<div class="welcome">
|
||||||
|
<p>欢迎登录 {{ homeTitle }}</p>
|
||||||
|
</div>
|
||||||
|
<img class="welcome-img" :src="leftBg2" />
|
||||||
|
</div>
|
||||||
|
<div class="box-item login" v-if="isRegister">
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div class="login-title">账号登录</div>
|
||||||
|
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password" style="margin-bottom: 15px">
|
||||||
|
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-5">
|
||||||
|
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||||
|
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-item login" v-else>
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div class="login-title">账号注册</div>
|
||||||
|
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
||||||
|
<el-form-item label="手机号" prop="username">
|
||||||
|
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
||||||
|
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码" prop="password" >
|
||||||
|
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false" align-center>
|
||||||
|
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
||||||
|
status="success" />
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
v-model="isImg"
|
||||||
|
title="人机验证"
|
||||||
|
width="500"
|
||||||
|
style=" -webkit-app-region: no-drag;"
|
||||||
|
>
|
||||||
|
<span>根据图片回答相关问题1</span>
|
||||||
|
<div style="display: flex;align-items: center;;margin-top:30px">
|
||||||
|
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
||||||
|
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;justify-content: center;margin-top:30px">
|
||||||
|
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<!--选择学科-->
|
||||||
|
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
||||||
|
<!--注册弹框-->
|
||||||
|
<Register ref="RegModel"></Register>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import leftBg2 from '@/assets/images/login/left-bg2.png'
|
||||||
|
import WindowTools from '@/components/window-tools/index.vue'
|
||||||
|
import SelectSubject from '@/components/select-subject/index.vue'
|
||||||
|
import Register from './components/Register.vue'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
||||||
|
|
||||||
|
const { session } = require('@electron/remote')
|
||||||
|
const downloadProp = ref(0)
|
||||||
|
const showDownLoading = ref(false)
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
const formRef = ref()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const btnLoading = ref(false)
|
||||||
|
const isSubject = ref(false)
|
||||||
|
const RegModel = ref(false)
|
||||||
|
const isRegister = ref(true)
|
||||||
|
const ruleFormRef = ref(null)
|
||||||
|
const codeName=ref('发送验证码')
|
||||||
|
const timer=ref(null)
|
||||||
|
const isImg=ref(false)
|
||||||
|
const isPeopleImg=ref(null)
|
||||||
|
const type=ref(1) // 1注册 2找回密码
|
||||||
|
const resImg = reactive({ imgData: {} });
|
||||||
|
|
||||||
|
//表单
|
||||||
|
const loginForm = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
rememberMe: false
|
||||||
|
})
|
||||||
|
// 注册表单
|
||||||
|
const ruleForm = reactive({
|
||||||
|
|
||||||
|
})
|
||||||
|
//表单规则
|
||||||
|
const rules = reactive({
|
||||||
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
|
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||||
|
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
||||||
|
})
|
||||||
|
|
||||||
|
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
|
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||||
|
ipcRenderer.on('update-app-progress', (e, prop) => {
|
||||||
|
downloadProp.value = prop
|
||||||
|
showDownLoading.value = prop !== 100
|
||||||
|
})
|
||||||
|
const gotoreRegister=()=>{
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if(timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
isRegister.value=false
|
||||||
|
}
|
||||||
|
// 刷新
|
||||||
|
const refreshImg=()=>{
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
resImg.imgData=res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 提交人机验证
|
||||||
|
const sbmitImg=()=>{
|
||||||
|
if(ruleForm.imgCode){
|
||||||
|
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
||||||
|
const { username:username,imgCode:code } = ruleForm
|
||||||
|
const params = {
|
||||||
|
username, code,
|
||||||
|
uuid: resImg.imgData.uuid,
|
||||||
|
source:4
|
||||||
|
}
|
||||||
|
sendcode(params).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('短信发送成功')
|
||||||
|
ruleForm.Code=res.data
|
||||||
|
isImg.value=false
|
||||||
|
codeName.value=60
|
||||||
|
timer.value=setInterval(()=>{
|
||||||
|
codeName.value--
|
||||||
|
if(codeName.value==0){
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
},1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请根据图片输入验证码')
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// 发送验证码
|
||||||
|
const sendyzm=()=>{
|
||||||
|
if(ruleForm.username){
|
||||||
|
const pattern = /^1[3-9]\d{9}$/;
|
||||||
|
if( pattern.test(ruleForm.username) ){
|
||||||
|
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ruleForm.imgCode=null
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
isImg.value=true
|
||||||
|
resImg.imgData=res
|
||||||
|
// codeName.value=60
|
||||||
|
// timer.value=setInterval(()=>{
|
||||||
|
// codeName.value--
|
||||||
|
// if(codeName.value==0){
|
||||||
|
// codeName.value='发送验证码'
|
||||||
|
// clearInterval(timer.value);
|
||||||
|
// }
|
||||||
|
// },1000)
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入正确的手机号码')
|
||||||
|
}
|
||||||
|
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
||||||
|
// console.log('res->', res)
|
||||||
|
// })
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入手机号码')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 打开弹窗
|
||||||
|
const RegisterModel = type => {
|
||||||
|
RegModel.value.OpenModel(type)
|
||||||
|
}
|
||||||
|
//登录
|
||||||
|
const submitForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
btnLoading.value = true
|
||||||
|
|
||||||
|
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||||
|
if (loginForm.rememberMe) {
|
||||||
|
await setCookie('username', loginForm.username)
|
||||||
|
await setCookie('password', encrypt(loginForm.password))
|
||||||
|
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
||||||
|
} else {
|
||||||
|
// 否则移除
|
||||||
|
await session.defaultSession.clearStorageData({
|
||||||
|
origin: curWinUrl,
|
||||||
|
storages: ['cookies']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await userStore.login(loginForm)
|
||||||
|
await userStore.getInfo()
|
||||||
|
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
ipcRenderer && ipcRenderer.send('openMainWindow')
|
||||||
|
} else {
|
||||||
|
isSubject.value = true
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
btnLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isStadium = (user) => {
|
||||||
|
let roles = user.roles
|
||||||
|
return roles.some(item => item.roleKey === 'stadium')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCookie = async () => {
|
||||||
|
const username = (await getCookieDetail('username'))[0]
|
||||||
|
const password = (await getCookieDetail('password'))[0]
|
||||||
|
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
||||||
|
loginForm.username = username ? username.value : loginForm.username
|
||||||
|
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
||||||
|
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取cookie
|
||||||
|
const getCookieDetail = (name) => {
|
||||||
|
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置cookie
|
||||||
|
const setCookie = (name, value) => {
|
||||||
|
// 30天过期
|
||||||
|
let Days = 30
|
||||||
|
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
||||||
|
const cookie = {
|
||||||
|
url: curWinUrl,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
expirationDate: times
|
||||||
|
}
|
||||||
|
return session.defaultSession.cookies.set(cookie)
|
||||||
|
}
|
||||||
|
const gotoLogin = () => {
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if (timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
isRegister.value = true
|
||||||
|
}
|
||||||
|
// 注册
|
||||||
|
const RegisterForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
instructorregister(ruleForm).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('您已注册成功')
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
gotoLogin()
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('submit!')
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
sessionStore.set('subject', {
|
||||||
|
bookList: null,
|
||||||
|
curBook: null,
|
||||||
|
curNode: null,
|
||||||
|
defaultExpandedKeys: [],
|
||||||
|
subjectTree: []
|
||||||
|
})
|
||||||
|
getCookie()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
|
.box-item {
|
||||||
|
width: 444px;
|
||||||
|
height: 520px;
|
||||||
|
|
||||||
|
&.desc {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px 0px 0px 12px;
|
||||||
|
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
||||||
|
padding: 23px 25px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
background-color: #003b94;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.login {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 0px 12px 12px 0px;
|
||||||
|
padding: 34px 42px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome {
|
||||||
|
padding-top: 35px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 25px;
|
||||||
|
letter-spacing: 0.26px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-img {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #1e1e1e;
|
||||||
|
margin-bottom: 35px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
.captcha-input {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 350px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tool {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,427 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login-container">
|
<ycLogin v-if="buildMode === 'yc'||buildMode === 'yc2'">
|
||||||
<div class="box-item desc">
|
</ycLogin>
|
||||||
<div class="welcome">
|
<defultLogin v-else>
|
||||||
<p>欢迎登录 {{ homeTitle }}</p>
|
</defultLogin>
|
||||||
</div>
|
|
||||||
<img class="welcome-img" :src="leftBg2" />
|
|
||||||
</div>
|
|
||||||
<div class="box-item login" v-if="isRegister">
|
|
||||||
<WindowTools :is-has-max="false" />
|
|
||||||
<div class="login-title">账号登录</div>
|
|
||||||
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
|
||||||
<el-form-item prop="username">
|
|
||||||
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="password" style="margin-bottom: 15px">
|
|
||||||
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
|
||||||
</el-form-item>
|
|
||||||
<div class="flex mb-5">
|
|
||||||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
|
||||||
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
|
||||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="box-item login" v-else>
|
|
||||||
<WindowTools :is-has-max="false" />
|
|
||||||
<div class="login-title">账号注册</div>
|
|
||||||
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
|
||||||
<el-form-item label="手机号" prop="username">
|
|
||||||
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
|
||||||
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="密码" prop="password" >
|
|
||||||
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
|
||||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
|
||||||
:close-on-press-escape="false" align-center>
|
|
||||||
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
|
||||||
status="success" />
|
|
||||||
</el-dialog>
|
|
||||||
<el-dialog
|
|
||||||
v-model="isImg"
|
|
||||||
title="人机验证"
|
|
||||||
width="500"
|
|
||||||
style=" -webkit-app-region: no-drag;"
|
|
||||||
>
|
|
||||||
<span>根据图片回答相关问题1</span>
|
|
||||||
<div style="display: flex;align-items: center;;margin-top:30px">
|
|
||||||
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
|
||||||
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
|
||||||
</div>
|
|
||||||
<div style="display: flex;justify-content: center;margin-top:30px">
|
|
||||||
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
<!--选择学科-->
|
|
||||||
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
|
||||||
<!--注册弹框-->
|
|
||||||
<Register ref="RegModel"></Register>
|
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import ycLogin from './yc-login.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import defultLogin from './defult-login.vue'
|
||||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
const buildMode = import.meta.env.MODE
|
||||||
import useUserStore from '@/store/modules/user'
|
|
||||||
import leftBg2 from '@/assets/images/login/left-bg2.png'
|
|
||||||
import WindowTools from '@/components/window-tools/index.vue'
|
|
||||||
import SelectSubject from '@/components/select-subject/index.vue'
|
|
||||||
import Register from './components/Register.vue'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
|
||||||
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
|
||||||
|
|
||||||
const { session } = require('@electron/remote')
|
|
||||||
const downloadProp = ref(0)
|
|
||||||
const showDownLoading = ref(false)
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
|
||||||
const formRef = ref()
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const btnLoading = ref(false)
|
|
||||||
const isSubject = ref(false)
|
|
||||||
const RegModel = ref(false)
|
|
||||||
const isRegister = ref(true)
|
|
||||||
const ruleFormRef = ref(null)
|
|
||||||
const codeName=ref('发送验证码')
|
|
||||||
const timer=ref(null)
|
|
||||||
const isImg=ref(false)
|
|
||||||
const isPeopleImg=ref(null)
|
|
||||||
const type=ref(1) // 1注册 2找回密码
|
|
||||||
const resImg = reactive({ imgData: {} });
|
|
||||||
|
|
||||||
//表单
|
|
||||||
const loginForm = reactive({
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
rememberMe: false
|
|
||||||
})
|
|
||||||
// 注册表单
|
|
||||||
const ruleForm = reactive({
|
|
||||||
|
|
||||||
})
|
|
||||||
//表单规则
|
|
||||||
const rules = reactive({
|
|
||||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
|
||||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
|
||||||
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
|
||||||
})
|
|
||||||
|
|
||||||
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
|
||||||
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
|
||||||
ipcRenderer.on('update-app-progress', (e, prop) => {
|
|
||||||
downloadProp.value = prop
|
|
||||||
showDownLoading.value = prop !== 100
|
|
||||||
})
|
|
||||||
const gotoreRegister=()=>{
|
|
||||||
codeName.value='发送验证码'
|
|
||||||
if(timer.value){
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
isRegister.value=false
|
|
||||||
}
|
|
||||||
// 刷新
|
|
||||||
const refreshImg=()=>{
|
|
||||||
getCodeImg().then(res=>{
|
|
||||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
|
||||||
resImg.imgData=res
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 提交人机验证
|
|
||||||
const sbmitImg=()=>{
|
|
||||||
if(ruleForm.imgCode){
|
|
||||||
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
|
||||||
const { username:username,imgCode:code } = ruleForm
|
|
||||||
const params = {
|
|
||||||
username, code,
|
|
||||||
uuid: resImg.imgData.uuid,
|
|
||||||
source:4
|
|
||||||
}
|
|
||||||
sendcode(params).then(res=>{
|
|
||||||
if(res.code==200){
|
|
||||||
ElMessage.success('短信发送成功')
|
|
||||||
ruleForm.Code=res.data
|
|
||||||
isImg.value=false
|
|
||||||
codeName.value=60
|
|
||||||
timer.value=setInterval(()=>{
|
|
||||||
codeName.value--
|
|
||||||
if(codeName.value==0){
|
|
||||||
codeName.value='发送验证码'
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
},1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
ElMessage.error('请根据图片输入验证码')
|
|
||||||
}
|
|
||||||
//
|
|
||||||
}
|
|
||||||
// 发送验证码
|
|
||||||
const sendyzm=()=>{
|
|
||||||
if(ruleForm.username){
|
|
||||||
const pattern = /^1[3-9]\d{9}$/;
|
|
||||||
if( pattern.test(ruleForm.username) ){
|
|
||||||
|
|
||||||
getCodeImg().then(res=>{
|
|
||||||
if(res.code==200){
|
|
||||||
ruleForm.imgCode=null
|
|
||||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
|
||||||
isImg.value=true
|
|
||||||
resImg.imgData=res
|
|
||||||
// codeName.value=60
|
|
||||||
// timer.value=setInterval(()=>{
|
|
||||||
// codeName.value--
|
|
||||||
// if(codeName.value==0){
|
|
||||||
// codeName.value='发送验证码'
|
|
||||||
// clearInterval(timer.value);
|
|
||||||
// }
|
|
||||||
// },1000)
|
|
||||||
}else{
|
|
||||||
ElMessage.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
ElMessage.error('请输入正确的手机号码')
|
|
||||||
}
|
|
||||||
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
|
||||||
// console.log('res->', res)
|
|
||||||
// })
|
|
||||||
}else{
|
|
||||||
ElMessage.error('请输入手机号码')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 打开弹窗
|
|
||||||
const RegisterModel = type => {
|
|
||||||
RegModel.value.OpenModel(type)
|
|
||||||
}
|
|
||||||
//登录
|
|
||||||
const submitForm = async (formEl) => {
|
|
||||||
if (!formEl) return
|
|
||||||
await formEl.validate(async (valid) => {
|
|
||||||
if (valid) {
|
|
||||||
btnLoading.value = true
|
|
||||||
|
|
||||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
|
||||||
if (loginForm.rememberMe) {
|
|
||||||
await setCookie('username', loginForm.username)
|
|
||||||
await setCookie('password', encrypt(loginForm.password))
|
|
||||||
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
|
||||||
} else {
|
|
||||||
// 否则移除
|
|
||||||
await session.defaultSession.clearStorageData({
|
|
||||||
origin: curWinUrl,
|
|
||||||
storages: ['cookies']
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await userStore.login(loginForm)
|
|
||||||
await userStore.getInfo()
|
|
||||||
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
|
||||||
ElMessage.success('登录成功')
|
|
||||||
ipcRenderer && ipcRenderer.send('openMainWindow')
|
|
||||||
} else {
|
|
||||||
isSubject.value = true
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
btnLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const isStadium = (user) => {
|
|
||||||
let roles = user.roles
|
|
||||||
return roles.some(item => item.roleKey === 'stadium')
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCookie = async () => {
|
|
||||||
const username = (await getCookieDetail('username'))[0]
|
|
||||||
const password = (await getCookieDetail('password'))[0]
|
|
||||||
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
|
||||||
loginForm.username = username ? username.value : loginForm.username
|
|
||||||
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
|
||||||
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取cookie
|
|
||||||
const getCookieDetail = (name) => {
|
|
||||||
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置cookie
|
|
||||||
const setCookie = (name, value) => {
|
|
||||||
// 30天过期
|
|
||||||
let Days = 30
|
|
||||||
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
|
||||||
const cookie = {
|
|
||||||
url: curWinUrl,
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
expirationDate: times
|
|
||||||
}
|
|
||||||
return session.defaultSession.cookies.set(cookie)
|
|
||||||
}
|
|
||||||
const gotoLogin = () => {
|
|
||||||
codeName.value='发送验证码'
|
|
||||||
if (timer.value){
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
|
||||||
isRegister.value = true
|
|
||||||
}
|
|
||||||
// 注册
|
|
||||||
const RegisterForm = async (formEl) => {
|
|
||||||
if (!formEl) return
|
|
||||||
await formEl.validate((valid, fields) => {
|
|
||||||
if (valid) {
|
|
||||||
instructorregister(ruleForm).then(res=>{
|
|
||||||
if(res.code==200){
|
|
||||||
ElMessage.success('您已注册成功')
|
|
||||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
|
||||||
gotoLogin()
|
|
||||||
}else{
|
|
||||||
ElMessage.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.log('submit!')
|
|
||||||
} else {
|
|
||||||
console.log('error submit!', fields)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
localStorage.clear()
|
|
||||||
sessionStore.set('subject', {
|
|
||||||
bookList: null,
|
|
||||||
curBook: null,
|
|
||||||
curNode: null,
|
|
||||||
defaultExpandedKeys: [],
|
|
||||||
subjectTree: []
|
|
||||||
})
|
|
||||||
getCookie()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
|
|
||||||
.box-item {
|
|
||||||
width: 444px;
|
|
||||||
height: 520px;
|
|
||||||
|
|
||||||
&.desc {
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 12px 0px 0px 12px;
|
|
||||||
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
|
||||||
padding: 23px 25px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
background-color: #003b94;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.login {
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 0px 12px 12px 0px;
|
|
||||||
padding: 34px 42px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome {
|
|
||||||
padding-top: 35px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: #ffffff;
|
|
||||||
line-height: 25px;
|
|
||||||
letter-spacing: 0.26px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 26px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome-img {
|
|
||||||
margin-top: 20px;
|
|
||||||
width: 350px;
|
|
||||||
height: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-title {
|
|
||||||
font-size: 20px;
|
|
||||||
text-align: center;
|
|
||||||
color: #1e1e1e;
|
|
||||||
margin-bottom: 35px;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-form {
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
|
|
||||||
.captcha-input {
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha-img {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 350px;
|
|
||||||
height: 50px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 700;
|
|
||||||
text-align: center;
|
|
||||||
color: #ffffff;
|
|
||||||
line-height: 50px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-tool {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
|
|
||||||
span {
|
|
||||||
padding: 5px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,463 @@
|
||||||
|
<template>
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="login-yc">
|
||||||
|
<img class="welcome-img" :src="buildMode === 'yc2'?leftBg2:leftBg1" />
|
||||||
|
</div>
|
||||||
|
<div class="box-item login" v-if="isRegister">
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div style="display: flex;justify-content: center;"><img class="title-logo" :src="yclogo" /></div>
|
||||||
|
<div class="login-title">永川中小学</div>
|
||||||
|
<div class="login-title2">{{buildMode === 'yc2'?'虚拟仿真AI实训教学管理系统':'人工智能赋能科学素养与劳动技能系统'}}</div>
|
||||||
|
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password" style="margin-bottom: 15px">
|
||||||
|
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-5">
|
||||||
|
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||||
|
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item style="margin-bottom: 20px">
|
||||||
|
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
||||||
|
</div>
|
||||||
|
<div class="title-bottom">
|
||||||
|
重庆市永川区教育委员会
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-item login" v-else>
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div class="login-title">账号注册</div>
|
||||||
|
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
||||||
|
<el-form-item label="手机号" prop="username">
|
||||||
|
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
||||||
|
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码" prop="password" >
|
||||||
|
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false" align-center>
|
||||||
|
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
||||||
|
status="success" />
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
v-model="isImg"
|
||||||
|
title="人机验证"
|
||||||
|
width="500"
|
||||||
|
style=" -webkit-app-region: no-drag;"
|
||||||
|
>
|
||||||
|
<span>根据图片回答相关问题1</span>
|
||||||
|
<div style="display: flex;align-items: center;;margin-top:30px">
|
||||||
|
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
||||||
|
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;justify-content: center;margin-top:30px">
|
||||||
|
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<!--选择学科-->
|
||||||
|
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
||||||
|
<!--注册弹框-->
|
||||||
|
<Register ref="RegModel"></Register>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import WindowTools from '@/components/window-tools/index.vue'
|
||||||
|
import SelectSubject from '@/components/select-subject/index.vue'
|
||||||
|
import Register from './components/Register.vue'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
||||||
|
import yclogo from '@/assets/images/login/yc-logo.png'
|
||||||
|
import leftBg1 from '@/assets/images/login/ycpeitu.png'
|
||||||
|
import leftBg2 from '@/assets/images/login/ycpeitu2.jpg'
|
||||||
|
const { session } = require('@electron/remote')
|
||||||
|
const buildMode = import.meta.env.MODE
|
||||||
|
const downloadProp = ref(0)
|
||||||
|
const showDownLoading = ref(false)
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
const formRef = ref()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const btnLoading = ref(false)
|
||||||
|
const isSubject = ref(false)
|
||||||
|
const RegModel = ref(false)
|
||||||
|
const isRegister = ref(true)
|
||||||
|
const ruleFormRef = ref(null)
|
||||||
|
const codeName=ref('发送验证码')
|
||||||
|
const timer=ref(null)
|
||||||
|
const isImg=ref(false)
|
||||||
|
const isPeopleImg=ref(null)
|
||||||
|
const type=ref(1) // 1注册 2找回密码
|
||||||
|
const resImg = reactive({ imgData: {} });
|
||||||
|
|
||||||
|
//表单
|
||||||
|
const loginForm = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
rememberMe: false
|
||||||
|
})
|
||||||
|
// 注册表单
|
||||||
|
const ruleForm = reactive({
|
||||||
|
|
||||||
|
})
|
||||||
|
//表单规则
|
||||||
|
const rules = reactive({
|
||||||
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
|
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||||
|
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
||||||
|
})
|
||||||
|
|
||||||
|
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
|
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||||
|
ipcRenderer.on('update-app-progress', (e, prop) => {
|
||||||
|
downloadProp.value = prop
|
||||||
|
showDownLoading.value = prop !== 100
|
||||||
|
})
|
||||||
|
const gotoreRegister=()=>{
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if(timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
isRegister.value=false
|
||||||
|
}
|
||||||
|
// 刷新
|
||||||
|
const refreshImg=()=>{
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
resImg.imgData=res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 提交人机验证
|
||||||
|
const sbmitImg=()=>{
|
||||||
|
if(ruleForm.imgCode){
|
||||||
|
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
||||||
|
const { username:username,imgCode:code } = ruleForm
|
||||||
|
const params = {
|
||||||
|
username, code,
|
||||||
|
uuid: resImg.imgData.uuid,
|
||||||
|
source:4
|
||||||
|
}
|
||||||
|
sendcode(params).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('短信发送成功')
|
||||||
|
ruleForm.Code=res.data
|
||||||
|
isImg.value=false
|
||||||
|
codeName.value=60
|
||||||
|
timer.value=setInterval(()=>{
|
||||||
|
codeName.value--
|
||||||
|
if(codeName.value==0){
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
},1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请根据图片输入验证码')
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// 发送验证码
|
||||||
|
const sendyzm=()=>{
|
||||||
|
if(ruleForm.username){
|
||||||
|
const pattern = /^1[3-9]\d{9}$/;
|
||||||
|
if( pattern.test(ruleForm.username) ){
|
||||||
|
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ruleForm.imgCode=null
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
isImg.value=true
|
||||||
|
resImg.imgData=res
|
||||||
|
// codeName.value=60
|
||||||
|
// timer.value=setInterval(()=>{
|
||||||
|
// codeName.value--
|
||||||
|
// if(codeName.value==0){
|
||||||
|
// codeName.value='发送验证码'
|
||||||
|
// clearInterval(timer.value);
|
||||||
|
// }
|
||||||
|
// },1000)
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入正确的手机号码')
|
||||||
|
}
|
||||||
|
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
||||||
|
// console.log('res->', res)
|
||||||
|
// })
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入手机号码')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 打开弹窗
|
||||||
|
const RegisterModel = type => {
|
||||||
|
RegModel.value.OpenModel(type)
|
||||||
|
}
|
||||||
|
//登录
|
||||||
|
const submitForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
btnLoading.value = true
|
||||||
|
|
||||||
|
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||||
|
if (loginForm.rememberMe) {
|
||||||
|
await setCookie('username', loginForm.username)
|
||||||
|
await setCookie('password', encrypt(loginForm.password))
|
||||||
|
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
||||||
|
} else {
|
||||||
|
// 否则移除
|
||||||
|
await session.defaultSession.clearStorageData({
|
||||||
|
origin: curWinUrl,
|
||||||
|
storages: ['cookies']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await userStore.login(loginForm)
|
||||||
|
await userStore.getInfo()
|
||||||
|
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
ipcRenderer && ipcRenderer.send('openMainWindow')
|
||||||
|
} else {
|
||||||
|
isSubject.value = true
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
btnLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isStadium = (user) => {
|
||||||
|
let roles = user.roles
|
||||||
|
return roles.some(item => item.roleKey === 'stadium')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCookie = async () => {
|
||||||
|
const username = (await getCookieDetail('username'))[0]
|
||||||
|
const password = (await getCookieDetail('password'))[0]
|
||||||
|
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
||||||
|
loginForm.username = username ? username.value : loginForm.username
|
||||||
|
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
||||||
|
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取cookie
|
||||||
|
const getCookieDetail = (name) => {
|
||||||
|
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置cookie
|
||||||
|
const setCookie = (name, value) => {
|
||||||
|
// 30天过期
|
||||||
|
let Days = 30
|
||||||
|
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
||||||
|
const cookie = {
|
||||||
|
url: curWinUrl,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
expirationDate: times
|
||||||
|
}
|
||||||
|
return session.defaultSession.cookies.set(cookie)
|
||||||
|
}
|
||||||
|
const gotoLogin = () => {
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if (timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
isRegister.value = true
|
||||||
|
}
|
||||||
|
// 注册
|
||||||
|
const RegisterForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
instructorregister(ruleForm).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('您已注册成功')
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
gotoLogin()
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('submit!')
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
sessionStore.set('subject', {
|
||||||
|
bookList: null,
|
||||||
|
curBook: null,
|
||||||
|
curNode: null,
|
||||||
|
defaultExpandedKeys: [],
|
||||||
|
subjectTree: []
|
||||||
|
})
|
||||||
|
getCookie()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
|
.login-yc{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-item {
|
||||||
|
width: 370px;
|
||||||
|
height: 520px;
|
||||||
|
|
||||||
|
&.desc {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px 0px 0px 12px;
|
||||||
|
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
||||||
|
padding: 23px 25px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
background-color: #003b94;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.login {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 0px 12px 12px 0px;
|
||||||
|
padding: 34px 42px;
|
||||||
|
position: relative;
|
||||||
|
.title-logo{
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome {
|
||||||
|
padding-top: 35px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 25px;
|
||||||
|
letter-spacing: 0.26px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-img {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #1e1e1e;
|
||||||
|
margin-bottom: 35px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #1e1e1e;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
font-width: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
.captcha-input {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bottom{
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 350px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tool {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -98,10 +98,13 @@ import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue
|
||||||
import msgUtils from "@/plugins/modal";
|
import msgUtils from "@/plugins/modal";
|
||||||
import * as commUtils from "@/utils/comm";
|
import * as commUtils from "@/utils/comm";
|
||||||
import * as Api_server from "@/api/apiService"; // 学科名字文生图
|
import * as Api_server from "@/api/apiService"; // 学科名字文生图
|
||||||
|
import useClassTaskStore from '@/store/modules/classTask'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore().user // 用户信息
|
const userStore = useUserStore().user // 用户信息
|
||||||
const currentNode = ref({})
|
const currentNode = ref({})
|
||||||
const refs = ref([]);
|
const refs = ref([]);
|
||||||
|
const classTaskStore = useClassTaskStore();
|
||||||
|
|
||||||
const collectRef = (key) => {
|
const collectRef = (key) => {
|
||||||
return (el) => {
|
return (el) => {
|
||||||
|
@ -513,7 +516,9 @@ const changeClass = async (type, row, other) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面加载
|
// 页面加载
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
// 更新第三方题型题类
|
||||||
|
await classTaskStore.initJYInfo(userStore);
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -61,7 +61,8 @@
|
||||||
<div>
|
<div>
|
||||||
<div v-if="myClassActive.filetype=='apt'">开始新的课堂,需要点击先创建课堂,才能显示手机二维码</div>
|
<div v-if="myClassActive.filetype=='apt'">开始新的课堂,需要点击先创建课堂,才能显示手机二维码</div>
|
||||||
<div v-else>开始新的课堂,需要点击先创建课堂</div>
|
<div v-else>开始新的课堂,需要点击先创建课堂</div>
|
||||||
<el-button type="warning" :loading="dt.loading" @click="createClasscourse">创建课堂</el-button>
|
<el-button type="warning" :loading="dt.loading" @click="createClasscourse()">创建课堂</el-button>
|
||||||
|
<el-button type="success" @click="createClasscourse(true)">公屏上课</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- 故障备用 -->
|
<!-- 故障备用 -->
|
||||||
|
@ -146,7 +147,7 @@ const open = async (id, classObj) => {
|
||||||
await getAptInfo(id)
|
await getAptInfo(id)
|
||||||
// 获取班级列表
|
// 获取班级列表
|
||||||
getClassList()
|
getClassList()
|
||||||
console.log('classObj', classObj)
|
// console.log('classObj', classObj)
|
||||||
// 继续上课
|
// 继续上课
|
||||||
if (!!classObj) {
|
if (!!classObj) {
|
||||||
dt.ctCourse = classObj
|
dt.ctCourse = classObj
|
||||||
|
@ -245,8 +246,8 @@ const getClasscourseList = async type => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 创建课程
|
// 创建课程 isPublic 公屏上课
|
||||||
const createClasscourse = async () => {
|
const createClasscourse = async (isPublic = false) => {
|
||||||
const { classid } = classForm.form
|
const { classid } = classForm.form
|
||||||
if (!classid) {
|
if (!classid) {
|
||||||
ElMessage.warning('请选择班级')
|
ElMessage.warning('请选择班级')
|
||||||
|
@ -255,8 +256,8 @@ const createClasscourse = async () => {
|
||||||
dt.loading = true
|
dt.loading = true
|
||||||
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // 课件对象
|
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // 课件对象
|
||||||
const curDate = commUtil.getDateNow('yyyy-MM-dd')
|
const curDate = commUtil.getDateNow('yyyy-MM-dd')
|
||||||
const params = {
|
const params = { // 公屏上课直接 status = open
|
||||||
id: 0, coursetype: '', courseverid: 0, coursedesc: '', status: '',
|
id: 0, coursetype: '', courseverid: 0, coursedesc: '', status: isPublic?'open':'',
|
||||||
teacherid: userStore.id, entpcoursefileid: id, classid,
|
teacherid: userStore.id, entpcoursefileid: id, classid,
|
||||||
entpcourseid, evalid, coursetitle,
|
entpcourseid, evalid, coursetitle,
|
||||||
plandate: curDate, opendate: curDate
|
plandate: curDate, opendate: curDate
|
||||||
|
@ -274,7 +275,7 @@ const createClasscourse = async () => {
|
||||||
setTimeout(async() => {
|
setTimeout(async() => {
|
||||||
msgEl.close()
|
msgEl.close()
|
||||||
const res = await Http_Classcourse.getClasscourse(teacherForm.form.classcourseid)
|
const res = await Http_Classcourse.getClasscourse(teacherForm.form.classcourseid)
|
||||||
openPublicScreen(res.data)
|
openPublicScreen(res.data, isPublic)
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
@ -355,7 +356,7 @@ const getQrUrl = async() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开公屏
|
// 打开公屏
|
||||||
const openPublicScreen = (classcourse) => {
|
const openPublicScreen = (classcourse, isPublic) => {
|
||||||
console.log('打开公屏', classcourse)
|
console.log('打开公屏', classcourse)
|
||||||
if (!dt.ctCourse) { // 新开课需要发送消息-继续上课不需要直接打开
|
if (!dt.ctCourse) { // 新开课需要发送消息-继续上课不需要直接打开
|
||||||
// 发送app端待开课消息
|
// 发送app端待开课消息
|
||||||
|
@ -366,11 +367,14 @@ const openPublicScreen = (classcourse) => {
|
||||||
const resource = toRaw(myClassActive.value)
|
const resource = toRaw(myClassActive.value)
|
||||||
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||||
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
||||||
|
// 公屏开课
|
||||||
|
sessionStore.set('curr.isPublic', isPublic) // 缓存是否公屏开课
|
||||||
createWindow('open-win', {
|
createWindow('open-win', {
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
close: () => {
|
close: () => {
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
sessionStore.set('curr.resource', null) // 清除缓存
|
||||||
sessionStore.set('curr.classcourse', null) // 清除缓存
|
sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||||
|
sessionStore.set('curr.isPublic', null) // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
visible.value = false // 关闭弹窗
|
visible.value = false // 关闭弹窗
|
||||||
|
|
|
@ -126,11 +126,17 @@
|
||||||
<span>下载</span>
|
<span>下载</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
|
<!-- <div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
|
||||||
<el-button text @click="adToKj(item)">
|
<el-button text @click="adToKj(item)">
|
||||||
<i class="iconfont icon-jiahao"></i>
|
<i class="iconfont icon-jiahao"></i>
|
||||||
<span>加入课件</span>
|
<span>加入课件</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
</div>-->
|
||||||
|
<div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
|
||||||
|
<el-button text @click="importPPT(item)">
|
||||||
|
<i class="iconfont icon-jiahao"></i>
|
||||||
|
<span>导入PPT</span>
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-popover-item">
|
<div class="item-popover-item">
|
||||||
<el-button text @click="moveSmarttalkFun(item)">
|
<el-button text @click="moveSmarttalkFun(item)">
|
||||||
|
@ -181,7 +187,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null },
|
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null,'on-importPPT': null },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
listenList: [],
|
listenList: [],
|
||||||
|
@ -217,6 +223,9 @@ export default {
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
},
|
},
|
||||||
|
importPPT(item) {
|
||||||
|
this.$emit('on-importPPT', item)
|
||||||
|
},
|
||||||
downloadFile(item) {
|
downloadFile(item) {
|
||||||
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
|
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
|
||||||
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
|
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item>
|
<el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item>
|
||||||
<input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation">
|
<input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation">
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
|
@ -98,6 +99,7 @@
|
||||||
@on-delete="deleteTalk"
|
@on-delete="deleteTalk"
|
||||||
@on-set="openSet"
|
@on-set="openSet"
|
||||||
@on-delhomework="delhomework"
|
@on-delhomework="delhomework"
|
||||||
|
@on-importPPT="importPPT"
|
||||||
@on-filearg="isOpenHomework = true"
|
@on-filearg="isOpenHomework = true"
|
||||||
>
|
>
|
||||||
<el-checkbox v-if="!item.uniquekey" label="" :value="item" />
|
<el-checkbox v-if="!item.uniquekey" label="" :value="item" />
|
||||||
|
@ -193,7 +195,7 @@ import outLink from '@/utils/linkConfig'
|
||||||
import { createWindow, sessionStore, getAppInstallUrl, ipcMsgSend } from '@/utils/tool'
|
import { createWindow, sessionStore, getAppInstallUrl, ipcMsgSend } from '@/utils/tool'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { delClasswork, listEntpcourse } from '@/api/teaching/classwork'
|
import { delClasswork, listEntpcourse } from '@/api/teaching/classwork'
|
||||||
import { updateClasscourse } from '@/api/teaching/classcourse'
|
import { updateClasscourse, getClasscourse } from '@/api/teaching/classcourse'
|
||||||
import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage'
|
import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
import { editListItem } from '@/hooks/useClassTask'
|
import { editListItem } from '@/hooks/useClassTask'
|
||||||
|
@ -296,7 +298,7 @@ export default {
|
||||||
},
|
},
|
||||||
currentKJFileList() {
|
currentKJFileList() {
|
||||||
// return this.currentFileList.filter((item) => item.fileFlag === 'apt' || item.fileFlag === '课件')
|
// return this.currentFileList.filter((item) => item.fileFlag === 'apt' || item.fileFlag === '课件')
|
||||||
return this.currentFileList.filter((item) => ['apt','aippt','课件'].includes(item.fileFlag))
|
return this.currentFileList.filter((item) => ['aippt'].includes(item.fileFlag))
|
||||||
},
|
},
|
||||||
currentSCFileList() {
|
currentSCFileList() {
|
||||||
// return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '课件')
|
// return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '课件')
|
||||||
|
@ -341,6 +343,14 @@ export default {
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
methods: {
|
methods: {
|
||||||
|
openGridPic() {
|
||||||
|
createWindow('open-win', {
|
||||||
|
url: '/gridPic', // 窗口关闭时,清除缓存
|
||||||
|
option: {
|
||||||
|
maximizable: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
// 延时
|
// 延时
|
||||||
sleep(ms){return new Promise(resolve => setTimeout(resolve, ms))},
|
sleep(ms){return new Promise(resolve => setTimeout(resolve, ms))},
|
||||||
addAiPPT(item) {
|
addAiPPT(item) {
|
||||||
|
@ -355,8 +365,8 @@ export default {
|
||||||
// 开始上课
|
// 开始上课
|
||||||
startClass(item, classObj) {
|
startClass(item, classObj) {
|
||||||
// 关闭状态,打开上课相关功能(已打开,忽略)
|
// 关闭状态,打开上课相关功能(已打开,忽略)
|
||||||
// const id = sessionStore.has('activeClass.id') ? sessionStore.get('activeClass.id') : null
|
const iscourse = !!sessionStore.get('curr.classcourse')
|
||||||
// if (id && id == item.id) return ElMessage.warning('当前正在上课,请勿重复操作')
|
if (iscourse) return ElMessage.warning('公屏已打开,请勿重复操作')
|
||||||
// 当前上课-store
|
// 当前上课-store
|
||||||
sessionStore.set('activeClass', item)
|
sessionStore.set('activeClass', item)
|
||||||
this.activeClass = item
|
this.activeClass = item
|
||||||
|
@ -367,7 +377,8 @@ export default {
|
||||||
this.$refs.calssRef.open(item.fileId, classObj)
|
this.$refs.calssRef.open(item.fileId, classObj)
|
||||||
}
|
}
|
||||||
if(item.fileFlag === 'aippt') {
|
if(item.fileFlag === 'aippt') {
|
||||||
this.$refs.calssRef.open(item.fileId, classObj)
|
if (!!classObj) this.changeClass('continue', classObj) // 继续上课
|
||||||
|
else this.$refs.calssRef.open(item.fileId, classObj) // 新开课
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 继续上课-apt
|
// 继续上课-apt
|
||||||
|
@ -375,7 +386,20 @@ export default {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 'continue': { // 继续上课
|
case 'continue': { // 继续上课
|
||||||
const aptFileId = row.entpcoursefileid
|
const aptFileId = row.entpcoursefileid
|
||||||
this.$refs.calssRef.open(aptFileId, row)
|
const res = await getEntpcoursefile(aptFileId)
|
||||||
|
if (res.code == 200) {
|
||||||
|
const resource = res.data
|
||||||
|
if (resource.filetype != 'aippt') this.$refs.calssRef.open(aptFileId, row)
|
||||||
|
else { // aippt 继续上课
|
||||||
|
if (!!sessionStore.get('curr.classcourse')) return ElMessage.warning('公屏已打开,请勿重复操作')
|
||||||
|
const { data:classcourse } = await getClasscourse(row.id) // 获取最新课堂信息
|
||||||
|
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
||||||
|
setTimeout(()=>{
|
||||||
|
msgEl.close()
|
||||||
|
this.openPublicScreen('class', resource, classcourse||row) // 打开公屏-窗口
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
} else ElMessage.error(res.msg||'获取课件信息失败')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'close': { // 关闭上课
|
case 'close': { // 关闭上课
|
||||||
|
@ -428,16 +452,7 @@ export default {
|
||||||
if (row.fileFlag === 'aippt' && !!row.fileId) {
|
if (row.fileFlag === 'aippt' && !!row.fileId) {
|
||||||
const res = await getEntpcoursefile(row.fileId)
|
const res = await getEntpcoursefile(row.fileId)
|
||||||
if (res && res.code === 200) {
|
if (res && res.code === 200) {
|
||||||
sessionStore.set('curr.resource', res.data) // 缓存当前资源信息
|
this.openPublicScreen('edit', res.data, row) // 打开公屏-窗口
|
||||||
sessionStore.set('curr.smarttalk', row) // 缓存当前文件smarttalk
|
|
||||||
createWindow('open-win', {
|
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
|
||||||
close: () => {
|
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
|
||||||
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
|
||||||
this.asyncAllFile() // 刷新资源列表
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
ElMessage.warning(res.msg||'文件获取异常!')
|
ElMessage.warning(res.msg||'文件获取异常!')
|
||||||
}
|
}
|
||||||
|
@ -448,6 +463,7 @@ export default {
|
||||||
}
|
}
|
||||||
case 'wsApp': { // 发送app端待开课消息
|
case 'wsApp': { // 发送app端待开课消息
|
||||||
// console.log('wsApp', row)
|
// console.log('wsApp', row)
|
||||||
|
if (!!sessionStore.get('curr.classcourse')) return ElMessage.warning('公屏已打开,请勿重复操作')
|
||||||
const head = MsgEnum.HEADS.MSG_0000
|
const head = MsgEnum.HEADS.MSG_0000
|
||||||
const data = { id: row.id }
|
const data = { id: row.id }
|
||||||
const type = ChatWs.TYPES.single
|
const type = ChatWs.TYPES.single
|
||||||
|
@ -462,24 +478,38 @@ export default {
|
||||||
msgEl.close() // 关闭提示
|
msgEl.close() // 关闭提示
|
||||||
const resource = res?.data||{}
|
const resource = res?.data||{}
|
||||||
const classcourse = row
|
const classcourse = row
|
||||||
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
this.openPublicScreen('class',resource, classcourse) // 打开公屏-窗口
|
||||||
sessionStore.set('curr.classcourse', classcourse) // 缓存当前当前上课
|
|
||||||
createWindow('open-win', {
|
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
|
||||||
close: () => {
|
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
|
||||||
sessionStore.set('curr.classcourse', null) // 清除缓存
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* description 打开公屏
|
||||||
|
* @param {string} type 类型 edit 打开 class 上课
|
||||||
|
* @param {object} resource 资源信息
|
||||||
|
* @param {object} currData 当前数据 type: edit/class 备课信息 | 课堂信息
|
||||||
|
*/
|
||||||
|
openPublicScreen(type, resource, currData) {
|
||||||
|
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||||
|
if (type=='edit') sessionStore.set('curr.smarttalk', currData) // 缓存当前文件smarttalk
|
||||||
|
else sessionStore.set('curr.classcourse', currData) // 缓存当前当前上课
|
||||||
|
createWindow('open-win', {
|
||||||
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
|
close: () => {
|
||||||
|
sessionStore.set('curr.resource', null) // 清除缓存
|
||||||
|
if (type=='edit') {
|
||||||
|
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
||||||
|
this.asyncAllFile() // 刷新资源列表
|
||||||
|
} else sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
closeChange() { // 上课弹窗被关闭-触发
|
closeChange() { // 上课弹窗被关闭-触发
|
||||||
// console.log('关闭上课弹窗')
|
// console.log('关闭上课弹窗')
|
||||||
// this.activeClass = null
|
this.activeClass = null
|
||||||
sessionStore.delete('activeClass')
|
sessionStore.delete('activeClass')
|
||||||
},
|
},
|
||||||
initReserv(id) {
|
initReserv(id) {
|
||||||
|
@ -526,6 +556,15 @@ export default {
|
||||||
progDownFile(e, num) {
|
progDownFile(e, num) {
|
||||||
this.downloadNum = num
|
this.downloadNum = num
|
||||||
},
|
},
|
||||||
|
importPPT(item) {
|
||||||
|
let _this = this;
|
||||||
|
fetch(item.fileFullPath)
|
||||||
|
.then(res => res.arrayBuffer())
|
||||||
|
.then(buffer => {
|
||||||
|
let name = item.fileShowName.substring(0, item.fileShowName.lastIndexOf('.')) + '.aippt'
|
||||||
|
_this.createAIPPTByFile(buffer, name)
|
||||||
|
})
|
||||||
|
},
|
||||||
createFile() {
|
createFile() {
|
||||||
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
|
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
|
||||||
this.currentFileList.unshift(res.resData)
|
this.currentFileList.unshift(res.resData)
|
||||||
|
@ -544,7 +583,7 @@ export default {
|
||||||
console.log('文件名:', file.name);
|
console.log('文件名:', file.name);
|
||||||
console.log('文件类型:', file.type);
|
console.log('文件类型:', file.type);
|
||||||
console.log('文件大小:', file.size);
|
console.log('文件大小:', file.size);
|
||||||
this.createAIPPTByFile(file)
|
this.createAIPPTByFile(file, this.currentNode.itemtitle + '.aippt')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async toRousrceUrl(o) {
|
async toRousrceUrl(o) {
|
||||||
|
@ -590,7 +629,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async createAIPPTByFile(file) {
|
async createAIPPTByFile(file,fileShowName) {
|
||||||
this.pgDialog.visible = true
|
this.pgDialog.visible = true
|
||||||
this.pgDialog.pg.percentage = 0
|
this.pgDialog.pg.percentage = 0
|
||||||
const resPptJson = await PPTXFileToJson(file)
|
const resPptJson = await PPTXFileToJson(file)
|
||||||
|
@ -636,7 +675,7 @@ export default {
|
||||||
...this.uploadData,
|
...this.uploadData,
|
||||||
fileId: slideid,
|
fileId: slideid,
|
||||||
fileFlag: 'aippt',
|
fileFlag: 'aippt',
|
||||||
fileShowName: this.currentNode.itemtitle + '.aippt'
|
fileShowName: fileShowName
|
||||||
}).then(async (res) => {
|
}).then(async (res) => {
|
||||||
|
|
||||||
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
|
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog v-model="model" class="preview-drawer" :title="row.fileShowName" :modal="true" :destroy-on-close="true" :with-header="false" :append-to-body="true"
|
||||||
|
width="60%">
|
||||||
|
<video style="margin: 0 auto;" :src="row.fileFullPath" controls autoplay></video>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
const model = defineModel()
|
||||||
|
const props = defineProps({
|
||||||
|
row: {
|
||||||
|
type: Object,
|
||||||
|
default(){
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.header-close {
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,214 @@
|
||||||
|
<template>
|
||||||
|
<div class="page-resource flex">
|
||||||
|
<!-- 左侧 教材 目录 -->
|
||||||
|
<div class="page-right">
|
||||||
|
<!-- 排序 -->
|
||||||
|
<div style="margin-left: 5px;margin-top: 10px;height: 45px;">
|
||||||
|
<el-form size="large">
|
||||||
|
<el-form-item label="排序:">
|
||||||
|
<div
|
||||||
|
:class="['score-circle', { 'active': active == item.active }]"
|
||||||
|
v-for="(item,index) in screenList" :key="index" @click="chooseItem(item)">
|
||||||
|
<el-text
|
||||||
|
:style="{fontWeight:'bold', color: active == item.active ? 'rgb(57, 184, 244)':'rgb(131,131,131)' }"
|
||||||
|
size="large">{{ item.title }}</el-text>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<el-scrollbar>
|
||||||
|
<el-empty v-if="!sourceStore.result.list.length" description="暂无数据" />
|
||||||
|
<div class="list-content">
|
||||||
|
<div class="list-container" v-loading="loading">
|
||||||
|
<div v-for="(item, index) in sourceStore.result.list" :key="index" class="content">
|
||||||
|
<div class="content-list">
|
||||||
|
<!-- 封面 -->
|
||||||
|
<el-image style="width: 100%;border-radius: 8px;" :src="item.coverPic" fit="contain" @click="chooseVedio(item)"/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div style="text-align: left;">
|
||||||
|
<el-text>{{ item.fileShowName }}</el-text>
|
||||||
|
</div>
|
||||||
|
<!-- 观看人数 -->
|
||||||
|
<!-- <div style="text-align: left;display: flex;align-items: center;">
|
||||||
|
<el-icon type="info"><View /></el-icon><el-text size="small" type="info">{{ item.nums }}</el-text>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
<div class="pagination-box">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="sourceStore.query.pageNum"
|
||||||
|
v-model:page-size="sourceStore.query.pageSize"
|
||||||
|
:page-sizes="[10, 20, 30, 50]"
|
||||||
|
background
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="sourceStore.result.total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 播放视频 -->
|
||||||
|
<VideoLog v-model="isShow" :row="curRow"></VideoLog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import VideoLog from './components/VideoLog.vue'
|
||||||
|
import useResoureStore from '../store'
|
||||||
|
const sourceStore = useResoureStore()
|
||||||
|
// 排序列表
|
||||||
|
const screenList = ref([
|
||||||
|
{
|
||||||
|
title: '最新发布',
|
||||||
|
active: 1,
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const active = ref(1)
|
||||||
|
// 弹出视频
|
||||||
|
const isShow = ref(false)
|
||||||
|
const curRow = ref({})
|
||||||
|
// loading框
|
||||||
|
const loading = computed(() => sourceStore.loading)
|
||||||
|
const chooseItem = (item) => {
|
||||||
|
active.value = item.active
|
||||||
|
}
|
||||||
|
// 分页change
|
||||||
|
const handleSizeChange = (limit) => {
|
||||||
|
sourceStore.query.pageSize = limit
|
||||||
|
sourceStore.handleQuery()
|
||||||
|
}
|
||||||
|
const handleCurrentChange = (page) => {
|
||||||
|
sourceStore.query.pageNum = page
|
||||||
|
sourceStore.handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const chooseVedio = (item) => {
|
||||||
|
isShow.value = true
|
||||||
|
curRow.value = item
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-resource {
|
||||||
|
height: 100%;
|
||||||
|
padding: 10px 15px 0;
|
||||||
|
|
||||||
|
.page-right {
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.icon-jiahao {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 3px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.create-btn {
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 5px 13px;
|
||||||
|
}
|
||||||
|
.list-content {
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 90%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.list-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
border-radius: 8px;
|
||||||
|
// box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
width: calc(20%);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
padding: 5px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
// justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
// box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
.content-list{
|
||||||
|
height: 150px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #409eff;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-bottom {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 过渡动画 */
|
||||||
|
.fade-enter-active, .fade-leave-active {
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter, .fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.score-circle {
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: auto;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-circle.active {
|
||||||
|
background-color: rgb(218, 236, 255);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.pagination-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
height: 65px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -3,19 +3,21 @@
|
||||||
<el-row justify="space-between">
|
<el-row justify="space-between">
|
||||||
<el-col :span="12" class="tab-btns flex">
|
<el-col :span="12" class="tab-btns flex">
|
||||||
<el-button text v-for="item in sourceStore.resourceTypeList" :key="item.id"
|
<el-button text v-for="item in sourceStore.resourceTypeList" :key="item.id"
|
||||||
:type="sourceStore.query.fileFlags == item.value ? 'primary' : ''"
|
:type="sourceStore.activeIndex == item.id ? 'primary' : ''"
|
||||||
@click="sourceStore.changeType(item.value)" :disabled="item.disabled">{{ item.label
|
@click="sourceStore.changeType(item)" :disabled="item.disabled">{{ item.label
|
||||||
}}</el-button>
|
}}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="search-box flex" v-if="isThird">
|
<template v-if="!isExper">
|
||||||
<el-input v-model="sourceStore.thirdQuery.title" @input="onchangeInput()" style="width: 240px"
|
<el-col :span="12" class="search-box flex" v-if="isThird">
|
||||||
placeholder="请输入关键词" />
|
<el-input v-model="sourceStore.thirdQuery.title" @input="onchangeInput()" style="width: 240px"
|
||||||
</el-col>
|
placeholder="请输入关键词" />
|
||||||
<el-col :span="12" class="search-box flex" v-else>
|
</el-col>
|
||||||
<el-input v-model="sourceStore.query.fileName" @input="onchangeInput()" style="width: 240px"
|
<el-col :span="12" class="search-box flex" v-else>
|
||||||
placeholder="请输入关键词" />
|
<el-input v-model="sourceStore.query.fileName" @input="onchangeInput()" style="width: 240px"
|
||||||
</el-col>
|
placeholder="请输入关键词" />
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 第三方资源筛选-->
|
<!-- 第三方资源筛选-->
|
||||||
|
@ -34,22 +36,24 @@
|
||||||
<el-col :span="24" class="query-row flex">
|
<el-col :span="24" class="query-row flex">
|
||||||
<div class="flex row-left">
|
<div class="flex row-left">
|
||||||
<!-- 第三方资源筛选-->
|
<!-- 第三方资源筛选-->
|
||||||
<el-select v-if="isThird" v-model="sourceStore.thirdQuery.type" @change="sourceStore.thirdChangeType"
|
<template v-if="!isExper">
|
||||||
style="width: 110px">
|
<el-select v-if="isThird" v-model="sourceStore.thirdQuery.type" @change="sourceStore.thirdChangeType"
|
||||||
<el-option v-for="item in coursewareTypeList" :key="item.value" :label="item.label"
|
style="width: 110px">
|
||||||
:value="item.value" />
|
<el-option v-for="item in coursewareTypeList" :key="item.value" :label="item.label"
|
||||||
</el-select>
|
:value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
|
||||||
<el-select v-else v-model="sourceStore.query.fileSuffix" @change="sourceStore.changeSuffix"
|
<el-select v-else v-model="sourceStore.query.fileSuffix" @change="sourceStore.changeSuffix"
|
||||||
style="width: 110px">
|
style="width: 110px">
|
||||||
<el-option v-for="item in sourceStore.resourceFormatList" :key="item.value" :label="item.label"
|
<el-option v-for="item in sourceStore.resourceFormatList" :key="item.value" :label="item.label"
|
||||||
:value="item.value" />
|
:value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
<el-button v-for="item in sourceStore.tabs" :key="item.id"
|
<el-button v-for="item in sourceStore.tabs" :key="item.id"
|
||||||
:type="sourceStore.query.fileSource == item.value ? 'primary' : ''"
|
:type="sourceStore.query.fileSource == item.value ? 'primary' : ''"
|
||||||
@click="sourceStore.changeTab(item.value)">{{
|
@click="sourceStore.changeTab(item.value)">{{
|
||||||
item.label }}</el-button>
|
item.label }}</el-button>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<slot name="add" />
|
<slot name="add" />
|
||||||
|
@ -63,7 +67,10 @@
|
||||||
import {watch,ref,onMounted} from 'vue'
|
import {watch,ref,onMounted} from 'vue'
|
||||||
import useResoureStore from '../store'
|
import useResoureStore from '../store'
|
||||||
import {coursewareTypeList} from '@/utils/resourceDict'
|
import {coursewareTypeList} from '@/utils/resourceDict'
|
||||||
|
// 是否是第三方资源
|
||||||
const isThird = ref(false)
|
const isThird = ref(false)
|
||||||
|
//判断是不是进入实验室
|
||||||
|
const isExper = ref(false)
|
||||||
const sourceStore = useResoureStore()
|
const sourceStore = useResoureStore()
|
||||||
// 防抖函数
|
// 防抖函数
|
||||||
const debounce = (fn, t) => {
|
const debounce = (fn, t) => {
|
||||||
|
@ -85,6 +92,9 @@ onMounted(() => {
|
||||||
watch(() => sourceStore.query.fileSource,() => {
|
watch(() => sourceStore.query.fileSource,() => {
|
||||||
sourceStore.query.fileSource === '第三方'?isThird.value = true:isThird.value = false
|
sourceStore.query.fileSource === '第三方'?isThird.value = true:isThird.value = false
|
||||||
})
|
})
|
||||||
|
watch(() => sourceStore.query.orderByColumn,() => {
|
||||||
|
sourceStore.query.orderByColumn === 'uploadTime'?isExper.value = true:isExper.value = false
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.resoure-search {
|
.resoure-search {
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="page-resource flex">
|
<div class="page-resource flex">
|
||||||
<!--左侧 教材 目录-->
|
<!--左侧 教材 目录-->
|
||||||
<Third v-if="isThird" @node-click="getDataOther"></Third>
|
<template v-if="!isExper">
|
||||||
<ChooseTextbook v-else @node-click="getData" />
|
<Third v-if="isThird" @node-click="getDataOther"/>
|
||||||
|
<ChooseTextbook v-else @node-click="getData" />
|
||||||
|
</template>
|
||||||
|
<!-- 实验室的左侧树结构列表 -->
|
||||||
|
<template v-else>
|
||||||
|
<ExperimentBook @node-click="getExperData"/>
|
||||||
|
</template>
|
||||||
<div class="page-right">
|
<div class="page-right">
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<ResoureSearch #add>
|
<ResoureSearch #add>
|
||||||
|
@ -19,9 +24,14 @@
|
||||||
>
|
>
|
||||||
</ResoureSearch>
|
</ResoureSearch>
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<!-- 第三方列表-->
|
<template v-if="!isExper">
|
||||||
<ThirdList v-if="isThird" />
|
<!-- 第三方列表-->
|
||||||
<ResoureList v-else />
|
<ThirdList v-if="isThird" />
|
||||||
|
<ResoureList v-else />
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<ExperList/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 上传弹窗 -->
|
<!-- 上传弹窗 -->
|
||||||
|
@ -33,8 +43,12 @@ import { onMounted, ref, toRaw,watch } from 'vue'
|
||||||
import useResoureStore from './store'
|
import useResoureStore from './store'
|
||||||
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
import ChooseTextbook from '@/components/choose-textbook/index.vue'
|
||||||
import Third from '@/components/choose-textbook/third.vue'
|
import Third from '@/components/choose-textbook/third.vue'
|
||||||
|
// 科学学科对应实验室
|
||||||
|
import ExperimentBook from '@/components/choose-textbook/experimentBook.vue'
|
||||||
import ResoureSearch from './container/resoure-search.vue'
|
import ResoureSearch from './container/resoure-search.vue'
|
||||||
import ResoureList from './container/resoure-list.vue'
|
import ResoureList from './container/resoure-list.vue'
|
||||||
|
// 实验列表
|
||||||
|
import ExperList from './container/exper-list.vue'
|
||||||
import ThirdList from './container/third-list.vue'
|
import ThirdList from './container/third-list.vue'
|
||||||
import uploadDialog from '@/components/upload-dialog/index.vue'
|
import uploadDialog from '@/components/upload-dialog/index.vue'
|
||||||
import uploaderState from '@/store/modules/uploader'
|
import uploaderState from '@/store/modules/uploader'
|
||||||
|
@ -48,6 +62,8 @@ const openDialog = () => {
|
||||||
}
|
}
|
||||||
//判断是否去查看第三方资源
|
//判断是否去查看第三方资源
|
||||||
const isThird = ref(false)
|
const isThird = ref(false)
|
||||||
|
//判断是不是进入实验室
|
||||||
|
const isExper = ref(false)
|
||||||
|
|
||||||
// 查询
|
// 查询
|
||||||
const getData = (data) => {
|
const getData = (data) => {
|
||||||
|
@ -73,6 +89,7 @@ const getData = (data) => {
|
||||||
// 头部 教材分析打开外部链接需要当前章节ID
|
// 头部 教材分析打开外部链接需要当前章节ID
|
||||||
localStorage.setItem('unitId', JSON.stringify({ levelFirstId, levelSecondId}))
|
localStorage.setItem('unitId', JSON.stringify({ levelFirstId, levelSecondId}))
|
||||||
}
|
}
|
||||||
|
// 查询第三方资源
|
||||||
const getDataOther = (data) => {
|
const getDataOther = (data) => {
|
||||||
sourceStore.thirdQuery.chapterId = data.chapterId
|
sourceStore.thirdQuery.chapterId = data.chapterId
|
||||||
sourceStore.thirdQuery.bookId = data.bookId
|
sourceStore.thirdQuery.bookId = data.bookId
|
||||||
|
@ -80,6 +97,19 @@ const getDataOther = (data) => {
|
||||||
sourceStore.thirdQuery.subjectId = data.subjectId
|
sourceStore.thirdQuery.subjectId = data.subjectId
|
||||||
sourceStore.handleQuery()
|
sourceStore.handleQuery()
|
||||||
}
|
}
|
||||||
|
// 查询科学实验室的资源
|
||||||
|
const getExperData = (data) => {
|
||||||
|
const { textBook, node } = data
|
||||||
|
if (node.parentNode) {
|
||||||
|
sourceStore.query.levelFirstId = node.parentNode.id
|
||||||
|
sourceStore.query.levelSecondId = node.id
|
||||||
|
} else {
|
||||||
|
sourceStore.query.levelFirstId = node.id
|
||||||
|
sourceStore.query.levelSecondId = ''
|
||||||
|
}
|
||||||
|
sourceStore.query.textbookId = node.rootid
|
||||||
|
sourceStore.handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
// 提交文件
|
// 提交文件
|
||||||
const submitFile = (data) => {
|
const submitFile = (data) => {
|
||||||
|
@ -108,6 +138,15 @@ onMounted(() => {
|
||||||
watch(() => sourceStore.query.fileSource,() => {
|
watch(() => sourceStore.query.fileSource,() => {
|
||||||
sourceStore.query.fileSource === '第三方'?isThird.value = true:isThird.value = false
|
sourceStore.query.fileSource === '第三方'?isThird.value = true:isThird.value = false
|
||||||
})
|
})
|
||||||
|
watch(() => sourceStore.query.orderByColumn,() => {
|
||||||
|
if(sourceStore.query.orderByColumn === 'uploadTime'){
|
||||||
|
isExper.value = true
|
||||||
|
sourceStore.getCreate()
|
||||||
|
}else{
|
||||||
|
isExper.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -77,6 +77,7 @@ export default defineStore('resource', {
|
||||||
list: [],
|
list: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
},
|
},
|
||||||
|
activeIndex:1
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
|
@ -119,7 +120,16 @@ export default defineStore('resource', {
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
changeType(val) {
|
changeType(val) {
|
||||||
this.query.fileFlags = val
|
// 实验列表
|
||||||
|
if(val.label === '实验室'){
|
||||||
|
this.query.orderByColumn = 'uploadTime'
|
||||||
|
this.query.fileSuffix = 'mp4'
|
||||||
|
}else{
|
||||||
|
this.query.orderByColumn = 'createTime'
|
||||||
|
this.query.fileSuffix = ''
|
||||||
|
}
|
||||||
|
this.query.fileFlags = val.value
|
||||||
|
this.activeIndex = val.id
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
thirdChangeType(val) {
|
thirdChangeType(val) {
|
||||||
|
@ -136,7 +146,11 @@ export default defineStore('resource', {
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
getCreate(){
|
getCreate(){
|
||||||
if(this.query.fileSource == '平台' || this.query.fileSource == '第三方' ){
|
// 实验的时候也需要进入
|
||||||
|
if((this.query.fileSource == '平台' || this.query.fileSource == '第三方') || this.query.orderByColumn == 'uploadTime' ){
|
||||||
|
if(this.query.orderByColumn == 'uploadTime'){
|
||||||
|
this.query.fileSource = '平台'
|
||||||
|
}
|
||||||
this.isCreate = hasPermission(['platformmanager'])
|
this.isCreate = hasPermission(['platformmanager'])
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
|
@ -42,9 +42,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { completion } from '@/api/mode/index'
|
import { completion } from '@/api/mode/index'
|
||||||
|
import { dataSetJson } from '@/utils/comm.js'
|
||||||
import emitter from '@/utils/mitt';
|
import emitter from '@/utils/mitt';
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { ElMessage } from 'element-plus'
|
import { sendChart } from '@/api/ai/index'
|
||||||
|
|
||||||
const textarea = ref('')
|
const textarea = ref('')
|
||||||
|
|
||||||
|
@ -56,6 +57,14 @@ const props = defineProps({
|
||||||
default: () => {
|
default: () => {
|
||||||
return { name: '11' }
|
return { name: '11' }
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
curMode:{
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
conversation_id: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -77,13 +86,36 @@ const send = () => {
|
||||||
}
|
}
|
||||||
const curNode = reactive({})
|
const curNode = reactive({})
|
||||||
|
|
||||||
// 获取会话ID
|
const params = reactive(
|
||||||
|
{
|
||||||
|
prompt: '',
|
||||||
|
dataset_id: '',
|
||||||
|
template: ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 大模型对话
|
||||||
const getConversation = async (val) => {
|
const getConversation = async (val) => {
|
||||||
try {
|
try {
|
||||||
const { data } = await completion({
|
params.prompt = `按照${val}的要求,针对${curNode.edustage}${curNode.edusubject}课标,对${curNode.itemtitle}进行教学分析`
|
||||||
dataset_id: 'cee3062a9fcf11efa6910242ac140006',
|
params.template = props.item.prompt
|
||||||
prompt: val
|
|
||||||
})
|
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
|
||||||
|
}
|
||||||
|
|
||||||
msgList.value.push({
|
msgList.value.push({
|
||||||
type: 'robot',
|
type: 'robot',
|
||||||
msg: data.answer,
|
msg: data.answer,
|
||||||
|
@ -94,15 +126,16 @@ const getConversation = async (val) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveAdjust = (item) => {
|
const saveAdjust = (item) => {
|
||||||
// emit('saveAdjust', item.msg)
|
|
||||||
emitter.emit('changeAdjust', item.msg)
|
|
||||||
isDialog.value = false
|
isDialog.value = false
|
||||||
ElMessage.success('操作成功')
|
emitter.emit('onSaveAdjust', item.msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let data = sessionStore.get('subject.curNode')
|
let data = sessionStore.get('subject.curNode')
|
||||||
Object.assign(curNode, data);
|
Object.assign(curNode, data);
|
||||||
|
// 框架设计 用课标的dataset_id
|
||||||
|
let jsonKey = `课标-${data.edustage}-${data.edusubject}`
|
||||||
|
params.dataset_id = dataSetJson[jsonKey]
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
<div class="container-right flex">
|
<div class="container-right flex">
|
||||||
<div class="right-header flex">
|
<div class="right-header flex">
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<el-button type="primary" link>
|
<!-- <el-button type="primary" link>
|
||||||
<i class="iconfont icon-jiahao"></i>新活动
|
<i class="iconfont icon-jiahao"></i>新活动
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" link>
|
<el-button type="primary" link>
|
||||||
<i class="iconfont icon-baocun"></i>保存为教学模式
|
<i class="iconfont icon-baocun"></i>保存为教学模式
|
||||||
</el-button>
|
</el-button> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<el-select v-model="curMode" placeholder="Select" class="mr-4 w-30">
|
<el-select v-model="curMode" placeholder="Select" class="mr-4 w-30">
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<EditDialog v-model="isEdit" :item="curItem" />
|
<EditDialog v-model="isEdit" :item="curItem" />
|
||||||
<AdjustDialog v-model="isAdjust" :item="curItem" />
|
<AdjustDialog v-model="isAdjust" :item="curItem" :curMode="curMode" :conversation_id="conversation_id" />
|
||||||
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog" />
|
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog" />
|
||||||
<progress-dialog v-model:visible="pgDialog.visible" v-bind="pgDialog" />
|
<progress-dialog v-model:visible="pgDialog.visible" v-bind="pgDialog" />
|
||||||
<!--添加、编辑提示词-->
|
<!--添加、编辑提示词-->
|
||||||
|
@ -92,7 +92,9 @@ import * as API_entpcourse from '@/api/education/entpcourse' // 相关api
|
||||||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||||
import * as Api_server from '@/api/apiService' // 相关api
|
import * as Api_server from '@/api/apiService' // 相关api
|
||||||
import * as API_smarttalk from '@/api/file' // 文件相关api
|
import * as API_smarttalk from '@/api/file' // 文件相关api
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal'
|
||||||
|
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
|
import { createWindow } from '@/utils/tool' // 消息工具
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const pptDialog = ref(false)
|
const pptDialog = ref(false)
|
||||||
|
@ -117,7 +119,7 @@ const pgDialog = reactive({ // 弹窗-进度条
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const curMode = ref(1)
|
const curMode = ref(2)
|
||||||
const modeOptions = ref([
|
const modeOptions = ref([
|
||||||
{
|
{
|
||||||
label: '教学大模型',
|
label: '教学大模型',
|
||||||
|
@ -223,7 +225,7 @@ const editKeyWord = (item, val) => {
|
||||||
const removeItem = async (item, isChild) => {
|
const removeItem = async (item, isChild) => {
|
||||||
/**
|
/**
|
||||||
* item: 当前操作的模板
|
* item: 当前操作的模板
|
||||||
* isChild: 子模板中的移除为 true
|
* isChild: 子模板中的移除为 true
|
||||||
*/
|
*/
|
||||||
if (item.ex3 != '1') {
|
if (item.ex3 != '1') {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
|
@ -280,7 +282,7 @@ const scrollToBottom = (height, index) => {
|
||||||
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)
|
||||||
|
@ -346,13 +348,20 @@ const addAiPPT = async (res) => {
|
||||||
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
||||||
if (!!parentid ?? null) { // 生成内容幻灯片
|
if (!!parentid ?? null) { // 生成内容幻灯片
|
||||||
// 生成备课资源-Smarttalk
|
// 生成备课资源-Smarttalk
|
||||||
HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
||||||
if (slides.length > 0) {
|
if (slides.length > 0) {
|
||||||
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
|
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
|
||||||
const params = { parentid, filetype: 'slide', title: '', slides: resSlides }
|
const params = { parentid, filetype: 'slide', title: '', slides: resSlides }
|
||||||
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
|
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
|
||||||
if (res_3 && res_3.code == 200) {
|
if (res_3 && res_3.code == 200) {
|
||||||
msgUtils.msgSuccess('生成PPT课件成功')
|
msgUtils.msgSuccess('生成PPT课件成功')
|
||||||
|
//TODO 打开生成的课件
|
||||||
|
const res = await getEntpcoursefile(parentid)
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
openPublicScreen('edit', res.data, smarttalk.resData) // 打开公屏-窗口
|
||||||
|
} else {
|
||||||
|
ElMessage.warning(res.msg||'文件获取异常!')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msgUtils.msgWarning('生成PPT课件失败')
|
msgUtils.msgWarning('生成PPT课件失败')
|
||||||
}
|
}
|
||||||
|
@ -361,7 +370,20 @@ const addAiPPT = async (res) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openPublicScreen = (type, resource, currData)=> {
|
||||||
|
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||||
|
if (type=='edit') sessionStore.set('curr.smarttalk', currData) // 缓存当前文件smarttalk
|
||||||
|
else sessionStore.set('curr.classcourse', currData) // 缓存当前当前上课
|
||||||
|
createWindow('open-win', {
|
||||||
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
|
close: () => {
|
||||||
|
sessionStore.set('curr.resource', null) // 清除缓存
|
||||||
|
if (type=='edit') {
|
||||||
|
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
||||||
|
} else sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
const isEdit = ref(false)
|
const isEdit = ref(false)
|
||||||
// 当前操作的索引
|
// 当前操作的索引
|
||||||
const curIndex = ref(-1)
|
const curIndex = ref(-1)
|
||||||
|
@ -393,7 +415,7 @@ const againResult = async (index, item) => {
|
||||||
|
|
||||||
let data = null;
|
let data = null;
|
||||||
// 教学大模型
|
// 教学大模型
|
||||||
if (mode.value == 1) {
|
if (curMode.value == 1) {
|
||||||
const res = await sendChart({
|
const res = await sendChart({
|
||||||
content: params.prompt,
|
content: params.prompt,
|
||||||
conversationId: conversation_id.value,
|
conversationId: conversation_id.value,
|
||||||
|
@ -421,11 +443,21 @@ const onAdjust = (index, item) => {
|
||||||
Object.assign(curItem, item)
|
Object.assign(curItem, item)
|
||||||
isAdjust.value = true
|
isAdjust.value = true
|
||||||
}
|
}
|
||||||
emitter.on('changeAdjust', (item) => {
|
|
||||||
|
// 替换分析结果
|
||||||
|
emitter.on('onSaveAdjust', (item) => {
|
||||||
resultList.value[curIndex.value].answer = item
|
resultList.value[curIndex.value].answer = item
|
||||||
|
onEditSave(resultList.value[curIndex.value])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 保存 重新研读后的结果
|
||||||
|
const onEditSave = async (item) => {
|
||||||
|
const { msg } = await editTempResult({ id: item.resultId, content: item.answer })
|
||||||
|
ElMessage.success(msg)
|
||||||
|
getChildTemplate()
|
||||||
|
}
|
||||||
|
|
||||||
// 编辑
|
// 编辑
|
||||||
const onEdit = (index, item) => {
|
const onEdit = (index, item) => {
|
||||||
curIndex.value = index
|
curIndex.value = index
|
||||||
|
@ -585,7 +617,7 @@ onMounted(() => {
|
||||||
let data = sessionStore.get('subject.curNode')
|
let data = sessionStore.get('subject.curNode')
|
||||||
Object.assign(curNode, data);
|
Object.assign(curNode, data);
|
||||||
courseObj.node = data
|
courseObj.node = data
|
||||||
|
// 框架设计 用课标的dataset_id
|
||||||
let jsonKey = `课标-${data.edustage}-${data.edusubject}`
|
let jsonKey = `课标-${data.edustage}-${data.edusubject}`
|
||||||
params.dataset_id = commUtils.dataSetJson[jsonKey]
|
params.dataset_id = commUtils.dataSetJson[jsonKey]
|
||||||
|
|
||||||
|
@ -605,7 +637,7 @@ onUnmounted(() => {
|
||||||
emitter.off('changeMode')
|
emitter.off('changeMode')
|
||||||
emitter.off('changeResult')
|
emitter.off('changeResult')
|
||||||
emitter.off('changeAdjust')
|
emitter.off('changeAdjust')
|
||||||
|
emitter.off('onSaveAdjust');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -630,7 +662,7 @@ onUnmounted(() => {
|
||||||
background: #F6F6F6;
|
background: #F6F6F6;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
|
|
||||||
.con-item {
|
.con-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -725,4 +757,4 @@ onUnmounted(() => {
|
||||||
width: 110px !important;
|
width: 110px !important;
|
||||||
min-width: 110px !important;
|
min-width: 110px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue