<template>
  <vxe-grid :scroll-x="scrollX"
            :scroll-y="scrollY"
            v-bind="$attrs"
            v-on="new$listeners"
            ref="vxeGrid"
            :columns="columns"
            :keep-source="keepSource"
            :show-overflow="showOverflow"
            class="x-table"
            :keyboard-config="realKeyboardConfig"
            :footer-method="realFooterMethod"
            :radio-config="realRadioConfig"
            :checkbox-config="realCheckboxConfig"
            @filter-change="handleFilterChange"
            @custom="handleCustomChange"
            @resizable-change="handleResizableChange">
    <template v-for="(item, index) in slotArray" v-slot:[item]="scope">
      <slot :name="item" v-bind="scope"></slot>
    </template>
  </vxe-grid>
</template>

<script>
import keyDownCaptureMixin from '../../mixins/key-down-capture-mixin';
import {Grid} from 'vxe-table';
import mouseDownCaptureMixin from '../../mixins/mouse-down-capture-mixin';
import tableSettingMixin from '../../mixins/table-setting-mixin';
import {EXPAND_CHANGE, SIDE_BAR_LOCK_CHANGE, WINDOW_RESIZE, ROOT_DIALOG_RESIZE_EVENT_NAME} from '../../constant/eventKey';
import {convertSortList, countSingleColumn, setTabindex} from '../../util/componentUtil';
function getSlotArray(array, columns) {
  if (!Array.isArray(columns)) {
    return;
  }
  for (const item of columns) {
    if (item.children) {
      getSlotArray(array, item.children);
    }
    if (item.slots) {
      for (const key in item.slots) {
        const slot = item.slots[key];
        if ((typeof slot).toLowerCase() === 'string' || slot instanceof String) {
          array.push(slot);
        }
      }
    }
  }
}

function footerMethod({columns, data}) {
  return [
    columns.map((column, columnIndex) => {
      if (columnIndex === 0) {
        return '合计';
      }
      const params = column.params;
      if (!params || !params.showFooterCount) {
        return null;
      }
      return countSingleColumn({column, rows: data});
    })
  ];
}

