<template>
  <el-form 
    ref="fForm" 
    :key="update" 
    :rules="rules" 
    class="flex-wrap f-form" 
    :class="text ? 'text' : ''"
    :model="form"
    :label-position="labelPosition">
    <el-form-item
      v-for="(item, index) in configList"
      :key="'form-item' + index"
      :ref="'formItem'+item.prop"
      :label-width="setWidth(item, index)"
      :label="item.label"
      :prop="item.prop"
      :style="{
        width: !autoWidth
          ? (item.span && colVal * item.span + '%') || colVal + '%'
          : 'auto'
      }"
      class="pb-10 mb-8"
      :class="getClass(item,index)"
      :rules="item.rules"
      :required="item.disabled ? false : item.required"
    >
      <div :style="{ width: item.width || itemWidth }">
        <components
          v-if="!item.hasSlot && item.itemType !== 'text' && item.itemType"
          :is="'f-' + item.itemType"
          v-model="form[item.prop]"
          v-bind="{ disabled:formItemDisabled(item),...item.attrs }"
          @change="handleEmit($event,item,'change')"
          @blur="handleEmit($event,item,'blur')"
          @focus="handleEmit($event,item,'focus')"
        />
        <span v-else-if="!item.hasSlot && item.itemType === 'text'" class="text-break-all" :class="(item.click?'f-cursor--pointer link-type':'') +(item.className || '')" @click="()=>{item.click && item.click(item,form)}">
          {{
            (item.formatter && item.formatter(form)) ||( formatter(item,form[item.prop]))
          }}
        </span>
        <slot v-else v-bind="item" :name="item.prop" />
        
        <slot v-if="item.orderSlot" :name="item.orderSlot" /></slot>
      </div>
      <!-- label插槽 -->
      <template v-if="item.hasLabelSlot" #label>
        <template v-if="item.hasLabelSlot">
          <slot v-bind="item" :name="item.prop + 'Label'" />
        </template>
      </template>
    </el-form-item>
    <el-form-item
      v-if="$slots.default"
      label-width="0px"
      class="flex-auto slot"
    >
      <slot />
    </el-form-item>
  </el-form>
</template>

<script>
import { formatNumber } from '../../utils/index';
import formMixins from'../../mixins/formMixins.js'

