| | |
| | | <template> |
| | | <div> |
| | | <el-dialog :title="dialogTitle" v-model="visible" width="760px"> |
| | | <div class="lims-attachment"> |
| | | <div v-if="inline" class="attachment-inline"> |
| | | <div class="attachment-header"> |
| | | <div class="el-upload__tip">{{ tip }}</div> |
| | | <el-upload :action="uploadAction" :headers="uploadHeader" multiple :show-file-list="false" |
| | | :on-success="handleUploadSuccess" :on-error="handleUploadError"> |
| | | <div class="el-upload__tip"> |
| | | {{ readonly ? '仅可预览、下载附件' : ((currentId || deferUpload) ? tip : emptyTip) }} |
| | | </div> |
| | | <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple |
| | | :show-file-list="false" :disabled="!canUpload" :auto-upload="!deferUpload" |
| | | :on-change="handleFileChange" :on-success="handleUploadSuccess" |
| | | :on-error="handleUploadError"> |
| | | <el-button size="small" type="primary" :disabled="!canUpload">上传附件</el-button> |
| | | </el-upload> |
| | | </div> |
| | | <el-table :data="displayList" border size="small" max-height="180" style="margin-top:8px"> |
| | | <el-table-column label="文件名称" prop="fileName" min-width="220" show-overflow-tooltip /> |
| | | <el-table-column label="上传时间" prop="createTime" width="160" /> |
| | | <el-table-column label="操作" width="170"> |
| | | <template #default="scope"> |
| | | <template v-if="scope.row.pending"> |
| | | <el-button link type="danger" @click="removePending(scope.row)">删除</el-button> |
| | | </template> |
| | | <template v-else> |
| | | <el-button link type="primary" @click="previewFile(scope.row)">预览</el-button> |
| | | <el-button link type="primary" @click="downloadFile(scope.row)">下载</el-button> |
| | | <el-button v-if="!readonly" link type="danger" @click="removeFile(scope.row)">删除</el-button> |
| | | </template> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | <el-dialog v-else :title="dialogTitle" v-model="visible" width="760px" append-to-body @close="$emit('closed')"> |
| | | <div class="attachment-header"> |
| | | <div class="el-upload__tip">{{ readonly ? '仅可预览、下载附件' : tip }}</div> |
| | | <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple |
| | | :show-file-list="false" :on-success="handleUploadSuccess" :on-error="handleUploadError"> |
| | | <el-button size="small" type="primary">上传附件</el-button> |
| | | </el-upload> |
| | | </div> |
| | |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="previewFile(scope.row)">预览</el-button> |
| | | <el-button link type="primary" @click="downloadFile(scope.row)">下载</el-button> |
| | | <el-button link type="danger" @click="removeFile(scope.row)">删除</el-button> |
| | | <el-button v-if="!readonly" link type="danger" @click="removeFile(scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | components: { |
| | | filePreview |
| | | }, |
| | | emits: ['closed'], |
| | | props: { |
| | | // 上传接口地址,如 /supplierManagement/uploadAttachment |
| | | uploadUrl: { |
| | |
| | | tip: { |
| | | type: String, |
| | | default: '支持任意格式文件,单个文件不超过200MB' |
| | | }, |
| | | // 只读模式:仅预览/下载,不显示上传和删除 |
| | | readonly: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 内嵌模式:直接渲染上传区和附件列表,不弹管理弹窗 |
| | | inline: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 内嵌模式关联主表ID,变化时自动加载附件 |
| | | mainId: { |
| | | type: [String, Number], |
| | | default: '' |
| | | }, |
| | | // 内嵌模式未关联主表ID时的提示 |
| | | emptyTip: { |
| | | type: String, |
| | | default: '请先选择数据后再上传附件' |
| | | }, |
| | | // 内嵌模式:没有主表ID时也允许选择文件,先暂存在页面,提交时再统一上传 |
| | | deferUpload: { |
| | | type: Boolean, |
| | | default: false |
| | | } |
| | | }, |
| | | watch: { |
| | | mainId: { |
| | | immediate: true, |
| | | handler(val) { |
| | | if (!this.inline) { |
| | | return |
| | | } |
| | | const field = this.idField || this.idParam |
| | | this.currentRow = { [field]: val } |
| | | this.attachmentList = [] |
| | | if (val !== null && val !== undefined && val !== '') { |
| | | this.loadList() |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | visible: false, |
| | | attachmentList: [], |
| | | pendingFiles: [], |
| | | currentRow: {}, |
| | | previewVisible: false, |
| | | previewRow: {}, |
| | |
| | | currentId() { |
| | | const field = this.idField || this.idParam |
| | | return this.currentRow ? this.currentRow[field] : undefined |
| | | }, |
| | | canUpload() { |
| | | return !this.readonly && (!!this.currentId || this.deferUpload) |
| | | }, |
| | | displayList() { |
| | | const pending = this.pendingFiles.map(item => ({ |
| | | id: 'pending_' + item.uid, |
| | | uid: item.uid, |
| | | fileName: item.fileName, |
| | | createTime: '待上传', |
| | | pending: true |
| | | })) |
| | | return pending.concat(this.attachmentList) |
| | | }, |
| | | dialogTitle() { |
| | | const name = this.nameField && this.currentRow ? this.currentRow[this.nameField] : '' |
| | |
| | | handleUploadError() { |
| | | this.$message.error('上传失败,文件可能超过200MB') |
| | | }, |
| | | // 延迟上传模式:文件先暂存在页面,提交保存时再统一上传 |
| | | handleFileChange(file) { |
| | | if (!this.deferUpload || !file || !file.raw) { |
| | | return |
| | | } |
| | | this.pendingFiles.push({ uid: file.uid, fileName: file.name, raw: file.raw }) |
| | | }, |
| | | removePending(row) { |
| | | this.pendingFiles = this.pendingFiles.filter(item => item.uid !== row.uid) |
| | | }, |
| | | // 提交时调用:把暂存的附件上传到指定主表ID,全部成功才算完成 |
| | | flushPending(planDetailsId) { |
| | | if (!this.pendingFiles.length) { |
| | | return Promise.resolve() |
| | | } |
| | | const field = this.idField || this.idParam |
| | | this.currentRow = { [field]: planDetailsId } |
| | | return Promise.all(this.pendingFiles.slice().map(item => { |
| | | const formData = new FormData() |
| | | formData.append('file', item.raw) |
| | | return request({ |
| | | url: this.uploadUrl, |
| | | method: 'post', |
| | | params: { [this.idParam]: planDetailsId }, |
| | | data: formData, |
| | | headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false } |
| | | }).then(res => { |
| | | if (!res || res.code !== 200) { |
| | | throw new Error((res && res.msg) || ('附件“' + item.fileName + '”上传失败')) |
| | | } |
| | | this.pendingFiles = this.pendingFiles.filter(pending => pending.uid !== item.uid) |
| | | }) |
| | | })).then(() => { |
| | | this.loadList() |
| | | }) |
| | | }, |
| | | previewFile(row) { |
| | | this.previewRow = row |
| | | this.previewUrl = this.fullUrl(row.fileUrl) |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .lims-attachment { |
| | | width: 100%; |
| | | } |
| | | |
| | | .attachment-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .attachment-inline { |
| | | width: 100%; |
| | | } |
| | | </style> |