EditSelectQuestion.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  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="primary"
  152. @click="insertProperty"
  153. style="margin-left:-30px;"
  154. ><i class="el-icon-plus"></i> 新增属性</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" @click="addQuesOption"
  195. ><i class="el-icon-plus"></i> 新增选项</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. ><i class="el-icon-arrow-left"></i> 返回列表
  209. </el-button>
  210. </el-form-item>
  211. </el-form>
  212. </div>
  213. </section>
  214. </div>
  215. </template>
  216. <script>
  217. import { QUESTION_API } from "@/constants/constants";
  218. import { QUESTION_TYPES } from "../constants/constants";
  219. import ckeditor from "../component/ckeditor.vue";
  220. import LinkTitlesCustom from "@/components/LinkTitlesCustom.vue";
  221. export default {
  222. name: "editSelectApp",
  223. components: { ckeditor, LinkTitlesCustom },
  224. data() {
  225. return {
  226. questionTypes: QUESTION_TYPES,
  227. fullscreenLoading: false,
  228. paperId: "",
  229. paperDetailId: "",
  230. questionId: "",
  231. quesModel: {
  232. quesBody: "",
  233. quesOptions: [],
  234. quesAnswer: "",
  235. questionType: "",
  236. courseName: "",
  237. courseNo: "",
  238. difficultyDegree: "",
  239. publicity: true,
  240. quesProperties: [],
  241. score: 1
  242. },
  243. difficultyDegreeList: [
  244. { label: 0.1, value: 0.1 },
  245. { label: 0.2, value: 0.2 },
  246. { label: 0.3, value: 0.3 },
  247. { label: 0.4, value: 0.4 },
  248. { label: 0.5, value: 0.5 },
  249. { label: 0.6, value: 0.6 },
  250. { label: 0.7, value: 0.7 },
  251. { label: 0.8, value: 0.8 },
  252. { label: 0.9, value: 0.9 },
  253. { label: 1.0, value: 1.0 }
  254. ],
  255. publicityList: [
  256. { label: "公开", value: true },
  257. { label: "非公开", value: false }
  258. ],
  259. coursePropertyList: [],
  260. coursePropertyName: "", //课程属性名
  261. firstPropertyList: [], //一级属性集合
  262. firstPropertyId: "", //一级属性id
  263. secondPropertyList: [], //二级属性集合
  264. secondPropertyId: "", //二级属性id
  265. //验证
  266. rules: {
  267. // quesBody: [
  268. // { required: true, message: '请输入题干', trigger: 'blur'}
  269. // ]
  270. },
  271. singleRightAnswer: "", //接收单选答案
  272. multipleRightAnswer: [] //接收多选答案
  273. };
  274. },
  275. methods: {
  276. findQuestionById(questionId) {
  277. this.$http
  278. .get(QUESTION_API + "/question/" + questionId)
  279. .then(response => {
  280. this.quesModel = response.data;
  281. if (this.quesModel.quesOptions) {
  282. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  283. var option = this.quesModel.quesOptions[i];
  284. if (
  285. this.quesModel.questionType == "SINGLE_ANSWER_QUESTION" &&
  286. option.isCorrect == 1
  287. ) {
  288. this.singleRightAnswer = String.fromCharCode(65 + i);
  289. }
  290. if (
  291. this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION" &&
  292. option.isCorrect == 1
  293. ) {
  294. this.multipleRightAnswer.push(String.fromCharCode(65 + i));
  295. }
  296. }
  297. }
  298. this.initCourseProperty();
  299. });
  300. },
  301. submitForm(formName) {
  302. this.$refs[formName].validate(valid => {
  303. if (valid) {
  304. this.setRightAnswer();
  305. if (this.questionId) {
  306. this.editQuestion();
  307. } else {
  308. this.saveNewQuestion();
  309. }
  310. } else {
  311. return false;
  312. }
  313. });
  314. },
  315. //修改试题
  316. editQuestion() {
  317. if (this.quesModel.quesOptions.length == 0) {
  318. this.$confirm("无选项将删除该试题, 是否继续?", "提示", {
  319. confirmButtonText: "确定",
  320. cancelButtonText: "取消",
  321. type: "warning"
  322. })
  323. .then(() => {
  324. this.fullscreenLoading = true;
  325. this.$http
  326. .delete(
  327. QUESTION_API + "/paper/deleteQuestion/" + this.quesModel.id
  328. )
  329. .then(response => {
  330. if (response.data.length > 0) {
  331. this.deleteInfo =
  332. "该试题被试卷:" +
  333. response.data.join(" , ") +
  334. "使用,不能删除";
  335. this.deleteDialogVisible = true;
  336. } else {
  337. this.$notify({
  338. message: "删除成功",
  339. type: "success"
  340. });
  341. this.$router.push({ path: "/questions/question_list/0" });
  342. }
  343. });
  344. })
  345. .catch(() => {});
  346. } else {
  347. this.fullscreenLoading = true;
  348. this.$http.put(QUESTION_API + "/question", this.quesModel).then(() => {
  349. this.$notify({
  350. message: "保存成功",
  351. type: "success"
  352. });
  353. this.fullscreenLoading = false;
  354. });
  355. }
  356. },
  357. //新增试题
  358. saveNewQuestion() {
  359. if (!this.quesModel.difficultyDegree) {
  360. this.$notify({
  361. message: "请选择试题难度",
  362. type: "error"
  363. });
  364. return false;
  365. }
  366. this.fullscreenLoading = true;
  367. this.$http
  368. .post(
  369. QUESTION_API +
  370. "/paper/addQuestion/" +
  371. this.paperId +
  372. "/" +
  373. this.paperDetailId,
  374. this.quesModel
  375. )
  376. .then(() => {
  377. this.fullscreenLoading = false;
  378. this.$notify({
  379. type: "success",
  380. message: "保存成功"
  381. });
  382. this.$router.push({ path: "/questions/question_list/0" });
  383. })
  384. .catch(() => {
  385. this.fullscreenLoading = false;
  386. console.log("添加失败");
  387. });
  388. },
  389. //新增选项
  390. addQuesOption() {
  391. this.quesModel.quesOptions.push({
  392. number: "",
  393. optionBody: "",
  394. isCorrect: ""
  395. });
  396. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  397. this.quesModel.quesOptions[i]["number"] = i + 1;
  398. }
  399. },
  400. //删除选项
  401. removeQuesOption(option) {
  402. this.singleRightAnswer = "";
  403. this.multipleRightAnswer = [];
  404. let index = this.quesModel.quesOptions.indexOf(option);
  405. if (index !== -1) {
  406. this.quesModel.quesOptions.splice(index, 1);
  407. }
  408. if (this.quesModel.quesOptions.length > 0) {
  409. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  410. var quesOption = this.quesModel.quesOptions[i];
  411. quesOption["number"] = i + 1;
  412. if (quesOption.isCorrect == 1) {
  413. var answerOrderNum = String.fromCharCode(65 + i);
  414. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  415. this.singleRightAnswer = answerOrderNum;
  416. }
  417. if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  418. this.multipleRightAnswer.push(answerOrderNum);
  419. }
  420. }
  421. }
  422. }
  423. },
  424. //在正确的option上设置isCorrect=1
  425. setRightAnswer() {
  426. if (this.quesModel.quesOptions.length == 0) {
  427. return false;
  428. }
  429. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  430. var option = this.quesModel.quesOptions[i];
  431. var answerOrderNum = String.fromCharCode(65 + i);
  432. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  433. option["isCorrect"] =
  434. answerOrderNum == this.singleRightAnswer ? 1 : 0;
  435. }
  436. if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  437. option["isCorrect"] =
  438. this.multipleRightAnswer.indexOf(answerOrderNum) > -1 ? 1 : 0;
  439. }
  440. }
  441. },
  442. backToQuesList() {
  443. this.$router.push({
  444. path: "/questions/question_list/1"
  445. });
  446. },
  447. //查询所有课程属性名
  448. initCourseProperty() {
  449. console.log(this.quesModel);
  450. var code = this.quesModel.course.code;
  451. this.$http
  452. .get(QUESTION_API + "/courseProperty/enable/" + code)
  453. .then(response => {
  454. this.coursePropertyList = response.data;
  455. });
  456. },
  457. //查询一级属性
  458. searchFirst() {
  459. this.firstPropertyId = "";
  460. this.secondPropertyId = "";
  461. this.secondPropertyList = [];
  462. for (let courseProperty of this.coursePropertyList) {
  463. if (courseProperty.name == this.coursePropertyName) {
  464. this.$http
  465. .get(QUESTION_API + "/property/first/" + courseProperty.id)
  466. .then(response => {
  467. this.firstPropertyList = response.data;
  468. });
  469. }
  470. }
  471. },
  472. //查询二级属性
  473. searchSecond() {
  474. this.secondPropertyId = "";
  475. if (this.firstPropertyId) {
  476. this.$http
  477. .get(QUESTION_API + "/property/second/" + this.firstPropertyId)
  478. .then(response => {
  479. this.secondPropertyList = response.data;
  480. });
  481. }
  482. },
  483. //新增属性
  484. insertProperty() {
  485. if (!this.checkInsertPro()) {
  486. return false;
  487. }
  488. var quesProperty = {
  489. id: "",
  490. coursePropertyName: "",
  491. firstProperty: {},
  492. secondProperty: {}
  493. };
  494. if (
  495. this.quesModel.quesProperties === undefined ||
  496. this.quesModel.quesProperties.length == 0
  497. ) {
  498. this.quesModel.quesProperties = [];
  499. }
  500. quesProperty.id =
  501. this.coursePropertyName +
  502. "-" +
  503. this.firstPropertyId +
  504. "-" +
  505. this.secondPropertyId;
  506. for (let quesPro of this.quesModel.quesProperties) {
  507. if (quesPro.id == quesProperty.id) {
  508. this.$notify({
  509. message: "该属性已存在,请重新选择",
  510. type: "error"
  511. });
  512. return false;
  513. }
  514. }
  515. quesProperty.coursePropertyName = this.coursePropertyName;
  516. //取到一级属性对象
  517. for (let property of this.firstPropertyList) {
  518. if (property.id == this.firstPropertyId) {
  519. quesProperty.firstProperty = property;
  520. }
  521. }
  522. //判断是否有二级属性
  523. if (
  524. this.secondPropertyList != undefined &&
  525. this.secondPropertyList.length > 0
  526. ) {
  527. if (!this.secondPropertyId) {
  528. this.$notify({
  529. message: "请选择二级属性",
  530. type: "error"
  531. });
  532. return false;
  533. }
  534. }
  535. //取到二级属性对象
  536. for (let property of this.secondPropertyList) {
  537. if (property.id == this.secondPropertyId) {
  538. quesProperty.secondProperty = property;
  539. }
  540. }
  541. this.quesModel.quesProperties.push(quesProperty);
  542. this.quesModel = Object.assign({}, this.quesModel);
  543. console.log(
  544. "this.quesModel.quesProperties:",
  545. this.quesModel.quesProperties
  546. );
  547. //清空下拉框
  548. this.coursePropertyName = "";
  549. this.firstPropertyId = "";
  550. this.secondPropertyId = "";
  551. this.firstPropertyList = [];
  552. this.secondPropertyList = [];
  553. },
  554. //删除属性
  555. handleClose(tag) {
  556. console.log("tag:", tag);
  557. this.quesModel.quesProperties.splice(
  558. this.quesModel.quesProperties.indexOf(tag),
  559. 1
  560. );
  561. this.quesModel = Object.assign({}, this.quesModel);
  562. },
  563. //新增属性验证
  564. checkInsertPro() {
  565. if (!this.coursePropertyName) {
  566. this.$notify({
  567. message: "请选择属性",
  568. type: "error"
  569. });
  570. return false;
  571. }
  572. if (!this.firstPropertyId) {
  573. this.$notify({
  574. message: "请选择一级属性",
  575. type: "error"
  576. });
  577. return false;
  578. }
  579. return true;
  580. }
  581. },
  582. computed: {
  583. answer() {
  584. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  585. return this.singleRightAnswer;
  586. } else if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  587. var obj = this.multipleRightAnswer;
  588. return obj.sort().toString();
  589. }
  590. return this.quesModel.quesAnswer;
  591. },
  592. saveDisabled: function() {
  593. if (!this.questionId && this.quesModel.quesOptions.length == 0) {
  594. return true;
  595. }
  596. return false;
  597. }
  598. },
  599. created() {
  600. let questionId = this.$route.params.id;
  601. if (questionId) {
  602. this.questionId = questionId;
  603. this.quesModel["id"] = questionId;
  604. this.findQuestionById(questionId);
  605. }
  606. this.paperId = this.$route.params.paperId;
  607. this.paperDetailId = this.$route.params.paperDetailId;
  608. this.courseNo = this.$route.params.courseNo;
  609. let questionType = this.$route.params.questionType;
  610. if (questionType) {
  611. this.quesModel.questionType = questionType;
  612. }
  613. if (this.courseNo) {
  614. this.$http
  615. .get(QUESTION_API + "/courseProperty/enable/" + this.courseNo)
  616. .then(response => {
  617. this.coursePropertyList = response.data;
  618. });
  619. }
  620. }
  621. };
  622. </script>
  623. <style scoped src="../styles/Common.css"></style>