EditSelectQuestion.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. <template>
  2. <div v-loading="fullscreenLoading" id="editSelectApp">
  3. <section class="content">
  4. <!-- 头信息 -->
  5. <h3 class="box-title">
  6. <span v-if="!quesModel.id"
  7. ><LinkTitlesCustom :currentPaths="['试题新增']"
  8. /></span>
  9. <span v-if="quesModel.id"
  10. ><LinkTitlesCustom :currentPaths="['试题修改']"
  11. /></span>
  12. </h3>
  13. <!-- 正文信息 -->
  14. <div class="box-body">
  15. <el-form
  16. :model="quesModel"
  17. ref="quesModel"
  18. :rules="rules"
  19. label-width="100px"
  20. class="demo-ruleForm"
  21. label-position="right"
  22. >
  23. <el-form-item label="题型">
  24. <el-select
  25. :disabled="true"
  26. v-model="quesModel.questionType"
  27. placeholder="请输入题型"
  28. >
  29. <el-option
  30. v-for="item in questionTypes"
  31. :label="item.label"
  32. :value="item.value"
  33. :key="item.value"
  34. >
  35. </el-option>
  36. </el-select>
  37. </el-form-item>
  38. <!--
  39. <el-form-item label="分数">
  40. <el-input placeholder="分数" v-model="quesModel.score" style="width:50px;"></el-input>
  41. </el-form-item>
  42. -->
  43. <!-- created by weiwenhai -->
  44. <el-form-item label="难度">
  45. <el-select
  46. v-model="quesModel.difficultyDegree"
  47. placeholder="请输入难度"
  48. >
  49. <el-option
  50. v-for="item in difficultyDegreeList"
  51. :label="item.label"
  52. :value="item.value"
  53. :key="item.value"
  54. >
  55. </el-option>
  56. </el-select>
  57. </el-form-item>
  58. <el-form-item label="公开度">
  59. <el-select v-model="quesModel.publicity" placeholder="请输入公开度">
  60. <el-option
  61. v-for="item in publicityList"
  62. :label="item.label"
  63. :value="item.value"
  64. :key="item.value"
  65. >
  66. </el-option>
  67. </el-select>
  68. </el-form-item>
  69. <el-form-item label="属性列表">
  70. <el-tooltip
  71. placement="top"
  72. v-for="(content, index) in quesModel.quesProperties"
  73. :key="index"
  74. >
  75. <div slot="content">
  76. <span v-if="content.firstProperty != null"
  77. >一级属性:{{ content.firstProperty.name }}</span
  78. ><br />
  79. <span v-if="content.secondProperty != null"
  80. >二级属性:{{ content.secondProperty.name }}</span
  81. >
  82. </div>
  83. <el-tag
  84. style="margin-right:5px;"
  85. :key="content.id"
  86. closable
  87. type="primary"
  88. @close="handleClose(content)"
  89. >
  90. {{ content.coursePropertyName }}
  91. </el-tag>
  92. </el-tooltip>
  93. </el-form-item>
  94. <el-row :gutter="20">
  95. <el-col :xs="6" :sm="6" :md="6" :lg="6">
  96. <el-form-item label="属性名">
  97. <el-select
  98. v-model="coursePropertyName"
  99. placeholder="属性名"
  100. @change="searchFirst"
  101. class="property_with"
  102. >
  103. <el-option
  104. v-for="item in coursePropertyList"
  105. :label="item.name"
  106. :value="item.name"
  107. :key="item.name"
  108. >
  109. </el-option>
  110. </el-select>
  111. </el-form-item>
  112. </el-col>
  113. <el-col :xs="6" :sm="6" :md="6" :lg="6">
  114. <el-form-item label="一级">
  115. <el-select
  116. v-model="firstPropertyId"
  117. placeholder="一级"
  118. @change="searchSecond"
  119. class="property_with"
  120. >
  121. <el-option
  122. v-for="item in firstPropertyList"
  123. :label="item.name"
  124. :value="item.id"
  125. :key="item.id"
  126. >
  127. </el-option>
  128. </el-select>
  129. </el-form-item>
  130. </el-col>
  131. <el-col :xs="6" :sm="6" :md="6" :lg="6">
  132. <el-form-item label="二级">
  133. <el-select
  134. v-model="secondPropertyId"
  135. placeholder="二级"
  136. class="property_with"
  137. >
  138. <el-option
  139. v-for="item in secondPropertyList"
  140. :label="item.name"
  141. :value="item.id"
  142. :key="item.id"
  143. >
  144. </el-option>
  145. </el-select>
  146. </el-form-item>
  147. </el-col>
  148. <el-col :xs="3" :sm="3" :md="3" :lg="3">
  149. <el-form-item>
  150. <el-button
  151. type="info"
  152. @click="insertProperty"
  153. style="margin-left:-30px;"
  154. >新增属性</el-button
  155. >
  156. </el-form-item>
  157. </el-col>
  158. </el-row>
  159. <!-- end -->
  160. <el-form-item label="题干" prop="quesBody">
  161. <ckeditor v-model="quesModel.quesBody"></ckeditor>
  162. </el-form-item>
  163. <el-form-item
  164. v-for="(option, index) in quesModel.quesOptions"
  165. :key="option.number"
  166. >
  167. <el-col :span="1">
  168. <el-radio
  169. v-model="singleRightAnswer"
  170. :label="index | optionOrderWordFilter"
  171. v-if="quesModel.questionType === 'SINGLE_ANSWER_QUESTION'"
  172. ></el-radio>
  173. <el-checkbox
  174. v-model="multipleRightAnswer"
  175. :label="index | optionOrderWordFilter"
  176. v-if="quesModel.questionType === 'MULTIPLE_ANSWER_QUESTION'"
  177. ></el-checkbox>
  178. </el-col>
  179. <el-col :span="20">
  180. <ckeditor v-model="option.optionBody"></ckeditor>
  181. </el-col>
  182. <el-col :span="2">
  183. <i
  184. class="el-icon-delete"
  185. @click.prevent="removeQuesOption(option)"
  186. title="删除"
  187. ></i>
  188. </el-col>
  189. </el-form-item>
  190. <el-form-item label="答案">
  191. <el-col> <span v-html="answer"></span> </el-col>
  192. </el-form-item>
  193. <el-form-item>
  194. <el-button type="primary" icon="plus" @click="addQuesOption"
  195. >新增选项</el-button
  196. >
  197. <el-button
  198. type="primary"
  199. icon="check"
  200. @click="submitForm('quesModel')"
  201. :disabled="saveDisabled"
  202. >保存</el-button
  203. >
  204. <el-button
  205. type="primary"
  206. icon="caret-left"
  207. @click="backToQuesList()"
  208. >
  209. 返回列表
  210. </el-button>
  211. </el-form-item>
  212. </el-form>
  213. </div>
  214. </section>
  215. </div>
  216. </template>
  217. <script>
  218. import { QUESTION_API } from "@/constants/constants";
  219. import { QUESTION_TYPES } from "../constants/constants";
  220. import ckeditor from "../component/ckeditor.vue";
  221. import LinkTitlesCustom from "@/components/LinkTitlesCustom.vue";
  222. export default {
  223. name: "editSelectApp",
  224. components: { ckeditor, LinkTitlesCustom },
  225. data() {
  226. return {
  227. questionTypes: QUESTION_TYPES,
  228. fullscreenLoading: false,
  229. paperId: "",
  230. paperDetailId: "",
  231. questionId: "",
  232. quesModel: {
  233. quesBody: "",
  234. quesOptions: [],
  235. quesAnswer: "",
  236. questionType: "",
  237. courseName: "",
  238. courseNo: "",
  239. difficultyDegree: "",
  240. publicity: true,
  241. quesProperties: [],
  242. score: 1
  243. },
  244. difficultyDegreeList: [
  245. { label: 0.1, value: 0.1 },
  246. { label: 0.2, value: 0.2 },
  247. { label: 0.3, value: 0.3 },
  248. { label: 0.4, value: 0.4 },
  249. { label: 0.5, value: 0.5 },
  250. { label: 0.6, value: 0.6 },
  251. { label: 0.7, value: 0.7 },
  252. { label: 0.8, value: 0.8 },
  253. { label: 0.9, value: 0.9 },
  254. { label: 1.0, value: 1.0 }
  255. ],
  256. publicityList: [
  257. { label: "公开", value: true },
  258. { label: "非公开", value: false }
  259. ],
  260. coursePropertyList: [],
  261. coursePropertyName: "", //课程属性名
  262. firstPropertyList: [], //一级属性集合
  263. firstPropertyId: "", //一级属性id
  264. secondPropertyList: [], //二级属性集合
  265. secondPropertyId: "", //二级属性id
  266. //验证
  267. rules: {
  268. // quesBody: [
  269. // { required: true, message: '请输入题干', trigger: 'blur'}
  270. // ]
  271. },
  272. singleRightAnswer: "", //接收单选答案
  273. multipleRightAnswer: [] //接收多选答案
  274. };
  275. },
  276. methods: {
  277. findQuestionById(questionId) {
  278. this.$http
  279. .get(QUESTION_API + "/question/" + questionId)
  280. .then(response => {
  281. this.quesModel = response.data;
  282. if (this.quesModel.quesOptions) {
  283. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  284. var option = this.quesModel.quesOptions[i];
  285. if (
  286. this.quesModel.questionType == "SINGLE_ANSWER_QUESTION" &&
  287. option.isCorrect == 1
  288. ) {
  289. this.singleRightAnswer = String.fromCharCode(65 + i);
  290. }
  291. if (
  292. this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION" &&
  293. option.isCorrect == 1
  294. ) {
  295. this.multipleRightAnswer.push(String.fromCharCode(65 + i));
  296. }
  297. }
  298. }
  299. this.initCourseProperty();
  300. });
  301. },
  302. submitForm(formName) {
  303. this.$refs[formName].validate(valid => {
  304. if (valid) {
  305. this.setRightAnswer();
  306. if (this.questionId) {
  307. this.editQuestion();
  308. } else {
  309. this.saveNewQuestion();
  310. }
  311. } else {
  312. return false;
  313. }
  314. });
  315. },
  316. //修改试题
  317. editQuestion() {
  318. if (this.quesModel.quesOptions.length == 0) {
  319. this.$confirm("无选项将删除该试题, 是否继续?", "提示", {
  320. confirmButtonText: "确定",
  321. cancelButtonText: "取消",
  322. type: "warning"
  323. })
  324. .then(() => {
  325. this.fullscreenLoading = true;
  326. this.$http
  327. .delete(
  328. QUESTION_API + "/paper/deleteQuestion/" + this.quesModel.id
  329. )
  330. .then(response => {
  331. if (response.data.length > 0) {
  332. this.deleteInfo =
  333. "该试题被试卷:" +
  334. response.data.join(" , ") +
  335. "使用,不能删除";
  336. this.deleteDialogVisible = true;
  337. } else {
  338. this.$notify({
  339. message: "删除成功",
  340. type: "success"
  341. });
  342. this.$router.push({ path: "/questions/question_list/0" });
  343. }
  344. });
  345. })
  346. .catch(() => {});
  347. } else {
  348. this.fullscreenLoading = true;
  349. this.$http.put(QUESTION_API + "/question", this.quesModel).then(() => {
  350. this.$notify({
  351. message: "保存成功",
  352. type: "success"
  353. });
  354. this.fullscreenLoading = false;
  355. });
  356. }
  357. },
  358. //新增试题
  359. saveNewQuestion() {
  360. if (!this.quesModel.difficultyDegree) {
  361. this.$notify({
  362. message: "请选择试题难度",
  363. type: "error"
  364. });
  365. return false;
  366. }
  367. this.fullscreenLoading = true;
  368. this.$http
  369. .post(
  370. QUESTION_API +
  371. "/paper/addQuestion/" +
  372. this.paperId +
  373. "/" +
  374. this.paperDetailId,
  375. this.quesModel
  376. )
  377. .then(() => {
  378. this.fullscreenLoading = false;
  379. this.$message({
  380. type: "info",
  381. message: `保存成功`
  382. });
  383. this.$router.push({ path: "/questions/question_list/0" });
  384. })
  385. .catch(() => {
  386. this.fullscreenLoading = false;
  387. console.log("添加失败");
  388. });
  389. },
  390. //新增选项
  391. addQuesOption() {
  392. this.quesModel.quesOptions.push({
  393. number: "",
  394. optionBody: "",
  395. isCorrect: ""
  396. });
  397. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  398. this.quesModel.quesOptions[i]["number"] = i + 1;
  399. }
  400. },
  401. //删除选项
  402. removeQuesOption(option) {
  403. this.singleRightAnswer = "";
  404. this.multipleRightAnswer = [];
  405. let index = this.quesModel.quesOptions.indexOf(option);
  406. if (index !== -1) {
  407. this.quesModel.quesOptions.splice(index, 1);
  408. }
  409. if (this.quesModel.quesOptions.length > 0) {
  410. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  411. var quesOption = this.quesModel.quesOptions[i];
  412. quesOption["number"] = i + 1;
  413. if (quesOption.isCorrect == 1) {
  414. var answerOrderNum = String.fromCharCode(65 + i);
  415. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  416. this.singleRightAnswer = answerOrderNum;
  417. }
  418. if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  419. this.multipleRightAnswer.push(answerOrderNum);
  420. }
  421. }
  422. }
  423. }
  424. },
  425. //在正确的option上设置isCorrect=1
  426. setRightAnswer() {
  427. if (this.quesModel.quesOptions.length == 0) {
  428. return false;
  429. }
  430. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  431. var option = this.quesModel.quesOptions[i];
  432. var answerOrderNum = String.fromCharCode(65 + i);
  433. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  434. option["isCorrect"] =
  435. answerOrderNum == this.singleRightAnswer ? 1 : 0;
  436. }
  437. if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  438. option["isCorrect"] =
  439. this.multipleRightAnswer.indexOf(answerOrderNum) > -1 ? 1 : 0;
  440. }
  441. }
  442. },
  443. backToQuesList() {
  444. this.$router.push({
  445. path: "/questions/question_list/0"
  446. });
  447. },
  448. //查询所有课程属性名
  449. initCourseProperty() {
  450. console.log(this.quesModel);
  451. var code = this.quesModel.course.code;
  452. this.$http
  453. .get(QUESTION_API + "/courseProperty/enable/" + code)
  454. .then(response => {
  455. this.coursePropertyList = response.data;
  456. });
  457. },
  458. //查询一级属性
  459. searchFirst() {
  460. this.firstPropertyId = "";
  461. this.secondPropertyId = "";
  462. this.secondPropertyList = [];
  463. for (let courseProperty of this.coursePropertyList) {
  464. if (courseProperty.name == this.coursePropertyName) {
  465. this.$http
  466. .get(QUESTION_API + "/property/first/" + courseProperty.id)
  467. .then(response => {
  468. this.firstPropertyList = response.data;
  469. });
  470. }
  471. }
  472. },
  473. //查询二级属性
  474. searchSecond() {
  475. this.secondPropertyId = "";
  476. if (this.firstPropertyId) {
  477. this.$http
  478. .get(QUESTION_API + "/property/second/" + this.firstPropertyId)
  479. .then(response => {
  480. this.secondPropertyList = response.data;
  481. });
  482. }
  483. },
  484. //新增属性
  485. insertProperty() {
  486. if (!this.checkInsertPro()) {
  487. return false;
  488. }
  489. var quesProperty = {
  490. id: "",
  491. coursePropertyName: "",
  492. firstProperty: {},
  493. secondProperty: {}
  494. };
  495. if (
  496. this.quesModel.quesProperties === undefined ||
  497. this.quesModel.quesProperties.length == 0
  498. ) {
  499. this.quesModel.quesProperties = [];
  500. }
  501. quesProperty.id =
  502. this.coursePropertyName +
  503. "-" +
  504. this.firstPropertyId +
  505. "-" +
  506. this.secondPropertyId;
  507. for (let quesPro of this.quesModel.quesProperties) {
  508. if (quesPro.id == quesProperty.id) {
  509. this.$notify({
  510. message: "该属性已存在,请重新选择",
  511. type: "error"
  512. });
  513. return false;
  514. }
  515. }
  516. quesProperty.coursePropertyName = this.coursePropertyName;
  517. //取到一级属性对象
  518. for (let property of this.firstPropertyList) {
  519. if (property.id == this.firstPropertyId) {
  520. quesProperty.firstProperty = property;
  521. }
  522. }
  523. //判断是否有二级属性
  524. if (
  525. this.secondPropertyList != undefined &&
  526. this.secondPropertyList.length > 0
  527. ) {
  528. if (!this.secondPropertyId) {
  529. this.$notify({
  530. message: "请选择二级属性",
  531. type: "error"
  532. });
  533. return false;
  534. }
  535. }
  536. //取到二级属性对象
  537. for (let property of this.secondPropertyList) {
  538. if (property.id == this.secondPropertyId) {
  539. quesProperty.secondProperty = property;
  540. }
  541. }
  542. this.quesModel.quesProperties.push(quesProperty);
  543. this.quesModel = Object.assign({}, this.quesModel);
  544. console.log(
  545. "this.quesModel.quesProperties:",
  546. this.quesModel.quesProperties
  547. );
  548. //清空下拉框
  549. this.coursePropertyName = "";
  550. this.firstPropertyId = "";
  551. this.secondPropertyId = "";
  552. this.firstPropertyList = [];
  553. this.secondPropertyList = [];
  554. },
  555. //删除属性
  556. handleClose(tag) {
  557. console.log("tag:", tag);
  558. this.quesModel.quesProperties.splice(
  559. this.quesModel.quesProperties.indexOf(tag),
  560. 1
  561. );
  562. this.quesModel = Object.assign({}, this.quesModel);
  563. },
  564. //新增属性验证
  565. checkInsertPro() {
  566. if (!this.coursePropertyName) {
  567. this.$notify({
  568. message: "请选择属性",
  569. type: "error"
  570. });
  571. return false;
  572. }
  573. if (!this.firstPropertyId) {
  574. this.$notify({
  575. message: "请选择一级属性",
  576. type: "error"
  577. });
  578. return false;
  579. }
  580. return true;
  581. },
  582. answer() {
  583. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  584. return this.singleRightAnswer;
  585. } else if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  586. return this.multipleRightAnswer.sort().toString();
  587. }
  588. }
  589. },
  590. computed: {
  591. // answer: function() {
  592. // if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  593. // return this.singleRightAnswer;
  594. // } else if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  595. // return this.multipleRightAnswer.sort().toString();
  596. // }
  597. // },
  598. saveDisabled: function() {
  599. if (!this.questionId && this.quesModel.quesOptions.length == 0) {
  600. return true;
  601. }
  602. return false;
  603. }
  604. },
  605. created() {
  606. let questionId = this.$route.params.id;
  607. if (questionId) {
  608. this.questionId = questionId;
  609. this.quesModel["id"] = questionId;
  610. this.findQuestionById(questionId);
  611. }
  612. this.paperId = this.$route.params.paperId;
  613. this.paperDetailId = this.$route.params.paperDetailId;
  614. this.courseNo = this.$route.params.courseNo;
  615. let questionType = this.$route.params.questionType;
  616. if (questionType) {
  617. this.quesModel.questionType = questionType;
  618. }
  619. if (this.courseNo) {
  620. this.$http
  621. .get(QUESTION_API + "/courseProperty/enable/" + this.courseNo)
  622. .then(response => {
  623. this.coursePropertyList = response.data;
  624. });
  625. }
  626. }
  627. };
  628. </script>
  629. <style scoped src="../styles/Common.css"></style>