履约验收

This commit is contained in:
吴红兵
2026-02-24 18:16:00 +08:00
parent d34d8d7e54
commit cdbd7147e9
3 changed files with 115 additions and 22 deletions

View File

@@ -74,13 +74,53 @@
</el-col> </el-col>
</template> </template>
<el-col :span="12" class="mb20">
<el-form-item label="验收地点" prop="acceptAddress">
<el-input v-model="form.acceptAddress" placeholder="请输入验收地点" :disabled="readonly" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="存在问题及改进意见" prop="question">
<el-input
v-model="form.question"
type="textarea"
:rows="2"
placeholder="请输入存在问题及改进意见"
:disabled="readonly"
/>
</el-form-item>
</el-col>
<!-- 验收小组 --> <!-- 验收小组 -->
<el-col :span="12"> <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">
<el-input v-model="m.name" placeholder="姓名" size="small" style="width:120px" :disabled="readonly" /> <el-select
<el-input v-model="m.deptName" placeholder="部门" size="small" style="width:160px" :disabled="readonly" /> v-model="m.roleType"
placeholder="身份"
size="small"
style="width: 130px; margin-right: 8px"
:disabled="readonly"
@change="(val) => onRoleChange(idx, val as string)"
>
<el-option label="组长(校内)" value="LEADER_IN" />
<el-option label="组长(校外)" value="LEADER_OUT" />
<el-option label="组员(校内)" value="MEMBER_IN" />
<el-option label="组员(校外)" value="MEMBER_OUT" />
</el-select>
<template v-if="m.roleType === 'LEADER_IN' || m.roleType === 'MEMBER_IN'">
<org-selector
v-model:orgList="m.userList"
type="user"
:multiple="false"
@update:orgList="(list: any[]) => onTeamUserChange(idx, list)"
/>
</template>
<template v-else>
<el-input v-model="m.name" placeholder="姓名" size="small" style="width:120px" :disabled="readonly" />
<el-input v-model="m.deptName" placeholder="单位/部门" size="small" style="width:160px" :disabled="readonly" />
</template>
<el-button v-if="!readonly && form.acceptTeam.length > 3" type="danger" link size="small" @click="removeTeam(idx)">删除</el-button> <el-button v-if="!readonly && form.acceptTeam.length > 3" type="danger" link size="small" @click="removeTeam(idx)">删除</el-button>
</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>
@@ -149,11 +189,13 @@ const form = reactive({
acceptDate: '', acceptDate: '',
acceptContents: [] as any[], acceptContents: [] as any[],
acceptTeam: [ acceptTeam: [
{ name: '', deptCode: '', deptName: '' }, { name: '', deptCode: '', deptName: '', roleType: '' },
{ name: '', deptCode: '', deptName: '' }, { name: '', deptCode: '', deptName: '', roleType: '' },
{ name: '', deptCode: '', deptName: '' }, { name: '', deptCode: '', deptName: '', roleType: '' },
] as any[], ] as any[],
templateFileIds: [] as string[], templateFileIds: [] as string[],
acceptAddress: '',
question: '',
remark: '', remark: '',
...props.modelValue, ...props.modelValue,
}) })
@@ -197,7 +239,7 @@ watch(() => form.templateFileIds, (arr) => {
}, { immediate: true, deep: true }) }, { immediate: true, deep: true })
const addTeam = () => { const addTeam = () => {
form.acceptTeam.push({ name: '', deptCode: '', deptName: '' }) form.acceptTeam.push({ name: '', deptCode: '', deptName: '', roleType: '' })
} }
const removeTeam = (idx: number) => { const removeTeam = (idx: number) => {
@@ -212,6 +254,7 @@ const onCopyFromBatch = (n: number | null) => {
name: m.name || '', name: m.name || '',
deptCode: m.deptCode || '', deptCode: m.deptCode || '',
deptName: m.deptName || '', deptName: m.deptName || '',
roleType: m.roleType || '',
})) }))
} }
copyFromBatch.value = null copyFromBatch.value = null
@@ -222,6 +265,37 @@ const rules: FormRules = {
acceptDate: [{ required: true, message: '请选择验收日期', trigger: 'change' }], acceptDate: [{ required: true, message: '请选择验收日期', trigger: 'change' }],
} }
const onRoleChange = (idx: number, val: string) => {
const isLeader = val === 'LEADER_IN' || val === 'LEADER_OUT'
if (isLeader) {
const hasOtherLeader = form.acceptTeam.some((m, i) =>
i !== idx && (m.roleType === 'LEADER_IN' || m.roleType === 'LEADER_OUT')
)
if (hasOtherLeader) {
// 只能有一个组长
form.acceptTeam[idx].roleType = ''
return
}
}
}
const onTeamUserChange = (idx: number, list: any[]) => {
const m = form.acceptTeam[idx]
if (!m) return
if (list && list.length) {
const u = list[0]
m.name = u.name || u.realName || ''
m.deptCode = u.deptCode || u.commonDeptCode || ''
m.deptName = u.deptName || u.commonDeptName || ''
m.userList = list
} else {
m.name = ''
m.deptCode = ''
m.deptName = ''
m.userList = []
}
}
const validate = () => formRef.value?.validate() const validate = () => formRef.value?.validate()
defineExpose({ validate, form }) defineExpose({ validate, form })

