一、初始代码
1. 初始使用组件代码片段
<DialogUploadFile ref="uploadFile" @success="refresh" />
const uploadHandle = () => {if (selections.value.length != 1) {onceMessage.warning('请选择一条数据操作')return}uploadFile.value.show(selections.value[0])
}
2. 上传组件初始代码 DialogUploadFile.vue
<template><div class="no-modal-dialog"><el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px" :close-on-click-modal="false"><el-row :gutter="20"><el-col :span="12"><div class="title">选择附件</div><el-uploadclass="upload-box"multiple:show-file-list="false":accept="fileTypes":before-upload="beforeUpload":drag="true"@drop.native="e => beforeUploadHandler(e.dataTransfer.files)"><div><el-button type="primary">点击选择附件</el-button><p class="el-upload__text">或将附件拖到这里</p><p class="el-upload__text">请上传pdf、pptx、ppt、docx、doc、zip、mp3格式</p></div></el-upload></el-col><el-col :span="12"><div class="title">附件列表</div><div class="list-header list-item"><div class="left">名称</div><div class="right">上传状态</div></div><ul class="list-box"><template v-if="fileList && fileList.length > 0"><li :class="['list-item', item.statusName == '上传中' ? 'gray' : '']" v-for="item of fileList" :key="item.id"><div class="left">{{ item.fileName }}</div><div :class="['right', item.statusName == '上传失败' ? 'error' : '']"><span>{{ item.statusName }}</span><el-icon v-if="item.statusName != '上传中'" class="del-icon" @click="delFile(item)"><Close /></el-icon></div></li></template><el-empty v-else description="暂无数据" /></ul></el-col></el-row><template #footer><el-button @click="onReset" v-out>取消</el-button><el-button @click="onSubmit" :disabled="disabledBtn" :loading="submitLoading" type="primary" v-out>确定</el-button></template></el-dialog></div>
</template>
<script setup lang="ts" name="DialogUploadFile">
import lodash from 'lodash'
import { appendixList, uploadFileApi, singleUploadBook } from '@/api/product-manage/electronic'
import { ElMessageBox } from 'element-plus'
import type { UploadProps } from 'element-plus'
import { onMounted, ref, inject, nextTick } from 'vue'
import type { productItem, fileItem } from '@/models/product'
import { compactEmpty } from '@/utils/tool'const onceMessage: any = inject('$onceMessage')
const dialogTitle = ref<string>('')
const submitLoading = ref<boolean>(false)
const dialogVisible = ref<boolean>(false)
const disabledBtn = ref<boolean>(false)
const productInfo = ref<productItem>({})
const fileTypes = ref<string>('.pdf, .doc, .docx, .ppt, .pptx,.zip,.mp3')
const fileList = ref<fileItem[]>([])
const delList = ref<fileItem[]>([])
const emits = defineEmits<{(e: 'success'): void
}>()const show = (row: productItem) => {dialogVisible.value = trueproductInfo.value = rowdelList.value = []getFileList(row.serialNo)dialogTitle.value = `上传:${row.productName}`
}
defineExpose({ show })
const setType = (str: string) => {let index = str.lastIndexOf('.')let fileType = str.substring(index + 1, str.length)let shortName = str.substring(0, index)return {fileType,shortName}
}
const getFileList = (serialNo: string) => {if (!serialNo) {return}appendixList(serialNo).then(res => {let arr = res.data || []arr.forEach((item: fileItem, index: number) => {item.statusName = '已完成'let e = setType(item.fileName)item.fileType = e.fileTypeitem.shortName = e.shortName})fileList.value = arr})
}
const beforeUploadHandler = (obj: {}) => {for (var i in obj) {let e = setType(obj[i].name)let types = ['pdf', 'doc', 'docx', 'ppt', 'pptx', 'zip', 'mp3']if (types.indexOf(e.fileType) == -1) {ElMessageBox.confirm(`请上传pdf、pptx、ppt、docx、doc、zip、mp3格式`, obj[i].name + '格式错误', {confirmButtonText: '确定',showCancelButton: false,type: 'warning',closeOnClickModal: false}).then(() => {}).catch(() => {})}}
}
const beforeUpload: UploadProps['beforeUpload'] = rawFile => {let e = setType(rawFile.name)let exit = falseif (['doc', 'docx'].indexOf(e.fileType) != -1) {let arr = lodash.filter(fileList.value, function (item) {return ['doc', 'docx'].indexOf(item.fileType) != -1})arr.forEach(item => {if (item.shortName == e.shortName) {exit = true}})} else if (['ppt', 'pptx'].indexOf(e.fileType) != -1) {let arr = lodash.filter(fileList.value, function (item) {return ['ppt', 'pptx'].indexOf(item.fileType) != -1})arr.forEach(item => {if (item.shortName == e.shortName) {exit = true}})} else {fileList.value.forEach(item => {if (item.shortName == e.shortName && item.fileType == e.fileType) {exit = true}})}if (exit) {ElMessageBox.confirm(`附件列表中存在为${rawFile.name}的文件?`, '重名提示', {confirmButtonText: '替换附件列表文件',cancelButtonText: '跳过文件',type: 'warning',closeOnClickModal: false}).then(() => {fileList.value.forEach((item: fileItem, index: number) => {let files = setType(item.fileName)if (['doc', 'docx'].indexOf(e.fileType) != -1 && ['doc', 'docx'].indexOf(files.fileType) != -1 && e.shortName == files.shortName) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id)} else if (['ppt', 'pptx'].indexOf(e.fileType) != -1 && ['ppt', 'pptx'].indexOf(files.fileType) != -1 && e.shortName == files.shortName) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id)} else if (item.fileName == rawFile.name) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id)}})}).catch(() => {})} else {let item = {id: rawFile.uid + '',fileName: rawFile.name,filePath: '',statusName: '上传中',fileType: e.fileType,shortName: e.shortName,updateFlag: 0}fileList.value.push(item)uploadFile(rawFile, item.id)}return false
}
const uploadFile = (e: any, id: string | number, markFlag: any = 1) => {let params = new FormData()params.append('file', e)params.append('folderId', '')params.append('markFlag', markFlag)uploadFileApi(params).then(res => {fileList.value.forEach(item => {if (item.id == id) {item.filePath = res.dataitem.statusName = '已完成'}})}).catch(err => {fileList.value.forEach(item => {if (item.id == id) {item.statusName = '上传失败'}})})
}
const delFile = (e: fileItem) => {fileList.value = lodash.filter(fileList.value, function (item) {return item.id != e.id})if (compactEmpty(e.updateFlag)) {delList.value.push(e)}
}
const onReset = () => {dialogVisible.value = false
}
const onSubmit = () => {let updateArr = lodash.filter(fileList.value, function (item) {return item.statusName == '已完成' && !compactEmpty(item.updateFlag)})if (delList.value.length < 1 && updateArr.length < 1) {dialogVisible.value = falseallMark.value = falsemarkFlag.value = nullreturn} let param = {bookName: productInfo.value.productName,serialNo: productInfo.value.serialNo}let appendixes: fileItem[] = []fileList.value.forEach((item: fileItem) => {if (item.statusName == '已完成' && !compactEmpty(item.updateFlag)) {appendixes.push({id: item.updateFlag == 0 ? '' : item.id,fileName: item.fileName,filePath: item.filePath,updateFlag: item.updateFlag})}})delList.value.forEach((item: fileItem) => {if (item.statusName == '已完成') {appendixes.push({id: item.id,fileName: item.fileName,filePath: item.filePath,updateFlag: 2})}})submitLoading.value = truesingleUploadBook({...param,appendixes}).then(res => {emits('success')onceMessage.success('上传成功')submitLoading.value = falsedialogVisible.value = false}).catch(e => {submitLoading.value = false})
}
</script>
<style lang="scss">
.el-overlay {background-color: transparent;
}
.upload-box {.ep-upload.is-drag {display: block;height: 60vh;width: 100%;.ep-upload-dragger {width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;background-color: transparent;border: 2px dashed #e5e6eb;&:hover {border-color: #e5e6eb;}}}
}
</style><style lang="scss" scoped>
.title {font-size: $text_color;font-size: 16px;font-weight: 600;margin-bottom: $spacing;
}
.upload-box {height: 60vh;width: 100%;display: flex;justify-content: center;align-items: center;.el-upload__text {color: $gray_text_color;margin-top: $spacing;}
}
.list-box {height: calc(60vh - 30px);box-sizing: border-box;overflow: auto;
}
.list-item {display: flex;justify-content: flex-start;align-items: center;border-top: 1px solid $border_color;padding: 5px 0;.left {width: 70%;padding-right: 24px;box-sizing: border-box;}.right {width: 30%;display: flex;justify-content: space-between;align-items: center;}.del-icon {cursor: pointer;&:hover {color: $primary_color;}}
}
.list-header {border: none;font-weight: bold;
}
.gray {color: $gray_text_color;
}
.error {color: $danger_color;
}
</style>
二、需求

- 上传文件前判断是否是pdf文件,如果是则弹出如下是否增加水印提示框
- 批量选择文件,碰到pdf文件,依次弹出如上提示框
- 若勾选了为后续pdf文件执行相同操作,则不再弹出如上提示框
- 若选择的文件中只有一个pdf文件,则不显示提示框中的复选框和“为后续pdf文件执行相同操作”文字
- 添加批量上传功能
三、需求实现
1. 修改后使用组件代码片段
<DialogUploadFile ref="uploadFile" @success="refresh" />
<DialogUploadFile ref="batchUploadFile" :isBatch="true" />
const uploadHandle = () => {if (selections.value.length != 1) {onceMessage.warning('请选择一条数据操作')return}uploadFile.value.show(selections.value[0])
}
const batchUploadHandle = () => {batchUploadFile.value.show()
}
2. 是否增加水印弹窗代码 DialogWatermark.vue
<template><div><el-dialog v-model="dialogVisible" title="是否增加水印提示" width="500px" :show-close="false" :close-on-click-modal="false"><div class="txt center">附件“{{ fileName || '' }}”是否增加水印?</div><div class="btns-box center"><el-button class="btn" type="primary" size="small" @click="handleYes">是</el-button><el-button class="btn" size="small" @click="handleNo">否</el-button></div><div class="center" v-if="showCheck"><el-checkbox v-model="checked">为后续pdf文件执行相同操作</el-checkbox></div></el-dialog></div>
</template><script setup lang="ts" name="DialogWatermark">
import { ref } from 'vue'
const emits = defineEmits(['on-change'])const dialogVisible = ref<boolean>(false)
const showCheck = ref<boolean>(true)
const checked = ref<boolean>(false)
const info = ref<any>()
const fileName = ref<any>('')
const listIndex = ref<any>(null)const show = (e: any, index: any, bool: boolean) => {checked.value = false listIndex.value = indexif (String(index) != 'null') {info.value = e || {}fileName.value = e?.nameshowCheck.value = bool} else {info.value = e || []fileName.value = e && e.length ? e[0].name : ''showCheck.value = e && e.length == 1 ? false : true}dialogVisible.value = true
}defineExpose({ show })
const handleYes = () => {dialogVisible.value = falselet obj = {data: info.value,index: listIndex.value,check: checked.value,flag: 1}emits('on-change', obj)
}
const handleNo = () => {dialogVisible.value = falselet obj = {data: info.value,index: listIndex.value,check: checked.value,flag: 0}emits('on-change', obj)
}
</script><style lang="scss" scoped>
.txt {font-size: 16px;line-height: 32px;margin-bottom: $spacing * 2;
}
.btns-box {margin-bottom: $spacing * 2;:deep(.ep-button--small) {width: 60px;}.btn + .btn {margin-left: $spacing * 6;}
}.center {text-align: center;
}
</style>
3. 上传组件修改后代码 DialogUploadFile.vue
<template><div class="no-modal-dialog"><el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px" :close-on-click-modal="false"></el-dialog><DialogIFWatermark ref="dialogIFWatermarkRef" @on-change="changeWatermark" /><DialogErrorUpload ref="dialogErrorUploadRef" /></div>
</template><script setup lang="ts" name="DialogUploadFile">
import lodash from 'lodash'
import { appendixList, uploadFileApi, singleUploadBook, batchUploadBook } from '@/api/product-manage/electronic'
import { ElMessageBox, ElCheckbox, ElButton } from 'element-plus'
import type { UploadProps } from 'element-plus'
import { onMounted, ref, inject, nextTick, h } from 'vue'
import type { productItem, fileItem } from '@/models/product'
import { compactEmpty } from '@/utils/tool'
import DialogIFWatermark from './DialogIFWatermark.vue'
import DialogErrorUpload from './DialogErrorUpload.vue'const props = defineProps({isBatch: {type: Boolean,default: false}
})const onceMessage: any = inject('$onceMessage')
const dialogTitle = ref<string>('')
const submitLoading = ref<boolean>(false)
const dialogVisible = ref<boolean>(false)
const disabledBtn = ref<boolean>(false)const allMark = ref<boolean>(false)
const markFlag = ref<any>(null)const productInfo = ref<productItem>({})
const fileTypes = ref<string>('.pdf, .doc, .docx, .ppt, .pptx,.zip,.mp3')
const fileList = ref<fileItem[]>([])
const delList = ref<fileItem[]>([])const tempList = ref<fileItem[]>([])
const pdfList = ref<any>([])
const dialogIFWatermarkRef = ref<any>()
const dialogErrorUploadRef = ref<any>()
const emits = defineEmits<{(e: 'success'): void
}>()const show = (row: productItem) => {dialogVisible.value = trueif (!props.isBatch) {productInfo.value = rowdelList.value = []getFileList(row.serialNo)dialogTitle.value = `上传:${row.productName}`} else {fileList.value = []delList.value = []tempList.value = []pdfList.value = []dialogTitle.value = '批量上传'}
}
defineExpose({ show })
const setType = (str: string) => {
}
const getFileList = (serialNo: string) => {
}
const beforeUploadHandler = (obj: {}) => {
}
const changeWatermark = (e: any) => {allMark.value = e.checkmarkFlag.value = e.flagif (String(e.index) != 'null') {let rawFile = e.data || {}let obj = setType(rawFile.name)fileList.value.map((item, index) => {if (index == e.index) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = obj.fileTypeitem.shortName = obj.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id, e.flag)pdfList.value.shift()}})} else {let list = e.data || []handleUpload(list, allMark.value)}
}
const handleUpload = (list: any, isChecked: boolean) => {if (isChecked) {list.map((item: any) => {let o = setType(item.name)let obj = {id: item.uid + '',fileName: item.name,filePath: '',statusName: '上传中',fileType: o.fileType,shortName: o.shortName,updateFlag: 0}fileList.value.push(obj)uploadFile(item, obj.id, markFlag.value)})tempList.value = []} else {let o = setType(list[0].name)let obj = {id: list[0].uid + '',fileName: list[0].name,filePath: '',statusName: '上传中',fileType: o.fileType,shortName: o.shortName,updateFlag: 0}fileList.value.push(obj)uploadFile(list[0], obj.id, markFlag.value)nextTick(() => {list.shift()if (list.length) {dialogIFWatermarkRef.value.show(list, null)}})}
}
const beforeUpload: UploadProps['beforeUpload'] = rawFile => {allMark.value = falsemarkFlag.value = nulllet e = setType(rawFile.name)let exit = falseif (['doc', 'docx'].indexOf(e.fileType) != -1) {let arr = lodash.filter(fileList.value, function (item) {return ['doc', 'docx'].indexOf(item.fileType) != -1})arr.forEach(item => {if (item.shortName == e.shortName) {exit = true}})} else if (['ppt', 'pptx'].indexOf(e.fileType) != -1) {let arr = lodash.filter(fileList.value, function (item) {return ['ppt', 'pptx'].indexOf(item.fileType) != -1})arr.forEach(item => {if (item.shortName == e.shortName) {exit = true}})} else {fileList.value.forEach(item => {if (item.shortName == e.shortName && item.fileType == e.fileType) {exit = true}})}if (exit) {let selectList = pdfList.value || []selectList.push(rawFile)pdfList.value = selectList.filter((item: any) => setType(item.name).fileType == 'pdf')ElMessageBox.confirm(`附件列表中存在为${rawFile.name}的文件?`, '重名提示', {confirmButtonText: '替换附件列表文件',cancelButtonText: '跳过文件',type: 'warning',closeOnClickModal: false}).then(() => {fileList.value.forEach((item: fileItem, index: number) => {let files = setType(item.fileName)if (['doc', 'docx'].indexOf(e.fileType) != -1 && ['doc', 'docx'].indexOf(files.fileType) != -1 && e.shortName == files.shortName) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id)} else if (['ppt', 'pptx'].indexOf(e.fileType) != -1 && ['ppt', 'pptx'].indexOf(files.fileType) != -1 && e.shortName == files.shortName) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id)} else if (['pdf'].indexOf(e.fileType) != -1 && ['pdf'].indexOf(files.fileType) != -1 && e.shortName == files.shortName) {if (allMark.value) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id, markFlag.value)pdfList.value.shift()} else {let bool = pdfList.value && pdfList.value.length == 1 ? false : truedialogIFWatermarkRef.value.show(rawFile, index, bool)}} else if (item.fileName == rawFile.name) {item.statusName = '上传中'item.filePath = ''item.id = item.id ? item.id : rawFile.uid + ''item.fileName = rawFile.nameitem.fileType = e.fileTypeitem.shortName = e.shortNameitem.updateFlag = item.updateFlag == 0 ? 0 : 1uploadFile(rawFile, item.id)}})}).catch(() => {if (e.fileType.indexOf('pdf') != -1) {pdfList.value.shift()}})} else {let originList = tempList.value || []let obj: any = rawFileif (['pdf'].indexOf(e.fileType) != -1) {originList.push(obj)tempList.value = originListdialogIFWatermarkRef.value.show(tempList.value, null)} else {let item = {id: rawFile.uid + '',fileName: rawFile.name,filePath: '',statusName: '上传中',fileType: e.fileType,shortName: e.shortName,updateFlag: 0}fileList.value.push(item)uploadFile(rawFile, item.id)}}return false
}
const uploadFile = (e: any, id: string | number, markFlag: any = 1) => {let params = new FormData()params.append('file', e)params.append('folderId', '') params.append('markFlag', markFlag) uploadFileApi(params).then(res => {fileList.value.forEach(item => {if (item.id == id) {item.filePath = res.dataitem.statusName = '已完成'}})}).catch(err => {fileList.value.forEach(item => {if (item.id == id) {item.statusName = '上传失败'}})})
}
const delFile = (e: fileItem) => {
}
const onReset = () => {dialogVisible.value = falseallMark.value = falsemarkFlag.value = null
}
const onSubmit = () => {let updateArr = lodash.filter(fileList.value, function (item) {return item.statusName == '已完成' && !compactEmpty(item.updateFlag)})if (delList.value.length < 1 && updateArr.length < 1) {dialogVisible.value = falseallMark.value = falsemarkFlag.value = nullreturn}if (props.isBatch) {let arr: any = []if (fileList.value && fileList.value.length) {fileList.value.forEach(item => {arr.push({fileName: item.fileName,filePath: item.filePath})})}submitLoading.value = truebatchUploadBook(arr).then(res => {dialogErrorUploadRef.value.show(res.data)submitLoading.value = falsedialogVisible.value = falseallMark.value = falsemarkFlag.value = null}).catch(err => {submitLoading.value = falseallMark.value = falsemarkFlag.value = null})} else {let param = {bookName: productInfo.value.productName,serialNo: productInfo.value.serialNo}let appendixes: fileItem[] = []fileList.value.forEach((item: fileItem) => {if (item.statusName == '已完成' && !compactEmpty(item.updateFlag)) {appendixes.push({id: item.updateFlag == 0 ? '' : item.id,fileName: item.fileName,filePath: item.filePath,updateFlag: item.updateFlag})}})delList.value.forEach((item: fileItem) => {if (item.statusName == '已完成') {appendixes.push({id: item.id,fileName: item.fileName,filePath: item.filePath,updateFlag: 2})}})submitLoading.value = truesingleUploadBook({...param,appendixes}).then(res => {emits('success')onceMessage.success('上传成功')submitLoading.value = falsedialogVisible.value = falseallMark.value = falsemarkFlag.value = null}).catch(e => {submitLoading.value = falseallMark.value = falsemarkFlag.value = null})}
}
</script><style lang="scss">
</style>