Ver Fonte

右侧工具栏

dsy há 2 meses atrás
pai
commit
91973c45cf

BIN
src/assets/icon/arrow-down.png


BIN
src/assets/icon/arrow-up.png


BIN
src/assets/icon/sidebar-audio.png


BIN
src/assets/icon/sidebar-audit.png


BIN
src/assets/icon/sidebar-collect.png


BIN
src/assets/icon/sidebar-file.png


BIN
src/assets/icon/sidebar-fullscreen.png


BIN
src/assets/icon/sidebar-image.png


BIN
src/assets/icon/sidebar-knowledge.png


BIN
src/assets/icon/sidebar-mindmap.png


BIN
src/assets/icon/sidebar-note.png


BIN
src/assets/icon/sidebar-search.png


BIN
src/assets/icon/sidebar-setting.png


BIN
src/assets/icon/sidebar-toolkit.png


BIN
src/assets/icon/sidebar-totalResources.png


BIN
src/assets/icon/sidebar-translate.png


BIN
src/assets/icon/sidebar-video.png


+ 1 - 1
src/styles/variables.scss

@@ -19,7 +19,7 @@ $right-color: #30a47d;
 $right-bc-color: #e8f7f2;
 $label-color: #076aff;
 $setting-active-color: #4176ff;
-$courseware-bgColor: #fdfdfd; // 教材内容背景色
+$courseware-bgColor: #fff; // 教材内容背景色
 
 // px
 $header-h: 64px; // 顶部内容高度

+ 108 - 15
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -1,19 +1,5 @@
 <template>
-  <div
-    ref="courserware"
-    class="courserware"
-    :style="[
-      {
-        backgroundImage: background.background_image_url ? `url(${background.background_image_url})` : '',
-        backgroundSize: background.background_image_url
-          ? `${background.background_position.width}% ${background.background_position.height}%`
-          : '',
-        backgroundPosition: background.background_image_url
-          ? `${background.background_position.left}% ${background.background_position.top}%`
-          : '',
-      },
-    ]"
-  >
+  <div ref="courserware" class="courserware" :style="computedCourserwareStyle()">
     <template v-for="(row, i) in data.row_list">
       <div v-show="computedRowVisibility(row.row_id)" :key="i" class="row" :style="getMultipleColStyle(i)">
         <el-checkbox
@@ -31,6 +17,7 @@
             <template v-for="(grid, k) in col.grid_list">
               <component
                 :is="previewComponentList[grid.type]"
+                :id="grid.id"
                 :key="k"
                 ref="preview"
                 :content="computedColContent(grid.id)"
@@ -40,7 +27,41 @@
                   gridArea: grid.grid_area,
                   height: grid.height,
                 }"
+                @contextmenu.native.prevent="handleContextMenu($event, grid.id)"
               />
+
+              <div
+                v-if="showMenu && componentId === grid.id"
+                :key="'menu' + grid.id + k"
+                class="custom-context-menu"
+                :style="{ left: menuPosition.x + 'px', top: menuPosition.y + 'px' }"
+                @click="handleMenuItemClick"
+              >
+                添加批注
+              </div>
+              <div
+                v-if="showRemark && Object.keys(componentRemarkObj).length !== 0 && componentRemarkObj[grid.id]"
+                :key="'show' + grid.id + k"
+              >
+                <el-popover
+                  v-for="(items, indexs) in componentRemarkObj[grid.id]"
+                  :key="indexs"
+                  placement="bottom"
+                  width="200"
+                  trigger="click"
+                >
+                  <div v-html="items.content"></div>
+                  <template #reference>
+                    <SvgIcon
+                      slot="reference"
+                      icon-class="icon-info"
+                      size="24"
+                      class="remark-info"
+                      :style="{ left: items.position_x - 12 + 'px', top: items.position_y - 12 + 'px' }"
+                    />
+                  </template>
+                </el-popover>
+              </div>
             </template>
           </div>
         </template>
@@ -97,6 +118,10 @@ export default {
       type: Boolean,
       default: true,
     },
