<template>
<div>
<Row style="display:inline-block;">
<viewer :options="options" @inited="inited">
<div v-for="(item,index) in uploadList" :key="index" class="demo-upload-list" :style="styleDesign">
<template v-if="item.status === 'finished'">
<Row
v-if="item.mediaType.indexOf('image')!=-1"
>
<img :ref="'img'+index" :src="item.smallUrl" data-enable="1" :data-source="item.url">
<div class="demo-upload-list-cover">
<Icon title="预览" type="ios-eye-outline" @click.native="handleView(item.url,index)" />
<Icon v-if="!uploadConfig.readOnly" title="删除" type="ios-trash-outline" @click.native="handleRemove(item,index)" />
</div>
</Row>
<Row v-else>
<file-image :media-type="item.mediaType" :file-name="item.fileName" :size="size || 80" />
<div class="demo-upload-list-cover" :title="item.fileName">
<Icon title="预览" type="ios-eye-outline" @click.native="handleLinkView(item)" />
<Icon v-if="uploadConfig.readOnly" title="下载" type="ios-cloud-download-outline" @click.native="handleDownload(item.url)" />
<Icon v-if="!uploadConfig.readOnly" title="删除" type="ios-trash-outline" @click.native="handleRemove(item,index)" />
</div>
</Row>
</template>
<template v-else>
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info />
</template>
</div>
<div v-if="!uploadConfig.readOnly" class="my-upload" style="display:inline-block;">
<div :class="myUploadClass"
@drop.prevent="onDrop"
@dragover.prevent="dragOver = true"
@dragleave.prevent="dragOver = false"
@click="handleClick"
>
<input ref="input" type="file"
:accept="acceptType"
:multiple="multiple" style="display:none;" @change="handleChange"
>
<div :style="styleDesign">
<Icon type="ios-add" size="20" />
</div>
</div>
</div>
</viewer>
</Row>
<preview-file ref="perviewFile" :read-only="wpsReadOnly" />
<Modal
v-model="viedoCtrl"
title="视频播放"
:width="540"
:mask-closable="false"
:footer-hide="true"
@on-cancel="cancel"
>
<video :src="videoUrl" width="500px" height="400px" controls="controls">
您的浏览器不支持 video 标签。
</video>
</Modal>
</div>
</template>
<script>
import COS from 'cos-js-sdk-v5'
import fileImage from './../fileImage/fileImage.vue'
export default {
components: {
fileImage
},
props: {
defaultList: {
type: Array,
default() {
return []
}
},
multiple: {
type: Boolean,
default: true
},
uploadConfig: {
type: Object,
default() {
return { fileName: 'base', readOnly: false, maxNum: 100 }
}
},
acceptType: {
type: String,
default: '*'
},
format: {
type: Array,
default () {
return []
}
},
size: {
type: String || Number,
default: ''
},
wpsReadOnly: {
type: Boolean,
default: true
},
hrefUrl: {
type: Boolean || String,
default: false
}
},
data() {
return {
uploadList: [],
type: '',
cos: '',
dragOver: false,
viedoCtrl: false,
videoUrl: '',
styleDesign: {
width: this.size ? this.size + 'px' : '80px',
height: this.size ? this.size + 'px' : '80px',
lineHeight: this.size ? this.size + 'px' : '80px'
},
options: {
url: 'data-source',
filter (image) {
return image.dataset.enable === '1'
}
},
uploadType: 'public'
}
},
computed: {
myUploadClass() {
return [
`my-upload my-upload-drag`,
{
'my-upload-dragOver': this.dragOver
}
]
}
},
watch: {
defaultList: {
immediate: true,
handler(fileList) {
this.uploadList = fileList && fileList.map(item => {
if (typeof (item) === 'string') {
return {
url: item,
smallUrl: item,
status: 'finished',
mediaType: 'image'
}
} else {
const obj = {
fileName: item.fileName,
url: item.url,
smallUrl: item.url,
status: 'finished',
mediaType: item.mediaType || 'image'
}
item.id ? obj.id = item.id : ''
item.fileId ? obj.fileId = item.fileId : ''
return obj
}
})
this.$nextTick(() => {
this.updateViewer()
})
}
}
},
mounted: function() {
const path = '/base/cos/sesseionToken/ap-guangzhou/' + (this.uploadType == 'public' ? this.config.uploadPublicUrl : this.config.uploadPrivateUrl)
const _this = this
var COS = require('cos-js-sdk-v5')
this.cos = new COS({
getAuthorization: function (options, callback) {
_this.$get(path).then(res => {
callback({
TmpSecretId: res.data.tmpSecretId,
TmpSecretKey: res.data.tmpSecretKey,
XCosSecurityToken: res.data.token,
StartTime: new Date().getTime() / 1000,
ExpiredTime: res.data.expiredTime
})
})
}
})
},
methods: {
inited(viewer) {
this.$viewer = viewer
},
updateViewer() {
if (this.$viewer) {
this.$viewer.update()
}
},
getFileType(name) {
let fileType = ''
if (name.lastIndexOf('.') != -1) {
const places = name.lastIndexOf('.') + 1
fileType = name.substring(places).toLowerCase()
}
const archiveArr = ['arj', 'cab', 'rar', 'tar', 'zip', '7z', 'gzip', 'jar', 'z', 'ace']
if (archiveArr.indexOf(fileType) != -1) {
return fileType
} else {
return false
}
},
handleView (url, index) {
this.$refs[`img${index}`][0].click()
},
handleLinkView(item) {
if (item.mediaType.includes('video')) {
this.videoUrl = item.url
this.viedoCtrl = true
} else {
if (this.hrefUrl) {
const url = Object.prototype.toString.call(this.hrefUrl) == '[object String]' ? this.hrefUrl : item.url
window.open(url, '_blank')
return
}
this.$refs.perviewFile.preview(item)
}
},
cancel() {
this.videoUrl = ''
this.viedoCtrl = false
},
handleDownload(url) {
window.open(url)
},
handleClick () {
if (this.itemDisabled) { return }
if (this.uploadList.length >= this.uploadConfig.maxNum) {
this.$Message.error(`最多上传${this.uploadConfig.maxNum}份附件`)
return
}
this.$refs.input.click()
},
onDrop(e) {
this.dragOver = false
if (this.itemDisabled) return
this.uploadFiles(e.dataTransfer.files)
},
handleChange(e) {
const files = e.target.files
if (!files) { return }
this.uploadFiles(files)
this.$refs.input.value = null
},
formatFile(file) {
if (this.format.length) {
const _file_format = file.name.split('.').pop().toLocaleLowerCase()
const checked = this.format.some(item => item.toLocaleLowerCase() === _file_format)
if (!checked) {
this.onFormatError(file)
return false
}
}
this.upload(file)
},
onFormatError(file) {
this.$Message.error(file.name + '的文件格式不正确,请选择' + this.acceptType + '格式的文件。')
},
uploadFiles(files) {
let postFiles = Array.prototype.slice.call(files)
if (!this.multiple) postFiles = postFiles.slice(0, 1)
if (postFiles.length === 0) return
postFiles.forEach(file => {
this.formatFile(file)
})
},
upload (file) {
const fileSplitArr = file.name.split('.')
const key = file.lastModified + Math.floor(Math.random() * 9999) + '.' + fileSplitArr[fileSplitArr.length - 1]
const _this = this
const index = _this.uploadList.length
const json = { key: key }
this.cos.putObject({
Bucket: _this.uploadType == 'public' ? _this.config.uploadPublicUrl : _this.config.uploadPrivateUrl,
Region: 'ap-guangzhou',
Key: key,
StorageClass: 'STANDARD',
Body: file,
onProgress: function(progressData) {
json.status = 'unFinished'
json.showProgress = true
json.percentage = (progressData.percent) * 100
_this.$set(_this.uploadList, index, json)
}
}, function(err, data) {
if (data.statusCode == 200) {
json.status = 'finished'
json.showProgress = false
json.percentage = 100
json.mediaType = file.type && file.type.length > 0 ? file.type : `.${file.name.split('.').pop().toLocaleLowerCase()}`
json.fileName = file.name
json.smallUrl = 'http://' + data.Location + '?imageView2/1/w/80/h/80'
json.url = 'http://' + data.Location
if (_this.uploadType != 'public') {
_this.getPublicUrl(key, json, index)
} else {
_this.$set(_this.uploadList, index, json)
_this.$emit('getFileList', _this.uploadList)
}
} else {
_this.uploadList.splice(index, 1)
}
_this.$nextTick(() => {
_this.updateViewer()
})
})
},
handleRemove (file, index) {
this.uploadList.splice(index, 1)
this.$emit('getFileList', this.uploadList)
this.$nextTick(() => {
this.updateViewer()
})
},
getPublicUrl(key, json, index) {
const url = '/base/cos/presigned-url/ap-guangzhou/' + this.config.uploadPrivateUrl + '?keys=' + key
this.$get(url).then(res => {
if (res.code == 0) {
const pubUrl = res.data[0]
json.smallUrl = pubUrl
json.url = pubUrl
this.$set(this.uploadList, index, json)
this.$emit('getFileList', this.uploadList)
}
})
}
}
}
</script>
<style scoped lang="scss">
@import "./fileUpload.scss";
</style>
@import '@/assets/globalStyle.scss';
.demo-upload-list{
display: inline-block;
text-align: center;
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0,0,0,.2);
margin-right: 4px;
}
.demo-upload-list img{
width: 100%;
height: 100%;
}
.demo-upload-list-cover{
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0,0,0,.6);
}
.demo-upload-list:hover .demo-upload-list-cover{
display: block;
}
.demo-upload-list-cover i{
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}
.my-upload-drag{
background: #fff;
border: 1px dashed $borderColor;
border-radius: 4px;
text-align: center;
cursor: pointer;
position: relative;
overflow: hidden;
-webkit-transition: border-color 0.2s ease;
transition: border-color 0.2s ease;
}
.my-upload-drag:hover {
border: 1px dashed $globalMainColor;
}
.my-upload-dragOver{
border: 2px dashed $globalMainColor;
}