<template> <Dialog :title="dialogTitle" v-model="dialogVisible"> <template #footer> <el-card class="hl-incard" :class="{ 'alter-class': fieldHasAlter('attachments') }"> <el-upload ref="contractUploadRef" :file-list="contractUploadFiles" multiple :action="uploadUrl" :headers="{ Authorization: 'Bearer ' + getAccessToken(), 'tenant-id': getTenantId() }" name="files" :show-file-list="false" :auto-upload="false" :data="contractUploadData" :on-change="contractUploadChange" :on-error="handleError" :on-success="handleSuccess" :before-upload="before" class="upload-file-uploader"> <el-button type="danger"> <Icon icon="ep:upload-filled" />上传附件 </el-button> </el-upload> <el-table :data="formData.attachments" v-loading.fullscreen.lock="uploading" element-loading-text="附件上传中..." element-loading-background="rgba(122, 122, 122, 0.6)" class="hl-table"> <el-table-column prop="name" label="文件名称" align="center" /> <el-table-column prop="createTime" align="center" label="上传时间" :formatter="dateFormatter" /> <el-table-column label="操作" align="center"> <template #default="scope"> <el-button link type="danger" size="small" @click="handleDeleteAttachment(scope.$index, scope.row.businessFileType)"> 删除 </el-button> <el-button link type="primary" size="small" @click="downloadAttachment(scope.row.name, scope.row.url)"> 下载 </el-button> </template> </el-table-column> </el-table> </el-card> <el-button type="success" @click="submitForm">确定</el-button> </template> </Dialog> </template> <script setup lang="ts"> import { getAccessToken, getTenantId } from '@/utils/auth' import * as MaterialApi from '@/api/heli/material' import { deleteFileLogic, downloadFile, getFilePage } from '@/api/infra/file' import { inject } from 'vue' import { dateFormatter, formatDate } from '@/utils/formatTime' const { t } = useI18n() // 国际化 const formData = ref({ id: undefined, code: undefined, name: undefined, brand: undefined, spec: undefined, sizeInfo: undefined, traceType: undefined, dftStoreWh: undefined, dftStoreRg: undefined, dftStorePn: undefined, dftRoute: undefined, description: undefined, status: 1, shortName: undefined, materialType: undefined, compositionId: undefined, outputInputTaxRate: undefined, mainSupplierId: undefined, mainFrom: undefined, unit: undefined, invSafe: undefined, invUpperLimit: undefined, invLowerLimit: undefined, barcode: undefined, virtualPart: undefined, logo: undefined, }) const reload = inject('reload') const uploading = ref(false) const uploadUrl = ref(import.meta.env.VITE_UPLOAD_BATCH_URL) const contractUploadRef = ref() const sumbefore = ref(0) const contractUploadFiles = ref<UploadUserFile[]>([]) const failedAttachments = ref<UploadUserFile[]>([]) const protocolUploadFiles = ref<UploadUserFile[]>([]) const contractUploadData = ref({ businessType: 'PROJECT_MATER', businessId: formData.value.id, businessFileType: 'CONTRACT' }) const failedAttachmentsName = ref() const failedUploadsCount = ref(0) const successfulUploadsCount = ref(0) const dialogVisible = ref(false) // 弹窗的是否展示 const dialogTitle = ref('') // 弹窗的标题 const fieldHasAlter = (fieldName) => { return formData.value.alterFieldNames && formData.value.alterFieldNames.indexOf(fieldName) > -1 } /** 打开弹窗 */ const open = async (type: string, id?: number) => { dialogVisible.value = true dialogTitle.value = t('action.' + type) formData.value = await MaterialApi.getMaterial(id) // 附件信息 let attParams = { pageNo: 1, pageSize: 99, businessId: id, businessType: 'PROJECT_MATER' } formData.value.attachments = (await getFilePage(attParams)).list } const contractUploadChange =async (file, files) => { contractUploadFiles.value = files refreshAttachments(files, 'CONTRACT') // if (contractUploadFiles.value.length > 0) { // contractUploadData.value.businessId = formData.value.id // await contractUploadRef.value!.submit() // } } const refreshAttachments = (files, type) => { formData.value.attachments=[] formData.value.attachments = formData.value.attachments.filter((value, index, array) => { return value.businessFileType != type || value.id }) // for (let i = 0; i < files.length; i++) { // let file = files[i] // file.businessFileType = type // file.createTime = new Date() // formData.value.attachments.push(file) // } // // 排序 // formData.value.attachments.sort((v1, v2) => { // return v1.createTime - v2.createTime > 0 // }) // formData.value.attachments = formData.value.attachments.filter((value) => value.id) for (let i = 0; i < files.length; i++) { let file = files[i] file.businessFileType = type file.createTime = new Date() formData.value.attachments.push(file) } // 排序 formData.value.attachments.sort((v1, v2) => v1.createTime - v2.createTime) // 文件上传一遍 上传总数等于要上传文件时 刷新页面 const sum = successfulUploadsCount.value + failedUploadsCount.value // console.log('上传总数', sum) // console.log('要上传文件数量', sumbefore.value) if (sumbefore.value !== sum && sumbefore.value !== 0 && sum !== 0) { // console.log('要上传文件数量不等于上传总数时等待',uploading.value) uploading.value = true } else if (sum == sumbefore.value && sumbefore.value > 0 && sum > 0) { // console.log('要上传文件数量等于上传总数 刷新页面并给出提示') if (failedUploadsCount.value > 0) { ElMessageBox.alert( // 使用错误信息作为提示内容 `文件名为:${failedAttachmentsName.value.join(' / ')}上传失败`, `文件格式不正确或网络问题 请您稍后再试`, { dangerouslyUseHTMLString: false, // 由于我们不是使用HTML字符串,所以这里设置为false confirmButtonText: '知道了', center: true } ) } reload() uploading.value = false } } async function submitForm() { if (contractUploadFiles.value.length > 0) { contractUploadData.value.businessId = formData.value.id; await contractUploadRef.value!.submit(); }else{ dialogVisible.value=false } } // 处理单个文件上传失败的情况 const handleError = (error: Error, file: UploadUserFile) => { failedUploadsCount.value++ if (failedUploadsCount.value > 0) { // 当有上传错误时 // 将失败的附件添加到failedAttachments.value数组中 failedAttachments.value.push(file) failedAttachmentsName.value = failedAttachments.value.map((value) => value.name) } // console.log('上传失败数量', failedUploadsCount.value) } const handleSuccess = (response: any, file: UploadUserFile) => { successfulUploadsCount.value++ // console.log('上传成功数量', successfulUploadsCount.value) } // 文件上传前的钩子 const before = (rawFile) => { sumbefore.value++ } // 删除附件 const handleDeleteAttachment = async (index, type) => { const deletedAttachments = formData.value.attachments.splice(index, 1) for (let i = 0; i < deletedAttachments.length; i++) { const attachment = deletedAttachments[i] if (attachment.id) { // 清理已上传文件 await deleteFileLogic(attachment.id) } // 清理待上传文件 contractUploadFiles.value = contractUploadFiles.value.filter((file1) => { return file1.name != attachment.name || file1.businessFileType != type }) protocolUploadFiles.value = protocolUploadFiles.value.filter((file2) => { return file2.name != attachment.name || file2.businessFileType != type }) } } defineExpose({ open }) // 提供 open 方法,用于打开弹窗 </script>