npm package: @icreate/ics-basic-form-builder
Description: 表单设计器
Author: dingwei
Latest version: 0.0.29

@[toc]
**版本更新说明**
 - [ 0.0.29] 引入新的地址组件
 - [ 0.0.28-beta.1] 更新ics-ui/ics-icon版本
 - [ 0.0.28-beta.1]  multi-column-select支持多选以及自定义搜索条件customFilter（结合数据tbodyOptions的data属性）
 - [ 0.0.28-beta.0] 1.提供按钮点击时触发的方法buttonClickRender  2.地址组件支持添加同步按钮isShowButton,点击按钮触发方法syncAddress  3.栅格列支持设置padding
 - [ 0.0.28] 1.地址组件更新(增加level/返回数据为对象)  2.基础字段支持重复拖入repeatFlag
 - [ 0.0.27-beta.6] 修复：checkbox报错
 - [ 0.0.27-beta.4] 修复：combogrid的label报错
 - [ 0.0.27-beta.3] 修复：formData数据实时回显
 - [ 0.0.27-beta.2] 修复：打包引入地址组件
 - [ 0.0.27-beta.1] 1.地址级联组件(业务组件) area-cascader  2.新模板/ace-builds放入ics-ui
 - [ 0.0.27] 1.label添加tooltip (字段labelTooltipContent/labelTooltipPlacement) 2.添加multi-column-select(select自定义模板：多列select)
 - [ 0.0.26-beta.0] 修复栅格组件的自适应宽度问题
 - [ 0.0.25 ] 1.可隐藏保存模板按钮saveFormTemplate:false，提供了自己保存的方法customSaveTemplate 2.栅格垂直方向对齐
 - [ 0.0.24 ] 随ics-ui更新版本
 - [ 0.0.23 ] 计数器默认值问题
 - [ 0.0.22 ] 1.自定义组件的name值改为'自定义组件的类型(type) + Widget' 2.属性collapseTags:select多选时是否将选中值按文字的形式展示  -            3.组件设置增加了标签行高  4.表单设置：静态字段增加了左侧标识
 - [ 0.0.21 ] 1.input:placeholder  2.组件设置：组件大小 3.表单设置：设置标签颜色labelColor以及标签字体大小labelFontSize 4.子表单
 - [ 0.0.20 ] 支持引入自定义组件
 - [ 0.0.19 ] input组件只读属性的样式，设置属性 readOnlyNoBorder


##  说明
这是一个表单设计器

## 安装

```bash
npm i @icreate/ics-basic-form-builder   # 安装包
```

## 在vue使用
1. 在vue项目的main.js中引入


```javascript
import VForm from '@icreate/ics-basic-form-builder'  //引入VForm库
import '@icreate/ics-basic-form-builder/styles/form-builder.css'  //引入VForm样式
import IcsUI from '@icreate/ics-ui'  //引入ics-ui
import '@icreate/ics-ui/lib/ics-ui.css'
Vue.use(IcsUI)  //全局注册ics-ui
Vue.use(VForm)  //全局注册VForm(同时注册了v-form-designer和v-form-render组件)
```

2. 在Vue模板中使用表单设计器组件
```html
     <v-form-designer
      ref="vfDesignerRef"
      :designer-config="designerConfig"
      :basicFieldsTransfer="basicFieldsTransfer"
      :formJson="formJson"
      :formTemplateJson="formTemplateJson"
      @saveFormTemplateHandler="saveFormTemplateHandler"
      :customComponentObj="customComponentObj"
    ></v-form-designer>
```


3. 在Vue模板中使用表单渲染器组件
```html
 <v-form-render
       ref="vFormRef"
      :form-json="formJson"
      :form-data="formData"
      :option-data="optionData"
      @appendButtonClick="appendButtonClickHandler"
      @formChange="handleFormChange"
      @buttonClickRender="buttonClickHandler"
      @syncAddress="syncAddressHandler"
      :customComponentObj="customComponentObj"
    >
    </v-form-render>
    <ics-button type="primary" @click="submitForm">Submit</ics-button>
```

4. 引入自定义组件（可选）
```js
import customCom from "./customCom.vue";    //自定义组件的格式，请参考最后的示例
```



## 数据格式：

>**v-form-designer 表单设计器**  
>designerConfig ：表单设计器配置 （必传）
>basicFieldsTransfer ： 基础字段组件（必传）
>formJson：  显示上次编辑的设计器页面 （选传）
>formTemplateJson ：显示保存的模板 （选传）
>saveFormTemplateHandler ：保存模板后的回调函数，可以获取到模板的json数据
>customComponentObj: 自定义组件的对象格式

