拉钩教育管理系统项目实战(六) - 课程内容管理

624 阅读5分钟

笔记来源:拉勾教育 - 大前端就业集训营

文章内容:学习过程中的笔记、感悟、和经验

课程内容管理

内容管理组件、路由处理、跳转操作,动态路径传参

//src/router/index.js - 在路由中添加新的课程内容管理路由

{
  // 课程内容管理
  path: '/contentManagement/:courseId',
  name: 'contentManagement',
  component: () => import(/* webpackChunkName:'contentManagement' */ '@/views/course/contentManagement'),
  props: true
}
src/views/course/contentManagement.vue  新建课程内容管理页面

<template>
  <div>课程内容管理</div>
</template>

<script>
export default {
  name: 'contentManagement',
  // 参数
  props: ['courseId']
}
</script>

src/views/course/son/content.vue  内容管理按钮添加点击事件,带着课程id跳转到内容管理页面

<el-table-column
  label="操作">
  <template slot-scope="scope">
    <!-- 操作按钮 -->
    <el-button @click="editCoures(scope.row.id)">编辑</el-button>
    <el-button @click="managementCoures(scope.row.id)">内容管理</el-button>
  </template>
</el-table-column
  
// 内容管理
  managementCoures (courseId) {
    this.$router.push({
      name: 'contentManagement',
      params: {
        courseId
      }
    })
  },

课程数据展示

使用树形组件,使用拖拽功能

使用接口 获取课程数据

章节名和课时名字不同,需要特殊设置

// src/services/coures.js  封装获取课程全部章节内容接口 - getSectionAndLesson

// 获取课程全部章节内容
export const getSectionAndLesson = courseId => {
  return request({
    method: 'get',
    url: `/boss/course/section/getSectionAndLesson?courseId=${courseId}`
  })
}
src/views/course/contentManagement.vue  树勇树形组件、使用接口并且重新对应节点

<template>
  <el-card class="box-card">
    <!-- 标题 -->
    <div slot="header" class="clearfix">
      <span>编辑课程内容 - 课程ID:{{courseId}}</span>
    </div>
    <!-- 树形控件 -->
    <el-tree :data="treeData" :props="defaultProps" draggable></el-tree>
  </el-card>
</template>

<script>
// 引入接口 获取全部章节信息
import { getSectionAndLesson } from '@/services/coures'
export default {
  name: 'contentManagement',
  // 参数
  props: ['courseId'],
  data () {
    return {
      // 树形控件数据
      treeData: [],
      // 树形控件节点对应关系
      defaultProps: {
        // 子节点对应名字
        children: 'lessonDTOS',
        // 节点名称对应,因为章节名和节点名不同,所以要设置两个
        label (data) {
          return data.sectionName || data.theme
        }
      }
    }
  },
  // 生命周期钩子
  created () {
    // 调用方法获取课程全部章节数据
    this.getInfo(this.courseId)
  },
  methods: {
    // 获取课程全部内容
    async getInfo (courseId) {
      // 调用接口
      const { data } = await getSectionAndLesson(courseId)
      if (data.code === '000000') {
        // 如果获取成功,把数据交给树形结构
        this.treeData = data.data
      }
    }
  }
}
</script>

tree组件定制

结构设置,样式美化处理

src/views/course/contentManagement.vue

<template>
  <el-card class="box-card">
    <!-- 标题 -->
    <div slot="header" class="clearfix">
      <span>编辑课程内容 - 课程ID:{{courseId}}</span>
    </div>
    <!-- 树形控件 -->
    <el-tree :data="treeData" :props="defaultProps" draggable>
      <!-- 自定义结构 -->
      <div class="custom-tree-node" slot-scope="{ node, data }">
        <!-- 两个span 便于使用flex布局 -->
        <span>{{ node.label }}</span>
        <span>
          <el-button
            type="text"
            size="mini"
            @click="() => edit(data)">
            编辑
          </el-button>
          <!-- 使用v-if判断当前节点是不是章节,是章节添加按钮添加课时,否则按钮位为传视频 -->
          <el-button
            type="text"
            size="mini"
            v-if="node.level === 1">
            添加课时
          </el-button>
          <el-button
            type="text"
            size="mini"
            v-else>
            上传视频
          </el-button>
          <el-button
            type="text"
            size="mini"
            @click="() => now(node, data)">
            状态
          </el-button>
        </span>
      </div>
    </el-tree>
  </el-card>
</template>

