<template> <div class="upload-file" :style="{width: maxNums>1?'100%':'auto'}"> <a-upload :action="action" :listType="listType" :fileList="fileList" :disabled="disabled" @preview="handlePreview" @change="handleChange" :headers="headers" :remove="handleRemove" :beforeUpload="beforeUpload" :data="params" :value="comVal" > <div v-if="fileList.length < maxNums && listType=='picture-card'"> <a-icon type="plus" /> <div class="ant-upload-text"> {{ upText }}</div> </div> <div v-if="fileList.length < maxNums && listType!='picture-card'"> <a-button> <a-icon type="upload" /> {{ upText }} </a-button> </div> </a-upload> <a-modal :visible="previewVisible" :footer="null" centered :maskClosable="false" @cancel="handleCancel"> <div style="height: 30px;">预览</div> <video v-if="fileType=='video/mp4'" controls="controls" style="width: 100%" :src="previewImage" /> <img v-else alt="example" style="width: 100%" :src="previewImage" /> </a-modal> </div> </template> <script> import Sortable from 'sortablejs' import { moveElement } from '@/libs/tools' export default { name: 'Upload', props: { maxNums: { type: Number, default: 1 }, fileType: { type: String, default: 'image/jpeg,image/png' }, fileSize: { type: Number, default: 5 }, previewFile: { type: Function, default: function () { } }, action: { type: String, default: process.env.VUE_APP_API_BASE_URL + '/upload' }, listType: { type: String, default: 'text' }, upText: { type: String, default: '上传文件' }, value: { type: String }, uploadParams: { type: Object, default: function () { return { savePathType: 'ali' // 存储类型 local 服务器本地,ali 阿里云, web } } }, disabled: { type: Boolean, default: false }, uploadType: { // 上传类型 img图片;attach附件;import导入 type: String, default: 'img' } }, watch: { value (a, b) { this.comVal = a || '' if (a == undefined) { this.fileList = [] } }, uploadParams (val) { this.params = val } }, data () { return { previewVisible: false, previewImage: '', fileList: [], comVal: this.value, params: this.uploadParams, headers: { 'access-token': this.$store.state.user.token } } }, created () { const _this = this this.$nextTick(() => { const el = document.querySelector('.ant-upload-list-picture-card') if (el) { const sortable = Sortable.create(el, { onEnd: function (evt) { console.log(evt.oldIndex, evt.newIndex) const a = _this.formatFile() console.log(a.split(',')) const ret = moveElement(a.split(','), evt.oldIndex, evt.newIndex) console.log(ret) _this.$emit('change', ret.join(',')) _this.$emit('input', ret.join(',')) } }) } }) }, methods: { setFileList (a) { const temp = [] if (a && a.length > 0) { if (this.uploadType == 'img' || this.uploadType == 'import') { // 图片/导入 a.split(',').map((item, index) => { if (item) { temp.push({ uid: index, name: item, status: 'done', url: item, response: { data: item } }) } }) } else if (this.uploadType == 'attach') { // 附件 a.map((item, index) => { if (item) { const arr = [] arr.push(item) // 包裹成与新上传文件数据返回结构一致 temp.push({ uid: index, name: item.fileName, status: 'done', url: item.filePath, response: { data: arr } }) } }) } } this.fileList = temp }, handleCancel () { this.previewVisible = false }, handlePreview (file) { console.log(file) if (file.type && (file.type.indexOf('image') >= 0 || file.type.indexOf('video') >= 0)) { if (file.response && file.response.status && file.response.status == 200) { const src = file.response.data this.previewImage = src && Array.isArray(src) ? src[0] && src[0].filePath : src } else { this.previewImage = file.url || file.thumbUrl } this.previewVisible = true } else { const src = file.response.data if (!Array.isArray(src)) { this.previewImage = file.url || file.thumbUrl this.previewVisible = true } } }, handleRemove (file) { this.$emit('remove') }, handleChange ({ file, fileList }) { // console.log(file, fileList, '-----change') // if (file.status == 'error' || (file.response && (file.response.status == 500 || file.response.status == 900))) { // this.$message.error('上传失败,请重试!') // this.$emit('remove') // return // } if (file.response && (file.response.status == 500 || file.response.status == 900)) { if (file.status == 'error' || file.status == 'done') { this.$message.error(file.response.message || '上传失败,请重试!') this.$emit('remove') // return } } this.fileList = this.validaFile(file, fileList) this.$emit('change', this.formatFile()) this.$emit('input', this.formatFile()) }, // 格式化文件列表数据,给表单 formatFile () { const a = this.fileList let temp = [] let obj = null if (a && a.length) { if (this.uploadType == 'img' || this.uploadType == 'import') { // 图片/导入 将接口的返回图片地址逗号拼接后返回页面 a.map(item => { if (item.response && item.status == 'done') { temp.push(item.response.data) } }) obj = temp.join(',') } else if (this.uploadType == 'attach') { // 附件 将接口的返回数据返回页面 a.map(item => { if (item.response && item.status == 'done') { if (item.response.data instanceof Array) { temp = [...temp, ...item.response.data] } else { temp = [...temp, ...[item.response.data]] } } }) // console.log(temp) obj = JSON.stringify(temp) } } return obj }, // 文件校验 validaFile (file, filesList) { if (filesList.length == 0) { return [] } // console.log(file, filesList, this.beforeUpload(file, 0)) if (!this.beforeUpload(file, 0) && file.status != 'removed' || file.status == 'error') { const index = filesList.findIndex(item => item.uid == file.uid) filesList.splice(index, 1) } return filesList || [] }, // 上传前校验 beforeUpload (file, tip) { // 不限制 if (this.fileType == '*') { // 文件大小 const isLt2M = file.size / 1024 / 1024 < this.fileSize if (!isLt2M) { if (tip != 0) { this.$message.error('上传文件不能超过 ' + this.fileSize + 'MB!') } return isLt2M } return true } const isType = this.fileType.indexOf(file.type) >= 0 && file.type != '' if (!isType) { if (tip != 0) { this.$message.error('请上传正确的格式!') } return isType } // 文件大小 const isLt2M = file.size / 1024 / 1024 < this.fileSize if (!isLt2M) { if (tip != 0) { if (this.fileType != 'video/mp4') { this.$message.error('图片不能超过 ' + this.fileSize + 'MB!') } else { this.$message.error('视频不能超过 ' + this.fileSize + 'MB!') } } return isLt2M } return true } } } </script> <style lang="less" scoped> .upload-file{ float: left; overflow: hidden; /* you can make up upload button and sample style by using stylesheets */ .ant-upload-select-picture-card i { font-size: 32px; color: #999; } .ant-upload-select-picture-card .ant-upload-text { color: #666; } .ant-upload-btn{ height: 100%; >div{ padding: 4px 0; } } .ant-upload-list-picture-card-container{ height: 80px; width: 80px; } .ant-upload.ant-upload-select-picture-card, .ant-upload-list-picture-card .ant-upload-list-item{ width:80px; height:80px; padding: 4px; margin: 0; } .ant-upload-list-item-info{ padding: 0 22px 0 4px; } .ant-upload-list-item .anticon-close{ color: red; } .ant-upload-list-item-name{ word-break: break-all; white-space: normal; } } /deep/.ant-modal-body{ max-height:860px; text-align:center; } /deep/.ant-modal-close-x{ height: 35px; line-height: 35px; width: 35px; } /deep/.ant-modal-body video{ width: 90% !important; } </style>