Source: packages/PageForm/index.vue

<!--  -->
<template>
  <a-form-model :ref="formKey" :model="form" :label-col="layout_.labelCol" :wrapper-col="layout_.wrapperCol" :rules="formRules" style="width: 100%;">
    <div class="p-page-form-con" :style="getLayoutStyle">
      <div
        :key="'p-page-form-item-' + index"
        v-for="(item, index) in formList"
        class="item"
        :style="getItemOccupiedNum(item)"
      >
        <a-form-model-item  :label="item.cnName" :style="['label','imgGroup'].indexOf(item.type)>=0?'width: 100%; margin-bottom: 0px;':'width: 100%;'" :prop="item.enName" v-bind="item.formItemAttr || {}" >
          <a-input v-if="item.type === 'input'" v-model="item.value" v-bind="item.itemAttr || {}" @change="(...ages)=>{changeEvent(item,...ages)}"/>
          <p-ImgGroup  v-if="item.type === 'imgGroup'" v-model="item.value"  v-bind="item.itemAttr || {}"  @change="(...ages)=>{changeEvent(item,...ages)}"></p-ImgGroup>
          <p-UpLoadFile  v-if="item.type === 'UpLoad'" v-model="item.value"  v-bind="item.itemAttr || {}" @change="(...ages)=>{changeEvent(item,...ages)}"></p-UpLoadFile>
          <p-Cascader  v-if="item.type === 'cascader'" v-model="item.value" :optionsList="item.optionList"  :itemAttr="item.itemAttr || {}" @change="(...ages)=>{changeEvent(item,...ages)}"></p-Cascader>
          <p-InputRange  v-if="item.type === 'inputRange'" v-model="item.value" v-bind="item.itemAttr || {}"  @change="(...ages)=>{changeEvent(item,...ages)}"></p-InputRange>
          <!-- <p-RadioGroup  v-if="item.type === 'radioGroup'" v-model="item.value" :optionsList="item.optionList"  :itemAttr="item.itemAttr || {}" ></p-RadioGroup> -->
          <p-TextGroup  v-if="item.type === 'TextGroup'" v-model="item.value"   v-bind="item.itemAttr || {}" @textGroupEvent="textGroupEvent"></p-TextGroup>


          <!-- <a-date-picker  v-if="item.type === 'datePicker'" v-model="item.value" valueFormat="YYYY-MM-DD" type="date" v-bind="item.itemAttr || {}"/> -->
          <a-date-picker v-if="item.type === 'datePicker'"
            v-bind="item.itemAttr || {}"
            v-model="item.value"
            :locale="locale"
            @change="(...ages)=>{changeEvent(item,...ages)}"
          />
          <!-- :default-value="moment(item.value, 'YYYY-MM-DD')" -->
          <!-- type="date"
            valueFormat="YYYY-MM-DD"
            format="YYYY-MM-DD" -->
          <!-- @change="(...args)=>{onDateChange(...args,item)}" -->
          <a-range-picker v-bind="item.itemAttr || {}" v-if="item.type === 'rangePicker'"   :locale="locale"  v-model="item.value" @change="(...ages)=>{changeEvent(item,...ages)}"  @panelChange="(...ages)=>{rangePickerPanelChange(item,index,...ages)}" />

          
          <div v-bind="item.itemAttr || {}" v-if="item.type === 'label'">  {{ item.value }} </div>

          <a-select v-bind="item.itemAttr || {}" v-if="item.type === 'select'" v-model="item.value" @change="(...ages)=>{changeEvent(item,...ages)}">
            <a-select-option :key="(optItem.enName  || optItem.value )+ optIndex" v-for="(optItem, optIndex) in item.optionList"
              :value="optItem.enName || optItem.value" v-bind="optItem">
              {{ optItem.cnName || optItem.label }}
            </a-select-option>
          </a-select>

          <a-checkbox-group v-bind="item.itemAttr || {}" v-if="item.type === 'checkboxGroup'" :options="item.optionList"  v-model="item.value" @change="(...ages)=>{changeEvent(item,...ages)}"/>

          <a-textarea v-bind="item.itemAttr || {}" v-if="item.type=== 'textarea'" v-model="item.value"  @change="(...ages)=>{changeEvent(item,...ages)}"/>

          <a-radio-group v-bind="item.itemAttr || {}" v-if="item.type === 'radioGroup'" v-model="item.value" @change="(...ages)=>{changeEvent(item,...ages)}">
            <a-radio v-if="!item.itemAttr.type || item.itemAttr.type=='radio'" :key="(optItem.enName || optItem.value) + optIndex" v-for="(optItem, optIndex) in item.optionList"
              :value="optItem.enName || optItem.value" v-bind="optItem">
              {{ optItem.cnName || optItem.label }}
            </a-radio>
            <a-radio-button v-if="item.itemAttr.type && item.itemAttr.type=='button'" :key="(optItem.enName || optItem.value) + optIndex" v-for="(optItem, optIndex) in item.optionList"
              :value="optItem.enName || optItem.value" v-bind="optItem">
              {{ optItem.cnName || optItem.label }}
            </a-radio-button>
          </a-radio-group>

          <!-- item.itemAttr.type=='custom1' && -->
          <slot v-if="item.type === 'custom' && !item.componentName" :name="item.enName" :value="item.value" :itemData="{ attr: item.itemAttr || {}, value: item.value }" ></slot>

          <component v-if="item.type=='custom' && item.componentName" :is="item.componentName" v-bind="item.itemAttr || {}" v-model="item.value" @change="(...ages)=>{changeEvent(item,...ages)}"></component>

        </a-form-model-item>
      </div>
    </div>
  </a-form-model>
