<!--
 * @Description: file content
 * @Author: RongWei
 * @Date: 2020-07-02 16:17:22
 * @LastEditors: RongWei
 * @LastEditTime: 2020-07-10 17:53:02
--> 

##### 功能说明

依赖FormChef实现的自定义多列可编辑表格表单，高阶组件。  
作为二级表单使用的话，推荐 TableField

<!-- 选择添加 -->

##### 使用说明

```js static
import { FormDish, WebFormFood，EditableTable as HocEditableTable } from 'maycur-business'; 
import fieldMaps from 'xx/FormFields'; //引入字段映射关系表
//构建FieldFood，WebFormFood为适用于web端的表单字段容器。
const FieldFood = FormDish(WebFormFood, { fieldMaps }); 
const EditableTable = HocEditableTable({ FieldFood }); 
const formFields = [{{

    identifier: 'name',
    type: 'SingleTextInput',
    property: {
        label: '名称',
        isFieldHide: false,
        required: true,
        placeholder: '请输入名称',
    }

}}]; // 跟表单内formFields一样的结构

export default function (props) {

    const [value, setValue] = useState([]);

    const onAdd = () => { };

    const onDelete = (index) => { };

    const onChange = (newValue) => { };

    const addExtraColumns = (formFields) => { };

    return (
        <>
            <Button type="primary" onClick={onAdd}>添加一行</Button>
            <EditableTable
                formFields={formFields}
                value={value}
                onChange={onChange}
                addExtraColumns={addExtraColumns}
            />
        </>
    );

}

``` 

<!-- 分隔符 -->
***
<!-- 必须 -->

##### 代码演示

###### 基本使用

```jsx
import React, { useState } from 'react';
import { Button } from 'maycur-antd';
import WebFormFood from '../WebFormFood/FormFood';
import FormDish from '../FormDish/FormDish';
import fields from '../FormFields';
import HocEditableTable from './EditableTable';
import utils from '../utils/utils';

const { InputField, MoneyField } = fields;
const fieldMaps = {
    SingleTextInput: InputField,
    AmountInput: MoneyField,
};

const FieldFood = FormDish(WebFormFood, { fieldMaps });
const EditableTable1 = HocEditableTable({ FieldFood });
const formFields = [{
    identifier: 'name',
    type: 'SingleTextInput',
    property: {
        label: '名称',
        isFieldHide: false,
        required: true,
        placeholder: '请输入名称',
    }
}, {
    identifier: 'schedules',
    type: 'AmountInput',
    property: {
        label: '金额',
        required: true,
        isFieldHide: false,
        placeholder: '请输入金额'
    }
}, {
    identifier: 'name2',
    type: 'SingleTextInput',
    property: {
        label: '名称2',
        isFieldHide: false,
        required: true,
        placeholder: '请输入名称2',
    }
}, {
    identifier: 'schedules2',
    type: 'AmountInput',
    property: {
        label: '金额2',
        required: true,
        isFieldHide: false,
        placeholder: '请输入金额2'
    }
}];
const [value, setValue] = useState([]);

const onAdd = () => {
    setValue([...value, { key: utils.makeId() }]);
};

const onDelete = (index) => {
    let _value = [...value];
    if (index > -1) {
        _value.splice(index, 1);
    }
    setValue(_value)
};

const onChange = (newValue) => {
    setValue(newValue);
};

const addExtraColumns = (formFields) => {
    formFields.unshift({
        identifier: 'sequence',
        editable: false,
        width: 80,
        property: { label: '序号' },
        render: (value, row, index) => {
            return index + 1;
        }
    });
    formFields.push({
        identifier: 'opt',
        editable: false,
        width: 80,
        property: { label: '操作', },
        render: (value, row, index) => {
            return <span onClick={onDelete.bind(null, index)}>删除</span>
        }
    });
    return formFields;
};

(
    <>
        <Button type="primary" onClick={onAdd}>添加一行</Button>
        <EditableTable1
            formFields={formFields}
            value={value}
            onChange={onChange}
            addExtraColumns={addExtraColumns}
        />
    </>
);
```

###### 表头拆分

***需要为 column 提供 children 字段***