+    project: {
+      type: Object,
+      default: () => ({}),
+    },
   },
   data() {
     return {
@@ -134,6 +159,10 @@ export default {
       left: rect.left,
       top: rect.top,
     };
+    window.addEventListener('mousedown', this.handleMouseDown);
+  },
+  beforeDestroy() {
+    window.removeEventListener('mousedown', this.handleMouseDown);
   },
   methods: {
     /**
@@ -281,6 +310,70 @@ export default {
         gridTemplateRows,
       };
     },
+
+    /**
+     * 计算课件背景样式
+     * @returns {Object} 课件背景样式对象
+     */
+    computedCourserwareStyle() {
+      const { background_image_url: bcImgUrl = '', background_position: pos = {} } = this.background || {};
+      const hasNoRows = !Array.isArray(this.data?.row_list) || this.data.row_list.length === 0;
+      const projectCover = this.project?.cover_image_file_url || '';
+
+      // 优先在空行时使用背景图或项目封面
+      const backgroundImage = hasNoRows ? bcImgUrl || projectCover : '';
+
+      // 保护性读取位置/大小值,避免 undefined 导致字符串 "undefined%"
+      const widthPct = typeof pos.width === 'undefined' ? '' : pos.width;
+      const heightPct = typeof pos.height === 'undefined' ? '' : pos.height;
+      const leftPct = typeof pos.left === 'undefined' ? '' : pos.left;
+      const topPct = typeof pos.top === 'undefined' ? '' : pos.top;
+
+      const hasBcImg = Boolean(bcImgUrl);
+      const backgroundSize = hasBcImg ? `${widthPct}% ${heightPct}%` : hasNoRows ? 'contain' : '';
+      const backgroundPosition = hasBcImg ? `${leftPct}% ${topPct}%` : hasNoRows ? 'center' : '';
+
+      return {
+        backgroundImage: backgroundImage ? `url(${backgroundImage})` : '',
+        backgroundSize,
+        backgroundPosition,
+      };
+    },
+    handleContextMenu(event, id) {
+      if (this.canRemark) {
+        event.preventDefault(); // 阻止默认的上下文菜单显示
+        this.menuPosition = {
+          x: event.clientX - this.divPosition.left,
+          y: event.clientY - this.divPosition.top,
+        }; // 设置菜单位置
+        this.componentId = id;
+        this.$emit('computeScroll');
+      }
+    },
+    handleResult(top, left, select_node) {
+      this.menuPosition = {
+        x: this.menuPosition.x + left,
+        y: this.menuPosition.y + top,
+        select_node,
+      }; // 设置菜单位置
+      this.showMenu = true; // 显示菜单
+    },
+    handleMenuItemClick() {
+      this.showMenu = false; // 隐藏菜单
+      this.$emit(
+        'addRemark',
+        this.menuPosition.select_node,
+        this.menuPosition.x,
+        this.menuPosition.y,
+        this.componentId,
+      );
+    },
+    handleMouseDown(event) {
+      if (event.button === 0 && event.target.className !== 'custom-context-menu') {
+        // 0 表示左键
+        this.showMenu = false;
+      }
+    },
     /**
      * 查找子组件
      * @param {string} id 组件的唯一标识符

+ 496 - 7
src/web_preview/index.vue

@@ -29,7 +29,7 @@
             <img v-if="project.cover_image_file_url.length > 0" :src="project.cover_image_file_url" alt="cover-image" />
           </div>
           <div class="info-content">
-            <div class="catalogue-icon">
+            <div class="catalogue-icon" @click="toggleNavigationShow">
               <SvgIcon icon-class="catalogue" size="54" />
             </div>
             <div class="courseware">
@@ -58,8 +58,13 @@
         </div>
       </aside>
 
-      <div ref="previewMain" class="main-container">
-        <div v-if="!navigationShow" class="catalogue-bar">
+      <div
+        ref="previewMain"
+        class="main-container"
+        :style="{ paddingLeft: navigationShow ? '15px' : '315px', paddingRight: sidebarShow ? '15px' : '315px' }"
+      >
+        <!-- 左侧菜单栏 - 收缩 -->
+        <div v-if="!navigationShow" class="catalogue-bar" @click="toggleNavigationShow">
           <SvgIcon icon-class="catalogue" size="54" />
         </div>
 
@@ -76,23 +81,128 @@
             :background="background"
             :can-remark="isTrue(courseware_info.is_my_audit_task) && isTrue(courseware_info.is_can_add_audit_remark)"
             :show-remark="false"
+            :project="project"
             :component-remark-obj="remark_list_obj"
             @computeScroll="computeScroll"
           />
           <div class="preview-right"></div>
         </main>
+
+        <!-- 右侧菜单栏 - 收缩 -->
+        <aside v-if="!sidebarShow" class="sidebar-bar">
+          <aside class="toolbar">
+            <div class="toolbar-special">
+              <!-- <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" />
+              <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" /> -->
+              <img :src="require(`@/assets/icon/arrow-down.png`)" alt="伸缩" @click="toggleSidebarShow" />
+            </div>
+          </aside>
+        </aside>
       </div>
 
       <div class="back-top" @click="backTop">
         <img :src="require(`@/assets/icon/back-top.png`)" alt="返回顶部" />
       </div>
+
+      <!-- 右侧工具栏 -->
+      <aside v-if="sidebarShow" ref="sidebarMenu" class="sidebar">
+        <aside class="toolbar">
+          <div class="toolbar-special">
+            <!-- <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" />
+            <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" /> -->
+          </div>
+          <div v-if="sidebarShow" class="toolbar-list">
+            <div
+              v-for="{ icon, title, handle, param } in sidebarIconList"
+              :key="icon"
+              :class="['sidebar-item', { active: curToolbarIcon === icon }]"
+              :title="title"
+              @click="handleSidebarClick(handle, param, icon)"
+            >
+              <div
+                class="sidebar-icon icon-mask"
+                :style="{
+                  backgroundColor: curToolbarIcon === icon ? '#fff' : '#1E2129',
+                  maskImage: `url(${require(`@/assets/icon/sidebar-${icon}.png`)})`,
+                }"
+              ></div>
+            </div>
+          </div>
+          <div class="adjustable" @click="toggleSidebarShow">
+            <img :src="require(`@/assets/icon/arrow-up.png`)" alt="伸缩" />
+          </div>
+        </aside>
+        <div class="content"></div>
+
+        <div class="back-top" @click="backTop">
+          <img :src="require(`@/assets/icon/back-top.png`)" alt="返回顶部" />
+        </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">
+            <ul
+              v-infinite-scroll="loadMore"
+              class="scroll-container"
+              infinite-scroll-disabled="disabled"
+              :infinite-scroll-immediate="false"
+            >
+              <li
+                v-for="(item, index) in file_list"
+                :key="index"
+                class="list-item"
+                @click="handleFileClick(item?.courseware_id, item?.component_id)"
+              >
+                <template v-if="parseInt(drawerType) === 0">
+                  <el-image :src="item.file_url" fit="contain" />
+                  <span class="text-box">{{ 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 class="text-box">{{ 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>
+      </aside>
     </div>
+
+    <el-dialog title="" :visible="visibleMindMap" width="1100px" class="audit-dialog" @close="dialogClose('MindMap')">
+      <MindMap
+        v-if="isChildDataLoad"
+        ref="mindMapRef"
+        :project-id="projectId"
+        :mind-map-json-data="mindMapJsonData"
+        @child-click="handleNodeClick"
+      />
+    </el-dialog>
   </div>
 </template>
 
 <script>
 import CoursewarePreview from '@/views/book/courseware/preview/CoursewarePreview.vue';
 import { isTrue } from '@/utils/validate';
+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 * as OpenCC from 'opencc-js';
 
 import { GetBookCoursewareInfo, GetCoursewareAuditRemarkList, GetProjectInfo } from '@/api/project';
@@ -100,6 +210,8 @@ import {
   ContentGetCoursewareContent_View,
   ChapterGetBookChapterStructExpandList,
   GetBookBaseInfo,
+  MangerGetBookMindMap,
+  PageQueryBookResourceList,
   GetLanguageTypeList,
   GetBookUnifiedAttrib,
 } from '@/api/book';
@@ -108,6 +220,9 @@ export default {
   name: 'CommonPreview',
   components: {
     CoursewarePreview,
+    MindMap,
+    VideoPlay,
+    AudioPlay,
   },
   provide() {
     return {
@@ -118,9 +233,23 @@ export default {
     };
   },
   data() {
+    const sidebarIconList = [
+      // { icon: 'search', title: '搜索', handle: '', param: {} },
+      { icon: 'mindmap', title: '思维导图', handle: 'openMindMap', param: {} },
+      // { icon: 'knowledge', title: '知识图谱', handle: '', param: {} },
+      // { icon: 'totalResources', title: '总资源', handle: '', param: {} },
+      // { icon: 'collect', 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: 'note', title: '笔记', handle: '', param: {} },
+      // { icon: 'translate', title: '翻译', handle: '', param: {} },
+      // { icon: 'setting', title: '设置', handle: '', param: {} },
+    ];
+
     return {
       book_id: this.$route.query.book_id || '',
-      select_node: '',
+      select_node: this.id,
       courseware_info: {
         book_name: '',
         is_can_start_edit: 'false',
@@ -151,6 +280,29 @@ export default {
       remark_content: '',
       submit_loading: false,
       isTrue,
+      menuPosition: {
+        x: -1,
+        y: -1,
+        componentId: 'WHOLE',
+      },
+      curToolbarIcon: this.isShowAudit ? 'audit' : '',
+      sidebarIconList,
+      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: true,
+      lastLoadTime: 0,
+      minLoadInterval: 3 * 1000,
       isShowGroup: false,
       groupShowAll: true,
       opencc: OpenCC.Converter({ from: 'cn', to: 'tw' }),
@@ -162,13 +314,24 @@ export default {
       unified_attrib: {},
       curSelectId: this.id,
       navigationShow: true,
+      sidebarShow: true,
       project: {
-        editor: '', // 主编
+        editor: '', // 作者
         cover_image_file_id: null, // 封面图片ID
         cover_image_file_url: '', // 封面图片URL
       },
     };
   },
+  computed: {
+    disabled() {
+      const result = this.loading || this.noMore;
+      return result;
+    },
+    noMore() {
+      const result = this.file_list.length >= this.total_count;
+      return result;
+    },
+  },
   watch: {
     isJudgeCorrect(newVal) {
       if (!newVal) {
@@ -180,6 +343,9 @@ export default {
       this.simulateAnswer();
     },
   },
+  mounted() {
+    this.calcDrawerPosition();
+  },
   created() {
     this.getBookBaseInfo();
     this.getBookChapterStructExpandList();
@@ -306,6 +472,150 @@ export default {
     },
 
     /**
+     * 处理侧边栏图标点击事件
+     * @param {string} handle - 处理函数名
+     * @param {any} param - 处理函数参数
+     * @param {string} icon - 图标名称
+     */
+    handleSidebarClick(handle, param, icon) {
+      if (typeof handle === 'string' && handle && typeof this[handle] === 'function') {
+        this[handle](param);
+      }
+      this.curToolbarIcon = icon;
+    },
+
+    openMindMap() {
+      MangerGetBookMindMap({ book_id: this.projectId }).then(({ content }) => {
+        if (content) {
+          this.mindMapJsonData = JSON.parse(content);
+          this.isChildDataLoad = true;
+        }
+      });
+      this.visibleMindMap = true;
+    },
+
+    async handleNodeClick(data) {
+      let [nodeId, componentId] = data.split('#');
+      if (nodeId) this.selectNode(nodeId);
+      if (componentId) {
+        let node = await this.$refs.courserware.findChildComponentByKey(componentId);
+        if (node) {
+          await this.$nextTick();
+          this.$refs.previewMain.scrollTo({
+            top: node.$el.offsetTop - 50,
+            left: node.$el.offsetLeft - 50,
+            behavior: 'smooth',
+          });
+        }
+      }
+      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.resetLoadState();
+      this.drawerType = type; // 假设这是你的类型变量
+      this.$nextTick(() => {
+        // 确保DOM更新后触发加载
+        this.loadMore();
+      });
+    },
+    openAudit() {},
+    resetLoadState() {
+      this.cur_page = 1;
+      this.file_list = [];
+      this.total_count = 0;
+      this.loading = false;
+      this.lastLoadTime = 0; // 重置时间戳,允许立即加载
+      this.loadCount = 0;
+    },
+    // 加载更多数据
+    async loadMore() {
+      const now = Date.now();
+      // 只有当lastLoadTime不为0(不是第一次)且时间间隔太短时才return
+      if (this.lastLoadTime > 0 && now - this.lastLoadTime < this.minLoadInterval) {
+        return;
+      }
+
+      if (this.disabled || this.loading) {
+        if (this.lastLoadTime > 0) {
+          return;
+        }
+      }
+      this.loading = true;
+      const params = {
+        page_capacity: this.page_capacity,
+        cur_page: this.cur_page,
+        book_id: this.projectId,
+        type: parseInt(this.drawerType),
+      };
+      await PageQueryBookResourceList(params)
+        .then(({ total_count, resource_list }) => {
+          this.total_count = total_count;
+          // 记录加载前的滚动高度
+          const scrollContainer = this.$el.querySelector('.el-drawer__body');
+          const isAtBottom = this.isScrollAtBottom(scrollContainer);
+
+          this.file_list = this.cur_page === 1 ? resource_list : [...this.file_list, ...resource_list];
+          if (!resource_list || resource_list.length === 0) {
+            return;
+          }
+          this.cur_page += 1;
+
+          // 只有当前已经在底部时才微调滚动位置
+          if (isAtBottom) {
+            this.$nextTick(() => {
+              // 轻微向上滚动,创造滚动空间
+              scrollContainer.scrollTop -= 5;
+            });
+          }
+        })
+        .finally(() => {
+          this.loading = false;
+          this.lastLoadTime = now;
+        });
+    },
+    isScrollAtBottom(container) {
+      if (!container) return false;
+      return container.scrollHeight - container.scrollTop <= container.clientHeight + 5;
+    },
+    async handleFileClick(courseware_id, component_id) {
+      if (courseware_id) this.selectNode(courseware_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',
+          });
+        }
+      }
+    },
+
+    /**
      * 文本转换
      * @param {string} text - 要转换的文本
      * @returns {string} - 转换后的文本
@@ -350,6 +660,12 @@ export default {
     toggleNavigationShow() {
       this.navigationShow = !this.navigationShow;
     },
+    /**
+     * 切换右侧工具栏显示与隐藏
+     */
+    toggleSidebarShow() {
+      this.sidebarShow = !this.sidebarShow;
+    },
 
     backTop() {
       this.$refs.previewMain.scrollTo({
@@ -441,9 +757,12 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
     min-width: 1110px;
     padding: 15px 0;
     overflow: auto;
-    background: #ececec;
+    background-color: #ececec;
 
     .catalogue-bar {
+      position: absolute;
+      top: 15px;
+      left: 0;
       display: flex;
       align-items: center;
       justify-content: center;
@@ -455,11 +774,47 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
       border-radius: 2px;
       box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 40%);
     }
+
+    .sidebar-bar {
+      position: absolute;
+      top: 0;
+      right: 240px;
+      display: flex;
+      width: 60px;
+      height: calc(100vh - 166px);
+
+      .toolbar {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        width: 60px;
+        height: 100%;
+
+        img {
+          cursor: pointer;
+        }
+
+        &-special {
+          display: flex;
+          flex-direction: column;
+          row-gap: 16px;
+          align-items: center;
+          width: 100%;
+          margin-bottom: 24px;
+          background-color: #fff;
+
+          img {
+            width: 36px;
+            height: 36px;
+          }
+        }
+      }
+    }
   }
 
   .back-top {
     position: absolute;
-    right: 24px;
+    right: 240px;
     bottom: 0;
     display: flex;
     place-content: center center;
@@ -618,6 +973,140 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
         }
       }
     }
