dusenyao 3 tahun lalu
induk
melakukan
0bbda10f11

+ 2 - 0
.env.development

@@ -3,3 +3,5 @@ ENV = 'development'
 
 # base api
 VUE_APP_BASE_API = '/api'
+
+VUE_APP_PDF = '/pdf'

+ 2 - 0
.env.production

@@ -3,3 +3,5 @@ ENV = 'production'
 
 # base api
 VUE_APP_BASE_API = ''
+
+VUE_APP_PDF = ''

+ 1 - 4
src/api/app.js

@@ -56,10 +56,7 @@ export function fileUpload(SecurityLevel, file) {
     },
     data: formData,
     onUploadProgress: progressEvent => {
-      store.commit(
-        `app/${app.SET_PERCENTAGE}`,
-        ((progressEvent.loaded / progressEvent.total) * 100) | 0
-      );
+      store.commit(`app/${app.SET_PERCENTAGE}`, ((progressEvent.loaded / progressEvent.total) * 100) | 0);
     }
   }).finally(() => {
     store.commit(`app/${app.SHOW_PROGRESS}`, false);

+ 15 - 0
src/api/course.js

@@ -542,3 +542,18 @@ export function CheckMyGoodsCollectionStatus(data) {
     data
   });
 }
+
+/**
+ * 得到资料信息
+ * @param {Object} data
+ */
+export function GetMaterialInfo(data) {
+  let params = getRequestParams('live_room-live_room_dispatch-GetMaterialInfo');
+
+  return request({
+    method: 'post',
+    url: process.env.VUE_APP_LearnWebSI,
+    params,
+    data
+  });
+}

+ 2 - 2
src/api/live.js

