import XEUtils from 'xe-utils/methods/xe-utils'
import GlobalConfig from '../../conf'
import VXETable from '../../v-x-e-table'
import VxeTableBody from '../../body'
import { UtilTools, GlobalEvent } from '../../tools'
import methods from './methods'

/**
 * 渲染浮固定列
 * 分别渲染左边固定列和右边固定列
 * 如果宽度足够情况下,则不需要渲染固定列
 * @param {Function} h 创建 VNode 函数
 * @param {Object} $table 表格实例
 * @param {String} fixedType 固定列类型
 */
function renderFixed (h, $table, fixedType) {
  let { tableData, tableColumn, visibleColumn, collectColumn, isGroup, vSize, showHeader, showFooter, columnStore, footerData } = $table
  let fixedColumn = columnStore[`${fixedType}List`]
  return h('div', {
    class: `plx-table--fixed-${fixedType}-wrapper`,
    ref: `${fixedType}Container`
  }, [
    showHeader ? h('plx-table-header', {
      props: {
        fixedType,
        tableData,
        tableColumn,
        visibleColumn,
        collectColumn,
        size: vSize,
        fixedColumn,
        isGroup
      },
      ref: `${fixedType}Header`
    }) : null,
    h('plx-table-body', {
      props: {
        fixedType,
        tableData,
        tableColumn,
        visibleColumn,
        collectColumn,
        fixedColumn,
        size: vSize,
        isGroup
      },
      ref: `${fixedType}Body`
    }),
    showFooter ? h('plx-table-footer', {
      props: {
        fixedType,
        footerData,
        tableColumn,
        visibleColumn,
        size: vSize,
        fixedColumn
      },
      ref: `${fixedType}Footer`
    }) : null
  ])
}

export default {
  name: 'PlxTable',
  props: {
    /** 基本属性 */
    // 数据
    data: Array,
    // 初始化绑定动态列
    customs: Array,
    // 表格的高度
    height: [Number, String],
    // 表格的最大高度
    maxHeight: [Number, String],
    // 所有列是否允许拖动列宽调整大小
    resizable: { type: Boolean, default: () => GlobalConfig.resizable },
    // 是否带有斑马纹
    stripe: { type: Boolean, default: () => GlobalConfig.stripe },
    // 是否带有纵向边框
    border: { type: [Boolean, String], default: () => GlobalConfig.border },
    // 表格的尺寸
    size: { type: String, default: () => GlobalConfig.size },
    // 列的宽度是否自撑开
    fit: { type: Boolean, default: () => GlobalConfig.fit },
    // 表格是否加载中
    loading: Boolean,
    // 所有的列对其方式
    align: { type: String, default: () => GlobalConfig.align },
    // 所有的表头列的对齐方式
    headerAlign: { type: String, default: () => GlobalConfig.headerAlign },
    // 所有的表尾列的对齐方式
    footerAlign: { type: String, default: () => GlobalConfig.footerAlign },
    // 是否显示表头
    showHeader: { type: Boolean, default: () => GlobalConfig.showHeader },
    // (v3.0 废弃)
    startIndex: { type: Number, default: 0 },
    // 是否要高亮当前选中行
    highlightCurrentRow: { type: Boolean, default: () => GlobalConfig.highlightCurrentRow },
    // 鼠标移到行是否要高亮显示
    highlightHoverRow: { type: Boolean, default: () => GlobalConfig.highlightHoverRow },
    // 是否要高亮当前选中列
    highlightCurrentColumn: { type: Boolean, default: () => GlobalConfig.highlightCurrentColumn },
    // 鼠标移到列是否要高亮显示
    highlightHoverColumn: { type: Boolean, default: () => GlobalConfig.highlightHoverColumn },
    // 激活单元格编辑时是否高亮显示
    highlightCell: Boolean,
    // 是否显示表尾合计
    showFooter: Boolean,
    // 表尾合计的计算方法
    footerMethod: Function,
    // 给行附加 className
    rowClassName: [String, Function],
    // 给单元格附加 className
    cellClassName: [String, Function],
    // 给表头的行附加 className
    headerRowClassName: [String, Function],
    // 给表头的单元格附加 className
    headerCellClassName: [String, Function],
    // 给表尾的行附加 className
    footerRowClassName: [String, Function],
    // 给表尾的单元格附加 className
    footerCellClassName: [String, Function],
    // 给单元格附加样式
    cellStyle: [Object, Function],
    // 给表头单元格附加样式
    headerCellStyle: [Object, Function],
    // 给表尾单元格附加样式
    footerCellStyle: [Object, Function],
    // 给行附加样式
    rowStyle: [Object, Function],
    // 给表头行附加样式
    headerRowStyle: [Object, Function],
    // 给表尾行附加样式
    footerRowStyle: [Object, Function],
    // 合并行或列
    spanMethod: Function,
    // 表尾合并行或列
    footerSpanMethod: Function,
    // 设置所有内容过长时显示为省略号
    showOverflow: { type: [Boolean, String], default: () => GlobalConfig.showOverflow },
    // 设置表头所有内容过长时显示为省略号
    showHeaderOverflow: { type: [Boolean, String], default: () => GlobalConfig.showHeaderOverflow },
    // 是否所有服务端筛选
    remoteFilter: Boolean,
    // 是否所有服务端排序
    remoteSort: Boolean,
    // 自定义所有列的排序方法
    sortMethod: Function,
    // 所有列宽度
    columnWidth: [Number, String],
    // 所有列最小宽度,把剩余宽度按比例分配
    columnMinWidth: [Number, String],

    /** 高级属性 */
    // 主键配置
    columnKey: Boolean,
    rowKey: Boolean,
    rowId: { type: String, default: () => GlobalConfig.rowId },
    zIndex: Number,
    // 是否自动监听父容器变化去更新响应式表格宽高
    autoResize: Boolean,
    // 是否自动根据状态属性去更新响应式表格宽高
    syncResize: [Boolean, String],
    // 序号配置项
    seqConfig: Object,
    // 排序配置项
    sortConfig: Object,
    // 筛选配置项
    filterConfig: Object,
    // 单选框配置
    radioConfig: Object,
    // (v3.0 废弃)
    selectConfig: Object,
    // 复选框配置项
    checkboxConfig: Object,
    // tooltip 配置项
    tooltipConfig: Object,
    // 导出配置项
    exportConfig: [Boolean, Object],
    // 导入配置项
    importConfig: [Boolean, Object],
    // 打印配置项
    printConfig: Object,
    // 展开行配置项
    expandConfig: Object,
    // 树形结构配置项
    treeConfig: [Boolean, Object],
    // 快捷菜单配置项
    contextMenu: Object,
    // 鼠标配置项
    mouseConfig: Object,
    // 按键配置项
    keyboardConfig: Object,
    // 编辑配置项
    editConfig: [Boolean, Object],
    // 校验配置项
    validConfig: Object,
    // 校验规则配置项
    editRules: Object,
    // 优化配置项
    optimization: Object,
    // 额外的参数
    params: Object
  },
  components: {
    VxeTableBody
  },
  provide () {
    return {
      $table: this
    }
  },
  inject: {
    $grid: {
      default: null
    }
  },
  mixins: [],
  data () {
    return {
      id: `${XEUtils.uniqueId()}`,
      // 列分组配置
      collectColumn: [],
      // 完整所有列
      tableFullColumn: [],
      // 渲染的列
      tableColumn: [],
      // 渲染中的数据
      tableData: [],
      // 是否启用了横向 X 可视渲染方式加载
      scrollXLoad: false,
      // 是否启用了纵向 Y 可视渲染方式加载
      scrollYLoad: false,
      // 是否存在纵向滚动条
      overflowY: true,
      // 是否存在横向滚动条
      overflowX: false,
      // 纵向滚动条的宽度
      scrollbarWidth: 0,
      // 横向滚动条的高度
      scrollbarHeight: 0,
      // 所有列是否覆盖整个表格
      isCoverBody: false,
      // 行高
      rowHeight: 0,
      // 复选框属性,是否全选
      isAllSelected: false,
      // 复选框属性,有选中且非全选状态
      isIndeterminate: false,
      // 复选框属性,已选中的行
      selection: [],
      // 当前行
      currentRow: null,
      // 单选框属性,选中行
      selectRow: null,
      // 表尾合计数据
      footerData: [],
      // 已展开的行
      rowExpandeds: [],
      // 懒加载中的展开行的列表
      expandLazyLoadeds: [],
      // 已展开树节点
      treeExpandeds: [],
      // 懒加载中的树节点的列表
      treeLazyLoadeds: [],
      // 树节点不确定状态的列表
      treeIndeterminates: [],
      // 当前选中的筛选列
      filterStore: {
        isAllSelected: false,
        isIndeterminate: false,
        style: null,
        options: [],
        column: null,
        multiple: false,
        visible: false
      },
      // 存放列相关的信息
      columnStore: {
        leftList: [],
        centerList: [],
        rightList: [],
        resizeList: [],
        pxList: [],
        pxMinList: [],
        scaleList: [],
        scaleMinList: [],
        autoList: []
      },
      // 存放快捷菜单的信息
      ctxMenuStore: {
        selected: null,
        visible: false,
        showChild: false,
        selectChild: null,
        list: [],
        childPos: null,
        style: null
      },
      // 存放可编辑相关信息
      editStore: {
        indexs: {
          columns: []
        },
        titles: {
          columns: []
        },
        // 所有选中
        checked: {
          rows: [],
          columns: [],
          tRows: [],
          tColumns: []
        },
        // 选中源
        selected: {
          row: null,
          column: null
        },
        // 已复制源
        copyed: {
          cut: false,
          rows: [],
          columns: []
        },
        // 激活
        actived: {
          row: null,
          column: null
        },
        insertList: [],
        removeList: []
      },
      // 存放数据校验相关信息
      validStore: {
        visible: false,
        row: null,
        column: null,
        content: '',
        rule: null,
        isArrow: false
      },
      // 导入相关信息
      importStore: {
        file: null,
        type: '',
        filename: '',
        visible: false
      },
      importParams: {
        mode: '',
        types: null,
        message: true
      },
      // 导出相关信息
      exportStore: {
        name: '',
        mode: '',
        columns: [],
        selectRecords: [],
        hasFooter: false,
        visible: false,
        isTree: false
      },
      exportParams: {
        filename: '',
        sheetName: '',
        type: '',
        types: [],
        original: false,
        message: true,
        isHeader: false,
        isFooter: false
      }
    }
  },
  computed: {
    vSize () {
      return this.size || this.$parent.size || this.$parent.vSize
    },
    validOpts () {
      return Object.assign({ message: 'default' }, GlobalConfig.validConfig, this.validConfig)
    },
    optimizeOpts () {
      return Object.assign({}, GlobalConfig.optimization, this.optimization)
    },
    rowHeightMaps () {
      return Object.assign({
        default: 48,
        medium: 44,
        small: 40,
        mini: 36
      }, this.optimizeOpts.rHeights)
    },
    seqOpts () {
      return Object.assign({ startIndex: 0 }, GlobalConfig.seqConfig, this.seqConfig)
    },
    radioOpts () {
      return Object.assign({}, GlobalConfig.radioConfig, this.radioConfig)
    },
    checkboxOpts () {
      return Object.assign({}, GlobalConfig.checkboxConfig, this.checkboxConfig || this.selectConfig)
    },
    tooltipOpts () {
      return Object.assign({ size: this.vSize, leaveDelay: 300 }, GlobalConfig.tooltipConfig, this.tooltipConfig)
    },
    vaildTipOpts () {
      return Object.assign({ isArrow: false }, this.tooltipOpts)
    },
    editOpts () {
      return Object.assign({}, GlobalConfig.editConfig, this.editConfig)
    },
    sortOpts () {
      return Object.assign({}, GlobalConfig.sortConfig, this.sortConfig)
    },
    filterOpts () {
      return Object.assign({}, GlobalConfig.filterConfig, this.filterConfig)
    },
    mouseOpts () {
      return Object.assign({}, GlobalConfig.mouseConfig, this.mouseConfig)
    },
    // 是否使用了分组表头
    isGroup () {
      return this.collectColumn.some(column => UtilTools.hasChildrenList(column))
    },
    hasTip () {
      return VXETable._tooltip
    },
    visibleColumn () {
      return this.tableFullColumn ? this.tableFullColumn.filter(column => column.visible) : []
    },
    isResizable () {
      return this.resizable || this.tableFullColumn.some(column => column.resizable)
    },
    hasFilter () {
      return this.tableColumn.some(column => column.filters && column.filters.length)
    },
    headerCtxMenu () {
      return this.ctxMenuOpts.header && this.ctxMenuOpts.header.options ? this.ctxMenuOpts.header.options : []
    },
    bodyCtxMenu () {
      return this.ctxMenuOpts.body && this.ctxMenuOpts.body.options ? this.ctxMenuOpts.body.options : []
    },
    isCtxMenu () {
      return this.headerCtxMenu.length || this.bodyCtxMenu.length
    },
    ctxMenuOpts () {
      return Object.assign({}, GlobalConfig.menu, this.contextMenu)
    },
    ctxMenuList () {
      let rest = []
      this.ctxMenuStore.list.forEach(list => {
        list.forEach(item => {
          rest.push(item)
        })
      })
      return rest
    },
    exportOpts () {
      return Object.assign({}, GlobalConfig.exportConfig, this.exportConfig)
    },
    importOpts () {
      return Object.assign({}, GlobalConfig.importConfig, this.importConfig)
    },
    printOpts () {
      return Object.assign({}, GlobalConfig.printConfig, this.printConfig)
    },
    expandOpts () {
      return Object.assign({}, GlobalConfig.expandConfig, this.expandConfig)
    },
    treeOpts () {
      return Object.assign({
        children: 'children',
        hasChild: 'hasChild',
        indent: 20
      }, GlobalConfig.treeConfig, this.treeConfig)
    },
    cellOffsetWidth () {
      return this.border ? Math.max(2, Math.ceil(this.scrollbarWidth / this.tableColumn.length)) : 1
    },
    expandColumn () {
      return this.tableColumn.find(column => column.type === 'expand')
    },
    /**
     * 判断列全选的复选框是否禁用
     */
    isAllCheckboxDisabled () {
      let { tableFullData, treeConfig, checkboxOpts } = this
      let { strict, checkMethod } = checkboxOpts
      if (strict) {
        if (tableFullData.length) {
          if (checkMethod) {
            if (treeConfig) {
              // 暂时不支持树形结构
            }
            // 如果所有行都被禁用
            return tableFullData.every((row, rowIndex) => !checkMethod({ row, rowIndex, $rowIndex: rowIndex }))
          }
          return false
        }
        return true
      }
      return false
    }
  },
  watch: {
    data (value) {
      this.loadTableData(value).then(() => {
        if (!this.inited) {
          this.inited = true
          this.handleDefaults()
        }
      })
    },
    customs (value) {
      if (!this.isUpdateCustoms) {
        this.mergeCustomColumn(value)
      }
      this.isUpdateCustoms = false
    },
    collectColumn (value) {
      let tableFullColumn = UtilTools.getColumnList(value)
      this.tableFullColumn = tableFullColumn
      this.cacheColumnMap()
      if (this.customs) {
        this.mergeCustomColumn(this.customs)
      }
      this.refreshColumn().then(() => {
        if (this.scrollXLoad) {
          this.updateVirtualScrollX(true)
        }
      })
      this.handleTableData(true)
      if (this.$toolbar) {
        this.$toolbar.updateColumn(tableFullColumn)
      }
      // 在 v3.0 中废弃 prop、label
      if (tableFullColumn.length) {
        let cIndex = Math.floor((tableFullColumn.length - 1) / 2)
        if (tableFullColumn[cIndex].prop) {
          UtilTools.warn('plx.error.delProp', ['prop', 'field'])
        }
        if (tableFullColumn[cIndex].label) {
          UtilTools.warn('plx.error.delProp', ['label', 'title'])
        }
      }
      if (this.treeConfig && tableFullColumn.some(column => column.fixed) && tableFullColumn.some(column => column.type === 'expand')) {
        UtilTools.warn('plx.error.treeFixedExpand')
      }
    },
    tableColumn () {
      this.analyColumnWidth()
    },
    height () {
      this.$nextTick(() => this.recalculate(true))
    },
    loading () {
      if (!this._isLoading) {
        this._isLoading = true
      }
    },
    syncResize (value) {
      if (value) {
        this.$nextTick(() => {
          // 只在可视状态下才去更新
          if (this.$el.clientWidth && this.$el.clientHeight) {
            this.recalculate(true)
          }
        })
      }
    }
  },
  created () {
    let { scrollXStore, scrollYStore, optimizeOpts, data, loading, treeOpts, treeConfig, showOverflow } = Object.assign(this, {
      tZindex: 0,
      elemStore: {},
      // 存放横向 X 虚拟滚动相关的信息
      scrollXStore: {},
      // 存放纵向 Y 虚拟滚动相关信息
      scrollYStore: {},
      // 存放 tooltip 相关信息
      tooltipStore: {},
      // 表格父容器的高度
      parentHeight: 0,
      // 表格宽度
      tableWidth: 0,
      // 表格高度
      tableHeight: 0,
      // 表头高度
      headerHeight: 0,
      // 表尾高度
      footerHeight: 0,
      // 单选框属性,选中列
      // currentColumn: null,
      // 当前 hover 行
      // hoverRow: null,
      // 最后滚动位置
      lastScrollLeft: 0,
      lastScrollTop: 0,
      // 复选框属性,已选中保留的行
      selectReserveRowMap: {},
      // 完整数据、条件处理后
      tableFullData: [],
      afterFullData: [],
      // 缓存数据集
      fullAllDataRowMap: new Map(),
      fullAllDataRowIdData: {},
      fullDataRowMap: new Map(),
      fullDataRowIdData: {},
      fullColumnMap: new Map(),
      fullColumnIdData: {}
    })
    let { scrollX, scrollY } = optimizeOpts
    // 是否加载过 Loading 模块
    this._isLoading = loading
    if (!UtilTools.getRowkey(this)) {
      UtilTools.error('plx.error.emptyProp', ['row-id'])
    }
    if (this.startIndex) {
      // UtilTools.warn('plx.error.delProp', ['start-index', 'seq-config.startIndex'])
    }
    if (this.selectConfig) {
      // UtilTools.warn('plx.error.delProp', ['select-config', 'checkbox-config'])
    }
    if (treeConfig && treeOpts.line && (!this.rowKey || !showOverflow)) {
      UtilTools.warn('plx.error.reqProp', ['row-key | show-overflow'])
    }
    if (this.customs) {
      // UtilTools.warn('plx.error.removeProp', ['customs'])
    }
    if (this.sortMethod) {
      // UtilTools.warn('plx.error.delProp', ['sort-method', 'sort-config.sortMethod'])
    }
    if (this.remoteSort) {
      // UtilTools.warn('plx.error.delProp', ['remote-sort', 'sort-config.remote'])
    }
    if (this.remoteFilter) {
      // UtilTools.warn('plx.error.delProp', ['remote-filter', 'filter-config.remote'])
    }
    // 检查是否有安装需要的模块
    let errorModuleName
    if (!VXETable._edit && this.editConfig) {
      errorModuleName = 'Edit'
    } else if (!VXETable._valid && this.editRules) {
      errorModuleName = 'Validator'
    } else if (!VXETable._keyboard && (this.keyboardConfig || this.mouseConfig)) {
      errorModuleName = 'Keyboard'
    } else if (!VXETable._resize && this.autoResize) {
      errorModuleName = 'Resize'
    }
    if (errorModuleName) {
      throw new Error(UtilTools.getLog('plx.error.reqModule', [errorModuleName]))
    }
    if (scrollY) {
      Object.assign(scrollYStore, {
        startIndex: 0,
        visibleIndex: 0,
        adaptive: XEUtils.isBoolean(scrollY.adaptive) ? scrollY.adaptive : true,
        renderSize: XEUtils.toNumber(scrollY.rSize),
        offsetSize: XEUtils.toNumber(scrollY.oSize)
      })
    }
    if (scrollX) {
      Object.assign(scrollXStore, {
        startIndex: 0,
        visibleIndex: 0,
        renderSize: XEUtils.toNumber(scrollX.rSize),
        offsetSize: XEUtils.toNumber(scrollX.oSize)
      })
    }
    this.loadTableData(data).then(() => {
      if (data && data.length) {
        this.inited = true
        this.handleDefaults()
      }
      this.updateStyle()
    })
    GlobalEvent.on(this, 'mousedown', this.handleGlobalMousedownEvent)
    GlobalEvent.on(this, 'blur', this.handleGlobalBlurEvent)
    GlobalEvent.on(this, 'mousewheel', this.handleGlobalMousewheelEvent)
    GlobalEvent.on(this, 'keydown', this.handleGlobalKeydownEvent)
    GlobalEvent.on(this, 'resize', this.handleGlobalResizeEvent)
    GlobalEvent.on(this, 'contextmenu', this.handleGlobalContextmenuEvent)
    this.preventEvent(null, 'created', { $table: this })
  },
  mounted () {
    if (this.autoResize && VXETable._resize) {
      this.bindResize()
    }
    document.body.appendChild(this.$refs.tableWrapper)
    this.preventEvent(null, 'mounted', { $table: this })
  },
  activated () {
    this.refreshScroll()
    this.preventEvent(null, 'activated', { $table: this })
  },
  deactivated () {
    this.preventEvent(null, 'deactivated', { $table: this })
  },
  beforeDestroy () {
    let tableWrapper = this.$refs.tableWrapper
    if (tableWrapper && tableWrapper.parentNode) {
      tableWrapper.parentNode.removeChild(tableWrapper)
    }
    if (VXETable._resize) {
      this.unbindResize()
    }
    this.closeFilter()
    this.closeMenu()
    this.clearAll()
    this.preventEvent(null, 'beforeDestroy', { $table: this })
  },
  destroyed () {
    GlobalEvent.off(this, 'mousedown')
    GlobalEvent.off(this, 'blur')
    GlobalEvent.off(this, 'mousewheel')
    GlobalEvent.off(this, 'keydown')
    GlobalEvent.off(this, 'resize')
    GlobalEvent.off(this, 'contextmenu')
    this.preventEvent(null, 'destroyed', { $table: this })
  },
  render (h) {
    let {
      _e,
      id,
      isCoverBody,
      tableData,
      tableColumn,
      visibleColumn,
      collectColumn,
      isGroup,
      hasFilter,
      isResizable,
      isCtxMenu,
      loading,
      stripe,
      _isLoading,
      showHeader,
      height,
      border,
      treeOpts,
      treeConfig,
      mouseConfig,
      mouseOpts,
      vSize,
      validOpts,
      editRules,
      showFooter,
      footerMethod,
      overflowX,
      overflowY,
      scrollXLoad,
      scrollYLoad,
      scrollbarHeight,
      highlightCell,
      highlightHoverRow,
      highlightHoverColumn,
      editConfig,
      checkboxOpts,
      optimizeOpts,
      vaildTipOpts,
      tooltipOpts,
      columnStore,
      filterStore,
      ctxMenuStore,
      footerData,
      hasTip
    } = this
    let { leftList, rightList } = columnStore
    // 在 v3.0 中废弃 mouse-config.checked
    let isMouseChecked = mouseConfig && (mouseOpts.range || mouseOpts.checked)
    return h('div', {
      class: ['plx-table', `tid_${id}`, vSize ? `size--${vSize}` : '', border && XEUtils.isString(border) ? `b--style-${border}` : '', {
        'plx-editable': editConfig,
        'show--head': showHeader,
        'show--foot': showFooter,
        'is--group': isGroup,
        'has--height': height,
        'has--tree-line': treeConfig && treeOpts.line,
        'fixed--left': leftList.length,
        'fixed--right': rightList.length,
        'c--highlight': highlightCell,
        't--animat': optimizeOpts.animat,
        't--stripe': stripe,
        't--border': border,
        't--selected': mouseConfig && mouseOpts.selected,
        't--checked': isMouseChecked,
        'row--highlight': highlightHoverRow,
        'column--highlight': highlightHoverColumn,
        'is--cover': isCoverBody,
        'is--loading': loading,
        'scroll--y': overflowY,
        'scroll--x': overflowX,
        'virtual--x': scrollXLoad,
        'virtual--y': scrollYLoad
      }]
    }, [
      /**
       * 隐藏列
       */
      h('div', {
        class: 'plx-table-hidden-column',
        ref: 'hideColumn'
      }, this.$slots.default),
      h('div', {
        class: 'plx-table--main-wrapper'
      }, [
        /**
         * 主头部
         */
        showHeader ? h('plx-table-header', {
          ref: 'tableHeader',
          props: {
            tableData,
            tableColumn,
            visibleColumn,
            collectColumn,
            size: vSize,
            isGroup
          }
        }) : _e(),
        /**
         * 主内容
         */
        h('plx-table-body', {
          ref: 'tableBody',
          props: {
            tableData,
            tableColumn,
            visibleColumn,
            collectColumn,
            size: vSize,
            isGroup
          }
        }),
        /**
         * 底部汇总
         */
        showFooter ? h('plx-table-footer', {
          props: {
            footerData,
            footerMethod,
            tableColumn,
            visibleColumn,
            size: vSize
          },
          ref: 'tableFooter'
        }) : null
      ]),
      /**
       * 左侧固定列
       */
      leftList && leftList.length && overflowX ? renderFixed(h, this, 'left') : _e(),
      /**
       * 右侧固定列
       */
      rightList && rightList.length && overflowX ? renderFixed(h, this, 'right') : _e(),
      /**
       * 空数据
       */
      !loading && !tableData.length ? h('div', {
        ref: 'emptyPlaceholder',
        class: 'plx-table--empty-placeholder'
      }, [
        h('div', {
          class: 'plx-table--empty-content'
        }, this.$scopedSlots.empty ? this.$scopedSlots.empty.call(this, { $table: this }, h) : GlobalConfig.i18n('plx.table.emptyText'))
      ]) : _e(),
      /**
       * 列宽线
       */
      isResizable ? h('div', {
        class: 'plx-table--resizable-bar',
        style: overflowX ? {
          'padding-bottom': `${scrollbarHeight}px`
        } : null,
        ref: 'resizeBar'
      }) : _e(),
      /**
       * 边框线
       */
      h('div', {
        class: 'plx-table--border-line'
      }),
      /**
       * 加载中
       */
      _isLoading ? h('plx-table-loading', {
        props: {
          visible: loading
        }
      }) : _e(),
      /**
       * 筛选
       */
      hasFilter ? h('plx-table-filter', {
        props: {
          optimizeOpts,
          filterStore
        },
        ref: 'filterWrapper'
      }) : _e(),
      /**
       * 导入
       */
      VXETable._export ? h('plx-import-panel', {
        props: {
          defaultOptions: this.importParams,
          storeData: this.importStore
        },
        on: {
          import: this.confirmImportEvent
        }
      }) : _e(),
      /**
       * 导出
       */
      VXETable._export ? h('plx-export-panel', {
        props: {
          defaultOptions: this.exportParams,
          storeData: this.exportStore
        },
        on: {
          print: this.confirmPrintEvent,
          export: this.confirmExportEvent
        }
      }) : _e(),
      h('div', {
        class: `plx-table${id}-wrapper ${this.$vnode.data.staticClass || ''}`,
        ref: 'tableWrapper'
      }, [
        /**
         * 复选框-范围选择
         */
        checkboxOpts.range ? h('div', {
          class: 'plx-table--checkbox-range',
          ref: 'checkboxRange'
        }) : _e(),
        /**
         * 快捷菜单
         */
        isCtxMenu ? h('plx-table-context-menu', {
          props: {
            ctxMenuStore
          },
          ref: 'ctxWrapper'
        }) : _e(),
        /**
         * 单元格内容溢出的 tooltip
         */
        hasTip ? h('plx-tooltip', {
          ref: 'tooltip',
          props: tooltipOpts,
          on: tooltipOpts.enterable ? {
            leave: this.handleTooltipLeaveEvent
          } : null
        }) : _e(),
        /**
         * 校验不通过的 tooltip
         */
        hasTip && editRules && (validOpts.message === 'default' ? !height : validOpts.message === 'tooltip') ? h('plx-tooltip', {
          class: 'plx-table--valid-error',
          props: validOpts.message === 'tooltip' || tableData.length === 1 ? vaildTipOpts : null,
          ref: 'validTip'
        }) : _e()
      ])
    ])
  },
  methods
}