*
* 上传亚马逊的基本思路为
* ***
* 1.调用后端接口,获取需要上传到亚马逊的数据(从后台获取亚马逊需要的数据)
* 2.提交数据到亚马逊之后,亚马逊会自动刷新当前form表单的页面,刷新后 将form表单所在页面的url改变,将我们需要的字段通过url返回给我们
* (后台通过这些字段可以找到当前上传视频所在亚马逊的位置及视频信息)
* 3.获取到url中的信息后 将获取信息通过接口发送给后端 完成上传
*
* 因此需要注意的是:
* 1.使用form表单提交(不然会有跨域问题)
* 2.使用iframe包裹表单上传(上传成功后会刷新页面我们不能让我们操作的页面刷新,只能通过iframe),
* 3.同步上传多个视频就要同时生成多少个iframe,因为每一个上传都会有不同的返回值,想要获取对应数据 就不能动当前上传的iframe
* (再次操作正在上传的iframe会让上传停止)
******按照我下面所做可以解决网上说的跨域问题
1.主上传页面:
<template>
<!--创建EXT跟grid配对的按钮-->
<el-dialog
:title="$t('lang.addvideo')"
:visible.sync="data.show"
width="700px"
:center="true"
:close-on-click-modal="false"
class="add-source-dialog"
@close="cancel"
:destroy-on-close="true"
>
<div class="content scrollbar">
<el-row>
<el-col :span="8" v-for="item in videoList" :key="item.id">
<div class="videoList"
v-loading="item.loading"
:element-loading-text="$t('lang.proccessing')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(40,71,48, 1)"
v-if="!item.iframe"
>
<div class="waitThumbneil">
<i class="iconfont videoWait"></i>
<div class="delete">
<i class="iconfont" @click="cancelUploadedVideo('deleteOne',item)"
:title="$t('lang.delete')"></i>
</div>
<div class="timeInfo" v-if="item.time && item.time != ''">
{{item.time}}
</div>
</div>
<div class="videoName ellipsis" @click="showEditName(item)">
<span v-if='!item.editName'>{{item.fileName}}</span>
<el-input
v-model="item.fileName"
v-if='item.editName'
class="editName"
:id="item.id"
@change="editName"
@blur="editName"
></el-input>
</div>
</div>
</el-col>
<el-col :span="8">
<div class="uploadP">
<i class="el-icon-plus avatar-uploader-icon"></i>
{{$t('lang.upload')}}
<uploadIframe @getUploadInfo="getUploadInfo"
:data="item"
:session="session"
:class="{opcaty:!item.show}"
v-for="item in iframe"
:key="item.id"
></uploadIframe>
</div>
</el-col>
</el-row>
</div>
<span slot="footer" class="dialog-footer">
<el-button class="save" @click.stop="save">{{$t('lang.add')}}</el-button>
<el-button class="cancel" @click="cancelUploadedVideo('deleteAll')">{{$t('lang.cancel')}}</el-button>
</span>
</el-dialog>
</template>
<script>
import 'vuex';
import uploadIframe from './uploadIframe'
export default {
props: {
data: Object,
edit: Boolean,
editData: Object,
session: String
},
components: {
uploadIframe,
},
data() {
return {
loading: true,
videoList: [],
iframe: [
{
id: Math.random(),
show: true,
session: session
},
],
}
},
mounted() {
},
created() {
},
methods: {
getUploadInfo(data) {
// console.log(data);
if (data.type == 'loadingStart') {
let addVideoObj = data.videoObj
let isHaveSameVideo = false; //是否上传了 相同的video文件
this.videoList.map((item) => {
if (addVideoObj.id == item.id) {
isHaveSameVideo = true;
}
});
if (!isHaveSameVideo) {
this.videoList.push(addVideoObj);
this.videoList = Object.assign([], this.videoList);
this.iframe.map((item) => {
item.show = false;
})
this.iframe.unshift({
show: true,
id: Math.random(),
session: session
})
} else {
this.$message({
type: 'warning',
message: this.$t('lang.uploadHasSame')
})
}
} else if (data.type == 'loadingEnd') {
let updateVideo = [];
this.videoList.map((item) => {
if (item.id == data.videoObj.id) {
item.loading = false;
}
updateVideo.push(item);
})
this.videoList = [];
this.videoList = Object.assign([], updateVideo);
} else if (data.type == 'hasGetVideoTime') {
let videoTime = data.videoTime;
let md5 = data.md5;
this.showTimeInfo(md5, videoTime);
} else {
this.$message({
type: 'warning',
message: this.$t('lang.failed')
})
}
},
showTimeInfo(id, time) {//获取到时间的时候将时间赋值给对应的vue数据 id => 对应的md5 time 对应的视屏时长
let videoData = [];
this.videoList.map((item) => {
if (item.id == id) { //文件一样
item.time = time;
}
})
},
showEditName(data) {
let update = [];
let currentId = data.id;
this.videoList.map((item) => {
if (item.id == data.id) {
item.editName = true;
}
update.push(item);
});
this.videoList = Object.assign([], update);
this.$nextTick(() => {
$("#" + currentId).focus();
})
},
editName() {
let update = [];
this.videoList.map((item) => {
item.editName = false;
update.push(item);
})
this.videoList = Object.assign([], update);
},
cancelUploadedVideo(type, data) {
/*
* type:"是什么操作 1.删除一个 2.点击X号 或者cancel按钮"
* */
let Url = '';
// let Url = '/event/editVideo';
let params = [];
if (type == 'deleteOne') {
let param = {
"fileName": data.fileName,
"md5Id": data.id,
"operationType": "del"
};
params.push(param);
} else if (type == 'deleteAll') {
this.videoList.map((item) => {
let param = {
"fileName": item.fileName,
"md5Id": item.id,
"operationType": "del"
}
params.push(param);
});
} else if (type == 'addAll') {
this.videoList.map((item) => {
let param = {
"fileName": item.fileName,
"md5Id": item.id,
"operationType": "add"
}
params.push(param);
})
}
if (params.length == 0) { //添加的时候 没选择视频文件
if (type == 'addAll') {
this.$message({
type: 'warning',
message: this.$t('lang.selectAVideo')
})
return false;
} else if (type == 'deleteAll') { //取消全部
this.clear();
return false;
}
}
this.axios.post(Url, params, {contentType: 'application/json;charset=UTF-8'}).then(res => {
if (res.data.errorCode == '0x0') {
if (type == 'deleteOne') {
this.videoList.map((item, index) => { //刪除當前刪除的視屏
if (data.id == item.id) {
this.videoList.splice(index, 1);
}
})
} else { //cancel和add操作 关闭弹窗
this.clear();
if (type == 'addAll') {
this.$emit('queryList');
this.$message({
type: 'success',
message: this.$t('lang.success')
})
}
}
} else if (res.data.errorCode == '80600700') {
this.$message({
type: 'warning',
message: this.$t('lang.serverFailed')
})
}
})
},
save() {
this.cancelUploadedVideo('addAll');
// bookingAnalyze(`bookingVideoAdd`, '/bk');
},
cancel() {
// this.cancelUploadedVideo('deleteAll');
this.clear();
this.data.show = false;
//bookingAnalyze(`bookingVideoCancel`, '/bk');
},
clear() {
this.data.show = false;
this.videoList = [];
this.iframe = [
{
id: Math.random(),
show: true,
session: session
},
]
}
}
}
</script>
<style lang="less" scoped>
.opcaty {
opacity: 0 !important;
width: 0 !important;
height: 0 !important;
}
/deep/ .el-upload__input {
display: none;
}
.videoList {
width: 90%;
height: 140px;
margin: 20px auto;
.editName {
height: 30px;
width: 100%;
/deep/ .el-input__inner {
width: 100% !important;
height: 30px !important;
background: #333333 !important;
border: none !important;
}
}
.waitThumbneil:hover .delete {
display: block;
}
.waitThumbneil {
height: 106px;
line-height: 106px;
text-align: center;
background: rgba(44, 44, 44, 1);
position: relative;
font-size: 24px;
color: #318F47;
i {
cursor: pointer;
}
.delete {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 16px;
color: white;
background: rgba(2, 0, 3, .1);
display: none;
z-index: 2;
i {
cursor: pointer;
}
}
.timeInfo {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 30px;
line-height: 30px;
text-align: right;
color: white;
font-size: .12rem;
padding: 0 10px;
z-index: 1;
}
}
.videoName {
height: 30px;
line-height: 30px;
text-align: center;
width: 100%;
padding: 0 10px;
color: #6B6B6B;
background: #333333;
margin-top: 4px;
}
}
.uploadP {
width: 100%;
height: 140px;
margin: 20px auto;
border: 1px dashed #3A3A3A;
line-height: 140px;
position: relative;
text-align: center;
#iframe {
position: absolute;
top: 0;
left: 0;
opacity: 0;
width: 182px;
height: 140px;
cursor: pointer;
}
}
.add-source-dialog {
.scrollbar {
overflow-x: hidden;
}
.content {
text-align: left;
font-size: 16px;
height: 200px;
max-height: 55vh;
overflow-y: auto;
.item {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
span {
display: block;
margin-bottom: 5px;
}
}
/deep/ .el-input .el-input__inner {
border: 1px solid #444;
background: #444;
height: 46px;
line-height: 46px;
color: white !important;
&::-webkit-input-placeholder {
color: #666;
}
}
/deep/ .select-box {
width: 100%;
.el-input__inner {
border: 1px solid #444;
background: #444;
height: 46px;
line-height: 46px;
}
}
/deep/ .el-select {
width: 100%;
.el-select__input {
color: #fff;
}
}
/deep/ .selectRlist {
width: 100%;
height: 300px;
overflow-y: auto;
}
}
}
.delete {
width: 120px;
}
</style>
2.Iframe页面
<template>
<iframe id="iframe" frameborder=0 scrolling=auto width="100%" height="100%" :src="iframeUrl"
:session="cusession"></iframe>
</template>
<script>
import {bookingAnalyze} from '@/assets/js/googleAnalyze/booking.js'
export default {
data() {
return {
cusession: this.session,
iframeUrl: '',
currentData: this.item,
}
},
props: ['data', 'session'],
created() {
let protocol = document.location.protocol;
let seession = this.session;
// this.iframeUrl = `${protocol}//${localStorage.getItem('newCCUrl')}/uploadVideo.html#?session=${seession}`; //线上使用
this.iframeUrl = window.location.origin + '/uploadVideo.html#/?session=' + this.session;
let _this = this;
window.uploadVideo = (data) => { //获取上传的成功失败信息
if (data.type == 'loadingStart') {
let videoObj = {
fileName: data.msg.fileName,
loading: true,
id: data.msg.id,
editName: false,
time: '',
};
let msg = {
type: 'loadingStart',
videoObj: videoObj
}
_this.$emit('getUploadInfo', msg);
// this.$message({
// type: 'warning',
// message: this.$t('lang.uploadHasSame')
// })
} else if (data.type == 'loadingEnd') {
let videoObj = {
id: data.msg.id,
};
let msg = {
type: 'loadingEnd',
videoObj: videoObj
}
_this.$emit('getUploadInfo', msg);
} else if (data.type == 'hasGetVideoTime') {//获取到当前视频的时长
let timeInfo = data.msg;
timeInfo.type = 'hasGetVideoTime';
_this.$emit('getUploadInfo', timeInfo);
} else if (data.type == 'alertErrorCode') {
if(data.msg == '80601804'){
_this.$message({
type: 'warning',
message: this.$t('lang.videoExist')
})
}else{
_this.$message({
type: 'warning',
message: this.$t('lang.failed')
})
}
}
}
window.getSessionIframe = () => {
// console.log(111,this.$store.state.common); //所有的initConfig信息
let videoInfo = {};
return this.session;
}
},
}
</script>
<style scoped>
.uploadP {
width: 100%;
height: 140px;
margin: 20px auto;
border: 1px dashed #3A3A3A;
line-height: 140px;
position: relative;
text-align: center;
}
#iframe {
position: absolute;
top: 0;
left: 0;
opacity: 0;
width: 182px;
height: 140px;
cursor: pointer;
}
</style>
3.镶嵌在iframe内的form表单
<template>
<div class="button">
<form class="form-horizontal" id="formUpload" :action="formdata.uploadUrl" method="post"
enctype="multipart/form-data">
<input type="hidden" name="acl" :value="formdata.acl"/>
<input type="hidden" name="key" :value="formdata.objectKey"/>
<input type="hidden" name="policy" :value="formdata.policy"/>
<input type="hidden" name="success_action_redirect" :value="href"/>
<input type="hidden" name="success_action_status" value="200"/>
<input type="hidden" name="x-amz-algorithm" :value="formdata.algorithm"/>
<input type="hidden" name="x-amz-credential" :value="formdata.credential"/>
<input type="hidden" name="x-amz-date" :value="formdata.date"/>
<input type="hidden" name="x-amz-signature" :value="formdata.signature"/>
<!-- <input type="hidden" name="x-amz-meta-programId" :value="programId"/>-->
<!-- <input type="hidden" name="x-amz-meta-name" :value="fileName"/>-->
<label for="videoUpload" class="videoUpload">
<input type="file" name="file" :accept="accept" @change="handlePrepareUpload($event)" class="videoUpload"
id="videoUpload"/>
</label>
<button id="uploadFile" type="submit"></button>
</form>
<video :src="videoUrl" id="file"></video>
</div>
</template>
<script>
import {requestUpload, notifyUploadVideoSuccess} from '@/assets/js/uploadApi';
import SparkMD5 from 'spark-md5';
import Outil from '@/assets/js/utils.js'
const url = require("url");
export default {
created() {
const href = window.location.href;
let programId = '1000';
const urlPaseObj = url.parse(href, true).query;
const urlOwnSend = url.parse(href, true).hash;//自己传递的参数
// if(urlPaseObj.hasOwnProperty("programId")){
// this.programId = urlPaseObj.programId;
// }
if (urlPaseObj.hasOwnProperty("region")) {
this.region = urlPaseObj.region;
}
if (urlPaseObj.hasOwnProperty("bucket")) {
let videoUplodInfo = JSON.parse(window.localStorage.getItem('uploadVideo'));
let md5 = Outil.getQueryString('md5', urlOwnSend);
let bucketSend = Outil.getQueryString('bucketSend', urlOwnSend);
let region = Outil.getQueryString('region', urlOwnSend);
let fileName = Outil.getQueryString('fileName', urlOwnSend);
let session = Outil.getQueryString('session', urlOwnSend);
const params = {
bucket: urlPaseObj.bucket,
key: urlPaseObj.key,
fileMD5Id: md5,
region: region,
nickName: fileName,
url: urlPaseObj.key,
session: session
}
let fileInfo = {
id: md5, //每一个file都有一个不一样的md5 相同文件有相同的md5 (可以用于相同文件上传的去重操作)
}
parent.uploadVideo({type: 'loadingEnd', msg: fileInfo});
this.notifyUploadSuccess(params);
}
this.href = location.href;
},
data() {
return {
programId: '1000',
fileName: '',
region: '',
href: '',
accept: '.ts,.rm,.rmvb,.wmv,.wtv,.avi,.3gp,.mkv,.mpg,video/mpeg,video/mp4,.mov',
formdata: {
acl: "",
algorithm: "",
bucket: "",
credential: "",
date: "",
objectKey: "",
policy: '',
region: "",
signature: "",
uploadUrl: "",
},
videoUrl: '',
}
},
methods: {
async inputValue(event, md5) { // 触发onchange 事件之后,需要获取文件名,等信息,和java获取上传的一下信息,填入文件之后,自动触发上传事件上传文件
// 获取名字
const pathArr = event.target.value.split('\\');
const names = pathArr[pathArr.length - 1].split(".");
const idx = pathArr[pathArr.length - 1].lastIndexOf('.');
const sourceName = pathArr[pathArr.length - 1].substring(0, idx);
this.fileName = sourceName;
let suffix = names[names.length - 1];
// 遍历数据
const arr = this.accept.split(',').filter(item => {
if (item.indexOf(suffix) > -1) {
return item;
}
});
if (arr.length == 0) {
// parent.uploadVideo({type: 'error', msg: 'file type error'});
event.target.value = '';
return false;
}
const params = { //bucket和region需要向亚马逊平台申请
"fileName": pathArr[pathArr.length - 1],
"bucket": "",
"region": "",
fileMD5Id: md5,
}
const res = await requestUpload(params);
// return false;
if (res.data.errorCode === "0x0") {
let protocol = document.location.protocol;
let seession = parent.getSessionIframe();
this.href = window.location.origin + '/uploadVideo.html#/?session=' + parent.getSessionIframe() + '&md5=' + md5 + '®ion=ap-northeast-2' + "&bucketSend=pp-kr-001" + '&fileName=' + pathArr[pathArr.length - 1] + '&session=' + parent.getSessionIframe(); //本地test使用
let sendObj = {
md5: md5,
region: '',
bucketSend: '',
fileName: pathArr[pathArr.length - 1],
};
const result = res.data.result;
this.formdata = result;
this.$nextTick(() => {
document.getElementById("uploadFile").click();
let fileInfo = {
fileName: pathArr[pathArr.length - 1],
id: md5, //每一个file都有一个不一样的md5 相同文件有相同的md5 (可以用于相同文件上传的去重操作)
}
parent.uploadVideo({type: 'loadingStart', msg: fileInfo});
})
} else {
if (res.data.errorCode) {
parent.uploadVideo({type: 'alertErrorCode', msg: res.data.errorCode});
}
event.target.value = '';
}
},
async notifyUploadSuccess(params) { // 上传成功,s3回调之后,通知java去修改状态
const res = await notifyUploadVideoSuccess(params);
if (res.data.errorCode !== '0x0' && res.data.errorCode != '80601804') {
setTimeout(() => {
this.notifyUploadSuccess(params);
}, 1000);
}
},
handlePrepareUpload(event) { // 文件上传获取md5值
var fileReader = new FileReader();
//文件读取完毕之后的处理
fileReader.onload = function (e) {
spark.appendBinary(e.target.result);
var md5 = spark.end();
_this.inputValue(event, md5);
// _this.getMd5Checked(md5)
let video = document.getElementById('file');
let inputFile = document.getElementById('videoUpload').files[0];
let url = URL.createObjectURL(inputFile);
console.log(url);
video.src = url;
setTimeout(() => {
//获取时长方式: 将获取的本地地址给video去播放 然后获取video的属性 获取时长,但是赋值给video的时候不会在瞬间获取到视频信息 因此需要延迟1s左右的时间
if (video.readyState > 0) {
let videoTime = Outil.MillisecondToDate(video.duration);
let timeInfo = {
videoTime: videoTime,
md5: md5,
}
parent.uploadVideo({type: 'hasGetVideoTime', msg: timeInfo});
}
}, 1000)
};
var dataFile = event.srcElement.files[0];
const _this = this
var spark = new SparkMD5(); //创建md5对象(基于SparkMD5)
if (dataFile.size > 1024 * 1024 * 10) {
var data1 = dataFile.slice(0, 1024 * 1024 * 10); //将文件进行分块 file.slice(start,length)
fileReader.readAsBinaryString(data1); //将文件读取为二进制码
} else {
fileReader.readAsBinaryString(dataFile);
}
},
},
mounted() {
const formUpload = document.getElementById("formUpload");
formUpload.onsubmit = (event) => {
// 触发父页面的加载状态
parent.uploadVideo({type: 'loadingPage'});
return true;
};
},
}
</script>
<style lang="less">
* {
margin: 0;
padding: 0;
}
html, body {
width: 182px;
height: 140px;
display: block;
}
#file {
width: 0;
height: 0;
opacity: 1;
}
.button {
width: 182px;
height: 140px;
button {
display: none;
}
.videoUpload {
width: 182px;
height: 140px;
opacity: 0;
cursor: pointer;
display: block;
}
#videoUpload {
display: none;
}
}
</style>
4.请求后台接口js(根据实际情况修改)
import Axios from 'axios';
import Tool from '@/assets/js/utils.js';
const session = Tool.getSession();
// example
export async function requestUpload(params) {
// axios.defaults.headers.authorization = token;
let url = '';
const res = await Axios.post(url, params,{contentType: 'application/json;charset=UTF-8'});
return res;
}
export async function notifyUploadVideoSuccess(params) {
let url = '';
const res = await Axios.post(url, params,{contentType: 'application/json;charset=UTF-8'});
return res;
}