Compare commits
47 Commits
f7a3aa6e53
...
62a419356c
Author | SHA1 | Date |
---|---|---|
lyc | 62a419356c | |
lyc | 4b2d13db8e | |
zhengdegang | f63bb69919 | |
zdg | b3ffa9bdaa | |
zdg | 5510021566 | |
lyc | 89e0b2f97c | |
lyc | 406e581182 | |
lyc | ea0e1c91cf | |
lyc | d4dce61555 | |
lyc | d6d5d13232 | |
zhengdegang | 33e38f8992 | |
zdg | 11968879d8 | |
zdg | db86299523 | |
zdg | c152a3d3ee | |
lyc | 9c8872579f | |
lyc | 4f32927b49 | |
zhangxuelin | e132f3927b | |
朱浩 | c290c170d3 | |
朱浩 | 3867a9603f | |
zhangxuelin | f732520d8d | |
lyc | 01fbb9d05c | |
lyc | 1334becb54 | |
lyc | c95508ed59 | |
zhangxuelin | cf540d73df | |
baigl | 35bf246975 | |
白了个白 | e3c4706880 | |
白了个白 | c507331fb5 | |
lyc | abd7be0698 | |
lyc | 92e8aa64d7 | |
zhangxuelin | 83d3cd5df8 | |
朱浩 | b1407706a8 | |
朱浩 | 996b4006a2 | |
朱浩 | 4531533382 | |
朱浩 | a601a9f8dd | |
zhengdegang | 086836e016 | |
zdg | acb0231304 | |
baigl | 94e23c3d69 | |
白了个白 | ea5ed4b6ac | |
白了个白 | 6b45fa61dd | |
白了个白 | 7aa75794dc | |
朱浩 | a2c2c4eec7 | |
CYS | 4095390f45 | |
cys | d75af2636d | |
朱浩 | 1983dafbba | |
朱浩 | 6c7284383a | |
baigl | 28f79f7ab0 | |
zhangxuelin | 64272467a2 |
|
@ -17,6 +17,7 @@ VITE_APP_RES_FILE_PATH = 'https://file.ysaix.com:7868/src/assets/textbook/booktx
|
||||||
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
|
VITE_APP_BUILD_BASE_PATH = 'https://file.ysaix.com:7868/'
|
||||||
|
|
||||||
# websocket 地址
|
# websocket 地址
|
||||||
|
# VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
||||||
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
VITE_APP_WS_URL = 'wss://file.ysaix.com:7868'
|
||||||
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865'
|
# VITE_APP_WS_URL = 'ws://192.168.2.16:7865'
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 文枢课堂
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV = 'production'
|
||||||
|
|
||||||
|
# AIx融合数字管理系统/生产环境
|
||||||
|
VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||||
|
|
||||||
|
VITE_APP_DOMAIN = 'prev.ysaix.com'
|
||||||
|
|
||||||
|
VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||||
|
|
||||||
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
|
||||||
|
VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
|
||||||
|
|
||||||
|
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||||
|
|
||||||
|
# websocket 地址
|
||||||
|
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
||||||
|
|
||||||
|
# 是否显示开发工具
|
||||||
|
VITE_SHOW_DEV_TOOLS = 'false'
|
|
@ -0,0 +1,25 @@
|
||||||
|
# 页面标题
|
||||||
|
VITE_APP_TITLE = 实训教学
|
||||||
|
|
||||||
|
# 生产环境配置
|
||||||
|
VITE_APP_ENV = 'production'
|
||||||
|
|
||||||
|
# AIx融合数字管理系统/生产环境
|
||||||
|
VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||||
|
|
||||||
|
VITE_APP_DOMAIN = 'prev.ysaix.com'
|
||||||
|
|
||||||
|
VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||||
|
|
||||||
|
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||||
|
VITE_BUILD_COMPRESS = gzip
|
||||||
|
|
||||||
|
VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
|
||||||
|
|
||||||
|
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||||
|
|
||||||
|
# websocket 地址
|
||||||
|
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
||||||
|
|
||||||
|
# 是否显示开发工具
|
||||||
|
VITE_SHOW_DEV_TOOLS = 'false'
|
|
@ -0,0 +1,54 @@
|
||||||
|
appId: com.electron.app.yc
|
||||||
|
productName: 文枢课堂
|
||||||
|
directories:
|
||||||
|
output: dist
|
||||||
|
buildResources: build
|
||||||
|
win:
|
||||||
|
executableName: 文枢课堂
|
||||||
|
icon: resources/yc-logo.png
|
||||||
|
files:
|
||||||
|
- '!**/.vscode/*'
|
||||||
|
- '!src/*'
|
||||||
|
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||||
|
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||||
|
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||||
|
asarUnpack:
|
||||||
|
- resources/**
|
||||||
|
nsis:
|
||||||
|
oneClick: false
|
||||||
|
allowToChangeInstallationDirectory: true
|
||||||
|
artifactName: ${name}-yc-${version}-setup.${ext}
|
||||||
|
shortcutName: ${productName}
|
||||||
|
uninstallDisplayName: ${productName}
|
||||||
|
createDesktopShortcut: always
|
||||||
|
mac:
|
||||||
|
entitlementsInherit: build/entitlements.mac.plist
|
||||||
|
extendInfo:
|
||||||
|
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||||
|
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||||
|
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||||
|
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||||
|
notarize: false
|
||||||
|
dmg:
|
||||||
|
artifactName: ${name}-${version}.${ext}
|
||||||
|
linux:
|
||||||
|
target:
|
||||||
|
- AppImage
|
||||||
|
- snap
|
||||||
|
- deb
|
||||||
|
maintainer: electronjs.org
|
||||||
|
category: Utility
|
||||||
|
appImage:
|
||||||
|
artifactName: ${name}-${version}.${ext}
|
||||||
|
npmRebuild: false
|
||||||
|
publish:
|
||||||
|
provider: generic
|
||||||
|
url: https://prev.ysaix.com:7868/src/assets/smarttalkyc/
|
||||||
|
electronDownload:
|
||||||
|
mirror: https://npmmirror.com/mirrors/electron/
|
||||||
|
# 额外依赖打包到输出目录
|
||||||
|
extraFiles:
|
||||||
|
- from: ./node_modules/im_electron_sdk/lib/
|
||||||
|
to: ./resources
|
||||||
|
filter:
|
||||||
|
- '**/*'
|
|
@ -0,0 +1,54 @@
|
||||||
|
appId: com.electron.app.yc2
|
||||||
|
productName: 实训教学
|
||||||
|
directories:
|
||||||
|
output: dist
|
||||||
|
buildResources: build
|
||||||
|
win:
|
||||||
|
executableName: 实训教学
|
||||||
|
icon: resources/yc-logo.png
|
||||||
|
files:
|
||||||
|
- '!**/.vscode/*'
|
||||||
|
- '!src/*'
|
||||||
|
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||||
|
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||||
|
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||||
|
asarUnpack:
|
||||||
|
- resources/**
|
||||||
|
nsis:
|
||||||
|
oneClick: false
|
||||||
|
allowToChangeInstallationDirectory: true
|
||||||
|
artifactName: ${name}-ycsx-${version}-setup.${ext}
|
||||||
|
shortcutName: ${productName}
|
||||||
|
uninstallDisplayName: ${productName}
|
||||||
|
createDesktopShortcut: always
|
||||||
|
mac:
|
||||||
|
entitlementsInherit: build/entitlements.mac.plist
|
||||||
|
extendInfo:
|
||||||
|
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||||
|
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||||
|
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||||
|
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||||
|
notarize: false
|
||||||
|
dmg:
|
||||||
|
artifactName: ${name}-${version}.${ext}
|
||||||
|
linux:
|
||||||
|
target:
|
||||||
|
- AppImage
|
||||||
|
- snap
|
||||||
|
- deb
|
||||||
|
maintainer: electronjs.org
|
||||||
|
category: Utility
|
||||||
|
appImage:
|
||||||
|
artifactName: ${name}-${version}.${ext}
|
||||||
|
npmRebuild: false
|
||||||
|
publish:
|
||||||
|
provider: generic
|
||||||
|
url: https://prev.ysaix.com:7868/src/assets/smarttalkycsx/
|
||||||
|
electronDownload:
|
||||||
|
mirror: https://npmmirror.com/mirrors/electron/
|
||||||
|
# 额外依赖打包到输出目录
|
||||||
|
extraFiles:
|
||||||
|
- from: ./node_modules/im_electron_sdk/lib/
|
||||||
|
to: ./resources
|
||||||
|
filter:
|
||||||
|
- '**/*'
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "aix-win-ws",
|
"name": "aix-win-ws",
|
||||||
"version": "2.5.7",
|
"version": "2.5.8",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "上海交大重庆人工智能研究院",
|
"author": "上海交大重庆人工智能研究院",
|
||||||
|
@ -16,6 +16,8 @@
|
||||||
"build:dev": "npm run build && electron-builder --win --config ./electron-builder-test.yml",
|
"build:dev": "npm run build && electron-builder --win --config ./electron-builder-test.yml",
|
||||||
"build:test": "electron-vite build --mode test && electron-builder --win --config ./electron-builder.yml",
|
"build:test": "electron-vite build --mode test && electron-builder --win --config ./electron-builder.yml",
|
||||||
"build:prod": "electron-vite build --mode production && electron-builder --win --config ./electron-builder-prod.yml",
|
"build:prod": "electron-vite build --mode production && electron-builder --win --config ./electron-builder-prod.yml",
|
||||||
|
"build:yc": "electron-vite build --mode yc && electron-builder --win --config ./electron-builder-yc.yml",
|
||||||
|
"build:yc2": "electron-vite build --mode yc2 && electron-builder --win --config ./electron-builder-yc2.yml",
|
||||||
"build:lt": "electron-vite build --mode lt && electron-builder --win --config ./electron-builder-lt.yml",
|
"build:lt": "electron-vite build --mode lt && electron-builder --win --config ./electron-builder-lt.yml",
|
||||||
"build:mac": "electron-vite build --mode production && electron-builder --mac --config ./electron-builder-prod.yml",
|
"build:mac": "electron-vite build --mode production && electron-builder --mac --config ./electron-builder-prod.yml",
|
||||||
"build:linux": "npm run build && electron-builder --linux"
|
"build:linux": "npm run build && electron-builder --linux"
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
|
@ -7,6 +7,7 @@ import Logger from './logger' // 日志封装
|
||||||
import chat from './chat' // chat封装
|
import chat from './chat' // chat封装
|
||||||
import Store from './store' // Store封装
|
import Store from './store' // Store封装
|
||||||
import updateInit from './update'
|
import updateInit from './update'
|
||||||
|
|
||||||
// 代理 electron/remote
|
// 代理 electron/remote
|
||||||
// 第一步:引入remote
|
// 第一步:引入remote
|
||||||
import remote from '@electron/remote/main'
|
import remote from '@electron/remote/main'
|
||||||
|
@ -41,19 +42,19 @@ if(!gotTheLock){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
let logoIco = import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?'../../resources/yc-logo.png':'../../resources/logo2.ico'
|
||||||
//登录窗口
|
//登录窗口
|
||||||
function createLoginWindow() {
|
function createLoginWindow() {
|
||||||
if (loginWindow) return
|
if (loginWindow) return
|
||||||
loginWindow = new BrowserWindow({
|
loginWindow = new BrowserWindow({
|
||||||
width: 888,
|
width: import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?1060:888,
|
||||||
height: 520,
|
height: 520,
|
||||||
show: false,
|
show: false,
|
||||||
frame: false,
|
frame: false,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
icon: join(__dirname, '../../resources/logo2.ico'),
|
icon: join(__dirname, logoIco),
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
defaultEncoding: 'utf-8',
|
defaultEncoding: 'utf-8',
|
||||||
|
@ -95,7 +96,7 @@ function createMainWindow() {
|
||||||
frame: false, // 无边框
|
frame: false, // 无边框
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
icon: join(__dirname, '../../resources/logo2.ico'),
|
icon: join(__dirname, logoIco),
|
||||||
...(process.platform === 'linux' ? { icon } : {}),
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
defaultEncoding: 'utf-8',
|
defaultEncoding: 'utf-8',
|
||||||
|
|
|
@ -74,8 +74,6 @@ const initLoad: Function = () => {
|
||||||
!!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// 有比例配置项
|
!!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// 有比例配置项
|
||||||
}
|
}
|
||||||
return PPTApi.getSlideList(resource.id)
|
return PPTApi.getSlideList(resource.id)
|
||||||
// PPTApi.updateWorkList()
|
|
||||||
// return Promise.resolve()
|
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ 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() // 课堂信息-状态管理
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
// 上课状态才-初始化socket
|
||||||
|
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' })
|
||||||
|
|
|
@ -50,6 +50,8 @@ export class Utils {
|
||||||
}, delay)
|
}, delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 延时
|
||||||
|
static sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ppt相关后端接口处理 */
|
/** ppt相关后端接口处理 */
|
||||||
|
@ -84,6 +86,12 @@ export class PPTApi {
|
||||||
slidesStore.setWorkItem(workItem)
|
slidesStore.setWorkItem(workItem)
|
||||||
// 没有上课时调用-作业列表
|
// 没有上课时调用-作业列表
|
||||||
if(!classcourse) this.updateWorkList()
|
if(!classcourse) this.updateWorkList()
|
||||||
|
// 没有上课时调用-批量更新缩略图
|
||||||
|
if(!classcourse) {
|
||||||
|
Utils.sleep(1500).then(() => {
|
||||||
|
this.batchUpdateThumUrl()
|
||||||
|
})
|
||||||
|
}
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else msgUtils.msgError(res.msg || '获取数据失败');resolve(false)
|
} else msgUtils.msgError(res.msg || '获取数据失败');resolve(false)
|
||||||
})
|
})
|
||||||
|
@ -233,13 +241,20 @@ export class PPTApi {
|
||||||
|
|
||||||
// 批量更新缩略图-异步
|
// 批量更新缩略图-异步
|
||||||
static batchUpdateThumUrl() {
|
static batchUpdateThumUrl() {
|
||||||
return new Promise(async resolve => {
|
return nextTick().then(async () => {
|
||||||
const list = slidesStore.workItem || []
|
const list = slidesStore.workItem || []
|
||||||
if (!list.length) return resolve()
|
if (!list.length) return
|
||||||
const upList = []
|
const upList = []
|
||||||
for (const [ind,o] of list.entries()) {
|
for (const [ind,o] of list.entries()) {
|
||||||
const thumUrl = await this.getSlideThumUrl(ind)
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,8 @@ 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: 疑惑 */
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { MsgEnum } from './types' // 消息枚举
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
import Classcourse from './classcourse' // 课程相关
|
import Classcourse from './classcourse' // 课程相关
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal' // 消息工具
|
||||||
|
import * as dialogUtils from '@/utils/dialog' // 弹窗-函数
|
||||||
import { Homework } from './index' // api-作业相关
|
import { Homework } from './index' // api-作业相关
|
||||||
// import emitter from '@/utils/mitt' //mitt 事件总线
|
// import emitter from '@/utils/mitt' //mitt 事件总线
|
||||||
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
||||||
|
@ -114,6 +115,10 @@ 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
|
||||||
|
@ -137,4 +142,4 @@ export default () => {
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
|
import { useScreenStore, useSlidesStore, useClasscourseStore } from '../store'
|
||||||
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
import { enterFullscreen, exitFullscreen, isFullscreen } from '../utils/fullscreen'
|
||||||
|
import { sessionStore } from '@/utils/store' // electron-store 状态管理
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
@ -25,6 +26,9 @@ export default () => {
|
||||||
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
if (!!classcourse) { //DOTO 有课堂,执行退相关操作
|
||||||
console.log('退出放映状态')
|
console.log('退出放映状态')
|
||||||
ChatWs?.close() // 关闭ws
|
ChatWs?.close() // 关闭ws
|
||||||
|
sessionStore.delete('curr.classcourse') // 清除课堂信息
|
||||||
|
sessionStore.delete('curr.resource') // 清除课件信息
|
||||||
|
sessionStore.delete('curr.isPublic') // 清除公屏状态
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
|
@ -21,6 +21,7 @@ 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'])
|
||||||
|
|
||||||
|
@ -60,73 +61,31 @@ const fileUrl = computed(() => (item) =>{
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// 插入
|
// 插入
|
||||||
const onInsert = async (item) =>{
|
const onInsert = async (item) =>{
|
||||||
|
loading.value = true
|
||||||
const res = await fetch(item.fileFullPath)
|
const res = await fetch(item.fileFullPath)
|
||||||
const bolb = await res.blob()
|
const bolb = await res.blob()
|
||||||
const file = commUtils.blobToFile(bolb, item.fileShowName)
|
const file = commUtils.blobToFile(bolb, item.fileShowName)
|
||||||
|
|
||||||
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
try {
|
||||||
emit('insertMaterial',{ type: 'video', file })
|
const data = await PPTApi.toRousrceUrl(file)
|
||||||
}
|
if(videoSuffix.indexOf(getFileSuffix(item.fileShowName)) != -1){
|
||||||
else{
|
emit('insertMaterial',{ type: 'video', data })
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
emit('insertMaterial',{ type: 'img', data })
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|
|
@ -281,20 +281,17 @@ const toggleNotesPanel = () => {
|
||||||
// 插入素材
|
// 插入素材
|
||||||
interface MaterialParams {
|
interface MaterialParams {
|
||||||
type: string,
|
type: string,
|
||||||
file: any
|
data: string
|
||||||
}
|
}
|
||||||
const insertMaterial = (item: MaterialParams) =>{
|
const insertMaterial = async (item: MaterialParams) =>{
|
||||||
const { type, file } = item
|
const { type, data } = item
|
||||||
PPTApi.toRousrceUrl(file).then(data=>{
|
if(type == 'video'){
|
||||||
if(type == 'video'){
|
createVideoElement(data)
|
||||||
createVideoElement(data)
|
}
|
||||||
}
|
else{
|
||||||
else{
|
createImageElement(data)
|
||||||
createImageElement(data)
|
}
|
||||||
}
|
materiaVisible.value = false
|
||||||
materiaVisible.value = false
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文生图
|
// 文生图
|
||||||
|
|
|
@ -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,7 +15,7 @@
|
||||||
}">
|
}">
|
||||||
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
|
<PopoverMenuItem>导入 pptx 文件</PopoverMenuItem>
|
||||||
</FileInput>
|
</FileInput>
|
||||||
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem>
|
<PopoverMenuItem @click="setDialogForExport('pptx')">导出文件</PopoverMenuItem> -->
|
||||||
<PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem>
|
<PopoverMenuItem @click="resetSlides(); mainMenuVisible = false">重置幻灯片</PopoverMenuItem>
|
||||||
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> -->
|
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/issues')">意见反馈</PopoverMenuItem> -->
|
||||||
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
|
<!-- <PopoverMenuItem @click="goLink('https://github.com/pipipi-pikachu/PPTist/blob/master/doc/Q&A.md')">常见问题</PopoverMenuItem> -->
|
||||||
|
@ -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>
|
||||||
|
|
|
@ -2,6 +2,8 @@ import axios from 'axios'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import { getToken } from "@/utils/auth";
|
import { getToken } from "@/utils/auth";
|
||||||
|
|
||||||
|
let rootPath = import.meta.env.VITE_APP_ENV === 'production' ? 'https://ai.ysaix.com:7864' : ''
|
||||||
|
|
||||||
// 文生图片
|
// 文生图片
|
||||||
export function convertTextToPicture(data) {
|
export function convertTextToPicture(data) {
|
||||||
return axios({
|
return axios({
|
||||||
|
@ -42,7 +44,7 @@ export function getPicture(data) {
|
||||||
// 大模型对话生成prompt模板
|
// 大模型对话生成prompt模板
|
||||||
export function chattoprompt(dataset_id,prompt) {
|
export function chattoprompt(dataset_id,prompt) {
|
||||||
return axios({
|
return axios({
|
||||||
url: '/api/v1/parse/docs',
|
url: rootPath + '/api/v1/parse/docs',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
|
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
After Width: | Height: | Size: 520 KiB |
|
@ -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" />
|
<keywordDialog v-model="isWordDialog" :item="editItem" :modeType="type" />
|
||||||
</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(1)
|
const curMode = ref(2)
|
||||||
const modeOptions = ref([
|
const modeOptions = ref([
|
||||||
{
|
{
|
||||||
label: '教学大模型',
|
label: '教学大模型',
|
||||||
|
@ -205,7 +205,7 @@ const scrollToBottom = (height, index) => {
|
||||||
let listDom = listRef.value.children
|
let listDom = listRef.value.children
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
// 220 去掉头部
|
// 220 去掉头部
|
||||||
let screenHeight = window.innerHeight - 220
|
let screenHeight = window.innerHeight - 220
|
||||||
if (height > screenHeight) {
|
if (height > screenHeight) {
|
||||||
listRef.value.scrollTop = (height - screenHeight + 50)
|
listRef.value.scrollTop = (height - screenHeight + 50)
|
||||||
|
@ -240,7 +240,7 @@ const changeTemplate = (val) => {
|
||||||
const removeItem = async (item, isChild) => {
|
const removeItem = async (item, isChild) => {
|
||||||
/**
|
/**
|
||||||
* item: 当前操作的模板
|
* item: 当前操作的模板
|
||||||
* isChild: 子模板中的移除为 true
|
* isChild: 子模板中的移除为 true
|
||||||
*/
|
*/
|
||||||
if (item.ex3 != '1') {
|
if (item.ex3 != '1') {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
|
@ -320,7 +320,7 @@ const againResult = async (index, item) => {
|
||||||
str = str.replace('{模板内容}',item.prompt)
|
str = str.replace('{模板内容}',item.prompt)
|
||||||
params.prompt = str
|
params.prompt = str
|
||||||
params.template = item.prompt
|
params.template = item.prompt
|
||||||
|
|
||||||
let data = null;
|
let data = null;
|
||||||
// 教学大模型
|
// 教学大模型
|
||||||
if (curMode.value == 1) {
|
if (curMode.value == 1) {
|
||||||
|
@ -415,7 +415,7 @@ const onEditSave = async (item) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
const onSaveTemp = (item) => {
|
const onSaveTemp = async (item) => {
|
||||||
if (item.answer == '') return
|
if (item.answer == '') return
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -425,7 +425,10 @@ const onSaveTemp = (item) => {
|
||||||
content: item.answer,
|
content: item.answer,
|
||||||
ex1: curNode.id
|
ex1: curNode.id
|
||||||
}
|
}
|
||||||
tempSave(data).then(res => { })
|
const res = await tempSave(data)
|
||||||
|
if(!item.resultId){
|
||||||
|
item.resultId = res.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 去掉字符串中的 ### **
|
// 去掉字符串中的 ### **
|
||||||
|
@ -606,4 +609,4 @@ onUnmounted(() => {
|
||||||
width: 110px !important;
|
width: 110px !important;
|
||||||
min-width: 110px !important;
|
min-width: 110px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -38,6 +38,7 @@ const closeWindow = () => {
|
||||||
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
|
customClass: 'login-close-tool',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
userStore.logOut().then(() => {
|
userStore.logOut().then(() => {
|
||||||
|
@ -54,7 +55,11 @@ onMounted(() =>{
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
.login-close-tool {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.header-tool {
|
.header-tool {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -81,4 +86,4 @@ onMounted(() =>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -87,7 +87,7 @@ const getHomeWorkList = async () => {
|
||||||
// } else
|
// } else
|
||||||
// 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加
|
// 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加
|
||||||
if (res.rows[i].worktype == '课堂展示') {
|
if (res.rows[i].worktype == '课堂展示') {
|
||||||
res.rows[i].workclass = 'primary';
|
res.rows[i].workclass = 'success';
|
||||||
} 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 == '常规作业') {
|
||||||
|
@ -95,7 +95,7 @@ const getHomeWorkList = async () => {
|
||||||
} 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 == '科学实验') {
|
} else if (res.rows[i].worktype == '科学实验') {
|
||||||
res.rows[i].workclass = 'danger';
|
res.rows[i].workclass = 'primary';
|
||||||
} else {
|
} else {
|
||||||
res.rows[i].workclass = 'primary';
|
res.rows[i].workclass = 'primary';
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,8 @@ 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: 疑惑 */
|
||||||
|
|
|
@ -49,10 +49,10 @@ export function blobToFile(blob, fileName, contentType) {
|
||||||
/**
|
/**
|
||||||
* @description 计算两点直线距离 (获取直径)
|
* @description 计算两点直线距离 (获取直径)
|
||||||
* (欧几里得距离公式): [ \text{distance} = \sqrt{(x2 - x1)^2 + (y2 - y1)^2} ]
|
* (欧几里得距离公式): [ \text{distance} = \sqrt{(x2 - x1)^2 + (y2 - y1)^2} ]
|
||||||
* @param {*} x1
|
* @param {*} x1
|
||||||
* @param {*} y1
|
* @param {*} y1
|
||||||
* @param {*} x2
|
* @param {*} x2
|
||||||
* @param {*} y2
|
* @param {*} y2
|
||||||
*/
|
*/
|
||||||
export function getDistance(x1,y1,x2,y2) {
|
export function getDistance(x1,y1,x2,y2) {
|
||||||
return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2))
|
return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2))
|
||||||
|
@ -62,10 +62,10 @@ export function getRadius(x1,y1,x2,y2) { return getDistance(x1,y1,x2,y2) / 2 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算某个值在总数中所占的百分比。
|
* 计算某个值在总数中所占的百分比。
|
||||||
*
|
*
|
||||||
* 此函数用于根据给定的值和总数,计算该值占总数的百分比。它还支持指定百分比的小数位数。
|
* 此函数用于根据给定的值和总数,计算该值占总数的百分比。它还支持指定百分比的小数位数。
|
||||||
* 如果计算结果小于0,则返回0;如果大于100,则返回100,以确保百分比的合理范围。
|
* 如果计算结果小于0,则返回0;如果大于100,则返回100,以确保百分比的合理范围。
|
||||||
*
|
*
|
||||||
* @param {number} v - 待计算的值。
|
* @param {number} v - 待计算的值。
|
||||||
* @param {number} total - 总数。
|
* @param {number} total - 总数。
|
||||||
* @param {number} [step=2] - 百分比的小数位数,默认为2。
|
* @param {number} [step=2] - 百分比的小数位数,默认为2。
|
||||||
|
@ -76,7 +76,7 @@ export function getPercent(v, total, step=2) {
|
||||||
!total && (total = 1)
|
!total && (total = 1)
|
||||||
// 计算百分比,保留指定的小数位,并转换为数字类型
|
// 计算百分比,保留指定的小数位,并转换为数字类型
|
||||||
let res = (v / total * 100).toFixed(step)-0
|
let res = (v / total * 100).toFixed(step)-0
|
||||||
|
|
||||||
// 确保百分比在0到100之间
|
// 确保百分比在0到100之间
|
||||||
return res < 0 ? 0 : res > 100 ? 100 : res
|
return res < 0 ? 0 : res > 100 ? 100 : res
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ export function getPercent(v, total, step=2) {
|
||||||
* @param {*} start 前面保留几位 默认 3位
|
* @param {*} start 前面保留几位 默认 3位
|
||||||
* @param {*} end 后面保留几位 默认 3位
|
* @param {*} end 后面保留几位 默认 3位
|
||||||
* @param {*} rstr 替换字符 默认 ****
|
* @param {*} rstr 替换字符 默认 ****
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function phoneHideFormat(phone, start = 3, end = 4, rstr = '****') {
|
export function phoneHideFormat(phone, start = 3, end = 4, rstr = '****') {
|
||||||
// const reg = /^(\d{3})\d*(\d{4})$/
|
// const reg = /^(\d{3})\d*(\d{4})$/
|
||||||
|
@ -101,8 +101,8 @@ export function phoneHideFormat(phone, start = 3, end = 4, rstr = '****') {
|
||||||
// ============= 习题工具--相关 ===================
|
// ============= 习题工具--相关 ===================
|
||||||
/**
|
/**
|
||||||
* @description 将字符串转换为数组
|
* @description 将字符串转换为数组
|
||||||
* @param {*} str
|
* @param {*} str
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function quizStrToList(str = '') {
|
export function quizStrToList(str = '') {
|
||||||
if (!str) return []
|
if (!str) return []
|
||||||
|
@ -175,8 +175,8 @@ export const validateUrl = (url) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 时间 秒 转化 时分秒
|
* @description 时间 秒 转化 时分秒
|
||||||
* @param {*} seconds
|
* @param {*} seconds
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function formatTime(seconds) {
|
export function formatTime(seconds) {
|
||||||
seconds = parseInt(seconds) // 转换整数
|
seconds = parseInt(seconds) // 转换整数
|
||||||
|
@ -188,9 +188,9 @@ export function formatTime(seconds) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 时间格式化
|
* @description 时间格式化
|
||||||
* @param {*} time
|
* @param {*} time
|
||||||
* @param {*} fmt
|
* @param {*} fmt
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function formatDate(time, fmt = 'yyyy-MM-dd') {
|
export function formatDate(time, fmt = 'yyyy-MM-dd') {
|
||||||
let date
|
let date
|
||||||
|
@ -300,7 +300,7 @@ export function getDateStr1(num, fmt = 'yyyy-MM-dd hh:mm:ss') {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取当前 0:0:0:0 时间
|
* 获取当前 0:0:0:0 时间
|
||||||
* @param {*} [fmt] 格式 'yyyy-MM-dd hh:mm:ss'
|
* @param {*} [fmt] 格式 'yyyy-MM-dd hh:mm:ss'
|
||||||
*/
|
*/
|
||||||
export function getDateNow(fmt) {
|
export function getDateNow(fmt) {
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
|
@ -339,9 +339,9 @@ export function timeToStr(time,str = '时分秒', isPad = false) {
|
||||||
* debounce(() => {
|
* debounce(() => {
|
||||||
console.log('Input event handled');
|
console.log('Input event handled');
|
||||||
}, 300);
|
}, 300);
|
||||||
* @param {*} func
|
* @param {*} func
|
||||||
* @param {*} wait
|
* @param {*} wait
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function debounce(func, wait) {
|
export function debounce(func, wait) {
|
||||||
let timeout;
|
let timeout;
|
||||||
|
@ -358,9 +358,9 @@ export function debounce(func, wait) {
|
||||||
* throttle(() => {
|
* throttle(() => {
|
||||||
console.log('Scroll event handled');
|
console.log('Scroll event handled');
|
||||||
}, 300);
|
}, 300);
|
||||||
* @param {*} func
|
* @param {*} func
|
||||||
* @param {*} wait
|
* @param {*} wait
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function throttle(func, wait) {
|
export function throttle(func, wait) {
|
||||||
let lastTime = 0;
|
let lastTime = 0;
|
||||||
|
@ -376,7 +376,7 @@ export function throttle(func, wait) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 大模型对话dataset_id
|
* 大模型对话dataset_id
|
||||||
*/
|
*/
|
||||||
export const dataSetJson = {
|
export const dataSetJson = {
|
||||||
|
@ -403,5 +403,11 @@ export const dataSetJson = {
|
||||||
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
||||||
"教材-高中-地理": "270516829fd111efb13c0242ac140006",
|
"教材-高中-地理": "270516829fd111efb13c0242ac140006",
|
||||||
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
||||||
|
"课标-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
||||||
|
"课标-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
||||||
|
"课标-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
||||||
|
"教材-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
||||||
|
"教材-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
||||||
|
"教材-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
||||||
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 弹窗-函数
|
||||||
|
*/
|
||||||
|
import { h, render } from 'vue'
|
||||||
|
import { ElDialog } from 'element-plus'
|
||||||
|
|
||||||
|
// 打开弹窗-函数
|
||||||
|
export const openDialog = (option, content) => {
|
||||||
|
let vNode
|
||||||
|
const body = document.body
|
||||||
|
const dOpts = {
|
||||||
|
modelValue: true,
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
title: '添加-超连接',
|
||||||
|
draggable: true,
|
||||||
|
'onUpdate:modelValue': val => {
|
||||||
|
if (vNode && !val) render(null, body)
|
||||||
|
},
|
||||||
|
...option
|
||||||
|
}
|
||||||
|
vNode = h(ElDialog, dOpts, {
|
||||||
|
default: typeof content == 'function' ? content(h) : content
|
||||||
|
})
|
||||||
|
render(vNode, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开链接
|
||||||
|
export const openLink = (option, title) => {
|
||||||
|
// https://phet.colorado.edu/sims/html/number-play/latest/number-play_zh_CN.html
|
||||||
|
const isStr = typeof option == 'string'
|
||||||
|
const opt = isStr ? {} : option
|
||||||
|
const url = isStr ? option : option?.url || option?.src || option?.href
|
||||||
|
const titleNew = isStr? title||'实验室' : option?.title || '添加-超连接'
|
||||||
|
openDialog({
|
||||||
|
title: titleNew,
|
||||||
|
...opt
|
||||||
|
}, (h) => {
|
||||||
|
return h('iframe', {
|
||||||
|
src: url,
|
||||||
|
width: '100%',
|
||||||
|
style: {
|
||||||
|
height: 'calc(80vh - 75px)',
|
||||||
|
},
|
||||||
|
scrolling: 'no',
|
||||||
|
frameborder: '0',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* 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'
|
||||||
|
// 延时
|
||||||
|
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)
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ export const asyncLocalFile = (item) => {
|
||||||
if (isAsync === true) {
|
if (isAsync === true) {
|
||||||
item.async = 'on'
|
item.async = 'on'
|
||||||
if (type === 'down') {
|
if (type === 'down') {
|
||||||
console.log(item)
|
// console.log(item)
|
||||||
ipcRenderer.send('download-file-default', {
|
ipcRenderer.send('download-file-default', {
|
||||||
url: item.fileFullPath,
|
url: item.fileFullPath,
|
||||||
fileName: item.fileNewName
|
fileName: item.fileNewName
|
||||||
|
|
|
@ -248,10 +248,11 @@ export function toolWindow(type, {url, isConsole, isWeb=true, option={}}) {
|
||||||
const devUrl = `${BaseUrl}${url}`
|
const devUrl = `${BaseUrl}${url}`
|
||||||
const buildUrl = path.join(__dirname, 'index.html')
|
const buildUrl = path.join(__dirname, 'index.html')
|
||||||
const urlAll = isDev ? devUrl : buildUrl
|
const urlAll = isDev ? devUrl : buildUrl
|
||||||
|
let logoIco = import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?'/resources/yc-logo.png':'/resources/logo2.ico'
|
||||||
return new Promise(async(resolve) => {
|
return new Promise(async(resolve) => {
|
||||||
const config = {
|
const config = {
|
||||||
width, height,
|
width, height,
|
||||||
icon: path.join(appPath, '/resources/logo2.ico'),
|
icon: path.join(appPath, logoIco),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(API.preloadPath, '/index.js'),
|
preload: path.join(API.preloadPath, '/index.js'),
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
|
|
|
@ -154,14 +154,14 @@ const getClassWorkList = async () => {
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
// 处理任务类型的UI
|
// 处理任务类型的UI
|
||||||
if (list[i].worktype == '学习目标定位') {
|
if (list[i].worktype == '课堂展示') {
|
||||||
list[i].workclass = 'success'
|
list[i].workclass = 'success'
|
||||||
list[i].workcodesList = JSON.parse(list[i].workcodes)
|
list[i].workcodesList = JSON.parse(list[i].workcodes)
|
||||||
} else if (list[i].worktype == '教材研读') {
|
} else if (list[i].worktype == '科学实验') {
|
||||||
list[i].workclass = 'primary'
|
list[i].workclass = 'primary'
|
||||||
} else if (list[i].worktype == '框架梳理') {
|
} else if (list[i].worktype == '框架梳理') {
|
||||||
list[i].workclass = 'warning'
|
list[i].workclass = 'warning'
|
||||||
} else if (list[i].worktype == '学科定位') {
|
} else if (list[i].worktype == '常规作业') {
|
||||||
list[i].workclass = 'info'
|
list[i].workclass = 'info'
|
||||||
} else if (list[i].worktype == '习题训练') {
|
} else if (list[i].worktype == '习题训练') {
|
||||||
list[i].workclass = 'danger'
|
list[i].workclass = 'danger'
|
||||||
|
|
|
@ -437,13 +437,15 @@ const queryPushRecords = (row) => {
|
||||||
// } else
|
// } else
|
||||||
// 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加
|
// 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加
|
||||||
if (res.rows[i].worktype == '课堂展示') {
|
if (res.rows[i].worktype == '课堂展示') {
|
||||||
res.rows[i].workclass = 'primary';
|
res.rows[i].workclass = 'success';
|
||||||
} 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';
|
||||||
}
|
}
|
||||||
|
|
|
@ -709,29 +709,33 @@ const acceptParams = async (params) => {
|
||||||
} else {
|
} else {
|
||||||
// 学生回答
|
// 学生回答
|
||||||
if (params.studentObj.worktype == '常规作业' || params.studentObj.worktype == '科学实验') {
|
if (params.studentObj.worktype == '常规作业' || params.studentObj.worktype == '科学实验') {
|
||||||
try {
|
if(params.studentObj.worktype == '常规作业'){
|
||||||
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
try {
|
||||||
const res = await getClassworkdata(params.studentObj.id);
|
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
||||||
if(res.data.datacontent != ''){
|
const res = await getClassworkdata(params.studentObj.id);
|
||||||
const teachWorkFileList = JSON.parse(res.data.datacontent);
|
if(res.data.datacontent != ''){
|
||||||
console.log(teachWorkFileList, '老师filelist-------------')
|
const teachWorkFileList = JSON.parse(res.data.datacontent);
|
||||||
teachWorkFileList &&
|
console.log(teachWorkFileList, '老师filelist-------------')
|
||||||
teachWorkFileList.forEach((item) => {
|
teachWorkFileList &&
|
||||||
if (
|
teachWorkFileList.forEach((item) => {
|
||||||
item.name.indexOf('jpg') > -1 ||
|
if (
|
||||||
item.name.indexOf('jpeg') > -1 ||
|
item.name.indexOf('jpg') > -1 ||
|
||||||
item.name.indexOf('png') > -1
|
item.name.indexOf('jpeg') > -1 ||
|
||||||
) {
|
item.name.indexOf('png') > -1
|
||||||
teachImageList.value.push(item)
|
) {
|
||||||
} else {
|
teachImageList.value.push(item)
|
||||||
teachFileList.value.push(item)
|
} else {
|
||||||
}
|
teachFileList.value.push(item)
|
||||||
})
|
}
|
||||||
teacherFeedContentList.value.push(teachWorkFileList)
|
})
|
||||||
}
|
teacherFeedContentList.value.push(teachWorkFileList)
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Invalid JSON:', error)
|
console.error('Invalid JSON:', error)
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// TODO 科学实验 老师布置的活动 暂时不在批改中显示 2024-12-20
|
||||||
}
|
}
|
||||||
|
|
||||||
params.studentQuizAllList.forEach((item) => {
|
params.studentQuizAllList.forEach((item) => {
|
||||||
|
|
|
@ -29,15 +29,15 @@ import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const emit = defineEmits(['itemClick'])
|
const emit = defineEmits(['itemClick'])
|
||||||
const items = shallowRef([
|
const items = shallowRef([
|
||||||
{ title: '自主搜题', description: '上千万高质量习题资源,历届考试真题,每道题均有习题解析', icon: '#icon-soutibao-',type:'primary' },
|
{ title: '自主搜题', description: '上千万高质量习题资源,历届考试真题,每道题均有习题解析', icon: '#icon-soutibao-',type:'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-tubiao_wuxing-',type:'primary' },
|
// { title: '智能推荐', description: '通过对学生的薄弱知识点分析,推送不同难度的习题进行强化训练。', icon: '#icon-tubiao_wuxing-',type:'primary' },
|
||||||
{ title: '课堂展示', description: '通过课堂白板绘制作业,提升学生的创作思维能力。', icon: '#icon-huaban',type:'danger' },
|
{ title: '课堂展示', description: '通过课堂白板绘制作业,提升学生的创作思维能力。', icon: '#icon-huaban',type:'success' },
|
||||||
{ title: '常规作业', description: '推送pdf、视频、音频、图片,学生可以拍照上传。', icon: '#icon-zhaoxiangji',type:'danger' },
|
{ title: '常规作业', description: '推送pdf、视频、音频、图片,学生可以拍照上传。', icon: '#icon-zhaoxiangji',type:'info' },
|
||||||
// { title: 'AI设计作业', description: '通过AI助手,根据课标、教材、考试等分析结果,智能创建作业。', icon: '#icon-jiqiren_o',type:'danger' },
|
// { title: 'AI设计作业', description: '通过AI助手,根据课标、教材、考试等分析结果,智能创建作业。', icon: '#icon-jiqiren_o',type:'danger' },
|
||||||
{ title: '习题上传', description: '自己上传个人题库。', icon: '#icon-shangchuan',type:'danger' },
|
{ title: '习题上传', description: '自己上传个人题库。', icon: '#icon-shangchuan',type:'danger' },
|
||||||
{ title: '科学实验', description: '学生完成虚拟仿真实验,并提交实验结果。', icon: '#icon-shangchuan',type:'danger' },
|
{ title: '科学实验', description: '学生完成虚拟仿真实验,并提交实验结果。', icon: '#icon-shangchuan',type:'primary' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleClick = (item) => {
|
const handleClick = (item) => {
|
||||||
|
|
|
@ -721,19 +721,23 @@ const msgHandle = (msg) => {
|
||||||
const { head, content, ...other } = msg
|
const { head, content, ...other } = msg
|
||||||
switch(head) {
|
switch(head) {
|
||||||
case MsgEnum.HEADS.MSG_closed: // 下课:
|
case MsgEnum.HEADS.MSG_closed: // 下课:
|
||||||
Homework.win = null
|
Homework.win = null
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_finishHomework: // 跟新作业:
|
case MsgEnum.HEADS.MSG_finishHomework: // 跟新作业:
|
||||||
console.log('更新作业', head, content)
|
console.log('更新作业', head, content)
|
||||||
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
||||||
openDialog(data, false);
|
openDialog(data, false);
|
||||||
break
|
break
|
||||||
case MsgEnum.HEADS.MSG_slideFlapping: // 切换页面
|
case MsgEnum.HEADS.MSG_slideFlapping: // 切换页面
|
||||||
console.log('切换页面-关闭窗口')
|
console.log('切换页面-关闭窗口')
|
||||||
Homework.win = null
|
Homework.win = null
|
||||||
window.close() // 关闭窗口
|
window.close() // 关闭窗口
|
||||||
break
|
break
|
||||||
|
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 实验:
|
||||||
|
Homework.win = null
|
||||||
|
window.close() // 关闭窗口
|
||||||
|
break
|
||||||
// case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
// case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
||||||
// {
|
// {
|
||||||
// (data||[]).forEach(o => {
|
// (data||[]).forEach(o => {
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -0,0 +1,427 @@
|
||||||
|
<template>
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="box-item desc">
|
||||||
|
<div class="welcome">
|
||||||
|
<p>欢迎登录 {{ homeTitle }}</p>
|
||||||
|
</div>
|
||||||
|
<img class="welcome-img" :src="leftBg2" />
|
||||||
|
</div>
|
||||||
|
<div class="box-item login" v-if="isRegister">
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div class="login-title">账号登录</div>
|
||||||
|
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password" style="margin-bottom: 15px">
|
||||||
|
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-5">
|
||||||
|
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||||
|
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-item login" v-else>
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div class="login-title">账号注册</div>
|
||||||
|
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
||||||
|
<el-form-item label="手机号" prop="username">
|
||||||
|
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
||||||
|
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码" prop="password" >
|
||||||
|
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false" align-center>
|
||||||
|
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
||||||
|
status="success" />
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
v-model="isImg"
|
||||||
|
title="人机验证"
|
||||||
|
width="500"
|
||||||
|
style=" -webkit-app-region: no-drag;"
|
||||||
|
>
|
||||||
|
<span>根据图片回答相关问题1</span>
|
||||||
|
<div style="display: flex;align-items: center;;margin-top:30px">
|
||||||
|
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
||||||
|
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;justify-content: center;margin-top:30px">
|
||||||
|
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<!--选择学科-->
|
||||||
|
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
||||||
|
<!--注册弹框-->
|
||||||
|
<Register ref="RegModel"></Register>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import leftBg2 from '@/assets/images/login/left-bg2.png'
|
||||||
|
import WindowTools from '@/components/window-tools/index.vue'
|
||||||
|
import SelectSubject from '@/components/select-subject/index.vue'
|
||||||
|
import Register from './components/Register.vue'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
||||||
|
|
||||||
|
const { session } = require('@electron/remote')
|
||||||
|
const downloadProp = ref(0)
|
||||||
|
const showDownLoading = ref(false)
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
const formRef = ref()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const btnLoading = ref(false)
|
||||||
|
const isSubject = ref(false)
|
||||||
|
const RegModel = ref(false)
|
||||||
|
const isRegister = ref(true)
|
||||||
|
const ruleFormRef = ref(null)
|
||||||
|
const codeName=ref('发送验证码')
|
||||||
|
const timer=ref(null)
|
||||||
|
const isImg=ref(false)
|
||||||
|
const isPeopleImg=ref(null)
|
||||||
|
const type=ref(1) // 1注册 2找回密码
|
||||||
|
const resImg = reactive({ imgData: {} });
|
||||||
|
|
||||||
|
//表单
|
||||||
|
const loginForm = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
rememberMe: false
|
||||||
|
})
|
||||||
|
// 注册表单
|
||||||
|
const ruleForm = reactive({
|
||||||
|
|
||||||
|
})
|
||||||
|
//表单规则
|
||||||
|
const rules = reactive({
|
||||||
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
|
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||||
|
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
||||||
|
})
|
||||||
|
|
||||||
|
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
|
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||||
|
ipcRenderer.on('update-app-progress', (e, prop) => {
|
||||||
|
downloadProp.value = prop
|
||||||
|
showDownLoading.value = prop !== 100
|
||||||
|
})
|
||||||
|
const gotoreRegister=()=>{
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if(timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
isRegister.value=false
|
||||||
|
}
|
||||||
|
// 刷新
|
||||||
|
const refreshImg=()=>{
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
resImg.imgData=res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 提交人机验证
|
||||||
|
const sbmitImg=()=>{
|
||||||
|
if(ruleForm.imgCode){
|
||||||
|
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
||||||
|
const { username:username,imgCode:code } = ruleForm
|
||||||
|
const params = {
|
||||||
|
username, code,
|
||||||
|
uuid: resImg.imgData.uuid,
|
||||||
|
source:4
|
||||||
|
}
|
||||||
|
sendcode(params).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('短信发送成功')
|
||||||
|
ruleForm.Code=res.data
|
||||||
|
isImg.value=false
|
||||||
|
codeName.value=60
|
||||||
|
timer.value=setInterval(()=>{
|
||||||
|
codeName.value--
|
||||||
|
if(codeName.value==0){
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
},1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请根据图片输入验证码')
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// 发送验证码
|
||||||
|
const sendyzm=()=>{
|
||||||
|
if(ruleForm.username){
|
||||||
|
const pattern = /^1[3-9]\d{9}$/;
|
||||||
|
if( pattern.test(ruleForm.username) ){
|
||||||
|
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ruleForm.imgCode=null
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
isImg.value=true
|
||||||
|
resImg.imgData=res
|
||||||
|
// codeName.value=60
|
||||||
|
// timer.value=setInterval(()=>{
|
||||||
|
// codeName.value--
|
||||||
|
// if(codeName.value==0){
|
||||||
|
// codeName.value='发送验证码'
|
||||||
|
// clearInterval(timer.value);
|
||||||
|
// }
|
||||||
|
// },1000)
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入正确的手机号码')
|
||||||
|
}
|
||||||
|
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
||||||
|
// console.log('res->', res)
|
||||||
|
// })
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入手机号码')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 打开弹窗
|
||||||
|
const RegisterModel = type => {
|
||||||
|
RegModel.value.OpenModel(type)
|
||||||
|
}
|
||||||
|
//登录
|
||||||
|
const submitForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
btnLoading.value = true
|
||||||
|
|
||||||
|
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||||
|
if (loginForm.rememberMe) {
|
||||||
|
await setCookie('username', loginForm.username)
|
||||||
|
await setCookie('password', encrypt(loginForm.password))
|
||||||
|
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
||||||
|
} else {
|
||||||
|
// 否则移除
|
||||||
|
await session.defaultSession.clearStorageData({
|
||||||
|
origin: curWinUrl,
|
||||||
|
storages: ['cookies']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await userStore.login(loginForm)
|
||||||
|
await userStore.getInfo()
|
||||||
|
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
ipcRenderer && ipcRenderer.send('openMainWindow')
|
||||||
|
} else {
|
||||||
|
isSubject.value = true
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
btnLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isStadium = (user) => {
|
||||||
|
let roles = user.roles
|
||||||
|
return roles.some(item => item.roleKey === 'stadium')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCookie = async () => {
|
||||||
|
const username = (await getCookieDetail('username'))[0]
|
||||||
|
const password = (await getCookieDetail('password'))[0]
|
||||||
|
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
||||||
|
loginForm.username = username ? username.value : loginForm.username
|
||||||
|
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
||||||
|
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取cookie
|
||||||
|
const getCookieDetail = (name) => {
|
||||||
|
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置cookie
|
||||||
|
const setCookie = (name, value) => {
|
||||||
|
// 30天过期
|
||||||
|
let Days = 30
|
||||||
|
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
||||||
|
const cookie = {
|
||||||
|
url: curWinUrl,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
expirationDate: times
|
||||||
|
}
|
||||||
|
return session.defaultSession.cookies.set(cookie)
|
||||||
|
}
|
||||||
|
const gotoLogin = () => {
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if (timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
isRegister.value = true
|
||||||
|
}
|
||||||
|
// 注册
|
||||||
|
const RegisterForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
instructorregister(ruleForm).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('您已注册成功')
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
gotoLogin()
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('submit!')
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
sessionStore.set('subject', {
|
||||||
|
bookList: null,
|
||||||
|
curBook: null,
|
||||||
|
curNode: null,
|
||||||
|
defaultExpandedKeys: [],
|
||||||
|
subjectTree: []
|
||||||
|
})
|
||||||
|
getCookie()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
|
.box-item {
|
||||||
|
width: 444px;
|
||||||
|
height: 520px;
|
||||||
|
|
||||||
|
&.desc {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px 0px 0px 12px;
|
||||||
|
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
||||||
|
padding: 23px 25px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
background-color: #003b94;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.login {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 0px 12px 12px 0px;
|
||||||
|
padding: 34px 42px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome {
|
||||||
|
padding-top: 35px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 25px;
|
||||||
|
letter-spacing: 0.26px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-img {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #1e1e1e;
|
||||||
|
margin-bottom: 35px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
.captcha-input {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 350px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tool {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,427 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="login-container">
|
<ycLogin v-if="buildMode === 'yc'||buildMode === 'yc2'">
|
||||||
<div class="box-item desc">
|
</ycLogin>
|
||||||
<div class="welcome">
|
<defultLogin v-else>
|
||||||
<p>欢迎登录 {{ homeTitle }}</p>
|
</defultLogin>
|
||||||
</div>
|
|
||||||
<img class="welcome-img" :src="leftBg2" />
|
|
||||||
</div>
|
|
||||||
<div class="box-item login" v-if="isRegister">
|
|
||||||
<WindowTools :is-has-max="false" />
|
|
||||||
<div class="login-title">账号登录</div>
|
|
||||||
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
|
||||||
<el-form-item prop="username">
|
|
||||||
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item prop="password" style="margin-bottom: 15px">
|
|
||||||
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
|
||||||
</el-form-item>
|
|
||||||
<div class="flex mb-5">
|
|
||||||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
|
||||||
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
|
||||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="box-item login" v-else>
|
|
||||||
<WindowTools :is-has-max="false" />
|
|
||||||
<div class="login-title">账号注册</div>
|
|
||||||
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
|
||||||
<el-form-item label="手机号" prop="username">
|
|
||||||
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
|
||||||
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="密码" prop="password" >
|
|
||||||
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
|
||||||
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
|
||||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
|
||||||
:close-on-press-escape="false" align-center>
|
|
||||||
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
|
||||||
status="success" />
|
|
||||||
</el-dialog>
|
|
||||||
<el-dialog
|
|
||||||
v-model="isImg"
|
|
||||||
title="人机验证"
|
|
||||||
width="500"
|
|
||||||
style=" -webkit-app-region: no-drag;"
|
|
||||||
>
|
|
||||||
<span>根据图片回答相关问题1</span>
|
|
||||||
<div style="display: flex;align-items: center;;margin-top:30px">
|
|
||||||
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
|
||||||
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
|
||||||
</div>
|
|
||||||
<div style="display: flex;justify-content: center;margin-top:30px">
|
|
||||||
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
<!--选择学科-->
|
|
||||||
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
|
||||||
<!--注册弹框-->
|
|
||||||
<Register ref="RegModel"></Register>
|
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from 'vue'
|
import ycLogin from './yc-login.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import defultLogin from './defult-login.vue'
|
||||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
const buildMode = import.meta.env.MODE
|
||||||
import useUserStore from '@/store/modules/user'
|
|
||||||
import leftBg2 from '@/assets/images/login/left-bg2.png'
|
|
||||||
import WindowTools from '@/components/window-tools/index.vue'
|
|
||||||
import SelectSubject from '@/components/select-subject/index.vue'
|
|
||||||
import Register from './components/Register.vue'
|
|
||||||
import { sessionStore } from '@/utils/store'
|
|
||||||
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
|
||||||
|
|
||||||
const { session } = require('@electron/remote')
|
|
||||||
const downloadProp = ref(0)
|
|
||||||
const showDownLoading = ref(false)
|
|
||||||
const { ipcRenderer } = window.electron || {}
|
|
||||||
const formRef = ref()
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const btnLoading = ref(false)
|
|
||||||
const isSubject = ref(false)
|
|
||||||
const RegModel = ref(false)
|
|
||||||
const isRegister = ref(true)
|
|
||||||
const ruleFormRef = ref(null)
|
|
||||||
const codeName=ref('发送验证码')
|
|
||||||
const timer=ref(null)
|
|
||||||
const isImg=ref(false)
|
|
||||||
const isPeopleImg=ref(null)
|
|
||||||
const type=ref(1) // 1注册 2找回密码
|
|
||||||
const resImg = reactive({ imgData: {} });
|
|
||||||
|
|
||||||
//表单
|
|
||||||
const loginForm = reactive({
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
rememberMe: false
|
|
||||||
})
|
|
||||||
// 注册表单
|
|
||||||
const ruleForm = reactive({
|
|
||||||
|
|
||||||
})
|
|
||||||
//表单规则
|
|
||||||
const rules = reactive({
|
|
||||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
|
||||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
|
||||||
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
|
||||||
})
|
|
||||||
|
|
||||||
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
|
||||||
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
|
||||||
ipcRenderer.on('update-app-progress', (e, prop) => {
|
|
||||||
downloadProp.value = prop
|
|
||||||
showDownLoading.value = prop !== 100
|
|
||||||
})
|
|
||||||
const gotoreRegister=()=>{
|
|
||||||
codeName.value='发送验证码'
|
|
||||||
if(timer.value){
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
isRegister.value=false
|
|
||||||
}
|
|
||||||
// 刷新
|
|
||||||
const refreshImg=()=>{
|
|
||||||
getCodeImg().then(res=>{
|
|
||||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
|
||||||
resImg.imgData=res
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 提交人机验证
|
|
||||||
const sbmitImg=()=>{
|
|
||||||
if(ruleForm.imgCode){
|
|
||||||
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
|
||||||
const { username:username,imgCode:code } = ruleForm
|
|
||||||
const params = {
|
|
||||||
username, code,
|
|
||||||
uuid: resImg.imgData.uuid,
|
|
||||||
source:4
|
|
||||||
}
|
|
||||||
sendcode(params).then(res=>{
|
|
||||||
if(res.code==200){
|
|
||||||
ElMessage.success('短信发送成功')
|
|
||||||
ruleForm.Code=res.data
|
|
||||||
isImg.value=false
|
|
||||||
codeName.value=60
|
|
||||||
timer.value=setInterval(()=>{
|
|
||||||
codeName.value--
|
|
||||||
if(codeName.value==0){
|
|
||||||
codeName.value='发送验证码'
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
},1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
ElMessage.error('请根据图片输入验证码')
|
|
||||||
}
|
|
||||||
//
|
|
||||||
}
|
|
||||||
// 发送验证码
|
|
||||||
const sendyzm=()=>{
|
|
||||||
if(ruleForm.username){
|
|
||||||
const pattern = /^1[3-9]\d{9}$/;
|
|
||||||
if( pattern.test(ruleForm.username) ){
|
|
||||||
|
|
||||||
getCodeImg().then(res=>{
|
|
||||||
if(res.code==200){
|
|
||||||
ruleForm.imgCode=null
|
|
||||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
|
||||||
isImg.value=true
|
|
||||||
resImg.imgData=res
|
|
||||||
// codeName.value=60
|
|
||||||
// timer.value=setInterval(()=>{
|
|
||||||
// codeName.value--
|
|
||||||
// if(codeName.value==0){
|
|
||||||
// codeName.value='发送验证码'
|
|
||||||
// clearInterval(timer.value);
|
|
||||||
// }
|
|
||||||
// },1000)
|
|
||||||
}else{
|
|
||||||
ElMessage.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
ElMessage.error('请输入正确的手机号码')
|
|
||||||
}
|
|
||||||
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
|
||||||
// console.log('res->', res)
|
|
||||||
// })
|
|
||||||
}else{
|
|
||||||
ElMessage.error('请输入手机号码')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 打开弹窗
|
|
||||||
const RegisterModel = type => {
|
|
||||||
RegModel.value.OpenModel(type)
|
|
||||||
}
|
|
||||||
//登录
|
|
||||||
const submitForm = async (formEl) => {
|
|
||||||
if (!formEl) return
|
|
||||||
await formEl.validate(async (valid) => {
|
|
||||||
if (valid) {
|
|
||||||
btnLoading.value = true
|
|
||||||
|
|
||||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
|
||||||
if (loginForm.rememberMe) {
|
|
||||||
await setCookie('username', loginForm.username)
|
|
||||||
await setCookie('password', encrypt(loginForm.password))
|
|
||||||
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
|
||||||
} else {
|
|
||||||
// 否则移除
|
|
||||||
await session.defaultSession.clearStorageData({
|
|
||||||
origin: curWinUrl,
|
|
||||||
storages: ['cookies']
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await userStore.login(loginForm)
|
|
||||||
await userStore.getInfo()
|
|
||||||
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
|
||||||
ElMessage.success('登录成功')
|
|
||||||
ipcRenderer && ipcRenderer.send('openMainWindow')
|
|
||||||
} else {
|
|
||||||
isSubject.value = true
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
btnLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const isStadium = (user) => {
|
|
||||||
let roles = user.roles
|
|
||||||
return roles.some(item => item.roleKey === 'stadium')
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCookie = async () => {
|
|
||||||
const username = (await getCookieDetail('username'))[0]
|
|
||||||
const password = (await getCookieDetail('password'))[0]
|
|
||||||
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
|
||||||
loginForm.username = username ? username.value : loginForm.username
|
|
||||||
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
|
||||||
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取cookie
|
|
||||||
const getCookieDetail = (name) => {
|
|
||||||
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置cookie
|
|
||||||
const setCookie = (name, value) => {
|
|
||||||
// 30天过期
|
|
||||||
let Days = 30
|
|
||||||
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
|
||||||
const cookie = {
|
|
||||||
url: curWinUrl,
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
expirationDate: times
|
|
||||||
}
|
|
||||||
return session.defaultSession.cookies.set(cookie)
|
|
||||||
}
|
|
||||||
const gotoLogin = () => {
|
|
||||||
codeName.value='发送验证码'
|
|
||||||
if (timer.value){
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
|
||||||
isRegister.value = true
|
|
||||||
}
|
|
||||||
// 注册
|
|
||||||
const RegisterForm = async (formEl) => {
|
|
||||||
if (!formEl) return
|
|
||||||
await formEl.validate((valid, fields) => {
|
|
||||||
if (valid) {
|
|
||||||
instructorregister(ruleForm).then(res=>{
|
|
||||||
if(res.code==200){
|
|
||||||
ElMessage.success('您已注册成功')
|
|
||||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
|
||||||
gotoLogin()
|
|
||||||
}else{
|
|
||||||
ElMessage.error(res.msg)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.log('submit!')
|
|
||||||
} else {
|
|
||||||
console.log('error submit!', fields)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
localStorage.clear()
|
|
||||||
sessionStore.set('subject', {
|
|
||||||
bookList: null,
|
|
||||||
curBook: null,
|
|
||||||
curNode: null,
|
|
||||||
defaultExpandedKeys: [],
|
|
||||||
subjectTree: []
|
|
||||||
})
|
|
||||||
getCookie()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.login-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
|
|
||||||
.box-item {
|
|
||||||
width: 444px;
|
|
||||||
height: 520px;
|
|
||||||
|
|
||||||
&.desc {
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 12px 0px 0px 12px;
|
|
||||||
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
|
||||||
padding: 23px 25px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
background-color: #003b94;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.login {
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 0px 12px 12px 0px;
|
|
||||||
padding: 34px 42px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome {
|
|
||||||
padding-top: 35px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: #ffffff;
|
|
||||||
line-height: 25px;
|
|
||||||
letter-spacing: 0.26px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 26px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome-img {
|
|
||||||
margin-top: 20px;
|
|
||||||
width: 350px;
|
|
||||||
height: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-title {
|
|
||||||
font-size: 20px;
|
|
||||||
text-align: center;
|
|
||||||
color: #1e1e1e;
|
|
||||||
margin-bottom: 35px;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-form {
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
|
|
||||||
.captcha-input {
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.captcha-img {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 350px;
|
|
||||||
height: 50px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 700;
|
|
||||||
text-align: center;
|
|
||||||
color: #ffffff;
|
|
||||||
line-height: 50px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-tool {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
|
|
||||||
span {
|
|
||||||
padding: 5px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,463 @@
|
||||||
|
<template>
|
||||||
|
<div class="login-container">
|
||||||
|
<div class="login-yc">
|
||||||
|
<img class="welcome-img" :src="buildMode === 'yc2'?leftBg2:leftBg1" />
|
||||||
|
</div>
|
||||||
|
<div class="box-item login" v-if="isRegister">
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div style="display: flex;justify-content: center;"><img class="title-logo" :src="yclogo" /></div>
|
||||||
|
<div class="login-title">永川中小学</div>
|
||||||
|
<div class="login-title2">{{buildMode === 'yc2'?'虚拟仿真AI实训教学管理系统':'人工智能赋能科学素养与劳动技能系统'}}</div>
|
||||||
|
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password" style="margin-bottom: 15px">
|
||||||
|
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-5">
|
||||||
|
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||||
|
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item style="margin-bottom: 20px">
|
||||||
|
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
||||||
|
</div>
|
||||||
|
<div class="title-bottom">
|
||||||
|
重庆市永川区教育委员会
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-item login" v-else>
|
||||||
|
<WindowTools :is-has-max="false" />
|
||||||
|
<div class="login-title">账号注册</div>
|
||||||
|
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
||||||
|
<el-form-item label="手机号" prop="username">
|
||||||
|
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
||||||
|
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="密码" prop="password" >
|
||||||
|
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||||
|
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false" align-center>
|
||||||
|
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
||||||
|
status="success" />
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
v-model="isImg"
|
||||||
|
title="人机验证"
|
||||||
|
width="500"
|
||||||
|
style=" -webkit-app-region: no-drag;"
|
||||||
|
>
|
||||||
|
<span>根据图片回答相关问题1</span>
|
||||||
|
<div style="display: flex;align-items: center;;margin-top:30px">
|
||||||
|
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
||||||
|
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;justify-content: center;margin-top:30px">
|
||||||
|
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<!--选择学科-->
|
||||||
|
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
||||||
|
<!--注册弹框-->
|
||||||
|
<Register ref="RegModel"></Register>
|
||||||
|
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import WindowTools from '@/components/window-tools/index.vue'
|
||||||
|
import SelectSubject from '@/components/select-subject/index.vue'
|
||||||
|
import Register from './components/Register.vue'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
||||||
|
import yclogo from '@/assets/images/login/yc-logo.png'
|
||||||
|
import leftBg1 from '@/assets/images/login/ycpeitu.png'
|
||||||
|
import leftBg2 from '@/assets/images/login/ycpeitu2.jpg'
|
||||||
|
const { session } = require('@electron/remote')
|
||||||
|
const buildMode = import.meta.env.MODE
|
||||||
|
const downloadProp = ref(0)
|
||||||
|
const showDownLoading = ref(false)
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
const formRef = ref()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const btnLoading = ref(false)
|
||||||
|
const isSubject = ref(false)
|
||||||
|
const RegModel = ref(false)
|
||||||
|
const isRegister = ref(true)
|
||||||
|
const ruleFormRef = ref(null)
|
||||||
|
const codeName=ref('发送验证码')
|
||||||
|
const timer=ref(null)
|
||||||
|
const isImg=ref(false)
|
||||||
|
const isPeopleImg=ref(null)
|
||||||
|
const type=ref(1) // 1注册 2找回密码
|
||||||
|
const resImg = reactive({ imgData: {} });
|
||||||
|
|
||||||
|
//表单
|
||||||
|
const loginForm = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
rememberMe: false
|
||||||
|
})
|
||||||
|
// 注册表单
|
||||||
|
const ruleForm = reactive({
|
||||||
|
|
||||||
|
})
|
||||||
|
//表单规则
|
||||||
|
const rules = reactive({
|
||||||
|
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||||
|
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||||
|
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
||||||
|
})
|
||||||
|
|
||||||
|
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
|
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||||
|
ipcRenderer.on('update-app-progress', (e, prop) => {
|
||||||
|
downloadProp.value = prop
|
||||||
|
showDownLoading.value = prop !== 100
|
||||||
|
})
|
||||||
|
const gotoreRegister=()=>{
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if(timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
isRegister.value=false
|
||||||
|
}
|
||||||
|
// 刷新
|
||||||
|
const refreshImg=()=>{
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
resImg.imgData=res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 提交人机验证
|
||||||
|
const sbmitImg=()=>{
|
||||||
|
if(ruleForm.imgCode){
|
||||||
|
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
||||||
|
const { username:username,imgCode:code } = ruleForm
|
||||||
|
const params = {
|
||||||
|
username, code,
|
||||||
|
uuid: resImg.imgData.uuid,
|
||||||
|
source:4
|
||||||
|
}
|
||||||
|
sendcode(params).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('短信发送成功')
|
||||||
|
ruleForm.Code=res.data
|
||||||
|
isImg.value=false
|
||||||
|
codeName.value=60
|
||||||
|
timer.value=setInterval(()=>{
|
||||||
|
codeName.value--
|
||||||
|
if(codeName.value==0){
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
},1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请根据图片输入验证码')
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// 发送验证码
|
||||||
|
const sendyzm=()=>{
|
||||||
|
if(ruleForm.username){
|
||||||
|
const pattern = /^1[3-9]\d{9}$/;
|
||||||
|
if( pattern.test(ruleForm.username) ){
|
||||||
|
|
||||||
|
getCodeImg().then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ruleForm.imgCode=null
|
||||||
|
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||||
|
isImg.value=true
|
||||||
|
resImg.imgData=res
|
||||||
|
// codeName.value=60
|
||||||
|
// timer.value=setInterval(()=>{
|
||||||
|
// codeName.value--
|
||||||
|
// if(codeName.value==0){
|
||||||
|
// codeName.value='发送验证码'
|
||||||
|
// clearInterval(timer.value);
|
||||||
|
// }
|
||||||
|
// },1000)
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入正确的手机号码')
|
||||||
|
}
|
||||||
|
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
||||||
|
// console.log('res->', res)
|
||||||
|
// })
|
||||||
|
}else{
|
||||||
|
ElMessage.error('请输入手机号码')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 打开弹窗
|
||||||
|
const RegisterModel = type => {
|
||||||
|
RegModel.value.OpenModel(type)
|
||||||
|
}
|
||||||
|
//登录
|
||||||
|
const submitForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
btnLoading.value = true
|
||||||
|
|
||||||
|
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||||
|
if (loginForm.rememberMe) {
|
||||||
|
await setCookie('username', loginForm.username)
|
||||||
|
await setCookie('password', encrypt(loginForm.password))
|
||||||
|
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
||||||
|
} else {
|
||||||
|
// 否则移除
|
||||||
|
await session.defaultSession.clearStorageData({
|
||||||
|
origin: curWinUrl,
|
||||||
|
storages: ['cookies']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await userStore.login(loginForm)
|
||||||
|
await userStore.getInfo()
|
||||||
|
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
ipcRenderer && ipcRenderer.send('openMainWindow')
|
||||||
|
} else {
|
||||||
|
isSubject.value = true
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
btnLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isStadium = (user) => {
|
||||||
|
let roles = user.roles
|
||||||
|
return roles.some(item => item.roleKey === 'stadium')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCookie = async () => {
|
||||||
|
const username = (await getCookieDetail('username'))[0]
|
||||||
|
const password = (await getCookieDetail('password'))[0]
|
||||||
|
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
||||||
|
loginForm.username = username ? username.value : loginForm.username
|
||||||
|
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
||||||
|
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取cookie
|
||||||
|
const getCookieDetail = (name) => {
|
||||||
|
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置cookie
|
||||||
|
const setCookie = (name, value) => {
|
||||||
|
// 30天过期
|
||||||
|
let Days = 30
|
||||||
|
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
||||||
|
const cookie = {
|
||||||
|
url: curWinUrl,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
expirationDate: times
|
||||||
|
}
|
||||||
|
return session.defaultSession.cookies.set(cookie)
|
||||||
|
}
|
||||||
|
const gotoLogin = () => {
|
||||||
|
codeName.value='发送验证码'
|
||||||
|
if (timer.value){
|
||||||
|
clearInterval(timer.value);
|
||||||
|
}
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
isRegister.value = true
|
||||||
|
}
|
||||||
|
// 注册
|
||||||
|
const RegisterForm = async (formEl) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
instructorregister(ruleForm).then(res=>{
|
||||||
|
if(res.code==200){
|
||||||
|
ElMessage.success('您已注册成功')
|
||||||
|
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||||
|
gotoLogin()
|
||||||
|
}else{
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('submit!')
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
localStorage.clear()
|
||||||
|
sessionStore.set('subject', {
|
||||||
|
bookList: null,
|
||||||
|
curBook: null,
|
||||||
|
curNode: null,
|
||||||
|
defaultExpandedKeys: [],
|
||||||
|
subjectTree: []
|
||||||
|
})
|
||||||
|
getCookie()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.login-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
|
.login-yc{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-item {
|
||||||
|
width: 370px;
|
||||||
|
height: 520px;
|
||||||
|
|
||||||
|
&.desc {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px 0px 0px 12px;
|
||||||
|
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
||||||
|
padding: 23px 25px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
background-color: #003b94;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.login {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 0px 12px 12px 0px;
|
||||||
|
padding: 34px 42px;
|
||||||
|
position: relative;
|
||||||
|
.title-logo{
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome {
|
||||||
|
padding-top: 35px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 25px;
|
||||||
|
letter-spacing: 0.26px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-img {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #1e1e1e;
|
||||||
|
margin-bottom: 35px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #1e1e1e;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-top: 5px;
|
||||||
|
font-width: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-title2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
.captcha-input {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.captcha-img {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bottom{
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 350px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tool {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 5px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -83,6 +83,8 @@ 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";
|
||||||
|
@ -94,11 +96,11 @@ 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 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 // 用户信息
|
||||||
|
@ -278,12 +280,14 @@ const handleFileChange = ()=> {
|
||||||
createAIPPTByFile(file)
|
createAIPPTByFile(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ppt文件转PPT线上数据
|
||||||
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
|
||||||
|
@ -335,6 +339,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
<div class="paragraphs">
|
<div class="paragraphs">
|
||||||
{{ outputText }}
|
{{ outputText }}
|
||||||
</div>
|
</div>
|
||||||
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">从新生成</el-button>
|
<el-button style="margin-bottom: 5px;" type="primary" @click="addMessage">{{ outputText ? '重新生成' : '生成大纲' }}</el-button>
|
||||||
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1">下一步</el-button>
|
<el-button style="margin-bottom: 5px;" type="primary" @click="activeStep = 1" :disabled="!outputText">下一步</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" v-loading="createPPTLoading" @click="outlineCreatePPT()">生成PPT</el-button>
|
<el-button style="margin-bottom: 5px;" type="primary" :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,6 +177,8 @@ const outlineCreatePPT = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
checkProgress();
|
checkProgress();
|
||||||
|
}).finally(()=>{
|
||||||
|
createPPTLoading.value = false
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
<c-form v-bind="classForm">
|
<c-form v-bind="classForm">
|
||||||
<template #item_classid="{prop, form}">
|
<template #item_classid="{prop, form}">
|
||||||
<span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span>
|
<span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span>
|
||||||
<el-select v-else v-model="form[prop]" placeholder="请选择班级">
|
<el-select v-else v-model="form[prop]" placeholder="请选择班级" clearable>
|
||||||
<el-option v-for="item in listData.classList" :value="item.id"
|
<el-option v-for="item in listData.classList" :value="item.id"
|
||||||
:label="`${item.caption} (${item.classstudentcount}人)`" />
|
:label="`${item.caption} (${item.classstudentcount}人)`" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</c-form>
|
</c-form>
|
||||||
|
@ -249,10 +249,10 @@ const getClasscourseList = async type => {
|
||||||
// 创建课程 isPublic 公屏上课
|
// 创建课程 isPublic 公屏上课
|
||||||
const createClasscourse = async (isPublic = false) => {
|
const createClasscourse = async (isPublic = false) => {
|
||||||
const { classid } = classForm.form
|
const { classid } = classForm.form
|
||||||
if (!classid) {
|
// if (!classid) {
|
||||||
ElMessage.warning('请选择班级')
|
// ElMessage.warning('请选择班级')
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
dt.loading = true
|
dt.loading = true
|
||||||
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // 课件对象
|
const { entpcourseid, evalid, id, coursetitle } = myClassActive.value // 课件对象
|
||||||
const curDate = commUtil.getDateNow('yyyy-MM-dd')
|
const curDate = commUtil.getDateNow('yyyy-MM-dd')
|
||||||
|
@ -372,9 +372,9 @@ const openPublicScreen = (classcourse, isPublic) => {
|
||||||
createWindow('open-win', {
|
createWindow('open-win', {
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
close: () => {
|
close: () => {
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
sessionStore.delete('curr.resource') // 清除缓存
|
||||||
sessionStore.set('curr.classcourse', null) // 清除缓存
|
sessionStore.delete('curr.classcourse') // 清除缓存
|
||||||
sessionStore.set('curr.isPublic', null) // 清除缓存
|
sessionStore.delete('curr.isPublic') // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
visible.value = false // 关闭弹窗
|
visible.value = false // 关闭弹窗
|
||||||
|
|
|
@ -126,11 +126,17 @@
|
||||||
<span>下载</span>
|
<span>下载</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
|
<!-- <div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
|
||||||
<el-button text @click="adToKj(item)">
|
<el-button text @click="adToKj(item)">
|
||||||
<i class="iconfont icon-jiahao"></i>
|
<i class="iconfont icon-jiahao"></i>
|
||||||
<span>加入课件</span>
|
<span>加入课件</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
</div>-->
|
||||||
|
<div v-if="item.fileSuffix === 'ppt' || item.fileSuffix === 'pptx'" class="item-popover-item">
|
||||||
|
<el-button text @click="importPPT(item)">
|
||||||
|
<i class="iconfont icon-jiahao"></i>
|
||||||
|
<span>导入PPT</span>
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-popover-item">
|
<div class="item-popover-item">
|
||||||
<el-button text @click="moveSmarttalkFun(item)">
|
<el-button text @click="moveSmarttalkFun(item)">
|
||||||
|
@ -181,7 +187,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null },
|
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null,'on-importPPT': null },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
listenList: [],
|
listenList: [],
|
||||||
|
@ -217,6 +223,9 @@ export default {
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
},
|
},
|
||||||
|
importPPT(item) {
|
||||||
|
this.$emit('on-importPPT', item)
|
||||||
|
},
|
||||||
downloadFile(item) {
|
downloadFile(item) {
|
||||||
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
||||||
},
|
},
|
||||||
|
|
|
@ -99,6 +99,7 @@
|
||||||
@on-delete="deleteTalk"
|
@on-delete="deleteTalk"
|
||||||
@on-set="openSet"
|
@on-set="openSet"
|
||||||
@on-delhomework="delhomework"
|
@on-delhomework="delhomework"
|
||||||
|
@on-importPPT="importPPT"
|
||||||
@on-filearg="isOpenHomework = true"
|
@on-filearg="isOpenHomework = true"
|
||||||
>
|
>
|
||||||
<el-checkbox v-if="!item.uniquekey" label="" :value="item" />
|
<el-checkbox v-if="!item.uniquekey" label="" :value="item" />
|
||||||
|
@ -204,13 +205,12 @@ import TreeLog from '@/views/prepare/components/treeLog.vue'
|
||||||
import classStart from './container/class-start.vue' // 预备上课
|
import classStart from './container/class-start.vue' // 预备上课
|
||||||
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
||||||
import * as commUtils from "@/utils/comm";
|
import * as commUtils from "@/utils/comm";
|
||||||
import * as Api_server from "@/api/apiService";
|
|
||||||
import msgUtils from "@/plugins/modal";
|
import msgUtils from "@/plugins/modal";
|
||||||
|
import * as Api_server from "@/api/apiService";
|
||||||
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
||||||
|
import { slidesToImg } from '@/utils/ppt' // ppt相关工具
|
||||||
import ChatWs from '@/plugins/socket' // 聊天socket
|
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||||
if (!ChatWs.ws) ChatWs.init()
|
if (!ChatWs.ws) ChatWs.init()
|
||||||
// import Chat from '@/utils/chat' // im 登录初始化
|
|
||||||
// if (!Chat.imChat) Chat.init()
|
|
||||||
|
|
||||||
const toolStore = useToolState()
|
const toolStore = useToolState()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
@ -497,11 +497,11 @@ export default {
|
||||||
createWindow('open-win', {
|
createWindow('open-win', {
|
||||||
url: '/pptist', // 窗口关闭时,清除缓存
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
close: () => {
|
close: () => {
|
||||||
sessionStore.set('curr.resource', null) // 清除缓存
|
sessionStore.delete('curr.resource') // 清除缓存
|
||||||
if (type=='edit') {
|
if (type=='edit') {
|
||||||
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
sessionStore.delete('curr.smarttalk') // 清除缓存
|
||||||
this.asyncAllFile() // 刷新资源列表
|
this.asyncAllFile() // 刷新资源列表
|
||||||
} else sessionStore.set('curr.classcourse', null) // 清除缓存
|
} else sessionStore.delete('curr.classcourse') // 清除缓存
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -555,6 +555,15 @@ export default {
|
||||||
progDownFile(e, num) {
|
progDownFile(e, num) {
|
||||||
this.downloadNum = num
|
this.downloadNum = num
|
||||||
},
|
},
|
||||||
|
importPPT(item) {
|
||||||
|
let _this = this;
|
||||||
|
fetch(item.fileFullPath)
|
||||||
|
.then(res => res.arrayBuffer())
|
||||||
|
.then(buffer => {
|
||||||
|
let name = item.fileShowName.substring(0, item.fileShowName.lastIndexOf('.')) + '.aippt'
|
||||||
|
_this.createAIPPTByFile(buffer, name)
|
||||||
|
})
|
||||||
|
},
|
||||||
createFile() {
|
createFile() {
|
||||||
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
|
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
|
||||||
this.currentFileList.unshift(res.resData)
|
this.currentFileList.unshift(res.resData)
|
||||||
|
@ -563,8 +572,9 @@ export default {
|
||||||
},500)
|
},500)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
openFilePicker(){
|
async openFilePicker(){
|
||||||
this.$refs.fileInput.click();
|
this.$refs.fileInput.click();
|
||||||
|
// const files = await commUtils.getFiles()
|
||||||
},
|
},
|
||||||
handleFileChange(){
|
handleFileChange(){
|
||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
|
@ -573,7 +583,7 @@ export default {
|
||||||
console.log('文件名:', file.name);
|
console.log('文件名:', file.name);
|
||||||
console.log('文件类型:', file.type);
|
console.log('文件类型:', file.type);
|
||||||
console.log('文件大小:', file.size);
|
console.log('文件大小:', file.size);
|
||||||
this.createAIPPTByFile(file)
|
this.createAIPPTByFile(file, this.currentNode.itemtitle + '.aippt')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async toRousrceUrl(o) {
|
async toRousrceUrl(o) {
|
||||||
|
@ -619,11 +629,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async createAIPPTByFile(file) {
|
async createAIPPTByFile(file,fileShowName) {
|
||||||
this.pgDialog.visible = true
|
this.pgDialog.visible = true
|
||||||
this.pgDialog.pg.percentage = 0
|
this.pgDialog.pg.percentage = 0
|
||||||
const resPptJson = await PPTXFileToJson(file)
|
const resPptJson = await PPTXFileToJson(file)
|
||||||
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
|
||||||
|
@ -665,7 +677,7 @@ export default {
|
||||||
...this.uploadData,
|
...this.uploadData,
|
||||||
fileId: slideid,
|
fileId: slideid,
|
||||||
fileFlag: 'aippt',
|
fileFlag: 'aippt',
|
||||||
fileShowName: this.currentNode.itemtitle + '.aippt'
|
fileShowName: fileShowName
|
||||||
}).then(async (res) => {
|
}).then(async (res) => {
|
||||||
|
|
||||||
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
|
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
|
||||||
|
@ -676,6 +688,7 @@ export default {
|
||||||
title: '',
|
title: '',
|
||||||
filetype: 'slide',
|
filetype: 'slide',
|
||||||
slides: resSlides,
|
slides: resSlides,
|
||||||
|
thumbnails, // 缩略图
|
||||||
edituserid: this.userStore.userId
|
edituserid: this.userStore.userId
|
||||||
}
|
}
|
||||||
const res_3 = await API_entpcoursefile.batchAddNew(params)
|
const res_3 = await API_entpcoursefile.batchAddNew(params)
|
||||||
|
|
|
@ -93,6 +93,9 @@ emitter.on('onGetMain', (item) => {
|
||||||
const emit = defineEmits([''])
|
const emit = defineEmits([''])
|
||||||
const onSelect = (item) =>{
|
const onSelect = (item) =>{
|
||||||
actId.value = item.id
|
actId.value = item.id
|
||||||
|
item.child.forEach(el =>{
|
||||||
|
el.aiShow = false
|
||||||
|
})
|
||||||
emitter.emit('changeMode', item)
|
emitter.emit('changeMode', item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
|
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
|
||||||
<el-button type="primary">生成大纲</el-button>
|
<el-button type="danger" @click="onCreate">生成PPT</el-button>
|
||||||
<el-button type="danger" @click="pptDialog = true">生成PPT</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-con flex" ref="listRef">
|
<div class="right-con flex" ref="listRef">
|
||||||
|
@ -92,7 +91,10 @@ import * as API_entpcourse from '@/api/education/entpcourse' // 相关api
|
||||||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||||
import * as Api_server from '@/api/apiService' // 相关api
|
import * as Api_server from '@/api/apiService' // 相关api
|
||||||
import * as API_smarttalk from '@/api/file' // 文件相关api
|
import * as API_smarttalk from '@/api/file' // 文件相关api
|
||||||
import msgUtils from '@/plugins/modal' // 消息工具
|
import msgUtils from '@/plugins/modal'
|
||||||
|
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
|
import { createWindow } from '@/utils/tool' // 消息工具
|
||||||
|
import { slidesToImg } from '@/utils/ppt' // ppt相关工具
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const pptDialog = ref(false)
|
const pptDialog = ref(false)
|
||||||
|
@ -117,7 +119,7 @@ const pgDialog = reactive({ // 弹窗-进度条
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const curMode = ref(1)
|
const curMode = ref(2)
|
||||||
const modeOptions = ref([
|
const modeOptions = ref([
|
||||||
{
|
{
|
||||||
label: '教学大模型',
|
label: '教学大模型',
|
||||||
|
@ -134,6 +136,16 @@ emitter.on('changeMode', (item) => {
|
||||||
getTempResult(item.id)
|
getTempResult(item.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const onCreate = () =>{
|
||||||
|
let isAnswer = resultList.value.every(item => !item.answer)
|
||||||
|
if(isAnswer){
|
||||||
|
ElMessage.warning('请先进行研读')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pptDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 一键研读
|
// 一键研读
|
||||||
const getCompletion = async () => {
|
const getCompletion = async () => {
|
||||||
|
@ -194,7 +206,7 @@ const handleCompleteText = async (answer, index) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存模板
|
// 保存模板
|
||||||
const onSaveTemp = (item) => {
|
const onSaveTemp = async (item) => {
|
||||||
if (item.answer == '') return
|
if (item.answer == '') return
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -204,7 +216,11 @@ const onSaveTemp = (item) => {
|
||||||
content: item.answer,
|
content: item.answer,
|
||||||
ex1: curNode.id
|
ex1: curNode.id
|
||||||
}
|
}
|
||||||
tempSave(data).then(res => { })
|
const res = await tempSave(data)
|
||||||
|
|
||||||
|
if(!item.resultId){
|
||||||
|
item.resultId = res.data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isWordDialog = ref(false)
|
const isWordDialog = ref(false)
|
||||||
|
@ -223,7 +239,7 @@ const editKeyWord = (item, val) => {
|
||||||
const removeItem = async (item, isChild) => {
|
const removeItem = async (item, isChild) => {
|
||||||
/**
|
/**
|
||||||
* item: 当前操作的模板
|
* item: 当前操作的模板
|
||||||
* isChild: 子模板中的移除为 true
|
* isChild: 子模板中的移除为 true
|
||||||
*/
|
*/
|
||||||
if (item.ex3 != '1') {
|
if (item.ex3 != '1') {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
|
@ -256,7 +272,7 @@ const listRef = ref()
|
||||||
// 查询模板结果
|
// 查询模板结果
|
||||||
const isStarted = ref([]);
|
const isStarted = ref([]);
|
||||||
const getTempResult = (id) => {
|
const getTempResult = (id) => {
|
||||||
tempResult({ mainModelId: id }).then(res => {
|
tempResult({ mainModelId: id, pageNum: 1, pageSize: 10000, ex1: curNode.id }).then(res => {
|
||||||
let rows = res.rows
|
let rows = res.rows
|
||||||
if (rows.length > 0) {
|
if (rows.length > 0) {
|
||||||
isStarted.value = new Array(rows.length).fill(true)
|
isStarted.value = new Array(rows.length).fill(true)
|
||||||
|
@ -280,7 +296,7 @@ const scrollToBottom = (height, index) => {
|
||||||
let listDom = listRef.value.children
|
let listDom = listRef.value.children
|
||||||
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
// 220 去掉头部
|
// 220 去掉头部
|
||||||
let screenHeight = window.innerHeight - 220
|
let screenHeight = window.innerHeight - 220
|
||||||
if (height > screenHeight) {
|
if (height > screenHeight) {
|
||||||
listRef.value.scrollTop = (height - screenHeight + 50)
|
listRef.value.scrollTop = (height - screenHeight + 50)
|
||||||
|
@ -312,6 +328,7 @@ const prompt = ref('')
|
||||||
|
|
||||||
|
|
||||||
const addAiPPT = async (res) => {
|
const addAiPPT = async (res) => {
|
||||||
|
// res = { url: 'https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx' }
|
||||||
let node = courseObj.node
|
let node = courseObj.node
|
||||||
pptDialog.value = false;
|
pptDialog.value = false;
|
||||||
if (!node) return msgUtils.msgWarning('请选择章节?')
|
if (!node) return msgUtils.msgWarning('请选择章节?')
|
||||||
|
@ -330,6 +347,8 @@ const addAiPPT = async (res) => {
|
||||||
.then(async buffer => {
|
.then(async buffer => {
|
||||||
const resPptJson = await PPTXFileToJson(buffer)
|
const resPptJson = await PPTXFileToJson(buffer)
|
||||||
const { def, slides, ...content } = resPptJson
|
const { def, slides, ...content } = resPptJson
|
||||||
|
// 生成缩略图
|
||||||
|
const thumbnails = await slidesToImg(slides, content.width)
|
||||||
// 转换图片|音频|视频 为线上地址
|
// 转换图片|音频|视频 为线上地址
|
||||||
let completed = 0
|
let completed = 0
|
||||||
const total = slides.length
|
const total = slides.length
|
||||||
|
@ -346,13 +365,20 @@ const addAiPPT = async (res) => {
|
||||||
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
||||||
if (!!parentid ?? null) { // 生成内容幻灯片
|
if (!!parentid ?? null) { // 生成内容幻灯片
|
||||||
// 生成备课资源-Smarttalk
|
// 生成备课资源-Smarttalk
|
||||||
HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
||||||
if (slides.length > 0) {
|
if (slides.length > 0) {
|
||||||
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
|
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
|
||||||
const params = { parentid, filetype: 'slide', title: '', slides: resSlides }
|
const params = { parentid, filetype: 'slide', title: '', thumbnails, slides: resSlides }
|
||||||
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
|
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
|
||||||
if (res_3 && res_3.code == 200) {
|
if (res_3 && res_3.code == 200) {
|
||||||
msgUtils.msgSuccess('生成PPT课件成功')
|
msgUtils.msgSuccess('生成PPT课件成功')
|
||||||
|
//TODO 打开生成的课件
|
||||||
|
const res = await getEntpcoursefile(parentid)
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
openPublicScreen('edit', res.data, smarttalk.resData) // 打开公屏-窗口
|
||||||
|
} else {
|
||||||
|
ElMessage.warning(res.msg||'文件获取异常!')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msgUtils.msgWarning('生成PPT课件失败')
|
msgUtils.msgWarning('生成PPT课件失败')
|
||||||
}
|
}
|
||||||
|
@ -361,7 +387,20 @@ const addAiPPT = async (res) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openPublicScreen = (type, resource, currData)=> {
|
||||||
|
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||||
|
if (type=='edit') sessionStore.set('curr.smarttalk', currData) // 缓存当前文件smarttalk
|
||||||
|
else sessionStore.set('curr.classcourse', currData) // 缓存当前当前上课
|
||||||
|
createWindow('open-win', {
|
||||||
|
url: '/pptist', // 窗口关闭时,清除缓存
|
||||||
|
close: () => {
|
||||||
|
sessionStore.set('curr.resource', null) // 清除缓存
|
||||||
|
if (type=='edit') {
|
||||||
|
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
||||||
|
} else sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
const isEdit = ref(false)
|
const isEdit = ref(false)
|
||||||
// 当前操作的索引
|
// 当前操作的索引
|
||||||
const curIndex = ref(-1)
|
const curIndex = ref(-1)
|
||||||
|
@ -735,4 +774,4 @@ onUnmounted(() => {
|
||||||
width: 110px !important;
|
width: 110px !important;
|
||||||
min-width: 110px !important;
|
min-width: 110px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -81,10 +81,10 @@ export const getClassWorkList = async (id) => {
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
// 处理任务类型的UI
|
// 处理任务类型的UI
|
||||||
if (list[i].worktype == '学习目标定位') {
|
if (list[i].worktype == '课堂展示') {
|
||||||
list[i].workclass = 'success'
|
list[i].workclass = 'success'
|
||||||
list[i].workcodesList = JSON.parse(list[i].workcodes)
|
list[i].workcodesList = JSON.parse(list[i].workcodes)
|
||||||
} else if (list[i].worktype == '教材研读') {
|
} else if (list[i].worktype == '科学实验') {
|
||||||
list[i].workclass = 'primary'
|
list[i].workclass = 'primary'
|
||||||
} else if (list[i].worktype == '框架梳理') {
|
} else if (list[i].worktype == '框架梳理') {
|
||||||
list[i].workclass = 'warning'
|
list[i].workclass = 'warning'
|
||||||
|
|
Loading…
Reference in New Issue