<template>
  <div :key="key" class="y-table">
    <div class="table-top">
      <div v-if="hasTopLeft" class="table-top-left">
        <slot name="default"></slot>
      </div>
      <div v-if="hasTopRight" class="table-top-right">
        <slot name="table-top-right"></slot>
        <div v-if="showUtilBar" class="utils-wrapper">
          <i v-if="utilConfig.includes('setting')" class="iconfont el-icon-coin" @click="handleSave"> 保存</i>
          <Refresh v-if="utilConfig.includes('refresh')" @refresh="handleRefresh"></Refresh>
          <Density v-if="utilConfig.includes('density')" :size="size" @resize="handleResize"></Density>
          <!-- <Setting v-if="utilConfig.includes('setting')" v-model="currentColumns" :origin-columns="originColumns"></Setting> -->
          <SetColumns v-if="utilConfig.includes('setting')" v-model="currentColumns" :origin-columns="originColumns"></SetColumns>
        </div>
      </div>
    </div>
    <slot name="list-top"></slot>
    <template v-if="virtual">
      <template v-if="isVxe">
        <VTable
          ref="virtualList"
          :columns="currentColumns"
          :data="data"
          :row-key="rowKey"
          v-bind="$attrs"
          virtual
          v-on="$listeners"
          @selection-change="handleSelectChange"
          @select-all="handleSelectAll"
        ></VTable>
      </template>
      <y-virtual-list
        v-else
        ref="virtualList"
        :columns="currentColumns"
        :data="data"
        :row-key="rowKey"
        v-bind="$attrs"
        v-on="$listeners"
        @selection-change="handleSelectChange"
        @select-all="handleSelectAll"
      ></y-virtual-list>
      <div
        v-if="hasBatchAction"
        class="y-table-batch-action-area"
        :style="`left: ${leftOffset}px`"
      >
        <div class="action-left">
          <div v-if="showSelectCount">已选择当前页<span :style="{color: primaryColor}"> {{ selection.length }}</span> 项</div>
          <slot name="action-left"></slot>
        </div>
        <div class="action-right">
          <slot name="action-right" :selection="selection"></slot>
          <el-button @click="handleCancelSelection">取消选择</el-button>
        </div>
      </div>
    </template>
    <template v-else>

      <!-- 自适应表格 -->
      <template v-if="autoAdaptiveHeight">
        <template v-if="isVxe">
          <VTable
            :columns="currentColumns"
            :data="data"
            v-bind="$attrs"
            :pagination="pagination"
            :row-key="rowKey"
            :total="total"
            v-on="$listeners"
            @selection-change="handleSelectChange"
            @select-all="handleSelectAll"
          ></VTable>
        </template>
        <el-table
          v-else
          ref="table"
          v-adaptive="{bottomOffset}"
          :border="$attrs.border === undefined ? true : $attrs.border"
          v-bind="tableAttrs"
          :data="data"
          :tooltip-effect="tableAttrs['tooltip-effect'] || 'dark'"
          :style="`width: ${$attrs.width || '100%'}`"
          :size="size"
          :row-key="rowKey || tableAttrs['row-key']"
          :max-height="height"
          :class="borderClass"
          v-on="$listeners"
        >
          <template v-for="(col, index) in columnAttrs">
            <TableItem
              v-if="col.showCol || col.showCol === undefined"
              :key="index"
              :col="col"
              :columns="columns"
              :data="data"
              :has-tree-table="hasTreeTable"
            ></TableItem>
          </template>
          <!-- 数据为空时 -->
          <div slot="empty" class="empty">
            <y-empty></y-empty>
          </div>
        </el-table>
      </template>

      <!-- 普通表格 -->
      <template v-else>
        <template v-if="isVxe">
          <VTable
            ref="vxeTable"
            :columns="currentColumns"
            :export-config="{}"
            :data="data"
            v-bind="$attrs"
            :pagination="pagination"
            :row-key="rowKey"
            :total="total"
            v-on="$listeners"
            @selection-change="handleSelectChange"
            @select-all="handleSelectAll"
          ></VTable>
        </template>
        <el-table
          v-else
          :key="key"
          ref="table"
          v-bind="tableAttrs"
          :data="data"
          :tooltip-effect="tableAttrs['tooltip-effect'] || 'dark'"
          :style="`width: ${$attrs.width || '100%'}`"
          :size="size"
          :row-key="rowKey || tableAttrs['row-key']"
          :max-height="height"
          :class="borderClass"
          v-on="$listeners"
          @selection-change="handleSelectChange"
          @select-all="handleSelectAll"
        >
          <template v-for="(col, index) in columnAttrs">
            <TableItem
              v-if="!hasTreeTable && (col.showCol || col.showCol === undefined)"
              :key="index"
              :col="col"
              :columns="columns"
              :data="data"
              :col-index="index"
            ></TableItem>
            <TableTreeItem
              v-if="hasTreeTable && (col.showCol || col.showCol === undefined)"
              :key="index"
              :col="col"
              :columns="columns"
              :data="data"
              :col-index="index"
            >

            </TableTreeItem>
          </template>
          <!-- 数据为空时 -->
          <div slot="empty" class="empty">
            <y-empty></y-empty>
          </div>
        </el-table>
      </template>

      <el-pagination
        v-if="paginationAttrs.isPagination"
        v-bind="paginationAttrs"
        :style="paginationStyle"
        :current-page="paginationAttrs['currentPage']"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      ></el-pagination>
      <div
        v-if="hasBatchAction"
        class="y-table-batch-action-area"
        :style="`left: ${leftOffset}px`"
      >
        <div class="action-left">
          <div v-if="showSelectCount">已选择当前页<span :style="{color: primaryColor}"> {{ selection.length }}</span> 项</div>
          <slot name="action-left"></slot>
        </div>
        <div class="action-right">
          <slot name="action-right" :selection="selection"></slot>
          <el-button @click="handleCancelSelection">取消选择</el-button>
        </div>
      </div>
    </template>
  </div>
