第一步:npm install vod-js-sdk-v6
写成组件 upload代码片
。
// An highlighted block
<template>
<div style="width: 400px">
<el-upload
action="#"
:accept="accept"
:disabled="disabled"
:limit="1"
:http-request="uploadVideo"
:before-upload="beforeUploadVideo"
:on-exceed="handleExceed"
:show-file-list="false"
>
<el-button :disabled="disabled" :loading="loading" class="button-uploader" size="small" type="primary">
<i class="fa fa-upload" />
上传视频/音频
</el-button>
</el-upload>
<el-progress v-if="loading" :percentage="progress" />
</div>
</template>
<script>
import { getSignature, getAntiLeechUrl } from '@/api/upload.js'
import { sendVideoResource } from '@/api/learning'
import moment from 'moment'
import TcVod from 'vod-js-sdk-v6'
export default {
name: 'UploadVideo',
props: {
accept: {
type: String,
default: 'video/mp4, audio/mp3'
},
title: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
watermarkFlag: {
type: String,
default: '1'
},
classId: {
type: String,
default: ''
}
},
data() {
return {
resourceType: '',
videoDuration: 1000,
uploaderInfo: {},
progress: 0,
percentageImage: 0,
loading: false
}
},
created() {
},
methods: {
// 视频处理
handleExceed(files, fileList) {
this.$message.error(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
},
beforeUploadVideo(file) {
if (this.title === '') {
this.popMessage('视频上传前,请先填写课程标题')
return false
}
if (this.classId === '') {
this.popMessage('视频上传前,请先选择科目并确定是否添加水印')
return false
}
if (['video/mp4', 'audio/mp3'].indexOf(file.type) === -1) {
this.popMessage('请上传正确的音频或视频格式')
return false
}
if (file.type === 'video/mp4') {
const isLt1G = file.size / 1024 / 1024 < 1024
if (!isLt1G) {
this.popMessage('上传视频大小不能超过1G')
return false
}
this.resourceType = '1'
}
if (file.type === 'audio/mp3') {
const isLt100M = file.size / 1024 / 1024 < 100
if (!isLt100M) {
this.popMessage('上传音频大小不能超过100M')
return false
}
this.resourceType = '2'
}
},
popMessage(message) {
this.$message.error(message)
this.loading = false
},
uploadVideo(event) {
this.loading = true
this.start(event.file)
},
// 自定义上传
async start(file) {
try {
// eslint-disable-next-line no-irregular-whitespace
const userName = this.$store.getters.name
const currentTime = moment(Date.now()).format('YYYYMMDDHHmmss')
const type = file.type.split('/')[1]
const copyFile = new File([file], `${this.title}_${currentTime}.${type}`)
const _this = this
const tcVod = new TcVod({ getSignature: this.getSignature })
// 视频,类型为 File
const uploader = tcVod.upload({
mediaFile: copyFile
})
// 视频上传进度
uploader.on('media_progress', info => {
this.progress = parseInt(info.percent * 100)
uploaderInfo.progress = parseInt(info.percent * 100)
})
// 视频上传完成
uploader.on('media_upload', function(info) {
uploaderInfo.isVideoUploadSuccess = true
})
var uploaderInfo = {
videoInfo: uploader.videoInfo,
coverInfo: uploader.coverInfo,
isVideoUploadSuccess: false,
isVideoUploadCancel: false,
isCoverUploadSuccess: false,
resourceType: _this.resourceType,
progress: 0,
coverProgress: 0,
fileId: '',
videoUrl: '',
coverUrl: '',
cancel: function() {
uploaderInfo.isVideoUploadCancel = true
uploader.cancel()
}
}
this.uploaderInfo = uploaderInfo
uploader.done().then(function(doneResult) {
uploaderInfo.fileId = doneResult.fileId
if (uploaderInfo.isVideoUploadSuccess) {
_this.sendVideoResource(doneResult.fileId, doneResult.video.url, userName)
}
return _this.getAntiLeechUrl(doneResult.video.url, _this.videoDuration)
}).then(function(videoUrl) {
uploaderInfo.videoUrl = videoUrl
_this.$emit('subUploadSucceed', uploaderInfo)
_this.loading = false
})
} catch (error) {
this.loading = false
this.$emit('subUploadSucceed', '')
}
},
async getSignature() {
const params = {
resourceType: this.resourceType,
watermarkFlag: Number(this.watermarkFlag),
classId: this.classId
}
const res = await getSignature(params)
if (res.code === 0) {
return res.data
} else this.$message({ message: res.msg, type: 'error' })
},
async getAntiLeechUrl(url, duration) {
const query = {
originalUrl: url,
duration: duration
}
const res = await getAntiLeechUrl(query)
if (res.code === 0) {
this.videoUrl = res.data
return res.data
} else this.$message({ message: res.msg, type: 'error' })
},
async sendVideoResource(fileId, url, userName) {
const query = {
fileId: fileId,
mediaUrl: url,
createdBy: userName
}
const res = await sendVideoResource(query)
if (res.code === 0) {
return res.data
} else this.$message({ message: res.msg, type: 'error' })
}
}
}
</script>
<style lang="scss" scoped>
.clear-margin-top {
margin-top: 0;
}
.button-uploader {
background: #EEF5FF;
border: 1px solid #CFE3FD;
color: #5E9FF8;
}
</style>
父组件接收
下面展示一些 内联代码片
。
// An highlighted block
<template>
<el-form-item label="课件" required>
<div class="tip">视频大小不超过1G,格式为mp4;音频大小不超过100M,格式为mp3</div>
<UploadVideo
:title="formData.title"
:watermark-flag="formData.watermarkFlag"
:class-id="String(formData.subject)"
:disabled="formData.packageFlag"
@subUploadSucceed="getVideoUploadSucceedResult"
/>
<video v-if="videoUrl && resourceType === '1'" controls="controls" class="avatar" :src="videoUrl" />
<audio
v-if="videoUrl && resourceType === '2'"
controls="controls"
:src="videoUrl"
:style="{ height: '74px'}"
/>
<div v-if="isUploadFailed" style="color: red">上传失败,请重新上传</div>
</el-form-item>
</template>
<scirpt>
export default {
methods: {
getVideoUploadSucceedResult(uploaderInfo) {
if (uploaderInfo !== '') {
this.videoUrl = uploaderInfo.videoUrl
this.resourceType = uploaderInfo.resourceType
this.formData.fileId = uploaderInfo.fileId
} else {
this.isUploadFailed = true
}
}
}
}
</script>
更新版本
<template>
<div style="width: 400px;">
<el-upload
ref="media"
action="#"
:disabled="disabled"
:accept="accept"
:http-request="uploadVideo"
:before-upload="beforeUploadVideo"
:on-exceed="handleExceed"
:limit="1"
:show-file-list="false"
>
<el-button :disabled="disabled" :loading="loading" plain size="mini" type="primary">
<i class="fa fa-upload" />
上传视频/音频
</el-button>
</el-upload>
<el-row style="margin-top: 10px">
<span v-if="fileName" style="margin: 10px;color: #606266;"> {{ fileName }} </span>
<div v-if="videoUrl && resourceType === '1'" class="video">
<video controls="controls" class="avatar-video" :src="videoUrl" />
<i v-if="videoUrl && !disabled" class="el-icon-close close" @click="removeMedia" />
</div>
<div v-if="videoUrl && resourceType === '2' && showAudio" class="audio">
<audio controls="controls" class="avatar-audio" :src="videoUrl" />
<i v-if="videoUrl && !disabled" class="el-icon-close close" @click="removeMedia" />
</div>
</el-row>
<div v-if="isUploadFailed" style="color: red">上传失败,请重新上传</div>
<el-row type="flex" class="progress">
<el-progress v-if="loading" :percentage="progress" />
<i v-if="loading" class="el-icon-close" @click="cancelUpload" />
</el-row>
</div>
</template>
<script>
import { getSignature, getAntiLeechUrl } from '@/api/upload.js'
import { sendVideoResource } from '@/api/learning'
import moment from 'moment'
import TcVod from 'vod-js-sdk-v6'
export default {
name: 'UploadMediaVideo',
props: {
accept: {
type: String,
default: '.mp4, .mp3, .vob, .mpg'
},
disabled: {
type: Boolean,
default: false
},
watermarkFlag: {
type: Boolean,
default: true
},
classId: {
type: String,
default: ''
},
mediaType: {
type: Number,
default: 1
},
showAudio: {
type: Boolean,
default: true
},
mediaContent: {
type: Object,
default: null
}
},
data() {
return {
resourceType: '',
videoDuration: 1000,
uploaderInfo: {},
progress: 0,
percentageImage: 0,
loading: false,
isUploadFailed: false,
videoUrl: '', // 图片路径
fileId: '', // 视频id
fileName: '' // 音视频名称
}
},
watch: {
mediaContent(val) {
this.videoUrl = val.mediaUrl
this.resourceType = String(val.mediaType)
this.fileName = val.fileName
},
showAudio(val) {
if (!val) {
this.fileId = ''
this.fileName = ''
this.progress = 0
this.loading = false
this.$refs.media.clearFiles()
this.$emit('setTitle', this.fileName)
}
}
},
methods: {
// 视频处理
handleExceed(files, fileList) {
this.$message.error(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
},
beforeUploadVideo(file) {
if (!this.classId) {
this.popMessage('音视频上传前,请先选择云存储路径和水印')
return false
}
const startLength = Number(file.name.lastIndexOf('.')) + 1
const type = file.name.substr(startLength).toLowerCase()
if (this.mediaType === 1) {
if (type === 'mp4' || type === 'mpg' || type === 'vob') {
const isLt2G = file.size / 1024 / 1024 < 2048
if (!isLt2G) {
this.popMessage('上传视频大小不能超过2G')
return false
}
this.resourceType = '1'
} else {
this.popMessage('请上传视频类型文件')
return false
}
}
if (this.mediaType === 2) {
if (type === 'mp3') {
const isLt100M = file.size / 1024 / 1024 < 100
if (!isLt100M) {
this.popMessage('上传音频大小不能超过100M')
return false
}
this.resourceType = '2'
} else {
this.popMessage('请上传音频类型文件')
return false
}
}
},
popMessage(message) {
this.$message.error(message)
this.loading = false
},
uploadVideo(event) {
this.loading = true
this.start(event.file)
},
// 自定义上传
async start(file) {
try {
// eslint-disable-next-line no-irregular-whitespace
const userName = this.$store.getters.name
const currentTime = moment(Date.now()).format('YYYYMMDDHHmmss')
const startLength = Number(file.name.lastIndexOf('.'))
const type = file.name.substr(startLength).toLowerCase()
const title = file.name.substr(0, startLength)
const copyFile = new File([file], `${title}_${currentTime}${type}`)
const _this = this
_this.fileName = file.name
_this.$emit('setTitle', _this.fileName)
const tcVod = new TcVod({ getSignature: this.getSignature })
// 视频,类型为 File
const uploader = tcVod.upload({
mediaFile: copyFile
})
// 视频上传进度
uploader.on('media_progress', info => {
this.progress = parseInt(info.percent * 100)
uploaderInfo.progress = parseInt(info.percent * 100)
})
// 视频上传完成
uploader.on('media_upload', function(info) {
uploaderInfo.isVideoUploadSuccess = true
})
var uploaderInfo = {
videoInfo: uploader.videoInfo,
coverInfo: uploader.coverInfo,
isVideoUploadSuccess: false,
isVideoUploadCancel: false,
isCoverUploadSuccess: false,
resourceType: _this.resourceType,
progress: 0,
coverProgress: 0,
fileId: '',
videoUrl: '',
coverUrl: '',
cancel: function() {
uploaderInfo.isVideoUploadCancel = true
uploader.cancel()
}
}
this.uploaderInfo = uploaderInfo
uploader.done().then(function(doneResult) {
_this.fileId = doneResult.fileId
if (uploaderInfo.isVideoUploadSuccess) {
_this.sendVideoResource(doneResult.fileId, doneResult.video.url, userName)
}
return _this.getAntiLeechUrl(doneResult.video.url, _this.videoDuration)
}).then(function(videoUrl) {
const content = {
fileId: _this.fileId,
fileName: _this.fileName
}
_this.$emit('subUploadSucceed', content)
_this.isUploadFailed = false
_this.loading = false
})
} catch (error) {
this.fileName = ''
this.loading = false
this.isUploadFailed = true
}
},
cancelUpload() {
if (this.uploaderInfo.progress !== 0) {
this.uploaderInfo.cancel()
}
this.fileName = ''
this.progress = 0
this.loading = false
this.$refs.media.clearFiles()
this.$emit('setTitle', this.fileName)
},
removeMedia() {
this.uploaderInfo = {}
this.videoUrl = ''
this.fileId = ''
this.fileName = ''
this.progress = 0
this.$refs.media.clearFiles()
const content = {
fileId: this.fileId,
fileName: this.fileName
}
this.$emit('subUploadSucceed', content)
},
async getSignature() {
const params = {
resourceType: this.resourceType,
watermarkFlag: this.watermarkFlag,
classId: this.classId
}
const res = await getSignature(params)
if (res.code === 0) {
return res.data
} else this.$message({ message: res.msg, type: 'error' })
},
async getAntiLeechUrl(url, duration) {
const query = {
originalUrl: url,
duration: duration
}
const res = await getAntiLeechUrl(query)
if (res.code === 0) {
this.videoUrl = res.data
return res.data
} else this.$message({ message: res.msg, type: 'error' })
},
async sendVideoResource(fileId, url, userName) {
const query = {
fileId: fileId,
mediaUrl: url,
createdBy: userName
}
const res = await sendVideoResource(query)
if (res.code === 0) {
return res.data
} else this.$message({ message: res.msg, type: 'error' })
}
}
}
</script>
<style lang="scss" scoped>
.clear-margin-top {
margin-top: 0;
}
.progress {
.el-progress {
width: 90%;
}
i {
color: #FF0000;
border-radius: 50%;
background-color: #F9F9F9;
}
i:hover {
background: #FF0000;
color: #FFFFFF;
}
}
.video {
display: flex;
width: 178px;
position: relative;
.avatar-video {
width: 100%;
height: 178px;
display: block;
}
.close {
position: absolute;
top: 4px;
right: 4px;
background: rgba(255, 255, 255, 1);
border-radius: 50%;
font-weight: 600;
}
i {
height: 15px;
color: #FF0000;
border-radius: 50%;
background-color: #F9F9F9;
}
i:hover {
background: #FF0000;
color: #FFFFFF;
}
}
.audio {
display: flex;
width: 360px;
position: relative;
.avatar-audio {
width: 100%;
margin-top: 10px;
display: block;
}
.close {
position: absolute;
top: 4px;
right: 4px;
background: rgba(255, 255, 255, 1);
border-radius: 50%;
font-weight: 600;
}
i {
height: 15px;
color: #FF0000;
border-radius: 50%;
background-color: #F9F9F9;
}
i:hover {
background: #FF0000;
color: #FFFFFF;
}
}
</style>