diff --git a/src/api/purchase/docProcess.ts b/src/api/purchase/docProcess.ts index 48a6c0e..8f4de67 100644 --- a/src/api/purchase/docProcess.ts +++ b/src/api/purchase/docProcess.ts @@ -176,4 +176,76 @@ export function getApplyFiles(purchaseId: string | number) { export function getFileUploadUrl() { const baseUrl = import.meta.env.VITE_API_URL || ''; return `${baseUrl}/purchase/purchasingfiles/upload`; +} + +/** + * 保存草稿(招标代理) + * @param data 文件信息 + */ +export function saveDraft(data: any) { + return request({ + url: '/purchase/purchasingdoc/save-draft', + method: 'post', + data + }); +} + +/** + * 提交草稿(招标代理) + * @param data 文件信息 + */ +export function submitDraft(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-draft', + method: 'post', + data + }); +} + +/** + * 补充上传(资产管理处) + * @param data 文件信息(含fileRemark) + */ +export function supplyUpload(data: any) { + return request({ + url: '/purchase/purchasingdoc/supply-upload', + method: 'post', + data + }); +} + +/** + * 提交至需求部门(资产管理处) + * @param data 审核信息 + */ +export function submitToDept(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-to-dept', + method: 'post', + data + }); +} + +/** + * 提交至内审部门(资产管理处) + * @param data 审核信息 + */ +export function submitToAudit(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-to-audit', + method: 'post', + data + }); +} + +/** + * 提交至资产管理处(需求部门/内审部门) + * @param data 审核信息 + */ +export function submitToAsset(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-to-asset', + method: 'post', + data + }); } \ No newline at end of file diff --git a/src/api/purchase/purchasingdoc.ts b/src/api/purchase/purchasingdoc.ts index 76c62f0..ce9e330 100644 --- a/src/api/purchase/purchasingdoc.ts +++ b/src/api/purchase/purchasingdoc.ts @@ -152,4 +152,76 @@ export function getDocAuditPage(params?: any) { method: 'get', params }); +} + +/** + * 保存草稿(招标代理) + * @param data 文件信息 + */ +export function saveDraft(data: any) { + return request({ + url: '/purchase/purchasingdoc/save-draft', + method: 'post', + data + }); +} + +/** + * 提交草稿(招标代理) + * @param data 文件信息 + */ +export function submitDraft(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-draft', + method: 'post', + data + }); +} + +/** + * 补充上传(资产管理处) + * @param data 文件信息(含fileRemark) + */ +export function supplyUpload(data: any) { + return request({ + url: '/purchase/purchasingdoc/supply-upload', + method: 'post', + data + }); +} + +/** + * 提交至需求部门(资产管理处) + * @param data 审核信息 + */ +export function submitToDept(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-to-dept', + method: 'post', + data + }); +} + +/** + * 提交至内审部门(资产管理处) + * @param data 审核信息 + */ +export function submitToAudit(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-to-audit', + method: 'post', + data + }); +} + +/** + * 提交至资产管理处(需求部门/内审部门) + * @param data 审核信息 + */ +export function submitToAsset(data: any) { + return request({ + url: '/purchase/purchasingdoc/submit-to-asset', + method: 'post', + data + }); } \ No newline at end of file diff --git a/src/views/purchase/purchasingrequisition/docProcess/DocProcessDialog.vue b/src/views/purchase/purchasingrequisition/docProcess/DocProcessDialog.vue index cbf2b39..38fa513 100644 --- a/src/views/purchase/purchasingrequisition/docProcess/DocProcessDialog.vue +++ b/src/views/purchase/purchasingrequisition/docProcess/DocProcessDialog.vue @@ -11,7 +11,7 @@ - + + @@ -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([]) const uploadRef = ref() const fileList = ref([]) const uploadSubmitting = ref(false) +const uploadedFileData = ref(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 = { '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 = { 'PENDING_UPLOAD': '待上传', + 'DRAFT': '草稿', 'ASSET_REVIEWING': '资产管理处审核中', 'DEPT_REVIEWING': '需求部门审核中', 'AUDIT_REVIEWING': '内审部门审核中', diff --git a/src/views/purchase/purchasingrequisition/docProcess/index.vue b/src/views/purchase/purchasingrequisition/docProcess/index.vue index dd3a66c..1708b54 100644 --- a/src/views/purchase/purchasingrequisition/docProcess/index.vue +++ b/src/views/purchase/purchasingrequisition/docProcess/index.vue @@ -34,6 +34,7 @@ clearable style="width: 200px"> + @@ -210,6 +211,7 @@ const getRowStatus = (row: any) => { const getStatusType = (status: string) => { const typeMap: Record = { 'PENDING_UPLOAD': 'info', + 'DRAFT': 'info', 'ASSET_REVIEWING': 'warning', 'DEPT_REVIEWING': 'warning', 'AUDIT_REVIEWING': 'warning', @@ -223,6 +225,7 @@ const getStatusType = (status: string) => { const getStatusLabel = (status: string) => { const labelMap: Record = { 'PENDING_UPLOAD': '待上传', + 'DRAFT': '草稿', 'ASSET_REVIEWING': '资产管理处审核中', 'DEPT_REVIEWING': '需求部门审核中', 'AUDIT_REVIEWING': '内审部门审核中',