一,代码内容
新建Vue文件名为vxe-upload.vue
<template>
<div class="upload-file pms-upload-file">
<el-upload
multiple
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
class="upload-file-uploader"
:auto-upload="autoUpload"
:on-change="loadJsonFromFile"
:data="uploadData"
:timeout="60000"
:name="uploadName"
ref="fileUpload"
>
<!-- 上传按钮 -->
<slot name="btn">
<el-button
size="mini"
type="primary"
>
上传附件
</el-button>
</slot>
<!-- 上传提示 -->
<div
class="el-upload__tip"
slot="tip"
v-if="showTip"
>
请上传
<template v-if="fileSize">
大小不超过
<b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为
<b style="color: #f56c6c">{{ fileType.join('/') }}</b>
</template>
的文件
</div>
</el-upload>
</div>
</template>
<script>
export default {
name: 'FileUpload',
props: {
uploadName: {
type: String,
default: 'file'
},
// 值
value: [String, Object, Array],
// 数量限制
limit: {
type: Number,
default: 5
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => [
'doc',
'docx',
'xls',
'xlsx',
'ppt',
'pptx',
'txt',
'pdf',
'jpg',
'png',
'jpeg',
'zip'
]
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
// 是否在选取文件后立即进行上传
autoUpload: {
type: Boolean,
default: true
},
// 是否显示已上传文件列表
showFileList: {
type: Boolean,
default: true
},
//是否显示删除按钮
showDelButton: {
type: Boolean,
default: true
},
// 是否在input事件回调中返回url字符串拼接
isReturnUrlStr: {
type: Boolean,
default: false
},
uploadFileUrl: {
type: String,
default: '/znpl_api/tblManual/uploadFile' // 默认上传接口
},
// 上传文件的额外参数
uploadData: {
type: Object,
default: () => {
return {};
}
}
},
data () {
return {
number: 0,
uploadList: [],
headers: {
// 'content-type': 'multipart/form-data;'
},
fileList: []
};
},
created () {
// 设置请求头
this.setHeaders();
},
watch: {
value: {
handler (val) {
if (val) {
let temp = 1;
// 首先将值转为数组
const list = Array.isArray(val) ? val : this.value.split(',');
// 然后将数组转为对象数组
this.fileList = list.map((item) => {
if (typeof item === 'string') {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
this.fileList = [];
return [];
}
},
deep: true,
immediate: true
}
},
computed: {
// 是否显示提示
showTip () {
return this.isShowTip && (this.fileType || this.fileSize);
}
},
methods: {
// 文件预览
async previewFile (file) {
if (!file.fileToken) {
this.$message.error('缺少文件fileToken');
return;
}
this.$fileFn.previewFile(file.fileName, file.fileToken, file.fileId);
},
// 文件下载
async downFile (file) {
this.$emit('downFile', file);
},
// 设置请求头
setHeaders () {
// 上传请求头设置
const headers = {
"token": '080549cf543f23dbbbba7632909af4fa',
"x-auth-token": '080549cf543f23dbbbba7632909af4fa'
};
this.headers = headers;
},
// 设置请求头的 sign 参数
setHeaderSign (file) {
const data = { ...this.uploadData };
const form = new FormData();
for (const key in data) {
form.append(key, data[key]);
}
form.append('uploadFile', file);
},
// 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
loadJsonFromFile (file, fileList) {
// 当上传交互为手动触发再去上传时,通过该钩子获取file文件对象
if (!this.autoUpload && this.showFileList) {
console.log(fileList);
this.fileList = fileList;
}
},
onRemove (file, fileList) {
// 只有手动触发时再去删除
if (!this.autoUpload && this.showFileList) {
const index = this.fileList.findIndex(
(fileItem) => fileItem.uid === file.uid
);
this.fileList.splice(index, 1);
}
},
// 上传前校检格式和大小
handleBeforeUpload (file) {
// 校检文件类型
if (this.fileType) {
const fileName = file.name.split('.');
const fileExt = fileName[fileName.length - 1];
const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) {
this.$message({
message: `文件格式不正确, 请上传${this.fileType.join('/')}格式文件!`,
type: 'error'
});
return false;
}
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message({
message: `上传文件大小不能超过 ${this.fileSize} MB!`,
type: 'error'
});
return false;
}
}
// 设置请求头 sing 参数
this.setHeaderSign(file);
this.number++;
return true;
},
// 文件个数超出
handleExceed () {
this.$message({
message: `上传文件数量不能超过 ${this.limit} 个!`,
type: 'error'
});
},
// 上传失败
handleUploadError (err) {
this.$message({
message: `上传文件失败,请重试`,
type: 'error'
});
},
// 上传成功回调
handleUploadSuccess (res, file) {
console.log(res, file);
if (res.uid) {
this.uploadList.push(res);
this.uploadedSuccessfully();
} else {
this.number--;
this.$message({
message: `${res.msg}`,
type: 'error'
});
this.$refs.fileUpload.handleRemove(file);
this.uploadedSuccessfully();
}
},
// 删除文件
handleDelete (index) {
this.fileList.splice(index, 1);
this.$emit('input', this.listToString(this.fileList));
},
// 上传结束处理
uploadedSuccessfully () {
if (this.number > 0 && this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList);
this.uploadList = [];
this.number = 0;
console.log(this.fileList,'this.fileList');
this.$emit('input', this.listToString(this.fileList));
}
},
// 对象转成指定字符串分隔
listToString (list, separator) {
if (!this.isReturnUrlStr) {
return list;
}
let strs = '';
separator = separator || ',';
for (let i in list) {
strs += list[i].url + separator;
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
}
};
</script>
二,调用
vxe控件中定义全局配置-借助高级渲染器使用没有被Vxe官方控件定义的组件。
// 高级渲染器使用外部组件
VXETable.renderer.add("UploadManual", {
/**
*
* @param {*} h 创建元素方法:createElement
* @param {*} renderOpts formConfig.items里当前数据项配置信息里itemRender的内容
* @param {*} params 包含$form(搜索表单实例)、data(表单绑定数据的集合)、field(表单项字段)、item(表单项配置数据(包含itemRender那种))、property(表单项字段)
* @returns
*/
renderItemContent (h, renderOpts, params) {
const { data, property } = params;
const props = renderOpts.props || {};
return [
<VxeUpload v-model={data[property]} {...{ props }} defaultValue={renderOpts.defaultValue}>
</VxeUpload>
];
}
});
界面中代码
{
field: "UploadManual",
title: "上传文件",
folding: false,
itemRender: {
name: "UploadManual",
props: {
uploadFileUrl: '/znpl_api/tblManual/uploadFile',
uploadName:'uploadManual',
uploadData:{
}
},
},
},