``` jsx
import React, { useState } from 'react';
import { Button } from 'maycur-antd';
import WebFormFood from '../WebFormFood/FormFood';
import FormDish from '../FormDish/FormDish';
import fields from '../FormFields';
import HocEditableTable from './EditableTable';
import utils from '../utils/utils';

const { InputField, MoneyField } = fields;
const fieldMaps = {
    SingleTextInput: InputField,
    AmountInput: MoneyField,
};

const FieldFood = FormDish(WebFormFood, { fieldMaps });
const EditableTable2 = HocEditableTable({ FieldFood });
const formFields = [{
    identifier: 'name',
    property: { label: '名称' },
    children: [{
        identifier: 'name_1',
        type: 'SingleTextInput',
        property: {
            isFieldHide: false,
            required: true,
            placeholder: '请输入名称',
            label: '名称1'
        }
    }, {
        identifier: 'name_2',
        type: 'SingleTextInput',
        property: {
            isFieldHide: false,
            required: true,
            placeholder: '请输入名称',
            label: '名称2'
        }
    }]
}, {
    identifier: 'schedules',
    property: { label: '金额' },
    children: [{
        identifier: 'schedules_1',
        type: 'AmountInput',
        property: {
            label: '金额1',
            required: true,
            isFieldHide: false,
            placeholder: '请输入金额'
        }
    }, {
        identifier: 'schedules_2',
        type: 'AmountInput',
        property: {
            label: '金额2',
            required: true,
            isFieldHide: false,
            placeholder: '请输入金额'
        }
    }]
}];

const [value, setValue] = useState([]);

const onAdd = () => {
    setValue([...value, { key: utils.makeId() }]);
};

const onDelete = (index) => {
    let _value = [...value];
    if (index > -1) {
        _value.splice(index, 1);
    }
    setValue(_value)
};

const onChange = (newValue) => {
    setValue(newValue);
};

const addExtraColumns = (formFields) => {
    formFields.unshift({
        identifier: 'sequence',
        editable: false,
        width: 80,
        property: { label: '序号' },
        render: (value, row, index) => {
            return index + 1;
        }
    });
    formFields.push({
        identifier: 'opt',
        editable: false,
        width: 80,
        property: { label: '操作', },
        render: (value, row, index) => {
            return <span onClick={onDelete.bind(null, index)}>删除</span>
        }
    });
    return formFields;
};

(
    <>
        <Button type="primary" onClick={onAdd}>添加一行</Button>
        <EditableTable2
            formFields={formFields}
            value={value}
            onChange={onChange}
            addExtraColumns={addExtraColumns}
        />
    </>
);

```

###### 表格行合并

***在添加和删除数据时，需要对数据进行特殊处理***

``` jsx
import React, { useState } from 'react';
import { Button } from 'maycur-antd';
import WebFormFood from '../WebFormFood/FormFood';
import FormDish from '../FormDish/FormDish';
import fields from '../FormFields';
import HocEditableTable from './EditableTable';
import { map,findIndex } from 'lodash';
import utils from '../utils/utils';

const { InputField, MoneyField } = fields;
const fieldMaps = {
    SingleTextInput: InputField,
    AmountInput: MoneyField,
};

const FieldFood = FormDish(WebFormFood, { fieldMaps });
const EditableTable3 = HocEditableTable({ FieldFood });
const lengthOfRowMerge = 2;
const formFields = [{
    identifier: 'name',
    property: { label: '名称' },
    children: [{
        identifier: 'name_1',
        type: 'SingleTextInput',
        property: {
            isFieldHide: false,
            required: true,
            placeholder: '请输入名称',
            label: '名称1'
        }
    }, {
        identifier: 'name_2',
        type: 'SingleTextInput',
        property: {
            isFieldHide: false,
            required: true,
            placeholder: '请输入名称',
            label: '名称2'
        }
    }]
}, {
    identifier: 'schedules',
    property: { label: '金额' },
    children: [{
        identifier: 'schedules_1',
        type: 'AmountInput',
        property: {
            label: '金额1',
            required: true,
            isFieldHide: false,
            placeholder: '请输入金额'
        }
    }, {
        identifier: 'schedules_2',
        type: 'AmountInput',
        property: {
            label: '金额2',
            required: true,
            isFieldHide: false,
            placeholder: '请输入金额'
        }
    }]
}];

const [value, setValue] = useState([]);

const onAdd = () => {
    const arr = new Array(lengthOfRowMerge);
    const rowIndex = utils.makeId();
    const data = map(arr, () => ({ key: utils.makeId(), rowIndex }));
    setValue([
        ...value,
        ...data
    ]);
};

const onDelete = (row) => {
    let _value = [...value];
    const index = findIndex(value, v => v.rowIndex === row.rowIndex);
    if (index > -1) {
        _value.splice(index, 2);
    }
    setValue(_value)
};

const onChange = (newValue) => {
    setValue(newValue);
};

const addExtraColumns = (formFields) => {
    formFields.unshift({
        identifier: 'sequence',
        editable: false,
        width: 80,
        property: { label: '序号' },
        render: (value, row, index) => {
            return index / lengthOfRowMerge + 1;
        }
    });
    formFields.push({
        identifier: 'opt',
        editable: false,
        width: 80,
        property: { label: '操作', },
        render: (value, row) => {
            return <span onClick={onDelete.bind(null, row)}>删除</span>
        }
    });
    return formFields;
};

(
    <>
        <Button type="primary" onClick={onAdd}>添加一行</Button>
        <EditableTable3
            formFields={formFields}
            value={value}
            onChange={onChange}
            addExtraColumns={addExtraColumns}
            lengthOfRowMerge={lengthOfRowMerge}
            mergeColmns={['sequence', 'opt']}
        />
    </>
);

```

