|
|
|
<template>
|
|
|
|
<div v-show="loaded">
|
|
|
|
<div class="header" :class="{ hh: $config.isHh }">
|
|
|
|
<img v-if="$config.isHh" src="@/assets/images/logo-hh.png" alt="" class="logo">
|
|
|
|
<p v-else>{{ curriculumName }}</p>
|
|
|
|
<p v-if="third === 'ai'">账号:{{ account }};密码:112233aa</p>
|
|
|
|
<el-button class="back btn" type="primary" @click="back">退出实验</el-button>
|
|
|
|
</div>
|
|
|
|
<template v-if="!notAllowed">
|
|
|
|
<iframe v-if="third" class="AI" :src="iframeSrc" frameborder="0" width="100%"></iframe>
|
|
|
|
<template v-else>
|
|
|
|
<div class="top">
|
|
|
|
<div class="language">
|
|
|
|
<p v-if="$config.isHh" style="font-size: 18px">{{ $config.title }}</p>
|
|
|
|
<p>编程语言</p>
|
|
|
|
<el-select v-model="language" @change="languageChange">
|
|
|
|
<el-option v-for="(item, i) in languages" :key="i" :value="item.name"></el-option>
|
|
|
|
</el-select>
|
|
|
|
|
|
|
|
<el-button v-if="language === 'vscode'" class="open-vs" type="primary" size="small"
|
|
|
|
@click="openVscode">打开Vscode新窗口</el-button>
|
|
|
|
</div>
|
|
|
|
<div class="inline-center">
|
|
|
|
<el-tooltip class="item" effect="dark" content="支持导入其它数据用于实验,总上传的文件大小不可以超过10M" placement="bottom">
|
|
|
|
<i class="info el-icon-warning" style="margin-right: 10px"></i>
|
|
|
|
</el-tooltip>
|
|
|
|
<el-button type="primary" size="small" icon="el-icon-document" @click="toData">我的数据</el-button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tab">
|
|
|
|
<el-tabs v-model="curTab" type="card" @tab-click="judChange">
|
|
|
|
<el-tab-pane v-for="(item, i) in workbench" :key="item.judgmentId" :label="item.name"
|
|
|
|
:value="item.judgmentId">
|
|
|
|
<codemirror v-if="language !== 'vscode'" :ref="'code' + i" :key="codeKey" :projectId.sync="projectId"
|
|
|
|
:systemId.sync="systemId" :code.sync="item.code" :finalCode.sync="item.finalCode"
|
|
|
|
:judgmentId="item.judgmentId" :codeId.sync="item.codeId" :answer.sync="item.answer"
|
|
|
|
:retResult.sync="item.retResult" :photoUrl.sync="item.photoUrl" :index="i" :curTab.sync="curTab"
|
|
|
|
:modelIsShow.sync="modelIsShow"></codemirror>
|
|
|
|
<iframe v-else class="vscode" :src="Config.vscodeUrl" frameborder="0" width="100%"></iframe>
|
|
|
|
</el-tab-pane>
|
|
|
|
</el-tabs>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<div class="menu">
|
|
|
|
<testPanel @tell="setPoints" @recoveryCode="recoveryCode" ref="mainindex" :workbench.sync="workbench">
|
|
|
|
</testPanel>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="isSubmit" class="mask"></div>
|
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import newmain from "../util/newMain"
|
|
|
|
import Util from '@/util'
|
|
|
|
import testPanel from "../components/TestPanel"
|
|
|
|
import codemirror from "../components/codemirror"
|
|
|
|
import Cookie from 'js-cookie'
|
|
|
|
import { Loading } from 'element-ui'
|
|
|
|
import Config from '@/config'
|
|
|
|
export default {
|
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
Config,
|
|
|
|
third: Cookie.get('admin-third'), // 第三方平台用iframe嵌入
|
|
|
|
iframeSrc: '',
|
|
|
|
isSubmit: Cookie.get('admin-isSubmit') == 'true' ? true : false, // 是否提交的标识
|
|
|
|
loaded: false, // 页面是否加载完的标识,页面默认隐藏,一进来先显示加载条,接口加载完后再显示页面,不然一开始会一闪而过没有样式的页面
|
|
|
|
loadIns: null, // loading实例
|
|
|
|
competitionId: Cookie.get('admin-competitionId'),
|
|
|
|
fromManager: Cookie.get('admin-fromManager'), // 是否是从教师端进入
|
|
|
|
courseId: Cookie.get('admin-courseId'), // 课程id
|
|
|
|
curriculumName: Cookie.get('admin-curriculumName') ? decodeURIComponent(Cookie.get('admin-curriculumName')) : 'python', // 课程名称
|
|
|
|
assessmentId: Cookie.get('admin-assessmentId'), // 考核id
|
|
|
|
mallId: Cookie.get('admin-mallId'),
|
|
|
|
language: Cookie.get('admin-language') || 'python3.7.9', // 编程语言
|
|
|
|
projectId: '',
|
|
|
|
systemId: '',
|
|
|
|
modelIsShow: false, // 导入模型按钮是否显示
|
|
|
|
projectPermissions: 0, // 项目权限(0、练习 1、考核 2、竞赛)
|
|
|
|
languages: [
|
|
|
|
{
|
|
|
|
name: 'python3.7.9'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'python3.9'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'python3.10.9'
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'python3.12.4'
|
|
|
|
},
|
|
|
|
// {
|
|
|
|
// name: 'vscode'
|
|
|
|
// },
|
|
|
|
],
|
|
|
|
curTab: '', // 选中后绑定的对象
|
|
|
|
workbench: [], // 判分点切换列表
|
|
|
|
codeKey: 1, // 编辑器索引
|
|
|
|
notAllowed: 0,
|
|
|
|
account: '',
|
|
|
|
};
|
|
|
|
},
|
|
|
|
components: {
|
|
|
|
codemirror,
|
|
|
|
testPanel
|
|
|
|
},
|
|
|
|
mounted () {
|
|
|
|
if (this.third) {
|
|
|
|
this.language = 'vscode'
|
|
|
|
this.third === 'ai' && this.handleAI()
|
|
|
|
this.iframeSrc = this.third === 'ai' ? 'https://ai.huorantech.cn/' : 'https://lowcode.izhixinyun.com/'
|
|
|
|
document.body.style.overflow = 'hidden'
|
|
|
|
this.loaded = true
|
|
|
|
} else {
|
|
|
|
Cookie.set('admin-language', 'python3.7.9')
|
|
|
|
|
|
|
|
// const opened = +localStorage.getItem('opened')
|
|
|
|
// if (opened) {
|
|
|
|
// localStorage.setItem('opened', opened + 1)
|
|
|
|
// this.$alert('我们注意到您当前已尝试打开多个实验页面。为保证实验的公平性和诚信,系统仅允许单个实验页面处于活跃状态。', '提示', {
|
|
|
|
// confirmButtonText: '退出当前页面',
|
|
|
|
// showClose: false,
|
|
|
|
// beforeClose: () => {
|
|
|
|
// Util.exit()
|
|
|
|
// },
|
|
|
|
// })
|
|
|
|
// } else {
|
|
|
|
// this.notAllowed = 0
|
|
|
|
// localStorage.setItem('opened', 1)
|
|
|
|
// }
|
|
|
|
this.notAllowed = 0
|
|
|
|
|
|
|
|
document.onkeydown = function (event) {
|
|
|
|
var e = event || window.event || arguments.callee.caller.arguments[0];
|
|
|
|
|
|
|
|
if (e && e.keyCode == 123) {
|
|
|
|
e.returnValue = false;
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.loadIns = Loading.service({
|
|
|
|
background: 'rgba(255, 255, 255, .1)'
|
|
|
|
})
|
|
|
|
//兄弟组件传值
|
|
|
|
newmain.$on("isSubmit", isSubmit => {
|
|
|
|
this.isSubmit = isSubmit
|
|
|
|
})
|
|
|
|
}
|
|
|
|
this.autoLogout()
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
// 给ai平台添加账号
|
|
|
|
async handleAI () {
|
|
|
|
const res = await this.$get(`${this.api.getTheMostRecentlyRunProject}`, {
|
|
|
|
ai: 1,
|
|
|
|
cid: Cookie.get('admin-courseId')
|
|
|
|
})
|
|
|
|
if (res.account) {
|
|
|
|
this.account = res.account
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// 获取导入模型按钮展示状态
|
|
|
|
getModelStatus (systemId) {
|
|
|
|
this.$post(`${this.api.displayListOrNotByStudent}?systemId=${systemId}`).then(res => {
|
|
|
|
this.modelIsShow = res.studentSideShowsTheStatus == 'true' ? true : false
|
|
|
|
}).catch(res => { })
|
|
|
|
},
|
|
|
|
// 编程语言选择回调
|
|
|
|
languageChange (id) {
|
|
|
|
Cookie.set('admin-language', id)
|
|
|
|
this.$refs.mainindex.reportVisible = false
|
|
|
|
},
|
|
|
|
// 打开Vscode新窗口
|
|
|
|
openVscode () {
|
|
|
|
window.open(Config.vscodeUrl)
|
|
|
|
},
|
|
|
|
// 跳转我的数据
|
|
|
|
toData () {
|
|
|
|
this.$router.push('/data')
|
|
|
|
},
|
|
|
|
// 长时间未点击页面,就自动退出页面
|
|
|
|
autoLogout () {
|
|
|
|
let lastTime = new Date().getTime()
|
|
|
|
let logout = false
|
|
|
|
// 页面点击后赋值当前时间
|
|
|
|
document.onmousedown = () => {
|
|
|
|
lastTime = new Date().getTime()
|
|
|
|
}
|
|
|
|
// 每秒钟判断一次,如果当前时间距离上次点击页面的试卷超过了设置的时间,就退出登录
|
|
|
|
setInterval(() => {
|
|
|
|
if ((new Date().getTime() - lastTime) > this.$config.autoLogoutTime) {
|
|
|
|
logout || this.$message.error('用户登录过期,请重新登录')
|
|
|
|
logout = true
|
|
|
|
setTimeout(Util.exit, 1500)
|
|
|
|
}
|
|
|
|
}, 1000)
|
|
|
|
},
|
|
|
|
// 判分规则切换
|
|
|
|
judChange () {
|
|
|
|
this.$nextTick(_ => {
|
|
|
|
const code = this.$refs['code' + this.curTab][0].$refs.codemirror.codemirror // 获取codemirror实例
|
|
|
|
code.focus() // 编辑器聚焦
|
|
|
|
code.setCursor(code.lineCount(), 0) // 焦点移动至最后面
|
|
|
|
})
|
|
|
|
},
|
|
|
|
// 重置编辑器
|
|
|
|
recoveryCode (curTab = '0') {
|
|
|
|
this.curTab = curTab
|
|
|
|
this.codeKey++
|
|
|
|
},
|
|
|
|
// 退出实验
|
|
|
|
back () {
|
|
|
|
Util.exit()
|
|
|
|
},
|
|
|
|
// 赋值项目id、项目列表
|
|
|
|
setPoints (projectId, systemId, workbench) {
|
|
|
|
this.projectId = projectId
|
|
|
|
this.systemId = systemId
|
|
|
|
this.workbench = workbench
|
|
|
|
},
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
[v-cloak] {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.header {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
height: 58px;
|
|
|
|
line-height: 58px;
|
|
|
|
background-color: #f8f8f8;
|
|
|
|
|
|
|
|
&.hh {
|
|
|
|
padding: 10px 0;
|
|
|
|
line-height: normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
p {
|
|
|
|
margin-left: 18px;
|
|
|
|
font-size: 20px;
|
|
|
|
color: rgba(51, 51, 51, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo {
|
|
|
|
width: 200px;
|
|
|
|
margin-left: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.back {
|
|
|
|
padding: 23px 50px;
|
|
|
|
border: none;
|
|
|
|
border-radius: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.AI {
|
|
|
|
height: calc(100vh - 58px);
|
|
|
|
}
|
|
|
|
|
|
|
|
/deep/.top {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
height: 60px;
|
|
|
|
padding: 0 15px;
|
|
|
|
line-height: 60px;
|
|
|
|
|
|
|
|
.language {
|
|
|
|
display: inline-flex;
|
|
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
p {
|
|
|
|
font-size: 16px;
|
|
|
|
margin-right: 15px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-input {
|
|
|
|
width: 200px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-input .el-input__inner {
|
|
|
|
border-radius: 30px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.open-vs {
|
|
|
|
margin-left: 20px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.vscode {
|
|
|
|
height: calc(100vh - 186px);
|
|
|
|
}
|
|
|
|
|
|
|
|
.menu {
|
|
|
|
position: relative;
|
|
|
|
z-index: 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
::v-deep .el-dialog--center {
|
|
|
|
width: 400px;
|
|
|
|
}
|
|
|
|
|
|
|
|
::v-deep .el-dialog__headerbtn .el-icon-close:before {
|
|
|
|
padding: 3px;
|
|
|
|
border-radius: 50%;
|
|
|
|
}
|
|
|
|
|
|
|
|
/deep/.tab {
|
|
|
|
height: 50px;
|
|
|
|
line-height: 50px;
|
|
|
|
|
|
|
|
.el-tabs__header {
|
|
|
|
margin-bottom: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-tabs__item.is-active {
|
|
|
|
color: #333;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-icon-circle-plus-outline:before {
|
|
|
|
font-size: 16px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-tabs--card>.el-tabs__header {
|
|
|
|
border-bottom: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-tabs--card>.el-tabs__header .el-tabs__nav {
|
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.el-tabs--card>.el-tabs__header .el-tabs__item {
|
|
|
|
border-left: none;
|
|
|
|
border-bottom: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.info {
|
|
|
|
color: #bfbfbf;
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
opacity: 0.9;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.mask {
|
|
|
|
z-index: 999;
|
|
|
|
position: absolute;
|
|
|
|
top: 58px;
|
|
|
|
left: 0;
|
|
|
|
bottom: 0;
|
|
|
|
right: 0;
|
|
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
|
|
}
|
|
|
|
</style>
|