具体需求是:
1 根据后台数据动态生成表单项
2 表单项可以编辑和增减,提交保存数据到后台
大概界面如下:
对于需求1,找了下基本通过map枚举,配合getFieldDecorator
对于需求2,如果编辑过程中,增减表单项,将造成正在编辑的表单数据丢失的情况,如下:
没找到完整的解决方案,自己摸索了下,通过onValuesChange监听所有表单改动,更新state来保存实时编辑的.
还有一个问题是,对于编辑过的表单,即使数据更新了,表单还是不会刷新(重新渲染),如在tab切换时,因为所有两个tab的key是一样的,如果在左边某个表单做了编辑,切换到右边tab时,对应的表单就不会数据变化了,如下:
下面是实现的代码:
组件加载完后去获取后台数据:
componentDidMount() {
const { dispatch } = this.props;
const {activeKey} = this.state;
dispatch({
type: 'brokage/fetchTable',
paylaod:{Category:activeKey},
});
}
render函数,根据后台数据渲染表单:
render() {
const limitDecimals = value => {
const reg = /^(\-)*(\d+)\.(\d\d).*$/;
if (typeof value === 'string') {
return !isNaN(Number(value)) ? value.replace(reg, '$1$2.$3') : '';
} else if (typeof value === 'number') {
return !isNaN(value) ? String(value).replace(reg, '$1$2.$3') : '';
} else {
return '';
}
};
const {
brokage: { table },
loading,
} = this.props;
const { getFieldDecorator } = this.props.form;
return (
<PageHeaderWrapper
title="佣金设置"
content="佣金规则最少两条,价格必须递增,最后一条规则为佣金上限"
>
<Form onSubmit={this.handleSubmit}>
<Tabs defaultActiveKey="1" onChange={this.HandChangePane}>
<TabPane
tab={
<span>
<Icon type="user" />
客户佣金设置
</span>
}
key="1"
>
<Card bordered={false}>
<div>
{table.data &&
table.data.map((element, index) => (
<span key={index}>
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 64 }}>
<Col span={6}>
<FormItem label="单价小于" {...this.formLayout}>
{getFieldDecorator(`price${index}`, {
initialValue: element.Max,
rules: [
{
required: true,
message: '请输入价格,只能输入数字,小数最多两位',
},
],
})(
<InputNumber
min={0}
step={0.01}
formatter={limitDecimals}
parser={limitDecimals}
placeholder="请输入价格上限"
/>
)}
</FormItem>
</Col>
<Col md={5} sm={10}>
<FormItem label="佣金" {...this.formLayout}>
{getFieldDecorator(`brokage${index}`, {
initialValue: element.Brokerage,
rules: [
{
required: true,
message: '请输入佣金,只能输入数字,小数最多两位',
},
],
})(
<InputNumber
key={{ index }}
min={0}
step={0.01}
size={40}
formatter={limitDecimals}
parser={limitDecimals}
placeholder="请输入佣金"
/>
)}
</FormItem>
</Col>
<Col md={4} sm={24}>
{index > table.data.length - 2 && (
<Button
shape="circle"
size="small"
icon="plus"
type="primary"
onClick={() => this.addTag()}
/>
)}
{index > 1 && (
<Button
shape="circle"
size="small"
icon="minus"
type="default"
onClick={() => this.removeTag(index)}
/>
)}
</Col>
</Row>
</span>
))}
</div>
</Card>
</TabPane>
<TabPane
tab={
<span>
<Icon type="shop" />
商家佣金设置
</span>
}
key="2"
>
<Card bordered={false}>
<div>
{table.data &&
table.data.map((element, index) => (
<span key={index}>
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 64 }}>
<Col span={6}>
<FormItem label="单价小于" {...this.formLayout}>
{getFieldDecorator(`price${index}`, {
initialValue: element.Max,
rules: [
{
required: true,
message: '请输入价格,只能输入数字,小数最多两位',
},
],
})(
<InputNumber
// disabled={index != table.data.length - 1 ? false : true}
min={0}
step={0.01}
formatter={limitDecimals}
parser={limitDecimals}
placeholder="请输入价格上限"
/>
)}
</FormItem>
</Col>
<Col md={5} sm={10}>
<FormItem label="佣金" {...this.formLayout}>
{getFieldDecorator(`brokage${index}`, {
initialValue: element.Brokerage,
rules: [
{
required: true,
message: '请输入佣金,只能输入数字,小数最多两位',
},
],
})(
<InputNumber
key={{ index }}
min={0}
step={0.01}
size={40}
formatter={limitDecimals}
parser={limitDecimals}
placeholder="请输入佣金"
/>
)}
</FormItem>
</Col>
<Col md={4} sm={24}>
{index > table.data.length - 2 && (
<Button
shape="circle"
size="small"
icon="plus"
type="primary"
onClick={() => this.addTag()}
/>
)}
{index > 1 && (
<Button
shape="circle"
size="small"
icon="minus"
type="default"
onClick={() => this.removeTag(index)}
/>
)}
</Col>
</Row>
</span>
))}
</div>
</Card>
</TabPane>
</Tabs>
<div style={{ overflow: 'hidden' }}>
<div style={{ float: 'left', marginBottom: 24 }}>
<Button type="primary" htmlType="submit" >
保存
</Button>
</div>
</div>
</Form>
</PageHeaderWrapper>
);
添加表单项处理:
addTag() {
const { dispatch, brokage } = this.props;
let data = brokage.table.data || [];
let count = brokage.table.count || 0;
data = data.concat({ Brokerage: 0, Max: 0 });
count = count + 1;
dispatch({
type: 'brokage/updateTable',
payload: { data: data, count: count },
});
}
对应model处理是,其实就是在table的data末尾附加新元素,触发表单重新渲染:
effects: {
*updateTable({ payload }, { select, call, put }) {
yield put({
type: 'update',
payload: payload,
});
},
....
reducers: {
update(state, action) {
if (action.payload.count === 0 || !action.payload.data) {
let data = [];
data = data.concat({ Brokerage: 0, Max: 0 }, { Brokerage: 0, Max: 0 });
return {
...state,
table: { data: data, count: 2 },
};
}
return {
...state,
table: action.payload,
};
},
....
删除表单项处理:
removeTag(index) {
const { dispatch, brokage } = this.props;
let data = brokage.table.data;
let count = brokage.table.count;
if (count === 0 || data.length === 0) {
return;
}
// can use data-binding to set
data.splice(index, 1);
count = count - 1;
dispatch({
type: 'brokage/updateTable',
payload: { data: data, count: count },
});
}
对应model处理,和添加表单项处理是一样的。
数据编辑实时更新到state,这里比较粗暴,把表单项数据枚举一遍,赋值的state:
@Form.create({
onValuesChange(props, changedValues, allValues) {
// 表单项变化时请求数据
const { dispatch, brokage } = props;
let data = [];
let count = brokage.table.count;
for (let i = 0; i < count; i++) {
data = data.concat({ Brokerage: allValues[`brokage${i}`], Max: allValues[`price${i}`] });
}
// 更新state
dispatch({
type: 'brokage/updateTable',
payload: { data: data, count: count },
});
},
})
还有一个就是,表单项编辑后,切换tab,后台数据更新,表单项也也不更新问题,只需reset一下表单就行了:
HandChangePane(key){
const { dispatch } = this.props;
//重置表单
this.props.form.resetFields();
let activeKey=0;
if(key=="1"){
activeKey=0;
}else{
activeKey=1;
}
this.setState({activeKey:activeKey});
setTimeout(function(){
dispatch({
type: 'brokage/fetchTable',
payload:{Category:activeKey},
});
},10);
}