export default {
  name: 'FForm',
  mixins:[formMixins],
  props: {
    config: { type: Array, default: () => [] }, // 配置文件
    form: {
      type: Object,
      default: () => {}
    }, // 传进来的共享的form表单值对象
    rules: { type: Object, default: () => ({}) }, // 传进来的共享的form验证规则
    column: { type: Number, default: 4 }, // 总的col布局
    itemWidth: { type: String, default: '100%' }, // form-item项的宽度
    disabled: { type: Boolean, default: false },
    clearable: { type: Boolean, default: true },
    // label位置
    labelPosition: {
      type: String,
      default: 'top'
    },
    // 是否自动宽度
    autoWidth: {
      type: Boolean,
      default: false
    },
    // 是否文字展示
    text: {
      type: Boolean,
      default: false
    },
  },
  data() {
    return {
      configdata: [],
      update: 0
    };
  },
  computed: {
    // 组件内部config
    configList() {
      return this.config;
    },
    // 整体列数对应的col
    colVal() {
      return 100 / this.column;
    },
    labelWidth() {
      // rowList每一行的数据，初始化的时候给一个二维数组，并制定第一个参数为new Array（）
      // columnList每一列的数据
      const rowList = [new Array(this.column)];
      const columnList = [];
      // count用来计算是否换行新增rowList的数组元素空数组，用来填补二维数组空位
      // index代表的是rowList的当前操作项的下标
      let count = 0;
      let index = 0;
      this.config.forEach((e, i, arr) => {
        count += e.span || 1;
        rowList[index][count - (e.span || 1)] = {
          name: e.label || '',
          prop: e.prop,
          index: i
        };
        if (
          count + ((arr[i + 1] || {}).span || 1) > this.column &&
          arr[i + 1]
        ) {
          rowList.push(new Array(this.column));
          index++;
          count = 0;
        }
      });
      // 行数据转列数据
      rowList.forEach((e) => {
        for (let i = 0; i < e.length; i++) {
          if (!columnList[i]) {
            columnList[i] = [];
          }
          columnList[i].push(e[i]);
        }
      });
      // 取出每一列最大值nameLength
      // 取出每一列的index下标
      return columnList.map((e) => {
        const nameLength = Math.max.apply(
          null,
          e.map((el) => (el && this.charCode(el.name).length / 4) || 0)
        );
        let hasRules = false;
        e.map((el) => {
          if (
            el &&
            el.name &&
            this.rules[el.prop] &&
            this.rules[el.prop][0].required
          ) {
            hasRules = true;
          }
        });
        const indexList = e.map((el) => el && el.index);
        return { nameLength, indexList, hasRules };
      });
    }
  },
  methods: {
    // 表单重置
    resetFields(){
      this.$refs.fForm.resetFields();
    },
    // 优先子组件自己的 再表单的
    formItemDisabled(item){
      if(item.attrs&&item.attrs.hasOwnProperty('disabled')){
        return item.attrs.disabled
      }
      return this.isDisabled
    },
    // 获取class
    getClass(item, ind) {
      const { labelPosition, column, configList } = this;
      let classStr = ''
      // 计算当前配置是不是没行最后一个
      let allSpan = 0;
      let pr = 'pr-8';
      for (let _index = 0; _index <= Number(ind); _index++) {
        const newSpan = configList[_index].span || 1;
        allSpan += newSpan;
      }
      if (allSpan % column === 0) {
        pr = '';
      }
      classStr += pr;

      if (item.itemClass) {
        classStr += item.itemClass;
      }
      return classStr;
    },
    // 通过labelWidth获取对应index里面的值
    setWidth(item, index) {
      // 增加rules为入参，判断当前项是否有必填校验，如果有那么width加上11px；
      const val = this.labelWidth.find((e) => e.indexList.includes(index));
      const rulesWidth = val.hasRules ? 11 : 0;
      return val.nameLength * 14 + rulesWidth + 16 + 'px';
    },
    // 将字符串转为16进制值，汉子转4位，英文字母和数组转2位
    charCode: (str) =>
      str
        .split('')
        .reduce((total, e) => total + e.codePointAt(0).toString(16), ''),

    //   格式化
    formatter(column, v) {
      if (v === null || v === undefined) return '-';
      let value = v;
      const { dataType } = column;
      const type = dataType || '';
      if (value !== '') {
        if (type === 'money') {
          value = formatNumber(value);
        } else if (type === 'ten-thousand') {
          value = formatNumber(value, 'ten-thousand');
        } else if (type === 'number' || type === 'area') {
          let decimal = 2;
          if (type === 'number') {
            decimal = 0;
          }
          value = formatNumber(value, null, decimal);
        } else if (type === 'rate') {
          value = formatNumber(value, 'rate');
        } else if (type === 'date-d') {
          // value = value
        }
      }
      if(value === '0' || value === 0) return value
      return value || '-';
    },

    // 事件传递
    handleEmit($event,item,type){
      item[type] && item[type]($event);
      this.$emit(type,item,this.form)
    },

    // 校验
    validate(callback){
      return new Promise(resolve=>{
        this.$refs.fForm.validate(resolve);
      })
    }
  }
};
</script>
<style lang="scss" scoped>
.f-form .el-form-item {
  margin-bottom: 25px;
  // display: flex;
  // align-items: center;
  .el-change-icon {
    transform: rotate(90deg);
  }
  .el-form-item_custom {
    cursor: pointer;
    i {
      margin-left: 2px;
    }
  }
}

</style>
