huminmin
2026-06-01 a563ea879ef5fb6897e76d2df661e465dce2ab9b
src/components/Dialog/FileList.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,263 @@
<template>
  <el-dialog v-model="isShow"
             :title="title"
             :width="width"
             @close="handleClose"
             class="attachment-dialog">
    <!-- å·¥å…·æ  -->
    <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="closeUpload">
      <AttachmentUpload v-model:file-list="newFileList" />
      <template #footer>
        <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="150"
                         align="center">
          <template #default="scope">
            <el-button link
                       type="primary"
                       size="small"
                       class="download-link"
                       @click="previewFile(scope.row.previewURL)">
              é¢„览
            </el-button>
            <el-button link
                       type="primary"
                       size="small"
                       class="download-link"
                       @click="downloadFile(scope.row.downloadURL)">
              ä¸‹è½½
            </el-button>
            <el-button v-if="editable"
                       link
                       type="danger"
                       size="small"
                       @click="handleDelete(scope.row)">
              åˆ é™¤
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
  </el-dialog>
  <filePreview ref="filePreviewRef" />
</template>
<script setup>
import { ElMessage } from 'element-plus'
  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 filePreview from '@/components/filePreview/index.vue'
  const filePreviewRef = ref()
  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 { 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 handleClose = () => {
    isShow.value = false;
  };
  // é¢„览文件
  const previewFile = (url) => {
    if (url) {
      filePreviewRef.value.open(url)
    } else {
      ElMessage.warning('文件地址无效,无法预览')
    }
  }
  const handleUpload = () => {
    uploadDialogVisible.value = true;
  };
  const saveUpload = async () => {
    // æ£€æŸ¥æ˜¯å¦æœ‰æ–°ä¸Šä¼ çš„æ–‡ä»¶
    if (newFileList.value.length > 0) {
      createAttachment({
        application: "file",
        recordType: props.recordType,
        recordId: props.recordId,
        storageBlobDTOs: [...newFileList.value, ...tableData.value],
      }).then((res) => {
        if (res && res.code === 200) {
          proxy?.$modal?.msgSuccess("上传成功");
          newFileList.value = [];
          // åˆ·æ–°åˆ—表
          setList();
        }
      }).finally(() => {
        uploadDialogVisible.value = false;
      })
    }
  }
  const closeUpload = () => {
    newFileList.value = [];
    uploadDialogVisible.value = false;
  };
  const handleDelete = async (row, index) => {
    deleteAttachment([row.storageAttachmentId]).then((res) => {
      if (res && res.code === 200) {
        proxy?.$modal?.msgSuccess("删除成功");
        setList();
      }
    })
  };
  const setList = () => {
    attachmentList({
      recordType: props.recordType,
      recordId: props.recordId,
    }).then(res => {
      tableData.value = (res && res.data) || [];
    });
  };
  const downloadFile = url => {
    window.open(url, "_blank");
  };
  onMounted(() => {
    setList();
  });
</script>
<style scoped>
  .attachment-dialog {
    border-radius: 12px;
  }
  .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;
  }
  :deep(.el-table) {
    margin-bottom: 0;
  }
  :deep(.el-table__body-wrapper) {
    overflow-y: auto;
    will-change: transform;
    transform: translateZ(0);
  }
  :deep(.el-table__body tr) {
    transition: none;
  }
  :deep(.el-dialog__footer) {
    padding-top: 12px;
    border-top: 1px solid #e9ecef;
  }
  .attachment-table {
    border-radius: 8px;
  }
  :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__body) {
    padding: 16px 20px;
  }
  :deep(.el-table__empty-text) {
    color: #999;
  }
</style>