MarkParamObjectiveAnswer.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <template>
  2. <div class="mark-param-objective-answer">
  3. <div class="box-justify part-box part-box-pad">
  4. <div>
  5. <p class="tips-info">1.请录入客观题标答;</p>
  6. <p class="tips-info">
  7. 2.多选题请根据需求设置判分策略,目前支持漏选给半分,任选给半分或者不设置,不设置时表示与标答一致得分,否则不得分。
  8. </p>
  9. </div>
  10. <div>
  11. <mark-status field="objective"></mark-status>
  12. </div>
  13. </div>
  14. <div class="part-box part-box-pad">
  15. <p class="tips-info mb-1">
  16. <i class="el-icon-warning"></i> 客观题标答只能输入大写字母ABCDE...
  17. ,判断题正确请输入A,错误输入B
  18. </p>
  19. <el-table
  20. ref="TableList"
  21. :data="tableData"
  22. border
  23. :row-class-name="getRowClassName"
  24. >
  25. <el-table-column width="50" align="center">
  26. <template slot-scope="scope" v-if="scope.row.mainFirstSub">
  27. <div
  28. :class="[
  29. 'expand-btn',
  30. { 'expand-btn-unexpand': !scope.row.expandSub },
  31. ]"
  32. @click="switchExpandSub(scope.row)"
  33. >
  34. <i
  35. :class="scope.row.expandSub ? 'el-icon-minus' : 'el-icon-plus'"
  36. ></i>
  37. </div>
  38. </template>
  39. </el-table-column>
  40. <el-table-column prop="mainTitle" label="大题名称">
  41. <span slot-scope="scope" v-if="scope.row.mainFirstSub">
  42. {{ scope.row.mainTitle }}
  43. </span>
  44. </el-table-column>
  45. <el-table-column prop="typeName" label="题型" width="120">
  46. <template slot-scope="scope" v-if="scope.row.mainFirstSub">
  47. {{ scope.row.typeName }}
  48. </template>
  49. </el-table-column>
  50. <el-table-column prop="mainNumber" label="大题号" width="80">
  51. <template slot-scope="scope" v-if="scope.row.mainFirstSub">
  52. <span>{{ scope.row.mainNumber }}</span>
  53. </template>
  54. </el-table-column>
  55. <el-table-column
  56. prop="subNumber"
  57. label="小题号"
  58. width="80"
  59. ></el-table-column>
  60. <!-- <el-table-column prop="totalScore" label="小题满分" width="105">
  61. </el-table-column> -->
  62. <el-table-column label="答案" width="200px" class-name="answer-column">
  63. <div
  64. slot-scope="scope"
  65. :class="['el-form-item', { 'is-error': scope.row.error }]"
  66. >
  67. <div class="el-form-item__content">
  68. <el-input
  69. v-model.trim="scope.row.answer"
  70. :placeholder="
  71. scope.row.type === 3 ? 'A:正确,B:错误' : '请输入答案'
  72. "
  73. :maxlength="scope.row.optionCount"
  74. clearable
  75. @change="validateAnswer(scope.row)"
  76. ></el-input>
  77. <div v-if="scope.row.error" class="el-form-item__error">
  78. {{ scope.row.errMsg }}
  79. </div>
  80. </div>
  81. </div>
  82. </el-table-column>
  83. <el-table-column label="判分规则" width="140px">
  84. <template v-if="scope.row.type === 2" slot-scope="scope">
  85. <el-select v-model="scope.row.objectivePolicy">
  86. <el-option
  87. v-for="(val, key) in QUESTION_SCORE_TYPE"
  88. :key="key"
  89. :value="key"
  90. :label="val"
  91. ></el-option>
  92. </el-select>
  93. </template>
  94. </el-table-column>
  95. </el-table>
  96. </div>
  97. <div class="text-center">
  98. <el-button type="primary" :disabled="loading" @click="submit"
  99. >提交</el-button
  100. >
  101. <el-button @click="cancel">取消</el-button>
  102. </div>
  103. </div>
  104. </template>
  105. <script>
  106. import { QUESTION_SCORE_TYPE } from "@/constants/enumerate";
  107. import { updateObjectiveAnswer } from "../../api";
  108. import { mapState, mapMutations } from "vuex";
  109. import MarkStatus from "./MarkStatus.vue";
  110. export default {
  111. name: "modify-objective-answer",
  112. components: { MarkStatus },
  113. data() {
  114. return {
  115. loading: false,
  116. tableData: [],
  117. QUESTION_SCORE_TYPE,
  118. abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
  119. };
  120. },
  121. computed: {
  122. ...mapState("markParam", ["objectiveStructure", "markParamInfos"]),
  123. },
  124. mounted() {
  125. this.initData();
  126. },
  127. methods: {
  128. ...mapMutations("markParam", ["setObjectiveStructure"]),
  129. initData() {
  130. let objectiveStructure = this.objectiveStructure.length || [];
  131. let objectiveAnswerMap = {};
  132. objectiveStructure.forEach((item) => {
  133. objectiveAnswerMap[
  134. `${item.type}_${item.mainNumber}_${item.subNumber}`
  135. ] = {
  136. answer: item.answer,
  137. objectivePolicy: item.objectivePolicy,
  138. };
  139. });
  140. let curMainNumber = null;
  141. this.tableData = this.markParamInfos.paperStructureInfo
  142. .filter((item) => item.qType === "objective")
  143. .map((item) => {
  144. let nitem = { ...item };
  145. if (nitem.mainNumber !== curMainNumber) {
  146. curMainNumber = nitem.mainNumber;
  147. nitem.mainFirstSub = true;
  148. } else {
  149. nitem.mainFirstSub = false;
  150. }
  151. const cacheVal =
  152. objectiveAnswerMap[
  153. `${item.type}_${item.mainNumber}_${item.subNumber}`
  154. ] || {};
  155. nitem.expandSub = true;
  156. nitem.answer = cacheVal.answer || "";
  157. nitem.objectivePolicy = cacheVal.objectivePolicy || "NONE";
  158. nitem.error = false;
  159. nitem.errMsg = "";
  160. return nitem;
  161. });
  162. },
  163. getRowClassName({ row }) {
  164. let classNames = [];
  165. if (row.mainFirstSub) {
  166. classNames.push("row-main-first-sub");
  167. }
  168. if (!row.mainFirstSub && !row.expandSub) {
  169. classNames.push("row-unexpand-sub");
  170. }
  171. return classNames.join(" ");
  172. },
  173. switchExpandSub(row) {
  174. row.expandSub = !row.expandSub;
  175. this.tableData
  176. .filter((item) => item.mainId === row.mainId && !item.mainFirstSub)
  177. .forEach((item) => (item.expandSub = row.expandSub));
  178. },
  179. validateAnswer(row) {
  180. if (!row.answer) {
  181. row.error = true;
  182. row.errMsg = "不能为空";
  183. return;
  184. }
  185. if (!/^[A-Z]{1,26}$/.test(row.answer)) {
  186. row.error = true;
  187. row.errMsg = "只能输入英文大写字母";
  188. return;
  189. }
  190. const validAnswers = this.abc.substring(0, row.optionCount);
  191. // 单选题 判断题
  192. if (row.type === 1 || row.type === 3) {
  193. if (
  194. row.answer.length !== 1 ||
  195. row.answer.split("").some((item) => !validAnswers.includes(item))
  196. ) {
  197. row.error = true;
  198. row.errMsg = `只能输入${validAnswers}中的一个`;
  199. return;
  200. }
  201. }
  202. // 多选题
  203. if (row.type === 2) {
  204. if (row.answer.length <= 1) {
  205. row.error = true;
  206. row.errMsg = `答案必须为多个`;
  207. return;
  208. }
  209. if (row.answer.split("").some((item) => !validAnswers.includes(item))) {
  210. row.error = true;
  211. row.errMsg = `只能输入${validAnswers}中的字符`;
  212. return;
  213. }
  214. const ansSet = new Set(row.answer.split(""));
  215. if (ansSet.size !== row.answer.length) {
  216. row.error = true;
  217. row.errMsg = "答案不能重复";
  218. return;
  219. }
  220. }
  221. row.error = false;
  222. row.errMsg = "";
  223. },
  224. checkData() {
  225. this.tableData.forEach((item) => {
  226. this.validateAnswer(item);
  227. });
  228. return !this.tableData.some((item) => item.error);
  229. },
  230. async submit() {
  231. if (!this.checkData()) return;
  232. if (this.loading) return;
  233. this.loading = true;
  234. const datas = {
  235. id: this.markParamInfos.basicPaperInfo.id,
  236. objectiveStructure: this.tableData.map((item) => {
  237. let nitem = { ...item };
  238. delete nitem.errMsg;
  239. delete nitem.error;
  240. return nitem;
  241. }),
  242. };
  243. const data = await updateObjectiveAnswer(datas).catch(() => {});
  244. this.loading = false;
  245. if (!data) return;
  246. this.setObjectiveStructure(datas.objectiveStructure);
  247. this.$message.success("编辑成功!");
  248. this.$emit("confirm");
  249. },
  250. cancel() {
  251. this.$emit("cancel");
  252. },
  253. },
  254. };
  255. </script>