上传组件:
<template>
<div class="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"
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 = true
showPdfViewer.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.sbszhuangtai
form.value.masterId = props.masterId
getFileList()
})
</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, //主表id
type: ''
});
//上传清单附件
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>