QuestionEditDialog.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <template>
  2. <el-dialog
  3. custom-class="question-edit-dialog"
  4. :visible.sync="modalIsShow"
  5. :close-on-click-modal="false"
  6. :close-on-press-escape="false"
  7. append-to-body
  8. fullscreen
  9. :show-close="false"
  10. @open="visibleChange"
  11. >
  12. <div slot="title" class="box-justify">
  13. <div>
  14. <h2>{{ isEdit ? "编辑试题" : "创建试题" }}</h2>
  15. <span>课程代码:{{ questionModel.courseCode }}</span>
  16. <span>课程名称:{{ questionModel.courseName }}</span>
  17. </div>
  18. <div>
  19. <el-button
  20. size="small"
  21. type="primary"
  22. :loading="loading"
  23. @click="confirm"
  24. >确定</el-button
  25. >
  26. <el-button size="small" @click="cancel">取消</el-button>
  27. </div>
  28. </div>
  29. <div class="part-box question-edit">
  30. <el-form label-width="100px">
  31. <el-form-item v-if="isEdit" label="题型">
  32. <el-button type="primary" size="small">
  33. {{ questionModel.sourceDetailName }}
  34. </el-button>
  35. </el-form-item>
  36. <el-form-item v-else label="题型">
  37. <el-button
  38. v-for="item in sourceDetailList"
  39. :key="item.id"
  40. :type="
  41. questionModel.sourceDetailId === item.id ? 'primary' : 'default'
  42. "
  43. size="small"
  44. :disabled="loading"
  45. @click="switchType(item)"
  46. >{{ item.name }}</el-button
  47. >
  48. <el-button
  49. v-if="sourceDetailAllList.length > limitShowCount"
  50. size="small"
  51. :icon="showMore ? 'el-icon-arrow-up' : 'el-icon-more'"
  52. @click="switchMoreSourceDetail"
  53. ></el-button>
  54. <el-button
  55. size="small"
  56. icon="el-icon-plus"
  57. @click="toAddSourceDetail"
  58. ></el-button>
  59. <p class="tips-info">
  60. 说明:如果是综合类试题(套题)可以选择题型为阅卷理解进行录入操作。
  61. </p>
  62. </el-form-item>
  63. </el-form>
  64. <!-- question-body -->
  65. <component
  66. :is="structTypeComp"
  67. :key="questionKey"
  68. ref="QuestionEditDetail"
  69. :question="questionModel"
  70. ></component>
  71. </div>
  72. <div slot="footer"></div>
  73. <!-- ModifySourceDetail -->
  74. <modify-source-detail
  75. ref="ModifySourceDetail"
  76. :instance="curSourceInfo"
  77. @modified="sourceDetailAdded"
  78. ></modify-source-detail>
  79. </el-dialog>
  80. </template>
  81. <script>
  82. import { QUESTION_TYPES } from "@/constants/constants";
  83. import { STRUCT_TYPE_COMP_DICT } from "./edit/questionModel";
  84. import BooleanQuestion from "./edit/BooleanQuestion.vue";
  85. import FillBlankQuestion from "./edit/FillBlankQuestion.vue";
  86. import SelectQuestion from "./edit/SelectQuestion.vue";
  87. import TextAnswerQuestion from "./edit/TextAnswerQuestion.vue";
  88. import NestedQuestion from "./edit/NestedQuestion.vue";
  89. import BankedClozeQuestion from "./edit/BankedClozeQuestion.vue";
  90. import { randomCode } from "@/plugins/utils";
  91. import {
  92. updateQuestionApi,
  93. sourceDetailPageListApi,
  94. questionDetailApi,
  95. } from "../api";
  96. import ModifySourceDetail from "./ModifySourceDetail.vue";
  97. const initQuestionModel = {
  98. courseId: null,
  99. courseCode: "",
  100. courseName: "",
  101. sourceDetailId: null,
  102. questionType: "",
  103. };
  104. export default {
  105. name: "QuestionEditDialog",
  106. components: {
  107. FillBlankQuestion,
  108. SelectQuestion,
  109. TextAnswerQuestion,
  110. BooleanQuestion,
  111. NestedQuestion,
  112. BankedClozeQuestion,
  113. ModifySourceDetail,
  114. },
  115. props: {
  116. question: {
  117. type: Object,
  118. default() {
  119. return { id: "" };
  120. },
  121. },
  122. editMode: {
  123. type: String,
  124. default: "question",
  125. },
  126. },
  127. data() {
  128. return {
  129. modalIsShow: false,
  130. sourceDetailAllList: [],
  131. sourceDetailList: [],
  132. curSourceDetail: {},
  133. limitShowCount: 10,
  134. showMore: false,
  135. questionModel: {
  136. questionType: "SINGLE_ANSWER_QUESTION",
  137. },
  138. detailName: "",
  139. questionKey: "",
  140. loading: false,
  141. hasModifyQuestion: false,
  142. curSourceInfo: {},
  143. };
  144. },
  145. computed: {
  146. isEdit() {
  147. return !!this.question.id;
  148. },
  149. title() {
  150. return this.isEdit ? "编辑试题" : "创建试题";
  151. },
  152. structTypeComp() {
  153. return STRUCT_TYPE_COMP_DICT[this.questionModel.questionType];
  154. },
  155. },
  156. methods: {
  157. async visibleChange() {
  158. // paper模式时试题结构{question,[试卷相关信息]}
  159. const questionId =
  160. this.editMode === "paper"
  161. ? this.question.question.id
  162. : this.question.id;
  163. if (questionId) {
  164. const res = await questionDetailApi(questionId, this.editMode);
  165. const courseInfo = {
  166. courseId: res.data.course.id,
  167. courseCode: res.data.course.code,
  168. courseName: res.data.course.name,
  169. };
  170. let questionModel = {
  171. ...res.data,
  172. ...courseInfo,
  173. editMode: this.editMode,
  174. };
  175. if (this.editMode === "paper") {
  176. questionModel.score = this.question.score;
  177. }
  178. if (questionModel.subQuestions && questionModel.subQuestions.length) {
  179. questionModel.subQuestions = questionModel.subQuestions.map(
  180. (q, qindex) => {
  181. let nq = { ...q, ...courseInfo, editMode: this.editMode };
  182. if (this.editMode === "paper")
  183. nq.score = this.question.subScoreList[qindex];
  184. return nq;
  185. }
  186. );
  187. }
  188. this.questionModel = questionModel;
  189. } else {
  190. await this.getSourceDetailList();
  191. this.questionModel = Object.assign(
  192. {},
  193. initQuestionModel,
  194. this.question
  195. );
  196. }
  197. this.initData();
  198. },
  199. initData() {
  200. this.loading = false;
  201. this.hasModifyQuestion = false;
  202. if (this.isEdit) {
  203. this.sourceDetailList = this.sourceDetailAllList;
  204. this.curSourceDetail = {
  205. id: this.questionModel.sourceDetailId,
  206. questionType: this.questionModel.questionType,
  207. };
  208. } else {
  209. if (this.sourceDetailAllList.length > this.limitShowCount) {
  210. this.sourceDetailList = this.sourceDetailAllList.slice(
  211. 0,
  212. this.limitShowCount
  213. );
  214. } else {
  215. this.sourceDetailList = this.sourceDetailAllList;
  216. }
  217. if (!this.questionModel.sourceDetailId && !this.curSourceDetail.id) {
  218. this.curSourceDetail = this.sourceDetailList[0];
  219. }
  220. this.questionModel.questionType = this.curSourceDetail.questionType;
  221. this.questionModel.sourceDetailId = this.curSourceDetail.id;
  222. }
  223. this.questionKey = randomCode();
  224. },
  225. close() {
  226. this.modalIsShow = false;
  227. },
  228. open() {
  229. this.modalIsShow = true;
  230. },
  231. cancel() {
  232. if (this.hasModifyQuestion) this.$emit("modified");
  233. this.close();
  234. },
  235. async getSourceDetailList() {
  236. const res = await sourceDetailPageListApi({
  237. pageNumber: 1,
  238. pageSize: 100,
  239. courseId: this.question.courseId,
  240. rootOrgId: this.$store.state.user.rootOrgId,
  241. });
  242. this.sourceDetailAllList = res.data.content || [];
  243. let questionTypeSerial = {};
  244. QUESTION_TYPES.forEach((item, index) => {
  245. questionTypeSerial[item.code] = index;
  246. });
  247. this.sourceDetailAllList.sort(
  248. (a, b) =>
  249. questionTypeSerial[a.questionType] -
  250. questionTypeSerial[b.questionType]
  251. );
  252. },
  253. switchMoreSourceDetail() {
  254. if (this.showMore) {
  255. this.sourceDetailList = this.sourceDetailAllList.slice(
  256. 0,
  257. this.limitShowCount
  258. );
  259. } else {
  260. this.sourceDetailList = this.sourceDetailAllList;
  261. }
  262. this.showMore = !this.showMore;
  263. },
  264. toAddSourceDetail() {
  265. this.curSourceInfo = {
  266. courseId: this.question.courseId,
  267. rootOrgId: this.$store.state.user.rootOrgId,
  268. };
  269. this.$refs.ModifySourceDetail.open();
  270. },
  271. async sourceDetailAdded(sourceDetail) {
  272. await this.getSourceDetailList();
  273. this.showMore = !this.showMore;
  274. this.switchMoreSourceDetail();
  275. this.curSourceDetail = sourceDetail;
  276. this.initData();
  277. },
  278. async switchType(item) {
  279. if (this.isEdit) return;
  280. if (this.questionModel.sourceDetailId === item.id) return;
  281. if (this.questionModel.questionType === item.questionType) {
  282. this.curSourceDetail = item;
  283. this.questionModel.sourceDetailId = item.id;
  284. return;
  285. }
  286. const confirm = await this.$confirm("确认更改题型吗?", "提示", {
  287. type: "warning",
  288. }).catch(() => {});
  289. if (confirm !== "confirm") return;
  290. this.curSourceDetail = item;
  291. this.questionKey = randomCode();
  292. this.questionModel = Object.assign({}, this.questionModel, {
  293. questionType: item.questionType,
  294. sourceDetailId: item.id,
  295. });
  296. },
  297. async confirm() {
  298. const valid = await this.$refs.QuestionEditDetail.validate().catch(
  299. () => {}
  300. );
  301. if (!valid) return;
  302. if (this.loading) return;
  303. this.loading = true;
  304. let questionModel = this.$refs.QuestionEditDetail.getData();
  305. questionModel.sourceDetailId = this.questionModel.sourceDetailId;
  306. if (this.editMode === "paper") {
  307. this.$emit("modified", questionModel);
  308. this.loading = false;
  309. this.close();
  310. return;
  311. }
  312. const res = await updateQuestionApi(questionModel).catch(() => {});
  313. this.loading = false;
  314. if (!res) return;
  315. this.$message.success(this.title + "成功");
  316. this.hasModifyQuestion = true;
  317. if (this.isEdit) {
  318. this.$emit(
  319. "modified",
  320. Object.assign({}, this.questionModel, questionModel)
  321. );
  322. this.close();
  323. return;
  324. }
  325. const confirm = await this.$confirm("是否继续出题吗?", "提示", {
  326. type: "warning",
  327. }).catch(() => {});
  328. if (confirm !== "confirm") {
  329. this.$emit("modified");
  330. this.close();
  331. } else {
  332. this.initData();
  333. }
  334. },
  335. },
  336. };
  337. </script>