feat: 前端集成更新材料功能和PDF预览
- 列表页添加更新材料按钮(更多操作中) - 添加updateFiles API接口 - 文件归档弹窗添加PDF预览功能 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -359,3 +359,15 @@ export function listDownloadUrls(purchaseId: string | number) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新采购材料(部门申请人或负责人重新上传文件)
|
||||||
|
* @param data 包含purchaseId和fileIds的对象
|
||||||
|
*/
|
||||||
|
export function updateFiles(data: { purchaseId: string; fileIds: string[] }) {
|
||||||
|
return request({
|
||||||
|
url: '/purchase/purchasingfiles/updateFiles',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
class="file-table"
|
class="file-table"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
<el-table-column prop="fileTitle" label="文件名称" min-width="250" show-overflow-tooltip>
|
<el-table-column prop="fileTitle" label="文件名称" min-width="220" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="file-name">
|
<div class="file-name">
|
||||||
<el-icon class="file-icon"><Document /></el-icon>
|
<el-icon class="file-icon"><Document /></el-icon>
|
||||||
@@ -40,13 +40,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="fileTypeDesc" label="文件类型" width="180" align="center">
|
<el-table-column prop="fileTypeDesc" label="文件类型" width="160" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag type="info">{{ row.fileTypeDesc || '未知类型' }}</el-tag>
|
<el-tag type="info">{{ row.fileTypeDesc || '未知类型' }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
icon="View"
|
||||||
|
@click="handlePreview(row)"
|
||||||
|
>
|
||||||
|
预览
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@@ -67,6 +75,26 @@
|
|||||||
<el-button @click="visible = false">关闭</el-button>
|
<el-button @click="visible = false">关闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</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>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -87,6 +115,8 @@ interface FileItem {
|
|||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const downloading = ref(false)
|
const downloading = ref(false)
|
||||||
|
const previewVisible = ref(false)
|
||||||
|
const previewUrl = ref('')
|
||||||
const purchaseId = ref('')
|
const purchaseId = ref('')
|
||||||
const purchaseNo = ref('')
|
const purchaseNo = ref('')
|
||||||
const fileList = ref<FileItem[]>([])
|
const fileList = ref<FileItem[]>([])
|
||||||
@@ -119,6 +149,29 @@ const loadFileList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isPdfFile = (fileName: string): boolean => {
|
||||||
|
if (!fileName) return false
|
||||||
|
const ext = fileName.toLowerCase().split('.').pop()
|
||||||
|
return ext === 'pdf'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePreview = (row: FileItem) => {
|
||||||
|
if (!row.downloadUrl) {
|
||||||
|
useMessage().warning('文件预览地址不存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPdfFile(row.fileTitle)) {
|
||||||
|
useMessage().info('仅支持PDF格式文件预览,将为您下载文件')
|
||||||
|
handleDownloadFile(row)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用iframe预览PDF(通过后端下载接口获取文件流)
|
||||||
|
previewUrl.value = row.downloadUrl
|
||||||
|
previewVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
const handleDownloadFile = (row: FileItem) => {
|
const handleDownloadFile = (row: FileItem) => {
|
||||||
if (row.downloadUrl) {
|
if (row.downloadUrl) {
|
||||||
window.open(row.downloadUrl, '_blank')
|
window.open(row.downloadUrl, '_blank')
|
||||||
@@ -182,4 +235,14 @@ defineExpose({
|
|||||||
.empty-tip {
|
.empty-tip {
|
||||||
padding: 40px 0;
|
padding: 40px 0;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.preview-container {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(90vh - 120px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -295,6 +295,9 @@
|
|||||||
<!-- 文件归档弹窗 -->
|
<!-- 文件归档弹窗 -->
|
||||||
<FileArchiveDialog ref="fileArchiveDialogRef" />
|
<FileArchiveDialog ref="fileArchiveDialogRef" />
|
||||||
|
|
||||||
|
<!-- 更新材料弹窗 -->
|
||||||
|
<UpdateFilesDialog ref="updateFilesDialogRef" @refresh="getDataList" />
|
||||||
|
|
||||||
<!-- 招标文件审核弹窗 -->
|
<!-- 招标文件审核弹窗 -->
|
||||||
<!-- <DocAuditDialog ref="docAuditDialogRef" @refresh="getDataList" />-->
|
<!-- <DocAuditDialog ref="docAuditDialogRef" @refresh="getDataList" />-->
|
||||||
|
|
||||||
@@ -348,12 +351,12 @@
|
|||||||
import { ref, reactive, defineAsyncComponent, onMounted, computed } from 'vue'
|
import { ref, reactive, defineAsyncComponent, onMounted, computed } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||||
import { getPage, delObj, submitObj, getApplyTemplateDownloadUrl, getFileApplyTemplateDownloadUrl, getDeptMembers, saveRepresentor, listDownloadUrls } from "/@/api/purchase/purchasingrequisition";
|
import { getPage, delObj, submitObj, getApplyTemplateDownloadUrl, getFileApplyTemplateDownloadUrl, getDeptMembers, saveRepresentor, listDownloadUrls, updateFiles } from "/@/api/purchase/purchasingrequisition";
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
import { useAuth } from '/@/hooks/auth';
|
import { useAuth } from '/@/hooks/auth';
|
||||||
import { getDicts } from '/@/api/admin/dict';
|
import { getDicts } from '/@/api/admin/dict';
|
||||||
import { getTree } from '/@/api/purchase/purchasingcategory';
|
import { getTree } from '/@/api/purchase/purchasingcategory';
|
||||||
import { List, Document, DocumentCopy, Search, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning, DocumentChecked, Edit, Delete, Upload, FolderOpened, Download, User } from '@element-plus/icons-vue'
|
import { List, Document, DocumentCopy, Search, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning, DocumentChecked, Edit, Delete, Upload, FolderOpened, Download, User, RefreshRight } from '@element-plus/icons-vue'
|
||||||
import other from '/@/utils/other'
|
import other from '/@/utils/other'
|
||||||
import { Session } from '/@/utils/storage'
|
import { Session } from '/@/utils/storage'
|
||||||
|
|
||||||
@@ -369,6 +372,7 @@ const ActionDropdown = defineAsyncComponent(() => import('/@/components/tools/ac
|
|||||||
const PurchasingAcceptModal = defineAsyncComponent(() => import('./accept/PurchasingAcceptModal.vue'));
|
const PurchasingAcceptModal = defineAsyncComponent(() => import('./accept/PurchasingAcceptModal.vue'));
|
||||||
const FlowCommentTimeline = defineAsyncComponent(() => import('/@/views/jsonflow/comment/timeline.vue'));
|
const FlowCommentTimeline = defineAsyncComponent(() => import('/@/views/jsonflow/comment/timeline.vue'));
|
||||||
const FileArchiveDialog = defineAsyncComponent(() => import('./FileArchiveDialog.vue'));
|
const FileArchiveDialog = defineAsyncComponent(() => import('./FileArchiveDialog.vue'));
|
||||||
|
const UpdateFilesDialog = defineAsyncComponent(() => import('./UpdateFilesDialog.vue'));
|
||||||
// const DocAuditDialog = defineAsyncComponent(() => import('./docAudit/DocAuditDialog.vue'));
|
// const DocAuditDialog = defineAsyncComponent(() => import('./docAudit/DocAuditDialog.vue'));
|
||||||
|
|
||||||
// 字典数据和品目树数据
|
// 字典数据和品目树数据
|
||||||
@@ -398,6 +402,7 @@ const currFlowCommentType = ref<'apply' | 'file'>('apply')
|
|||||||
|
|
||||||
const implementFormRef = ref()
|
const implementFormRef = ref()
|
||||||
const fileArchiveDialogRef = ref()
|
const fileArchiveDialogRef = ref()
|
||||||
|
const updateFilesDialogRef = ref()
|
||||||
|
|
||||||
/** 采购代表弹窗 */
|
/** 采购代表弹窗 */
|
||||||
const representorDialogVisible = ref(false)
|
const representorDialogVisible = ref(false)
|
||||||
@@ -636,6 +641,12 @@ const getActionMenuItems = (row: any) => {
|
|||||||
icon: User,
|
icon: User,
|
||||||
visible: () => isDeptAuditRole.value,
|
visible: () => isDeptAuditRole.value,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
command: 'updateFiles',
|
||||||
|
label: '更新材料',
|
||||||
|
icon: RefreshRight,
|
||||||
|
visible: () => isCompleted && hasAuth('purchase_purchasingapply_edit'),
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// command: 'downloadFileApply',
|
// command: 'downloadFileApply',
|
||||||
// label: '下载文件审批表',
|
// label: '下载文件审批表',
|
||||||
@@ -691,6 +702,9 @@ const handleMoreCommand = (command: string, row: any) => {
|
|||||||
case 'representor':
|
case 'representor':
|
||||||
openRepresentorDialog(row);
|
openRepresentorDialog(row);
|
||||||
break;
|
break;
|
||||||
|
case 'updateFiles':
|
||||||
|
handleUpdateFiles(row);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user