# 表单设计器 y-form

## 简介

基于项目[k-form-design](https://gitee.com/kcz66/k-form-design)做出修改，基于vue和ant-design-vue实现的表单设计器，样式使用less作为开发语言，主要功能是能通过简单操作来生成配置表单，生成可保存的JSON数据，并能将JSON还原成表单，使表单开发更简单更快速

## 安装
```cmd
# 使用yarn 
yarn add y-form

# 使用npm 
npm i y-form --save
```


## 组件
- KFormDesign 表单设计器（基于可视化操作快速设计出表单页面，生成配置json或页面）

## 引入组件
``` javascript
// 在main.js引入
import KFormDesign from 'k-form-design'
import 'k-form-design/lib/y-form.css'
Vue.use(KFormDesign)
```

## 使用组件
``` html
<template>
  <div>
   <k-form-design />
  </div>
</template>
```

## showToolbarsText 展示组件操作按钮文字（不展示即不在组件上添加此api）

<template>
  <div>
   <k-form-design showToolbarsText/>
  </div>
</template>

## title="自定义标题" 自定义组件名称（目前项目弃用）

<template>
  <div>
   <k-form-design title="自定义标题"/>
  </div>
</template>

## :fields="['input', 'textarea']" 限制组件展示,只展示fields绑定的数组中有的组件

  目前已有组件类型['text','textarea','radio','checkbox','select','number','date','columnPanel_2','columnPanel_2']

<template>
  <div>
   <k-form-design :fields="['input', 'textarea']"/>
  </div>
</template>

## :toolbars=[ 'save', 'preview', 'importJson', 'exportJson', 'exportCode', 'reset', 'close' ] 组件操作项控制
                保存、预览、导入、生成JSON、生成代码、清空、关闭
<template>
  <div>
   <k-form-design :toolbars=["save"]/>
  </div>
</template>


## 自定义操作按钮 需要项目引入a-tooltip，a-icon组件

<k-form-design >
     <!-- 自定义按钮 -->
      <template slot="left-action">
        <a-tooltip title="自定义按钮">
          <a>
            <a-icon type="experiment" @click='绑定需要执行的函数'/>
            <!-- <span>测试左侧插槽（showToolbarsText属性为true时需要）</span> -->
          </a>
        </a-tooltip>
      </template>
</k-form-design>

## 提交按钮触发 函数名称 handleSave 可自行修改

<template>
  <div>
    <k-form-design @save="handleSave" />
  </div>
</template>
<script>
export default {
  methods: {
    handleSave(values) {
      // values为当前所设计的表单组件的json数据对象
      console.log(values);
    }
  }
};
</script>

## 导入json数据 ref绑定唯一id 用于组件赋值操作

<template>
  <k-form-design ref='yForm' />
</template>
<script>
export default {
  data () {
    return {
      jsonData: {
        "list": [
          {
            "type": "text",
            "label": "单行文本框",
            "key": "text_1588924629338",
            "options": {
              "defaultValue": {
                "name": "默认值",
                "value": "",
                "descr": ""
              },
              "unique": {
                "name": "是否唯一性",
                "value": false,
                "descr": ""
              },
              "width": {
                "name": "控件大小",
                "value": [
                  {
                    "value": "100%",
                    "label": "大尺寸"
                  },
                  {
                    "value": "75%",
                    "label": "标注尺寸"
                  },
                  {
                    "value": "50%",
                    "label": "小尺寸"
                  }
                ],
                "defValue": "50%",
                "descr": ""
              },
              "placeholder": {
                "name": "自定义输入提示",
                "value": "",
                "descr": ""
              },
              "title": {
                "name": "标题",
                "value": "单行文本框",
                "descr": ""
              },
              "maxLength": {
                "name": "最大长度",
                "value": "200",
                "descr": ""
              },
              "required": {
                "name": "是否必填",
                "value": false,
                "descr": ""
              }
            },
            "rules": [
              {
                "message": "必填项",
                "required": false
              }
            ]
          }
        ],
        "config": {
          "id": 2,
          "ftName": "12345",
          "ftDescr": "123",
          "tableVersion": 1,
          "layout": "horizontal"
        }
      }
    }
  },
  methods: {
    importData () {
      this.$refs.yForm.handleSetData(this.jsonData)
    }
  },
  mounted () {
    this.importData()
  }
}
</script>

## 获取数据及完整使用示例

<template>
  <div>
      <k-form-design :title="tableName" toolbarsTop showToolbarsText :toolbars='list' @save="handleSave" ref='yForm'>
          <template slot="right-action">
                <a-button type="link" @click="goBack">返回</a-button>
          </template>
      </k-form-design>
  </div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data(){
    return {
      // 限定操作按钮数组
      list:[ 'save', 'preview', 'importJson', 'exportJson', 'exportCode', 'reset'],
      // list:['save', 'preview','reset']
      tableName:'',
      tableID:'',
      //是否为编辑状态
      isEdit:false,
    }
  },
  created(){
      //获取传入id
      this.tableID = this.$route.query.id;
      //调用获取数据方法
      this.isQForm(this.tableID);
  },
  methods:{
      //返回上一页
      goBack(){
          this.$router.go(-1)
      },
      //提交
      handleSave(val) {
          let x = JSON.parse(val)
          x.formBaseId = this.tableID;
          x.formBaseName = this.tableName;
          //判断是否为新建
          if(!this.isEdit){
            // 新建
              this.$api.upDts(x).then(res => {
                  if(res.code == 0){
                      this.$message.success('创建成功');
                      this.$router.go(-1)
                  }
              })
          }else{
            // 编辑
              this.$api.upDts(x).then(res => {
                  if(res.code == 0){
                      this.$message.success('编辑成功');
                      this.$router.go(-1)
                  }
              })
          }
      },
      //查询是否已创建表单并获取数据
      isQForm(obj){

          let val = {
              id:obj,
              val:{}
          };
          this.$api.getDts(val).then(res => {
              if(res.data.list != null && res.data.list.length > 0){
                  this.isEdit = true;
                  let list = res.data;
                  this.$refs.yForm.handleSetData(list);
              }
          })
      }
  }
};
</script>

