GptQuestionEditDialog.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. @open="visibleChange"
  10. >
  11. <div slot="title" class="box-justify">
  12. <div>
  13. <h2>编辑试题</h2>
  14. <span
  15. >课程:{{ formModel.courseName }}({{ formModel.courseCode }})</span
  16. >
  17. </div>
  18. <div>
  19. <el-button
  20. size="small"
  21. type="primary"
  22. :disabled="hasTaskRunning || buildLoading"
  23. :loading="confirmLoading"
  24. @click="confirm"
  25. >确定</el-button
  26. >
  27. <el-button size="small" @click="cancel">取消</el-button>
  28. </div>
  29. </div>
  30. <div class="part-box">
  31. <el-form label-width="100px">
  32. <el-form-item class="inline-top" label="题型:">
  33. {{ formModel.questionType | questionTypeFilter }}
  34. </el-form-item>
  35. <el-form-item
  36. v-if="IS_SELECTION_QUESTION"
  37. class="inline-top margin-left-10"
  38. label="选项个数:"
  39. >
  40. {{ formModel.optionCount }}
  41. </el-form-item>
  42. <el-form-item
  43. v-if="IS_FILL_QUESTION"
  44. class="inline-top margin-left-10"
  45. label="填空个数:"
  46. >
  47. {{ formModel.blankCount }}
  48. </el-form-item>
  49. <el-form-item label="知识点:">
  50. <el-tag
  51. v-for="content in quesProperties"
  52. :key="content.key"
  53. effect="dark"
  54. type="primary"
  55. style="margin-right: 5px; margin-bottom: 5px"
  56. >
  57. {{ content.courseProperty && content.courseProperty.name }}
  58. <span style="margin: 0 3px">/</span>
  59. {{ content.firstProperty && content.firstProperty.name }}
  60. <span
  61. v-if="content.secondProperty && content.secondProperty.name"
  62. style="margin: 0 3px"
  63. >/</span
  64. >
  65. {{ content.secondProperty && content.secondProperty.name }}
  66. </el-tag>
  67. <el-input
  68. v-model="formModel.knowledgeNotes"
  69. placeholder="请录入知识点补充说明"
  70. type="textarea"
  71. clearable
  72. ></el-input>
  73. </el-form-item>
  74. <el-form-item style="margin: 0">
  75. <el-button
  76. type="danger"
  77. :loading="hasTaskRunning || buildLoading"
  78. :disabled="confirmLoading"
  79. @click="toProduct"
  80. >重新生成</el-button
  81. >
  82. </el-form-item>
  83. </el-form>
  84. </div>
  85. <!-- question-body -->
  86. <div class="part-box question-edit">
  87. <component
  88. :is="structTypeComp"
  89. :key="questionKey"
  90. ref="QuestionEditDetail"
  91. :question="questionModel"
  92. :can-edit-question-info="false"
  93. ></component>
  94. </div>
  95. </el-dialog>
  96. </template>
  97. <script>
  98. import { STRUCT_TYPE_COMP_DICT } from "./edit/questionModel";
  99. import BooleanQuestion from "./edit/BooleanQuestion.vue";
  100. import FillBlankQuestion from "./edit/FillBlankQuestion.vue";
  101. import SelectQuestion from "./edit/SelectQuestion.vue";
  102. import TextAnswerQuestion from "./edit/TextAnswerQuestion.vue";
  103. import { randomCode } from "@/plugins/utils";
  104. import {
  105. buildGptQuestionApi,
  106. gptRebuildQuestionListApi,
  107. updateGptQuestionApi,
  108. gptTaskDetailApi,
  109. } from "../api";
  110. import timeMixin from "@/mixins/timeMixin";
  111. export default {
  112. name: "GptQuestionEditDialog",
  113. components: {
  114. FillBlankQuestion,
  115. SelectQuestion,
  116. TextAnswerQuestion,
  117. BooleanQuestion,
  118. },
  119. mixins: [timeMixin],
  120. props: {
  121. question: {
  122. type: Object,
  123. default() {
  124. return { id: "" };
  125. },
  126. },
  127. },
  128. data() {
  129. return {
  130. modalIsShow: false,
  131. curTaskId: null,
  132. hasTaskRunning: false,
  133. questionModel: {
  134. questionType: "SINGLE_ANSWER_QUESTION",
  135. },
  136. formModel: {},
  137. quesProperties: [],
  138. questionKey: "",
  139. editMode: "question",
  140. buildLoading: false,
  141. confirmLoading: false,
  142. };
  143. },
  144. computed: {
  145. structTypeComp() {
  146. return STRUCT_TYPE_COMP_DICT[this.questionModel.questionType];
  147. },
  148. IS_SELECTION_QUESTION() {
  149. return ["SINGLE_ANSWER_QUESTION", "MULTIPLE_ANSWER_QUESTION"].includes(
  150. this.questionModel.questionType
  151. );
  152. },
  153. IS_FILL_QUESTION() {
  154. return this.questionModel.questionType === "FILL_BLANK_QUESTION";
  155. },
  156. },
  157. beforeDestroy() {
  158. this.clearSetTs();
  159. },
  160. methods: {
  161. async visibleChange() {
  162. this.curTaskId = this.question.taskId;
  163. const res = await gptTaskDetailApi(this.question.taskId).catch(() => {});
  164. if (!res || !res.data) return;
  165. const { prompt } = res.data;
  166. this.formModel = {
  167. courseId: this.question.courseId,
  168. courseCode: this.question.courseCode,
  169. courseName: this.question.courseName,
  170. questionType: prompt.questionType,
  171. questionCount: 1,
  172. optionCount: prompt.optionCount,
  173. blankCount: prompt.blankCount,
  174. propertyIdList: this.question.propertyIds,
  175. knowledgeNotes: prompt.knowledgeNotes,
  176. };
  177. let quesProperties = [];
  178. this.question.propertyInfos.forEach((item) => {
  179. let nitem = {};
  180. nitem.key = item.map((elem) => elem.id).join("_");
  181. nitem.courseProperty = item[0];
  182. nitem.firstProperty = item[1];
  183. if (item[2]) nitem.secondProperty = item[2];
  184. quesProperties.push(nitem);
  185. });
  186. this.quesProperties = quesProperties;
  187. this.initData(this.question);
  188. },
  189. initData(question) {
  190. const courseInfo = {
  191. courseId: this.formModel.courseId,
  192. courseCode: this.formModel.courseCode,
  193. courseName: this.formModel.courseName,
  194. };
  195. let questionModel = {
  196. ...question,
  197. ...courseInfo,
  198. editMode: this.editMode,
  199. };
  200. if (questionModel.subQuestions && questionModel.subQuestions.length) {
  201. questionModel.subQuestions = questionModel.subQuestions.map((q) => {
  202. let nq = { ...q, ...courseInfo, editMode: this.editMode };
  203. return nq;
  204. });
  205. }
  206. this.questionModel = questionModel;
  207. this.questionKey = randomCode();
  208. },
  209. async cancel() {
  210. if (this.hasTaskRunning) {
  211. const confirm = await this.$confirm(
  212. "当前正在生成试题,确定要退出吗?",
  213. "提示",
  214. {
  215. type: "warning",
  216. }
  217. ).catch(() => {});
  218. if (confirm !== "confirm") return;
  219. this.clearSetTs();
  220. }
  221. this.modalIsShow = false;
  222. },
  223. open() {
  224. this.modalIsShow = true;
  225. },
  226. async toProduct() {
  227. this.buildLoading = true;
  228. const res = await buildGptQuestionApi({
  229. ...this.formModel,
  230. insteadQuestionId: this.question.id,
  231. }).catch(() => {});
  232. this.buildLoading = false;
  233. if (!res) return;
  234. this.curTaskId = res.data;
  235. this.hasTaskRunning = true;
  236. this.addSetTime(() => {
  237. this.checkTaskStatus();
  238. }, 3 * 1000);
  239. },
  240. async checkTaskStatus() {
  241. this.clearSetTs();
  242. if (!this.curTaskId) return;
  243. const res = await gptTaskDetailApi({
  244. courseId: this.formModel.courseId,
  245. taskId: this.curTaskId,
  246. }).catch(() => {});
  247. if (!res || !res.data) return;
  248. if (res.data.status === "FAILED") {
  249. this.hasTaskRunning = false;
  250. this.$message.error("重新生成试题失败,请重新尝试!");
  251. this.getResult();
  252. return;
  253. }
  254. if (res.data.status === "FINISH") {
  255. this.hasTaskRunning = false;
  256. this.$message.success("重新生成试题成功!");
  257. this.getResult();
  258. return;
  259. }
  260. this.hasTaskRunning = res.data.status === "RUNNING";
  261. this.addSetTime(() => {
  262. this.checkTaskStatus();
  263. }, 3 * 1000);
  264. },
  265. async getResult() {
  266. const res = await gptRebuildQuestionListApi(this.curTaskId).catch(
  267. () => {}
  268. );
  269. if (!res) return;
  270. this.initData(res.data);
  271. },
  272. async confirm() {
  273. const valid = await this.$refs.QuestionEditDetail.validate().catch(
  274. () => {}
  275. );
  276. if (!valid) return;
  277. if (this.confirmLoading) return;
  278. this.confirmLoading = true;
  279. let questionModel = this.$refs.QuestionEditDetail.getData();
  280. const res = await updateGptQuestionApi({
  281. ...questionModel,
  282. propertyIdList: this.formModel.propertyIdList,
  283. }).catch(() => {});
  284. this.confirmLoading = false;
  285. if (!res) return;
  286. this.$message.success("保存成功");
  287. this.$emit("modified");
  288. this.modalIsShow = false;
  289. },
  290. },
  291. };
  292. </script>