## fieldMap
存放表单中每一个表单域的 type 和组件的映射关系。如：
|表单域type|对应组件|描述
|--|--|--
|SingleTextInput|MkInput|单行文本输入框
|ExpenseTypeInput|ExpenseTypeInput|费用类型选择组件
|OptionInput|{ MANUAL: 'MkSelect', DataSource: 'OptionInput'}|选项组组件。选项组的选项分为手动输入和数据源导入。Manual对应手动输入情况下的选项组组件，DataSource对应数据源导入情况下的选项组组件
|CityInput|{ SINGLE: 'CityInput', PAIR: 'CityPairPicker' }|城市选择组件。城市组件分为单个城市和起止城市两种模式。Single对应单个城市的组件，PAIR对应起止城市模式的组件。

## FormDish
主要用来进行表单域的渲染。
根据 fieldMap 中的映射关系，映射出对应的组件。并传入相应的props，设置相应的校验规则

### 高阶组件 
接收两个参数 WrapperComponent 和 options，返回由 WrapperComponent 包裹着的 node, options 作为 props 传入 WrapperComponent 中使用。
WrapperComponent 主要用于显示组件的 label、错误信息等，web 端可直接传入 antd 的 Form.Item
```jsx static
function enhanceFormItem(WrapperComponent, options) {
  const node = getFieldDecorator(identifier, { rules })(
    <Field
    fieldProperties={property}
    fieldProps={fieldProps}
    extraProps={extraProps}
    disabled={disabled}
    readOnly={readOnly}
    />
  );
  return WrapperComponent ? (
    <WrapperComponent
      field={field}
      form={form}
    >
      {node}
    </WrapperComponent>
  ) : node 
}
```
### props传值
- property 为表单 scheme 中相应的设置，包括 placeholder、required、label、webSize等。
- extraProps：自定义props，有其他业务逻辑需要传入 Field 中的 props

|name|说明|其他|
|--|--|--|
|fieldProperties|为表单 scheme 中相应相应field.property属性，包括 placeholder、required、label、webSize等||
|fieldProps|为表单 scheme 中相应相应field的属性（不包括二级属性）||
|extraProps|自定义props，有其他业务逻辑需要传入||
|fieldForm|表单实例（部分继承）,当前继承getFieldValue,setWatch,getFormFieldByName|包括的表单实例功能有（getFieldValue）|
|disabled|失效标示||
|readOnly|只读标示||


***表单域经过 antd 中 Form.create() 处理后的表单具有自动收集数据并校验的功能，会自带 this.props.form 的属性。getFieldDecorator 用于和表单进行双向绑定，不用显式的传入 value 和 onChange。***
```jsx static
// FormDish 组件接收的 props
// setFieldMap 用于设置组件与schema 中 type 的映射关系
// setValidator 用于设置自定义校验方法
<FormDish
    field={field}
    publicProps={publicProps}
    privateProps={privateProps}
    form={form}
    setFieldMap={setFieldMap}
    setValidator={setValidator}
/>
```
FormDish 代码实现
```jsx static
// extraProps
generatetProps = () => {
  const {
    publicProps = {},
    privateProps = {},
    form,
    field,
    ...restProps
  } = this.props;
  let props = {
    ...publicProps,
    ...privateProps,
    ...restProps
  };
  return props;
}
// fieldProps
filterFieldProps = () => {
  // 若需要 field 中的 type, identifier 等作为props，可在此返回
  // const { field: { type } } = this.props;
  return {};
}
generateNode = () => {
    const { 
    field: { type, identifier }, 
    form: { getFieldDecorator } 
  } = this.props;
  const { property } = field;
  const Field = fieldMap[type];
  const extraProps = this.generatetProps();
  const fieldProps = this.filterFieldProps();
  const rules = this.generatetRules();
  return getFieldDecorator(identifier, {
    rules
  })(
    <Field
      {...property}
      {...fieldProps}
      extraProps={extraProps}
    />
  )
}
render() {
    const { field: { property } } = this.props;
  const { isFieldHide } = property;
  return isFieldHide ? null : this.generateNode()
}
```
### validator
通过 setValidator 方法返回组件所需的所有自定义校验方法，方法命名规则为 `validate${type}`，如下：
```jsx static
export default {
    validateRatioInput: validateNumericalValue,
    validateAmountInput: validateNumericalValue,
    validateMoneyAdjust: validateNumericalValue,
    validateDateTimeInput,
    validateCityInput,
    validateAccountInput,
    validateCollectionAccountInput: validateAccountInput,
    validateInvoiceInput,
    validateTableInput: validateDetailTable
};
```
在 generateRules 中，同样通过 type 来匹配相应的校验方法
```jsx static
const rules = [];
const rule = { required };
if (this.validators[`validate${type}`]) {
  rule.validator = this.customValidator;
}
rules.push(rule);
```
### FormFood

props说明

|name|说明|其他|
|--|--|--|
|field|表单scheme中的配置信息||
|form|formchef实例|参考formchef的api说明|
|isInTable|是否table类型的表单|table类型表单通常是二级表，在实现上，跟正常的表单会不一样|

FormFood需要实现表单的label，必填的标识，表单校验信息的显示等一致性的UI控制。

案例代码
```jsx static
  function FormItem(props) {
    const {
        field: { property, type, extra, identifier },
        children,
        form,
        isInTable
    } = props;

    const { label, webSize, required } = property;//获取label,必填标识
    let _label = label;
    let hasSplit = false;
    let labelClz = classnames(`${cmClzName}-label`, {
        'complex': complexFields.includes(type),
        'required': required
    });
    if (isInTable || specialFields.includes(type)) {
        _label = null;
    }
    //table类型的表单通常在UI上，会有很大区别，所以在UI做额外处理
    if ((isInTable || specialFields.includes(type)) || complexFields.includes(type)) {
        hasSplit = true;
    }
    const errMsg = form.getFieldError(identifier);//获取错误信息
    const Wrap = isInTable ? React.Fragment : Col;
    const wrapProps = isInTable ? {} : {
        span: 24 * webSize,
        className: `mk-col ${errMsg ? 'has-err' : ''}`,
    }//控制页面元素布局
    return (
        <Wrap {...wrapProps}>
            {hasSplit ? <div className={`${cmClzName}-split`}></div> : null}
            <div className={cmClzName}>
                {_label ?
                    <div className={`${cmClzName}-header`}>
                        <div className={labelClz}>{_label}</div>
                        <div className={`${cmClzName}-header_extra`}>
                            {extra}
                        </div>
                    </div> : null
                }
                <div className={`${cmClzName}-body`}>
                    <div>
                        {children}
                        {!!errMsg && <span className={`${cmClzName}-error`}>{errMsg}</span>}
                    </div>
                </div>
            </div>
        </Wrap>
    )
  }
```