<template>
  <component class="es-box-card ed-table-editor-card" :is="tempName" :title="title" :shadow="shadow" :body-style="bodyStyle" :is-title="isTitle">
    <template #operate>
      <slot name="extra">
        <el-button v-if="isAdd" icon="el-icon-plus" size="small" type="text" @click="handleAdd">新增</el-button>
      </slot>
    </template>

    <el-form ref="ElForm" :model="form" :rules="rules">
      <el-table ref="ElTable" :data="form.data" v-bind="_bindTableAttrs()" v-on="tableOn" v-loading="loading">
        <!-- 是否显示拖拽-->
        <el-table-column v-if="isDrag" align="center" class-name="ed-drag--cursor_move" width="40px">
          <i class="el-icon-rank"></i>
        </el-table-column>

        <!-- element-ui table-column组件 -->
        <template v-for="(col, index) in columns">
          <el-table-column :key="index" v-bind="col">
            <!-- table-column 作用域插槽； type 为 index / selection 时直接显示序号  -->
            <template v-if="!col.type || !['selection', 'index'].includes(col.type)" v-slot:default="scope">
              <!-- 对外暴露的作用域插槽 -->
              <slot :data="form.data[scope.$index]" :name="col.prop" v-bind="scope">
                <!-- 判断是否定义了children 属性 -->
                <template v-if="col.children">
                  <!-- children 为字符串类型, 直接渲染 span 标签 -->
                  <span v-if="typeof col.children === 'string'">{{ col.children }}</span>

                  <!-- children 为其它类型, 则按照动态组件渲染 -->
                  <el-form-item :prop="`data.${scope.$index}.${col.prop}`" :rules="rules[col.prop]">
                    <!-- 组件 -->
                    <component :is="col.children.tags"
                               v-model="scope.row[col.children.valueKey || col.prop]"
                               :class="col.children.class"
                               :style="col.children.style"
                               v-bind="getAttrs(scope, col.children)"
                               @change="emitChange(col, $event, scope.row, scope.$index)"
                               @input="handleChange(col.children.valueKey || col.prop, scope.$index, $event)">
                      <template v-if="col.children.options">
                        <ed-option-slot
                            v-for="(option, index) of col.children.options"
                            :key="index"
                            :data="option"
                            :optionAttrs="option.attrs"
                            :tags="col.children.tags"
                        ></ed-option-slot>
                      </template>
                    </component>
                  </el-form-item>
                </template>

                <!-- 没有定义children则这显示对应的文本值 -->
                <template v-else>{{ col.prop && getContentText(scope, col) }}</template>
              </slot>
            </template>
          </el-table-column>

          <!-- type 为 index / selection -->
          <!-- <el-table-column v-if="col.type && ['selection', 'type'].includes(col.type)" :key="index"
                           v-bind="col"></el-table-column> -->
        </template>
        <!-- 操作 -->
        <el-table-column v-if="isOperate"  v-bind="operateProps">
          <template v-slot:default="scope">
            <slot name="operate" v-bind="{ self, scope, ...scope }">
              <el-button type="text" @click="handleDelete(scope.$index)">删除</el-button>
            </slot>
          </template>
        </el-table-column>
      </el-table>
    </el-form>
  </component>
</template>

<script>
import props, {TableProps} from './Props'
import validate            from "./hooks/validate";
import {getVarType}        from "../../../tools/utils";
import Sortable            from '../../../plugin/sortable';