export default {
  name: 'XTable',
  components: {
    [Grid.name]: Grid
  },
  mixins: [tableSettingMixin, keyDownCaptureMixin, mouseDownCaptureMixin], // 表格变化保存到服务器
  inheritAttrs: false,
  props: {
    scrollX: {
      type: Object,
      default() {
        return {enabled: false};
      }
    },
    scrollY: {
      type: Object,
      default() {
        return {enabled: false};
      }
    },
    keepSource: {
      type: Boolean,
      default: true
    },
    columns: {
      type: Array,
      default() {
        return [];
      }
    },
    showOverflow: {
      type: [Boolean, String],
      default: 'tooltip'
    },
    keyboardConfig: Object,
    footerMethod: Function,
    radioConfig: Object,
    checkboxConfig: Object
  },
  mounted() {
    if (!this.addListListenerFlag) {
      this.$root.$on(ROOT_DIALOG_RESIZE_EVENT_NAME, this.handleWindowResize);
      // 监听大小变化，然后重新渲染列表
      this.$root.$on(WINDOW_RESIZE, this.handleWindowResize);
      this.$root.$on(SIDE_BAR_LOCK_CHANGE, this.handleSidebarLockChange);
      this.$root.$on(EXPAND_CHANGE, this.handleExpandChange);
      this.addListListenerFlag = true;
    }
  },
  activated() {
    if (this.$windowResize) {
      this.$windowResize = false;
      this.getGridInstance().recalculate(true);
    }
  },
  deactivated() {
    this.getGridInstance().closeTooltip();
  },
  methods: {
    getRecords () {
      const grid = this.getGridInstance();
      const row = grid.getRadioRecord();
      if (row) {
        return [row];
      }
      return grid.getCheckboxRecords();
    },
    getMouseDownCaptureDom() {
      return this.getGridInstance().$el;
    },
    getKeyDownCaptureDom() {
      return setTabindex({element: this.getGridInstance().$el});
    },
    onKeyDownCapture(event) {
      this.$emit('keydown-capture', {$event: event, $grid: this.getGridInstance()});
    },
    onMouseDownCapture(event) {
      this.$emit('mousedown-capture', {$event: event, $grid: this.getGridInstance()});
    },
    handleSortChange (args) {
      // 为了在表头显示多列排序的列顺序，这里先注释上面的代码
      const {sortList} = args;
      const columns = this.getGridInstance().getTableColumn().fullColumn;
      for (const item of columns) {
        if (item.params) {
          delete item.params.sortNumber;
        }
      }
      this.sortList = convertSortList({
        currentSortList: sortList,
        lastSortList: this.sortList
      });
      for (let i = 0; i < this.sortList.length; i++) {
        const item = this.sortList[i].column;
        if (!item.params) {
          item.params = {};
        }
        item.params.sortNumber = i + 1;
      }
      // 如果父组件的模板中直接传入了sort-change，就不需要通过这个方法发射事件
      // 经测试发现，如果本组件或者父组件模板中没有传入sort-change，直接使用$on来监听，回调不会被调用，vxe-table应该是根据$listener来判断是否需要$emit
      // 以下拷贝vxe-table的源码
      // _xeUtils.default.each($listeners, function (cb, type) {
      //   ons[type] = function () {
      //     for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      //       args[_key] = arguments[_key];
      //     }
      //
      //     _vm.$emit.apply(_vm, [type].concat(args));
      //   };
      // });
      // 通过new$listeners来控制事件发射，使handleSortChange的逻辑比父组件监听的事件先执行
      // this.sortList是按照点击顺序来排列的，更符合使用的习惯
      args.originSortList = args.sortList;
      args.sortList = this.sortList;
      this.$emit('sort-change', args);
    },
    handleFilterChange (args) {
      if (this.$listeners['filter-change']) {
        return;
      }
      this.$emit('filter-change', args);
    },
    handleCustomChange (event) {
      if (event.type !== 'confirm' && event.type !== 'reset') {
        return;
      }
      setTimeout(() => {
        // 隐藏或者显示部分字段后，表头层级有可能发生变化，需要重新初始化
        this.initColumnDrag();
        this.saveTableColumnMsg();
      }, 0);
    },
    recalculate(bool) {
      return this.getGridInstance().recalculate(bool);
    },
    reloadRow(rows, record, field) {
      this.getGridInstance().reloadRow(rows, record, field);
    },
    loadData(arr) {
      return this.getGridInstance().loadData(arr);
    },
    setActiveCell(row, fieldOrColumn) {
      return this.getGridInstance().setActiveCell(row, fieldOrColumn);
    },
    handleExpandChange() {
      if (this._inactive) {
        return;
      }
      this.$windowResize = false;
      this.getGridInstance().recalculate(true);
    },
    handleWindowResize($dialog) {
      if ($dialog) {
        this.getGridInstance().recalculate(true);
        return;
      }
      if (!this._inactive) {
        // 如果处于activated状态，会自动重新渲染，不需要调用调用重新计算的方法
        // 但是点击最大化按钮和还原按钮，不会重新计算，
        // 目前无法监听最大化和还原按钮的事件，因此这里仍然需要调用一次列表的计算
        this.getGridInstance().recalculate(true);
        this.$windowResize = false;
        return;
      }
      // 否则就等到activated方法调用时再重新计算
      this.$windowResize = true;
    },
    handleSidebarLockChange() {
      if (!this._inactive) {
        // 如果处于activated状态，就直接重新计算表格
        this.$windowResize = false;
        this.getGridInstance().recalculate(true);
        return;
      }
      this.$windowResize = true;
    },
    getScroll() {
      return this.getGridInstance().getScroll();
    },
    scrollTo(scrollLeft, scrollTop) {
      return this.getGridInstance().scrollTo(scrollLeft, scrollTop);
    },
    getColumns() {
      return this.getGridInstance().getColumns();
    },
    loadColumn(columns) {
      return this.getGridInstance().loadColumn(columns);
    },
    getCheckboxRecords() {
      return this.getGridInstance().getCheckboxRecords();
    },
    removeCheckboxRow() {
      return this.getGridInstance().removeCheckboxRow();
    },
    getRadioRecord() {
      return this.getGridInstance().getRadioRecord();
    },
    getTableData() {
      return this.getGridInstance().getTableData();
    },
    getGridInstance() {
      return this.$refs.vxeGrid;
    },
    setActiveRow(row) {
      return this.getGridInstance().setActiveRow(row);
    },
    getTableColumn() {
      return this.getGridInstance().getTableColumn();
    },
    clearSort(fieldOrColumn) {
      this.getGridInstance().clearSort(fieldOrColumn);
    },
    handleResizableChange ({ column }) {
      setTimeout(() => {
        this.saveTableColumnMsg();
      }, 0);
    }
  },
  computed: {
    new$listeners() {
      // 为了避免父组件监听子组件的方法被重复调用，替换了部分监听方法
      return Object.assign({}, this.$listeners, {
        'sort-change': this.handleSortChange
      });
    },
    realFooterMethod() {
      return this.footerMethod ? this.footerMethod : footerMethod;
    },
    realKeyboardConfig() {
      // isArrow必须要传，如果是undefined，调用setCellAreas时即使目标单元格在可见范围内都会导致滚动条滚动
      const defaultConfig = {isClip: true, isArrow: true, isEnter: true, isTab: true};
      if (this.keyboardConfig === undefined) {
        return defaultConfig;
      }
      if (this.keyboardConfig === null) {
        return null;
      }
      return Object.assign({}, defaultConfig, this.keyboardConfig);
    },
    slotArray() {
      const array = [];
      getSlotArray(array, this.columns);
      return array;
    },
    realRadioConfig() {
      const defaultConfig = {highlight: true};
      if (this.radioConfig) {
        Object.assign(defaultConfig, this.radioConfig);
      }
      return defaultConfig;
    },
    realCheckboxConfig() {
      const defaultConfig = {highlight: true};
      if (this.checkboxConfig) {
        Object.assign(defaultConfig, this.checkboxConfig);
      }
      return defaultConfig;
    }
  },
  watch: {
    columns: {
      handler(val) {
        for (const item of val) {
          if (item.sortable !== true) {
            continue;
          }
          if (!item.slots) {
            item.slots = {};
          }
          item.slots.header = ({column}, createElement) => {
            const params = column.params;
            if (!params || !params.sortNumber) {
              return [createElement('span', {}, column.title)];
            }
            return [createElement('span', {}, column.title), createElement('span', {class: 'table-header-sort-number'}, params.sortNumber)];
          };
        }
      },
      immediate: true
    }
  },
  beforeDestroy() {
    this.getGridInstance().closeTooltip();
    if (this.addListListenerFlag) {
      this.$root.$off(ROOT_DIALOG_RESIZE_EVENT_NAME, this.handleWindowResize);
      this.$root.$off(WINDOW_RESIZE, this.handleWindowResize);
      this.$root.$off(SIDE_BAR_LOCK_CHANGE, this.handleSidebarLockChange);
      this.$root.$off(EXPAND_CHANGE, this.handleExpandChange);
      this.addListListenerFlag = false;
    }
  }
};
</script>
