yujialong 4 years ago
parent ef8522d1e1
commit 707e739922
  1. 144
      package-lock.json
  2. 1
      package.json
  3. 6
      src/api/index.js
  4. 42
      src/components/doReview/index.vue
  5. 124
      src/components/pdf/index.vue
  6. 5
      src/libs/util.js
  7. 70
      src/mixins/file/index.js
  8. 291
      src/pages/achievement/detail/index.vue
  9. 4
      src/pages/achievement/list/examResults.vue
  10. 75
      src/pages/achievement/statistics/index.vue
  11. 81
      src/pages/assessment/detail/index.vue
  12. 343
      src/pages/assessment/doReview/index.vue
  13. 4
      src/pages/assessment/review/index.vue
  14. 2
      src/pages/assessment/scoreQuery/index.vue
  15. 33
      src/pages/practice/detail/index.vue
  16. 43
      src/pages/practice/doReview/index.vue
  17. 3
      src/pages/quesBank/list/myQuesBank.vue
  18. 266
      src/pages/system/list/role.vue
  19. 2
      src/pages/testPaper/add/index.vue
  20. 4
      src/pages/testPaper/list/myTestPaper.vue
  21. 6
      src/router/modules/achievement.js
  22. 18
      src/router/modules/assessment.js
  23. 5
      src/router/modules/testPaper.js
  24. 9
      src/setting.js

144
package-lock.json generated

@ -1039,8 +1039,7 @@
"@types/json-schema": { "@types/json-schema": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
"dev": true
}, },
"@types/minimatch": { "@types/minimatch": {
"version": "3.0.3", "version": "3.0.3",
@ -1597,8 +1596,7 @@
"ajv-keywords": { "ajv-keywords": {
"version": "3.4.1", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
"integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ=="
"dev": true
}, },
"alphanum-sort": { "alphanum-sort": {
"version": "1.0.2", "version": "1.0.2",
@ -2099,6 +2097,11 @@
"resolve": "^1.4.0" "resolve": "^1.4.0"
} }
}, },
"babel-plugin-syntax-dynamic-import": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
"integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo="
},
"babel-polyfill": { "babel-polyfill": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
@ -9332,6 +9335,11 @@
"sha.js": "^2.4.8" "sha.js": "^2.4.8"
} }
}, },
"pdfjs-dist": {
"version": "2.5.207",
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.5.207.tgz",
"integrity": "sha512-xGDUhnCYPfHy+unMXCLCJtlpZaaZ17Ew3WIL0tnSgKFUZXHAPD49GO9xScyszSsQMoutNDgRb+rfBXIaX/lJbw=="
},
"performance-now": { "performance-now": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@ -10435,6 +10443,71 @@
"unpipe": "1.0.0" "unpipe": "1.0.0"
} }
}, },
"raw-loader": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
"integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
},
"dependencies": {
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
},
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"json5": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
"requires": {
"minimist": "^1.2.5"
}
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"schema-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
"requires": {
"@types/json-schema": "^7.0.6",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
}
}
},
"read-pkg": { "read-pkg": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -12807,6 +12880,44 @@
"vue-style-loader": "^4.1.0" "vue-style-loader": "^4.1.0"
} }
}, },
"vue-pdf": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/vue-pdf/-/vue-pdf-4.2.0.tgz",
"integrity": "sha512-GpAbZfM48Hom1R8f4XL5ZzoVBLlbyy+4z0VYmTQORVOSieVIIu+XtnNl0RY6EXg60Qni6T6nIgrmsCcCkWv39A==",
"requires": {
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"loader-utils": "^1.4.0",
"pdfjs-dist": "^2.5.207",
"raw-loader": "^4.0.1",
"vue-resize-sensor": "^2.0.0",
"worker-loader": "^2.0.0"
},
"dependencies": {
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"requires": {
"minimist": "^1.2.0"
}
},
"loader-utils": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
"integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^1.0.1"
}
}
}
},
"vue-quill-editor": { "vue-quill-editor": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz", "resolved": "https://registry.npmjs.org/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz",
@ -12816,6 +12927,11 @@
"quill": "^1.3.4" "quill": "^1.3.4"
} }
}, },
"vue-resize-sensor": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/vue-resize-sensor/-/vue-resize-sensor-2.0.0.tgz",
"integrity": "sha512-W+y2EAI/BxS4Vlcca9scQv8ifeBFck56DRtSwWJ2H4Cw1GLNUYxiZxUHHkuzuI5JPW/cYtL1bPO5xPyEXx4LmQ=="
},
"vue-router": { "vue-router": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.3.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.3.tgz",
@ -13389,6 +13505,26 @@
"errno": "~0.1.7" "errno": "~0.1.7"
} }
}, },
"worker-loader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz",
"integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==",
"requires": {
"loader-utils": "^1.0.0",
"schema-utils": "^0.4.0"
},
"dependencies": {
"schema-utils": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
"integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
"requires": {
"ajv": "^6.1.0",
"ajv-keywords": "^3.1.0"
}
}
}
},
"wrap-ansi": { "wrap-ansi": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",

@ -23,6 +23,7 @@
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-cropperjs": "^3.0.0", "vue-cropperjs": "^3.0.0",
"vue-i18n": "^8.10.0", "vue-i18n": "^8.10.0",
"vue-pdf": "^4.2.0",
"vue-quill-editor": "^3.0.6", "vue-quill-editor": "^3.0.6",
"vue-router": "^3.0.3", "vue-router": "^3.0.3",
"vue-schart": "^2.0.0", "vue-schart": "^2.0.0",

@ -1,5 +1,5 @@
import Setting from '@/setting' import Setting from '@/setting'
let uploadURL = Setting.apiUploadURL let uploadURL = Setting.upload.apiURL
export default { export default {
// 登录  // 登录 
logins: `management/userInfo/login`, logins: `management/userInfo/login`,
@ -166,7 +166,9 @@ export default {
savepaperRecord:`management/paperRecord/save`, savepaperRecord:`management/paperRecord/save`,
teacherByGetAchievement:`management/paperRecord/teacherByGetAchievement`, teacherByGetAchievement:`management/paperRecord/teacherByGetAchievement`,
achievementStatistics:`/management/paperRecord/achievementStatistics`, achievementStatistics:`/management/paperRecord/achievementStatistics`,
exportAssessment:`/management/paperRecord/export`, exportAssessment:`${Setting.apiBaseURL}/management/paperRecord/export`,
getRanking:`/management/paperRecord/getRanking`,
getRankingExport:`${Setting.apiBaseURL}/management/paperRecord/getRankingExport`,
// 留言板 // 留言板
delComment:`/management/messageBoard/delComment`, delComment:`/management/messageBoard/delComment`,

@ -43,6 +43,13 @@
<span class="key">知识点</span> <span class="key">知识点</span>
<span class="val">{{item.knowledge_points}}</span> <span class="val">{{item.knowledge_points}}</span>
</div> </div>
<div class="meta" v-if="item.isSub">
<p class="key">附件</p>
<div class="val">
<el-button v-if="item.fileUrl || item.videoAudio" type="text" @click="preview(item)">{{item.fileName}}</el-button>
<el-button v-if="item.fileUrl" type="primary" size="mini" @click="download(item)">下载</el-button>
</div>
</div>
<div class="meta"> <div class="meta">
<span class="key">答案解析</span> <span class="key">答案解析</span>
<span class="val">{{item.answer_analysis}}</span> <span class="val">{{item.answer_analysis}}</span>
@ -66,13 +73,22 @@
<button type="button" class="submit" @click="save(1)">提交</button> <button type="button" class="submit" @click="save(1)">提交</button>
<button type="button" @click="save(0)">保存</button> <button type="button" @click="save(0)">保存</button>
</div> </div>
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{active: playAuth}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="player" id="player"></div>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div> </div>
</template> </template>
<script> <script>
import mixins from '@/mixins/setBackground' import setBackground from '@/mixins/setBackground'
import file from '@/mixins/file'
import { mapState,mapGetters,mapActions } from 'vuex' import { mapState,mapGetters,mapActions } from 'vuex'
import pdf from '@/components/pdf'
export default { export default {
mixins: [ mixins ], mixins: [ setBackground,file ],
data() { data() {
return { return {
paperName: '', paperName: '',
@ -99,6 +115,7 @@ export default {
val == 1 ? this.getData() : this.getWrong() val == 1 ? this.getData() : this.getWrong()
} }
}, },
components: { pdf },
mounted() { mounted() {
this.getData() this.getData()
}, },
@ -118,6 +135,16 @@ export default {
n.answer = answer.join('|') n.answer = answer.join('|')
n.user_answer = n.user_answer.replace(/&lt;&gt;/g,'|') n.user_answer = n.user_answer.replace(/&lt;&gt;/g,'|')
} }
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
}) })
this.list = list this.list = list
this.paperName = list[0].name this.paperName = list[0].name
@ -131,8 +158,7 @@ export default {
this.$post(`${this.api.getWrong}?assessmentId=${this.reviewId}&userId=${this.stuId}&paperId=${this.paperId}`) this.$post(`${this.api.getWrong}?assessmentId=${this.reviewId}&userId=${this.stuId}&paperId=${this.paperId}`)
.then(res => { .then(res => {
this.list = res.data.list this.list = res.data.list
}) }).catch(err => {})
.catch(err => {})
}, },
save(status) { save(status) {
let isEmpty = false let isEmpty = false
@ -283,4 +309,12 @@ export default {
} }
} }
} }
.player{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 1200px !important;
height: 600px !important;
}
</style> </style>

