Merge branch 'feature-purchase' into developer
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
class="file-table"
|
||||
>
|
||||
<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 }">
|
||||
<div class="file-name">
|
||||
<el-icon class="file-icon"><Document /></el-icon>
|
||||
@@ -40,13 +40,21 @@
|
||||
</div>
|
||||
</template>
|
||||
</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 }">
|
||||
<el-tag type="info">{{ row.fileTypeDesc || '未知类型' }}</el-tag>
|
||||
</template>
|
||||
</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 }">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="View"
|
||||
@click="handlePreview(row)"
|
||||
>
|
||||
预览
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@@ -67,6 +75,26 @@
|
||||
<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">
|
||||
@@ -87,6 +115,8 @@ interface FileItem {
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const downloading = ref(false)
|
||||
const previewVisible = ref(false)
|
||||
const previewUrl = ref('')
|
||||
const purchaseId = ref('')
|
||||
const purchaseNo = ref('')
|
||||
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) => {
|
||||
if (row.downloadUrl) {
|
||||
window.open(row.downloadUrl, '_blank')
|
||||
@@ -182,4 +235,14 @@ defineExpose({
|
||||
.empty-tip {
|
||||
padding: 40px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
.preview-container {
|
||||
width: 100%;
|
||||
height: calc(90vh - 120px);
|
||||
}
|
||||
|
||||
.preview-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
181
src/views/purchase/purchasingrequisition/UpdateFilesDialog.vue
Normal file
181
src/views/purchase/purchasingrequisition/UpdateFilesDialog.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="更新材料"
|
||||
width="900px"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<template #header>
|
||||
<div class="dialog-header">
|
||||
<span class="dialog-title">
|
||||
<el-icon><Upload /></el-icon>
|
||||
更新材料 - {{ purchaseNo || purchaseId }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
title="仅支持上传PDF格式文件,上传新文件将替换原有同类型文件"
|
||||
type="info"
|
||||
:closable="false"
|
||||
style="margin-bottom: 16px"
|
||||
/>
|
||||
|
||||
<el-form label-width="120px">
|
||||
<el-form-item label="采购编号">
|
||||
<el-input v-model="purchaseNo" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
v-for="item in fileTypeList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
>
|
||||
<upload-file
|
||||
v-model="fileMap[item.value]"
|
||||
:limit="5"
|
||||
:file-type="['pdf']"
|
||||
:data="{ fileType: item.value, purchaseId: purchaseId }"
|
||||
upload-file-url="/purchase/purchasingfiles/upload"
|
||||
@success="(res) => handleUploadSuccess(res, item.value)"
|
||||
/>
|
||||
<div class="file-tips">{{ item.desc }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">
|
||||
确认更新
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { Upload } from '@element-plus/icons-vue'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import { updateFiles } from '/@/api/purchase/purchasingrequisition'
|
||||
|
||||
interface FileItem {
|
||||
id: string
|
||||
name: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface FileTypeItem {
|
||||
value: string
|
||||
label: string
|
||||
desc: string
|
||||
}
|
||||
|
||||
const visible = ref(false)
|
||||
const submitting = ref(false)
|
||||
const purchaseId = ref('')
|
||||
const purchaseNo = ref('')
|
||||
|
||||
const fileMap = reactive<Record<string, FileItem[]>>({})
|
||||
|
||||
const fileTypeList: FileTypeItem[] = [
|
||||
{ value: '10', label: '商务洽谈纪要', desc: '商务洽谈相关纪要文件' },
|
||||
{ value: '20', label: '市场采购纪要', desc: '市场采购相关纪要文件' },
|
||||
{ value: '30', label: '网上商城采购材料', desc: '网上商城采购相关材料' },
|
||||
{ value: '40', label: '可行性论证报告', desc: '项目可行性论证报告' },
|
||||
{ value: '50', label: '会议记录', desc: '相关会议记录文件' },
|
||||
{ value: '60', label: '其他材料', desc: '其他相关材料' },
|
||||
{ value: '70', label: '单一来源专家论证表', desc: '单一来源采购专家论证表' },
|
||||
{ value: '80', label: '进口产品申请表', desc: '进口产品申请相关表格' },
|
||||
{ value: '90', label: '进口产品专家论证表', desc: '进口产品专家论证表' },
|
||||
{ value: '100', label: '政府采购意向表', desc: '政府采购意向公示表' },
|
||||
{ value: '110', label: '履约验收单', desc: '履约验收相关单据' },
|
||||
{ value: '120', label: '采购需求表', desc: '采购需求明细表' },
|
||||
]
|
||||
|
||||
const open = (id: string, no?: string) => {
|
||||
purchaseId.value = id || ''
|
||||
purchaseNo.value = no || ''
|
||||
visible.value = true
|
||||
// 清空文件列表
|
||||
fileTypeList.forEach((item) => {
|
||||
fileMap[item.value] = []
|
||||
})
|
||||
}
|
||||
|
||||
const handleUploadSuccess = (res: any, fileType: string) => {
|
||||
if (res && res.data) {
|
||||
useMessage().success('上传成功')
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!purchaseId.value) {
|
||||
useMessage().warning('无法获取采购申请ID')
|
||||
return
|
||||
}
|
||||
|
||||
// 收集所有上传的文件ID
|
||||
const allFileIds: string[] = []
|
||||
fileTypeList.forEach((item) => {
|
||||
const files = fileMap[item.value] || []
|
||||
files.forEach((file) => {
|
||||
if (file.id) {
|
||||
allFileIds.push(file.id)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (allFileIds.length === 0) {
|
||||
useMessage().warning('请至少上传一个文件')
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
await updateFiles({
|
||||
purchaseId: purchaseId.value,
|
||||
fileIds: allFileIds,
|
||||
})
|
||||
useMessage().success('更新材料成功')
|
||||
visible.value = false
|
||||
emit('refresh')
|
||||
} catch (err: any) {
|
||||
useMessage().error(err?.msg || '更新材料失败')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'refresh'): void
|
||||
}>()
|
||||
|
||||
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-tips {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -295,6 +295,9 @@
|
||||
<!-- 文件归档弹窗 -->
|
||||
<FileArchiveDialog ref="fileArchiveDialogRef" />
|
||||
|
||||
<!-- 更新材料弹窗 -->
|
||||
<UpdateFilesDialog ref="updateFilesDialogRef" @refresh="getDataList" />
|
||||
|
||||
<!-- 招标文件审核弹窗 -->
|
||||
<!-- <DocAuditDialog ref="docAuditDialogRef" @refresh="getDataList" />-->
|
||||
|
||||
@@ -348,12 +351,12 @@
|
||||
import { ref, reactive, defineAsyncComponent, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
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 { useAuth } from '/@/hooks/auth';
|
||||
import { getDicts } from '/@/api/admin/dict';
|
||||
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 { Session } from '/@/utils/storage'
|
||||
|
||||
@@ -369,6 +372,7 @@ const ActionDropdown = defineAsyncComponent(() => import('/@/components/tools/ac
|
||||
const PurchasingAcceptModal = defineAsyncComponent(() => import('./accept/PurchasingAcceptModal.vue'));
|
||||
const FlowCommentTimeline = defineAsyncComponent(() => import('/@/views/jsonflow/comment/timeline.vue'));
|
||||
const FileArchiveDialog = defineAsyncComponent(() => import('./FileArchiveDialog.vue'));
|
||||
const UpdateFilesDialog = defineAsyncComponent(() => import('./UpdateFilesDialog.vue'));
|
||||
// const DocAuditDialog = defineAsyncComponent(() => import('./docAudit/DocAuditDialog.vue'));
|
||||
|
||||
// 字典数据和品目树数据
|
||||
@@ -398,6 +402,7 @@ const currFlowCommentType = ref<'apply' | 'file'>('apply')
|
||||
|
||||
const implementFormRef = ref()
|
||||
const fileArchiveDialogRef = ref()
|
||||
const updateFilesDialogRef = ref()
|
||||
|
||||
/** 采购代表弹窗 */
|
||||
const representorDialogVisible = ref(false)
|
||||
@@ -636,6 +641,12 @@ const getActionMenuItems = (row: any) => {
|
||||
icon: User,
|
||||
visible: () => isDeptAuditRole.value,
|
||||
},
|
||||
{
|
||||
command: 'updateFiles',
|
||||
label: '更新材料',
|
||||
icon: RefreshRight,
|
||||
visible: () => isCompleted && hasAuth('purchase_purchasingapply_edit'),
|
||||
},
|
||||
// {
|
||||
// command: 'downloadFileApply',
|
||||
// label: '下载文件审批表',
|
||||
@@ -691,6 +702,9 @@ const handleMoreCommand = (command: string, row: any) => {
|
||||
case 'representor':
|
||||
openRepresentorDialog(row);
|
||||
break;
|
||||
case 'updateFiles':
|
||||
handleUpdateFiles(row);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user