基于jeecgboot的个人网盘功能开发(二)

简介: 基于jeecgboot的个人网盘功能开发(二)

      今天讲基于jeecgboot的个人网盘功能开发的前端部分,如下图:

      之前讲了数据库部分,为了快速方便,通过online在线开发建好后,自动生成相应的前后端代码,前端部分modules与下面很多文件都是自动生成的,但有些目前也没有去用它,以后需要管理的话可以用。

上面中netdisk两个主要文件file.vue与share.vue

其中file.vue为网盘的主界面,share.vue主要是分享用

主界面主要是分两个部分,左边是菜单 AsideMenu,右边是文件列表FileList

其中AsideMenu相对比较简单,就是分成8种不同的文件类型,显示不同的内容而已,相对比较简单。

<template>
  <div class="side-menu-wrapper">
    <!-- 768px 下,以抽屉形式展示 -->
    <el-drawer
      :visible.sync="isDrawer"
      :with-header="false"
      :size="210"
      direction="ltr"
      v-if="screenWidth <= 768"
    >
      <!-- collapse 属性:控制菜单收缩展开 -->
      <el-menu
        class="side-menu"
        :default-active="activeIndex"
        :router="true"
        :collapse="isCollapse"
      >
        <el-submenu index="myFile" class="my-file">
          <template slot="title">
            <!-- 图标均来自 Element UI 官方图标库 https://element.eleme.cn/#/zh-CN/component/icon -->
            <i class="el-icon-files"></i>
            <span slot="title">我的文件</span>
          </template>
          <el-menu-item
            index="0"
            :route="{ name: 'File', query: { fileType: 0, filePath: '/' } }"
          >
            <i class="el-icon-menu"></i>
            <span slot="title">全部</span>
          </el-menu-item>
          <el-menu-item
            index="1"
            :route="{ name: 'File', query: { fileType: 1 } }"
          >
            <i class="el-icon-picture-outline"></i>
            <span slot="title">图片</span>
          </el-menu-item>
          <el-menu-item
            index="2"
            :route="{ name: 'File', query: { fileType: 2 } }"
          >
            <i class="el-icon-document"></i>
            <span slot="title">文档</span>
          </el-menu-item>
          <el-menu-item
            index="3"
            :route="{ name: 'File', query: { fileType: 3 } }"
          >
            <i class="el-icon-video-camera"></i>
            <span slot="title">视频</span>
          </el-menu-item>
          <el-menu-item
            index="4"
            :route="{ name: 'File', query: { fileType: 4 } }"
          >
            <i class="el-icon-headset"></i>
            <span slot="title">音乐</span>
          </el-menu-item>
          <el-menu-item
            index="5"
            :route="{ name: 'File', query: { fileType: 5 } }"
          >
            <i class="el-icon-takeaway-box"></i>
            <span slot="title">其他</span>
          </el-menu-item>
        </el-submenu>
        <el-menu-item
          index="6"
          :route="{ name: 'File', query: { fileType: 6 } }"
          class="recovery"
        >
          <i class="el-icon-delete"></i>
          <span slot="title">回收站</span>
        </el-menu-item>
        <el-menu-item
          index="8"
          :route="{ name: 'File', query: { fileType: 8, filePath: '/' } }"
          class="my-share"
        >
          <i class="el-icon-share"></i>
          <span slot="title">我的分享</span>
        </el-menu-item>
      </el-menu>
      <!-- 存储信息显示 -->
      <div class="storage-wrapper" :class="{ fold: isCollapse }">
        <el-progress
          :percentage="storagePercentage"
          :color="storageColor"
          :show-text="false"
          :type="isCollapse ? 'circle' : 'line'"
          :width="32"
          :stroke-width="isCollapse ? 4 : 6"
          stroke-linecap="square"
        ></el-progress>
        <div class="text" v-show="!isCollapse">
          <span class="label">存储</span>
          <span>
            {{ $file.calculateFileSize(storageValue) }} /
            {{ $file.calculateFileSize(totalStorageValue) }}
          </span>
        </div>
        <div class="text" v-show="isCollapse">
          <span>{{ $file.calculateFileSize(storageValue) }}</span>
        </div>
      </div>
    </el-drawer>
    <!-- 768px 以上,平铺展示 -->
    <template v-else>
      <!-- collapse 属性:控制菜单收缩展开 -->
      <el-menu
        class="side-menu"
        :default-active="activeIndex"
        :router="true"
        :collapse="isCollapse"
      >
        <el-submenu index="myFile" class="my-file">
          <template slot="title">
            <!-- 图标均来自 Element UI 官方图标库 https://element.eleme.cn/#/zh-CN/component/icon -->
            <i class="el-icon-files"></i>
            <span slot="title">我的文件</span>
          </template>
          <el-menu-item
            index="0"
            :route="{ name: 'netdiskfile', query: { fileType: 0, filePath: '/' } }"
          >
            <i class="el-icon-menu"></i>
            <span slot="title">全部</span>
          </el-menu-item>
          <el-menu-item
            index="1"
            :route="{ name: 'netdiskfile', query: { fileType: 1 } }"
          >
            <i class="el-icon-picture-outline"></i>
            <span slot="title">图片</span>
          </el-menu-item>
          <el-menu-item
            index="2"
            :route="{ name: 'netdiskfile', query: { fileType: 2 } }"
          >
            <i class="el-icon-document"></i>
            <span slot="title">文档</span>
          </el-menu-item>
          <el-menu-item
            index="3"
            :route="{ name: 'netdiskfile', query: { fileType: 3 } }"
          >
            <i class="el-icon-video-camera"></i>
            <span slot="title">视频</span>
          </el-menu-item>
          <el-menu-item
            index="4"
            :route="{ name: 'netdiskfile', query: { fileType: 4 } }"
          >
            <i class="el-icon-headset"></i>
            <span slot="title">音乐</span>
          </el-menu-item>
          <el-menu-item
            index="5"
            :route="{ name: 'netdiskfile', query: { fileType: 5 } }"
          >
            <i class="el-icon-takeaway-box"></i>
            <span slot="title">其他</span>
          </el-menu-item>
        </el-submenu>
        <el-menu-item
          index="6"
          :route="{ name: 'netdiskfile', query: { fileType: 6 } }"
          class="recovery"
        >
          <i class="el-icon-delete"></i>
          <span slot="title">回收站</span>
        </el-menu-item>
        <el-menu-item
          index="8"
          :route="{ name: 'netdiskfile', query: { fileType: 8, filePath: '/' } }"
          class="my-share"
        >
          <i class="el-icon-share"></i>
          <span slot="title">我的分享</span>
        </el-menu-item>
      </el-menu>
      <!-- 存储信息显示 -->
      <div class="storage-wrapper" :class="{ fold: isCollapse }">
        <el-progress
          :percentage="storagePercentage"
          :color="storageColor"
          :show-text="false"
          :type="isCollapse ? 'circle' : 'line'"
          :width="32"
          :stroke-width="isCollapse ? 4 : 6"
          stroke-linecap="square"
        ></el-progress>
        <div class="text" v-show="!isCollapse">
          <span class="label">存储</span>
          <span
            >{{ $file.calculateFileSize(storageValue) }} /
            {{ $file.calculateFileSize(totalStorageValue) }}</span
          >
        </div>
        <div class="text" v-show="isCollapse">
          <span>{{ $file.calculateFileSize(storageValue) }}</span>
        </div>
      </div>
    </template>
    <!-- 展开 & 收缩分类栏 -->
    <el-tooltip
      effect="dark"
      :content="isCollapse ? '展开' : '收起'"
      placement="right"
    >
      <div
        class="aside-title"
        @click="isCollapse ? (isCollapse = false) : (isCollapse = true)"
      >
        <i
          class="icon"
          :class="isCollapse ? 'el-icon-d-arrow-right' : 'el-icon-d-arrow-left'"
          :title="isCollapse ? '展开' : '收起'"
        ></i>
      </div>
    </el-tooltip>
  </div>