@ -0,0 +1,124 @@
<template>
<div>
<el-dialog
custom-class="pdf-dia"
:close-on-click-modal="false"
:visible.sync="visible"
@close="closePdf"
:fullscreen="true"
:modal="false"
:append-to-body="true">
<div>
<button type="button" aria-label="Close" class="el-dialog__headerbtn" @click="closePdf"><i class="el-dialog__close el-icon el-icon-close"></i></button>
<div class="pdf">
<p class="arrow">
<span @click="changePdfPage(0)" class="turn el-icon-arrow-left" :class="{grey: currentPage==1}"></span>
{{currentPage}} / {{pageCount}}
<span @click="changePdfPage(1)" class="turn el-icon-arrow-right" :class="{grey: currentPage==pageCount}"></span>
</p>
<pdf
class="pdf-wrap"
:src="src"
:page="currentPage"
@num-pages="pageCount=$event"
@page-loaded="currentPage=$event"
@loaded="loadPdfHandler"
>
</pdf>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import pdf from "vue-pdf";
export default {
props: ['visible','src'],
data() {
return {
pdfVisible: false,
pdfSrc: '',
currentPage: 0,
pageCount: 0,
fileType: 'pdf',
};
},
components: { pdf },
mounted(){
this.addEvent()
},
methods: {
closePdf(){
this.$emit('update:visible',false)
this.$emit('update:src','')
this.currentPage = 1
},
changePdfPage (val) {
if (val === 0 && this.currentPage > 1) {
this.currentPage--
}
if (val === 1 && this.currentPage < this.pageCount) {
this.currentPage++
}
},
loadPdfHandler (e) {
this.currentPage = 1
},
addEvent(){
document.onkeydown = e => {
let key = window.event.keyCode
if(key == 37){
this.changePdfPage(0)
}else if(key == 39){
this.changePdfPage(1)
}
}
this.$once('hook:beforeDestroy',() => {
document.onkeydown = null
})
}
}
};
</script>
<style lang="scss" scoped>
/deep/.pdf-dia{
border-radius: 0 !important;
.el-dialog__header{
display: none;
}
.el-dialog__body{
padding: 0;
}
.el-dialog__headerbtn{
top: 10px;
.el-dialog__close{
color: #fff;
font-size: 16px;
}
}
.pdf{
.arrow{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 10px 0;
font-size: 16px;
color: #fff;
background-color: #333;
.turn{
margin: 0 10px;
font-size: 18px;
cursor: pointer;
}
}
.pdf-wrap{
height: calc(100vh - 45px);
margin: 0 auto;
overflow: auto;
}
}
}
</style>