</template>
<script>
import { defaultTableAttrs, defaultColumn, defaultPagination } from './config'
import { cloneDeep, uniqWith, isEqual, isEmpty } from 'lodash'
import local from '../../utils/local.js'
import TableItem from './TableItem'
import Refresh from './Refresh.vue'
import Density from './Density.vue'
import SetColumns from './SetColumns.vue'
import TableTreeItem from './TableTreeItem.vue'
// import Setting from './Setting.vue'
// import ElTable from './table/src/table.vue'
import VTable from './VxeTable'
import color from '../../../styles/element-variables.scss'
import { findComponentForward } from '../../utils'
export default {
  name: 'YTable',
  components: {
    VTable,
    TableItem,
    TableTreeItem,
    Refresh,
    Density,
    // Setting,
    // ElTable,
    SetColumns
  },
  props: {
    isVxe: {
      type: Boolean,
      default: false
    },
    /* 是否用虚拟列表显示 */
    virtual: {
      type: Boolean,
      default: false
    },
    /* 表格列定义名称 解决有 在一个页面有 2个表格的情况 缓存列定义*/
    columnName: {
      type: String,
      default: ''
    },
    /* data:  显示的数据， 等同于el-table中的data属性 */
    data: {
      type: Array,
      default() {
        return []
      }
    },
    /* columns: 显示和表格项，数组里的每一项都是一个对象，对象中的属性与el-table-column中的属性一一对应 */
    columns: {
      type: Array,
      default() {
        return []
      }
    },
    bottomOffset: {
      type: [Number],
      default: 100
    },
    /* pagination: 分页属性：如果为Boolean为true,则取默认值，如果是对象，则merge默认值， 如果total有值，会覆盖pagination中的total属性 */
    pagination: {
      type: [Object, Boolean],
      default: false
    },
    /*  分页总数 */
    total: {
      type: Number,
      default: 0
    },
    /*  每页条数 */
    pageSize: {
      type: Number,
      default: 0
    },
    /* 重新加载函数 */
    reload: {
      type: Function,
      default() {
        return () => {}
      }
    },
    /* 是否显示工具栏 */
    showUtilBar: {
      type: Boolean,
      default: false
    },
    /* 工具栏配置项 */
    utilConfig: {
      type: Array,
      default: () => ['refresh', 'density']
    },
    offsetHeight: {
      type: [String, Number],
      default: 0
    },
    // 自适应高度
    autoAdaptiveHeight: {
      type: Boolean,
      default: false
    },
    maxHeight: {
      type: [String, Number],
      default: 'auto'
    },
    rowKey: {
      type: [String, Function],
      default: ''
    },
    hasBatchButton: {
      type: Boolean,
      default: false
    },
    //  虚拟表格多选专用 virtual为true才有效
    leftOffset: {
      type: [String, Number],
      default: 200
    },
    // 虚拟表格多选专用 virtual为true才有效
    showSelectCount: {
      type: Boolean,
      default: true
    },
    // 如果total变化，是否需要重新加载分页参数
    hasReloadPagination: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      key: Math.random().toString(32).replace('.', ''),
      tableAttrs: defaultTableAttrs, // 表格属性，同el-table上的属性
      columnAttrs: [], // 表格项属性， 同el-table-column上的属性
      paginationAttrs: {}, // 分页属性，同el-pagination上的属性
      size: 'mini',
      originColumns: cloneDeep(this.columns),
      hasTreeTable: false,
      //  虚拟表格多选专用
      selection: [],
      //  虚拟表格多选专用
      filterFn: null,
      primaryColor: color.primaryColor
    }
  },
  computed: {
    staffId() {
      return this.$store?.state?.userInfo?.staffId
    },
    currentColumns: {
      get() {
        return this.columns.filter(c => !c.hidden)
      },
      set(columns) {
        this.$emit('update', columns)
      }
    },
    height() {
      // const scrollHeight = document.body.scrollHeight
      // if (scrollHeight - this.offsetHeight < this.maxHeight) {
      //   return scrollHeight - this.offsetHeight
      // }
      return this.maxHeight
    },
    borderClass() {
      return this.data.length === 0 ? 'el-table--border__bottom' : ''
    },
    hasTopLeft() {
      return Object.keys(this.$slots).includes('default')
    },
    hasTopRight() {
      return Object.keys(this.$slots).includes('table-top-right') || this.showUtilBar
    },
    hasBatchAction() {
      const hasSelection = this.columns.find(column => column.type === 'selection')
      if (this.hasBatchButton && hasSelection && !isEmpty(this.selection)) {
        return true
      }
      return false
    },
    selectableFunc() {
      const selectionColumn = this.columns.find(v => v.type === 'selection')
      return selectionColumn.selectable
    },
    paginationStyle() {
      /* 居左，还是居右 */
      const paginationOffset = this.$attrs['pagination-offset'] || this.$attrs.paginationOffset || 'right'
      const style = {
        textAlign: paginationOffset,
        marginTop: '10px'
      }

      return style
    }
  },
  watch: {
    pagination: {
      handler() {
        this.getPagination()
      },
      deep: true,
      immediate: false
    },
    total() {
      this.hasReloadPagination && this.getPagination()
    },
    pageSize(val) {
      if (val) {
        this.paginationAttrs['page-size'] = val
      }
    },
    columns: {
      handler(val) {
        this.initColumns()
      },
      deep: true,
      immediate: false
    },
    data: {
      handler(value) {
        this.setHasTreeTable()
        this.hasTreeTable && setTimeout(() => {
          this.$forceUpdate()
        }, 100)
      },
      deep: true,
      immediate: true
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    setHasTreeTable() {
      const treeProps = this.treeProps || { children: 'children', hasChildren: 'hasChildren' }
      this.hasTreeTable = this.data.some(item => {
        if (item[treeProps.children] && item[treeProps.children].length) {
          return true
        }
        return false
      })
    },
    reLayout() {
      // 对数据进行重新渲染
      this.$nextTick(() => {
        !this.virtual && this.$refs.table.doLayout()
      })
    },
    init() {
      // 解决y-table组件没有相关方法的问题
      let table
      if (this.isVxe) {
        table = findComponentForward(this, 'VTable')
      } else {
        table = findComponentForward(this, 'ElTable')
      }

      // 解决y-table-pro组件没有相关方法的问题
      Object.keys(table).forEach(key => {
        if (['clearSelection', 'toggleRowSelection', 'toggleAllSelection', 'toggleRowExpansion', 'setCurrentRow', 'clearSort', 'clearFilter', 'doLayout', 'sort'].includes(key)) {
          this[key] = table[key]
        }
      })

      // 获取element table上的属性
      const tableAttrs = {}
      Object.keys(defaultTableAttrs).forEach(key => {
        if (this.$attrs[key] !== undefined) {
          tableAttrs[key] = this.$attrs[key]
        }
      })
      this.tableAttrs = Object.assign({}, defaultTableAttrs, tableAttrs)
      this.initColumns(true)
      this.getPagination()
      if (!this.isVxe) {
        this.reLayout()
      }
    },
    // 列定义数据变化时，需要初始化列定义
    initColumns(isInit = false) {
      if (this.isVxe) return
      // this.reLayout()
      // 如果是初始化页面，并且存在 用户信息，那么优先取 缓存的列定义数据
      if (isInit && this.staffId) {
        const name = this.$route?.name
        const columnKey = `${this.staffId}${name}_${this.columnName}`
        const userColumns = local.get(columnKey)
        if (userColumns) {
          this.columnAttrs = userColumns.map(col => {
            const originCol = this.originColumns.find(im => im.prop === col.prop && (!col.fieldType || !col.filter)) // 此处需要保证 列定义配置不能重复，重复不会报错，但是缓存不准确
            const newCol = Object.assign({}, originCol, col)
            return newCol
          })
          this.$emit('update:columns', this.columnAttrs)
          return
        }
      }
      // 获取element table col上的属性
      const columnAttrs = this.currentColumns.map(column => {
        if (!column.formatter) {
          this.$set(column, 'formatter', function(row, col) {
            const val = row[col.property || col.prop || col.field]
            if (val === undefined || val === null || val === '') {
              return '-'
            }
            return val
          })
        }
        const obj = Object.assign({}, defaultColumn, column)
        return obj
      })

      const firstColumn = cloneDeep(this.originColumns).find(column => ['expand'].includes(column.type))

      if (firstColumn) {
        this.columnAttrs = uniqWith([Object.assign({}, defaultColumn, firstColumn), ...columnAttrs], (arrVal, othVal) => {
          if (arrVal.type) {
            return arrVal.type === othVal.type
          } else {
            return isEqual(arrVal, othVal)
          }
        })
      } else {
        this.columnAttrs = columnAttrs
      }
    },
    getPagination() {
      // 获取element 分页属性
      const pagination = this.pagination
      let paginationAttrs = {}
      if (pagination) {
        if (typeof pagination === 'object') {
          paginationAttrs = {
            ...defaultPagination,
            ...pagination,
            isPagination: true
          }
        } else {
          paginationAttrs = {
            ...defaultPagination,
            isPagination: true
          }
        }
      }
      Object.keys(paginationAttrs).forEach(key => {
        if (this.$attrs[key] !== undefined && key !== 'pagination') {
          paginationAttrs[key] = this.$attrs[key]
        }
      })

      if (this.total) {
        paginationAttrs.total = this.total
      }
      if (this.pageSize) {
        paginationAttrs['page-size'] = this.pageSize
      }
      this.paginationAttrs = paginationAttrs
    },
    handleSizeChange(pageSize) {
      this.$emit('size-change', pageSize)
      this.paginationAttrs = Object.assign({}, this.paginationAttrs, {
        type: 'size-change',
        pageSize: pageSize, // 兼容老系统
        currentPage: 1 // 兼容老系统
      })
      if (typeof this.reload === 'function') {
        this.reload(this.paginationAttrs)
      }
    },
    handleCurrentChange(currentPage) {
      this.$emit('page-current-change', currentPage)
      this.paginationAttrs = Object.assign({}, this.paginationAttrs, {
        currentPage: currentPage,
        type: 'current-change'
      })

      if (typeof this.reload === 'function') {
        this.reload(this.paginationAttrs)
      }
    },
    handleResize({ size, close }) {
      this.size = size
      close && close()
      this.reLayout()
    },
    handleRefresh() {
      this.paginationAttrs = Object.assign({}, this.paginationAttrs, {
        currentPage: 1
      })
      if (typeof this.reload === 'function') {
        this.reload(this.paginationAttrs)
      }
    },
    columnsReload() {
      this.originColumns = cloneDeep(this.columns)
    },
    // 保存列定义配置
    handleSave() {
      if (!this.staffId) return
      const data = cloneDeep(this.currentColumns).map(col => {
        const { width, fixed, prop } = col
        return { width, fixed, prop }
      })
      const name = this.$route.name
      local.set(`${this.staffId}${name}_${this.columnName}`, data)
      this.$message.success('保存成功')
    },
    /* 选择框 */
    handleSelectChange(selection) {
      if (!this.isVxe) {
        console.log('YTable selection', this.selection)
        this.selection = selection
      } else {
        setTimeout(() => {
          const refTable = findComponentForward(this, 'VxeTable')
          const records = refTable.getCheckboxRecords()
          const reserveSelection = refTable.getCheckboxReserveRecords()
          this.selection = records.concat(reserveSelection)
        }, 200)
      }
    },
    // 取消全选
    handleCancelSelection() {
      // const refTable = this.$refs.virtualList || this.$refs.table
      // if (refTable) {
      //   if (typeof refTable.clearSelection === 'function') {
      //     refTable.clearSelection()
      //   }
      //   if (typeof refTable.clearCheckboxRow === 'function') {
      //     /* 针对VxeTable */
      //     refTable.clearCheckboxRow()
      //   }
      //   this.$emit('clear-selection')
      //   this.$emit('select-all-page', false)
      // }
      let refTable
      if (this.isVxe) {
        refTable = findComponentForward(this, 'VTable')
      } else {
        refTable = findComponentForward(this, 'ElTable')
      }
      if (refTable) {
        if (typeof refTable.clearSelection === 'function') {
          refTable.clearSelection()
          this.selection = []
        }
        // if (typeof refTable.clearCheckboxRow === 'function') {
        //   /* 针对VxeTable */
        //   refTable.clearCheckboxRow()
        // }
        this.$emit('clear-selection')
        this.isCheckedAll = false
        this.$emit('select-all-page', false)
      }
    },
    handleSelectAll(selection) {
      if (selection) {
        this.selection = selection
        if (!selection.length) {
          this.handleCancelSelection()
        }
        return
      }

      const tableData = this.data.filter((v, index) => {
        if (this.selectableFunc) {
          return this.selectableFunc(v, index)
        }
        return true
      })

      if (this.selection.length === tableData.length) {
        this.handleCancelSelection()
      } else {
        const virtualList = this.$refs.virtualList
        virtualList && tableData.forEach(row => virtualList.toggleRowSelection(row, true))
        this.$emit('select-all-page', true)

        // if (this.beforeCheckAll && typeof this.beforeCheckAll === 'function') {
        //   this.beforeCheckAll((valid, filterFn) => {
        //     // filterFn是用来过滤tableData的， 用来对某些disabled的项，不作勾选操作
        //     this.filterFn = filterFn
        //     if (valid) {
        //       selectAll(filterFn)
        //     }
        //   })
        // } else {
        //   // 如果beforeCheckAll不是一个Function,走以前的逻辑
        //   selectAll()
        // }
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.empty {
  display: flex;
  justify-content: center;
}
::v-deep .el-table__empty-text{
  line-height: 1.5;
}
.iconfont {
  margin: 0 0 0 10px;
  font-size: 16px;
  cursor: pointer;
  color: #8c8c8c;
}
.y-table {
  overflow: auto;
}
.table-top{
  display: flex;
  justify-content: flex-start;
}
.table-top-left{
  flex: 1;
  text-align: left;
  justify-content: flex-start;
  margin-bottom: 15px;
}
.table-top-right{
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  margin-bottom: 15px;
}
.utils-wrapper {
  display: flex;
  align-items: center;
  margin:0 18px;
}

.el-table--border.el-table--border__bottom{
  border-right: 1px solid #EBEEF5;
  border-bottom: 1px solid #EBEEF5;
}

.y-table-batch-action-area {
  z-index: 5;
  display: flex;
  position: fixed !important;
  height: 64px;
  align-items: center;
  bottom: 0;
  right: 0;
  background-color: $--color-white;
  box-sizing: border-box;
  padding: 0 24px;
  box-shadow: 0px -3px 6px -4px rgba(0, 0, 0, 0.12),
  0px -6px 16px 0px rgba(0, 0, 0, 0.08), 0px -9px 28px 8px rgba(0, 0, 0, 0.05);
  .action-left {
    flex: 4;
    height: 100%;
    display: inline-flex;
    align-items: center;
    font-size: 14px;
    button {
      margin-left: 16px;
    }
  }
  .action-right {
    flex: 1;
    height: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
  }
}

</style>