</template>

<script>
import IS from "./../utils/is";
import UUID from "./../utils/uuid";
import PCascader from './components/cascader.vue'
// import PInputRange from './components/InputGroup.vue'
import PRadioGroup from './components/RadioGroup.vue'
// import PTextGroup from './components/TextGroup.vue'
import moment from 'moment';
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN';
// import Vue from 'Vue';
export default {
  // import引入的组件需要注入到对象中才能使用
  name: "PPageForm",
  components: {PCascader,PRadioGroup},
  props: {
    // columnNum 此值必填  表示表单按照几列进行布局 默认值为 3
    // rowNum 此值选填 表示表单按几行进行布局 ,先设置一个初值,之后会根据formDataList的值自动进行校正  默认值为 4
    // rowHeight: 设置行高,默认为 100px
    // rowGap 此值选填 表示表单的每一行之间的间隙 默认值为 1px
    // coliumnGap 此值选填 表示表单每一列之间的间隙  默认值为 10px
    // labelCol 此值选填  为 Form 本身属性,label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12} 请参照 Form  span: 4
    // wrapperCol 此值选填  为 Form 本身属性,需要为输入控件设置布局样式时,使用该属性,用法同 labelCol   请参照 Form  span: 14
    /**
     * 用于控制表单布局
     * @prop {Object} layout   { rowNum: 4, columnNum: 3, rowGap: "1px", rowHeight:'100px', coliumnGap: "10px", labelCol: { span: 4 }, wrapperCol: { span: 14 }, }
     *  columnNum 此值必填  表示表单按照几列进行布局 默认值为 3
     *  rowNum 此值选填 表示表单按几行进行布局 ,先设置一个初值,之后会根据formDataList的值自动进行校正  默认值为 4
     *  rowHeight: 设置行高,默认为 100px
     *  rowGap 此值选填 表示表单的每一行之间的间隙 默认值为 1px
     *  coliumnGap 此值选填 表示表单每一列之间的间隙  默认值为 10px
     *  labelCol 此值选填  为 Form 本身属性,label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12} 请参照 Form  span: 4
     *  wrapperCol 此值选填  为 Form 本身属性,需要为输入控件设置布局样式时,使用该属性,用法同 labelCol   请参照 Form  span: 14
     */
    layout: {
      type: Object,
      default: ()=>{ return { rowNum: 4, columnNum: 3, rowGap: "1px", rowHeight:'100px', coliumnGap: "10px", labelCol: { span: 4 }, wrapperCol: { span: 14 }, }},
    },
    // 表示表单的校验规则 此对象中的key值将与formDataList中的enName的值对应 详细可参考 Form 的 rules	表单验证规则
    formRules:{type: Object,  default:()=>{
      return {
        // userName1: [
        //   { required: true, message: 'Please input Activity name', trigger: 'blur' },
        //   { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
        // ],
        // userName2: [{ required: true, message: 'Please select Activity zone', trigger: 'blur' }],
        // userName3: [{ required: true, message: 'Please pick a date', trigger: 'blur' }],
        // userName4: [
        //   {
        //     required: true,
        //     message: 'Please select at least one activity type',
        //     trigger: 'blur',
        //   },
        // ],
        // userName5: [
        //   { required: true, message: 'Please select activity resource', trigger: 'blur' },
        // ],
        // userName6: [{ required: true, message: 'Please input activity form', trigger: 'blur' }],
      }
    } },
    // 表单数据
    // enName 表示表单字段英文名称,主要用于最后表单返回的key
    // cnName 表示表单字段中文名称,主要用于表单的label
    // type   表示表单项的类型,包含:input  select 等,具体参照
    formDataList:{type:Array, required: false, default:()=>{ return [
        // { enName:'userName1', cnName:'用户名1', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName2', cnName:'用户名2', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName3', cnName:'用户名3', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName4', cnName:'用户名4', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName5', cnName:'用户名5', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName6', cnName:'用户名6', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName7', cnName:'用户名7', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName8', cnName:'用户名8', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName9', cnName:'用户名9', type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName10',cnName:'用户名10',type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName11',cnName:'用户名11',type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
        // { enName:'userName12',cnName:'用户名12',type:'input',value:'',numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},},
    ]}},
    // 表单的事件
    PEvent:{type:Function},
    showHelp:{type:Boolean, default: () => { return false }}
  },
  data() {
    // 这里存放数据
    return {
      // moment,
      locale,
      formKey:UUID(),
      layout_: { rowNum: 4, columnNum: 3, rowGap: "1px", rowHeight:'100px', coliumnGap: "10px", labelCol: { span: 4 }, wrapperCol: { span: 14 }, }, // rowNum: 4, columnNum: 3, rowGap: "1px", coliumnGap: "2px"
      formList: [],
      form: {},
      // 存放字段事件
      eventList:{},
      formChangeKey:'',
      formListItemKeys:{}
    };
  },
  // 监听属性 类似于data概念
  computed: {
    getLayoutStyle() {
      const res = {
        "grid-template-columns": "",
        "grid-template-rows": "",
        gap: "",
      };
      const { rowNum, columnNum, rowGap, rowHeight, coliumnGap } = this.layout;
      res["grid-template-columns"] = new Array(columnNum)
        .fill(`${100 / columnNum}%`)
        .join(" ");
      // res['grid-template-rows'] = new Array(rowNum).fill(`${100/rowNum}%`).join(' ')
      //     grid-template-rows: repeat(auto-fill, 100px);
      // grid-template-columns: repeat(auto-fill, 100px);
      // res['grid-template-columns'] = new Array(columnNum).fill(`repeat(auto-fill, 100px)`).join(' ')
      res["grid-template-rows"] = new Array(Math.ceil(rowNum))
        .fill(`repeat(auto-fill, ${rowHeight})`)
        .join(" ");
      res["gap"] = `${rowGap} ${coliumnGap}`;
      return res;
    },
  },
  // 监控data中的数据变化
  watch: {
    layout: {
      handler(val) {
       this.layout_ = {...this.layout_,...val}
      },
      deep: true,
      immediate: true,
    },
    formDataList: {
      handler(val) {
        const newDataKey = UUID('MDUUID',JSON.stringify(val))
        if(!this.formChangeKey){
          this.formChangeKey = newDataKey
          this.registerComponent(val)
          this.setLayout(val);
          this.setFormValue(val)
        }else{
          if(this.formChangeKey != newDataKey){
            this.formChangeKey = newDataKey
            this.registerComponent(val)
            this.setLayout(val);
            this.setFormValue(val)
          }
        }
      },
      deep: true,
      immediate: true,
    },
    formList: {
      handler(val) {
        const tempObj = {}
        val.forEach(item=>{
          const {enName,value}= item
          tempObj[enName] = value
        })
        this.form = {...this.form,...tempObj}
      },
      deep: true,
      // immediate: true,
    },
    form: {
      handler(val, oldVal) {
        // this.eventList
        // Object.keys(val).forEach(key=>{
        //   if(val[key] != oldVal[key] && this.eventList[key]){
        //     // console.log('判断更新===》',val[key] != oldVal[key] && this.eventList[key],oldVal[key],val[key]);
        //   }
        // })
        // if(!IS.isNullOrUnDef(val) && !IS.isEmpty(val)){
        //   this.PEvent && this.PEvent('formChange',val)
        // }
      },
      deep: true,
      // immediate: true,
    },

  },
  // 生命周期 - 创建完成(可以访问当前this实例)
  created() {},
  // 生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {
    // this.formList = this.createFormItem(12);
    // console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@==1===>',UUID('MDUUID',JSON.stringify({name:'小明',age:12,class:[]})));
    // console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@==2===>', UUID('MDUUID',JSON.stringify({name:'小明',age:12,class:[{name:'一般',sss:'12'}]})));
    if(this.$isShowHelp == true &&this.showHelp==true){
      console.log(`
      组件名称:
          PPageForm
      使用方法:
          <p-PageForm ref="PPageForm" :formDataList="[]" >
            <template v-slot:userName7="{value, itemData}" >
              <a-date-picker :format="'YYYY-MM-DD'"v-model="value" v-bind="itemData || {}"/>
            </template>
          </p-PageForm>
          备注:
            <template v-slot:userName7="{value, itemData}" ></template>  中的 【v-slot:userName7="{value, itemData}"】 是固定用法,
            userName7 :表示 【formDataList】中对应的数据的【enName】的值
            value : 表示 【formDataList】中对应的数据的【value】的值,可用于绑定v-model
            itemData : 表示 【formDataList】中对应的数据的 【itemAttr + value】 的值 ,如:{attr: itemAttr || {}, value: value }

      props属性说明
          props: {
            // 表单的事件
            // 参数: @param {string} type  对应的取值有:change 、textGroupEvent 、formChange; change 表示表单项值的change事件 ; textGroupEvent 表示 【TextGroup】类型 的点击事件; formChange 表示表单上的值变化事件
            // 参数: @param {*} item
            // 参数: @param {*} data

            PEvent:{type:Function},
            // columnNum 此值必填  表示表单按照几列进行布局 默认值为 3
            // rowNum 此值选填 表示表单按几行进行布局 ,先设置一个初值,之后会根据formDataList的值自动进行校正  默认值为 4
            // rowGap 此值选填 表示表单的每一行之间的间隙 默认值为 1px
            // rowHeight: 设置行高,默认为 100px
            // coliumnGap 此值选填 表示表单每一列之间的间隙  默认值为 10px
            // labelCol 此值选填  为 Form 本身属性,label 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12} 或 sm: {span: 3, offset: 12} 请参照 Form  span: 4
            // wrapperCol 此值选填  为 Form 本身属性,需要为输入控件设置布局样式时,使用该属性,用法同 labelCol   请参照 Form  span: 14
            layout: {
              type: Object,
              default: ()=>{ return { rowNum: 4, columnNum: 3, rowGap: "1px", rowHeight:'100px', coliumnGap: "10px", labelCol: { span: 4 }, wrapperCol: { span: 14 }, }},
            },
            // 表示表单的校验规则 此对象中的key值将与formDataList中的enName的值对应 详细可参考 Form 的 rules	表单验证规则
            formRules:{type: Object,
              default:()=>{
                return {
                  // userName1: [
                  //   { required: true, message: 'Please input Activity name', trigger: 'blur' },
                  //   { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
                  // ],
                }
              }
            },


            // 表单数据
              // enName 此项必填 表示表单字段英文名称,主要用于最后表单返回的key
              // cnName 此项必填 表示表单字段中文名称,主要用于表单的label
              // type   此项必填   表示表单项的类型,包含如下:
                        input           对应的value值的类型: String
                        select,         对应的value值的类型: String || Array
                        checkboxGroup,  对应的value值的类型: String || Array
                        textarea,       对应的value值的类型: String
                        radioGroup,     对应的value值的类型: String
                        inputRange,     对应的value值的类型: Array                // input范围  可接受input的所有属性  对应的value 是数组
                        datePicker,     对应的value值的类型: moment 具体参照  https://1x.antdv.com/components/date-picker-cn/
                        rangePicker,    对应的value值的类型: moment[]    自定义日期范围选择   具体参照 https://1x.antdv.com/components/date-picker-cn/  中的 RangePicker
                        cascader,       对应的value值的类型: Array
                        imgGroup,       对应的value值的类型: Array     // 展示图片用的(可参照【PImgGroup】的帮助文档)  [{url:'',title:''}]  || ['url1','url1']   || [{ status:'success' | 'error' | 'info' | 'warning'| '404' | '403' | '500',statusTitle:''}]  ||  [{url:'',title:'', isShowWatermark: true}]
                        UpLoad,         对应的value值的类型:
                        TextGroup,      对应的value值的类型: Array     // 用于展示 【 字符串(text)  link按钮(link) 】格式的数据,其中个数可选,搭配任意。 此项可配点击事件,事件将会触发表单的【PEvent】事件(对应的type值为:textGroupEvent);  如: value:[{ type: 'text', label: '待定', border: true, isEvent: true }, { type: 'link', label: '查看核定通知书', isEvent: true },]
                        label,          对应的value值的类型: String    // 此类型用于显示值 一般的文本
                        custom,         对应的value值的类型: 请参照自定义组件要求填写   // 自定义组件可在 标签内使用<p-PageForm> </p-PageForm>
              // componentName 此项可选  表示自定义组件名称,和【type = 'custom'】 配套使用,使用场景为:当自定义组件不想使用插槽的方式时可使用此方式    如在<p-QueryCard>组件中想要扩展自定义查询条件时,可用此方式
              // componentItem 此项可选  表示自定义组件本身,和【type = 'custom'】 配套使用,使用场景为:当自定义组件不想使用插槽的方式时可使用此方式    如在<p-QueryCard>组件中想要扩展自定义查询条件时,可用此方式
              // value 此项必填 表单元素的预设值;此项值的类型需要根据所使用的的表单项类型不同而不同,详情参看上面的 【type】的对应类型
              // numRowsOccupied 此项可选 表示当前表单项所占的行数 默认值 1行
              // numColumnOccupied 此项可选  表示当前表单项所占列数  默认值 1列 最大值不能超过 【columnNum】 的值
              // formItemAttr 此项可选  表示【a-form-model】所对应的属性,具体请参照 https://1x.antdv.com/components/form-model-cn/#Form.Item  中   【Form.Item 】 的属性
              // itemAttr 此项可选  表示表单项对应的属性值,可对自定义组件进行传值
              // optionList 此项可选 表示表单项所需要使用的数据
              // isChangeEvent 此项可选 表示是否监听表单项的变化,具体会通过【PEvent】返回
            formDataList:{type:Array, required: false, default:()=>{ return [
                // { enName:'userName1', cnName:'用户名1', type:'input',value:'', componentName:'Pbutton', componentItem:Pbutton, numRowsOccupied: 1, numColumnOccupied: 1 ,formItemAttr:{},itemAttr:{},optionList:[],isChangeEvent:true,},
                // { enName:'userName2', cnName:'用户名2', type:'input',value:''},
            ]}}
          }

      表单提交事件的使用
          方法名称: onSubmit
          参数: @param {Function} backFun     参数(formRes)为表单结果 如: {userName1:'',userName2:''}
          使用方式: this.$refs['PPageForm'].onSubmit((formRes)=>{})   ||  const formRes = await this.$refs['PPageForm'].onSubmit()  ||  this.$refs['PPageForm'].onSubmit().then(formRes=>{})
      `);
    }
  },
  // 方法集合
  methods: {
    registerComponent(componentlist){
      // console.log('注册组件======》',componentlist);
      componentlist.forEach(item=>{
        const {componentItem,componentName} = item
        if(!IS.isNullOrUnDef(componentItem)){
          // Vue.component(componentName,componentItem)
          this.$VUE.component(componentName,componentItem)
        }
      })
      // console.log('注册组件 1======》',Vue);
    },
    changeEvent(item,...args){
      const {eventList, form, PEvent, $nextTick} = this
      // console.log('changeEvent 1======>',item);
      // console.log('changeEvent 2======>',...args);
      const changeList = {
        select:(value, option)=>{
          // console.log('判断更新===》',item.enName,value)
          this.PEvent && this.PEvent('change',item.enName,value)
        },
        checkboxGroup:(checkedValue)=>{
          this.PEvent && this.PEvent('change',item.enName,checkedValue)
        },
        textarea:(e)=>{
          this.PEvent && this.PEvent('change',item.enName,e.target.value)
        },
        radioGroup:(e)=>{
          this.PEvent && this.PEvent('change',item.enName,e.target.value)
        },
        rangePicker:(dates,dateStrings)=>{
          // function(dates: [moment, moment] | [string, string], dateStrings: [string, string])
          this.PEvent && this.PEvent('change',item.enName,dates)
        },
        datePicker:(date,dateString)=>{
          // function(date: moment | string, dateString: string)
          this.PEvent && this.PEvent('change',item.enName,date)
        },
        cascader:(value, selectedOptions)=>{
          this.PEvent && this.PEvent('change',item.enName,value)
        },
        input:(e)=>{
          this.PEvent && this.PEvent('change',item.enName,e.target.value)
        },
        UpLoad:(val)=>{
          this.PEvent && this.PEvent('change',item.enName,val)
        }
      }
      eventList[item.enName] && changeList[item.type] && changeList[item.type](...args)
      if(!IS.isNullOrUnDef(form) && !IS.isEmpty(form)){
        $nextTick(()=>{
          setTimeout(() => {
            PEvent && PEvent('formChange','form',form)
          }, 500);
        })
      }
    },
    rangePickerPanelChange(item,index,value, mode){
      const {itemAttr} = item
      const getDateFormat = (item_)=>{
        const mode_ = item_.itemAttr['mode']
        const format_ = item_.itemAttr['format']
        let valFormat = 'YYYY-MM'
        if(!IS.isNullOrUnDef(mode_) && !IS.isEmpty(mode_)){
          if(IS.isArray(mode_)){
            valFormat = mode_[0]
          }
        }
        if(!IS.isNullOrUnDef(format_) && !IS.isEmpty(format_)){
          valFormat = format_
        }
        return valFormat
      }
      const type = getDateFormat(item)
      const tempVal = [moment(value[0]).format(type),moment(value[1]).format(type)]
      // console.log('rangePickerPanelChange=====>',item,index,tempVal, mode,this.formList,item.itemAttr['format']);
      this.formList[index].value =tempVal
      itemAttr['mode'] && (item.itemAttr['mode'] = [...itemAttr['mode']])
      itemAttr['mode'] && (this.formList[index].itemAttr['mode'] = [...itemAttr['mode']])
    },
    getMomentVal(dateStr,dateFormat){
      return !dateStr?null:moment(dateStr,dateFormat)
    },
   
    textGroupEvent(label){
      const {PEvent} = this
      PEvent && PEvent('textGroupEvent',label)
    },
    createFormItem(count_) {
      const itemObj = { numRowsOccupied: 1, numColumnOccupied: 2 };
      const tempArr = new Array(count_).fill({});
      for (let i = 0; i < 5; i++) {
        const ll = Math.floor(Math.random() * (11 - 1) + 1);
        tempArr[ll] = { ...itemObj };
      }
      return tempArr;
    },
    getItemOccupiedNum(item) {
      const tempStyle = {};
      const { columnNum } = this.layout;
      // numRowsOccupied 表示占几行  numColumnOccupied 表示占几列
      const { numRowsOccupied, numColumnOccupied } = item;
      if (IS.isNumber(numColumnOccupied)) {
        let tempNumColumnOccupied = numColumnOccupied;
        if (columnNum < numColumnOccupied) {
          tempNumColumnOccupied = columnNum;
        }
        tempStyle["grid-row-end"] = 1;
        tempStyle["grid-column-end"] = `span ${tempNumColumnOccupied || 1}`;
        tempStyle["grid-row-end"] = `span ${numRowsOccupied || 1}`;
      }
      return tempStyle;
    },
    setLayout(dataList) {
      const { columnNum } = this.layout_;
      let tempRowCount = dataList.length / columnNum;
      dataList.forEach((item) => {
        const { numRowsOccupied, numColumnOccupied } = item;
        if (IS.isNumber(numColumnOccupied) && numColumnOccupied > 1) {
          // 行数加1
          if (IS.isNumber(numRowsOccupied)) {
            tempRowCount = tempRowCount + numRowsOccupied;
          } else {
            // tempRowCount = tempRowCount + numColumnOccupied
            tempRowCount += 1;
          }
        }
      });
      this.layout_.rowNum = tempRowCount;
    },
    setFormValue(dataList){
      this.setFormValueNew(dataList)
      // // this.form
      // const tempObj = {}
      // const tempArr = dataList
      // dataList.forEach((item,index_)=>{
      //   const {enName,value,isChangeEvent,key} = item
      //   const newKey = UUID('MDUUID',JSON.stringify(item))
      //   tempObj[enName] = value
      //   if(!key){
      //     tempArr[index_].key = newKey
      //   }
      //   // tempArr.push({...item,key:UUID('MDUUID',JSON.stringify(item))})
      //   this.eventList[enName] = isChangeEvent || false
      // })
      // console.log('重新渲染=======》',dataList,tempArr);
      // // this.formListItemKeys
      // this.formList = tempArr
      // this.form = tempObj
    },
    setFormValueNew(dataList){
      const getKey = (val)=>{
        return UUID('MDUUID',JSON.stringify(val))
      }
      const tempObj = {}
      const tempArr = []
      const listItemKey = {}
      if(this.formList.length==0){
        dataList.forEach(item=>{
          const {enName,value,isChangeEvent} = item
          tempObj[enName] = value
          const newKey = getKey(item)
          tempArr.push({...item,key:newKey})
          listItemKey[enName] = newKey
          this.eventList[enName] = isChangeEvent || false
        })
        this.formListItemKeys = listItemKey
        this.formList = tempArr
        this.form = tempObj
      }else{
        const tempList = []
        const createItem = (enName_,value_,newKey_,item_,index_,isChangeEvent_)=>{
          this.formListItemKeys[enName_] = newKey_
          this.form[enName_] = value_
          tempList.push(Object.assign({},this.formList[index_],{...item_,key:newKey_}))
          this.eventList[enName_] = isChangeEvent_ || false
        }

        dataList.forEach((item,index)=>{
          const {enName,value,isChangeEvent,key} = item
          const newKey = getKey(item)
          const oldKey = key // this.formListItemKeys[enName]
          if(oldKey){
            if(oldKey != newKey){
              // 新的数据key和老的数据key不一样,直接创建新的key和对应的数据
              createItem(enName,value,newKey,item,index,isChangeEvent)
            }else{
              tempList.push(item)
            }
          }else{
            // 没有指定字段的key,直接创建新的key和对应的数据
            createItem(enName,value,newKey,item,index,isChangeEvent)
          }
        })
        this.formList = tempList

      }
    },

    resetForm(){
      this.setFormValue(this.formDataList)
    },
    onSubmit(backFun){
      const self=this
      return new Promise((resolve, reject) => {
        self.$refs[self.formKey].validate(valid => {
          if (valid) {
            backFun && backFun(self.form)
            resolve(self.form);
          } else {
            console.log('error submit!!');
            reject('error submit!!');
            return false;
          }
        });

      })
    },
  },
};
</script>
<style lang="less" scoped>
.p-page-form-con {
  // width: 300px;
  // height: 200px;
  // background: #9c5b5b;
  // border: 3px solid #f2f30e;
  display: grid;
  grid-template-columns: 1fr 1fr;
  // grid-template-rows: 1fr 1fr 1fr 1fr;
  gap: 2px 3px;
  justify-content: center;
  //  在容器中设置grid-auto-flow 属性可以改变单元格排列方式
  // column 按列排序  row	按行排列   dense	元素使用前面空余栅格
  grid-auto-flow: row;
  // overflow: auto;
  .item {
    // height: 40px;
    // line-height: 40px;
    // border: 1px solid red;
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
    overflow: hidden;
    // padding: 5px;
  }
  // .item:nth-child(3) {
  //   // grid-row-start: 1;
  //   grid-row-end:1;
  //   /* 占几列 */
  //   grid-column-end: span 3;
  //   /* 占几行 */
  //   grid-row-end: span 1;
  // }
}
</style>