> **v-form-render 表单渲染器**
>formJson：需要渲染的表单的json数据（从设计器复制json数据）（必传）
>formData：需要渲染的表单数据（选传）
>optionData：动态传入的选项数据（例如：多选框的选项）（选传）
>appendButtonClickHandler ： 输入框后置按钮的回调函数（选传）
>handleFormChange:  表单数据改变时触发
>submitForm:  可以获取到表单数据formData
>customComponentObj: 自定义组件的对象格式

```javascript
export default {
  data() {
    return {
      customComponentArr:[customCom],    //自定义组件的数组
      customComponentObj:{},   //将数组转成对象的格式 (写在created())
      designerConfig: {         
        resetFormJson: false,  
        toolbarMaxWidth: 490,
        saveFormTemplate: false, //隐藏保存模板
      },     
      basicFieldsTransfer: [
        {                                //自定义组件
          type: "customType",            //自定义类型
          repeatFlag: true, // 组件可重复
          formItemFlag: true,
          options: {
            name: "customName", //name唯一值
            label: "自定义组件", //label值
            labelAlign: "", //label对齐方式
            defaultValue: null, //默认值
            labelWidth: null, //标签宽度
            labelHidden: false, //标签是否隐藏
            hidden: false, //是否隐藏
            required: false, //是否必填
            requiredHint: "", //必填提示
            columnWidth: '200px',  //在子表单中的组件列宽
            optionItems: [   //选项（ics-radio/ics-checkbox/ics-select...）
              { label: "选项1", value: 1 },
              { label: "选项2", value: 2 },
            ],
          },
        },
          {
          type: "data-table",   //数据表格
          options: {
            name: "dataTable",
            label: "数据表格",
            tableWidth: "100%", //表格宽度
            tableHeight: "300px", //表格高度
            showCheckBox: true, //是否显示复选框列
            stripe: true, //是否斑马线
            tableBorder: true, //是否带有边框
            showActionButton: true, //显示操作按钮列
            optionItems: {
              thOptions: [
                //表头
                {
                  label: "日期",
                  value: "date",
                  width: "180",
                },
                {
                  label: "姓名",
                  value: "name",
                  width: "180",
                },
                {
                  label: "地址",
                  value: "address",
                  width: "",
                },
              ],
              tbodyOptions: [
                {
                  id: "1",
                  date: "2016-05-02",
                  name: "张三",
                  address: "上海市普陀区金沙江路 1518 弄",
                },
                {
                  id: "2",
                  date: "2016-05-04",
                  name: "李四",
                  address: "上海市普陀区金沙江路 1517 弄",
                },
                {
                  id: "3",
                  date: "2016-05-01",
                  name: "王二麻子",
                  address: "上海市普陀区金沙江路 1519 弄",
                },
              ], //表格内容
            },
          },
        },
        {
          type: "input",     //表单组件类型（必传）
          options: {
            label: "输入框",   //组件label（必传）
            name: "inputtext",    //组件name（必传，而且必须是唯一值）
            type: "text",         //input 输入框的类型（可传）
            defaultValue:"",    //默认值（可传）
            required: true,      //是否必填（可传）
            requiredHint:'',     //必填提示（可传）
            validation: "/^[\u4e00-\u9fa5]+$/",    //组件的正则校验规则 （可传）
            validationHint: "只能输入中文哦",      //校验提示语（可传）
            reverseValidation:'/[^\u4e00-\u9fa5]/g',   //数据格式：正则取反+g  (需要限制输入时，必传)
            max:"" ,//限制输入的最大值  (限制输入是数字的情况)
            readOnlyNoBorder: true,   //只读时的样式  不要边框
            labelTooltipContent:"标签文字提示内容",   //标签文字提示内容
            labelTooltipPlacement:"top"   //标签文字提示位置
          },
        },
        {
          type: "input",
          options: {
            label: "输入框",
            name: "inputpsw",
            type: "password",
          },
        },
        {
          type: "textarea",
          options: {
            label: "文本域",
            name: "textarea",
          },
        },
        {
          type: "radio",
          options: {
            name: "radio",
            label: "单选项",
            optionItems: [    //选项列表（必传）
              {
                label: "选项1",
                value: "1",
              },
              {
                label: "选项2",
                value: "2",
              },
            ],
          },
        },
        {
          type: "checkbox",
          options: {
            name: "checkbox",
            label: "多选框",
            max: 1, // 可被勾选的 checkbox 的最大数量
            optionItems: [     //选项列表（必传）
              {
                label: "选项1",
                value: "1",
              },
              {
                label: "选项2",
                value: "2",
              },
              {
                label: "选项3",
                value: "3",
              },
            ],
          },
        },
        {
          type: "number",
          options: {
            name: "number",
            label: "计数器",
            min: 0,         //最小值（可传）
            max: 100000,    //最大值（可传）
            precision: 0,   //精度（可传）
            step: 1,        //增减步长（可传）
          },
        },
        {
          type: "select",
          options: {
            name: "select",
            label: "下拉框",
            labelAndValue: true, // 获取选项数据的格式（例如：选中下拉框，是否需要获取label值，默认不获取）
            collapseTags: true, //多选时是否将选中值按文字的形式展示  默认为fale
            optionItems: [      //下拉列表（必传）
              {
                id:"",     //   唯一key值  （如果value值不唯一，id必传）
                label: "select 1",
                value: 1,
              },
              {
                label: "select 2",
                value: 2,
              },
              {
                label: "select 3",
                value: 3,
              },
            ],
          },
        },
        {
          type: "select-plus",
          options: {
            name: "select-plus",
            label: "下拉框加强版",
            optionItems: [
              {
                label: "select 1",
                value: 1,
              },
              {
                label: "select 2",
                value: 2,
              },
              {
                label: "select 3",
                value: 3,
              },
            ],
          },
        },
        {
          type: "multi-column-select",
          options: {
            name: "multi-column-select",
            label: "多列select",
            labelColumn: "name", //label绑定的列
            valueColumn: "id", //value绑定的列
            showHeader: true, //是否显示表头
            labelAndValue: true, //返回值是对象（label和value）
            customFilter: ['id', 'name'],  //自定义搜索的字段
            optionItems: {
              thOptions: [
                // 表头
                {
                  label: "日期",
                  value: "date",
                  width: "100",
                },
                {
                  label: "姓名",
                  value: "name",
                  width: "100",
                },
                {
                  label: "地址",
                  value: "address",
                  width: "260",
                },
              ],
              tbodyOptions: [
                {
                  id: "1",
                  date: "2016-05-02",
                  name: "张三",
                  address: "上海市普陀区金沙江路 1518 弄",
                  data: {
                    id: '1',
                    name: '张三'
                  }
                },
                {
                  id: "2",
                  date: "2016-05-04",
                  name: "李四",
                  address: "上海市普陀区金沙江路 1517 弄",
                  data: {
                    id: '2',
                    name: '李四'
                  }
                },
                {
                  id: "3",
                  date: "2016-05-01",
                  name: "王二麻子",
                  address: "上海市普陀区金沙江路 1519 弄",
                  data: {
                    id: '3',
                    name: '王二麻子'
                  }
                },
              ], // 表格内容
            },
          },
        },
        {
          type: "time",
          options: {
            name: "time",
            label: "时间",
            format: "HH:mm:ss", //时间格式（可传）
          },
        },

        {
          type: "time-range",
          options: {
            name: "time-range",
            label: "时间范围",
            format: "HH:mm:ss", //时间格式（可传）
          },
        },

        {
          type: "date",
          options: {
            name: "date",
            label: "日期",
            format: "yyyy-MM-dd",  //日期显示格式（可传）
            valueFormat: "yyyy-MM-dd",  //日期对象格式（可传）
          },
        },

        {
          type: "date-range",
          options: {
            name: "date-range",
            label: "日期范围",
            format: "yyyy-MM-dd", //日期显示格式（可传）
            valueFormat: "yyyy-MM-dd", //日期对象格式（可传）
          },
        },
            {
          type: "datetime",
          options: {
            name: "datetime",
            label: "日期时间",
            format: "yyyy-MM-dd HH:mm:ss", //日期显示格式（可传）
            valueFormat: "yyyy-MM-dd HH:mm:ss", //日期对象格式（可传）
          },
        },
        {
          type: "switch",
          options: {
            name: "switch",
            label: "开关",
          },
        },

        {
          type: "rate",
          options: {
            name: "rate",
            label: "评分",
          },
        },
        {
          type: "button",
          options: {
            name: "button",
            label: "按钮",
          },
        },
        {
          type: "cascader",
          options: {
            name: "cascader",
            label: "级联选择",
            optionItems: [    //级联选择选项（必传）
              {
                label: "select 1",
                value: 1,
                children: [{ label: "child 1", value: 11 }],
              },
              { label: "select 2", value: 2 },
              { label: "select 3", value: 3 },
            ],
          },
        },
        {
          type: "combo-grid",
          options: {
            name: "comboGrid",
            label: "组合网格",
            labelColumn: "name",   //name列对应label
            valueColumn: "id",     //id列对应value(选中列表，获取的值)
            valueKey:"",           //添加表格数据的唯一key值属性（不传，默认是valueColumn）
            labelAndValue: true,   //true: 绑定的值是对象(含label)    默认为false
            customFilter: ["id", "name"],     //自定义搜索字段
            optionItems: {         //选项值：表头字段+表格数据 （必传）
              thOptions: [
                //表头
                {
                  label: "日期",
                  value: "date",
                  width: "180",
                },
                {
                  label: "姓名",
                  value: "name",
                  width: "180",
                },
                {
                  label: "地址",
                  value: "address",
                  width: "260",
                },
              ],
              tbodyOptions: [
                //表格内容
                {
                  id: "111111",
                  date: "2016-05-02",
                  name: "王小虎1",
                  address: "上海市普陀区金沙江路 1518 弄",
                },
                {
                  id: "111112",
                  date: "2016-05-04",
                  name: "王小虎2",
                  address: "上海市普陀区金沙江路 1517 弄",
                },
                {
                  id: "111113",
                  date: "2016-05-01",
                  name: "王小虎3",
                  address: "上海市普陀区金沙江路 1519 弄",
                },
              ], 
            },
          },
        },
      {
          type: 'area-cascader', // 业务组件 地址级联选择器
          options: {
            name: 'area-cascader',
            label: '地址级联',
            level: 1,
            isShowButton: true,   //是否显示右侧按钮
            syncAddressData: [    //右侧checkbox-group的数据
              { id: 'nativeAddress', name: '籍贯地址' },
              { id: 'residenceAddress', name: '户口地址' },
              { id: 'birthAddress', name: '出生地址' },
              { id: 'unitAddress', name: '单位地址' },
              { id: 'connectAddress', name: '联系人地址' },
              { id: 'currentAddress', name: '现住址' }
            ]
          }
        },
        {
          type: 'address-cascader', // 新地址级联
          options: {
            name: 'address-cascader',
            label: '新地址组件',
            level: 3,
            isShowButton: true,
            syncAddressData: [
              { id: 'nativeAddress', name: '籍贯地址' },
              { id: 'residenceAddress', name: '户口地址' },
              { id: 'birthAddress', name: '出生地址' },
              { id: 'unitAddress', name: '单位地址' },
              { id: 'connectAddress', name: '联系人地址' },
              { id: 'currentAddress', name: '现住址' }
            ]
          }
        }
      ],
      formTemplateJson:
        JSON.parse(localStorage.getItem("saveFormTemplateJson")) || null,

      formJson: {
        widgetList: [
          {
            type: "input",
            options: {
              labelAlign: "",
              defaultValue: "",
              placeholder: "",
              columnWidth: "200px",
              size: "",
              labelWidth: null,
              labelHidden: false,
              readonly: false,
              disabled: false,
              hidden: false,
              clearable: true,
              showPassword: false,
              required: true,
              requiredHint: "",
              validation: "/^[一-龥]+$/",
              validationHint: "只能输入中文哦",
              minLength: null,
              maxLength: null,
              showWordLimit: false,
              appendButton: true,
              appendButtonDisabled: false,
              buttonIcon: "el-icon-search",
              label: "用户名",
              name: "username",
              type: "text",
            },
            icon: "text-field",
            formItemFlag: true,
            id: "username",
          },
          {
            type: "input",
            options: {
              labelAlign: "",
              defaultValue: "",
              placeholder: "",
              columnWidth: "200px",
              size: "",
              labelWidth: null,
              labelHidden: false,
              readonly: false,
              disabled: false,
              hidden: false,
              clearable: true,
              showPassword: false,
              required: false,
              requiredHint: "",
              validation: "",
              validationHint: "",
              minLength: null,
              maxLength: null,
              showWordLimit: false,
              appendButton: false,
              appendButtonDisabled: false,
              buttonIcon: "el-icon-search",
              label: "密码",
              name: "password",
              type: "password",
            },
            icon: "text-field",
            formItemFlag: true,
            id: "password",
          },
          {
            type: "textarea",
            options: {
              labelAlign: "",
              defaultValue: "",
              placeholder: "",
              columnWidth: "200px",
              size: "",
              labelWidth: null,
              labelHidden: false,
              readonly: false,
              disabled: false,
              hidden: false,
              clearable: true,
              showPassword: false,
              required: false,
              requiredHint: "",
              validation: "",
              validationHint: "",
              minLength: null,
              maxLength: null,
              showWordLimit: false,
              appendButton: false,
              appendButtonDisabled: false,
              buttonIcon: "el-icon-search",
              label: "留言板",
              name: "message",
              rows: 3,
            },
            icon: "text-field",
            formItemFlag: true,
            id: "message",
          },
        ],
        formConfig: {
          labelWidth: 80,
          labelPosition: "left",
          size: "",
          labelAlign: "label-left-align",
          labelColor:"",   //label颜色
          labelFontSize:"", //label字体大小
          labelLineHeight: "", //标签行高
          cssCode: "",
          customClass: "",
          functions: "",
          layoutType: "PC",
          modelName: "formData",
          refName: "vForm",
          rulesName: "rules",
          onFormCreated: "",
          onFormMounted: "",
          onFormDataChange: "",
        },
      },
      formData: {},
      optionData: {        //动态传入的选项数据
        checkbox: [       //checkbox  是name名称 
          {
            label: "动态选项1",
            value: "1",
          },
          {
            label: "动态选项2",
            value: "2",
          },
          {
            label: "动态选项3",
            value: "3",
          },
        ],
      },
    };
  },
    methods: {
    submitForm() {
      this.$refs.vFormRef
        .getFormData()
        .then((formData) => {
          // Form Validation OK
          alert(JSON.stringify(formData));
        })
        .catch((error) => {
          // Form Validation failed
          this.$message.error(error);
        });
    },
    saveFormTemplateHandler(data) {
      //保存模板json数据
      localStorage.setItem("saveFormTemplateJson", data);
      this.$message.success("模板保存成功");
    },
    appendButtonClickHandler(data) {
      //输入框添加后置按钮，回调函数
      console.log("appendButtonClickHandler=======", data.$data.fieldModel);
    },
    handleFormChange(
      fieldName,
      newValue,
      oldValue,
      formDataModel,
      subFormName,
      subFormRowIndex，
      comboGridItem
    ) {
      //fieldName  name
      //newValue   新值
      //oldValue   旧值
      //formDataModel  表单数据
      //comboGridItem  组合网格组件，传过来的对象

     console.log(this.$refs["vFormRef"].widgetRefList)   //获取每个组件的属性方法

      this.$refs["vFormRef"].widgetRefList["select"].setRequired(true);  //设置select组件必填属性为true
      this.$refs["vFormRef"].widgetRefList["select"].setValue("1");     //设置select组件值为1
 
      this.$refs["vFormRef"].widgetRefList["input"].setWidgetOption("max",newValue)  //设置input组件的最大值为newValue

      this.$refs["vFormRef"].widgetRefList["comboGrid"].setValueNotEmitHandler(newValue);   //给组合网格赋值（赋值不会触发handleFormChange）  //改变组合网格选项,会触发
     
    this.$refs["vFormRef"].widgetRefList["select"].$refs.fieldEditor.toggleMenu();    //select组件  自动展开下拉框

    },
    customSaveTemplate(){
      //自己保存模板的方法  
      this.$refs.vfDesignerRef.$refs.toolbarRef.saveFormTemplate()  //方法的返回值即是保存的数据
    },
    buttonClickHandler(){}
  },
  created(){
    this.customComponentArr.map((item) => {
      return (this.customComponentObj[item.name] = item);
    });
  }
}
```

