<template>
  <div class="by-form" :style="{ width: attrs.width }">
    <el-descriptions v-if="attrs.showType == 'desc'" :title="attrs.title" :column="attrs.itemCount" :border="attrs.border"
      :direction="attrs.direction" :size="attrs.size ? attrs.size : 'medium'" :colon="attrs.colon"
      contentClassName="clas123">
      <template v-for="(itemChild, index) of columns">
        <el-descriptions-item :label="item.label" v-for="(item, _ind) of itemChild" :span="item.colspan"
          :key="index + '-' + _ind">
          <slot v-if="item.descSlot" :name='item.prop + "_desc"' :value='value'></slot>
          <template v-else>{{ value[item.prop] ? value[item.prop] : '--' }}</template>
        </el-descriptions-item>
      </template>
    </el-descriptions>
    <el-form class="byForm" v-else :style="{ height: attrs.height ? attrs.height + 'px' : 'auto' }" :model="value"
      ref="byForm" :validate-on-rule-change="false" :size="attrs.size ? attrs.size : 'small'" :inline-message="true"
      v-bind="$attrs" :disabled="attrs.disabled" :label-width="attrs.labelWidth ? attrs.labelWidth : '100px'"
      :rules="attrs.readonly ? {} : attrs.rules" :label-position="attrs.labelPosition ? attrs.labelPosition : ''">
      <el-row class="form-row" v-for="(itemChild, index) of columns" :key="index">
        <el-col v-for="(item, _ind) of itemChild" :span="item.span" :key="'itemChild' + _ind">
          <el-form-item class="by-form-item" :label="item.label" :rules="attrs.readonly ? [] : item.rules" :prop="item.prop"
            :required="item.required" :error="item.error" :size="item.size" :label-width="item.labelWidth">
            <component v-bind:is="item.component" class="form-comp" :propConfig="item.compConfig"
              :ref="item.prop + suffixCode" :parentValue="value" :propValue="value[item.prop]"
              @onChange="onChange($event, item)" v-bind="$attrs" v-on="$listeners" />
            <slot v-if="item.slot" :name='item.prop' :value='value'></slot>
            <!-- <slot :[item.prop]="value" ></slot> -->
            <div class="readonly-cover" v-if="attrs.readonly"></div>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <!-- <el-button @click="getValueData">获取数据</el-button> -->
  </div>
</template>

<script lang="ts">
/*
  基础配置
  config:{
    attr:{
      width:'', //表单宽度
      showType: ''  //展示形式
      title:''  //标题（desc的时候用）
      itemCount:''  //每行展示几列（desc的时候用）
      border：true/false  //是否有边框（desc的时候用）
      direction: vertical / horizontal  排列的方向（desc的时候用）
      colon：true/false  //是否显示冒号 （desc的时候用）
      disabled:true/false //表单禁用
      readonly:true/false //表单只读
      size:medium / small / mini, //表单域下组件的尺寸,
      height:'',  //高度
      labelPosition: right/left/top //标签位置
      labelWidth:  '' //标签的宽度
      rules:[]  //验证规则
    },
    columns: [[{   //表单列
        span:''  //分栏，
        label:''  //标签
        prop:''  //字段
        labelWidth:'' 标签的的宽度
        rule:{}  //验证规则
        size：medium / small / mini  //表单域下组件的尺寸,
        component:''   //组件
        compConfig:{}  //组件配置
        slot：true/false  //插槽
        colspan：''  //在itemCount的基础上 列的数量（desc的时候用）
        descSlot：true/false  //插槽（desc的时候用）
    }]]
    request:{
      url:'',
      method:'',
      headers:{},
      data:{}
    }
  }
 */
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import VueViews from '@/benyun/compVue/VueViews'
@Component
export default class ByForm extends VueViews {
  value: any = {}
  suffixCode = "--comp"
  get columns() {
    let columns: Array<any> = this.config?.columns ? this.config.columns : []
    //分栏设置
    if (columns.length > 0) {
      for (const itemChild of columns) {
        let spans = 24
        let n = itemChild.length
        for (const item of itemChild) {
          if (item && ((Number(item.span) > 0 && Number(item.span) <= 24))) {
            spans = spans - Number(item.span)
            n--;
          }
        }

        for (const item of itemChild) {
          if (Number(item.span) > 0 && Number(item.span) <= 24) {
            item.span = Number(item.span)
          } else {
            item.span = spans / n
          }
        }

      }
    }
    return columns
  }

  created() {
    if (this.propConfig) {
      this.setConfig(this.propConfig)
    }
  }
  mounted() {
    if (this.attrs.data) {
      this.setValue(this.attrs.data);
    }
  }
  getValueData() {
    console.log('表单数据', this.value)
  }
  //设置数据
  setValue(data: any) {
    if (data) {
      this.value = (this as any).$lodash.cloneDeep(data);
    } else {
      this.value = {};
    }
    this.$nextTick(() => {
      this.setChildrenComValue();
    })
    setTimeout(() => {
      this.clearValidate();
    }, 100)
    this.$forceUpdate();
  }