<script>
// 引入接口 获取全部章节信息
import { getSectionAndLesson } from '@/services/coures'
export default {
  name: 'contentManagement',
  // 参数
  props: ['courseId'],
  data () {
    return {
      // 树形控件数据
      treeData: [],
      // 树形控件节点对应关系
      defaultProps: {
        // 子节点对应名字
        children: 'lessonDTOS',
        // 节点名称对应,因为章节名和节点名不同,所以要设置两个
        label (data) {
          return data.sectionName || data.theme
        }
      }
    }
  },
  // 生命周期钩子
  created () {
    // 调用方法获取课程全部章节数据
    this.getInfo(this.courseId)
  },
  methods: {
    // 获取课程全部内容
    async getInfo (courseId) {
      // 调用接口
      const { data } = await getSectionAndLesson(courseId)
      if (data.code === '000000') {
        // 如果获取成功,把数据交给树形结构
        this.treeData = data.data
      }
    }
  }
}
</script>

<style lang="scss" scoped>
// 树形结构样式
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
</style>

节点拖拽处理

要限制不合理拖拽,判断是否能放置

src/views/course/contentManagement.vue  给树形结构添加allow-drop属性并绑定判断方法

// 判断是否可放置方法
// 三个参数分别是拖动的元素,要放置的元素,位置
allowDrop (draggingNode, dropNode, type) {
  // 条件1:位置不能是inner(内部),意味着不可以放到其他节点内部
  // 条件2:两个节点有相同的父节点,意味着只能在同一个父节点内部拖动
  return type !== 'inner' && draggingNode.parent.id === dropNode.parent.id
}

拖拽后数据更新ca

拖拽后触发数据更新,组件提供事件,使用对应接

判断是章节还是课时。使用不同接口

为了避免每次都要请求多次接口,使用Promise.all()处理全部的请求 async 方法(await Promise.all(遍历(调用接口))使用try - cath进行成功和失败的操作

添加loading效果

src/services/coures.js  替阿甲课程更新和课时更新接口的封装

// 保存或者更新章节
export const saveOrUpdateSection = data => {
  return request({
    method: 'post',
    url: '/boss/course/section/saveOrUpdateSection',
    data
  })
}

// 保存或者更新课时
export const saveOrUpdate = data => {
  return request({
    method: 'post',
    url: '/boss/course/lesson/saveOrUpdate',
    data
  })
}
// src/views/course/contentManagement.vue  使用v-loading给树形结构添加加载中状态,使用node-drop添加拖拽成功事件函数

<el-tree v-loading="loading" :data="treeData" :props="defaultProps"  default-expand-all draggable :allow-drop="allowDrop" @node-drop="nodeDrop">
  
  
// 拖拽成功回调函数
    async nodeDrop (meNode, endNode, type, event) {
      // 更改信号值使树形结构处于加载中
      this.loading = true
      // 使用try-catch进行判断
      try {
        // 因为可能会包含多个节点所以可能会多次调用接口,所以使用await Promise.all接收全部调用的接口一起发送
        // 遍历要移动到的节点的父节点下的所有子节点
        await Promise.all(endNode.parent.childNodes.map((item, index) => {
          // 判断移动的是课时还是章节,课时有sectionId属性
          if (meNode.data.sectionId) {
            // 如果移动的是课时,使用课时更新接口
            return saveOrUpdate({
              id: item.data.id,
              orderNum: index
            })
          } else {
            // 如果不是课时,那就是章节,使用章节接口
            return saveOrUpdateSection({
              id: item.data.id,
              orderNum: index
            })
          }
        }))
        // 最后弹出提示
        this.$message.success('更新成功')
      } catch (err) {
        // 出现错误也弹出提示
        this.$message.error('更新失败')
      }
      // 不管成功还是失败。都要把结构加载状态取消
      this.loading = false
    },

上传课时视频

点击双传视频按钮跳转路由,新建组件,修改路由,点击跳转,路径参数

//src/router/index.js  添加上传视频的路由
{
    // 上传课时视频
    path: '/uploadVideo/:courseId',
    name: 'uploadVideo',
    component: () => import(/* webpackChunkName:'uploadVideo' */ '@/views/course/uploadVideo'),
    props: true
  }
src/views/course/contentManagement.vue  上传视频按钮添加点击事件,带参数跳转到上传视频页面

<el-button
  type="text"
  size="mini"
  v-else
  @click="$router.push({
    name: 'uploadVideo',
    params: {
      courseId
    },
    query: {
      lessonId: data.id
    }
  })">
  上传视频