***
<!-- 必须 -->

##### API

##### options

高阶组件的入参 options

| 参数 | 说明 | 类型 | 默认值 | 是否必传 |
| --- | --- | ---- | ----- | ------- |
| options.FieldFood | FormChef的FormDish实例化对象 | - | - | 是 |

##### EditableTable 组件 props

| 参数 | 说明 | 类型 | 默认值 | 
| --- | --- | ---- | ----- |
| value | 表格数据源 | any[] | [] | 
| formFields | 表格列，结构与自定义表单内的formFields结构基本一致 | any[] | [] | 
| rowKey | 表格行 key 的取值，可以是字符串或一个函数 | string\|Function(record):string | 'key' |
| bordered | 是否展示外边框和列边框	| boolean | false |
| addExtraColumns | 为表格增加额外列；如序号、操作列 | Function(formFields):any[] | - |
| setCustomWidth | 设置表格列宽 | Function(field):number | - |
| lengthOfRowMerge | 表格行合并时，需要设置几行合并为一行；如Demo3中，每增加一行都会将两行合并为一行，则该值为2 | number | - |
| mergeColmns | 需要进行行合并的列；如Demo3中，每增加一行都将序号和操作列进行了行合并，其他列未进行合并 | string[] | - |
| privateProps | 为每一列组件传入对应的props | object | - |
| rowsPrivateProps | 为每一行中每一列组件传入对应的props | [{ rowKey:string, privateProps:object }] | - |
| genPreFormulas|生成每一行的自定义联动规则,公式规则，请参考formchef对联动规则的定义|Function|-|
|brandNewRowKeys|table中属于新建行的数据RowKeys集合，用于判定行对应的表单是否是新建的状态|array|-|

###### formFields 中单个 field

以下只列出与单据中 formFields结构不同的部分  

| 参数 | 说明 | 类型 | 默认值 | 
| --- | --- | ---- | ----- |
| editable | 列是否可编辑；如序号删除列需传false | boolean | true |
| children | 表格头列拆分 | field | - |
| width | 列宽，也可以通过 setCustomWidth 设置 | number | 200 |

###### addExtraColumns 使用示例

```js static
const addExtraColumns = (formFields) => {
    formFields.unshift({
        identifier: 'sequence',
        editable: false,
        width: 80,
        property: { label: '序号' },
        render: (value, row, index) => {
            return index / lengthOfRowMerge + 1;
        }
    });
    formFields.push({
        identifier: 'opt',
        editable: false,
        width: 80,
        property: { label: '操作', },
        render: (value, row) => {
            return <span onClick={onDelete.bind(null, row)}>删除</span>
        }
    });
    return formFields;
};

``` 

###### privateProps 结构

```js static
/* 
 * 会为表格中所有 identifier 为 coverDepartment 的组件传入 userCode 属性, 
 * 所有 identifier 为 details 的组件传入 type 属性
 */
{

    coverDepartment: {
        userCode: 'XX'
    },
    details: {
        type: 'XX'
    }

}
```

###### rowsPrivateProps 结构

```js static
/* 
 * 分别为表格中 rowKey 为 ‘001’和‘002’ 的行中， identifier 为 coverDepartment 的组件传入对应的 userCode 属性,
 * identifier 为 details 的组件传入对应的 type 属性
 */
[{
    rowKey: '001',
    privateProps: {
        coverDepartment: {
            userCode: 'XX'
        },
        details: {
            type: 'XX'
        }
    }
}, {
    rowKey: '002',
    privateProps: {
        coverDepartment: {
            userCode: 'XX'
        },
        details: {
            type: 'XX'
        }
    }
}]
```

##### tableValidation

组件实例方法，可通过 ref 调用对 EditableTable 进行校验，返回 promise。
