Compare commits
No commits in common. "b1407706a8e298d9b8985fa2115c9114f98c7f3d" and "54be3cad4f4f1573769ce64f5cc2aee987d4fe11" have entirely different histories.
b1407706a8
...
54be3cad4f
25
.env.yc
25
.env.yc
|
@ -1,25 +0,0 @@
|
|||
# 页面标题
|
||||
VITE_APP_TITLE = 文枢课堂
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
# AIx融合数字管理系统/生产环境
|
||||
VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||
|
||||
VITE_APP_DOMAIN = 'prev.ysaix.com'
|
||||
|
||||
VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
|
||||
|
||||
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||
|
||||
# websocket 地址
|
||||
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
||||
|
||||
# 是否显示开发工具
|
||||
VITE_SHOW_DEV_TOOLS = 'false'
|
25
.env.yc2
25
.env.yc2
|
@ -1,25 +0,0 @@
|
|||
# 页面标题
|
||||
VITE_APP_TITLE = 实训教学
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
# AIx融合数字管理系统/生产环境
|
||||
VITE_APP_BASE_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||
|
||||
VITE_APP_DOMAIN = 'prev.ysaix.com'
|
||||
|
||||
VITE_APP_UPLOAD_API = 'https://prev.ysaix.com:7868/prod-api'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
VITE_APP_RES_FILE_PATH = 'https://prev.ysaix.com:7868/src/assets/textbook/booktxt/'
|
||||
|
||||
VITE_APP_BUILD_BASE_PATH = 'https://prev.ysaix.com:7868/'
|
||||
|
||||
# websocket 地址
|
||||
VITE_APP_WS_URL = 'wss://prev.ysaix.com:7868'
|
||||
|
||||
# 是否显示开发工具
|
||||
VITE_SHOW_DEV_TOOLS = 'false'
|
|
@ -1,54 +0,0 @@
|
|||
appId: com.electron.app.yc
|
||||
productName: 文枢课堂
|
||||
directories:
|
||||
output: dist
|
||||
buildResources: build
|
||||
win:
|
||||
executableName: 文枢课堂
|
||||
icon: resources/yc-logo.png
|
||||
files:
|
||||
- '!**/.vscode/*'
|
||||
- '!src/*'
|
||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
nsis:
|
||||
oneClick: false
|
||||
allowToChangeInstallationDirectory: true
|
||||
artifactName: ${name}-yc-${version}-setup.${ext}
|
||||
shortcutName: ${productName}
|
||||
uninstallDisplayName: ${productName}
|
||||
createDesktopShortcut: always
|
||||
mac:
|
||||
entitlementsInherit: build/entitlements.mac.plist
|
||||
extendInfo:
|
||||
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||
notarize: false
|
||||
dmg:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
- snap
|
||||
- deb
|
||||
maintainer: electronjs.org
|
||||
category: Utility
|
||||
appImage:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
npmRebuild: false
|
||||
publish:
|
||||
provider: generic
|
||||
url: https://prev.ysaix.com:7868/src/assets/smarttalkyc/
|
||||
electronDownload:
|
||||
mirror: https://npmmirror.com/mirrors/electron/
|
||||
# 额外依赖打包到输出目录
|
||||
extraFiles:
|
||||
- from: ./node_modules/im_electron_sdk/lib/
|
||||
to: ./resources
|
||||
filter:
|
||||
- '**/*'
|
|
@ -1,54 +0,0 @@
|
|||
appId: com.electron.app.yc2
|
||||
productName: 实训教学
|
||||
directories:
|
||||
output: dist
|
||||
buildResources: build
|
||||
win:
|
||||
executableName: 实训教学
|
||||
icon: resources/yc-logo.png
|
||||
files:
|
||||
- '!**/.vscode/*'
|
||||
- '!src/*'
|
||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
nsis:
|
||||
oneClick: false
|
||||
allowToChangeInstallationDirectory: true
|
||||
artifactName: ${name}-ycsx-${version}-setup.${ext}
|
||||
shortcutName: ${productName}
|
||||
uninstallDisplayName: ${productName}
|
||||
createDesktopShortcut: always
|
||||
mac:
|
||||
entitlementsInherit: build/entitlements.mac.plist
|
||||
extendInfo:
|
||||
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||
notarize: false
|
||||
dmg:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
- snap
|
||||
- deb
|
||||
maintainer: electronjs.org
|
||||
category: Utility
|
||||
appImage:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
npmRebuild: false
|
||||
publish:
|
||||
provider: generic
|
||||
url: https://prev.ysaix.com:7868/src/assets/smarttalkycsx/
|
||||
electronDownload:
|
||||
mirror: https://npmmirror.com/mirrors/electron/
|
||||
# 额外依赖打包到输出目录
|
||||
extraFiles:
|
||||
- from: ./node_modules/im_electron_sdk/lib/
|
||||
to: ./resources
|
||||
filter:
|
||||
- '**/*'
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "aix-win-ws",
|
||||
"version": "2.5.8",
|
||||
"version": "2.5.6",
|
||||
"description": "",
|
||||
"main": "./out/main/index.js",
|
||||
"author": "上海交大重庆人工智能研究院",
|
||||
|
@ -16,8 +16,6 @@
|
|||
"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: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:mac": "electron-vite build --mode production && electron-builder --mac --config ./electron-builder-prod.yml",
|
||||
"build:linux": "npm run build && electron-builder --linux"
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 51 KiB |
|
@ -7,7 +7,6 @@ import Logger from './logger' // 日志封装
|
|||
import chat from './chat' // chat封装
|
||||
import Store from './store' // Store封装
|
||||
import updateInit from './update'
|
||||
|
||||
// 代理 electron/remote
|
||||
// 第一步:引入remote
|
||||
import remote from '@electron/remote/main'
|
||||
|
@ -42,19 +41,19 @@ if(!gotTheLock){
|
|||
}
|
||||
})
|
||||
}
|
||||
let logoIco = import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?'../../resources/yc-logo.png':'../../resources/logo2.ico'
|
||||
|
||||
//登录窗口
|
||||
function createLoginWindow() {
|
||||
if (loginWindow) return
|
||||
loginWindow = new BrowserWindow({
|
||||
width: import.meta.env.MODE==='yc'||import.meta.env.MODE==='yc2'?1060:888,
|
||||
width: 888,
|
||||
height: 520,
|
||||
show: false,
|
||||
frame: false,
|
||||
autoHideMenuBar: true,
|
||||
maximizable: false,
|
||||
resizable: false,
|
||||
icon: join(__dirname, logoIco),
|
||||
icon: join(__dirname, '../../resources/logo2.ico'),
|
||||
...(process.platform === 'linux' ? { icon } : {}),
|
||||
webPreferences: {
|
||||
defaultEncoding: 'utf-8',
|
||||
|
@ -96,7 +95,7 @@ function createMainWindow() {
|
|||
frame: false, // 无边框
|
||||
autoHideMenuBar: true,
|
||||
maximizable: false,
|
||||
icon: join(__dirname, logoIco),
|
||||
icon: join(__dirname, '../../resources/logo2.ico'),
|
||||
...(process.platform === 'linux' ? { icon } : {}),
|
||||
webPreferences: {
|
||||
defaultEncoding: 'utf-8',
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
|
||||
/> -->
|
||||
<meta http-equiv="Content-Security-Policy" content="connect-src * blob: data:; frame-src 'self' *; default-src 'self' https://wzyzoss.eos-chongqing-3.cmecloud.cn/; script-src 'self' 'unsafe-eval' http://www.wiris.net 'unsafe-inline'; style-src 'self' 'unsafe-inline' http://www.wiris.net; media-src * blob:;img-src * 'self' data: blob:;font-src 'self' http://www.wiris.net;" />
|
||||
<meta http-equiv="Content-Security-Policy" content="connect-src * blob: data:; default-src 'self' https://wzyzoss.eos-chongqing-3.cmecloud.cn/; script-src 'self' 'unsafe-eval' http://www.wiris.net 'unsafe-inline'; style-src 'self' 'unsafe-inline' http://www.wiris.net; media-src * blob:;img-src * 'self' data: blob:;font-src 'self' http://www.wiris.net;" />
|
||||
|
||||
</head>
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ const initLoad: Function = () => {
|
|||
!!(opt.ratio??null) && slidesStore.setViewportRatio(opt.ratio)// 有比例配置项
|
||||
}
|
||||
return PPTApi.getSlideList(resource.id)
|
||||
// PPTApi.updateWorkList()
|
||||
// return Promise.resolve()
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
|
|
@ -50,8 +50,6 @@ export class Utils {
|
|||
}, delay)
|
||||
}
|
||||
}
|
||||
// 延时
|
||||
static sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
/** ppt相关后端接口处理 */
|
||||
|
@ -61,7 +59,6 @@ export class PPTApi {
|
|||
|
||||
// 获取所有幻灯片列表 isUpdate为true不更新
|
||||
static getSlideList(parentid: (Number | String),isUpdate?:Boolean): Promise<Boolean> {
|
||||
const classcourse = sessionStore.get('curr.classcourse') // 课堂信息
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const params: object = { parentid, orderByColumn: 'fileidx', isAsc: 'asc', pageSize: 9999 }
|
||||
const res: Result = await API_entpcoursefile.listEntpcoursefileNew(params)
|
||||
|
@ -82,16 +79,12 @@ export class PPTApi {
|
|||
// 活动列表处理
|
||||
// const workList = (res.rows || []).map(o => o.activityContent)
|
||||
const workItem = res.rows ? [...res.rows] : []
|
||||
// 写入作业列表数据
|
||||
// slidesStore.setWorkList(workList)
|
||||
// 获取所有的pptlist的数据
|
||||
slidesStore.setWorkItem(workItem)
|
||||
// 没有上课时调用-作业列表
|
||||
if(!classcourse) this.updateWorkList()
|
||||
// 没有上课时调用-批量更新缩略图
|
||||
if(!classcourse) {
|
||||
Utils.sleep(1500).then(() => {
|
||||
this.batchUpdateThumUrl()
|
||||
})
|
||||
}
|
||||
|
||||
this.updateWorkList()
|
||||
resolve(true)
|
||||
} else msgUtils.msgError(res.msg || '获取数据失败');resolve(false)
|
||||
})
|
||||
|
@ -239,29 +232,10 @@ export class PPTApi {
|
|||
})
|
||||
}
|
||||
|
||||
// 批量更新缩略图-异步
|
||||
static batchUpdateThumUrl() {
|
||||
return nextTick().then(async () => {
|
||||
const list = slidesStore.workItem || []
|
||||
if (!list.length) return
|
||||
const upList = []
|
||||
for (const [ind,o] of list.entries()) {
|
||||
const isCreate = !o.fileurl // 是否创建
|
||||
if (isCreate) {
|
||||
const thumUrl = await this.getSlideThumUrl(ind)
|
||||
upList.push({ id: o.id, fileurl: thumUrl })
|
||||
}
|
||||
}
|
||||
if (!upList.length) return
|
||||
// 批量更新
|
||||
return await API_entpcoursefile.batchUpdateNew(upList)
|
||||
})
|
||||
}
|
||||
|
||||
// thumbnail-slide thumbnail 缩略图
|
||||
static getSlideThumUrl(index?:number): Promise<Boolean> {
|
||||
static getSlideThumUrl(): Promise<Boolean> {
|
||||
return nextTick().then(async() => {
|
||||
const slideIndex = index ?? slidesStore.slideIndex
|
||||
const slideIndex = slidesStore.slideIndex
|
||||
const elements = document.querySelectorAll('.thumbnail-slide')
|
||||
if (elements.length && slideIndex >= 0) {
|
||||
const element = elements[slideIndex]
|
||||
|
|
|
@ -126,8 +126,6 @@ export class MsgEnum {
|
|||
MSG_homework : 'HOMEWORK',
|
||||
/** @desc: 公屏 - 课堂作业|活动 */
|
||||
MSG_pushSreen_work : 'pushSreen_work',
|
||||
/** @desc: 公屏 - 实验 */
|
||||
MSG_pushSreen_experiment : 'pushSreen_experiment',
|
||||
/** @desc: 点赞 */
|
||||
MSG_dz : 'dz',
|
||||
/** @desc: 疑惑 */
|
||||
|
|
|
@ -10,7 +10,6 @@ import { MsgEnum } from './types' // 消息枚举
|
|||
import ChatWs from '@/plugins/socket' // 聊天socket
|
||||
import Classcourse from './classcourse' // 课程相关
|
||||
import msgUtils from '@/plugins/modal' // 消息工具
|
||||
import * as dialogUtils from '@/utils/dialog' // 弹窗-函数
|
||||
import { Homework } from './index' // api-作业相关
|
||||
// import emitter from '@/utils/mitt' //mitt 事件总线
|
||||
import useExecPlay from '../views/Screen/hooks/useExecPlay' // 播放控制
|
||||
|
@ -115,10 +114,6 @@ export default () => {
|
|||
if (!content.id) return
|
||||
Homework.showHomework(content.id)
|
||||
break
|
||||
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 打开实验:
|
||||
if (!content.url) return
|
||||
dialogUtils.openLink(content.url)
|
||||
break
|
||||
case MsgEnum.HEADS.MSG_closed: // 下课:
|
||||
close()
|
||||
break
|
||||
|
|
|
@ -25,12 +25,6 @@
|
|||
<div style="margin-top: 10px">常规作业</div>
|
||||
</div>
|
||||
</el-button>
|
||||
<el-button size="small" title="科学实验" text style="height: 54px;margin-left: 0" @click="showDialog('科学实验')">
|
||||
<div class="buttonDiv">
|
||||
<svg width="26" height="26" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#646473"><path d="M901.705143 511.926857h-55.954286a8.045714 8.045714 0 0 1-8.045714-8.045714V183.881143H181.686857v656.091428H501.76c4.388571 0 8.045714 3.510857 8.045714 7.899429v56.027429c0 4.388571-3.657143 8.045714-8.045714 8.045714H141.750857a31.963429 31.963429 0 0 1-32.036571-32.036572V143.872c0-17.627429 14.336-31.963429 32.036571-31.963429H877.714286c17.700571 0 32.036571 14.336 32.036571 31.963429V503.954286c0 4.388571-3.657143 8.045714-8.045714 8.045714zM731.428571 911.945143a36.571429 36.571429 0 0 1-36.571428-36.571429v-109.714285H585.142857a36.571429 36.571429 0 0 1 0-73.142858h109.714286v-109.714285a36.571429 36.571429 0 0 1 73.142857 0v109.714285H877.714286a36.571429 36.571429 0 1 1 0 73.142858h-109.714286v109.714285a36.571429 36.571429 0 0 1-36.571429 36.571429z" p-id="22184"></path></svg>
|
||||
<div style="margin-top: 10px">科学实验</div>
|
||||
</div>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
@ -163,10 +157,6 @@ const type = ref<WorkType[]>([
|
|||
{
|
||||
label: '框架梳理',
|
||||
value: 'primary'
|
||||
},
|
||||
{
|
||||
label: '科学实验',
|
||||
value: 'primary'
|
||||
}
|
||||
])
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
</div>
|
||||
<div
|
||||
class="tools-right" :class="{ 'visible': rightToolsVisible }"
|
||||
@mouseleave="toolTrigger('leave')"
|
||||
@mouseenter="toolTrigger('enter')"
|
||||
@mouseleave="rightToolsVisible = false"
|
||||
@mouseenter="rightToolsVisible = true"
|
||||
>
|
||||
<div class="content">
|
||||
<div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{slideIndex + 1}} / {{slides.length}}</div>
|
||||
|
@ -50,10 +50,6 @@
|
|||
<IconPower class="tool-btn" v-tooltip="'结束放映'" @click="exitScreening()" />
|
||||
<IconPower class="tool-btn close" v-if="chat.groupid" v-tooltip="'结束课堂'" @click="exitCourse()" />
|
||||
</div>
|
||||
<div :class="['tools-icon',{opacity:iconHide}]" @click.stop="toolTrigger('icon')">
|
||||
<circle-double-down v-if="rightToolsVisible" theme="outline" size="30" fill="#409EFF"/>
|
||||
<circle-double-up v-else="!rightToolsVisible" theme="outline" size="30" fill="#E6A23C"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -75,7 +71,6 @@ import WritingBoardTool from './WritingBoardTool.vue'
|
|||
import CountdownTimer from './CountdownTimer.vue'
|
||||
import emitter from '@/utils/mitt';
|
||||
import Chat from '../../api/chat' // 聊天
|
||||
import { CircleDoubleDown, CircleDoubleUp } from '@icon-park/vue-next' // icon-park 图标库
|
||||
|
||||
const props = defineProps<{
|
||||
changeViewMode: (mode: 'base' | 'presenter') => void
|
||||
|
@ -108,15 +103,12 @@ const { exitScreening } = useScreening()
|
|||
const { fullscreenState, manualExitFullscreen } = useFullscreen()
|
||||
const chat:any = Chat() // 聊天室
|
||||
|
||||
const screenStore =useScreenStore()
|
||||
const rightToolsVisible = ref(false)
|
||||
const writingBoardToolVisible = ref(false)
|
||||
const timerlVisible = ref(false)
|
||||
const slideThumbnailModelVisible = ref(false)
|
||||
const laserPen = ref(false)
|
||||
const timer = ref(0) // 记录操作时间
|
||||
const iconHide = ref(false) // 工具栏图标是否显示
|
||||
const timerId = ref(null) // 定时器id
|
||||
const screenStore =useScreenStore()
|
||||
const contextmenus = (): ContextmenuItem[] => {
|
||||
return [
|
||||
{
|
||||
|
@ -199,30 +191,6 @@ const contextmenus = (): ContextmenuItem[] => {
|
|||
]
|
||||
}
|
||||
|
||||
const toolTrigger = (type:string) => {
|
||||
const curT = Date.now()
|
||||
if (curT - timer.value < 200) return
|
||||
iconHide.value = false // 显示图标按钮
|
||||
if (timerId.value) clearTimeout(timerId.value) // 清除定时器
|
||||
switch (type) {
|
||||
case 'icon': // 点击图标
|
||||
timer.value = curT
|
||||
rightToolsVisible.value = !rightToolsVisible.value
|
||||
break
|
||||
case 'enter': // 移入
|
||||
timer.value = curT
|
||||
rightToolsVisible.value = true
|
||||
break
|
||||
case 'leave': // 移出
|
||||
rightToolsVisible.value = false
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
timerId.value = setTimeout(() => { // 定时器
|
||||
iconHide.value = true // 隐藏图标按钮
|
||||
}, 2000)
|
||||
}
|
||||
// 下课
|
||||
const exitCourse = async () => {
|
||||
// console.log('下课', chat)
|
||||
|
@ -285,18 +253,6 @@ const exitCourse = async () => {
|
|||
top: -66px;
|
||||
}
|
||||
|
||||
.tools-icon{
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: -35px;
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
transition: opacity $transitionDelay;
|
||||
&.opacity{
|
||||
opacity: .35;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -2,8 +2,6 @@ import axios from 'axios'
|
|||
import request from '@/utils/request'
|
||||
import { getToken } from "@/utils/auth";
|
||||
|
||||
let rootPath = import.meta.env.VITE_APP_ENV === 'production' ? 'https://ai.ysaix.com:7864' : ''
|
||||
|
||||
// 文生图片
|
||||
export function convertTextToPicture(data) {
|
||||
return axios({
|
||||
|
@ -44,7 +42,7 @@ export function getPicture(data) {
|
|||
// 大模型对话生成prompt模板
|
||||
export function chattoprompt(dataset_id,prompt) {
|
||||
return axios({
|
||||
url: rootPath + '/api/v1/parse/docs',
|
||||
url: '/api/v1/parse/docs',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
|
||||
|
@ -70,7 +68,7 @@ export function textSensitiveWord(data) {
|
|||
// 图片上传资源库
|
||||
export function uploadPicture(data) {
|
||||
return axios({
|
||||
url: import.meta.env.VITE_APP_BASE_API + '/smarttalk/file/upload',
|
||||
url: '/dev-api/smarttalk/file/upload',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 51 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
Before Width: | Height: | Size: 520 KiB |
|
@ -1,16 +1,3 @@
|
|||
<!--
|
||||
依赖: vuedraggable、v-viewer
|
||||
属性: showToolbar //是否显示工具栏 默认:false
|
||||
工具栏 添加图片:默认6个测试图片,不输入框添加则添加默认,输入图片链接,展示图片链接的图片
|
||||
清空图片:清空图片
|
||||
事件: clear 清空时触发
|
||||
outIndex 超出九个图片时触发
|
||||
方法: addPic //添加图片
|
||||
参数: src 图片链接
|
||||
clearPic //清空图片
|
||||
参数: 无
|
||||
使用方法: 加载组件后,通过ref调用addPic方法添加图片即可
|
||||
-->
|
||||
<template>
|
||||
<div style="position: relative;height: 100%;width: 100%;">
|
||||
<draggable handle=".header-btn" :draggable="false" item-key="backgroundColor" v-model="gridPicList" class="grid-pic-wrap" :style="getGrid">
|
||||
|
@ -22,21 +9,16 @@
|
|||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<div v-if="showToolbar" class="grid-pic-toolbar">
|
||||
<el-input style="width: 500px" v-model="inputValue" type="text" />
|
||||
<el-button class="add-btn" @click="pushPic">
|
||||
<el-input style="position:fixed;bottom: 20px;right: 180px;width: 1000px" v-model="inputValue" type="text" />
|
||||
<el-button class="add-btn" @click="addPic">
|
||||
添加
|
||||
</el-button>
|
||||
<el-button class="add-btn" @click="clearPic">
|
||||
清空
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- <el-button style="position:fixed;bottom: 20px;right: 80px;" @click="startPencil">
|
||||
<el-button style="position:fixed;bottom: 20px;right: 80px;" @click="startPencil">
|
||||
画笔
|
||||
</el-button>-->
|
||||
<!-- <div class="modal-mode">
|
||||
</el-button>
|
||||
<div class="modal-mode">
|
||||
<canvas id="canvas_pic_001" style="position: absolute;top: 0;left: 0;width: 100%;height: 100%;"></canvas>
|
||||
</div>-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -44,18 +26,10 @@
|
|||
import {ref, computed, onMounted} from 'vue'
|
||||
import Draggable from 'vuedraggable'
|
||||
import ViewerItem from "./viewer-item.vue";
|
||||
// import Fabric from 'fabric';
|
||||
import Fabric from 'fabric';
|
||||
const gridPicList = ref([])
|
||||
const inputValue = ref('')
|
||||
const isShow = ref(false)
|
||||
const emits = defineEmits(['clear','outIndex']);
|
||||
|
||||
const props = defineProps({
|
||||
showToolbar: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
// 获取图片样式
|
||||
const getWH = (item,index)=>{
|
||||
return {
|
||||
|
@ -144,19 +118,13 @@
|
|||
}
|
||||
})
|
||||
|
||||
const pushPic = () => {
|
||||
let src = inputValue.value||picList[gridPicList.value.length]
|
||||
addPic(src)
|
||||
}
|
||||
// 添加图片
|
||||
const addPic = (src) => {
|
||||
const addPic = () => {
|
||||
if (gridPicList.value.length >= 9) {
|
||||
console.log("超出九个图片")
|
||||
emits('outIndex')
|
||||
return
|
||||
}
|
||||
let src = inputValue.value||picList[gridPicList.value.length]
|
||||
if (!src) {
|
||||
console.log("图片链接不能为空")
|
||||
return;
|
||||
}
|
||||
gridPicList.value.push({
|
||||
|
@ -165,11 +133,6 @@
|
|||
})
|
||||
inputValue.value = ''
|
||||
}
|
||||
// 清空图片
|
||||
const clearPic = () => {
|
||||
gridPicList.value = []
|
||||
emits('clear')
|
||||
}
|
||||
//开始画笔
|
||||
const startPencil = () => {
|
||||
isShow.value = !isShow.value
|
||||
|
@ -185,7 +148,7 @@
|
|||
b = b.length === 1? '0' + b : b;
|
||||
return `#${r}${g}${b}`;
|
||||
}
|
||||
/* //初始化画笔
|
||||
//初始化画笔
|
||||
const initPend = () => {
|
||||
let canvas = new Fabric.fabric.Canvas('canvas_pic_001',{
|
||||
interactive: false,
|
||||
|
@ -199,11 +162,10 @@
|
|||
canvas.freeDrawingBrush = new Fabric.fabric.PencilBrush(canvas)
|
||||
canvas.freeDrawingBrush.width = 1//设置画笔粗细
|
||||
canvas.freeDrawingBrush.color = "red"//设置画笔颜色
|
||||
}*/
|
||||
/*onMounted(() => {
|
||||
}
|
||||
onMounted(() => {
|
||||
initPend()
|
||||
})*/
|
||||
defineExpose({addPic,clearPic})
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.modal-mode{
|
||||
|
@ -242,13 +204,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.grid-pic-toolbar{
|
||||
.add-btn{
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
display: flex;
|
||||
.add-btn{
|
||||
}
|
||||
}
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<script setup>
|
||||
import {ref, watch, nextTick, onMounted} from "vue";
|
||||
import { component as Viewer } from 'v-viewer'
|
||||
// import Fabric from 'fabric';
|
||||
import Fabric from 'fabric';
|
||||
import 'viewerjs/dist/viewer.css'
|
||||
const props = defineProps({
|
||||
images: {
|
||||
|
@ -36,13 +36,16 @@ const inited = (viewer) => {
|
|||
}
|
||||
//缩放时
|
||||
const zoomed = (e) => {
|
||||
// setImgStyle()
|
||||
setImgStyle()
|
||||
// console.log('zoomed', e)
|
||||
}
|
||||
//移动时
|
||||
const moved = (e) => {
|
||||
// setImgStyle()
|
||||
setImgStyle()
|
||||
// console.log('moved',e)
|
||||
}
|
||||
const move = (e) => {
|
||||
// console.log('move', e)
|
||||
}
|
||||
const appendCanvasToShow = () => {
|
||||
initImgStyle()
|
||||
|
@ -89,7 +92,7 @@ const optins = ref({
|
|||
"tooltip": true,
|
||||
"zoomable": true,
|
||||
"rotatable": true,
|
||||
"movable": true,
|
||||
"movable": false,
|
||||
"scalable": true,
|
||||
"transition": true,
|
||||
"fullscreen": true,
|
||||
|
@ -97,9 +100,9 @@ const optins = ref({
|
|||
})
|
||||
const initViewers = () => {
|
||||
refs.value['viewerRef'+props.index]?.rebuildViewer()
|
||||
/*setTimeout(()=>{
|
||||
setTimeout(()=>{
|
||||
initImgStyle()
|
||||
},300)*/
|
||||
},300)
|
||||
}
|
||||
//初始化画笔
|
||||
const initPend = () => {
|
||||
|
@ -130,11 +133,11 @@ watch(props.images, (newValue, oldValue) => {
|
|||
});
|
||||
*/
|
||||
|
||||
/*onMounted(()=>{
|
||||
onMounted(()=>{
|
||||
setTimeout(()=>{
|
||||
appendCanvasToShow()
|
||||
}, 300)
|
||||
})*/
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.viewer-item-wrap{
|
||||
|
|
|
@ -104,7 +104,7 @@ import { cloneDeep } from 'lodash'
|
|||
const props = defineProps(['type'])
|
||||
const { user } = useUserStore()
|
||||
|
||||
const curMode = ref(2)
|
||||
const curMode = ref(1)
|
||||
const modeOptions = ref([
|
||||
{
|
||||
label: '教学大模型',
|
||||
|
|
|
@ -38,7 +38,6 @@ const closeWindow = () => {
|
|||
ElMessageBox.confirm('确认退出系统吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
customClass: 'login-close-tool',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
userStore.logOut().then(() => {
|
||||
|
@ -55,11 +54,7 @@ onMounted(() =>{
|
|||
})
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.login-close-tool {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-tool {
|
||||
width: 100%;
|
||||
|
|
|
@ -32,7 +32,7 @@ export const editListItem = (row, courseObj) => {
|
|||
worktype: '', // 设计中的作业类型
|
||||
quizlist: [], // 设计中的试题列表
|
||||
chooseWorkLists: [],// 设计中的框架梳理list
|
||||
fileHomeworkList: [],//TODO 暂时共用这个字段(新增了 科学实验) 设计中的常规作业list
|
||||
fileHomeworkList: [],// 设计中的常规作业list
|
||||
whiteboardObj: '',// 设计中的课堂展示对象
|
||||
question: '', // 设计中的[课堂展示]的问题
|
||||
};
|
||||
|
@ -112,16 +112,6 @@ export const editListItem = (row, courseObj) => {
|
|||
return resolve(classtaskObj);
|
||||
}
|
||||
}
|
||||
else if (row.worktype == '科学实验') {
|
||||
if(isJson(row.workcodes)){
|
||||
classtaskObj.fileHomeworkList = JSON.parse(row.workcodes);
|
||||
//
|
||||
// console.log('科学实验', classtaskObj);
|
||||
// 更新默认的科学实验( 学段 学科 以及实验科目)
|
||||
console.log('科学实验', classtaskObj);
|
||||
return resolve(classtaskObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -94,8 +94,6 @@ const getHomeWorkList = async () => {
|
|||
res.rows[i].workclass = 'info';
|
||||
} else if (res.rows[i].worktype == '习题训练') {
|
||||
res.rows[i].workclass = 'danger';
|
||||
} else if (res.rows[i].worktype == '科学实验') {
|
||||
res.rows[i].workclass = 'danger';
|
||||
} else {
|
||||
res.rows[i].workclass = 'primary';
|
||||
}
|
||||
|
|
|
@ -100,8 +100,6 @@ export class MsgEnum {
|
|||
MSG_homework : 'HOMEWORK',
|
||||
/** @desc: 公屏 - 课堂作业|活动 */
|
||||
MSG_pushSreen_work : 'pushSreen_work',
|
||||
/** @desc: 公屏 - 实验 */
|
||||
MSG_pushSreen_experiment : 'pushSreen_experiment',
|
||||
/** @desc: 点赞 */
|
||||
MSG_dz : 'dz',
|
||||
/** @desc: 疑惑 */
|
||||
|
|
|
@ -5,11 +5,6 @@ import { JYApiListCT, JYApiListOriginYear, JYApiListSO} from "@/utils/examQuesti
|
|||
|
||||
const useClassTaskStore = defineStore('classTask',{
|
||||
state: () => ({
|
||||
experimentObj:{
|
||||
edustage: '小学', // 教育阶段
|
||||
edusubject: '', // 学科
|
||||
experimentList: [], // 实验科目列表
|
||||
},
|
||||
isOpenQuestUploadView: false, // 是否打开习题上传的页面
|
||||
classListIds: [],
|
||||
entpCourseWorkTypeList: [
|
||||
|
|
|
@ -403,11 +403,5 @@ export const dataSetJson = {
|
|||
"教材-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
|
||||
"教材-高中-地理": "270516829fd111efb13c0242ac140006",
|
||||
"教材-高中-政治": "a2f0b247b85d11ef84290242ac140005",
|
||||
"课标-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
||||
"课标-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
||||
"课标-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
||||
"教材-小学-科学": "935cfec8bf6a11ef98950242ac140006",
|
||||
"教材-小学-数学": "3c4e298fbf7911ef8e8b0242ac140002",
|
||||
"教材-小学-语文": "f76f1aa5bf7111ef90c80242ac140002",
|
||||
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* 弹窗-函数
|
||||
*/
|
||||
import { h, render } from 'vue'
|
||||
import { ElDialog } from 'element-plus'
|
||||
|
||||
// 打开弹窗-函数
|
||||
export const openDialog = (option, content) => {
|
||||
let vNode
|
||||
const body = document.body
|
||||
const dOpts = {
|
||||
modelValue: true,
|
||||
width: 800,
|
||||
height: 600,
|
||||
title: '添加-超连接',
|
||||
draggable: true,
|
||||
'onUpdate:modelValue': val => {
|
||||
if (vNode && !val) render(null, body)
|
||||
},
|
||||
...option
|
||||
}
|
||||
vNode = h(ElDialog, dOpts, {
|
||||
default: typeof content == 'function' ? content(h) : content
|
||||
})
|
||||
render(vNode, body)
|
||||
}
|
||||
|
||||
// 打开链接
|
||||
export const openLink = (option, title) => {
|
||||
// https://phet.colorado.edu/sims/html/number-play/latest/number-play_zh_CN.html
|
||||
const isStr = typeof option == 'string'
|
||||
const opt = isStr ? {} : option
|
||||
const url = isStr ? option : option?.url || option?.src || option?.href
|
||||
const titleNew = isStr? title||'实验室' : option?.title || '添加-超连接'
|
||||
openDialog({
|
||||
title: titleNew,
|
||||
...opt
|
||||
}, (h) => {
|
||||
return h('iframe', {
|
||||
src: url,
|
||||
width: '100%',
|
||||
style: {
|
||||
height: 'calc(80vh - 75px)',
|
||||
},
|
||||
scrolling: 'no',
|
||||
frameborder: '0',
|
||||
})
|
||||
})
|
||||
}
|
|
@ -1,734 +0,0 @@
|
|||
{
|
||||
"title": "实验",
|
||||
"data": {
|
||||
"primary":[
|
||||
{
|
||||
"label": "数量比较",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/number-compare/latest/number-compare_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "数字游戏",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/number-play/latest/number-play_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "数轴:距离",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/number-line-distance/latest/number-line-distance_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "比率和比例",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/ratio-and-proportion/latest/ratio-and-proportion_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "数轴:运算",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/number-line-operations/latest/number-line-operations_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "数轴:整数",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/number-line-integers/latest/number-line-integers_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "向量的和:等式",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/vector-addition-equations/latest/vector-addition-equations_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "向量相加",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/vector-addition/latest/vector-addition_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "曲线拟合",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/curve-fitting/latest/curve-fitting_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "分数:带分数",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/fractions-mixed-numbers/latest/fractions-mixed-numbers_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "分数:入门",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/fractions-intro/latest/fractions-intro_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "构建一个分数",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/build-a-fraction/latest/build-a-fraction_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "分数:等式",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/fractions-equality/latest/fractions-equality_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"label": "单位价格",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/unit-rates/latest/unit-rates_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "获得一个10",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/make-a-ten/latest/make-a-ten_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "木棒的计算问题",
|
||||
"fileurl": "https://www.netpad.net.cn/resource_web/course/?pack_id=6dc2ab05-cb06-4716-92ca-e00fb89ad1e6#/20808",
|
||||
"subject": "math"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"label": "几何光学",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/geometric-optics/latest/geometric-optics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "密度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "能量滑板竞技场: 基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/energy-skate-park-basics/latest/energy-skate-park-basics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "法拉第定律",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/faradays-law/latest/faradays-law_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "绳波",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "光的混合",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/color-vision/latest/color-vision_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "平衡探究实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/balancing-act/latest/balancing-act_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "受到压力",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/under-pressure/latest/under-pressure_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "摩擦力",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/friction/latest/friction_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "力和运动:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/forces-and-motion-basics/latest/forces-and-motion-basics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "静电电压",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/john-travoltage/latest/john-travoltage_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "万有引力实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab/latest/gravity-force-lab_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "气球和静电(摩擦起电)",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/balloons-and-static-electricity/latest/balloons-and-static-electricity_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
"label": "密度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
{
|
||||
"label": "基因表达基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gene-expression-essentials/latest/gene-expression-essentials_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
|
||||
|
||||
|
||||
{
|
||||
"label": "密度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "PH值",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale/latest/ph-scale_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"label": "密度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/density/latest/density_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "创造一个分子",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/build-a-molecule/latest/build-a-molecule_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "扩散",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/diffusion/latest/diffusion_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
}
|
||||
],
|
||||
"junior": [
|
||||
{
|
||||
"label": "二项分布弹珠台几率",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/plinko-probability/latest/plinko-probability_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "建立方程",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/function-builder/latest/function-builder_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "三角函数之旅",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/trig-tour/latest/trig-tour_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "四则运算",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/arithmetic/latest/arithmetic_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "二次函数图像",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/graphing-quadratics/latest/graphing-quadratics_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "质量和弹簧",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/masses-and-springs/latest/masses-and-springs_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "等式探索:两个变量",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/equality-explorer-two-variables/latest/equality-explorer-two-variables_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "等式探索:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/equality-explorer-basics/latest/equality-explorer-basics_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "等式探索",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/equality-explorer/latest/equality-explorer_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "面积模型代数",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/area-model-algebra/latest/area-model-algebra_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "面积模型:小数",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/area-model-decimals/latest/area-model-decimals_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "面积模型乘法",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/area-model-multiplication/latest/area-model-multiplication_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "面积模型入门",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/area-model-introduction/latest/area-model-introduction_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "钟摆实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/pendulum-lab/latest/pendulum-lab_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "斜抛运动",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/projectile-motion/latest/projectile-motion_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "表达式变换",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/expression-exchange/latest/expression-exchange_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "电路建设工具包:交流",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-ac/latest/circuit-construction-kit-ac_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "交流虚拟实验室",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-ac-virtual-lab/latest/circuit-construction-kit-ac-virtual-lab_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "碰撞实验室",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/collision-lab/latest/collision-lab_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "能量滑板竞技场",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/energy-skate-park/latest/energy-skate-park_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "向量相加",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/vector-addition/latest/vector-addition_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "曲线拟合",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/curve-fitting/latest/curve-fitting_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "引力实验室:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab-basics/latest/gravity-force-lab-basics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "波动入门",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/waves-intro/latest/waves-intro_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "扩散",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/diffusion/latest/diffusion_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "气体基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gases-intro/latest/gases-intro_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "气体性质",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gas-properties/latest/gas-properties_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "质量与弹簧:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/masses-and-springs-basics/latest/masses-and-springs-basics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "黑体辐射",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/blackbody-spectrum/latest/blackbody-spectrum_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "能量的形式和转换",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/energy-forms-and-changes/latest/energy-forms-and-changes_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "波的干涉",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/wave-interference/latest/wave-interference_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "库仑定律",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/coulombs-law/latest/coulombs-law_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "质量和弹簧",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/masses-and-springs/latest/masses-and-springs_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "电容器实验:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/capacitor-lab-basics/latest/capacitor-lab-basics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "电路组建实验:直流虚拟实验室",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-dc-virtual-lab/latest/circuit-construction-kit-dc-virtual-lab_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "电路组建实验:直流",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/circuit-construction-kit-dc/latest/circuit-construction-kit-dc_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "钟摆实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/pendulum-lab/latest/pendulum-lab_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "斜抛运动",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/projectile-motion/latest/projectile-motion_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "物质状态:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter-basics/latest/states-of-matter-basics_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "物质状态",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter/latest/states-of-matter_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "重力和轨道",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gravity-and-orbits/latest/gravity-and-orbits_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "分子与光",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecules-and-light/latest/molecules-and-light_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "PH值",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale/latest/ph-scale_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
{
|
||||
"label": "光的混合",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/color-vision/latest/color-vision_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
{
|
||||
"label": "自然选择",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/natural-selection/latest/natural-selection_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "受到压力",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/under-pressure/latest/under-pressure_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "万有引力实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab/latest/gravity-force-lab_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "气球和静电(摩擦起电)",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/balloons-and-static-electricity/latest/balloons-and-static-electricity_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "气体基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gases-intro/latest/gases-intro_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "气体性质",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gas-properties/latest/gas-properties_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "黑体辐射",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/blackbody-spectrum/latest/blackbody-spectrum_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "能量的形式和转换",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/energy-forms-and-changes/latest/energy-forms-and-changes_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "库仑定律",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/coulombs-law/latest/coulombs-law_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "分子极性",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecule-polarity/latest/molecule-polarity_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "物质状态:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter-basics/latest/states-of-matter-basics_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "物质状态",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/states-of-matter/latest/states-of-matter_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "原子的相互作用",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/atomic-interactions/latest/atomic-interactions_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "卢瑟福散射",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/rutherford-scattering/latest/rutherford-scattering_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "原子的相互作用",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/atomic-interactions/latest/atomic-interactions_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
}
|
||||
],
|
||||
"senior": [
|
||||
|
||||
{
|
||||
"label": "一次线性函数的拟合",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/least-squares-regression/latest/least-squares-regression_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "区域建造者",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/area-builder/latest/area-builder_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "绳波",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "直线图形",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/graphing-lines/latest/graphing-lines_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "分数配对",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/fraction-matcher/latest/fraction-matcher_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "平衡探究实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/balancing-act/latest/balancing-act_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "绘图:斜率与截距",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/graphing-slope-intercept/latest/graphing-slope-intercept_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "函数构造器:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/function-builder-basics/latest/function-builder-basics_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
{
|
||||
"label": "比例游乐场",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/proportion-playground/latest/proportion-playground_zh_CN.html",
|
||||
"subject": "math"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "二项分布弹珠台几率",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/plinko-probability/latest/plinko-probability_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "原子的相互作用",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/atomic-interactions/latest/atomic-interactions_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "电荷与电场",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/charges-and-fields/latest/charges-and-fields_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "卢瑟福散射",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/rutherford-scattering/latest/rutherford-scattering_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "光的折射",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/bending-light/latest/bending-light_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "胡克定律",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/hookes-law/latest/hookes-law_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "部分电路欧姆定律",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/ohms-law/latest/ohms-law_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "电线的电阻",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/resistance-in-a-wire/latest/resistance-in-a-wire_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
{
|
||||
"label": "原子模型",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/build-an-atom/latest/build-an-atom_zh_CN.html",
|
||||
"subject": "physics"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "分子极性",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecule-polarity/latest/molecule-polarity_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
{
|
||||
"label": "神经元",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/neuron/latest/neuron_zh_CN.html",
|
||||
"subject": "biology"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "引力实验室:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gravity-force-lab-basics/latest/gravity-force-lab-basics_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "波动入门",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/waves-intro/latest/waves-intro_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "扩散",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/diffusion/latest/diffusion_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "气体基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gases-intro/latest/gases-intro_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "气体性质",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gas-properties/latest/gas-properties_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "分子与光",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecules-and-light/latest/molecules-and-light_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "绳波",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "黑体辐射",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/blackbody-spectrum/latest/blackbody-spectrum_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "波的干涉",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/wave-interference/latest/wave-interference_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
{
|
||||
"label": "重力和轨道",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/gravity-and-orbits/latest/gravity-and-orbits_zh_CN.html",
|
||||
"subject": "sciences"
|
||||
},
|
||||
|
||||
{
|
||||
"label": "同位素和原子的质量",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/isotopes-and-atomic-mass/latest/isotopes-and-atomic-mass_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "分子与光",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecules-and-light/latest/molecules-and-light_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "分子形状",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecule-shapes/latest/molecule-shapes_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "分子形状:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molecule-shapes-basics/latest/molecule-shapes-basics_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "反应物,生成物及未反应物",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/reactants-products-and-leftovers/latest/reactants-products-and-leftovers_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "pH值:基础",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale-basics/latest/ph-scale-basics_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "绳波",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/wave-on-a-string/latest/wave-on-a-string_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "PH值",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/ph-scale/latest/ph-scale_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "配平化学方程式",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/balancing-chemical-equations/latest/balancing-chemical-equations_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "酸碱溶度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/acid-base-solutions/latest/acid-base-solutions_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "浓度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/concentration/latest/concentration_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "气球和静电(摩擦起电)",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/balloons-and-static-electricity/latest/balloons-and-static-electricity_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "比尔定律实验",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/beers-law-lab/latest/beers-law-lab_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},{
|
||||
"label": "摩尔浓度",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/molarity/latest/molarity_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
},
|
||||
{
|
||||
"label": "原子模型",
|
||||
"fileurl": "https://phet.colorado.edu/sims/html/build-an-atom/latest/build-an-atom_zh_CN.html",
|
||||
"subject": "chemistry"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ export const asyncLocalFile = (item) => {
|
|||
if (isAsync === true) {
|
||||
item.async = 'on'
|
||||
if (type === 'down') {
|
||||
// console.log(item)
|
||||
console.log(item)
|
||||
ipcRenderer.send('download-file-default', {
|
||||
url: item.fileFullPath,
|
||||
fileName: item.fileNewName
|
||||
|
|
|
@ -248,11 +248,10 @@ export function toolWindow(type, {url, isConsole, isWeb=true, option={}}) {
|
|||
const devUrl = `${BaseUrl}${url}`
|
||||
const buildUrl = path.join(__dirname, 'index.html')
|
||||
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) => {
|
||||
const config = {
|
||||
width, height,
|
||||
icon: path.join(appPath, logoIco),
|
||||
icon: path.join(appPath, '/resources/logo2.ico'),
|
||||
webPreferences: {
|
||||
preload: path.join(API.preloadPath, '/index.js'),
|
||||
sandbox: false,
|
||||
|
|
|
@ -141,8 +141,7 @@
|
|||
v-if="
|
||||
dialogProps.studentObj.worktype == '常规作业' ||
|
||||
dialogProps.studentObj.worktype == '课堂展示' ||
|
||||
dialogProps.studentObj.worktype == '框架梳理' ||
|
||||
dialogProps.studentObj.worktype == '科学实验'
|
||||
dialogProps.studentObj.worktype == '框架梳理'
|
||||
"
|
||||
>
|
||||
<div v-for="(stuItem, sIndex) in dialogProps.studentQuizAllList" :key="stuItem.id">
|
||||
|
@ -158,8 +157,7 @@
|
|||
v-if="
|
||||
dialogProps.studentObj.worktype == '常规作业' ||
|
||||
dialogProps.studentObj.worktype == '课堂展示' ||
|
||||
dialogProps.studentObj.worktype == '框架梳理' ||
|
||||
dialogProps.studentObj.worktype == '科学实验'
|
||||
dialogProps.studentObj.worktype == '框架梳理'
|
||||
"
|
||||
>
|
||||
<!-- 文件内容格式:mp3/mp4/doc/docx/excel/pdf/ppt/pptx/jpg/jpeg/gif/png/txt ->
|
||||
|
@ -212,13 +210,7 @@
|
|||
|
||||
<!-- 学生答题展示 -->
|
||||
<div v-if="feedContentList.length > 0">
|
||||
<div
|
||||
v-if="
|
||||
(dialogProps.studentObj.worktype == '常规作业' || dialogProps.studentObj.worktype == '科学实验') &&
|
||||
stuItem.rightanswer != '' &&
|
||||
stuItem.rightanswer != null
|
||||
"
|
||||
>
|
||||
<div v-if="dialogProps.studentObj.worktype == '常规作业' && stuItem.rightanswer != ''&& stuItem.rightanswer != null">
|
||||
<!-- 常规作业:学生有的会答复 -->
|
||||
<p style="padding: 10px 0;text-align: left;">学生答复内容</p>
|
||||
<div style="padding: 0 20px;text-align: left;">{{stuItem.rightanswer}}</div>
|
||||
|
@ -708,7 +700,6 @@ const acceptParams = async (params) => {
|
|||
})
|
||||
} else {
|
||||
// 学生回答
|
||||
if (params.studentObj.worktype == '常规作业' || params.studentObj.worktype == '科学实验') {
|
||||
if (params.studentObj.worktype == '常规作业') {
|
||||
try {
|
||||
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
||||
|
@ -734,9 +725,6 @@ const acceptParams = async (params) => {
|
|||
} catch (error) {
|
||||
console.error('Invalid JSON:', error)
|
||||
}
|
||||
}else{
|
||||
// TODO 科学实验 老师布置的活动 暂时不在批改中显示 2024-12-20
|
||||
}
|
||||
|
||||
params.studentQuizAllList.forEach((item) => {
|
||||
classWorkFormScore.teacherRating.push({
|
||||
|
|
|
@ -37,7 +37,6 @@ const items = shallowRef([
|
|||
{ title: '常规作业', description: '推送pdf、视频、音频、图片,学生可以拍照上传。', icon: '#icon-zhaoxiangji',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' },
|
||||
]);
|
||||
|
||||
const handleClick = (item) => {
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
<template>
|
||||
<div style="display: flex;">
|
||||
<el-select
|
||||
v-model="value"
|
||||
placeholder="请选择实验课程"
|
||||
size="large"
|
||||
style="width: 240px"
|
||||
@change="onSelectOption"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in classTaskStore.experimentList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import {ArrowDown} from '@element-plus/icons-vue'
|
||||
import { onMounted,ref } from 'vue';
|
||||
import useClassTaskStore from '@/store/modules/classTask'
|
||||
const userStore = useUserStore().user
|
||||
const subjectList = ref([])
|
||||
const classTaskStore = useClassTaskStore().experimentObj
|
||||
|
||||
// 定义要发送的emit事件
|
||||
let emit = defineEmits(['selectItem'])
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
})
|
||||
const value = ref('')
|
||||
|
||||
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
})
|
||||
|
||||
const onSelectOption = (option) => {
|
||||
console.log(option,'选择的实验课-------')
|
||||
emit('selectItem', classTaskStore.experimentList.filter(item => item.label === option)[0])
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
<template>
|
||||
<div style="display: flex;">
|
||||
<div style="margin-left: 15px">
|
||||
<el-dropdown @command="handleUserEduStage">
|
||||
<span class="el-dropdown-link">
|
||||
<el-button class="custom-button" type="default" round >{{ useClassTaskStore().experimentObj.edustage }}
|
||||
<el-icon><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<!-- <el-dropdown-item command="幼儿园">幼儿园</el-dropdown-item> -->
|
||||
<el-dropdown-item command="小学">小学</el-dropdown-item>
|
||||
<el-dropdown-item command="初中">初中</el-dropdown-item>
|
||||
<el-dropdown-item command="高中">高中</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<div style="margin-left: 15px">
|
||||
<el-dropdown @command="handleUserEduSubject">
|
||||
<span class="el-dropdown-link">
|
||||
<el-button class="custom-button" type="default" round>{{ useClassTaskStore().experimentObj.edusubject }}
|
||||
<el-icon><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<template v-for="(item, index) in subjectList">
|
||||
<el-dropdown-item v-if="item.edustage == useClassTaskStore().experimentObj.edustage && isExpList(item.itemtitle)" :command="item.itemtitle">{{
|
||||
item.itemtitle }}</el-dropdown-item>
|
||||
</template>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import {ArrowDown} from '@element-plus/icons-vue'
|
||||
import { onMounted,ref } from 'vue';
|
||||
import { listEvaluation } from '@/api/subject/index'
|
||||
import jsonData from "@/utils/phetData.json";
|
||||
import useClassTaskStore from '@/store/modules/classTask'
|
||||
const userStore = useUserStore().user
|
||||
|
||||
// 定义要发送的emit事件
|
||||
// let emit = defineEmits(['experlist'])
|
||||
// const expObj = ref({
|
||||
// edustage: useClassTaskStore().experimentObj.edustage,
|
||||
// edusubject: useClassTaskStore().experimentObj.edusubject,
|
||||
// })
|
||||
const subjectList = ref([])
|
||||
const chooseGrade= ref({})
|
||||
const expList = ref([]) // 当前年级的所有课程
|
||||
const checkList = ref([])// 当前年级对应学科的课程,
|
||||
|
||||
|
||||
// 获取基础的学科
|
||||
const getSubject = () => {
|
||||
//没有学科则不进行下面的步骤
|
||||
// if(!userStore.subject) return
|
||||
// listEvaluation({ itemkey: 'subject', pageSize: 500 }).then((res) => {
|
||||
// const arr = userStore.subject.split(',')
|
||||
// subjectList.value = res.rows.filter(item => arr.includes(String(item.id))).map(items => items)
|
||||
// console.log(subjectList,'subjectList');
|
||||
// })
|
||||
//这里获取死数据 学科list
|
||||
const edustageList = ['小学','初中','高中'];
|
||||
const subList = ['数学','物理','化学','生物','科学'];
|
||||
edustageList.forEach((item) => {
|
||||
subList.forEach((subItems) => {
|
||||
subjectList.value.push({
|
||||
edustage: item,
|
||||
edusubject: subItems,
|
||||
itemtitle: subItems
|
||||
})
|
||||
})
|
||||
})
|
||||
console.log(subjectList,'subjectList');
|
||||
// 默认读取一个学科
|
||||
handleUserEduStage(useClassTaskStore().experimentObj.edustage)
|
||||
}
|
||||
// 展示有 实验科目的学科
|
||||
const isExpList = (edusubject) => {
|
||||
let list = [];
|
||||
switch (edusubject){
|
||||
case '数学':
|
||||
list = expList.value.filter(item => item.subject === 'math')
|
||||
break;
|
||||
case '物理':
|
||||
list = expList.value.filter(item => item.subject === 'physics')
|
||||
break;
|
||||
case '化学':
|
||||
checkList.value = expList.value.filter(item => item.subject === 'chemistry')
|
||||
break;
|
||||
case '生物':
|
||||
list = expList.value.filter(item => item.subject === 'biology')
|
||||
break;
|
||||
case '科学':
|
||||
list = expList.value.filter(item => item.subject === 'sciences')
|
||||
break;
|
||||
}
|
||||
return list.length > 0
|
||||
}
|
||||
// 选择学段
|
||||
const handleUserEduStage = (item) => {
|
||||
// userStore.edustage = item
|
||||
useClassTaskStore().experimentObj.edustage = item
|
||||
//清空操作
|
||||
expList.value = []
|
||||
if(item === '小学'){
|
||||
chooseGrade.value = jsonData.data.primary
|
||||
expList.value = chooseGrade.value
|
||||
const newSubjectList = subjectList.value.filter(item => item.edustage === '小学');
|
||||
for(let i in newSubjectList){
|
||||
const name = newSubjectList[i].itemtitle
|
||||
if(isExpList(name)){
|
||||
useClassTaskStore().experimentObj.edusubject = name;
|
||||
// 更改学科默认与学科下的实验科目
|
||||
handleUserEduSubject(name)
|
||||
}
|
||||
}
|
||||
}else if(item === '初中'){
|
||||
chooseGrade.value = jsonData.data.junior
|
||||
expList.value = chooseGrade.value
|
||||
const newSubjectList = subjectList.value.filter(item => item.edustage === '初中');
|
||||
for(let i in newSubjectList){
|
||||
const name = newSubjectList[i].itemtitle
|
||||
if(isExpList(name)){
|
||||
useClassTaskStore().experimentObj.edusubject = name;
|
||||
// 更改学科默认与学科下的实验科目
|
||||
handleUserEduSubject(name)
|
||||
}
|
||||
}
|
||||
}else if(item === '高中'){
|
||||
chooseGrade.value = jsonData.data.senior
|
||||
expList.value = chooseGrade.value
|
||||
const newSubjectList = subjectList.value.filter(item => item.edustage === '高中');
|
||||
for(let i in newSubjectList){
|
||||
const name = newSubjectList[i].itemtitle
|
||||
if(isExpList(name)){
|
||||
useClassTaskStore().experimentObj.edusubject = name;
|
||||
// 更改学科默认与学科下的实验科目
|
||||
handleUserEduSubject(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 选择学科
|
||||
const handleUserEduSubject = (item) => {
|
||||
// userStore.edusubject = item;
|
||||
useClassTaskStore().experimentObj.edusubject = item;
|
||||
console.log(item,'选择的学科-------')
|
||||
checkList.value = []
|
||||
switch (item){
|
||||
case '数学':
|
||||
checkList.value = expList.value.filter(item => item.subject === 'math')
|
||||
break;
|
||||
case '物理':
|
||||
checkList.value = expList.value.filter(item => item.subject === 'physics')
|
||||
break;
|
||||
case '化学':
|
||||
checkList.value = expList.value.filter(item => item.subject === 'chemistry')
|
||||
break;
|
||||
case '生物':
|
||||
checkList.value = expList.value.filter(item => item.subject === 'biology')
|
||||
break;
|
||||
case '科学':
|
||||
checkList.value = expList.value.filter(item => item.subject === 'sciences')
|
||||
break;
|
||||
}
|
||||
console.log(checkList.value,'checkList')
|
||||
useClassTaskStore().experimentObj.experimentList = checkList.value;
|
||||
// emit('experlist',checkList.value)
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
getSubject()
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.custom-button {
|
||||
width: auto;
|
||||
border: 1px solid rgb(59, 130, 246);
|
||||
outline: none;
|
||||
outline-offset: none;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.custom-button i {
|
||||
margin-left: 8px; /* 调整图标与文字之间的间距 */
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
<template>
|
||||
<div class="experiment-page">
|
||||
<div class="activeExp-header">
|
||||
<div class="infomation" v-if="isStadium() !== true" >
|
||||
<!-- <selectClass v-if="!isSubject" @experlist="getExperimentList" /> -->
|
||||
<selectClass v-if="!isSubject" />
|
||||
</div>
|
||||
<div>
|
||||
<selectExperiment @selectItem="getExperimentListItem" />
|
||||
</div>
|
||||
</div>
|
||||
<div ref="mainDiv" class="activeExp-main" style="overflow: auto">
|
||||
<div v-if="!activeExp.fileurl"><el-empty description="暂无学科实验"></el-empty></div>
|
||||
<iframe v-else :src="activeExp.fileurl" ref="myuunity" width="100%" height="100%" scrolling="no" frameborder="0"></iframe>
|
||||
<!-- <phet/>-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
//import html2canvas from 'html2canvas';
|
||||
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useClassTaskStore from '@/store/modules/classTask'
|
||||
import selectClass from './components/selectClass.vue' //选择学校和班级
|
||||
import selectExperiment from './components/experimentList.vue' // 选择的 学科实验
|
||||
|
||||
|
||||
// 定义要发送的emit事件
|
||||
let emit = defineEmits(['clickExpObj'])
|
||||
const { proxy } = getCurrentInstance()
|
||||
const userStore = useUserStore().user
|
||||
|
||||
const props = defineProps({
|
||||
bookobj: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
expObj: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
// 学科的 实验列
|
||||
// const experimentList = ref([]);
|
||||
const activeExp = ref({});
|
||||
|
||||
const isStadium = () => {
|
||||
let roles = userStore.roles
|
||||
return roles.some(item => item.roleKey === 'stadium')
|
||||
}
|
||||
|
||||
// const mainLeftBarHeight = ref(0);
|
||||
|
||||
onMounted(() => {
|
||||
// var mainLeftBar = document.getElementById("mainLeftBar");
|
||||
// mainLeftBarHeight.value = document.documentElement.clientHeight-50-mainLeftBar.offsetParent.offsetTop - 10;
|
||||
|
||||
// getDivHeight()
|
||||
// window.addEventListener('resize', getDivHeight)
|
||||
})
|
||||
// const getDivHeight = () => {
|
||||
// const screenheight = window.innerHeight;
|
||||
// proxy.$refs.mainDiv.style.height = screenheight-140 > 320 ? screenheight-140+'px' : 320+'px';
|
||||
// console.log("height", proxy.$refs.mainDiv.style.height);
|
||||
// // 704 为 头部组件高度 + 底部组件高度
|
||||
// // mainDiv 为需控制高度自适应盒子,通过 ref="mainDiv" 绑定
|
||||
// }
|
||||
|
||||
// 选择的学科 获取实验课程信息
|
||||
// const getExperimentList = (val) => {
|
||||
// console.log(val,'选择的学科,获取实验课程list信息')
|
||||
// // experimentList.value = val;
|
||||
// }
|
||||
// 选择的实验课
|
||||
const getExperimentListItem = (val) => {
|
||||
console.log(val,'选择的实验课程信息')
|
||||
activeExp.value = val;
|
||||
emit('clickExpObj', val)
|
||||
}
|
||||
// 监听实验课程信息
|
||||
watch(() => props.expObj.fileurl, (newVal, oldVal) => {
|
||||
console.log(props.expObj,'科学实验科目')
|
||||
activeExp.value = props.expObj;
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.experiment-page {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.activeExp-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.activeExp-main{
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
|
@ -77,11 +77,6 @@
|
|||
<FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="(currentRow.worktype == '科学实验' || classWorkForm.worktype == '科学实验')&& currentRow.id>0" class="page-center">
|
||||
<div class="experiment-homework">
|
||||
<ExperimentQuestion :expObj="classWorkForm.fileHomeworkList&&classWorkForm.fileHomeworkList[0]" @clickExpObj="getExpObj" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="currentRow.id>0 " class="page-right">
|
||||
<div class="prepare-top" >
|
||||
|
@ -145,7 +140,6 @@ import { editListItem } from '@/hooks/useClassTask'
|
|||
import MyQuestion from '@/views/classTask/newClassTaskAssign/myQuestion/index.vue'
|
||||
import SchoolQuestion from '@/views/classTask/newClassTaskAssign/schoolQuestion/index.vue'
|
||||
import SearchQuestion from '@/views/classTask/newClassTaskAssign/searchQuestion/index.vue'
|
||||
import ExperimentQuestion from "@/views/classTask/newClassTaskAssign/experimentQuestion/index.vue";
|
||||
import whiteboard from '@/components/whiteboard/whiteboard.vue'
|
||||
import FileUpload from "@/components/FileUpload/index.vue";
|
||||
import Right from './Right/index.vue'
|
||||
|
@ -200,7 +194,7 @@ const fileLoading = ref(false); // 常规作业loading
|
|||
|
||||
onMounted(() => {
|
||||
console.log("----onMounted-------")
|
||||
currentRow.value.id = 0
|
||||
currentRow.value = {id:0};
|
||||
if(propsQueryCourseObj){
|
||||
if(JSON.parse(propsQueryCourseObj)){
|
||||
courseObj.textbookId = JSON.parse(propsQueryCourseObj).bookObj // 版本
|
||||
|
@ -235,7 +229,7 @@ const isInToMyQuestion = () => {
|
|||
if(useClassTaskStores.isOpenQuestUploadView){
|
||||
useClassTaskStores.isOpenQuestUploadView = false;
|
||||
|
||||
currentRow.value.id = 1; // 作业设计
|
||||
currentRow.value = {id:1}; // 作业设计
|
||||
activeAptTab.value = "个人题库";
|
||||
//提交内容清空 重置
|
||||
classWorkForm.id = 0;
|
||||
|
@ -264,16 +258,6 @@ watch(() => props.currentCourse, (newVal, oldVal) => {
|
|||
}
|
||||
console.log(newVal,'newval');
|
||||
},{deep:true})
|
||||
|
||||
// ------------科学实验
|
||||
const getExpObj = (obj)=>{
|
||||
// obj:{
|
||||
// fileurl: "https://phet.colorado.edu/sims/html/number-compare/latest/number-compare_zh_CN.html"
|
||||
// label: "数量比较"
|
||||
// subject: "math"
|
||||
// }
|
||||
classWorkForm.fileHomeworkList = [obj];
|
||||
}
|
||||
//---------作业设计---
|
||||
const handleItemClick = (itemName) => {
|
||||
console.log('itemName', itemName);
|
||||
|
@ -282,7 +266,7 @@ const handleItemClick = (itemName) => {
|
|||
return;
|
||||
}
|
||||
|
||||
currentRow.value.id = 1; // 作业设计
|
||||
currentRow.value = {id:1}; // 作业设计
|
||||
/**
|
||||
* 智能推荐?AI设计作业?
|
||||
* 习题训练: 自主搜题 校本题库 个人题库
|
||||
|
@ -325,7 +309,7 @@ const initHomeWork = async()=> {
|
|||
|
||||
const handleNewAllClass = () => {
|
||||
taskTable.value.setCurrentRow({});// 清除表格选中项背景色
|
||||
currentRow.value.id = 0; // 作业设计
|
||||
currentRow.value = {id:0}; // 作业设计
|
||||
//--------
|
||||
classWorkForm.id = 0;
|
||||
classWorkForm.uniquekey = ""; // 作业唯一标识 作业名称
|
||||
|
@ -352,7 +336,7 @@ const handleDelete =() => {
|
|||
return delClasswork(ids.join(','));
|
||||
}).then(() => {
|
||||
taskTable.value.setCurrentRow({});// 清除表格选中项背景色
|
||||
currentRow.value.id = 0; // 作业设计
|
||||
currentRow.value = {id:0}; // 作业设计
|
||||
taskList.value = [];
|
||||
// initHomeWork();
|
||||
setTimeout(() => {
|
||||
|
@ -446,7 +430,7 @@ const handleCurrentChange = (val) => {
|
|||
|
||||
console.log(val,'???????????')
|
||||
if(val && val.id >0 ) {
|
||||
currentRow.value.id = 1;
|
||||
currentRow.value = val;
|
||||
classWorkForm.worktype = val.worktype; //作业类型
|
||||
editListItem(val, courseObj).then((obj) => {
|
||||
if(obj){
|
||||
|
@ -598,32 +582,6 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
|||
fileLoading.value = false
|
||||
}
|
||||
}
|
||||
else if(classWorkForm.worktype === "科学实验"){
|
||||
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验的课程!'});
|
||||
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
||||
cform.entpcourseworklist = JSON.stringify([{'id':-3, 'score': '10'}]);
|
||||
try {
|
||||
console.log(cform,'科学实验')
|
||||
addClassworkReturnId(cform).then((res) => {
|
||||
ElMessage({ type: 'success', message: '作业设计成功!'});
|
||||
// 重置提交表单
|
||||
classWorkForm.worktype = "科学实验";
|
||||
classWorkForm.uniquekey = ''; // props.propsformobj.uniquekey, // 作业唯一标识 作业名称
|
||||
classWorkForm.title = "";
|
||||
classWorkForm.quizlist = [], // 作业习题列表内容
|
||||
|
||||
// 情况选择的资源缓存
|
||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||
classWorkForm.fileHomeworkList = []; // 常规作业list
|
||||
classWorkForm.id = res
|
||||
emits('getData',classWorkForm)
|
||||
// TODO 科学实验 待完善
|
||||
})
|
||||
} finally{
|
||||
//
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 正常新任务
|
||||
var ll = [];
|
||||
|
@ -670,9 +628,9 @@ const handleClassWorkFormQuizRemove = (index) =>{
|
|||
console.log('该清空左侧列表数据了');
|
||||
// 清空左侧 选中的布置列表 并刷新列表
|
||||
if(isShow.value){
|
||||
currentRow.value.id = 1;
|
||||
currentRow.value = {id:1};
|
||||
}else{
|
||||
currentRow.value.id = 0;
|
||||
currentRow.value = {id:0};
|
||||
}
|
||||
initHomeWork();
|
||||
|
||||
|
@ -709,10 +667,7 @@ const editWork = async (cform) =>{
|
|||
}else{
|
||||
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请上传常规作业附件!'});
|
||||
}
|
||||
}else if( classWorkForm.worktype == '科学实验') {
|
||||
if (classWorkForm.fileHomeworkList.length == 0) return ElMessage({ type: 'warning', message: '请选择科学实验科目!'});
|
||||
}
|
||||
else {
|
||||
}else {
|
||||
if (classWorkForm.chooseWorkLists.length == 0) {
|
||||
// 框架梳理
|
||||
ElMessage.error('请先添加作业资源!');
|
||||
|
@ -804,21 +759,13 @@ const editWork = async (cform) =>{
|
|||
// 1.更新作业任务下的课堂展示内容 (这里未做校验, 直接将当前文件对象更新过去)
|
||||
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
||||
}
|
||||
else if (classWorkForm.worktype=='科学实验') { //TODO 注意,fileHomeworkList字段与常规作业共用
|
||||
// 1.更新作业任务下的课堂展示内容 (这里未做校验, 直接将当前文件对象更新过去)
|
||||
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
|
||||
}
|
||||
|
||||
// 3.更新作业任务本身
|
||||
let res = await updateClasswork(cform);
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('更新成功');
|
||||
// 清空左侧 选中的布置列表 并刷新列表
|
||||
if(isShow.value){
|
||||
currentRow.value.id = 1;
|
||||
}else{
|
||||
currentRow.value.id = 0;
|
||||
}
|
||||
currentRow.value = {id:0};
|
||||
initHomeWork();
|
||||
// // 返回上一页
|
||||
// router.back()
|
||||
|
@ -918,11 +865,6 @@ const editWork = async (cform) =>{
|
|||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.experiment-homework{
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.page-right {
|
||||
overflow: hidden;
|
||||
|
|
|
@ -734,10 +734,6 @@ const msgHandle = (msg) => {
|
|||
Homework.win = null
|
||||
window.close() // 关闭窗口
|
||||
break
|
||||
case MsgEnum.HEADS.MSG_pushSreen_experiment: // 实验:
|
||||
Homework.win = null
|
||||
window.close() // 关闭窗口
|
||||
break
|
||||
// case 'TIMAddRecvNewMsgCallback': // 收到新消息 data=[]
|
||||
// {
|
||||
// (data||[]).forEach(o => {
|
||||
|
|
|
@ -1,427 +0,0 @@
|
|||
<template>
|
||||
<div class="login-container">
|
||||
<div class="box-item desc">
|
||||
<div class="welcome">
|
||||
<p>欢迎登录 {{ homeTitle }}</p>
|
||||
</div>
|
||||
<img class="welcome-img" :src="leftBg2" />
|
||||
</div>
|
||||
<div class="box-item login" v-if="isRegister">
|
||||
<WindowTools :is-has-max="false" />
|
||||
<div class="login-title">账号登录</div>
|
||||
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="password" style="margin-bottom: 15px">
|
||||
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<div class="flex mb-5">
|
||||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
||||
</div>
|
||||
|
||||
<el-form-item>
|
||||
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
||||
</el-form-item>
|
||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="box-item login" v-else>
|
||||
<WindowTools :is-has-max="false" />
|
||||
<div class="login-title">账号注册</div>
|
||||
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
||||
<el-form-item label="手机号" prop="username">
|
||||
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
||||
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password" >
|
||||
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
||||
</el-form-item>
|
||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" align-center>
|
||||
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
||||
status="success" />
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="isImg"
|
||||
title="人机验证"
|
||||
width="500"
|
||||
style=" -webkit-app-region: no-drag;"
|
||||
>
|
||||
<span>根据图片回答相关问题1</span>
|
||||
<div style="display: flex;align-items: center;;margin-top:30px">
|
||||
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
||||
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
||||
</div>
|
||||
<div style="display: flex;justify-content: center;margin-top:30px">
|
||||
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--选择学科-->
|
||||
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
||||
<!--注册弹框-->
|
||||
<Register ref="RegModel"></Register>
|
||||
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import leftBg2 from '@/assets/images/login/left-bg2.png'
|
||||
import WindowTools from '@/components/window-tools/index.vue'
|
||||
import SelectSubject from '@/components/select-subject/index.vue'
|
||||
import Register from './components/Register.vue'
|
||||
import { sessionStore } from '@/utils/store'
|
||||
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
||||
|
||||
const { session } = require('@electron/remote')
|
||||
const downloadProp = ref(0)
|
||||
const showDownLoading = ref(false)
|
||||
const { ipcRenderer } = window.electron || {}
|
||||
const formRef = ref()
|
||||
const userStore = useUserStore()
|
||||
const btnLoading = ref(false)
|
||||
const isSubject = ref(false)
|
||||
const RegModel = ref(false)
|
||||
const isRegister = ref(true)
|
||||
const ruleFormRef = ref(null)
|
||||
const codeName=ref('发送验证码')
|
||||
const timer=ref(null)
|
||||
const isImg=ref(false)
|
||||
const isPeopleImg=ref(null)
|
||||
const type=ref(1) // 1注册 2找回密码
|
||||
const resImg = reactive({ imgData: {} });
|
||||
|
||||
//表单
|
||||
const loginForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
rememberMe: false
|
||||
})
|
||||
// 注册表单
|
||||
const ruleForm = reactive({
|
||||
|
||||
})
|
||||
//表单规则
|
||||
const rules = reactive({
|
||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
||||
})
|
||||
|
||||
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||
ipcRenderer.on('update-app-progress', (e, prop) => {
|
||||
downloadProp.value = prop
|
||||
showDownLoading.value = prop !== 100
|
||||
})
|
||||
const gotoreRegister=()=>{
|
||||
codeName.value='发送验证码'
|
||||
if(timer.value){
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
isRegister.value=false
|
||||
}
|
||||
// 刷新
|
||||
const refreshImg=()=>{
|
||||
getCodeImg().then(res=>{
|
||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||
resImg.imgData=res
|
||||
})
|
||||
}
|
||||
// 提交人机验证
|
||||
const sbmitImg=()=>{
|
||||
if(ruleForm.imgCode){
|
||||
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
||||
const { username:username,imgCode:code } = ruleForm
|
||||
const params = {
|
||||
username, code,
|
||||
uuid: resImg.imgData.uuid,
|
||||
source:4
|
||||
}
|
||||
sendcode(params).then(res=>{
|
||||
if(res.code==200){
|
||||
ElMessage.success('短信发送成功')
|
||||
ruleForm.Code=res.data
|
||||
isImg.value=false
|
||||
codeName.value=60
|
||||
timer.value=setInterval(()=>{
|
||||
codeName.value--
|
||||
if(codeName.value==0){
|
||||
codeName.value='发送验证码'
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
|
||||
})
|
||||
}else{
|
||||
ElMessage.error('请根据图片输入验证码')
|
||||
}
|
||||
//
|
||||
}
|
||||
// 发送验证码
|
||||
const sendyzm=()=>{
|
||||
if(ruleForm.username){
|
||||
const pattern = /^1[3-9]\d{9}$/;
|
||||
if( pattern.test(ruleForm.username) ){
|
||||
|
||||
getCodeImg().then(res=>{
|
||||
if(res.code==200){
|
||||
ruleForm.imgCode=null
|
||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||
isImg.value=true
|
||||
resImg.imgData=res
|
||||
// codeName.value=60
|
||||
// timer.value=setInterval(()=>{
|
||||
// codeName.value--
|
||||
// if(codeName.value==0){
|
||||
// codeName.value='发送验证码'
|
||||
// clearInterval(timer.value);
|
||||
// }
|
||||
// },1000)
|
||||
}else{
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}else{
|
||||
ElMessage.error('请输入正确的手机号码')
|
||||
}
|
||||
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
||||
// console.log('res->', res)
|
||||
// })
|
||||
}else{
|
||||
ElMessage.error('请输入手机号码')
|
||||
}
|
||||
}
|
||||
// 打开弹窗
|
||||
const RegisterModel = type => {
|
||||
RegModel.value.OpenModel(type)
|
||||
}
|
||||
//登录
|
||||
const submitForm = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
btnLoading.value = true
|
||||
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.rememberMe) {
|
||||
await setCookie('username', loginForm.username)
|
||||
await setCookie('password', encrypt(loginForm.password))
|
||||
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
||||
} else {
|
||||
// 否则移除
|
||||
await session.defaultSession.clearStorageData({
|
||||
origin: curWinUrl,
|
||||
storages: ['cookies']
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await userStore.login(loginForm)
|
||||
await userStore.getInfo()
|
||||
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
||||
ElMessage.success('登录成功')
|
||||
ipcRenderer && ipcRenderer.send('openMainWindow')
|
||||
} else {
|
||||
isSubject.value = true
|
||||
}
|
||||
} finally {
|
||||
btnLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const isStadium = (user) => {
|
||||
let roles = user.roles
|
||||
return roles.some(item => item.roleKey === 'stadium')
|
||||
}
|
||||
|
||||
const getCookie = async () => {
|
||||
const username = (await getCookieDetail('username'))[0]
|
||||
const password = (await getCookieDetail('password'))[0]
|
||||
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
||||
loginForm.username = username ? username.value : loginForm.username
|
||||
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
||||
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
||||
}
|
||||
|
||||
// 获取cookie
|
||||
const getCookieDetail = (name) => {
|
||||
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
||||
}
|
||||
|
||||
// 设置cookie
|
||||
const setCookie = (name, value) => {
|
||||
// 30天过期
|
||||
let Days = 30
|
||||
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
||||
const cookie = {
|
||||
url: curWinUrl,
|
||||
name,
|
||||
value,
|
||||
expirationDate: times
|
||||
}
|
||||
return session.defaultSession.cookies.set(cookie)
|
||||
}
|
||||
const gotoLogin = () => {
|
||||
codeName.value='发送验证码'
|
||||
if (timer.value){
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||
isRegister.value = true
|
||||
}
|
||||
// 注册
|
||||
const RegisterForm = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
instructorregister(ruleForm).then(res=>{
|
||||
if(res.code==200){
|
||||
ElMessage.success('您已注册成功')
|
||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||
gotoLogin()
|
||||
}else{
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
console.log('submit!')
|
||||
} else {
|
||||
console.log('error submit!', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
localStorage.clear()
|
||||
sessionStore.set('subject', {
|
||||
bookList: null,
|
||||
curBook: null,
|
||||
curNode: null,
|
||||
defaultExpandedKeys: [],
|
||||
subjectTree: []
|
||||
})
|
||||
getCookie()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.login-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
-webkit-app-region: drag;
|
||||
|
||||
.box-item {
|
||||
width: 444px;
|
||||
height: 520px;
|
||||
|
||||
&.desc {
|
||||
background: #ffffff;
|
||||
border-radius: 12px 0px 0px 12px;
|
||||
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
||||
padding: 23px 25px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
background-color: #003b94;
|
||||
}
|
||||
|
||||
&.login {
|
||||
background: #ffffff;
|
||||
border-radius: 0px 12px 12px 0px;
|
||||
padding: 34px 42px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
padding-top: 35px;
|
||||
|
||||
p {
|
||||
color: #ffffff;
|
||||
line-height: 25px;
|
||||
letter-spacing: 0.26px;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-img {
|
||||
margin-top: 20px;
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
color: #1e1e1e;
|
||||
margin-bottom: 35px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
.captcha-input {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.captcha-img {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 350px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
line-height: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-tool {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
span {
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
</style>
|
|
@ -1,13 +1,427 @@
|
|||
<template>
|
||||
<ycLogin v-if="buildMode === 'yc'||buildMode === 'yc2'">
|
||||
</ycLogin>
|
||||
<defultLogin v-else>
|
||||
</defultLogin>
|
||||
<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 ycLogin from './yc-login.vue'
|
||||
import defultLogin from './defult-login.vue'
|
||||
const buildMode = import.meta.env.MODE
|
||||
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,463 +0,0 @@
|
|||
<template>
|
||||
<div class="login-container">
|
||||
<div class="login-yc">
|
||||
<img class="welcome-img" :src="buildMode === 'yc2'?leftBg2:leftBg1" />
|
||||
</div>
|
||||
<div class="box-item login" v-if="isRegister">
|
||||
<WindowTools :is-has-max="false" />
|
||||
<div style="display: flex;justify-content: center;"><img class="title-logo" :src="yclogo" /></div>
|
||||
<div class="login-title">永川中小学</div>
|
||||
<div class="login-title2">{{buildMode === 'yc2'?'虚拟仿真AI实训教学管理系统':'人工智能赋能科学素养与劳动技能系统'}}</div>
|
||||
<el-form ref="formRef" class="login-form" :model="loginForm" :rules="rules" size="large">
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="password" style="margin-bottom: 15px">
|
||||
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<div class="flex mb-5">
|
||||
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
|
||||
<!-- <el-checkbox >阅读并同意《xxx》</el-checkbox> -->
|
||||
</div>
|
||||
|
||||
<el-form-item style="margin-bottom: 20px">
|
||||
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
|
||||
</el-form-item>
|
||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoreRegister">注册账号</a>
|
||||
</div>
|
||||
<div class="title-bottom">
|
||||
重庆市永川区教育委员会
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="box-item login" v-else>
|
||||
<WindowTools :is-has-max="false" />
|
||||
<div class="login-title">账号注册</div>
|
||||
<el-form ref="ruleFormRef" class="login-form" :model="ruleForm" label-width="auto" :rules="rules" size="large">
|
||||
<el-form-item label="手机号" prop="username">
|
||||
<el-input v-model="ruleForm.username" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码" prop="smsCode" style="display: flex">
|
||||
<el-input style="width:185px" v-model="ruleForm.smsCode" placeholder="请输入验证码" /><el-button style="margin-left:10px;width:100px" :disabled="codeName=='发送验证码'?false:true" type="primary" @click="sendyzm">{{ codeName }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password" >
|
||||
<el-input autocomplete="on" type="password" v-model="ruleForm.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button class="btn" type="primary" @click="RegisterForm(ruleFormRef)">立即注册</el-button>
|
||||
</el-form-item>
|
||||
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
|
||||
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="gotoLogin"> 《 返回登录 </a>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
|
||||
:close-on-press-escape="false" align-center>
|
||||
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
|
||||
status="success" />
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
v-model="isImg"
|
||||
title="人机验证"
|
||||
width="500"
|
||||
style=" -webkit-app-region: no-drag;"
|
||||
>
|
||||
<span>根据图片回答相关问题1</span>
|
||||
<div style="display: flex;align-items: center;;margin-top:30px">
|
||||
<img :src="isPeopleImg" style="width:200px;height:60px;cursor: pointer;" alt="" srcset="" @click="refreshImg">
|
||||
<el-input v-model="ruleForm.imgCode" style="width: 250px;height:40px;margin-left:20px" placeholder="请根据图片填入答案" />
|
||||
</div>
|
||||
<div style="display: flex;justify-content: center;margin-top:30px">
|
||||
<el-button type="primary" @click="sbmitImg">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--选择学科-->
|
||||
<SelectSubject v-model="isSubject" :login-data="loginForm" />
|
||||
<!--注册弹框-->
|
||||
<Register ref="RegModel"></Register>
|
||||
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import WindowTools from '@/components/window-tools/index.vue'
|
||||
import SelectSubject from '@/components/select-subject/index.vue'
|
||||
import Register from './components/Register.vue'
|
||||
import { sessionStore } from '@/utils/store'
|
||||
import {sendcode,instructorregister,getCodeImg} from '@/api/login'
|
||||
import yclogo from '@/assets/images/login/yc-logo.png'
|
||||
import leftBg1 from '@/assets/images/login/ycpeitu.png'
|
||||
import leftBg2 from '@/assets/images/login/ycpeitu2.jpg'
|
||||
const { session } = require('@electron/remote')
|
||||
const buildMode = import.meta.env.MODE
|
||||
const downloadProp = ref(0)
|
||||
const showDownLoading = ref(false)
|
||||
const { ipcRenderer } = window.electron || {}
|
||||
const formRef = ref()
|
||||
const userStore = useUserStore()
|
||||
const btnLoading = ref(false)
|
||||
const isSubject = ref(false)
|
||||
const RegModel = ref(false)
|
||||
const isRegister = ref(true)
|
||||
const ruleFormRef = ref(null)
|
||||
const codeName=ref('发送验证码')
|
||||
const timer=ref(null)
|
||||
const isImg=ref(false)
|
||||
const isPeopleImg=ref(null)
|
||||
const type=ref(1) // 1注册 2找回密码
|
||||
const resImg = reactive({ imgData: {} });
|
||||
|
||||
//表单
|
||||
const loginForm = reactive({
|
||||
username: '',
|
||||
password: '',
|
||||
rememberMe: false
|
||||
})
|
||||
// 注册表单
|
||||
const ruleForm = reactive({
|
||||
|
||||
})
|
||||
//表单规则
|
||||
const rules = reactive({
|
||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||
smsCode: [{ required: true, trigger: 'blur', message: '请输入您的验证码' }],
|
||||
})
|
||||
|
||||
let curWinUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||
ipcRenderer.on('update-app-progress', (e, prop) => {
|
||||
downloadProp.value = prop
|
||||
showDownLoading.value = prop !== 100
|
||||
})
|
||||
const gotoreRegister=()=>{
|
||||
codeName.value='发送验证码'
|
||||
if(timer.value){
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
isRegister.value=false
|
||||
}
|
||||
// 刷新
|
||||
const refreshImg=()=>{
|
||||
getCodeImg().then(res=>{
|
||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||
resImg.imgData=res
|
||||
})
|
||||
}
|
||||
// 提交人机验证
|
||||
const sbmitImg=()=>{
|
||||
if(ruleForm.imgCode){
|
||||
// {mobile:ruleForm.phoneNumber,code:ruleForm.imgCode,uuid:resImg.imgData.uuid}
|
||||
const { username:username,imgCode:code } = ruleForm
|
||||
const params = {
|
||||
username, code,
|
||||
uuid: resImg.imgData.uuid,
|
||||
source:4
|
||||
}
|
||||
sendcode(params).then(res=>{
|
||||
if(res.code==200){
|
||||
ElMessage.success('短信发送成功')
|
||||
ruleForm.Code=res.data
|
||||
isImg.value=false
|
||||
codeName.value=60
|
||||
timer.value=setInterval(()=>{
|
||||
codeName.value--
|
||||
if(codeName.value==0){
|
||||
codeName.value='发送验证码'
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
|
||||
})
|
||||
}else{
|
||||
ElMessage.error('请根据图片输入验证码')
|
||||
}
|
||||
//
|
||||
}
|
||||
// 发送验证码
|
||||
const sendyzm=()=>{
|
||||
if(ruleForm.username){
|
||||
const pattern = /^1[3-9]\d{9}$/;
|
||||
if( pattern.test(ruleForm.username) ){
|
||||
|
||||
getCodeImg().then(res=>{
|
||||
if(res.code==200){
|
||||
ruleForm.imgCode=null
|
||||
isPeopleImg.value='data:image/jpg;base64,'+res.img
|
||||
isImg.value=true
|
||||
resImg.imgData=res
|
||||
// codeName.value=60
|
||||
// timer.value=setInterval(()=>{
|
||||
// codeName.value--
|
||||
// if(codeName.value==0){
|
||||
// codeName.value='发送验证码'
|
||||
// clearInterval(timer.value);
|
||||
// }
|
||||
// },1000)
|
||||
}else{
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
}else{
|
||||
ElMessage.error('请输入正确的手机号码')
|
||||
}
|
||||
// captchaImg({mobile:ruleForm.phoneNumber}).then(res=>{
|
||||
// console.log('res->', res)
|
||||
// })
|
||||
}else{
|
||||
ElMessage.error('请输入手机号码')
|
||||
}
|
||||
}
|
||||
// 打开弹窗
|
||||
const RegisterModel = type => {
|
||||
RegModel.value.OpenModel(type)
|
||||
}
|
||||
//登录
|
||||
const submitForm = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
btnLoading.value = true
|
||||
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.rememberMe) {
|
||||
await setCookie('username', loginForm.username)
|
||||
await setCookie('password', encrypt(loginForm.password))
|
||||
await setCookie('rememberMe', loginForm.rememberMe.toString())
|
||||
} else {
|
||||
// 否则移除
|
||||
await session.defaultSession.clearStorageData({
|
||||
origin: curWinUrl,
|
||||
storages: ['cookies']
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await userStore.login(loginForm)
|
||||
await userStore.getInfo()
|
||||
if (userStore.user.edustage || userStore.user.edusubject || isStadium(userStore.user)) {
|
||||
ElMessage.success('登录成功')
|
||||
ipcRenderer && ipcRenderer.send('openMainWindow')
|
||||
} else {
|
||||
isSubject.value = true
|
||||
}
|
||||
} finally {
|
||||
btnLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const isStadium = (user) => {
|
||||
let roles = user.roles
|
||||
return roles.some(item => item.roleKey === 'stadium')
|
||||
}
|
||||
|
||||
const getCookie = async () => {
|
||||
const username = (await getCookieDetail('username'))[0]
|
||||
const password = (await getCookieDetail('password'))[0]
|
||||
const rememberMe = (await getCookieDetail('rememberMe'))[0]
|
||||
loginForm.username = username ? username.value : loginForm.username
|
||||
loginForm.password = password ? decrypt(password.value) : loginForm.password
|
||||
loginForm.rememberMe = rememberMe ? Boolean(rememberMe.value) : false
|
||||
}
|
||||
|
||||
// 获取cookie
|
||||
const getCookieDetail = (name) => {
|
||||
return session.defaultSession.cookies.get({ url: curWinUrl, name })
|
||||
}
|
||||
|
||||
// 设置cookie
|
||||
const setCookie = (name, value) => {
|
||||
// 30天过期
|
||||
let Days = 30
|
||||
let times = Math.round(Date.now() / 1000) + Days * 24 * 60 * 60
|
||||
const cookie = {
|
||||
url: curWinUrl,
|
||||
name,
|
||||
value,
|
||||
expirationDate: times
|
||||
}
|
||||
return session.defaultSession.cookies.set(cookie)
|
||||
}
|
||||
const gotoLogin = () => {
|
||||
codeName.value='发送验证码'
|
||||
if (timer.value){
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||
isRegister.value = true
|
||||
}
|
||||
// 注册
|
||||
const RegisterForm = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
instructorregister(ruleForm).then(res=>{
|
||||
if(res.code==200){
|
||||
ElMessage.success('您已注册成功')
|
||||
if (ruleFormRef.value) ruleFormRef.value.resetFields()
|
||||
gotoLogin()
|
||||
}else{
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
})
|
||||
console.log('submit!')
|
||||
} else {
|
||||
console.log('error submit!', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
localStorage.clear()
|
||||
sessionStore.set('subject', {
|
||||
bookList: null,
|
||||
curBook: null,
|
||||
curNode: null,
|
||||
defaultExpandedKeys: [],
|
||||
subjectTree: []
|
||||
})
|
||||
getCookie()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.login-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
-webkit-app-region: drag;
|
||||
|
||||
.login-yc{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.box-item {
|
||||
width: 370px;
|
||||
height: 520px;
|
||||
|
||||
&.desc {
|
||||
background: #ffffff;
|
||||
border-radius: 12px 0px 0px 12px;
|
||||
box-shadow: 0px 16px 73px 8px rgba(203, 203, 203, 0.2);
|
||||
padding: 23px 25px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
background-color: #003b94;
|
||||
}
|
||||
|
||||
&.login {
|
||||
background: #ffffff;
|
||||
border-radius: 0px 12px 12px 0px;
|
||||
padding: 34px 42px;
|
||||
position: relative;
|
||||
.title-logo{
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome {
|
||||
padding-top: 35px;
|
||||
|
||||
p {
|
||||
color: #ffffff;
|
||||
line-height: 25px;
|
||||
letter-spacing: 0.26px;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-img {
|
||||
margin-top: 20px;
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
color: #1e1e1e;
|
||||
margin-bottom: 35px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
color: #1e1e1e;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 5px;
|
||||
font-width: bold;
|
||||
}
|
||||
|
||||
.login-title2 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
.captcha-input {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.captcha-img {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.title-bottom{
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 350px;
|
||||
height: 50px;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
line-height: 50px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-tool {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
span {
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
</style>
|
|
@ -98,13 +98,10 @@ import progressDialog from '@/views/teachingDesign/container/progress-dialog.vue
|
|||
import msgUtils from "@/plugins/modal";
|
||||
import * as commUtils from "@/utils/comm";
|
||||
import * as Api_server from "@/api/apiService"; // 学科名字文生图
|
||||
import useClassTaskStore from '@/store/modules/classTask'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore().user // 用户信息
|
||||
const currentNode = ref({})
|
||||
const refs = ref([]);
|
||||
const classTaskStore = useClassTaskStore();
|
||||
|
||||
const collectRef = (key) => {
|
||||
return (el) => {
|
||||
|
@ -516,9 +513,7 @@ const changeClass = async (type, row, other) => {
|
|||
}
|
||||
|
||||
// 页面加载
|
||||
onMounted(async () => {
|
||||
// 更新第三方题型题类
|
||||
await classTaskStore.initJYInfo(userStore);
|
||||
onMounted(() => {
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
@ -126,17 +126,11 @@
|
|||
<span>下载</span>
|
||||
</el-button>
|
||||
</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)">
|
||||
<i class="iconfont icon-jiahao"></i>
|
||||
<span>加入课件</span>
|
||||
</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 class="item-popover-item">
|
||||
<el-button text @click="moveSmarttalkFun(item)">
|
||||
|
@ -187,7 +181,7 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null,'on-importPPT': null },
|
||||
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null },
|
||||
data() {
|
||||
return {
|
||||
listenList: [],
|
||||
|
@ -223,9 +217,6 @@ export default {
|
|||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
importPPT(item) {
|
||||
this.$emit('on-importPPT', item)
|
||||
},
|
||||
downloadFile(item) {
|
||||
ipcRenderer.send('save-as', item.fileFullPath, item.fileShowName)
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="createAIPPT">新建文枢课件</el-dropdown-item>
|
||||
<el-dropdown-item @click="aiTOPPT">AI一键生成</el-dropdown-item>
|
||||
<el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item>
|
||||
<!-- <el-dropdown-item @click="openGridPic">打开宫格</el-dropdown-item>-->
|
||||
<el-dropdown-item @click="openFilePicker">导入PPT</el-dropdown-item>
|
||||
<input type="file" ref="fileInput" style="display: none;" @change="handleFileChange" accept="application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation">
|
||||
</el-dropdown-menu>
|
||||
|
@ -99,7 +99,6 @@
|
|||
@on-delete="deleteTalk"
|
||||
@on-set="openSet"
|
||||
@on-delhomework="delhomework"
|
||||
@on-importPPT="importPPT"
|
||||
@on-filearg="isOpenHomework = true"
|
||||
>
|
||||
<el-checkbox v-if="!item.uniquekey" label="" :value="item" />
|
||||
|
@ -195,7 +194,7 @@ import outLink from '@/utils/linkConfig'
|
|||
import { createWindow, sessionStore, getAppInstallUrl, ipcMsgSend } from '@/utils/tool'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { delClasswork, listEntpcourse } from '@/api/teaching/classwork'
|
||||
import { updateClasscourse, getClasscourse } from '@/api/teaching/classcourse'
|
||||
import { updateClasscourse } from '@/api/teaching/classcourse'
|
||||
import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage'
|
||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||
import { editListItem } from '@/hooks/useClassTask'
|
||||
|
@ -390,13 +389,12 @@ export default {
|
|||
if (res.code == 200) {
|
||||
const resource = res.data
|
||||
if (resource.filetype != 'aippt') this.$refs.calssRef.open(aptFileId, row)
|
||||
else { // aippt 继续上课
|
||||
else {
|
||||
if (!!sessionStore.get('curr.classcourse')) return ElMessage.warning('公屏已打开,请勿重复操作')
|
||||
const { data:classcourse } = await getClasscourse(row.id) // 获取最新课堂信息
|
||||
const msgEl = ElMessage.warning({message:'正在打开公屏,请稍后...',duration: 0})
|
||||
setTimeout(()=>{
|
||||
msgEl.close()
|
||||
this.openPublicScreen('class', resource, classcourse||row) // 打开公屏-窗口
|
||||
this.openPublicScreen('class', resource, row) // 打开公屏-窗口
|
||||
}, 2000)
|
||||
}
|
||||
} else ElMessage.error(res.msg||'获取课件信息失败')
|
||||
|
@ -556,15 +554,6 @@ export default {
|
|||
progDownFile(e, 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() {
|
||||
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
|
||||
this.currentFileList.unshift(res.resData)
|
||||
|
@ -583,7 +572,7 @@ export default {
|
|||
console.log('文件名:', file.name);
|
||||
console.log('文件类型:', file.type);
|
||||
console.log('文件大小:', file.size);
|
||||
this.createAIPPTByFile(file, this.currentNode.itemtitle + '.aippt')
|
||||
this.createAIPPTByFile(file)
|
||||
}
|
||||
},
|
||||
async toRousrceUrl(o) {
|
||||
|
@ -629,7 +618,7 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
async createAIPPTByFile(file,fileShowName) {
|
||||
async createAIPPTByFile(file) {
|
||||
this.pgDialog.visible = true
|
||||
this.pgDialog.pg.percentage = 0
|
||||
const resPptJson = await PPTXFileToJson(file)
|
||||
|
@ -675,7 +664,7 @@ export default {
|
|||
...this.uploadData,
|
||||
fileId: slideid,
|
||||
fileFlag: 'aippt',
|
||||
fileShowName: fileShowName
|
||||
fileShowName: this.currentNode.itemtitle + '.aippt'
|
||||
}).then(async (res) => {
|
||||
|
||||
const resSlides = slides.map(({id, ...slide}) => JSON.stringify(slide))
|
||||
|
|
|
@ -92,9 +92,7 @@ import * as API_entpcourse from '@/api/education/entpcourse' // 相关api
|
|||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||
import * as Api_server from '@/api/apiService' // 相关api
|
||||
import * as API_smarttalk from '@/api/file' // 文件相关api
|
||||
import msgUtils from '@/plugins/modal'
|
||||
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||
import { createWindow } from '@/utils/tool' // 消息工具
|
||||
import msgUtils from '@/plugins/modal' // 消息工具
|
||||
|
||||
const userStore = useUserStore()
|
||||
const pptDialog = ref(false)
|
||||
|
@ -119,7 +117,7 @@ const pgDialog = reactive({ // 弹窗-进度条
|
|||
}
|
||||
})
|
||||
|
||||
const curMode = ref(2)
|
||||
const curMode = ref(1)
|
||||
const modeOptions = ref([
|
||||
{
|
||||
label: '教学大模型',
|
||||
|
@ -348,20 +346,13 @@ const addAiPPT = async (res) => {
|
|||
const parentid = await HTTP_SERVER_API('addEntpcoursefile', p_params)
|
||||
if (!!parentid ?? null) { // 生成内容幻灯片
|
||||
// 生成备课资源-Smarttalk
|
||||
const smarttalk = await HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
||||
HTTP_SERVER_API('addSmarttalk', { fileId: parentid })
|
||||
if (slides.length > 0) {
|
||||
const resSlides = slides.map(({ id, ...slide }) => JSON.stringify(slide))
|
||||
const params = { parentid, filetype: 'slide', title: '', slides: resSlides }
|
||||
const res_3 = await HTTP_SERVER_API('batchAddNew', params)
|
||||
if (res_3 && res_3.code == 200) {
|
||||
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 {
|
||||
msgUtils.msgWarning('生成PPT课件失败')
|
||||
}
|
||||
|
@ -370,20 +361,7 @@ const addAiPPT = async (res) => {
|
|||
})
|
||||
}
|
||||
|
||||
const openPublicScreen = (type, resource, currData)=> {
|
||||
sessionStore.set('curr.resource', resource) // 缓存当前资源信息
|
||||
if (type=='edit') sessionStore.set('curr.smarttalk', currData) // 缓存当前文件smarttalk
|
||||
else sessionStore.set('curr.classcourse', currData) // 缓存当前当前上课
|
||||
createWindow('open-win', {
|
||||
url: '/pptist', // 窗口关闭时,清除缓存
|
||||
close: () => {
|
||||
sessionStore.set('curr.resource', null) // 清除缓存
|
||||
if (type=='edit') {
|
||||
sessionStore.set('curr.smarttalk', null) // 清除缓存
|
||||
} else sessionStore.set('curr.classcourse', null) // 清除缓存
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const isEdit = ref(false)
|
||||
// 当前操作的索引
|
||||
const curIndex = ref(-1)
|
||||
|
|
Loading…
Reference in New Issue