</el-button>
src/views/course/uploadVideo.vue  新建组件书写上传视频

<template>
  <el-card class="box-card">
    <!-- 顶部标题 -->
    <div slot="header" class="clearfix">
      <!-- 使用传递过来的路径参数和普通参数 -->
      <span>上传视频 / 课程ID:{{courseId}} / 课时ID:{{lessonId}}</span>
    </div>
    <el-form :model="form" label-width="80px">
      <el-form-item label="封面上传">
        <input type="file">
      </el-form-item>
      <el-form-item label="视频上传">
        <input type="file">
      </el-form-item>
      <el-button>返回</el-button>
      <el-button type="primary">开始上传</el-button>
    </el-form>
  </el-card>
</template>

<script>
export default {
  name: 'uploadVideo',
  // courseId - 路径参数
  props: ['courseId'],
  data () {
    return {
      // 课时id,通过参数获取
      lessonId: this.$route.query.lessonId,
      // form表单数据
      form: {}
    }
  }
}
</script>

阿里云视频点播

阿里云 - 产品 - 视频服务 - 视频点播 - 文档与帮助 - 点播服务API - 开发指南 - 概述 - 上传SDK - 使用js上传SDK(SDK - 工具包 ) - 使用web端SDK - 可以查看实例代码Vue

将阿里云SDK中的三个js文件引入根目录下的HTML文件(注意名称和路径)

<!DOCTYPE html>
<html lang="">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>

<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
      Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
    
  <!-- 引入阿里云SDK文件,课程中使用的绝对路径,但我这里使用相对路径 -->
  <!--  IE需要es6-promise -->
  <script src="/aliyun/es6-promise.min.js"></script>
  <script src="/aliyun/aliyun-oss-sdk-6.13.0.min.js"></script>
  <script src="/aliyun/aliyun-upload-sdk-1.5.2.min.js"></script>
    
</body>

</html>
初始化阿里云山传

文档地址

使用上传地址和凭证的方式 (官方推荐)

找到Vue示例下面的src - uploadauth.vue就是使用上传凭证和地址的方式,使用vscode查看

设置注释/* eslint-disable*/就可以设置不对注释下面的代码进行风格校验

阿里云id - 1618139964448548

上传钩子中设置地址和凭证

组件创建完毕后初始化阿里云,直接文档中的代码进行处理

添加点击上传事件,点击上传获取文件

  • 给两个按钮添加ref,使用refs.名字.files[0]获取文件信息
  • 将两个文件添加到阿里云文件列表中然后启动上传(先传封面再传视频-接口要求)

开始上传需要在上传钩子函数中设置

src/views/course/uploadVideo.vue  初始化上传功能,添加按钮点击事件实现上传

<template>
  <el-card class="box-card">
    <!-- 顶部标题 -->
    <div slot="header" class="clearfix">
      <!-- 使用传递过来的路径参数和普通参数 -->
      <span>上传视频 / 课程ID:{{courseId}} / 课时ID:{{lessonId}}</span>
    </div>
    <el-form label-width="80px">
      <!-- 添加封面 -->
      <el-form-item label="添加封面">
        <input type="file" ref="img">
      </el-form-item>
      <!-- 添加视频 -->
      <el-form-item label="添加视频">
        <input type="file" ref="video">
      </el-form-item>
      <el-button>返回</el-button>
      <!-- 开始上传按钮添加点击事件 -->
      <el-button type="primary" @click="beginUpload">开始上传</el-button>
    </el-form>
  </el-card>
</template>

