Commit 3de1377643b0b5503c05a57e42822b05929fccbc

Authored by 梁保满
1 parent 813d4d64

背题组卷修改答案

src/assets/css/index.scss
... ... @@ -79,6 +79,7 @@
79 79 }
80 80  
81 81 .answer-box {
  82 + padding-top: 12px;
82 83 .answer-s {
83 84 display: inline-block;
84 85 width: 30px;
... ... @@ -97,6 +98,19 @@
97 98 color: #fff;
98 99 }
99 100 }
  101 +
  102 + .delButton {
  103 + border-color: #ff6868;
  104 + background: #ff6868 url("../images/arrow.png") no-repeat center;
  105 + background-size: 19px;
  106 + color: transparent;
  107 + }
  108 +
  109 + .ac {
  110 + border-color: #ff6868;
  111 + background: #ff6868;
  112 + color: #fff;
  113 + }
100 114 }
101 115  
102 116 .el-menu-item i {
... ...
src/views/examinationPaper/edit.vue
... ... @@ -16,59 +16,143 @@
16 16 <p class="name">{{ form.title }}</p>
17 17 <p class="totals">卷面总分:{{ allScore }}分</p>
18 18 </div>
19   - <div v-for="(question, index) in form.questionList" :key="index">
20   - <p class="question-title">
21   - <span>{{ setBigNum(index) }}、</span>
22   - <el-input
23   - class="ipt"
24   - v-model.trim="question.questionTitle"
25   - maxlength="30"
26   - placeholder="填写大题名称"
27   - ></el-input>
28   - <span>共 {{ setScore(question) }} 分</span>
29   - </p>
30   - <ul class="questions-ul">
31   - <li class="sub-questions">
32   - <div class="qs-num">题号</div>
33   - <div class="qs-type">题型</div>
34   - <div class="qs-score">分数</div>
35   - <div class="qs-partScore">漏选得分</div>
36   - <div class="qs-options qs-options2">选项设置</div>
37   - </li>
38   - <li
39   - class="sub-questions"
40   - v-for="(subQuestions, indexs) in question.subQuestions"
41   - :key="indexs"
  19 + <template v-if="questionList[0]?.subQuestions">
  20 + <div v-for="(question, index) in questionList" :key="index">
  21 + <p class="question-title">
  22 + <span>{{ setBigNum(index) }}、</span>
  23 + <el-input
  24 + class="ipt"
  25 + v-model.trim="question.questionTitle"
  26 + maxlength="30"
  27 + placeholder="填写大题名称"
  28 + ></el-input>
  29 + <span>共 {{ setScore(question) }} 分</span>
  30 + </p>
  31 + <ul class="questions-ul">
  32 + <li class="sub-questions">
  33 + <div class="qs-num">题号</div>
  34 + <div class="qs-type">题型</div>
  35 + <div class="qs-score">分数</div>
  36 + <div class="qs-partScore">漏选得分</div>
  37 + <div class="qs-options qs-options2">选项设置</div>
  38 + </li>
  39 + <li
  40 + v-for="(subQuestions, indexs) in question.subQuestions"
  41 + :key="indexs"
  42 + >
  43 + <p
  44 + class="set-ans-btn"
  45 + v-if="
  46 + subQuestions.qusType &&
  47 + subQuestions.subNum &&
  48 + subQuestions.subNum > 4
  49 + "
  50 + >
  51 + <el-button type="primary" @click="setFormAns(indexs, index)"
  52 + >批量设置答案</el-button
  53 + >
  54 + </p>
  55 + <div v-else class="sub-questions">
  56 + <div class="qs-num">{{ subQuestions.questionIndex }}</div>
  57 + <div class="qs-type">
  58 + {{ setSubPro(subQuestions.questionType) }}
  59 + </div>
  60 + <div class="qs-score">
  61 + {{ subQuestions.score }}
  62 + </div>
  63 + <div class="qs-partScore">
  64 + <p v-if="subQuestions.questionType != 3">--</p>
  65 + <p v-else>{{ subQuestions.partScore }}</p>
  66 + </div>
  67 + <div class="qs-options qs-options2">
  68 + <p v-if="subQuestions.questionType == 5">--</p>
  69 + <p v-if="subQuestions.questionType == 4" class="answer-box">
  70 + <span
  71 + class="answer-s"
  72 + :class="subQuestions.correctAnswer == 1 ? 'active' : ''"
  73 + @click="subQuestions.correctAnswer = 1"
  74 + >✓</span
  75 + >
  76 + <span
  77 + class="answer-s"
  78 + :class="subQuestions.correctAnswer == 2 ? 'active' : ''"
  79 + @click="subQuestions.correctAnswer = 2"
  80 + >✗</span
  81 + >
  82 + </p>
  83 + <p v-if="subQuestions.questionType == 3" class="answer-box">
  84 + <template
  85 + v-for="option in subQuestions.answerOptions.split(',')"
  86 + >
  87 + <span
  88 + v-if="option"
  89 + class="answer-s"
  90 + :class="
  91 + subQuestions.correctAnswer.includes(option)
  92 + ? 'active'
  93 + : ''
  94 + "
  95 + :key="option"
  96 + @click="changAnswer(subQuestions, option)"
  97 + >{{ option }}</span
  98 + >
  99 + </template>
  100 + </p>
  101 + <p v-if="subQuestions.questionType == 2" class="answer-box">
  102 + <template
  103 + v-for="option in subQuestions.answerOptions.split(',')"
  104 + >
  105 + <span
  106 + class="answer-s"
  107 + v-if="option"
  108 + :class="
  109 + subQuestions.correctAnswer == option ? 'active' : ''
  110 + "
  111 + :key="option"
  112 + @click="subQuestions.correctAnswer = option"
  113 + >{{ option }}</span
  114 + >
  115 + </template>
  116 + </p>
  117 + </div>
  118 + </div>
  119 + </li>
  120 + </ul>
  121 + </div>
  122 + </template>
  123 + <ul class="questions-ul" v-else>
  124 + <li class="sub-questions">
  125 + <div class="qs-num">题号</div>
  126 + <div class="qs-type">题型</div>
  127 + <div class="qs-score">分数</div>
  128 + <div class="qs-partScore">漏选得分</div>
  129 + <div class="qs-options qs-options2">选项设置</div>
  130 + </li>
  131 + <li v-for="(subQuestions, indexs) in questionList" :key="indexs">
  132 + <p
  133 + class="set-ans-btn"
  134 + v-if="
  135 + subQuestions.qusType &&
  136 + subQuestions.subNum &&
  137 + subQuestions.subNum > 4
  138 + "
42 139 >
  140 + <el-button type="primary" @click="setFormAns(indexs, index)"
  141 + >批量设置答案</el-button
  142 + >
  143 + </p>
  144 + <div v-else class="sub-questions">
43 145 <div class="qs-num">{{ subQuestions.questionIndex }}</div>
44 146 <div class="qs-type">
45 147 {{ setSubPro(subQuestions.questionType) }}
46 148 </div>
47 149 <div class="qs-score">
48   - <el-input-number
49   - class="number-ipt"
50   - size="medium"
51   - :min="1"
52   - :max="200"
53   - :precision="2"
54   - v-model="subQuestions.score"
55   - label="单题分值"
56   - ></el-input-number>
  150 + {{ subQuestions.score }}
57 151 </div>
58 152 <div class="qs-partScore">
59   - <p v-if="subQuestions.questionType != 3">--</p>
60   - <el-input-number
61   - class="number-ipt"
62   - v-else
63   - size="medium"
64   - :min="0"
65   - :precision="2"
66   - :max="subQuestions.score"
67   - :step="0.5"
68   - v-model="subQuestions.partScore"
69   - label="漏选得分"
70   - ></el-input-number>
71   - </div>
  153 + <p v-if="subQuestions.questionType != 3">--</p>
  154 + <p v-else>{{ subQuestions.partScore }}</p>
  155 + </div>
72 156 <div class="qs-options qs-options2">
73 157 <p v-if="subQuestions.questionType == 5">--</p>
74 158 <p v-if="subQuestions.questionType == 4" class="answer-box">
... ... @@ -120,19 +204,108 @@
120 204 </template>
121 205 </p>
122 206 </div>
123   - </li>
124   - </ul>
125   - </div>
  207 + </div>
  208 + </li>
  209 + </ul>
126 210 <div class="btn-box">
127 211 <el-button type="danger" plain round @click="linkBack">取消</el-button>
128 212 <el-button type="primary" round @click="save">保存</el-button>
129 213 </div>
  214 + <el-dialog
  215 + title="批量设置答案"
  216 + :close-on-click-modal="false"
  217 + :visible.sync="diaSetAns"
  218 + width="400"
  219 + :modal-append-to-body="false"
  220 + >
  221 + <div class="qs-options">
  222 + <p class="dia-tips">
  223 + 请点击选项按钮设置答案,多选题题目之间用“,”隔开,若添加5道题:“AC,AD,BD,AC,CD”
  224 + </p>
  225 + <p>{{ setSubPro(formAns.qusType) }}:</p>
  226 + <p class="ipt">
  227 + <el-input
  228 + v-if="formAns.qusType == 2 || formAns.qusType == 3"
  229 + v-model="formAns.answerList"
  230 + @keydown.native="keydownAnswer($event, formAns.qusType)"
  231 + @input="setAllAnswer($event, formAns.qusType)"
  232 + ></el-input>
  233 + <el-input
  234 + v-if="formAns.qusType == 4"
  235 + v-model="formAns.answerList"
  236 + readonly=""
  237 + ></el-input>
  238 + </p>
  239 + <p class="answer-box">
  240 + <template v-if="formAns.qusType == 4">
  241 + <span
  242 + class="answer-s active"
  243 + @click="
  244 + formAns.answerList.length < formAns.subNum
  245 + ? (formAns.answerList += '✓')
  246 + : ''
  247 + "
  248 + >✓</span
  249 + >
  250 + <span
  251 + class="answer-s active"
  252 + @click="
  253 + formAns.answerList.length < formAns.subNum
  254 + ? (formAns.answerList += '✗')
  255 + : ''
  256 + "
  257 + >✗</span
  258 + >
  259 + </template>
  260 + <template v-if="formAns.qusType == 3">
  261 + <span
  262 + class="answer-s active"
  263 + v-for="option in formAns.answerOptions.split(',')"
  264 + :key="option"
  265 + @click="setMultiple(formAns, option)"
  266 + >{{ option }}</span
  267 + >
  268 + <span
  269 + class="answer-s active"
  270 + @click="
  271 + formAns.answerList.split(',').length < formAns.subNum
  272 + ? (formAns.answerList += ',')
  273 + : ''
  274 + "
  275 + >,</span
  276 + >
  277 + </template>
  278 + <template v-if="formAns.qusType == 2" class="answer-box">
  279 + <span
  280 + class="answer-s active"
  281 + v-for="option in formAns.answerOptions.split(',')"
  282 + :key="option"
  283 + @click="
  284 + formAns.answerList.length < formAns.subNum
  285 + ? (formAns.answerList += option)
  286 + : ''
  287 + "
  288 + >{{ option }}</span
  289 + >
  290 + </template>
  291 + <span
  292 + class="answer-s delButton"
  293 + @click="formAns.answerList = formAns.answerList.slice(0, -1)"
  294 + >x</span
  295 + >
  296 + </p>
  297 + </div>
  298 + <div class="dialog-footer" slot="footer">
  299 + <el-button @click="saveFormAns">确 定</el-button>
  300 + <el-button @click="diaSetAns = false">取 消</el-button>
  301 + </div>
  302 + </el-dialog>
130 303 </div>
131 304 </div>
132 305 </template>
133 306  
134 307 <script>
135   -import { deepClone } from "utils";
  308 +import { deepClone, checkAnswer } from "utils";
136 309 export default {
137 310 data() {
138 311 return {
... ... @@ -145,21 +318,29 @@ export default {
145 318 examsDuration: 90,
146 319 gradeName: "",
147 320 share: 1,
148   -
149 321 questionList: [],
150 322 },
151 323 paperModifyLog: {
152 324 realName: "",
153 325 modifiedTime: "",
154 326 },
  327 + diaSetAns: false,
  328 + formAns: {
  329 + listIndex: 0, //大题位置
  330 + endIndex: 0, //相同题目最后一位题目的questionIndex
  331 + qusType: "", //题目类型
  332 + subNum: 0, //数量
  333 + answerOptions: [], //答案选项
  334 + answerList: "", //答案列表-字符串
  335 + },
155 336 };
156 337 },
157 338 computed: {
158 339 allScore: function () {
159 340 let score = 0;
160   - this.form.questionList.map((item) => {
  341 + this.questionList.map((item) => {
161 342 score += item.subQuestions.reduce((a, b) => {
162   - return a + Number(b.score);
  343 + return a + (Number(b.score) || 0);
163 344 }, 0);
164 345 }, 0);
165 346 return Number(score).toFixed(2);
... ... @@ -222,7 +403,7 @@ export default {
222 403 },
223 404 setScore(question) {
224 405 let score = question.subQuestions.reduce((a, b) => {
225   - return a + b.score;
  406 + return a + (b.score || 0);
226 407 }, 0);
227 408 return Number(score).toFixed(2);
228 409 },
... ... @@ -237,20 +418,136 @@ export default {
237 418 sub.correctAnswer = arrs.sort().join("");
238 419 }
239 420 },
  421 + keydownAnswer(event, type) {
  422 + let answerA = "ABCDEFG";
  423 + let answer_a = "abcdefg";
  424 + answerA = answerA.substring(0, this.formAns.subNum);
  425 + answer_a = answer_a.substring(0, this.formAns.subNum);
  426 + answerA += answer_a;
  427 + answerA = type == 2 ? answerA : answerA + ",";
  428 + if (
  429 + event.key == "Meta" ||
  430 + event.key == "CapsLock" ||
  431 + event.key == "Shift" ||
  432 + event.key == "Enter" ||
  433 + event.key == "Alt" ||
  434 + event.key == "Backspace" ||
  435 + event.key == "Delete" ||
  436 + event.key == "ArrowUp" ||
  437 + event.key == "ArrowDown" ||
  438 + event.key == "ArrowLeft" ||
  439 + event.key == "v" ||
  440 + event.key == "V" ||
  441 + event.key == "ArrowRight"
  442 + )
  443 + return;
  444 + if (!answerA.includes(event.key)) {
  445 + event.returnValue = "";
  446 + }
  447 + },
  448 + setAllAnswer(event, type) {
  449 + let str = this.formAns.answerList;
  450 + let str2 = checkAnswer(
  451 + str,
  452 + type,
  453 + this.formAns.answerOptions.split(",").length,
  454 + this.formAns.subNum
  455 + );
  456 + this.formAns.answerList = str2;
  457 + },
  458 + setAnswer(type, ans) {
  459 + let txt = "";
  460 + if (type == 2) {
  461 + txt = ans;
  462 + } else if (type == 3) {
  463 + txt = ans + ",";
  464 + } else if (type == 4) {
  465 + txt = ans == 1 ? "✓" : ans == 2 ? "✗" : "";
  466 + }
  467 + return txt;
  468 + },
  469 + setMultiple(obj, answer) {
  470 + //多选答案设置
  471 + obj.answerList += answer;
  472 + let str = obj.answerList;
  473 + let str2 = checkAnswer(
  474 + str,
  475 + 3,
  476 + obj.answerOptions.split(",").length,
  477 + obj.answerList.length
  478 + );
  479 + obj.answerList = str2;
  480 + },
  481 + setFormAns(indexs, index) {
  482 + //初始化要修改的答案
  483 + if (this.questionList[0].subQuestions) {
  484 + this.formAns = { ...this.questionList[index].subQuestions[indexs] };
  485 + this.formAns.listIndex = index;
  486 + } else {
  487 + this.formAns = { ...this.questionList[indexs] };
  488 + this.formAns.listIndex = indexs;
  489 + }
  490 + this.diaSetAns = true;
  491 + },
  492 + saveFormAns() {
  493 + //批量修改答案
  494 + let EndIndex;
  495 + let subNum = this.formAns.subNum - 1;
  496 + if (this.questionList[this.formAns.listIndex].subQuestions) {
  497 + this.questionList[this.formAns.listIndex].subQuestions.some(
  498 + (item, index) => {
  499 + if (this.formAns.endIndex == item.questionIndex) {
  500 + EndIndex = index;
  501 + return;
  502 + }
  503 + }
  504 + );
  505 + } else {
  506 + this.questionList.some((item, index) => {
  507 + if (this.formAns.endIndex == item.questionIndex) {
  508 + EndIndex = index;
  509 + return;
  510 + }
  511 + });
  512 + }
  513 +
  514 + for (let i = 0; i <= subNum; i++) {
  515 + let correctAnswer = "";
  516 + if (this.formAns.qusType == 2) {
  517 + correctAnswer = this.formAns.answerList[subNum - i];
  518 + } else if (this.formAns.qusType == 3) {
  519 + correctAnswer = this.formAns.answerList.split(",")[subNum - i];
  520 +
  521 + console.log(this.formAns.answerList.split(",")[subNum - i]);
  522 + } else if (this.formAns.qusType == 4) {
  523 + correctAnswer = this.formAns.answerList[subNum - i] == "✓" ? 1 : 2;
  524 + }
  525 + if (this.questionList[0].subQuestions) {
  526 + this.questionList[this.formAns.listIndex].subQuestions[
  527 + EndIndex - i
  528 + ].correctAnswer = correctAnswer;
  529 + } else {
  530 + this.questionList[EndIndex - i].correctAnswer = correctAnswer;
  531 + }
  532 + }
  533 + this.diaSetAns = false;
  534 + },
240 535 async save() {
241   - // let valid = "";
242   - // this.form.questionList.map((item, index) => {
243   - // if (!item.questionTitle) {
244   - // valid += index + 1 + "、";
245   - // }
246   - // });
247   - // if (valid) {
248   - // this.$message.error(
249   - // `大题名称不能为空,请检查第${valid.slice(0, -1)}题!`
250   - // );
251   - // return;
252   - // }
253   - let questionList = this.form.questionList.map((item) => {
  536 + for (let i = 0; i < this.questionList.length; i++) {
  537 + if (this.questionList[0].subQuestions) {
  538 + for (let j = 0; j < this.questionList[i].subQuestions.length; j++) {
  539 + if (this.questionList[i].subQuestions[j].qusType) {
  540 + this.questionList[i].subQuestions.splice(j, 1);
  541 + }
  542 + }
  543 + } else {
  544 + if (this.questionList[i].qusType) {
  545 + this.questionList.splice(i, 1);
  546 + i--;
  547 + }
  548 + }
  549 + }
  550 + let questionList = this.questionList.map((item) => {
254 551 item.score = null;
255 552 // item.questionId = "";
256 553 // item.questionIndex = "";
... ... @@ -276,13 +573,127 @@ export default {
276 573 });
277 574 if (status == 0) {
278 575 this.form = deepClone(data);
279   - this.form.questionList.map((item) => {
280   - item.score = "";
281   - });
  576 + this.questionList = deepClone(this.form.questionList);
282 577 this.paperModifyLog = {
283 578 ...this.paperModifyLog,
284 579 ...this.form.paperModifyLog,
285 580 };
  581 + if (!!this.questionList[0]?.subQuestions) {
  582 + this.questionList?.map((item) => {
  583 + let types = [{}];
  584 + let addndex = 0;
  585 + item.subQuestions.map((sub, index) => {
  586 + if (!!sub.questionType && sub.questionType != 5) {
  587 + if (sub.questionType == types[addndex].qusType) {
  588 + //同类型批量答案+1
  589 + types[addndex].subNum += 1;
  590 + if (
  591 + types[addndex].answerOptions.length <
  592 + sub.answerOptions.length
  593 + ) {
  594 + types[addndex].answerOptions = sub.answerOptions;
  595 + }
  596 + types[addndex].answerList += this.setAnswer(
  597 + sub.questionType,
  598 + sub.correctAnswer
  599 + );
  600 + if (index == item.subQuestions.length - 1) {
  601 + //循环最后类型数量大于等于5,保存批量答案
  602 + if (types[addndex].subNum && types[addndex].subNum >= 5) {
  603 + types[addndex].endIndex = sub.questionIndex;
  604 + types[addndex].index = index;
  605 + }
  606 + }
  607 + } else {
  608 + if (types[addndex].subNum && types[addndex].subNum >= 5) {
  609 + //不同类型时如果原有类型数量大于等于5,保存批量答案
  610 + types[addndex].endIndex =
  611 + item.subQuestions[index - 1].questionIndex;
  612 + types[addndex].index = index - 1;
  613 + addndex += 1;
  614 + types[addndex] = {};
  615 + }
  616 + //不同类型初始化批量答案
  617 + types[addndex].qusType = sub.questionType;
  618 + types[addndex].subNum = 1;
  619 + types[addndex].answerOptions = sub.answerOptions;
  620 + types[addndex].answerList = this.setAnswer(
  621 + sub.questionType,
  622 + sub.correctAnswer
  623 + );
  624 + }
  625 + }
  626 + });
  627 + for (let i = 0; i < types.length; i++) {
  628 + if (types[i].qusType == 3) {
  629 + types[i].answerList = types[i].answerList.slice(0, -1);
  630 + }
  631 + if (types[i].subNum >= 5) {
  632 + item.subQuestions.splice(
  633 + types[i].index + i + 1,
  634 + 0,
  635 + deepClone(types[i])
  636 + );
  637 + }
  638 + }
  639 + });
  640 + } else {
  641 + let types = [{}];
  642 + let addndex = 0;
  643 + this.questionList?.map((sub, index) => {
  644 + if (!!sub.questionType && sub.questionType != 5) {
  645 + if (sub.questionType == types[addndex].qusType) {
  646 + //同类型批量答案+1
  647 + types[addndex].subNum += 1;
  648 + if (
  649 + types[addndex].answerOptions.length < sub.answerOptions.length
  650 + ) {
  651 + types[addndex].answerOptions = sub.answerOptions;
  652 + }
  653 + types[addndex].answerList += this.setAnswer(
  654 + sub.questionType,
  655 + sub.correctAnswer
  656 + );
  657 + if (index == this.questionList.length - 1) {
  658 + //循环最后类型数量大于等于5,保存批量答案
  659 + if (types[addndex].subNum && types[addndex].subNum >= 5) {
  660 + types[addndex].endIndex = sub.questionIndex;
  661 + types[addndex].index = index;
  662 + }
  663 + }
  664 + } else {
  665 + if (types[addndex].subNum && types[addndex].subNum >= 5) {
  666 + //不同类型时如果原有类型数量大于等于5,保存批量答案
  667 + types[addndex].endIndex =
  668 + this.questionList[index - 1].questionIndex;
  669 + types[addndex].index = index - 1;
  670 + addndex += 1;
  671 + types[addndex] = {};
  672 + }
  673 + //不同类型初始化批量答案
  674 + types[addndex].qusType = sub.questionType;
  675 + types[addndex].subNum = 1;
  676 + types[addndex].answerOptions = sub.answerOptions;
  677 + types[addndex].answerList = this.setAnswer(
  678 + sub.questionType,
  679 + sub.correctAnswer
  680 + );
  681 + }
  682 + }
  683 + });
  684 + for (let i = 0; i < types.length; i++) {
  685 + if (types[i].qusType == 3) {
  686 + types[i].answerList = types[i].answerList.slice(0, -1);
  687 + }
  688 + if (types[i].subNum >= 5) {
  689 + item.subQuestions.splice(
  690 + types[i].index + i + 1,
  691 + 0,
  692 + deepClone(types[i])
  693 + );
  694 + }
  695 + }
  696 + }
286 697 } else {
287 698 this.$message.error(info);
288 699 }
... ... @@ -350,6 +761,13 @@ export default {
350 761 font-weight: 700;
351 762 }
352 763 }
  764 +.set-ans-btn {
  765 + width: 100%;
  766 + padding: 10px 0 10px 630px;
  767 + box-sizing: border-box;
  768 + border-bottom: 1px solid #e2e2e2;
  769 + border-right: 1px solid #e2e2e2;
  770 +}
353 771 .el-input-number {
354 772 width: 140px;
355 773 }
... ...
src/views/test/index.vue
... ... @@ -122,6 +122,7 @@
122 122 <el-table-column
123 123 prop="examStartTime"
124 124 label="测验时间"
  125 + width="160"
125 126 align="center"
126 127 ></el-table-column>
127 128 <el-table-column prop="avgScore" label="班平均分" align="center"
... ...