content: import React from 'react';
  import {
      Form,
      Input,
      Row,
      Col,
      Button,
      DatePicker,
      Select,
      Icon,
      Radio,
      InputNumber,
      Checkbox,
      message,
      Upload,
      notification
  } from 'antd';
  const FormItem = Form.Item;
  const RadioGroup = Radio.Group;
  const CheckboxGroup = Checkbox.Group;
  const Option = Select.Option;
  /**
    * 辅助函数, 将一个input元素包装下
    *
    * @param formItem
    * @param field
    * @returns {XML}
    */
  const colWrapper = (formItem, field) => {
      if (field.showType == 'textarea') {
          return (
              <Col key={field.key} sm={16}>
                  <FormItem key={field.key} label={field.title} labelCol={{ span: 5 }} wrapperCol={{ span: 17 }}>
                      {formItem}
                  </FormItem>
              </Col>
          );
      }
      return (
          <Col key={field.key} sm={8}>
              <FormItem key={field.key} label={field.title} labelCol={{ span: 10 }} wrapperCol={{ span: 14 }}>
                  {formItem}
              </FormItem>
          </Col>
      );
  }
  
  /**
   * 将schema中的一列转换为下拉框
   *
   * @param field
   */
  const transformSelect = (field,getFieldProps,canEdit) => {
      // TODO: 这里是否要做schema校验
      const options = [];
       
      field.options.forEach((option) => {
          options.push(<Option key={option.key} value={option.key}>{option.value}</Option>);
      });
      var type= field.dataType =='int' ?'number':'string';
      return colWrapper((
          <Select placeholder={field.placeholder} size="default" disabled={!canEdit} {...getFieldProps(field.key, { rules: [{ required : field.required, message: '必填' ,type:type}] }) }>
              {options}
          </Select>
      ), field);
  }
  
  /**
   * 将schema中的一列转换为单选框
   *
   * @param field
   */
  const transformRadio = (field,getFieldProps,canEdit) => {
      const options = [];
       
      field.options.forEach((option) => {
          options.push(<Radio key={option.key} value={option.key}>{option.value}</Radio>);
      });
  
      return colWrapper((
          <RadioGroup disabled={!canEdit} {...getFieldProps(field.key, { 
              initialValue: field.initialValue ,
              rules: [{ required : field.required, message: '必填' }] }) }>
              {options}
          </RadioGroup>
      ), field);
  }
  
  /**
   * 将schema中的一列转换为checkbox
   *
   * @param field
   */
  const transformCheckbox = (field,getFieldProps,canEdit) => {
      const options = [];
       
      field.options.forEach((option) => {
          options.push({ label: option.value, value: option.key });
      });
  
      return colWrapper((
          <CheckboxGroup options={options} disabled={!canEdit} {...getFieldProps(field.key, { rules: [{ required : field.required, message: '必填' ,type:'array'}] }) } />
      ), field);
  }
  
  /**
   * 转换为下拉多选框
   *
   * @param field
   * @returns {XML}
   */
  const transformMultiSelect = (field,getFieldProps,canEdit) => {
      const options = [];
       
      field.options.forEach((option) => {
          options.push(<Option key={option.key} value={option.key}>{option.value}</Option>);
      });
  
      return colWrapper((
          <Select multiple placeholder={field.placeholder} size="default" disabled={!canEdit} {...getFieldProps(field.key, { rules: [{ required : field.required, message: '必填' ,type:'array' }] }) }>
              {options}
          </Select>
      ), field);
  }
  const transformTextarea = (field, getFieldProps, canEdit) => { 
          return colWrapper((<Input  type="textarea" rows={4} 
              disabled={!canEdit} {...getFieldProps(field.key, 
                  { 
                      rules: [
                          { required : field.required, message: '必填'},
                          {
                              validator(rule, value, callback) {
                                  if (field.validType&&validator[field.validType]) {
                                      validator[field.validType](rule, value, callback)
                                  }
                                  else callback();
                              }
                          }
                      ]
                  }) 
              }
               />), field);
  }
  
  /**
   * 将schema中的一列转换为普通输入框
   *
   * @param field
   * @returns {XML}
   */
  const transformNormal = (field,getFieldProps,canEdit) => {
      
      switch (field.dataType) {
          case 'int': 
              return colWrapper((
                  <InputNumber size="default" disabled={!canEdit} {...getFieldProps(field.key, 
                      { rules: [
                          { 
                              required : field.required, 
                              message: '必填',
                              type:'number',
                          }, 
                      ] }) } min={field.min} max={field.max}/>
              ), field);
          case 'float': 
              return colWrapper((
                  <InputNumber step={0.01} size="default" disabled={!canEdit} {...getFieldProps(field.key,
                      { rules: [
                          { 
                              required : field.required, 
                              message: '必填',
                              type:'number',
                          },                      
  
                      ] }) } min={field.min} max={field.max}/>
              ), field);
          case 'date': ;
          case 'datetime':
              var format = field.dataType == 'datetime' ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD";
  
              return colWrapper((
                  <DatePicker showTime={field.dataType == 'datetime'}  format={format}
                      placeholder={field.placeholder } disabled={!canEdit} {...getFieldProps(field.key, { rules: [{ required : field.required, message: '必填',type:'date' }] }) } />
              ), field);
          default:  // 默认就是普通的输入框
               
              return colWrapper((
                  <Input placeholder={field.placeholder} size="default" disabled={!canEdit} {...getFieldProps(field.key, 
                      { 
                          rules: [
                          { 
                              required : field.required, 
                              message: '必填', 
                          },
                          {
                              pattern: field.pattern||null,
                              message: field.message||null,
                          }, 
                          {
                              validator(rule, value, callback) {
                                  if (field.validType&&validator[field.validType]) {
                                      validator[field.validType](rule, value, callback)
                                  }
                                  else callback();
                              }
                          }
                      ] 
                  }) } />
              
              ), field);
      }
  }
  
  /**
   * 也是个辅助函数, 由于是范围查询, 输入的formItem是两个, 一个用于begin一个用于end
   *
   * @param beginFormItem
   * @param endFormItem
   * @param field
   * @returns {XML}
   */
  const betweenColWrapper = (beginFormItem, endFormItem, field,getFieldProps) => {
      // 布局真是个麻烦事
      // col内部又用了一个row做布局
      // 
      return (
          <Col key={`${field.key}Begin`} sm={8}>
              <Row>
                  <Col span={16}>
                      <FormItem key={`${field.key}Begin`} label={field.title} labelCol={{ span: 15 }} wrapperCol={{ span: 9 }} >
                          {beginFormItem}
                      </FormItem>
                  </Col>
                  <Col span={7} offset={1}>
                      <FormItem key={`${field.key}End`} labelCol={{ span: 10 }} wrapperCol={{ span: 14 }}>
                          {endFormItem}
                      </FormItem>
                  </Col>
              </Row>
          </Col>
      );
  }
  
  /**
   * between类型比较特殊, 普通元素每个宽度是8, int和float的between元素宽度也是8, 但datetime类型的between元素宽度是16
   * 否则排版出来不能对齐, 太丑了, 逼死强迫症
   * 而且普通的transform函数返回是一个object, 而这个函数返回是一个array, 就是因为datetime的between要占用两列
   *
   * @param field
   */
  const transformBetween = (field,getFieldProps,canEdit) => {
      const cols = [];
      let beginFormItem;
      let endFormItem;
      
  
      switch (field.dataType) {
          case 'int':
          
              beginFormItem = (<InputNumber size="default" min={field.min} max={field.max}
                  placeholder={field.placeholderBegin || '最小值'} disabled={!canEdit} {...getFieldProps(`${field.key}Begin`, { rules: [{ required : field.required, message: '必填',type:'number' }] }) } />);
              endFormItem = (<InputNumber size="default" min={field.min} max={field.max}
                  placeholder={field.placeholderEnd || '最大值'} disabled={!canEdit} {...getFieldProps(`${field.key}End`, { rules: [{ required : field.required, message: '必填' ,type:'number'}] }) } />);
              cols.push(betweenColWrapper(beginFormItem, endFormItem, field));
              break;
          case 'float':
              
              beginFormItem = (<InputNumber step={0.01} size="default" min={field.min} max={field.max}
                  placeholder={field.placeholderBegin || '最小值'} disabled={!canEdit} {...getFieldProps(`${field.key}Begin`, { rules: [{ required : field.required, message: '必填' ,type:'number'}] }) } />);
              endFormItem = (<InputNumber step={0.01} size="default"
                  placeholder={field.placeholderEnd || '最大值'} disabled={!canEdit} {...getFieldProps(`${field.key}End`, { rules: [{ required : field.required, message: '必填',type:'number' }] }) } />);
              cols.push(betweenColWrapper(beginFormItem, endFormItem, field));
              break;
          case 'date': ; 
          case 'datetime':
              var format = field.dataType == 'datetime' ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD";
  
              cols.push(
                  <Col key={`${field.key}Begin`} sm={8}>
                      <FormItem key={`${field.key}Begin`} label={field.title} labelCol={{ span: 10 }} wrapperCol={{ span: 14 }}>
                          <DatePicker showTime={field.dataType == 'datetime'}  format={format}
                              placeholder={field.placeholderBegin || '开始日期'} disabled={!canEdit} {...getFieldProps(`${field.key}Begin`, { rules: [{ required : field.required, message: '必填' ,type:'date'}] }) } />
                      </FormItem>
                  </Col>
              );
              cols.push(<Col key={`${field.key}End`} sm={8}>
                  <FormItem key={`${field.key}End`} labelCol={{ span: 10 }} wrapperCol={{ span: 14 }}>
                      <DatePicker showTime={field.dataType == 'datetime'}  format={format}
                          placeholder={field.placeholderEnd || '结束日期'} disabled={!canEdit} {...getFieldProps(`${field.key}End`, { rules: [{ required : field.required, message: '必填' ,type:'date'}] }) } />
                  </FormItem>
              </Col>);
              break;
          default:
              // 理论上来说不会出现这种情况
              console.error('unknown dataType: %s', field.dataType);
      }
      return cols;
  }
   
  
  const renderForm=(schema,getFieldProps,canEdit)=>{
      const rows = [];
      let cols = [];
      let hiddenCols = [];
      // 参见antd的布局, 每行被分为24个格子
      // 普通的字段每个占用8格, between类型的字段每个占用16格
      let spaceLeft = 24;
      schema.forEach((field) => {
          if(field.hidden){
              hiddenCols.push( <Input key={field.key} disabled={!canEdit} {...getFieldProps(field.key) } type='hidden' />);
          }
          else {
              // 当前列需要占用几个格子? 普通的都是8, 只有datetime between是16
              let spaceNeed = 8;
              if (field.showType === 'between' && (field.dataType === 'datetime'||field.dataType === 'date')) {
                  spaceNeed = 16;
              }
              if (field.showType === 'textarea' ) {
                  spaceNeed = 24;
              }
              // 如果当前行空间不足, 就换行
              if (spaceLeft < spaceNeed) {
                  rows.push(<Row key={rows.length} gutter={16}>{cols}</Row>);
                  cols = [];  // 不知array有没有clear之类的方法
                  spaceLeft = 24;  // 剩余空间重置
              }
  
              // 开始push各种FormItem
              switch (field.showType) {
                  case 'select':
                      cols.push(transformSelect(field,getFieldProps,canEdit));
                      break;
                  case 'radio':
                      cols.push(transformRadio(field,getFieldProps,canEdit));
                      break;
                  case 'checkbox':
                      cols.push(transformCheckbox(field,getFieldProps,canEdit));
                      break;
                  case 'multiSelect':
                      cols.push(transformMultiSelect(field,getFieldProps,canEdit));
                      break;
                  case 'textarea':
                      cols.push(transformTextarea(field, getFieldProps, canEdit));
                      break;
                  case 'between':
                      for (const col of transformBetween(field,getFieldProps,canEdit)) {  // between类型比较特殊, 返回的是一个数组
                          cols.push(col)
                      }
                      break;
                  default:
                      cols.push(transformNormal(field,getFieldProps,canEdit));
              }
  
              spaceLeft -= spaceNeed;
          }
          
      });
  
      // 别忘了最后一行
      if (cols.length > 0) {
          rows.push(<Row key={rows.length} gutter={16}>{cols}{hiddenCols}</Row>);
      }
      return rows
  }
  module.exports = {
      renderForm
  }