From 230b189adbe6dd0706828b53662ed8e50ad4f06c Mon Sep 17 00:00:00 2001 From: 龚焕茏 <2842157468@qq.com> Date: 星期四, 13 六月 2024 11:25:04 +0800 Subject: [PATCH] feat:答卷 --- /dev/null | 5 src/views/answer/detail.vue | 130 ++++++++++++++ src/views/answer/info.vue | 126 ++++++++++++++ src/components/questionAnswerShow/index.vue | 128 ++++++++++++++ src/views/answer/list.vue | 73 ++++--- src/api/examPaperAnswer.js | 7 src/router.js | 14 + 7 files changed, 448 insertions(+), 35 deletions(-) diff --git a/src/api/examPaperAnswer.js b/src/api/examPaperAnswer.js new file mode 100644 index 0000000..d5dad9c --- /dev/null +++ b/src/api/examPaperAnswer.js @@ -0,0 +1,7 @@ +import { post } from '@/utils/request' + +export default { + page: query => post('/api/admin/examPaperAnswer/page', query), + pageExamPaper: query => post('/api/admin/examPaperAnswer/pageExamPaper', query), + read: id => post('/api/admin/examPaperAnswer/read/' + id) +} diff --git a/src/api/examPaperAnwser.js b/src/api/examPaperAnwser.js deleted file mode 100644 index c10dd2a..0000000 --- a/src/api/examPaperAnwser.js +++ /dev/null @@ -1,5 +0,0 @@ -import { post } from '@/utils/request' - -export default { - page: query => post('/api/admin/examPaperAnswer/page', query) -} diff --git a/src/components/questionAnswerShow/index.vue b/src/components/questionAnswerShow/index.vue new file mode 100644 index 0000000..3258152 --- /dev/null +++ b/src/components/questionAnswerShow/index.vue @@ -0,0 +1,128 @@ +<template> + <div v-loading="qLoading" style="line-height:1.8"> + <div v-if="qType == 1 || qType == 2 || qType == 3 || qType == 4 || qType == 5"> + <div v-if="qType == 1"> + <div class="q-title" v-html="question.title" /> + <div class="q-content"> + <el-radio-group v-model="answer.content"> + <el-radio v-for="item in question.items" :key="item.prefix" :label="item.prefix"> + <span class="question-prefix">{{ item.prefix }}.</span> + <span v-html="item.content" class="q-item-span-content"></span> + </el-radio> + </el-radio-group> + </div> + </div> + <div v-else-if="qType == 2"> + <div class="q-title" v-html="question.title" /> + <div class="q-content"> + <el-checkbox-group v-model="answer.contentArray"> + <el-checkbox v-for="item in question.items" :label="item.prefix" :key="item.prefix"> + <span class="question-prefix">{{ item.prefix }}.</span> + <span v-html="item.content" class="q-item-span-content"></span> + </el-checkbox> + </el-checkbox-group> + </div> + </div> + <div v-else-if="qType == 3"> + <div class="q-title" v-html="question.title" style="display: inline;margin-right: 10px" /> + <span style="padding-right: 10px;">(</span> + <el-radio-group v-model="answer.content"> + <el-radio v-for="item in question.items" :key="item.prefix" :label="item.prefix"> + <span v-html="item.content" class="q-item-span-content"></span> + </el-radio> + </el-radio-group> + <span style="padding-left: 10px;">)</span> + </div> + <div v-else-if="qType == 4"> + <div class="q-title" v-html="question.title" /> + <div v-if="answer.contentArray !== null"> + <el-form-item :label="item.prefix" :key="item.prefix" v-for="item in question.items" label-width="50px" + style="margin-top: 10px;margin-bottom: 10px;"> + <el-input v-model="answer.contentArray[item.prefix - 1]" /> + </el-form-item> + </div> + </div> + <div v-else-if="qType == 5"> + <div class="q-title" v-html="question.title" /> + <div> + <el-input v-model="answer.content" type="textarea" rows="5"></el-input> + </div> + </div> + <div class="question-answer-show-item" style="margin-top: 15px"> + <span class="question-show-item">缁撴灉锛�</span> + <el-tag :type="doRightTagFormatter(answer.doRight)"> + {{ doRightTextFormatter(answer.doRight) }} + </el-tag> + </div> + <div class="question-answer-show-item"> + <span class="question-show-item">鍒嗘暟锛�</span> + <span>{{ question.score }}</span> + </div> + <div class="question-answer-show-item"> + <span class="question-show-item">闅惧害锛�</span> + <el-rate disabled v-model="question.difficult" class="question-show-item"></el-rate> + </div> + <br /> + <div class="question-answer-show-item" style="line-height: 1.8"> + <span class="question-show-item">瑙f瀽锛�</span> + <span v-html="question.analyze" class="q-item-span-content" /> + </div> + <div class="question-answer-show-item"> + <span class="question-show-item">姝g‘绛旀锛�</span> + <span v-if="qType == 1 || qType == 2 || qType == 5" v-html="question.correct" class="q-item-span-content" /> + <span v-if="qType == 3" v-html="trueFalseFormatter(question)" class="q-item-span-content" /> + <span v-if="qType == 4">{{ question.correctArray }}</span> + </div> + </div> + <div v-else> + </div> + </div> + +</template> + +<script> +import { mapState, mapGetters } from 'vuex' +export default { + name: 'QuestionShow', + props: { + question: { + type: Object, + default: function () { + return {} + } + }, + answer: { + type: Object, + default: function () { + return { id: null, content: '', contentArray: [], doRight: false } + } + }, + qLoading: { + type: Boolean, + default: false + }, + qType: { + type: Number, + default: 0 + } + }, + methods: { + trueFalseFormatter(question) { + return question.items.filter(d => d.prefix === question.correct)[0].content + }, + doRightTagFormatter(status) { + return this.enumFormat(this.doRightTag, status) + }, + doRightTextFormatter(status) { + return this.enumFormat(this.doRightEnum, status) + } + }, + computed: { + ...mapGetters('enumItem', ['enumFormat']), + ...mapState('enumItem', { + doRightEnum: state => state.exam.question.answer.doRightEnum, + doRightTag: state => state.exam.question.answer.doRightTag + }) + } +} +</script> diff --git a/src/router.js b/src/router.js index fd84032..4a24ef3 100644 --- a/src/router.js +++ b/src/router.js @@ -233,6 +233,20 @@ component: () => import('@/views/answer/list'), name: 'AnswerPageList', meta: { title: '绛斿嵎鍒楄〃', noCache: true } + }, + { + path: 'answer-list', + component: () => import('@/views/answer/info'), + name: 'answerList', + meta: { title: '绛斿嵎淇℃伅', noCache: true }, + hidden: true + }, + { + path: 'answer-detail', + component: () => import('@/views/answer/detail'), + name: 'answerDetail', + meta: { title: '绛斿嵎璇︽儏', noCache: true }, + hidden: true } ] }, diff --git a/src/views/answer/detail.vue b/src/views/answer/detail.vue new file mode 100644 index 0000000..799cd8a --- /dev/null +++ b/src/views/answer/detail.vue @@ -0,0 +1,130 @@ +<template> + <div style="background-color: #FFFFFF; padding-top: 50px;min-height: 900px;"> + <el-row class="do-exam-title" style="background-color: #F5F5DC"> + <el-col :span="24"> + <span :key="item.itemOrder" v-for="item in answer.answerItems"> + <el-tag :type="questionDoRightTag(item.doRight)" class="do-exam-title-tag" + @click="goAnchor('#question-' + item.itemOrder)">{{ item.itemOrder }}</el-tag> + </span> + </el-col> + </el-row> + <el-row class="do-exam-title-hidden"> + <el-col :span="24"> + <span :key="item.itemOrder" v-for="item in answer.answerItems"> + <el-tag class="do-exam-title-tag">{{ item.itemOrder }}</el-tag> + </span> + </el-col> + </el-row> + <el-container class="app-item-contain"> + <el-header class="align-center"> + <h1>{{ form.name }}</h1> + <div> + <span class="question-title-padding">璇曞嵎寰楀垎锛歿{ answer.score }}</span> + <span class="question-title-padding">璇曞嵎鑰楁椂锛歿{ formatSeconds(answer.doTime) }}</span> + </div> + </el-header> + <el-main> + <el-form :model="form" ref="form" v-loading="formLoading" label-width="100px"> + <el-row :key="index" v-for="(titleItem, index) in form.titleItems"> + <h3>{{ titleItem.name }}</h3> + <el-card class="exampaper-item-box" v-if="titleItem.questionItems.length !== 0"> + <el-form-item :key="questionItem.itemOrder" :label="questionItem.itemOrder + '.'" + v-for="questionItem in titleItem.questionItems" class="exam-question-item" + label-width="50px" :id="'question-' + questionItem.itemOrder"> + <QuestionAnswerShow :qType="questionItem.questionType" :question="questionItem" + :answer="answer.answerItems[questionItem.itemOrder - 1]" /> + </el-form-item> + </el-card> + </el-row> + </el-form> + </el-main> + </el-container> + </div> +</template> + +<script> +import { mapState, mapGetters } from 'vuex' +import QuestionAnswerShow from '@/components/questionAnswerShow' +import examPaperAnswerApi from '@/api/examPaperAnswer' +export default { + components: { QuestionAnswerShow }, + data() { + return { + form: {}, + formLoading: false, + answer: { + id: null, + score: 0, + doTime: 0, + answerItems: [], + doRight: false + } + } + }, + created() { + let id = this.$route.query.id + let _this = this + if (id && parseInt(id) !== 0) { + _this.formLoading = true + examPaperAnswerApi.read(id).then(re => { + _this.form = re.data.paper + _this.answer = re.data.answer + _this.formLoading = false + }) + } + }, + methods: { + formatSeconds(theTime) { + let theTime1 = 0 + let theTime2 = 0 + if (theTime > 60) { + theTime1 = parseInt(theTime / 60) + theTime = parseInt(theTime % 60) + if (theTime1 > 60) { + theTime2 = parseInt(theTime1 / 60) + theTime1 = parseInt(theTime1 % 60) + } + } + let result = '' + parseInt(theTime) + '绉�' + if (theTime1 > 0) { + result = '' + parseInt(theTime1) + '鍒�' + result + } + if (theTime2 > 0) { + result = '' + parseInt(theTime2) + '灏忔椂' + result + } + return result + }, + questionDoRightTag(status) { + return this.enumFormat(this.doRightTag, status) + }, + goAnchor(selector) { + this.$el.querySelector(selector).scrollIntoView({ behavior: 'instant', block: 'center', inline: 'nearest' }) + } + }, + computed: { + ...mapGetters('enumItem', ['enumFormat']), + ...mapState('enumItem', { + doRightTag: state => state.exam.question.answer.doRightTag + }) + } +} +</script> + +<style lang="scss" scoped> +.align-center { + text-align: center +} + +.exam-question-item { + padding: 10px; + + .el-form-item__label { + font-size: 15px !important; + } +} + +.question-title-padding { + padding-left: 25px; + padding-right: 25px; +} +</style> \ No newline at end of file diff --git a/src/views/answer/info.vue b/src/views/answer/info.vue new file mode 100644 index 0000000..55df334 --- /dev/null +++ b/src/views/answer/info.vue @@ -0,0 +1,126 @@ +<!-- 绛斿嵎绠$悊 --> +<template> + <div class="c"> + <div class="bg"> + <div class="main"> + <!-- 寰呰繑鍥炵殑鏍囬 --> + <TitleIndex title="绛斿嵎绠$悊" /> + <div class="content"> + <!-- 鎼滅储 --> + <div> + <el-form :inline="true" :model="queryParam" class="demo-form-inline" label-width="80px"> + <el-form-item> + <el-input v-model="queryParam.userName" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" clearable></el-input> + </el-form-item> + <el-form-item> + <el-button style="width:100px;" type="primary" size="small" @click="search()">鏌ヨ</el-button> + <el-button style="width:100px;" type="danger" size="small" @click="handleExport()">瀵煎嚭</el-button> + </el-form-item> + </el-form> + </div> + <!-- 琛ㄦ牸 --> + <el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%"> + <el-table-column prop="paperName" label="璇曞嵎鍚嶇О" align="center" /> + <el-table-column prop="userName" label="鐢ㄦ埛鍚嶇О" align="center" /> + <el-table-column label="寰楀垎" width="100px"> + <template slot-scope="{row}"> + {{ row.userScore }} / {{ row.paperScore }} + </template> + </el-table-column> + <el-table-column label="棰樼洰瀵归敊" width="100px" align="center"> + <template slot-scope="{row}"> + {{ row.questionCorrect }} / {{ row.questionCount }} + </template> + </el-table-column> + <el-table-column prop="doTime" label="鑰楁椂" width="80px" align="center" /> + <el-table-column prop="createTime" label="鎻愪氦鏃堕棿" width="160px" align="center" /> + <el-table-column label="鎿嶄綔" width="200px" align="center"> + <template slot-scope="{row}"> + <el-button size="mini" @click="view(row)">璇︽儏</el-button> + </template> + </el-table-column> + </el-table> + <pagination v-show="total > 0" :total="total" :page.sync="queryParam.pageIndex" + :limit.sync="queryParam.pageSize" @pagination="search" /> + </div> + </div> + </div> + </div> +</template> +<script> +// 寮曞叆褰堝嚭绐楀彛绲勪欢 +import examPaperAnswerApi from '@/api/examPaperAnswer' +import Pagination from '@/components/Pagination' + +export default { + // 娉ㄥ唽 + components: { + Pagination + }, + data() { + return { + listLoading: true, + queryParam: { + examPaperId: '', + userName: '', + pageIndex: 1, + pageSize: 10 + }, + formLoading: false, + total: 0, + tableData: [], + visible: false, + subjects: [] + }; + }, + created() { + this.queryParam.examPaperId = this.$route.query.id + this.search() + }, + methods: { + // 鑾峰彇鍒楄〃 + search() { + this.listLoading = true + examPaperAnswerApi.page(this.queryParam).then(re => { + this.tableData = re.data.list + this.total = re.data.total + this.queryParam.pageSize = re.data.pageSize + this.queryParam.pageIndex = re.data.pageNum + this.listLoading = false + }) + }, + view(row) { + this.$router.push({ path: '/answer/answer-detail', query: { id: row.id } }); + }, + handleExport() { + let that = this + let url = '/api/admin/examPaperAnswer/exportExcel?examPaperId=' + this.queryParam.examPaperId + '&userName=' + this.queryParam.userName + var x = new XMLHttpRequest(); + x.open("POST", url, true); + x.responseType = "blob"; + x.onload = function () { + var url = window.URL.createObjectURL(x.response); + var a = document.createElement("a"); + a.href = url; + a.download = that.tableData[0].paperName + '.xlsx'; + a.click(); + }; + x.send(); + } + } +}; +</script> +<style scoped lang="scss"> +.flex { + display: flex; +} + +// 鍐呭 +.content { + width: 1262px; + margin-bottom: 80px; + background-color: #fff; + padding: 20px 40px; + border-radius: 10px; +} +</style> diff --git a/src/views/answer/list.vue b/src/views/answer/list.vue index 08e7c74..4789557 100644 --- a/src/views/answer/list.vue +++ b/src/views/answer/list.vue @@ -1,35 +1,46 @@ <template> <div class="app-container"> - <el-form :model="queryParam" ref="queryForm" :inline="true"> - <el-form-item label="瀛︾锛�" > - <el-select v-model="queryParam.subjectId" clearable> + <el-form :inline="true" :model="queryParam" class="demo-form-inline" label-width="80px"> + <el-form-item> + <el-input v-model="queryParam.name" placeholder="璇疯緭鍏ュ悕绉�" clearable></el-input> + </el-form-item> + <el-form-item> + <el-select v-model="queryParam.subjectId" placeholder="璇烽�夋嫨绉戠洰" clearable multiple @change="search"> <el-option v-for="item in subjects" :key="item.id" :value="item.id" :label="item.name"></el-option> </el-select> </el-form-item> <el-form-item> - <el-button type="primary" @click="submitForm">鏌ヨ</el-button> + <el-button style="width:100px;" type="primary" size="small" @click="search()">鏌ヨ</el-button> </el-form-item> </el-form> - <el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%"> - <el-table-column prop="id" label="Id" width="100" /> - <el-table-column prop="paperName" label="璇曞嵎鍚嶇О"/> - <el-table-column prop="userName" label="鐢ㄦ埛鍚嶇О"/> - <el-table-column label="寰楀垎" width="100px" > + <el-table v-loading="listLoading" :data="tableData" border style="width: 100%;"> + <el-table-column align="center" prop="paperName" label="璇曞嵎鍚嶇О" /> + <el-table-column align="center" prop="subjectName" label="绉戠洰" /> + <el-table-column align="center" prop="paperType" label="璇曞嵎绫诲瀷" width="150px"> <template slot-scope="{row}"> - {{row.userScore}} / {{row.paperScore}} + <span v-if="row.paperType === 1">鍥哄畾璇曞嵎</span> + <span v-if="row.paperType === 2">闅忔満璇曞嵎</span> + <span v-if="row.paperType === 3">椤哄簭璇曞嵎</span> </template> </el-table-column> - <el-table-column label="棰樼洰瀵归敊" width="80px" > + <el-table-column align="center" prop="questionCount" label="棰樼洰鏁伴噺" width="100px" /> + <el-table-column align="center" prop="systemScore" label="鎬诲垎" width="100px" /> + <el-table-column align="center" prop="suggestTime" label="寤鸿鏃堕暱" width="100px" /> + <el-table-column align="center" prop="personAnswerNum" label="鍙傝�冧汉鏁�" width="100px"> <template slot-scope="{row}"> - {{row.questionCorrect}} / {{row.questionCount}} + <span>{{ row.personAnswerNum + "/" + row.personTotalNum }}</span> </template> </el-table-column> - <el-table-column prop="doTime" label="鑰楁椂" width="100px"/> - <el-table-column prop="createTime" label="鎻愪氦鏃堕棿" width="160px"/> + <el-table-column align="center" prop="userName" label="鍒涘缓浜�" width="100px" /> + <el-table-column label="鎿嶄綔" align="center"> + <template slot-scope="{row}"> + <el-button size="mini" @click="view(row)">鏌ョ湅</el-button> + </template> + </el-table-column> </el-table> - <pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize" - @pagination="search"/> + <pagination v-show="total > 0" :total="total" :page.sync="queryParam.pageIndex" + :limit.sync="queryParam.pageSize" @pagination="search" /> </div> </template> @@ -37,40 +48,42 @@ import { mapGetters, mapState, mapActions } from 'vuex' import Pagination from '@/components/Pagination' -import examPaperAnswerApi from '@/api/examPaperAnwser' +import examPaperAnswerApi from '@/api/examPaperAnswer' export default { components: { Pagination }, data () { return { + listLoading: true, queryParam: { - subjectId: null, + name: '', pageIndex: 1, pageSize: 10 }, - listLoading: false, + formLoading: false, + total: 0, tableData: [], - total: 0 - } + visible: false + }; }, created () { this.initSubject() this.search() }, methods: { - search () { + // 鑾峰彇鍒楄〃 + search() { this.listLoading = true - examPaperAnswerApi.page(this.queryParam).then(data => { - const re = data.data - this.tableData = re.list - this.total = re.total - this.queryParam.pageIndex = re.pageNum + examPaperAnswerApi.pageExamPaper(this.queryParam).then(re => { + this.tableData = re.data.list + this.total = re.data.total + this.queryParam.pageSize = re.data.pageSize + this.queryParam.pageIndex = re.data.pageNum this.listLoading = false }) }, - submitForm () { - this.queryParam.pageIndex = 1 - this.search() + view(row) { + this.$router.push({ path: '/answer/answer-list', query: { id: row.id } }); }, ...mapActions('exam', { initSubject: 'initSubject' }) }, -- Gitblit v1.8.0