Compare commits

..

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

119 changed files with 2334 additions and 5816 deletions

View File

@ -17,7 +17,6 @@ VITE_APP_RES_FILE_PATH = 'https://file.ysaix.com:7868/src/assets/textbook/booktx
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/' VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
# websocket 地址 # websocket 地址
# VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868' VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865' # VITE_APP_WS_URL = 'ws://192.168.2.16:7865'

View File

@ -1,8 +1,6 @@
# 页面标题 # 页面标题
VITE_APP_TITLE = 文枢课堂 VITE_APP_TITLE = 文枢课堂
VITE_APP_ID = 'aix-win-ws'
# 生产环境配置 # 生产环境配置
VITE_APP_ENV = 'production' VITE_APP_ENV = 'production'

27
.env.yc
View File

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

View File

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

View File

@ -1,54 +0,0 @@
appId: com.electron.app.yc
productName: 永川中小学AI教学系统
directories:
output: dist
buildResources: build
win:
executableName: 永川中小学AI教学系统
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}-${version}-setup.${ext}
shortcutName: ${productName}
uninstallDisplayName: ${productName}
createDesktopShortcut: always
mac:
entitlementsInherit: build/entitlements.mac.plist
extendInfo:
- NSCameraUsageDescription: Application requests access to the device's camera.
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
notarize: false
dmg:
artifactName: ${name}-${version}.${ext}
linux:
target:
- AppImage
- snap
- deb
maintainer: electronjs.org
category: Utility
appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://prev.ysaix.com:7868/src/assets/smarttalkyc/
electronDownload:
mirror: https://npmmirror.com/mirrors/electron/
# 额外依赖打包到输出目录
extraFiles:
- from: ./node_modules/im_electron_sdk/lib/
to: ./resources
filter:
- '**/*'

View File

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

View File

@ -35,7 +35,7 @@ export default defineConfig({
target: 'http://27.128.240.72:7865', target: 'http://27.128.240.72:7865',
// target: 'https://prev.ysaix.com:7868/prod-api/', // target: 'https://prev.ysaix.com:7868/prod-api/',
// target: 'http://36.134.181.164:7863', // target: 'http://36.134.181.164:7863',
// target: 'http://192.168.2.237:7865', // target: 'http://192.168.0.102:7865',
changeOrigin: true, changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '') rewrite: (p) => p.replace(/^\/dev-api/, '')
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "aix-win-ws", "name": "aix-win-ws",
"version": "2.5.15", "version": "2.5.6",
"description": "", "description": "",
"main": "./out/main/index.js", "main": "./out/main/index.js",
"author": "上海交大重庆人工智能研究院", "author": "上海交大重庆人工智能研究院",
@ -10,13 +10,12 @@
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix", "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"start": "electron-vite preview", "start": "electron-vite preview",
"dev": "electron-vite dev", "dev": "electron-vite dev",
"build": "electron-vite build",
"postinstall": "electron-builder install-app-deps", "postinstall": "electron-builder install-app-deps",
"build:unpack": "npm run build && electron-builder --dir", "build:unpack": "npm run build && electron-builder --dir",
"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": "node updatePackageJsonName.js && 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": "node updatePackageJsonName.js && 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": "node updatePackageJsonName.js && electron-vite build --mode yc && electron-builder --win --config ./electron-builder-yc.yml",
"build:yc2": "node updatePackageJsonName.js && 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"
@ -35,14 +34,12 @@
"@electron/remote": "^2.1.2", "@electron/remote": "^2.1.2",
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
"@icon-park/vue-next": "^1.4.2", "@icon-park/vue-next": "^1.4.2",
"@kangc/v-md-editor": "^2.3.18",
"@tinymce/tinymce-vue": "5.1.1", "@tinymce/tinymce-vue": "5.1.1",
"@vitejs/plugin-vue-jsx": "^4.0.0", "@vitejs/plugin-vue-jsx": "^4.0.0",
"@vue-office/docx": "^1.6.2", "@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.11", "@vue-office/excel": "^1.7.11",
"@vue-office/pdf": "^2.0.2", "@vue-office/pdf": "^2.0.2",
"@vueuse/core": "^10.11.0", "@vueuse/core": "^10.11.0",
"aix-plugins-aitools": "^1.1.0",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"circular-json": "^0.5.9", "circular-json": "^0.5.9",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

View File

@ -13,34 +13,6 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
const appTempFilePath = userDataPath + '\\tempFile\\' const appTempFilePath = userDataPath + '\\tempFile\\'
let Spark = new SparkMD5.ArrayBuffer() let Spark = new SparkMD5.ArrayBuffer()
ipcMain.on('remove-local-file-list', (e, list) => {
let filePath = appRootFilePath
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (!isAccess(filePath + item.fileNewName)) {
e.reply('remove-local-file-list-not', item)
continue
}
try {
fs.unlinkSync(filePath + item.fileNewName);
console.log(`${filePath} 已成功删除`);
} catch (err) {
console.error(`删除文件时出错:`, err);
e.reply('remove-local-file-list-error', item)
}
}
e.reply('remove-local-file-list-reply')
})
const isAccess = (filePath) => {
try {
fs.accessSync(filePath);
return true
} catch (err) {
return false
}
}
ipcMain.on('upload-file-change', (e, { id, fileNewName, cookie, fileType }) => { ipcMain.on('upload-file-change', (e, { id, fileNewName, cookie, fileType }) => {
let filePath = appRootFilePath + fileNewName let filePath = appRootFilePath + fileNewName
//执行更新,上传文件 //执行更新,上传文件
@ -86,6 +58,7 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
} }
//倒数十秒提交更改,十秒之内有继续修改则重置倒数 //倒数十秒提交更改,十秒之内有继续修改则重置倒数
uploadId = setTimeout(() => { uploadId = setTimeout(() => {
console.log(223)
//执行更新,上传文件 //执行更新,上传文件
let formData = new FormData() let formData = new FormData()
formData.append('id', id) formData.append('id', id)
@ -116,12 +89,8 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
function getFileMsg(path) { function getFileMsg(path) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try {
const stats = fs.statSync(path) const stats = fs.statSync(path)
resolve(stats.mtime.getTime()) return resolve(stats.mtime.getTime())
}catch (e) {
reject(e)
}
}) })
} }
@ -334,20 +303,17 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
}, },
onDownloadCancelled: async () => { onDownloadCancelled: async () => {
console.log("取消") console.log("取消")
resolve({type:"取消了下载"}) reject({type:"取消了下载"})
}, },
onDownloadInterrupted: async () => { onDownloadInterrupted: async () => {
console.log('中断') console.log('中断')
resolve({type:"下载被中断"}) reject({type:"下载被中断"})
}, },
onError: (err, data) => { onError: (err, data) => {
console.log(err.toString()) console.log(err.toString())
resolve({type:"下载出错",err}) reject({type:"下载出错",err})
} }
} }
}).catch(err=>{
console.log(err)
resolve({type:"下载出错",err})
}) })
}) })
} }
@ -359,11 +325,6 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
//下载文件 //下载文件
ipcMain.on('download-file-default', (e, { url, fileName }) => { ipcMain.on('download-file-default', (e, { url, fileName }) => {
console.log(url, fileName)
if (!url) {
e.reply('download-file-default' + fileName, false)
return;
}
createFolder('selfFile') createFolder('selfFile')
.then(async () => { .then(async () => {
const browserWindow = BrowserWindow.getFocusedWindow() const browserWindow = BrowserWindow.getFocusedWindow()
@ -399,7 +360,6 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
}) })
}) })
.catch((error) => { .catch((error) => {
console.log(error)
e.reply('download-file-default' + fileName, false) e.reply('download-file-default' + fileName, false)
}) })
}) })

View File