+
+    .sidebar {
+      position: relative;
+      display: flex;
+      width: $sidebar-width;
+
+      .toolbar {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        width: 60px;
+        height: 100%;
+        background-color: rgba(247, 248, 250, 100%);
+
+        img {
+          cursor: pointer;
+        }
+
+        &-special {
+          display: flex;
+          flex-direction: column;
+          row-gap: 16px;
+          margin-bottom: 24px;
+        }
+
+        &-list {
+          display: flex;
+          flex-direction: column;
+          row-gap: 16px;
+          align-items: center;
+          width: 100%;
+
+          .sidebar-item {
+            width: 100%;
+            text-align: center;
+
+            .sidebar-icon {
+              width: 36px;
+              height: 36px;
+              cursor: pointer;
+            }
+
+            &.active {
+              background-color: #4095e5;
+            }
+          }
+        }
+      }
+
+      .content {
+        flex: 1;
+        background-color: #fff;
+      }
+
+      .back-top {
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        display: flex;
+        place-content: center center;
+        align-items: center;
+        width: 60px;
+        height: 60px;
+        cursor: pointer;
+      }
+    }
+  }
+
+  .el-drawer__body {
+    height: calc(100vh - 200px);
+    overflow-y: auto;
+
+    .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: calc(25vw - 110px);
+          border: none;
+          border-radius: 8px;
+        }
+
+        .el-image {
+          display: flex;
+          width: 30%;
+          min-width: 30%;
+          height: 90px;
+          margin: 6px;
+          background-color: #ccc;
+          border-radius: 8px;
+        }
+
+        .video-play {
+          width: 30%;
+          min-width: 30%;
+          margin: 6px;
+        }
+
+        .text-box {
+          word-break: break-word;
+        }
+      }
+    }
+
+    p {
+      color: #999;
+      text-align: center;
+    }
+  }
+}
+
+:deep .audit-dialog {
+  .el-dialog__body {
+    height: calc(100vh - 260px);
+    padding: 5px 20px;
+  }
+
+  .mind-map-container .mind-map {
+    height: calc(100vh - 310px);
   }
 }
 </style>