소스 검색

资源类型:显示文本

zq 16 시간 전
부모
커밋
d66fdf795d
3개의 변경된 파일183개의 추가작업 그리고 55개의 파일을 삭제
  1. 6 0
      src/assets/icon/sidebar-text.svg
  2. 17 2
      src/views/book/courseware/preview/CoursewarePreview.vue
  3. 160 53
      src/web_preview/index.vue

+ 6 - 0
src/assets/icon/sidebar-text.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="24" height="24" style="" filter="none">
+    
+    <g>
+    <path d="M26.667 29.333h-21.333c-0.736 0-1.333-0.597-1.333-1.333v0-24c0-0.736 0.597-1.333 1.333-1.333v0h21.333c0.736 0 1.333 0.597 1.333 1.333v0 24c0 0.736-0.597 1.333-1.333 1.333v0zM25.333 26.667v-21.333h-18.667v21.333h18.667zM10.667 9.333h10.667v2.667h-10.667v-2.667zM10.667 14.667h10.667v2.667h-10.667v-2.667zM10.667 20h10.667v2.667h-10.667v-2.667z" fill="rgba(51,51,51,1)"></path>
+    </g>
+  </svg>

+ 17 - 2
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -391,7 +391,7 @@ export default {
         this.menuPosition.select_node,
         this.menuPosition.x,
         this.menuPosition.y,
-        this.componentId,
+        this.componentId
       );
     },
     handleMouseDown(event) {
@@ -407,6 +407,21 @@ export default {
      */
     async findChildComponentByKey(id) {
       await this.$nextTick();
+      if (!this.$refs.preview) {
+        // 最多等待 1000ms
+        for (let i = 0; i < 20; i++) {
+          await this.$nextTick();
+          await new Promise((resolve) => setTimeout(resolve, 50));
+          if (this.$refs.preview) break;
+        }
+      }
+
+      // 如果等待后还是不存在,那就返回null
+      if (!this.$refs.preview) {
+        console.error('$refs.preview 不存在');
+        return null;
+      }
+
       return this.$refs.preview.find((child) => child.$el && child.$el.dataset && child.$el.dataset.id === id);
     },
     /**
@@ -635,7 +650,7 @@ export default {
         const searchStart = Math.max(0, cumulativeLength - selectedText.length * 3);
         const searchEnd = Math.min(
           fullText.length,
-          cumulativeLength + closestFragment.text.length + selectedText.length * 3,
+          cumulativeLength + closestFragment.text.length + selectedText.length * 3
         );
 
         const searchArea = fullText.substring(searchStart, searchEnd);

+ 160 - 53
src/web_preview/index.vue

@@ -164,14 +164,14 @@
                 </el-table-column>
                 <el-table-column label="" width="50">
                   <template #default="{ row }">
-                    <el-link type="primary" @click="handleLocation(row, 3)">定位</el-link>
+                    <el-link type="primary" @click="handleLocation(row, 0)">定位</el-link>
                   </template>
                 </el-table-column>
               </el-table>
             </div>
           </div>
           <!-- <div v-if="curToolbarIcon === 'totalResources'" class="resource_box"></div> -->
-          <div v-if="['image', 'audio', 'video'].includes(twoCurToolbarIcon)" class="resource_box">
+          <div v-if="['image', 'audio', 'video', 'text'].includes(twoCurToolbarIcon)" class="resource_box">
             <div class="source-toolbar-list">
               <div
                 v-for="{ icon, title, handle, param } in twoSidebarList"
@@ -203,46 +203,68 @@
 
                 <!-- 加载完成显示数据 -->
                 <div v-else-if="chapter.data">
-                  <ul class="scroll-container" infinite-scroll-disabled="disabled" :infinite-scroll-immediate="false">
-                    <li
-                      v-for="(item, index) in chapter.data"
-                      :key="`${chapter.id}-${index}`"
-                      class="list-item"
-                      @click="handleFileClick(item?.courseware_id, item?.component_id)"
-                    >
+                  <ul
+                    :class="parseInt(drawerType) == 5 ? 'scroll-container file-list' : 'scroll-container'"
+                    infinite-scroll-disabled="disabled"
+                    :infinite-scroll-immediate="false"
+                  >
+                    <li v-for="(item, index) in chapter.data" :key="`${chapter.id}-${index}`" class="list-item">
                       <template v-if="parseInt(drawerType) === 0">
-                        <el-image v-if="shouldShowItem(chapter, item)" :src="item.file_url" fit="contain" />
-                        <div class="mark">
-                          <span class="word">{{ item.file_name }}</span>
-                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 3)" />
-                        </div>
+                        <el-image v-if="shouldMediaShowItem(chapter, item)" :src="item.file_url" fit="contain" />
                       </template>
                       <template v-else-if="parseInt(drawerType) === 1">
                         <AudioPlay
-                          v-if="shouldShowItem(chapter, item)"
+                          v-if="shouldMediaShowItem(chapter, item)"
                           view-size="middle"
                           :file-id="item.file_id"
                           :file-name="item.file_name.slice(0, item.file_name.lastIndexOf('.'))"
                           :show-slider="true"
                           :audio-index="index"
                         />
-                        <div class="mark">
-                          <span class="word"></span>
-                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 3)" />
-                        </div>
                       </template>
                       <template v-else-if="parseInt(drawerType) === 2">
                         <VideoPlay
-                          v-if="shouldShowItem(chapter, item)"
+                          v-if="shouldMediaShowItem(chapter, item)"
                           view-size="small"
                           :file-id="item.file_id"
                           :video-index="index"
                         />
-                        <div class="mark">
-                          <span class="word">{{ item.file_name }}</span>
-                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 3)" />
+                      </template>
+                      <template v-else-if="parseInt(drawerType) === 3"> </template>
+                      <template v-else-if="parseInt(drawerType) === 4"> </template>
+                      <template v-else-if="parseInt(drawerType) === 5">
+                        <div class="file-name">
+                          <span>
+                            <SvgIcon icon-class="file" size="24" />
+                            <p>
+                              <span>{{ item.file_name }}</span>
+                            </p>
+                          </span>
+                          <div>
+                            <SvgIcon
+                              v-show="item.file_id"
+                              icon-class="uploadPreview"
+                              size="24"
+                              @click="viewDialog(item)"
+                            />
+
+                            <img
+                              style="width: 24px; height: 24px; cursor: pointer"
+                              src="@/assets/download.png"
+                              alt="download"
+                              @click="downLoad(item)"
+                            />
+                          </div>
                         </div>
                       </template>
+                      <!-- 资源底部的操作 -->
+                      <div class="file-handle-info">
+                        <span v-if="![1, 5].includes(parseInt(drawerType))" class="word">{{ item.file_name }}</span>
+                        <div class="mark">
+                          <span></span>
+                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 0)" />
+                        </div>
+                      </div>
                     </li>
                   </ul>
                 </div>
@@ -263,7 +285,7 @@
                 <div>
                   <el-button type="text" class="el-icon-delete" @click="handDelCollect(item.id)"> 删除</el-button>
                   <el-divider direction="vertical" />
-                  <el-button type="text" class="el-icon-place" @click="handleLocation(item, 2)"> 定位</el-button>
+                  <el-button type="text" class="el-icon-place" @click="handleLocation(item, 12)"> 定位</el-button>
                 </div>
               </li>
             </ul>
@@ -327,12 +349,27 @@
       @confirm="saveNote"
       @cancel="delNote"
     />
+
+    <el-dialog
+      v-if="fileViewVisible"
+      :visible.sync="fileViewVisible"
+      :show-close="true"
+      :close-on-click-modal="true"
+      :modal-append-to-body="true"
+      :append-to-body="true"
+      :lock-scroll="true"
+      :width="isMobile ? '100%' : '80%'"
+      top="0"
+    >
+      <iframe v-if="fileViewVisible" :src="newpath" width="100%" :height="iframeHeight" frameborder="0"></iframe>
+    </el-dialog>
   </div>
 </template>
 
 <script>
 import CoursewarePreview from '@/views/book/courseware/preview/CoursewarePreview.vue';
 import { isTrue } from '@/utils/validate';
+import { getConfig, getToken } from '@/utils/auth';
 import MindMap from '@/components/MindMap.vue';
 import VideoPlay from '@/views/book/courseware/preview/components/common/VideoPlay.vue';
 import AudioPlay from '@/views/book/courseware/preview/components/common/AudioPlay.vue';
@@ -386,7 +423,7 @@ export default {
   },
   data() {
     const sidebarIconList = [
-      { icon: 'search', title: '搜索', handle: 'getSearch', param: { type: '5' } },
+      { icon: 'search', title: '搜索', handle: 'getSearch', param: { type: '13' } },
       { icon: 'mindmap', title: '思维导图', handle: 'openMindMap', param: {} },
       { icon: 'knowledge', title: '知识图谱', handle: 'openVisNetwork', param: {} },
       {
@@ -398,18 +435,23 @@ export default {
           { icon: 'audio', title: '音频', handle: 'openDrawer', param: { type: '1' } },
           { icon: 'image', title: '图片', handle: 'openDrawer', param: { type: '0' } },
           { icon: 'video', title: '视频', handle: 'openDrawer', param: { type: '2' } },
+          { icon: 'text', title: '文本', handle: 'openDrawer', param: { type: '5' } },
         ],
       },
-      { icon: 'collect', title: '收藏', handle: 'getCollect', param: { type: '3' } },
-      { icon: 'note', title: '笔记', handle: 'getNote', param: { type: '4' } },
-      // { icon: 'translate', title: '翻译', handle: '', param: {} },
-      // { icon: 'setting', title: '设置', handle: '', param: {} },
+      { icon: 'collect', title: '收藏', handle: 'getCollect', param: { type: '11' } },
+      { icon: 'note', title: '笔记', handle: 'getNote', param: { type: '12' } },
+      { icon: 'translate', title: '翻译', handle: '', param: {} },
+      { icon: 'setting', title: '设置', handle: '', param: {} },
     ];
 
     const book_id = getLocalStore('book_id') || '';
     return {
       projectId: book_id,
       select_node: this.id,
+      file_preview_url: getConfig() ? getConfig().doc_preview_service_address : '',
+      newpath: '',
+      fileViewVisible: false,
+      iframeHeight: `${window.innerHeight - 100}px`,
       courseware_info: {
         book_name: '',
         is_can_start_edit: 'false',
@@ -519,13 +561,14 @@ export default {
         0: '图片资源',
         1: '音频资源',
         2: '视频资源',
-        3: '收藏列表',
-        4: '笔记列表',
-        5: '搜索结果',
+        5: '文本资源',
+        11: '收藏列表',
+        12: '笔记列表',
+        13: '搜索结果',
       };
       return titleMap[this.drawerType] || '资源列表';
     },
-    shouldShowItem() {
+    shouldMediaShowItem() {
       return (chapter, item) => {
         return this.activeBookChapterId === chapter.id && item && item.file_id;
       };
@@ -602,7 +645,7 @@ export default {
         ({ courseware_info }) => {
           this.courseware_info = { ...this.courseware_info, ...courseware_info };
           this.getLangList();
-        },
+        }
       );
     },
     /**
@@ -665,7 +708,7 @@ export default {
           });
 
           if (content_group_row_list) this.content_group_row_list = JSON.parse(content_group_row_list) || [];
-        },
+        }
       );
     },
     processHtmlString(pElements, styleConfig, isClear) {
@@ -689,7 +732,7 @@ export default {
       GetLanguageTypeList({ book_id: this.courseware_info.book_id, is_contain_zh: 'true' }).then(
         ({ language_type_list }) => {
           this.langList = language_type_list;
-        },
+        }
       );
     },
 
@@ -753,7 +796,7 @@ export default {
       this.$refs.courserware.handleResult(
         this.$refs.previewMain.scrollTop,
         this.$refs.previewMain.scrollLeft,
-        this.select_node,
+        this.select_node
       );
     },
 
@@ -831,7 +874,7 @@ export default {
     /**
      * 打开抽屉并初始化加载
      * @param {Object} param - 抽屉参数
-     * @param {string} param.type - 抽屉类型(0: 图片, 1: 音频, 2: 视频)
+     * @param {string} param.type - 抽屉类型(0: 图片, 1: 音频, 2: 视频, 3:H5 游戏,4:3D 模型,5:文本
      */
     openDrawer({ type }) {
       if (this.drawerType === type) {
@@ -1087,10 +1130,10 @@ export default {
     /**
      * 定位到对应位置
      * @param {Object} item - 位置对象
-     * @param {number} type - 定位类型(1: 笔记定位, 2: 收藏定位, 3: 资源定位)
+     * @param {number} type - 定位类型(11: 笔记定位, 12: 收藏定位, 0: 资源定位)
      */
     handleLocation(item, type) {
-      if (type === 3) {
+      if (type === 0) {
         let did = `${item.courseware_id}#${item.component_id}`;
         this.handleNodeClick(did);
         this.curSelectId = item.courseware_id;
@@ -1102,6 +1145,29 @@ export default {
         this.$refs.courserware.handleLocation(item);
       }
     },
+    downLoad(file) {
+      debugger
+      let userInfor = getToken();
+      let AccessToken = '';
+      if (userInfor) {
+        AccessToken = userInfor.access_token;
+      }
+      let FileID = file.file_id;
+      let data = {
+        AccessToken,
+        FileID,
+      };
+      location.href = `${process.env.VUE_APP_EEP}/FileServer/WebFileDownload?AccessToken=${data.AccessToken}&FileID=${data.FileID}`;
+    },
+    // 预览
+    viewDialog(file) {
+      this.newpath = `${this.file_preview_url}onlinePreview?url=${Base64.encode(file.file_url)}`;
+      this.fileViewVisible = true;
+    },
+    /**
+     * 获取笔记列表
+     * @param {Object} params - 参数对象
+     */
     async getNote(params) {
       if (params && params.type) this.drawerType = Number(params.type);
       this.allNoteList = [];
@@ -1135,7 +1201,7 @@ export default {
           x.coursewareId === note.coursewareId &&
           x.blockId === note.blockId &&
           x.startIndex === note.startIndex &&
-          x.endIndex === note.endIndex,
+          x.endIndex === note.endIndex
       );
       if (old) {
         this.oldRichData = old;
@@ -1229,7 +1295,7 @@ export default {
           x.coursewareId === collect.coursewareId &&
           x.blockId === collect.blockId &&
           x.startIndex === collect.startIndex &&
-          x.endIndex === collect.endIndex,
+          x.endIndex === collect.endIndex
       );
       if (old) {
         this.$message({
@@ -1709,7 +1775,8 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
             .list-item {
               // display: flex;
               align-items: center;
-              cursor: pointer;
+
+              // cursor: pointer;
               border: 1px solid #ccc;
               border-radius: 8px;
 
@@ -1756,21 +1823,24 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
             }
           }
 
-          .mark {
-            display: flex;
-            align-items: center;
-            justify-content: space-between;
-            padding: 3px;
+          .file-handle-info {
+            margin: 0 5px;
+
+            .mark {
+              display: flex;
+              align-items: center;
+              justify-content: space-between;
+              padding: 3px;
+
+              .linkLocation {
+                cursor: pointer;
+              }
+            }
 
             .word {
               flex: 1;
-              margin-right: 10px;
               word-break: break-all;
             }
-
-            .linkLocation {
-              cursor: pointer;
-            }
           }
 
           ::v-deep .el-collapse-item__header {
@@ -1847,6 +1917,43 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
   margin: 10px 0 0 !important;
   background-color: #eee;
 }
+
+.file-list {
+  display: flex;
+  flex-direction: column;
+  row-gap: 5px;
+
+  li {
+    align-items: center;
+
+    .file-name {
+      display: flex;
+      column-gap: 14px;
+      align-items: center;
+      justify-content: space-between;
+      max-width: 500px;
+      padding: 8px 12px;
+      font-size: 14px;
+      color: #1d2129;
+      background-color: #f7f8fa;
+      border-radius: 8px;
+
+      p {
+        margin: 0;
+      }
+
+      span,
+      div {
+        display: flex;
+        align-items: center;
+      }
+    }
+
+    .svg-icon {
+      cursor: pointer;
+    }
+  }
+}
 </style>
 
 <style lang="scss">