@@ -34,8 +34,8 @@ export function CloseLiveRoom(data) {
  * 得到直播间学员列表
  * @param {Object} data { task_id 任务ID }
  */
-export function GetLiveRoomStudentList(data) {
-  let params = getRequestParams('live_room-live_room_dispatch-GetLiveRoomStudentList');
+export function GetLiveRoomData_DRTD(data) {
+  let params = getRequestParams('live_room-live_room_dispatch-GetLiveRoomData_DRTD');
 
   return request({
     method: 'post',

+ 4 - 9
src/common/show_file/index.vue

@@ -1,10 +1,5 @@
 <template>
-  <el-dialog
-    class="show-file"
-    :visible="dialogVisibleShowFile"
-    width="900px"
-    @close="dialogShowFileClose"
-  >
+  <el-dialog class="show-file" :visible="dialogVisibleShowFile" width="900px" @close="dialogShowFileClose">
     <div slot="title">查看文件【{{ fileName }}】</div>
 
     <template v-if="fileType === 'pdf'">
@@ -79,11 +74,11 @@ export default {
   },
   methods: {
     getFileStoreInfo() {
-      GetFileStoreInfo({ file_id: this.fileId }).then(({ file_url_https }) => {
+      GetFileStoreInfo({ file_id: this.fileId }).then(({ file_url_https, file_relative_path }) => {
         this.fileUrl = file_url_https;
 
         if (this.fileType === 'pdf') {
-          this.getNumPages(file_url_https);
+          this.getNumPages(file_relative_path);
         }
 
         if (this.fileType === 'txt') {
@@ -94,7 +89,7 @@ export default {
     },
 
     getNumPages(url) {
-      let loadingTask = pdf.createLoadingTask(url);
+      let loadingTask = pdf.createLoadingTask(`${process.env.VUE_APP_PDF}${url}`);
       loadingTask.promise
         .then(pdf => {
           this.pdfSrc = loadingTask;

+ 217 - 90
src/components/live/CurMaterial.vue

@@ -1,37 +1,54 @@
 <template>
   <el-dialog
     :class="['cur-material', { 'align-left': !isAlignCenter }]"
-    :visible="dialogVisibleMaterial"
+    :visible="visible"
     :modal="false"
     width="900px"
     @close="dialogMaterialClose"
   >
     <div slot="title" class="dialog-header">
-      <span class="dialog-header-title">当前推送资料</span>
+      <span class="dialog-header-title">
+        {{
+          isCurMaterial
+            ? `当前推送资料 - ${material_name}`
+            : `学习资料 - ${material_type === 'COURSEWARE' ? '课件' : '文档'} - ${material_name}`
+        }}
+      </span>
       <span @click="isAlignCenter = !isAlignCenter">
         <svg-icon :icon-class="isAlignCenter ? 'align-left' : 'align-center'" />
       </span>
     </div>
 
-    <div class="material-name">{{ materialName }}</div>
-
-    <template v-if="materialType === 'COURSEWARE'">
-      <bookquestion
-        v-if="sys_type === 'GCLS'"
-        ref="courseware"
-        :context="context"
-        @handleBookUserAnswer="handleBookUserAnswer"
-      />
-
-      <bookailp
-        v-else
-        :context="context"
-        :ui-type="ui_type"
-        :preview-width="850"
-        :preview-height="478"
-        @handleBookUserAnswer="handleBookUserAnswer"
-      />
+    <div v-show="!isCurMaterial && material_type === 'COURSEWARE'" class="answer-data">
+      <span>用时</span>
+      <span class="answer-data-duration">{{ answerData.duration }}秒</span>
+      <span class="answer-data-label">正确</span>
+      <span class="answer-data-count-right">{{ answerData.count_right }}</span>
+      <span class="answer-data-label">错误</span>
+      <span class="answer-data-count-error">{{ answerData.count_error }}</span>
+    </div>
+
+    <template v-if="material_type === 'COURSEWARE' && visible">
+      <template v-if="sys_type === 'GCLS'">
+        <bookreport
+          v-if="isStudent"
+          :context="context"
+          :book-client-width="800"
+          :book-answer-content="bookAnswerContent"
+        />
+        <bookquestion v-else ref="courseware" :context="context" @handleBookUserAnswer="handleBookUserAnswer" />
+      </template>
+      <template v-else>
+        <bookailp
+          :context="context"
+          :ui-type="ui_type"
+          :preview-width="800"
+          :preview-height="450"
+          @handleBookUserAnswer="handleBookUserAnswer"
+        />
+      </template>
     </template>
+
     <template v-else>
       <template v-if="fileType === 'pdf'">
         <pdf v-for="i in numPages" :key="i" :src="pdfSrc" :page="i" />
@@ -52,16 +69,22 @@
     </template>
 
     <div slot="footer">
-      <el-button type="primary" @click="finishMyMaterial">完成</el-button>
+      <el-button
+        v-if="isCurMaterial || (!isFinished && material_type === 'COURSEWARE')"
+        type="primary"
+        @click="finishMyMaterial"
+      >
+        完成
+      </el-button>
     </div>
   </el-dialog>
 </template>
 
 <script>
 import pdf from 'vue-pdf';
-import { GetCoursewareContent_View } from '@/api/course';
+import { GetCoursewareContent_View, GetMaterialInfo } from '@/api/course';
 import { GetFileStoreInfo, getContentFile } from '@/api/app';
-import { FinishMyMaterial } from '@/api/live';
+import { FinishMyMaterial, GetCurMaterialSent, GetStudentExamAnswer_FinishMaterial } from '@/api/live';
 import { getToken } from '@/utils/auth';
 
 export default {
@@ -69,10 +92,6 @@ export default {
     pdf
   },
   props: {
-    dialogVisibleMaterial: {
-      default: false,
-      type: Boolean
-    },
     taskId: {
       default: '',
       type: String
@@ -81,21 +100,22 @@ export default {
       default: '',
       type: String
     },
-    materialName: {
-      default: '',
-      type: String
-    },
     materialType: {
       default: '',
       type: String
     },
-    materialPictureUrl: {
-      default: '',
-      type: String
+    isFinished: {
+      default: false,
+      type: Boolean
     }
   },
   data() {
     return {
+      visible: false,
+      material_id: '',
+      material_name: '',
+      material_type: '',
+      material_picture_url: '',
       context: null,
       exam_answer: '',
       ui_type: '',
@@ -104,19 +124,33 @@ export default {
       file_url_https: '',
       pdfSrc: '',
       numPages: 1,
-      isAlignCenter: true
+      curStudentID: '',
+      bookAnswerContent: '',
+      isAlignCenter: true,
+      timer: null,
+      isCurMaterial: true,
+      answerData: {
+        duration: 0,
+        count_not_done: 0,
+        count_right: 0,
+        count_error: 0
+      }
     };
   },
   computed: {
     fileType() {
-      return this.file_url_https.slice(
-        this.file_url_https.lastIndexOf('.') + 1,
-        this.file_url_https.length
-      );
+      return this.file_url_https.slice(this.file_url_https.lastIndexOf('.') + 1, this.file_url_https.length);
+    },
+    isStudent() {
+      return this.curStudentID.length > 0;
     }
   },
   watch: {
-    dialogVisibleMaterial(newVal) {
+    visible(newVal) {
+      if (newVal && !this.isCurMaterial) {
+        this.getMaterialInfo();
+      }
+
       if (!newVal) {
         this.context = null;
         this.exam_answer = '';
@@ -124,10 +158,17 @@ export default {
         this.file_url_https = '';
         this.pdfSrc = '';
         this.numPages = 1;
+        this.curStudentID = '';
+        this.material_id = '';
+        this.material_name = '';
+        this.material_type = '';
+        this.material_picture_url = '';
       }
     },
-    materialId() {
-      if (this.materialType === 'COURSEWARE') {
+
+    material_id(newVal) {
+      if (newVal.length === 0) return;
+      if (this.material_type === 'COURSEWARE') {
         this.getCoursewareContent_View();
       } else {
         this.getFileStoreInfo();
@@ -136,55 +177,119 @@ export default {
   },
   created() {
     this.uploadBookWriteParent();
+    this.getCurMaterialSent();
+  },
+  beforeDestroy() {
+    clearInterval(this.timer);
   },
   methods: {
+    dialogShow() {
+      this.isCurMaterial = false;
+      this.visible = true;
+    },
+
     dialogMaterialClose() {
+      this.visible = false;
+      if (!this.timer) this.getCurMaterialSent();
       this.$emit('dialogMaterialClose');
     },
 
-    getCoursewareContent_View() {
-      GetCoursewareContent_View({ id: this.materialId }).then(({ content }) => {
-        if (content) {
-          if (this.sys_type === 'GCLS') {
-            this.context = {
-              id: this.materialId,
-              ui_type: JSON.parse(content).question.ui_type,
-              content: JSON.parse(content)
-            };
-            this.$nextTick(() => {
-              this.$refs.courseware.handleAnswerTimeStart();
-            });
-          } else {
-            const contents = JSON.parse(content);
-            if (contents.question && contents.question.length > 0) {
-              this.context = JSON.parse(contents.question);
-              this.ui_type = contents.ui_type ? contents.ui_type : '';
+    getCurMaterialSent() {
+      this.timer = setInterval(() => {
+        GetCurMaterialSent({ task_id: this.taskId }).then(
+          ({ material_id, material_name, material_type, material_picture_url }) => {
+            if (material_id !== undefined && material_id.length > 0) {
+              this.visible = true;
+
+              this.isCurMaterial = true;
+              this.material_id = material_id;
+              this.material_name = material_name;
+              this.material_type = material_type;
+              this.material_picture_url = material_picture_url;
+              clearInterval(this.timer);
+              this.timer = null;
+              this.curStudentID = '-';
+              this.$nextTick(() => {
+                this.curStudentID = '';
+              });
             }
           }
-        } else {
-          this.context = null;
+        );
+      }, 2000);
+    },
+
+    getMaterialInfo() {
+      GetMaterialInfo({ task_id: this.taskId, material_id: this.materialId, material_type: this.materialType }).then(
+        ({ material_id, material_name, material_type }) => {
+          this.material_id = material_id;
+          this.material_name = material_name;
+          this.material_type = material_type;
         }
-      });
+      );
     },
 
-    getFileStoreInfo() {
-      GetFileStoreInfo({ file_id: this.materialId }).then(
-        ({ file_relative_path, file_url_https }) => {
-          this.file_relative_path = file_relative_path;
-          this.file_url_https = file_url_https;
-          let fileType = file_url_https.slice(
-            file_url_https.lastIndexOf('.') + 1,
-            file_url_https.length
-          );
-          if (fileType === 'pdf') {
-            this.getNumPages(file_url_https);
+    getCoursewareContent_View() {
+      GetCoursewareContent_View({ id: this.material_id })
+        .then(({ content }) => {
+          if (content) {
+            if (this.sys_type === 'GCLS') {
+              this.context = {
+                id: this.material_id,
+                ui_type: JSON.parse(content).question.ui_type,
+                content: JSON.parse(content)
+              };
+              this.$nextTick(() => {
+                this.$refs.courseware.handleAnswerTimeStart();
+              });
+            } else {
+              const contents = JSON.parse(content);
+              if (contents.question && contents.question.length > 0) {
+                this.context = JSON.parse(contents.question);
+                this.ui_type = contents.ui_type ? contents.ui_type : '';
+              }
+            }
+          } else {
+            this.context = null;
+          }
+        })
+        .then(() => {
+          if (this.isFinished && !this.isCurMaterial) {
+            this.getStudentExamAnswer_FinishMaterial();
           }
+        });
+    },
+
+    getFileStoreInfo() {
+      GetFileStoreInfo({ file_id: this.material_id }).then(({ file_relative_path, file_url_https }) => {
+        this.file_relative_path = file_relative_path;
+        this.file_url_https = file_url_https;
+        let fileType = file_url_https.slice(file_url_https.lastIndexOf('.') + 1, file_url_https.length);
+        if (fileType === 'pdf') {
+          this.getNumPages(file_relative_path);
         }
-      );
+      });
+    },
+
+    getStudentExamAnswer_FinishMaterial() {
+      let student_id = this.$store.state.user.user_code;
+      GetStudentExamAnswer_FinishMaterial({
+        task_id: this.taskId,
+        material_id: this.material_id,
+        material_type: this.material_type,
+        student_id
+      }).then(({ content, duration, count_not_done, count_right, count_error }) => {
+        this.bookAnswerContent = content;
+        this.answerData = { duration, count_not_done, count_right, count_error };
+
+        this.curStudentID = '';
+        this.$nextTick(() => {
+          this.curStudentID = student_id;
+        });
+      });
     },
 
     getNumPages(url) {
-      let loadingTask = pdf.createLoadingTask(url);
+      let loadingTask = pdf.createLoadingTask(`${process.env.VUE_APP_PDF}${url}`);
       loadingTask.promise
         .then(pdf => {
           this.pdfSrc = loadingTask;
@@ -201,24 +306,20 @@ export default {
     },
 
     finishMyMaterial() {
-      if (
-        this.materialType === 'COURSEWARE' &&
-        this.exam_answer.length === 0 &&
-        this.sys_type === 'GCLS'
-      ) {
+      if (this.material_type === 'COURSEWARE' && this.exam_answer.length === 0 && this.sys_type === 'GCLS') {
         this.$message.warning('请完成课件');
         return;
       }
       const loading = this.$loading();
       FinishMyMaterial({
         task_id: this.taskId,
-        material_id: this.materialId,
-        material_type: this.materialType,
+        material_id: this.material_id,
+        material_type: this.material_type,
         exam_answer: this.exam_answer
       })
         .then(() => {
-          this.$message.success('完成推送资料成功');
-          this.$emit('dialogMaterialClose');
+          this.$message.success(`完成${this.isCurMaterial ? '推送' : ''}资料成功`);
+          this.dialogMaterialClose();
         })
         .finally(() => {
           loading.close();
@@ -281,7 +382,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .cur-material {
   @include dialog;
@@ -299,8 +400,8 @@ export default {
       padding-right: 24px;
 
       &-title {
-        font-weight: bold;
         font-size: 18px;
+        font-weight: bold;
         line-height: 24px;
       }
 
@@ -310,11 +411,37 @@ export default {
     }
   }
 
-  .material-name {
+  .answer-data {
+    display: flex;
+    align-items: center;
+    margin-bottom: 12px;
     font-size: 16px;
-    font-weight: 700;
-    color: #000;
-    margin-bottom: 16px;
+
+    &-label {
+      margin-left: 24px;
+    }
+
+    &-duration,
+    &-count-right,
+    &-count-error {
+      min-width: 60px;
+      padding: 0 24px;
+      text-align: center;
+      border-right: 2px solid #dfdfdf;
+    }
+
+    &-count-error {
+      border-right-width: 0;
+    }
+  }
+
+  .el-dialog__body {
+    height: 60vh;
+
+    .el-image {
+      width: 100%;
+      height: calc(100% - 4px);
+    }
   }
 }
 </style>

+ 7 - 10
src/components/live/SelectMaterial.vue

@@ -3,6 +3,7 @@
     <el-dialog
       class="select-material"
       :visible="dialogVisible"
+      top="10vh"
       width="900px"
       title="学习资料推送"
       @close="dialogClose"
@@ -71,21 +72,17 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 $list-h: 120px;
 
 .select-material {
   @include dialog;
 
-  .el-dialog__body {
-    overflow-y: auto;
-  }
-
   .material {
     display: flex;
-    border: 1px solid #d9d9d9;
     padding: 16px;
     margin-bottom: 16px;
+    border: 1px solid #d9d9d9;
 
     .el-image {
       width: 192px;
@@ -93,12 +90,12 @@ $list-h: 120px;
     }
 
     &-info {
-      flex: 6;
-      height: $list-h;
-      margin-left: 16px;
       display: flex;
+      flex: 6;
       flex-direction: column;
       justify-content: space-between;
+      height: $list-h;
+      margin-left: 16px;
 
       &-name {
         font-size: 18px;
@@ -106,9 +103,9 @@ $list-h: 120px;
       }
 
       &-push {
-        width: 100%;
         display: flex;
         justify-content: space-between;
+        width: 100%;
       }
     }
   }

+ 4 - 0
src/icons/svg/word.svg

@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M19.5 3H4.5C3.67157 3 3 3.67157 3 4.5V19.5C3 20.3284 3.67157 21 4.5 21H19.5C20.3284 21 21 20.3284 21 19.5V4.5C21 3.67157 20.3284 3 19.5 3Z" stroke="#2A99FF" stroke-width="1.5"/>
+<path d="M7 8L9 16L12 9.5L15 16L17 8" stroke="#2A99FF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 0 - 1
src/utils/request.js

@@ -4,7 +4,6 @@ import { Message } from 'element-ui';
 import { getToken } from '@/utils/auth';
 
 axios.defaults.withCredentials = true; // 跨域请求时是否需要使用凭证
-axios.defaults.dataType = 'json';
 axios.defaults.headers['cache-control'] = 'no-cache';
 axios.defaults.headers['Content-Type'] = 'application/json';
 axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest';

+ 3 - 6
src/views/live/SelectDevice.vue

@@ -68,11 +68,8 @@ export default {
     dialogVisibleDevice(newValue) {
       if (newValue) {
         let device = this.$store.state.app.liveDevice;
-        this.video =
-          this.device.video.length === 0 ? '' : this.selectValue(this.device.video, device.video);
-
-        this.audio =
-          this.device.audio.length === 0 ? '' : this.selectValue(this.device.audio, device.audio);
+        this.video = this.device.video.length === 0 ? '' : this.selectValue(this.device.video, device.video);
+        this.audio = this.device.audio.length === 0 ? '' : this.selectValue(this.device.audio, device.audio);
       }
     }
   },
@@ -96,8 +93,8 @@ export default {
   }
 
   .title {
-    font-weight: bold;
     margin-bottom: 12px;
+    font-weight: bold;
   }
 
   &-video,

+ 70 - 41
src/views/live/student/index.vue

@@ -108,6 +108,23 @@
       </div>
     </div>
 
+    <!-- 推送资料列表 -->
+    <div class="material-list">
+      <el-tag
+        v-for="item in material_list"
+        :key="item.material_id"
+        color="#fff"
+        @click="showMaterial(item.material_id, item.material_type, item.is_finished)"
+      >
+        <svg-icon :icon-class="item.material_type === 'COURSEWARE' ? 'courseware' : 'word'" /> {{ item.material_name }}
+        <svg-icon
+          v-if="item.is_finished === 'true' && item.material_type === 'COURSEWARE'"
+          class="check-mark"
+          icon-class="check-mark"
+        />
+      </el-tag>
+    </div>
+
     <!-- 学员列表 -->
     <div class="student-list">
       <div class="student-list-title">
@@ -133,12 +150,11 @@
 
     <!-- 学员当前推送资料 -->
     <cur-material
+      ref="material"
       :task-id="task_id"
-      :dialog-visible-material="dialogVisibleMaterial"
-      :material-id="material_id"
-      :material-name="material_name"
-      :material-type="material_type"
-      :material-picture-url="material_picture_url"
+      :material-id="materialId"
+      :material-type="materialType"
+      :is-finished="is_finished"
       @dialogMaterialClose="dialogMaterialClose"
     />
 
@@ -153,9 +169,8 @@
 
 <script>
 import {
-  GetLiveRoomStudentList,
+  GetLiveRoomData_DRTD,
   StudentExitLiveRoom,
-  GetCurMaterialSent,
   GetLiveRoomInfo,
   GetGroupStatus,
   CreateEnterLiveRoomSession,
@@ -185,12 +200,6 @@ export default {
       connection_mode: 1,
       // 等待接通
       callLoading: false,
-      dialogVisibleMaterial: false,
-      // 资料信息
-      material_id: '',
-      material_name: '',
-      material_type: '',
-      material_picture_url: '',
       // 定时器
       timer: null,
       timer_group: null,
@@ -236,7 +245,11 @@ export default {
       device: {
         video: [],
         audio: []
-      }
+      },
+      material_list: [],
+      materialId: '',
+      materialType: '',
+      is_finished: false
     };
   },
   computed: {
@@ -290,7 +303,7 @@ export default {
           text: '加载直播所需SDK中...',
           background: '#fff'
         });
-        this.getLiveRoomStudentList();
+        this.getLiveRoomData_DRTD();
         this.getLiveRoomInfo();
 
         CreateEnterLiveRoomSession({
@@ -308,8 +321,7 @@ export default {
     });
   },
   mounted() {
-    this.getCurMaterialSent();
-    this.getLiveRoomStudentListPolling();
+    this.getLiveRoomData_DRTDPolling();
     this.GetGroupStatus();
   },
   beforeDestroy() {
@@ -402,7 +414,7 @@ export default {
         deal_mode,
         connection_mode
       }).then(() => {
-        this.getLiveRoomStudentList();
+        this.getLiveRoomData_DRTD();
       });
     },
 
@@ -449,15 +461,16 @@ export default {
       });
     },
 
-    getLiveRoomStudentList() {
-      GetLiveRoomStudentList({ task_id: this.task_id }).then(({ student_list }) => {
+    getLiveRoomData_DRTD() {
+      GetLiveRoomData_DRTD({ task_id: this.task_id }).then(({ student_list, material_list }) => {
         this.student_list = student_list;
+        this.material_list = material_list;
       });
     },
 
-    getLiveRoomStudentListPolling() {
+    getLiveRoomData_DRTDPolling() {
       this.timer = setInterval(() => {
-        this.getLiveRoomStudentList();
+        this.getLiveRoomData_DRTD();
       }, 5000);
     },
 
@@ -498,27 +511,17 @@ export default {
       return dom.msRequestFullscreen();
     },
 
-    // 弹出框方法
-    dialogMaterialClose() {
-      this.dialogVisibleMaterial = false;
-      this.getCurMaterialSent();
+    showMaterial(id, type, is_finished) {
+      this.materialId = id;
+      this.materialType = type;
+      this.is_finished = is_finished === 'true';
+      this.$refs.material.dialogShow();
     },
 
-    getCurMaterialSent() {
-      const timer = setInterval(() => {
-        GetCurMaterialSent({ task_id: this.task_id }).then(
-          ({ material_id, material_name, material_type, material_picture_url }) => {
-            if (material_id !== undefined && material_id.length > 0) {
-              this.dialogVisibleMaterial = true;
-              this.material_id = material_id;
-              this.material_name = material_name;
-              this.material_type = material_type;
-              this.material_picture_url = material_picture_url;
-              clearInterval(timer);
-            }
-          }
-        );
-      }, 2000);
+    dialogMaterialClose() {
+      this.materialId = '';
+      this.materialType = '';
+      this.is_finished = false;
     }
   }
 };
@@ -804,6 +807,32 @@ $draw-h: 520px;
     }
   }
 
+  .material-list {
+    padding: 12px;
+    background-color: #fff;
+    border-bottom: 1px solid #ccc;
+
+    .el-tag {
+      padding: 0 20px;
+      margin: 0 0 8px 12px;
+      color: $color;
+      cursor: pointer;
+      border-color: #e5e5e5;
+
+      .svg-icon {
+        margin-right: 8px;
+        font-size: 18px;
+      }
+
+      .check-mark {
+        position: relative;
+        top: 2px;
+        right: -20px;
+        margin-left: 12px;
+      }
+    }
+  }
+
   // 学员列表
   .student-list {
     width: 100%;

+ 1 - 1
src/views/live/student/live.js

@@ -165,7 +165,7 @@ export function initListener(vue) {
   // 房间全量信息事件(人员进出时广播)
   rtc.on('room_context', roomData => {
     vue.roomContext = JSON.parse(roomData);
-    vue.getLiveRoomStudentList();
+    vue.getLiveRoomData_DRTD();
     console.log('房间全量信息事件(人员进出时广播)', JSON.parse(roomData));
   });
 

+ 65 - 57
src/views/live/teacher/CompleteList.vue

@@ -29,9 +29,7 @@
               <el-avatar
                 icon="el-icon-user"
                 :src="item.student_image_url"
-                @click.native="
-                  getStudentExamAnswer_FinishMaterial(item.student_id, item.student_name)
-                "
+                @click.native="getStudentExamAnswer_FinishMaterial(item.student_id, item.student_name)"
               />
             </span>
           </div>
@@ -40,12 +38,14 @@
       </div>
       <div v-show="isStudent" class="answer-info">
         <span class="current-student-name">{{ curStudentName }}:</span>
-        <span>用时</span>
-        <span class="answer-info-duration">{{ duration }}秒</span>
-        <span class="answer-info-label">正确</span>
-        <span class="answer-info-count-right">{{ count_right }}</span>
-        <span class="answer-info-label">错误</span>
-        <span class="answer-info-count-error">{{ count_error }}</span>
+        <template v-if="material_type === 'COURSEWARE'">
+          <span>用时</span>
+          <span class="answer-info-duration">{{ duration }}秒</span>
+          <span class="answer-info-label">正确</span>
+          <span class="answer-info-count-right">{{ count_right }}</span>
+          <span class="answer-info-label">错误</span>
+          <span class="answer-info-count-error">{{ count_error }}</span>
+        </template>
       </div>
     </div>
 
@@ -61,12 +61,7 @@
           <bookquestion v-else :context="context" />
         </template>
         <template v-else>
-          <bookailp
-            :context="context"
-            :ui-type="ui_type"
-            :preview-width="800"
-            :preview-height="450"
-          />
+          <bookailp :context="context" :ui-type="ui_type" :preview-width="800" :preview-height="450" />
         </template>
       </template>
       <template v-else>
@@ -97,12 +92,8 @@
 
 <script>
 import pdf from 'vue-pdf';
-import {
-  GetCurMaterialSent,
-  GetStudentList_FinishMaterial,
-  GetStudentExamAnswer_FinishMaterial
-} from '@/api/live';
-import { GetCoursewareContent_View } from '@/api/course';
+import { GetCurMaterialSent, GetStudentList_FinishMaterial, GetStudentExamAnswer_FinishMaterial } from '@/api/live';
+import { GetCoursewareContent_View, GetMaterialInfo } from '@/api/course';
 import { GetFileStoreInfo, getContentFile } from '@/api/app';
 
 export default {
@@ -117,6 +108,14 @@ export default {
     taskId: {
       default: '',
       type: String
+    },
+    materialId: {
+      default: '',
+      type: String
+    },
+    materialType: {
+      default: '',
+      type: String
     }
   },
   data() {
@@ -147,10 +146,7 @@ export default {
   },
   computed: {
     fileType() {
-      return this.file_url_https.slice(
-        this.file_url_https.lastIndexOf('.') + 1,
-        this.file_url_https.length
-      );
+      return this.file_url_https.slice(this.file_url_https.lastIndexOf('.') + 1, this.file_url_https.length);
     },
     isStudent() {
       return this.curStudentID.length > 0;
@@ -158,10 +154,16 @@ export default {
   },
   watch: {
     dialogVisibleComplete(newVal) {
-      if (newVal) {
+      if (newVal && this.materialId.length === 0) {
         this.getCurMaterialSent();
-      } else {
-        // 对话框,关闭时清理
+      }
+
+      if (newVal && this.materialId.length > 0) {
+        this.getMaterialInfo();
+      }
+
+      // 对话框,关闭时清理
+      if (!newVal) {
         clearInterval(this.listTimer);
         this.material_id = '';
         this.material_name = '';
@@ -172,6 +174,7 @@ export default {
         this.bookAnswerContent = '';
       }
     },
+
     material_id(newVal) {
       if (newVal) {
         this.listTimer = setInterval(() => {
@@ -200,6 +203,16 @@ export default {
       );
     },
 
+    getMaterialInfo() {
+      GetMaterialInfo({ task_id: this.taskId, material_id: this.materialId, material_type: this.materialType }).then(
+        ({ material_id, material_name, material_type }) => {
+          this.material_id = material_id;
+          this.material_name = material_name;
+          this.material_type = material_type;
+        }
+      );
+    },
+
     getStudentList_FinishMaterial() {
       GetStudentList_FinishMaterial({
         task_id: this.taskId,
@@ -219,7 +232,7 @@ export default {
         if (content) {
           if (this.sys_type === 'GCLS') {
             this.context = {
-              id: this.currentCourse,
+              id: this.material_id,
               ui_type: JSON.parse(content).question.ui_type,
               content: JSON.parse(content)
             };
@@ -237,23 +250,18 @@ export default {
     },
 
     getFileStoreInfo() {
-      GetFileStoreInfo({ file_id: this.material_id }).then(
-        ({ file_relative_path, file_url_https }) => {
-          this.file_relative_path = file_relative_path;
-          this.file_url_https = file_url_https;
-          let fileType = file_url_https.slice(
-            file_url_https.lastIndexOf('.') + 1,
-            file_url_https.length
-          );
-          if (fileType === 'pdf') {
-            this.getNumPages(file_url_https);
-          }
+      GetFileStoreInfo({ file_id: this.material_id }).then(({ file_relative_path, file_url_https }) => {
+        this.file_relative_path = file_relative_path;
+        this.file_url_https = file_url_https;
+        let fileType = file_url_https.slice(file_url_https.lastIndexOf('.') + 1, file_url_https.length);
+        if (fileType === 'pdf') {
+          this.getNumPages(file_relative_path);
         }
-      );
+      });
     },
 
     getNumPages(url) {
-      let loadingTask = pdf.createLoadingTask(url);
+      let loadingTask = pdf.createLoadingTask(`${process.env.VUE_APP_PDF}${url}`);
       loadingTask.promise
         .then(pdf => {
           this.pdfSrc = loadingTask;
@@ -321,7 +329,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .complete-list {
   @include dialog;
@@ -339,8 +347,8 @@ export default {
       padding-right: 24px;
 
       &-title {
-        font-weight: bold;
         font-size: 18px;
+        font-weight: bold;
         line-height: 24px;
       }
 
@@ -353,11 +361,11 @@ export default {
   &-top {
     .student-list {
       display: flex;
+      align-items: center;
       justify-content: space-between;
       height: 66px;
-      align-items: center;
-      overflow: hidden;
       margin-bottom: 12px;
+      overflow: hidden;
 
       .avatar-list {
         width: calc(100% - 48px);
@@ -369,33 +377,33 @@ export default {
           white-space: nowrap;
 
           .active {
-            display: inline-block;
             position: relative;
+            display: inline-block;
             width: 58px;
 
             &::after {
-              content: '';
+              position: absolute;
+              top: 58px;
+              left: 24px;
               display: inline-block;
-              height: 8px;
               width: 8px;
+              height: 8px;
+              content: '';
               background-color: #2ece5b;
               border-radius: 50%;
-              position: absolute;
-              top: 58px;
-              left: 24px;
             }
           }
 
           .el-avatar {
-            cursor: pointer;
             margin: 0 9px;
+            cursor: pointer;
           }
         }
       }
 
       > i {
-        font-size: 18px;
         margin-top: -24px;
+        font-size: 18px;
         cursor: pointer;
       }
     }
@@ -403,12 +411,12 @@ export default {
     .answer-info {
       display: flex;
       align-items: center;
-      font-size: 16px;
       margin-bottom: 12px;
+      font-size: 16px;
 
       .current-student-name {
-        font-weight: 700;
         margin-right: 24px;
+        font-weight: 700;
       }
 
       &-label {
@@ -431,8 +439,8 @@ export default {
   }
 
   &-container {
-    overflow: auto;
     height: calc(55vh - 117px);
+    overflow: auto;
 
     .el-image {
       width: 100%;

+ 58 - 12
src/views/live/teacher/index.vue

@@ -144,6 +144,18 @@
       </div>
     </div>
 
+    <!-- 推送资料列表 -->
+    <div class="material-list">
+      <el-tag
+        v-for="item in material_list"
+        :key="item.material_id"
+        color="#fff"
+        @click="showMaterial(item.material_id, item.material_type)"
+      >
+        <svg-icon :icon-class="item.material_type === 'COURSEWARE' ? 'courseware' : 'word'" /> {{ item.material_name }}
+      </el-tag>
+    </div>
+
     <!-- 学员列表 -->
     <div class="student-list">
       <div class="student-list-title">
@@ -200,6 +212,8 @@
     <!-- 教师查看当前完成列表 -->
     <complete-list
       :task-id="task_id"
+      :material-id="materialId"
+      :material-type="materialType"
       :dialog-visible-complete="dialogVisibleComplete"
       @dialogCompleteClose="dialogCompleteClose"
     />
@@ -232,7 +246,7 @@
 
 <script>
 import {
-  GetLiveRoomStudentList,
+  GetLiveRoomData_DRTD,
   CloseLiveRoom,
   GetLiveRoomInfo,
   StudentExitLiveRoom,
@@ -321,7 +335,10 @@ export default {
       },
       // 本地视频流画面、声音
       hasVideo: false,
-      hasAudio: false
+      hasAudio: false,
+      material_list: [],
+      materialId: '',
+      materialType: ''
     };
   },
   computed: {
@@ -377,7 +394,7 @@ export default {
           background: '#fff'
         });
         common.downloadWebSDK(this);
-        this.getLiveRoomStudentList();
+        this.getLiveRoomData_DRTD();
         this.getLiveRoomInfo();
       }
     });
@@ -404,7 +421,7 @@ export default {
       },
       true
     );
-    this.getLiveRoomStudentListPolling();
+    this.getLiveRoomData_DRTDPolling();
   },
   beforeDestroy() {
     clearInterval(this.timer);
@@ -554,7 +571,7 @@ export default {
         deal_mode,
         connection_mode
       }).then(() => {
-        this.getLiveRoomStudentList();
+        this.getLiveRoomData_DRTD();
       });
     },
 
@@ -722,15 +739,16 @@ export default {
       this.isDrawSetting = !this.isDrawSetting;
     },
 
-    getLiveRoomStudentList() {
-      GetLiveRoomStudentList({ task_id: this.task_id }).then(({ student_list }) => {
+    getLiveRoomData_DRTD() {
+      GetLiveRoomData_DRTD({ task_id: this.task_id }).then(({ student_list, material_list }) => {
         this.student_list = student_list;
+        this.material_list = material_list;
       });
     },
 
-    getLiveRoomStudentListPolling() {
+    getLiveRoomData_DRTDPolling() {
       this.timer = setInterval(() => {
-        this.getLiveRoomStudentList();
+        this.getLiveRoomData_DRTD();
       }, 5000);
     },
 
@@ -750,6 +768,12 @@ export default {
       this.dialogVisibleGroup = true;
     },
 
+    showMaterial(id, type) {
+      this.materialId = id;
+      this.materialType = type;
+      this.dialogVisibleComplete = true;
+    },
+
     // 弹出框方法
     dialogGroup() {
       const loading = this.$loading({
@@ -788,6 +812,8 @@ export default {
 
     dialogCompleteClose() {
       this.dialogVisibleComplete = false;
+      this.materialId = '';
+      this.materialType = '';
     }
   }
 };
@@ -946,7 +972,7 @@ $draw-h: 520px;
             text-align: center;
           }
 
-          & > span.brush-shape {
+          > span.brush-shape {
             width: 28px;
             height: 28px;
             cursor: pointer;
@@ -990,7 +1016,8 @@ $draw-h: 520px;
             }
           }
 
-          > .brush-clear {
+          > %brush-clear,
+          .brush-clear {
             width: 28px;
             height: 28px;
             margin-right: 0;
@@ -1000,7 +1027,7 @@ $draw-h: 520px;
           }
 
           > .eraser {
-            @extend .brush-clear;
+            @extend %brush-clear;
 
             margin-right: 12px;
           }
@@ -1151,6 +1178,25 @@ $draw-h: 520px;
     }
   }
 
+  .material-list {
+    padding: 12px;
+    background-color: #fff;
+    border-bottom: 1px solid #ccc;
+
+    .el-tag {
+      padding: 0 20px;
+      margin: 0 0 8px 12px;
+      color: $color;
+      cursor: pointer;
+      border-color: #e5e5e5;
+
+      .svg-icon {
+        margin-right: 8px;
+        font-size: 18px;
+      }
+    }
+  }
+
   // 学员列表
   .student-list {
     width: 100%;

+ 1 - 1
src/views/live/teacher/live.js

@@ -216,7 +216,7 @@ export function initListener(vue) {
   // 房间全量信息事件(人员进出时广播)
   rtc.on('room_context', roomData => {
     vue.roomContext = JSON.parse(roomData);
-    vue.getLiveRoomStudentList();
+    vue.getLiveRoomData_DRTD();
     console.log('房间全量信息事件(人员进出时广播)', JSON.parse(roomData));
   });
 

+ 7 - 23
src/views/main/TemplateList.vue

@@ -3,23 +3,13 @@
     <!-- 查询条件 -->
     <div class="template-search">
       <div>
-        <el-input
-          v-model="name"
-          class="search-name"
-          prefix-icon="el-icon-search"
-          @change="queryCourseList"
-        >
+        <el-input v-model="name" class="search-name" prefix-icon="el-icon-search" @change="queryCourseList">
           <el-button slot="append" @click="queryCourseList">搜索</el-button>
         </el-input>
       </div>
       <div>
         <el-select v-model="release_status">
-          <el-option
-            v-for="item in releaseStatusList"
-            :key="item.value"
-            :label="item.name"
-            :value="item.value"
-          />
+          <el-option v-for="item in releaseStatusList" :key="item.value" :label="item.name" :value="item.value" />
         </el-select>
         <el-button class="query-button" type="primary" @click="queryCourseList">查询</el-button>
       </div>
@@ -28,10 +18,7 @@
     <div class="template-container">
       <div class="template-container-title">
         <span>模板库</span>
-        <el-button
-          class="create"
-          @click="$router.push('/create_course_step_table/course_info?is_template=true')"
-        >
+        <el-button class="create" @click="$router.push('/create_course_step_table/course_info?is_template=true')">
           <div><svg-icon icon-class="create" /><span>创建模板</span></div>
         </el-button>
       </div>
@@ -60,10 +47,7 @@
                   <el-dropdown-item @click.native="edit(row.id)">
                     <svg-icon icon-class="edit" /> 编辑
                   </el-dropdown-item>
-                  <el-dropdown-item
-                    v-if="row.is_release === 'false'"
-                    @click.native="releaseCourse(row.id, true)"
-                  >
+                  <el-dropdown-item v-if="row.is_release === 'false'" @click.native="releaseCourse(row.id, true)">
                     <svg-icon icon-class="publish" /> 发布
                   </el-dropdown-item>
                   <el-dropdown-item v-else @click.native="releaseCourse(row.id, false)">
@@ -176,7 +160,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .template {
   @include pagination;
@@ -204,11 +188,11 @@ export default {
 
     &-title {
       display: flex;
-      justify-content: space-between;
       align-items: center;
+      justify-content: space-between;
+      padding: 32px;
       font-size: 20px;
       font-weight: bold;
-      padding: 32px;
 
       .create {
         width: 138px;

+ 12 - 17
src/views/main/curricula_list/student.vue

@@ -43,9 +43,7 @@
       <div class="curricula-student-container-title">
         <div>
           <span class="title">课程列表</span>
-          <span class="tip">
-            你也可以去 <a @click="goLearningCenter">学习中心</a> 选择更多的课程。
-          </span>
+          <span class="tip"> 你也可以去 <a @click="goLearningCenter">学习中心</a> 选择更多的课程。 </span>
         </div>
       </div>
       <div class="curricula-student-container-list">
@@ -53,16 +51,11 @@
           <el-table-column prop="course_name" label="课程名称" width="300" />
           <el-table-column label="课程教师" prop="teacher_name_desc" width="360" />
           <el-table-column label="课程周期" width="280">
-            <template slot-scope="{ row }">
-              <i class="el-icon-date" /> {{ row.date_space_view_text }}
-            </template>
+            <template slot-scope="{ row }"> <i class="el-icon-date" /> {{ row.date_space_view_text }} </template>
           </el-table-column>
           <el-table-column label="完成状态" width="140">
             <template slot-scope="{ row }">
-              <span
-                class="status-name"
-                :style="{ 'background-color': statusColor(row.finish_status) }"
-              />
+              <span class="status-name" :style="{ 'background-color': statusColor(row.finish_status) }" />
               <span :style="{ color: statusColor(row.finish_status) }">
                 {{ row.finish_status_name }}
               </span>
@@ -178,7 +171,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .curricula-student {
   @include pagination;
@@ -213,16 +206,18 @@ export default {
     border-radius: 8px;
 
     &-title {
-      height: 88px;
-      padding: 24px 32px;
       display: flex;
-      justify-content: space-between;
       align-items: center;
+      justify-content: space-between;
+      height: 88px;
+      padding: 24px 32px;
 
       .title {
-        font-size: 20px;
-        font-weight: 700;
         margin-right: 36px;
+        font: {
+          size: 20px;
+          weight: 700;
+        }
       }
 
       .tip {
@@ -260,9 +255,9 @@ export default {
         display: inline-block;
         width: 8px;
         height: 8px;
-        border-radius: 50%;
         margin-right: 8px;
         margin-bottom: 1px;
+        border-radius: 50%;
       }
     }
   }

+ 6 - 9
src/views/main/curricula_list/teacher.vue

@@ -60,10 +60,7 @@
                   <el-dropdown-item @click.native="view(row.id)">
                     <svg-icon icon-class="view" /> 查看
                   </el-dropdown-item>
-                  <el-dropdown-item
-                    v-if="row.is_release === 'false'"
-                    @click.native="releaseCourse(row.id, true)"
-                  >
+                  <el-dropdown-item v-if="row.is_release === 'false'" @click.native="releaseCourse(row.id, true)">
                     <svg-icon icon-class="publish" /> 发布
                   </el-dropdown-item>
                   <el-dropdown-item v-else @click.native="releaseCourse(row.id, false)">
@@ -196,7 +193,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .curricula-teacher {
   @include pagination;
@@ -231,16 +228,16 @@ export default {
     border-radius: 8px;
 
     &-title {
-      height: 88px;
-      padding: 24px 32px;
       display: flex;
-      justify-content: space-between;
       align-items: center;
+      justify-content: space-between;
+      height: 88px;
+      padding: 24px 32px;
 
       .title {
+        margin-right: 36px;
         font-size: 20px;
         font-weight: 700;
-        margin-right: 36px;
       }
 
       .create {

+ 7 - 7
src/views/main/index.vue

@@ -89,7 +89,7 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .main-container {
   @include container;
@@ -97,24 +97,24 @@ export default {
   // 切换菜单
   .menu {
     display: inline-block;
-    border-radius: 30px;
     margin-bottom: 32px;
     background-color: #ebebeb;
+    border-radius: 30px;
 
     &-tab {
       display: inline-block;
       height: 48px;
-      line-height: 30px;
-      font-size: 20px;
       padding: 9px 39px;
-      border-radius: 30px;
-      background-color: #ebebeb;
+      font-size: 20px;
+      line-height: 30px;
       color: #9f9f9f;
       cursor: pointer;
+      background-color: #ebebeb;
+      border-radius: 30px;
 
       &.active {
-        color: #fff;
         font-weight: 700;
+        color: #fff;
         background-color: $basicColor;
       }
     }

+ 1 - 1
src/views/teacher/create_course/step_table/CreateTask.vue

@@ -25,7 +25,7 @@
             :class="['task-item-list-title', { selected: item.id === curItemID }]"
             @click="curItemID = item.id"
           >
-            <span class="nowrap-ellipsis task-item-name">{{ item.name }}</span>
+            <span class="nowrap-ellipsis task-item-name" :title="item.name">{{ item.name }}</span>
             <!-- 课节下拉框 -->
             <el-dropdown placement="bottom" trigger="click" @command="handleCSItem">
               <i class="el-icon-more"></i>

+ 10 - 18
src/views/teacher/student_list/index.vue

@@ -1,11 +1,7 @@
 <template>
   <div class="student-list">
     <div class="search">
-      <el-input
-        v-model="student_name"
-        prefix-icon="el-icon-search"
-        @change="queryCourseStudentList"
-      >
+      <el-input v-model="student_name" prefix-icon="el-icon-search" @change="queryCourseStudentList">
         <el-button slot="append" @click="queryCourseStudentList">搜索</el-button>
       </el-input>
     </div>
@@ -44,12 +40,8 @@
           <el-table-column fixed="right" width="120">
             <template slot-scope="{ row }">
               <template v-if="activeID === 'new'">
-                <span class="agree" @click="auditCourseStudent(row.course_student_id, 'true')">
-                  同意
-                </span>
-                <span class="refuse" @click="auditCourseStudent(row.course_student_id, 'false')">
-                  拒绝
-                </span>
+                <span class="agree" @click="auditCourseStudent(row.course_student_id, 'true')"> 同意 </span>
+                <span class="refuse" @click="auditCourseStudent(row.course_student_id, 'false')"> 拒绝 </span>
               </template>
             </template>
           </el-table-column>
@@ -145,7 +137,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '~@/styles/mixin.scss';
+@import '~@/styles/mixin';
 
 .student-list {
   @include container;
@@ -157,8 +149,8 @@ export default {
 
   &-container {
     width: 100%;
-    padding: 24px 32px;
     min-height: calc(100vh - 240px);
+    padding: 24px 32px;
     margin-top: 16px;
     background-color: #fff;
     border-radius: 8px;
@@ -172,9 +164,9 @@ export default {
         display: flex;
 
         .tabs-item {
-          cursor: pointer;
-          font-size: 18px;
           padding-bottom: 16px;
+          font-size: 18px;
+          cursor: pointer;
 
           &.active {
             font-weight: 600;
@@ -192,17 +184,17 @@ export default {
     .student-table {
       @include list;
 
-      margin-top: 0;
       min-height: calc(100vh - 343px);
+      margin-top: 0;
 
       .el-table__header {
         display: none;
       }
 
       .agree {
+        margin-right: 32px;
         color: #2a99ff;
         cursor: pointer;
-        margin-right: 32px;
       }
 
       .refuse {
@@ -215,8 +207,8 @@ export default {
       }
 
       .student-name {
-        margin-left: 16px;
         display: inline-block;
+        margin-left: 16px;
         vertical-align: super;
       }
     }

+ 7 - 0
vue.config.js

@@ -22,6 +22,13 @@ if (NODE_ENV === 'development') {
       pathRewrite: {
         ['^' + process.env.VUE_APP_BASE_API]: ''
       }
+    },
+    [process.env.VUE_APP_PDF]: {
+      target: 'https://file-kf.helxsoft.cn/',
+      changeOrigin: true,
+      pathRewrite: {
+        ['^' + process.env.VUE_APP_PDF]: ''
+      }
     }
   };
 }