parent
ddcf41931f
commit
2cf0f0674c
9 changed files with 566 additions and 419 deletions
After Width: | Height: | Size: 796 B |
@ -0,0 +1,402 @@ |
|||||||
|
<template> |
||||||
|
<div class="wrap"> |
||||||
|
<div class="left"> |
||||||
|
<codemirror |
||||||
|
v-model="codeVal" |
||||||
|
:options="cmOption" |
||||||
|
class="code-mirror" |
||||||
|
@ready="ready" |
||||||
|
ref="codemirror" |
||||||
|
></codemirror> |
||||||
|
<el-button |
||||||
|
class="run btn" |
||||||
|
type="primary" |
||||||
|
@click="runCode" |
||||||
|
>运行</el-button> |
||||||
|
</div> |
||||||
|
<div class="code-right answer"> |
||||||
|
<p class="text-wrapper">{{ runResult }}</p> |
||||||
|
<div class="pic-wrap" v-if="picSrcList.length"> |
||||||
|
<div class="pic-item" v-for="(img, i) in picSrcList" :key="i"> |
||||||
|
<el-image |
||||||
|
class="pic" |
||||||
|
:src="img" |
||||||
|
:preview-src-list="picSrcList"> |
||||||
|
</el-image> |
||||||
|
<el-button class="download-btn btn" type="primary" size="mini" @click="downloadPic(i)">下载图片</el-button> |
||||||
|
<a :ref="'picLink' + i" style="display: none;" download="运行结果.png" :href="img">下载图片</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="result-right t-color" v-show="isError"> |
||||||
|
<!-- <img :src="require(`@/assets/images/system/${systemId}/yes.png`)" alt />运行成功 --> |
||||||
|
</div> |
||||||
|
<div class="result-wrong" v-show="isError === 0"> |
||||||
|
<img src="@/assets/img/error.png" alt /> |
||||||
|
第{{errLine}}行出现错误 |
||||||
|
<el-button class="tips-btn" @click="getTips" v-show="showTips">提示</el-button> |
||||||
|
<el-dialog title="答案提示" center :close-on-click-modal="false" :visible.sync="tipsVisible"> |
||||||
|
<el-tabs> |
||||||
|
<el-tab-pane label="参考答案"> |
||||||
|
<div class="answer-wrap" v-html="answer"></div> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</el-dialog> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
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"; |
||||||
|
import { Loading } from 'element-ui'; |
||||||
|
export default { |
||||||
|
props: ['code', 'codeId', 'projectId', 'retResult'], |
||||||
|
data() { |
||||||
|
return { |
||||||
|
showTips: false, // 显示隐藏提示按钮 |
||||||
|
answer: '', // 正确答案 |
||||||
|
codeVal: this.code, |
||||||
|
runResult: '', // 运行结果 |
||||||
|
isError: false, // 运行正确与否 |
||||||
|
errLine: '', // 错误代码的位置 |
||||||
|
tipsVisible: false, // 答案提示弹框显示标识 |
||||||
|
picSrcList: [], |
||||||
|
loadIns: null, // loading实例 |
||||||
|
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 |
||||||
|
}, |
||||||
|
// 快捷键 可提供三种模式 sublime、emacs、vim |
||||||
|
keyMap: "sublime", |
||||||
|
matchBrackets: true, |
||||||
|
showCursorWhenSelecting: true, |
||||||
|
theme: "monokai" // 主题 |
||||||
|
} |
||||||
|
}; |
||||||
|
}, |
||||||
|
components: { |
||||||
|
codemirror |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
codeVal(val) { |
||||||
|
this.$emit("update:code", val) |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
methods: { |
||||||
|
// 页面加载完后重置编辑框大小 |
||||||
|
ready() { |
||||||
|
const code = this.$refs.codemirror.codemirror |
||||||
|
code.setSize("auto", "calc(100vh - 167px)"); |
||||||
|
code.on('keypress', function() { |
||||||
|
// 显示智能提示 |
||||||
|
code.showHint() |
||||||
|
}); |
||||||
|
}, |
||||||
|
// 运行代码 |
||||||
|
runCode() { |
||||||
|
let code = this.codeVal |
||||||
|
if (!code) { |
||||||
|
this.$message({ |
||||||
|
message: "警告哦,内容为空不可运行", |
||||||
|
type: "warning" |
||||||
|
}) |
||||||
|
} else { |
||||||
|
const bcId = this.judgmentId |
||||||
|
const cid = this.courseId |
||||||
|
const projectId = this.projectId |
||||||
|
this.loadIns = Loading.service({ |
||||||
|
background: 'transparent' |
||||||
|
}) |
||||||
|
// 如果代码有savefig(python里的保存图片的方法),则要把savefig里的图片名字加上个时间戳,防止后台保存图片到服务器的时候图片名字重复导致覆盖 |
||||||
|
code = code.replace(/\.savefig\(([\u4e00-\u9fa5\w]*?['"])/mg, str => { |
||||||
|
return str + Date.now() |
||||||
|
}) |
||||||
|
// 把代码传给后端,在后端运行Python代码 |
||||||
|
this.$post(this.api.runPythonCode, { |
||||||
|
code, |
||||||
|
bcId, |
||||||
|
cid, |
||||||
|
projectId |
||||||
|
}).then(res => { |
||||||
|
const data = res.code |
||||||
|
const photo = data.photoUrl |
||||||
|
const result = data.runResult |
||||||
|
this.$emit('cache') // 每次运行代码都要把代码传给后端做缓存 |
||||||
|
this.loadIns.close() |
||||||
|
this.picSrcList = [] |
||||||
|
if (photo) this.picSrcList = photo.split(',') |
||||||
|
this.$emit('update:codeId', res.codeId) // 更新coddeId |
||||||
|
this.$emit('update:answer', result) // 更新运行结果 |
||||||
|
this.$emit('update:retResult', data.retResult) // 更新返回结果 |
||||||
|
let imgList = '' |
||||||
|
let firtImg = '' |
||||||
|
try { |
||||||
|
imgList = eval(result) |
||||||
|
} catch (error) {} |
||||||
|
if (imgList && imgList.length) firtImg = imgList[0] |
||||||
|
// 如果是下载图片的代码,则要显示图片和运行结果,不用显示对错,换成显示下载图片 |
||||||
|
if (photo) { |
||||||
|
this.isError = '' // 对错隐藏 |
||||||
|
const text = result.replace(photo, '') // 结果里包含了图片路径,所以要把图片路径给去掉 |
||||||
|
this.runResult = text |
||||||
|
this.picSrcList = photo.split(',') |
||||||
|
} else if (imgList instanceof Array && imgList.length && typeof firtImg === 'string' && (firtImg.includes('.jpg') || firtImg.includes('.png') || firtImg.includes('img'))) { |
||||||
|
/** |
||||||
|
* 这段是为要下载图片的项目案例写的,后端会返回图片名称的数组,前端负责循环这个数组,然后下载下来 |
||||||
|
* 只有该系统有这段代码,因为其他7个系统没有下载图片的项目,后续如果加了,直接把这段代码复制过去即可 |
||||||
|
*/ |
||||||
|
imgList.map((n,i) => { |
||||||
|
// util.downloadFile(`${i+1}.jpg`,n) |
||||||
|
}) |
||||||
|
this.isError = 0 |
||||||
|
this.runResult = '下载完成' |
||||||
|
} else { |
||||||
|
this.isError = data.retResult |
||||||
|
this.runResult = result |
||||||
|
this.errLine = parseInt(result.substring(result.indexOf("line") + 4, result.length)) |
||||||
|
} |
||||||
|
}).catch(res => { |
||||||
|
res.status == 500 && this.$message.error('检测到代码里有非法代码,请检查是否有调用系统命令。') |
||||||
|
this.loadIns.close() |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
// 下载图片 |
||||||
|
downloadPic(i) { |
||||||
|
this.$refs['picLink' + i][0].click() |
||||||
|
}, |
||||||
|
// 获取正式答案 |
||||||
|
getTips() { |
||||||
|
this.tipsVisible = true |
||||||
|
this.$get(this.api.queryBcJudgmentByBcId, { |
||||||
|
bcId: this.judgmentId |
||||||
|
}).then(res => { |
||||||
|
this.answer = res.experimentCode |
||||||
|
}).catch(err => {}) |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.wrap { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
.left{ |
||||||
|
position: relative; |
||||||
|
width: calc(100% - 400px); |
||||||
|
} |
||||||
|
.text-wrapper { |
||||||
|
white-space: pre-wrap; |
||||||
|
} |
||||||
|
/deep/.answer { |
||||||
|
.el-tab-pane { |
||||||
|
padding: 0 10px; |
||||||
|
height: 340px; |
||||||
|
overflow: hidden; |
||||||
|
overflow-y: auto; |
||||||
|
white-space: pre-wrap; |
||||||
|
} |
||||||
|
.el-dialog--center { |
||||||
|
width: 500px; |
||||||
|
height: 500px; |
||||||
|
} |
||||||
|
.el-dialog__title { |
||||||
|
font-size: 22px; |
||||||
|
font-weight: 500; |
||||||
|
} |
||||||
|
.el-tabs__nav-wrap::after { |
||||||
|
background-color: #333; |
||||||
|
} |
||||||
|
.el-tabs__active-bar { |
||||||
|
height: 0; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
.el-tabs__header { |
||||||
|
background-color: #333; |
||||||
|
} |
||||||
|
.el-dialog--center .el-dialog__body { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
.el-tabs__item { |
||||||
|
width: 80px; |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
.el-tabs--top .el-tabs__item.is-top:nth-child(2) { |
||||||
|
padding-left: 20px; |
||||||
|
} |
||||||
|
.el-tabs__item.is-active { |
||||||
|
color: #fff !important; |
||||||
|
background-color: #333 !important; |
||||||
|
} |
||||||
|
.tips-btn { |
||||||
|
margin-top: 10px; |
||||||
|
height: 40px; |
||||||
|
width: 90px; |
||||||
|
border: none; |
||||||
|
position: absolute; |
||||||
|
right: 0; |
||||||
|
background: rgba(255, 49, 49, 1); |
||||||
|
color: rgba(255, 255, 255, 1); |
||||||
|
&:hover, |
||||||
|
&:focus, |
||||||
|
&:active { |
||||||
|
background: rgba(255, 49, 49, 1); |
||||||
|
color: rgba(255, 255, 255, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
/deep/.CodeMirror-wrap pre.CodeMirror-line, |
||||||
|
.CodeMirror-wrap pre.CodeMirror-line-like { |
||||||
|
height: 30px; |
||||||
|
line-height: 30px; |
||||||
|
} |
||||||
|
.result-right { |
||||||
|
background-color: rgba(43, 40, 22, 1); |
||||||
|
} |
||||||
|
.result-wrong { |
||||||
|
background-color: rgba(43, 22, 22, 1); |
||||||
|
color: #f00; |
||||||
|
} |
||||||
|
.result-wrong, |
||||||
|
.result-right { |
||||||
|
position: absolute; |
||||||
|
left: 20px; |
||||||
|
right: 20px; |
||||||
|
display: flex; |
||||||
|
bottom: 10px; |
||||||
|
padding: 0 10px; |
||||||
|
img { |
||||||
|
width: 40px; |
||||||
|
height: 40px; |
||||||
|
margin-top: 5px; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
.code-right { |
||||||
|
width: 500px; |
||||||
|
color: #fff; |
||||||
|
background: #1b1b1b; |
||||||
|
display: inline-block; |
||||||
|
position: relative; |
||||||
|
overflow-x: auto; |
||||||
|
p { |
||||||
|
font-size: 18px; |
||||||
|
margin: 10px; |
||||||
|
position: absolute; |
||||||
|
width: calc(100% - 14px); |
||||||
|
height: calc(100vh - 247px); |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
} |
||||||
|
.pic-wrap { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 5px; |
||||||
|
display: flex; |
||||||
|
max-width: calc(100% - 50px); |
||||||
|
margin: 0 auto; |
||||||
|
text-align: center; |
||||||
|
overflow: auto; |
||||||
|
.pic-item { |
||||||
|
margin: 0 5px 5px; |
||||||
|
&:only-child { |
||||||
|
.pic { |
||||||
|
width: 80%; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.pic { |
||||||
|
display: block; |
||||||
|
width: 100px; |
||||||
|
margin: 0 auto 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
.code-mask{ |
||||||
|
z-index: 2; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
bottom: 0; |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
.run{ |
||||||
|
z-index:99; |
||||||
|
position:absolute; |
||||||
|
right: 50px; |
||||||
|
bottom:15px; |
||||||
|
width:100px; |
||||||
|
color:#fff; |
||||||
|
} |
||||||
|
.download-btn{ |
||||||
|
color:#fff; |
||||||
|
} |
||||||
|
/deep/.answer-wrap{ |
||||||
|
pre{ |
||||||
|
width: 100%; |
||||||
|
white-space: pre-wrap; |
||||||
|
} |
||||||
|
img{ |
||||||
|
max-width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,55 @@ |
|||||||
|
<template> |
||||||
|
<div class="wrap"> |
||||||
|
<el-card shadow="hover" class="mgb20"> |
||||||
|
<div class="flex-between"> |
||||||
|
<div class="per_title" v-preventReClick @click="$router.back()"> |
||||||
|
<i class="el-icon-arrow-left"></i> |
||||||
|
<span class="per_back">返回</span> |
||||||
|
<span class="per_school" v-text="isDetail ? '查看源模型' : (customerId ? '编辑源模型' : '新增源模型')"></span> |
||||||
|
</div> |
||||||
|
<el-button v-if="!isDetail" type="primary" round v-preventReClick @click="submit">确定</el-button> |
||||||
|
</div> |
||||||
|
</el-card> |
||||||
|
|
||||||
|
<el-card shadow="hover"> |
||||||
|
<el-form ref="form" label-width="120px" :disabled="isDetail"> |
||||||
|
<el-form-item label="模型名称"> |
||||||
|
<el-input placeholder="请输入模型名称" v-model="form.position" maxlength="25"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="模型代码"> |
||||||
|
<codemirror |
||||||
|
></codemirror> |
||||||
|
</el-form-item> |
||||||
|
</el-form> |
||||||
|
</el-card> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import codemirror from '@/components/codemirror' |
||||||
|
export default { |
||||||
|
components:{ codemirror }, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
customerId : this.$route.query.id, |
||||||
|
isDetail : Boolean(this.$route.query.show), |
||||||
|
form: { |
||||||
|
|
||||||
|
} |
||||||
|
}; |
||||||
|
}, |
||||||
|
mounted() { |
||||||
|
|
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 保存 |
||||||
|
submit(){ |
||||||
|
|
||||||
|
}, |
||||||
|
} |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
|
||||||
|
</style> |
Loading…
Reference in new issue