export default {
  name: "EdTableEditor",
  props: props,
  mixins: [validate],
  data() {
    return {
      self: this,
      // 表单数据对象
      form: {
        data: []
      },
      bodyStyle:{
        padding: '5px'
      },
    }
  },
  model: {
    prop: 'value',
    event: 'change'
  },
  watch: {
    value: {
      handler(newVal, oldVal) {
        if (newVal) {
          this._setTableData(JSON.parse(JSON.stringify(newVal)))
        }
      },
      deep: true,
      immediate: true
    }
  },
  computed:{
    tempName(){
      return this.isCard ? "ed-card" : "div"
    },
    isOperate(){
      if(getVarType(this.operate) === 'boolean') {
        return this.operate
      }
      else if(getVarType(this.operate) === 'object'){
        return Object.keys(this.operate).length > 0
      }
      return false
    },
    operateProps(){
      let  defProp = {
        align:"center",
        fixed:"right",
        headerAlign:"center",
        label:"操作",
        minWidth: '140px'
      }
      if(getVarType(this.operate) === 'object') {
        return Object.assign(defProp, this.operate)
      }
      else {
        return defProp
      }
    }
  },
  mounted() {
    this._rowDrop()
  },
  methods: {
    _bindTableAttrs() {
      const props = Object.assign({}, this.$attrs, this.$props);
      Object.keys(props).map(prop => {
        if (!Object.prototype.hasOwnProperty.call(TableProps, prop)) {
          delete props[prop]
        }
      })
      return props
    },

    // 处理checkbox，radio的值
    _setTableData(newVal) {
      newVal.map((item, index) => {
        this.columns.map((col, i) => {
          if (col.children && col.children.tags === 'el-radio-group' && getVarType(item[col.prop]) === 'object') {
            item[col.prop] = item[col.prop].value
          } else if (col.children && col.children.tags === 'el-checkbox-group' && getVarType(item[col.prop]) === 'object') {
            let data = []
            item[col.prop].map(i => data.push(i.value))
            item[col.prop] = data
          }
        })
      })
      this.$set(this.form, 'data', newVal)
    },

    // 行拖拽
    _rowDrop() {
      const tbody = this.$refs.ElTable.$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0];
      let _this = this
      Sortable.create(tbody, {
        disabled: !this.isDrag, // 是否开启拖拽
        ghostClass: 'sortable-ghost', //拖拽样式
        group: {
          name: 'words',
          pull: true,
          put: true
        },
        animation: 150, // ms, number 单位：ms，定义排序动画的时间
        onEnd({newIndex, oldIndex}) { // 结束拖拽
          let currRow = _this.form.data.splice(oldIndex, 1)[0]
          _this.form.data.splice(newIndex, 0, currRow)
          _this.emitChange()
        }
      })
    },

    // 获取数据
    getData() {
      return this.form.data
    },

    /**
     * @name validate
     * @return {Promise<unknown>}
     * @description 数据校验
     */
    validate(callback) {
      return this.$refs.ElForm.validate(callback)
    },

    /**
     * 调用父组件的 change 函数
     */
    emitChange(col, val, row, index) {
      if (col && col.change) {
        col.change(col, val, row, index)
      }
      this.$emit('change', this.form.data)
      this.$emit("valueChange", {col: col, val: val, row: row, index: index});
    },

    // 值变化
    handleChange(prop, index, value) {
      this.validateOneValue(prop, index, value)
    },

    // 新增
    handleAdd() {
      let data = {}
      this.columns.filter(i=> !Object.prototype.hasOwnProperty.call(i, 'type')).map(col => {
        if (col.children?.tags === 'el-checkbox-group') {
          data[col.prop] = []
        } else if (col.children?.tags === 'el-switch') {
          data[col.prop] = false
        } else {
          data[col.prop] = ""
        }
      })
      this.form.data.push(data)
      this.emitChange()
    },

    // 删除
    handleDelete(index) {
      this.form.data.splice(index, 1)
      this.$emit('change', this.form.data)
    },

    // 获取属性 (为了将disabled统一设置)
    getAttrs(scope, item) {
      const attrs = typeof item.attrs === 'function' ? item.attrs(scope, this.value) : item.attrs
      return Object.assign({}, {disabled: this.disabled}, attrs)
    },

    // 获取文本内容
    getContentText(scope, item) {
      let text = scope.row[item.prop]
      // 通过options获取枚举值
      if (item.options && item.options[text]) {
        text = item.options[text]
      }
      // 通过 formatter 获取格式化的值
      if (item.formatter) {
        text = item.formatter(scope.row, scope.column)
      }
      return text
    }
  }
}
</script>

<style lang="scss" scoped>
@import "../../../style/index";

::v-deep {
  .el-table .cell {
    overflow: visible;
  }

  .el-form-item {
    margin-bottom: 0;
  }

  .el-icon-s-operation {
    font-size: 20px;
  }
}
</style>