<script>
/* eslint-disable*/
export default {
  name: 'uploadVideo',
  // courseId - 路径参数
  props: ['courseId'],
  data () {
    return {
      // 课时id,通过参数获取
      lessonId: this.$route.query.lessonId,
      // 阿里云上传SDK
      uploader: null
    }
  },
  // 生命周期钩子函数
  created () {
    // 初始化上传
    this.initAliyun()
  },
  methods: {
    // 开始上传按钮点击事件
    beginUpload () {
      // 将图片和视频添加到上传列表,使用ref获取视频和图片
      this.uploader.addFile(this.$refs.img.files[0])
      this.uploader.addFile(this.$refs.video.files[0])
      // 开始上传
      this.uploader.startUpload()
    },
    initAliyun () {
      this.uploader = new AliyunUpload.Vod({
        //阿里账号ID,必须有值(这里使用老师提供的账号)
        userId: '1618139964448548',
        //上传到视频点播的地域,默认值为'cn-shanghai',//eu-central-1,ap-southeast-1
        region: '',
        //分片大小默认1 MB,不能小于100 KB
        partSize: 1048576,
        //并行上传分片个数,默认5
        parallel: 5,
        //网络原因失败时,重新上传次数,默认为3
        retryCount: 3,
        //网络原因失败时,重新上传间隔时间,默认为2秒
        retryDuration: 2,
        //开始上传
        onUploadstarted: function (uploadInfo) {
          console.log('开始上传啦')
          console.log(uploadInfo)
        },
        //文件上传成功
        onUploadSuccee: function (uploadInfo) {
        },
        //文件上传失败
        onUploadFailed: function (uploadInfo, code, message) {
        },
        //文件上传进度,单位:字节
        onUploadProgress: function (uploadInfo, totalSize, loadedPercent) {
        },
        //上传凭证或STS token超时
        onUploadTokenExpired: function (uploadInfo) {
        },
        //全部文件上传结束
        onUploadEnd:function(uploadInfo){}
      })
    }
  }
}
</script>

封装接口

使用阿里云接口(4个)

src/services/aliyun-upload.js  封装需要使用的阿里云接口

// 引入接口模块
import request from '@/utils/request'

// 获取阿里云上传图片凭证
export const aliyunImagUploadAddressAdnAuth = () => {
  return request({
    method: 'get',
    url: '/boss/course/upload/aliyunImagUploadAddressAdnAuth.json'
  })
}

// 获取阿里云上传视频凭证
export const aliyunVideoUploadAddressAdnAuth = params => {
  return request({
    method: 'get',
    url: '/boss/course/upload/aliyunVideoUploadAddressAdnAuth.json',
    params
  })
}

// 阿里云转码请求
export const aliyunTransCode = data => {
  return request({
    method: 'post',
    url: '/boss/course/upload/aliyunTransCode.json',
    data
  })
}

// 获取阿里云转码进度
export const aliyunTransCodePercent = lessonId => {
  return request({
    method: 'get',
    url: '/boss/course/upload/aliyunTransCodePercent.json',
    params: {
      lessonId
    }
  })
}

上传凭证处理

建议创建阿里云山传的时候加上window.Aliyun.....避免问题

判断上传的文件是视频还是图片从事分别处理

保存图片上传地址,用于视频上传

保存图片和视频返回的凭证和地址,最后把地址设置给阿里云(示例代码里面有)

注意this

src/views/course/uploadVideo.vue

<template>
  <el-card class="box-card">
    <!-- 顶部标题 -->
    <div slot="header" class="clearfix">
      <!-- 使用传递过来的路径参数和普通参数 -->
      <span>上传视频 / 课程ID:{{courseId}} / 课时ID:{{lessonId}}</span>
    </div>
    <el-form label-width="80px">
      <!-- 添加封面 -->
      <el-form-item label="添加封面">
        <input type="file" ref="img">
      </el-form-item>
      <!-- 添加视频 -->
      <el-form-item label="添加视频">
        <input type="file" ref="video">
      </el-form-item>
      <el-button>返回</el-button>
      <!-- 开始上传按钮添加点击事件 -->
      <el-button type="primary" @click="beginUpload">开始上传</el-button>
    </el-form>
  </el-card>
</template>

