<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) {
|
const newItem = await props.uploadMethod()
|
if (newItem) {
|
addAttachment(newItem)
|
}
|
}
|
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>
|