1、最终效果:
考题是从后端接口获取循环遍历所得
动态表单校验:
2、代码示例:
<template>
<div>
<div class="detailContent">
<div class="stateLabel">
<div class="title">【{{ submitForm.typeName }}】 {{ submitForm.theme }}</div>
<div class="right">
<div class="examDate">{{ submitForm.startTime }} 至 {{ submitForm.endTime }}
<el-button size="mini" type="primary" @click="goBack">返回</el-button>
</div>
<div class="examUser">{{ submitForm.createUser }} {{ submitForm.initiateUnitName }}</div>
</div>
</div>
<el-divider></el-divider>
<div class="center" v-loading="loading">
<div class="examContent">
<div style="padding: 0 50px">
<el-form class="submit-form" :model="submitForm" ref="submitForm" :rules="submitRules"
:disabled="status != '1' && status != '5'">
<div v-for="(item, index) in submitForm.questionList" :key="index">
<div class="examTopic">
<div class="topicTitle">{{ index + 1 }} 、{{ item.name }}</div>
<div class="score">
<div class="examType">{{ findTopicType(item.type) }} {{ item.score }} 分</div><br>
</div>
</div>
<div class="answer">
<p>答案:</p>
<!-- 单选题 -->
<div class="answerList" v-if="item.type == 1">
<el-form-item :prop="'questionList.' + index + '.answer'" :rules="submitRules.answer">
<el-radio-group v-model="item.answer">
<el-radio v-for="info in item.options" style="margin-left:10px" :label="info.id">{{
info.option }}</el-radio>
</el-radio-group>
</el-form-item>
</div>
<!-- 多选题 -->
<div class="answerList" v-else-if="item.type == 2">
<el-form-item :prop="'questionList.' + index + '.answer'" :rules="submitRules.answer">
<el-checkbox-group v-model="item.answer">
<el-checkbox v-for="(info, index) in item.options" :key="index" :label="info.id">{{ info.option
}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</div>
<!-- 论述题 -->
<div class="answerList" v-else-if="item.type == 3">
<el-form-item :prop="'questionList.' + index + '.answer'" :rules="submitRules.answer">
<el-input class="textarea" type="textarea" v-model="item.answer" clearable show-word-limit
:autosize="{ minRows: 2, maxRows: 4 }" maxlength="800" placeholder="请输入"></el-input>
</el-form-item>
</div>
<!-- 简答题 -->
<div class="answerList" v-else-if="item.type == 4">
<el-form-item :prop="'questionList.' + index + '.answer'" :rules="submitRules.answer">
<el-input class="textarea" type="textarea" v-model="item.answer" clearable show-word-limit
:autosize="{ minRows: 2, maxRows: 4 }" maxlength="800" placeholder="请输入"></el-input>
</el-form-item>
</div>
</div>
</div>
</el-form>
</div>
</div>
<div class="requirement">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>考试要求:</span>
</div>
<div>
{{ submitForm.examAsk }}
</div>
</el-card>
<div v-if="status == 4 || status == 2" class="bigCircle">
{{ submitForm.score }} 分
</div>
</div>
</div>
<div>
<div style="padding: 0 50px" v-if="status == 1 || status == 5">
<div slot="footer" class="dialog-footer">
<el-button size="mini" class="cancel" @click="submit('1')">保 存</el-button>
<el-button size="mini" type="primary" @click="submit('2')">交 卷</el-button>
</div>
</div>
<div style="padding: 0 50px" v-else>
<div slot="footer" class="dialog-footer">
<el-button size="mini" class="cancel" @click="goBack">返 回</el-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { dictMixin } from "@/mixins/dictMinxin";
import baseUpload from '@/components/upload/baseUpload.vue'
import { Loading } from 'element-ui'
import fileListVue from "@/components/common/fileList.vue";
export default {
mixins: [dictMixin],
components: {
fileListVue,
baseUpload
},
data() {
return {
dateStatus: '',
loading: false,
totalData: 0,
pageNo: 1,
pageSize: 10,
examId: '',
isDisabled: false,
submitForm: {},
status: '', // 1 参加考试 2 详情 3 列表详情 4 打分
searchForm: {
examId: '',
userName: '',
pageNo: 1,
pageSize: 10,
},
personId: '',
submitRules: {
answer: [{ required: true, message: "请输入答案", trigger: "change" }],
},
};
},
mounted() {
if (this.$route.query) {
let { examId, status } = this.$route.query
this.status = status // 状态 1 参加考试 2 详情
this.examId = examId // 试卷id
// status 1 参加考试 2 详情
if (status == '1') {
this.getDetail(); // 获取考题
} else {
this.getMyExamList() // 获取我的试卷
}
}
},
methods: {
findTopicType(val) {
let str = ""
if (val == 1) {
str = '单选题'
} else if (val == 2) {
str = '多选题'
} else if (val == 3) {
str = '论述题'
} else if (val == 4) {
str = '简答题'
}
return str
},
goBack() {
window.history.go(-1);
},
submit(status) {
this.$refs["submitForm"].validate((valid) => {
if (valid) {
this.$confirm("请确认是否提交!", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
let params = { ...this.submitForm }
if (status == 1) { //保存
params.isComplete = 1
} else if (status == 2) { // 交卷
params.isComplete = 2
}
// this.$api.onlineExam.handPaper(params).then((res) => {
// if (res.code == 200) {
// this.$message({
// type: 'success',
// message: "操作成功!"
// })
// } else {
// this.$message({
// type: "error",
// message: res.message + "!",
// });
// }
// this.$router.push("/onlineExam");
// })
})
}
})
},
async getDetail() {
this.loading = true;
await this.$api.onlineExam.getExamInfo(this.examId).then((res) => {
this.loading = false;
if (res.code == 200) {
this.submitForm = res.data
this.submitForm.questionList.map(item => {
if (item.type == 2) {
item.answer = []
}
})
}
})
},
async getMyExamList() {
this.loading = true;
let params = {
examId: this.examId,
personId: this.personId
}
await this.$api.onlineExam.paperDetail(params).then((res) => {
this.loading = false;
if (res.code == 200) {
// this.submitForm = res.data
this.submitForm = {
createTime: "2024-01-19 14:51:52",
createUser: "admin",
endTime: "2024-01-23 00:00:00",
examAsk: "认真认真认真", // 考试要求
id: 15,
initiateUnitName: "国网四川省电力公司",
isComplete: null,
questionList: [{// 题目列表
answer: 47, // 答案
answerList: null,
examId: 15,
id: 26,
name: "在Vue中,被用来响应地更新HTML属性的指令是",
options: [{
answer: null,
id: 44,
option: "v-on",
questionId: 26,
},
{
answer: null,
id: 45,
option: "v-if",
questionId: 26,
}, {
answer: null,
id: 46,
option: "v-bind",
questionId: 26,
}, {
answer: null,
id: 47,
option: "v-model",
questionId: 26,
}],
partScore: null,
score: 10,
totalScore: 10,
type: 1, // 题目类型 1 单选 2 多选 3 论述 4 简答
}, {
answer: null, // 答案
answerList: [48, 49, 50],
examId: 15,
id: 27,
name: "在Vue中,被用来响应地更新HTML属性的指令是",
options: [{
answer: null,
id: 48,
option: "push()",
questionId: 27,
},
{
answer: null,
id: 49,
option: "pop()",
questionId: 27,
}, {
answer: null,
id: 50,
option: "shift()",
questionId: 27,
}],
partScore: null,
score: 10,
totalScore: 10,
type: 2, // 题目类型 1 单选 2 多选 3 论述 4 简答
}, {
answer: null, // 答案
answerList: null,
examId: 15,
id: 28,
name: "请说下封装 vue 组件的过程",
options: null,
partScore: null,
score: 50,
totalScore: 50,
type: 3, // 题目类型 1 单选 2 多选 3 论述 4 简答
}, {
answer: null, // 答案
answerList: null,
examId: 15,
id: 29,
name: "请说下 vue的生命周期",
options: null,
partScore: null,
score: 30,
totalScore: 30,
type: 4, // 题目类型 1 单选 2 多选 3 论述 4 简答
}
],
questionNum: 4,
receivingUnitName: "国网四川省电力公司",
score: 100,
startTime: "2024-01-19 00:00:00",
status: 1,
theme: "测试考试",
totalScore: 100,
type: "2",
typeName: "定期考试",
}
this.submitForm.questionList.map(item => {
if (item.type == 2) {
item.answer = []
item.answerList.map(i => {
item.answer.push(i)
})
} else if (item.type == 1) {
item.answer = item.answer
}
})
}
})
},
},
};
</script>
<style lang="less" scoped>
.examDate {}
/deep/ .el-form-item__content {
max-width: none !important;
}
/deep/ .el-date-editor.el-input__inner {
width: 100%;
}
/deep/.el-radio__input.is-checked .el-radio__inner {
border-color: #18a8a4;
background: #18a8a4;
}
/deep/ .el-radio__input.is-checked+.el-radio__label {
color: #18a8a4;
}
/deep/ .el-tree .el-tree-node .el-checkbox .el-checkbox__inner {
display: inline-block;
}
.title {
border-left: 3px solid rgba(24, 168, 164, 1);
opacity: 1;
font-size: 20px;
font-family: PingFangSC, PingFangSC-Medium;
font-weight: 600;
text-align: left;
color: #333c4f;
line-height: 20px;
padding-left: 11px;
margin: 20px 0;
width: auto;
margin-left: 25px;
}
.detailContent {
background: #fff;
width: calc(100% - 40px);
height: auto;
overflow: hidden;
padding: 20px;
}
.center {
display: flex;
justify-content: space-evenly;
.examContent {
width: 60%;
.examTopic {
display: flex;
align-items: center;
.topicTitle {
width: 75%;
background-color: aliceblue;
padding: 6px;
}
.score {
margin-left: 10px;
margin-top: 10px;
width: 20%;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: flex-start;
align-items: flex-start;
.scoreExam {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
}
}
.examType {
// padding: 5px;
}
}
.answer {
padding: 10px;
p {
display: inline-block;
padding: 10px;
}
.answerList {
width: 500px;
display: inline-block;
padding: 10px;
}
}
.textarea {
width: 100%;
}
}
.requirement {
width: 40%;
.box-card {
width: 100%;
}
.table-card {
margin-top: 20px;
width: 100%;
}
}
}
.cancel {
margin-left: 450px;
}
.stateLabel {
display: flex;
justify-content: space-between;
.right {
font-family: PingFangSC, PingFangSC-Medium;
text-align: left;
color: #41444a;
line-height: 28px;
}
}
.bigCircle {
margin-top: 200px;
width: 200px;
height: 200px;
background-color: #18A8A4;
// border: 1px solid #18A8A4;
border-radius: 50%;
font-size: 28px;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
</style>