<script>
/* eslint-disable*/
// 引入封装的四个阿里云相关接口呀
import {
  aliyunImagUploadAddressAdnAuth,
  aliyunVideoUploadAddressAdnAuth,
  aliyunTransCode,
  aliyunTransCodePercent
} from '@/services/aliyun-upload'
export default {
  name: 'uploadVideo',
  // courseId - 路径参数
  props: ['courseId'],
  data () {
    return {
      // 课时id,通过参数获取
      lessonId: this.$route.query.lessonId,
      // 阿里云上传SDK
      uploader: null,
      // 图片地址
      imageURL: ''
    }
  },
  // 生命周期钩子函数
  created () {
    // 初始化上传
    this.initAliyun()
  },
  methods: {
    // 开始上传按钮点击事件
    beginUpload () {
      // 将图片和视频添加到上传列表,使用ref获取视频和图片
      const uploader = this.uploader
      uploader.addFile(this.$refs.img.files[0])
      uploader.addFile(this.$refs.video.files[0])
      // 开始上传
      uploader.startUpload()
    },
    initAliyun () {
      this.uploader = new AliyunUpload.Vod({
        //阿里账号ID,必须有值(这里使用老师提供的账号)
        userId: '1618139964448548',
        //上传到视频点播的地域,默认值为'cn-shanghai',//eu-central-1,ap-southeast-1
        region: '',
        //分片大小默认1 MB,不能小于100 KB
        partSize: 1048576,
        //并行上传分片个数,默认5
        parallel: 5,
        //网络原因失败时,重新上传次数,默认为3
        retryCount: 3,
        //网络原因失败时,重新上传间隔时间,默认为2秒
        retryDuration: 2,
        //开始上传
        onUploadstarted: async uploadInfo => {
          // 新建一个变量用于接收凭证信息
          let ressAdnAuth = null
          // 判断文件是图片还是视频
          if (uploadInfo.isImage) {
            // 如果是图片调用图片接口
            const { data } = await aliyunImagUploadAddressAdnAuth()
            if (data.code === '000000') {
              // 获取成功后把凭证信息存起来
              ressAdnAuth = data.data
              // 保存图片地址,后面要使用
              this.imageURL = ressAdnAuth.imageURL
            }
          } else {
            // 如果不是图片那就是视频,调用视频接口
            const { data } = await aliyunVideoUploadAddressAdnAuth({
              // 设置参数
              fileName: uploadInfo.file.name,
              imageUrl: this.imageURL
            })
            if (data.code === '000000') {
              // 如果获取成功同样保存信息
              ressAdnAuth = data.data
            }
          }
          // 设置阿里云凭证
          this.uploader.setUploadAuthAndAddress(
            uploadInfo,
            ressAdnAuth.uploadAuth,
            ressAdnAuth.uploadAddress,
            ressAdnAuth.imageId || ressAdnAuth.videoId)
        },
        //文件上传成功
        onUploadSuccee: function (uploadInfo) {
        },
        //文件上传失败
        onUploadFailed: function (uploadInfo, code, message) {
        },
        //文件上传进度,单位:字节
        onUploadProgress: function (uploadInfo, totalSize, loadedPercent) {
        },
        //上传凭证或STS token超时
        onUploadTokenExpired: function (uploadInfo) {
        },
        //全部文件上传结束
        onUploadEnd:function(uploadInfo){
          console.log('全部文件上传完成')
        }
      })
    }
  }
}
</script>

转码处理

转码请求重点需要发送的数据:

  • 转码课时id - lessonId
  • 图片地址 - coverImageUrI
  • fileId - 视频id
  • fileName - 视频名称

全部文件上传完毕后进行转码

转码成功调轮循转码进度,使用定时器循环查询转码进度,注意要停止定时器

添加结构监听进度

文件上传进度可以直接使用阿里云内置钩子

注意先后顺序

点击上传重置数据

<template>
  <el-card class="box-card">
    <!-- 顶部标题 -->
    <div slot="header" class="clearfix">
      <!-- 使用传递过来的路径参数和普通参数 -->
      <span>上传视频 / 课程ID:{{courseId}} / 课时ID:{{lessonId}}</span>
    </div>
    <el-form label-width="80px">
      <!-- 添加封面 -->
      <el-form-item label="添加封面">
        <input type="file" ref="img">
      </el-form-item>
      <!-- 添加视频 -->
      <el-form-item label="添加视频">
        <input type="file" ref="video">
      </el-form-item>
      <el-form-item label="上传进度"  v-if="uploading">
        <el-progress :percentage="uploadProgress" :text-inside="true" :stroke-width="30"  style="width: 300px"></el-progress>
      </el-form-item>
      <el-form-item label="转码进度"  v-if="transcoding">
        <el-progress :percentage="transcodingProgress" :text-inside="true" :stroke-width="30" style="width: 300px"></el-progress>
      </el-form-item>
      <el-button>返回</el-button>
      <!-- 开始上传按钮添加点击事件 -->
      <el-button type="primary" @click="beginUpload">开始上传</el-button>
    </el-form>
  </el-card>
</template>

