ModifyMarkParams.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <template>
  2. <el-dialog
  3. class="modify-mark-params"
  4. :visible.sync="modalIsShow"
  5. top="0"
  6. :close-on-click-modal="false"
  7. :close-on-press-escape="false"
  8. :show-close="false"
  9. append-to-body
  10. fullscreen
  11. @open="initData"
  12. >
  13. <div slot="title">
  14. <h2 class="el-dialog__title">评卷参数设置</h2>
  15. <span
  16. >课程名称:{{ instance.courseName }}({{ instance.courseCode }})</span
  17. >
  18. <button class="el-dialog__headerbtn" @click="cancel"></button>
  19. </div>
  20. <div class="mb-4 tab-btns">
  21. <el-button
  22. v-for="tab in tabs"
  23. :key="tab.val"
  24. size="medium"
  25. :type="curTab == tab.val ? 'primary' : 'default'"
  26. :disabled="!basicInfoIsSave && tab.val !== 'structure'"
  27. @click="selectMenu(tab.val)"
  28. >{{ tab.name }}
  29. </el-button>
  30. </div>
  31. <div v-if="dataReady">
  32. <component
  33. :is="currentComponent"
  34. def="MarkParamRef"
  35. @cancel="cancel"
  36. @confirm="confirm"
  37. ></component>
  38. </div>
  39. <div slot="footer"></div>
  40. </el-dialog>
  41. </template>
  42. <script>
  43. import { mapState, mapMutations } from "vuex";
  44. import MarkParamStructure from "./MarkParamStructure.vue";
  45. import MarkParamMarker from "./MarkParamMarker.vue";
  46. import MarkParamMarkerLeader from "./MarkParamMarkerLeader.vue";
  47. import MarkParamObjectiveAnswer from "./MarkParamObjectiveAnswer.vue";
  48. import MarkParamUploadAnswer from "./MarkParamUploadAnswer.vue";
  49. import { cardDetail } from "../../../card/api";
  50. import { examStructureStatus } from "../../api";
  51. export default {
  52. name: "modify-mark-params",
  53. components: {
  54. MarkParamStructure,
  55. MarkParamMarker,
  56. MarkParamMarkerLeader,
  57. MarkParamObjectiveAnswer,
  58. MarkParamUploadAnswer,
  59. },
  60. props: {
  61. instance: {
  62. type: Object,
  63. default() {
  64. return {};
  65. },
  66. },
  67. },
  68. data() {
  69. return {
  70. modalIsShow: false,
  71. dataReady: false,
  72. // step
  73. curTab: "structure",
  74. tabs: [
  75. {
  76. name: "评卷参数设置",
  77. val: "structure",
  78. },
  79. {
  80. name: "科组长设置",
  81. val: "marker-leader",
  82. },
  83. {
  84. name: "评卷员管理",
  85. val: "marker",
  86. },
  87. {
  88. name: "客观题标答设置",
  89. val: "objective-answer",
  90. },
  91. {
  92. name: "主观题标答设置",
  93. val: "upload-answer",
  94. },
  95. ],
  96. current: 0,
  97. };
  98. },
  99. computed: {
  100. ...mapState("markParam", ["markParamInfos"]),
  101. currentComponent() {
  102. return `mark-param-${this.curTab}`;
  103. },
  104. isFirstStep() {
  105. return this.current === 0;
  106. },
  107. isLastStep() {
  108. return this.current === this.lastStep;
  109. },
  110. lastStep() {
  111. return this.tabs.length - 1;
  112. },
  113. basicInfoIsSave() {
  114. return !!this.markParamInfos.basicPaperInfo.id;
  115. },
  116. },
  117. watch: {
  118. curTab() {
  119. this.updateMarkStatus();
  120. },
  121. },
  122. methods: {
  123. ...mapMutations("markParam", [
  124. "setMarkParamInfos",
  125. "setObjectiveStructure",
  126. "setMarkStatus",
  127. "setMarkLeader",
  128. "initStore",
  129. ]),
  130. async initData() {
  131. const basicPaperInfo = {
  132. ...this.instance,
  133. openClassReading: !!this.instance.openClassReading,
  134. };
  135. if (this.instance.paperInfoJson) {
  136. const { paperStructureInfo, groupInfo, classInfo, structureCanEdit } =
  137. JSON.parse(this.instance.paperInfoJson);
  138. const infos = {
  139. structureCanEdit,
  140. paperStructureInfo: [
  141. ...paperStructureInfo.objectiveQuestionList,
  142. ...paperStructureInfo.subjectiveQuestionList,
  143. ],
  144. groupInfo: groupInfo || [],
  145. classInfo: classInfo || [],
  146. basicPaperInfo,
  147. };
  148. this.setMarkParamInfos(infos);
  149. } else {
  150. const detData = await cardDetail(this.instance.cardId);
  151. const cardContent = JSON.parse(detData.content);
  152. let infos = { basicPaperInfo, structureCanEdit: true };
  153. if (
  154. (detData.type === "GENERIC" && detData.createMethod === "STANDARD") ||
  155. detData.type === "CUSTOM"
  156. ) {
  157. infos.structureCanEdit = false;
  158. infos.paperStructureInfo = this.parsePaperStructureFromCard(
  159. cardContent.pages
  160. );
  161. }
  162. // console.log(infos);
  163. this.setMarkParamInfos(infos);
  164. }
  165. if (this.instance.status) {
  166. const data = JSON.parse(this.instance.status);
  167. this.setMarkStatus(data);
  168. }
  169. if (this.instance.markLeader) {
  170. const data = JSON.parse(this.instance.markLeader);
  171. this.setMarkLeader(data);
  172. }
  173. const objectiveStructure = JSON.parse(
  174. this.instance.objectiveStructure || "[]"
  175. );
  176. this.setObjectiveStructure(objectiveStructure);
  177. this.selectMenu("structure");
  178. this.dataReady = true;
  179. },
  180. async updateMarkStatus() {
  181. if (!this.markParamInfos.basicPaperInfo.id) return;
  182. const res = await examStructureStatus(
  183. this.markParamInfos.basicPaperInfo.id
  184. ).catch(() => {});
  185. if (!res) return;
  186. const data = JSON.parse(res);
  187. this.setMarkStatus(data);
  188. },
  189. parsePaperStructureFromCard(pages) {
  190. let structData = [];
  191. let curTopicId = 0;
  192. pages.forEach((page) => {
  193. page.columns.forEach((column) => {
  194. column.elements.forEach((topic) => {
  195. if (!topic.parent) return;
  196. if (curTopicId === topic.parent.id) return;
  197. curTopicId = topic.parent.id;
  198. let questionsCount = 1,
  199. startNumber = 1;
  200. if (topic.type === "COMPOSITION") {
  201. // 相同大题号的作文题合并处理
  202. const compositionData = structData.find(
  203. (struct) =>
  204. struct.cardTopicType === "COMPOSITION" &&
  205. struct.mainNumber === topic.parent.topicNo * 1
  206. );
  207. if (compositionData) return;
  208. } else {
  209. questionsCount = topic.parent.questionsCount;
  210. startNumber = topic.parent.startNumber || 1;
  211. }
  212. const typeInfo = this.getQuestionType(topic);
  213. if (!typeInfo) return;
  214. let data = {
  215. mainNumber: topic.parent.topicNo * 1,
  216. mainTitle: topic.parent.topicName,
  217. questionsCount,
  218. startNumber,
  219. cardTopicType: topic.type,
  220. ...typeInfo,
  221. };
  222. if (topic.type === "FILL_QUESTION") {
  223. data.optionCount = topic.optionCount;
  224. }
  225. structData.push(data);
  226. });
  227. });
  228. });
  229. // console.log(structData);
  230. let structure = [];
  231. let mainIds = {};
  232. structData.forEach((struct) => {
  233. const { startNumber, questionsCount, qType, mainNumber, mainTitle } =
  234. struct;
  235. if (!mainIds[mainNumber]) {
  236. mainIds[mainNumber] = this.$randomCode();
  237. }
  238. for (let i = 0; i < questionsCount; i++) {
  239. structure.push({
  240. id: this.$randomCode(),
  241. qType,
  242. mainId: mainIds[mainNumber],
  243. mainTitle,
  244. mainNumber,
  245. subNumber: startNumber + i,
  246. type: struct.type,
  247. typeName: struct.typeName,
  248. optionCount: struct.optionCount || null,
  249. totalScore: undefined,
  250. mainFirstSub: false,
  251. expandSub: true,
  252. });
  253. }
  254. });
  255. structure.sort(
  256. (a, b) => a.mainNumber - b.mainNumber || a.subNumber - b.subNumber
  257. );
  258. let curMainId = null;
  259. structure.forEach((item) => {
  260. if (curMainId !== item.mainId) {
  261. curMainId = item.mainId;
  262. item.mainFirstSub = true;
  263. }
  264. });
  265. return structure;
  266. },
  267. getQuestionType(topic) {
  268. // const questionType = {
  269. // 1: "SINGLE_ANSWER_QUESTION",
  270. // 2: "MULTIPLE_ANSWER_QUESTION",
  271. // 3: "BOOL_ANSWER_QUESTION",
  272. // 4: "FILL_BLANK_QUESTION",
  273. // 5: "TEXT_ANSWER_QUESTION",
  274. // };
  275. if (topic.type === "COMPOSITION" || topic.type === "EXPLAIN") {
  276. return {
  277. type: 5,
  278. typeName: "解答题",
  279. qType: "subjective",
  280. };
  281. }
  282. if (topic.type === "FILL_LINE") {
  283. return {
  284. type: 4,
  285. typeName: "填空题",
  286. qType: "subjective",
  287. };
  288. }
  289. if (topic.type === "FILL_QUESTION") {
  290. if (topic.isBoolean)
  291. return {
  292. type: 3,
  293. typeName: "判断题",
  294. qType: "objective",
  295. };
  296. if (topic.isMultiply)
  297. return {
  298. type: 2,
  299. typeName: "多选题",
  300. qType: "objective",
  301. };
  302. return {
  303. type: 1,
  304. typeName: "单选题",
  305. qType: "objective",
  306. };
  307. }
  308. return;
  309. },
  310. selectMenu(val) {
  311. this.curTab = val;
  312. this.current = this.tabs.findIndex((item) => item.val === val);
  313. },
  314. async cancel() {
  315. const res = await this.$confirm("确定要退出阅卷参数编辑吗?", "提示", {
  316. type: "warning",
  317. }).catch(() => {});
  318. if (res !== "confirm") return;
  319. this.initStore();
  320. this.dataReady = false;
  321. this.$emit("modified");
  322. this.modalIsShow = false;
  323. },
  324. open() {
  325. this.modalIsShow = true;
  326. },
  327. confirm() {
  328. if (this.isLastStep) {
  329. this.selectMenu(this.tabs[0].val);
  330. } else {
  331. this.selectMenu(this.tabs[this.current + 1].val);
  332. }
  333. },
  334. },
  335. };
  336. </script>