## 自定义组件的格式（.vue文件）：

```html
<!-- template 按需编写, 示例如下 -->
 <div>
    <ics-switch
      ref="fieldEditor"
      v-model="fieldModelData.switchVal"
    ></ics-switch>
    <ics-input
      class="marginBottom"
      ref="fieldEditor"
      v-model="fieldModelData.inputVal"
      placeholder="请输入内容"
      clearable
      show-password
    />
    <ics-select v-model="fieldModelData.selectVal" placeholder="请选择">
      <ics-option
        v-for="item in field.options.optionItems"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      >
      </ics-option>
    </ics-select>
    </div>
</template>
```

```javascript
  export default {
    name: "customTypeWidget", //自定义组件的类型(type) + 'Widget'
    data() {
      return {
        fieldModelData: {
          switchVal: false, //每个组件的绑定值（名称自定义），都放在fieldModelData里面
          inputVal: "",
          selectVal: "",
        }
      };
    },
    props: {
      field: Object, //basicFieldsTransfer的自定义组件的数据
      value: Object, 
    },
    model: {
      prop: "value",
      event: "change",
    }, // v-model
    methods: {
    },
    watch: {
      value: {
        handler(val) {
          if (val) {
            this.fieldModelData = this.value;
          }
        },
        deep: true,
        immediate: true,
      },
      fieldModelData: {
        handler(val) {
          this.$emit("change", val);
        },
        deep: true,
      },
    },
  };
```

```css
<style scoped>
.marginBottom {
  margin-bottom: 20px;
}
</style>
```