Browse Source

Merge branch 'master' into lhd

natasha 1 day ago
parent
commit
ac259ac31c

+ 17 - 0
src/api/book.js

@@ -54,6 +54,15 @@ export function ChapterAddChapterToBook(data) {
 export function ChapterAddCoursewareToBook(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_chapter_manager-AddCoursewareToBook`, data);
 }
+
+/**
+ * @description 删除课件
+ * @param {object} data
+ */
+export function ChapterDeleteCourseware(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_chapter_manager-DeleteCourseware`, data);
+}
+
 /**
  * @description 修改章节
  * @param {object} data
@@ -190,3 +199,11 @@ export function MangerGenerateMindMapByBookContent(data) {
 export function MangerSaveBookMindMap(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_content_manager-SaveBookMindMap`, data);
 }
+
+/**
+ * @description 分页查询教材资源列表
+ * @param {object} data
+ */
+export function PageQueryBookResourceList(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=page_query-PageQueryBookResourceList`, data);
+}

+ 192 - 13
src/components/CommonPreview.vue

@@ -49,18 +49,56 @@
         </ul>
         <p v-else style="text-align: center">暂无批注</p>
       </div>
-
-      <div class="sidebar">
+      <div ref="sidebarMenu" class="sidebar">
         <div
-          v-for="{ icon, title, handle } in sidebarIconList"
+          v-for="{ icon, title, handle, param } in sidebarIconList"
           :key="icon"
           :title="title"
           class="sidebar-icon"
-          @click="handleSidebarClick(handle)"
+          @click="handleSidebarClick(handle, param)"
         >
           <SvgIcon :icon-class="`sidebar-${icon}`" size="24" />
         </div>
       </div>
+      <el-drawer
+        custom-class="custom-drawer"
+        :visible="drawerType.length > 0"
+        :with-header="false"
+        :modal="false"
+        size="25%"
+        :style="drawerStyle"
+      >
+        <div class="infinite-list-wrapper" style="overflow: auto">
+          <ul v-infinite-scroll="loadMore" class="scroll-container" infinite-scroll-disabled="disabled">
+            <li
+              v-for="(item, index) in file_list"
+              :key="index"
+              class="list-item"
+              @click="handleFileClick(item?.component_id)"
+            >
+              <template v-if="parseInt(drawerType) === 0">
+                <el-image :src="item.file_url" fit="contain" />
+                <span>{{ item.file_name.slice(0, item.file_name.lastIndexOf('.')) }}</span>
+              </template>
+              <template v-else-if="parseInt(drawerType) === 1">
+                <AudioPlay
+                  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"
+                />
+              </template>
+              <template v-else-if="parseInt(drawerType) === 2">
+                <VideoPlay view-size="big" :file-id="item.file_id" :video-index="index" />
+                <span>{{ item.file_name.slice(0, item.file_name.lastIndexOf('.')) }}</span>
+              </template>
+            </li>
+          </ul>
+          <p v-if="loading">加载中...</p>
+          <p v-if="noMore">没有更多了</p>
+        </div>
+      </el-drawer>
     </div>
 
     <el-dialog
@@ -104,6 +142,8 @@ import MenuPopover from '@/views/personal_workbench/common/MenuPopover.vue';
 import RichText from '@/components/RichText.vue';
 import { isTrue } from '@/utils/common';
 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';
 
 import {
   GetBookCoursewareInfo,
@@ -117,6 +157,7 @@ import {
   ChapterGetBookChapterStructExpandList,
   GetBookBaseInfo,
   MangerGetBookMindMap,
+  PageQueryBookResourceList,
 } from '@/api/book';
 
 export default {
@@ -126,6 +167,8 @@ export default {
     MenuPopover,
     RichText,
     MindMap,
+    AudioPlay,
+    VideoPlay,
   },
   props: {
     projectId: {
@@ -188,21 +231,41 @@ export default {
         componentId: 'WHOLE',
       },
       sidebarIconList: [
-        { icon: 'search', title: '搜索', handle: '' },
-        { icon: 'mindmap', title: '思维导图', handle: 'openMindMap' },
-        { icon: 'connect', title: '连接', handle: '' },
-        { icon: 'audio', title: '音频', handle: '' },
-        { icon: 'image', title: '图片', handle: '' },
-        { icon: 'video', title: '视频', handle: '' },
-        { icon: 'text', title: '文本', handle: '' },
-        { icon: 'collect', title: '收藏', handle: '' },
-        { icon: 'setting', title: '设置', handle: '' },
+        { icon: 'search', title: '搜索', handle: '', param: {} },
+        { icon: 'mindmap', title: '思维导图', handle: 'openMindMap', param: {} },
+        { icon: 'connect', title: '连接', handle: '', param: {} },
+        { 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: '', param: {} },
+        { icon: 'file', title: '文件', handle: '', param: {} },
+        { icon: 'collect', title: '收藏', handle: '', param: {} },
+        { icon: 'setting', title: '设置', handle: '', param: {} },
       ],
       visibleMindMap: false,
       isChildDataLoad: false,
       mindMapJsonData: {}, // 思维导图json数据
+      drawerType: '', // 抽屉类型
+      drawerStyle: {
+        top: '0',
+        height: '0',
+        right: '0',
+      },
+      page_capacity: 10,
+      cur_page: 1,
+      file_list: [],
+      total_count: 0,
+      loading: false,
     };
   },
+  computed: {
+    disabled() {
+      return this.loading || this.noMore;
+    },
+    noMore() {
+      return this.file_list.length >= this.total_count && this.total_count > 0;
+    },
+  },
   created() {
     if (this.id) {
       this.getBookCoursewareInfo(this.id);
@@ -213,6 +276,9 @@ export default {
     }
     this.getBookChapterStructExpandList();
   },
+  mounted() {
+    this.calcDrawerPosition();
+  },
   methods: {
     getProjectBaseInfo() {
       GetProjectBaseInfo({ id: this.projectId }).then(({ project_info }) => {
@@ -366,6 +432,7 @@ export default {
         this[handle](param);
       }
     },
+
     openMindMap() {
       MangerGetBookMindMap({ book_id: this.projectId }).then(({ content }) => {
         if (content) {
@@ -392,6 +459,70 @@ export default {
       }
       this.visibleMindMap = false;
     },
+
+    // 计算抽屉滑出位置
+    calcDrawerPosition() {
+      const menu = this.$refs.sidebarMenu;
+      if (menu) {
+        const rect = menu.getBoundingClientRect();
+        this.drawerStyle = {
+          top: `${rect.top}px`,
+          height: `${rect.height}px`,
+          right: `${window.innerWidth - rect.left + 1}px`,
+        };
+      }
+    },
+    /**
+     * 打开抽屉并初始化加载
+     * @param {Object} param - 抽屉参数
+     * @param {string} param.type - 抽屉类型(0: 图片, 1: 音频, 2: 视频)
+     */
+    openDrawer({ type }) {
+      if (this.drawerType === type) {
+        this.drawerType = '';
+        return;
+      }
+      this.drawerType = type;
+      this.drawerVisible = true;
+      this.$nextTick(() => {
+        this.cur_page = 1;
+        this.file_list = [];
+        this.loadMore();
+      });
+    },
+    // 加载更多数据
+    loadMore() {
+      if (this.disabled) return;
+      this.loading = true;
+      const params = {
+        page_capacity: this.page_capacity,
+        cur_page: this.cur_page,
+        book_id: this.projectId,
+        type: parseInt(this.drawerType),
+      };
+      PageQueryBookResourceList(params)
+        .then(({ total_count, resource_list }) => {
+          this.total_count = total_count;
+          this.file_list = this.cur_page === 1 ? resource_list : [...this.file_list, ...resource_list];
+          this.cur_page += this.cur_page;
+        })
+        .finally(() => {
+          this.loading = false;
+        });
+    },
+    async handleFileClick(component_id) {
+      if (component_id) {
+        let node = await this.$refs.courserware.findChildComponentByKey(component_id);
+        if (node) {
+          await this.$nextTick();
+          this.$refs.previewMain.scrollTo({
+            top: node.offsetTop - 50,
+            left: node.offsetLeft - 50,
+            behavior: 'smooth',
+          });
+        }
+      }
+    },
   },
 };
 </script>
@@ -571,6 +702,54 @@ export default {
         cursor: pointer;
       }
     }
+
+    .el-drawer__body {
+      .scroll-container {
+        display: flex;
+        flex-direction: column;
+        row-gap: 8px;
+        margin: 6px;
+
+        .list-item {
+          display: flex;
+          align-items: center;
+          cursor: pointer;
+          border: 1px solid #ccc;
+          border-radius: 8px;
+
+          :deep .el-slider {
+            .el-slider__runway {
+              background-color: #eee;
+            }
+          }
+
+          :deep .audio-middle {
+            width: 100%;
+            border: none;
+            border-radius: 8px;
+          }
+
+          .el-image {
+            display: flex;
+            width: 30%;
+            height: 90px;
+            margin: 6px;
+            background-color: #ccc;
+            border-radius: 8px;
+          }
+
+          .video-play {
+            width: 30%;
+            margin: 6px;
+          }
+        }
+      }
+
+      p {
+        color: #999;
+        text-align: center;
+      }
+    }
   }
 }
 

+ 1 - 1
src/icons/svg/file.svg

@@ -5,4 +5,4 @@
   <path
     d="M694.6 234.3H329.4c-18.9 0-34.2 15.3-34.2 34.2s15.3 34.3 34.2 34.3h365.2c18.9 0 34.2-15.3 34.2-34.3 0-18.9-15.3-34.2-34.2-34.2z m0 136.9H329.4c-18.9 0-34.2 15.3-34.2 34.2s15.3 34.2 34.2 34.2h365.2c18.9 0 34.2-15.3 34.2-34.2s-15.3-34.2-34.2-34.2zM799.5 64h-575c-47.1 0-85.2 38.1-85.2 85.2v725.6c0 47 38.1 85.2 85.2 85.2h575c47 0 85.2-38.2 85.2-85.2V149.2c0-47.1-38.1-85.2-85.2-85.2z m0 768.2c0 23.5-19.1 42.5-42.6 42.5H267.1c-23.5 0-42.6-19.1-42.6-42.5V191.8c0-23.6 19.1-42.6 42.6-42.6h489.8c23.5 0 42.6 19.1 42.6 42.6v640.4z m-104.9-324H329.4c-18.9 0-34.2 15.3-34.2 34.2s15.3 34.3 34.2 34.3h365.2c18.9 0 34.2-15.3 34.2-34.3 0-18.9-15.3-34.2-34.2-34.2z"
     fill="currentColor" p-id="11771"></path>
-</svg>
+</svg>

+ 8 - 0
src/icons/svg/sibebar/sidebar-file.svg

@@ -0,0 +1,8 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1747197509965"
+  class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11770"
+  xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
+  <path
+    d="M694.6 234.3H329.4c-18.9 0-34.2 15.3-34.2 34.2s15.3 34.3 34.2 34.3h365.2c18.9 0 34.2-15.3 34.2-34.3 0-18.9-15.3-34.2-34.2-34.2z m0 136.9H329.4c-18.9 0-34.2 15.3-34.2 34.2s15.3 34.2 34.2 34.2h365.2c18.9 0 34.2-15.3 34.2-34.2s-15.3-34.2-34.2-34.2zM799.5 64h-575c-47.1 0-85.2 38.1-85.2 85.2v725.6c0 47 38.1 85.2 85.2 85.2h575c47 0 85.2-38.2 85.2-85.2V149.2c0-47.1-38.1-85.2-85.2-85.2z m0 768.2c0 23.5-19.1 42.5-42.6 42.5H267.1c-23.5 0-42.6-19.1-42.6-42.5V191.8c0-23.6 19.1-42.6 42.6-42.6h489.8c23.5 0 42.6 19.1 42.6 42.6v640.4z m-104.9-324H329.4c-18.9 0-34.2 15.3-34.2 34.2s15.3 34.3 34.2 34.3h365.2c18.9 0 34.2-15.3 34.2-34.3 0-18.9-15.3-34.2-34.2-34.2z"
+    fill="currentColor" p-id="11771"></path>
+</svg>

+ 2 - 2
src/views/create_project/createSuccess.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="create-success">
-    <p class="tips">教材编辑项目《{{ project_name }}》创建成功,请切换到“个人工作台” > “我的项目”进行管理。</p>
+    <p class="tips">教材编辑项目《{{ project_name }}》创建成功,请切换到“教材管理” > “我的项目”进行管理。</p>
     <div class="btns">
       <el-button type="primary" @click="$router.push('/create_project/create')">创建新的项目</el-button>
       <el-button type="primary" @click="$router.push('/personal_workbench/project')">
-        跳转到“个人工作台” > “我的项目”
+        跳转到“教材管理” > “我的项目”
       </el-button>
     </div>
   </div>

+ 34 - 9
src/views/personal_workbench/project/ProductionEditorialManage.vue

@@ -52,7 +52,9 @@
             <span class="link">修改</span>
             <span class="link" @click="openSetProducer(id)">设置制作人</span>
             <span class="link" @click="openSetAuditor(id)">设置审校人</span>
-            <span class="link danger" @click="deleteChapter(id)">删除</span>
+            <span class="link danger" @click="is_leaf_chapter === 'true' ? deleteCourseware(id) : deleteChapter(id)">
+              删除
+            </span>
           </div>
         </div>
       </div>
@@ -101,6 +103,7 @@ import {
   ChapterAddChapterToBook,
   ChapterAddCoursewareToBook,
   ChapterDeleteChapter,
+  ChapterDeleteCourseware,
   ChapterSetProducer,
 } from '@/api/book';
 
@@ -210,10 +213,6 @@ export default {
       this.addType = 'chapter';
     },
     addCoursewareDialog() {
-      if (this.curSelectId === '') {
-        this.$message.error('请先选择章节');
-        return;
-      }
       this.visible = true;
       this.addType = 'courseware';
     },
@@ -234,10 +233,36 @@ export default {
      * @param {string} id - 章节ID
      */
     deleteChapter(id) {
-      ChapterDeleteChapter({ id, is_force_delete: 'true' }).then(() => {
-        this.getBookChapterStructExpandList();
-        this.$message.success('删除成功');
-      });
+      this.$confirm('是否确认删除该章节?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          ChapterDeleteChapter({ id }).then(() => {
+            this.getBookChapterStructExpandList();
+            this.$message.success('删除成功');
+          });
+        })
+        .catch(() => {});
+    },
+    /**
+     * 删除课件
+     * @param {string} id - 课件ID
+     */
+    deleteCourseware(id) {
+      this.$confirm('是否确认删除该课件?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          ChapterDeleteCourseware({ id }).then(() => {
+            this.getBookChapterStructExpandList();
+            this.$message.success('删除成功');
+          });
+        })
+        .catch(() => {});
     },
     openSetProducer(id) {
       this.producer.visible = true;