</template>
<script>
export default {
  name: 'SideMenu',
  data() {
    return {
      isDrawer: false, //  控制移动端菜单抽屉是否显示
      isCollapse: false, //  控制菜单收缩展开
      // 菜单 index 和名称 Map
      myFileMenuMap: {
        0: '全部',
        1: '图片',
        2: '文档',
        3: '视频',
        4: '音乐',
        5: '其他',
        6: '回收站',
        8: '我的分享'
      },
      //  自定义进度条颜色,不同占比,进度条颜色不同
      storageColor: [
        { color: '#67C23A', percentage: 50 },
        { color: '#E6A23C', percentage: 80 },
        { color: '#F56C6C', percentage: 100 }
      ]
    }
  },
  computed: {
    // 当前激活菜单的 index
    activeIndex() {
      return String(this.$route.query.fileType) //  获取当前路由参数中包含的文件类型
    },
    // 存储容量
    storageValue() {
      console.log("storageValue =",this.$store.state.netdisk.storageValue)
      return this.$store.state.netdisk.storageValue
    },
    totalStorageValue() {
      console.log("totalStorageValue =",this.$store.state.netdisk.totalStorageValue)
      return this.$store.state.netdisk.totalStorageValue
    },
    // 存储百分比
    storagePercentage() {
      return this.totalStorageValue
        ? (this.storageValue / this.totalStorageValue) * 100
        : 0
    },
    // 屏幕宽度
    screenWidth() {
      return this.$store.state.netdisk.screenWidth
    }
  },
  watch: {
    // 监听左侧菜单切换,修改浏览器标签标题
    activeIndex(newValue) {
      document.title = `${this.myFileMenuMap[Number(newValue)]} - ${
        window._CONFIG['siteName']
      }`
      this.isDrawer = false
    },
    // 监听收缩状态变化,存储在 localStorage 中,保证页面刷新时仍然保存设置的状态
    isCollapse(newValue) {
      localStorage.setItem('estar_is_collapse', newValue)
      if (this.screenWidth <= 768 && newValue) {
        this.isDrawer = true
        this.isCollapse = false
      }
    }
  },
  created() {
    this.isCollapse = localStorage.getItem('estar_is_collapse') === 'true' //  读取保存的状态
  },
  mounted() {
    document.title = `${this.myFileMenuMap[Number(this.activeIndex)]} - ${
      window._CONFIG['siteName']
    }`
  }
}
</script>
<style lang="stylus" scoped>
@import '~@/assets/nd/styles/varibles.styl'
@import '~@/assets/nd/styles/mixins.styl'
.side-menu-wrapper {
  position: relative;
  height: calc(100vh - 61px);
  padding-right: 11px;
  .side-menu {
    // 高度设置为屏幕高度减去顶部导航栏的高度
    height: calc(100vh - 127px);
    overflow: auto;
    // 调整滚动条样式
    setScrollbar(6px, transparent, #C0C4CC);
    .el-menu-item.is-active {
      background: #ecf5ff;
    }
    .my-file, .recovery {
      box-shadow: 0 4px 12px 0 $BorderExtralight;
    }
  }
  >>> .el-menu {
    background: transparent;
  }
  // 对展开状态下的菜单设置宽度
  .side-menu:not(.el-menu--collapse) {
    width: 210px;
  }
  // 存储空间展示区
  .storage-wrapper {
    position: absolute;
    bottom: 0;
    left: 0;
    box-shadow: 0 -2px 12px 0 $BorderExtralight;
    border-right: solid 1px #e6e6e6;
    box-sizing: border-box;
    width: calc(100% - 11px);
    height: 66px;
    padding: 16px;
    z-index: 2;
    color: $PrimaryText;
    .text {
      margin-top: 8px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 12px;
      flex-wrap: wrap;
    }
  }
  .storage-wrapper.fold {
    padding: 0;
    >>> .el-progress--circle {
      margin: 0 auto;
      width: 32px;
      display: block;
    }
    .text {
      font-size: 12px;
      justify-content: center;
    }
  }
  // 折叠图标调整样式
  .aside-title {
    position: absolute;
    top: calc(50% - 50px);
    right: 0;
    z-index: 2;
    background: $BorderBase;
    color: #fff;
    width: 12px;
    height: 100px;
    line-height: 100px;
    cursor: pointer;
    border-radius: 0 16px 16px 0;
    &:hover {
      opacity: 0.7;
    }
    .icon {
      font-size: 12px;
    }
  }
}
</style>

右边的文件列表主要就是显示界面上方的上传数据及批量操作行为,同时提供三种显示模式

<template>
  <div class="file-list-wrapper">
    <!-- 操作按钮 -->
    <el-header height="auto">
      <OperationMenu
        :fileType="fileType"
        :filePath="filePath"
        @getSearchFileList="getSearchFileList"
        @getTableDataByType="getTableDataByType"
      ></OperationMenu>
    </el-header>
    <div class="middle-wrapper">
      <!-- 面包屑导航栏 -->
      <BreadCrumb
        class="breadcrumb"
        :fileType="fileType"
        :filePath="filePath"
        @getTableDataByType="getTableDataByType"
      ></BreadCrumb>
    </div>
    <!-- 文件列表-表格模式 -->
    <FileTable
      :fileType="fileType"
      :filePath="filePath"
      :fileList="fileList"
      :loading.sync="loading"
      v-if="fileModel === 0"
      @getTableDataByType="getTableDataByType"
      @click.native.right="handleClickRight"
    ></FileTable>
    <!-- 文件列表-网格模式 -->
    <FileGrid
      :fileType="fileType"
      :filePath="filePath"
      :fileList="fileList"
      :loading="loading"
      v-if="fileModel === 1"
      @getTableDataByType="getTableDataByType"
      @click.native.right="handleClickRight"
    ></FileGrid>
    <!-- 图片-时间线模式 -->
    <FileTimeLine
      class="image-model"
      :fileList="fileList"
      :loading.sync="loading"
      v-if="fileModel === 2 && fileType === 1"
      @getTableDataByType="getTableDataByType"
      @click.native.right="handleClickRight"
    ></FileTimeLine>
    <div class="pagination-wrapper">
      <div class="current-page-count">当前页{{ fileList.length }}条</div>
      <!-- 回收站不展示分页组件 -->
      <el-pagination
        :current-page="pageData.currentPage"
        :page-size="pageData.pageCount"
        :total="pageData.total"
        :page-sizes="[10, 50, 100, 200]"
        :layout="
          screenWidth <= 768
            ? 'total, prev, next, jumper'
            : 'sizes, total, prev, pager, next'
        "
        @current-change="handleCurrentChange"
        @size-change="handleSizeChange"
        v-if="fileType !== 6"
      >
      </el-pagination>
    </div>
  </div>
</template>
<script>
import OperationMenu from './components/OperationMenu.vue'
import BreadCrumb from '../common/BreadCrumb.vue'
import FileTable from '../common/FileTable.vue'
import FileGrid from './components/FileGrid.vue'
import FileTimeLine from './components/FileTimeLine.vue'
import {
  getFileListByPath,
  getFileListByType,
  getRecoveryFile,
  getMyShareFileList,
  searchFile
} from '@/api/netdisk/file.js'
export default {
  name: 'FileList',
  components: {
    OperationMenu,
    BreadCrumb,
    FileTable,
    FileGrid,
    FileTimeLine
  },
  data() {
    return {
      fileNameSearch: '',
      loading: true, //  表格数据-loading
      fileList: [], //  表格数据-文件列表
      // 分页数据
      pageData: {
        currentPage: 1,
        pageCount: 50,
        total: 0
      }
    }
  },
  computed: {
    // 左侧菜单选中的文件类型
    fileType() {
      return this.$route.query.fileType ? Number(this.$route.query.fileType) : 0
    },
    // 当前所在路径
    filePath() {
      return this.$route.query.filePath ? this.$route.query.filePath : '/'
    },
    // 文件查看模式 0列表模式 1网格模式 2 时间线模式
    fileModel() {
      return this.$store.getters.fileModel
    },
    // 屏幕宽度
    screenWidth() {
      return this.$store.state.netdisk.screenWidth
    }
  },
  watch: {
    filePath() {
      // 当左侧菜单选择“全部”或“我的分享”,文件路径发生变化时,再重新获取文件列表
      if (this.$route.name === 'netdiskfile' && [0, 8].includes(this.fileType)) {
        this.setPageCount()
        this.getTableDataByType()
      }
    },
    fileType() {
      if (this.$route.name === 'netdiskfile') {
        this.setPageCount()
        this.getTableDataByType()
      }
    },
    // 监听文件查看模式
    fileModel() {
      this.setPageCount()
    }
  },
  created() {
    this.setPageCount()
    this.getTableDataByType()
  },
  methods: {
    /**
     * 文件展示区域的空白处右键事件
     * @param {Document} event 右键事件对象
     */
    handleClickRight(event) {
      event.preventDefault()
      // 只有在全部页面才可以进行以下操作
      if (![6, 8].includes(this.fileType)) {
        this.$openBox
          .contextMenu({
            selectedFile: undefined,
            domEvent: event,
            serviceEl: this
          })
          .then((res) => {
            if (res === 'confirm') {
              this.getTableDataByType() //  刷新文件列表
              this.$store.dispatch('showStorage') //  刷新存储容量
            }
          })
      }
    },
    /**
     * 表格数据获取相关事件 | 调整分页大小
     */
    setPageCount() {
      this.pageData.currentPage = 1
      if (this.fileModel === 0) {
        this.pageData.pageCount = 50
      }
      if (this.fileModel === 1) {
        this.pageData.pageCount = 100
      }
    },
    /**
     * 表格数据获取相关事件 | 获取文件列表数据
     */
    getTableDataByType() {
      this.loading = true
      console.log("getTableDataByType this.fileType=",this.fileType)
      // 分类型
      if (Number(this.fileType)) {
        switch (Number(this.fileType)) {
          case 6: {
            this.showFileRecovery() //  回收站
            break
          }
          case 8: {
            this.showMyShareFile() //  我的分享
            break
          }
          default: {
            this.showFileList()
            break
          }
        }
      } else {
        // 全部文件
        this.showFileList()
      }
      this.$store.dispatch('showStorage')
    },
    /**
     * 表格数据获取相关事件 | 获取当前路径下的文件列表
     */
    showFileList() {
      let data = {
        fileType: this.fileType,
        filePath: this.filePath,
        currentPage: this.pageData.currentPage,
        pageCount: this.pageData.pageCount
      }
      getFileListByPath(data).then((res) => {
        if (res.success) {
          console.log("getFileListByPath res=",res);
          this.fileList = res.result.records
          this.pageData.total = Number(res.result.total)
          this.loading = false
        } else {
          this.$message.error(res.message)
        }
      })
    },
    /**
     * 表格数据获取相关事件 | 分页组件 | 当前页码改变
     */
    handleCurrentChange(currentPage) {
      this.pageData.currentPage = currentPage
      this.getTableDataByType()
    },
    /**
     * 表格数据获取相关事件 | 分页组件 | 页大小改变时
     */
    handleSizeChange(pageCount) {
      this.pageData.pageCount = pageCount
      this.getTableDataByType()
    },
    /**
     * 表格数据获取相关事件 | 获取回收站文件列表
     */
    showFileRecovery() {
      getRecoveryFile().then((res) => {
        console.log("getRecoveryFile res",res)
        if (res.success) {
          this.fileList = res.result
          this.loading = false
        } else {
          this.$message.error(res.message)
        }
      })
    },
    /**
     * 表格数据获取相关事件 | 获取我的分享列表
     */
    showMyShareFile() {
      let data = {
        shareFilePath: this.filePath,
        shareBatchNum: this.$route.query.shareBatchNum,
        currentPage: this.pageData.currentPage,
        pageCount: this.pageData.pageCount
      }
      getMyShareFileList(data).then((res) => {
        if (res.success) {
          this.fileList = res.result
          this.pageData.total = Number(res.total)
          this.loading = false
        } else {
          this.$message.error(res.message)
        }
      })
    },
    /**
     * 表格数据获取相关事件 | 根据文件类型展示文件列表
     */
    showFileListByType() {
      //  分类型
      let data = {
        fileType: this.fileType,
        currentPage: this.pageData.currentPage,
        pageCount: this.pageData.pageCount
      }
      getFileListByType(data).then((res) => {
        if (res.success) {
          this.fileList = res.result.records
          this.pageData.total = Number(res.total)
          this.loading = false
        } else {
          this.$message.error(res.message)
        }
      })
    },
    /**
     * 获取搜索文件结果列表
     * @param {string} fileName 文件名称
     */
    getSearchFileList(fileName) {
      this.loading = true
      let data = {
        fileName: fileName,
        filePath: this.filePath,
        currentPage: this.pageData.currentPage,
        pageCount: this.pageData.pageCount
      }
      searchFile(data).then((res) => {
        this.loading = false
        if (res.success) {
          this.fileList = res.result.records
          this.pageData.total = Number(res.total)
          this.loading = false
        } else {
          this.$message.error(res.message)
        }
      })
    }
  }
}
</script>
<style lang="stylus" scoped>
@import '~@/assets/nd/styles/varibles.styl'
@import '~@/assets/nd/styles/mixins.styl'
.file-list-wrapper {
  >>> .el-header {
    padding: 0;
  }
  .middle-wrapper {
    margin-bottom: 8px;
  }
  .pagination-wrapper {
    position: relative;
    border-top: 1px solid $BorderBase;
    height: 44px;
    line-height: 44px;
    text-align: center;
    .current-page-count {
      position: absolute;
      left: 16px;
      height: 32px;
      line-height: 32px;
      font-size: 13px;
      color: $RegularText;
    }
  }
}
</style>

其中,文件列表模式如下

<template>
  <div class="file-table-wrapper">
    <!-- 文件表格 -->
    <el-table
      class="file-table"
      :class="['file-type-' + fileType, routeName === 'Share' ? 'share' : '']"
      ref="multipleTable"
      fit
      v-loading="loading"
      element-loading-text="文件加载中……"
      tooltip-effect="dark"
      :data="fileList"
      :highlight-current-row="true"
      @selection-change="handleSelectRow"
      @sort-change="handleSortChange"
      @row-contextmenu="handleContextMenu"
    >
      <el-table-column
        type="selection"
        key="selection"
        width="56"
        align="center"
        v-if="fileType !== 8"
      ></el-table-column>
      <el-table-column
        label
        prop="isDir"
        key="isDir"
        :width="screenWidth <= 768 ? 40 : 56"
        align="center"
        class-name="file-icon-column"
      >
        <template slot-scope="scope">
          <video
            style="width: 30px; max-height: 30px; cursor: pointer"
            v-if="$file.isVideoFile(scope.row)"
            :src="$file.setFileImg(scope.row)"
          ></video>
          <img
            :src="$file.setFileImg(scope.row)"
            :title="`${scope.row.isDir ? '' : '点击预览'}`"
            style="width: 30px; max-height: 30px; cursor: pointer"
            @click="
              $file.handleFileNameClick(scope.row, scope.$index, sortedFileList)
            "
            v-else
          />
        </template>
      </el-table-column>
      <el-table-column
        prop="fileName"
        key="fileName"
        :sort-by="['isDir', 'fileName']"
        sortable
        show-overflow-tooltip
      >
        <template slot="header">
          <span>文件名</span>
        </template>
        <template slot-scope="scope">
          <span
            @click="
              $file.handleFileNameClick(scope.row, scope.$index, sortedFileList)
            "
          >
            <span
              class="file-name"
              style="cursor: pointer"
              :title="`${scope.row.isDir ? '' : '点击预览'}`"
              v-html="$file.getFileNameComplete(scope.row, true)"
            ></span>
            <div class="file-info" v-if="screenWidth <= 768">
              {{ scope.row.uploadTime }}
              <span class="file-size">
                {{
                  scope.row.isDir === 0
                    ? $file.calculateFileSize(scope.row.fileSize)
                    : ''
                }}
              </span>
            </div>
          </span>
        </template>
      </el-table-column>
      <el-table-column
        :label="fileType === 6 ? '原路径' : '路径'"
        prop="filePath"
        key="filePath"
        show-overflow-tooltip
        v-if="
          ![8].includes(Number($route.query.fileType)) &&
          routeName !== 'Share' &&
          screenWidth > 768
        "
      >
        <template slot-scope="scope">
          <span
            style="cursor: pointer"
            title="点击跳转"
            @click="
              $router.push({
                query: { filePath: scope.row.filePath, fileType: 0 }
              })
            "
            >{{ scope.row.filePath }}</span
          >
        </template>
      </el-table-column>
      <el-table-column
        label="类型"
        width="80"
        prop="extendName"
        key="extendName"
        :sort-by="['isDir', 'extendName']"
        sortable
        show-overflow-tooltip
        v-if="selectedColumnList.includes('extendName') && screenWidth > 768"
      >
        <template slot-scope="scope">
          <span>{{ $file.getFileType(scope.row) }}</span>
        </template>
      </el-table-column>
      <el-table-column
        label="大小"
        width="100"
        prop="fileSize"
        key="fileSize"
        :sort-by="['isDir', 'fileSize']"
        sortable
        align="right"
        v-if="selectedColumnList.includes('fileSize') && screenWidth > 768"
      >
        <template slot-scope="scope">
          {{
            scope.row.isDir === 0
              ? $file.calculateFileSize(scope.row.fileSize)
              : ''
          }}
        </template>
      </el-table-column>
      <el-table-column
        label="修改日期"
        prop="uploadTime"
        key="uploadTime"
        width="160"
        :sort-by="['isDir', 'uploadTime']"
        sortable
        align="center"
        v-if="
          selectedColumnList.includes('uploadTime') &&
          ![7, 8].includes(fileType) &&
          !['Share'].includes(this.routeName) &&
          screenWidth > 768
        "
      ></el-table-column>
      <el-table-column
        label="删除日期"
        prop="deleteTime"
        key="deleteTime"
        width="160"
        :sort-by="['isDir', 'deleteTime']"
        sortable
        align="center"
        v-if="
          fileType === 6 &&
          selectedColumnList.includes('deleteTime') &&
          screenWidth > 768
        "
      ></el-table-column>
      <el-table-column
        label="分享类型"
        prop="shareType"
        key="shareType"
        width="100"
        align="center"
        v-if="fileType === 8 && screenWidth > 768"
      >
        <template slot-scope="scope">
          {{ scope.row.shareType === 1 ? '私密' : '公共' }}
        </template>
      </el-table-column>
      <el-table-column
        label="分享时间"
        prop="shareTime"
        key="shareTime"
        width="160"
        :sort-by="['isDir', 'shareTime']"
        show-overflow-tooltip
        sortable
        align="center"
        v-if="fileType === 8 && screenWidth > 768"
      ></el-table-column>
      <el-table-column
        label="过期时间"
        prop="endTime"
        key="endTime"
        width="190"
        :sort-by="['isDir', 'endTime']"
        show-overflow-tooltip
        sortable
        align="center"
        v-if="fileType === 8 && screenWidth > 768"
      >
        <template slot-scope="scope">
          <div>
            <i
              class="el-icon-warning"
              v-if="$file.getFileShareStatus(scope.row.endTime)"
            ></i>
            <i class="el-icon-time" v-else></i>
            {{ scope.row.endTime }}
          </div>
        </template>
      </el-table-column>
      <el-table-column
        label=""
        key="operation"
        width="48"
        v-if="screenWidth <= 768"
      >
        <template slot-scope="scope">
          <i
            class="file-operate el-icon-more"
            :class="`operate-more-${scope.$index}`"
            @click="handleClickMore(scope.row, $event)"
          ></i>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
import '@/assets/nd/styles/varibles.styl'
import '@/assets/nd/styles/mixins.styl'  
import { mapGetters } from 'vuex'
export default {
  name: 'FileTable',
  props: {
    // 文件类型
    fileType: {
      required: true,
      type: Number
    },
    // 文件路径
    filePath: {
      required: true,
      type: String
    },
    // 文件列表
    fileList: {
      required: true,
      type: Array
    },
    // 文件加载状态
    loading: {
      required: true,
      type: Boolean
    }
  },
  data() {
    return {
      officeFileType: ['ppt', 'pptx', 'doc', 'docx', 'xls', 'xlsx'],
      sortedFileList: [] //  排序后的表格数据
    }
  },
  computed: {
    //  selectedColumnList: 判断当前用户设置的左侧栏是否折叠
    ...mapGetters(['selectedColumnList']),
    // 路由名称
    routeName() {
      return this.$route.name
    },
    // 屏幕宽度
    screenWidth() {
      return this.$store.state.netdisk.screenWidth
    }
  },
  watch: {
    /**
     * 文件路径变化时清空表格已选行
     */
    filePath() {
      this.clearSelectedTable()
      this.$refs.multipleTable.clearSort()
    },
    /**
     * 文件类型变化时清空表格已选行
     */
    fileType() {
      this.clearSelectedTable()
      this.$refs.multipleTable.clearSort()
    },
    /**
     * 文件列表变化时清空表格已选行
     */
    fileList() {
      this.clearSelectedTable()
      this.$refs.multipleTable.clearSort()
      this.sortedFileList = this.fileList
    }
  },
  methods: {
    /**
     * 当表格的排序条件发生变化的时候会触发该事件
     */
    handleSortChange() {
      this.sortedFileList = this.$refs.multipleTable.tableData
    },
    /**
     * 表格某一行右键事件
     * @description 打开右键菜单
     * @param {object} row 当前行数据
     * @param {object} column 当前列数据
     * @param {object} event 当前右键元素
     */
    handleContextMenu(row, column, event) {
      // 阻止右键事件冒泡
      event.cancelBubble = true
      // xs 以上的屏幕
      if (this.screenWidth > 768) {
        event.preventDefault()
        this.$refs.multipleTable.setCurrentRow(row) //  选中当前行
        this.$openBox
          .contextMenu({
            selectedFile: row,
            domEvent: event
          })
          .then((res) => {
            this.$refs.multipleTable.setCurrentRow() //  取消当前选中行
            if (res === 'confirm') {
              this.$emit('getTableDataByType') //  刷新文件列表
              this.$store.dispatch('showStorage') //  刷新存储容量
            }
          })
      }
    },
    /**
     * 清空表格已选行
     * @description 用于父组件调用 | 本组件调用,请勿删除
     */
    clearSelectedTable() {
      this.$refs.multipleTable.clearSelection()
    },
    /**
     * 表格选择项发生变化时的回调函数
     * @param {[]} selection 勾选的行数据
     */
    handleSelectRow(selection) {
      this.$store.commit('changeSelectedFiles', selection)
      this.$store.commit('changeIsBatchOperation', selection.length !== 0)
    },
    /**
     * 更多图标点击事件
     * @description 打开右键菜单
     * @param {object} row 当前行数据
     * @param {object} event 当前右键元素
     */
    handleClickMore(row, event) {
      this.$refs.multipleTable.setCurrentRow(row) //  选中当前行
      this.$openBox
        .contextMenu({
          selectedFile: row,
          domEvent: event
        })
        .then((res) => {
          this.$refs.multipleTable.setCurrentRow() //  取消当前选中行
          if (res === 'confirm') {
            this.$emit('getTableDataByType') //  刷新文件列表
            this.$store.dispatch('showStorage') //  刷新存储容量
          }
        })
    }
  }
}
</script>
<style lang="stylus" scoped>
.file-table-wrapper {
  margin-top: 2px;
  .file-type-0 {
    height: calc(100vh - 206px) !important;
    >>> .el-table__body-wrapper {
      height: calc(100vh - 262px) !important;
    }
  }
  .file-type-6 {
    height: calc(100vh - 211px) !important;
    >>> .el-table__body-wrapper {
      height: calc(100vh - 263px) !important;
    }
  }
  .file-table.share {
    height: calc(100vh - 109px) !important;
    >>> .el-table__body-wrapper {
      height: calc(100vh - 161px) !important;
    }
  }
  .file-table {
    width: 100% !important;
    height: calc(100vh - 203px);
    >>> .el-table__header-wrapper {
      th {
        // background: $tabBackColor;
        padding: 4px 0;
        color: $RegularText;
      }
      .el-icon-circle-plus, .el-icon-remove {
        margin-left: 6px;
        cursor: pointer;
        font-size: 16px;
        &:hover {
          color: $Primary;
        }
      }
    }
    >>> .el-table__body-wrapper {
      height: calc(100vh - 255px);
      overflow-y: auto;
      setScrollbar(6px, transparent, #C0C4CC);
      td {
        padding: 8px 0;
        .file-name {
          .keyword {
            color: $Danger;
          }
        }
      }
      .el-icon-warning {
        font-size: 16px;
        color: $Warning;
      }
      .el-icon-time {
        font-size: 16px;
        color: $Success;
      }
    }
  }
}
.right-menu-list {
  position: fixed;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid $BorderLighter;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 2;
  padding: 4px 0;
  color: $RegularText;
  .right-menu-item,
  .unzip-item {
    padding: 0 16px;
    height: 36px;
    line-height: 36px;
    cursor: pointer;
    &:hover {
      background: $PrimaryHover;
      color: $Primary;
    }
    i {
      margin-right: 8px;
    }
  }
  .unzip-menu-item {
    position: relative;
    &:hover {
      .unzip-list {
        display: block;
      }
    }
    .unzip-list {
      position: absolute;
      display: none;
      .unzip-item {
        width: 200px;
        setEllipsis(1)
      }
    }
  }
}
.right-menu-list,
.unzip-list {
  background: #fff;
  border: 1px solid $BorderLighter;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 2;
  padding: 4px 0;
  color: $RegularText;
}
</style>

上面主要是一个对文件或目录的右键菜单操作

<template>
  <!-- 右键列表 -->
  <transition name="el-fade-in-linear">
    <!-- 在某个文件上右键 -->
    <ul
      class="right-menu-list"
      id="rightMenuList"
      v-show="visible"
      v-if="selectedFile !== undefined"
      :style="`top: ${rightMenu.top};right: ${rightMenu.right};bottom: ${rightMenu.bottom};left: ${rightMenu.left};`"
    >
      <li
        class="right-menu-item"
        @click="$file.handleFileNameClick(selectedFile, 0, [selectedFile])"
        v-if="seeBtnShow"
      >
        <i class="el-icon-view"></i> 查看
      </li>
      <li
        class="right-menu-item"
        @click="handleDeleteFileBtnClick(selectedFile)"
        v-if="deleteBtnShow"
      >
        <i class="el-icon-delete"></i> 删除
      </li>
      <li
        class="right-menu-item"
        @click="handleRestoreFileBtnClick(selectedFile)"
        v-if="restoreBtnShow"
      >
        <i class="el-icon-refresh-left"></i> 还原
      </li>
      <li
        class="right-menu-item"
        @click="handleCopyFileBtnClick(selectedFile)"
        v-if="copyBtnShow"
      >
        <i class="el-icon-copy-document"></i> 复制到
      </li>
      <li
        class="right-menu-item"
        @click="handleMoveFileBtnClick(selectedFile)"
        v-if="moveBtnShow"
      >
        <i class="el-icon-s-promotion"></i> 移动
      </li>
      <li
        class="right-menu-item"
        @click="handleRenameFileBtnClick(selectedFile)"
        v-if="renameBtnShow"
      >
        <i class="el-icon-edit-outline"></i> 重命名
      </li>
      <li
        class="right-menu-item"
        @click="handleShareFileBtnClick(selectedFile)"
        v-if="shareBtnShow"
      >
        <i class="el-icon-share"></i> 分享
      </li>
      <li
        class="right-menu-item"
        @click="visible = false"
        v-if="downloadBtnShow"
      >
        <a
          target="_blank"
          style="display: block; color: inherit"
          :href="$file.getDownloadFilePath(selectedFile)"
          :download="selectedFile.fileName + '.' + selectedFile.extendName"
        >
          <i class="el-icon-download"></i> 下载
        </a>
      </li>
      <!-- 0-解压到当前文件夹, 1-自动创建该文件名目录,并解压到目录里, 3-手动选择解压目录 -->
      <li class="right-menu-item unzip-menu-item" v-if="unzipBtnShow">
        <i class="el-icon-files"></i> 解压缩
        <i class="el-icon-arrow-right"></i>
        <ul
          class="unzip-list"
          :style="`top: ${unzipMenu.top};bottom: ${unzipMenu.bottom};left: ${unzipMenu.left};right: ${unzipMenu.right};`"
        >
          <li
            class="unzip-item"
            @click="handleUnzipFileBtnClick(selectedFile, 0)"
          >
            <i class="el-icon-files"></i> 解压到当前文件夹
          </li>
          <li
            class="unzip-item"
            @click="handleUnzipFileBtnClick(selectedFile, 1)"
            :title="`解压到&quot;${selectedFile.fileName}&quot;`"
          >
            <i class="el-icon-files"></i> 解压到"{{ selectedFile.fileName }}"
          </li>
          <li
            class="unzip-item"
            @click="handleUnzipFileBtnClick(selectedFile, 2)"
          >
            <i class="el-icon-files"></i> 解压到目标文件夹
          </li>
        </ul>
      </li>
      <!-- <li
        class="right-menu-item"
        @click="handleClickFolderEdit"
        v-if="folderEditBtnShow"
      >
        <i class="el-icon-edit"></i> 编辑文件夹
      </li> -->
      <li
        class="right-menu-item"
        @click="handleClickFileEdit(selectedFile)"
        v-if="onlineEditBtnShow"
      >
        <i class="el-icon-edit"></i> 在线编辑
      </li>
      <li
        class="right-menu-item"
        @click="
          $file.copyShareLink(
            selectedFile.shareBatchNum,
            selectedFile.extractionCode
          )
        "
        v-if="copyLinkBtnShow"
      >
        <i class="el-icon-edit"></i> 复制链接
      </li>
      <li
        class="right-menu-item"
        @click="handleShowDetailInfo(selectedFile)"
        v-if="detailInfoBtnShow"
      >
        <i class="el-icon-document"></i> 文件详情
      </li>
    </ul>
    <!-- 在空白处右键,右键列表展示新建文件夹、新建文件等操作按钮 -->
    <ul
      class="right-menu-list add"
      id="rightMenuList"
      v-show="visible"
      v-else
      :style="`top: ${rightMenu.top};right: ${rightMenu.right};bottom: ${rightMenu.bottom};left: ${rightMenu.left};`"
    >
      <li class="right-menu-item" @click="callback('confirm')">
        <i class="el-icon-refresh"></i> 刷新
      </li>
      <template v-if="fileType === 0">
        <el-divider />
        <li class="right-menu-item" @click="handleClickAddFolderBtn">
          <i class="el-icon-folder-add"></i> 新建文件夹
        </li>
        <li class="right-menu-item" @click="handleCreateFile('docx')">
          <img :src="wordImg" />新建 Word 文档
        </li>
        <li class="right-menu-item" @click="handleCreateFile('xlsx')">
          <img :src="excelImg" />新建 Excel 工作表
        </li>
        <li class="right-menu-item" @click="handleCreateFile('pptx')">
          <img :src="pptImg" />新建 PPT 演示文稿
        </li>
        <el-divider />
        <li class="right-menu-item" @click="handleUploadFileBtnClick(1)">
          <i class="el-icon-upload2"></i> 上传文件
        </li>
        <li class="right-menu-item" @click="handleUploadFileBtnClick(2)">
          <i class="el-icon-folder-opened"></i> 上传文件夹
        </li>
        <li class="right-menu-item" @click="handleUploadFileBtnClick(3)">
          <i class="el-icon-thumb"></i> 拖拽上传
        </li>
      </template>
    </ul>
  </transition>
</template>
<script>
import router from '@/router/index.js'
import {
  officeFileType,
  fileSuffixCodeModeMap,
  markdownFileType
} from '@/libs/map.js'
export default {
  name: 'ContextMenu',
  data() {
    return {
      officeFileType,
      fileSuffixCodeModeMap,
      markdownFileType,
      visible: false, //  右键菜单是否显示
      sortedFileList: [], //  排序后的表格数据
      // 右键菜单
      rightMenu: {
        top: 0,
        left: 0,
        bottom: 'auto',
        right: 'auto'
      },
      // 右键解压缩菜单
      unzipMenu: {
        top: 0,
        bottom: 'auto',
        left: '126px',
        right: 'auto'
      },
      dirImg: require('@/assets/nd/images/file/dir.png'),
      wordImg: require('@/assets/nd/images/file/file_word.svg'),
      excelImg: require('@/assets/nd/images/file/file_excel.svg'),
      pptImg: require('@/assets/nd/images/file/file_ppt.svg')
    }
  },
  computed: {
    // 路由名称
    routeName() {
      return router.currentRoute.name
    },
    // 左侧菜单选中的文件类型
    fileType() {
      return router.currentRoute.query.fileType
        ? Number(router.currentRoute.query.fileType)
        : 0
    },
    // 当前路径
    filePath() {
      return router.currentRoute.query.filePath
    },
    // 查看按钮是否显示
    seeBtnShow() {
      return this.fileType !== 6
    },
    // 删除按钮是否显示
    deleteBtnShow() {
      return this.fileType !== 8 && !['Share'].includes(this.routeName)
    },
    // 还原按钮是否显示
    restoreBtnShow() {
      return this.fileType === 6 && !['Share'].includes(this.routeName)
    },
    // 复制按钮是否显示
    copyBtnShow() {
      return (
        ![6, 8].includes(this.fileType) && !['Share'].includes(this.routeName)
      )
    },
    // 移动按钮是否显示
    moveBtnShow() {
      return (
        ![6, 8].includes(this.fileType) && !['Share'].includes(this.routeName)
      )
    },
    // 重命名按钮是否显示
    renameBtnShow() {
      return (
        ![6, 8].includes(this.fileType) && !['Share'].includes(this.routeName)
      )
    },
    // 分享按钮是否显示
    shareBtnShow() {
      return (
        ![6, 8].includes(this.fileType) && !['Share'].includes(this.routeName)
      )
    },
    // 下载按钮是否显示
    downloadBtnShow() {
      return ![6, 8].includes(this.fileType)
    },
    // 解压缩按钮是否显示
    unzipBtnShow() {
      return (
        ![6, 8].includes(this.fileType) &&
        !['Share'].includes(this.routeName) &&
        ['zip', 'rar', '7z', 'tar', 'gz'].includes(this.selectedFile.extendName)
      )
    },
    // 编辑文件夹按钮是否显示
    folderEditBtnShow() {
      return (
        ![6, 8].includes(this.fileType) &&
        this.selectedFile.isDir === 1 &&
        !['Share'].includes(this.routeName)
      )
    },
    // 在线编辑按钮是否显示
    onlineEditBtnShow() {
      return (
        ![6, 8].includes(this.fileType) &&
        (this.officeFileType.includes(this.selectedFile.extendName) ||
          this.markdownFileType.includes(this.selectedFile.extendName) ||
          this.fileSuffixCodeModeMap.has(this.selectedFile.extendName)) &&
        !['Share'].includes(this.routeName)
      )
    },
    // 复制链接按钮是否显示
    copyLinkBtnShow() {
      return this.fileType === 8
    },
    // 文件详情按钮是否显示
    detailInfoBtnShow() {
      return true
    },
    // 上传文件组件参数
    uploadFileParams() {
      return {
        filePath: this.filePath,
        isDir: 0
      }
    }
  },
  watch: {
    /**
     * 监听右键列表状态
     * @description 右键列表打开时,body 添加点击事件的监听
     */
    visible(newValue) {
      if (newValue === true) {
        document.body.addEventListener('click', this.closeRightMenu)
        this.handleOpenContextMenu()
      } else {
        document.body.removeEventListener('click', this.closeRightMenu)
      }
    }
  },
  methods: {
    /**
     * 打开右键菜单
     */
    handleOpenContextMenu() {
      // 纵坐标设置
      if (
        document.body.clientHeight - this.domEvent.clientY <
        document.querySelectorAll('#rightMenuList > .right-menu-item').length *
          36 +
          10
      ) {
        // 如果到底部的距离小于元素总高度
        this.rightMenu.top = 'auto'
        this.rightMenu.bottom = `${
          document.body.clientHeight - this.domEvent.clientY
        }px`
        this.unzipMenu.top = 'auto'
        this.unzipMenu.bottom = '0px'
      } else {
        this.rightMenu.top = `${this.domEvent.clientY}px`
        this.rightMenu.bottom = 'auto'
        this.unzipMenu.top = '0px'
        this.unzipMenu.bottom = 'auto'
      }
      // 横坐标设置
      if (document.body.clientWidth - this.domEvent.clientX < 138) {
        // 如果到右边的距离小于元素总宽度
        this.rightMenu.left = 'auto'
        this.rightMenu.right = `${
          document.body.clientWidth - this.domEvent.clientX
        }px`
        this.unzipMenu.left = '-200px'
        this.unzipMenu.right = 'auto'
      } else {
        this.rightMenu.left = `${this.domEvent.clientX + 8}px`
        this.rightMenu.right = 'auto'
        this.unzipMenu.left = '126px'
        this.unzipMenu.right = 'auto'
      }
      this.visible = true
    },
    /**
     * 关闭右键列表
     */
    closeRightMenu(event) {
      if (
        !event.target.className.includes('operate-more-') &&
        !event.target.className.includes('unzip-menu-item')
      ) {
        this.visible = false
        if (this.selectedFile !== undefined) {
          // 不是在空白处右键时
          this.callback('cancel')
        }
      }
    },
    /**
     * 复制按钮点击事件
     * @description 向父组件传递当前操作的文件信息,并打开“复制文件对话框”
     * @param {object} fileInfo 文件信息
     */
    handleCopyFileBtnClick(fileInfo) {
      this.visible = false
      this.$openDialog
        .copyFile({
          fileInfo
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 移动按钮点击事件
     * @description 向父组件传递当前操作的文件信息,并打开“移动文件对话框”
     * @param {object} fileInfo 文件信息
     */
    handleMoveFileBtnClick(fileInfo) {
      this.visible = false
      this.$openDialog
        .moveFile({
          isBatchMove: false,
          fileInfo
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 解压缩按钮点击事件
     * @description 调用解压缩文件接口,并展示新的文件列表
     * @param {object} fileInfo 文件信息
     * @param {number} unzipMode 解压模式 0-解压到当前文件夹, 1-自动创建该文件名目录,并解压到目录里, 2-手动选择解压目录
     */
    handleUnzipFileBtnClick(fileInfo, unzipMode) {
      this.visible = false
      this.$openDialog
        .unzipFile({
          unzipMode: unzipMode,
          userFileId: fileInfo.userFileId
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 删除按钮点击事件
     * @description 区分 删除到回收站中 | 在回收站中彻底删除,打开确认对话框
     * @param {object} fileInfo 文件信息
     */
    handleDeleteFileBtnClick(fileInfo) {
      this.visible = false
      this.$openDialog
        .deleteFile({
          isBatchOperation: false,
          fileInfo,
          deleteMode: this.fileType === 6 ? 2 : 1 //  删除类型:1-删除到回收站 2-彻底删除
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 还原按钮点击事件
     * @description 调用接口,在回收站中还原文件
     * @param {object} fileInfo 文件信息
     */
    handleRestoreFileBtnClick(fileInfo) {
      this.visible = false
      this.$openDialog
        .restoreFile({
          deleteBatchNum: fileInfo.deleteBatchNum,
          filePath: fileInfo.filePath
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 文件重命名按钮点击事件
     * @description 打开确认对话框让用户输入新的文件名
     * @param {object} fileInfo 文件信息
     */
    handleRenameFileBtnClick(fileInfo) {
      this.visible = false
      this.$openDialog
        .renameFile({
          oldFileName: fileInfo.fileName,
          userFileId: fileInfo.userFileId
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 文件分享按钮点击事件
     * @description 打开对话框让用户选择过期时间和提取码
     * @param {object} fileInfo 文件信息
     */
    handleShareFileBtnClick(fileInfo) {
      this.visible = false
      this.$openDialog.shareFile({
        fileInfo: [
          {
            userFileId: fileInfo.userFileId
          }
        ]
      })
    },
    /**
     * 编辑文件夹按钮点击事件
     */
    handleClickFolderEdit() {
      router.push({
        name: 'WebIDE',
        query: { filePath: this.selectedFile.filePath }
      })
    },
    /**
     * 文件在线编辑按钮点击事件
     * @description 打开 代码预览对话框 或 office 编辑页面
     * @param {object} fileInfo 文件信息
     */
    handleClickFileEdit(fileInfo) {
      if (this.officeFileType.includes(fileInfo.extendName)) {
        // office 编辑页面
        this.$file.getFileOnlineEditPathByOffice(fileInfo)
      } else if (this.markdownFileType.includes(fileInfo.extendName)) {
        // markdown 编辑浮层
        this.$openBox.markdownPreview({
          fileInfo: fileInfo,
          editable: true
        })
      } else {
        // 代码编辑对话框
        this.$openBox.codePreview({ fileInfo: fileInfo, isEdit: true })
      }
    },
    /**
     * 文件详情按钮点击事件
     * @description 打开对话框展示文件完整信息
     * @param {object} fileInfo 文件信息
     */
    handleShowDetailInfo(fileInfo) {
      this.visible = false
      this.$openDialog.showFileDetail({ fileInfo })
    },
    /**
     * 新建文件夹按钮点击事件
     * @description 调用新建文件夹服务,并在弹窗确认回调事件中刷新文件列表
     */
    handleClickAddFolderBtn() {
      this.$openDialog
        .addFolder({
          filePath: router.currentRoute.query.filePath || '/'
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 新建 office 文件
     * @description 调用新建 office 文件服务,并在弹窗确认回调事件中刷新文件列表
     * @param {string} 文件扩展名 docx xlsx pptx
     */
    handleCreateFile(extendName) {
      this.$openDialog
        .addFile({
          extendName: extendName
        })
        .then((res) => {
          this.callback(res)
        })
    },
    /**
     * 上传文件按钮点击事件
     * @description 通过Bus通信,开启全局上传文件流程
     * @param {boolean} uploadWay 上传方式 0-文件上传 1-文件夹上传 2-粘贴图片或拖拽上传
     */
    handleUploadFileBtnClick(uploadWay) {
      this.$openBox.uploadFile({
        params: this.uploadFileParams,
        uploadWay,
        serviceEl: this.serviceEl,
        callType: true //  callType 调用此服务的方式:1 - 顶部栏,2 - 右键菜单
      })
    }
  }
}
</script>
<style lang="stylus" scoped>
@import '~@/assets/nd/styles/varibles.styl'
@import '~@/assets/nd/styles/mixins.styl'
.right-menu-list {
  position: fixed;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid $BorderLighter;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 2;
  padding: 4px 0;
  color: $RegularText;
  list-style: none;
  .right-menu-item,
  .unzip-item {
    padding: 0 16px;
    height: 36px;
    line-height: 36px;
    cursor: pointer;
    &:hover {
      background: $PrimaryHover;
      color: $Primary;
    }
    i {
      margin-right: 8px;
    }
  }
  &.add {
    .right-menu-item {
      display: flex;
      align-items: center;
      img {
        margin-right: 4px;
        height: 20px;
      }
      i {
        margin-right: 4px;
        font-size: 18px;
      }
    }
  }
  .unzip-menu-item {
    position: relative;
    &:hover {
      .unzip-list {
        display: block;
      }
    }
    .unzip-list {
      position: absolute;
      display: none;
      list-style: none;
      .unzip-item {
        width: 200px;
        setEllipsis(1)
      }
    }
  }
}
.right-menu-list,
.unzip-list {
  background: #fff;
  border: 1px solid $BorderLighter;
  border-radius: 6px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 2;
  padding: 8px 0;
  color: $RegularText;
  font-size: 14px;
  .el-divider {
    margin: 2px 0;
  }
}
</style>

整个前端的主要操作与代码就是这样。

相关文章
|
5天前
|
资源调度 前端开发 Java
基于Jeecgboot前后端分离的流程管理平台演示系统安装(二)
基于Jeecgboot前后端分离的流程管理平台演示系统安装(二)
13 1
|
5天前
|
网络协议 Java 网络安全
基于Jeecgboot前后端分离的流程管理平台演示系统安装(一)
基于Jeecgboot前后端分离的流程管理平台演示系统安装(一)
14 1
|
5天前
|
存储 对象存储
基于jeecgboot的个人网盘功能开发(三)
基于jeecgboot的个人网盘功能开发(三)
13 2
|
5天前
|
数据库
基于jeecgboot的个人网盘功能开发(一)
基于jeecgboot的个人网盘功能开发(一)
|
5天前
|
资源调度 前端开发 jenkins
基于Jeecgboot前后端分离的流程管理平台演示系统安装(四)
基于Jeecgboot前后端分离的流程管理平台演示系统安装(四)
14 1
|
5天前
|
前端开发 jenkins Java
基于Jeecgboot前后端分离的流程管理平台演示系统安装(三)
基于Jeecgboot前后端分离的流程管理平台演示系统安装(三)
13 1
|
5天前
|
jenkins 持续交付
基于Jeecgboot前后端分离的流程管理平台演示系统安装(五)
基于Jeecgboot前后端分离的流程管理平台演示系统安装(五)
10 0
基于Jeecgboot前后端分离的流程管理平台演示系统安装(五)
|
5天前
|
移动开发 前端开发
基于jeecgboot的个人网盘功能演示系统发布
基于jeecgboot的个人网盘功能演示系统发布
10 0
|
5天前
|
前端开发 Java 关系型数据库
基于Jeecgboot前后端分离的流程管理平台
基于Jeecgboot前后端分离的流程管理平台
15 0
|
5天前
|
移动开发 供应链 前端开发
基于jeecgboot的ERP部分演示功能发布
基于jeecgboot的ERP部分演示功能发布
10 0