Files
school-developer/src/views/purchase/purchasingrequisition/docProcess/DocProcessDialog.vue
2026-03-01 23:46:32 +08:00

867 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-dialog
v-model="visible"
:title="dialogTitle"
width="85%"
destroy-on-close
:close-on-click-modal="false"
@close="handleClose">
<el-tabs v-model="activeTab">
<!-- 采购需求文件 -->
<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="fileName" label="文件名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="fileType" label="文件类型" width="120">
<template #default="scope">
{{ getFileTypeLabel(scope.row.fileType) }}
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center">
<template #default="scope">
<el-button type="primary" link icon="Download" @click="handleDownloadRequirement(scope.row)">
下载
</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-if="!requirementLoading && requirementFiles.length === 0" description="暂无采购需求文件" />
</el-tab-pane>
<!-- 招标文件 -->
<el-tab-pane label="招标文件" name="doc">
<div class="doc-header">
<!-- 状态显示 -->
<el-tag :type="getStatusType(statusField)" class="mr-4">
{{ getStatusLabel(statusField) }}
</el-tag>
<!-- 草稿标识 -->
<el-tag v-if="isDraft" type="info" class="mr-4">草稿</el-tag>
<!-- 上传按钮 - 招标代理模式 -->
<template v-if="canSaveDraft || canSubmitDraft || canReupload">
<el-upload
ref="uploadRef"
:action="uploadAction"
:headers="uploadHeaders"
:data="uploadData"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
:before-upload="beforeUpload"
:on-change="handleFileChange"
: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="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="handleSubmitDraft"
class="ml-2">
提交审核
</el-button>
<!-- 重新上传并提交按钮 -->
<el-button
v-if="canReupload && fileList.length > 0"
type="success"
:loading="uploadSubmitting"
@click="handleReuploadSubmit"
class="ml-2">
重新上传并提交
</el-button>
</div>
<!-- 文件列表 -->
<el-table :data="docList" stripe v-loading="docLoading">
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="fileName" label="文件名称" min-width="200" show-overflow-tooltip />
<el-table-column prop="version" label="版本" width="80" align="center" />
<el-table-column prop="uploadByName" label="上传人" width="100" />
<el-table-column prop="uploadTime" label="上传时间" width="160" />
<!-- <el-table-column label="状态" width="120" align="center">-->
<!-- <template #default="scope">-->
<!-- <el-tag :type="getStatusType(scope.row.status)" size="small">-->
<!-- {{ getStatusLabel(scope.row.status) }}-->
<!-- </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)">
下载
</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-if="!docLoading && docList.length === 0" description="暂无招标文件" />
<!-- 状态提示 -->
<el-alert v-if="mode === 'agent' && !canSaveDraft && !canSubmitDraft && !canReupload" type="warning" :closable="false" class="mt-4">
<template #title>
<span v-if="isReviewing">文件审核中请等待审核结果</span>
<span v-else-if="isConfirming">文件审核中请等待确认</span>
<span v-else-if="isCompleted">文件审核已完成</span>
<span v-else>当前状态不允许上传</span>
</template>
</el-alert>
</el-tab-pane>
<!-- 审核记录 -->
<el-tab-pane label="审核记录" name="audit">
<AuditRecordList :apply-id="applyId" ref="auditRecordListRef" />
</el-tab-pane>
</el-tabs>
<!-- 操作区域 -->
<template #footer>
<div class="dialog-footer">
<!-- 资产管理处操作按钮 -->
<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="canFinalize" type="success" @click="handleFinalize">定稿</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="success" @click="handleComplete">确认流程结束</el-button>
<el-button @click="handleClose">关闭</el-button>
</div>
</template>
<!-- 退回原因弹窗 -->
<el-dialog v-model="returnDialogVisible" title="退回原因" width="400px" append-to-body>
<el-form>
<el-form-item label="退回原因">
<el-input v-model="returnRemark" type="textarea" :rows="3" placeholder="请输入退回原因" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="returnDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitReturn">确定</el-button>
</template>
</el-dialog>
<!-- 备注输入弹窗提交至资产处/内审部门 -->
<el-dialog v-model="remarkDialogVisible" :title="remarkDialogTitle" width="400px" append-to-body>
<el-form>
<el-form-item label="批注意见">
<el-input v-model="remarkInput" type="textarea" :rows="3" placeholder="请输入批注意见(选填)" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="remarkDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitRemarkAction">确定</el-button>
</template>
</el-dialog>
<!-- 定稿弹窗 -->
<el-dialog v-model="finalizeDialogVisible" title="定稿确认" width="400px" append-to-body>
<el-form>
<el-form-item label="批注意见">
<el-input v-model="finalizeRemark" type="textarea" :rows="3" placeholder="请输入批注意见(选填)" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="finalizeDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitFinalize">确定定稿</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="选择文件" required>
<el-upload
ref="supplyUploadRef"
:action="uploadAction"
:headers="uploadHeaders"
:data="uploadData"
:on-success="handleSupplyUploadSuccess"
:on-error="handleUploadError"
:before-upload="beforeUpload"
:on-change="handleSupplyFileChange"
:auto-upload="false"
:limit="1"
:file-list="supplyFileList"
:show-file-list="true"
accept=".doc,.docx,.pdf">
<el-button type="primary" icon="Upload">选择文件</el-button>
</el-upload>
</el-form-item>
<el-form-item label="文件名称">
<el-input v-model="supplyUploadForm.fileName" disabled placeholder="上传后自动显示" />
</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>
<script setup lang="ts" name="DocProcessDialog">
import { ref, computed, defineAsyncComponent } from 'vue'
import { useMessage, useMessageBox } from '/@/hooks/message'
import { Session } from '/@/utils/storage'
import {
getRequirementFiles,
getDocList,
uploadDoc,
reuploadDoc,
returnDoc,
completeDoc,
getAvailableActions,
downloadDocById,
downloadFileById,
saveDraft,
submitDraft,
supplyUpload as supplyUploadApi,
submitToDept as submitToDeptApi,
submitToAudit as submitToAuditApi,
submitToAsset as submitToAssetApi,
finalizeDoc as finalizeDocApi
} from '/@/api/purchase/docProcess'
import type { UploadInstance, UploadProps, UploadUserFile } from 'element-plus'
const AuditRecordList = defineAsyncComponent(() => import('./AuditRecordList.vue'))
const props = defineProps<{
mode: 'agent' | 'audit'
}>()
const emit = defineEmits(['refresh'])
const visible = ref(false)
const activeTab = ref('requirement')
const applyId = ref<string | number>('')
const rowData = ref<any>({})
const requirementFiles = ref<any[]>([])
const requirementLoading = ref(false)
const docList = ref<any[]>([])
const docLoading = ref(false)
const auditRecordListRef = ref()
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 remarkDialogVisible = ref(false)
const remarkDialogTitle = ref('')
const remarkInput = ref('')
const remarkActionType = ref('')
// 定稿相关
const finalizeDialogVisible = ref(false)
const finalizeRemark = ref('')
// 补充上传相关
const supplyUploadRef = ref<UploadInstance>()
const supplyUploadDialogVisible = ref(false)
const supplyUploadSubmitting = ref(false)
const supplyFileList = ref<UploadUserFile[]>([])
const supplyUploadedFileData = ref<any>(null)
const supplyUploadForm = ref({
fileName: '',
filePath: '',
fileRemark: ''
})
// 弹窗标题
const dialogTitle = computed(() => {
return props.mode === 'agent' ? `处理项目 - ${rowData.value.purchaseNo || ''}` : '招标文件审核'
})
// 状态字段(两个模式使用不同字段名)
const statusField = computed(() => {
return props.mode === 'agent' ? rowData.value.status : rowData.value.docAuditStatus
})
// 是否草稿状态
const isDraft = computed(() => statusField.value === 'DRAFT')
// 招标代理操作权限
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'))
// 是否可完成
const canComplete = computed(() => availableActions.value.includes('complete'))
// 是否可定稿
const canFinalize = computed(() => availableActions.value.includes('finalize'))
// 状态快捷判断
const isReturned = computed(() => statusField.value === 'RETURNED')
const isReviewing = computed(() => ['ASSET_REVIEWING', 'DEPT_REVIEWING', 'AUDIT_REVIEWING'].includes(statusField.value))
const isConfirming = computed(() => statusField.value === 'ASSET_CONFIRMING')
const isCompleted = computed(() => statusField.value === 'COMPLETED')
// 上传配置
const uploadAction = computed(() => {
const baseUrl = import.meta.env.VITE_API_URL || ''
return `${baseUrl}/purchase/purchasingfiles/upload`
})
const uploadHeaders = computed(() => {
const token = Session.getToken()
return {
Authorization: `Bearer ${token}`,
'TENANT-ID': Session.getTenant() || '1'
}
})
const uploadData = computed(() => ({
fileType: '130', // 招标文件类型
purchaseId: applyId.value || ''
}))
const open = async (row: any) => {
visible.value = true
activeTab.value = 'requirement'
rowData.value = { ...row }
requirementFiles.value = []
docList.value = []
returnRemark.value = ''
fileList.value = []
uploadedFileData.value = null
// 获取申请ID兼容 id 和 applyId 两种字段名)
applyId.value = row.applyId || row.id
// 加载可执行操作
try {
const actionsRes = await getAvailableActions(applyId.value)
availableActions.value = actionsRes.data || []
} catch (e) {
availableActions.value = []
}
// 加载采购需求文件
loadRequirementFiles()
// 加载招标文件
loadDocList()
}
const loadRequirementFiles = async () => {
if (!applyId.value) return
requirementLoading.value = true
try {
const res = await getRequirementFiles(applyId.value)
requirementFiles.value = res.data || []
} catch (e) {
requirementFiles.value = []
} finally {
requirementLoading.value = false
}
}
const loadDocList = async () => {
if (!applyId.value) return
docLoading.value = true
try {
const res = await getDocList(applyId.value)
docList.value = res.data || []
} catch (e) {
docList.value = []
} finally {
docLoading.value = false
}
}
const handleDownloadRequirement = async (row: any) => {
try {
const res = await downloadFileById(row.id)
const fileName = row.fileName || row.fileTitle || 'download'
const blob = new Blob([res])
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
} catch (e: any) {
useMessage().error(e?.msg || '下载失败')
}
}
const handleDownloadDoc = async (row: any) => {
try {
const res = await downloadDocById(row.id)
const fileName = row.fileName || 'download'
const blob = new Blob([res])
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
} catch (e: any) {
useMessage().error(e?.msg || '下载失败')
}
}
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
const allowedTypes = ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/pdf']
const allowedExtensions = ['.doc', '.docx', '.pdf']
const fileExt = rawFile.name.substring(rawFile.name.lastIndexOf('.')).toLowerCase()
if (!allowedTypes.includes(rawFile.type) && !allowedExtensions.includes(fileExt)) {
useMessage().error('只能上传 .doc, .docx, .pdf 格式的文件')
return false
}
if (rawFile.size / 1024 / 1024 > 50) {
useMessage().error('文件大小不能超过 50MB')
return false
}
return true
}
const handleFileChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
fileList.value = uploadFiles
}
const handleUploadSuccess: UploadProps['onSuccess'] = async (response: any, uploadFile: any) => {
if (response?.code === 0 || response?.code === 200) {
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
}
}
const handleUploadError: UploadProps['onError'] = (error: any) => {
useMessage().error('文件上传失败:' + (error?.message || '未知错误'))
uploadSubmitting.value = false
}
const startUpload = async () => {
if (fileList.value.length === 0) {
useMessage().warning('请先选择文件')
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 handleSaveDraft = async () => {
const uploaded = await startUpload()
if (!uploaded || !uploadedFileData.value) {
useMessage().error('文件上传失败')
return
}
try {
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: ''
}
supplyFileList.value = []
supplyUploadedFileData.value = null
supplyUploadDialogVisible.value = true
}
// 补充上传文件选择变化
const handleSupplyFileChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
supplyFileList.value = uploadFiles
}
// 补充上传文件上传成功回调
const handleSupplyUploadSuccess: UploadProps['onSuccess'] = (response: any, uploadFile: any) => {
if (response?.code === 0 || response?.code === 200) {
supplyUploadedFileData.value = {
fileName: response.data.fileTitle || uploadFile.name,
filePath: response.data.remark || response.data.filePath
}
supplyUploadForm.value.fileName = supplyUploadedFileData.value.fileName
supplyUploadForm.value.filePath = supplyUploadedFileData.value.filePath
supplyUploadSubmitting.value = false
} else {
useMessage().error(response?.msg || '上传失败')
supplyUploadSubmitting.value = false
}
}
// 补充上传文件上传
const startSupplyUpload = async () => {
if (supplyFileList.value.length === 0) {
useMessage().warning('请先选择文件')
return false
}
supplyUploadSubmitting.value = true
supplyUploadRef.value?.submit()
// 等待上传完成
return new Promise((resolve) => {
const checkInterval = setInterval(() => {
if (!supplyUploadSubmitting.value) {
clearInterval(checkInterval)
resolve(supplyUploadedFileData.value !== null)
}
}, 100)
})
}
const submitSupplyUpload = async () => {
// 先上传文件
const uploaded = await startSupplyUpload()
if (!uploaded || !supplyUploadedFileData.value) {
useMessage().error('文件上传失败')
return
}
if (!supplyUploadForm.value.fileRemark) {
useMessage().warning('请填写文件意见')
supplyUploadSubmitting.value = false
return
}
supplyUploadSubmitting.value = true
try {
const res = await supplyUploadApi({
applyId: applyId.value,
fileName: supplyUploadedFileData.value.fileName,
filePath: supplyUploadedFileData.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 = () => {
remarkDialogTitle.value = '提交至需求部门'
remarkInput.value = ''
remarkActionType.value = 'dept'
remarkDialogVisible.value = true
}
// 提交至内审部门
const handleSubmitToAudit = () => {
remarkDialogTitle.value = '提交至内审部门'
remarkInput.value = ''
remarkActionType.value = 'audit'
remarkDialogVisible.value = true
}
// 提交至资产管理处
const handleSubmitToAsset = () => {
remarkDialogTitle.value = '提交至资产管理处'
remarkInput.value = ''
remarkActionType.value = 'asset'
remarkDialogVisible.value = true
}
// 提交备注操作
const submitRemarkAction = async () => {
remarkDialogVisible.value = false
try {
let res: any
const params = { applyId: applyId.value, remark: remarkInput.value }
if (remarkActionType.value === 'dept') {
res = await submitToDeptApi(params)
} else if (remarkActionType.value === 'audit') {
res = await submitToAuditApi(params)
} else if (remarkActionType.value === 'asset') {
res = await submitToAssetApi(params)
}
if (res?.code === 0 || res?.code === 200) {
useMessage().success('提交成功')
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 || '提交失败')
}
}
const handleReturn = () => {
returnRemark.value = ''
returnDialogVisible.value = true
}
const submitReturn = async () => {
try {
await returnDoc({ applyId: applyId.value, remark: returnRemark.value })
useMessage().success('退回成功')
returnDialogVisible.value = false
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 handleComplete = async () => {
try {
await useMessageBox().confirm('确定要确认流程结束吗?')
} catch {
return
}
try {
await completeDoc(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 handleFinalize = () => {
finalizeRemark.value = ''
finalizeDialogVisible.value = true
}
// 提交定稿
const submitFinalize = async () => {
try {
const res = await finalizeDocApi({ applyId: applyId.value, remark: finalizeRemark.value })
if (res?.code === 0 || res?.code === 200) {
useMessage().success('定稿成功')
finalizeDialogVisible.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 || '定稿失败')
}
}
const handleClose = () => {
visible.value = false
}
const getStatusType = (status: string) => {
const typeMap: Record<string, string> = {
'PENDING_UPLOAD': 'info',
'DRAFT': 'info',
'ASSET_REVIEWING': 'warning',
'DEPT_REVIEWING': 'warning',
'AUDIT_REVIEWING': 'warning',
'ASSET_CONFIRMING': 'primary',
'COMPLETED': 'success',
'RETURNED': 'danger'
}
return typeMap[status] || 'info'
}
const getStatusLabel = (status: string) => {
const labelMap: Record<string, string> = {
'PENDING_UPLOAD': '待上传',
'DRAFT': '草稿',
'ASSET_REVIEWING': '资产管理处审核中',
'DEPT_REVIEWING': '需求部门审核中',
'AUDIT_REVIEWING': '内审部门审核中',
'ASSET_CONFIRMING': '资产管理处确认中',
'COMPLETED': '已完成',
'RETURNED': '已退回'
}
return labelMap[status] || '-'
}
const getFileTypeLabel = (type: string) => {
const labelMap: Record<string, string> = {
'120': '采购需求表',
'130': '招标文件'
}
return labelMap[type] || type
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.doc-header {
margin-bottom: 16px;
display: flex;
align-items: center;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.ml-2 {
margin-left: 8px;
}
.mr-4 {
margin-right: 16px;
}
.mt-4 {
margin-top: 16px;
}
</style>