完整流程前端实现
parent
949725ffc6
commit
8c7c10f252
|
|
@ -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 } })
|
||||
|
|
|
|||
|
|
@ -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 ====================
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
// 预验收审核(对口人初审10、组长审核20)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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' } })
|
||||
}
|
||||
// 默认查看详情
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue