text: import Vue from 'vue';
  import merge from 'element-ui/src/utils/merge';
  import { getKeysMap, getRowIdentity, getColumnById, getColumnByKey, orderBy, toggleRowStatus } from '../util';
  import expand from './expand';
  import current from './current';
  import tree from './tree';
  
  const sortData = (data, states) => {
    const sortingColumn = states.sortingColumn;
    if (!sortingColumn || typeof sortingColumn.sortable === 'string') {
      return data;
    }
    return orderBy(data, states.sortProp, states.sortOrder, sortingColumn.sortMethod, sortingColumn.sortBy);
  };
  
  const doFlattenColumns = (columns) => {
    const result = [];
    columns.forEach((column) => {
      if (column.children) {
        result.push.apply(result, doFlattenColumns(column.children));
      } else {
        result.push(column);
      }
    });
    return result;
  };
  
  export default Vue.extend({
    data() {
      return {
        states: {
          // 3.0 版本后要求必须设置该属性
          rowKey: null,
  
          // 渲染的数据来源，是对 table 中的 data 过滤排序后的结果
          data: [],
  
          // 是否包含固定列
          isComplex: false,
  
          // 列
          _columns: [], // 不可响应的
          originColumns: [],
          columns: [],
          fixedColumns: [],
          rightFixedColumns: [],
          leafColumns: [],
          fixedLeafColumns: [],
          rightFixedLeafColumns: [],
          leafColumnsLength: 0,
          fixedLeafColumnsLength: 0,
          rightFixedLeafColumnsLength: 0,
  
          // 选择
          isAllSelected: false,
          selection: [],
          reserveSelection: false,
          selectOnIndeterminate: false,
          selectable: null,
  
          // 过滤
          filters: {}, // 不可响应的
          filteredData: null,
  
          // 排序
          sortingColumn: null,
          sortProp: null,
          sortOrder: null,
  
          hoverRow: null
        }
      };
    },
  
    mixins: [expand, current, tree],
  
    methods: {
      // 检查 rowKey 是否存在
      assertRowKey() {
        const rowKey = this.states.rowKey;
        if (!rowKey) throw new Error('[ElTable] prop row-key is required');
      },
  
      // 更新列
      updateColumns() {
        const states = this.states;
        const _columns = states._columns || [];
        states.fixedColumns = _columns.filter((column) => column.fixed === true || column.fixed === 'left');
        states.rightFixedColumns = _columns.filter((column) => column.fixed === 'right');
  
        if (states.fixedColumns.length > 0 && _columns[0] && _columns[0].type === 'selection' && !_columns[0].fixed) {
          _columns[0].fixed = true;
          states.fixedColumns.unshift(_columns[0]);
        }
  
        const notFixedColumns = _columns.filter(column => !column.fixed);
        states.originColumns = [].concat(states.fixedColumns).concat(notFixedColumns).concat(states.rightFixedColumns);
  
        const leafColumns = doFlattenColumns(notFixedColumns);
        const fixedLeafColumns = doFlattenColumns(states.fixedColumns);
        const rightFixedLeafColumns = doFlattenColumns(states.rightFixedColumns);
  
        states.leafColumnsLength = leafColumns.length;
        states.fixedLeafColumnsLength = fixedLeafColumns.length;
        states.rightFixedLeafColumnsLength = rightFixedLeafColumns.length;
  
        states.columns = [].concat(fixedLeafColumns).concat(leafColumns).concat(rightFixedLeafColumns);
        states.isComplex = states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0;
      },
  
      // 更新 DOM
      scheduleLayout(needUpdateColumns) {
        if (needUpdateColumns) {
          this.updateColumns();
        }
        this.table.debouncedUpdateLayout();
      },
  
      // 选择
      isSelected(row) {
        const { selection = [] } = this.states;
        return selection.indexOf(row) > -1;
      },
  
      clearSelection() {
        const states = this.states;
        states.isAllSelected = false;
        const oldSelection = states.selection;
        if (oldSelection.length) {
          states.selection = [];
          this.table.$emit('selection-change', []);
        }
      },
  
      cleanSelection() {
        const states = this.states;
        const { data, rowKey, selection } = states;
        let deleted;
        if (rowKey) {
          deleted = [];
          const selectedMap = getKeysMap(selection, rowKey);
          const dataMap = getKeysMap(data, rowKey);
          for (let key in selectedMap) {
            if (selectedMap.hasOwnProperty(key) && !dataMap[key]) {
              deleted.push(selectedMap[key].row);
            }
          }
        } else {
          deleted = selection.filter(item => data.indexOf(item) === -1);
        }
        if (deleted.length) {
          const newSelection = selection.filter(item => deleted.indexOf(item) === -1);
          states.selection = newSelection;
          this.table.$emit('selection-change', newSelection.slice());
        }
      },
  
      toggleRowSelection(row, selected, emitChange = true) {
        const changed = toggleRowStatus(this.states.selection, row, selected);
        if (changed) {
          const newSelection = (this.states.selection || []).slice();
          // 调用 API 修改选中值，不触发 select 事件
          if (emitChange) {
            this.table.$emit('select', newSelection, row);
          }
          this.table.$emit('selection-change', newSelection);
        }
      },
  
      _toggleAllSelection() {
        const states = this.states;
        const { data = [], selection } = states;
        // when only some rows are selected (but not all), select or deselect all of them
        // depending on the value of selectOnIndeterminate
        const value = states.selectOnIndeterminate
          ? !states.isAllSelected
          : !(states.isAllSelected || selection.length);
        states.isAllSelected = data.length !== 0 && value;
  
        let selectionChanged = false;
        data.forEach((row, index) => {
          if (states.selectable) {
            if (states.selectable.call(null, row, index) && toggleRowStatus(selection, row, value)) {
              selectionChanged = true;
            }
          } else {
            if (toggleRowStatus(selection, row, value)) {
              selectionChanged = true;
            }
          }
        });
  
        if (selectionChanged) {
          this.table.$emit('selection-change', selection ? selection.slice() : []);
        }
        this.table.$emit('select-all', selection);
      },
  
      updateSelectionByRowKey() {
        const states = this.states;
        const { selection, rowKey, data } = states;
        const selectedMap = getKeysMap(selection, rowKey);
        data.forEach(row => {
          const rowId = getRowIdentity(row, rowKey);
          const rowInfo = selectedMap[rowId];
          if (rowInfo) {
            selection[rowInfo.index] = row;
          }
        });
      },
  
      updateAllSelected() {
        const states = this.states;
        const { selection, rowKey, selectable } = states;
        // data 为 null 时，解构时的默认值会被忽略
        const data = states.data || [];
        if (data.length === 0) {
          states.isAllSelected = false;
          return;
        }
  
        let selectedMap;
        if (rowKey) {
          selectedMap = getKeysMap(selection, rowKey);
        }
        const isSelected = function(row) {
          if (selectedMap) {
            return !!selectedMap[getRowIdentity(row, rowKey)];
          } else {
            return selection.indexOf(row) !== -1;
          }
        };
        let isAllSelected = true;
        let selectedCount = 0;
        for (let i = 0, j = data.length; i < j; i++) {
          const item = data[i];
          const isRowSelectable = selectable && selectable.call(null, item, i);
          if (!isSelected(item)) {
            if (!selectable || isRowSelectable) {
              isAllSelected = false;
              break;
            }
          } else {
            selectedCount++;
          }
        }
  
        if (selectedCount === 0) isAllSelected = false;
        states.isAllSelected = isAllSelected;
      },
  
      // 过滤与排序
      updateFilters(columns, values) {
        if (!Array.isArray(columns)) {
          columns = [columns];
        }
        const states = this.states;
        const filters = {};
        columns.forEach(col => {
          states.filters[col.id] = values;
          filters[col.columnKey || col.id] = values;
        });
  
        return filters;
      },
  
      updateSort(column, prop, order) {
        if (this.states.sortingColumn && this.states.sortingColumn !== column) {
          this.states.sortingColumn.order = null;
        }
        this.states.sortingColumn = column;
        this.states.sortProp = prop;
        this.states.sortOrder = order;
      },
  
      execFilter() {
        const states = this.states;
        const { _data, filters } = states;
        let data = _data;
  
        Object.keys(filters).forEach((columnId) => {
          const values = states.filters[columnId];
          if (!values || values.length === 0) return;
          const column = getColumnById(this.states, columnId);
          if (column && column.filterMethod) {
            data = data.filter((row) => {
              return values.some(value => column.filterMethod.call(null, value, row, column));
            });
          }
        });
  
        states.filteredData = data;
      },
  
      execSort() {
        const states = this.states;
        states.data = sortData(states.filteredData, states);
      },
  
      // 根据 filters 与 sort 去过滤 data
      execQuery(ignore) {
        if (!(ignore && ignore.filter)) {
          this.execFilter();
        }
        this.execSort();
      },
  
      clearFilter(columnKeys) {
        const states = this.states;
        const { tableHeader, fixedTableHeader, rightFixedTableHeader } = this.table.$refs;
  
        let panels = {};
        if (tableHeader) panels = merge(panels, tableHeader.filterPanels);
        if (fixedTableHeader) panels = merge(panels, fixedTableHeader.filterPanels);
        if (rightFixedTableHeader) panels = merge(panels, rightFixedTableHeader.filterPanels);
  
        const keys = Object.keys(panels);
        if (!keys.length) return;
  
        if (typeof columnKeys === 'string') {
          columnKeys = [columnKeys];
        }
  
        if (Array.isArray(columnKeys)) {
          const columns = columnKeys.map(key => getColumnByKey(states, key));
          keys.forEach(key => {
            const column = columns.find(col => col.id === key);
            if (column) {
              // TODO: 优化这里的代码
              panels[key].filteredValue = [];
            }
          });
          this.commit('filterChange', {
            column: columns,
            values: [],
            silent: true,
            multi: true
          });
        } else {
          keys.forEach(key => {
            // TODO: 优化这里的代码
            panels[key].filteredValue = [];
          });
  
          states.filters = {};
          this.commit('filterChange', {
            column: {},
            values: [],
            silent: true
          });
        }
      },
  
      clearSort() {
        const states = this.states;
        if (!states.sortingColumn) return;
  
        this.updateSort(null, null, null);
        this.commit('changeSortCondition', {
          silent: true
        });
      },
  
      // 适配层，expand-row-keys 在 Expand 与 TreeTable 中都有使用
      setExpandRowKeysAdapter(val) {
        // 这里会触发额外的计算，但为了兼容性，暂时这么做
        this.setExpandRowKeys(val);
        this.updateTreeExpandKeys(val);
      },
  
      // 展开行与 TreeTable 都要使用
      toggleRowExpansionAdapter(row, expanded) {
        const hasExpandColumn = this.states.columns.some(({ type }) => type === 'expand');
        if (hasExpandColumn) {
          this.toggleRowExpansion(row, expanded);
        } else {
          this.toggleTreeExpansion(row, expanded);
        }
      }
    }
  });
  