@@ -11,7 +11,7 @@
< el-tab-pane label = "采购需求文件" name = "requirement" >
< el-table :data = "requirementFiles" stripe v-loading = "requirementLoading" >
< el -table -column type = "index" label = "序号" width = "70" align = "center" / >
< el-table-column prop = "fileTitl e" label = "文件名称" min -width = " 200 " show -overflow -tooltip / >
< el-table-column prop = "fileNam e" label = "文件名称" min -width = " 200 " show -overflow -tooltip / >
< el-table-column prop = "fileType" label = "文件类型" width = "120" >
< template # default = "scope" >
{ { getFileTypeLabel ( scope . row . fileType ) } }
@@ -35,34 +35,55 @@
< el-tag :type = "getStatusType(statusField)" class = "mr-4" >
{ { getStatusLabel ( statusField ) } }
< / el-tag >
<!-- 上传按钮 - 仅招标代理且可上传时显示 -- >
< el-upload
v-if = "canUpload"
ref = " uploadRef "
:action = "uploadAction"
:headers = "uploadHeaders "
:data = "uploadData "
:on-success = "handleUploadSucces s"
:on-error = "handleUploadError "
:before-upload = "befor eUpload"
:on-change = "handleFileChange "
:file-list = "fileList "
:auto-upload = "fals e"
:limit = "1 "
:show-file-list = "false"
accept = ".doc,.docx,.pdf" >
< el-button type = "primary" icon = "Upload" >
{ { isReturned ? '重新上传' : '上传文件' } }
</ el-button >
< / el-upload >
<!-- 提交按钮 - 有文件时显示 -- >
<!-- 草稿标识 -- >
< el-tag v-if = "isDraft" type="info" class="mr-4" > 草稿 < / el -tag >
<!-- 上传按钮 - 招标代理模式 -- >
< template v-if = "canSaveDraft || canSubmitDraft || canRe upload">
< el -upload
ref = "uploadRef "
:action = "uploadAction "
:headers = "uploadHeader s"
:data = "uploadData "
:on-success = "handl eUploadSuccess "
:on-error = "handleUploadError "
:before-upload = "beforeUpload "
:on-change = "handleFileChang e"
:file-list = "fileList "
:auto-upload = "false"
:limit = "1"
:show-file-list = "false"
accept = ".doc,.docx,.pdf" >
< el-button type = "primary" icon = "Upload" >
{ { canReupload ? '重新上传' : '上传文件' } }
< / el-button >
< / el-upload >
< / template >
<!-- 保存草稿按钮 -- >
< el-button
v-if = "canUpload && fileList.length > 0"
v-if = "canSaveDraft && fileList.length > 0"
type = "info"
:loading = "uploadSubmitting"
@click ="handleSaveDraft"
class = "ml-2" >
保存草稿
< / el-button >
<!-- 提交审核按钮 -- >
< el-button
v-if = "canSubmitDraft && fileList.length > 0"
type = "success"
:loading = "uploadSubmitting"
@click ="handleUpload Submit"
@click ="handleSubmitDraf t"
class = "ml-2" >
{ { isReturned ? '重新上传并提交' : '上传并提交' } }
提交审核
< / el-button >
<!-- 重新上传并提交按钮 -- >
< el-button
v-if = "canReupload && fileList.length > 0"
type = "success"
:loading = "uploadSubmitting"
@click ="handleReuploadSubmit"
class = "ml-2" >
重新上传并提交
< / el-button >
< / div >
@@ -80,6 +101,7 @@
< / el-tag >
< / template >
< / el-table-column >
< el-table-column prop = "fileRemark" label = "文件意见" min -width = " 150 " show -overflow -tooltip / >
< el-table-column label = "操作" width = "100" align = "center" >
< template # default = "scope" >
< el-button type = "primary" link icon = "Download" @click ="handleDownloadDoc(scope.row)" >
@@ -91,7 +113,7 @@
< el-empty v-if = "!docLoading && docList.length === 0" description="暂无招标文件" / >
<!-- 状态提示 -- >
< el-alert v-if = "mode === 'agent' && !canU pload" type="warning" :closable="false" class="mt-4" >
< el-alert v-if = "mode === 'agent' && !canSaveDraft && !canSubmitDraft && !canReu pload" type="warning" :closable="false" class="mt-4" >
< template # title >
< span v-if = "isReviewing" > 文件审核中 , 请等待审核结果 < / span >
< span v-else-if = "isConfirming" > 文件审核中 , 请等待确认 < / span >
@@ -110,9 +132,15 @@
<!-- 操作区域 -- >
< template # footer >
< div class = "dialog-footer" >
< el-button v-if = "canConfirm" type="success" @click="handleConfirm" > 确认无误 < / el -button >
<!-- 资产管理处操作按钮 -- >
< el-button v-if = "canSubmitToDept" type="primary" @click="handleSubmitToDept" > 提交至需求部门 < / el -button >
< el-button v-if = "canSubmitToAudit" type="primary" @click="handleSubmitToAudit" > 提交至内审部门 < / el -button >
< el-button v-if = "canSupplyUpload" type="info" @click="handleSupplyUpload" > 补充上传 < / el -button >
<!-- 需求部门 / 内审部门操作按钮 -- >
< el-button v-if = "canSubmitToAsset" type="primary" @click="handleSubmitToAsset" > 提交至资产管理处 < / el -button >
<!-- 通用操作按钮 -- >
< el-button v-if = "canReturn" type="warning" @click="handleReturn" > 退回修改 < / el -button >
< el-button v-if = "canComplete" type="primary " @click="handleComplete" > 确认流程结束 < / el -button >
< el-button v-if = "canComplete" type="success " @click="handleComplete" > 确认流程结束 < / el -button >
< el-button @click ="handleClose" > 关闭 < / el -button >
< / div >
< / template >
@@ -129,6 +157,22 @@
< el-button type = "primary" @click ="submitReturn" > 确定 < / el -button >
< / template >
< / el-dialog >
<!-- 补充上传弹窗 -- >
< el-dialog v-model = "supplyUploadDialogVisible" title="补充上传" width="500px" append -to -body >
< el-form :model = "supplyUploadForm" label -width = " 100px " >
< el-form-item label = "文件名称" >
< el-input v-model = "supplyUploadForm.fileName" disabled / >
< / el-form-item >
< el-form-item label = "文件意见" required >
< el-input v-model = "supplyUploadForm.fileRemark" type="textarea" :rows="3" placeholder="请输入文件意见(必填)" / >
< / el-form-item >
< / el-form >
< template # footer >
< el-button @click ="supplyUploadDialogVisible = false" > 取消 < / el -button >
< el-button type = "primary" :loading = "supplyUploadSubmitting" @click ="submitSupplyUpload" > 确定 < / el -button >
< / template >
< / el-dialog >
< / el-dialog >
< / template >
@@ -141,12 +185,17 @@ import {
getDocList ,
uploadDoc ,
reuploadDoc ,
confirmDoc ,
returnDoc ,
completeDoc ,
getAvailableActions ,
downloadDocById ,
downloadFileById
downloadFileById ,
saveDraft ,
submitDraft ,
supplyUpload as supplyUploadApi ,
submitToDept as submitToDeptApi ,
submitToAudit as submitToAuditApi ,
submitToAsset as submitToAssetApi
} from '/@/api/purchase/docProcess'
import type { UploadInstance , UploadProps , UploadUserFile } from 'element-plus'
@@ -173,11 +222,21 @@ const availableActions = ref<string[]>([])
const uploadRef = ref < UploadInstance > ( )
const fileList = ref < UploadUserFile [ ] > ( [ ] )
const uploadSubmitting = ref ( false )
const uploadedFileData = ref < any > ( null )
// 退回相关
const returnDialogVisible = ref ( false )
const returnRemark = ref ( '' )
// 补充上传相关
const supplyUploadDialogVisible = ref ( false )
const supplyUploadSubmitting = ref ( false )
const supplyUploadForm = ref ( {
fileName : '' ,
filePath : '' ,
fileRemark : ''
} )
// 弹窗标题
const dialogTitle = computed ( ( ) => {
return props . mode === 'agent' ? ` 处理项目 - ${ rowData . value . purchaseNo || '' } ` : '招标文件审核'
@@ -188,15 +247,19 @@ const statusField = computed(() => {
return props . mode === 'agent' ? rowData . value . status : rowData . value . docAuditStatus
} )
// 是否可以上传
const canUpload = computed ( ( ) => {
if ( props . mode !== 'agent' ) return false
const status = statusField . value
return status === 'PENDING_UPLOAD' || status === 'RETURNED'
} )
// 是否草稿状态
const isDraft = computed ( ( ) => statusField . value === 'DRAFT' )
// 是否可确认
const canConfirm = computed ( ( ) => availableActions . value . includes ( 'confirm ' ) )
// 招标代理操作权限
const canSaveDraft = computed ( ( ) => availableActions . value . includes ( 'saveDraft ' ) )
const canSubmitDraft = computed ( ( ) => availableActions . value . includes ( 'submitDraft' ) )
const canReupload = computed ( ( ) => availableActions . value . includes ( 'reupload' ) )
// 审核操作权限
const canSubmitToDept = computed ( ( ) => availableActions . value . includes ( 'submitToDept' ) )
const canSubmitToAudit = computed ( ( ) => availableActions . value . includes ( 'submitToAudit' ) )
const canSupplyUpload = computed ( ( ) => availableActions . value . includes ( 'supplyUpload' ) )
const canSubmitToAsset = computed ( ( ) => availableActions . value . includes ( 'submitToAsset' ) )
// 是否可退回
const canReturn = computed ( ( ) => availableActions . value . includes ( 'return' ) )
@@ -237,6 +300,7 @@ const open = async (row: any) => {
docList . value = [ ]
returnRemark . value = ''
fileList . value = [ ]
uploadedFileData . value = null
// 获取申请ID( 兼容 id 和 applyId 两种字段名)
applyId . value = row . applyId || row . id
@@ -341,35 +405,11 @@ const handleFileChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
const handleUploadSuccess : UploadProps [ 'onSuccess' ] = async ( response : any , uploadFile : any ) => {
if ( response ? . code === 0 || response ? . code === 200 ) {
const fileData = response . data
try {
const submitData = {
applyId : applyId . value ,
fileName : fileData . fileTitle || uploadFile . name ,
filePath : fileData . remark || fileData . filePath
}
let submitRes
if ( isReturned . value ) {
submitRes = await reuploadDoc ( submitData )
} else {
submitRes = await uploadDoc ( submitData )
}
if ( submitRes ? . code === 0 || submitRes ? . code === 200 ) {
useMessage ( ) . success ( '招标文件提交成功' )
emit ( 'refresh' )
await loadDocList ( )
fileList . value = [ ]
// 重新加载可执行操作
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} else {
useMessage ( ) . error ( submitRes ? . msg || '提交失败' )
}
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '提交失败' )
} finally {
uploadSubmitting . value = false
uploadedFileData . value = {
fileName : response . data . fileTitle || uploadFile . name ,
filePath : response . data . remark || response . data . filePath
}
uploadSubmitting . value = false
} else {
useMessage ( ) . error ( response ? . msg || '上传失败' )
uploadSubmitting . value = false
@@ -381,33 +421,215 @@ const handleUploadError: UploadProps['onError'] = (error: any) => {
uploadSubmitting . value = false
}
const handleUploadSubmit = async ( ) => {
const startUpload = async ( ) => {
if ( fileList . value . length === 0 ) {
useMessage ( ) . warning ( '请先选择文件' )
return
return false
}
uploadSubmitting . value = true
uploadRef . value ? . submit ( )
// 等待上传完成
return new Promise ( ( resolve ) => {
const checkInterval = setInterval ( ( ) => {
if ( ! uploadSubmitting . value ) {
clearInterval ( checkInterval )
resolve ( uploadedFileData . value !== null )
}
} , 100 )
} )
}
const handleConfirm = async ( ) => {
// 保存草稿
const handleSaveDraft = async ( ) => {
const uploaded = await startUpload ( )
if ( ! uploaded || ! uploadedFileData . value ) {
useMessage ( ) . error ( '文件上传失败' )
return
}
try {
await useMessageBox ( ) . confirm ( '确定要确认该招标文件无误吗?' )
const res = await saveDraft ( {
applyId : applyId . value ,
fileName : uploadedFileData . value . fileName ,
filePath : uploadedFileData . value . filePath ,
isDraft : true
} )
if ( res ? . code === 0 || res ? . code === 200 ) {
useMessage ( ) . success ( '草稿保存成功' )
emit ( 'refresh' )
await loadDocList ( )
fileList . value = [ ]
uploadedFileData . value = null
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} else {
useMessage ( ) . error ( res ? . msg || '保存失败' )
}
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '保存失败' )
}
}
// 提交草稿
const handleSubmitDraft = async ( ) => {
const uploaded = await startUpload ( )
if ( ! uploaded || ! uploadedFileData . value ) {
useMessage ( ) . error ( '文件上传失败' )
return
}
try {
const res = await submitDraft ( {
applyId : applyId . value ,
fileName : uploadedFileData . value . fileName ,
filePath : uploadedFileData . value . filePath ,
isDraft : false
} )
if ( res ? . code === 0 || res ? . code === 200 ) {
useMessage ( ) . success ( '提交成功' )
emit ( 'refresh' )
await loadDocList ( )
fileList . value = [ ]
uploadedFileData . value = null
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} else {
useMessage ( ) . error ( res ? . msg || '提交失败' )
}
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '提交失败' )
}
}
// 重新上传并提交
const handleReuploadSubmit = async ( ) => {
const uploaded = await startUpload ( )
if ( ! uploaded || ! uploadedFileData . value ) {
useMessage ( ) . error ( '文件上传失败' )
return
}
try {
const res = await reuploadDoc ( {
applyId : applyId . value ,
fileName : uploadedFileData . value . fileName ,
filePath : uploadedFileData . value . filePath
} )
if ( res ? . code === 0 || res ? . code === 200 ) {
useMessage ( ) . success ( '重新上传成功' )
emit ( 'refresh' )
await loadDocList ( )
fileList . value = [ ]
uploadedFileData . value = null
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} else {
useMessage ( ) . error ( res ? . msg || '上传失败' )
}
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '上传失败' )
}
}
// 补充上传
const handleSupplyUpload = ( ) => {
supplyUploadForm . value = {
fileName : '' ,
filePath : '' ,
fileRemark : ''
}
supplyUploadDialogVisible . value = true
}
const submitSupplyUpload = async ( ) => {
if ( ! supplyUploadForm . value . fileRemark ) {
useMessage ( ) . warning ( '请填写文件意见' )
return
}
if ( ! supplyUploadForm . value . filePath ) {
useMessage ( ) . warning ( '请先上传文件' )
return
}
supplyUploadSubmitting . value = true
try {
const res = await supplyUploadApi ( {
applyId : applyId . value ,
fileName : supplyUploadForm . value . fileName ,
filePath : supplyUploadForm . value . filePath ,
fileRemark : supplyUploadForm . value . fileRemark
} )
if ( res ? . code === 0 || res ? . code === 200 ) {
useMessage ( ) . success ( '补充上传成功' )
supplyUploadDialogVisible . value = false
emit ( 'refresh' )
await loadDocList ( )
auditRecordListRef . value ? . refresh ( )
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} else {
useMessage ( ) . error ( res ? . msg || '上传失败' )
}
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '上传失败' )
} finally {
supplyUploadSubmitting . value = false
}
}
// 提交至需求部门
const handleSubmitToDept = async ( ) => {
try {
await useMessageBox ( ) . confirm ( '确定要提交至需求部门审核吗?' )
} catch {
return
}
try {
await confirmDoc ( { applyId : applyId . value } )
useMessage ( ) . success ( '确认 成功' )
await submitToDeptApi ( { applyId : applyId . value } )
useMessage ( ) . success ( '提交 成功' )
emit ( 'refresh' )
loadDocList ( )
await loadDocList( )
auditRecordListRef . value ? . refresh ( )
// 重新加载可执行操作
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '确认 失败' )
useMessage ( ) . error ( e ? . msg || '提交 失败' )
}
}
// 提交至内审部门
const handleSubmitToAudit = async ( ) => {
try {
await useMessageBox ( ) . confirm ( '确定要提交至内审部门审核吗?' )
} catch {
return
}
try {
await submitToAuditApi ( { applyId : applyId . value } )
useMessage ( ) . success ( '提交成功' )
emit ( 'refresh' )
await loadDocList ( )
auditRecordListRef . value ? . refresh ( )
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '提交失败' )
}
}
// 提交至资产管理处
const handleSubmitToAsset = async ( ) => {
try {
await useMessageBox ( ) . confirm ( '确定要提交至资产管理处吗?' )
} catch {
return
}
try {
await submitToAssetApi ( { applyId : applyId . value } )
useMessage ( ) . success ( '提交成功' )
emit ( 'refresh' )
await loadDocList ( )
auditRecordListRef . value ? . refresh ( )
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} catch ( e : any ) {
useMessage ( ) . error ( e ? . msg || '提交失败' )
}
}
@@ -422,9 +644,8 @@ const submitReturn = async () => {
useMessage ( ) . success ( '退回成功' )
returnDialogVisible . value = false
emit ( 'refresh' )
loadDocList ( )
await loadDocList( )
auditRecordListRef . value ? . refresh ( )
// 重新加载可执行操作
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} catch ( e : any ) {
@@ -442,9 +663,8 @@ const handleComplete = async () => {
await completeDoc ( applyId . value )
useMessage ( ) . success ( '流程已结束' )
emit ( 'refresh' )
loadDocList ( )
await loadDocList( )
auditRecordListRef . value ? . refresh ( )
// 重新加载可执行操作
const actionsRes = await getAvailableActions ( applyId . value )
availableActions . value = actionsRes . data || [ ]
} catch ( e : any ) {
@@ -459,6 +679,7 @@ const handleClose = () => {
const getStatusType = ( status : string ) => {
const typeMap : Record < string , string > = {
'PENDING_UPLOAD' : 'info' ,
'DRAFT' : 'info' ,
'ASSET_REVIEWING' : 'warning' ,
'DEPT_REVIEWING' : 'warning' ,
'AUDIT_REVIEWING' : 'warning' ,
@@ -472,6 +693,7 @@ const getStatusType = (status: string) => {
const getStatusLabel = ( status : string ) => {
const labelMap : Record < string , string > = {
'PENDING_UPLOAD' : '待上传' ,
'DRAFT' : '草稿' ,
'ASSET_REVIEWING' : '资产管理处审核中' ,
'DEPT_REVIEWING' : '需求部门审核中' ,
'AUDIT_REVIEWING' : '内审部门审核中' ,