<style scoped>
.form-designer-container-9136076486841527 .content aside.left ul li:hover {
  color: #13c2c2;
  border: 1px solid #3db389;
  position: relative;
  z-index: 1;
  -webkit-box-shadow: 0 2px 6px #3db389;
  box-shadow: 0 2px 6px #3db389;
}
</style>

## 组件控制参数解析
  
  1.input单行文本组件

    参数解析：
        {
          "type": "text",                       类型： 用于判断组件是否显示，必须为已定义的类型才可显示
          "label": "单行文本框",                 标题
          "key": "text_1588929368181",          唯一ID： 用于获取和设置输入框组件的value值
          "options": {
          "defaultValue": {                     默认值属性
            "name": "默认值",                    默认值设置输入框标题
            "value": "",                        默认值
            "descr": ""                         默认值描述（暂未使用）
          },
          "unique": {                           暂时没有使用
            "name": "是否唯一性",
            "value": false,
            "descr": ""
          },
          "width": {                            控件宽度选择
            "name": "控件大小",                  控件宽度 标题
            "value": [                          控件宽度 value
              {
              "value": "100%",
              "label": "大尺寸"
              },
              {
              "value": "75%",
              "label": "标注尺寸"
              },
              {
              "value": "50%",
              "label": "小尺寸"
              }
            ],
            "defValue": "50%",                  默认宽度       
            "descr": ""                         宽度描述
          },
          "placeholder": {                      提示文案属性
            "name": "自定义输入提示",            提示文案默认标题
            "value": "",                        提示文案默认值
            "descr": ""                         提示文案描述（暂未使用）
          },
          "title": {                            标题属性
            "name": "标题"，                     标题属性输入框标题
            "value": "单行文本框",               标题默认值
            "descr": ""                         标题描述（暂未使用）
          },  
          "maxLength": {                        最大输入长度属性
            "name": "最大长度",                  最大输入长度标题
            "value": "200",                     最大输入长度默认值
            "descr": ""
          },
          "required": {                         暂未使用
            "name": "是否必填",
            "value": false,
            "descr": ""
          }
        },  
        "rules": [                              验证规则对象(可选以下验证规则可多个，可单一)
          {
            "message": "必填项",                 验证失败提示
            "required": true                    是否必填是否验证
          },
          {
            "message": "长度验证失败",           验证失败提示
            "len": 50                           长度必须为50才能验证成功
          },
          {
            "message": "最大长度验证失败",       验证失败提示
            "max": 30                           最大长度
          },
          {
            "message": "最小长度验证失败",       验证失败提示
            "min": 20                           最小长度
          },
          {
            "message": "最小长度验证失败",       验证失败提示
            "pattern": new RegExp(xxxx);        自定义正则验证
          },
          
        ]







- KFormBuild 表单构建器（根据设计器中获取的配置json数据，快速构建出表单页面）

## 基础用法 ：value 绑定组件数据

<template>
  <div>
    <k-form-build :value="jsonData" />
  </div>
</template>
<script>
export default {
  data () {
    return {
      jsonData: {
        "list": [
          {
            "type": "text",
            "label": "单行文本框",
            "key": "text_1588924629338",
            "options": {
              "defaultValue": {
                "name": "默认值",
                "value": "",
                "descr": ""
              },
              "unique": {
                "name": "是否唯一性",
                "value": false,
                "descr": ""
              },
              "width": {
                "name": "控件大小",
                "value": [
                  {
                    "value": "100%",
                    "label": "大尺寸"
                  },
                  {
                    "value": "75%",
                    "label": "标注尺寸"
                  },
                  {
                    "value": "50%",
                    "label": "小尺寸"
                  }
                ],
                "defValue": "50%",
                "descr": ""
              },
              "placeholder": {
                "name": "自定义输入提示",
                "value": "",
                "descr": ""
              },
              "title": {
                "name": "标题",
                "value": "单行文本框",
                "descr": ""
              },
              "maxLength": {
                "name": "最大长度",
                "value": "200",
                "descr": ""
              },
              "required": {
                "name": "是否必填",
                "value": false,
                "descr": ""
              }
            },
            "rules": [
              {
                "message": "必填项",
                "required": false
              }
            ]
          }
        ],
        "config": {
          "id": 2,
          "ftName": "12345",
          "ftDescr": "123",
          "tableVersion": 1,
          "layout": "horizontal"
        }
      }
    }
  }
}
</script>

## 获取生成的表单提交的数据 （使用getData函数获取数据）

<template>
  <div>
    <k-form-build ref="yForm" :value="jsonData" />
    <button @click="handleGetData">获取数据</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      jsonData: {
        list: [
          
        ],
        config: {
          layout: 'horizontal',
          labelCol: { span: 4 },
          wrapperCol: { span: 18 },
          hideRequiredMark: false,
          customStyle: ''
        }
      }
    }
  },
  methods: {
    handleGetData () {
      // 使用getData函数获取数据
      this.$refs.yForm.getData().then(values => {
        console.log('表单定义验证通过', values)
      }).catch(() => {
        console.log('表单定义验证未通过，获取失败')
      })
    }
  }
}
</script>

