| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="isShow" |
| | | :title="title" |
| | | :width="width" |
| | | @close="handleClose" |
| | | class="attachment-dialog" |
| | | > |
| | | <el-dialog v-model="isShow" |
| | | :title="title" |
| | | :width="width" |
| | | @close="handleClose" |
| | | class="attachment-dialog"> |
| | | <!-- 工具栏 --> |
| | | <div class="toolbar"> |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | @click="handleUpload" |
| | | > |
| | | <div v-if="editable" |
| | | class="toolbar"> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="handleUpload"> |
| | | 上传附件 |
| | | </el-button> |
| | | </div> |
| | | |
| | | <!-- 上传组件弹窗 --> |
| | | <el-dialog |
| | | v-model="uploadDialogVisible" |
| | | title="上传附件" |
| | | width="50%" |
| | | @close="handleUploadClose" |
| | | > |
| | | <AttachmentUpload |
| | | v-model:file-list="newFileList" |
| | | /> |
| | | <el-dialog v-model="uploadDialogVisible" |
| | | title="上传附件" |
| | | width="50%" |
| | | @close="closeUpload"> |
| | | <AttachmentUpload v-model:file-list="newFileList" /> |
| | | <template #footer> |
| | | <el-button @click="handleUploadClose">关闭</el-button> |
| | | <el-button @click="saveUpload">保存</el-button> |
| | | <el-button @click="closeUpload">关闭</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 文件列表表格 --> |
| | | <div class="table-container"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | class="attachment-table" |
| | | :height="tableData.length > 0 ? 'auto' : '120px'" |
| | | > |
| | | <el-table-column |
| | | label="附件名称" |
| | | prop="originalFilename" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | v-if="showActions" |
| | | fixed="right" |
| | | label="操作" |
| | | :width="120" |
| | | align="center" |
| | | > |
| | | <el-table :data="tableData" |
| | | border |
| | | class="attachment-table" |
| | | :height="tableData.length > 0 ? 'auto' : '120px'"> |
| | | <el-table-column label="附件名称" |
| | | prop="originalFilename" |
| | | show-overflow-tooltip /> |
| | | <el-table-column v-if="showActions" |
| | | fixed="right" |
| | | label="操作" |
| | | :width="120" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | :href="scope.row.downloadURL" |
| | | class="download-link" |
| | | > |
| | | <el-button link |
| | | type="primary" |
| | | size="small" |
| | | class="download-link" |
| | | @click="downloadFile(scope.row.downloadURL)"> |
| | | 下载 |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | size="small" |
| | | @click="handleDelete(scope.row)" |
| | | > |
| | | <el-button v-if="editable" |
| | | link |
| | | type="danger" |
| | | size="small" |
| | | @click="handleDelete(scope.row)"> |
| | | 删除 |
| | | </el-button> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, getCurrentInstance, onMounted, watch } from 'vue' |
| | | import AttachmentUpload from '@/components/AttachmentUpload/file/index.vue' |
| | | import {attachmentList, deleteAttachment, createAttachment} from "@/api/basicData/storageAttachment.js"; |
| | | import { ref, computed, getCurrentInstance, onMounted, watch } from "vue"; |
| | | import AttachmentUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { |
| | | attachmentList, |
| | | deleteAttachment, |
| | | createAttachment, |
| | | } from "@/api/basicData/storageAttachment.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | recordType: { |
| | | type: String, |
| | | default: '', |
| | | required: true |
| | | }, |
| | | recordId: { |
| | | type: Number, |
| | | default: 0, |
| | | required: true |
| | | }, |
| | | title: { |
| | | type: String, |
| | | default: '附件' |
| | | }, |
| | | width: { |
| | | type: String, |
| | | default: '50%' |
| | | }, |
| | | showActions: { |
| | | type: Boolean, |
| | | default: true |
| | | } |
| | | }) |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | recordType: { |
| | | type: String, |
| | | default: "", |
| | | required: true, |
| | | }, |
| | | recordId: { |
| | | type: Number, |
| | | default: 0, |
| | | required: true, |
| | | }, |
| | | title: { |
| | | type: String, |
| | | default: "附件", |
| | | }, |
| | | width: { |
| | | type: String, |
| | | default: "50%", |
| | | }, |
| | | showActions: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | editable: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits([ |
| | | 'close', |
| | | 'download', |
| | | 'upload', |
| | | 'delete' |
| | | ]) |
| | | const emit = defineEmits(["close", "download", "upload", "delete"]); |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | const tableData = ref([]) |
| | | const uploadDialogVisible = ref(false) |
| | | const newFileList = ref([]) |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const uploadDialogVisible = ref(false); |
| | | const newFileList = ref([]); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit("update:visible", val); |
| | | }, |
| | | }); |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit("update:visible", val); |
| | | }, |
| | | }); |
| | | |
| | | const handleClose = () => { |
| | | isShow.value = false |
| | | } |
| | | const handleClose = () => { |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const handleUpload = () => { |
| | | uploadDialogVisible.value = true |
| | | } |
| | | const handleUpload = () => { |
| | | uploadDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleUploadClose = async () => { |
| | | // 检查是否有新上传的文件 |
| | | if (newFileList.value.length > 0) { |
| | | const saveUpload = async () => { |
| | | // 检查是否有新上传的文件 |
| | | if (newFileList.value.length > 0) { |
| | | try { |
| | | await createAttachment({ |
| | | application: "file", |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | storageBlobDTOs: [...newFileList.value, ...tableData.value], |
| | | }); |
| | | newFileList.value = []; |
| | | // 刷新列表 |
| | | setList(); |
| | | } catch (error) { |
| | | proxy?.$modal?.msgError("上传失败"); |
| | | } |
| | | } |
| | | uploadDialogVisible.value = false; |
| | | }; |
| | | |
| | | const closeUpload = () => { |
| | | newFileList.value = []; |
| | | uploadDialogVisible.value = false; |
| | | }; |
| | | |
| | | const handleDelete = async (row, index) => { |
| | | try { |
| | | await createAttachment({ |
| | | application: 'file', |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | storageBlobDTOs: [...newFileList.value, ...tableData.value] |
| | | }) |
| | | newFileList.value = [] |
| | | // 刷新列表 |
| | | setList() |
| | | await deleteAttachment([row.storageAttachmentId]); |
| | | proxy?.$modal?.msgSuccess("删除成功"); |
| | | setList(); |
| | | } catch (error) { |
| | | proxy?.$modal?.msgError('上传失败') |
| | | proxy?.$modal?.msgError("删除失败"); |
| | | } |
| | | } |
| | | uploadDialogVisible.value = false |
| | | } |
| | | }; |
| | | |
| | | const setList = () => { |
| | | attachmentList({ |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | }).then(res => { |
| | | if (res && res.data) { |
| | | tableData.value = res.data || []; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | |
| | | const handleDelete = async (row, index) => { |
| | | try { |
| | | await deleteAttachment([row.storageAttachmentId]) |
| | | proxy?.$modal?.msgSuccess('删除成功') |
| | | setList() |
| | | } catch (error) { |
| | | proxy?.$modal?.msgError('删除失败') |
| | | } |
| | | } |
| | | |
| | | const setList = () => { |
| | | attachmentList({ |
| | | recordType: props.recordType, |
| | | recordId: props.recordId, |
| | | }).then(res => { |
| | | if (res && res.data) { |
| | | tableData.value = res.data || [] |
| | | } |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | setList() |
| | | }) |
| | | const downloadFile = url => { |
| | | window.open(url, "_blank"); |
| | | }; |
| | | onMounted(() => { |
| | | setList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .attachment-dialog { |
| | | border-radius: 12px; |
| | | } |
| | | .attachment-dialog { |
| | | border-radius: 12px; |
| | | } |
| | | |
| | | .toolbar { |
| | | margin-bottom: 16px; |
| | | text-align: right; |
| | | } |
| | | .toolbar { |
| | | margin-bottom: 16px; |
| | | text-align: right; |
| | | } |
| | | |
| | | .table-container { |
| | | max-height: 40vh; |
| | | overflow-y: auto; |
| | | min-height: 120px; |
| | | padding-bottom: 16px; |
| | | box-sizing: border-box; |
| | | will-change: scroll-position; |
| | | transform: translateZ(0); |
| | | -webkit-overflow-scrolling: touch; |
| | | } |
| | | .table-container { |
| | | max-height: 40vh; |
| | | overflow-y: auto; |
| | | min-height: 120px; |
| | | padding-bottom: 16px; |
| | | box-sizing: border-box; |
| | | will-change: scroll-position; |
| | | transform: translateZ(0); |
| | | -webkit-overflow-scrolling: touch; |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | margin-bottom: 0; |
| | | } |
| | | :deep(.el-table) { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | :deep(.el-table__body-wrapper) { |
| | | overflow-y: auto; |
| | | will-change: transform; |
| | | transform: translateZ(0); |
| | | } |
| | | :deep(.el-table__body-wrapper) { |
| | | overflow-y: auto; |
| | | will-change: transform; |
| | | transform: translateZ(0); |
| | | } |
| | | |
| | | :deep(.el-table__body tr) { |
| | | transition: none; |
| | | } |
| | | :deep(.el-table__body tr) { |
| | | transition: none; |
| | | } |
| | | |
| | | :deep(.el-dialog__footer) { |
| | | padding-top: 12px; |
| | | border-top: 1px solid #e9ecef; |
| | | } |
| | | :deep(.el-dialog__footer) { |
| | | padding-top: 12px; |
| | | border-top: 1px solid #e9ecef; |
| | | } |
| | | |
| | | .attachment-table { |
| | | border-radius: 8px; |
| | | } |
| | | .attachment-table { |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | :deep(.el-dialog__header) { |
| | | background-color: #f8f9fa; |
| | | border-bottom: 1px solid #e9ecef; |
| | | padding: 16px 20px; |
| | | } |
| | | :deep(.el-dialog__header) { |
| | | background-color: #f8f9fa; |
| | | border-bottom: 1px solid #e9ecef; |
| | | padding: 16px 20px; |
| | | } |
| | | |
| | | :deep(.el-dialog__title) { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | } |
| | | :deep(.el-dialog__title) { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 16px 20px; |
| | | } |
| | | :deep(.el-dialog__body) { |
| | | padding: 16px 20px; |
| | | } |
| | | |
| | | :deep(.el-table__empty-text) { |
| | | color: #999; |
| | | } |
| | | :deep(.el-table__empty-text) { |
| | | color: #999; |
| | | } |
| | | </style> |