完整流程前端实现

pull/874/head
wh 2026-02-12 17:39:21 +08:00
parent 949725ffc6
commit 8c7c10f252
6 changed files with 164 additions and 30 deletions

View File

@ -145,6 +145,21 @@ export const expertCheck = (data: AcceptanceAuditReqVO) => {
return request.post({ url: '/project/acceptance/expert-check', data })
}
// 提交整改说明书(联络人)
export const submitRectifyManual = (acceptanceId: number) => {
return request.post({ url: '/project/acceptance/submit-rectify-manual?acceptanceId=' + acceptanceId })
}
// 重新提交终验材料(联络人)
export const submitExpertReupload = (acceptanceId: number) => {
return request.post({ url: '/project/acceptance/submit-expert-reupload?acceptanceId=' + acceptanceId })
}
// 提交会议评审结果
export const submitMeetingResult = (data: any) => {
return request.post({ url: '/project/acceptance/submit-meeting-result', data })
}
// 强制归档
export const forceArchive = (acceptanceId: number, reason: string) => {
return request.post({ url: '/project/acceptance/force-archive', params: { acceptanceId, reason } })

View File

@ -28,14 +28,16 @@ export interface AcceptanceMeetingBatchCreateReqVO {
// 批量录入会议结果请求 VO
export interface AcceptanceMeetingBatchResultReqVO {
meetingId: number
results: AcceptanceMeetingResultVO[]
signFileUrl: string
meetingOpinion?: string
projectResults: AcceptanceMeetingResultVO[]
}
// 单个会议结果 VO
// 单个项目结论 VO
export interface AcceptanceMeetingResultVO {
acceptanceId: number
result: string
opinion: string
opinion?: string
}
// ==================== 基础 CRUD ====================

View File

@ -427,6 +427,7 @@
</div>
</el-button>
<el-button
v-if="canSubmitRectify"
type="warning"
@ -441,7 +442,7 @@
</div>
</el-button>
<el-button
<el-button
v-if="canSubmitFinal"
type="primary"
plain
@ -455,6 +456,36 @@
<span class="text-xs opacity-80 font-normal">初审通过进入终验</span>
</div>
</el-button>
<el-button
v-if="canSubmitRectifyManual"
type="warning"
plain
size="large"
class="!w-full !justify-start !text-left !py-5"
@click="handleSubmitRectifyManual"
>
<Icon icon="ep:document-checked" class="mr-2 text-xl" />
<div class="flex flex-col items-start leading-tight">
<span class="font-bold">上传整改说明书</span>
<span class="text-xs opacity-80 font-normal">提交整改说明供管理员审核</span>
</div>
</el-button>
<el-button
v-if="canSubmitExpertReupload"
type="danger"
plain
size="large"
class="!w-full !justify-start !text-left !py-5"
@click="handleSubmitExpertReupload"
>
<Icon icon="ep:files" class="mr-2 text-xl" />
<div class="flex flex-col items-start leading-tight">
<span class="font-bold">重新提交材料</span>
<span class="text-xs opacity-80 font-normal">专家驳回需完善材料</span>
</div>
</el-button>
<el-divider class="!my-4" />
@ -636,10 +667,13 @@ const statusMap: Record<string, { label: string; type: string }> = {
'20': { label: '组长审核中', type: 'primary' },
'30': { label: '待终验申请', type: 'info' },
'40': { label: '管理员初审中', type: 'primary' }, // FINAL_ADMIN_REVIEW
'45': { label: '待组织会议', type: 'warning' }, // WAIT_ORGANIZE_MEETING
'50': { label: '待会议评审', type: 'info' }, // WAIT_MEETING
'60': { label: '待整改', type: 'danger' }, // FINAL_RECTIFY
'61': { label: '整改审核中', type: 'warning' }, // FINAL_RECTIFY_REVIEW
'62': { label: '待专家复核', type: 'warning' }, // WAIT_EXPERT_CHECK
'65': { label: '待上传整改说明书', type: 'warning' }, // WAIT_UPLOAD_RECTIFY
'66': { label: '待重新提交终验材料', type: 'danger' }, // WAIT_REUPLOAD_FINAL
'98': { label: '已取消', type: 'info' },
'99': { label: '已归档', type: 'success' }
}
@ -669,8 +703,8 @@ const getOpinionColor = (result: string) => {
//
const canUploadMaterial = computed(() => {
const currentUserId = useUserStore().getUser.id
// (05)(11)(30)(60)
return projectInfo.value.liaisonUserId === currentUserId && ['05', '11', '30', '60'].includes(acceptance.value.status)
// (05)(11)(30)(60)(65)(66)
return projectInfo.value.liaisonUserId === currentUserId && ['05', '11', '30', '60', '65', '66'].includes(acceptance.value.status)
})
const canSubmitMaterial = computed(() => {
@ -688,8 +722,18 @@ const canSubmitFinal = computed(() => {
return projectInfo.value.liaisonUserId === currentUserId && acceptance.value.status === '30' // WAIT_FINAL_APPLY
})
const canSubmitExpertReupload = computed(() => {
const currentUserId = useUserStore().getUser.id
return projectInfo.value.liaisonUserId === currentUserId && acceptance.value.status === '66'
})
const canSubmitRectifyManual = computed(() => {
const currentUserId = useUserStore().getUser.id
return projectInfo.value.liaisonUserId === currentUserId && acceptance.value.status === '65'
})
const showActions = computed(() => {
return canSubmitMaterial.value || canSubmitRectify.value || canSubmitFinal.value || canAudit.value
return canSubmitMaterial.value || canSubmitRectify.value || canSubmitFinal.value || canAudit.value || canSubmitExpertReupload.value || canSubmitRectifyManual.value
})
// (: 10, : 20, : 40)
@ -768,6 +812,23 @@ const handleAudit = async () => {
if (status === '40') {
//
await AcceptanceApi.auditFinalAdmin(auditData)
} else if (status === '61') {
//
await AcceptanceApi.auditRectify({
...auditData,
needExpert: false, //
targetExpertIds: []
} as any)
} else if (status === '62') {
//
await AcceptanceApi.expertCheck(auditData)
} else if (status === '50') {
//
await AcceptanceApi.submitMeetingResult({
acceptanceId: acceptance.value.id,
meetingResult: auditForm.value.result,
opinion: auditForm.value.opinion
})
} else {
// 1020
await AcceptanceApi.auditPreAcceptance(auditData)
@ -781,6 +842,36 @@ const handleAudit = async () => {
}
}
/** 提交终验申请 */
const handleSubmitFinal = async () => {
try {
await message.confirm('确定提交终验申请吗?')
await AcceptanceApi.submitFinalAcceptance({ acceptanceId: acceptance.value.id })
message.success('终验申请提交成功')
await getDetail()
} catch {}
}
/** 提交整改说明书 */
const handleSubmitRectifyManual = async () => {
try {
await message.confirm('确定提交整改说明书吗?')
await AcceptanceApi.submitRectifyManual(acceptance.value.id)
message.success('整改说明书提交成功')
await getDetail()
} catch {}
}
/** 重新提交终验材料 */
const handleSubmitExpertReupload = async () => {
try {
await message.confirm('确定重新提交终验材料吗?')
await AcceptanceApi.submitExpertReupload(acceptance.value.id)
message.success('材料提交成功')
await getDetail()
} catch {}
}
/** 获取验收详情 */
const getDetail = async () => {
loading.value = true

View File

@ -97,7 +97,7 @@ const handleProcess = (row: AcceptanceApi.AcceptanceTodoVO) => {
router.push({ path: '/project/acceptance/detail/' + row.acceptanceId, query: { tab: 'info' } })
}
// tab
else if (['task_liaison_submit', 'task_pre_rectify', 'task_final_rectify', 'task_final_apply'].includes(taskType)) {
else if (['task_liaison_submit', 'task_pre_rectify', 'task_final_rectify', 'task_final_apply', 'task_lianluoren_upload_rectify', 'task_lianluoren_reupload_final_materies'].includes(taskType)) {
router.push({ path: '/project/acceptance/detail/' + row.acceptanceId, query: { tab: 'materials' } })
}
//

View File

@ -122,8 +122,8 @@ const uploadHeaders = { Authorization: 'Bearer ' + getAccessToken() }
const open = async () => {
dialogVisible.value = true
resetForm()
//
const result = await AcceptanceApi.getAcceptancePage({ pageNo: 1, pageSize: 100, status: '30' })
//
const result = await AcceptanceApi.getAcceptancePage({ pageNo: 1, pageSize: 100, status: '45' })
acceptanceList.value = result.list
//
userList.value = await UserApi.getSimpleUserList()

View File

@ -14,24 +14,30 @@
/>
<el-divider content-position="left">会议整体结论</el-divider>
<el-form-item label="会议结论" prop="meetingResult">
<el-select v-model="formData.overallResult" placeholder="请选择整体结论">
<el-option label="通过" value="PASS" />
<el-option label="不通过" value="REJECT" />
<el-option label="需整改" value="RECTIFY" />
</el-select>
</el-form-item>
<el-form-item label="专家意见" prop="meetingOpinion">
<el-input
v-model="formData.overallOpinion"
v-model="formData.meetingOpinion"
type="textarea"
:rows="3"
placeholder="请输入专家组集体意见"
/>
</el-form-item>
<el-form-item label="签字文件" prop="signFileUrl">
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
:show-file-list="false"
:on-success="handleUploadSuccess"
>
<el-button type="primary">上传签字扫描件</el-button>
</el-upload>
<el-link v-if="formData.signFileUrl" :href="formData.signFileUrl" target="_blank" class="ml-2">
查看文件
</el-link>
</el-form-item>
<el-divider content-position="left">各项目结果</el-divider>
<el-table :data="formData.results" border>
<el-table :data="formData.projectResults" border>
<el-table-column label="验收ID" align="center" prop="acceptanceId" width="100" />
<el-table-column label="结论" align="center" width="150">
<template #default="scope">
@ -59,6 +65,7 @@
<script lang="ts" setup>
import * as AcceptanceMeetingApi from '@/api/project/acceptanceMeeting'
import * as AcceptanceMeetingRelationApi from '@/api/project/acceptanceMeetingRelation'
import { getAccessToken } from '@/utils/auth'
defineOptions({ name: 'BatchResultForm' })
@ -72,12 +79,16 @@ const meetingInfo = ref({
})
const formData = ref({
meetingId: undefined as number | undefined,
overallResult: 'PASS',
overallOpinion: '',
results: [] as AcceptanceMeetingApi.AcceptanceMeetingResultVO[]
meetingOpinion: '',
signFileUrl: '',
projectResults: [] as { acceptanceId: number; result: string; opinion: string }[]
})
const formRef = ref() // Ref
//
const uploadUrl = import.meta.env.VITE_BASE_URL + '/infra/file/upload'
const uploadHeaders = { Authorization: 'Bearer ' + getAccessToken() }
/** 打开弹窗 */
const open = async (row: AcceptanceMeetingApi.AcceptanceMeetingVO) => {
dialogVisible.value = true
@ -94,24 +105,38 @@ const open = async (row: AcceptanceMeetingApi.AcceptanceMeetingVO) => {
pageSize: 100,
meetingId: row.id
})
formData.value.results = result.list.map((item: any) => ({
formData.value.projectResults = result.list.map((item: any) => ({
acceptanceId: item.acceptanceId,
result: item.meetingResult || 'PASS',
opinion: item.meetingOpinion || ''
result: item.individualResult || 'PASS',
opinion: item.individualOpinion || ''
}))
}
defineExpose({ open }) // open
/** 上传成功 */
const handleUploadSuccess = (response: any) => {
if (response.code === 0) {
formData.value.signFileUrl = response.data
message.success('上传成功')
}
}
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
if (!formData.value.signFileUrl) {
message.warning('请上传专家组签字扫描件')
return
}
//
formLoading.value = true
try {
await AcceptanceMeetingApi.batchInputResult({
meetingId: formData.value.meetingId!,
results: formData.value.results
})
signFileUrl: formData.value.signFileUrl,
meetingOpinion: formData.value.meetingOpinion,
projectResults: formData.value.projectResults
} as any)
message.success('结果录入成功')
dialogVisible.value = false
//
@ -129,10 +154,11 @@ const resetForm = () => {
}
formData.value = {
meetingId: undefined,
overallResult: 'PASS',
overallOpinion: '',
results: []
meetingOpinion: '',
signFileUrl: '',
projectResults: []
}
formRef.value?.resetFields()
}
</script>