Kaynağa Gözat

Merge branch 'master' of http://60.205.254.193:3000/GCLS/eep_page

dsy 16 saat önce
ebeveyn
işleme
eec2a64b4f

+ 24 - 0
src/api/book.js

@@ -234,3 +234,27 @@ export function PageQueryBookResourceList(data) {
 export function GetLanguageTypeList(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_manager-GetLanguageTypeList`, data);
 }
+
+/**
+ * @description 保存课件练习题
+ * @param {Object} data
+ */
+export function SaveCoursewareExercise(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_content_manager-SaveCoursewareExercise`, data);
+}
+
+/**
+ * @description 得到课件练习题
+ * @param {Object} data
+ */
+export function GetCoursewareExercise(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_content_manager-GetCoursewareExercise`, data);
+}
+
+/**
+ * @description 得到课件练习题(展示内容)
+ * @param {Object} data
+ */
+export function GetCoursewareExerciseView(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_content_manager-GetCoursewareExercise_View`, data);
+}

+ 1 - 1
src/views/book/courseware/create/components/common/ModuleMixin.js

@@ -69,7 +69,7 @@ const mixin = {
     content: {
       handler(newVal) {
         if (this.type !== 'interaction') return;
-        this.data = JSON.parse(newVal);
+        if(newVal) this.data = JSON.parse(newVal);
       },
       immediate: true,
     },

+ 143 - 7
src/views/book/courseware/create/components/question/video_interaction/ExerciseAdd.vue

@@ -1,21 +1,157 @@
 <template>
   <div class="Exercise-add">
-    <div class="main"></div>
+    <div class="type-box">
+      <span>题型</span
+      ><el-select v-model="typeValue" size="small">
+        <el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value" />
+      </el-select>
+    </div>
+    <div class="type-content">
+      <RichText
+        ref="richText"
+        v-model="title"
+        toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+        placeholder="输入标题"
+      />
+      <div class="type-content-inner">
+        <component
+          :is="getViewCom"
+          type="interaction"
+          :content="content"
+          ref="component"
+          :border-color="''"
+          id="1"
+          :component-move="componentMove"
+        />
+        <!-- <component :is="getSettingCom" ref="setting" /> -->
+      </div>
+    </div>
+    <footer style="text-align: right">
+      <el-button @click="handleCancle">取 消</el-button>
+      <el-button :loading="loading" type="primary" @click="submitAdd">确 定</el-button>
+    </footer>
   </div>
 </template>
 
 <script>
+import SelectPage from '@/views/book/courseware/create/components/question/select/Select.vue';
+import SelectSetting from '@/views/book/courseware/create/components/question/select/SelectSetting.vue';
+import Judge from '@/views/book/courseware/create/components/question/judge/Judge.vue';
+import JudgeSetting from '@/views/book/courseware/create/components/question/judge/JudgeSetting.vue';
+import RichText from '@/components/RichText.vue';
+import { SaveCoursewareExercise } from '@/api/book';
 export default {
   name: 'ExerciseAdd',
-  components: {},
-  props: [''],
+  components: { SelectPage, SelectSetting, Judge, JudgeSetting, RichText },
+  props: ['exerciseContent'],
   data() {
-    return {};
+    return {
+      typeList: [
+        {
+          label: '选择题',
+          value: 'select',
+        },
+        {
+          label: '判断题',
+          value: 'judge',
+        },
+      ],
+      typeValue: 'select',
+      title: '',
+      loading: false,
+      content: null,
+      exercise_id: '',
+    };
+  },
+  computed: {
+    getViewCom() {
+      switch (this.typeValue) {
+        case 'select':
+          return SelectPage;
+        case 'judge':
+          return Judge;
+      }
+    },
+    getSettingCom() {
+      switch (this.typeValue) {
+        case 'select':
+          return SelectSetting;
+        case 'judge':
+          return JudgeSetting;
+      }
+    },
   },
   // 生命周期 - 创建完成(可以访问当前this实例)
-  created() {},
-  methods: {},
+  created() {
+    if (this.exerciseContent) {
+      this.content = this.exerciseContent.content_exercise;
+      this.title = this.exerciseContent.content_title;
+      this.typeValue = this.exerciseContent.content_exercise
+        ? JSON.parse(this.exerciseContent.content_exercise).type
+        : 'select';
+      this.exercise_id = this.exerciseContent.exercise_id;
+    }
+  },
+  methods: {
+    componentMove() {},
+    submitAdd() {
+      this.loading = true;
+      let data = {
+        exercise_id: this.exercise_id,
+        courseware_id: this.$route.params.courseware_id,
+        content_title: this.title,
+        content_exercise: JSON.stringify(this.$refs.component.data),
+      };
+      SaveCoursewareExercise(data)
+        .then((res) => {
+          this.loading = false;
+          if (res.status === 1) {
+            this.$message.success('操作成功');
+            if (this.exercise_id) {
+              this.$emit('submitAdd');
+            } else {
+              this.$emit('submitAdd', res.exercise_id, this.typeList.find((p) => p.value === this.typeValue).label);
+            }
+          }
+        })
+        .catch(() => {
+          this.$emit('handleCancle');
+        });
+    },
+    handleCancle() {
+      this.$emit('handleCancle');
+    },
+  },
 };
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.type-box {
+  display: flex;
+  gap: 5px;
+  align-items: center;
+}
+
+.type-content {
+  margin: 5px 0;
+}
+
+.type-content-inner {
+  display: flex;
+  gap: 20px;
+  margin: 10px 0;
+
+  :deep .module-wrapper {
+    flex: 1;
+  }
+}
+
+:deep .module-icon {
+  display: none !important;
+}
+</style>
+<style lang="scss">
+.tox-tinymce-aux {
+  z-index: 9999 !important;
+}
+</style>

+ 64 - 11
src/views/book/courseware/create/components/question/video_interaction/VideoInteraction.vue

@@ -18,8 +18,8 @@
       />
       <div class="interaction-box" v-if="data.video_list.length > 0">
         <video id="interaction-video" :src="data.video_list[0].file_url" width="100%" height="400" controls></video>
-        <el-button type="primary" size="small" @click="handlePause">暂停视频上传文件</el-button>
-        <el-button @click="handleMultilingual">多语言</el-button>
+        <el-button type="primary" size="small" @click="handlePause">暂停视频编辑题目</el-button>
+        <!-- <el-button @click="handleMultilingual">多语言</el-button> -->
         <ul v-if="data.file_info_list.length > 0" class="file-list">
           <li v-for="(file, i) in data.file_info_list" :key="i">
             <div class="file-name">
@@ -28,12 +28,13 @@
                 <span>{{ file.file_name ?? file.name }}</span>
               </span>
             </div>
+            <SvgIcon icon-class="edit" size="12" @click="editFile(file, i)" />
             <SvgIcon icon-class="delete-black" size="12" @click="removeFile(file, i)" />
           </li>
         </ul>
       </div>
       <!-- 上传 -->
-      <el-dialog
+      <!-- <el-dialog
         :visible.sync="sourceAddFlag"
         width="500px"
         append-to-body
@@ -61,6 +62,24 @@
           <el-button @click="handleCancle">取 消</el-button>
           <el-button :loading="loading" type="primary" @click="submitAdd">确 定</el-button>
         </footer>
+      </el-dialog> -->
+      <!-- 编辑练习题题目 -->
+      <el-dialog
+        :visible.sync="exerciseFlag"
+        width="90%"
+        append-to-body
+        :show-close="true"
+        title="练习题"
+        :close-on-click-modal="false"
+        class="module-content"
+        @close="handleCancle"
+        v-if="exerciseFlag"
+      >
+        <exercise-add
+          :exerciseContent="exerciseContent"
+          @handleCancle="handleCancle"
+          @submitAdd="submitAdd"
+        ></exercise-add>
       </el-dialog>
       <MultilingualFill
         :visible.sync="multilingualVisible"
@@ -75,13 +94,15 @@
 <script>
 import ModuleMixin from '../../common/ModuleMixin';
 import UploadFile from '../../base/common/UploadFile.vue';
+import ExerciseAdd from './ExerciseAdd.vue';
 
 import { getVideoInteractionData } from '@/views/book/courseware/data/videoInteraction';
 import { GetFileURLMap } from '@/api/app';
+import { GetCoursewareExercise } from '@/api/book';
 
 export default {
   name: 'VideoInteractionPage',
-  components: { UploadFile },
+  components: { UploadFile, ExerciseAdd },
   mixins: [ModuleMixin],
   data() {
     return {
@@ -91,11 +112,13 @@ export default {
       uploadTip: '支持上传mp4格式视频文件,单个视频文件最大2GB,总文件体积不超10GB。',
       iconClass: 'video',
       sourceAddFlag: false,
+      exerciseFlag: false,
       file_list: [],
       file_id_list: [],
       loading: false,
       currentTime: 0,
       multilingualText: '',
+      exerciseContent: null,
     };
   },
   watch: {
@@ -151,13 +174,23 @@ export default {
       }
     },
     handleCancle() {
-      this.sourceAddFlag = false;
-      this.file_list = [];
-      this.file_id_list = [];
+      // this.sourceAddFlag = false;
+      this.exerciseFlag = false;
+      document.getElementById('interaction-video').play();
     },
     // 确定新增资源
-    submitAdd() {
-      this.loading = true;
+    submitAdd(id, type) {
+      if (id) {
+        this.data.file_info_list.push({
+          currentTime: this.currentTime,
+          file_name: type,
+          id: id,
+        });
+        this.file_id_list.push(id);
+      }
+
+      this.exerciseFlag = false;
+      document.getElementById('interaction-video').play();
     },
     // 暂停视频上传资源
     handlePause() {
@@ -166,17 +199,20 @@ export default {
       this.currentTime = video.currentTime.toFixed(3);
       this.file_list = [];
       this.file_id_list = [];
-      this.sourceAddFlag = true;
+      // this.sourceAddFlag = true;
+      this.exerciseContent = null;
+      this.exerciseFlag = true;
     },
     // 删除文件
     removeFile(file, i) {
-      this.$confirm('是否删除当前文件?', '提示', {
+      this.$confirm('是否删除当前题目?', '提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
         type: 'warning',
       })
         .then(() => {
           this.data.file_info_list.splice(i, 1);
+          this.file_id_list.splice(i, 1);
         })
         .catch(() => {});
     },
@@ -187,6 +223,23 @@ export default {
       });
       this.multilingualVisible = true;
     },
+    // 获取练习题题目
+    editFile(file) {
+      let data = {
+        exercise_id: file.id,
+        courseware_id: this.$route.params.courseware_id,
+      };
+      GetCoursewareExercise(data)
+        .then((res) => {
+          if (res.status === 1) {
+            this.exerciseContent = res;
+            this.exerciseFlag = true;
+          }
+        })
+        .catch(() => {
+          this.$emit('handleCancle');
+        });
+    },
   },
 };
 </script>

+ 88 - 0
src/views/book/courseware/preview/components/video_interaction/ExercisePreview.vue

@@ -0,0 +1,88 @@
+<template>
+  <div class="Exercise-preview" v-loading="loading">
+    <div class="type-content">
+      <div class="type-content-inner">
+        <div class="rich-text" v-html="sanitizeHTML(title)"></div>
+        <component :is="getViewCom" :content="content" ref="preview" />
+      </div>
+    </div>
+    <footer style="text-align: right">
+      <el-button @click="handleCancle">取 消</el-button>
+      <el-button :loading="loading" type="primary" @click="submitAdd">确 定</el-button>
+    </footer>
+  </div>
+</template>
+
+<script>
+import SelectPreview from '@/views/book/courseware/preview/components/select/SelectPreview.vue';
+import JudgePreview from '@/views/book/courseware/preview/components/judge/JudgePreview.vue';
+import { GetCoursewareExerciseView } from '@/api/book';
+import { sanitizeHTML } from '@/utils/common';
+export default {
+  name: 'ExercisePreview',
+  components: { SelectPreview, JudgePreview },
+  props: ['exercise_id'],
+  data() {
+    return {
+      sanitizeHTML,
+      typeValue: '',
+      title: '',
+      content: null,
+      loading: false,
+    };
+  },
+  computed: {
+    getViewCom() {
+      switch (this.typeValue) {
+        case 'select':
+          return SelectPreview;
+        case 'judge':
+          return JudgePreview;
+      }
+    },
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created() {
+    this.handleData();
+  },
+  methods: {
+    componentMove() {},
+
+    handleCancle() {
+      this.$emit('handleCancle');
+    },
+    submitAdd() {
+      this.$emit('submitAdd', this.exercise_id, this.$refs.preview.answer);
+    },
+    handleData() {
+      this.loading = true;
+      let data = {
+        exercise_id: this.exercise_id,
+        courseware_id: this.$route.params.id,
+      };
+      GetCoursewareExerciseView(data)
+        .then((res) => {
+          this.loading = false;
+          if (res.status === 1) {
+            this.content = res.content_exercise;
+            this.title = res.content_title;
+            this.typeValue = res.content_exercise ? JSON.parse(res.content_exercise).type : '';
+          }
+        })
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.type-content {
+  margin: 5px 0;
+}
+
+.type-content-inner {
+  width: 100%;
+}
+</style>

+ 18 - 17
src/views/book/courseware/preview/components/video_interaction/VideoInteractionPreview.vue

@@ -22,15 +22,16 @@
       :append-to-body="true"
       :lock-scroll="true"
       width="80%"
-      top="0"
       @close="handleClose"
     >
-      <iframe v-if="visible" :src="newpath" width="100%" :height="iframeHeight" frameborder="0"></iframe>
+      <ExercisePreview :exercise_id="exercise_id" @handleCancle="handleClose" @submitAdd="submitAdd"></ExercisePreview>
+      <!-- <iframe v-if="visible" :src="newpath" width="100%" :height="iframeHeight" frameborder="0"></iframe> -->
     </el-dialog>
   </div>
 </template>
 
 <script>
+import ExercisePreview from './ExercisePreview.vue';
 import PreviewMixin from '../common/PreviewMixin';
 import { getVideoInteractionData } from '@/views/book/courseware/data/videoInteraction';
 import { GetFileURLMap } from '@/api/app';
@@ -38,7 +39,7 @@ import { getConfig } from '@/utils/auth';
 export default {
   name: 'VideoInteractionPreview',
 
-  components: {},
+  components: { ExercisePreview },
   mixins: [PreviewMixin],
   data() {
     return {
@@ -49,6 +50,8 @@ export default {
       newpath: '',
       iframeHeight: `${window.innerHeight - 100}px`,
       first: '',
+      exercise_id: '',
+      userAnswer: {},
     };
   },
   watch: {},
@@ -58,14 +61,6 @@ export default {
   mounted() {},
   methods: {
     initData() {
-      if (!this.isJudgingRightWrong) {
-        this.answer.answer_list = [];
-        let obj = {
-          answer: '',
-        };
-        this.answer.answer_list.push(obj);
-      }
-
       this.data.video_list.forEach((item) => {
         GetFileURLMap({ file_id_list: [item.file_id] }).then(({ url_map }) => {
           this.video_info = url_map[item.file_id];
@@ -79,14 +74,16 @@ export default {
         if (
           Number(item.currentTime) > Math.floor(currentTime) &&
           Number(item.currentTime) < Math.floor(currentTime) + 1 &&
-          item.file_id !== this.first
+          item.id !== this.first
         ) {
-          this.first = item.file_id;
+          this.first = item.id;
           document.getElementById('interaction-preview-video').pause();
-          GetFileURLMap({ file_id_list: [item.file_id] }).then(({ url_map }) => {
-            this.newpath = `${this.file_preview_url}onlinePreview?url=${Base64.encode(url_map[item.file_id])}`;
-            this.visible = true;
-          });
+          this.exercise_id = item.id;
+          this.visible = true;
+          // GetFileURLMap({ file_id_list: [item.file_id] }).then(({ url_map }) => {
+          //   this.newpath = `${this.file_preview_url}onlinePreview?url=${Base64.encode(url_map[item.file_id])}`;
+          //   this.visible = true;
+          // });
         }
       });
     },
@@ -97,6 +94,10 @@ export default {
         this.first = '';
       }, 1000);
     },
+    submitAdd(id, answer) {
+      this.visible = false;
+      this.$set(this.userAnswer, id, answer);
+    },
   },
 };
 </script>