履约验收
This commit is contained in:
@@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="160px" class="accept-batch-form">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="160px" >
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="12">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="验收方式" prop="acceptType">
|
<el-form-item label="验收方式" prop="acceptType">
|
||||||
<el-radio-group v-model="form.acceptType" :disabled="readonly">
|
<el-radio-group v-model="form.acceptType" :disabled="readonly">
|
||||||
<el-radio label="1">填写履约验收评价表</el-radio>
|
<el-radio label="1" :disabled="!canFill">填写履约验收评价表</el-radio>
|
||||||
<el-radio label="2" :disabled="!canFill">上传履约验收评价表</el-radio>
|
<el-radio label="2">上传履约验收评价表</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<div v-if="!canFill" class="el-form-item__tip">金额≥30万,仅支持上传模版</div>
|
<div v-if="!canFill" class="el-form-item__tip">金额≥30万,仅支持上传模版</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="验收日期" prop="acceptDate">
|
<el-form-item label="验收日期" prop="acceptDate">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="form.acceptDate"
|
v-model="form.acceptDate"
|
||||||
@@ -26,23 +26,26 @@
|
|||||||
|
|
||||||
<!-- 填报方式:验收内容表格 -->
|
<!-- 填报方式:验收内容表格 -->
|
||||||
<template v-if="form.acceptType === '1' && canFill">
|
<template v-if="form.acceptType === '1' && canFill">
|
||||||
<el-col :span="24">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="验收内容" prop="acceptContents">
|
<el-form-item label="验收内容" prop="acceptContents">
|
||||||
<el-table :data="form.acceptContents" border size="small" max-height="260" class="accept-content-table">
|
<el-table :data="form.acceptContents" border size="small" class="accept-content-table">
|
||||||
<el-table-column prop="itemName" label="验收项" >
|
<el-table-column prop="itemName" label="验收项" >
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{row.itemName}}
|
<div>
|
||||||
<el-input
|
<span>{{row.itemName}}</span>
|
||||||
v-if="row.type === 'input'"
|
<el-input
|
||||||
v-model="row.remark"
|
v-if="row.type === 'input'"
|
||||||
placeholder="请输入"
|
v-model="row.remark"
|
||||||
size="small"
|
placeholder="请输入"
|
||||||
:disabled="readonly"
|
size="small"
|
||||||
/>
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="isQualified" label="合格/不合格" width="140" align="center">
|
<el-table-column prop="isQualified" label="合格/不合格" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-radio-group v-model="row.isQualified" size="small" :disabled="readonly">
|
<el-radio-group v-model="row.isQualified" size="small" :disabled="readonly">
|
||||||
<el-radio label="1">合格</el-radio>
|
<el-radio label="1">合格</el-radio>
|
||||||
@@ -58,7 +61,7 @@
|
|||||||
|
|
||||||
<!-- 上传方式 -->
|
<!-- 上传方式 -->
|
||||||
<template v-if="form.acceptType === '2'">
|
<template v-if="form.acceptType === '2'">
|
||||||
<el-col :span="24">
|
<el-col :span="12">
|
||||||
<el-form-item label="履约验收模版" prop="templateFileIds">
|
<el-form-item label="履约验收模版" prop="templateFileIds">
|
||||||
<UploadFile
|
<UploadFile
|
||||||
v-model="templateFileIdsStr"
|
v-model="templateFileIdsStr"
|
||||||
@@ -72,7 +75,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 验收小组 -->
|
<!-- 验收小组 -->
|
||||||
<el-col :span="24">
|
<el-col :span="12">
|
||||||
<el-form-item label="验收小组" prop="acceptTeam">
|
<el-form-item label="验收小组" prop="acceptTeam">
|
||||||
<div class="team-list">
|
<div class="team-list">
|
||||||
<div v-for="(m, idx) in form.acceptTeam" :key="idx" class="team-row">
|
<div v-for="(m, idx) in form.acceptTeam" :key="idx" class="team-row">
|
||||||
@@ -82,7 +85,30 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-button v-if="!readonly" type="primary" link size="small" @click="addTeam">+ 增加成员</el-button>
|
<el-button v-if="!readonly" type="primary" link size="small" @click="addTeam">+ 增加成员</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-form-item__tip">至少3人,且为单数</div>
|
<div class="el-form-item__tip">
|
||||||
|
至少3人,且为单数
|
||||||
|
<template v-if="(previousBatchesTeams || []).length > 0">
|
||||||
|
;
|
||||||
|
<span class="copy-from-inline">
|
||||||
|
从往期带入
|
||||||
|
<el-select
|
||||||
|
v-model="copyFromBatch"
|
||||||
|
placeholder="同第N期"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
style="width: 100px"
|
||||||
|
@change="onCopyFromBatch"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in (previousBatchesTeams || [])"
|
||||||
|
:key="item.batch"
|
||||||
|
:label="`同第${item.batch}期`"
|
||||||
|
:value="item.batch"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
@@ -106,14 +132,17 @@ const props = withDefaults(
|
|||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
purchaseId?: string
|
purchaseId?: string
|
||||||
acceptanceItems?: any[]
|
acceptanceItems?: any[]
|
||||||
|
batchNum?: number
|
||||||
|
previousBatchesTeams?: { batch: number; team: any[] }[]
|
||||||
}>(),
|
}>(),
|
||||||
{ readonly: false, canFill: true, purchaseId: '' }
|
{ readonly: false, canFill: true, purchaseId: '', batchNum: 1, previousBatchesTeams: () => [] }
|
||||||
)
|
)
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
const templateFileIdsStr = ref('')
|
const templateFileIdsStr = ref('')
|
||||||
|
const copyFromBatch = ref<number | null>(null)
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
acceptType: '1',
|
acceptType: '1',
|
||||||
@@ -129,8 +158,20 @@ const form = reactive({
|
|||||||
...props.modelValue,
|
...props.modelValue,
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.modelValue, (val) => Object.assign(form, val || {}), { deep: true })
|
watch(() => props.modelValue, (val) => {
|
||||||
|
Object.assign(form, val || {})
|
||||||
|
// 金额≥30万时,强制为上传方式
|
||||||
|
if (!props.canFill && form.acceptType === '1') {
|
||||||
|
form.acceptType = '2'
|
||||||
|
}
|
||||||
|
}, { deep: true })
|
||||||
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
||||||
|
// 金额≥30万时,默认选中上传方式
|
||||||
|
watch(() => props.canFill, (val) => {
|
||||||
|
if (!val && form.acceptType === '1') {
|
||||||
|
form.acceptType = '2'
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
watch(() => props.acceptanceItems, (items) => {
|
watch(() => props.acceptanceItems, (items) => {
|
||||||
if (items?.length && form.acceptContents.length === 0) {
|
if (items?.length && form.acceptContents.length === 0) {
|
||||||
@@ -163,6 +204,19 @@ const removeTeam = (idx: number) => {
|
|||||||
form.acceptTeam.splice(idx, 1)
|
form.acceptTeam.splice(idx, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onCopyFromBatch = (n: number | null) => {
|
||||||
|
if (!n) return
|
||||||
|
const item = props.previousBatchesTeams?.find((x) => x.batch === n)
|
||||||
|
if (item?.team?.length) {
|
||||||
|
form.acceptTeam = item.team.map((m: any) => ({
|
||||||
|
name: m.name || '',
|
||||||
|
deptCode: m.deptCode || '',
|
||||||
|
deptName: m.deptName || '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
copyFromBatch.value = null
|
||||||
|
}
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
acceptType: [{ required: true, message: '请选择验收方式', trigger: 'change' }],
|
acceptType: [{ required: true, message: '请选择验收方式', trigger: 'change' }],
|
||||||
acceptDate: [{ required: true, message: '请选择验收日期', trigger: 'change' }],
|
acceptDate: [{ required: true, message: '请选择验收日期', trigger: 'change' }],
|
||||||
@@ -174,26 +228,16 @@ defineExpose({ validate, form })
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.accept-batch-form :deep(.el-form-item) {
|
.mb20 {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.accept-content-table :deep(.el-table__body td) {
|
.copy-from-inline {
|
||||||
padding: 10px 0;
|
display: inline-flex;
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
.team-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
.team-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 6px;
|
||||||
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
.el-form-item__tip {
|
.copy-from-inline :deep(.el-select) {
|
||||||
font-size: 12px;
|
vertical-align: middle;
|
||||||
color: #909399;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px" class="accept-common-form compact-form">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="项目名称">
|
<el-form-item label="项目名称">
|
||||||
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" />
|
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="需求部门">
|
<el-form-item label="需求部门">
|
||||||
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" />
|
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="是否签订合同" prop="hasContract">
|
<el-form-item label="是否签订合同" prop="hasContract">
|
||||||
<el-radio-group v-model="form.hasContract">
|
<el-radio-group v-model="form.hasContract">
|
||||||
<el-radio label="0">否</el-radio>
|
<el-radio label="0">否</el-radio>
|
||||||
@@ -19,12 +19,12 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.hasContract === '1'">
|
<el-col :span="8" class="mb20" v-if="form.hasContract === '1'">
|
||||||
<el-form-item label="合同" prop="contractId">
|
<el-form-item label="合同" prop="contractId">
|
||||||
<el-input v-model="form.contractId" placeholder="请选择合同(待对接合同接口)" clearable />
|
<el-input v-model="form.contractId" placeholder="请选择合同(待对接合同接口)" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="是否分期验收" prop="isInstallment">
|
<el-form-item label="是否分期验收" prop="isInstallment">
|
||||||
<el-radio-group v-model="form.isInstallment">
|
<el-radio-group v-model="form.isInstallment">
|
||||||
<el-radio label="0">否</el-radio>
|
<el-radio label="0">否</el-radio>
|
||||||
@@ -32,27 +32,27 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.isInstallment === '1'">
|
<el-col :span="8" class="mb20" v-if="form.isInstallment === '1'">
|
||||||
<el-form-item label="分期次数" prop="totalPhases">
|
<el-form-item label="分期次数" prop="totalPhases">
|
||||||
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
|
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="供应商名称" prop="supplierName">
|
<el-form-item label="供应商名称" prop="supplierName">
|
||||||
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
|
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="供应商联系人及电话" prop="supplierContact">
|
<el-form-item label="供应商联系人及电话" prop="supplierContact">
|
||||||
<el-input v-model="form.supplierContact" placeholder="请输入" clearable />
|
<el-input v-model="form.supplierContact" placeholder="请输入" clearable />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="采购人员" prop="purchaserId">
|
<el-form-item label="采购人员" prop="purchaserId">
|
||||||
<org-selector v-model:orgList="purchaserList" type="user" :multiple="false" @update:orgList="onPurchaserChange" />
|
<org-selector v-model:orgList="purchaserList" type="user" :multiple="false" @update:orgList="onPurchaserChange" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="资产管理员" prop="assetAdminId">
|
<el-form-item label="资产管理员" prop="assetAdminId">
|
||||||
<org-selector v-model:orgList="assetAdminList" type="user" :multiple="false" @update:orgList="onAssetAdminChange" />
|
<org-selector v-model:orgList="assetAdminList" type="user" :multiple="false" @update:orgList="onAssetAdminChange" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -69,6 +69,8 @@ const props = defineProps<{
|
|||||||
modelValue: Record<string, any>
|
modelValue: Record<string, any>
|
||||||
projectName?: string
|
projectName?: string
|
||||||
deptName?: string
|
deptName?: string
|
||||||
|
/** 每次打开弹窗时变化,用于强制重置内部 form */
|
||||||
|
resetKey?: number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
@@ -91,9 +93,8 @@ const form = reactive({
|
|||||||
...props.modelValue,
|
...props.modelValue,
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.modelValue, (val) => {
|
const syncFormFromModel = (val: Record<string, any> | undefined) => {
|
||||||
Object.assign(form, val || {})
|
Object.assign(form, val || {})
|
||||||
// 人员选择回显
|
|
||||||
if (form.purchaserId && form.purchaserName) {
|
if (form.purchaserId && form.purchaserName) {
|
||||||
purchaserList.value = [{ id: form.purchaserId, name: form.purchaserName, type: 'user' }]
|
purchaserList.value = [{ id: form.purchaserId, name: form.purchaserName, type: 'user' }]
|
||||||
} else {
|
} else {
|
||||||
@@ -104,7 +105,11 @@ watch(() => props.modelValue, (val) => {
|
|||||||
} else {
|
} else {
|
||||||
assetAdminList.value = []
|
assetAdminList.value = []
|
||||||
}
|
}
|
||||||
}, { deep: true, immediate: true })
|
}
|
||||||
|
|
||||||
|
watch(() => props.modelValue, syncFormFromModel, { deep: true, immediate: true })
|
||||||
|
// resetKey 变化时强制用 modelValue 覆盖内部 form
|
||||||
|
watch(() => props.resetKey, () => syncFormFromModel(props.modelValue))
|
||||||
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
|
||||||
|
|
||||||
const onPurchaserChange = (list: any[]) => {
|
const onPurchaserChange = (list: any[]) => {
|
||||||
@@ -140,26 +145,7 @@ defineExpose({ validate, form })
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.accept-common-form {
|
.mb20 {
|
||||||
padding: 0 4px;
|
margin-bottom: 20px;
|
||||||
}
|
|
||||||
.accept-common-form :deep(.el-form-item) {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
/* 紧凑表单样式 */
|
|
||||||
.compact-form {
|
|
||||||
:deep(.el-form-item) {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-form-item__label) {
|
|
||||||
padding-right: 12px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-input__inner),
|
|
||||||
:deep(.el-textarea__inner) {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
title="履约验收"
|
title="履约验收"
|
||||||
width="85%"
|
width="75%"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
class="purchasing-accept-modal"
|
class="purchasing-accept-modal"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
<div v-loading="loading" class="modal-body">
|
<div v-loading="loading" class="modal-body" :key="String(purchaseId)">
|
||||||
<div class="main-tabs">
|
<div class="main-tabs">
|
||||||
<div class="main-tab-nav">
|
<div class="main-tab-nav">
|
||||||
<div
|
<div
|
||||||
@@ -23,12 +23,14 @@
|
|||||||
:class="{ active: mainTab === 'batch' }"
|
:class="{ active: mainTab === 'batch' }"
|
||||||
@click="mainTab = 'batch'"
|
@click="mainTab = 'batch'"
|
||||||
>
|
>
|
||||||
分期验收{{ batches.length > 0 ? ` (${batches.length})` : '' }}
|
{{ commonForm?.isInstallment === '0' ? '验收' : '分期验收' }}{{ commonForm?.isInstallment !== '0' && batches.length > 0 ? ` (${batches.length})` : '' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main-tab-content">
|
<div class="main-tab-content">
|
||||||
<div v-show="mainTab === 'common'" class="tab-content">
|
<div v-show="mainTab === 'common'" class="tab-content">
|
||||||
<AcceptCommonForm
|
<AcceptCommonForm
|
||||||
|
:key="`${purchaseId}-${openToken}`"
|
||||||
|
:reset-key="openToken"
|
||||||
ref="commonFormRef"
|
ref="commonFormRef"
|
||||||
v-model="commonForm"
|
v-model="commonForm"
|
||||||
:project-name="applyInfo?.projectName"
|
:project-name="applyInfo?.projectName"
|
||||||
@@ -37,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-show="mainTab === 'batch'" class="tab-content">
|
<div v-show="mainTab === 'batch'" class="tab-content">
|
||||||
<div v-if="batches.length > 0">
|
<div v-if="batches.length > 0">
|
||||||
<div class="batch-tabs">
|
<div v-show="commonForm?.isInstallment !== '0'" class="batch-tabs">
|
||||||
<div
|
<div
|
||||||
v-for="b in batches"
|
v-for="b in batches"
|
||||||
:key="b.id"
|
:key="b.id"
|
||||||
@@ -55,11 +57,14 @@
|
|||||||
v-for="b in batches"
|
v-for="b in batches"
|
||||||
v-show="String(b.batch) === activeTab"
|
v-show="String(b.batch) === activeTab"
|
||||||
:key="b.id"
|
:key="b.id"
|
||||||
|
:ref="(el) => setBatchFormRef(b.batch, el)"
|
||||||
v-model="batchForms[b.batch]"
|
v-model="batchForms[b.batch]"
|
||||||
:can-fill="canFillForm"
|
:can-fill="canFillForm"
|
||||||
:readonly="false"
|
:readonly="false"
|
||||||
:purchase-id="String(purchaseId)"
|
:purchase-id="String(purchaseId)"
|
||||||
:acceptance-items="acceptanceItems"
|
:acceptance-items="acceptanceItems"
|
||||||
|
:batch-num="b.batch"
|
||||||
|
:previous-batches-teams="getPreviousBatchesTeams(b.batch)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -125,14 +130,33 @@ const batches = ref<any[]>([])
|
|||||||
const mainTab = ref('common')
|
const mainTab = ref('common')
|
||||||
const activeTab = ref('1')
|
const activeTab = ref('1')
|
||||||
const commonFormRef = ref()
|
const commonFormRef = ref()
|
||||||
const commonForm = reactive<Record<string, any>>({})
|
const batchFormRefMap = ref<Record<number, any>>({})
|
||||||
|
/** 使用 ref 并在每次打开时替换整个对象,确保子组件能感知引用变化并清空 */
|
||||||
|
const commonForm = ref<Record<string, any>>({})
|
||||||
|
/** 每次打开自增,用于强制 AcceptCommonForm 重新挂载,确保公共信息彻底清空 */
|
||||||
|
const openToken = ref(0)
|
||||||
const batchForms = reactive<Record<number, any>>({})
|
const batchForms = reactive<Record<number, any>>({})
|
||||||
|
|
||||||
|
const setBatchFormRef = (batch: number, el: any) => {
|
||||||
|
if (el) batchFormRefMap.value[batch] = el
|
||||||
|
}
|
||||||
|
|
||||||
const activeBatchId = computed(() => {
|
const activeBatchId = computed(() => {
|
||||||
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
||||||
return b?.id || ''
|
return b?.id || ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const getPreviousBatchesTeams = (batchNum: number) => {
|
||||||
|
const list: { batch: number; team: any[] }[] = []
|
||||||
|
for (let n = 1; n < batchNum; n++) {
|
||||||
|
const team = batchForms[n]?.acceptTeam
|
||||||
|
if (Array.isArray(team) && team.length > 0) {
|
||||||
|
list.push({ batch: n, team })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
const canEditBatch = (batch: number) => {
|
const canEditBatch = (batch: number) => {
|
||||||
if (batch === 1) return true
|
if (batch === 1) return true
|
||||||
for (let i = 1; i < batch; i++) {
|
for (let i = 1; i < batch; i++) {
|
||||||
@@ -142,7 +166,8 @@ const canEditBatch = (batch: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isBatchCompleted = (b: any) => {
|
const isBatchCompleted = (b: any) => {
|
||||||
return !!(b.acceptType && b.acceptDate)
|
const form = batchForms[b.batch]
|
||||||
|
return !!(form?.acceptType && form?.acceptDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isBatchCompletedByIdx = (batch: number) => {
|
const isBatchCompletedByIdx = (batch: number) => {
|
||||||
@@ -152,35 +177,43 @@ const isBatchCompletedByIdx = (batch: number) => {
|
|||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
if (!purchaseId.value) return
|
if (!purchaseId.value) return
|
||||||
|
const currentId = String(purchaseId.value)
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const [configRes, canFillRes] = await Promise.all([
|
const [configRes, canFillRes] = await Promise.all([
|
||||||
getCommonConfigWithBatches(String(purchaseId.value)),
|
getCommonConfigWithBatches(currentId),
|
||||||
apiCanFillForm(String(purchaseId.value)),
|
apiCanFillForm(currentId),
|
||||||
])
|
])
|
||||||
|
// 防止快速切换:若已打开其他申请单,忽略本次结果
|
||||||
|
if (String(purchaseId.value) !== currentId) return
|
||||||
|
|
||||||
const config = configRes?.data
|
const config = configRes?.data
|
||||||
canFillForm.value = !!canFillRes?.data
|
canFillForm.value = !!canFillRes?.data
|
||||||
|
|
||||||
if (config?.common) {
|
if (config?.common) {
|
||||||
Object.assign(commonForm, {
|
|
||||||
hasContract: config.common.hasContract || '0',
|
|
||||||
contractId: config.common.contractId || '',
|
|
||||||
isInstallment: config.common.isInstallment || '0',
|
|
||||||
totalPhases: config.common.totalPhases || 1,
|
|
||||||
supplierName: config.common.supplierName || '',
|
|
||||||
supplierContact: config.common.supplierContact || '',
|
|
||||||
purchaserId: config.common.purchaserId || '',
|
|
||||||
purchaserName: config.common.purchaserName || '',
|
|
||||||
assetAdminId: config.common.assetAdminId || '',
|
|
||||||
assetAdminName: config.common.assetAdminName || '',
|
|
||||||
})
|
|
||||||
applyInfo.value = config.common
|
applyInfo.value = config.common
|
||||||
|
// 仅当存在已保存批次时,才用接口数据回填公共信息;否则保持 open() 中的默认清空值
|
||||||
|
if (config?.batches?.length) {
|
||||||
|
Object.assign(commonForm.value, {
|
||||||
|
hasContract: config.common.hasContract || '0',
|
||||||
|
contractId: config.common.contractId || '',
|
||||||
|
isInstallment: config.common.isInstallment || '0',
|
||||||
|
totalPhases: config.common.totalPhases || 1,
|
||||||
|
supplierName: config.common.supplierName || '',
|
||||||
|
supplierContact: config.common.supplierContact || '',
|
||||||
|
purchaserId: config.common.purchaserId || '',
|
||||||
|
purchaserName: config.common.purchaserName || '',
|
||||||
|
assetAdminId: config.common.assetAdminId || '',
|
||||||
|
assetAdminName: config.common.assetAdminName || '',
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectType = applyInfo.value?.projectType || rowProjectType.value || 'A'
|
const projectType = applyInfo.value?.projectType || rowProjectType.value || 'A'
|
||||||
const typeMap: Record<string, string> = { A: 'A', B: 'B', C: 'C' }
|
const typeMap: Record<string, string> = { A: 'A', B: 'B', C: 'C' }
|
||||||
const at = typeMap[projectType] || 'A'
|
const at = typeMap[projectType] || 'A'
|
||||||
const itemsRes = await getAcceptanceItems(at)
|
const itemsRes = await getAcceptanceItems(at)
|
||||||
|
if (String(purchaseId.value) !== currentId) return
|
||||||
acceptanceItems.value = itemsRes?.data || []
|
acceptanceItems.value = itemsRes?.data || []
|
||||||
|
|
||||||
if (config?.batches?.length) {
|
if (config?.batches?.length) {
|
||||||
@@ -191,6 +224,7 @@ const loadData = async () => {
|
|||||||
if (!batchForms[b.batch]) batchForms[b.batch] = {}
|
if (!batchForms[b.batch]) batchForms[b.batch] = {}
|
||||||
}
|
}
|
||||||
await loadBatchDetails()
|
await loadBatchDetails()
|
||||||
|
if (String(purchaseId.value) !== currentId) return
|
||||||
} else {
|
} else {
|
||||||
batches.value = []
|
batches.value = []
|
||||||
}
|
}
|
||||||
@@ -252,9 +286,13 @@ const loadBatchDetails = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const saveCommonConfig = async () => {
|
const saveCommonConfig = async () => {
|
||||||
const valid = await commonFormRef.value?.validate?.().catch(() => false)
|
const formRef = commonFormRef.value
|
||||||
|
const valid = await formRef?.validate?.().catch(() => false)
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
if (commonForm.isInstallment === '1' && (!commonForm.totalPhases || commonForm.totalPhases < 1)) {
|
// 直接从子组件 form 读取,确保拿到用户填写的最新值(避免 v-model 同步延迟)
|
||||||
|
const form = formRef?.form || commonForm.value
|
||||||
|
const isInstallment = form.isInstallment === '1' || form.isInstallment === 1
|
||||||
|
if (isInstallment && (!form.totalPhases || form.totalPhases < 1)) {
|
||||||
useMessage().error('请填写分期次数')
|
useMessage().error('请填写分期次数')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -262,16 +300,16 @@ const saveCommonConfig = async () => {
|
|||||||
try {
|
try {
|
||||||
await apiSaveCommonConfig({
|
await apiSaveCommonConfig({
|
||||||
purchaseId: String(purchaseId.value),
|
purchaseId: String(purchaseId.value),
|
||||||
hasContract: commonForm.hasContract,
|
hasContract: form.hasContract ?? '0',
|
||||||
contractId: commonForm.contractId,
|
contractId: form.contractId ?? '',
|
||||||
isInstallment: commonForm.isInstallment,
|
isInstallment: form.isInstallment ?? '0',
|
||||||
totalPhases: commonForm.isInstallment === '1' ? commonForm.totalPhases : 1,
|
totalPhases: isInstallment ? (Number(form.totalPhases) || 1) : 1,
|
||||||
supplierName: commonForm.supplierName,
|
supplierName: String(form.supplierName ?? ''),
|
||||||
supplierContact: commonForm.supplierContact,
|
supplierContact: String(form.supplierContact ?? ''),
|
||||||
purchaserId: commonForm.purchaserId,
|
purchaserId: String(form.purchaserId ?? ''),
|
||||||
purchaserName: commonForm.purchaserName,
|
purchaserName: String(form.purchaserName ?? ''),
|
||||||
assetAdminId: commonForm.assetAdminId,
|
assetAdminId: String(form.assetAdminId ?? ''),
|
||||||
assetAdminName: commonForm.assetAdminName,
|
assetAdminName: String(form.assetAdminName ?? ''),
|
||||||
})
|
})
|
||||||
useMessage().success('保存成功')
|
useMessage().success('保存成功')
|
||||||
await loadData()
|
await loadData()
|
||||||
@@ -283,11 +321,25 @@ const saveCommonConfig = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const saveCurrentBatch = async () => {
|
const saveCurrentBatch = async () => {
|
||||||
|
const curBatch = Number(activeTab.value)
|
||||||
|
const batchFormRef = batchFormRefMap.value[curBatch]
|
||||||
|
const valid = await batchFormRef?.validate?.().catch(() => false)
|
||||||
|
if (!valid) return
|
||||||
|
|
||||||
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
const b = batches.value.find((x: any) => String(x.batch) === activeTab.value)
|
||||||
if (!b?.id) return
|
if (!b?.id) return
|
||||||
const form = batchForms[Number(activeTab.value)]
|
const form = batchForms[curBatch]
|
||||||
if (!form) return
|
if (!form) return
|
||||||
|
|
||||||
|
if (!form.acceptType) {
|
||||||
|
useMessage().error('请选择验收方式')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!form.acceptDate) {
|
||||||
|
useMessage().error('请选择验收日期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const team = (form.acceptTeam || []).filter((m: any) => m?.name)
|
const team = (form.acceptTeam || []).filter((m: any) => m?.name)
|
||||||
if (team.length < 3 || team.length % 2 === 0) {
|
if (team.length < 3 || team.length % 2 === 0) {
|
||||||
useMessage().error('验收小组至少3人且为单数')
|
useMessage().error('验收小组至少3人且为单数')
|
||||||
@@ -320,13 +372,50 @@ const handleClose = () => {
|
|||||||
emit('refresh')
|
emit('refresh')
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = (row: any) => {
|
const DEFAULT_COMMON_FORM = {
|
||||||
|
hasContract: '0',
|
||||||
|
contractId: '',
|
||||||
|
isInstallment: '0',
|
||||||
|
totalPhases: 1,
|
||||||
|
supplierName: '',
|
||||||
|
supplierContact: '',
|
||||||
|
purchaserId: '',
|
||||||
|
purchaserName: '',
|
||||||
|
assetAdminId: '',
|
||||||
|
assetAdminName: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将弹窗内所有内容恢复为初始空值(替换整个对象以确保引用变化) */
|
||||||
|
const resetAllToDefault = () => {
|
||||||
|
openToken.value++
|
||||||
|
commonForm.value = { ...DEFAULT_COMMON_FORM }
|
||||||
|
applyInfo.value = null
|
||||||
|
mainTab.value = 'common'
|
||||||
|
activeTab.value = '1'
|
||||||
|
batchFormRefMap.value = {}
|
||||||
|
batches.value = []
|
||||||
|
acceptanceItems.value = []
|
||||||
|
canFillForm.value = true
|
||||||
|
Object.keys(batchForms).forEach((k) => delete batchForms[Number(k)])
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = async (row: any) => {
|
||||||
purchaseId.value = row?.id ?? ''
|
purchaseId.value = row?.id ?? ''
|
||||||
rowProjectType.value = row?.projectType || 'A'
|
rowProjectType.value = row?.projectType || 'A'
|
||||||
|
|
||||||
|
// 1. 先将弹窗内所有内容恢复为初始空值
|
||||||
|
resetAllToDefault()
|
||||||
|
|
||||||
|
// 2. 显示弹窗并开启 loading,避免接口返回前展示旧数据
|
||||||
visible.value = true
|
visible.value = true
|
||||||
batches.value = []
|
loading.value = true
|
||||||
Object.keys(batchForms).forEach((k) => delete batchForms[Number(k)])
|
|
||||||
nextTick(() => loadData())
|
// 3. 等待 Vue 完成渲染,确保子组件已接收并展示空值
|
||||||
|
await nextTick()
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
// 4. 再进行接口查询并覆盖
|
||||||
|
await loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
@@ -337,6 +426,7 @@ defineExpose({ open })
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
.main-tab-nav {
|
.main-tab-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -403,3 +493,10 @@ defineExpose({ open })
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 弹窗横向滚动修复,需非 scoped 以影响 el-dialog */
|
||||||
|
.purchasing-accept-modal .el-dialog__body {
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user