BaseCreateChild.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. <template>
  2. <div class="ev-container" :id="refId">
  3. <div class="display-flex">
  4. <div class="exersices-attr my-radio-style">
  5. <IconText :text="$t('evaluation.newExercise.field')" :color="'#00b8ff'" :icon="'md-planet'"></IconText>
  6. <Select v-model="exerciseField">
  7. <Option v-for="(item, index) in fieldList" :value="index" :key="index">{{ item }}</Option>
  8. </Select>
  9. </div>
  10. <div class="exersices-attr my-radio-style">
  11. <IconText :text="$t('evaluation.newExercise.knowledge')" :color="'#00b8ff'" :icon="'md-infinite'"></IconText>
  12. <Button type="info" style="margin-top: 20px" @click="onSelectPoints" v-if="exercisePoints.length === 0">{{$t('evaluation.newExercise.choosePoint')}}</Button>
  13. <div v-else style="margin-top: 10px">
  14. <span v-for="(item, index) in exercisePoints" :key="index" class="exercise-item-point">
  15. {{ item }}
  16. <span class="exercise-item-point-close">
  17. <Icon type="md-close" @click="onDeletePoint(index)" /></span>
  18. </span>
  19. <span class="exercise-item-point-modify" @click="selectPointsModal = true">{{ $t('evaluation.newExercise.modify') }}</span>
  20. </div>
  21. </div>
  22. </div>
  23. <div class="exersices-attr display-flex">
  24. <div class="exersices-attr my-radio-style">
  25. <IconText :text="$t('evaluation.newExercise.type')" :color="'#00b8ff'" :icon="'md-pricetags'"></IconText>
  26. <RadioGroup v-model="exersicesType" type="button" @on-change="typeChange">
  27. <Radio label="single" :disabled="isEdit">{{ $t('evaluation.single') }}</Radio>
  28. <Radio label="multiple" :disabled="isEdit">{{ $t('evaluation.multiple') }}</Radio>
  29. <Radio label="judge" :disabled="isEdit">{{ $t('evaluation.judge') }}</Radio>
  30. <Radio label="complete" :disabled="isEdit">{{ $t('evaluation.complete') }}</Radio>
  31. <Radio label="subjective" :disabled="isEdit">{{ $t('evaluation.subjective') }}</Radio>
  32. <Radio label="connector" :disabled="isEdit">{{ $t('evaluation.connector') }}</Radio>
  33. <Radio label="correct" :disabled="isEdit">{{ $t('evaluation.correct') }}</Radio>
  34. </RadioGroup>
  35. </div>
  36. <div class="exersices-attr edit-exersices-attr-diff my-radio-style">
  37. <IconText :text="$t('evaluation.newExercise.diff')" :color="'#00b8ff'" :icon="'md-pulse'"></IconText>
  38. <RadioGroup v-model="exersicesDiff" type="button">
  39. <Radio label="1" @click.native="diffChange($event, '1')">{{$t('evaluation.diff1')}}</Radio>
  40. <Radio label="2" @click.native="diffChange($event, '2')">{{$t('evaluation.diff2')}}</Radio>
  41. <Radio label="3" @click.native="diffChange($event, '3')">{{$t('evaluation.diff3')}}</Radio>
  42. <Radio label="4" @click.native="diffChange($event, '4')">{{$t('evaluation.diff4')}}</Radio>
  43. <Radio label="5" @click.native="diffChange($event, '5')">{{$t('evaluation.diff5')}}</Radio>
  44. </RadioGroup>
  45. </div>
  46. </div>
  47. <BaseSingle v-if="exersicesType === 'single'" ref="single" :editInfo="editInfo"></BaseSingle>
  48. <BaseMultiple v-else-if="exersicesType === 'multiple'" ref="multiple" :editInfo="editInfo"></BaseMultiple>
  49. <BaseJudge v-else-if="exersicesType === 'judge'" ref="judge" :editInfo="editInfo"></BaseJudge>
  50. <BaseCompletion v-else-if="exersicesType === 'complete'" ref="complete" :editInfo="editInfo"></BaseCompletion>
  51. <BaseConnector v-else-if="exersicesType === 'connector'" ref="connector" :editInfo="editInfo"></BaseConnector>
  52. <BaseCorrect v-else-if="exersicesType === 'correct'" ref="correct" :editInfo="editInfo"></BaseCorrect>
  53. <BaseSubjective v-else-if="exersicesType === 'subjective'" ref="subjective" :editInfo="editInfo"></BaseSubjective>
  54. <!-- 解析的富文本部分 -->
  55. <div class="exersices-analysis child-exercise-analysis">
  56. <IconText :text="$t('evaluation.explain')" :color="'#2892DD'" :icon="'md-list'" style="margin-bottom: 10px"></IconText>
  57. <div>
  58. <div ref="analysisEditor" style="text-align: left"></div>
  59. </div>
  60. </div>
  61. <!-- 补救的富文本部分 -->
  62. <!-- 补救的富文本部分 -->
  63. <div class="exersices-analysis" v-show="exersicesType !== 'compose'">
  64. <IconText :text="$t('evaluation.newExercise.repair')" :color="'#2892DD'" :icon="'md-link'" style="margin-bottom: 10px"></IconText>
  65. <BaseRepair ref="repairRef" :repairs="editInfo.repair"></BaseRepair>
  66. </div>
  67. <div class="save-wrap display-flex">
  68. <Button type="success" @click="getContent(exersicesType)" :loading="saveLoading">{{ $t('evaluation.newExercise.save') }}</Button>
  69. </div>
  70. <!-- 选择知识点弹窗 -->
  71. <Modal v-model="selectPointsModal" :title="$t('evaluation.newExercise.choosePoint')" width="600px" class="related-point-modal" style="z-index: 99999">
  72. <BasePoints v-if="selectPointsModal" ref="pointRef" :period="schoolInfo.period[curPeriodIndex].id" :subject="schoolInfo.period[curPeriodIndex].subjects[curSubjectIndex].id"
  73. @onCheckChange="onCheckChange" :points="exercisePoints" :scope="curScope"></BasePoints>
  74. <!--<CreateNewChild v-if="isLoadModal" ref="newChild" :isChildEdit="isChildEdit" :editItem="editChild"></CreateNewChild>-->
  75. <div slot="footer">
  76. <Button type="text" @click="selectPointsModal = false">{{ $t('evaluation.cancel') }}</Button>
  77. <Button type="primary" @click="selectPointsModal = false">{{ $t('evaluation.confirm') }}</Button>
  78. </div>
  79. </Modal>
  80. </div>
  81. </template>
  82. <script>
  83. import "videojs-contrib-hls.js/src/videojs.hlsjs";
  84. import IconText from "@/components/evaluation/IconText.vue";
  85. import BaseSingle from "@/view/evaluation/types/BaseSingle.vue";
  86. import BaseMultiple from "@/view/evaluation/types/BaseMultiple.vue";
  87. import BaseCompletion from "@/view/evaluation/types/BaseCompletion.vue";
  88. import BaseJudge from "@/view/evaluation/types/BaseJudge.vue";
  89. import BaseSubjective from "@/view/evaluation/types/BaseSubjective.vue";
  90. import BaseCorrect from "@/view/evaluation/types/BaseCorrect.vue";
  91. import BaseConnector from "@/view/evaluation/types/BaseConnector.vue";
  92. import NewChooseContent from "@/components/selflearn/NewChooseContent";
  93. import E from "wangeditor";
  94. // 默认创建题目模板
  95. const defaultExercise = {
  96. question: "",
  97. option: [],
  98. level: 1,
  99. answer: [],
  100. explain: "",
  101. type: "",
  102. };
  103. export default {
  104. name:'BaseCreateChild',
  105. components: {
  106. IconText,
  107. BaseSingle,
  108. BaseJudge,
  109. BaseMultiple,
  110. BaseCompletion,
  111. BaseSubjective,
  112. BaseCorrect,
  113. BaseConnector,
  114. NewChooseContent,
  115. },
  116. props: {
  117. editItem: {
  118. type: Object,
  119. default: null,
  120. },
  121. refId: {
  122. type: String,
  123. default: "createChild",
  124. },
  125. curPeriodIndex: {
  126. type: Number,
  127. default: 0,
  128. },
  129. curSubjectIndex: {
  130. type: Number,
  131. default: 0,
  132. },
  133. },
  134. data() {
  135. return {
  136. isRelatedContent: false,
  137. selectPointsModal: false,
  138. isEdit: false,
  139. isFalse: false,
  140. isLoading: false,
  141. relateFileList: [],
  142. editInfo: {},
  143. schoolInfo: {},
  144. saveLoading: false,
  145. exersicesType: "single",
  146. exerciseField: 0,
  147. exercisePeriod: 0,
  148. exerciseGrade: [],
  149. exerciseSubject: 0,
  150. exerciseScope: 0,
  151. exercisePoints: [],
  152. scopeList: [this.$t('evaluation.filter.schoolBank'),this.$t('evaluation.filter.privateBank')],
  153. fieldList: [this.$t('evaluation.level1'),this.$t('evaluation.level2'),this.$t('evaluation.level3'),
  154. this.$t('evaluation.level4'),this.$t('evaluation.level5'),this.$t('evaluation.level6')],
  155. periodList: [],
  156. gradeList: [],
  157. subjectList: [],
  158. exersicesDiff: "1",
  159. analysisContent: "",
  160. repairContent: "",
  161. stemContent: "",
  162. analysisEditor: null,
  163. repairEditor: null,
  164. curId:''
  165. };
  166. },
  167. created() {
  168. this.getSchoolInfo();
  169. },
  170. methods: {
  171. getSchoolInfo() {
  172. this.$store.dispatch("user/getSchoolProfile").then((res) => {
  173. let schoolBaseInfo = res.school_base;
  174. if (schoolBaseInfo) {
  175. this.schoolInfo = schoolBaseInfo;
  176. if (schoolBaseInfo.period.length) {
  177. this.gradeList = schoolBaseInfo.period[0].grades;
  178. this.subjectList = schoolBaseInfo.period[0].subjects;
  179. }
  180. }
  181. });
  182. },
  183. onSelectPoints(){
  184. if(this.hasSchool){
  185. console.log(this.schoolInfo)
  186. console.log(this.curPeriodIndex)
  187. console.log(this.curSubjectIndex)
  188. this.selectPointsModal = true
  189. }else{
  190. this.$Message.warning(this.$t('evaluation.newExercise.noSchoolTip'))
  191. }
  192. },
  193. onSelectFile(val) {
  194. this.relateFileList = val.files;
  195. },
  196. onConfirmRelate() {
  197. console.log(this.relateFileList);
  198. this.isRelatedContent = false;
  199. },
  200. async getContent(type) {
  201. let exerciseItem = this.editInfo && this.editInfo.id ? JSON.parse(JSON.stringify(this.editInfo)) : Object.assign({}, defaultExercise);
  202. switch (type) {
  203. case "single":
  204. this.$refs.single.doSave()
  205. exerciseItem.question = this.$refs.single.stemContent;
  206. exerciseItem.option = this.checkOptionNull(this.$refs.single.optionsContent) ? this.$refs.single.optionsContent : null;
  207. exerciseItem.type = this.exersicesType;
  208. exerciseItem.level = +this.exersicesDiff;
  209. exerciseItem.explain = this.analysisContent;
  210. exerciseItem.answer = [
  211. String.fromCharCode(64 + parseInt(this.$refs.single.trueIndex + 1)),
  212. ];
  213. break;
  214. case "multiple":
  215. this.$refs.multiple.doSave()
  216. exerciseItem.question = this.$refs.multiple.stemContent;
  217. exerciseItem.option = this.checkOptionNull(this.$refs.multiple.optionsContent) ?
  218. this.$refs.multiple.optionsContent :
  219. null;
  220. exerciseItem.type = this.exersicesType;
  221. exerciseItem.level = +this.exersicesDiff;
  222. exerciseItem.explain = this.analysisContent;
  223. exerciseItem.answer = this.$refs.multiple.multipleAnswers;
  224. break;
  225. case "judge":
  226. exerciseItem.question = this.$refs.judge.stemContent;
  227. exerciseItem.option = [];
  228. exerciseItem.type = this.exersicesType;
  229. exerciseItem.level = +this.exersicesDiff;
  230. exerciseItem.explain = this.analysisContent;
  231. exerciseItem.answer = [this.$refs.judge.trueAnswer];
  232. break;
  233. case "complete":
  234. exerciseItem.question = this.$refs.complete.stemContent;
  235. exerciseItem.option = [];
  236. exerciseItem.type = this.exersicesType;
  237. exerciseItem.level = +this.exersicesDiff;
  238. exerciseItem.explain = this.analysisContent;
  239. exerciseItem.answer = [this.$refs.complete.answerContent];
  240. exerciseItem.blankCount = this.$refs.complete.blankCount || 1;
  241. break;
  242. case "subjective":
  243. exerciseItem.question = this.$refs.subjective.stemContent;
  244. exerciseItem.option = [];
  245. exerciseItem.type = this.exersicesType;
  246. exerciseItem.level = +this.exersicesDiff;
  247. exerciseItem.explain = this.analysisContent;
  248. exerciseItem.answer = [this.$refs.subjective.answerContent];
  249. break;
  250. case "connector":
  251. exerciseItem.question = this.$refs.connector.stemContent;
  252. exerciseItem.option = [];
  253. exerciseItem.type = this.exersicesType;
  254. exerciseItem.level = +this.exersicesDiff;
  255. exerciseItem.explain = this.analysisContent;
  256. exerciseItem.answer = [this.$refs.connector.answerContent];
  257. break;
  258. case "correct":
  259. exerciseItem.question = this.$refs.correct.stemContent;
  260. exerciseItem.option = [];
  261. exerciseItem.type = this.exersicesType;
  262. exerciseItem.level = +this.exersicesDiff;
  263. exerciseItem.explain = this.analysisContent;
  264. exerciseItem.answer = [this.$refs.correct.answerContent];
  265. break;
  266. }
  267. exerciseItem.repair = this.repairContent;
  268. exerciseItem.repair = this.formatRepairResource(
  269. this.$refs.repairRef.datas
  270. );
  271. exerciseItem.field = this.exerciseField + 1;
  272. exerciseItem.knowledge = this.exercisePoints;
  273. exerciseItem.children = [];
  274. exerciseItem.score = 0;
  275. exerciseItem.code =
  276. this.$parent.$parent.exerciseScope === 0 ?
  277. this.$store.state.userInfo.TEAMModelId :
  278. this.$store.state.userInfo.schoolCode;
  279. // 判断获取的数据是否有空数据以及是否为空字符串
  280. if (
  281. this.checkContent(exerciseItem) &&
  282. this.getSimpleText(exerciseItem.question)
  283. ) {
  284. // this.saveLoading = true
  285. exerciseItem.id = this.curId;
  286. console.log('编辑后的小题',exerciseItem)
  287. this.$emit("addFinish", exerciseItem);
  288. } else {
  289. console.log(exerciseItem);
  290. this.$Message.warning(this.$t('evaluation.newExercise.unCompleteTip'));
  291. }
  292. },
  293. /* 知识点勾选变动事件 */
  294. onCheckChange(val, list) {
  295. this.exercisePoints = val;
  296. },
  297. /**
  298. * 移除指定知识点
  299. * @param index
  300. */
  301. onDeletePoint(index) {
  302. this.exercisePoints.splice(index, 1);
  303. // this.$refs.pointRef.$children[1].onDeletePoint(index)
  304. },
  305. // 题目类型转换
  306. typeChange(val) {
  307. if (this.isEdit) {
  308. this.$Message.warning(this.$t('evaluation.newExercise.typeChangeTip'));
  309. }else {
  310. this.exersicesType = val;
  311. this.analysisEditor.txt.clear();
  312. // this.repairEditor.txt.clear()
  313. }
  314. },
  315. // 重置本页面
  316. doReset() {
  317. this.exerciseField = 0;
  318. this.exercisePoints = [];
  319. this.exersicesDiff = "1";
  320. this.exersicesType = "single";
  321. this.analysisEditor.txt.clear();
  322. // this.repairEditor.txt.clear()
  323. this.editInfo = null;
  324. },
  325. /* 检测补救资源超链接 去除无效链接 */
  326. formatRepairResource(list) {
  327. if (list.length) {
  328. let arr = [];
  329. list.forEach((i, index) => {
  330. i.blobUrl.forEach(j => {
  331. arr.push({
  332. blobUrl:j.url,
  333. name:i.name,
  334. type:i.type
  335. })
  336. })
  337. });
  338. return arr;
  339. } else {
  340. return [];
  341. }
  342. },
  343. // 难度与背景颜色切换
  344. diffChange(e, type) {
  345. this.exersicesDiff = +type;
  346. e.preventDefault();
  347. let colorArr = ["#10abe7", "#E8BE15", "#F19300", "#EB5E00", "#D30000"];
  348. let ac = document
  349. .getElementById(this.refId)
  350. .getElementsByClassName("edit-exersices-attr-diff")[0].children[1]
  351. .children;
  352. for (let i = 0; i < ac.length; i++) {
  353. ac[i].style.background = "#fff";
  354. ac[i].style.color = "#515a6e";
  355. }
  356. e.target.style.background = colorArr[type - 1];
  357. e.target.style.color = "#fff";
  358. },
  359. // 提取富文本内容中的文本
  360. getSimpleText(html) {
  361. var r = /<(?!img|video|audio).*?>/g;
  362. return html.replace(r, "");
  363. },
  364. /* 检测数组是否有空数据 */
  365. checkOptionNull(arr) {
  366. let flag = true;
  367. for (let i = 0; i < arr.length; i++) {
  368. if (this.getSimpleText(arr[i].value) === "") {
  369. flag = false;
  370. }
  371. }
  372. return flag;
  373. },
  374. // 排除对象空属性
  375. checkContent(Obj) {
  376. let flag = true;
  377. let whiteList = this.getWhiteListByType(Obj.type);
  378. console.log("验证的");
  379. console.log(Obj);
  380. for (let key in Obj) {
  381. if (whiteList.includes(key) && typeof Obj[key] === "string") {
  382. if (!this.getSimpleText(Obj[key])) {
  383. console.log(key);
  384. flag = false;
  385. }
  386. } else if (whiteList.includes(key) && key === "answer") {
  387. if (Obj[key].length === 0) {
  388. console.log(key);
  389. flag = false;
  390. }
  391. } else {
  392. if (whiteList.includes(key) && !Obj[key]) {
  393. console.log(key);
  394. flag = false;
  395. }
  396. }
  397. }
  398. return flag;
  399. },
  400. // 根据不同题型 给出需要必填选项
  401. getWhiteListByType(type) {
  402. switch (type) {
  403. case "single":
  404. return ["question", "option", "answer"];
  405. break;
  406. case "multiple":
  407. return ["question", "option", "answer"];
  408. break;
  409. case "complete":
  410. return ["question", "answer"];
  411. break;
  412. default:
  413. return ["question", "answer"];
  414. break;
  415. }
  416. },
  417. // 渲染编辑习题内容回显
  418. async renderExercise(editItem) {
  419. this.isEdit = true;
  420. this.exersicesDiff = editItem.level.toString() || "0";
  421. this.exerciseScope =
  422. editItem.code === this.$store.state.userInfo.TEAMModelId ? 0 : 1;
  423. this.exersicesType = editItem.type;
  424. this.exerciseField = editItem.field - 1;
  425. this.exercisePoints = editItem.knowledge || editItem.points;
  426. if (editItem.level) {
  427. let ac = document
  428. .getElementById(this.refId)
  429. .getElementsByClassName("edit-exersices-attr-diff")[0].children[1]
  430. .children;
  431. for (let i = 0; i < ac.length; i++) {
  432. ac[i].style.background = "#fff";
  433. ac[i].style.color = "#515a6e";
  434. }
  435. // 重新渲染题目难度
  436. let diffDom = document
  437. .getElementById(this.refId)
  438. .getElementsByClassName("edit-exersices-attr-diff")[0].children[1]
  439. .children[editItem.level - 1];
  440. let colorArr = ["#32CF74", "#E8BE15", "#F19300", "#EB5E00", "#D30000"];
  441. diffDom.style.background = colorArr[editItem.level - 1];
  442. diffDom.style.color = "#fff";
  443. } else {
  444. let ac = document
  445. .getElementById(this.refId)
  446. .getElementsByClassName("edit-exersices-attr-diff")[0].children[1]
  447. .children;
  448. for (let i = 0; i < ac.length; i++) {
  449. ac[i].style.background = "#fff";
  450. ac[i].style.color = "#515a6e";
  451. }
  452. }
  453. this.childList = editItem.children || [];
  454. let schoolInfo = await this.$store.dispatch('user/getSchoolProfile');
  455. this.schoolInfo = schoolInfo.school_base;
  456. this.stemContent = editItem.question;
  457. this.relateFileList = editItem.repair || [];
  458. this.optionsContent = editItem.option;
  459. this.analysisContent = editItem.explain;
  460. this.analysisEditor.txt.html(editItem.explain);
  461. this.editInfo = editItem;
  462. },
  463. },
  464. mounted() {
  465. let analysisEditor = new E(this.$refs.analysisEditor);
  466. analysisEditor.config.uploadImgShowBase64 = true;
  467. analysisEditor.config.onchange = (html) => {
  468. this.analysisContent = html;
  469. },
  470. this.$editorTools.initMyEditor(analysisEditor,this)
  471. analysisEditor.create();
  472. this.analysisEditor = analysisEditor;
  473. this.curId = this.$tools.guid()
  474. if (this.editItem && this.editItem.id) {
  475. this.renderExercise(JSON.parse(JSON.stringify(this.editItem)));
  476. // 先生成随机ID
  477. this.curId = this.editItem.id || this.$tools.guid()
  478. }
  479. },
  480. computed:{
  481. curScope(){
  482. return this.exerciseScope === 1 ? 'school' : 'private'
  483. },
  484. hasSchool() {
  485. let user = JSON.parse(
  486. decodeURIComponent(localStorage.user_profile, "utf-8")
  487. );
  488. return (
  489. user.schools &&
  490. user.schools.length &&
  491. user.schools.filter((i) => i.status === "join").length > 0
  492. );
  493. },
  494. },
  495. watch: {
  496. editItem: {
  497. handler(newValue, oldValue) {
  498. if (newValue) {
  499. console.log("要编辑的小题");
  500. console.log(newValue);
  501. this.renderExercise(JSON.parse(JSON.stringify(newValue)));
  502. this.curId = newValue.id || this.$tools.guid()
  503. // this.$refs.pointRef.doReset()
  504. }
  505. },
  506. //immediate:true
  507. }
  508. },
  509. };
  510. </script>
  511. <style src="../index/CreateExercises.less" lang="less" scoped>
  512. </style>
  513. <style>
  514. .related-point-modal .ivu-modal-header-inner {
  515. font-weight: bold;
  516. }
  517. .exersices-attr .ivu-select-multiple .ivu-tag {
  518. height: 32px;
  519. line-height: 31px;
  520. }
  521. .exersices-attr .ivu-select-multiple .ivu-tag i {
  522. top: 9px;
  523. }
  524. .exersices-attr .ivu-select-multiple .ivu-select-selection .ivu-select-placeholder {
  525. line-height: 38px;
  526. }
  527. .child-exercise-analysis .w-e-toolbar{
  528. z-index: 0 !important;
  529. }
  530. .child-exercise-analysis .w-e-text-container{
  531. position: unset;
  532. }
  533. </style>