@ -7,7 +7,6 @@ import Logger from './logger' // 日志封装
import chat from './chat' // chat封装 import chat from './chat' // chat封装
import Store from './store' // Store封装 import Store from './store' // Store封装
import updateInit from './update' import updateInit from './update'
// 代理 electron/remote // 代理 electron/remote
// 第一步引入remote // 第一步引入remote
import remote from '@electron/remote/main' import remote from '@electron/remote/main'
@ -42,19 +41,19 @@ if(!gotTheLock){
} }
}) })
} }
let logoIco = import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?'../../resources/yc-logo.png':'../../resources/logo2.ico'
//登录窗口 //登录窗口
function createLoginWindow() { function createLoginWindow() {
if (loginWindow) return if (loginWindow) return
loginWindow = new BrowserWindow({ loginWindow = new BrowserWindow({
width: import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?1060:888, width: 888,
height: 520, height: 520,
show: false, show: false,
frame: false, frame: false,
autoHideMenuBar: true, autoHideMenuBar: true,
maximizable: false, maximizable: false,
resizable: false, resizable: false,
icon: join(__dirname, logoIco), icon: join(__dirname, '../../resources/logo2.ico'),
...(process.platform === 'linux' ? { icon } : {}), ...(process.platform === 'linux' ? { icon } : {}),
webPreferences: { webPreferences: {
defaultEncoding: 'utf-8', defaultEncoding: 'utf-8',
@ -96,7 +95,7 @@ function createMainWindow() {
frame: false, // 无边框 frame: false, // 无边框
autoHideMenuBar: true, autoHideMenuBar: true,
maximizable: false, maximizable: false,
icon: join(__dirname, logoIco), icon: join(__dirname, '../../resources/logo2.ico'),
...(process.platform === 'linux' ? { icon } : {}), ...(process.platform === 'linux' ? { icon } : {}),
webPreferences: { webPreferences: {
defaultEncoding: 'utf-8', defaultEncoding: 'utf-8',
@ -244,13 +243,6 @@ app.on('ready', () => {
loginWindow.show() loginWindow.show()
loginWindow.focus() loginWindow.focus()
}) })
// 打印窗口
ipcMain.on('printPage', (event, printOptions) => {
//console.log("ipcMain-print-page")
mainWindow.webContents.print(printOptions, (success, failureReason) => {
if (!success) console.error(failureReason);
});
});
//打开作业窗口 //打开作业窗口
ipcMain.on('openWindow', (e, data) => { ipcMain.on('openWindow', (e, data) => {

View File

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

5430
src/renderer/public/aaa.pdf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
<svg style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6511">
<path d="M512 34.133333c263.466667 0 477.866667 214.4 477.866667 477.866667S775.466667 989.866667 512 989.866667 34.133333 775.466667 34.133333 512 248.533333 34.133333 512 34.133333M512 0C229.333333 0 0 229.333333 0 512s229.333333 512 512 512 512-229.333333 512-512S794.666667 0 512 0z" fill="#87C1FF" p-id="6512"></path><path d="M505.173333 611.62666667c100.053333 0 181.333333-80.64 181.333334-180.053333 0-99.2-81.28-180.053333-181.333334-180.053334-100.053333 0-181.333333 80.64-181.333333 180.053334s81.28 180.053333 181.333333 180.053333zM579.84 661.54666667h-135.893333c-126.293333 0-229.12 102.4-229.12 228.053333v13.44c0 65.706667 101.12 65.706667 229.12 65.706667h135.893333c122.88 0 229.12 0 229.12-65.706667v-13.44c0-125.653333-102.826667-228.053333-229.12-228.053333z" fill="#87C1FF" p-id="6513"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1006 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 58 44" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path id="path" d="M57.25 3.64C56.64 3.33 56.37 3.91 56.01 4.21C55.89 4.3 55.79 4.43 55.68 4.54C54.79 5.52 53.74 6.16 52.37 6.08C50.38 5.97 48.67 6.61 47.16 8.16C46.84 6.24 45.77 5.1 44.15 4.36C43.3 3.98 42.45 3.6 41.85 2.77C41.44 2.17 41.32 1.51 41.12 0.86C40.98 0.47 40.85 0.07 40.41 0C39.93 -0.07 39.74 0.34 39.55 0.68C38.8 2.09 38.5 3.64 38.53 5.2C38.6 8.73 40.06 11.54 42.96 13.54C43.29 13.76 43.38 13.99 43.27 14.33C43.08 15.02 42.84 15.68 42.63 16.37C42.5 16.81 42.3 16.91 41.84 16.72C40.25 16.04 38.87 15.04 37.65 13.82C35.59 11.79 33.72 9.54 31.39 7.78C30.85 7.37 30.3 6.99 29.73 6.63C27.36 4.28 30.05 2.35 30.67 2.12C31.32 1.88 30.89 1.06 28.79 1.06C26.69 1.07 24.77 1.79 22.31 2.75C21.96 2.89 21.58 3 21.19 3.08C18.97 2.65 16.66 2.56 14.24 2.83C9.7 3.35 6.07 5.54 3.4 9.27C0.19 13.76 -0.56 18.87 0.36 24.19C1.33 29.8 4.14 34.44 8.46 38.07C12.94 41.84 18.1 43.68 23.98 43.33C27.56 43.12 31.54 42.63 36.02 38.76C37.16 39.33 38.34 39.56 40.31 39.74C41.83 39.88 43.29 39.66 44.43 39.42C46.2 39.04 46.08 37.37 45.43 37.06C40.24 34.6 41.38 35.6 40.34 34.79C42.98 31.6 46.96 28.3 48.52 17.59C48.64 16.74 48.54 16.2 48.52 15.51C48.51 15.09 48.6 14.93 49.07 14.88C50.38 14.73 51.64 14.37 52.8 13.72C56.16 11.84 57.52 8.77 57.84 5.08C57.89 4.51 57.83 3.93 57.25 3.64ZM27.91 36.83C22.88 32.8 20.44 31.47 19.43 31.53C18.49 31.59 18.65 32.68 18.86 33.4C19.08 34.11 19.36 34.6 19.76 35.22C20.03 35.63 20.22 36.24 19.48 36.7C17.86 37.72 15.04 36.35 14.91 36.29C11.63 34.32 8.89 31.72 6.95 28.16C5.09 24.74 4 21.07 3.82 17.16C3.78 16.21 4.05 15.88 4.97 15.7C6.19 15.48 7.44 15.43 8.66 15.61C13.8 16.37 18.17 18.71 21.84 22.42C23.94 24.53 25.52 27.06 27.15 29.52C28.89 32.14 30.75 34.63 33.13 36.68C33.97 37.4 34.64 37.94 35.28 38.34C33.35 38.56 30.12 38.61 27.91 36.83ZM30.33 21.02C30.33 20.6 30.66 20.26 31.07 20.26C31.17 20.26 31.25 20.28 31.33 20.31C31.43 20.35 31.53 20.41 31.6 20.49C31.73 20.63 31.81 20.82 31.81 21.02C31.81 21.44 31.48 21.77 31.06 21.77C30.65 21.77 30.33 21.44 30.33 21.02ZM37.82 24.93C37.34 25.14 36.86 25.31 36.4 25.33C35.68 25.36 34.9 25.07 34.48 24.71C33.82 24.14 33.35 23.83 33.15 22.84C33.06 22.42 33.11 21.77 33.19 21.4C33.36 20.6 33.17 20.08 32.61 19.61C32.16 19.23 31.58 19.12 30.95 19.12C30.72 19.12 30.5 19.02 30.34 18.93C30.07 18.8 29.86 18.47 30.06 18.05C30.13 17.92 30.45 17.6 30.53 17.54C31.38 17.04 32.37 17.2 33.29 17.58C34.14 17.93 34.78 18.58 35.7 19.5C36.65 20.61 36.82 20.91 37.35 21.74C37.78 22.39 38.16 23.06 38.43 23.83C38.59 24.3 38.38 24.7 37.82 24.93Z" fill="#4D6BFE" fill-opacity="1.000000" fill-rule="nonzero"></path></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="96" height="97">
<g transform="matrix(1.3333334 0 0 1.3333334 0 0)">
<image x="0" y="0" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABhCAYAAAApxKSdAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAT2SURBVHhe7Z0/stowEMYp04UuZahSZqjSZYYmXQqKpEtBn+IxSZcm3ABuQG7wuAFH4AgcgSMQfcp7xDYf9uKVZOt5d+bXyJYt76c/K9mIkdlwbOyYOKaOmWPuWBRYOlaJwL2K90ZZUCaAMqKs2RoKj4daOx4dR8fJcc4MlPngwDNANIgEcXppqNW/HXA2e5iXBERB5eqFGGiyewcr6BDAs8MHyQ3qD9nxVbaOZC3iwZFjn54CdMPRDIOr1fpmMGgHbw244BAG2FDAV8FEQIRjzr+fICJYzdeBsbK1COb8MLRuCeb8cGDydtfyBmZ67EJGe+BTkWEdh13A0COaNVvXEw/4trYrwkyOZTTCgZVVahb1pAGhKW0F1veng7YCq/3pQFhaMiw3sBONeJQiIrwjZScZ8YDPL2bLzOmBzy9mL1jSA597Q0jEThgm48k/2LHw+EU6DAbs4LD48HAe/TydR7/O//m2jy0GPnWx+H/0aV12fJEfTpS3M55PD3zvJwXsYGvm8/m5yXa7Hc3bluPx+HTlehuPx+W87xfc8UW+H8t5wuEnZH8KCUFYLBZPj3vb9nvXvEneNkjuB9tut9f5vz5yp1d5M73Oqwefs/i3+Oxga1ILIK39kwnpz9HPM4dXQUup5tXjBQg+B0gpgKr2A3QvzOFV4gjg5wJZC4DrSIzWfiDtgt7NeX4dXoDgi3CpBIBTJXaz9oOPK+7wKq+jhKPwfb4CwLESm81qwshXLiqqxv9VPtcIqCNfAaS1X3SfulaAQRoisXx68hVAWvtRFpb/Ama6xRaAQRl8cWNDnIG3iBeAHVCRQgBJ6IlzWN4S6NshQrxa3gRNVBFbAMn1YY21vx/QRBWxBQhW+/sBTVQRU4AXVvsBTVQRUwDka7KMaj+giSpiCSANPafTKAtnsaCJKmIJIAk9VysX05O8PYYmqoghgKT2bzYbmrfn0EQVMQSoq/2Hw8Hfk+XLAJqoQiLA6XTyIkjB+beMnQ/W63UO4wFNVCERIKWh9dxcju4emqiibwLAEJr2tDXQRBV9FACGbqyHLYEmquhagLqlCowNrMwdQhNVdCkAnI+5QJ3VvqBJD01U0aUAuHeTAD1rBTRRRVcCLJdLf/8mATAWVMvcITRRRUoB4EzMgIuDa5MAsB4NxjRRhUQAzF7RF7cFIeXVZ4ZPSATANVjeDqCJKiQCxOyHTQAT4B5oogoT4C5oogoT4C5oogoT4C5oooquBcB8oMlMgIgCSO5vApgAz+T5bWgdGQmQ78e5dZgAJoAUE6BjvABZ/0aMkZEA+f9Ij5GbANn/ULtKRgLsHCZAh/gfagffK8IEEOP3igi+W4oJIMbvloI9a9jB1pgAYvzGfdi1iR004nPZwNX2jEvPZc84WPC5gNGInwM8m+0bmp7SvqG2cV96sFtxybCfMTvRCI9fhKta8AmZcRMf/1cNIZFFQ/FB7b/5r0rWCuLjlx9uGVpB8Bc0xgXa91fNIqJ40L6f2cbBLmC0Bz4VG7oiC0vDIep6qmb/qhSG2qinyZDRQtP2qJz/bNYS2gGfXS03tDUT4T6C1Pyq4YLBd1p/gWCZ+fKiJYbZbJmDsbK0xBzT0BqCf86SMaj1wbsciWHWPOS3aXh2/2K9a4P6mOkNYfKGARbdcLAIJ7RBDHzqgkJi0IYoOc4lUGY4G8+AyoV1nMCD62j0F2POfFZ8DMaTAAAAAElFTkSuQmCC" preserveAspectRatio="none" width="72" height="72.75"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 220 KiB

View File

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

View File

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

View File

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

View File

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

View File

@ -126,14 +126,10 @@ export class MsgEnum {
MSG_homework : 'HOMEWORK', MSG_homework : 'HOMEWORK',
/** @desc: 公屏 - 课堂作业|活动 */ /** @desc: 公屏 - 课堂作业|活动 */
MSG_pushSreen_work : 'pushSreen_work', MSG_pushSreen_work : 'pushSreen_work',
/** @desc: 公屏 - 实验 */
MSG_pushSreen_experiment : 'pushSreen_experiment',
/** @desc: 点赞 */ /** @desc: 点赞 */
MSG_dz : 'dz', MSG_dz : 'dz',
/** @desc: 疑惑 */ /** @desc: 疑惑 */
MSG_yh : 'yh', MSG_yh : 'yh',
/** @desc: 推图片上屏 */
MSG_pushSreen_ImgList : 'pushSreen_ImgList',
// === 新定义-消息头 === // === 新定义-消息头 ===
/** @desc: 课程创建-待开课 */ /** @desc: 课程创建-待开课 */
MSG_0000: 0x0000, MSG_0000: 0x0000,

View File

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

View File

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

View File

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

View File

@ -5,21 +5,14 @@
</header> </header>
<div class="flex material-list" v-loading="loading"> <div class="flex material-list" v-loading="loading">
<div class="flex material-item" v-for="item in list" :key="item.id" > <div class="flex material-item" v-for="item in list" :key="item.id" >
<div class="flex material-item"> <div class="flex">
<el-image v-if="item.fileType.indexOf('image')!=-1" :src="fileUrl(item)" class="img" /> <el-image :src="fileUrl(item)" class="img" />
<svg v-if="item.fileType.indexOf('video')!=-1" class="icon file-icon" aria-hidden="true" :style="{ 'font-size': 100 + 'px' }"> <el-text truncated>{{ item.fileShowName }}</el-text>
<use :xlink:href="'#icon-video'"></use>
</svg>
<svg class="icon file-icon" v-if="item.fileType.indexOf('audio')!=-1" aria-hidden="true" :style="{ 'font-size': 100 + 'px' }">
<use :xlink:href="'#icon-mp'"></use>
</svg>
<div class="texts">{{ item.fileShowName }}</div>
<!-- <el-text truncated>{{ item.fileShowName }}</el-text> -->
</div> </div>
<el-button style="margin-left: 10px;" type="primary" @click="onInsert(item)">插入</el-button> <el-button type="primary" @click="onInsert(item)">插入</el-button>
</div> </div>
<el-empty description="暂无素材" v-if="!list.length" /> <el-empty description="暂无素材" v-if="!list.length" />
</div> </div>
</template> </template>
<script setup> <script setup>
@ -28,7 +21,6 @@ import { sessionStore } from '@/utils/store'
import { getSmarttalkPage } from '@/api/file' import { getSmarttalkPage } from '@/api/file'
import * as commUtils from '@/utils/comm.js' import * as commUtils from '@/utils/comm.js'
import { getFileSuffix } from '@/utils/ruoyi.js' import { getFileSuffix } from '@/utils/ruoyi.js'
import { PPTApi } from '../../../api'
const emit = defineEmits(['insertMaterial', 'close']) const emit = defineEmits(['insertMaterial', 'close'])
@ -44,7 +36,7 @@ let params = {
pageSize: 500 pageSize: 500
} }
const suffixAry = [ 'jpeg','jpg','png','gif','mp3','mp4','avi','mov',"wav"] const suffixAry = [ 'jpeg','jpg','png','gif','mp3','mp4','avi','mov']
const videoSuffix = ['mp3','mp4','avi','mov'] const videoSuffix = ['mp3','mp4','avi','mov']
const list = ref([]) const list = ref([])
const loading = ref(false) const loading = ref(false)
@ -55,7 +47,6 @@ const init = () => {
if(res.rows && res.rows.length){ if(res.rows && res.rows.length){
// //
list.value = res.rows.filter( item => suffixAry.indexOf(getFileSuffix(item.fileShowName)) != -1) list.value = res.rows.filter( item => suffixAry.indexOf(getFileSuffix(item.fileShowName)) != -1)
console.log(list.value)
} }
}) })
} }
@ -69,34 +60,73 @@ const fileUrl = computed(() => (item) =>{
} }
}) })
// //
const onInsert = async (item) =>{ const onInsert = async (item) =>{
loading.value = true const res = await fetch(item.fileFullPath)
const bolb = await res.blob()
const file = commUtils.blobToFile(bolb, item.fileShowName)
// const res = await fetch(item.fileFullPath)
// const bolb = await res.blob()
// const file = commUtils.blobToFile(bolb, item.fileShowName)
const data=item.fileFullPath
try {
console.log('item', item)
// const data = await PPTApi.toRousrceUrl(file)
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){ if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
emit('insertMaterial',{ type: 'video', data }) emit('insertMaterial',{ type: 'video', file })
}else if(item.fileType.indexOf('audio') != -1){
emit('insertMaterial',{ type: 'audio', data })
}else{
emit('insertMaterial',{ type: 'img', data })
} }
} finally { else{
loading.value = false emit('insertMaterial',{ type: 'img', file })
} }
} }
const GetUrlParameters = (parameters) => {
let resData = "";
let url = document.location.toString();
let arrUrl = url.split("?");
//
if (arrUrl.length > 1) {
//
let parametersArr = arrUrl[1].split("&");
//
for (let i = 0; i <= parametersArr.length; i++) {
if (parametersArr[i]) {
//
let parameterStr = parametersArr[i].split("=");
if (parameters == parameterStr[0]) {
resData = parameterStr[1];
break;
}
}
}
}
return resData;
}
const proxyToBase64 = (url)=> {
const dourl = GetUrlParameters(url)
console.log(dourl,'dourl')
return
axios({
url: "/api/logo.png",
method: "get",
responseType: "blob",
}).then((res) => {
const reader = new FileReader();
reader.readAsDataURL(res.data);
reader.onload = () => {
console.log(reader.result);
};
});
}
// //
const onClose = () =>{ const onClose = () =>{
emit('close') emit('close')
} }
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data);
@ -136,17 +166,11 @@ onMounted(() => {
align-items: center; align-items: center;
margin-bottom: 10px; margin-bottom: 10px;
font-size: 14px; font-size: 14px;
justify-content: space-between;
.img{ .img{
width: 100px; width: 100px;
height: 100px; height: 100px;
margin-right: 20px; margin-right: 20px;
} }
} }
.texts{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 600px;
}
</style> </style>

View File

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

View File

@ -3,7 +3,7 @@
<div class="left"> <div class="left">
<Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible"> <Popover trigger="click" placement="bottom-start" v-model:value="mainMenuVisible">
<template #content> <template #content>
<!-- <FileInput accept=".pptist" @change="files => { <FileInput accept=".pptist" @change="files => {
importSpecificFile(files) importSpecificFile(files)
mainMenuVisible = false mainMenuVisible = false
}"> }">
@ -15,8 +15,8 @@
}"> }">
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem> <PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
</FileInput> </FileInput>
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem> --> <PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem>
<!-- <PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem> --> <PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem>
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> --> <!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> -->
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> --> <!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
<PopoverMenuItem @click="mainMenuVisible = false; hotkeyDrawerVisible = true">快捷操作</PopoverMenuItem> <PopoverMenuItem @click="mainMenuVisible = false; hotkeyDrawerVisible = true">快捷操作</PopoverMenuItem>
@ -54,9 +54,9 @@
<div class="arrow-btn"><IconDown class="arrow" /></div> <div class="arrow-btn"><IconDown class="arrow" /></div>
</Popover> </Popover>
</div> </div>
<!-- <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')"> <div class="menu-item" v-tooltip="'导出'" @click="setDialogForExport('pptx')">
<IconDownload class="icon" /> <IconDownload class="icon" />
</div> --> </div>
<div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`"> <div class="menu-item" v-tooltip="`${userStore.user.parentDeptName}-${userStore.user.nickName}`">
<el-avatar size="small" :src="avatar" /> <el-avatar size="small" :src="avatar" />
</div> </div>

View File

@ -95,8 +95,8 @@
style="width: 65%;" style="width: 65%;"
:options="[ :options="[
{ label: '主动触发', value: 'click' }, { label: '主动触发', value: 'click' },
// { label: '', value: 'meantime' }, { label: '与上一动画同时', value: 'meantime' },
// { label: '', value: 'auto' }, { label: '上一动画之后', value: 'auto' },
]" ]"
/> />
</div> </div>

View File

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

View File

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

View File

@ -36,8 +36,8 @@
</div> </div>
<div <div
class="tools-right" :class="{ 'visible': rightToolsVisible }" class="tools-right" :class="{ 'visible': rightToolsVisible }"
@mouseleave="toolTrigger('leave')" @mouseleave="rightToolsVisible = false"
@mouseenter="toolTrigger('enter')" @mouseenter="rightToolsVisible = true"
> >
<div class="content"> <div class="content">
<div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div> <div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
@ -47,14 +47,8 @@
<IconListView class="tool-btn" v-tooltip="'演讲者视图'" @click="changeViewMode('presenter')" /> <IconListView class="tool-btn" v-tooltip="'演讲者视图'" @click="changeViewMode('presenter')" />
<IconOffScreenOne class="tool-btn" v-tooltip="'退出全屏'" v-if="fullscreenState" @click="manualExitFullscreen()" /> <IconOffScreenOne class="tool-btn" v-tooltip="'退出全屏'" v-if="fullscreenState" @click="manualExitFullscreen()" />
<IconFullScreenOne class="tool-btn" v-tooltip="'进入全屏'" v-else @click="enterFullscreen()" /> <IconFullScreenOne class="tool-btn" v-tooltip="'进入全屏'" v-else @click="enterFullscreen()" />
<Hands class="tool-btn" v-if="classcourse" v-tooltip="'课堂点名'" @click="ToolHandle('named')" /> <IconPower class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
<Share class="tool-btn" v-if="classcourse" v-tooltip="'分享'" @click="ShareCode()" /> <IconPower class="tool-btn close" v-if="chat.groupid" v-tooltip="'结束课堂'" @click="exitCourse()" />
<IconPower class="tool-btn" v-if="!classcourse" v-tooltip="'结束放映'" @click="exitScreening()" />
<IconPower class="tool-btn" v-else v-tooltip="'结束课堂'" @click="exitCourse()" size="30" fill="#d0021b" strokeLinecap="butt" />
</div>
<div :class="['tools-icon',{opacity:iconHide}]" @click.stop="toolTrigger('icon')">
<circle-double-down v-if="rightToolsVisible" theme="outline" size="30" fill="#409EFF"/>
<circle-double-up v-else="!rightToolsVisible" theme="outline" size="30" fill="#E6A23C"/>
</div> </div>
</div> </div>
</div> </div>
@ -77,8 +71,6 @@ import WritingBoardTool from './WritingBoardTool.vue'
import CountdownTimer from './CountdownTimer.vue' import CountdownTimer from './CountdownTimer.vue'
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
import Chat from '../../api/chat' // import Chat from '../../api/chat' //
import { CircleDoubleDown, CircleDoubleUp, Share, Hands } from '@icon-park/vue-next' // icon-park
import { ShareCode, ToolHandle } from '@/utils/ppt' // ppt
const props = defineProps<{ const props = defineProps<{
changeViewMode: (mode: 'base' | 'presenter') => void changeViewMode: (mode: 'base' | 'presenter') => void
@ -105,22 +97,18 @@ const {
execPrev, execPrev,
execNext, execNext,
animationIndex, animationIndex,
turning,
} = useExecPlay() } = useExecPlay()
const { slideWidth, slideHeight } = useSlideSize() const { slideWidth, slideHeight } = useSlideSize()
const { exitScreening } = useScreening() const { exitScreening } = useScreening()
const { fullscreenState, manualExitFullscreen } = useFullscreen() const { fullscreenState, manualExitFullscreen } = useFullscreen()
const chat:any = Chat() // const chat:any = Chat() //
const screenStore =useScreenStore()
const rightToolsVisible = ref(false) const rightToolsVisible = ref(false)
const writingBoardToolVisible = ref(false) const writingBoardToolVisible = ref(false)
const timerlVisible = ref(false) const timerlVisible = ref(false)
const slideThumbnailModelVisible = ref(false) const slideThumbnailModelVisible = ref(false)
const laserPen = ref(false) const laserPen = ref(false)
const timer = ref(0) // const screenStore =useScreenStore()
const iconHide = ref(false) //
const timerId = ref(null) // id
const contextmenus = (): ContextmenuItem[] => { const contextmenus = (): ContextmenuItem[] => {
return [ return [
{ {
@ -202,31 +190,7 @@ const contextmenus = (): ContextmenuItem[] => {
}, },
] ]
} }
//
const toolTrigger = (type:string) => {
const curT = Date.now()
if (curT - timer.value < 200) return
iconHide.value = false //
if (timerId.value) clearTimeout(timerId.value) //
switch (type) {
case 'icon': //
timer.value = curT
rightToolsVisible.value = !rightToolsVisible.value
break
case 'enter': //
timer.value = curT
rightToolsVisible.value = true
break
case 'leave': //
rightToolsVisible.value = false
break
default:
break
}
timerId.value = setTimeout(() => { //
iconHide.value = true //
}, 2000)
}
// //
const exitCourse = async () => { const exitCourse = async () => {
// console.log('', chat) // console.log('', chat)
@ -289,18 +253,6 @@ const exitCourse = async () => {
top: -66px; top: -66px;
} }
.tools-icon{
position: absolute;
right: 8px;
top: -35px;
z-index: 1;
cursor: pointer;
transition: opacity $transitionDelay;
&.opacity{
opacity: .35;
}
}
.content { .content {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

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

View File

@ -28,9 +28,8 @@ export default (isLoader?: boolean = true) => {
// 执行元素动画 isAsync 为 true 时,异步执行,否则同步执行 // 执行元素动画 isAsync 为 true 时,异步执行,否则同步执行
const runAnimation = (isAsync: boolean) => { const runAnimation = (isAsync: boolean) => {
return new Promise((resolve, reject) => {
// 正在执行动画时,禁止其他新的动画开始 // 正在执行动画时,禁止其他新的动画开始
if (inAnimation.value && !isAsync) return resolve() if (inAnimation.value && !isAsync) return
const { animations, autoNext } = formatedAnimations.value[animationIndex.value] const { animations, autoNext } = formatedAnimations.value[animationIndex.value]
animationIndex.value += 1 animationIndex.value += 1
@ -61,7 +60,7 @@ export default (isLoader?: boolean = true) => {
elRef.classList.add(animationName, `${ANIMATION_CLASS_PREFIX}animated`) elRef.classList.add(animationName, `${ANIMATION_CLASS_PREFIX}animated`)
// 执行动画结束,将“退场”以外的动画状态清除 // 执行动画结束,将“退场”以外的动画状态清除
const handleAnimationEnd = async() => { const handleAnimationEnd = () => {
if (animation.type !== 'out') { if (animation.type !== 'out') {
elRef.style.removeProperty('--animate-duration') elRef.style.removeProperty('--animate-duration')
elRef.classList.remove(animationName, `${ANIMATION_CLASS_PREFIX}animated`) elRef.classList.remove(animationName, `${ANIMATION_CLASS_PREFIX}animated`)
@ -71,13 +70,11 @@ export default (isLoader?: boolean = true) => {
endAnimationCount += 1 endAnimationCount += 1
if (endAnimationCount === animations.length) { if (endAnimationCount === animations.length) {
inAnimation.value = false inAnimation.value = false
if (autoNext) await runAnimation() if (autoNext) runAnimation()
resolve() // 执行完成
} }
} }
elRef.addEventListener('animationend', handleAnimationEnd, { once: true }) elRef.addEventListener('animationend', handleAnimationEnd, { once: true })
} }
})
} }
if (isLoader) { // 加载相关钩子 if (isLoader) { // 加载相关钩子
onMounted(() => { onMounted(() => {
@ -150,7 +147,7 @@ export default (isLoader?: boolean = true) => {
} }
inAnimation.value = false inAnimation.value = false
} }
const execNext = async(isAsync: boolean) => { const execNext = (isAsync: boolean) => {
if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) { if (formatedAnimations.value.length && animationIndex.value < formatedAnimations.value.length) {
runAnimation(isAsync) runAnimation(isAsync)
} }
@ -219,17 +216,9 @@ export default (isLoader?: boolean = true) => {
// 向上翻页/向下翻页 // 向上翻页/向下翻页
const turning = async (e, type) => { const turning = async (e, type) => {
e.preventDefault() // 阻止默认事件 e.preventDefault() // 阻止默认事件
window.scrollTo(0, 0) // 滚动到顶部 if (type === 'prev') execPrev()
const isCourse = !!classcourseStore.classcourse else if (type === 'next') execNext()
if (type === 'prev') { if (classcourseStore.classcourse) { // 上课中
if (!isCourse) execPrev() // 上一步
else { // 上课状态: 上一步 动作变成 上一页
const current = slideIndex.value
if (current <= 0) return throttleMassage('已经是第一页了')
turnSlideToIndex(current - 1) // 翻页: 上一页
}
} else if (type === 'next') execNext()
if (isCourse) { // 上课中
const current = slideIndex.value const current = slideIndex.value
const animationSteps = animationIndex.value const animationSteps = animationIndex.value
const animation = type == 'next'?'Nextsteps':'Previoustep' const animation = type == 'next'?'Nextsteps':'Previoustep'
@ -296,6 +285,5 @@ export default (isLoader?: boolean = true) => {
execPrev, execPrev,
execNext, execNext,
animationIndex, animationIndex,
turning,
} }
} }

View File

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

View File

@ -15,7 +15,7 @@ const size = ref('default')
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
/* text-align: center; */ text-align: center;
color: #2c3e50; color: #2c3e50;
width: 100%; width: 100%;
} }

View File

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

View File

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

View File

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

View File

@ -79,19 +79,3 @@ export const getModelInfo = (params) => {
params params
}) })
} }
// 上传tts语音
export const aitts = (data) => {
return request({
url: '/aitts/createTts',
method: 'post',
data
})
}
// 语音关联课
export const addFileToSC = (params) => {
return request({
url: '/smarttalk/file/addFileToSC',
method: 'post',
params
})
}

View File

@ -118,36 +118,4 @@ export function docList(params) {
}) })
} }
// 保存教学大纲
export function addSyllabus(data) {
return request({
url: '/education/generate',
method: 'post',
data
})
}
// 获取保存的大纲列表
export function syllabusList(params) {
return request({
url: '/education/generate/list',
method: 'get',
params
})
}
// 删除大纲
export function removeSyllabus(id) {
return request({
url: '/education/generate/' + id,
method: 'delete',
})
}
export function editSyllabus(data) {
return request({
url: '/education/generate',
method: 'put',
data
})
}

View File

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

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4723712 */ font-family: "iconfont"; /* Project id 4723712 */
src: url('iconfont.woff2?t=1735483000546') format('woff2'), src: url('iconfont.woff2?t=1734337029245') format('woff2'),
url('iconfont.woff?t=1735483000546') format('woff'), url('iconfont.woff?t=1734337029245') format('woff'),
url('iconfont.ttf?t=1735483000546') format('truetype'); url('iconfont.ttf?t=1734337029245') format('truetype');
} }
.iconfont { .iconfont {
@ -13,10 +13,6 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-chuangzuo:before {
content: "\e6cc";
}
.icon-yinle:before { .icon-yinle:before {
content: "\e6c9"; content: "\e6c9";
} }

File diff suppressed because one or more lines are too long

View File

@ -5,13 +5,6 @@
"css_prefix_text": "icon-", "css_prefix_text": "icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "39170417",
"name": "创作",
"font_class": "chuangzuo",
"unicode": "e6cc",
"unicode_decimal": 59084
},
{ {
"icon_id": "11819186", "icon_id": "11819186",
"name": "音乐", "name": "音乐",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 KiB

View File

@ -1,240 +0,0 @@
<template>
<div>
<div style="height: auto; display: flex">
<div style="flex: 1">
<div class="audio-container">
<aiAudio
@saveClick="saveClick"
ref="audioRef"
:audioSrc="audioSrc"
@auditionClick="auditionClick"
></aiAudio>
</div>
</div>
<div style="background: #fff; height: 85vh; min-width: 364px; margin-left: 20px;overflow: hidden;">
<div style="padding: 0 20px; height: 100%;">
<el-tabs v-model="activeTab" class="prepare-tabs">
<el-tab-pane label="素材" name="素材">
<div class="prepare-body-header">
<div>
<label style="font-size: 15px"
>{{
currentFileList.filter(
(ite) => ite.fileFlag !== 'apt' && ite.fileFlag !== '课件'
).length
}}个文件</label
>&nbsp;
<!-- <el-popover placement="top-start" :width="250" trigger="hover">
<template #default>
<div>
<el-button
v-if="lastAsyncAllTime"
type="success"
size="small"
:icon="Check"
circle
/>
{{ lastAsyncAllTime ? toTimeText(lastAsyncAllTime) + '同步成功' : '' }}
</div>
</template>
<template #reference>
<el-button size="small" text @click="asyncAllFile">
<el-icon v-loading="asyncAllFileVisiable">
<Refresh />
</el-icon>
{{ asyncAllFileVisiable ? '同步中' : '云同步' }}
</el-button>
</template>
</el-popover> -->
<!-- <el-button size="small" @click="isDialogOpen = true">上传资料</el-button>
<el-button size="small" @click="reloadFiles">资源重载</el-button> -->
</div>
</div>
<el-checkbox-group
v-model="checkFileList"
class="prepare-body-main"
:style="{ 'margin-bottom': checkFileList.length > 0 ? '40px' : '0' }"
>
<file-list-item
v-for="(item, index) in currentSCFileList"
:key="index"
:item="item"
:index="index"
@on-delete="deleteSuccess"
>
</file-list-item>
</el-checkbox-group>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</div>
</template>
<script>
import { useRoute } from 'vue-router'
import { getSmarttalkPage, moveSmarttalk, creatAPT } from '@/api/file'
import FileListItem from '@/views/prepare/container/file-list-item.vue'
import { parseCataByNode, creatPPT, asyncLocalFile, removeLocalFiles } from '@/utils/talkFile'
import { uploadPicture } from '@/api/aiGeneratedImage/index.js'
import { aitts, addFileToSC } from '@/api/file/index.js'
export default {
components: {
FileListItem
},
props: {},
data() {
return {
activeTab: '素材',
currentFileList: [],
uploadData: {},
checkFileList: [],
isLoading: false,
lastAsyncAllTime: '',
audioSrc: null,
filedata: null
}
},
computed: {
isCheckAll() {
return (
this.checkFileList.length > 0 && this.checkFileList.length === this.currentSCFileList.length
)
},
currentSCFileList() {
// return this.currentFileList.filter((item) => item.fileFlag !== 'apt' && item.fileFlag !== '')
return this.currentFileList.filter((item) => !['apt', 'aippt'].includes(item.fileFlag))
}
},
methods: {
deleteSuccess(item) {
this.asyncAllFile() //
},
auditionClick(requestData) {
this.$refs.audioRef.startLoading = true
aitts(requestData)
.then((res) => {
console.log(res)
if (res.code == 200) {
this.audioSrc = res.data.fullUrl
this.filedata = res.data
this.$refs.audioRef.startLoading = false
} else {
this.$message.error(res.msg)
this.$refs.audioRef.startLoading = false
}
})
.catch((err) => {
this.$refs.audioRef.startLoading = false
})
},
saveClick(requestData) {
this.$refs.audioRef.saveLoading = true
aitts(requestData)
.then((res) => {
if (res.code == 200) {
this.filedata = res.data
const saveObj = {
textbookId: this.uploadData.textbookId,
levelFirstId: this.uploadData.levelFirstId,
levelSecondId: this.uploadData.levelSecondId,
fileSource: this.uploadData.fileSource,
fileRoot: this.uploadData.fileRoot,
fileShowName: this.filedata.uploadTime+'音频.' + this.filedata.fileSuffix,
fileFlag: '素材',
fileId: this.filedata.id
}
addFileToSC(saveObj)
.then((resone) => {
this.$message.success('上传成功')
this.asyncAllFile()
this.$refs.audioRef.saveLoading = false
})
.catch((err) => {
this.$refs.audioRef.saveLoading = false
})
} else {
this.$message.error(res.msg)
this.$refs.audioRef.saveLoading = false
}
})
.catch((err) => {
console.log(err)
this.$refs.audioRef.saveLoading = false
})
},
asyncAllFile() {
this.isLoading = true
return getSmarttalkPage({
...this.uploadData,
orderByColumn: 'createTime',
isAsc: 'desc',
pageSize: 500
})
.then(async (res) => {
this.currentFileList = [...res.rows].filter((item) => item.fileType === 'audio/wav')
this.isLoading = false
this.lastAsyncAllTime = new Date()
localStorage.setItem('lastAsyncAllTime', this.lastAsyncAllTime)
this.asyncAllFileVisiable = true
for (let i = 0; i < this.currentFileList.length; i++) {
let item = this.currentFileList[i]
if (item.fileFlag === 'apt') continue
if (item.fileFlag === 'aippt') continue
await asyncLocalFile(item)
}
this.asyncAllFileVisiable = false
return Promise.resolve()
})
.catch(() => {
this.isLoading = false
return Promise.resolve()
})
},
onMoveSingleFile(item) {
this.moveFile = [item]
this.isMoveDialogOpen = true
},
deleteTalk(item) {
let index = this.currentFileList.indexOf(item)
this.currentFileList.splice(index, 1)
},
//
openSet(row) {
// row list
this.rows = [row]
this.setDialog = true
}
},
mounted() {
const route = useRoute()
this.uploadData = route.query
// this.dataset_id = route.query.datasetId;
// this.courseName = route.query.coursetitle;
// this.levelFirstId = route.query.levelFirstId;
// this.levelSecondId = route.query.levelSecondId;
// this.textbookId = route.query.textbookId;
this.asyncAllFile() //
},
beforeDestroy() {}
}
</script>
<style scoped scss>
:deep(.prepare-item-info-title) {
line-height: 30px;
}
.prepare-body-main{
overflow-y: auto;
height: 74vh;
}
:deep(.audio-container .content-main){
height: 85vh !important ;
}
:deep(.audio-container .content-main div:nth-of-type(1)){
display: flex;
flex: 1;
}
</style>

View File

@ -10,23 +10,8 @@
<el-tree :data="treeData" accordion :props="defaultProps" node-key="id" <el-tree :data="treeData" accordion :props="defaultProps" node-key="id"
:default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current :default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<template #default="{ node, data }"> <template #default="{ node }">
<div v-if="props.isClassTask && (data.bookId == '' || data.bookId == '0')" class="tree-label-wrap"> <span :title="node.label" class="tree-label">{{ node.label }}</span>
<el-tooltip effect="light" placement="right" >
<template #content> {{ node.label }}<br /><span style="color: red;">-该单元章节无自主试题-</span> </template>
<div class="tree-label" style="color: #A5B3CA" >
{{ node.label }}
</div>
</el-tooltip>
</div>
<div v-else class="tree-label-wrap">
<el-tooltip effect="light" placement="right" >
<template #content> {{ node.label }}</template>
<div class="tree-label">
{{ node.label }}
</div>
</el-tooltip>
</div>
</template> </template>
</el-tree> </el-tree>
</div> </div>
@ -44,9 +29,8 @@
<div class="textbook-container"> <div class="textbook-container">
<el-scrollbar height="450px"> <el-scrollbar height="450px">
<div <div class="textbook-item flex" v-for="item in subjectList" :class="curBook.data.id == item.id ? 'active-item' : ''"
v-for="item in subjectList" :key="item.id" class="textbook-item flex" :key="item.id" @click="changeBook(item)">
:class="curBook.data.id == item.id ? 'active-item' : ''" @click="changeBook(item)">
<img v-if="item.avartar" :src="item.avartar.indexOf('http') === 0 ? item.avartar : BaseUrl + item.avartar" class="textbook-img" alt=""> <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"> <div v-else class="textbook-img">
<i class="iconfont icon-jiaocaixuanze" style="font-size: 40px;"></i> <i class="iconfont icon-jiaocaixuanze" style="font-size: 40px;"></i>
@ -67,13 +51,6 @@ import useUserStore from '@/store/modules/user'
const userStore = useUserStore() const userStore = useUserStore()
const BaseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH const BaseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
const props = defineProps({
// []使()
isClassTask: {
default: false
},
})
const isStadium = () => { const isStadium = () => {
let roles = userStore.user.roles let roles = userStore.user.roles
return roles.some(item => item.roleKey === 'stadium') return roles.some(item => item.roleKey === 'stadium')
@ -201,7 +178,6 @@ const handleNodeClick = (data) => {
sessionStore.set('subject.curNode', nodeData) sessionStore.set('subject.curNode', nodeData)
emit('nodeClick', curData) emit('nodeClick', curData)
} }
onMounted( async () => { onMounted( async () => {
treeLoading.value = true treeLoading.value = true
try{ try{
@ -341,8 +317,7 @@ onMounted( async () => {
} }
} }
.tree-label-wrap, .tree-label { .tree-label {
max-width: 100%;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -26,7 +26,6 @@ const getFileTypeIcon = () => {
doc: 'icon-word', doc: 'icon-word',
docx: 'icon-word', docx: 'icon-word',
mp4: 'icon-video', mp4: 'icon-video',
wav: 'icon-mp',
mov: 'icon-mov', mov: 'icon-mov',
avi: 'icon-avi', avi: 'icon-avi',
jpeg: 'icon-jpeg', jpeg: 'icon-jpeg',

View File

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

View File

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

View File

@ -83,7 +83,7 @@
<!--AI 对话调整--> <!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :type="type" :item="editItem" :curMode="curMode" :conversation_id="conversation_id"/> <AdjustDialog v-model="isAdjust" :type="type" :item="editItem" :curMode="curMode" :conversation_id="conversation_id"/>
<!--添加编辑提示词--> <!--添加编辑提示词-->
<keywordDialog v-model="isWordDialog" :item="editItem" :modeType="type" /> <keywordDialog v-model="isWordDialog" :item="editItem" />
</template> </template>
<script setup> <script setup>
@ -104,7 +104,7 @@ import { cloneDeep } from 'lodash'
const props = defineProps(['type']) const props = defineProps(['type'])
const { user } = useUserStore() const { user } = useUserStore()
const curMode = ref(2) const curMode = ref(1)
const modeOptions = ref([ const modeOptions = ref([
{ {
label: '教学大模型', label: '教学大模型',
@ -344,8 +344,6 @@ const againResult = async (index, item) => {
} }
} }
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// //
const getCompletion = async () => { const getCompletion = async () => {
isStarted.value = new Array(childTempList.length).fill(false) isStarted.value = new Array(childTempList.length).fill(false)
@ -374,7 +372,6 @@ const getCompletion = async () => {
conversationId: conversation_id.value, conversationId: conversation_id.value,
stream: false stream: false
}) })
await delay(1000); // 1
data = res.data data = res.data
} }
// //
@ -418,7 +415,7 @@ const onEditSave = async (item) => {
} }
// //
const onSaveTemp = async (item) => { const onSaveTemp = (item) => {
if (item.answer == '') return if (item.answer == '') return
const data = { const data = {
@ -428,10 +425,7 @@ const onSaveTemp = async (item) => {
content: item.answer, content: item.answer,
ex1: curNode.id ex1: curNode.id
} }
const res = await tempSave(data) tempSave(data).then(res => { })
if(!item.resultId){
item.resultId = res.data
}
} }
// ### ** // ### **

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="whiteboart-container" :style="{ height: height + 'px' }"> <div class="whiteboart-container" :style="{ height: height + 'px' }">
<div class="canvasBox" ref="box" @mouseenter.capture="handleMouseEnter" @mouseleave.capture="handleMouseLeave"></div> <div class="canvasBox" ref="box"></div>
<div class="footerLeft" @click.stop <div class="footerLeft" @click.stop
:style="type == 'design' ? ['top: 10px', 'justify-content: space-between'] : ['bottom: 10px', 'justify-content: center']"> :style="type == 'design' ? ['top: 10px', 'justify-content: space-between'] : ['bottom: 10px', 'justify-content: center']">
@ -123,7 +123,7 @@
<!-- 边框样式 --> <!-- 边框样式 -->
<div class="blockBox"> <div class="blockBox">
<el-dropdown @command="updateStyle('lineDash', $event)" placement="top"> <el-dropdown @command="updateStyle('lineDash', $event)" placement="top">
<el-button><el-image :src="borderStyleImg" <el-button><el-image src="../../../src/assets/images/borderstyle.png"
style="width: 14px; height: 14px"></el-image></el-button> style="width: 14px; height: 14px"></el-image></el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
@ -278,7 +278,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, onBeforeUnmount, ref, getCurrentInstance, watch, toRaw, nextTick, computed, reactive, defineProps, defineEmits } from 'vue' import { onMounted, ref, watch, toRaw, nextTick, computed, reactive, defineProps, defineEmits } from 'vue'
import TinyWhiteboard from 'whiteboard_lyc' import TinyWhiteboard from 'whiteboard_lyc'
import ColorPicker from './components/ColorPicker.vue' import ColorPicker from './components/ColorPicker.vue'
import { import {
@ -303,10 +303,8 @@ import {
import Contextmenu from './components/Contextmenu.vue' import Contextmenu from './components/Contextmenu.vue'
import { fontFamilyList, fontSizeList } from './constants' import { fontFamilyList, fontSizeList } from './constants'
const borderStyleImg = new URL('../../../src/assets/images/borderstyle.png', import.meta.url).href
const borderImg = new URL('../../../src/assets/images/borderwidth.png', import.meta.url).href const borderImg = new URL('../../../src/assets/images/borderwidth.png', import.meta.url).href
const pointerImg = new URL('../../../src/assets/images/mouse-pointer.png', import.meta.url).href const pointerImg = new URL('../../../src/assets/images/mouse-pointer.png', import.meta.url).href
const { proxy } = getCurrentInstance()
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -509,7 +507,6 @@ const backToCenter = () => {
app.scrollToCenter() app.scrollToCenter()
} }
// //
const showFit = () => { const showFit = () => {
let elementList = app.elements.elementList let elementList = app.elements.elementList
@ -703,6 +700,8 @@ const getCanvasBlob = async () =>{
}) })
} }
watch(() => props.data, (newVal) => { watch(() => props.data, (newVal) => {
if (newVal) { if (newVal) {
setCanvasData(newVal) setCanvasData(newVal)
@ -714,13 +713,6 @@ watch(() => props.data, (newVal) => {
// dom // dom
onMounted(() => { onMounted(() => {
init();
})
/**
* 初始化画布内容
*/
const init = () => {
// //
app = new TinyWhiteboard({ app = new TinyWhiteboard({
container: box.value, container: box.value,
@ -742,7 +734,6 @@ const init = () => {
}) })
// //
app.on('activeElementChange', element => { app.on('activeElementChange', element => {
console.log('点击元素 监听 activeElementChange-----------')
if (activeElement.value) { if (activeElement.value) {
activeElement.value.off('elementRotateChange', onElementRotateChange) activeElement.value.off('elementRotateChange', onElementRotateChange)
} }
@ -790,39 +781,7 @@ const init = () => {
app.resize() app.resize()
}, 300) }, 300)
}) })
} })
const isMyCanvas = ref(false); //
const handleKeyDown=(event)=> {
// console.log(':', event.key);
// console.log(isMyCanvas.value,'??????????')
if(isMyCanvas.value == false){
event.stopPropagation();
// console.log(':', event.key);
}
}
/**
* 鼠标进入事件
*/
const handleMouseEnter = () => {
console.log('进入白板')
isMyCanvas.value = true;
document.addEventListener('keydown', handleKeyDown, true);
}
/**
* 课堂展示-鼠标离开白板监听事件该事件是避免选中状态在其他地方点击后退删除等事件会删除白板内选中的元素
*/
const handleMouseLeave = () => {
console.log('离开白板')
// --
app.cancelActiveElement()
//
isMyCanvas.value = false;
//
document.addEventListener('keydown', handleKeyDown, true);
};
// //
defineExpose({ defineExpose({
@ -832,7 +791,7 @@ defineExpose({
getCanvasJson, getCanvasJson,
getCanvasBase64, getCanvasBase64,
setCanvasData, setCanvasData,
getCanvasBlob, getCanvasBlob
}) })
</script> </script>

View File

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

View File

@ -1,7 +1,5 @@
import { listEntpcoursework,getEvaluationclue } from '@/api/classTask'; import { listEntpcoursework,getEvaluationclue } from '@/api/classTask';
import { processList } from '@/hooks/useProcessList'; import { processList } from '@/hooks/useProcessList';
import useClassTaskStore from '@/store/modules/classTask'
const useClassTaskStores = useClassTaskStore();
const isJson = (str) => { const isJson = (str) => {
if (typeof str == 'string') { if (typeof str == 'string') {
@ -34,7 +32,7 @@ export const editListItem = (row, courseObj) => {
worktype: '', // 设计中的作业类型 worktype: '', // 设计中的作业类型
quizlist: [], // 设计中的试题列表 quizlist: [], // 设计中的试题列表
chooseWorkLists: [],// 设计中的框架梳理list chooseWorkLists: [],// 设计中的框架梳理list
fileHomeworkList: [],//TODO 暂时共用这个字段(新增了 科学实验) 设计中的常规作业list fileHomeworkList: [],// 设计中的常规作业list
whiteboardObj: '',// 设计中的课堂展示对象 whiteboardObj: '',// 设计中的课堂展示对象
question: '', // 设计中的[课堂展示]的问题 question: '', // 设计中的[课堂展示]的问题
}; };
@ -114,24 +112,6 @@ export const editListItem = (row, courseObj) => {
return resolve(classtaskObj); return resolve(classtaskObj);
} }
} }
else if (row.worktype == '科学实验') {
if(isJson(row.workcodes)){
// 同步更新实验内部的科目信息
if (row.worktag && row.worktag.indexOf('-') > -1){
const eduInfo = row.worktag.split('-');
useClassTaskStores.experimentObj.edustage = eduInfo[0];
useClassTaskStores.experimentObj.edusubject = eduInfo[1];
useClassTaskStores.experimentObj.updateEduInfo = row.worktag;
}
// 更新科学实验内容
classtaskObj.fileHomeworkList = JSON.parse(row.workcodes);
//
// console.log('科学实验', classtaskObj);
// 更新默认的科学实验( 学段 学科 以及实验科目)
console.log('科学实验', classtaskObj);
return resolve(classtaskObj);
}
}
} }
}); });
} }

View File

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

View File

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

View File

@ -60,7 +60,6 @@ import useUserStore from '@/store/modules/user'
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' import { sessionStore } from '@/utils/store'
import {toLinkLeftWeb} from "@/utils/tool"
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
@ -85,7 +84,7 @@ const isStadium = () => {
const headerMenus = isStadium() ?[{ const headerMenus = isStadium() ?[{
name: '教学实践', name: '教学实践',
id: 6, id: 4,
icon: 'icon-jiaoxueshijian', icon: 'icon-jiaoxueshijian',
path: '/prepare' path: '/prepare'
},]:[ },]:[
@ -95,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,
@ -119,14 +118,6 @@ const headerMenus = isStadium() ?[{
icon: 'icon-kechengziyuan1', icon: 'icon-kechengziyuan1',
path: '/resource/index' path: '/resource/index'
}, },
{
name: '科学',
id: 4,
icon: 'icon-kechengziyuan1',
path: '/scientific/index',
// path: 'https://res.bakclass.com/resource/laboratoryIndex',
// type: 'webview', //
},
] ]
const sideBottomMenu = [ const sideBottomMenu = [
@ -167,17 +158,10 @@ const computedregistertype = computed(() => {
} }
}) })
const clickMenu = (item) => { const clickMenu = ({ id, disabled, path }) => {
const { id, disabled, path, type } = item
if (disabled) return if (disabled) return
if (type == 'webview') { //
toLinkLeftWeb(item.path)
} else if (type == 'link') {
window.open(path)
} else {
activeId.value = id activeId.value = id
router.push(path) router.push(path)
}
} }
const onUserTo = (path) =>{ const onUserTo = (path) =>{
@ -345,7 +329,6 @@ onMounted(() => {
color: #fff; color: #fff;
font-size: 12px; font-size: 12px;
margin-top: 5px; margin-top: 5px;
text-align: center;
} }
.pointer-events{ .pointer-events{
pointer-events: none; pointer-events: none;

View File

@ -10,15 +10,6 @@ import './assets/iconfont/iconfont'
import 'virtual:windi.css' import 'virtual:windi.css'
import request from "@/utils/request"; import request from "@/utils/request";
//v-md-editor
import VMdPreview from '@kangc/v-md-editor/lib/preview';
import '@kangc/v-md-editor/lib/style/preview.css';
// 引入你所使用的主题 此处以 github 主题为例
import githubTheme from '@kangc/v-md-editor/lib/theme/github';
import '@kangc/v-md-editor/lib/theme/style/github.css';
// highlightjs
import hljs from 'highlight.js';
import { store } from '@/store' import { store } from '@/store'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
@ -26,9 +17,6 @@ import log from 'electron-log/renderer' // 渲染进程日志-文件记录
import customComponent from '@/components/common' // 自定义组件 import customComponent from '@/components/common' // 自定义组件
import plugins from './plugins' // plugins插件 import plugins from './plugins' // plugins插件
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import aiAudio from 'aix-plugins-aitools' // 文字转语音插件
import '../../../node_modules/aix-plugins-aitools/aitools.css'
if(process.env.NODE_ENV != 'development') { // 非开发环境,将日志打印到日志文件 if(process.env.NODE_ENV != 'development') { // 非开发环境,将日志打印到日志文件
Object.assign(console, log.functions) // 渲染进程日志-控制台替换 Object.assign(console, log.functions) // 渲染进程日志-控制台替换
@ -51,10 +39,6 @@ app.config.globalProperties.$requestGetJYW = (url,config)=>{
import Icon from '@/AixPPTist/src/plugins/icon' import Icon from '@/AixPPTist/src/plugins/icon'
import Directive from '@/AixPPTist/src/plugins/directive' import Directive from '@/AixPPTist/src/plugins/directive'
VMdPreview.use(githubTheme, {
Hljs: hljs,
});
app.use(router) app.use(router)
.use(store) .use(store)
.use(ElementPlus, { locale: zhLocale }) .use(ElementPlus, { locale: zhLocale })
@ -62,8 +46,6 @@ app.use(router)
.use(plugins) .use(plugins)
.use(Icon) .use(Icon)
.use(Directive) .use(Directive)
.use(aiAudio)
.use(VMdPreview)
.mount('#app') .mount('#app')
const isStadium = (user) => { const isStadium = (user) => {

View File

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

View File

@ -96,12 +96,6 @@ export const constantRoutes = [
name: 'aiKolors', name: 'aiKolors',
meta: { title: '文生图片', showBread: true } meta: { title: '文生图片', showBread: true }
}, },
{
path: 'aiVoice',
component: () => import('@/components/ai-voice/index.vue'),
name: 'aiVoice',
meta: { title: '语音生成', showBread: true }
},
] ]
}, },
@ -221,18 +215,6 @@ const dynamicRoutes = [
} }
] ]
}, },
{
path: '/scientific',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/scientific/index.vue'),
name: 'scientific',
meta: { title: '科学' },
}
]
},
{ {
path: '/hashrate', path: '/hashrate',
component: Layout, component: Layout,

View File

@ -2,17 +2,9 @@ import { defineStore } from 'pinia'
import { } from '@/api/classTask/index.js' import { } from '@/api/classTask/index.js'
import { listClassmain } from '@/api/classManage/index' import { listClassmain } from '@/api/classManage/index'
import { JYApiListCT, JYApiListOriginYear, JYApiListSO} from "@/utils/examQuestion/jyeoo" import { JYApiListCT, JYApiListOriginYear, JYApiListSO} from "@/utils/examQuestion/jyeoo"
import { listEvaluation } from '@/api/subject'
import { getBindlist, listKnowlegepointFormat } from '@/api/education/knowledgePoint'
const useClassTaskStore = defineStore('classTask',{ const useClassTaskStore = defineStore('classTask',{
state: () => ({ state: () => ({
experimentObj:{
edustage: '小学', // 教育阶段
edusubject: '数学', // 学科
experimentList: [], // 实验科目列表
updateEduInfo: '小学-数学', //实际需上传的学段+学科信息(用于上传及回显实验内的学段学科)
},
isOpenQuestUploadView: false, // 是否打开习题上传的页面 isOpenQuestUploadView: false, // 是否打开习题上传的页面
classListIds: [], classListIds: [],
entpCourseWorkTypeList: [ entpCourseWorkTypeList: [
@ -40,7 +32,6 @@ const useClassTaskStore = defineStore('classTask',{
{label: '2021', value: '2021'}, {label: '2021', value: '2021'},
{label: '2020', value: '2020'}, {label: '2020', value: '2020'},
], // 习题查询条件 - 年份 ], // 习题查询条件 - 年份
entpCourseWorkPointList: [], // 习题查询条件 - 知识点
}), }),
actions: { actions: {
listClassmain(params) { listClassmain(params) {
@ -72,36 +63,6 @@ const useClassTaskStore = defineStore('classTask',{
console.error('更新第三方题源+题型err:', error); console.error('更新第三方题源+题型err:', error);
}); });
}, },
// 根据学科和学段获取知识点
initJYPoint(params) {
/**
* 格式化知识点: 分两种情况
* 1. 语文/英语: 获取学科下的所有知识点(该学科对应无章节与知识点绑定, 故只获取全知识点)
* 2. 其他: 获取当前章节下的所有知识点
*/
this.entpCourseWorkPointList = [];
let id = params.levelSecondId!='' ? params.levelSecondId : params.levelFirstId;
if( params.edusubject == '语文' || params.edusubject == '英语'){
id = params.textbookId;
listEvaluation({ edusubject: params.edusubject, edustage: params.edustage, itemkey: "subject", pageSize: 10 }).then((res => {
id = res.rows[0]?.id;
if (id) {
listKnowlegepointFormat({evalId: id, pageNum: 1, pageSize: 5000,}).then(res => {
this.entpCourseWorkPointList = formatKnowledgePoint(res.rows);
console.log('1.entpCourseWorkPointList->', this.entpCourseWorkPointList);
});
}
}))
}else{
getBindlist({ eid: id }).then(res => {
if (res.data && res.data.length > 0) {
this.entpCourseWorkPointList = res.data;
console.log('2.entpCourseWorkPointList->', this.entpCourseWorkPointList);
}
})
}
},
}, },
persist: true persist: true
}) })
@ -142,20 +103,3 @@ const getJYCT = (params) => {
}) })
}) })
} }
/**
* @desc: 遍历原知识点数据, 将title字段转为knowTitle以供knowledgePointProps进行tree的格式转换显示
* @return: {*}
* @param {*} list
*/
const formatKnowledgePoint = (list) => {
list.forEach(item => {
if (item.title && item.title != '') {
item.knowTitle = item.title;
}
if (item.children && Array.isArray(item.children)) {
formatKnowledgePoint(item.children);
}
});
return list;
};

View File

@ -395,11 +395,7 @@ export const dataSetJson = {
"课标-高中-英语": "e889fcac9fd011efb22a0242ac140006", "课标-高中-英语": "e889fcac9fd011efb22a0242ac140006",
"课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006", "课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
"课标-高中-地理": "270516829fd111efb13c0242ac140006", "课标-高中-地理": "270516829fd111efb13c0242ac140006",
"课标-高中-物理": "3865b5afc68211ef90890242ac140002",
"课标-高中-化学": "013d0c52c68311ef84220242ac140002",
"课标-高中-政治": "a2f0b247b85d11ef84290242ac140005", "课标-高中-政治": "a2f0b247b85d11ef84290242ac140005",
"教材-高中-物理": "3865b5afc68211ef90890242ac140002",
"教材-高中-化学": "013d0c52c68311ef84220242ac140002",
"教材-高中-语文": "cee3062a9fcf11efa6910242ac140006", "教材-高中-语文": "cee3062a9fcf11efa6910242ac140006",
"教材-高中-生物": "fb5d01d59fd011ef9bb90242ac140006", "教材-高中-生物": "fb5d01d59fd011ef9bb90242ac140006",
"教材-高中-历史": "f2f6c1fb9fd011ef98740242ac140006", "教材-高中-历史": "f2f6c1fb9fd011ef98740242ac140006",
@ -407,52 +403,5 @@ export const dataSetJson = {
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006", "教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
"教材-高中-地理": "270516829fd111efb13c0242ac140006", "教材-高中-地理": "270516829fd111efb13c0242ac140006",
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005", "教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
"考试-小学-语文": "570f7ed2cc9d11ef9e070242ac140002",
"考试-小学-数学": "983270b8cc9d11efbbd80242ac140002",
"考试-小学-英语": "d5f80e4ccc9d11ef96fa0242ac140002",
"课标-小学-科学": "935cfec8bf6a11ef98950242ac140006",
"课标-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
"课标-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
"课标-小学-道德": "8da87869cbd711ef92280242ac140002",
"课标-小学-英语": "dc963316cbd811ef8d820242ac140002",
"课标-小学-劳动": "fc047d81cbdc11efa1740242ac140002",
"教材-小学-科学": "935cfec8bf6a11ef98950242ac140006",
"教材-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
"教材-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
"教材-小学-道德": "8da87869cbd711ef92280242ac140002",
"教材-小学-英语": "dc963316cbd811ef8d820242ac140002",
"教材-小学-劳动": "fc047d81cbdc11efa1740242ac140002",
"教材-初中-道德与法治": "df9f3ccccbdd11ef9e550242ac140002",
"教材-初中-语文": "3770ad18cbde11efadaa0242ac140002",
"教材-初中-数学": "8cc0a799cbde11ef8b440242ac140002",
"教材-初中-英语": "07b58ca2cbdf11efaa180242ac140002",
"教材-初中-物理": "86f2c018cbf211ef9d6a0242ac140002",
"教材-初中-化学": "c7b34790cbf211ef92350242ac140002",
"教材-初中-生物": "083ac3edcbf311efaad30242ac140002",
"教材-初中-地理": "7ee584e1cbf311efbd270242ac140002",
"教材-初中-历史": "8ae07971cbf411ef81e70242ac140002",
"教材-初中-信息技术": "ca476233cbf411efa9860242ac140002",
"课标-初中-道德与法治": "df9f3ccccbdd11ef9e550242ac140002",
"课标-初中-语文": "3770ad18cbde11efadaa0242ac140002",
"课标-初中-数学": "8cc0a799cbde11ef8b440242ac140002",
"课标-初中-英语": "07b58ca2cbdf11efaa180242ac140002",
"课标-初中-物理": "86f2c018cbf211ef9d6a0242ac140002",
"课标-初中-化学": "c7b34790cbf211ef92350242ac140002",
"课标-初中-生物": "083ac3edcbf311efaad30242ac140002",
"课标-初中-地理": "7ee584e1cbf311efbd270242ac140002",
"课标-初中-历史": "8ae07971cbf411ef81e70242ac140002",
"课标-初中-信息技术": "ca476233cbf411efa9860242ac140002",
"考试-初中-语文": "6be6d201cc0111ef89100242ac140002",
"考试-初中-数学": "d764b539cc0111ef8f1b0242ac140002",
"考试-初中-英语": "3477cff7cc9911efbfa50242ac140002",
"考试-初中-政治": "7ac981d8cc9a11efa5dc0242ac140002",
"考试-初中-历史": "c058a33acc9a11efb7f00242ac140002",
"考试-初中-地理": "5548224ecc9b11efa76d0242ac140002",
"考试-初中-生物": "206c5fd3cc9c11ef990f0242ac140002",
"考试-初中-物理": "93039442cc9c11ef89b10242ac140002",
"考试-初中-化学": "f8d78002cc9c11efbbf60242ac140002",
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm" "鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
} }

View File

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

View File

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

View File

@ -106,22 +106,6 @@ const getBackGroundV2 = async () => {
throw error; throw error;
} }
}; };
const createOutlineV2 = async (data) => {
try {
const response = await request({
url:"/api/aipptV2/createOutlineV2",
method: "POST",
data
});
console.log("createOutline response:", response);
return response.data;
} catch (error) {
console.error("请求失败:", error);
throw error;
}
};
const createPPTV2 = async (data) => { const createPPTV2 = async (data) => {
try { try {
const response = await req("/api/aipptV2/createV2", "POST", data); const response = await req("/api/aipptV2/createV2", "POST", data);
@ -133,18 +117,6 @@ const createPPTV2 = async (data) => {
throw error; throw error;
} }
}; };
const createPptByOutline = async (data) => {
try {
const response = await req("/api/aipptV2/createPptByOutline", "POST", data);
console.log("createOutline response:", response);
return response.data;
} catch (error) {
console.error("请求失败:", error);
throw error;
}
};
const getProgressV2 = async (id) => { const getProgressV2 = async (id) => {
try { try {
const response = await req(`/api/aipptV2/progressV2?sid=${id}`, "GET"); const response = await req(`/api/aipptV2/progressV2?sid=${id}`, "GET");
@ -155,4 +127,4 @@ const getProgressV2 = async (id) => {
} }
}; };
export { createOutline, getBackGround, createPPT, getProgress, getBackGroundV2, createOutlineV2, createPPTV2, getProgressV2, createByOutline, createPptByOutline }; export { createOutline, getBackGround, createPPT, getProgress, getBackGroundV2, createPPTV2, getProgressV2, createByOutline };

View File

@ -1,210 +0,0 @@
/**
* ppt 相关方法
*/
import { h, render, getCurrentInstance } from 'vue'
import { toPng, toJpeg } from 'html-to-image' // 引入html-to-image库
import { PPTXFileToJson } from "@/AixPPTist/src/hooks/useImport"
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
import { useSlidesStore } from '@/AixPPTist/src/store'
import * as ElementPlus from 'element-plus'
import { sessionStore } from '@/utils/store' // electron-store 状态管理
import { getStaticUrl } from '@/utils/tool' // 工具类
import * as Http_Classcourse from '@/api/teaching/classcourse' // api接口
// 延时
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
/**
* @description: 渲染组件
* @param {*} node 节点或属性
* @param {*} props 属性
* @param {*} children 子元素
* @param {*} container 容器
*/
const renderComponent = (node, props = {}, children, container) => {
let vNode, body
if (!node) throw new Error('vNode is required')
if (typeof container == 'string') {
if (node == 'slide') {
vNode = h(ThumbnailSlide, props, children)
} else throw new Error('vNode has no corresponding component')
} else {
vNode = h(node, props, children)
}
if (!container) body = document.body // 默认为body
else { // 判断是否为字符串
if (typeof container == 'string') {
body = document.querySelector(container)
} else {
body = container
}
}
return render(vNode, body)
}
/**
* @description: 幻灯片转换为图片
* 提示icon组件找不到是应为 h() 渲染是底层创建的虚拟节点找不到全局组件
* @param {*} slides 幻灯片数据
* @param {*} options 配置 number 为幻灯片宽度 | object 为配置项
* @returns
*/
export const slidesToImg = (slides = [], options) => {
let width, option, ispng = true
if (typeof options =='number'){width = options; option = {}}
else {const { width: w, isPng, ...opt } = options;width = w; ispng=isPng; option = opt}
const slidesStore = useSlidesStore()
!!width && slidesStore.setViewportSize(width) // 设置幻灯片宽度
return new Promise(async(resolve) => {
const instance = getCurrentInstance()
console.log('instance', instance)
const slidesDom = []
for(const slide of slides) {
const props = { class: 'c-thumbnail', slide, size: 120, ...option }
const node = h(ThumbnailSlide, props)
slidesDom.push(node)
}
// 渲染组件到body
const props = { class: 'c-thumbnails', style:{position:'absolute',top:0,left:'-200vw'}}
renderComponent('div', props, slidesDom)
let imgs = []
const toImag = ispng? toPng : toJpeg
for(const slide of slidesDom) {
const img = await toImag(slide.el)
imgs.push(img)
}
// console.log('ppt生成图片: ', imgs)
// console.log('图片已生成,正在卸载组件')
!!width && slidesStore.setViewportSize(1000) // 设置幻灯片宽度-恢复
render(null, document.body) // 卸载组件
resolve(imgs)
})
}
/**
* description: ppt 文件转换为图片
* @param {*} file file 为文件对象| arrayBuffer 为数组
* @param {*} options 配置 number 为幻灯片宽度 | object 为配置项
* @returns
*/
export const pptToImg = async(file, options) => {
const { slides } = await PPTXFileToJson(file)
return slidesToImg(slides, options)
}
/**
* 课堂-分享码
*/
export const ShareCode = async(code, cb) => {
let shareCode
if (typeof code =='string') shareCode = code
else { // 自动获取邀请码
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
if (!classcourse) return ElementPlus.ElMessage.warning('没有课堂信息')
const isRefresh = typeof code == 'boolean' && code // 是否刷新邀请码
shareCode = classcourse.shareCode
if (!shareCode || isRefresh) { // 获取邀请码
const res = await Http_Classcourse.getShareCode(classcourse.id)
shareCode = res.msg
// 更新邀请码
sessionStore.set('curr.classcourse.shareCode', shareCode)
}
}
const msg = h('div', [
h('h1', [`我的邀请码:`, h('b',{style:{color:'#F56C6C',fontSize:'1.5em'}}, shareCode)]),
h('div', {style:{color:'#E6A23C',fontSize:'13px'}}, `该邀请码1小时内有效请在学生端填写邀请码后即可进入课堂。`)
])
return ElementPlus.ElMessageBox.alert(msg, '分享课程', {
confirmButtonText: '更新',
cancelButtonText: '关闭',
showCancelButton: true,
beforeClose: (action, instance, done) => {
if (action =='confirm') { // 更新
if (!!cb) { // 回调
cb({ h, instance, action, done }, done) && done()
} else { // 默认更新
ShareCode(true)
done()
}
} else done()
}
}).catch(() => {})
}
/**
* 提示框
* @param {*} msg 内容
* @param {*} title 标题
* @param {*} option 配置
* @param {*} cb 关闭前回调 ({ h, instance, action, done }, done)
* @returns
*/
export const Alert = async (msg, title, option, cb) => {
try {
if (typeof msg == 'function') msg = await msg(h)
return await ElementPlus.ElMessageBox.alert(msg, title, {
confirmButtonText: '确认',
cancelButtonText: '关闭',
showCancelButton: true,
beforeClose: (action, instance, done) => {
if (action == 'confirm') { // 确认
if (!!cb) { // 回调
cb({ h, instance, action, done }, done) && done()
} else { // 默认确认
done()
}
} else done()
},
...option,
})
} catch { }
}
/**
* 课堂工具栏-钩子
*/
export const ToolType = {
/** 分享码 */
SHARE_CODE: 'shareCode',
/** 课堂点名 */
NAMED: 'named',
}
export const ToolHandle = async(type, data, cb) => {
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
switch (type) {
case ToolType.SHARE_CODE:
return ShareCode(data, cb)
case ToolType.NAMED: {
if (!classcourse) return ElementPlus.ElMessage.warning('没有课堂信息!')
const avatar = getStaticUrl('/icon/avatar.svg')
const timgroupid = classcourse.timgroupid
if (!timgroupid) return ElementPlus.ElMessage.warning('没有课堂群信息!')
// 课堂点名
const res = await Http_Classcourse.rollCall(timgroupid)
if (!(res && res.code == 200 && res.data)) return ElementPlus.ElMessage.warning('点名失败!')
const userList = res?.data || []
const refresh = () => { ToolHandle(ToolType.NAMED); return true }
Alert(h => {
const attr_0 = {style:{display:'flex',gap:'10px', cursor:'pointer'}}
const attr_1 = { style:{display:'inline-flex',alignItems:'center',gap:'10px',padding:'5px 10px'}}
const attr_2 = { src: avatar, style: { width: '50px', height: '50px' }}
const attr_3 = { style: { fontSize: '20px', fontWeight: 'bold', color: '#409EFF' }}
const attr_4 = { style: { fontSize: '12px' }}
const userList_H = userList.map(o => {
attr_1.title = o.name
attr_4.style.color = o.online ? '#67C23A' : '#F56C6C'
return h('div', attr_1, [
h('img', attr_2),
h('div', [
h('p', attr_3, o.name),
h('span', attr_4, o.online?'在线':'离线')
])
])
})
return h('div', attr_0, userList_H)
}, '课堂点名', { confirmButtonText: '刷新' }, refresh)
break;
}
default:
break
}
}

View File

@ -1,5 +1,3 @@
import {ElMessage} from "element-plus";
const { ipcRenderer } = window.electron || {} const { ipcRenderer } = window.electron || {}
export const asyncLocalFile = (item) => { export const asyncLocalFile = (item) => {
@ -11,15 +9,12 @@ 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
}) })
ipcRenderer.once('download-file-default' + item.fileNewName, (e, isSuccess) => { ipcRenderer.once('download-file-default' + item.fileNewName, (e, isSuccess) => {
if (isSuccess == false) {
ElMessage.error(`${item.fileShowName}下载失败!`)
}
item.async = isSuccess item.async = isSuccess
resolve() resolve()
}) })
@ -117,24 +112,3 @@ export const creatAIPPT = (name, url, uploadData) => {
}) })
}) })
} }
export const removeLocalFiles = async (list) => {
return new Promise((resolve, reject) => {
ipcRenderer.send('remove-local-file-list', JSON.parse(JSON.stringify(list)))
ipcRenderer.removeListener('remove-local-file-list-error', removeLocalFileListError)
ipcRenderer.removeListener('remove-local-file-list-not', removeLocalFileListNot)
ipcRenderer.on('remove-local-file-list-error', removeLocalFileListError)
ipcRenderer.on('remove-local-file-list-not', removeLocalFileListNot)
ipcRenderer.once('remove-local-file-list-reply', (e, res) => {
resolve(res)
})
})
}
function removeLocalFileListError(e, item) {
ElMessage.error(`${item.fileShowName}删除失败`)
}
function removeLocalFileListNot(e, item) {
ElMessage.error(`${item.fileShowName}删除失败,并没有该文件!`)
}

View File

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

View File

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

View File

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

View File

@ -141,8 +141,7 @@
v-if=" v-if="
dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '常规作业' ||
dialogProps.studentObj.worktype == '课堂展示' || dialogProps.studentObj.worktype == '课堂展示' ||
dialogProps.studentObj.worktype == '框架梳理' || dialogProps.studentObj.worktype == '框架梳理'
dialogProps.studentObj.worktype == '科学实验'
" "
> >
<div v-for="(stuItem, sIndex) in dialogProps.studentQuizAllList" :key="stuItem.id"> <div v-for="(stuItem, sIndex) in dialogProps.studentQuizAllList" :key="stuItem.id">
@ -158,8 +157,7 @@
v-if=" v-if="
dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '常规作业' ||
dialogProps.studentObj.worktype == '课堂展示' || dialogProps.studentObj.worktype == '课堂展示' ||
dialogProps.studentObj.worktype == '框架梳理' || dialogProps.studentObj.worktype == '框架梳理'
dialogProps.studentObj.worktype == '科学实验'
" "
> >
<!-- 文件内容格式mp3/mp4/doc/docx/excel/pdf/ppt/pptx/jpg/jpeg/gif/png/txt -> <!-- 文件内容格式mp3/mp4/doc/docx/excel/pdf/ppt/pptx/jpg/jpeg/gif/png/txt ->
@ -212,13 +210,7 @@
<!-- 学生答题展示 --> <!-- 学生答题展示 -->
<div v-if="feedContentList.length > 0"> <div v-if="feedContentList.length > 0">
<div <div v-if="dialogProps.studentObj.worktype == '常规作业' && stuItem.rightanswer != ''&& stuItem.rightanswer != null">
v-if="
(dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '科学实验') &&
stuItem.rightanswer != '' &&
stuItem.rightanswer != null
"
>
<!-- 常规作业学生有的会答复 --> <!-- 常规作业学生有的会答复 -->
<p style="padding: 10px 0;text-align: left;">学生答复内容</p> <p style="padding: 10px 0;text-align: left;">学生答复内容</p>
<div style="padding: 0 20px;text-align: left;">{{stuItem.rightanswer}}</div> <div style="padding: 0 20px;text-align: left;">{{stuItem.rightanswer}}</div>
@ -435,7 +427,7 @@ import useUserStore from '@/store/modules/user'
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
// import { Plus } from '@element-plus/icons-vue' // import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import { getClassworkdata, updateClassworkevalList, updateClassWorkDataAutoFinish } from '@/api/classTask' import { updateClassworkeval, updateClassworkdata, getClassworkdata } from '@/api/classTask'
import { getTimeDate } from '@/utils/date' import { getTimeDate } from '@/utils/date'
import ReFilePreview from '@/components/refile-preview/index.vue' import ReFilePreview from '@/components/refile-preview/index.vue'
import { quizStrToList } from '@/utils/comm'; import { quizStrToList } from '@/utils/comm';
@ -708,8 +700,7 @@ const acceptParams = async (params) => {
}) })
} else { } else {
// //
if (params.studentObj.worktype == '常规作业' || params.studentObj.worktype == '科学实验') { if (params.studentObj.worktype == '常规作业') {
if(params.studentObj.worktype == '常规作业'){
try { try {
// datacontent TODO // datacontent TODO
const res = await getClassworkdata(params.studentObj.id); const res = await getClassworkdata(params.studentObj.id);
@ -734,9 +725,6 @@ const acceptParams = async (params) => {
} 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) => {
classWorkFormScore.teacherRating.push({ classWorkFormScore.teacherRating.push({
@ -890,12 +878,12 @@ const onSubmit = () => {
updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm; updatedate: getTimeDate(),// = year+'-'+month+'-'+day+' '+hh+':'+mm;
}; };
// //
updateClassWorkDataAutoFinish(formd).then(res => { updateClassworkdata(formd).then(res => {
}) })
// //
const queryList = []; classWorkFormScore.teacherRating &&
classWorkFormScore.teacherRating && classWorkFormScore.teacherRating.map((item, index) => { classWorkFormScore.teacherRating.map((item, index) => {
const queryParams = { const queryParams = {
id: item.id, id: item.id,
teacherRating: item.score, // teacherRating: item.score, //
@ -903,32 +891,13 @@ const onSubmit = () => {
teacherremark: classWorkFormScore.teacherremark, // teacherremark: classWorkFormScore.teacherremark, //
timestamp: getTimeDate() // timestamp: getTimeDate() //
} }
queryList.push(queryParams) console.log(queryParams)
}) updateClassworkeval(queryParams).then((res) => {
//console.log('queryList->', queryList)
updateClassworkevalList(queryList).then((res) => {
// if(res.code == 200){ // if(res.code == 200){
// //
// } // }
}) })
})
//
// classWorkFormScore.teacherRating &&
// classWorkFormScore.teacherRating.map((item, index) => {
// const queryParams = {
// id: item.id,
// teacherRating: item.score, //
// rating: classWorkFormScore.rating, //
// teacherremark: classWorkFormScore.teacherremark, //
// timestamp: getTimeDate() //
// }
// console.log(queryParams)
// updateClassworkeval(queryParams).then((res) => {
// // if(res.code == 200){
// //
// // }
// })
// })
ElMessage({ ElMessage({
type: 'success', type: 'success',
message: '提交成功!' message: '提交成功!'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -58,9 +58,9 @@
<el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst"> <el-tab-pane label="自主搜题" name="自主搜题" class="prepare-center-zzst">
<SearchQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd" /> <SearchQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd" />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk"> <el-tab-pane label="校本题库" name="校本题库" class="prepare-center-xbtk">
<SchoolQuestion /> <SchoolQuestion />
</el-tab-pane> --> </el-tab-pane>
<el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst"> <el-tab-pane label="个人题库" name="个人题库" class="prepare-center-grst">
<MyQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd"/> <MyQuestion :bookobj="courseObj" @addQuiz="handleClassWorkQuizAdd"/>
</el-tab-pane> </el-tab-pane>
@ -68,7 +68,8 @@
</div> </div>
<div v-if="(currentRow.worktype == '课堂展示' || classWorkForm.worktype == '课堂展示') && currentRow.id>0" class="page-center"> <div v-if="(currentRow.worktype == '课堂展示' || classWorkForm.worktype == '课堂展示') && currentRow.id>0" class="page-center">
<div v-loading="boardLoading" class="board-wrap" style="height: 100%; flex: 1; overflow: hidden;"> <div v-loading="boardLoading" class="board-wrap" style="height: 100%; flex: 1; overflow: hidden;">
<whiteboard ref="boardref" height="100%" width="100%" :isShowSave="false" :data="classWorkForm.whiteboardObj" /> <!-- <whiteboard v-if="isShowBoard" ref="boardref" :height="mainHeight - 150" :isShowSave="false" :data="whiteboardObj"/> -->
<whiteboard ref="boardref" height="100%" width="100%" :isShowSave="false" :data="classWorkForm.whiteboardObj"/>
</div> </div>
</div> </div>
<div v-if="(currentRow.worktype == '常规作业' || classWorkForm.worktype == '常规作业')&& currentRow.id>0" class="page-center"> <div v-if="(currentRow.worktype == '常规作业' || classWorkForm.worktype == '常规作业')&& currentRow.id>0" class="page-center">
@ -76,11 +77,6 @@
<FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/> <FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
</div> </div>
</div> </div>
<div v-if="(currentRow.worktype == '科学实验' || classWorkForm.worktype == '科学实验')&& currentRow.id>0" class="page-center">
<div class="experiment-homework">
<ExperimentQuestion :expObj="classWorkForm.fileHomeworkList&&classWorkForm.fileHomeworkList[0]" @clickExpObj="getExpObj" />
</div>
</div>
<div v-if="currentRow.id>0 " class="page-right"> <div v-if="currentRow.id>0 " class="page-right">
<div class="prepare-top" > <div class="prepare-top" >
@ -144,7 +140,6 @@ import { editListItem } from '@/hooks/useClassTask'
import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue' import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue'
import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue' import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue'
import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue' import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue'
import ExperimentQuestion from "@/views/classTask/newClassTaskAssign/experimentQuestion/index.vue";
import whiteboard from '@/components/whiteboard/whiteboard.vue' import whiteboard from '@/components/whiteboard/whiteboard.vue'
import FileUpload from "@/components/FileUpload/index.vue"; import FileUpload from "@/components/FileUpload/index.vue";
import Right from './Right/index.vue' import Right from './Right/index.vue'
@ -161,7 +156,6 @@ const route = useRoute();
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const useClassTaskStores = useClassTaskStore(); const useClassTaskStores = useClassTaskStore();
const { ipcRenderer } = require('electron')
const props = defineProps({ const props = defineProps({
currentCourse: Object, currentCourse: Object,
@ -170,10 +164,6 @@ const emits = defineEmits(['getData'])
// ppt // ppt
const isShow = ref(false) const isShow = ref(false)
const propsQueryTask = {
id: route.query.classTaskId, // id
isInit: false, //
}
const propsQueryCourseObj = route.query.courseObj;// const propsQueryCourseObj = route.query.courseObj;//
const courseObj = reactive({ const courseObj = reactive({
// : id,id,id, // : id,id,id,
@ -203,8 +193,8 @@ const boardLoading = ref(false);
const fileLoading = ref(false); // loading 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 //
@ -239,7 +229,7 @@ const isInToMyQuestion = () => {
if(useClassTaskStores.isOpenQuestUploadView){ if(useClassTaskStores.isOpenQuestUploadView){
useClassTaskStores.isOpenQuestUploadView = false; useClassTaskStores.isOpenQuestUploadView = false;
currentRow.value.id = 1; // currentRow.value = {id:1}; //
activeAptTab.value = "个人题库"; activeAptTab.value = "个人题库";
// //
classWorkForm.id = 0; classWorkForm.id = 0;
@ -268,16 +258,6 @@ watch(() => props.currentCourse, (newVal, oldVal) => {
} }
console.log(newVal,'newval'); console.log(newVal,'newval');
},{deep:true}) },{deep:true})
// ------------
const getExpObj = (obj)=>{
// obj:{
// fileurl: "https://phet.colorado.edu/sims/html/number-compare/latest/number-compare_zh_CN.html"
// label: ""
// subject: "math"
// }
classWorkForm.fileHomeworkList = [obj];
}
//------------ //------------
const handleItemClick = (itemName) => { const handleItemClick = (itemName) => {
console.log('itemName', itemName); console.log('itemName', itemName);
@ -286,7 +266,7 @@ const handleItemClick = (itemName) => {
return; return;
} }
currentRow.value.id = 1; // currentRow.value = {id:1}; //
/** /**
* 智能推荐AI设计作业 * 智能推荐AI设计作业
* 习题训练 自主搜题 校本题库 个人题库 * 习题训练 自主搜题 校本题库 个人题库
@ -316,7 +296,7 @@ const selectable=(row, index)=>{
/** /**
* 获取 entpcourseid 获取作业列表 * 获取 entpcourseid 获取作业列表
*/ */
const initHomeWork = async ()=> { const initHomeWork = async()=> {
tasklist_loading.value = true; tasklist_loading.value = true;
// const { res, chapterId } = await useGetHomework(courseObj.node); // const { res, chapterId } = await useGetHomework(courseObj.node);
const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode')); const { res, chapterId } = await useGetHomework(sessionStore.get('subject.curNode'));
@ -324,22 +304,12 @@ const initHomeWork = async ()=> {
console.log('res', res); console.log('res', res);
entpcourseid.value = chapterId; entpcourseid.value = chapterId;
taskList.value = res; taskList.value = res;
// , id
const taskId = propsQueryTask?.id ?? 0;
if (!propsQueryTask.isInit && taskId!=0){
const activeRow = taskList.value.find(o => o.id == taskId);
if (activeRow){
propsQueryTask.isInit = true; //
taskTable.value.setCurrentRow(activeRow);
handleCurrentChange(activeRow);
}
}
tasklist_loading.value = false; tasklist_loading.value = false;
} }
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 = ""; //
@ -366,7 +336,7 @@ const handleDelete =() => {
return delClasswork(ids.join(',')); return delClasswork(ids.join(','));
}).then(() => { }).then(() => {
taskTable.value.setCurrentRow({});// taskTable.value.setCurrentRow({});//
currentRow.value.id = 0; // currentRow.value = {id:0}; //
taskList.value = []; taskList.value = [];
// initHomeWork(); // initHomeWork();
setTimeout(() => { setTimeout(() => {
@ -429,6 +399,7 @@ const successHomework = () => {
initHomeWork(); initHomeWork();
}) })
} }
// -------------------- // --------------------
let classWorkForm = reactive({ let classWorkForm = reactive({
id: '',// cloneDeep(props.propsformobj.id), id: '',// cloneDeep(props.propsformobj.id),
@ -459,7 +430,7 @@ const handleCurrentChange = (val) => {
console.log(val,'???????????') console.log(val,'???????????')
if(val && val.id >0 ) { if(val && val.id >0 ) {
currentRow.value.id = 1; currentRow.value = val;
classWorkForm.worktype = val.worktype; // classWorkForm.worktype = val.worktype; //
editListItem(val, courseObj).then((obj) => { editListItem(val, courseObj).then((obj) => {
if(obj){ if(obj){
@ -611,33 +582,6 @@ const handleClassWorkFormQuizRemove = (index) =>{
fileLoading.value = false fileLoading.value = false
} }
} }
else if(classWorkForm.worktype === "科学实验"){
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验的课程!'});
cform.worktag = useClassTaskStores.experimentObj.updateEduInfo; // , [-]
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); //
cform.entpcourseworklist = JSON.stringify([{'id':-3, 'score': '10'}]);
try {
console.log(cform,'科学实验')
addClassworkReturnId(cform).then((res) => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "科学实验";
classWorkForm.uniquekey = ''; // props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = []; // list
classWorkForm.whiteboardObj = ''; // ? //
classWorkForm.fileHomeworkList = []; // list
classWorkForm.id = res
emits('getData',classWorkForm)
// TODO
})
} finally{
//
}
}
else { else {
// //
var ll = []; var ll = [];
@ -684,9 +628,9 @@ const handleClassWorkFormQuizRemove = (index) =>{
console.log('该清空左侧列表数据了'); console.log('该清空左侧列表数据了');
// //
if(isShow.value){ if(isShow.value){
currentRow.value.id = 1; currentRow.value = {id:1};
}else{ }else{
currentRow.value.id = 0; currentRow.value = {id:0};
} }
initHomeWork(); initHomeWork();
@ -723,10 +667,7 @@ const editWork = async (cform) =>{
}else{ }else{
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请上传常规作业附件!'}); if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请上传常规作业附件!'});
} }
}else if( classWorkForm.worktype == '科学实验') { }else {
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验科目!'});
}
else {
if (classWorkForm.chooseWorkLists.length == 0) { if (classWorkForm.chooseWorkLists.length == 0) {
// //
ElMessage.error('请先添加作业资源!'); ElMessage.error('请先添加作业资源!');
@ -818,46 +759,19 @@ const editWork = async (cform) =>{
// 1. (, ) // 1. (, )
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList); cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
} }
else if (classWorkForm.worktype=='科学实验') { //TODO fileHomeworkList
// 1. (, )
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
cform.worktag = useClassTaskStores.experimentObj.updateEduInfo;
}
// 3. // 3.
let res = await updateClasswork(cform); let res = await updateClasswork(cform);
if (res.code == 200) { if (res.code == 200) {
ElMessage.success('更新成功'); ElMessage.success('更新成功');
taskList.value = [];
// //
if(isShow.value){ currentRow.value = {id:0};
currentRow.value.id = 1;
}else{
handleNewAllClass();
currentRow.value.id = 0;
}
initHomeWork(); initHomeWork();
// // // //
// router.back() // router.back()
} }
} }
// ,
const handlePrint = () => {
const printOptions = {
silent: false, //
printBackground: true, //
color: false, //
marginsType: 0, // 0: 1: 2:
pageSize: 'A4', //
//
};
console.log("print-page-click");
ipcRenderer.send('printPage', printOptions);
};
//---- //----
@ -951,11 +865,6 @@ const handlePrint = () => {
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;
@ -994,8 +903,5 @@ const handlePrint = () => {
} }
} }
} }
::v-deep img {
display: inline-block !important;
}
</style> </style>

View File

@ -17,13 +17,6 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4" :offset="2">
<el-button v-if="!props.isHtml2canvas" type="primary" @click="goToQuestUpload()">添加习题</el-button>
</el-col>
</el-row>
<!-- 习题筛选2 -->
<el-row style="width: 100%; height: 50px;">
<el-col :span="7"> <el-col :span="7">
<el-form-item label="年份" label-width="70"> <el-form-item label="年份" label-width="70">
<el-select v-model="entpCourseWorkQueryParams.yearStr" placeholder="请选择"> <el-select v-model="entpCourseWorkQueryParams.yearStr" placeholder="请选择">
@ -31,6 +24,9 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<!-- 习题筛选2 -->
<el-row style="width: 100%; height: 50px;">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="关键词" label-width="70"> <el-form-item label="关键词" label-width="70">
<el-input <el-input
@ -43,6 +39,9 @@
<el-col :span="5"> <el-col :span="5">
<el-button @click="handleQueryParamFromEntpCourseWork(1)"><el-icon><Search /></el-icon> </el-button> <el-button @click="handleQueryParamFromEntpCourseWork(1)"><el-icon><Search /></el-icon> </el-button>
</el-col> </el-col>
<el-col :span="5">
<el-button v-if="!props.isHtml2canvas" type="primary" @click="goToQuestUpload()">添加习题</el-button>
</el-col>
</el-row> </el-row>
<!-- 习题表格 --> <!-- 习题表格 -->
<div class="page-table" > <div class="page-table" >
@ -130,7 +129,6 @@ import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import QuesItem from "@/views/classTask/newClassTaskAssign/questionUpload/quesItem/index.vue"; import QuesItem from "@/views/classTask/newClassTaskAssign/questionUpload/quesItem/index.vue";
import { useHandleData } from "@/hooks/useHandleData"; import { useHandleData } from "@/hooks/useHandleData";
import { processList } from '@/hooks/useProcessList'; import { processList } from '@/hooks/useProcessList';
import { isJson } from "@/utils/comm";
import { debounce } from '@/utils/comm' import { debounce } from '@/utils/comm'
@ -256,7 +254,6 @@ function Apis(key) {
const client = new Apis('/paht'); const client = new Apis('/paht');
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const evalId = props.bookobj.levelSecondId=='' ? props.bookobj.levelFirstId : props.bookobj.levelSecondId;
const queryForm = { const queryForm = {
// //
worktype: entpCourseWorkQueryParams.worktype.label, worktype: entpCourseWorkQueryParams.worktype.label,
@ -269,7 +266,7 @@ const t = function(name, time) {
// //
edustage: userStore.edustage, // this.userStore.edustage, edustage: userStore.edustage, // this.userStore.edustage,
edusubject: userStore.edusubject, // this.userStore.edusubject, edusubject: userStore.edusubject, // this.userStore.edusubject,
eid: evalId, // id eid: props.bookobj.levelSecondId, // this.activeParams.lession.id,
status: "1", status: "1",
editUserId: userStore.userId, editUserId: userStore.userId,
//orderby: 'concat(worktype,timestamp) DESC', //orderby: 'concat(worktype,timestamp) DESC',
@ -329,13 +326,10 @@ const handleQueryFromEntpCourseWork= async (queryType) => {
} }
//console.log("clueres.rows[i].childlist",clueres.rows[i].childlist); //console.log("clueres.rows[i].childlist",clueres.rows[i].childlist);
if (clueres.rows[i].childlist != '') { if (clueres.rows[i].childlist != '') {
const tmpJson = '['+clueres.rows[i].childlist+']'; clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
if (isJson(tmpJson)){
clueres.rows[i].childArray = JSON.parse(tmpJson);
for (var j=0; j<clueres.rows[i].childArray.length; j++) { for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, ''); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
} }
}
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
} }
@ -488,16 +482,8 @@ const debounceQueryData = debounce(() => {
}, 1000); }, 1000);
watch([ watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
() => props.bookobj.levelFirstId,
() => props.bookobj.levelSecondId
], ([newLevelSecondId, newLevelFirstId], [oldLevelSecondId, oldLevelFirstId]) => {
console.log(props.bookobj,'课程选择') console.log(props.bookobj,'课程选择')
// , ,
if (props.bookobj.levelSecondId == '') {
workResource.entpCourseWorkList = [];
return;
}
debounceQueryData(); debounceQueryData();
}) })

View File

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

View File

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

View File

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

View File

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

View File

@ -18,9 +18,9 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<!-- <el-form-item label="知识点" label-width="70"> <el-form-item label="知识点" label-width="70">
<el-cascader <el-cascader
:disabled="entpCourseWorkPointList.length==0" disabled
v-model="entpCourseWorkQueryParams.point" v-model="entpCourseWorkQueryParams.point"
clearable clearable
style="width: 100%" style="width: 100%"
@ -31,7 +31,7 @@
collapse-tags collapse-tags
collapse-tags-tooltip collapse-tags-tooltip
/> />
</el-form-item> --> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<!-- 习题筛选2 --> <!-- 习题筛选2 -->
@ -117,8 +117,6 @@ import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
import { getBindlist } from '@/api/education/knowledgePoint' import { getBindlist } from '@/api/education/knowledgePoint'
import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue' import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import { processList } from '@/hooks/useProcessList' import { processList } from '@/hooks/useProcessList'
import { isJson } from "@/utils/comm";
import { useGetHomework } from '@/hooks/useGetHomework' import { useGetHomework } from '@/hooks/useGetHomework'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import {throttle,debounce } from '@/utils/comm' import {throttle,debounce } from '@/utils/comm'
@ -132,8 +130,7 @@ const userStore = useUserStore().user
const { const {
entpCourseWorkTypeList, entpCourseWorkTypeList,
entpCourseWorkGroupList, entpCourseWorkGroupList,
entpCourseWorkYearList, entpCourseWorkYearList
entpCourseWorkPointList
} = useClassTaskStore(); } = useClassTaskStore();
const props = defineProps({ const props = defineProps({
@ -147,11 +144,12 @@ const props = defineProps({
}, },
}) })
// const entpCourseWorkPointList = ref([ const entpCourseWorkPointList = ref([
// {label: '', value: []}, {label: '不限', value: []},
// ]); // - ]); // -
const knowledgePointProps = reactive({value: 'thirdId', label: 'knowTitle'}); const knowledgePointProps = ref({value: 'thirdId', label: 'title'});
//const knowledgePointProps = ref({value: 'thirdId', label: 'title'}); //const knowledgePointProps = ref({value: 'thirdId', label: 'knowTitle'});
// //
const entpCourseWorkQueryParams = reactive({ const entpCourseWorkQueryParams = reactive({
@ -192,8 +190,6 @@ const workResource = reactive({
onMounted(() => { onMounted(() => {
console.log('entpCourseWorkTypeList', entpCourseWorkTypeList); console.log('entpCourseWorkTypeList', entpCourseWorkTypeList);
// ()
//getEntpCourseWorkPointList();
debounceQueryData(); // debounceQueryData(); //
}) })
@ -239,13 +235,12 @@ function Apis(key) {
const client = new Apis('/paht'); const client = new Apis('/paht');
const t = function(name, time) { const t = function(name, time) {
return new Promise(resolve => { return new Promise(resolve => {
const evalId = props.bookobj.levelSecondId=='' ? props.bookobj.levelFirstId : props.bookobj.levelSecondId;
const queryForm = { const queryForm = {
// //
currentPage: paginationParams.pageNum, currentPage: paginationParams.pageNum,
pageSize: paginationParams.pageSize, pageSize: paginationParams.pageSize,
// //
eid: evalId, // id eid: props.bookobj.levelSecondId,
sectionName: props.bookobj.coursetitle, sectionName: props.bookobj.coursetitle,
edusubject: userStore.edusubject, edusubject: userStore.edusubject,
edustage: userStore.edustage, edustage: userStore.edustage,
@ -258,7 +253,7 @@ const t = function(name, time) {
// //
yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'', yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
// //
thirdId: entpCourseWorkQueryParams.point&&entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[entpCourseWorkQueryParams.point.length-1]:'', thirdId: entpCourseWorkQueryParams.point&&entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[0]:'',
// //
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'', keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
@ -334,13 +329,10 @@ const handleQueryFromEntpCourseWork= async (queryType) => {
} }
//console.log("clueres.rows[i].childlist",clueres.rows[i].childlist); //console.log("clueres.rows[i].childlist",clueres.rows[i].childlist);
if (clueres.rows[i].childlist != '') { if (clueres.rows[i].childlist != '') {
const tmpJson = '['+clueres.rows[i].childlist+']'; clueres.rows[i].childArray = JSON.parse('['+clueres.rows[i].childlist+']');
if (isJson(tmpJson)){
clueres.rows[i].childArray = JSON.parse(tmpJson);
for (var j=0; j<clueres.rows[i].childArray.length; j++) { for (var j=0; j<clueres.rows[i].childArray.length; j++) {
clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, ''); clueres.rows[i].childArray[j].title = clueres.rows[i].childArray[j].title.replace(/(<([^>]+)>)/ig, '');
} }
}
} else { } else {
clueres.rows[i].childArray = {}; clueres.rows[i].childArray = {};
} }
@ -351,7 +343,6 @@ const handleQueryFromEntpCourseWork= async (queryType) => {
} }
/** /**
* 注意: 该方法已不再使用, 具体知识点初始化方法查看 useClassTaskStore - 241230
* 3知识点 * 3知识点
*/ */
const getEntpCourseWorkPointList = async () => { const getEntpCourseWorkPointList = async () => {
@ -469,29 +460,19 @@ const captureScreenshot = (id) => {
// //
const debounceQueryData = debounce(() => { const debounceQueryData = debounce(() => {
console.log("防抖 加载数据中...") console.log("防抖 加载数据中...")
console.log(props.bookobj,'课程选择')
// //
initPageParams(); initPageParams();
// //
handleQueryFromEntpCourseWork(0); handleQueryFromEntpCourseWork(0);
// //
//getQueryFromEvaluationclue(); getQueryFromEvaluationclue();
// //
//getEntpCourseWorkPointList(); getEntpCourseWorkPointList();
}, 1000); }, 1000);
//watch(() => props.bookobj.levelSecondId, async (newVal, oldVal) => {
watch([ watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
() => props.bookobj.levelFirstId,
() => props.bookobj.levelSecondId
], ([newLevelSecondId, newLevelFirstId], [oldLevelSecondId, oldLevelFirstId]) => {
console.log(props.bookobj,'课程选择') console.log(props.bookobj,'课程选择')
// , ,
if (props.bookobj.levelSecondId == '') {
workResource.entpCourseWorkList = [];
return;
}
debounceQueryData(); debounceQueryData();
}) })

View File

@ -734,10 +734,6 @@ const msgHandle = (msg) => {
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 => {
@ -821,7 +817,6 @@ onUnmounted(() => {
<style scoped lang="scss"> <style scoped lang="scss">
.teachClassTask{ .teachClassTask{
padding: 10px;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<template> <template>
<el-row class="model-wrap"> <el-row class="model-wrap">
<!-- 左侧 选择教材 目录 --> <!-- 左侧 选择教材 目录 -->
<ChooseTextbook :isClassTask="true" @change-book="changeBook" @node-click="changeBook" /> <ChooseTextbook @change-book="changeBook" @node-click="changeBook" />
<!-- 右侧 展示内容 --> <!-- 右侧 展示内容 -->
<div class="right-content"> <div class="right-content">
<div class="content-header-wrap"> <div class="content-header-wrap">
@ -63,8 +63,7 @@
<div class="content-body-right-body"> <div class="content-body-right-body">
<div class="content-body-right-item" v-for="(item,index) in tools" :key="index" @click="gotoRoute(item)"> <div class="content-body-right-item" v-for="(item,index) in tools" :key="index" @click="gotoRoute(item)">
<div class="content-body-right-item-img"> <div class="content-body-right-item-img">
<img v-if="item.suffix" :src="getStaticUrl(`/icon/${item.img}.${item.suffix}`)" /> <FileImage :fileName="item.img"/>
<FileImage v-else :fileName="item.img"/>
</div> </div>
<div class="content-body-right-item-text">{{item.name}}</div> <div class="content-body-right-item-text">{{item.name}}</div>
</div> </div>
@ -84,8 +83,6 @@ import useUserStore from '@/store/modules/user' // 用户信息
import ChooseTextbook from '@/components/choose-textbook/index.vue' import ChooseTextbook from '@/components/choose-textbook/index.vue'
import KjListItem from '@/views/prepare/container/kj-list-item.vue' import KjListItem from '@/views/prepare/container/kj-list-item.vue'
import FileImage from '@/components/file-image/index.vue' import FileImage from '@/components/file-image/index.vue'
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
import ThumbnailSlide from '@/AixPPTist/src/views/components/ThumbnailSlide/index.vue'
import {creatAPT, getSmarttalkPage, getModelInfo} from '@/api/file' import {creatAPT, getSmarttalkPage, getModelInfo} from '@/api/file'
import {ArrowDown, Flag, Position} from '@element-plus/icons-vue' import {ArrowDown, Flag, Position} from '@element-plus/icons-vue'
import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile"; import {asyncLocalFile, parseCataByNode} from "@/utils/talkFile";
@ -93,21 +90,18 @@ import { dataSetJson } from '@/utils/comm' // 数据集id文生图
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import {listEntpcourse} from "@/api/teaching/classwork"; import {listEntpcourse} from "@/api/teaching/classwork";
import {addEntpcoursefileReturnId, getEntpcoursefile} from "@/api/education/entpcoursefile"; import {addEntpcoursefileReturnId, getEntpcoursefile} from "@/api/education/entpcoursefile";
import {createWindow, toLinkLeftWeb, getStaticUrl} from "@/utils/tool"; import {createWindow, toLinkLeftWeb} from "@/utils/tool";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport"; import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
import * as API_entpcoursefile from "@/api/education/entpcoursefile"; import * as API_entpcoursefile from "@/api/education/entpcoursefile";
import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue'
import msgUtils from "@/plugins/modal"; import msgUtils from "@/plugins/modal";
import * as commUtils from "@/utils/comm"; import * as commUtils from "@/utils/comm";
import * as Api_server from "@/api/apiService"; // import * as Api_server from "@/api/apiService"; //
import useClassTaskStore from '@/store/modules/classTask'
import { slidesToImg } from '@/utils/ppt' // ppt
const router = useRouter() const router = useRouter()
const userStore = useUserStore().user // const userStore = useUserStore().user //
const currentNode = ref({}) const currentNode = ref({})
const refs = ref([]); const refs = ref([]);
const classTaskStore = useClassTaskStore();
const collectRef = (key) => { const collectRef = (key) => {
return (el) => { return (el) => {
@ -153,7 +147,7 @@ const tools = reactive([{
img: 'airobot' img: 'airobot'
},{ },{
name: '语音生成', name: '语音生成',
path: '/model/aiVoice', path: '',
img: 'aiyuyin' img: 'aiyuyin'
},{ },{
name: '文生图片', name: '文生图片',
@ -172,26 +166,7 @@ const tools = reactive([{
path: 'https://ai.ysaix.com:7845/', path: 'https://ai.ysaix.com:7845/',
type: 'link', type: 'link',
img: 'aiyinyue' img: 'aiyinyue'
},{ }])
name: 'Kimi',
path: 'https://kimi.moonshot.cn',
type: 'link',
img: 'kimi',
suffix: 'svg'
},{
name: 'Deepseek',
path: 'https://chat.deepseek.com',
type: 'link',
img: 'deepseek',
suffix: 'svg'
},{
name: '通义千问',
path: 'https://tongyi.aliyun.com/qianwen',
type: 'link',
img: 'tongyi',
suffix: 'svg'
}
])
const uploadData = ref({ const uploadData = ref({
textbookId: null, textbookId: null,
@ -211,19 +186,6 @@ const gotoRoute = (item) => {
if (item.path) { if (item.path) {
if (item.path === '/model/aiKolors') { if (item.path === '/model/aiKolors') {
gotoAiKolors(item.path) gotoAiKolors(item.path)
}else if(item.path == '/model/aiVoice'){
console.log('aiVoice',uploadData.value)
const path = '/model/aiVoice'
let subjectdata = sessionStore.get('subject.curNode')
let datasubject = `课标-${subjectdata.edustage}-${subjectdata.edusubject}`
router.push({
path,
query: {
datasetId: dataSetJson[datasubject],
coursetitle: currentNode.value.itemtitle,
...uploadData.value
}
});
}else { }else {
router.push(item.path) router.push(item.path)
} }
@ -313,14 +275,12 @@ const handleFileChange = ()=> {
createAIPPTByFile(file) createAIPPTByFile(file)
} }
} }
// pptPPT线
const createAIPPTByFile = async (file)=> { const createAIPPTByFile = async (file)=> {
// pgDialog.value.visible = true pgDialog.value.visible = true
// pgDialog.value.pg.percentage = 0 pgDialog.value.pg.percentage = 0
const resPptJson = await PPTXFileToJson(file) const resPptJson = await PPTXFileToJson(file)
const { def, slides, ...content } = resPptJson const { def, slides, ...content } = resPptJson
//
const thumbnails = await slidesToImg(slides, content.width)
// || 线 // || 线
let completed = 0 let completed = 0
const total = slides.length const total = slides.length
@ -372,7 +332,6 @@ const createAIPPTByFile = async (file)=> {
entpcourseid: resCourse.id, entpcourseid: resCourse.id,
title: '', title: '',
filetype: 'slide', filetype: 'slide',
thumbnails, // -
slides: resSlides, slides: resSlides,
edituserid: userStore.userId edituserid: userStore.userId
} }
@ -443,8 +402,8 @@ const changeBook = async(data) => {
let cata = parseCataByNode(data.node) let cata = parseCataByNode(data.node)
currentNode.value = data.node currentNode.value = data.node
uploadData.value.levelFirstId = cata[0] uploadData.value.levelFirstId = cata[0]
uploadData.value.levelSecondId = cata[1] ?? '' uploadData.value.levelSecondId = cata[1]
uploadData.value.levelThirdId = cata[2] ?? '' uploadData.value.levelThirdId = cata[2]
uploadData.value.textbookId = data.textBook.curBookId uploadData.value.textbookId = data.textBook.curBookId
getModelInfo({cataid: currentNode.value.id}).then(res=>{ getModelInfo({cataid: currentNode.value.id}).then(res=>{
console.log(res) console.log(res)
@ -484,14 +443,6 @@ const changeBook = async(data) => {
}).then((res) => { }).then((res) => {
currentFileList.value = [...res.rows] currentFileList.value = [...res.rows]
}) })
//
const pointParams = {
...uploadData.value,
edustage: data.node.edustage,
edusubject: data.node.edusubject,
}
await classTaskStore.initJYPoint(pointParams);
} }
const onchange = (item) => { const onchange = (item) => {
let path = item.path let path = item.path
@ -535,8 +486,8 @@ const changeClass = async (type, row, other) => {
createWindow('open-win', { createWindow('open-win', {
url: '/pptist', // url: '/pptist', //
close: () => { close: () => {
sessionStore.delete('curr.resource') // sessionStore.set('curr.resource', null) //
sessionStore.delete('curr.smarttalk') // sessionStore.set('curr.smarttalk', null) //
getSmarttalkPage({ getSmarttalkPage({
...uploadData.value, ...uploadData.value,
orderByColumn: 'createTime', orderByColumn: 'createTime',
@ -562,9 +513,7 @@ const changeClass = async (type, row, other) => {
} }
// //
onMounted(async () => { onMounted(() => {
//
await classTaskStore.initJYInfo(userStore);
}) })
</script> </script>
@ -691,15 +640,12 @@ onMounted(async () => {
} }
.content-body-right-body{ .content-body-right-body{
display: flex; display: flex;
flex-wrap: wrap;
gap: 15px;
padding: 10px;
.content-body-right-item{ .content-body-right-item{
&:hover{ &:hover{
cursor: pointer; cursor: pointer;
} }
height: 80px; height: 80px;
width: 70px; width: 100px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;

View File

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

Some files were not shown because too many files have changed in this diff Show More