diff --git a/package-lock.json b/package-lock.json index 9e4c256..1e8e120 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3177,6 +3177,15 @@ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, + "bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -4478,6 +4487,15 @@ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, + "d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "requires": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -5167,6 +5185,36 @@ "is-symbol": "^1.0.2" } }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "requires": { + "d": "^1.0.2", + "ext": "^1.7.0" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -5193,6 +5241,17 @@ "estraverse": "^4.1.1" } }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -5234,6 +5293,15 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "event-pubsub": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", @@ -5397,6 +5465,14 @@ } } }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "requires": { + "type": "^2.7.2" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz", @@ -7044,8 +7120,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-utf8": { "version": "0.2.1", @@ -7872,6 +7947,11 @@ "integrity": "sha1-rCetpmFn+ohJpq3dg39rGJrSCBw=", "dev": true }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -7921,6 +8001,12 @@ } } }, + "node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "optional": true + }, "node-ipc": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.2.1.tgz", @@ -11117,6 +11203,14 @@ "readable-stream": "^2.0.1" } }, + "stompjs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/stompjs/-/stompjs-2.3.3.tgz", + "integrity": "sha512-5l/Ogz0DTFW7TrpHF0LAETGqM/so8UxNJvYZjJKqcX31EVprSQgnGkO80tZctPC/lFBDUrSFiTG3xd0R27XAIA==", + "requires": { + "websocket": "^1.0.34" + } + }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", @@ -11645,6 +11739,11 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, "type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", @@ -11667,6 +11766,15 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "optional": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "uglify-js": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", @@ -11956,6 +12064,15 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -12798,6 +12915,37 @@ } } }, + "websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "optional": true, + "requires": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "optional": true + } + } + }, "websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -12971,6 +13119,12 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "optional": true + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 85c0526..d5871f4 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "postcss-pxtorem": "^5.1.1", "px2rem-loader": "^0.1.9", "quill": "^1.3.7", + "stompjs": "^2.3.3", "tinymce": "^6.8.3", "vue": "^2.6.14", "vue-codemirror": "^4.0.6", diff --git a/src/api/index.js b/src/api/index.js index 03b35bd..c92574f 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -44,4 +44,6 @@ export default { getStartTime: `python/python/getStartTime`, getProductSystemTheme: `nakadai/mall/getProductSystemTheme`, heartbeatDetection : `nakadai/message/heartbeatDetection`, + createQueue : `python/rabbitMessage/createQueue`, + endRunningProcess : `python/python/endRunningProcess`, } \ No newline at end of file diff --git a/src/components/TestPanel.vue b/src/components/TestPanel.vue index d70e0ef..65af807 100644 --- a/src/components/TestPanel.vue +++ b/src/components/TestPanel.vue @@ -319,6 +319,12 @@ import "codemirror/theme/monokai.css"; import "codemirror/theme/base16-light.css"; import { mavonEditor } from 'mavon-editor' import 'mavon-editor/dist/css/index.css' +import Stomp from 'stompjs' +export const IP = "x.108.x.33" // 自己的mq服务ip +export const MQTT_USERNAME = 'huoran' // 连接用户名, todo: read from database +export const MQTT_PASSWORD = 'huoran2024' // 连接密码, todo: read from database +export const VIRTUAL_HOST = '15674' // 侦听器端口 + export default { data () { return { @@ -396,7 +402,10 @@ export default { reportVisible: false, tableHeight: 0, dragIds: ['panelHeader', 'aside', 'main', 'infoContainer'], - submiting: false + submiting: false, + client: '', + accountId: '', + runCodeType: '', }; }, components: { @@ -419,6 +428,10 @@ export default { await this.getEntryTime() + newmain.$on('changeRunStatus', val => { + this.runCodeType = val + }) + if (this.assessmentId) { // 考核(考核才会从外面带进来assessmentId,练习是默认显示第一个项目,竞赛会带进来competitionId) this.getAssList() } else { // 练习 @@ -840,6 +853,14 @@ export default { } } }, + vscodeRunCode (data) { + // this.$parent.workbench[i].codeId = data.codeId + // this.$parent.workbench[i].retResult = 1 + }, + emptyRunCode (data) { + this.$parent.workbench[0].codeId = data.codeId + this.submit() + }, // 提交询问 confirmSubmit () { if (this.submiting) return false @@ -869,17 +890,17 @@ export default { 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, { + this.runCodeType = 'vscodeRunCode' + await this.$post(this.api.runPythonCode, { code: e.code, bcId: e.judgmentId, cid: this.courseId, projectId: this.projectId, userAnswer: e.codeResult || null, - type: 0 + type: 0, + sort: i }) - this.$parent.workbench[i].codeId = codeId this.$parent.workbench[i].answer = e.codeResult - this.$parent.workbench[i].retResult = 1 resolve() })) }) @@ -889,16 +910,14 @@ export default { } else { // 如果全部都没运行直接点提交,则主动运行一个空代码。(不然会造成上次运行的结果,这次进来不运行直接提交的话,会无法取到运行结果) if (!pointList.find(e => e.codeId)) { + this.runCodeType = 'emptyRunCode' this.$post(this.api.runPythonCode, { code: '', bcId: pointList[0].judgmentId, cid: this.courseId, projectId: this.projectId, type: 0 - }).then(({ codeId }) => { - this.$parent.workbench[0].codeId = codeId - this.submit() - }).catch(err => { + }).then(res => { }).catch(err => { this.submiting = false }) } else { @@ -1198,6 +1217,52 @@ export default { // 监听socket消息 this.socket.onmessage = this.getMessage; }, + + // 消息队列获取 + connect () { + let ws = new WebSocket(`ws://124.71.74.9:15674/ws`); + this.client = Stomp.over(ws); + //初始化连接 + const headers = { + login: MQTT_USERNAME, + passcode: MQTT_PASSWORD + }; + //进行连接 + this.client.connect(headers.login, headers.passcode, this.onConnected, this.onFailed, 'pyhost'); + }, + onConnected: function () { + //订阅频道 + const topic = '/amq/queue/pythonQueue_' + this.accountId; + this.client.subscribe(topic, this.responseCallback, this.onFailed); + }, + onFailed: function (frame) { + console.log("MQ Failed: " + frame); + // this.$message.error('连接失败') + }, + // 回传消息 + responseCallback: function (frame) { + const data = JSON.parse(frame.body) + + console.log("接收信息:", data, typeof data); + if (typeof data === 'object') { + newmain.$emit('setPid', '') + if (this.runCodeType) { + this[this.runCodeType](data) + } else { + newmain.$emit('runCode', data) + } + this.runCodeType = '' + } else if (typeof data === 'string') { + newmain.$emit('setPid', data) + } + }, + // 断开相应的连接 + close: function () { + this.client.disconnect(function () { + console.log("已退出账号"); + }) + }, + // 心跳检测 heartbeatDetection () { setInterval(async () => { @@ -1206,7 +1271,10 @@ export default { }, // 获取用户详情 getUserDetail () { - this.$get(this.api.queryUserInfoDetails).then(res => { + this.$get(this.api.queryUserInfoDetails).then(async (res) => { + this.accountId = res.result.userAccount.id + await this.$get(this.api.createQueue) + this.connect(); this.initSocket(res.result.userAccount) }).catch(res => { }) }, diff --git a/src/components/codemirror.vue b/src/components/codemirror.vue index c52dba1..a72ccf0 100644 --- a/src/components/codemirror.vue +++ b/src/components/codemirror.vue @@ -9,20 +9,31 @@
- - 我的代码 - 导入模型 - 运行 + + + 终止运行 + +
@@ -420,6 +431,10 @@ export default { curRow: {}, curCode: '', curPhotoUrl: [], + runCodeType: '', + pid: '', + cancelRunTimer: null, + runCodeConfirm: null, }; }, components: { @@ -445,9 +460,19 @@ export default { if (!this.assessmentId && !this.competitionId) this.isPrac = true //兄弟组件传值 - newmain.$on("isSubmit", isSubmit => { + newmain.$on('isSubmit', isSubmit => { this.isSubmit = isSubmit }) + newmain.$on('runCode', data => { + this.handleRunCode(data) + }) + newmain.$on('setPid', pid => { + if (this.runCodeConfirm) this.runCodeConfirm.close() + this.pid = pid + }) + newmain.$on('cancelRunTimer', () => { + clearTimeout(this.cancelRunTimer) + }) this.dragSide() }, @@ -556,6 +581,44 @@ export default { }) }).catch(res => { }) }, + handleRunCodeCb (fn) { + newmain.$emit('changeRunStatus', '') + this.runCodeType = fn + clearTimeout(this.cancelRunTimer) + // this.cancelRunTimer = setTimeout(() => { + // this.runCodeConfirm = this.$confirm('当前代码已运行超过5秒钟,是否终止运行?', '提示', { + // type: 'warning', + // closeOnClickModal: false, + // showClose: false + // }).then(async () => { + // if (this.pid) await this.$post(`${this.api.endRunningProcess}?pid=${this.pid}`) + // if (this.loadIns) this.loadIns.close() + // }).catch(() => { }) + // }, 5000) + }, + // 终止运行 + async stopRunCode () { + if (this.pid) await this.$post(`${this.api.endRunningProcess}?pid=${this.pid}`) + this.pid = '' + if (this.loadIns) this.loadIns.close() + }, + inputRunCode (data) { + const result = data.runResult + if (result.includes('File ')) { + this.runResult = result + this.errLine = this.getErrLine(result) + this.isError = data.retResult + } else if (result.includes('validing:')) { + this.isError = 1 + this.confirmInput(result) + } else if (data.retResult) { + this.isError = 1 + this.runResult += result + } + this.$emit('update:codeId', data.codeId) // 更新coddeId + this.$emit('update:answer', this.runResult) // 更新运行结果 + this.$emit('update:retResult', data.retResult) // 更新返回结果 + }, /** * python代码里如果有input函数的话,是做了单独的处理的,原理是先把所有input函数都替换成exit函数,再在exit函数里加上特定标识,再通过接口传给后端去执行 * 因为exit函数是跟input有类似的效果,就是都会产生阻塞,所以python引擎一旦遇到exit,进程就会被停止,然后返回exit函数里面的值,而这个值,就是上面说的特定标识加上原本这个input函数里的值 @@ -583,6 +646,7 @@ export default { this.requestList.map(n => n('interrupt')) }, 1000) + this.handleRunCodeCb('inputRunCode') axios.post(config.host + this.api.runPythonCode, { code: this.sourceCode, bcId: this.judgmentId, @@ -596,25 +660,8 @@ export default { cancelToken: new CANCEL_TOKEN(c => { //强行中断请求要用到的,记录请求信息 this.requestList.push(c) }) - }).then(response => { - let res = response.data - const data = res.code - const result = data.runResult - if (result.includes('File ')) { - this.runResult = result - this.errLine = this.getErrLine(result) - this.isError = data.retResult - } else if (result.includes('validing:')) { - this.isError = 1 - this.confirmInput(result) - } else if (data.retResult) { - this.isError = 1 - this.runResult += result - } + }).then(res => { this.$emit('update:finalCode', this.sourceCode) - this.$emit('update:codeId', res.codeId) // 更新coddeId - this.$emit('update:answer', this.runResult) // 更新运行结果 - this.$emit('update:retResult', data.retResult) // 更新返回结果 }).catch(e => { if (e && e.message == 'interrupt') { this.runCode(true) @@ -628,6 +675,72 @@ export default { getErrLine (result) { return parseInt(result.substring(result.indexOf('line') + 4, result.length)) || 1 }, + handleRunCode (data) { + if (this.runCodeType && this[this.runCodeType]) this[this.runCodeType](data) + }, + runCodeCb1 (res) { + const result = data.runResult + if (result.includes('File ')) { + if (isWhile) { + this.runResult += result + } else { + this.runResult = result + } + this.errLine = this.getErrLine(result) + this.isError = data.retResult + } else if (result.includes('validing:')) { + this.isError = 1 + this.confirmInput(result) + } + this.$emit('update:codeId', res.codeId) // 更新coddeId + this.$emit('update:answer', this.runResult) // 更新运行结果 + this.$emit('update:retResult', data.retResult) // 更新返回结果 + }, + runCodeCb2 (data) { + // 正常返回结果 + if (data) { + const photo = data.photoUrl + const result = data.runResult || '' + this.$emit('cache') // 每次运行代码都要把代码传给后端做缓存 + if (this.loadIns) this.loadIns.close() + this.picSrcList = [] + this.$emit('update:photoUrl', '') + if (photo) { + this.picSrcList = photo.split(',') + this.$emit('update:photoUrl', photo) + } + this.$emit('update:codeId', data.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 = data.retResult // 对错隐藏 + const text = result.replace(photo, '') // 结果里包含了图片路径,所以要把图片路径给去掉 + this.runResult = text + this.picSrcList = photo.split(',') + this.errLine = this.getErrLine(result) + } else if (imgList instanceof Array && imgList.length && typeof firtImg === 'string' && (firtImg.includes('.jpg') || firtImg.includes('.png') || firtImg.includes('img'))) { + /** + * 这段是为要下载图片的项目案例写的,后端会返回图片名称的数组,前端负责循环这个数组,然后下载下来 + */ + 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 = this.getErrLine(result) + } + } + }, // 运行代码 runCode (isWhile) { // isWhile为true表示代码里有while循环,右边的运行结果需要拼接展示,而不是直接覆盖 if (!this.isSubmit) { @@ -657,6 +770,7 @@ export default { this.sourceCode = code if (!isWhile) this.runResult = '' + this.handleRunCodeCb('runCodeCb1') this.$post(this.api.runPythonCode, { code, bcId, @@ -664,37 +778,23 @@ export default { projectId, type: 0 }).then(res => { - const data = res.code - const result = data.runResult - if (result.includes('File ')) { - if (isWhile) { - this.runResult += result - } else { - this.runResult = result - } - this.errLine = this.getErrLine(result) - this.isError = data.retResult - } else if (result.includes('validing:')) { - this.isError = 1 - this.confirmInput(result) - } this.$emit('update:finalCode', code) - this.$emit('update:codeId', res.codeId) // 更新coddeId - this.$emit('update:answer', this.runResult) // 更新运行结果 - this.$emit('update:retResult', data.retResult) // 更新返回结果 }).catch(err => { this.loadIns.close() }) } else { this.loadIns = Loading.service({ - text: '代码运行中请稍等几分钟', - background: 'transparent' + text: '代码运行中,请稍候', + background: 'transparent', + customClass: 'code-load', }) // 如果代码有savefig(python里的保存图片的方法),则要把savefig里的图片名字加上个时间戳,防止后台保存图片到服务器的时候图片名字重复导致覆盖 code = code.replace(/\.savefig\(([\u4e00-\u9fa5\w]*?['"])/mg, str => { return str + Date.now() }) // 把代码传给后端,在后端运行Python代码 + + this.handleRunCodeCb('runCodeCb2') this.$post(this.api.runPythonCode, { code, bcId, @@ -702,55 +802,7 @@ export default { projectId, type: 0 }).then(res => { - // 正常返回结果 - if (res.code) { - const data = res.code - const photo = data.photoUrl - const result = data.runResult || '' - this.$emit('cache') // 每次运行代码都要把代码传给后端做缓存 - this.loadIns.close() - this.picSrcList = [] - this.$emit('update:photoUrl', '') - if (photo) { - this.picSrcList = photo.split(',') - this.$emit('update:photoUrl', photo) - } - this.$emit('update:finalCode', code) - 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 = data.retResult // 对错隐藏 - const text = result.replace(photo, '') // 结果里包含了图片路径,所以要把图片路径给去掉 - this.runResult = text - this.picSrcList = photo.split(',') - this.errLine = this.getErrLine(result) - } else if (imgList instanceof Array && imgList.length && typeof firtImg === 'string' && (firtImg.includes('.jpg') || firtImg.includes('.png') || firtImg.includes('img'))) { - /** - * 这段是为要下载图片的项目案例写的,后端会返回图片名称的数组,前端负责循环这个数组,然后下载下来 - */ - 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 = this.getErrLine(result) - } - } else if (res.data && res.data.current) { - // 进入运行队列 - this.$message.success(`当前队列有${res.data.current - 1}人在排队,请稍等!`) - this.loadIns.close() - } + this.$emit('update:finalCode', code) }).catch(res => { this.isError = false this.runResult = '' diff --git a/src/config/index.js b/src/config/index.js index acebe26..824c44e 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -13,9 +13,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.217:9000/' + host = 'http://192.168.31.51:9000/' // host = 'http://121.37.12.51:9000/' - host = 'https://occupationlab.com/' + // host = 'https://occupationlab.com/' bankPath = `http://${location.hostname}:8093` } else if (isPro) { host = 'https://occupationlab.com/' diff --git a/src/styles/common.scss b/src/styles/common.scss index facf3f7..34185af 100644 --- a/src/styles/common.scss +++ b/src/styles/common.scss @@ -99,3 +99,7 @@ body .cus-table.el-table { text-align: left; line-height: 30px; } + +.code-load { + bottom: 50px !important; +}