完整流程前端实现
parent
949725ffc6
commit
8c7c10f252
|
|
@ -145,6 +145,21 @@ export const expertCheck = (data: AcceptanceAuditReqVO) => {
|
||||||
return request.post({ url: '/project/acceptance/expert-check', data })
|
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) => {
|
export const forceArchive = (acceptanceId: number, reason: string) => {
|
||||||
return request.post({ url: '/project/acceptance/force-archive', params: { acceptanceId, reason } })
|
return request.post({ url: '/project/acceptance/force-archive', params: { acceptanceId, reason } })
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,16 @@ export interface AcceptanceMeetingBatchCreateReqVO {
|
||||||
// 批量录入会议结果请求 VO
|
// 批量录入会议结果请求 VO
|
||||||
export interface AcceptanceMeetingBatchResultReqVO {
|
export interface AcceptanceMeetingBatchResultReqVO {
|
||||||
meetingId: number
|
meetingId: number
|
||||||
results: AcceptanceMeetingResultVO[]
|
signFileUrl: string
|
||||||
|
meetingOpinion?: string
|
||||||
|
projectResults: AcceptanceMeetingResultVO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单个会议结果 VO
|
// 单个项目结论 VO
|
||||||
export interface AcceptanceMeetingResultVO {
|
export interface AcceptanceMeetingResultVO {
|
||||||
acceptanceId: number
|
acceptanceId: number
|
||||||
result: string
|
result: string
|
||||||
opinion: string
|
opinion?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 基础 CRUD ====================
|
// ==================== 基础 CRUD ====================
|
||||||
|
|
|
||||||
|
|
@ -427,6 +427,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canSubmitRectify"
|
v-if="canSubmitRectify"
|
||||||
type="warning"
|
type="warning"
|
||||||
|
|
@ -441,7 +442,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
v-if="canSubmitFinal"
|
v-if="canSubmitFinal"
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
|
|
@ -456,6 +457,36 @@
|
||||||
</div>
|
</div>
|
||||||
</el-button>
|
</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" />
|
<el-divider class="!my-4" />
|
||||||
|
|
||||||
<el-button @click="goBack" class="!w-full" plain>
|
<el-button @click="goBack" class="!w-full" plain>
|
||||||
|
|
@ -636,10 +667,13 @@ const statusMap: Record<string, { label: string; type: string }> = {
|
||||||
'20': { label: '组长审核中', type: 'primary' },
|
'20': { label: '组长审核中', type: 'primary' },
|
||||||
'30': { label: '待终验申请', type: 'info' },
|
'30': { label: '待终验申请', type: 'info' },
|
||||||
'40': { label: '管理员初审中', type: 'primary' }, // 对应 FINAL_ADMIN_REVIEW
|
'40': { label: '管理员初审中', type: 'primary' }, // 对应 FINAL_ADMIN_REVIEW
|
||||||
|
'45': { label: '待组织会议', type: 'warning' }, // WAIT_ORGANIZE_MEETING
|
||||||
'50': { label: '待会议评审', type: 'info' }, // WAIT_MEETING
|
'50': { label: '待会议评审', type: 'info' }, // WAIT_MEETING
|
||||||
'60': { label: '待整改', type: 'danger' }, // FINAL_RECTIFY
|
'60': { label: '待整改', type: 'danger' }, // FINAL_RECTIFY
|
||||||
'61': { label: '整改审核中', type: 'warning' }, // FINAL_RECTIFY_REVIEW
|
'61': { label: '整改审核中', type: 'warning' }, // FINAL_RECTIFY_REVIEW
|
||||||
'62': { label: '待专家复核', type: 'warning' }, // WAIT_EXPERT_CHECK
|
'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' },
|
'98': { label: '已取消', type: 'info' },
|
||||||
'99': { label: '已归档', type: 'success' }
|
'99': { label: '已归档', type: 'success' }
|
||||||
}
|
}
|
||||||
|
|
@ -669,8 +703,8 @@ const getOpinionColor = (result: string) => {
|
||||||
// 权限判断
|
// 权限判断
|
||||||
const canUploadMaterial = computed(() => {
|
const canUploadMaterial = computed(() => {
|
||||||
const currentUserId = useUserStore().getUser.id
|
const currentUserId = useUserStore().getUser.id
|
||||||
// 必须是联络人,且状态符合:待提交材料(05)、预验收整改(11)、待终验申请(30)、终验整改(60)
|
// 必须是联络人,且状态符合:待提交材料(05)、预验收待整改(11)、待终验申请(30)、终验待整改(60)、待上传整改说明书(65)、待重新提交终验材料(66)
|
||||||
return projectInfo.value.liaisonUserId === currentUserId && ['05', '11', '30', '60'].includes(acceptance.value.status)
|
return projectInfo.value.liaisonUserId === currentUserId && ['05', '11', '30', '60', '65', '66'].includes(acceptance.value.status)
|
||||||
})
|
})
|
||||||
|
|
||||||
const canSubmitMaterial = computed(() => {
|
const canSubmitMaterial = computed(() => {
|
||||||
|
|
@ -688,8 +722,18 @@ const canSubmitFinal = computed(() => {
|
||||||
return projectInfo.value.liaisonUserId === currentUserId && acceptance.value.status === '30' // WAIT_FINAL_APPLY
|
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(() => {
|
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)
|
// 是否可以审核 (对口人初审: 10, 专家组长审核: 20, 管理员终验初审: 40)
|
||||||
|
|
@ -768,6 +812,23 @@ const handleAudit = async () => {
|
||||||
if (status === '40') {
|
if (status === '40') {
|
||||||
// 管理员终验初审
|
// 管理员终验初审
|
||||||
await AcceptanceApi.auditFinalAdmin(auditData)
|
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 {
|
} else {
|
||||||
// 预验收审核(对口人初审10、组长审核20)
|
// 预验收审核(对口人初审10、组长审核20)
|
||||||
await AcceptanceApi.auditPreAcceptance(auditData)
|
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 () => {
|
const getDetail = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ const handleProcess = (row: AcceptanceApi.AcceptanceTodoVO) => {
|
||||||
router.push({ path: '/project/acceptance/detail/' + row.acceptanceId, query: { tab: 'info' } })
|
router.push({ path: '/project/acceptance/detail/' + row.acceptanceId, query: { tab: 'info' } })
|
||||||
}
|
}
|
||||||
// 材料提交类任务:跳转到详情页的材料tab
|
// 材料提交类任务:跳转到详情页的材料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' } })
|
router.push({ path: '/project/acceptance/detail/' + row.acceptanceId, query: { tab: 'materials' } })
|
||||||
}
|
}
|
||||||
// 默认查看详情
|
// 默认查看详情
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,8 @@ const uploadHeaders = { Authorization: 'Bearer ' + getAccessToken() }
|
||||||
const open = async () => {
|
const open = async () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
resetForm()
|
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
|
acceptanceList.value = result.list
|
||||||
// 加载用户列表
|
// 加载用户列表
|
||||||
userList.value = await UserApi.getSimpleUserList()
|
userList.value = await UserApi.getSimpleUserList()
|
||||||
|
|
|
||||||
|
|
@ -14,24 +14,30 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<el-divider content-position="left">会议整体结论</el-divider>
|
<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-form-item label="专家意见" prop="meetingOpinion">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.overallOpinion"
|
v-model="formData.meetingOpinion"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="3"
|
:rows="3"
|
||||||
placeholder="请输入专家组集体意见"
|
placeholder="请输入专家组集体意见"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</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-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="验收ID" align="center" prop="acceptanceId" width="100" />
|
||||||
<el-table-column label="结论" align="center" width="150">
|
<el-table-column label="结论" align="center" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|
@ -59,6 +65,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as AcceptanceMeetingApi from '@/api/project/acceptanceMeeting'
|
import * as AcceptanceMeetingApi from '@/api/project/acceptanceMeeting'
|
||||||
import * as AcceptanceMeetingRelationApi from '@/api/project/acceptanceMeetingRelation'
|
import * as AcceptanceMeetingRelationApi from '@/api/project/acceptanceMeetingRelation'
|
||||||
|
import { getAccessToken } from '@/utils/auth'
|
||||||
|
|
||||||
defineOptions({ name: 'BatchResultForm' })
|
defineOptions({ name: 'BatchResultForm' })
|
||||||
|
|
||||||
|
|
@ -72,12 +79,16 @@ const meetingInfo = ref({
|
||||||
})
|
})
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
meetingId: undefined as number | undefined,
|
meetingId: undefined as number | undefined,
|
||||||
overallResult: 'PASS',
|
meetingOpinion: '',
|
||||||
overallOpinion: '',
|
signFileUrl: '',
|
||||||
results: [] as AcceptanceMeetingApi.AcceptanceMeetingResultVO[]
|
projectResults: [] as { acceptanceId: number; result: string; opinion: string }[]
|
||||||
})
|
})
|
||||||
const formRef = ref() // 表单 Ref
|
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) => {
|
const open = async (row: AcceptanceMeetingApi.AcceptanceMeetingVO) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
|
|
@ -94,24 +105,38 @@ const open = async (row: AcceptanceMeetingApi.AcceptanceMeetingVO) => {
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
meetingId: row.id
|
meetingId: row.id
|
||||||
})
|
})
|
||||||
formData.value.results = result.list.map((item: any) => ({
|
formData.value.projectResults = result.list.map((item: any) => ({
|
||||||
acceptanceId: item.acceptanceId,
|
acceptanceId: item.acceptanceId,
|
||||||
result: item.meetingResult || 'PASS',
|
result: item.individualResult || 'PASS',
|
||||||
opinion: item.meetingOpinion || ''
|
opinion: item.individualOpinion || ''
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 上传成功 */
|
||||||
|
const handleUploadSuccess = (response: any) => {
|
||||||
|
if (response.code === 0) {
|
||||||
|
formData.value.signFileUrl = response.data
|
||||||
|
message.success('上传成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 提交表单 */
|
/** 提交表单 */
|
||||||
const emit = defineEmits(['success']) // 定义 success 事件
|
const emit = defineEmits(['success']) // 定义 success 事件
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
|
if (!formData.value.signFileUrl) {
|
||||||
|
message.warning('请上传专家组签字扫描件')
|
||||||
|
return
|
||||||
|
}
|
||||||
// 提交请求
|
// 提交请求
|
||||||
formLoading.value = true
|
formLoading.value = true
|
||||||
try {
|
try {
|
||||||
await AcceptanceMeetingApi.batchInputResult({
|
await AcceptanceMeetingApi.batchInputResult({
|
||||||
meetingId: formData.value.meetingId!,
|
meetingId: formData.value.meetingId!,
|
||||||
results: formData.value.results
|
signFileUrl: formData.value.signFileUrl,
|
||||||
})
|
meetingOpinion: formData.value.meetingOpinion,
|
||||||
|
projectResults: formData.value.projectResults
|
||||||
|
} as any)
|
||||||
message.success('结果录入成功')
|
message.success('结果录入成功')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
// 发送操作成功的事件
|
// 发送操作成功的事件
|
||||||
|
|
@ -129,10 +154,11 @@ const resetForm = () => {
|
||||||
}
|
}
|
||||||
formData.value = {
|
formData.value = {
|
||||||
meetingId: undefined,
|
meetingId: undefined,
|
||||||
overallResult: 'PASS',
|
meetingOpinion: '',
|
||||||
overallOpinion: '',
|
signFileUrl: '',
|
||||||
results: []
|
projectResults: []
|
||||||
}
|
}
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue