Files
school-developer/src/views/finance/purchasingrequisition/accept/AcceptBatchForm.vue
2026-02-24 18:16:00 +08:00

318 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="160px" >
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="验收方式" prop="acceptType">
<el-radio-group v-model="form.acceptType" :disabled="readonly">
<el-radio label="1" :disabled="!canFill">填写履约验收评价表</el-radio>
<el-radio label="2">上传履约验收评价表</el-radio>
</el-radio-group>
<div v-if="!canFill" class="el-form-item__tip">金额30万仅支持上传模版</div>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="验收日期" prop="acceptDate">
<el-date-picker
v-model="form.acceptDate"
type="date"
placeholder="请选择"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 100%"
:disabled="readonly"
/>
</el-form-item>
</el-col>
<!-- 填报方式验收内容表格 -->
<template v-if="form.acceptType === '1' && canFill">
<el-col :span="12" class="mb20">
<el-form-item label="验收内容" prop="acceptContents">
<el-table :data="form.acceptContents" border size="small" class="accept-content-table">
<el-table-column prop="itemName" label="验收项" >
<template #default="{ row }">
<div>
<span>{{row.itemName}}</span>
<el-input
v-if="row.type === 'input'"
v-model="row.remark"
placeholder="请输入"
size="small"
:disabled="readonly"
/>
</div>
</template>
</el-table-column>
<el-table-column prop="isQualified" label="合格/不合格" align="center">
<template #default="{ row }">
<el-radio-group v-model="row.isQualified" size="small" :disabled="readonly">
<el-radio label="1">合格</el-radio>
<el-radio label="0">不合格</el-radio>
</el-radio-group>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-col>
</template>
<!-- 上传方式 -->
<template v-if="form.acceptType === '2'">
<el-col :span="12">
<el-form-item label="履约验收模版" prop="templateFileIds">
<UploadFile
v-model="templateFileIdsStr"
:limit="1"
:data="{ purchaseId: purchaseId || '', fileType: '110' }"
upload-file-url="/purchase/purchasingfiles/upload"
:disabled="readonly"
/>
</el-form-item>
</el-col>
</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-form-item label="验收小组" prop="acceptTeam">
<div class="team-list">
<div v-for="(m, idx) in form.acceptTeam" :key="idx" class="team-row">
<el-select
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>
</div>
<el-button v-if="!readonly" type="primary" link size="small" @click="addTeam">+ 增加成员</el-button>
</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-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入" :disabled="readonly" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
const props = withDefaults(
defineProps<{
modelValue: Record<string, any>
canFill: boolean
readonly?: boolean
purchaseId?: string
acceptanceItems?: any[]
batchNum?: number
previousBatchesTeams?: { batch: number; team: any[] }[]
}>(),
{ readonly: false, canFill: true, purchaseId: '', batchNum: 1, previousBatchesTeams: () => [] }
)
const emit = defineEmits(['update:modelValue'])
const formRef = ref<FormInstance>()
const templateFileIdsStr = ref('')
const copyFromBatch = ref<number | null>(null)
const form = reactive({
acceptType: '1',
acceptDate: '',
acceptContents: [] as any[],
acceptTeam: [
{ name: '', deptCode: '', deptName: '', roleType: '' },
{ name: '', deptCode: '', deptName: '', roleType: '' },
{ name: '', deptCode: '', deptName: '', roleType: '' },
] as any[],
templateFileIds: [] as string[],
acceptAddress: '',
question: '',
remark: '',
...props.modelValue,
})
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 })
// 金额≥30万时默认选中上传方式
watch(() => props.canFill, (val) => {
if (!val && form.acceptType === '1') {
form.acceptType = '2'
}
}, { immediate: true })
watch(() => props.acceptanceItems, (items) => {
if (items?.length && form.acceptContents.length === 0) {
form.acceptContents = items.map((it: any) => ({
configId: it.id,
itemName: it.itemName,
type: it.type,
isQualified: '1',
remark: '',
}))
}
}, { immediate: true })
watch(templateFileIdsStr, (s) => {
const arr = s ? s.split(',').map((x: string) => x.trim()).filter(Boolean) : []
if (JSON.stringify(form.templateFileIds) !== JSON.stringify(arr)) {
form.templateFileIds = arr
}
})
watch(() => form.templateFileIds, (arr) => {
if (Array.isArray(arr) && arr.length) templateFileIdsStr.value = arr.join(',')
}, { immediate: true, deep: true })
const addTeam = () => {
form.acceptTeam.push({ name: '', deptCode: '', deptName: '', roleType: '' })
}
const removeTeam = (idx: number) => {
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 || '',
roleType: m.roleType || '',
}))
}
copyFromBatch.value = null
}
const rules: FormRules = {
acceptType: [{ 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()
defineExpose({ validate, form })
</script>
<style scoped>
.mb20 {
margin-bottom: 20px;
}
.copy-from-inline {
display: inline-flex;
align-items: center;
gap: 6px;
margin-left: 4px;
}
.copy-from-inline :deep(.el-select) {
vertical-align: middle;
}
</style>