@ -73,6 +73,11 @@ const util = {
if('jpg,jpeg,png,gif,svg,psd'.includes(ext)) return true if('jpg,jpeg,png,gif,svg,psd'.includes(ext)) return true
return false return false
}, },
// 传入文件后缀判断是否是pdf以外的文档
isDoc(ext) {
if(!util.isVideo(ext) && !util.isAudio(ext) && !util.isImg(ext) && ext != 'pdf') return true
return false
},
// 循环去除html标签 // 循环去除html标签
removeHtmlTag(list,attr) { removeHtmlTag(list,attr) {
list.map(n => { list.map(n => {

@ -0,0 +1,70 @@
import util from '@/libs/util'
export default {
data() {
return {
playAuth: '',
player: null,
iframeSrc: '',
pdfVisible: false,
pdfSrc: ''
}
},
mounted() {
this.insertScript()
},
methods: {
preview(row){
let ext = row.fileurl.substring(row.fileurl.lastIndexOf('.') + 1)
console.log(11,row.fileurl,row.fileurl.lastIndexOf('.'),ext)
if(row.videoAudio){
this.$get(`${this.api.getPlayAuth}/${row.fileurl}`).then(res => {
this.playAuth = res.data.playAuth
if(this.player){
this.player.replayByVidAndPlayAuth(row.fileurl,this.playAuth)
}else{
console.log(11,row,res.data.playAuth)
this.player = new Aliplayer({
id: 'player',
width: '100%',
autoplay: false,
vid : row.fileurl,
playauth : this.playAuth,
encryptType:1, //当播放私有加密流时需要设置。
})
}
}).catch(res => {})
}else if(ext == 'pdf'){
this.pdfSrc = row.fileurl
this.pdfVisible = true
}else if(util.isDoc(ext)){
window.open(`https://view.officeapps.live.com/op/view.aspx?src=${row.fileurl}`)
}else if(util.isImg(ext)){
window.open(row.fileurl)
}
},
insertScript(){
const linkTag = document.createElement('link')
linkTag.id = 'aliplayerLink'
linkTag.rel = 'stylesheet'
linkTag.href = 'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css'
document.body.appendChild(linkTag)
const scriptTag = document.createElement('script')
scriptTag.id = 'aliplayerScript'
scriptTag.type = 'text/javascript'
scriptTag.src = 'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js'
document.body.appendChild(scriptTag)
this.$once('hook:beforeDestroy', function () {
document.body.removeChild(document.querySelector('#aliplayerLink'))
document.body.removeChild(document.querySelector('#aliplayerScript'))
})
},
closePlayer(){
this.playAuth = ''
this.player.pause()
},
download(row){
window.open(row.fileurl)
}
}
}

@ -1,291 +0,0 @@
<template>
<div class="box">
<h1 class="title">{{paperName }}</h1>
<div class="metas">
<div class="m-r-20">
<span class="name">总分</span>
<span class="val">100</span>
</div>
<div class="m-r-20" v-if="thisScore != null">
<span class="name">得分</span>
<span class="val">{{thisScore}}</span>
</div>
<div class="m-r-20">
<span class="name">考试时长</span>
<span class="val">{{time}}分钟</span>
</div>
<div>
<span class="name">排名</span>
<span class="val">{{ranking === 0 ? 1 : ranking}}</span>
</div>
</div>
<ul class="tab">
<template v-for="(item,index) in tabs">
<li v-if="item.show" :key="index" :class="{active: active == item.id}" @click="tabChange(item.id)">{{item.name}}</li>
</template>
</ul>
<div class="wrap">
<div class="item" v-for="(item,index) in curType" :key="index">
<div class="answer">
<div class="info">
<p class="key">序号</p>
<p class="val">{{index+1}}</p>
</div>
<div class="info">
<p class="key">得分</p>
<p class="val">{{item.question_score}}</p>
</div>
</div>
<div class="meta">
<p class="key">题干</p>
<p class="val" v-html="item.question_stem"></p>
</div>
<div class="meta">
<p class="key">选项</p>
<div class="val">
<p v-for="(option,i) in item.options" :key="i">{{i}}.{{item.options[i]}}</p>
</div>
</div>
<div class="meta ans">
<div class="info">
<p class="key">正确答案</p>
<p class="val">{{item.answer}}</p>
</div>
<div class="info">
<p class="key">学生答案</p>
<p class="val">{{item.user_answer}}</p>
</div>
</div>
<div class="meta">
<p class="key">答案解析</p>
<p class="val" v-html="item.answer_analysis"></p>
</div>
</div>
</div>
</div>
</template>
<script>
import mixins from '@/mixins/setBackground'
import { mapState } from 'vuex'
export default {
mixins: [ mixins ],
data() {
return {
paperName: '',
time: 0,
ranking: 1,
selectVisible: false,
tabs: [
{
id: 1,
name: '单选题',
show: false
},{
id: 2,
name: '多选题',
show: false
},{
id: 3,
name: '判断题',
show: false
},{
id: 4,
name: '简答题',
show: false
},{
id: 5,
name: '填空题',
show: false
}
],
active: 1,
curType: []
};
},
computed: {
...mapState('user', [
'userId'
]),
...mapState('achievement', [
'id','assessmentId','stuId','thisScore'
])
},
mounted() {
this.getData()
},
methods: {
getData() {
this.$post(`${this.api.answerDetail}?userId=${this.stuId}&assessmentId=${this.assessmentId}&paperId=${this.id}`)
.then(res => {
this.paperName = res.paperName
this.time = res.time
this.ranking = res.ranking
this.allData = res.data
let tabs = this.tabs
res.data.list1.length && (tabs[0].show = true)
res.data.list2.length && (tabs[1].show = true)
res.data.list3.length && (tabs[2].show = true)
res.data.list4.length && (tabs[3].show = true)
res.data.list5.length && (tabs[4].show = true)
for(let n of tabs){
if(n.show){
this.active = n.id
this.curType = this.allData[`list${n.id}`]
break
}
}
this.handleOptions()
})
.catch(err => {})
},
tabChange(id){
this.active = id
this.curType = this.allData[`list${id}`]
this.handleOptions()
},
handleOptions(){
let curType = this.curType
curType.forEach(n => {
if(!n.options){
let options = {}
let answer = []
for(let i in n){
if(i.includes('option') && n[i]){
options[i.replace('option_','')] = n[i]
if(n.typeName == '填空题') answer.push(n[i])
}
}
if(n.typeName == '填空题') n.answer = answer.join('|')
n.options = options
}
})
this.curType = curType
}
},
};
</script>
<style lang="scss" scoped>
.box{
width: 90%;
margin: 0 auto;
}
.title{
text-align: center;
font-size: 18px;
font-weight: 600;
}
.metas{
display: flex;
justify-content: center;
margin: 20px 0 30px;
.name{
font-size: 12px;
color: #717171;
}
.val{
font-size: 12px;
color: #929292;
}
}
.tab{
display: flex;
align-items: center;
margin-bottom: 10px;
li{
position: relative;
padding: 0 44px;
margin-right: 7px;
font-size: 13px;
line-height: 46px;
text-align: center;
color: #444;
border: 1px solid #ececec;
cursor: pointer;
&:hover{
opacity: .8;
}
&.active:after{
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background-color: $main-color;
}
}
}
.wrap{
.item{
padding-bottom: 30px;
margin-bottom: 30px;
border-bottom: 1px dashed #f4f4f4;
.key{
font-weight: bold;
color: #333;
font-size: 14px;
}
.val{
color: #757575;
font-size: 14px;
}
.answer{
display: flex;
align-items: center;
padding: 15px;
margin: 15px 0;
font-size: 12px;
border: 1px solid #e8e8e8;
background-color: #f3f2f2;
.info{
display: inline-flex;
align-items: center;
margin-right: 30px;
}
}
.meta{
padding-left: 10px;
margin: 20px 0;
font-size: 12px;
&.ans{
display: flex;
.info{
margin-right: 20px;
}
}
.key{
margin-bottom: 5px;
}
}
}
}
.btns{
display: flex;
justify-content: center;
margin-top: 20px;
button{
height: 30px;
padding: 0 30px;
margin: 0 15px;
font-size: 14px;
color: #333;
line-height: 30px;
background-color: #fff;
border: 1px solid #ededed;
border-radius: 4px;
cursor: pointer;
&.submit{
color: #fff;
background-color: $main-color;
border-color: $main-color;
}
&:hover{
opacity: .8;
}
}
}
</style>

@ -183,7 +183,7 @@ export default {
stuId: row.stuId, stuId: row.stuId,
thisScore: row.thisScore thisScore: row.thisScore
}) })
this.$router.push('detail') this.$router.push('/assessment/detail')
}, },
toStat(){ toStat(){
if(this.listData.length){ if(this.listData.length){
@ -202,7 +202,7 @@ export default {
} }
}, },
exportData(){ exportData(){
location.href = `${Setting.apiBaseURL}${this.api.exportAssessment}?assessmentId=${this.assessmentId}&classId=${this.classId}&userId=${this.userId}` location.href = `${this.api.exportAssessment}?assessmentId=${this.assessmentId}&classId=${this.classId}&userId=${this.userId}`
}, },
} }
}; };

