281 lines
6.4 KiB
Vue
281 lines
6.4 KiB
Vue
<template>
|
||
<el-dialog
|
||
v-model="visible"
|
||
title="文件归档"
|
||
width="900px"
|
||
destroy-on-close
|
||
append-to-body
|
||
>
|
||
<template #header>
|
||
<div class="dialog-header">
|
||
<span class="dialog-title">
|
||
<el-icon><FolderOpened /></el-icon>
|
||
文件归档 - {{ purchaseNo || purchaseId }}
|
||
</span>
|
||
<el-button
|
||
type="primary"
|
||
:loading="downloading"
|
||
@click="handleDownloadAll"
|
||
>
|
||
<el-icon><Download /></el-icon>
|
||
下载全部文件
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
|
||
<el-table
|
||
v-loading="loading"
|
||
:data="fileList"
|
||
stripe
|
||
border
|
||
max-height="500px"
|
||
class="file-table"
|
||
>
|
||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||
<el-table-column prop="fileTitle" label="文件名称" min-width="220" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<div class="file-name">
|
||
<el-icon class="file-icon"><Document /></el-icon>
|
||
<span>{{ row.fileTitle }}</span>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="fileTypeDesc" label="文件类型" width="160" align="center">
|
||
<template #default="{ row }">
|
||
<el-tag type="info">{{ row.fileTypeDesc || '未知类型' }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button
|
||
type="primary"
|
||
link
|
||
icon="View"
|
||
@click="handlePreview(row)"
|
||
>
|
||
预览
|
||
</el-button>
|
||
<el-button
|
||
type="primary"
|
||
link
|
||
icon="Download"
|
||
@click="handleDownloadFile(row)"
|
||
>
|
||
下载
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div v-if="!loading && fileList.length === 0" class="empty-tip">
|
||
<el-empty description="暂无文件" />
|
||
</div>
|
||
|
||
<template #footer>
|
||
<el-button @click="visible = false">关闭</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- PDF预览弹窗 -->
|
||
<el-dialog
|
||
v-model="previewVisible"
|
||
title="文件预览"
|
||
width="90%"
|
||
top="5vh"
|
||
destroy-on-close
|
||
append-to-body
|
||
class="preview-dialog"
|
||
>
|
||
<div class="preview-container">
|
||
<iframe
|
||
v-if="previewUrl"
|
||
:src="previewUrl"
|
||
class="preview-iframe"
|
||
frameborder="0"
|
||
/>
|
||
</div>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onUnmounted } from 'vue'
|
||
import { FolderOpened, Download, Document } from '@element-plus/icons-vue'
|
||
import { useMessage } from '/@/hooks/message'
|
||
import { listDownloadUrls, getArchiveDownloadUrl, downloadFileById, previewFileById } from '/@/api/purchase/purchasingrequisition'
|
||
import other from '/@/utils/other'
|
||
|
||
interface FileItem {
|
||
id: string
|
||
fileTitle: string
|
||
fileType: string
|
||
fileTypeDesc: string
|
||
downloadUrl: string
|
||
}
|
||
|
||
const visible = ref(false)
|
||
const loading = ref(false)
|
||
const downloading = ref(false)
|
||
const previewVisible = ref(false)
|
||
const previewUrl = ref('')
|
||
const previewLoading = ref(false)
|
||
const purchaseId = ref('')
|
||
const purchaseNo = ref('')
|
||
const fileList = ref<FileItem[]>([])
|
||
|
||
const open = async (id: string, no?: string) => {
|
||
purchaseId.value = id || ''
|
||
purchaseNo.value = no || ''
|
||
visible.value = true
|
||
await loadFileList()
|
||
}
|
||
|
||
const loadFileList = async () => {
|
||
if (!purchaseId.value) {
|
||
useMessage().warning('无法获取采购申请ID')
|
||
return
|
||
}
|
||
loading.value = true
|
||
try {
|
||
const res = await listDownloadUrls(purchaseId.value)
|
||
if (res && res.data) {
|
||
fileList.value = res.data as FileItem[]
|
||
} else {
|
||
fileList.value = []
|
||
}
|
||
} catch (err: any) {
|
||
useMessage().error(err?.msg || '获取文件列表失败')
|
||
fileList.value = []
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const isPdfFile = (fileName: string): boolean => {
|
||
if (!fileName) return false
|
||
const ext = fileName.toLowerCase().split('.').pop()
|
||
return ext === 'pdf'
|
||
}
|
||
|
||
const handlePreview = async (row: FileItem) => {
|
||
if (!row.id) {
|
||
useMessage().warning('文件ID不存在')
|
||
return
|
||
}
|
||
|
||
if (!isPdfFile(row.fileTitle)) {
|
||
useMessage().info('仅支持PDF格式文件预览,将为您下载文件')
|
||
handleDownloadFile(row)
|
||
return
|
||
}
|
||
|
||
previewLoading.value = true
|
||
previewVisible.value = true
|
||
previewUrl.value = ''
|
||
|
||
try {
|
||
const res = await previewFileById(row.id)
|
||
const blob = res as unknown as Blob
|
||
const url = window.URL.createObjectURL(blob)
|
||
previewUrl.value = url
|
||
} catch (err: any) {
|
||
useMessage().error(err?.msg || '预览失败')
|
||
previewVisible.value = false
|
||
} finally {
|
||
previewLoading.value = false
|
||
}
|
||
}
|
||
|
||
const handleDownloadFile = async (row: FileItem) => {
|
||
if (!row.id) {
|
||
useMessage().warning('文件ID不存在')
|
||
return
|
||
}
|
||
try {
|
||
const res = await downloadFileById(row.id)
|
||
const blob = res as unknown as Blob
|
||
const url = window.URL.createObjectURL(blob)
|
||
const link = document.createElement('a')
|
||
link.href = url
|
||
link.download = row.fileTitle || 'download'
|
||
document.body.appendChild(link)
|
||
link.click()
|
||
document.body.removeChild(link)
|
||
window.URL.revokeObjectURL(url)
|
||
} catch (err: any) {
|
||
useMessage().error(err?.msg || '下载失败')
|
||
}
|
||
}
|
||
|
||
const handleDownloadAll = () => {
|
||
if (!purchaseId.value) {
|
||
useMessage().warning('无法获取采购申请ID')
|
||
return
|
||
}
|
||
downloading.value = true
|
||
try {
|
||
const url = getArchiveDownloadUrl(purchaseId.value)
|
||
const fileName = `归档_${purchaseNo.value || purchaseId.value}.zip`
|
||
other.downBlobFile(url, {}, fileName)
|
||
} finally {
|
||
setTimeout(() => {
|
||
downloading.value = false
|
||
}, 500)
|
||
}
|
||
}
|
||
|
||
onUnmounted(() => {
|
||
if (previewUrl.value) {
|
||
window.URL.revokeObjectURL(previewUrl.value)
|
||
}
|
||
})
|
||
|
||
defineExpose({
|
||
open
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.dialog-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
width: 100%;
|
||
}
|
||
|
||
.dialog-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.file-table {
|
||
width: 100%;
|
||
}
|
||
|
||
.file-name {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.file-icon {
|
||
color: #409eff;
|
||
}
|
||
|
||
.empty-tip {
|
||
padding: 40px 0;
|
||
}
|
||
|
||
.preview-container {
|
||
width: 100%;
|
||
height: calc(90vh - 120px);
|
||
}
|
||
|
||
.preview-iframe {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
</style>
|