318 lines
10 KiB
Vue
318 lines
10 KiB
Vue
<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>
|