@ -1,5 +1,6 @@
<template> <template>
<div class="box"> <div>
<div class="box">
<div class="left"> <div class="left">
<div class="title">基本信息</div> <div class="title">基本信息</div>
<div class="info"> <div class="info">
@ -49,6 +50,52 @@
</div> </div>
</div> </div>
</div> </div>
<el-card shadow="hover" class="m-b-20">
<div class="flex j-between m-b-20">
<div class="p-title">考试成绩</div>
<div>
<el-button
type="primary"
size="small"
round
@click="exportData"
>导出</el-button>
</div>
</div>
<el-table
:data="listData"
ref="table"
row-key="id"
class="table"
stripe
header-align="center"
>
<el-table-column type="index" width="100" label="序号" align="center">
<template
slot-scope="scope"
>{{scope.$index + (page - 1) * pageSize + 1}}</template>
</el-table-column>
<el-table-column prop="paperName" label="试卷名称" align="center"></el-table-column>
<el-table-column prop="userName" label="学生姓名" align="center"></el-table-column>
<el-table-column prop="workNumber" label="学号" align="center"></el-table-column>
<el-table-column prop="score" label="得分" align="center"></el-table-column>
<el-table-column prop="rank" label="名次" align="center"></el-table-column>
</el-table>
<div class="pagination">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-size="pageSize"
layout="total,prev, pager, next"
:total="total"
></el-pagination>
</div>
</el-card>
</div>
</template> </template>
<script> <script>
import { mapState,mapGetters } from 'vuex' import { mapState,mapGetters } from 'vuex'
@ -69,7 +116,11 @@ export default {
startTime: '', startTime: '',
totalScore: '', totalScore: '',
}, },
statData: [] statData: [],
listData: [],
page: 1,
pageSize: 10,
total: 0,
}; };
}, },
computed: { computed: {
@ -82,6 +133,7 @@ export default {
}, },
mounted() { mounted() {
this.getData() this.getData()
this.getList()
}, },
methods: { methods: {
getData() { getData() {
@ -102,11 +154,13 @@ export default {
title: { text: '成绩分布图' }, title: { text: '成绩分布图' },
tooltip: {}, tooltip: {},
xAxis: { xAxis: {
name: '分数',
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80','81-90','91-100'] data: ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80','81-90','91-100']
}, },
yAxis: { yAxis: {
name: '人数',
type: 'value' type: 'value'
}, },
series: [{ series: [{
@ -115,6 +169,21 @@ export default {
areaStyle: {} areaStyle: {}
}] }]
}) })
},
getList() {
this.$get(`${this.api.getRanking}?pageNum=${this.page}&pageSize=${this.pageSize}&assessmentId=${this.assessmentId}`)
.then(res => {
this.listData = res.data.list.list
this.total = res.data.list.totalCount
})
.catch(err => {})
},
handleCurrentChange(val) {
this.page = val
this.getList()
},
exportData(){
location.href = `${this.api.getRankingExport}?assessmentId=${this.assessmentId}`
} }
}, },
}; };
@ -125,7 +194,7 @@ export default {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
width: 90%; width: 90%;
margin: 0 auto; margin: 0 auto 20px;
.title{ .title{
padding-left: 5px; padding-left: 5px;
border-left: 5px solid #cb221c; border-left: 5px solid #cb221c;

@ -2,17 +2,21 @@
<div class="box"> <div class="box">
<h1 class="title">{{paperName }}</h1> <h1 class="title">{{paperName }}</h1>
<div class="metas"> <div class="metas">
<div style="margin-right: 20px;"> <div class="m-r-20">
<span class="name">总分</span> <span class="name">总分</span>
<span class="val">100</span> <span class="val">100</span>
</div> </div>
<div style="margin-right: 20px;"> <div class="m-r-20" v-if="thisScore != null">
<span class="name">得分</span> <span class="name">得分</span>
<span class="val">{{thisScore}}</span> <span class="val">{{thisScore}}</span>
</div> </div>
<div> <div class="m-r-20">
<span class="name">考试时长</span> <span class="name">考试时长</span>
<span class="val">{{timeSpent}}分钟</span> <span class="val">{{time}}分钟</span>
</div>
<div>
<span class="name">排名</span>
<span class="val">{{ranking === 0 ? 1 : ranking}}</span>
</div> </div>
</div> </div>
@ -54,23 +58,40 @@
<p class="val">{{item.user_answer}}</p> <p class="val">{{item.user_answer}}</p>
</div> </div>
</div> </div>
<div class="meta" v-if="active == 4">
<p class="key">附件</p>
<div class="val">
<el-button v-if="item.fileUrl || item.videoAudio" type="text" @click="preview(item)">{{item.fileName}}</el-button>
<el-button v-if="item.fileUrl" type="primary" size="mini" @click="download(item)">下载</el-button>
</div>
</div>
<div class="meta"> <div class="meta">
<p class="key">答案解析</p> <p class="key">答案解析</p>
<p class="val" v-html="item.answer_analysis"></p> <p class="val" v-html="item.answer_analysis"></p>
</div> </div>
</div> </div>
</div> </div>
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{active: playAuth}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="player" id="player"></div>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div> </div>
</template> </template>
<script> <script>
import mixins from '@/mixins/setBackground' import setBackground from '@/mixins/setBackground'
import file from '@/mixins/file'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import pdf from '@/components/pdf'
export default { export default {
mixins: [ mixins ], mixins: [ setBackground,file ],
data() { data() {
return { return {
paperName: '', paperName: '',
time: 0, time: 0,
ranking: 1,
selectVisible: false, selectVisible: false,
tabs: [ tabs: [
{ {
@ -99,12 +120,13 @@ export default {
curType: [] curType: []
}; };
}, },
components: { pdf },
computed: { computed: {
...mapState('user', [ ...mapState('user', [
'userId' 'userId'
]), ]),
...mapState('achievement', [ ...mapState('achievement', [
'id','assessmentId','stuId','timeSpent','thisScore' 'id','assessmentId','stuId','thisScore'
]) ])
}, },
mounted() { mounted() {
@ -116,6 +138,20 @@ export default {
.then(res => { .then(res => {
this.paperName = res.paperName this.paperName = res.paperName
this.time = res.time this.time = res.time
this.ranking = res.ranking
res.data.list4.map(n => {
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
})
this.allData = res.data this.allData = res.data
let tabs = this.tabs let tabs = this.tabs
res.data.list1.length && (tabs[0].show = true) res.data.list1.length && (tabs[0].show = true)
@ -257,29 +293,12 @@ export default {
} }
} }
} }
.btns{ .player{
display: flex; position: absolute;
justify-content: center; top: 50%;
margin-top: 20px; left: 50%;
button{ transform: translate(-50%,-50%);
height: 30px; width: 1200px !important;
padding: 0 30px; height: 600px !important;
margin: 0 15px;
font-size: 14px;
color: #333;
line-height: 30px;
background-color: #fff;
border: 1px solid #ededed;
border-radius: 4px;
cursor: pointer;
&.submit{
color: #fff;
background-color: $main-color;
border-color: $main-color;
}
&:hover{
opacity: .8;
}
}
} }
</style> </style>

@ -0,0 +1,343 @@
<template>
<div class="box">
<h1 class="title">{{paperName}}</h1>
<div class="metas">
<div>
<span class="name">学生姓名</span>
<span class="val">{{userName}}</span>
</div>
<div>
<span class="name">学生得分</span>
<span class="val">{{(reviewStatus == 2 || reviewStatus == 3) ? this_score : '--'}}</span>
</div>
<div>
<span class="name">试卷总分</span>
<span class="val">100</span>
</div>
<div>
<span class="name">练习时长</span>
<span class="val">{{duration}}</span>
</div>
</div>
<div class="wrap">
<div class="select">
<el-radio v-model="look" label="1">查看全部</el-radio>
<el-radio v-model="look" label="2" v-if="reviewStatus == 2 || reviewStatus == 3">只看错题</el-radio>
</div>
<div class="item" v-for="(item,index) in list" :key="index">
<div class="status" :class="{done: item.isCorrecting}">{{item.isSub ? '简答题' : '客观题'}}{{getCorrectingName(item.isCorrecting)}}</div>
<div class="name" v-html="item.question_stem"></div>
<div class="answer">
<div class="info" v-if="!item.isSub">
<p class="key">正确答案</p>
<p class="val">{{item.answer}}</p>
</div>
<div class="info">
<p class="key">学生答案</p>
<p class="val">{{item.user_answer}}</p>
</div>
</div>
<div class="meta">
<span class="key">知识点</span>
<span class="val">{{item.knowledge_points}}</span>
</div>
<div class="meta" v-if="item.isSub">
<p class="key">附件</p>
<div class="val">
<el-button v-if="item.fileUrl || item.videoAudio" type="text" @click="preview(item)">{{item.fileName}}</el-button>
<el-button v-if="item.fileUrl" type="primary" size="mini" @click="download(item)">下载</el-button>
</div>
</div>
<div class="meta">
<span class="key">答案解析</span>
<span class="val">{{item.answer_analysis}}</span>
</div>
<div class="flex a-center point">
<div class="meta">
<span class="key">题目分数</span>
<div class="val">{{item.question_points}} </div>
</div>
<div class="meta">
<span class="key">考试得分</span>
<div class="val">
<input type="text" v-model.number="item.question_score" :disabled="!isReview || !item.isSub">
</div>
</div>
</div>
</div>
</div>
<div class="btns" v-if="isReview">
<button type="button" class="submit" @click="save(1)">提交</button>
<button type="button" @click="save(0)">保存</button>
</div>
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{active: playAuth}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="player" id="player"></div>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div>
</template>
<script>
import setBackground from '@/mixins/setBackground'
import file from '@/mixins/file'
import { mapState,mapGetters,mapActions } from 'vuex'
import pdf from '@/components/pdf'
export default {
mixins: [ setBackground,file ],
data() {
return {
paperName: '',
userName: '',
this_score: '',
duration: '',
list: [],
look: '1',
};
},
computed: {
...mapState('user', [
'userId','clientId'
]),
...mapState('assessment', [
'reviewId','paperId','isReview','reviewStatus','stuId'
]),
...mapGetters('assessment', [
'getCorrectingName'
])
},
watch: {
look(val,oldVal){
val == 1 ? this.getData() : this.getWrong()
}
},
components: { pdf },
mounted() {
this.getData()
},
methods: {
getData() {
this.$post(`${this.api.correcting}?assessmentId=${this.reviewId}&userId=${this.stuId}&paperId=${this.paperId}`)
.then(res => {
let list = res.data.list
list.map(n => {
n.isCorrecting == 0 && (n.question_score = '')
n.isSub = n.typeName == '简答题'
if(n.typeName == '填空题'){
let answer = []
for(let i in n){
if(i.includes('option_')) answer.push(n[i])
}
n.answer = answer.join('|')
n.user_answer = n.user_answer.replace(/&lt;&gt;/g,'|')
}
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
})
this.list = list
this.paperName = list[0].name
this.userName = list[0].userName
this.this_score = list[0].this_score
this.duration = list[0].duration
})
.catch(err => {})
},
getWrong(){
this.$post(`${this.api.getWrong}?assessmentId=${this.reviewId}&userId=${this.stuId}&paperId=${this.paperId}`)
.then(res => {
let list = res.data.list
list.map(n => {
n.isCorrecting == 0 && (n.question_score = '')
n.isSub = n.typeName == '简答题'
if(n.typeName == '填空题'){
let answer = []
for(let i in n){
if(i.includes('option_')) answer.push(n[i])
}
n.answer = answer.join('|')
n.user_answer = n.user_answer.replace(/&lt;&gt;/g,'|')
}
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
})
this.list = list
}).catch(err => {})
},
save(status) {
let isEmpty = false
let isNotNum = false
let invalid = false
this.list.map(n => {
if(n.question_score === '') isEmpty = true
if(isNaN(n.question_score)) isNotNum = true
if(Number(n.question_score) > Number(n.question_points)) invalid = true
})
if(status){
if(isEmpty) return this.$message.warning('请批阅完所有题目')
if(isNotNum) return this.$message.warning('考试得分请输入数字')
}
if(invalid) return this.$message.warning('考试得分不得大于题目分数')
let data = {
review: [],
assessmentId: this.reviewId,
userId: this.stuId,
paperId: this.paperId,
teacherId: this.userId,
}
let totalScore = 0
this.list.map(n => {
n.question_score !== '' && n.isSub && data.review.push({
detailId: Number(n.detailId) ,
score: Number(n.question_score)
})
totalScore += Number(n.question_score)
})
if(!data.review.length) return this.$message.warning('请至少批阅一道题目')
if(status || this.list.filter(n => n.isSub).length == data.review.length){
data.totalScore = totalScore
}
this.$post(this.api.reviewByid,data).then(res => {
this.$message.success(status ? '提交成功' : '保存成功')
this.$router.back()
}).catch(err => {})
},
},
};
</script>
<style lang="scss" scoped>
.title{
text-align: center;
font-size: 18px;
font-weight: 600;
}
.metas{
display: flex;
justify-content: space-between;
margin: 20px 0 30px;
.name{
font-size: 12px;
color: #717171;
}
.val{
font-size: 12px;
color: #929292;
}
}
.wrap{
padding: 20px;
background-color: #fbfbfb;
.select{
padding: 10px;
margin-bottom: 20px;
border-bottom: 1px solid #f4f4f4;
}
.item{
padding-bottom: 30px;
margin-bottom: 30px;
border-bottom: 1px dashed #d2d2d2;
&:last-child{
border-bottom: 0;
}
.status{
color: #cb221c;
&.done{
color: #56d5bf;
}
}
.name{
margin-top: 15px;
font-size: 14px;
color: #555555;
}
.key{
font-weight: bold;
color: #333;
}
.val{
color: #757575;
}
.answer{
display: flex;
align-items: center;
padding: 15px;
margin: 15px 0;
font-size: 12px;
border: 1px solid #e8e8e8;
background-color: #f3f2f2;
.info{
display: inline-flex;
align-items: center;
margin-right: 30px;
}
}
.meta{
display: flex;
align-items: center;
padding-left: 10px;
margin: 10px 0;
font-size: 12px;
.key{
width: 80px;
margin-right: 10px;
text-align: right;
white-space: nowrap;
}
input{
width: 60px;
height: 28px;
padding: 0 5px;
margin-right: 5px;
color: #444;
background-color: #fff;
border: 1px solid #ebebeb;
box-sizing: border-box;
&:focus{
outline: none;
}
&:disabled{
background-color: #e8e8e8;
cursor: not-allowed;
}
}
}
.point{
.meta{
margin: 0;
}
}
}
}
.player{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 1200px !important;
height: 600px !important;
}
</style>

@ -57,7 +57,7 @@
{{getReviewStatusName(scope.row.reviewStatus)}} {{getReviewStatusName(scope.row.reviewStatus)}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center"> <el-table-column label="操作">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" @click="review(scope.row,false)">查看</el-button> <el-button type="text" @click="review(scope.row,false)">查看</el-button>
<el-button type="text" @click="review(scope.row,true)" v-if="(scope.row.reviewStatus == 0 || scope.row.reviewStatus == 1) && scope.row.examinationStatus == 2">批阅</el-button> <el-button type="text" @click="review(scope.row,true)" v-if="(scope.row.reviewStatus == 0 || scope.row.reviewStatus == 1) && scope.row.examinationStatus == 2">批阅</el-button>
@ -154,7 +154,7 @@ export default {
stuId: row.stuId, stuId: row.stuId,
reviewStatus: row.reviewStatus reviewStatus: row.reviewStatus
}) })
this.$router.push('/testPaper/doReview') this.$router.push('doReview')
}, },
} }
}; };

@ -202,7 +202,7 @@ export default {
} }
}, },
exportData(){ exportData(){
location.href = `${this.api.exportAssessment}?assessmentId=${this.assessmentId}&classId=${this.classId}&userId=${this.userId}`
}, },
} }
}; };

