【el-upload】批量上传图片时在before-upload中添加弹窗判断时的踩坑记录
一、初始代码
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) {// word文档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) {// pptlet 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) {// word文档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) {// pptitem.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 item = {// id: rawFile.uid + '',// fileName: rawFile.name,// filePath: '',// statusName: '上传中',// fileType: obj.fileType,// shortName: obj.shortName,// updateFlag: 0// }// fileList.value.push(item)// uploadFile(rawFile, item.id, e.flag)/* 最终实现 */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 {// 每次都上传数组的第0项,上传完把数组第0项删除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) {// word文档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) {// pptlet 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) {// word文档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) {// pptitem.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) {// pdf(这一块的判断一直是正常的)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 {// ------------------------------- 踩坑的地方主要在这块位置,上面的代码都正常 -------------------------------/* 第一次尝试使用的是dialog弹出框,即上面用el-dialog写的那个是否增加水印的组件,写法如下问题:选中多个pdf文件上传,只弹出来一次是否增加水印的弹出框,且是最后一个pdf的,而不是依次弹出*/// if (['pdf'].indexOf(e.fileType) != -1) {// // pdf// if (allMark.value) {// 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, markFlag.value)// } else {// dialogIFWatermarkRef.value.show(rawFile, 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)// }/* 考虑到上面ElMessageBox中的代码效果正常,是否增加水印弹出框能够正常的依次弹出所以第二次尝试使用ElMessageBox,写法如下问题:1.弹出框是可以依次弹出了,但是勾选复选框后续文件执行相同操作,弹出框还是会弹出,不会关闭,因为它不会再走上面判断allMark.value了;2.这里还要注意使用的ElCheckbox的modelValue值绑定的时候不能直接绑定allMark.value,否则会出现值变化了,但是复选框样式没有发生改变的问题*/// let item = {// id: rawFile.uid + '',// fileName: rawFile.name,// filePath: '',// statusName: '上传中',// fileType: e.fileType,// shortName: e.shortName,// updateFlag: 0// }// if (['pdf'].indexOf(e.fileType) != -1) {// // pdf// if (allMark.value) {// fileList.value.push(item)// uploadFile(rawFile, item.id, markFlag.value)// } else {// const checked = ref<any>(null)// // checked.value = allMark.value ? 1 : 0// ElMessageBox({// title: `附件“${rawFile.name}”是否增加水印?`,// center: true,// showCancelButton: true,// confirmButtonText: '是',// cancelButtonText: '否',// showClose: false,// closeOnClickModal: false,// message: h(ElCheckbox, {// modelValue: checked.value,// label: '为后续pdf文件执行相同操作',// // trueLabel: 1,// // falseLabel: 0,// 'onUpdate:modelValue': (val: any) => {// checked.value = val// // allMark.value = val == 1 ? true : false// allMark.value = val// }// })// })// .then(res => {// fileList.value.push(item)// uploadFile(rawFile, item.id, 1)// })// .catch(err => {// fileList.value.push(item)// uploadFile(rawFile, item.id, 0)// })// }// } else {// fileList.value.push(item)// uploadFile(rawFile, item.id)// }/* 最终实现 */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>
相关文章:
【el-upload】批量上传图片时在before-upload中添加弹窗判断时的踩坑记录
一、初始代码 1. 初始使用组件代码片段 <!-- 上传 --> <DialogUploadFile ref"uploadFile" success"refresh" />// 上传 const uploadHandle () > {if (selections.value.length ! 1) {onceMessage.warning(请选择一条数据操作)return}u…...
【Java基础】- JVM之Dump文件详解
Java基础 - JVM之Dump文件详解 文章目录 Java基础 - JVM之Dump文件详解一、什么是Dump三、为什么需要Dump分析思路 四、Dump记录哪些内容4.1 Java dump 文件的格式和内容段格式行格式 4.2 常用分类heap dump和thread dumpheap dumpthread dump 五、如何生产Dump文件5.1 获取hea…...
基于Vue+wangeditor实现富文本编辑
目录 前言分析实现具体解决的问题有具体代码实现如下效果图总结前言 一个网站需要富文本编辑器功能的原因有很多,以下是一些常见的原因: 方便用户编辑内容:富文本编辑器提供了类似于Office Word的编辑功能,使得那些不太懂HTML的用户也能够方便地编辑网站内容。提高用户体验…...
深入理解 Spring 中的 @RequestBody 和 @ResponseBody 注解及其区别
引言 在现代的 Web 开发中,处理 HTTP 请求和响应是不可或缺的任务。Spring Framework 提供了丰富的功能来简化这些任务,并使开发人员能够更专注于业务逻辑。在本文中,我们将深入探讨 Spring 中的 RequestBody 和 ResponseBody 注解࿰…...
【论文阅读】EULER:通过可扩展时间链接预测检测网络横向移动(NDSS-2022)
作者:乔治华盛顿大学-Isaiah J. King、H. Howie Huang 引用:King I J, Huang H H. Euler: Detecting Network Lateral Movement via Scalable Temporal Graph Link Prediction [C]. Proceedings 2022 Network and Distributed System Security Symposium…...
手动创建一个DOCKER镜像
1. 我们先使用C语言写一个hello-world程序 vim hello.c # include <stdio.h>int main() {print("hello docker\n"); } 2. 将hello.c文件编译成二进制文件, 需要安装工具 yum install gcc yum install glibc-static 开始编译 gcc -static hello.c -o hello 编译…...
SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--搭建Vue 前端工程[一]
文章目录 SSM--搭建Vue 前端工程--项目基础界面实现功能01-搭建Vue 前端工程需求分析/图解代码实现搭建Vue 前端工程下载node.js LTS 并安装: node.js 的npm创建Vue 项目使用idea 打开ssm_vue 项目, 并配置项目启动 Vue3 项目目录结构梳理Vue3 项目结构介绍 配置Vue 服务端口El…...
Idea使用Docker插件实现maven打包自动构建镜像
Docker 开启TCP 服务 vi /lib/systemd/system/docker.service改写以下内容 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock重启服务 #重新加载配置文件 systemctl daemon-reload #重启服务 systemctl restart docker.service此时docker已…...
Tailwind css优于Bootstrap 7个原因
在某些情况下,Tailwind css 比 Bootstrap 更好,因为它是一个低级 CSS 框架,可让您根据需要构建自己的自定义组件。如果使用得当,它非常注重性能,可以显着减少 CSS 负载并确保更快的渲染。如果 Web 性能和自定义是您的首…...
IDEA简单拷贝一份新项目记录
IDEA简单拷贝项目记录 拷贝后改项目名,然后iml 配置文件改项目名,然后 .idea 中的compiler.xml 里面的name标签改项目名。 就可以了...
华为OD真题--字符串加密
2023华为OD统一考试(AB卷)题库清单-带答案(持续更新)or2023年华为OD真题机考题库大全-带答案(持续更新) "给你一串未加密的字符串str,通过对字符串的每一个字母进行改变来实现加密…...
UML-状态图
目录 状态图 状态图的图符 状态机 状态 转换 电话机状态图 活动图和状态图区别: 状态图 状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为,显示了该实体如何根据当前所处的状态对不同的事件做出反应。通常我们创建一个UML状态…...
chrome插件开发实例07- Vue调试插件vue-devtools
目录 一、为什么使用vue-devtools插件 二、如何安装 三、使用源码方式,安装Vue-devtools插件...
HTML <span> 标签
定义和用法 <span> 标签被用来组合文档中的行内元素。 浏览器支持 元素ChromeIEFirefoxSafariOpera<span>YesYesYesYesYes所有浏览器都支持 <span> 标签。 HTML 与 XHTML 之间的差异 NONE 提示和注释: 提示:请使用 <span> 来组合行内元素,以便…...
【PythonGIS】Python处理矢量数据的基本操作(查询、修改、删除、新建)
ogr库是一个处理地理空间矢量数据的开源库。它可以读取多种数据格式,进行地理处理、属性表操作、数据分析等操作。目前ogr和osr库已集成到GDAL库中,可以对栅格数据、矢量数据进行处理分析,被3S的研究人员广泛应用。感兴趣的可以自己去了解一下…...
15.2 【Linux】仅执行一次的工作调度
15.2.1 atd 的启动与 at 运行的方式 要使用单一工作调度时,我们的 Linux 系统上面必须要有负责这个调度的服务,那就是 atd 。 不过并非所有的 Linux distributions 都默认会把他打开的,所以,某些时刻我们必须要手动将他启用才行。…...
时间复杂度与空间复杂度的详解
目录 1.时间复杂度 2.时间复杂度计算例题 3.空间复杂度 1.时间复杂度 算法中的基本操作的执行次数,为算法的时间复杂度。 如何表达 时间复杂度? 大O的渐进表示法 实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数…...
每日一学:什么是 Harbor ?
目录 什么是 Harbor ? 一、Harbor 的优势 二、Harbor 架构构成 三、Core services 这是 Harbor 的核心功能 什么是 Harbor ? Harbor 是 VMware 公司开源的企业级 Docker Registry 项目,其目标是帮助用户迅速搭建一个企业级的 Docker Reg…...
灰度均衡变换之c++实现(qt + 不调包)
1.基本原理 灰度均衡是以累计分布函数变换为基础的直方图修正法,它可以产生一副灰度级分布概率均匀的图像。也就是说,经过灰度均衡后的图像在没一级灰度上像素点的数量相差不大。公式见下图,为灰度值为x的像素点的个数,n为总像素点…...
flink1.17 自定义trigger ContinuousEventTimeTrigger
在 ContinuousEventTimeTrigger 的基础上新增了timeout,如果超时后窗口都没关闭,那么就硬输出一波,避免间断数据,留存窗口太久. ContinuousEventTimeTrigger ContinuousEventTimeTrigger连续事件时间触发器与ContinuousProcessingTimeTrigger连续处理时间触发器,指定一个固定…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