## 重置表单

<template>
  <div>
    <k-form-build ref="yForm" :value="jsonData" />
    <button @click="handleReset">重置表单</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      jsonData: {
        list: [
          
        ],
        config: {
          layout: 'horizontal',
          labelCol: { span: 4 },
          wrapperCol: { span: 18 },
          hideRequiredMark: false,
          customStyle: ''
        }
      }
    }
  },
  methods: {
    handleReset () {
      // 使用reset函数清空表单
      this.$refs.yForm.reset();
    }
  }
}
</script>

## 一键赋值

<template>
  <div>
    <k-form-build ref="yForm" :value="jsonData" />
    <button @click="handleChange">赋值</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      jsonData: {
        list: [
          {
            key:'001_input',
            ...
          },
          {
            key:'002_input',
            ...
          },
          {
            key:'003_input',
            ...
          }
        ],
        config: {
          layout: 'horizontal',
          labelCol: { span: 4 },
          wrapperCol: { span: 18 },
          hideRequiredMark: false,
          customStyle: ''
        }
      }
    }
  },
  methods: {
    handleChange () {
      // 使用ant-design form组件的特性修改表单数据


      // 在明确知道组件的情况下可使用直接赋值的方式
      this.$refs.yForm.form.setFieldsValue({
        '001_input': '设置input1值',
        '002_input': '设置input2值',
        '003_input': '设置input3值',
      });
      // 动态方式
      // 获取当前所有组件的key值
      let keyList = this.jsonData.list.map(item => {
        return item.key
      });
      //keyList值为['001_input','002_input','003_input']

      let valList = {
        '001_input': '设置input1值',
        '002_input': '设置input2值',
        '003_input': '设置input3值',
      };
      let valObj = {}
      keyList.forEach((e,i) =>{
        valObj[`${item}`] = valList[item];
        //动态添加 对象属性
        //valObj[001_input] = valList[001_input]
      });
      //传入组装好的对象 完成赋值
      this.$refs.kfb.form.setFieldsValue(valObj);
    }
  }
}
</script>

## 组件扩展

基础类型组件扩展 以时间选择器为例


在packages/KFormItem/index.vue中编写新组件或者，在packages目录下新建一个文件夹 例如 getDate  在getDate目录下 新建一个index.vue文件 在packages/KFormItem/index.vue 引入新增的组件

然后核对后端给出的属性

