添加vscode

openf12 V2.1.5
yujialong 1 year ago
parent f1d56abefe
commit 2599f0e6f3
  1. 251
      src/components/TestPanel.vue
  2. 12
      src/components/codemirror.vue
  3. 57
      src/components/quill/index.vue
  4. 4
      src/config/index.js
  5. 14
      src/store/index.js
  6. 38
      src/styles/common.scss
  7. 14
      src/views/Home.vue

@ -44,6 +44,8 @@
</div>
</div>
<div>
<el-button @click="toggleReport"
v-if="$parent.language && !isSubmit && !competitionId">填写实验报告</el-button>
<el-button @click="toReport"
v-if="isSubmit && !competitionId">查看实验报告</el-button>
<el-button class="reload"
@ -56,7 +58,42 @@
</div>
</div>
</el-header>
<el-container>
<div class="report-wrap"
v-if="reportVisible">
<i class="el-icon-caret-top close-report"></i>
<el-table class="report-table"
:data="taskList"
:max-height="tableHeight">
<el-table-column prop="name"
label="判分点"
width="210"
align="center"></el-table-column>
<el-table-column prop="score"
label="答案"
align="center">
<template slot-scope="scope">
<codemirror v-model="scope.row.code"
:options="cmOption"
class="code-mirror"
:ref="'codemirror' + scope.$index"
@ready="ready"></codemirror>
</template>
</el-table-column>
<el-table-column prop="score"
label="运行结果"
align="center">
<template slot-scope="scope">
<quill class="quill"
:tools="false"
:border="true"
v-model="scope.row.codeResult"
:height="300"
:index="1" />
</template>
</el-table-column>
</el-table>
</div>
<el-container v-else>
<el-aside width="30%">
<div class="aside-header">
<div :class="['p-title color', 'system' + systemId]">
@ -78,7 +115,8 @@
<el-col :span="24">
<el-card shadow="never"
:border="false">
<el-table :data="taskList"
<el-table class="task-table"
:data="taskList"
:stripe="true">
<el-table-column type="index"></el-table-column>
<el-table-column prop="name"
@ -121,7 +159,8 @@
</div>
</el-aside>
<el-main>
<el-tabs v-model="pannelTab"
<el-tabs class="info-tab"
v-model="pannelTab"
type="card">
<el-tab-pane label="项目背景"
name="first">
@ -145,7 +184,7 @@
</el-collapse>
</el-tab-pane>
<el-tab-pane label="实验提示"
name="fifth"
name="third"
v-if="hintOpen">
<div class="ql-editor"
v-html="experimentHint"></div>
@ -172,12 +211,54 @@
<script>
import newmain from "../util/newMain";
import quill from "@/components/quill";
import util from '@/util'
import Config from '@/config'
import Cookie from 'js-cookie'
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import { codemirror } from "vue-codemirror";
import "codemirror/theme/ambiance.css"; //
import "codemirror/mode/javascript/javascript.js";
import "codemirror/mode/python/python.js";
import "codemirror/lib/codemirror.css";
// require active-line.js
import "codemirror/addon/selection/active-line.js";
// styleSelectedText
import "codemirror/addon/selection/mark-selection.js";
// hint
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/sql-hint.js";
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/javascript-hint.js";
// highlightSelectionMatches
import "codemirror/addon/scroll/annotatescrollbar.js";
import "codemirror/addon/search/matchesonscrollbar.js";
import "codemirror/addon/search/match-highlighter.js";
// keyMap
import "codemirror/mode/clike/clike.js";
import "codemirror/mode/sql/sql.js";
import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/addon/comment/comment.js";
import "codemirror/addon/dialog/dialog.js";
import "codemirror/addon/dialog/dialog.css";
import "codemirror/addon/search/searchcursor.js";
import "codemirror/addon/search/search.js";
import "codemirror/keymap/sublime.js";
// foldGutter
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/fold/comment-fold.js";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/foldgutter.js";
import "codemirror/addon/fold/indent-fold.js";
import "codemirror/addon/fold/markdown-fold.js";
import "codemirror/addon/fold/xml-fold.js";
//
import "codemirror/theme/monokai.css";
import "codemirror/theme/base16-light.css";
export default {
data () {
return {
@ -221,9 +302,43 @@ export default {
pannelTab: 'first', //
isSelected: false, // true
statusTimer: null, //
reportId: ''
reportId: '',
cmOption: {
scrollbarStyle: "native",
tabSize: 2, // tab
styleActiveLine: true, //
lineNumbers: true, //
styleSelectedText: true,
line: true,
foldGutter: true, //
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: true }, //
mode: 'python',
lineWrapping: true, //
autoCloseTags: true,//
autoCloseBrackets: true,//
// hint.js options
hintOptions: {
//
completeSingle: false
},
// sublimeemacsvim
keyMap: "sublime",
matchBrackets: true,
showCursorWhenSelecting: true,
// theme: "monokai" //
},
reportTab: '',
reportPoints: [],
reportVisible: false,
tableHeight: 0
};
},
components: {
codemirror,
quill
},
mounted () {
// 210
this.projectPermissions = this.assessmentId ?
@ -256,6 +371,7 @@ export default {
}
}
this.drag()
this.tableHeight = window.innerHeight - 360
},
methods: {
//
@ -319,6 +435,14 @@ export default {
this.$parent.getModelStatus(systemId)
this.curReq = curReq // judgmentIditem
this.points = points
const reportPoints = JSON.parse(JSON.stringify(points))
points.forEach(e => {
e.codeResult = ''
})
this.reportPoints = reportPoints
if (points.length) this.reportTab = reportPoints[0].judgmentId + ''
console.log("🚀 ~ file: TestPanel.vue:423 ~ returnnewPromise ~ this.reportTab:", points, this.reportTab)
this.taskList = points //
this.judgmentId = points[0].judgmentId //
this.experimentTarget = project.experimentTarget
@ -532,12 +656,24 @@ export default {
this.countVal = 0
this.grade = '00'
this.pannelTab = 'first'
this.clearReport()
this.$emit('recoveryCode') //
},
//
toggleReport () {
this.reportVisible = !this.reportVisible
},
//
clearReport () {
this.taskList.forEach(e => {
e.code = ''
e.codeResult = ''
})
},
//
toReport () {
Cookie.set('doneProjectId', this.projectId) // id,id
this.$router.push(`/report?reportId=${this.reportId}`)
this.$router.push(`/report?reportId=${this.$store.state.reportId}`)
},
//
reload () {
@ -556,25 +692,63 @@ export default {
this.$emit('tell', this.projectId, this.curSystemId, points)
this.$emit('recoveryCode')
this.startCount()
this.clearReport()
},
//
ready () {
for (let i = 0; i < this.points.length; i++) {
const code = this.$refs['codemirror' + i][0].codemirror
console.log('ready', code)
// code && code.setSize('auto', 'calc(100vh - 150px)')
code && code.setSize('auto', '300px')
}
},
//
confirmSubmit () {
const isVscode = this.$parent.language // vscode
const { taskList } = this
const pointList = this.$parent.workbench
let msg = '此操作将视为结束考试,是否继续?'
if (pointList.find(e => !e.codeId && e.code)) msg = '有代码没有运行,该代码将不得分,确定提交?'
if (!isVscode && pointList.find(e => !e.codeId && e.code)) msg = '有代码没有运行,该代码将不得分,确定提交?'
if (isVscode && !taskList.find(e => e.code || e.codeResult)) msg = '实验报告未填写,实验成绩为零,是否确认提交?'
this.$confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(() => {
// vscodecodeId
if (isVscode) {
const promises = []
taskList.map(async (e, i) => {
(e.code || e.codeResult) && promises.push(new Promise(async (resolve, reject) => {
const { code, codeId } = await this.$post(this.api.runPythonCode, {
code: e.code,
bcId: e.judgmentId,
cid: this.courseId,
projectId: this.projectId,
userAnswer: e.codeResult || null,
type: 1
})
this.$parent.workbench[i].codeId = codeId
this.$parent.workbench[i].answer = e.codeResult
this.$parent.workbench[i].retResult = 1
resolve()
}))
})
Promise.all(promises).then(_ => {
this.submit()
})
} else {
//
if (!pointList.find(e => e.codeId)) {
this.$post(this.api.runPythonCode, {
code: '',
bcId: pointList[0].judgmentId,
cid: this.courseId,
projectId: this.projectId
projectId: this.projectId,
type: 0
}).then(({ codeId }) => {
this.$parent.workbench[0].codeId = codeId
this.submit()
@ -582,6 +756,7 @@ export default {
} else {
this.submit()
}
}
}).catch(() => { })
},
//
@ -632,6 +807,7 @@ export default {
localStorage.removeItem('codeCache')
this.setSubmit(true)
clearInterval(this.statusTimer)
this.reportVisible = false
let list = retInfo
let taskList = this.taskList
let score = 0
@ -648,6 +824,7 @@ export default {
})
this.grade = util.handleZero(score) // 0()
this.reportId = reportId
this.$store.commit('setReportId', reportId)
this.editReport(reportId)
//
this.competitionId && this.resultsDetails == 0 && this.$alert('提交成功,成绩将在' + this.resultAnnouncementTime + '小时后发布,请去参赛信息模块查看', '提示', {
@ -743,6 +920,7 @@ export default {
let gap = 10 //
let parent = document.body
document.querySelector('#header').onmousedown = e => {
console.log("🚀 ~ file: TestPanel.vue:746 ~ document.querySelector ~ e:", e)
var x = e.clientX - el.offsetLeft
var y = e.clientY - el.offsetTop
var left = 0
@ -840,11 +1018,6 @@ export default {
/deep/.el-collapse-item__header {
border-bottom: none;
}
/deep/.el-tabs__content {
margin: 0 20px;
max-height: calc(60vh - 70px);
overflow: auto;
}
/deep/.el-icon-s-ticket:before {
padding: 5px;
font-size: 16px;
@ -852,28 +1025,33 @@ export default {
/deep/.el-collapse-item__arrow {
margin: 0 5px 0 0;
}
/deep/.el-tabs__item {
/deep/.info-tab.el-tabs--card {
.el-tabs__item {
font-size: 16px;
}
/deep/.el-tabs--card > .el-tabs__header .el-tabs__nav {
}
.el-tabs__item.is-active {
color: #fff;
}
.el-tabs__header .el-tabs__nav {
border: none;
}
/deep/.el-tabs--card > .el-tabs__header .el-tabs__item {
}
.el-tabs__header .el-tabs__item {
border-left: none;
}
/deep/.el-tabs--card > .el-tabs__header {
}
.el-tabs__header {
padding: 5px 20px;
border-bottom: none;
}
& > .el-tabs__content {
margin: 0 20px;
max-height: calc(60vh - 70px);
overflow: auto;
}
}
/deep/.el-collapse {
border-bottom: none;
border-top: none;
}
/deep/.el-tabs__item.is-active {
color: #fff;
}
/deep/.el-tabs__header {
padding: 5px 20px;
}
.el-aside {
margin-bottom: 10px;
color: #333;
@ -924,7 +1102,7 @@ export default {
/deep/.el-card__body {
padding: 0;
}
/deep/.el-table {
/deep/.task-table {
font-size: 12px;
thead {
color: #fff;
@ -975,6 +1153,7 @@ export default {
}
}
.panel {
z-index: 1000;
position: relative;
top: 200px;
bottom: 20px;
@ -1020,4 +1199,22 @@ export default {
opacity: 0.9;
}
}
/deep/.report-table.el-table {
th {
background-color: #c6daff !important;
}
}
.report-wrap {
position: relative;
padding-top: 5px;
}
.close-report {
z-index: 2;
position: absolute;
top: -21px;
right: 296px;
font-size: 32px;
color: #c6daff;
cursor: pointer;
}
</style>

@ -397,7 +397,8 @@ export default {
code: this.sourceCode,
bcId: this.judgmentId,
cid: this.courseId,
projectId: this.projectId
projectId: this.projectId,
type: 0
}, {
headers: {
token: this.token
@ -465,7 +466,8 @@ export default {
code,
bcId,
cid,
projectId
projectId,
type: 0
}).then(res => {
const data = res.code
const result = data.runResult
@ -501,7 +503,8 @@ export default {
code,
bcId,
cid,
projectId
projectId,
type: 0
}).then(res => {
const data = res.code
const photo = data.photoUrl
@ -608,9 +611,6 @@ export default {
<style lang="scss" scoped>
.code-wrap {
position: relative;
.code-mirror {
line-height: 30px;
}
}
.left {
position: relative;

@ -1,15 +1,18 @@
<template>
<div class="quill" ref="quill" :class="classes">
<div ref="editor" :style="styles" v-loading="loading"></div>
<div class="quill"
ref="quill"
:class="classes">
<div ref="editor"
:style="styles"
v-loading="loading"></div>
<el-upload
:headers="headers"
<el-upload :headers="headers"
:action="this.api.fileuploadOss"
:before-upload="beforeUpload"
:on-success="editorUploadSuccess"
style="display: none"
>
<el-button :id="'editorUpload' + index" type="primary">点击上传</el-button>
style="display: none">
<el-button :id="'editorUpload' + index"
type="primary">点击上传</el-button>
</el-upload>
</div>
</template>
@ -58,8 +61,13 @@ export default {
type: Number,
default: 0
},
//
tools: {
type: Boolean,
default: true
},
},
data() {
data () {
const that = this
return {
headers: {
@ -75,7 +83,7 @@ export default {
toolbar: {
container: toolbarOptions,
handlers: {
"image": function(value) {
"image": function (value) {
if (value) {
// iview
document.querySelector("#editorUpload" + that.index).click();
@ -93,14 +101,15 @@ export default {
};
},
computed: {
classes() {
classes () {
return [
{
"quill-no-border": !this.border
"quill-no-border": !this.border,
'bd': !this.tools
}
];
},
styles() {
styles () {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
@ -114,7 +123,7 @@ export default {
},
watch: {
value: {
handler(val) {
handler (val) {
if (val !== this.currentValue) {
this.currentValue = val;
if (this.Quill) {
@ -125,7 +134,7 @@ export default {
immediate: true
}
},
mounted() {
mounted () {
this.init();
//
if (this.elseRead === "true") {
@ -136,7 +145,7 @@ export default {
children.borderTop = "0";
}
},
beforeDestroy() {
beforeDestroy () {
//
this.Quill = null;
},
@ -144,13 +153,13 @@ export default {
init () {
const editor = this.$refs.editor;
//
this.Quill = new Quill(editor, this.options);
this.Quill = new Quill(editor, this.tools ? this.options : []);
const ins = this.Quill
//
ins.pasteHTML(this.currentValue);
if(this.toTop){
if (this.toTop) {
this.$nextTick(() => {
window.scrollTo(0,0)
window.scrollTo(0, 0)
})
}
//
@ -187,7 +196,7 @@ export default {
const param = new FormData()
param.append('file', file)
// base64
this.$post(this.api.fileupload, param, {
this.$post(this.api.fileuploadOss, param, {
headers: { "Content-Type": "multipart/form-data" }
}).then(res => {
var range = ins.getSelection()
@ -197,15 +206,15 @@ export default {
//
ins.setSelection(range.index + 1)
}
}).catch(res => {})
}).catch(res => { })
});
}
}, false)
},
beforeUpload(file) {
beforeUpload (file) {
this.loading = true;
},
editorUploadSuccess(res) {
editorUploadSuccess (res) {
//
let quill = this.Quill;
//
@ -235,6 +244,9 @@ export default {
border: none;
}
}
.bd {
border: 1px solid #ebeef5;
}
.else {
.ql-toolbar.ql-snow {
@ -253,5 +265,4 @@ export default {
transform: translateY(10px);
}
}
</style>

@ -10,9 +10,9 @@ let host = location.origin + '/'
let bankPath = `${location.origin}/banksystem` // 银行系统
// 121.37.12.51 | 192.168.31.151
if (isDev) {
host = 'http://192.168.31.152:9000/'
// host = 'http://192.168.31.152:9000/'
// host = 'http://192.168.31.53:9000/'
// host = 'http://121.37.12.51:9000/'
host = 'http://121.37.12.51:9000/'
// host = 'https://occupationlab.com/'
bankPath = `http://${location.hostname}:8093`
} else if (isPro) {

@ -2,7 +2,17 @@ import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {},
mutations: {}
state: {
language: 0,
reportId: ''
},
mutations: {
setLanguage: (state, id) => {
state.language = id
},
setReportId: (state, id) => {
state.reportId = id
},
}
});
export default store;

@ -1,7 +1,7 @@
.flex {
display: flex;
}
.break-all{
.break-all {
word-break: break-all;
}
.c-p {
@ -35,29 +35,30 @@ input::-ms-input-placeholder {
}
body .cus-table.el-table {
border-radius: 4px;
th{
background-color: #E8F0FF !important;
.cell{
th {
background-color: #e8f0ff !important;
.cell {
color: #222326;
font-weight: normal;
.el-checkbox{
&:before{
.el-checkbox {
&:before {
opacity: 1;
}
}
}
}
th, td{
th,
td {
padding: 10px 0;
border-bottom-color: #E1E6F2;
border-bottom-color: #e1e6f2;
.cell {
font-size: 12px;
}
}
&.el-table--striped .el-table__body tr.el-table__row--striped td{
background-color: #FAFBFF !important;
&.el-table--striped .el-table__body tr.el-table__row--striped td {
background-color: #fafbff !important;
}
.el-button--text{
.el-button--text {
padding: 0;
}
}
@ -74,7 +75,10 @@ body .cus-table.el-table {
.pagination {
margin: 20px 0;
text-align: center;
button,.number,.more,.el-input__inner{
button,
.number,
.more,
.el-input__inner {
min-width: 32px !important;
height: 32px !important;
line-height: 32px;
@ -83,11 +87,15 @@ body .cus-table.el-table {
border: 1px solid #ccc !important;
border-radius: 2px !important;
}
button i{
button i {
color: #333;
}
.active{
.active {
color: #fff !important;
background-color: #007eff!important;
background-color: #007eff !important;
}
}
.code-mirror {
text-align: left;
line-height: 30px;
}

@ -60,14 +60,9 @@
:retResult.sync="item.retResult"
:modelIsShow.sync="modelIsShow"
@cache="leavePage"></codemirror>
<!-- <img v-else
src="@/assets/images/vscode.png"
alt=""
width="100%"
height="700"> -->
<iframe v-else
class="vscode"
src="https://vscode.occupationlab.com/"
:src="Config.isPro ? 'https://vscode.occupationlab.com/' : 'http://121.37.12.51:8088/?folder=/home/coder'"
frameborder="0"
width="100%"></iframe>
</el-tab-pane>
@ -88,9 +83,11 @@ 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,
loaded: false, //
loadIns: null, // loading
competitionId: Cookie.get('admin-competitionId'),
@ -99,6 +96,7 @@ export default {
curriculumName: Cookie.get('admin-curriculumName') ? unescape(Cookie.get('admin-curriculumName')) : 'python', //
assessmentId: Cookie.get('admin-assessmentId'), // id
mallId: Cookie.get('admin-mallId'),
language: +Cookie.get('admin-language') || 0, //
projectId: '',
systemId: '',
modelIsShow: false, //
@ -113,7 +111,6 @@ export default {
name: 'Vscode'
},
],
language: 0, //
curTab: '', //
workbench: [], //
codeKey: 1 //
@ -174,7 +171,8 @@ export default {
},
//
languageChange (id) {
Cookie.set('admin-language', id)
this.$refs.mainindex.reportVisible = false
},
//
toData () {

Loading…
Cancel
Save