有时候我们会遇到一些复杂的需求,需要用Table嵌套Form.List,逐层嵌套渲染表格表单列表,填写完毕后提交的复杂需求。
由于表单项分布在数据的各个层级里,因此,如何回填表单值就成了一个比较棘手的问题,处理不好,很容易引发一些逻辑bug(例如表单重置后,数据回填、表单校验异常等)
其实,antd的form实例对象很强,只需要提供给它指定的field和索引i组成的formName(表单项名称)即可自动回填到表单项中,完全不需要人工干预去处理多层级的数据的,如果有需要转换数据结构,也可以先对form实例的指定表单属性进行数据处理,之后再赋值回该属性名即可。
...
// 初始化设置数据
useEffect(() => {
// 由于提交的字段格式和回显的字段格式不一致,这边就是进行数据属性的处理
const newData = reversalFormData(cloneDeep(data));
// 设置完毕进行重置表单属性值,也就是上面提到的对属性进行转换,也可以自定义对数据处理
form.setFieldsValue({
schemeId: newData.schemeId,
schemeList: newData.schemeList
});
}, [data, form]);
return
(<div className={styles.formWrap}>
<Form
form={form}
onValuesChange={onValuesChange}
layout='vertical'
>
<Form.Item
hidden
name='schemeId'
></Form.Item>
<BasicInfo
form={form}
data={data}
/>
<ApplyScope form={form} />
<WelfareInfo
form={form}
data={data}
/>
<div className={styles.footer}>
<Button
className={styles.confirm}
onClick={onSubmit}
type='primary'
style={{ marginRight: 8 }}
htmlType='submit'
>
确定
</Button>
<Button
className={styles.cancel}
onClick={onClose}
>
取消
</Button>
</div>
</Form>
</div>)
const columns = [
{
title: '基数(MOP)'
key: 'macaoCardinalityDictValue',
dataIndex: 'macaoCardinalityDictValue',
render: (text, record, index) => (
<SalaryBaseFormItem // 这个是Form.Item表单项的封装组件
name={['socialSchemeOptionalList', index, 'macaoCardinalityDictValue']}
label=''
countryRegionType='MO'
rules={[{ required: true, message: '请选择'}]}
selectProps={{
style: { width: 200 }
}}
/>
)
},
{
title: '基数上限',
key: 'cardinalityMaximum',
dataIndex: 'cardinalityMaximum',
render: (text, record, index) => (
<Form.Item
name={['socialSchemeOptionalList', index, 'cardinalityMaximum']}
rules={[
{ required: true, message: '' },
({ getFieldValue }) => ({
validator(_, value) {
// 这边包含了对表单项的自定义校验以及赋值的方式
const val = getFieldValue(['socialSchemeOptionalList', index, 'cardinalityMinimum']);
if (value < val) {
form.setFields([
{
name: ['socialSchemeOptionalList', index, 'cardinalityMinimum'],
errors: [intl.formatMessage({ id: 'LMID_00038092' })]
}
]);
return Promise.reject(new Error(intl.formatMessage({ id: 'LMID_00038093' })));
}
form.setFields([
{
name: ['socialSchemeOptionalList', index, 'cardinalityMinimum'],
errors: undefined
}
]);
return Promise.resolve();
}
})
]}
>
<AmountInputNumber
min={0}
placeholder={intl.formatMessage({ id: 'LMID_00003499' })}
/>
</Form.Item>
)
},
]
...
<Form.Item name={'tableKey'}>
<VVTable
bordered
columns={columns}
loading={loading}
dataSource={dataSource}
// pagination={{ innerPagination: true }}
sticky
scroll={{ x: 'max-content' }}
/>
</Form.Item>
return (
<div className={styles.mainlandWelfare}>
<Form.List name='socialSchemeChinaList'>
{(fields, { add, remove }) => (
<>
{fields.length ? (
<>
{fields.map((field) => {
// 删除户口类型模块
const onRemove = () => {
modal.confirm({
title: '确定删除?',
content: '删除后数据不可恢复,确定删除吗?',
closable: true,
onOk: () => {
form.validateFields([['socialSchemeChinaList', field.name, 'accountTypeMap']], {
recursive: true
});
remove(field.name);
message.success('删除成功');
}
});
};
return (
// 这是一个折叠面板,包含头部和内容区
<WelfareCollapse
items={[
{
key: '1',
label: (
<AccountType
form={form}
field={field}
/>
),
children: (
<WelfareTable
form={form}
field={field}
>
<Button
type='default'
block
onClick={onRemove}
disabled={fields.length <= 1}
>
删除
</Button>
</WelfareTable>
)
}
]}
></WelfareCollapse>
);
})}
<Button
className={styles.addAccountType}
type='link'
onClick={() => add({ details: [{}] })}
>
<Icon
icon='iconsystem_tips_line_3_circle-plus'
size={18}
/>
添加户口类型
</Button>
</>
) : null}
{!fields.length ? (
<div className={styles.empty}>
<Empty
image={Empty.NO_RELEASE}
description={'暂无信息'}
/>
<Button
type='primary'
onClick={() => add({ details: [{}] })}
>
添加户口类型
</Button>
</div>
) : null}
</>
)}
</Form.List>
{contextHolder}
</div>
);