"options": {
  "clearable": {
    "name": "可清除",
    "value": false,
    "descr": ""
  },
  "defaultValue": {
    "name": "默认值",
    "value": "2020-05-08",
    "descr": ""
  },
  "showTime": {
    "name": "时间选择器",
    "value": false,
    "descr": ""
  },
  "width": {
    "name": "控件大小",
    "value": "28%",
    "descr": ""
  },
  "currentDate": {
    "name": "当前日期",
    "value": true,
    "descr": ""
  },
  "placeholder": {
    "name": "默认提示语",
    "value": "请选择",
    "descr": ""
  },
  "title": {
    "name": "标题",
    "value": "日期",
    "descr": ""
  },
  "dateformat": {
    "name": "日期格式设置",
    "value": [
      {
        "value": "YYYY-MM-DD",
        "label": "年-月-日"
      },
      {
        "value": "YYYY-MM-DD HH:mm:ss",
        "label": "年-月-日 时:分:秒"
      },
      {
        "value": "YYYY-MM-DD HH",
        "label": "年-月-日 时"
      },
      {
        "value": "YYYY-MM",
        "label": "年-月"
      },
      {
        "value": "YYYY-MM-DD HH:mm",
        "label": "年-月-日 时:分"
      },
      {
        "value": "YYYY",
        "label": "年"
      }
    ],
    "defValue": "YYYY-MM-DD",
    "descr": ""
  },
  "required": {
    "name": "是否必填",
    "value": false,
    "descr": ""
  }
},
rules:[{
  
}]

将属性一一绑定到自己写的组件之上（不必担心取值问题 利用form表单特性劫持数据 可一键获取）

属性解析

<template>
  <a-date-picker
    :style="`width:${record.options.width.value}`"          //绑定动态宽度
    v-if="record.type === 'date'"                           //判断组件的type属性是否为date 从而渲染组件
    :disabled="record.options.disabled || parentDisabled"   //是否禁用 parentDisabled默认为false
    :show-time="record.options.showTime.value"              //是否开启 时分秒选择
    :allowClear="record.options.clearable.value"            //一键清空icon图标
    :placeholder="record.options.placeholder.value"         //默认提示语
    :format="record.options.dateformat.defValue"            //绑定时间格式 例如：'YYYY-MM-DD'
    @change="handleSelectChange"
    //时间选择器value改变时触发的方法在此方法内部将moment时间对象转化为标准时间 例如：2020-05-08
    :value="date"                                           //绑定时间选择器value值
/>
</template>


进入src/packages/KFormDesign/module/formItemProperties  将现有属性一一绑定到操作栏 

此处数据直接取options 真实环境下为selectItem 例如：

<!-- 标题 -->
<a-form-item
  v-if="typeof selectItem.label !== 'undefined' && typeof selectItem.options.title !== 'undefined'"
  :label="selectItem.options.title.name"
>
  <a-input v-model="selectItem.options.title.value" :maxLength="20"/>
</a-form-item>

<!-- 提示值 -->
<a-form-item
  v-else-if="typeof options.placeholder !== 'undefined'"
  :label="options.placeholder.name"
>
  <a-input v-model="options.placeholder.value" :maxLength="20"/>
</a-form-item>

<!-- 宽度 -->
<a-form-item v-if="typeof options.width !== 'undefined' && selectItem.type != 'date'" :label="options.width.name">
  <a-radio-group v-model="options.width.defValue">
    <a-radio :value="itemLB.value" :style="radioStyle" v-for="itemLB in options.width.value">
        {{itemLB.label}}
    </a-radio>
  </a-radio-group>
</a-form-item>

<!-- 默认值 --> dateChange方法用于val改变时
<a-form-item v-if="selectItem.type === 'date'" :label="options.currentDate.name">
    <a-checkbox v-model="options.currentDate.value" @change="dateChange(options.currentDate.value,options)">{{options.currentDate.name}}</a-checkbox>
</a-form-item>
<!-- 是否显示时分秒选择界面 -->
<a-form-item v-if="selectItem.type === 'date'" :label="options.showTime.name">
    <a-checkbox v-model="options.showTime.value">{{options.showTime.name}}</a-checkbox>
</a-form-item>

<!-- 日期格式选择 -->
<a-form-item
  v-if="typeof options.dateformat !== 'undefined'"
  :label="options.dateformat.name"
>
  <a-select 
    :options="options.dateformat.value" 
    v-model="options.dateformat.defValue"
    placeholder="请选择"
  />
</a-form-item>


<!-- 校验 -->
<a-form-item
  v-if="
    typeof selectItem.rules !== 'undefined' &&
      selectItem.rules.length > 0
  "
  label="校验"
>
  <kCheckbox v-model="selectItem.rules[0].required" :label="selectItem.options.required.name"/>
  <a-input
    v-show='selectItem.rules[0].required'
    v-model="selectItem.rules[0].message"
    :maxLength="20"
    placeholder="必填校验提示信息"
  />
</a-form-item>

## 新增组件完成