View File

@@ -94,17 +94,19 @@ const props = defineProps<{
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const purchaserList = ref<any[]>([])
const assetAdminList = ref<any[]>([])
const contractOptions = ref<any[]>([]) const contractOptions = ref<any[]>([])
const contractLoading = ref(false) const contractLoading = ref(false)
const contractLoaded = ref(false) const contractLoaded = ref(false)
const purchaserList = ref<any[]>([])
const assetAdminList = ref<any[]>([])
const form = reactive({ const form = reactive({
hasContract: '0', hasContract: '0',
contractId: '', contractId: '',
isInstallment: '0', isInstallment: '0',
totalPhases: 1, totalPhases: 1,
projectName: '',
deptName: '',
supplierName: '', supplierName: '',
supplierContact: '', supplierContact: '',
purchaserId: '', purchaserId: '',
@@ -116,6 +118,7 @@ const form = reactive({
const syncFormFromModel = (val: Record<string, any> | undefined) => { const syncFormFromModel = (val: Record<string, any> | undefined) => {
Object.assign(form, val || {}) Object.assign(form, val || {})
// 同步采购人员、资产管理员回 org-selector
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 {
@@ -168,6 +171,21 @@ watch(() => form.hasContract, (val) => {
} }
}) })
// 选择合同后,自动带出合同供应商名称
watch(
() => form.contractId,
(val) => {
if (!val) {
form.supplierName = ''
return
}
const c = contractOptions.value.find((it: any) => it.id === val)
if (c && c.supplierName) {
form.supplierName = c.supplierName
}
}
)
onMounted(() => { onMounted(() => {
if (form.hasContract === '1') { if (form.hasContract === '1') {
loadContractOptions() loadContractOptions()

View File

@@ -212,20 +212,16 @@ const loadData = async () => {
if (config?.common) { if (config?.common) {
applyInfo.value = config.common applyInfo.value = config.common
// 仅当存在已保存批次时,才用接口数据回填公共信息;否则保持 open() 中的默认清空值 // 仅当存在已保存批次时,才用接口数据回填公共信息;否则保持 open() 中的默认清空值
if (config?.batches?.length) { if (config?.batches?.length) {
Object.assign(commonForm.value, { Object.assign(commonForm.value, {
hasContract: config.common.hasContract || '0', hasContract: config.common.hasContract || '0',
contractId: config.common.contractId || '', contractId: config.common.contractId || '',
isInstallment: config.common.isInstallment || '0', isInstallment: config.common.isInstallment || '0',
totalPhases: config.common.totalPhases || 1, totalPhases: config.common.totalPhases || 1,
supplierName: config.common.supplierName || '', supplierName: config.common.supplierName || '',
supplierContact: config.common.supplierContact || '', 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'
@@ -273,6 +269,8 @@ const loadBatchDetails = async () => {
batchForms[b.batch] = { batchForms[b.batch] = {
acceptType: d.accept.acceptType || '1', acceptType: d.accept.acceptType || '1',
acceptDate: d.accept.acceptDate || '', acceptDate: d.accept.acceptDate || '',
acceptAddress: d.accept.acceptAddress || '',
question: d.accept.question || '',
remark: d.accept.remark || '', remark: d.accept.remark || '',
templateFileIds: d.accept.templateFileIds || [], templateFileIds: d.accept.templateFileIds || [],
acceptContents: (d.contents || []).map((c: any) => { acceptContents: (d.contents || []).map((c: any) => {
@@ -289,6 +287,7 @@ const loadBatchDetails = async () => {
name: t.name, name: t.name,
deptCode: t.deptCode, deptCode: t.deptCode,
deptName: t.deptName, deptName: t.deptName,
roleType: t.roleType || '',
})), })),
} }
if (batchForms[b.batch].acceptTeam.length < 3) { if (batchForms[b.batch].acceptTeam.length < 3) {
@@ -378,6 +377,8 @@ const saveCurrentBatch = async () => {
purchaseId: String(purchaseId.value), purchaseId: String(purchaseId.value),
acceptType: form.acceptType, acceptType: form.acceptType,
acceptDate: form.acceptDate, acceptDate: form.acceptDate,
acceptAddress: form.acceptAddress,
question: form.question,
remark: form.remark, remark: form.remark,
templateFileIds: form.templateFileIds || [], templateFileIds: form.templateFileIds || [],
acceptContents: form.acceptContents || [], acceptContents: form.acceptContents || [],