@ -54,19 +54,35 @@
<p class="val">{{item.userAnswer}}</p> <p class="val">{{item.userAnswer}}</p>
</div> </div>
</div> </div>
<div class="meta" v-if="active == 4">
<p class="key">附件</p>
<div class="val">
<el-button v-if="item.fileUrl || item.videoAudio" type="text" @click="preview(item)">{{item.fileName}}</el-button>
<el-button v-if="item.fileUrl" type="primary" size="mini" @click="download(item)">下载</el-button>
</div>
</div>
<div class="meta"> <div class="meta">
<p class="key">答案解析</p> <p class="key">答案解析</p>
<p class="val" v-html="item.answerAnalysis"></p> <p class="val" v-html="item.answerAnalysis"></p>
</div> </div>
</div> </div>
</div> </div>
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{active: playAuth}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="player" id="player"></div>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div> </div>
</template> </template>
<script> <script>
import mixins from '@/mixins/setBackground' import setBackground from '@/mixins/setBackground'
import file from '@/mixins/file'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import pdf from '@/components/pdf'
export default { export default {
mixins: [ mixins ], mixins: [ setBackground,file ],
data() { data() {
return { return {
paperName: '', paperName: '',
@ -101,6 +117,7 @@ export default {
curType: [] curType: []
}; };
}, },
components: { pdf },
computed: { computed: {
...mapState('user', [ ...mapState('user', [
'userId' 'userId'
@ -128,6 +145,18 @@ export default {
n.answer = answer.join('|') n.answer = answer.join('|')
n.userAnswer = n.userAnswer ? n.userAnswer.replace(/&lt;&gt;/g,'|') : '' n.userAnswer = n.userAnswer ? n.userAnswer.replace(/&lt;&gt;/g,'|') : ''
} }
if(n.typeName == '简答题'){
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
}
}) })
this.list = data.list this.list = data.list
let tabs = this.tabs let tabs = this.tabs

@ -43,6 +43,13 @@
<span class="key">知识点</span> <span class="key">知识点</span>
<span class="val">{{item.knowledgePoints}}</span> <span class="val">{{item.knowledgePoints}}</span>
</div> </div>
<div class="meta" v-if="item.isSub">
<p class="key">附件</p>
<div class="val">
<el-button v-if="item.fileUrl || item.videoAudio" type="text" @click="preview(item)">{{item.fileName}}</el-button>
<el-button v-if="item.fileUrl" type="primary" size="mini" @click="download(item)">下载</el-button>
</div>
</div>
<div class="meta"> <div class="meta">
<span class="key">答案解析</span> <span class="key">答案解析</span>
<span class="val">{{item.answerAnalysis}}</span> <span class="val">{{item.answerAnalysis}}</span>
@ -66,13 +73,22 @@
<button type="button" class="submit" @click="save(1)">提交</button> <button type="button" class="submit" @click="save(1)">提交</button>
<button type="button" @click="save(0)">保存</button> <button type="button" @click="save(0)">保存</button>
</div> </div>
<div v-show="playAuth" class="el-image-viewer__wrapper" :class="{active: playAuth}" style="z-index: 2000">
<div class="el-image-viewer__mask"></div>
<span class="el-image-viewer__btn el-image-viewer__close" @click="closePlayer"><i class="el-icon-circle-close" style="color: #fff"></i></span>
<div class="player" id="player"></div>
</div>
<pdf :visible.sync="pdfVisible" :src.sync="pdfSrc"></pdf>
</div> </div>
</template> </template>
<script> <script>
import mixins from '@/mixins/setBackground' import setBackground from '@/mixins/setBackground'
import file from '@/mixins/file'
import { mapState,mapGetters,mapActions } from 'vuex' import { mapState,mapGetters,mapActions } from 'vuex'
import pdf from '@/components/pdf'
export default { export default {
mixins: [ mixins ], mixins: [ setBackground,file ],
data() { data() {
return { return {
paperName: '', paperName: '',
@ -99,6 +115,7 @@ export default {
val == 1 ? this.getData() : this.getWrong() val == 1 ? this.getData() : this.getWrong()
} }
}, },
components: { pdf },
mounted() { mounted() {
this.getData() this.getData()
}, },
@ -107,7 +124,7 @@ export default {
this.$post(`${this.api.reviewDetail}?id=${this.id}`) this.$post(`${this.api.reviewDetail}?id=${this.id}`)
.then(res => { .then(res => {
let data = res.data let data = res.data
data.list.forEach(n => { data.list.map(n => {
n.isCorrecting == 0 && (n.questionScore = '') n.isCorrecting == 0 && (n.questionScore = '')
n.isSub = n.typeName == '简答题' n.isSub = n.typeName == '简答题'
if(n.typeName == '填空题'){ if(n.typeName == '填空题'){
@ -118,6 +135,16 @@ export default {
n.answer = answer.join('|') n.answer = answer.join('|')
n.userAnswer = n.userAnswer ? n.userAnswer.replace(/&lt;&gt;/g,'|') : '' n.userAnswer = n.userAnswer ? n.userAnswer.replace(/&lt;&gt;/g,'|') : ''
} }
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
}) })
this.list = data.list this.list = data.list
this.paperName = data.paperName this.paperName = data.paperName
@ -137,6 +164,16 @@ export default {
n.questionPoints = n.question_points n.questionPoints = n.question_points
n.questionScore = n.question_score n.questionScore = n.question_score
n.questionStem = n.question_stem n.questionStem = n.question_stem
if(n.fileUrl){
let file = n.fileUrl.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
if(n.videoAudio){
let file = n.videoAudio.split(',')
n.fileName = file[0]
n.fileurl = file[1]
}
}) })
this.list = list this.list = list
}).catch(err => {}) }).catch(err => {})

@ -386,7 +386,8 @@ export default {
this.$message.success('上传成功') this.$message.success('上传成功')
} }
}else{ }else{
res.message ? this.$message.error(res.message) : this.$message.error('上传失败,请检查数据') // res.message ? this.$message.error(res.message) : this.$message.error('')
res.message && this.$message.error(res.message)
} }
}, },
showFaild(){ showFaild(){

@ -3,7 +3,6 @@
<el-card shadow="hover" class="m-b-20"> <el-card shadow="hover" class="m-b-20">
<div> <div>
<div class="p-title m-b-20">筛选</div> <div class="p-title m-b-20">筛选</div>
<div class="flex"> <div class="flex">
<div> <div>
<el-input placeholder="请输入角色名称" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input> <el-input placeholder="请输入角色名称" prefix-icon="el-icon-search" v-model="keyword" clearable></el-input>
@ -34,10 +33,10 @@
<el-table-column label="操作" width="180"> <el-table-column label="操作" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" @click="showRole(scope.row)" v-auth="'system:角色权限:查看'">查看</el-button> <el-button type="text" @click="showRole(scope.row)" v-auth="'system:角色权限:查看'">查看</el-button>
<template v-if="scope.row.id != 1"> <!-- <template v-if="scope.row.id != 1"> -->
<el-button type="text" @click="editRole(scope.row)" v-auth="'system:角色权限:编辑'">编辑</el-button> <el-button type="text" @click="editRole(scope.row)" v-auth="'system:角色权限:编辑'">编辑</el-button>
<el-button type="text" @click="handleDelete(scope.row)" v-auth="'system:角色权限:删除'">删除</el-button> <el-button type="text" @click="handleDelete(scope.row)" v-auth="'system:角色权限:删除'">删除</el-button>
</template> <!-- </template> -->
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -79,7 +78,7 @@
</template> </template>
<script> <script>
import { mapState } from 'vuex'; import { mapState } from 'vuex'
export default { export default {
name: 'role', name: 'role',
data() { data() {
@ -104,256 +103,13 @@ export default {
isAdd: true, isAdd: true,
roleVisible: false, roleVisible: false,
searchTimer: null, searchTimer: null,
permissions: [ permissions: [],
{
id: 111,
name: '学生管理',
children: [
{
id: 1,
name: '新增学生'
},{
id: 2,
name: '批量导入'
},{
id: 3,
name: '批量删除'
},{
id: 4,
name: '编辑'
},{
id: 5,
name: '重置密码'
},{
id: 6,
name: '删除'
},
]
},{
id: 7,
name: '题库管理',
children: [
{
id: 8,
name: '我上传的题库',
children: [
{
id: 8,
name: '新增'
},{
id: 10,
name: '批量删除'
},{
id: 11,
name: '编辑'
},{
id: 12,
name: '删除'
},
]
},{
id: 13,
name: '公共题库',
children: [
{
id: 14,
name: '新增'
},{
id: 15,
name: '批量删除'
},{
id: 16,
name: '编辑'
},{
id: 17,
name: '删除'
},
]
}
]
},{
id: 18,
name: '试卷管理',
children: [
{
id: 19,
name: '我的试卷',
children: [
{
id: 20,
name: '新增'
},{
id: 21,
name: '批量删除'
},{
id: 22,
name: '编辑'
},{
id: 23,
name: '删除'
},
]
},{
id: 24,
name: '所有试卷',
children: [
{
id: 25,
name: '新增'
},{
id: 27,
name: '编辑'
},{
id: 28,
name: '删除'
},
]
}
]
},{
id: 29,
name: '练习管理',
children: [
{
id: 30,
name: '新增'
},{
id: 32,
name: '编辑'
},{
id: 33,
name: '删除'
},
]
},{
id: 34,
name: '考核管理',
children: [
{
id: 35,
name: '新增'
},{
id: 38,
name: '编辑'
},{
id: 40,
name: '删除'
},
]
},{
id: 41,
name: '成绩管理',
children: [
{
id: 42,
name: '练习成绩',
children: [
{
id: 43,
name: '新增'
},{
id: 44,
name: '批量删除'
},{
id: 45,
name: '编辑'
},{
id: 46,
name: '删除'
},
]
},{
id: 47,
name: '考试成绩',
children: [
{
id: 48,
name: '新增'
},{
id: 49,
name: '批量删除'
},{
id: 50,
name: '编辑'
},{
id: 51,
name: '删除'
},
]
},{
id: 1,
name: '错题收藏',
children: [
{
id: 52,
name: '新增'
},{
id: 54,
name: '批量删除'
},{
id: 55,
name: '编辑'
},{
id: 56,
name: '删除'
},
]
}
]
},{
id: 57,
name: '系统设置',
children: [
{
id: 58,
name: '员工管理',
children: [
{
id: 59,
name: '新增'
},{
id: 60,
name: '批量删除'
},{
id: 61,
name: '编辑'
},{
id: 62,
name: '删除'
},
]
},{
id: 63,
name: '角色权限',
children: [
{
id: 64,
name: '新增'
},{
id: 65,
name: '批量删除'
},{
id: 66,
name: '编辑'
},{
id: 67,
name: '删除'
},
]
}
]
},{
id: 68,
name: '交流互动',
children: []
},
],
checkedIds: [] checkedIds: []
}; };
}, },
computed: { computed: {
...mapState('user', [ ...mapState('user', [
'clientId','clientName' 'userId','clientId'
]) ])
}, },
watch: { watch: {
@ -378,7 +134,7 @@ export default {
this.$get(`${this.api.queryRoles}/${this.pageNo}/${this.pageSize}`,data).then(res => { this.$get(`${this.api.queryRoles}/${this.pageNo}/${this.pageSize}`,data).then(res => {
this.roleData = res.data.items this.roleData = res.data.items
this.totals = res.data.total this.totals = res.data.total
}).catch(res => {}) }).catch(res => {});
}, },
closeRole(){ closeRole(){
this.isDetail = false this.isDetail = false
@ -387,8 +143,8 @@ export default {
remark : '', remark : '',
id: '' id: ''
} }
// this.checkedIds = [] this.checkedIds = []
// this.permissions = [] this.permissions = []
}, },
currentChange(val) { currentChange(val) {
this.pageNo = val; this.pageNo = val;
@ -397,7 +153,7 @@ export default {
getPer(){ getPer(){
if(!this.permissions.length){ if(!this.permissions.length){
this.$get(this.api.queryPermissionMenu).then(res => { this.$get(this.api.queryPermissionMenu).then(res => {
// this.permissions = res.data.children[0].children this.permissions = res.data.children[0].children
}).catch(res => {}) }).catch(res => {})
} }
}, },
@ -405,7 +161,7 @@ export default {
this.isAdd = true this.isAdd = true
this.getPer() this.getPer()
this.checkedIds = [] this.checkedIds = []
// this.permissions.length && this.$refs.per.setCheckedNodes([]) this.permissions.length && this.$refs.per.setCheckedNodes([])
this.roleVisible = true this.roleVisible = true
}, },
handleRolePer(data,permissions){ handleRolePer(data,permissions){
@ -428,7 +184,7 @@ export default {
let perRes = await this.$get(`${this.api.toAssign}/${row.id}`) let perRes = await this.$get(`${this.api.toAssign}/${row.id}`)
if(perRes.success){ if(perRes.success){
this.checkedIds = this.handleRolePer(perRes.data.rolePermissions,this.permissions) this.checkedIds = this.handleRolePer(perRes.data.rolePermissions,this.permissions)
// this.$refs.per.setCheckedNodes(this.checkedIds) this.$refs.per.setCheckedNodes(this.checkedIds)
} }
} }
}, },

@ -521,6 +521,7 @@ export default {
this.multipleSelected = val this.multipleSelected = val
}, },
removeQues(){ removeQues(){
if(!this.selectedData.length) return this.$message.error('请先添加试题')
if(this.multipleSelected.length){ if(this.multipleSelected.length){
this.$confirm('确定要移除吗?', '提示', { this.$confirm('确定要移除吗?', '提示', {
type: 'warning' type: 'warning'
@ -541,6 +542,7 @@ export default {
} }
}, },
preview(){ preview(){
if(!this.selectedData.length) return this.$message.error('请先添加试题')
this.$post(`${this.api.previewPaper}?qid=${this.selectedData.map(n => n.id).join(',')}`) this.$post(`${this.api.previewPaper}?qid=${this.selectedData.map(n => n.id).join(',')}`)
.then(res => { .then(res => {
this.setInfo({ this.setInfo({

@ -321,7 +321,6 @@ export default {
this.paperList = res.data this.paperList = res.data
this.handleOptions() this.handleOptions()
var title = row.name var title = row.name
// return false
this.$nextTick(() => { this.$nextTick(() => {
setTimeout(() => { setTimeout(() => {
html2Canvas(document.querySelector('#pdfDom'), { html2Canvas(document.querySelector('#pdfDom'), {
@ -448,9 +447,10 @@ export default {
} }
.testpaper{ .testpaper{
width: 90%; width: 90%;
padding: 20px; padding: 50px 100px;
margin: 0 auto; margin: 0 auto;
.title{ .title{
margin-bottom: 30px;
text-align: center; text-align: center;
font-size: 30px; font-size: 30px;
font-weight: bold; font-weight: bold;

@ -25,11 +25,5 @@ export default {
component: () => import('@/pages/achievement/statistics'), component: () => import('@/pages/achievement/statistics'),
meta: { title: '成绩统计' } meta: { title: '成绩统计' }
}, },
{
name: `${pre}detail`,
path: `detail`,
component: () => import('@/pages/achievement/detail'),
meta: { title: '答题详情' }
},
] ]
}; };

@ -31,12 +31,6 @@ export default {
component: () => import('@/pages/assessment/scoreQuery'), component: () => import('@/pages/assessment/scoreQuery'),
meta: { title: '成绩查询' } meta: { title: '成绩查询' }
}, },
{
name: `${pre}detail`,
path: `detail`,
component: () => import('@/pages/assessment/detail'),
meta: { title: '答题详情' }
},
{ {
name: `${pre}monitor`, name: `${pre}monitor`,
path: `monitor`, path: `monitor`,
@ -49,5 +43,17 @@ export default {
component: () => import('@/pages/assessment/show'), component: () => import('@/pages/assessment/show'),
meta: { title: '批阅详情' } meta: { title: '批阅详情' }
}, },
{
name: `${pre}doReview`,
path: `doReview`,
component: () => import('@/pages/assessment/doReview'),
meta: { title: '批改' }
},
{
name: `${pre}detail`,
path: `detail`,
component: () => import('@/pages/assessment/detail'),
meta: { title: '答题详情' }
},
] ]
}; };

@ -28,11 +28,6 @@ export default {
path: `show`, path: `show`,
component: () => import('@/pages/testPaper/show'), component: () => import('@/pages/testPaper/show'),
meta: { title: '试卷预览' } meta: { title: '试卷预览' }
},{
name: `${pre}doReview`,
path: `doReview`,
component: () => import('@/components/doReview'),
meta: { title: '批改' }
}, },
] ]
}; };

@ -17,8 +17,6 @@ const Setting = {
// 接口请求地址 // 接口请求地址
// apiBaseURL: env === 'development' ? 'http://192.168.31.152:8001' : 'http://39.108.250.202:8000/', // apiBaseURL: env === 'development' ? 'http://192.168.31.152:8001' : 'http://39.108.250.202:8000/',
apiBaseURL: env === 'development' ? 'http://192.168.31.152:8001' : 'http://39.108.250.202:9000', apiBaseURL: env === 'development' ? 'http://192.168.31.152:8001' : 'http://39.108.250.202:9000',
// oss文件管理接口地址
apiUploadURL: 'http://8.134.8.197:8001',
// 接口请求返回错误时,弹窗的持续时间,单位:秒 // 接口请求返回错误时,弹窗的持续时间,单位:秒
modalDuration: 3, modalDuration: 3,
// 接口请求返回错误时,弹窗的类型,可选值为 Message 或 Notice // 接口请求返回错误时,弹窗的类型,可选值为 Message 或 Notice
@ -51,13 +49,18 @@ const Setting = {
* */ * */
layout: { layout: {
// 需要隐藏顶栏的页面路径 // 需要隐藏顶栏的页面路径
hideNavList: ['testPaper-add','testPaper-review','testPaper-show','testPaper-doReview','assessment-show','assessment-review','assessment-scoreQuery','assessment-detail','assessment-monitor','achievement-show','achievement-statistics','achievement-detail','setting-person','practice-review','practice-scoreQuery','practice-result','practice-detail','practice-doReview'], hideNavList: ['testPaper-add','testPaper-review','testPaper-show','assessment-show','assessment-review','assessment-scoreQuery','assessment-detail','assessment-doReview','assessment-monitor','achievement-show','achievement-statistics','achievement-detail','setting-person','practice-review','practice-scoreQuery','practice-result','practice-detail','practice-doReview'],
}, },
/** /**
* 功能配置 * 功能配置
* */ * */
// 相同路由,不同参数间进行切换,是否强力更新 // 相同路由,不同参数间进行切换,是否强力更新
sameRouteForceUpdate: false, sameRouteForceUpdate: false,
// 文件上传
upload: {
apiURL: 'http://8.134.8.197:8001',
maxSize: 30,
},
// 是否使用动态路由 // 是否使用动态路由
dynamicRoute: false dynamicRoute: false
}; };

Loading…
Cancel
Save