  clearValue() {
    this.value = {};
    this.clearChildrenComp();
    this.defaultHandle();
    setTimeout(() => {
      this.clearValidate();
    }, 100)
  }

  //获取数据
  getValue() {
    return (this as any).$lodash.cloneDeep(this.value);
  }
  //设置表单内某组件配置
  setCompConfig(code: any, c: any) {
    if (this.$refs[code + this.suffixCode] && (this.$refs[code + this.suffixCode] as any)[0] && (this.$refs[code + this.suffixCode] as any)[0].setConfig) {
      (this.$refs[code + this.suffixCode] as any)[0].setConfig(c)
    }
  }
  setConfigAfter() {
    this.$nextTick(() => {
      if (this.columns.length > 0) {
        for (const itemData of this.columns) {
          for (const item of itemData) {
            if (this.$refs[item.prop + this.suffixCode] && (this.$refs[item.prop + this.suffixCode] as any)[0] && (this.$refs[item.prop + this.suffixCode] as any)[0].setConfig) {
              (this.$refs[item.prop + this.suffixCode] as any)[0].setConfig(item.compConfig)
            }
          }
        }
      }
    })
  }

  //清除下级组件组件值
  clearChildrenComp() {
    for (const key in this.$refs) {
      if (key.indexOf(this.suffixCode) >= 0 && (this as any).$refs[key][0] && (this as any).$refs[key][0].clearValue) {
        (this as any).$refs[key][0].clearValue()
      }
    }
  }
  //下级组件默认值
  defaultHandle() {
    for (const key in this.$refs) {
      if (key.indexOf(this.suffixCode) >= 0 && (this as any).$refs[key][0] && (this as any).$refs[key][0].defaultHandle) {
        (this as any).$refs[key][0].defaultHandle()
      }
    }
  }

  //设置下级组件值
  setChildrenComValue() {
    for (const key in (this as any).$refs) {
      if (key.indexOf(this.suffixCode) >= 0 && (this as any).$refs[key] && (this as any).$refs[key][0] && (this as any).$refs[key][0].setValue) {
        const code = key.split(this.suffixCode)[0];
        if (this.value) {
          (this as any).$refs[key][0].setValue(this.value[code])
        } else {
          (this as any).$refs[key][0].setValue(null)
        }
      }
    }
  }

  //表单数据变化
  onChange(v: any, config: any) {
    let code = config.prop;
    if (v && (v as any).constructor === Object) {
      for (const key in v) {
        this.changeSetValue(key, v[key])
      }
    } else {
      this.changeSetValue(code, v)
    }
    if ((this as any).$refs.byForm) {
      (this as any).$refs.byForm.validateField(code);
    }
    this.$emit('formChange', { value: v, code: code })
  }

  changeSetValue(code: string, v: any) {
    if (this.value[code]) {
      this.value[code] = v;
    } else {
      Vue.set(this.value, code, v);
    }
  }
  //表单验证
  validate(parames?: any): Promise<any> {
    return new Promise((resolve: Function, reject: Function) => {
      if (!this.$refs.byForm) {
        resolve(true)
      }
      const failHandel = () => {
        if (!parames || !parames.noMsg) {
          (this as any).$message({
            message: '验证未通过，请检查！',
            type: 'warning',
          })
        }
        reject()
      }
      (this as any).$refs.byForm.validate((valid: any) => {
        if (valid) {
          let va = true
          for (const col of this.columns) {
            for (const item of col) {
              if (this.$refs[item.prop + this.suffixCode] && (this.$refs[item.prop + this.suffixCode] as any)[0] && (this.$refs[item.prop + this.suffixCode] as any)[0].validate) {
                va = (this.$refs[item.prop + this.suffixCode] as any)[0].validate()
                if (!va) break
              }
            }
            if (!va) break
          }
          if (va) {
            resolve(true)
          } else {
            failHandel()
          }

        } else {
          failHandel()
        }
      });
    })
  }
  //清除过滤提示
  clearValidate() {
    if (this.$refs.byForm) {
      (this.$refs.byForm as any).clearValidate();
    }
  }
}
</script>

<style lang="scss" scoped>
.by-form {
  width: 100%;
  margin: 0 auto;

  .form-comp {
    width: 100%;
  }

  .readonly-cover {
    position: absolute;
    height: 100%;
    width: 100%;
    left: 0;
    top: 0;
  }
}
</style>

<style lang="scss">
.by-form-item {
  margin-bottom: 10px !important;
}
</style>