zouyu
4 天以前 1c0863efe062af3ebcdecb8c10568d779f5c8295
src/components/Dialog/FileListDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,309 @@
<template>
  <el-dialog
    v-model="dialogVisible"
    :title="title"
    :width="width"
    :before-close="handleClose"
  >
    <div class="file-list-toolbar" v-if="showToolbar">
      <template v-if="useBuiltInUpload">
        <el-upload
          v-model:file-list="uploadFileList"
          class="upload-demo"
          :action="uploadAction"
          :headers="uploadHeaders"
          :show-file-list="false"
          :on-success="handleDefaultUploadSuccess"
          :on-error="handleDefaultUploadError"
        >
          <el-button
            v-if="showUploadButton"
            type="primary"
            size="small"
          >
            ä¸Šä¼ é™„ä»¶
          </el-button>
        </el-upload>
      </template>
      <template v-else>
        <el-button
          v-if="showUploadButton"
          type="primary"
          size="small"
          @click="handleUpload"
        >
          æ–°å¢žé™„ä»¶
        </el-button>
      </template>
    </div>
    <el-table :data="tableData" border :height="tableHeight">
      <el-table-column
        :label="nameColumnLabel"
        :prop="nameColumnProp"
        :min-width="nameColumnMinWidth"
        show-overflow-tooltip
      />
      <el-table-column
        v-if="showActions"
        fixed="right"
        label="操作"
        :width="actionColumnWidth"
        align="center"
      >
        <template #default="scope">
          <el-button
            v-if="showDownload"
            link
            type="primary"
            size="small"
            @click="handleDownload(scope.row)"
          >
            ä¸‹è½½
          </el-button>
          <el-button
            v-if="showPreview"
            link
            type="primary"
            size="small"
            @click="handlePreview(scope.row)"
          >
            é¢„览
          </el-button>
          <el-button
            v-if="showDeleteButton"
            link
            type="danger"
            size="small"
            @click="handleDelete(scope.row, scope.$index)"
          >
            åˆ é™¤
          </el-button>
          <slot name="actions" :row="scope.row"></slot>
        </template>
      </el-table-column>
      <slot name="columns"></slot>
    </el-table>
  </el-dialog>
  <filePreview v-if="showPreview" ref="filePreviewRef" />
</template>
<script setup>
import { ref, computed, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import filePreview from '@/components/filePreview/index.vue'
import { getToken } from '@/utils/auth'
const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false
  },
  title: {
    type: String,
    default: '附件'
  },
  width: {
    type: String,
    default: '40%'
  },
  tableHeight: {
    type: String,
    default: '40vh'
  },
  nameColumnLabel: {
    type: String,
    default: '附件名称'
  },
  nameColumnProp: {
    type: String,
    default: 'name'
  },
  nameColumnMinWidth: {
    type: [String, Number],
    default: 400
  },
  actionColumnWidth: {
    type: [String, Number],
    default: 160
  },
  showActions: {
    type: Boolean,
    default: true
  },
  showDownload: {
    type: Boolean,
    default: true
  },
  showPreview: {
    type: Boolean,
    default: true
  },
  showUploadButton: {
    type: Boolean,
    default: false
  },
  showDeleteButton: {
    type: Boolean,
    default: false
  },
  urlField: {
    type: String,
    default: 'url'
  },
  downloadMethod: {
    type: Function,
    default: null
  },
  previewMethod: {
    type: Function,
    default: null
  },
  uploadMethod: {
    type: Function,
    default: null
  },
  deleteMethod: {
    type: Function,
    default: null
  },
  rulesRegulationsManagementId: {
    type: [String, Number],
    default: ''
  },
  uploadUrl: {
    type: String,
    default: `${import.meta.env.VITE_APP_BASE_API}/file/upload`
  }
})
const emit = defineEmits(['update:modelValue', 'close', 'download', 'preview', 'upload', 'delete'])
const { proxy } = getCurrentInstance()
const filePreviewRef = ref(null)
const uploadFileList = ref([])
const dialogVisible = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val)
})
const tableData = ref([])
const showToolbar = computed(() => props.showUploadButton)
const useBuiltInUpload = computed(() => !props.uploadMethod)
const uploadAction = computed(() => props.uploadUrl)
const uploadHeaders = computed(() => ({
  Authorization: `Bearer ${getToken()}`
}))
const handleClose = () => {
  emit('close')
  dialogVisible.value = false
}
const handleDownload = (row) => {
  if (props.downloadMethod) {
    props.downloadMethod(row)
  } else {
    // é»˜è®¤ä¸‹è½½æ–¹æ³•
    proxy.$download.name(row[props.urlField])
  }
  emit('download', row)
}
const handlePreview = (row) => {
  if (props.previewMethod) {
    props.previewMethod(row)
  } else {
    // é»˜è®¤é¢„览方法
    if (filePreviewRef.value) {
      filePreviewRef.value.open(row[props.urlField])
    }
  }
  emit('preview', row)
}
const open = (list) => {
  dialogVisible.value = true
  tableData.value = list || []
}
const handleUpload = async () => {
  if (props.uploadMethod) {
    // å¦‚果提供了自定义上传方法,由父组件负责更新列表(通过 setList)
    // è¿™é‡Œä¸å†è‡ªåŠ¨æ·»åŠ ï¼Œé¿å…ä¸Žçˆ¶ç»„ä»¶çš„ setList é‡å¤
    await props.uploadMethod()
  }
  emit('upload')
}
const handleDelete = async (row, index) => {
  if (props.deleteMethod) {
    const result = await props.deleteMethod(row, index)
    if (result === false) {
      return
    }
    // å¦‚果提供了 deleteMethod,由父组件负责刷新列表,不在这里删除
  } else {
    // å¦‚果没有提供 deleteMethod,才在组件内部删除
    removeAttachment(index)
  }
  emit('delete', row)
}
const addAttachment = (item) => {
  tableData.value = [...tableData.value, item]
}
const handleDefaultUploadSuccess = async (res, file) => {
  if (res?.code !== 200) {
    ElMessage.error(res?.msg || '文件上传失败')
    return
  }
  if (!props.rulesRegulationsManagementId) {
    ElMessage.error('缺少规章制度ID,无法保存附件')
    return
  }
  const fileName = res?.data?.originalName || file?.name
  const fileUrl = res?.data?.tempPath || res?.data?.url
  const payload = {
    fileName,
    fileUrl,
    rulesRegulationsManagementId: props.rulesRegulationsManagementId,
    raw: res?.data || {}
  }
  emit('upload', payload)
}
const handleDefaultUploadError = () => {
  ElMessage.error('文件上传失败')
}
const removeAttachment = (index) => {
  if (index > -1 && index < tableData.value.length) {
    const newList = [...tableData.value]
    newList.splice(index, 1)
    tableData.value = newList
  }
}
const setList = (list) => {
  tableData.value = list || []
}
defineExpose({
  open,
  addAttachment,
  removeAttachment,
  setList,
  handleUpload,
  handleDelete
})
</script>
<style scoped>
.file-list-toolbar {
  margin-bottom: 8px;
  text-align: right;
}
</style>