前端vue+elementplus实现上传通用组件
上传组件:
<template><div class="upload-file"><el-uploadmultiple: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"ref="fileUploadRef"><!-- 上传按钮 --><el-button type="primary">选取文件</el-button></el-upload><!-- 上传提示 --><div class="el-upload__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><!-- 文件列表 --><transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul"><li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList"><el-link :href="`${file.url}`" :underline="false" target="_blank"><span class="el-icon-document"> {{ getFileName(file.name) }} </span></el-link><div class="ele-upload-list__item-content-action"><el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link></div></li></transition-group></div>
</template><script setup lang="ts">
import { listByIds, delOss } from "@/api/system/oss";
import { propTypes } from '@/utils/propTypes';
import { globalHeaders } from "@/utils/request";const props = defineProps({modelValue: [String, Object, Array],// 数量限制limit: propTypes.number.def(5),// 大小限制(MB)fileSize: propTypes.number.def(5),// 文件类型, 例如['png', 'jpg', 'jpeg']fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),// 是否显示提示isShowTip: propTypes.bool.def(true),
});const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const emit = defineEmits(['update:modelValue']);
const number = ref(0);
const uploadList = ref<any[]>([]);const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadFileUrl = ref(baseUrl + "/resource/oss/upload"); // 上传文件服务器地址
const headers = ref(globalHeaders());const fileList = ref<any[]>([]);
const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize)
);const fileUploadRef = ref<ElUploadInstance>();watch(() => props.modelValue, async val => {if (val) {let temp = 1;// 首先将值转为数组let list = [];if (Array.isArray(val)) {list = val;} else {const res = await listByIds(val as string)list = res.data.map((oss) => {const data = { name: oss.originalName, url: oss.url, ossId: oss.ossId };return data;});}// 然后将数组转为对象数组fileList.value = list.map(item => {item = { name: item.name, url: item.url, ossId: item.ossId };item.uid = item.uid || new Date().getTime() + temp++;return item;});} else {fileList.value = [];return [];}
}, { deep: true, immediate: true });// 上传前校检格式和大小
const handleBeforeUpload = (file: any) => {// 校检文件类型if (props.fileType.length) {const fileName = file.name.split('.');const fileExt = fileName[fileName.length - 1];const isTypeOk = props.fileType.indexOf(fileExt) >= 0;if (!isTypeOk) {proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);return false;}}// 校检文件大小if (props.fileSize) {const isLt = file.size / 1024 / 1024 < props.fileSize;if (!isLt) {proxy?.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);return false;}}proxy?.$modal.loading("正在上传文件,请稍候...");number.value++;return true;
}// 文件个数超出
const handleExceed = () => {proxy?.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}// 上传失败
const handleUploadError = () => {proxy?.$modal.msgError("上传文件失败");
}// 上传成功回调
const handleUploadSuccess = (res: any, file: UploadFile) => {if (res.code === 200) {uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });uploadedSuccessfully();} else {number.value--;proxy?.$modal.closeLoading();proxy?.$modal.msgError(res.msg);fileUploadRef.value?.handleRemove(file);uploadedSuccessfully();}
}// 删除文件
const handleDelete = (index: number) => {let ossId = fileList.value[index].ossId;delOss(ossId);fileList.value.splice(index, 1);emit("update:modelValue", listToString(fileList.value));
}// 上传结束处理
const uploadedSuccessfully = () => {if (number.value > 0 && uploadList.value.length === number.value) {fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);uploadList.value = [];number.value = 0;emit("update:modelValue", listToString(fileList.value));proxy?.$modal.closeLoading();}
}// 获取文件名称
const getFileName = (name: string) => {// 如果是url那么取最后的名字 如果不是直接返回if (name.lastIndexOf("/") > -1) {return name.slice(name.lastIndexOf("/") + 1);} else {return name;}
}
// 对象转成指定字符串分隔
const listToString = (list: any[], separator?: string) => {let strs = "";separator = separator || ",";list.forEach(item => {if (item.ossId) {strs += item.ossId + separator;}})return strs != "" ? strs.substring(0, strs.length - 1) : "";
}
</script><style scoped lang="scss">
.upload-file-uploader {margin-bottom: 5px;
}.upload-file-list .el-upload-list__item {border: 1px solid #e4e7ed;line-height: 2;margin-bottom: 10px;position: relative;
}.upload-file-list .ele-upload-list__item-content {display: flex;justify-content: space-between;align-items: center;color: inherit;
}.ele-upload-list__item-content-action .el-link {margin-right: 10px;
}
</style>
自定义组件:
<template><div><el-dialog @close="onClose" :close-on-click-modal="false" :title="props.title" v-model="props.visible" append-to-body><div>
<!-- <DropFileUpload v-if="form.zhuangtai == '0'" :file-size="100" v-model="form.wenJianId" :file-type="['pdf']" :limit="1"></DropFileUpload>--><file-upload v-model="form.wenJianId" :file-type="['pdf']" :limit="5" :file-size="10" /></div><el-table :data="shenBaoShuList"><el-table-column label="文件名称" align="left" prop="originalName"><template #default="scope"><el-link link type="primary" @click="handleShowPdfViewer(scope.row.ossId)">{{scope.row.originalName}}</el-link></template></el-table-column><el-table-column label="上传时间" width="200" align="center" prop="createTime" /><el-table-column label="操作" width="100" align="center"><template #default="scope"><el-button size="small" :disabled="form.zhuangtai == '1'" type="danger" @click="handleDelete(scope.row)" >删除</el-button></template></el-table-column></el-table></el-dialog><el-drawer v-model="showPdfViewer.visible" :title="showPdfViewer.title" direction="rtl" size="60%"><oss-pdf-viewer v-if="showPdfViewer.visible" :oss-id="showPdfViewer.ossId"></oss-pdf-viewer></el-drawer></div>
</template>
<script setup lang="ts">
// 所有的专科
import DropFileUpload from '@/components/DropFileUpload/index.vue'import ossPdfViewer from '@/components/PdfViewer/oss.vue';
import {defineEmits} from "vue";
import FileUpload from "@/components/FileUpload/index.vue";
import {SysOssVo} from '@/api/medicaltechnology/beianKeshiDetail/types';const {proxy} = getCurrentInstance() as ComponentInternalInstance;
const {shenbaoshu_zhuangtai} = toRefs<any>(proxy?.useDict('shenbaoshu_zhuangtai'));
const emit = defineEmits<{(e: 'update:visible', value: boolean): void;
}>();
const shenBaoShuList = ref<SysOssVo[]>([]);
const form = ref({masterId:'',wenJianId: '',//可以上传多个文件,用,隔开zhuangtai: ''
});interface ShowPdfViewer {title: string;ossId?: string | number;visible: boolean;
}// 文件预览
const showPdfViewer = ref<ShowPdfViewer>({title: '',ossId: '',visible: false,
});
const props = defineProps({title: {type: String,default: ''},sbszhuangtai: {type: String,default: ''},visible: {type: Boolean,default: false},masterId: {type: [ Number],default: ''},type: {type: String,default: '' //附件清单上传,科室上传,负责人上传 file,dept,leader}
});
const onClose = () => {emit('update:visible', false);};
// 获取文件列表
const getFileList = async () => {console.log(props.masterId);//根据不同类型去获取文件列表shenBaoShuList.value = [];// const res = await getFileListByZhuBiaoId(props.zhuBiaoId as number);// if (res.data) { // 检查 res.data 是否为 null// shenBaoShuList.value.push(res.data);// }
};/** 删除按钮操作 */
const handleDelete = async (row?: SysOssVo) => {await proxy?.$modal.confirm('是否确认删除选择项?');//根据文件类型去删除// await deleteFileByFileId(row?.ossId || 0);proxy?.$modal.msgSuccess('删除成功');await getFileList();
};
//文件预览
const handleShowPdfViewer = (ossid: number) => {showPdfViewer.value.visible = trueshowPdfViewer.value.ossId = ossid
}
watch(() => form.value.wenJianId, () => {//根据文件类型触发上传// uploadZiPingFile(form.value.zhuBiaoId , form.value.wenJianId).then(() => {// proxy?.$modal.msgSuccess('上传成功');// getFileList()// })
})watch(() => props.masterId, () => {// form.value.zhuangtai = props.sbszhuangtaiform.value.masterId = props.masterIdgetFileList()
})
</script>
<style scoped lang="scss"></style>
页面实际调用:、
<!-- 上传附件的对话框--><qing-dan-upload:sbszhuangtai="showOtherFiles.zhuangtai":zhuBiaoId="showOtherFiles.zhuBiaoId"v-model:visible="showOtherFiles.visible":title="showOtherFiles.title"></qing-dan-upload>//上传
const showOtherFiles = reactive({visible: false, //对话跨title: '', //标题masterId: 0, //主表idtype: ''
});
//上传清单附件
const openUploadFileDialog = (row: QingdanVO,type:string) => {showOtherFiles.visible = true;showOtherFiles.title = row?.cailiaoMingcheng + '附件';showOtherFiles.masterId = row?.masterId;showOtherFiles.type = type;
};
pdf预览组件:oss.vue
<template><!-- {{pdfUrl}}--><iframe :src="pdfUrl" style="border: none; width: 100%; height: 100%;"></iframe><!-- <pdf-viewer :pdf-url="pdfUrl"></pdf-viewer>-->
</template><script setup name="OssPdfViewer" lang="ts">
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps({ossId: {type: [String , Number],required: true,},
});
const pdfUrl = ref('')
const handleDownload = () => {proxy?.$download.ossBlod(props.ossId).then(data=>{const blob = new Blob([data],{type:'application/pdf'})let url = window.URL.createObjectURL(blob)pdfUrl.value = url})
}
watch(()=>props.ossId,()=>{handleDownload()
})onMounted(()=>{handleDownload()
})
</script>