样式1
样式2
上传的格式
// annexUrl 数据格式如下
[
{
"uid": 1682329534561,
"name": "2023/04/24/273f36b860a74e79be3faed3ce20236f.pdf",
"suffix": ".pdf",
"url": "http://192.168.0.254:19000/annex/2023/04/24/273f36b860a74e79be3faed3ce20236f.pdf",
"status": "success"
},
{
"uid": 1682386966277,
"name": "2023/04/25/eee1b9f5271543989d792d0fd1bb690c.doc",
"suffix": ".doc",
"url": "http://192.168.0.254:19000/annex/2023/04/25/eee1b9f5271543989d792d0fd1bb690c.doc",
"status": "success"
},
{
"name": "2023/04/25/9f910e55bad44e91a9f96b6d4a1aaeb6.pdf",
"suffix": ".pdf",
"url": "http://192.168.0.254:19000/annex/2023/04/25/9f910e55bad44e91a9f96b6d4a1aaeb6.pdf"
},
{
"name": "2023/04/25/02b17209170f4765908d49ed8aa82908.docx",
"suffix": ".docx",
"url": "http://192.168.0.254:19000/annex/2023/04/25/02b17209170f4765908d49ed8aa82908.docx"
}
]
upload接口返回的数据格式如下
组件封装
<!--
* @Description: 文件上传通用 组件 页面
* @Author: mhf
* @Date: 2023-04-24 18:32:39
* @Desc: 具体使用请参考 attachConfigDialog.vue 页面
-->
<template>
<div class="">
<el-upload
class="upload-demo"
:disabled="utilsObj.isDisabled"
:action="actionUrl"
:headers="headerObj"
:file-list="utilsObj.fileList"
:limit="utilsObj.limitNum"
:multiple="utilsObj.isMultiple"
:on-preview="handlePreview"
:on-success="handleSuccess"
:on-remove="handleRemove"
:before-upload="handBeforeUpload"
:on-exceed="handleExceed"
>
<!-- 上传按钮样式选择 -->
<div v-if="utilsObj.typeStyle === 0">
<!-- 按钮样式 -->
<el-button
:disabled="utilsObj.isDisabled"
size="small"
icon="iconfont if-biaodancaozuo-xinzeng"
class=""
>附件
</el-button>
</div>
<!-- el-icon样式 -->
<div v-if="utilsObj.typeStyle === 1">
<div v-if="!utilsObj.isDisabled" class="fileBox">
<i class="iconfont if-daoru"/>
<div>点击上传</div>
</div>
</div>
<!-- 提示:若想使用自定义样式,可添加插槽:<slot></slot> -->
<!-- 上传按钮样式选择 -->
</el-upload>
</div>
</template>
<script>
import { getToken } from '@/utils/auth'
export default {
name: 'index',
components: {},
props: {
/* 注意: 如果props里面的对象有默认参数时,必须用函数return一个对象 */
utilsObj: {
type: Object,
default: () => ({
isDisabled: false, // 是否禁用
fileList: [], // 附件列表
limitNum: 3, // 限制上传的文件数量 (个)
fileSize: 50, // 单文件上传大小(MB)
typeStyle: 0, // 文件上传的样式控制
isMultiple: false // 是否支持同时选择多个文件
})
}, // 附件上传的配置项
actionUrl: {
type: String,
default: process.env.VUE_APP_BASE_API + '/tlxx-modules-annex/minioAnnex/upload'
}, // 文件上传接口,
headerObj: {
type: Object,
default: function() {
return {
AuthorizationSys: getToken()
}
}
}, // 文件上传请求头参数 --- token
},
data() {
return {
resFileArr: [], // 最终需要的文件数据
}
},
methods: {
/**
* @Event 方法
* @description: 点击文件列表中已上传的文件时的钩子
* */
handlePreview(file) {
if (file.response) {
// 上传文件的时候 查看
window.open(file.response.data.url)
} else {
// 文件上传成功之后返回值 查看
window.open(file.url)
}
},
/**
* @Event 方法
* @description: 文件上传成功时的钩子
* */
handleSuccess(file) {
if (file.code === 1) {
this.resFileArr.push(file.data)
console.log(this.resFileArr, 'resFileArr')
this.$emit("getFileUploadYt", this.resFileArr);
} else {
this.$message.warning(file.message)
}
},
/**
* @Event 方法
* @description: 文件列表移除文件时的钩子
* */
handleRemove(file) {
console.log(file.response, this.resFileArr, file)
if (file.response) {
console.log('response have')
this.resFileArr.map((item, index) => {
if (item === file.response.data || item.url === file.response.data.url) {
this.resFileArr.splice(index, 1)
console.log(index)
this.$emit("getFileUploadYt", this.resFileArr);
}
})
} else {
console.log('no response')
this.resFileArr.map((item, index) => {
if (item === file || item.url === file.url) {
this.resFileArr.splice(index, 1)
console.log(index)
this.$emit("getFileUploadYt", this.resFileArr);
}
})
}
},
/**
* @Event 方法
* @description: 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
* */
handBeforeUpload(file) {
if (
[
'application/vnd.android.package-archive',
'application/x-zip-compressed',
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
].indexOf(file.type) === -1
) {
this.$message.error(
'请上传后缀名为 apk、zip、pdf、doc、docx、xls、xlsx的文件'
)
return false
}
if (file.size > this.utilsObj.fileSize * 1024 * 1024) {
this.$message.error(`文件大小不能超过 ${this.utilsObj.fileSize}MB`)
return false
}
},
/**
* @Event 方法
* @description: 文件超出个数限制时的钩子
* */
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 ${this.utilsObj.limitNum} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
}
},
created() {
},
mounted() {
setTimeout(() =>{
if (this.utilsObj.fileList) {
this.resFileArr = this.utilsObj.fileList
}
}, 500)
}
}
</script>
<style lang="scss" scoped>
.fileBox {
height: 36px;
background: rgba(255, 255, 255, 0);
border-radius: 4px;
display: flex;
align-items: center;
color: #1492ff;
font-weight: bold;
font-size: 16px;
i {
margin-right: 5px;
}
}
.disabledClass {
margin-top: -35px;
}
</style>
页面中使用(红框部分)
效果:
<el-form-item label="附件 :" prop="annexUrl">
<fileUploadYt ref="fileUploadYt" @getFileUploadYt="getAnnexUrl" :utilsObj="fileUploadUtils"/>
</el-form-item>
data() {
return {
fileUploadUtils: {
isDisabled: false, // 是否禁用
fileList: [], // 回显的附件列表
limitNum: 4, // 限制上传的文件数量 (个)
typeStyle: 0, // 文件上传的样式控制
}, // 附件上传的配置项
}
}
/**
* @Event 方法
* @description: 弹窗关闭事件
* */
hideDialog() {
this.fileUploadUtils.fileList = []; // 关闭弹窗时,清空附件列表
},
/**
* @Interface 接口
* @description: 获取详情
* */
getDetail(id) {
getProjectAnnexInfo(id).then((res) => {
if (res.code === 1) {
this.formData = res.data;
this.formData.annexUrl = JSON.parse(res.data.annexUrl);
if (!this.formData.annexUrl) {
this.formData.annexUrl = [];
}
this.fileUploadUtils.fileList = this.formData.annexUrl; // 附件回显
console.log(this.fileUploadUtils.fileList, 0)
} else {
this.$message.error("获取详情数据失败!");
}
});
},
/**
* @Event 方法
* @description: 获取组件上传得到的最终文件数组
* */
getAnnexUrl(data) {
console.log(data)
this.formData.annexUrl = data
}
注意:如果是在弹窗中使用该组件,必须用 v-if 如下图,否则会存在resFileArr不清空完全的问题
完整版示例
<template>
<el-dialog
:close-on-click-modal="false"
:title="title"
:visible.sync="visibleFlag"
v-if="visibleFlag"
width="900px"
append-to-body
@close="hideDialog"
>
<el-form
ref="form"
:model="formData"
:rules="formRules"
label-width="110px"
>
<el-form-item label="图标 :" prop="iconUrl">
<el-upload
class="avatar-uploader"
:action="sendImgUrl"
:headers="headerObj"
:show-file-list="false"
accept=".jpg, .png, jpeg"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="formData.iconUrl" :src="formData.iconUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<span class="tips">ps:支持png,jpg,小于10M,比例建议1:1</span>
</el-form-item>
<el-form-item label="附件名称 :" prop="annexName">
<el-input v-model="formData.annexName" placeholder="请输入附件名称" />
</el-form-item>
<el-form-item label="附件类型 :" prop="annexType">
<el-select
v-model="formData.annexType"
placeholder="附件类型"
clearable
>
<el-option
v-for="dict in dict.type.sys_annex_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="项目名称 :" prop="projectId">
<el-select
v-model="formData.projectId"
placeholder="项目名称"
clearable
>
<el-option
v-for="item in sysNameList"
:key="item.id"
:label="item.sysName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="备注 :" prop="remark">
<el-input
v-model="formData.remark"
placeholder="请输入备注"
type="textarea"
/>
</el-form-item>
<el-form-item label="附件 :" prop="annexUrl">
<fileUploadYt
ref="fileUploadYt"
@getFileUploadYt="getAnnexUrl"
:utilsObj="fileUploadUtils"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="text-align: center">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="hideDialog">取 消</el-button>
</div>
</el-dialog>
</template>
<script>
import {
getProjectAllList,
addProjectAnnex,
getProjectAnnexInfo,
updateProjectAnnex,
} from "@/api/system/projectAnnex/attachConfig";
import { getToken } from "@/utils/auth";
export default {
name: "attachConfigDialog",
dicts: ["sys_annex_type"],
data() {
return {
title: "",
visibleFlag: false,
formData: {
annexUrl: [],
},
formRules: {
annexName: [
{
required: true,
message: "请输入附件名称",
trigger: "blur",
},
],
annexType: [
{
required: true,
message: "请选择附件类型",
trigger: "blur",
},
],
iconUrl: [
{
required: true,
message: "请选择图标",
trigger: "blur",
},
],
},
sysNameList: [],
sendImgUrl:
process.env.VUE_APP_BASE_API + "/tlxx-modules-annex/minioAnnex/upload", // 文件上传接口
headerObj: {
AuthorizationSys: getToken(),
}, // 文件上传token
fileUploadUtils: {
isDisabled: false, // 是否禁用
fileList: [], // 回显的附件列表
limitNum: 3, // 限制上传的文件数量 (个)
typeStyle: 0, // 文件上传的样式控制
}, // 附件上传的配置项
};
},
methods: {
hideDialog() {
this.visibleFlag = false;
this.formData = {};
this.$parent.getList();
this.fileUploadUtils.fileList = []; // 关闭弹窗时,清空附件列表
},
showDialog(data) {
this.visibleFlag = true;
this.title = data.title;
this.getSysNameList();
if (this.title === "修改项目附件配置") {
this.getDetail(data.data.id);
}
},
/* 详情 */
getDetail(id) {
getProjectAnnexInfo(id).then((res) => {
if (res.code === 1) {
this.formData = res.data;
this.formData.annexUrl = JSON.parse(res.data.annexUrl);
if (!this.formData.annexUrl) {
this.formData.annexUrl = [];
}
this.fileUploadUtils.fileList = this.formData.annexUrl; // 附件回显
} else {
this.$message.error("获取详情数据失败!");
}
});
},
submitForm() {
this.$refs.form.validate((valid) => {
if (valid) {
if (this.title === "修改项目附件配置") {
this.formData.annexUrl !== []
? (this.formData.annexUrl = JSON.stringify(
this.formData.annexUrl
))
: (this.formData.annexUrl = []);
updateProjectAnnex(this.formData)
.then((res) => {
if (res.code === 1) {
this.$message.success("修改成功!");
this.hideDialog();
} else {
this.$message.warning(res.message);
}
})
.catch((e) => {
throw e;
});
}
if (this.title === "新增项目附件配置") {
this.formData.annexUrl !== []
? (this.formData.annexUrl = JSON.stringify(
this.formData.annexUrl
))
: (this.formData.annexUrl = []);
// this.formData.annexUrl = JSON.stringify(this.formData.annexUrl);
addProjectAnnex(this.formData)
.then((res) => {
if (res.code === 1) {
this.$message.success("添加成功!");
this.hideDialog();
} else {
this.$message.warning(res.message);
}
})
.catch((e) => {
throw e;
});
}
} else {
return false;
}
});
},
/* 获取系统名称的下拉列表 */
getSysNameList() {
getProjectAllList().then((res) => {
if (res.code === 1) {
this.sysNameList = res.data;
}
});
},
/* 图片 */
// 图片添加成功
handleAvatarSuccess(res) {
if (res.code === 1) {
this.$set(this.formData, "iconUrl", res.data.url);
}
},
// 上传图片拦截配置
beforeAvatarUpload(file) {
const isType =
file.type === "image/jpeg" ||
file.type === "image/png" ||
file.type === "image/jpg";
const isLt2M = file.size / 1024 / 1024 < 20;
if (!isType) {
this.$message.error("上传图标只能是 JPG、png 格式!");
}
if (!isLt2M) {
this.$message.error("上传图标不能超过 10MB!");
}
return isType && isLt2M;
},
/* 图片 */
/* 附件 单个 */
/**
* @Event 方法
* @description: 获取组件上传得到的最终文件数组
* */
getAnnexUrl(data) {
this.formData.annexUrl = data;
console.log(data, this.formData.annexUrl);
},
/* 附件 */
},
};
</script>
<style scoped>
/deep/ .avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
/deep/ .avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
.avatar {
width: 100px;
height: 100px;
display: block;
}
.tips {
font-size: 14px;
color: #dd4a68;
}
.tableImg {
width: 24px;
height: 24px;
border-radius: 15%;
}
</style>