CreateExercises.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. <template>
  2. <div class="ev-container">
  3. <span class="ev-title">
  4. <Icon type="ios-paper" />{{ exerciseScope === 1 ? $t('evaluation.newExercise.newSchoolItem') : $t('evaluation.newExercise.newPrivateItem') }}</span>
  5. <Divider />
  6. <div class="display-flex" v-if="isSchool">
  7. <div class="exersices-attr my-radio-style">
  8. <IconText :text="$t('evaluation.newExercise.choosePeriod')" :color="'#00b8ff'" :icon="'md-school'"></IconText>
  9. <Select v-model="exercisePeriod" @on-change="onPeriodChange">
  10. <Option v-for="(period, index) in schoolInfo.period" :value="index" :key="index">{{ period.name }}</Option>
  11. </Select>
  12. </div>
  13. <div class="my-radio-style exersices-attr">
  14. <IconText :text="$t('evaluation.newExercise.chooseGrade')" :color="'#00b8ff'" :icon="'logo-buffer'"></IconText>
  15. <Select v-model="exerciseGrade" multiple :placeholder="$t('evaluation.newExercise.gradePlaceholder')">
  16. <Option v-for="(grade, index) in gradeList" :value="grade.id" :key="index">{{ grade.name }}</Option>
  17. </Select>
  18. </div>
  19. <div class="exersices-attr my-radio-style">
  20. <IconText :text="$t('evaluation.newExercise.chooseSubject')" :color="'#00b8ff'" :icon="'md-bookmarks'"></IconText>
  21. <Select v-model="exerciseSubject" @on-change="onSubjectChange">
  22. <Option v-for="(subject, index) in subjectList" :value="index" :key="index">{{ subject.name }}</Option>
  23. </Select>
  24. </div>
  25. </div>
  26. <div class="display-flex">
  27. <div class="exersices-attr exercises-attr-diff my-radio-style">
  28. <IconText :text="$t('evaluation.newExercise.diff')" :color="'#00b8ff'" :icon="'md-pulse'"></IconText>
  29. <RadioGroup v-model="exersicesDiff" type="button">
  30. <Radio label="1" @click.native="diffChange($event, '1')">{{$t('evaluation.diff1')}}</Radio>
  31. <Radio label="2" @click.native="diffChange($event, '2')">{{$t('evaluation.diff2')}}</Radio>
  32. <Radio label="3" @click.native="diffChange($event, '3')">{{$t('evaluation.diff3')}}</Radio>
  33. <Radio label="4" @click.native="diffChange($event, '4')">{{$t('evaluation.diff4')}}</Radio>
  34. <Radio label="5" @click.native="diffChange($event, '5')">{{$t('evaluation.diff5')}}</Radio>
  35. </RadioGroup>
  36. </div>
  37. <div class="exersices-attr my-radio-style">
  38. <IconText :text="$t('evaluation.newExercise.field')" :color="'#00b8ff'" :icon="'md-planet'"></IconText>
  39. <Select v-model="exerciseField">
  40. <Option v-for="(item, index) in fieldList" :value="index" :key="index">{{ item }}</Option>
  41. </Select>
  42. </div>
  43. <div class="exersices-attr my-radio-style">
  44. <IconText :text="$t('evaluation.newExercise.knowledge')" :color="'#00b8ff'" :icon="'md-infinite'"></IconText>
  45. <Button type="info" style="margin-top: 20px" @click="onSelectPoints" v-if="exercisePoints.length === 0">{{$t('evaluation.newExercise.choosePoint')}}</Button>
  46. <div v-else style="margin-top: 10px">
  47. <span v-for="(item, index) in exercisePoints" :key="index" class="exercise-item-point">
  48. {{ item }}
  49. <span class="exercise-item-point-close">
  50. <Icon type="md-close" @click="onDeletePoint(index)" /></span>
  51. </span>
  52. <span class="exercise-item-point-modify" @click="selectPointsModal = true">{{ $t('evaluation.newExercise.modify') }}</span>
  53. </div>
  54. </div>
  55. </div>
  56. <div class="exersices-attr display-flex">
  57. <div class="exersices-attr-type my-radio-style">
  58. <IconText :text="$t('evaluation.newExercise.type')" :color="'#00b8ff'" :icon="'md-pricetags'"></IconText>
  59. <RadioGroup v-model="exersicesType" type="button" @on-change="typeChange">
  60. <Radio label="single" :disabled="isEdit">{{ $t('evaluation.single') }}</Radio>
  61. <Radio label="multiple" :disabled="isEdit">{{ $t('evaluation.multiple') }}</Radio>
  62. <Radio label="judge" :disabled="isEdit">{{ $t('evaluation.judge') }}</Radio>
  63. <Radio label="complete" :disabled="isEdit">{{ $t('evaluation.complete') }}</Radio>
  64. <Radio label="subjective" :disabled="isEdit">{{ $t('evaluation.subjective') }}</Radio>
  65. <Radio label="connector" :disabled="isEdit">{{ $t('evaluation.connector') }}</Radio>
  66. <Radio label="correct" :disabled="isEdit">{{ $t('evaluation.correct') }}</Radio>
  67. <Radio label="compose" :disabled="isEdit">{{ $t('evaluation.compose') }}</Radio>
  68. </RadioGroup>
  69. </div>
  70. </div>
  71. <BaseSingle v-if="exersicesType === 'single'" ref="single" :editInfo="editInfo"></BaseSingle>
  72. <BaseMultiple v-else-if="exersicesType === 'multiple'" ref="multiple" :editInfo="editInfo"></BaseMultiple>
  73. <BaseJudge v-else-if="exersicesType === 'judge'" ref="judge" :editInfo="editInfo"></BaseJudge>
  74. <BaseCompletion v-else-if="exersicesType === 'complete'" ref="complete" :editInfo="editInfo"></BaseCompletion>
  75. <BaseSubjective v-else-if="exersicesType === 'subjective'" ref="subjective" :editInfo="editInfo"></BaseSubjective>
  76. <BaseConnector v-else-if="exersicesType === 'connector'" ref="connector" :editInfo="editInfo"></BaseConnector>
  77. <BaseCorrect v-else-if="exersicesType === 'correct'" ref="correct" :editInfo="editInfo"></BaseCorrect>
  78. <BaseCompose v-else-if="exersicesType === 'compose'" ref="compose" :editInfo="editInfo"></BaseCompose>
  79. <!-- 解析的富文本部分 -->
  80. <div class="exersices-analysis" v-show="exersicesType !== 'compose'">
  81. <IconText :text="$t('evaluation.explain')" :color="'#2892DD'" :icon="'md-list'" style="margin-bottom: 10px"></IconText>
  82. <div id="analysisEditor">
  83. <div ref="analysisEditor" style="text-align: left"></div>
  84. </div>
  85. </div>
  86. <!-- 补救的富文本部分 -->
  87. <div class="exersices-analysis" v-show="exersicesType !== 'compose'">
  88. <IconText :text="$t('evaluation.newExercise.repair')" :color="'#2892DD'" :icon="'md-link'" style="margin-bottom: 10px"></IconText>
  89. <BaseRepair ref="repairRef"></BaseRepair>
  90. </div>
  91. <!-- 小题展示区域 -->
  92. <div class="child-list-wrap" v-show="exersicesType === 'compose' && childList.length">
  93. <IconText :text="$t('evaluation.newExercise.childList')" :color="'#00b8ff'" :icon="'md-list'"></IconText>
  94. <BaseChildList :childList="childList"></BaseChildList>
  95. </div>
  96. <div class="save-wrap display-flex">
  97. <Button type="info" @click="onAddChild" style="margin-right: 10px" v-show="exersicesType === 'compose'">{{ $t('evaluation.newExercise.addChild')}}</Button>
  98. <Button type="success" @click="getContent(exersicesType)" :loading="saveLoading">{{ $t('evaluation.newExercise.save') }}</Button>
  99. </div>
  100. <Button type="text" @click="backToBank" class="btn-back-to-bank" icon="md-arrow-round-back" style="margin-left: 10px">{{ $t('evaluation.newExercise.backToBank')}}</Button>
  101. <Modal v-model="selectPointsModal" :title="$t('evaluation.newExercise.choosePoint')" ref="pointRef" width="600px" class="related-point-modal" style="z-index: 99999">
  102. <BasePoints v-if="selectPointsModal" :period="schoolInfo.period[exercisePeriod].id" :subject="subjectList[exerciseSubject].id"
  103. @onCheckChange="onCheckChange" :points="exercisePoints" :scope="curScope"></BasePoints>
  104. <div slot="footer">
  105. <Button type="text" @click="selectPointsModal = false">{{ $t('evaluation.cancel') }}</Button>
  106. <Button type="primary" @click="selectPointsModal = false">{{ $t('evaluation.confirm') }}</Button>
  107. </div>
  108. </Modal>
  109. <!-- 添加小题弹窗 -->
  110. <Modal v-model="addComposeChildModal" width="1080" footer-hide class="">
  111. <div class="modal-header" slot="header">{{ $t('evaluation.newExercise.addChild') }}</div>
  112. <BaseCreateChild @addFinish="onAddChildFinish" ref="createAddChild" v-if="addComposeChildModal" :curPeriodIndex="exercisePeriod"
  113. :curSubjectIndex="exerciseSubject"></BaseCreateChild>
  114. </Modal>
  115. </div>
  116. </template>
  117. <script>
  118. import blobTool from "@/utils/blobTool.js";
  119. import IconText from "@/components/evaluation/IconText.vue";
  120. import BaseSingle from "@/view/evaluation/types/BaseSingle.vue";
  121. import BaseMultiple from "@/view/evaluation/types/BaseMultiple.vue";
  122. import BaseCompletion from "@/view/evaluation/types/BaseCompletion.vue";
  123. import BaseJudge from "@/view/evaluation/types/BaseJudge.vue";
  124. import BaseSubjective from "@/view/evaluation/types/BaseSubjective.vue";
  125. import BaseCorrect from "@/view/evaluation/types/BaseCorrect.vue";
  126. import BaseConnector from "@/view/evaluation/types/BaseConnector.vue";
  127. import BaseCompose from "@/view/evaluation/types/BaseCompose.vue";
  128. import BasePoints from "@/view/evaluation/components/BasePoints";
  129. import BaseRepair from "@/view/evaluation/components/BaseRepair";
  130. import BaseCreateChild from "@/view/evaluation/components/BaseCreateChild";
  131. import E from "wangeditor";
  132. // 默认创建题目模板
  133. const defaultExercise = {
  134. question: "",
  135. option: [],
  136. level: 1,
  137. answer: [],
  138. explain: "",
  139. type: "",
  140. };
  141. export default {
  142. components: {
  143. IconText,
  144. BaseSingle,
  145. BaseJudge,
  146. BaseMultiple,
  147. BaseCompletion,
  148. BaseSubjective,
  149. BaseCorrect,
  150. BaseConnector,
  151. BaseCompose,
  152. BasePoints,
  153. BaseRepair,
  154. BaseCreateChild,
  155. },
  156. data() {
  157. return {
  158. fromScope: "",
  159. isRelatedContent: false,
  160. selectPointsModal: false,
  161. addComposeChildModal: false,
  162. isEdit: false,
  163. isFalse: false,
  164. isLoading: false,
  165. relateFileList: [],
  166. editInfo: {},
  167. schoolInfo: {},
  168. saveLoading: false,
  169. exersicesType: "single",
  170. exerciseField: 0,
  171. exercisePeriod: 0,
  172. exerciseGrade: [],
  173. exerciseSubject: 0,
  174. exerciseScope: 0,
  175. exercisePoints: [],
  176. scopeList: [this.$t('evaluation.filter.schoolBank'),this.$t('evaluation.filter.privateBank')],
  177. fieldList: [this.$t('evaluation.level1'),this.$t('evaluation.level2'),this.$t('evaluation.level3'),
  178. this.$t('evaluation.level4'),this.$t('evaluation.level5'),this.$t('evaluation.level6')],
  179. periodList: [],
  180. gradeList: [],
  181. subjectList: [],
  182. childList: [],
  183. exersicesDiff: "1",
  184. analysisContent: "",
  185. repairContent: "",
  186. stemContent: "",
  187. analysisEditor: null,
  188. repairEditor: null,
  189. curId: '',
  190. isComplete: false
  191. };
  192. },
  193. created() {
  194. // 初始化区班校信息
  195. this.getSchoolInfo();
  196. let scope = this.$route.name === 'newSchoolExercise' ? 'school' : 'private'; // 编辑题目
  197. if (scope) {
  198. this.exerciseScope = scope === "private" ? 0 : 1;
  199. this.fromScope = scope;
  200. }
  201. // 先生成随机ID
  202. this.curId = this.$tools.guid()
  203. },
  204. methods: {
  205. getSchoolInfo() {
  206. this.$store.dispatch("user/getSchoolProfile").then((res) => {
  207. let schoolBaseInfo = res.school_base;
  208. if (schoolBaseInfo) {
  209. this.schoolInfo = schoolBaseInfo;
  210. if (schoolBaseInfo.period.length) {
  211. this.gradeList = schoolBaseInfo.period[0].grades;
  212. this.subjectList = schoolBaseInfo.period[0].subjects;
  213. }
  214. }
  215. });
  216. },
  217. onSelectPoints() {
  218. if (this.hasSchool) {
  219. if(this.exersicesType === 'compose'){
  220. this.$Message.warning(this.$t('evaluation.newExercise.composeTip'))
  221. }else{
  222. this.selectPointsModal = true
  223. }
  224. } else {
  225. this.$Message.warning(this.$t('evaluation.newExercise.noSchoolTip'))
  226. }
  227. },
  228. onSelectFile(val) {
  229. this.relateFileList = val.files;
  230. },
  231. onConfirmRelate() {
  232. console.log(this.relateFileList);
  233. this.isRelatedContent = false;
  234. },
  235. async getContent(type) {
  236. let exerciseItem = Object.assign({}, defaultExercise);
  237. switch (type) {
  238. case "single":
  239. this.$refs.single.doSave()
  240. exerciseItem.question = this.$refs.single.stemContent;
  241. exerciseItem.option = this.checkOptionNull(this.$refs.single.optionsContent) ? this.$refs.single.optionsContent :
  242. null;
  243. exerciseItem.type = this.exersicesType;
  244. exerciseItem.level = +this.exersicesDiff;
  245. exerciseItem.explain = this.analysisContent;
  246. exerciseItem.answer = [
  247. String.fromCharCode(64 + parseInt(this.$refs.single.trueIndex + 1)),
  248. ];
  249. break;
  250. case "multiple":
  251. this.$refs.multiple.doSave()
  252. exerciseItem.question = this.$refs.multiple.stemContent;
  253. exerciseItem.option = this.checkOptionNull(this.$refs.multiple.optionsContent) ?
  254. this.$refs.multiple.optionsContent :
  255. null;
  256. exerciseItem.type = this.exersicesType;
  257. exerciseItem.level = +this.exersicesDiff;
  258. exerciseItem.explain = this.analysisContent;
  259. exerciseItem.answer = this.$refs.multiple.multipleAnswers;
  260. break;
  261. case "judge":
  262. exerciseItem.question = this.$refs.judge.stemContent;
  263. exerciseItem.option = [];
  264. exerciseItem.type = this.exersicesType;
  265. exerciseItem.level = +this.exersicesDiff;
  266. exerciseItem.explain = this.analysisContent;
  267. exerciseItem.answer = [this.$refs.judge.trueAnswer];
  268. break;
  269. case "complete":
  270. exerciseItem.question = this.$refs.complete.stemContent;
  271. exerciseItem.option = [];
  272. exerciseItem.type = this.exersicesType;
  273. exerciseItem.level = +this.exersicesDiff;
  274. exerciseItem.explain = this.analysisContent;
  275. exerciseItem.answer = [this.$refs.complete.answerContent];
  276. break;
  277. case "subjective":
  278. exerciseItem.question = this.$refs.subjective.stemContent;
  279. exerciseItem.option = [];
  280. exerciseItem.type = this.exersicesType;
  281. exerciseItem.level = +this.exersicesDiff;
  282. exerciseItem.explain = this.analysisContent;
  283. exerciseItem.answer = [this.$refs.subjective.answerContent];
  284. break;
  285. case "connector":
  286. exerciseItem.question = this.$refs.connector.stemContent;
  287. exerciseItem.option = [];
  288. exerciseItem.type = this.exersicesType;
  289. exerciseItem.level = +this.exersicesDiff;
  290. exerciseItem.explain = this.analysisContent;
  291. exerciseItem.answer = [this.$refs.connector.answerContent];
  292. break;
  293. case "correct":
  294. exerciseItem.question = this.$refs.correct.stemContent;
  295. exerciseItem.option = [];
  296. exerciseItem.type = this.exersicesType;
  297. exerciseItem.level = +this.exersicesDiff;
  298. exerciseItem.explain = this.analysisContent;
  299. exerciseItem.answer = [this.$refs.correct.answerContent];
  300. break;
  301. case "compose":
  302. exerciseItem.question = this.$refs.compose.stemContent;
  303. exerciseItem.option = [];
  304. exerciseItem.type = this.exersicesType;
  305. exerciseItem.level = +this.exersicesDiff;
  306. exerciseItem.explain = this.analysisContent;
  307. exerciseItem.children = this.childList;
  308. exerciseItem.answer = []
  309. break;
  310. default:
  311. break;
  312. }
  313. exerciseItem.repair = this.formatRepairResource(this.$refs.repairRef.datas);
  314. exerciseItem.field = this.exerciseField + 1;
  315. exerciseItem.knowledge = this.exercisePoints; //新知识点
  316. exerciseItem.periodId = this.isSchool ? this.schoolInfo.period[this.exercisePeriod].id : null;
  317. exerciseItem.gradeIds = this.isSchool ?
  318. this.exerciseGrade.length ?
  319. this.exerciseGrade :
  320. this.gradeList.map((i) => i.id) :
  321. null;
  322. exerciseItem.subjectId = this.isSchool ?
  323. this.schoolInfo.period[this.exercisePeriod].subjects[
  324. this.exerciseSubject
  325. ].id :
  326. null;
  327. exerciseItem.code =
  328. this.exerciseScope === 0 ?
  329. this.$store.state.userInfo.TEAMModelId :
  330. this.schoolInfo.id;
  331. exerciseItem.scope = this.exerciseScope === 0 ? "private" : "school";
  332. // 收集编辑器宽度 方便压缩富文本图片中宽度为百分比的图片
  333. let editorWidth = {}
  334. if(exerciseItem.type === 'single'){
  335. editorWidth.questionWidth = this.$refs.single.stemEditor.$textContainerElem.elems[0].clientWidth
  336. editorWidth.optionWidth = this.$refs.single.optionEditors[0].$textContainerElem.elems[0].clientWidth
  337. }else if(exerciseItem.type === 'multiple'){
  338. editorWidth.questionWidth = this.$refs.multiple.stemEditor.$textContainerElem.elems[0].clientWidth
  339. editorWidth.optionWidth = this.$refs.multiple.optionEditors[0].$textContainerElem.elems[0].clientWidth
  340. }else{
  341. editorWidth.questionWidth = this.analysisEditor.$textContainerElem.elems[0].clientWidth
  342. }
  343. // 判断获取的数据是否有空数据以及是否为空字符串
  344. if (this.checkContent(exerciseItem)) {
  345. exerciseItem = await this.$editorTools.transBase64Src(exerciseItem,editorWidth)
  346. console.log('转换后的试题')
  347. console.log(exerciseItem)
  348. this.saveLoading = true;
  349. // 生成JSON文件名称以及新增试题的ID
  350. const guid = this.curId;
  351. // 给新增的试题赋值ID
  352. exerciseItem.id = guid;
  353. // 如果是综合题 则需要完善子题的信息 并且进行保存
  354. if (exerciseItem.children && exerciseItem.children.length && exerciseItem.type === 'compose') {
  355. exerciseItem.children.forEach((child) => {
  356. child.periodId = exerciseItem.periodId
  357. child.gradeIds = exerciseItem.gradeIds
  358. child.subjectId = exerciseItem.subjectId
  359. child.scope = exerciseItem.scope
  360. child.code = exerciseItem.code
  361. child.pid = exerciseItem.id
  362. })
  363. // 保存完题目返回子题的ID集合 作为cosmos内综合题的children字段
  364. exerciseItem.children = await this.saveChildrens(exerciseItem.children)
  365. }
  366. // 将当前的试题数据转化为BLOB内部的试题JSON格式
  367. const itemJsonFile = await this.$evTools.createBlobItem(exerciseItem);
  368. // 首先保存新题目的JSON文件到Blob 然后返回URL链接
  369. let file = new File([JSON.stringify(itemJsonFile)], guid + ".json", {
  370. type: "",
  371. });
  372. // 获取初始化Blob需要的数据
  373. let sasData =
  374. this.exerciseScope === 0 ?
  375. await this.$tools.getPrivateSas() :
  376. await this.$tools.getSchoolSas();
  377. //初始化Blob
  378. let containerClient = new blobTool(
  379. sasData.url,
  380. sasData.name,
  381. sasData.sas,
  382. exerciseItem.scope
  383. );
  384. try {
  385. // 等待上传blob的返回结果
  386. let blobFile = await containerClient.upload(file, "item/" + guid);
  387. if (blobFile.blob) {
  388. // 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
  389. exerciseItem.blob = blobFile.blob;
  390. this.saveExercise({
  391. itemInfo: await this.$evTools.createCosmosItem(exerciseItem),
  392. option: "insert",
  393. }).then((res) => {
  394. this.isComplete = true
  395. this.$router.push({
  396. name: this.exerciseScope === 0 ? "personalBank" : "schoolBank",
  397. params: {
  398. tabName: "exercise",
  399. },
  400. });
  401. this.saveLoading = false;
  402. });
  403. } else {
  404. this.$Message.error(this.$t('evaluation.newExercise.uploadErrorTip'));
  405. }
  406. } catch (e) {
  407. this.$Message.error(e.spaceError);
  408. }
  409. } else {
  410. console.log(exerciseItem);
  411. this.$Message.warning(this.$t('evaluation.newExercise.unCompleteTip'));
  412. this.saveLoading = false;
  413. }
  414. },
  415. /* 保存综合题的子题 */
  416. saveChildrens(childrens) {
  417. return new Promise((resolve, reject) => {
  418. let promiseArr = []
  419. childrens.forEach(exerciseItem => {
  420. promiseArr.push(new Promise(async (r, j) => {
  421. // 将当前的试题数据转化为BLOB内部的试题JSON格式
  422. const itemJsonFile = await this.$evTools.createBlobItem(exerciseItem);
  423. // 首先保存新题目的JSON文件到Blob 然后返回URL链接
  424. let file = new File([JSON.stringify(itemJsonFile)], exerciseItem.id + ".json");
  425. // 获取初始化Blob需要的数据
  426. let sasData =
  427. exerciseItem.scope === 'private' ?
  428. await this.$tools.getPrivateSas() :
  429. await this.$tools.getSchoolSas();
  430. //初始化Blob
  431. let containerClient = new blobTool(
  432. sasData.url,
  433. sasData.name,
  434. sasData.sas,
  435. exerciseItem.scope
  436. );
  437. try {
  438. // 等待上传blob的返回结果
  439. let blobFile = await containerClient.upload(file, "item/" + exerciseItem.id);
  440. if (blobFile.blob) {
  441. // 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
  442. exerciseItem.blob = blobFile.blob;
  443. this.saveExercise({
  444. itemInfo: await this.$evTools.createCosmosItem(exerciseItem),
  445. option: "insert",
  446. }).then((res) => {
  447. r(res.itemInfo)
  448. });
  449. } else {
  450. this.$Message.error(this.$t('evaluation.newExercise.uploadErrorTip'));
  451. }
  452. } catch (e) {
  453. this.$Message.error(e.spaceError);
  454. }
  455. }))
  456. })
  457. Promise.all(promiseArr).then(result => {
  458. console.log('子题保存后的返回结果promiseArr', result)
  459. if (result.length) {
  460. resolve(result.map(i => i.id))
  461. } else {
  462. resolve([])
  463. }
  464. })
  465. })
  466. },
  467. /* 保存单个试题 */
  468. saveExercise(item) {
  469. return new Promise((r, j) => {
  470. this.$api.newEvaluation.SaveSingleExercise(item).then((res) => {
  471. if (res) {
  472. r(res);
  473. } else {
  474. j(res);
  475. this.$Message.error("服务器繁忙!");
  476. this.saveLoading = false;
  477. }
  478. });
  479. });
  480. },
  481. /* 检测补救资源超链接 去除无效链接 */
  482. formatRepairResource(list) {
  483. if (list.length) {
  484. let arr = [];
  485. list.forEach((i, index) => {
  486. i.blobUrl.forEach(j => {
  487. arr.push({
  488. blobUrl:j.url,
  489. name:i.name,
  490. type:i.type
  491. })
  492. })
  493. });
  494. return arr;
  495. } else {
  496. return [];
  497. }
  498. },
  499. /* 添加小题 重置新增页面 */
  500. onAddChild() {
  501. this.addComposeChildModal = true;
  502. if (this.$refs.createAddChild) this.$refs.createAddChild.doReset();
  503. },
  504. /* 添加小题完成 */
  505. onAddChildFinish(item) {
  506. console.log(item);
  507. this.addComposeChildModal = false;
  508. this.childList.push(item);
  509. },
  510. /* 知识点勾选变动事件 */
  511. onCheckChange(val, list) {
  512. this.exercisePoints = val;
  513. },
  514. /**
  515. * 移除指定知识点
  516. * @param index
  517. */
  518. onDeletePoint(index) {
  519. this.exercisePoints.splice(index, 1);
  520. this.$refs.pointRef.$children[1].onDeletePoint(index);
  521. },
  522. // 题目类型转换
  523. typeChange(val) {
  524. if (this.isEdit) {
  525. this.$Message.warning(this.$t('evaluation.newExercise.typeChangeTip'));
  526. } else {
  527. this.exersicesType = val;
  528. this.childList = [];
  529. this.analysisEditor.txt.clear();
  530. // this.repairEditor.txt.clear()
  531. }
  532. },
  533. // 难度与背景颜色切换
  534. diffChange(e, type) {
  535. console.log(document.getElementsByClassName("exercises-attr-diff"))
  536. this.exersicesDiff = +type;
  537. e.preventDefault();
  538. let colorArr = ["#10abe7", "#E8BE15", "#F19300", "#EB5E00", "#D30000"];
  539. let ac = document.getElementsByClassName("exercises-attr-diff")[0]
  540. .children[1].children;
  541. for (let i = 0; i < ac.length; i++) {
  542. ac[i].style.background = "#fff";
  543. ac[i].style.color = "#515a6e";
  544. }
  545. e.target.style.background = colorArr[type - 1];
  546. e.target.style.color = "#fff";
  547. },
  548. /* 学段变化 */
  549. onPeriodChange(val) {
  550. this.gradeList = this.schoolInfo.period[val].grades;
  551. this.subjectList = this.schoolInfo.period[val].subjects;
  552. this.exerciseGrade = 0;
  553. this.exerciseSubject = 0;
  554. this.exercisePoints = []; // 切换学段后 知识点需要重新选择
  555. },
  556. /* 切换科目 将知识点重置 */
  557. onSubjectChange() {
  558. this.exercisePoints = []
  559. },
  560. // 提取富文本内容中的文本
  561. getSimpleText(html) {
  562. var r = /<(?!img|video|audio).*?>/g;
  563. return html.replace(r, "");
  564. },
  565. /* 检测数组是否有空数据 */
  566. checkOptionNull(arr) {
  567. let flag = true;
  568. for (let i = 0; i < arr.length; i++) {
  569. if (this.getSimpleText(arr[i].value) === "") {
  570. flag = false;
  571. }
  572. }
  573. return flag;
  574. },
  575. // 排除对象空属性
  576. checkContent(Obj) {
  577. let flag = true;
  578. let whiteList = this.getWhiteListByType(Obj.type);
  579. console.log("富文本获取的原始试题数据", Obj);
  580. for (let key in Obj) {
  581. if (whiteList.includes(key) && typeof Obj[key] === "string") {
  582. if (!this.getSimpleText(Obj[key])) {
  583. console.log(key);
  584. flag = false;
  585. }
  586. } else if (whiteList.includes(key) && key === "answer") {
  587. if (Obj[key].length === 0) {
  588. console.log(key);
  589. flag = false;
  590. }
  591. } else {
  592. if (whiteList.includes(key) && !Obj[key]) {
  593. console.log(key);
  594. flag = false;
  595. }
  596. }
  597. }
  598. return flag;
  599. },
  600. // 重置编辑器
  601. backToBank() {
  602. this.$router.push({
  603. name: this.fromScope === "private" ? "personalBank" : "schoolBank",
  604. params: {
  605. tabName: "exercise",
  606. },
  607. });
  608. },
  609. // 重置
  610. reloadCreate() {
  611. location.reload();
  612. },
  613. // 根据不同题型 给出需要必填选项
  614. getWhiteListByType(type) {
  615. switch (type) {
  616. case "single":
  617. return ["question", "option", "answer"];
  618. break;
  619. case "multiple":
  620. return ["question", "option", "answer"];
  621. break;
  622. case "complete":
  623. return ["question", "answer"];
  624. break;
  625. default:
  626. return ["question"];
  627. break;
  628. }
  629. },
  630. },
  631. mounted() {
  632. let analysisEditor = new E(this.$refs.analysisEditor);
  633. analysisEditor.config.uploadImgShowBase64 = true;
  634. analysisEditor.config.onchange = (html) => {
  635. this.analysisContent = html;
  636. },
  637. this.$editorTools.addVideoUpload(this, analysisEditor)
  638. this.$editorTools.addAudio(this, analysisEditor)
  639. this.$editorTools.addCanvas(this, analysisEditor)
  640. this.$editorTools.initMyEditor(analysisEditor)
  641. analysisEditor.create();
  642. this.analysisEditor = analysisEditor;
  643. },
  644. computed: {
  645. isSchool() {
  646. return this.$route.name === 'newSchoolExercise';
  647. },
  648. curScope() {
  649. return this.$route.name === 'newSchoolExercise' ? 'school' : 'private'
  650. },
  651. hasSchool() {
  652. let user = JSON.parse(
  653. decodeURIComponent(localStorage.user_profile, "utf-8")
  654. );
  655. return (
  656. user.schools &&
  657. user.schools.length &&
  658. user.schools.filter((i) => i.status === "join").length > 0
  659. );
  660. },
  661. },
  662. // 路由离开生命周期函数
  663. beforeRouteLeave(to, from, next) {
  664. if (this.isComplete) {
  665. next()
  666. } else {
  667. this.$Modal.confirm({
  668. title: this.$t('evaluation.newExercise.modalTip'),
  669. content: this.$t('evaluation.newExercise.unSaveTip'),
  670. onOk: () => {
  671. next();
  672. }
  673. });
  674. }
  675. },
  676. };
  677. </script>
  678. <style src="../index/CreateExercises.less" lang="less" scoped>
  679. /*@import"../index/CreateExercises.css";*/
  680. </style>
  681. <style>
  682. .related-point-modal .ivu-modal-header-inner {
  683. font-weight: bold;
  684. }
  685. .exersices-attr .ivu-select-multiple .ivu-tag {
  686. height: 32px;
  687. line-height: 31px;
  688. }
  689. .exersices-attr .ivu-select-multiple .ivu-tag i {
  690. top: 9px;
  691. }
  692. .exersices-attr .ivu-select-multiple .ivu-select-selection .ivu-select-placeholder {
  693. line-height: 38px;
  694. }
  695. /* 修改iview Modal样式 */
  696. .related-modal .ivu-modal-content {
  697. background: #3c3c3c;
  698. overflow: hidden;
  699. color: #fff;
  700. }
  701. .related-modal .ivu-modal-body {
  702. height: 400px;
  703. padding: 20px;
  704. }
  705. .related-modal .ivu-modal-body {
  706. height: 700px;
  707. }
  708. .related-modal .ivu-modal-header {
  709. border-bottom: none;
  710. font-size: 18px;
  711. font-weight: bold;
  712. padding: 25px;
  713. }
  714. .related-modal .modal-content {
  715. padding: 0 35px 30px 35px;
  716. }
  717. .related-modal .modal-btn {
  718. margin-left: 2%;
  719. width: 96%;
  720. height: 40px;
  721. background: rgb(11, 151, 117);
  722. border: none;
  723. color: #fff;
  724. margin-top: 30px;
  725. }
  726. .related-modal .choose-content {
  727. height: 85%;
  728. }
  729. </style>