<script>
/* eslint-disable*/
// 引入封装的四个阿里云相关接口呀
import {
  aliyunImagUploadAddressAdnAuth,
  aliyunVideoUploadAddressAdnAuth,
  aliyunTransCode,
  aliyunTransCodePercent
} from '@/services/aliyun-upload'
export default {
  name: 'uploadVideo',
  // courseId - 路径参数
  props: ['courseId'],
  data () {
    return {
      // 课时id,通过参数获取
      lessonId: this.$route.query.lessonId,
      // 阿里云上传SDK
      uploader: null,
      // 图片地址
      imageURL: '',
      // 视频id
      videoId: null,
      // 转码进度
      transcodingProgress: 0,
      // 转码状态
      transcoding: false,
      // 上传进度
      uploadProgress: 0,
      // 上传状态
      uploading: false
    }
  },
  // 生命周期钩子函数
  created () {
    // 初始化上传
    this.initAliyun()
  },
  methods: {
    // 开始上传按钮点击事件
    beginUpload () {
      // 重置所有状态和进度
      this.imageURL= ''
      this.videoId= null
      this.transcodingProgress= 0
      this.uploadProgress= 0
      // 将图片和视频添加到上传列表,使用ref获取视频和图片
      const uploader = this.uploader
      uploader.addFile(this.$refs.img.files[0])
      uploader.addFile(this.$refs.video.files[0])
      // 开始上传
      uploader.startUpload()
    },
    initAliyun () {
      this.uploader = new AliyunUpload.Vod({
        //阿里账号ID,必须有值(这里使用老师提供的账号)
        userId: '1618139964448548',
        //上传到视频点播的地域,默认值为'cn-shanghai',//eu-central-1,ap-southeast-1
        region: '',
        //分片大小默认1 MB,不能小于100 KB
        partSize: 1048576,
        //并行上传分片个数,默认5
        parallel: 5,
        //网络原因失败时,重新上传次数,默认为3
        retryCount: 3,
        //网络原因失败时,重新上传间隔时间,默认为2秒
        retryDuration: 2,
        //开始上传
        onUploadstarted: async uploadInfo => {
          this.uploading = true
          // 新建一个变量用于接收凭证信息
          let ressAdnAuth = null
          // 判断文件是图片还是视频
          if (uploadInfo.isImage) {
            // 如果是图片调用图片接口
            const { data } = await aliyunImagUploadAddressAdnAuth()
            if (data.code === '000000') {
              // 获取成功后把凭证信息存起来
              ressAdnAuth = data.data
              // 保存图片地址,后面要使用
              this.imageURL = ressAdnAuth.imageURL
            }
          } else {
            // 如果不是图片那就是视频,调用视频接口
            const { data } = await aliyunVideoUploadAddressAdnAuth({
              // 设置参数
              fileName: uploadInfo.file.name,
              imageUrl: this.imageURL
            })
            if (data.code === '000000') {
              // 如果获取成功同样保存信息
              ressAdnAuth = data.data
              this.videoId = data.data.videoId
            }
          }
          // 设置阿里云凭证
          this.uploader.setUploadAuthAndAddress(
            uploadInfo,
            ressAdnAuth.uploadAuth,
            ressAdnAuth.uploadAddress,
            ressAdnAuth.imageId || ressAdnAuth.videoId)
        },
        //文件上传成功
        onUploadSuccee: function (uploadInfo) {
        },
        //文件上传失败
        onUploadFailed: function (uploadInfo, code, message) {
        },
        //文件上传进度,单位:字节
        onUploadProgress: (uploadInfo, totalSize, loadedPercent) => {
          // 图片不需要进度,所有判断不是图片才输出进度
          if (!uploadInfo.isImage) {
            this.uploadProgress = Math.floor(loadedPercent * 100)
          }
        },
        //上传凭证或STS token超时
        onUploadTokenExpired: function (uploadInfo) {
        },
        //全部文件上传结束
        onUploadEnd: async uploadInfo => {
          // 上传成功后请求转码
          const { data } = await aliyunTransCode({
            lessonId: this.lessonId,
            coverImageUrl: this.imageURL,
            fileId: this.videoId,
            fileName: this.$refs.video.files[0].name
          })
          if (data.code === '000000') {
            // 如果转码申请成功设置转码状态
            this.transcoding = true
            // 设置定时器获取循环转码进度
            const timer = setInterval(async () => {
              // 获取转码进度
              const { data } = await aliyunTransCodePercent(this.lessonId)
              if (data.code === '000000') {
                // 获取成功把转码进度同步给数据
                this.transcodingProgress = data.data
                // 判断转码进度为100%则删除定时器
                if (data.data === 100) clearInterval(timer)
              }
            }, 1000)
          }
        }
      })
    }
  }
}
</script>

部署发布

打包 --->