a-upload封装
- 效果
- 自定义上传customRequest
- transformFile上传前修改文件流
- 自定义预览
- 调整props和a-uoload一致
- install封装vue组件
- 结束
效果
编辑
预览
不展示删除和上传
空数据
自定义图片样式
自定义上传customRequest
入参是本地上传的文件流
async customRequest(file) {
const form = new FormData()
form.append('file', file.file)
form.append('name', file.name)
try {
this.uploadLoading = true
const res = await postAction(this.uploadActionUrl, form)
if (res.success) {
this.picUrl = true
const length = this.fileList.length
const url = getFileAccessHttpUrl(res.message)
const type = res.message ? res.message.split('.')[res.message.split('.').length - 1] : 'null'
const addFile = {
uid: new Date().valueOf(),
type: type,
name: this.renderDisplayName(file.file.name),
status: 'done',
response: {
status: 'done',
message: res.message,
},
url: url,
message: res.message,
index: length,
}
this.fileList.push(addFile)
this.$message.success('上传成功')
this.$emit('change', this.fileList.map((item) => item.message).join(','))
} else {
this.$message.error('上传失败')
}
this.uploadLoading = false
} catch (r) {
this.uploadLoading = false
this.$message.error('上传失败')
console.warn(r)
}
}
transformFile上传前修改文件流
入参是本地上传的文件流
这里我修改文件流的名称,返回file的promise
transformFile(file) {
return new Promise((resolve) => {
const currentTime = new Date()
const type = file.type.split('/')
const renameFile = new File([file], currentTime.valueOf() + '.' + type[1], { type: file.type })
resolve(renameFile)
})
}
自定义预览
handlePreview(file) {
return new Promise((resolve, reject) => {
try {
resolve(this.previewFile(file))
} catch (r) {
reject(r)
}
})
},
调整props和a-uoload一致
<template>
<div style="display: inline-block">
<div>
<a-upload
name="file"
:accept="accept"
:multiple="isMultiple"
:disabled="disabled"
:headers="headers"
:fileList="[]"
:customRequest="customRequest"
:beforeUpload="beforeUpload"
:remove="handleDelete"
:transformFile="transformFile"
>
<a-button :loading="uploadLoading" v-if="!disabled && isMultiple && fileList.length < limit">
<a-icon type="upload" /> {{text}}
</a-button>
</a-upload>
<template v-if="fileList.length">
<div v-for="(item, index) in fileList" :key="index" class="file-list-box">
<img v-if="isImg(item.type)" :src="item.url" class="upload-icon-view" />
<a-icon v-else-if="isPdf(item.type)" class="upload-icon-view" type="file" />
<a-tooltip :title="item.name">
<span class="upload-name-view">{{ item.name }}</span>
</a-tooltip>
<a-tooltip title="预览">
<span style="color: #0071fc; margin: 0 20px"><a-icon type="eye" @click="handlePreview(item)" /></span>
</a-tooltip>
<a-tooltip title="删除">
<span style="color: #f5222d" v-if="!disabled"><a-icon type="delete" @click="handleDelete(item)" /></span>
</a-tooltip>
</div>
</template>
<template v-else-if="disabled">
<div style="text-align: left">
<img :src="require('@/assets/gaoxinImgs/null-content.png')" alt="暂无数据" style="max-width: 100px" />
<p style="text-align: center; width: 100px">暂无数据</p>
</div>
</template>
</div>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="图片" style="width: 100%; height: 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { postAction, getFileAccessHttpUrl, getAction } from '@/api/manage'
const uidGenerator = () => {
return '-' + parseInt(Math.random() * 10000 + 1, 10)
}
const getFileName = (path) => {
if (path.lastIndexOf('\\') >= 0) {
let reg = new RegExp('\\\\', 'g')
path = path.replace(reg, '/')
}
return path.substring(path.lastIndexOf('/') + 1)
}
export default {
name: 'JFileUpload',
data() {
return {
url: window._CONFIG['pdfDomainURL'],
staticUrl: window._CONFIG['pdfPreviewURL'],
id: 'pdfFilePreviewIframeId',
fileName: '',
uploadAction: window._CONFIG['domianURL'] + '/sys/common/upload',
uploadActionUrl: '/sys/common/upload',
uploadLoading: false,
picUrl: false,
headers: {},
token: {},
fileList: [],
previewImage: '',
previewVisible: false,
}
},
props: {
accept: {
type: String,
default: () => 'image/*,.pdf',
},
limit: {
type: Number,
default: 10,
},
text: {
type: String,
required: false,
default: '上传附件(图片、pdf)',
},
/*这个属性用于控制文件上传的业务路径*/
bizPath: {
type: String,
required: false,
default: 'temp',
},
value: {
type: [String, Array],
required: false,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
isMultiple: {
type: Boolean,
required: false,
default: true,
},
},
watch: {
value: {
deep: true,
handler(val) {
this.initFile(val)
},
},
},
created() {
const token = Vue.ls.get(ACCESS_TOKEN)
this.token = token
this.headers = { 'X-Access-Token': token }
this.initFile(this.value)
},
methods: {
initFile(val) {
if (val instanceof Array) {
this.initFileList(val.join(','))
} else {
this.initFileList(val)
}
},
isWord(fileType) {
const wordTypeArray = ['doc', 'docx']
const isWord = wordTypeArray.some((type) => {
return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
})
return isWord
},
isExcel(fileType) {
const excelTypeArray = ['XLS', 'XLSX', 'XLSB', 'XLSM', 'XLST', 'sheet']
const isExcel = excelTypeArray.some((type) => {
return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
})
return isExcel
},
isImg(fileType) {
const imgTypeArray = ['BMP', 'JPG', 'JPEG', 'PNG', 'GIF']
const isImgType = imgTypeArray.some((type) => {
return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
})
return isImgType
},
isPdf(fileType) {
const pdfTypeArray = ['PDF']
const isPdfType = pdfTypeArray.some((type) => {
return fileType.toString().toUpperCase().includes(type.toString().toUpperCase())
})
return isPdfType
},
renderDisplayName(name) {
return name
},
async customRequest(file) {
const form = new FormData()
form.append('file', file.file)
form.append('biz', this.bizPath)
try {
this.uploadLoading = true
const res = await postAction(this.uploadActionUrl, form)
if (res.success) {
this.picUrl = true
const length = this.fileList.length
const url = getFileAccessHttpUrl(res.message)
const type = res.message ? res.message.split('.')[res.message.split('.').length - 1] : 'null'
const addFile = {
uid: uidGenerator(),
type: type,
name: this.renderDisplayName(file.file.name),
status: 'done',
response: {
status: 'done',
message: res.message,
},
url: url,
message: res.message,
index: length,
}
this.fileList.push(addFile)
this.$message.success('上传成功')
this.$emit('change', this.fileList.map((item) => item.message).join(','))
} else {
this.$message.error('上传失败')
}
this.uploadLoading = false
} catch (r) {
this.uploadLoading = false
this.$message.error('上传失败')
console.warn(r)
}
},
transformFile(file) {
return new Promise((resolve) => {
const currentTime = new Date()
const type = file.type.split('/')
const renameFile = new File([file], currentTime.valueOf() + '.' + type[1], { type: file.type })
resolve(renameFile)
})
},
previewPdf(file) {
const prefixUrl = this.staticUrl
const path = file.response.message
const fileUrl = prefixUrl + path
return getAction(`/mybiz/myfile/preview/${fileUrl}`).then((previewUrl) => {
if (previewUrl.toString().indexOf('http://') === 0) {
const page = window.open(previewUrl)
console.warn('page', page)
} else {
const page = window.open('http://' + previewUrl)
console.warn('page', page)
}
})
},
previewImg(file) {
this.previewImage = file.url
this.previewVisible = true
},
previewExcel(file) {
console.log('previewExcel', file)
// 创建blob对象,解析流数据
},
previewFile(file) {
const fileType = file.type
console.log('fileType', fileType)
if (this.isImg(fileType)) {
return this.previewImg(file)
} else {
return this.previewPdf(file)
}
},
initFileList(paths) {
this.fileList = []
if (!paths || paths.length === 0) {
return 0
}
paths.split(',').forEach((item, index) => {
const url = getFileAccessHttpUrl(item)
const name = getFileName(item)
const type = name && name.split('.').length ? name.split('.')[name.split('.').length - 1] : 'null'
this.fileList.push({
uid: uidGenerator(),
name: this.renderDisplayName(name),
type: type,
status: 'done',
url: url,
response: {
status: 'history',
message: item,
},
message: item,
index: index,
})
})
},
beforeUpload(file) {
console.log('file', file)
const fileType = file.name.split('.')[file.name.split('.').length - 1]
// console.log('fileType', fileType)
if (!this.isImg(fileType) && !this.isPdf(fileType)) {
this.$message.warning('请上传图片或PDF')
return false
}
},
// 自定义预览
handlePreview(file) {
return new Promise((resolve, reject) => {
try {
resolve(this.previewFile(file))
} catch (r) {
reject(r)
}
})
},
handleDelete(file) {
this.fileList = this.fileList.filter((item) => item.uid!== file.uid)
},
handleCancel() {
this.close()
},
close() {
this.previewImage = ''
this.previewVisible = false
},
},
model: {
prop: 'value',
event: 'change',
},
}
</script>
<style scoped>
.upload-name-view {
max-width: 80px;
white-space: nowrap;
text-overflow: ellipsis;
}
.upload-icon-view {
position: relative;
max-height: 48px;
min-height: 48px;
font-size: 32px;
padding: 2px 10px 2px 2px;
color: #0071fc;
}
.after-icon {
line-height: 48px;
}
.file-list-box {
position: relative;
height: 66px;
line-height: 48px;
padding: 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
margin-top: 10px;
width: fit-content;
}
</style>
install封装vue组件
抛出去install在入口调用即可
import JFileUpload from './JFileUpload.vue'
export default {
install(Vue) {
Vue.component(JFileUpload.name, JFileUpload)
},
}